Skip to content

Commit

Permalink
feat(Form): Add EnumField
Browse files Browse the repository at this point in the history
  • Loading branch information
tplevko committed Jan 30, 2025
1 parent c6743e2 commit e8ad2b6
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { FormGroup, FormGroupLabelHelp, Popover } from '@patternfly/react-core';
import { FunctionComponent, useCallback, useContext, useMemo } from 'react';
import { isDefined } from '../../../../../utils';
import { useFieldValue } from '../hooks/field-value';
import { SchemaContext } from '../providers/SchemaProvider';
import { FieldProps } from '../typings';
import { Typeahead } from '../../../../typeahead/Typeahead';
import { TypeaheadItem } from '../../../../typeahead/Typeahead.types';

export const EnumField: FunctionComponent<FieldProps> = ({ propName, required }) => {
const { schema } = useContext(SchemaContext);
const { value = '', onChange } = useFieldValue<string | undefined>(propName);

const items: TypeaheadItem<string>[] = useMemo(
() =>
schema?.enum?.map((item) => ({
name: String(item),
description: '',
value: String(item),
})) ?? [],
[schema],
);

const selectedItem = useMemo(() => {
if (!value) {
return undefined;
}
return items.find((item) => item.name === value);
}, [items, value]);

const onItemChange = useCallback(
(item?: TypeaheadItem<string>) => {
onChange(item?.name);
},
[onChange],
);

const onCleanInput = useCallback(() => {
onChange(undefined);
}, [onChange]);

if (!schema) {
return <div>EnumField - Schema not defined</div>;
}

const id = `${propName}-popover`;

return (
<FormGroup
fieldId={propName}
label={`${schema.title} (${propName})`}
isRequired={required}
labelHelp={
<Popover
id={id}
headerContent={<p>{schema.title}</p>}
bodyContent={<p>{schema.description}</p>}
footerContent={<p>Default: {schema.default?.toString() ?? 'no default value'}</p>}
triggerAction="hover"
withFocusTrap={false}
>
<FormGroupLabelHelp aria-label={`More info for ${schema.title} field`} />
</Popover>
}
>
<Typeahead
selectedItem={selectedItem}
items={items}
id={propName}
onChange={onItemChange}
onCleanInput={onCleanInput}
/>
</FormGroup>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { KaotoSchemaDefinition } from '../../../../../../models';
import { isDefined } from '../../../../../../utils';
import { OneOfSchemas } from '../../../../../../utils/get-oneof-schema-list';
import { FieldProps } from '../../typings';
import { SimpleSelector } from './SimpleSelector';
import { Typeahead } from './Typeahead';
import { TypeaheadItem } from './Typeahead.types';
import { SimpleSelector } from '../../../../../typeahead/SimpleSelector';
import { Typeahead } from '../../../../../typeahead/Typeahead';
import { TypeaheadItem } from '../../../../../typeahead/Typeahead.types';

interface SchemaList extends FieldProps {
selectedSchema: OneOfSchemas | undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { OneOfField } from '../fields/OneOfField/OneOfField';
import { PasswordField } from '../fields/PasswordField';
import { StringField } from '../fields/StringField';
import { FieldProps } from '../typings';
import { EnumField } from '../fields/EnumField';

type FormComponentFactoryContextValue = (schema: KaotoSchemaDefinition['schema']) => FunctionComponent<FieldProps>;

Expand All @@ -18,6 +19,10 @@ export const FormComponentFactoryProvider: FunctionComponent<PropsWithChildren>
if (schema.format === 'password') {
return PasswordField;
}
if (schema.type === 'string' && Array.isArray(schema.enum)) {
return EnumField;
}

switch (schema.type) {
case 'string':
case 'number':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
useCallback,
useState,
} from 'react';
import { isDefined } from '../../../../../../utils';
import { isDefined } from '../../utils';
import { TypeaheadProps } from './Typeahead.types';

export const SimpleSelector: FunctionComponent<TypeaheadProps> = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ import {
} from '@patternfly/react-core';
import { TimesIcon } from '@patternfly/react-icons';
import { FormEvent, FunctionComponent, MouseEventHandler, Ref, useCallback, useMemo, useRef, useState } from 'react';
import { isDefined } from '../../../../../../utils';
import { isDefined } from '../../utils';
import { TypeaheadProps } from './Typeahead.types';

export const Typeahead: FunctionComponent<TypeaheadProps> = ({
selectedItem,
items,
id,
onChange,
onCleanInput,
'data-testid': dataTestId,
}) => {
const [inputValue, setInputValue] = useState<string>(selectedItem?.name ?? '');
Expand Down Expand Up @@ -57,6 +58,7 @@ export const Typeahead: FunctionComponent<TypeaheadProps> = ({
const onTextInputClear = () => {
setInputValue('');
setIsOpen(true);
onCleanInput?.();
inputRef.current?.focus();
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IDataTestID } from '../../../../../../models';
import { IDataTestID } from '../../models';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface TypeaheadItem<T = any> {
Expand All @@ -12,4 +12,5 @@ export interface TypeaheadProps extends IDataTestID {
items: TypeaheadItem[];
id?: string;
onChange?: (item?: TypeaheadItem) => void;
onCleanInput?: () => void;
}

0 comments on commit e8ad2b6

Please sign in to comment.