diff --git a/.changeset/healthy-fireants-behave.md b/.changeset/healthy-fireants-behave.md new file mode 100644 index 0000000000..b3f3bbd7ae --- /dev/null +++ b/.changeset/healthy-fireants-behave.md @@ -0,0 +1,5 @@ +--- +"@comet/cms-admin": minor +--- + +Exchange Content Scope FormField Checkbox List with Datagrid view and selection diff --git a/packages/admin/cms-admin/src/userPermissions/user/permissions/ContentScopeGrid.tsx b/packages/admin/cms-admin/src/userPermissions/user/permissions/ContentScopeGrid.tsx index a755a7d22e..75ccb89c8a 100644 --- a/packages/admin/cms-admin/src/userPermissions/user/permissions/ContentScopeGrid.tsx +++ b/packages/admin/cms-admin/src/userPermissions/user/permissions/ContentScopeGrid.tsx @@ -1,44 +1,19 @@ -import { gql, useApolloClient, useQuery } from "@apollo/client"; -import { Field, FinalForm, FinalFormCheckbox, Loading, SaveButton, ToolbarActions, ToolbarFillSpace, ToolbarTitleItem } from "@comet/admin"; -import { Card, CardContent, Toolbar } from "@mui/material"; +import { gql, useQuery } from "@apollo/client"; +import { GridColDef, Loading, ToolbarActions, ToolbarFillSpace, ToolbarTitleItem } from "@comet/admin"; +import { Select } from "@comet/admin-icons"; +import { Button, Card, CardContent, Toolbar, Typography } from "@mui/material"; import { styled } from "@mui/material/styles"; -import isEqual from "lodash.isequal"; -import { FormattedMessage } from "react-intl"; +import { DataGrid } from "@mui/x-data-grid"; +import { useState } from "react"; +import { FormattedMessage, IntlShape, useIntl } from "react-intl"; import { camelCaseToHumanReadable } from "../../utils/camelCaseToHumanReadable"; -import { - GQLContentScopesQuery, - GQLContentScopesQueryVariables, - GQLUpdateContentScopesMutation, - GQLUpdateContentScopesMutationVariables, -} from "./ContentScopeGrid.generated"; - -type FormValues = { - contentScopes: string[]; -}; -type ContentScope = { - [key: string]: string; -}; +import { GQLContentScopesQuery, GQLContentScopesQueryVariables } from "./ContentScopeGrid.generated"; +import { SelectScopesDialog } from "./selectScopesDialog/SelectScopesDialog"; export const ContentScopeGrid = ({ userId }: { userId: string }) => { - const client = useApolloClient(); - - const submit = async (data: FormValues) => { - await client.mutate({ - mutation: gql` - mutation UpdateContentScopes($userId: String!, $input: UserContentScopesInput!) { - userPermissionsUpdateContentScopes(userId: $userId, input: $input) - } - `, - variables: { - userId, - input: { - contentScopes: data.contentScopes.map((contentScope) => JSON.parse(contentScope)), - }, - }, - refetchQueries: ["ContentScopes"], - }); - }; + const intl = useIntl(); + const [open, setOpen] = useState(false); const { data, error } = useQuery( gql` @@ -53,6 +28,8 @@ export const ContentScopeGrid = ({ userId }: { userId: string }) => { }, ); + const columns: GridColDef<{ [key in string]: string }>[] = generateGridColumnsFromContentScopeProperties(data?.userContentScopes || [], intl); + if (error) throw new Error(error.message); if (!data) { @@ -60,46 +37,34 @@ export const ContentScopeGrid = ({ userId }: { userId: string }) => { } return ( - - - mode="edit" - onSubmit={submit} - onAfterSubmit={() => null} - initialValues={{ contentScopes: data.userContentScopes.map((cs) => JSON.stringify(cs)) }} - > + <> + - - - + - {data.availableContentScopes.map((contentScope: ContentScope) => ( - isEqual(cs, contentScope))} - key={JSON.stringify(contentScope)} - name="contentScopes" - fullWidth - variant="horizontal" - type="checkbox" - component={FinalFormCheckbox} - value={JSON.stringify(contentScope)} - label={Object.entries(contentScope).map(([scope, value]) => ( - <> - {camelCaseToHumanReadable(scope)}: {camelCaseToHumanReadable(value)} -
- - ))} - /> - ))} + "auto"} + getRowId={(row) => JSON.stringify(row)} + sx={{ "&.MuiDataGrid-root .MuiDataGrid-cell": { py: "8px" } }} + />
- -
+
+ setOpen(false)} data={data} userId={userId} /> + ); }; @@ -107,3 +72,29 @@ const CardToolbar = styled(Toolbar)` top: 0px; border-bottom: 1px solid ${({ theme }) => theme.palette.grey[100]}; `; + +export function generateGridColumnsFromContentScopeProperties( + data: GQLContentScopesQuery["userContentScopes"] | GQLContentScopesQuery["availableContentScopes"], + intl: IntlShape, +): GridColDef[] { + const uniquePropertyNames = Array.from(new Set(data.flatMap((item) => Object.keys(item)))); + return uniquePropertyNames.map((propertyName) => { + return { + field: propertyName, + flex: 1, + pinnable: false, + sortable: false, + filterable: false, + headerName: camelCaseToHumanReadable( + intl.formatMessage({ id: `comet.userPermissions.contentScope.${propertyName}`, defaultMessage: propertyName }), + ), + renderCell: ({ row }) => { + if (row[propertyName] != null) { + return {camelCaseToHumanReadable(row[propertyName])}; + } else { + return "-"; + } + }, + }; + }); +} diff --git a/packages/admin/cms-admin/src/userPermissions/user/permissions/selectScopesDialog/SelectScopesDialog.tsx b/packages/admin/cms-admin/src/userPermissions/user/permissions/selectScopesDialog/SelectScopesDialog.tsx new file mode 100644 index 0000000000..b28a47e0b8 --- /dev/null +++ b/packages/admin/cms-admin/src/userPermissions/user/permissions/selectScopesDialog/SelectScopesDialog.tsx @@ -0,0 +1,135 @@ +import { useApolloClient } from "@apollo/client"; +import { + CancelButton, + DataGridToolbar, + Field, + FinalForm, + SaveBoundary, + SaveBoundarySaveButton, + ToolbarFillSpace, + ToolbarItem, + useFormApiRef, +} from "@comet/admin"; +import { Dialog, DialogActions, DialogTitle } from "@mui/material"; +import { DataGrid, GridColDef, GridToolbarQuickFilter } from "@mui/x-data-grid"; +import gql from "graphql-tag"; +import { FormattedMessage, useIntl } from "react-intl"; + +import { generateGridColumnsFromContentScopeProperties } from "../ContentScopeGrid"; +import { GQLContentScopesQuery } from "../ContentScopeGrid.generated"; +import { GQLUpdateContentScopesMutation, GQLUpdateContentScopesMutationVariables } from "./SelectScopesDialog.generated"; + +export interface SelectScopesDialogProps { + open: boolean; + onClose: () => void; + data: GQLContentScopesQuery; + userId: string; +} + +type FormValues = { + contentScopes: string[]; +}; + +type ContentScope = { + [key: string]: string; +}; + +function SelectScopesGridToolbar() { + return ( + + + + + + + ); +} + +export const SelectScopesDialog: React.FunctionComponent> = ({ open, onClose, data, userId }) => { + const client = useApolloClient(); + const intl = useIntl(); + const formApiRef = useFormApiRef(); + const submit = async (values: FormValues) => { + await client.mutate({ + mutation: gql` + mutation UpdateContentScopes($userId: String!, $input: UserContentScopesInput!) { + userPermissionsUpdateContentScopes(userId: $userId, input: $input) + } + `, + variables: { + userId, + input: { + contentScopes: values.contentScopes.map((contentScope) => JSON.parse(contentScope)), + }, + }, + refetchQueries: ["ContentScopes"], + }); + }; + + const columns: GridColDef<{ [key in string]: string }>[] = generateGridColumnsFromContentScopeProperties( + data?.availableContentScopes || [], + intl, + ); + + return ( + { + onClose(); + }} + > + + + + + + apiRef={formApiRef} + subscription={{ values: true }} + mode="edit" + onSubmit={submit} + onAfterSubmit={() => null} + initialValues={{ + contentScopes: data.userContentScopes.map((cs) => JSON.stringify(cs)), + }} + > + + {(props) => { + return ( + !Object.values(obj).every((value) => value === undefined)) ?? [] + } + columns={columns} + rowCount={data?.availableContentScopes.length ?? 0} + loading={false} + getRowHeight={() => "auto"} + getRowId={(row) => JSON.stringify(row)} + isRowSelectable={(params) => { + return !data.userContentScopesSkipManual.some( + (cs: ContentScope) => JSON.stringify(cs) === JSON.stringify(params.row), + ); + }} + checkboxSelection + sx={{ "&.MuiDataGrid-root .MuiDataGrid-cell": { py: "8px" }, width: "100%" }} + selectionModel={props.input.value} + onSelectionModelChange={(selectionModel) => { + props.input.onChange(selectionModel.map((id) => String(id))); + }} + components={{ + Toolbar: SelectScopesGridToolbar, + }} + /> + ); + }} + + + + + + + + + + + ); +};