diff --git a/web/e2e/project/item/metadata/update.spec.ts b/web/e2e/project/item/metadata/update.spec.ts new file mode 100644 index 0000000000..f3facfe1e4 --- /dev/null +++ b/web/e2e/project/item/metadata/update.spec.ts @@ -0,0 +1,41 @@ +import { closeNotification } from "@reearth-cms/e2e/common/notification"; +import { handleFieldForm } from "@reearth-cms/e2e/project/utils/field"; +import { createModel } from "@reearth-cms/e2e/project/utils/model"; +import { createProject, deleteProject } from "@reearth-cms/e2e/project/utils/project"; +import { expect, test } from "@reearth-cms/e2e/utils"; + +test.beforeEach(async ({ reearth, page }) => { + await reearth.goto("/", { waitUntil: "domcontentloaded" }); + await createProject(page); + await createModel(page); + await page.locator("li").filter({ hasText: "Text" }).locator("div").first().click(); + await handleFieldForm(page, "text"); + await page.getByText("Content").click(); + await page.getByRole("button", { name: "plus New Item" }).click(); + await page.getByRole("button", { name: "Save" }).click(); + await closeNotification(page); + await page.getByText("Schema").click(); + await page.getByRole("tab", { name: "Meta Data" }).click(); + await page.locator("li").filter({ hasText: "Boolean" }).locator("div").first().click(); + await handleFieldForm(page, "boolean"); + await page.getByText("Content").click(); +}); + +test.afterEach(async ({ page }) => { + await deleteProject(page); +}); + +test("Updating metadata added later from table has succeeded", async ({ page }) => { + await page.getByRole("switch").click(); + await closeNotification(page); + await page.getByRole("link", { name: "edit", exact: true }).click(); + await expect(page.getByLabel("boolean")).toHaveAttribute("aria-checked", "true"); +}); + +test("Updating metadata added later from edit page has succeeded", async ({ page }) => { + await page.getByRole("link", { name: "edit", exact: true }).click(); + await page.getByLabel("boolean").click(); + await closeNotification(page); + await page.getByLabel("Back").click(); + await expect(page.getByRole("switch")).toHaveAttribute("aria-checked", "true"); +}); diff --git a/web/src/components/molecules/Content/Details/index.tsx b/web/src/components/molecules/Content/Details/index.tsx index adb23af0f5..5022da72a9 100644 --- a/web/src/components/molecules/Content/Details/index.tsx +++ b/web/src/components/molecules/Content/Details/index.tsx @@ -78,7 +78,7 @@ type Props = { metaFields: ItemField[]; }) => Promise<void>; onItemUpdate: (data: { itemId: string; fields: ItemField[] }) => Promise<void>; - onMetaItemUpdate: (data: { metaItemId: string; metaFields: ItemField[] }) => Promise<void>; + onMetaItemUpdate: (data: { metaItemId?: string; metaFields: ItemField[] }) => Promise<void>; onBack: (modelId?: string) => void; onAssetsCreate: (files: UploadFile[]) => Promise<(Asset | undefined)[]>; onAssetCreateFromUrl: (url: string, autoUnzip: boolean) => Promise<Asset | undefined>; diff --git a/web/src/components/molecules/Content/Form/index.tsx b/web/src/components/molecules/Content/Form/index.tsx index e299fc58e4..889e773753 100644 --- a/web/src/components/molecules/Content/Form/index.tsx +++ b/web/src/components/molecules/Content/Form/index.tsx @@ -93,7 +93,7 @@ interface Props { metaFields: ItemField[]; }) => Promise<void>; onItemUpdate: (data: { itemId: string; fields: ItemField[] }) => Promise<void>; - onMetaItemUpdate: (data: { metaItemId: string; metaFields: ItemField[] }) => Promise<void>; + onMetaItemUpdate: (data: { metaItemId?: string; metaFields: ItemField[] }) => Promise<void>; onBack: (modelId?: string) => void; onAssetsCreate: (files: UploadFile[]) => Promise<(Asset | undefined)[]>; onAssetCreateFromUrl: (url: string, autoUnzip: boolean) => Promise<Asset | undefined>; @@ -403,7 +403,7 @@ const ContentForm: React.FC<Props> = ({ }, [model, form, metaForm, itemId, onGroupGet, inputValueGet, onItemUpdate, onItemCreate]); const handleMetaUpdate = useCallback(async () => { - if (!itemId || !item?.metadata?.id) return; + if (!itemId) return; try { const metaValues = await metaForm.validateFields(); const metaFields: { schemaFieldId: string; type: FieldType; value: string }[] = []; @@ -414,8 +414,8 @@ const ContentForm: React.FC<Props> = ({ type: model?.metadataSchema?.fields?.find(field => field.id === key)?.type as FieldType, }); } - await onMetaItemUpdate?.({ - metaItemId: item.metadata.id, + await onMetaItemUpdate({ + metaItemId: item?.metadata?.id, metaFields, }); } catch (info) { diff --git a/web/src/components/organisms/Project/Content/ContentDetails/hooks.ts b/web/src/components/organisms/Project/Content/ContentDetails/hooks.ts index 4856ae2c93..b23738323a 100644 --- a/web/src/components/organisms/Project/Content/ContentDetails/hooks.ts +++ b/web/src/components/organisms/Project/Content/ContentDetails/hooks.ts @@ -289,21 +289,58 @@ export default () => { ); const handleMetaItemUpdate = useCallback( - async ({ metaItemId, metaFields }: { metaItemId: string; metaFields: ItemField[] }) => { - const item = await updateItem({ - variables: { - itemId: metaItemId, - fields: metaFields as ItemFieldInput[], - version: currentItem?.metadata?.version ?? "", - }, - }); - if (item.errors || !item.data?.updateItem) { + async ({ metaItemId, metaFields }: { metaItemId?: string; metaFields: ItemField[] }) => { + if (metaItemId) { + const item = await updateItem({ + variables: { + itemId: metaItemId, + fields: metaFields as ItemFieldInput[], + version: currentItem?.metadata?.version ?? "", + }, + }); + if (item.errors || !item.data?.updateItem) { + Notification.error({ message: t("Failed to update item.") }); + return; + } + } else if ( + currentItem && + currentItem.fields && + currentModel?.id && + currentModel.metadataSchema.id + ) { + const metaItem = await createItem({ + variables: { + modelId: currentModel.id, + schemaId: currentModel.metadataSchema.id, + fields: metaFields as ItemFieldInput[], + }, + }); + if (metaItem.errors || !metaItem.data?.createItem) { + Notification.error({ message: t("Failed to update item.") }); + return; + } + const item = await updateItem({ + variables: { + itemId: currentItem.id, + fields: currentItem.fields.map(field => ({ + ...field, + value: field.value ?? "", + })) as ItemFieldInput[], + metadataId: metaItem?.data.createItem.item.id, + version: currentItem.version, + }, + }); + if (item.errors || !item.data?.updateItem) { + Notification.error({ message: t("Failed to update item.") }); + return; + } + } else { Notification.error({ message: t("Failed to update item.") }); return; } Notification.success({ message: t("Successfully updated Item!") }); }, - [updateItem, currentItem?.metadata?.version, t], + [createItem, currentItem, currentModel?.id, currentModel?.metadataSchema.id, t, updateItem], ); const dateConvert = useCallback((value?: ItemValue) => {