From 9e97d43ce0e41cdb57a730dd5abef5a4e6e690c3 Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Date: Tue, 13 Aug 2024 06:34:01 -0400 Subject: [PATCH] [RHOAIENG-10318] Add connection type field modal --- .../src/concepts/connectionTypes/types.ts | 12 +- .../fields/ConnectionTypeDataFieldModal.tsx | 277 ++++++++++++++++++ .../pages/connectionTypes/fields/TextForm.tsx | 37 +++ .../AddConnectionTypeFieldModal.spec.tsx | 93 ++++++ .../manage/ConnectionTypeFieldModal.tsx | 12 +- .../ManageConnectionTypeFieldsTable.tsx | 3 +- .../ManageConnectionTypeFieldsTableRow.tsx | 2 +- 7 files changed, 420 insertions(+), 16 deletions(-) create mode 100644 frontend/src/pages/connectionTypes/fields/ConnectionTypeDataFieldModal.tsx create mode 100644 frontend/src/pages/connectionTypes/fields/TextForm.tsx create mode 100644 frontend/src/pages/connectionTypes/fields/__tests__/AddConnectionTypeFieldModal.spec.tsx diff --git a/frontend/src/concepts/connectionTypes/types.ts b/frontend/src/concepts/connectionTypes/types.ts index b6cc883877..853cb48d8f 100644 --- a/frontend/src/concepts/connectionTypes/types.ts +++ b/frontend/src/concepts/connectionTypes/types.ts @@ -31,15 +31,17 @@ type Field = { description?: string; }; +export type ConnectionTypeCommonProperties = { + defaultValue?: V; + defaultReadOnly?: boolean; +}; + // P default to an empty set of properties // eslint-disable-next-line @typescript-eslint/ban-types -type DataField = Field & { +export type DataField = Field & { envVar: string; required?: boolean; - properties: P & { - defaultValue?: V; - defaultReadOnly?: boolean; - }; + properties: P & ConnectionTypeCommonProperties; }; export type SectionField = Field; diff --git a/frontend/src/pages/connectionTypes/fields/ConnectionTypeDataFieldModal.tsx b/frontend/src/pages/connectionTypes/fields/ConnectionTypeDataFieldModal.tsx new file mode 100644 index 0000000000..441dfb34bb --- /dev/null +++ b/frontend/src/pages/connectionTypes/fields/ConnectionTypeDataFieldModal.tsx @@ -0,0 +1,277 @@ +import * as React from 'react'; +import { + Checkbox, + Form, + FormGroup, + FormHelperText, + HelperText, + HelperTextItem, + MenuToggle, + Modal, + Popover, + Select, + SelectList, + SelectOption, + TextArea, + TextInput, + ValidatedOptions, +} from '@patternfly/react-core'; +import { ExclamationCircleIcon, OutlinedQuestionCircleIcon } from '@patternfly/react-icons'; +import DashboardModalFooter from '~/concepts/dashboard/DashboardModalFooter'; +import { + ConnectionTypeCommonProperties, + ConnectionTypeDataField, + ConnectionTypeFieldType, +} from '~/concepts/connectionTypes/types'; +import { TextForm } from '~/pages/connectionTypes/fields/TextForm'; +import { isEnumMember } from '~/utilities/utils'; +import DashboardPopupIconButton from '~/concepts/dashboard/DashboardPopupIconButton'; + +const ENV_VAR_NAME_REGEX = new RegExp('^[-._a-zA-Z][-._a-zA-Z0-9]*$'); + +const isConnectionTypeFieldType = ( + fieldType: string | number | undefined, +): fieldType is ConnectionTypeFieldType => + isEnumMember(fieldType?.toString(), ConnectionTypeFieldType); + +interface ConnectionTypeFieldModalProps { + field?: ConnectionTypeDataField; + isOpen?: boolean; + onClose: () => void; + onSubmit: (field: ConnectionTypeDataField) => void; + isEdit?: boolean; +} + +const fieldTypeLabels: { [key: string]: string } = { + [ConnectionTypeFieldType.Boolean]: 'Boolean', + [ConnectionTypeFieldType.Dropdown]: 'Short text', + [ConnectionTypeFieldType.File]: 'File', + [ConnectionTypeFieldType.Hidden]: 'Hidden', + [ConnectionTypeFieldType.Numeric]: 'Numeric', + [ConnectionTypeFieldType.ShortText]: 'Short text', + [ConnectionTypeFieldType.Text]: 'Text', + [ConnectionTypeFieldType.URI]: 'URI', +}; + +const validateForType = (value: string, fieldType: ConnectionTypeFieldType): ValidatedOptions => { + switch (fieldType) { + default: + return ValidatedOptions.default; + } +}; + +export const ConnectionTypeDataFieldModal: React.FC = ({ + field, + isOpen, + onClose, + onSubmit, + isEdit, +}) => { + const [name, setName] = React.useState(field?.name || ''); + const [description, setDescription] = React.useState(field?.description); + const [envVar, setEnvVar] = React.useState(field?.envVar || ''); + const [fieldType, setFieldType] = React.useState( + ConnectionTypeFieldType.ShortText, + ); + const [required, setRequired] = React.useState(field?.required); + const [isTypeSelectOpen, setIsTypeSelectOpen] = React.useState(false); + const [textProperties, setTextProperties] = React.useState( + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions,@typescript-eslint/no-explicit-any + (field?.properties as any) || {}, + ); + + const envVarValidation = + !envVar || ENV_VAR_NAME_REGEX.test(envVar) ? ValidatedOptions.default : ValidatedOptions.error; + const valid = React.useMemo( + () => !!name && !!envVar && envVarValidation === ValidatedOptions.default, + [envVar, envVarValidation, name], + ); + + const handleSubmit = () => { + switch (fieldType) { + case ConnectionTypeFieldType.Hidden: + case ConnectionTypeFieldType.File: + case ConnectionTypeFieldType.ShortText: + case ConnectionTypeFieldType.Text: + case ConnectionTypeFieldType.URI: + onSubmit({ + name, + description, + envVar, + type: fieldType, + properties: { + defaultValue: textProperties.defaultValue, + defaultReadOnly: textProperties.defaultValue + ? textProperties.defaultReadOnly + : undefined, + }, + required, + }); + } + onClose(); + }; + + const fieldTypeForm = React.useMemo(() => { + switch (fieldType) { + case ConnectionTypeFieldType.Hidden: + case ConnectionTypeFieldType.File: + case ConnectionTypeFieldType.ShortText: + case ConnectionTypeFieldType.Text: + return ( + setTextProperties(updatedProperties)} + validate={(value) => validateForType(value, fieldType)} + /> + ); + } + return null; + }, [fieldType, textProperties]); + + return ( + + } + data-testid="archive-model-version-modal" + > +
+ + setName(value)} + data-testid="field-name-input" + /> + + + } + aria-label="More info for section heading" + /> + + } + > +