diff --git a/packages/react/.changeset/eight-pans-beg.md b/packages/react/.changeset/eight-pans-beg.md new file mode 100644 index 000000000..7c9f872c9 --- /dev/null +++ b/packages/react/.changeset/eight-pans-beg.md @@ -0,0 +1,5 @@ +--- +"@gadgetinc/react": patch +--- + +Removed deprecated Polaris `Frame` usage from AutoTable diff --git a/packages/react/.changeset/fair-files-repair.md b/packages/react/.changeset/fair-files-repair.md new file mode 100644 index 000000000..980b0dad8 --- /dev/null +++ b/packages/react/.changeset/fair-files-repair.md @@ -0,0 +1,5 @@ +--- +"@gadgetinc/react": patch +--- + +Fixed bug in `AutoForm` where dynamically changing findBy object props did not cause the form to re-render diff --git a/packages/react/cypress/component/auto/table/AutoTableBulkActions.cy.tsx b/packages/react/cypress/component/auto/table/AutoTableBulkActions.cy.tsx index 78e5191c0..2d5418498 100644 --- a/packages/react/cypress/component/auto/table/AutoTableBulkActions.cy.tsx +++ b/packages/react/cypress/component/auto/table/AutoTableBulkActions.cy.tsx @@ -115,16 +115,17 @@ describe("AutoTable - Bulk actions", () => { cy.wait("@getWidgets").its("request.body.variables").should("deep.equal", { first: 50 }); // No search value cy.contains(ActionSuccessMessage); + cy.get("button").contains("Close").click(); // Now ensure that error response appears in the modal selectRecordIds(["20", "21", "22"]); + openBulkAction("Delete"); mockBulkDeleteWidgets(bulkDeleteFailureResponse, "bulkDeleteWidgets2"); cy.get("button").contains("Run").click(); cy.wait("@bulkDeleteWidgets2"); - cy.contains(ActionErrorMessage); }); @@ -152,6 +153,7 @@ describe("AutoTable - Bulk actions", () => { cy.wait("@getWidgets").its("request.body.variables").should("deep.equal", { first: 50 }); // No search value cy.contains(ActionSuccessMessage); + cy.get("button").contains("Close").click(); }); }); }); diff --git a/packages/react/src/auto/polaris/PolarisAutoBulkActionModal.tsx b/packages/react/src/auto/polaris/PolarisAutoBulkActionModal.tsx index c181d338e..864bf2823 100644 --- a/packages/react/src/auto/polaris/PolarisAutoBulkActionModal.tsx +++ b/packages/react/src/auto/polaris/PolarisAutoBulkActionModal.tsx @@ -1,4 +1,4 @@ -import { Button, ButtonGroup, Modal, Spinner, Text, Toast } from "@shopify/polaris"; +import { Banner, Button, ButtonGroup, Modal, Spinner, Text } from "@shopify/polaris"; import React, { useCallback, useEffect, useMemo } from "react"; import type { TableRow } from "../../use-table/types.js"; import { useBulkAction } from "../../useBulkAction.js"; @@ -12,32 +12,7 @@ export const PolarisAutoBulkActionModal = (props: { selectedRows: TableRow[]; clearSelection: () => void; }) => { - const [toastMessage, setToastMessage] = React.useState(undefined); - - return ( - <> - {toastMessage && ( - setToastMessage(undefined)} - duration={4500} - error={toastMessage.includes(ActionErrorMessage)} - /> - )} - - - ); -}; - -const BulkActionModal = (props: { - model: any; - modelActionDetails?: ModelActionDetails; - ids: string[]; - selectedRows: TableRow[]; - clearSelection: () => void; - setToastMessage: (message: string) => void; -}) => { - const { model, modelActionDetails, ids, selectedRows, clearSelection, setToastMessage } = props; + const { model, modelActionDetails, ids, selectedRows, clearSelection } = props; const [showModal, setShowModal] = React.useState(!!modelActionDetails); const [actionName, setActionName] = React.useState(modelActionDetails?.apiIdentifier); @@ -55,7 +30,10 @@ const BulkActionModal = (props: { const modalTitle = useMemo(() => humanizeCamelCase(actionName ?? ""), [actionName]); - const closeModal = useCallback(() => setShowModal(false), [setShowModal]); + const closeAndClear = useCallback(() => { + setShowModal(false); + clearSelection(); + }, [setShowModal, clearSelection]); if (!actionIsLoaded || !isBulkGadgetAction) { return null; @@ -63,15 +41,13 @@ const BulkActionModal = (props: { return ( <> - setShowModal(false)} title={modalTitle} open={showModal}> + @@ -87,10 +63,8 @@ const GadgetBulkActionModalContent = (props: { actionLabel: string; ids: string[]; close: () => void; - clearSelection: () => void; - setToastMessage: (message: string) => void; }) => { - const { model, modelActionDetails, actionLabel: actionName, ids, close, clearSelection, setToastMessage } = props; + const { model, modelActionDetails, actionLabel: actionName, ids, close } = props; const [hasRun, setHasRun] = React.useState(false); @@ -100,25 +74,26 @@ const GadgetBulkActionModalContent = (props: { const hasError = !!(error || (data && (data as any).success === false)); + const actionResultBanner = useMemo( + () => + hasError ? ( + + ) : ( + + ), + [hasError] + ); + const runAction = useCallback(() => { void runBulkAction(ids); setHasRun(true); - }, [runBulkAction, ids, clearSelection, close]); - - // Automatically close the modal if the action is successful - useEffect(() => { - if (!fetching && hasRun) { - clearSelection(); - close(); - setToastMessage(hasError ? `${actionName}${ActionErrorMessage}` : `${actionName}${ActionSuccessMessage}`); - } - }, [fetching, hasRun, hasError, clearSelection, close, setToastMessage, actionName]); + }, [runBulkAction, ids]); return ( <> {fetching && } - {!fetching && !hasRun && } + {!fetching && (hasRun ? actionResultBanner : )}
diff --git a/packages/react/src/auto/polaris/PolarisAutoTable.tsx b/packages/react/src/auto/polaris/PolarisAutoTable.tsx index 88c8b63f7..9ef62465a 100644 --- a/packages/react/src/auto/polaris/PolarisAutoTable.tsx +++ b/packages/react/src/auto/polaris/PolarisAutoTable.tsx @@ -6,13 +6,11 @@ import { Box, DataTable, EmptySearchResult, - Frame, IndexFilters, IndexTable, SkeletonBodyText, useSetIndexFiltersMode, } from "@shopify/polaris"; - import pluralize from "pluralize"; import type { ReactNode } from "react"; import React, { useCallback, useMemo } from "react"; @@ -153,105 +151,102 @@ const PolarisAutoTableComponent = < return ( - - - + + {searchable && ( + undefined} + tabs={[]} + canCreateNewView={false} + selected={1} + loading={fetching} + cancelAction={{ onAction: () => search.clear() }} + disabled={!!error} + // Search + queryValue={search.value} + onQueryChange={search.set} + onQueryClear={search.clear} /> + )} - {searchable && ( - undefined} - tabs={[]} - canCreateNewView={false} - selected={1} - loading={fetching} - cancelAction={{ onAction: () => search.clear() }} - disabled={!!error} - // Search - queryValue={search.value} - onQueryChange={search.set} - onQueryClear={search.clear} - /> - )} + {error && ( + + + + )} - {error && ( - - - - )} - - } - loading={fetching} - hasMoreItems={page.hasNextPage} - itemCount={ - error - ? 1 // Don't show the empty state if there's an error - : rows?.length ?? 0 - } - pagination={ - paginate - ? { - hasNext: page.hasNextPage, - hasPrevious: page.hasPreviousPage, - onNext: page.goToNextPage, - onPrevious: page.goToPreviousPage, - } - : undefined - } - sortDirection={gadgetToPolarisDirection(sort.direction)} - sortColumnIndex={columns ? getColumnIndex(columns, sort.column) : undefined} - onSort={(headingIndex) => handleColumnSort(headingIndex)} - selectable={props.selectable === undefined ? bulkActionOptions.length !== 0 : props.selectable} - lastColumnSticky={props.lastColumnSticky} - hasZebraStriping={props.hasZebraStriping} - condensed={props.condensed} - > - {rows && - columns && - rows.map((row, index) => { - const rawRecord = rawRecords?.[index]; - return ( - - {columns.map((column) => ( - -
- {column.type == "CustomRenderer" ? ( - (row[column.identifier] as ReactNode) - ) : ( - - )} -
-
- ))} -
- ); - })} -
-
- + } + loading={fetching} + hasMoreItems={page.hasNextPage} + itemCount={ + error + ? 1 // Don't show the empty state if there's an error + : rows?.length ?? 0 + } + pagination={ + paginate + ? { + hasNext: page.hasNextPage, + hasPrevious: page.hasPreviousPage, + onNext: page.goToNextPage, + onPrevious: page.goToPreviousPage, + } + : undefined + } + sortDirection={gadgetToPolarisDirection(sort.direction)} + sortColumnIndex={columns ? getColumnIndex(columns, sort.column) : undefined} + onSort={(headingIndex) => handleColumnSort(headingIndex)} + selectable={props.selectable === undefined ? bulkActionOptions.length !== 0 : props.selectable} + lastColumnSticky={props.lastColumnSticky} + hasZebraStriping={props.hasZebraStriping} + condensed={props.condensed} + > + {rows && + columns && + rows.map((row, index) => { + const rawRecord = rawRecords?.[index]; + return ( + + {columns.map((column) => ( + +
+ {column.type == "CustomRenderer" ? ( + (row[column.identifier] as ReactNode) + ) : ( + + )} +
+
+ ))} +
+ ); + })} +
+
); };