/*! Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ import { Field } from 'aws-northstar/components/FormRenderer'; import { api } from '$api/client'; import React, { FunctionComponent, memo, useEffect, useState } from 'react'; import TextField from 'aws-northstar/components/FormRenderer/components/TextField'; import useFieldApi, { UseFieldApiConfig } from '@data-driven-forms/react-form-renderer/use-field-api'; import useFormApi from '@data-driven-forms/react-form-renderer/use-form-api'; export const DynamoDBTableFieldResolveProps: Field['resolveProps'] = (_props, { input }) => { return { helperText: renderHelperText(input.value), }; }; const TABLE_ARN_PATTERN = /^arn:aws:dynamodb:([a-z])+-([a-z])+-\d:\d+:table\/([A-Za-z0-9-]+)$/; const PATTERN_ROLE_ARN = /^arn:aws:iam::\d{12}:role\/([A-Za-z0-9-]+)$/; function renderHelperText(tableStreamDetails?: TableStreamDetails, tableArn?: string): React.ReactNode { let returnLine = -; if (tableStreamDetails?.tableStreamArn) returnLine = ( <> Table stream ARN: {tableStreamDetails.tableStreamArn} : {tableStreamDetails.streamViewType} ); if (tableStreamDetails && tableStreamDetails.crossAccount) { returnLine = ( This table exists in another account, please supply an IAM role that can be used to access the table ); } if (tableStreamDetails && !tableStreamDetails.streamEnabled) { returnLine = No table stream configured, one may be created if'Automatic updates' are selected; } if (tableArn?.match(TABLE_ARN_PATTERN) && !tableStreamDetails) { returnLine = Retrieving table details...; } if (tableStreamDetails?.badRequest) { returnLine = ( <> Unable to inspect table ARN. Please check the ARN and try again. ); } return {returnLine}; } interface TableStreamDetails { crossAccount?: boolean; tableStreamArn?: string; streamViewType?: string; streamEnabled?: boolean; badRequest?: boolean; } export const DynamoDBTableField: FunctionComponent = (props) => { const form = useFormApi(); const { input } = useFieldApi(props); const [tableStreamDetails, setTableStreamDetails] = useState(); const [tableArn, setTableArn] = useState(undefined); const [roleArn, setRoleArn] = useState(undefined); const [helperText, setHelperText] = useState(renderHelperText(props.value)); useEffect(() => { setHelperText(renderHelperText(tableStreamDetails, tableArn)); }, [tableArn, tableStreamDetails]); useEffect(() => { if (tableArn?.match(TABLE_ARN_PATTERN) && !tableStreamDetails) { // get stream from arn api .getDataProductDynamoDBTableStream({ tableArn: encodeURIComponent(tableArn) }) .then((data) => { setTableStreamDetails({ ...data }); }) .catch((response) => { if (response.status === 400) { setTableStreamDetails({ badRequest: true }); } else { throw new Error(`Error response from get-data-stream api: ${response}`); } }); } else if (!tableArn || (!tableArn.match(TABLE_ARN_PATTERN) && tableStreamDetails)) { setTableStreamDetails(undefined); setRoleArn(undefined); } }, [form, tableArn, setTableStreamDetails, tableStreamDetails]); useEffect(() => { form.change(input.name, { tableArn, roleArn, }); }, [roleArn, tableArn]); const tableArnChangeHandler = (value: string) => { setTableArn(value); setTableStreamDetails(undefined); }; const roleArnChangeHandler = (value: string) => { setRoleArn(value); }; // A complex wizard field that requires its own validation instead of the one provided by the index manifest file return ( <> {tableStreamDetails?.crossAccount && ( )} ); }; export default memo(DynamoDBTableField);