diff --git a/cypress/e2e/schema/field.spec.js b/cypress/e2e/schema/field.spec.js index 8cd78c312..cfd1c4a8d 100644 --- a/cypress/e2e/schema/field.spec.js +++ b/cypress/e2e/schema/field.spec.js @@ -54,6 +54,9 @@ const SELECTORS = { MAX_CHARACTER_LIMIT_INPUT: "MaxCharacterLimitInput", MIN_CHARACTER_ERROR_MSG: "MinCharacterErrorMsg", MAX_CHARACTER_ERROR_MSG: "MaxCharacterErrorMsg", + ADD_NEW_RELATED_ITEM: "add-relational-item-button", + CONFIRM_NEW_RELATED_ITEM: "done-selecting-item-button", + ACTIVE_RELATED_ITEM: "active-relational-item", }; /** @@ -341,13 +344,12 @@ describe("Schema: Fields", () => { // click on the default value checkbox cy.getBySelector(SELECTORS.DEFAULT_VALUE_CHECKBOX).click(); // enter a default value - cy.getBySelector(SELECTORS.DEFAULT_VALUE_INPUT).click(); + cy.getBySelector(SELECTORS.ADD_NEW_RELATED_ITEM).click(); // Select the option - cy.get("[role=listbox] [role=option]").first().click(); + cy.get(".MuiDataGrid-row").first().find("input").click(); + cy.getBySelector(SELECTORS.CONFIRM_NEW_RELATED_ITEM).click(); // verify that the default value is set - cy.getBySelector(SELECTORS.DEFAULT_VALUE_INPUT) - .find("input") - .should("have.value", "- None -"); + cy.getBySelector(SELECTORS.ACTIVE_RELATED_ITEM).should("have.length", 1); cy.getBySelector(SELECTORS.DEFAULT_VALUE_CHECKBOX).click(); // Click done diff --git a/src/apps/schema/src/app/components/AddFieldModal/DefaultValueInput.tsx b/src/apps/schema/src/app/components/AddFieldModal/DefaultValueInput.tsx index 91c52679d..77f361419 100644 --- a/src/apps/schema/src/app/components/AddFieldModal/DefaultValueInput.tsx +++ b/src/apps/schema/src/app/components/AddFieldModal/DefaultValueInput.tsx @@ -4,7 +4,6 @@ import { Menu, MenuItem, Button, - Chip, ToggleButtonGroup, ToggleButton, Select, @@ -24,23 +23,13 @@ import { } from "../../../../../content-editor/src/app/components/Editor/Field/FieldShell"; import KeyboardArrowDownRoundedIcon from "@mui/icons-material/KeyboardArrowDownRounded"; import { FieldTypeMedia } from "../../../../../content-editor/src/app/components/FieldTypeMedia"; -import { AppLink } from "@zesty-io/core/AppLink"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faEdit } from "@fortawesome/free-solid-svg-icons"; + import { useDispatch, useSelector } from "react-redux"; -import { fetchItems, searchItems } from "../../../../../../shell/store/content"; -import { - FieldTypeOneToMany, - OneToManyOptions, -} from "../../../../../../shell/components/FieldTypeOneToMany"; +import { searchItems } from "../../../../../../shell/store/content"; + import { AppState } from "../../../../../../shell/store/types"; import { FieldSettingsOptions } from "../../../../../../shell/services/types"; -import { FieldTypeOneToOne } from "../../../../../../shell/components/FieldTypeOneToOne"; -import { - resolveRelatedOptions, - sortHTML, -} from "../../../../../content-editor/src/app/components/Editor/Field/Field"; -import { fetchFields } from "../../../../../../shell/store/fields"; +import { sortHTML } from "../../../../../content-editor/src/app/components/Editor/Field/Field"; import { FieldTypeInternalLink } from "../../../../../../shell/components/FieldTypeInternalLink"; import { LinkOption } from "../../../../../content-editor/src/app/components/Editor/Field/LinkOption"; import { FieldTypeNumber } from "../../../../../../shell/components/FieldTypeNumber"; @@ -49,6 +38,7 @@ import { FieldTypeDate } from "../../../../../../shell/components/FieldTypeDate" import { FieldTypeDateTime } from "../../../../../../shell/components/FieldTypeDateTime"; import { FieldTypeColor } from "../../../../../../shell/components/FieldTypeColor"; import { FieldTypeSort } from "../../../../../../shell/components/FieldTypeSort"; +import { RelationalFieldBase } from "../../../../../../shell/components/RelationalFieldBase"; import moment from "moment"; type DefaultValueInputProps = { @@ -311,170 +301,24 @@ export const DefaultValueInput = ({ ); case "one_to_one": - const onOneToOneOpen = () => { - return dispatch( - fetchItems(relatedModelZUID, { - lang: "en-US", - }) - ); - }; - - let oneToOneOptions: OneToManyOptions[] = useMemo(() => { - const filterValidItems = (items: any) => { - // remove items that are only saved in memory - const filteredValidItems = Object.entries(items).filter( - ([, value]) => value.web.version - ); - // Reshape the array back into an object - let options = Object.fromEntries(filteredValidItems); - - return options; - }; - const options = filterValidItems(allItems); - - return [ - { - inputLabel: "- None -", - value: null, - component: "- None -", - }, - ...resolveRelatedOptions( - allFields, - options, - relatedFieldZUID, - relatedModelZUID, - 1, - value - ), - ]; - }, [ - Object.keys(allFields).length, - Object.keys(allItems).length, - relatedModelZUID, - relatedFieldZUID, - value, - ]); - - if (value && !oneToOneOptions.find((opt) => opt.value === value)) { - //the related option is not in the array, we need to insert it - oneToOneOptions.unshift({ - value: value as string, - inputLabel: `Selected item not found: ${value}`, - component: ( - - evt.stopPropagation()}> - - - - -  Selected item not found: {value} - - ), - }); - } - return ( - options.value === value) || null - } - onChange={(_, option) => onChange(option.value)} - options={oneToOneOptions} - // @ts-ignore - onOpen={onOneToOneOpen} - startAdornment={ - value && ( - - - - ) - } - endAdornment={value && en-US} - error={error} + onChange(value)} /> ); case "one_to_many": - const oneToManyOptions: OneToManyOptions[] = useMemo(() => { - const filterValidItems = (items: any) => { - // remove items that are only saved in memory - const filteredValidItems = Object.entries(items).filter( - ([, value]) => value.web.version - ); - // Reshape the array back into an object - let options = Object.fromEntries(filteredValidItems); - - return options; - }; - const options = filterValidItems(allItems); - - return resolveRelatedOptions( - allFields, - options, - relatedFieldZUID, - relatedModelZUID, - 1, - value - ); - }, [ - Object.keys(allFields).length, - Object.keys(allItems).length, - relatedModelZUID, - relatedFieldZUID, - 1, - value, - ]); - const onOneToManyOpen = useCallback(() => { - return Promise.all([ - dispatch(fetchFields(relatedModelZUID)), - dispatch( - fetchItems(relatedModelZUID, { - lang: "en-US", - }) - ), - ]); - }, [relatedModelZUID]); - return ( - - oneToManyOptions?.find( - (options) => options.value === value - ) || { value, inputLabel: value, component: value } - )) || - [] - } - onChange={(_, options: OneToManyOptions[]) => { - const selectedOptions = options?.length - ? options.map((option) => option.value).join(",") - : null; - onChange(selectedOptions); - }} - options={oneToManyOptions} - onOpen={onOneToManyOpen} - renderTags={(tags, getTagProps) => - tags.map((tag, index) => ( - - )) - } - error={error} + onChange(value)} /> ); case "link": diff --git a/src/apps/schema/src/app/components/AddFieldModal/views/FieldForm.tsx b/src/apps/schema/src/app/components/AddFieldModal/views/FieldForm.tsx index 32c999569..1357f409c 100644 --- a/src/apps/schema/src/app/components/AddFieldModal/views/FieldForm.tsx +++ b/src/apps/schema/src/app/components/AddFieldModal/views/FieldForm.tsx @@ -338,12 +338,18 @@ export const FieldForm = ({ let newErrorsObj: Errors = {}; Object.keys(formData).map((inputName) => { - if ( - inputName === "defaultValue" && - isDefaultValueEnabled && - (formData.defaultValue === "" || formData.defaultValue === null) - ) { - newErrorsObj[inputName] = "Required Field. Please enter a value."; + if (inputName === "defaultValue" && isDefaultValueEnabled) { + if (formData.defaultValue === "" || formData.defaultValue === null) { + newErrorsObj[inputName] = "Required Field. Please enter a value."; + } else if ( + type === "one_to_many" && + (formData.defaultValue as string)?.length > 255 + ) { + // Value is stored as string in DB with max char limit of 255. + // This means users can only add up to 12 item zuids + newErrorsObj[inputName] = + "Cannot save field. Please reduce the total number of items selected."; + } } if (type === "text" || type === "textarea") { diff --git a/src/shell/components/RelationalFieldBase/FieldSelectorDialog/index.tsx b/src/shell/components/RelationalFieldBase/FieldSelectorDialog/index.tsx index 1678851b9..b751486d5 100644 --- a/src/shell/components/RelationalFieldBase/FieldSelectorDialog/index.tsx +++ b/src/shell/components/RelationalFieldBase/FieldSelectorDialog/index.tsx @@ -532,6 +532,7 @@ export const FieldSelectorDialog = ({ sx: { width: 800, maxWidth: 800, + minHeight: 680, maxHeight: "min(1240px, calc(100% - 64px))", }, }} diff --git a/src/shell/components/RelationalFieldBase/index.tsx b/src/shell/components/RelationalFieldBase/index.tsx index eccfa7ee2..4f29c23c5 100644 --- a/src/shell/components/RelationalFieldBase/index.tsx +++ b/src/shell/components/RelationalFieldBase/index.tsx @@ -136,7 +136,7 @@ export const RelationalFieldBase = ({ sx={{ mt: 1, }} - disabled={isLoadingModelData || isLoadingModelFields} + disabled={isLoadingModelData || isLoadingModelFields || !modelData} > Add Existing {modelData?.label}