From 2762587da74f2f70261b6ea03381d75ddf8343d6 Mon Sep 17 00:00:00 2001 From: Xavier Rutayisire Date: Thu, 31 Aug 2023 16:48:06 +0200 Subject: [PATCH] feat(SlicesTemplates): Add from template button --- .../scenario_slice_association.cy.js | 3 +- .../pages/customTypes/customTypeBuilder.js | 3 +- .../CustomTypeBuilder/SliceZone/index.tsx | 59 ++++++++++++++----- .../CustomTypeBuilder/TabZone/index.tsx | 26 ++++---- .../lib/builders/common/Zone/index.jsx | 10 ++-- .../src/components/List/List.css.ts | 2 - .../src/components/List/List.tsx | 10 +--- .../SliceZoneBlankSlate.tsx | 13 +++- .../test/pages/custom-types.test.tsx | 56 ++++++++++++------ 9 files changed, 118 insertions(+), 64 deletions(-) diff --git a/cypress/e2e/user-flows/scenario_slice_association.cy.js b/cypress/e2e/user-flows/scenario_slice_association.cy.js index 298c4071df..6ef6f26807 100644 --- a/cypress/e2e/user-flows/scenario_slice_association.cy.js +++ b/cypress/e2e/user-flows/scenario_slice_association.cy.js @@ -86,7 +86,8 @@ describe.skip("I am an existing SM user (Next) and I want to associate a Slice t it.skip("Add the Slice to the Custom Type", () => { cy.visit(`/custom-types/${customTypeId}`); - cy.get("[data-cy=update-slices]").click(); + cy.contains("Add").click(); + cy.contains("Add from your library").click(); // forcing this because the input itself is invisible and an svg is displayed cy.get(`[data-cy=check-${sliceId}]`).click({ force: true }); cy.get("[data-cy=update-slices-modal]").submit(); diff --git a/cypress/pages/customTypes/customTypeBuilder.js b/cypress/pages/customTypes/customTypeBuilder.js index a202d2fa8e..312c35090b 100644 --- a/cypress/pages/customTypes/customTypeBuilder.js +++ b/cypress/pages/customTypes/customTypeBuilder.js @@ -6,7 +6,8 @@ class CustomTypeBuilder extends BaseBuilder { } get updateSliceZoneButton() { - return cy.get("[data-cy=update-slices]"); + cy.contains("Add").click(); + return cy.contains("Add from your library"); } get headerCustomTypeName() { diff --git a/packages/slice-machine/lib/builders/CustomTypeBuilder/SliceZone/index.tsx b/packages/slice-machine/lib/builders/CustomTypeBuilder/SliceZone/index.tsx index eef885df8a..946082b590 100644 --- a/packages/slice-machine/lib/builders/CustomTypeBuilder/SliceZone/index.tsx +++ b/packages/slice-machine/lib/builders/CustomTypeBuilder/SliceZone/index.tsx @@ -1,4 +1,13 @@ -import { Button, Box, Switch } from "@prismicio/editor-ui"; +import { + Button, + Box, + Switch, + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + Icon, +} from "@prismicio/editor-ui"; import { useEffect, useMemo, useState } from "react"; import { useSelector } from "react-redux"; import { BaseStyles } from "theme-ui"; @@ -100,6 +109,7 @@ const SliceZone: React.FC = ({ sliceZone, tabId, }) => { + const isSlicesTemplatesSupported = true; const [formIsOpen, setFormIsOpen] = useState(false); const [isCreateSliceModalOpen, setIsCreateSliceModalOpen] = useState(false); const { remoteSlices, libraries, slices } = useSelector( @@ -155,20 +165,40 @@ const SliceZone: React.FC = ({ - - {availableSlices.length > 0 ? ( - - ) : undefined} - + + + + } + onSelect={onCreateNewSlice} + > + Create a new slice + + + {availableSlices.length > 0 ? ( + } + > + Add from your library + + ) : undefined} + + {isSlicesTemplatesSupported ? ( + } + > + Add from template + + ) : undefined} + + ) : undefined } toggle={ @@ -205,6 +235,7 @@ const SliceZone: React.FC = ({ onAddNewSlice={onAddNewSlice} onCreateNewSlice={onCreateNewSlice} projectHasAvailableSlices={availableSlices.length > 0} + isSlicesTemplatesSupported={isSlicesTemplatesSupported} /> ) ) : undefined} diff --git a/packages/slice-machine/lib/builders/CustomTypeBuilder/TabZone/index.tsx b/packages/slice-machine/lib/builders/CustomTypeBuilder/TabZone/index.tsx index 0a091c62cd..ed96af1b3d 100644 --- a/packages/slice-machine/lib/builders/CustomTypeBuilder/TabZone/index.tsx +++ b/packages/slice-machine/lib/builders/CustomTypeBuilder/TabZone/index.tsx @@ -1,5 +1,5 @@ import { Box } from "@prismicio/editor-ui"; -import type { FC } from "react"; +import { FC, Suspense } from "react"; import type { DropResult } from "react-beautiful-dnd"; import { useSelector } from "react-redux"; import type { AnyObjectSchema } from "yup"; @@ -165,17 +165,19 @@ const TabZone: FC = ({ isRepeatableCustomType={customType.repeatable} /> - + + + ); }; diff --git a/packages/slice-machine/lib/builders/common/Zone/index.jsx b/packages/slice-machine/lib/builders/common/Zone/index.jsx index f5c1dfb002..3fb106b758 100644 --- a/packages/slice-machine/lib/builders/common/Zone/index.jsx +++ b/packages/slice-machine/lib/builders/common/Zone/index.jsx @@ -1,4 +1,4 @@ -import { Button } from "@prismicio/editor-ui"; +import { Button, ButtonGroup } from "@prismicio/editor-ui"; import { array, arrayOf, bool, func, object, shape, string } from "prop-types"; import { useState } from "react"; import { FaCode, FaPlus } from "react-icons/fa"; @@ -80,7 +80,7 @@ const Zone = ({ actions={ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access fields.length > 0 ? ( - <> + @@ -94,7 +94,7 @@ const Zone = ({ > Add a new Field - + ) : undefined } > @@ -107,7 +107,7 @@ const Zone = ({ Actions={ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access fields.length > 0 ? ( - <> + setShowHints(!showHints)} @@ -139,7 +139,7 @@ const Zone = ({ /> Add a new Field - + ) : null } /> diff --git a/packages/slice-machine/src/components/List/List.css.ts b/packages/slice-machine/src/components/List/List.css.ts index adb542d46f..71188d201b 100644 --- a/packages/slice-machine/src/components/List/List.css.ts +++ b/packages/slice-machine/src/components/List/List.css.ts @@ -26,5 +26,3 @@ export const header = style([ }, }, ]); - -export const headerActions = sprinkles({ flexGrow: 1, justifyContent: "end" }); diff --git a/packages/slice-machine/src/components/List/List.tsx b/packages/slice-machine/src/components/List/List.tsx index b9b73da98b..c6076424b9 100644 --- a/packages/slice-machine/src/components/List/List.tsx +++ b/packages/slice-machine/src/components/List/List.tsx @@ -1,4 +1,4 @@ -import { ButtonGroup, Text } from "@prismicio/editor-ui"; +import { Box, Text } from "@prismicio/editor-ui"; import type { FC, PropsWithChildren, ReactNode } from "react"; import * as styles from "./List.css"; @@ -23,12 +23,8 @@ export const ListHeader: FC = ({ {children} {toggle} - + {actions} - + ); diff --git a/packages/slice-machine/src/features/customTypes/customTypesBuilder/SliceZoneBlankSlate.tsx b/packages/slice-machine/src/features/customTypes/customTypesBuilder/SliceZoneBlankSlate.tsx index 1d058d9914..77d2daad63 100644 --- a/packages/slice-machine/src/features/customTypes/customTypesBuilder/SliceZoneBlankSlate.tsx +++ b/packages/slice-machine/src/features/customTypes/customTypesBuilder/SliceZoneBlankSlate.tsx @@ -13,12 +13,14 @@ export type SliceZoneBlankSlateProps = { onAddNewSlice: () => void; onCreateNewSlice: () => void; projectHasAvailableSlices: boolean; + isSlicesTemplatesSupported: boolean; }; export const SliceZoneBlankSlate: FC = ({ onCreateNewSlice, onAddNewSlice, projectHasAvailableSlices, + isSlicesTemplatesSupported, }) => { return ( @@ -32,11 +34,16 @@ export const SliceZoneBlankSlate: FC = ({ {projectHasAvailableSlices && ( - + )} + {isSlicesTemplatesSupported && ( + )} diff --git a/packages/slice-machine/test/pages/custom-types.test.tsx b/packages/slice-machine/test/pages/custom-types.test.tsx index 19306de052..6b6916153a 100644 --- a/packages/slice-machine/test/pages/custom-types.test.tsx +++ b/packages/slice-machine/test/pages/custom-types.test.tsx @@ -28,7 +28,7 @@ describe("Custom Type Builder", () => { vi.clearAllMocks(); }); - beforeEach(async () => { + beforeEach(() => { mockRouter.setCurrentUrl("/"); }); @@ -125,7 +125,7 @@ describe("Custom Type Builder", () => { test("should send a tracking event when the user adds a field", async () => { const customTypeId = "a-page"; - Router.push({ + void Router.push({ pathname: "custom-types/[customTypeId]", query: { customTypeId }, }); @@ -201,11 +201,14 @@ describe("Custom Type Builder", () => { const saveFieldButton = screen.getByText("Add"); - await act(async () => { + // eslint-disable-next-line @typescript-eslint/await-thenable + await act(() => { fireEvent.click(saveFieldButton); }); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledOnce(); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledWith( expect.objectContaining({ event: "SliceMachine Custom Type Field Added", @@ -224,7 +227,7 @@ describe("Custom Type Builder", () => { test("should send a tracking event when the user adds a slice", async () => { const customTypeId = "a-page"; - Router.push({ + void Router.push({ pathname: "custom-types/[customTypeId]", query: { customTypeId }, }); @@ -295,26 +298,31 @@ describe("Custom Type Builder", () => { }, }); - const addButton = screen.getAllByText("Update Slices")[0]; - await act(async () => { + const addButton = screen.getByText("Add from your library"); + // eslint-disable-next-line @typescript-eslint/await-thenable + await act(() => { fireEvent.click(addButton); }); const slicesToSelect = screen.getAllByTestId("slicezone-modal-item"); for (const elem of slicesToSelect) { - await act(async () => { + // eslint-disable-next-line @typescript-eslint/await-thenable + await act(() => { fireEvent.click(elem); }); } const saveButton = within(screen.getByRole("dialog")).getByText("Apply"); - await act(async () => { + // eslint-disable-next-line @typescript-eslint/await-thenable + await act(() => { fireEvent.click(saveButton); }); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledOnce(); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledWith( expect.objectContaining({ event: "SliceMachine Slicezone Updated", @@ -352,7 +360,7 @@ describe("Custom Type Builder", () => { const customTypeId = "a-page"; - Router.push({ + void Router.push({ pathname: "custom-types/[customTypeId]", query: { customTypeId }, }); @@ -424,11 +432,13 @@ describe("Custom Type Builder", () => { const saveFieldButton = screen.getByText("Add"); - await act(async () => { + act(() => { fireEvent.click(saveFieldButton); }); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledOnce(); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledWith( expect.objectContaining({ event: "SliceMachine Custom Type Field Added", @@ -445,12 +455,14 @@ describe("Custom Type Builder", () => { const saveCustomType = screen.getByTestId("builder-save-button"); - await act(async () => { + act(() => { fireEvent.click(saveCustomType); }); - await waitFor(async () => { + await waitFor(() => { + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledTimes(2); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledWith( expect.objectContaining({ event: "SliceMachine Custom Type Saved", @@ -495,7 +507,7 @@ describe("Custom Type Builder", () => { const customTypeId = "a-page"; - Router.push({ + void Router.push({ pathname: "custom-types/[customTypeId]", query: { customTypeId }, }); @@ -561,27 +573,32 @@ describe("Custom Type Builder", () => { }); const addButton = screen.getByText("Add a new field"); - await act(async () => { + // eslint-disable-next-line @typescript-eslint/await-thenable + await act(() => { fireEvent.click(addButton); }); const richText = screen.getByText("Rich Text"); - await act(async () => { + // eslint-disable-next-line @typescript-eslint/await-thenable + await act(() => { fireEvent.click(richText); }); const nameInput = screen.getByLabelText("label-input"); - await act(async () => { + // eslint-disable-next-line @typescript-eslint/await-thenable + await act(() => { fireEvent.change(nameInput, { target: { value: "New Field" } }); }); const saveFieldButton = screen.getByText("Add"); - - await act(async () => { + // eslint-disable-next-line @typescript-eslint/await-thenable + await act(() => { fireEvent.click(saveFieldButton); }); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledOnce(); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledWith( expect.objectContaining({ event: "SliceMachine Custom Type Field Added", @@ -598,12 +615,13 @@ describe("Custom Type Builder", () => { const saveCustomType = screen.getByTestId("builder-save-button"); - await act(async () => { + act(() => { fireEvent.click(saveCustomType); }); await new Promise((r) => setTimeout(r, 500)); + // eslint-disable-next-line @typescript-eslint/unbound-method expect(SegmentClient.prototype.track).toHaveBeenCalledOnce(); }); });