-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[RHOAIENG-10318] Add connection type field modal
- Loading branch information
1 parent
da75c87
commit 93223f0
Showing
7 changed files
with
458 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
261 changes: 261 additions & 0 deletions
261
frontend/src/pages/connectionTypes/connectionTypeFields/AddConnectionTypeFieldModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
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 { HelpIcon, ExclamationCircleIcon } from '@patternfly/react-icons'; | ||
import DashboardModalFooter from '~/concepts/dashboard/DashboardModalFooter'; | ||
import { | ||
ConnectionTypeCommonProperties, | ||
ConnectionTypeDataField, | ||
ConnectionTypeFieldType, | ||
} from '~/concepts/connectionTypes/types'; | ||
import { TextForm } from '~/pages/connectionTypes/connectionTypeFields/TextForm'; | ||
import { isEnumMember } from '~/utilities/utils'; | ||
|
||
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 AddConnectionTypeFieldModalProps { | ||
onCancel: () => void; | ||
onSubmit: (newField: ConnectionTypeDataField) => void; | ||
// existingFields?: ConnectionTypeField[]; | ||
} | ||
|
||
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 AddConnectionTypeFieldModal: React.FC<AddConnectionTypeFieldModalProps> = ({ | ||
onCancel, | ||
onSubmit, | ||
}) => { | ||
const [name, setName] = React.useState<string>(''); | ||
const [description, setDescription] = React.useState<string>(); | ||
const [envVar, setEnvVar] = React.useState<string>(''); | ||
const [fieldType, setFieldType] = React.useState<ConnectionTypeFieldType>( | ||
ConnectionTypeFieldType.ShortText, | ||
); | ||
const [required, setRequired] = React.useState<boolean>(); | ||
const [isOpen, setIsOpen] = React.useState<boolean>(false); | ||
const [textProperties, setTextProperties] = React.useState<ConnectionTypeCommonProperties>({}); | ||
|
||
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 onAdd = () => { | ||
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, | ||
}); | ||
} | ||
}; | ||
|
||
const fieldTypeForm = React.useMemo(() => { | ||
switch (fieldType) { | ||
case ConnectionTypeFieldType.Hidden: | ||
case ConnectionTypeFieldType.File: | ||
case ConnectionTypeFieldType.ShortText: | ||
case ConnectionTypeFieldType.Text: | ||
return ( | ||
<TextForm | ||
properties={textProperties} | ||
onChange={(updatedProperties) => setTextProperties(updatedProperties)} | ||
validate={(value) => validateForType(value, fieldType)} | ||
/> | ||
); | ||
} | ||
return null; | ||
}, [fieldType, textProperties]); | ||
|
||
return ( | ||
<Modal | ||
isOpen | ||
variant="medium" | ||
title="Add field" | ||
onClose={onCancel} | ||
footer={ | ||
<DashboardModalFooter | ||
onCancel={onCancel} | ||
onSubmit={onAdd} | ||
submitLabel="Add" | ||
isSubmitDisabled={!valid} | ||
alertTitle="Error" | ||
/> | ||
} | ||
data-testid="archive-model-version-modal" | ||
> | ||
<Form> | ||
<FormGroup fieldId="name" label="Field name" isRequired> | ||
<TextInput | ||
id="name" | ||
value={name} | ||
onChange={(_ev, value) => setName(value)} | ||
data-testid="field-name-input" | ||
/> | ||
</FormGroup> | ||
<FormGroup | ||
fieldId="description" | ||
label="Field description" | ||
labelIcon={ | ||
<Popover | ||
aria-label="field description help" | ||
headerContent="Field description" | ||
bodyContent="Use the field description to provide users in your organization with additional information about a field, or instructions for completing the field. Your input will appear in a popover, like this one." | ||
> | ||
<HelpIcon style={{ color: 'var(--pf-v5-global--icon--Color--light)' }} /> | ||
</Popover> | ||
} | ||
> | ||
<TextArea | ||
id="description" | ||
data-testid="field-description-input" | ||
value={description} | ||
onChange={(_ev, value) => setDescription(value)} | ||
/> | ||
</FormGroup> | ||
<FormGroup | ||
fieldId="envVar" | ||
label="Environment variable" | ||
labelIcon={ | ||
<Popover | ||
aria-label="environment variable help" | ||
headerContent="Environment variable" | ||
bodyContent="Environment variables grant you access to the value provided when attaching the connection to your workbench." | ||
> | ||
<HelpIcon style={{ color: 'var(--pf-v5-global--icon--Color--light)' }} /> | ||
</Popover> | ||
} | ||
isRequired | ||
> | ||
<TextInput | ||
id="envVar" | ||
value={envVar} | ||
onChange={(_ev, value) => setEnvVar(value)} | ||
data-testid="field-env-var-input" | ||
validated={envVarValidation} | ||
/> | ||
{envVarValidation === ValidatedOptions.error ? ( | ||
<FormHelperText> | ||
<HelperText> | ||
<HelperTextItem icon={<ExclamationCircleIcon />} variant="error"> | ||
{`Invalid variable name. The name must consist of alphabetic characters, digits, '_', '-', or '.', and must not start with a digit.`} | ||
</HelperTextItem> | ||
</HelperText> | ||
</FormHelperText> | ||
) : null} | ||
</FormGroup> | ||
<FormGroup | ||
fieldId="fieldType" | ||
label="Field type" | ||
isRequired | ||
data-testid="field-type-select" | ||
> | ||
<Select | ||
id="fieldType" | ||
isOpen={isOpen} | ||
shouldFocusToggleOnSelect | ||
selected={fieldType} | ||
onSelect={(_e, selection) => { | ||
if (isConnectionTypeFieldType(selection)) { | ||
setFieldType(selection); | ||
setIsOpen(false); | ||
} | ||
}} | ||
onOpenChange={(open) => setIsOpen(open)} | ||
toggle={(toggleRef) => ( | ||
<MenuToggle | ||
ref={toggleRef} | ||
id="type-select" | ||
isFullWidth | ||
onClick={() => { | ||
setIsOpen((open) => !open); | ||
}} | ||
isExpanded={isOpen} | ||
> | ||
{fieldTypeLabels[fieldType]} | ||
</MenuToggle> | ||
)} | ||
> | ||
<SelectList> | ||
<SelectOption | ||
value={ConnectionTypeFieldType.ShortText} | ||
data-testid="field-short-text-select" | ||
> | ||
{fieldTypeLabels[ConnectionTypeFieldType.ShortText]} | ||
</SelectOption> | ||
<SelectOption | ||
value={ConnectionTypeFieldType.Hidden} | ||
data-testid="field-hidden-select" | ||
> | ||
{fieldTypeLabels[ConnectionTypeFieldType.Hidden]} | ||
</SelectOption> | ||
</SelectList> | ||
</Select> | ||
</FormGroup> | ||
{fieldTypeForm} | ||
<FormGroup fieldId="isRequired"> | ||
<Checkbox | ||
id="isRequired" | ||
data-testid="field-required-checkbox" | ||
label="Field is required" | ||
isChecked={required || false} | ||
onChange={(_ev, checked) => { | ||
setRequired(checked); | ||
}} | ||
/> | ||
</FormGroup> | ||
</Form> | ||
</Modal> | ||
); | ||
}; |
37 changes: 37 additions & 0 deletions
37
frontend/src/pages/connectionTypes/connectionTypeFields/TextForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import * as React from 'react'; | ||
import { Checkbox, FormGroup, TextInput, ValidatedOptions } from '@patternfly/react-core'; | ||
import { ConnectionTypeCommonProperties } from '~/concepts/connectionTypes/types'; | ||
|
||
type TextFormProps = { | ||
properties: ConnectionTypeCommonProperties; | ||
onChange: (newProperties: ConnectionTypeCommonProperties) => void; | ||
validate: (value: string) => ValidatedOptions; | ||
}; | ||
|
||
export const TextForm: React.FC<TextFormProps> = ({ properties, onChange, validate }) => ( | ||
<> | ||
<FormGroup fieldId="defaultValue" label="Default value"> | ||
<TextInput | ||
id="defaultValue" | ||
value={properties.defaultValue || ''} | ||
onChange={(_ev, value) => | ||
onChange({ defaultValue: value, defaultReadOnly: properties.defaultReadOnly }) | ||
} | ||
validated={ | ||
properties.defaultValue ? validate(properties.defaultValue) : ValidatedOptions.default | ||
} | ||
data-testid="field-default-value-input" | ||
/> | ||
<Checkbox | ||
id="defaultReadOnly" | ||
label="Default value is read-only" | ||
isDisabled={!properties.defaultValue} | ||
isChecked={(properties.defaultValue && properties.defaultReadOnly) || false} | ||
onChange={(_ev, checked) => | ||
onChange({ defaultValue: properties.defaultValue, defaultReadOnly: checked }) | ||
} | ||
data-testid="field-default-value-readonly-checkbox" | ||
/> | ||
</FormGroup> | ||
</> | ||
); |
Oops, something went wrong.