/*! 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);