diff --git a/client/.eslintrc b/client/.eslintrc
index d9e5e722439..ff8c523e0d7 100644
--- a/client/.eslintrc
+++ b/client/.eslintrc
@@ -92,6 +92,8 @@
"bg-surface-neutral-secondary-hover",
"bg-surface-neutral-tertiary",
"bg-surface-popover-canvas",
+ "bg-surface-warning-primary",
+ "bg-surface-warning-secondary",
"border-accent",
"border-content-neutral-tertiary",
"border-input",
diff --git a/client/src/components/JsonSchemaBuilder/JsonSchemaBuilder.tsx b/client/src/components/JsonSchemaBuilder/JsonSchemaBuilder.tsx
index 40c3800365c..a4ce75bec34 100644
--- a/client/src/components/JsonSchemaBuilder/JsonSchemaBuilder.tsx
+++ b/client/src/components/JsonSchemaBuilder/JsonSchemaBuilder.tsx
@@ -54,6 +54,7 @@ const JsonSchemaBuilder = ({locale = 'en', onChange, schema}: JsonSchemaBuilderP
...schema,
});
}}
+ root
schema={curSchema}
/>
);
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaAddButton.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaAddButton.tsx
deleted file mode 100755
index b78a6af28db..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaAddButton.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import {PlusIcon} from 'lucide-react';
-
-import SchemaRoundedButton from './SchemaRoundedButton';
-
-interface AddButtonProps {
- onClick?: () => void;
- title?: string;
-}
-
-const SchemaAddButton = ({onClick = () => {}, title}: AddButtonProps) => {
- return (
-
-
-
- );
-};
-
-export default SchemaAddButton;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaBox.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaBox.tsx
deleted file mode 100755
index 1e8b124e879..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaBox.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import React, {PropsWithChildren} from 'react';
-
-const SchemaBox = ({children}: PropsWithChildren) => {
- return
{children}
;
-};
-
-export default SchemaBox;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaCheckbox.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaCheckbox.tsx
deleted file mode 100755
index 08cd9eb932d..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaCheckbox.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-import {Label} from '@/components/ui/label';
-import {Toggle} from '@/components/ui/toggle';
-import React from 'react';
-
-const handleChange = (handler: (value: boolean) => void) => {
- return (event: React.FormEvent): void => {
- handler((event.target as HTMLInputElement).checked);
- };
-};
-
-interface SchemaCheckboxProps {
- value: boolean;
- onChange: (v: boolean) => void;
- label?: string;
-}
-
-const SchemaCheckbox = ({label, onChange, value}: SchemaCheckboxProps) => {
- return (
-
-
-
-
-
- );
-};
-
-export default SchemaCheckbox;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaCloseButton.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaCloseButton.tsx
deleted file mode 100755
index 4f3338ca28f..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaCloseButton.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import {XIcon} from 'lucide-react';
-import React from 'react';
-
-import SchemaRoundedButton from './SchemaRoundedButton';
-
-interface CloseButtonProps {
- onClick?: () => void;
- title?: string;
-}
-
-const SchemaCloseButton = ({onClick = () => {}, title}: CloseButtonProps) => {
- return (
-
-
-
- );
-};
-
-export default SchemaCloseButton;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaCollapseButton.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaCollapseButton.tsx
deleted file mode 100755
index d6dfaeb6fe7..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaCollapseButton.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import {ChevronRightIcon} from '@radix-ui/react-icons';
-import {ChevronDownIcon} from 'lucide-react';
-
-import SchemaRoundedButton from './SchemaRoundedButton';
-
-interface CollapseButtonProps {
- onClick?: () => void;
- isCollapsed?: boolean;
- title?: string;
-}
-
-const SchemaCollapseButton = ({isCollapsed = false, onClick = () => {}, title}: CollapseButtonProps) => {
- return (
-
- {isCollapsed ? : }
-
- );
-};
-
-export default SchemaCollapseButton;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaControls.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaControls.tsx
index 67e6f4eb673..4b65eb51987 100755
--- a/client/src/components/JsonSchemaBuilder/components/SchemaControls.tsx
+++ b/client/src/components/JsonSchemaBuilder/components/SchemaControls.tsx
@@ -1,112 +1,193 @@
-import SchemaAddButton from '@/components/JsonSchemaBuilder/components/SchemaAddButton';
-import SchemaCollapseButton from '@/components/JsonSchemaBuilder/components/SchemaCollapseButton';
-import SchemaDeleteButton from '@/components/JsonSchemaBuilder/components/SchemaDeleteButton';
import SchemaInput from '@/components/JsonSchemaBuilder/components/SchemaInput';
-import SchemaMenu from '@/components/JsonSchemaBuilder/components/SchemaMenu';
-import SchemaMenuButton from '@/components/JsonSchemaBuilder/components/SchemaMenuButton';
-import SchemaMenuModal from '@/components/JsonSchemaBuilder/components/SchemaMenuModal';
+import SchemaMenuPopover from '@/components/JsonSchemaBuilder/components/SchemaMenuPopover';
import SchemaTypesSelect from '@/components/JsonSchemaBuilder/components/SchemaTypesSelect';
-import React, {useState} from 'react';
-import {useTranslation} from 'react-i18next';
-
-import * as helpers from '../utils/helpers';
+import {Badge} from '@/components/ui/badge';
+import {Button} from '@/components/ui/button';
+import {CircleEllipsisIcon, PlusIcon, TrashIcon} from 'lucide-react';
+import {useEffect, useState} from 'react';
+import {twMerge} from 'tailwind-merge';
+
+import {
+ addSchemaProperty,
+ getSchemaTitle,
+ getSchemaType,
+ setSchemaTitle,
+ setSchemaTypeAndRemoveWrongFields,
+} from '../utils/helpers';
import {SchemaRecordType} from '../utils/types';
interface SchemaControlsProps {
- schema: SchemaRecordType;
- schemakey: string;
isCollapsed?: boolean;
- onDelete?: () => void;
onAdd?: () => void;
- onCollapse?: () => void;
onChangeKey?: (key: string) => void;
onChange: (schema: SchemaRecordType) => void;
+ onCollapse?: () => void;
+ onDelete?: () => void;
+ root?: boolean;
+ schema: SchemaRecordType;
+ schemakey: string;
}
-export const SchemaControls = ({
- isCollapsed,
- onAdd,
- onChange,
- onChangeKey,
- onCollapse,
- onDelete,
- schema,
- schemakey,
-}: SchemaControlsProps) => {
+const SchemaControls = ({onAdd, onChange, onChangeKey, onDelete, root, schema, schemakey}: SchemaControlsProps) => {
const [isMenuOpen, setIsMenuOpen] = useState(false);
- const {t} = useTranslation();
+ const isObjectSchema = getSchemaType(schema) === 'object';
+
+ const extraFields = Object.keys(schema).filter((key) => key !== 'type' && key !== 'items' && key !== 'properties');
+
+ useEffect(() => {
+ if (!schema.type || !getSchemaType(schema)) {
+ onChange(setSchemaTypeAndRemoveWrongFields('object', schema));
+ }
+ }, [schema, onChange]);
return (
-
-
-
onChange(helpers.setSchemaTitle(title, schema))}
- placeholder={t('title')}
- value={helpers.getSchemaTitle(schema)}
+
+
+ onChange(setSchemaTypeAndRemoveWrongFields(translation, schema))}
+ type={getSchemaType(schema)}
/>
- onChange(helpers.setSchemaTypeAndRemoveWrongFields(t, schema))}
- type={helpers.getSchemaType(schema)}
+ onChange(setSchemaTitle(title, schema))}
+ placeholder="Untitled Pill"
+ value={getSchemaTitle(schema)}
/>
- {typeof onChangeKey === 'function' ? (
-
- ) : null}
+ {typeof onChangeKey === 'function' && (
+
+ )}
-
- {typeof onCollapse === 'function' ? (
-
- ) : null}
-
-
setIsMenuOpen((o) => !o)} title={t('extraOptions')} />
-
- {typeof onDelete === 'function' ? : null}
-
- {typeof onAdd === 'function' ? : null}
+
+
setIsMenuOpen(false)}
+ open={isMenuOpen}
+ schema={schema}
+ >
+
+
+
+ {typeof onDelete === 'function' && (
+
+ )}
+
+ {(typeof onAdd === 'function' || isObjectSchema) && (
+
+ )}
-
- {isMenuOpen && (
- setIsMenuOpen(false)} title={t('extraFields')}>
-
-
- )}
);
};
interface SchemaArrayControlsProps {
- schema: SchemaRecordType;
- onChange: (schema: SchemaRecordType) => void;
onAdd?: () => void;
+ onChange: (schema: SchemaRecordType) => void;
+ root?: boolean;
+ schema: SchemaRecordType;
}
-export const SchemaArrayControls = ({onAdd, onChange, schema}: SchemaArrayControlsProps) => {
+const SchemaArrayControls = ({onAdd, onChange, root, schema}: SchemaArrayControlsProps) => {
const [isMenuOpen, setIsMenuOpen] = useState
(false);
- const {t} = useTranslation();
+ const extraFields = Object.keys(schema).filter((key) => key !== 'type' && key !== 'items' && key !== 'properties');
return (
-
+
onChange(helpers.setSchemaTypeAndRemoveWrongFields(t, schema))}
- type={helpers.getSchemaType(schema)}
+ onChange={(value) => onChange(setSchemaTypeAndRemoveWrongFields(value, schema))}
+ type={getSchemaType(schema)}
/>
-
-
setIsMenuOpen((o) => !o)} title={t('extraOptions')} />
-
- {typeof onAdd === 'function' ? : null}
+
+
setIsMenuOpen(false)}
+ open={isMenuOpen}
+ schema={schema}
+ >
+
+
+
+ {typeof onAdd === 'function' && (
+
+ )}
-
- {isMenuOpen ? (
- setIsMenuOpen(false)} title={t('extraFields')}>
-
-
- ) : null}
);
};
+
+export {SchemaControls, SchemaArrayControls};
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaCreator.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaCreator.tsx
index cd3b49483fe..948c65e63df 100755
--- a/client/src/components/JsonSchemaBuilder/components/SchemaCreator.tsx
+++ b/client/src/components/JsonSchemaBuilder/components/SchemaCreator.tsx
@@ -1,6 +1,8 @@
-import SchemaBox from '@/components/JsonSchemaBuilder/components/SchemaBox';
-import {AsteriskIcon} from 'lucide-react';
-import React, {useState} from 'react';
+import {Badge} from '@/components/ui/badge';
+import {Button} from '@/components/ui/button';
+import {AsteriskIcon, ChevronDownIcon} from 'lucide-react';
+import {PropsWithChildren, useState} from 'react';
+import {twMerge} from 'tailwind-merge';
import {
addSchemaProperty,
@@ -19,12 +21,13 @@ import {SchemaRecordType} from '../utils/types';
import {SchemaArrayControls, SchemaControls} from './SchemaControls';
interface SchemaCreatorProps {
- schema: SchemaRecordType;
- schemakey?: string;
isRequired?: boolean;
onChangeKey?: (key: string) => void;
- onDelete?: (key: string) => void;
onChange?: (schema: SchemaRecordType) => void;
+ onDelete?: (key: string) => void;
+ root?: boolean;
+ schema: SchemaRecordType;
+ schemakey?: string;
}
const SchemaCreator = ({
@@ -32,33 +35,32 @@ const SchemaCreator = ({
onChange = () => {},
onChangeKey = () => {},
onDelete = () => {},
+ root = false,
schema,
schemakey = '__root__',
}: SchemaCreatorProps) => {
- const [isCollapsed, setIsCollapsed] = useState(false);
+ const objectPropertiesCount =
+ isSchemaObject(schema) && getSchemaProperties(schema) ? Object.keys(getSchemaProperties(schema)).length : 0;
return (
-
+
{isRequired &&
}
onChange(addSchemaProperty(schema)) : undefined}
onChange={onChange}
onChangeKey={schemakey !== '__root__' ? onChangeKey : undefined}
- onCollapse={
- isSchemaObject(schema) || isSchemaArray(schema) ? () => setIsCollapsed((c) => !c) : undefined
- }
onDelete={schemakey !== '__root__' ? () => onDelete(schemakey) : undefined}
+ root={root}
schema={schema}
schemakey={schemakey}
/>
-
+
{isSchemaObject(schema) && hasSchemaProperties(schema) && (
-
+
onChange(setSchemaProperty(key, s, schema))}
onChangeKey={(oldkey, newkey) => onChange(renameSchemaProperty(oldkey, newkey, schema))}
@@ -72,6 +74,7 @@ const SchemaCreator = ({
onChange(setSchemaItems(s, schema))}
+ root={schemakey === '__root__'}
schema={getSchemaItems(schema)}
/>
@@ -83,40 +86,41 @@ const SchemaCreator = ({
interface SchemaArrayItemsProps {
schema: SchemaRecordType;
+ root?: boolean;
onChange: (schema: SchemaRecordType) => void;
}
-const SchemaArrayItems = ({onChange, schema}: SchemaArrayItemsProps) => {
- return (
-
-
onChange(addSchemaProperty(schema)) : undefined}
- onChange={onChange}
- schema={schema}
- />
-
- {isSchemaObject(schema) && hasSchemaProperties(schema) && (
-
- onChange(setSchemaProperty(key, s, schema))}
- onChangeKey={(oldkey, newkey) => onChange(renameSchemaProperty(oldkey, newkey, schema))}
- onDelete={(key) => onChange(deleteSchemaProperty(key, schema))}
- schema={schema}
- />
-
- )}
+const SchemaArrayItems = ({onChange, root, schema}: SchemaArrayItemsProps) => (
+ <>
+ onChange(addSchemaProperty(schema)) : undefined}
+ onChange={onChange}
+ root={root}
+ schema={schema}
+ />
- {isSchemaArray(schema) && (
-
- onChange(setSchemaItems(s, schema))}
- schema={getSchemaItems(schema)}
- />
-
- )}
-
- );
-};
+ {isSchemaObject(schema) && hasSchemaProperties(schema) && (
+
+ onChange(setSchemaProperty(key, s, schema))}
+ onChangeKey={(oldkey, newkey) => onChange(renameSchemaProperty(oldkey, newkey, schema))}
+ onDelete={(key) => onChange(deleteSchemaProperty(key, schema))}
+ schema={schema}
+ />
+
+ )}
+
+ {isSchemaArray(schema) && (
+
+ onChange(setSchemaItems(s, schema))}
+ root={root}
+ schema={getSchemaItems(schema)}
+ />
+
+ )}
+ >
+);
interface SchemaObjectPropertiesProps {
schema: SchemaRecordType;
@@ -125,22 +129,44 @@ interface SchemaObjectPropertiesProps {
onChange: (key: string, schema: SchemaRecordType) => void;
}
-const SchemaObjectProperties = ({onChange, onChangeKey, onDelete, schema}: SchemaObjectPropertiesProps) => {
+const SchemaObjectProperties = ({onChange, onChangeKey, onDelete, schema}: SchemaObjectPropertiesProps) => (
+
+ {Object.entries(getSchemaProperties(schema)).map(([key, s]) => (
+ -
+ onChange(key, newSchema)}
+ onChangeKey={(newKey) => onChangeKey(key, newKey)}
+ onDelete={onDelete}
+ schema={s as SchemaRecordType}
+ schemakey={key}
+ />
+
+ ))}
+
+);
+
+const SchemaBox = ({children, itemCount}: {itemCount?: number} & PropsWithChildren) => {
+ const [isCollapsed, setIsCollapsed] = useState(false);
+
return (
-
- {Object.entries(getSchemaProperties(schema)).map(([key, s]) => (
- -
- onChange(key, newSchema)}
- onChangeKey={(newKey) => onChangeKey(key, newKey)}
- onDelete={onDelete}
- schema={s as SchemaRecordType}
- schemakey={key}
- />
-
- ))}
-
+
+
+
+ {isCollapsed ?
{itemCount} items nested :
{children}
}
+
);
};
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaDeleteButton.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaDeleteButton.tsx
deleted file mode 100755
index f3c47afab10..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaDeleteButton.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import {TrashIcon} from 'lucide-react';
-
-import SchemaRoundedButton from './SchemaRoundedButton';
-
-interface DeleteButtonProps {
- onClick?: () => void;
- title?: string;
-}
-
-const SchemaDeleteButton = ({onClick = () => {}, title}: DeleteButtonProps) => {
- return (
-
-
-
- );
-};
-
-export default SchemaDeleteButton;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaInput.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaInput.tsx
index 7b70e19b5d1..f91ccf88581 100755
--- a/client/src/components/JsonSchemaBuilder/components/SchemaInput.tsx
+++ b/client/src/components/JsonSchemaBuilder/components/SchemaInput.tsx
@@ -18,34 +18,35 @@ interface SchemaInputProps {
type?: string;
}
-const SchemaInput = ({label, onChange, placeholder, type = 'text', value = ''}: SchemaInputProps) => {
- const [localVal, setLocalVal] = useState(value);
-
- useEffect(() => {
- setLocalVal(value);
- }, [value]);
+const SchemaInput = ({label, onChange, placeholder, type = 'text', value = 'Untitled'}: SchemaInputProps) => {
+ const [localValue, setLocalValue] = useState(value);
const onChangeValue = () => {
- if (localVal === value) {
+ if (localValue === value) {
return;
}
- onChange(localVal);
+ onChange(localValue);
};
+ useEffect(() => {
+ setLocalValue(value);
+ }, [value]);
+
return (
-
+
+
);
};
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaMenu.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaMenu.tsx
deleted file mode 100755
index 64402f2e002..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaMenu.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-import React, {useMemo} from 'react';
-import {useTranslation} from 'react-i18next';
-import Select from 'react-select';
-
-import * as helpers from '../utils/helpers';
-import {SchemaMenuOptionType, SchemaRecordType} from '../utils/types';
-import SchemaMenuList from './SchemaMenuList';
-
-import '../../CreatableSelect/CreatableSelect.css';
-
-interface SchemaMenuProps {
- schema: SchemaRecordType;
- onChange: (schema: SchemaRecordType) => void;
-}
-
-const SchemaMenu = ({onChange, schema}: SchemaMenuProps) => {
- const {t} = useTranslation();
-
- const type = helpers.getSchemaType(schema);
- const allOptions = useMemo(() => helpers.translateLabels(t, helpers.getSchemaMenuOptions(type)), [type, t]);
-
- const fields = helpers.getAllSchemaKeys(schema);
-
- const displayFields = useMemo(() => allOptions.filter((item) => fields.includes(item.value)), [allOptions, fields]);
-
- return (
-
-
-
-
- );
-};
-
-export default SchemaMenu;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaMenuButton.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaMenuButton.tsx
deleted file mode 100755
index ea931cd3fec..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaMenuButton.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import {EllipsisVerticalIcon} from 'lucide-react';
-import React from 'react';
-
-import SchemaRoundedButton from './SchemaRoundedButton';
-
-interface MenuButtonProps {
- onClick?: () => void;
- title?: string;
-}
-
-const SchemaMenuButton = ({onClick = () => {}, title}: MenuButtonProps) => {
- return (
-
-
-
- );
-};
-
-export default SchemaMenuButton;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaMenuItem.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaMenuItem.tsx
index 8031037bb2d..20b4ef854a8 100755
--- a/client/src/components/JsonSchemaBuilder/components/SchemaMenuItem.tsx
+++ b/client/src/components/JsonSchemaBuilder/components/SchemaMenuItem.tsx
@@ -1,5 +1,3 @@
-import SchemaCheckbox from '@/components/JsonSchemaBuilder/components/SchemaCheckbox';
-import SchemaDeleteButton from '@/components/JsonSchemaBuilder/components/SchemaDeleteButton';
import SchemaInput from '@/components/JsonSchemaBuilder/components/SchemaInput';
import {Label} from '@/components/ui/label';
import React, {useMemo} from 'react';
@@ -24,22 +22,29 @@ import {SchemaMenuOptionType, SchemaRecordType} from '../utils/types';
import '../../CreatableSelect/CreatableSelect.css';
+import {Button} from '@/components/ui/button';
+import {Toggle} from '@/components/ui/toggle';
+import {TrashIcon} from 'lucide-react';
+
interface ItemProps {
onDelete: () => void;
children: React.ReactNode;
}
-const Item = ({children, onDelete}: ItemProps) => {
- return (
-
- );
-};
+const Item = ({children, onDelete}: ItemProps) => (
+
+);
interface ItemTypeProps {
field: SchemaMenuOptionType;
@@ -47,50 +52,38 @@ interface ItemTypeProps {
onChange: (schema: SchemaRecordType) => void;
}
-export const TextItem = ({field, onChange, schema}: ItemTypeProps) => {
- const {t} = useTranslation();
-
- return (
- - onChange(deleteSchemaField(field.value, schema))}>
- onChange(setSchemaField(field.value, text, schema))}
- value={getSchemaField(schema, field.value) as string}
- />
-
- );
-};
-
-export const NumberItem = ({field, onChange, schema}: ItemTypeProps) => {
- const {t} = useTranslation();
-
- return (
- - onChange(deleteSchemaField(field.value, schema))}>
- onChange(setSchemaField(field.value, parseInt(text, 10), schema))}
- type={'number'}
- value={getSchemaField(schema, field.value) as string}
- />
-
- );
-};
-
-export const BoolItem = ({field, onChange, schema}: ItemTypeProps) => {
- const {t} = useTranslation();
- return (
- - onChange(deleteSchemaField(field.value, schema))}>
- onChange(setSchemaField(field.value, text, schema))}
- value={getSchemaField(schema, field.value) as boolean}
- />
-
- );
-};
+export const TextItem = ({field, onChange, schema}: ItemTypeProps) => (
+ - onChange(deleteSchemaField(field.value, schema))}>
+ onChange(setSchemaField(field.value, text, schema))}
+ value={getSchemaField(schema, field.value) as string}
+ />
+
+);
+
+export const NumberItem = ({field, onChange, schema}: ItemTypeProps) => (
+ - onChange(deleteSchemaField(field.value, schema))}>
+ onChange(setSchemaField(field.value, parseInt(text, 10), schema))}
+ type={'number'}
+ value={getSchemaField(schema, field.value) as string}
+ />
+
+);
+
+export const BoolItem = ({field, onChange, schema}: ItemTypeProps) => (
+ - onChange(deleteSchemaField(field.value, schema))}>
+ onChange(setSchemaField(field.value, text, schema))}
+ value={getSchemaField(schema, field.value) as boolean}
+ />
+
+);
export const CreatableMultiSelectItem = ({field, onChange, schema}: ItemTypeProps) => {
- const {t} = useTranslation();
const selected = getSchemaField(schema, field.value);
const allOptions = useMemo(() => stringsToOptions(selected as string[]), [selected]);
@@ -98,19 +91,18 @@ export const CreatableMultiSelectItem = ({field, onChange, schema}: ItemTypeProp
return (
- onChange(deleteSchemaField(field.value, schema))}>
-
+
t('noOptions')}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- onChange={(options: any) => {
- onChange(setSchemaField(field.value, optionsToStrings(options), schema));
- }}
+ noOptionsMessage="No Options"
+ onChange={(options: {value: string}[]) =>
+ onChange(setSchemaField(field.value, optionsToStrings(options), schema))
+ }
options={allOptions}
- placeholder={t('options')}
+ placeholder="Options"
value={allOptions}
/>
@@ -119,26 +111,29 @@ export const CreatableMultiSelectItem = ({field, onChange, schema}: ItemTypeProp
};
export const SelectItem = ({field, onChange, schema}: ItemTypeProps) => {
- const {t} = useTranslation();
- const options = useMemo(() => translateLabels(t, field.optionList), [field.optionList, t]);
+ const {t: translation} = useTranslation();
+
+ const options = useMemo(() => translateLabels(translation, field.optionList), [field.optionList, translation]);
+
const option = getSchemaField(schema, field.value);
+
const selected = React.useMemo(() => findOption(option as string)(options), [options, option]);
return (
- onChange(deleteSchemaField(field.value, schema))}>
-
+
@@ -151,8 +146,6 @@ export const RequiredMultiSelectItem: React.FunctionComponent = (
onChange,
schema,
}: ItemTypeProps) => {
- const {t} = useTranslation();
-
if (!isSchemaObject(schema) || !hasSchemaProperties(schema)) {
return null;
}
@@ -163,22 +156,43 @@ export const RequiredMultiSelectItem: React.FunctionComponent = (
return (
- onChange(deleteSchemaField(field.value, schema))}>
-
+
);
};
+
+interface SchemaCheckboxProps {
+ value: boolean;
+ onChange: (value: boolean) => void;
+ label?: string;
+}
+
+const SchemaCheckbox = ({label, onChange, value}: SchemaCheckboxProps) => {
+ const handleChange =
+ (handler: (value: boolean) => void) =>
+ (event: React.FormEvent): void => {
+ handler((event.target as HTMLInputElement).checked);
+ };
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaMenuList.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaMenuList.tsx
index 2438d333bb4..5811ddef87c 100755
--- a/client/src/components/JsonSchemaBuilder/components/SchemaMenuList.tsx
+++ b/client/src/components/JsonSchemaBuilder/components/SchemaMenuList.tsx
@@ -26,14 +26,12 @@ interface SchemaMenuListProps {
schema: SchemaRecordType;
}
-const SchemaMenuList = ({fields, onChange, schema}: SchemaMenuListProps) => {
- return (
-
- {fields.map((field) => (
- - {typeToItem[field.type]({field, onChange, schema})}
- ))}
-
- );
-};
+const SchemaMenuList = ({fields, onChange, schema}: SchemaMenuListProps) => (
+
+ {fields.map((field) => (
+ - {typeToItem[field.type]({field, onChange, schema})}
+ ))}
+
+);
export default SchemaMenuList;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaMenuModal.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaMenuModal.tsx
deleted file mode 100755
index d5733edf008..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaMenuModal.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import {
- Dialog,
- DialogCloseButton,
- DialogContent,
- DialogDescription,
- DialogHeader,
- DialogTitle,
-} from '@/components/ui/dialog';
-import React from 'react';
-
-interface SchemaMenuModalProps {
- onClose: () => void;
- children?: React.ReactNode;
- title?: string | React.ReactNode;
-}
-
-const SchemaMenuModal = ({children, onClose, title}: SchemaMenuModalProps) => {
- return (
-
- );
-};
-
-export default SchemaMenuModal;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaMenuPopover.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaMenuPopover.tsx
new file mode 100755
index 00000000000..57bbb6c3556
--- /dev/null
+++ b/client/src/components/JsonSchemaBuilder/components/SchemaMenuPopover.tsx
@@ -0,0 +1,83 @@
+import {Button} from '@/components/ui/button';
+import {Label} from '@/components/ui/label';
+import {Popover, PopoverContent, PopoverTrigger} from '@/components/ui/popover';
+import {X as CloseIcon} from 'lucide-react';
+import {ReactNode, useMemo, useState} from 'react';
+import {useTranslation} from 'react-i18next';
+import Select from 'react-select';
+
+import {getAllSchemaKeys, getSchemaMenuOptions, getSchemaType, setSchemaField, translateLabels} from '../utils/helpers';
+import {SchemaMenuOptionType, SchemaRecordType} from '../utils/types';
+import SchemaMenuList from './SchemaMenuList';
+
+interface SchemaMenuPopoverProps {
+ onChange: (schema: SchemaRecordType) => void;
+ onClose: () => void;
+ schema: SchemaRecordType;
+ children?: ReactNode;
+ open?: boolean;
+}
+
+const SchemaMenuPopover = ({children, onChange, onClose, open: controlledOpen, schema}: SchemaMenuPopoverProps) => {
+ const [internalOpen, setInternalOpen] = useState(false);
+ const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;
+
+ const {t: translation} = useTranslation();
+
+ const type = getSchemaType(schema);
+ const fields = getAllSchemaKeys(schema);
+
+ const allOptions = useMemo(() => translateLabels(translation, getSchemaMenuOptions(type)), [type, translation]);
+
+ const displayFields = useMemo(() => allOptions.filter((item) => fields.includes(item.value)), [allOptions, fields]);
+
+ const handleOpenChange = (open: boolean) => {
+ if (!open) {
+ onClose();
+ }
+ if (controlledOpen === undefined) {
+ setInternalOpen(open);
+ }
+ };
+
+ return (
+
+ {children}
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default SchemaMenuPopover;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaRoundedButton.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaRoundedButton.tsx
deleted file mode 100755
index c4e05811191..00000000000
--- a/client/src/components/JsonSchemaBuilder/components/SchemaRoundedButton.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-import {twMerge} from 'tailwind-merge';
-
-interface RoundedButtonProps {
- onClick?: () => void;
- className?: string;
- title?: string;
- children: React.ReactNode;
-}
-
-const SchemaRoundedButton = ({children, className = '', onClick = () => {}, title}: RoundedButtonProps) => {
- return (
-
- );
-};
-
-export default SchemaRoundedButton;
diff --git a/client/src/components/JsonSchemaBuilder/components/SchemaTypesSelect.tsx b/client/src/components/JsonSchemaBuilder/components/SchemaTypesSelect.tsx
index 27ad7a3a218..426ee4a7cba 100755
--- a/client/src/components/JsonSchemaBuilder/components/SchemaTypesSelect.tsx
+++ b/client/src/components/JsonSchemaBuilder/components/SchemaTypesSelect.tsx
@@ -1,6 +1,4 @@
import {Label} from '@/components/ui/label';
-import React from 'react';
-import {useTranslation} from 'react-i18next';
import {SCHEMA_TYPES} from '../utils/constants';
import * as helpers from '../utils/helpers';
@@ -9,41 +7,39 @@ import {SchemaType} from '../utils/types';
import '../../CreatableSelect/CreatableSelect.css';
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@/components/ui/select';
+import {TYPE_ICONS} from '@/shared/typeIcons';
interface SchemaTypesSelectProps {
type: SchemaType;
onChange: (type: SchemaType) => void;
}
-const SchemaTypesSelect = ({onChange, type}: SchemaTypesSelectProps) => {
- const {t} = useTranslation();
-
- const options = React.useMemo(() => helpers.translateLabels(t, SCHEMA_TYPES), [t]);
-
- return (
-
-
-
-
-
- );
-};
+const SchemaTypesSelect = ({onChange, type}: SchemaTypesSelectProps) => (
+
+);
export default SchemaTypesSelect;
diff --git a/client/src/components/JsonSchemaBuilder/utils/constants.ts b/client/src/components/JsonSchemaBuilder/utils/constants.ts
index 3575c7ba4dd..15074a95364 100755
--- a/client/src/components/JsonSchemaBuilder/utils/constants.ts
+++ b/client/src/components/JsonSchemaBuilder/utils/constants.ts
@@ -20,27 +20,27 @@ import {
export const SCHEMA_TYPES: SchemaTypeOptionType[] = [
{
- label: 'schemaTypes.text',
+ label: 'String',
value: 'string',
},
{
- label: 'schemaTypes.integer',
+ label: 'Integer',
value: 'integer',
},
{
- label: 'schemaTypes.decimal',
+ label: 'Number',
value: 'number',
},
{
- label: 'schemaTypes.boolean',
+ label: 'Boolean',
value: 'boolean',
},
{
- label: 'schemaTypes.object',
+ label: 'Object',
value: 'object',
},
{
- label: 'schemaTypes.array',
+ label: 'Array',
value: 'array',
},
];
diff --git a/client/src/components/Note.tsx b/client/src/components/Note.tsx
new file mode 100644
index 00000000000..bebb81e438a
--- /dev/null
+++ b/client/src/components/Note.tsx
@@ -0,0 +1,17 @@
+import {XIcon} from 'lucide-react';
+import {ReactNode} from 'react';
+import {twMerge} from 'tailwind-merge';
+
+import {Button} from './ui/button';
+
+export const Note = ({content, icon}: {content: string; icon?: ReactNode}) => (
+
+ {icon && icon}
+
+
{content}
+
+
+
+);
diff --git a/client/src/pages/platform/workflow-editor/components/properties/components/property-json-schema-builder/PropertyJsonSchemaBuilderSheet.tsx b/client/src/pages/platform/workflow-editor/components/properties/components/property-json-schema-builder/PropertyJsonSchemaBuilderSheet.tsx
index 196287eadfd..8f15f420a15 100755
--- a/client/src/pages/platform/workflow-editor/components/properties/components/property-json-schema-builder/PropertyJsonSchemaBuilderSheet.tsx
+++ b/client/src/pages/platform/workflow-editor/components/properties/components/property-json-schema-builder/PropertyJsonSchemaBuilderSheet.tsx
@@ -1,9 +1,11 @@
import JsonSchemaBuilder from '@/components/JsonSchemaBuilder/JsonSchemaBuilder';
import {SchemaRecordType} from '@/components/JsonSchemaBuilder/utils/types';
+import {Note} from '@/components/Note';
import {Sheet, SheetCloseButton, SheetContent, SheetDescription, SheetHeader, SheetTitle} from '@/components/ui/sheet';
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@/components/ui/tabs';
import {SPACE} from '@/shared/constants';
import Editor from '@monaco-editor/react';
+import {MessageCircleQuestionIcon} from 'lucide-react';
import React from 'react';
interface PropertyJsonSchemaBuilderSheetProps {
@@ -24,7 +26,7 @@ const PropertyJsonSchemaBuilderSheet = ({locale, onChange, onClose, schema}: Pro
- JSON Schema Builder
+ Response template
Define desired response format for the output
@@ -37,14 +39,19 @@ const PropertyJsonSchemaBuilderSheet = ({locale, onChange, onClose, schema}: Pro
Designer
- Editor
+ Code Editor
-
+
+ }
+ />
+
diff --git a/client/src/styles/components.css b/client/src/styles/components.css
index c460ed4c71f..f95ad9599c5 100644
--- a/client/src/styles/components.css
+++ b/client/src/styles/components.css
@@ -53,6 +53,8 @@
--surface-neutral-secondary-hover: 214 32% 91%;
--surface-neutral-tertiary: 214 32% 91%;
--surface-popover-canvas: 210 40% 98%;
+ --surface-warning-primary: 48, 96%, 53%;
+ --surface-warning-secondary: 55, 92%, 95%;
--content-brand-primary: 217 91% 40%;
--content-destructive: 0 74% 42%;
--content-neutral-primary: 229 84% 5%;
diff --git a/client/tailwind.config.js b/client/tailwind.config.js
index 6bf9f394eb1..a2ae49479f7 100644
--- a/client/tailwind.config.js
+++ b/client/tailwind.config.js
@@ -134,6 +134,10 @@ module.exports = {
popover: {
canvas: 'hsl(var(--surface-popover-canvas))',
},
+ warning: {
+ primary: 'hsl(var(--surface-warning-primary))',
+ secondary: 'hsl(var(--surface-warning-secondary))',
+ },
},
},
height: {