Introduce datagrid to permission group list (#4102)

Co-authored-by: wojteknowacki <wojciech.nowacki@saleor.io>
This commit is contained in:
Paweł Chyła 2023-08-28 15:25:27 +02:00 committed by GitHub
parent 4a0b2230ac
commit 7d48cded75
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 319 additions and 274 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---
Add datagrid feature to permission group list

View file

@ -3,12 +3,8 @@
import faker from "faker"; import faker from "faker";
import { import { PERMISSION_GROUP_DETAILS_SELECTORS } from "../../elements/permissionGroup/permissionGroupDetails";
PERMISSION_GROUP_DETAILS_SELECTORS, import { PERMISSION_GROUP_LIST_SELECTORS } from "../../elements/permissionGroup/permissionGroupsList";
} from "../../elements/permissionGroup/permissionGroupDetails";
import {
PERMISSION_GROUP_LIST_SELECTORS,
} from "../../elements/permissionGroup/permissionGroupsList";
import { BUTTON_SELECTORS } from "../../elements/shared/button-selectors"; import { BUTTON_SELECTORS } from "../../elements/shared/button-selectors";
import { SHARED_ELEMENTS } from "../../elements/shared/sharedElements"; import { SHARED_ELEMENTS } from "../../elements/shared/sharedElements";
import { import {
@ -21,9 +17,8 @@ import {
createPermissionGroup, createPermissionGroup,
getPermissionGroup, getPermissionGroup,
} from "../../support/api/requests/PermissionGroup.js"; } from "../../support/api/requests/PermissionGroup.js";
import { import { getStaffMembersStartsWith } from "../../support/api/requests/StaffMembers";
getStaffMembersStartsWith, import { ensureCanvasStatic } from "../../support/customCommands/sharedElementsOperations/canvas";
} from "../../support/api/requests/StaffMembers";
describe("Permissions groups", () => { describe("Permissions groups", () => {
const startsWith = "CyPermissions-" + Date.now(); const startsWith = "CyPermissions-" + Date.now();
@ -69,37 +64,31 @@ describe("Permissions groups", () => {
() => { () => {
const permissionName = `A-${startsWith}${faker.datatype.number()}`; const permissionName = `A-${startsWith}${faker.datatype.number()}`;
let staffMember; let staffMember;
cy.addAliasToGraphRequest("PermissionGroupDelete");
getStaffMembersStartsWith(TEST_ADMIN_USER.email) getStaffMembersStartsWith(TEST_ADMIN_USER.email)
.its("body.data.staffUsers.edges") .its("body.data.staffUsers.edges")
.then(staffMemberResp => { .then(staffMemberResp => {
staffMember = staffMemberResp[0].node; staffMember = staffMemberResp[0].node;
createPermissionGroup({ createPermissionGroup({
name: permissionName, name: permissionName,
userIdsArray: `["${staffMember.id}"]`, userIdsArray: `["${staffMember.id}"]`,
permissionsArray: permissionManageProducts, permissionsArray: permissionManageProducts,
}).then(createPermissionGroupResponse => {
cy.visit(
urlList.permissionsGroups +
createPermissionGroupResponse.group.id,
);
cy.contains(SHARED_ELEMENTS.header, permissionName);
cy.get(BUTTON_SELECTORS.deleteButton).click();
cy.clickSubmitButton().waitForRequestAndCheckIfNoErrors(
"@PermissionGroupDelete",
);
ensureCanvasStatic(SHARED_ELEMENTS.dataGridTable);
cy.get(SHARED_ELEMENTS.dataGridTable).should(
"not.contain.text",
permissionName,
);
}); });
cy.visit(urlList.permissionsGroups);
cy.contains(
PERMISSION_GROUP_LIST_SELECTORS.permissionGroupRow,
permissionName,
)
.should("be.visible")
.find(BUTTON_SELECTORS.deleteIcon)
.click()
.get(BUTTON_SELECTORS.submit)
.click();
cy.contains(
PERMISSION_GROUP_LIST_SELECTORS.permissionGroupRow,
permissionName,
)
.should("not.exist")
.visit(staffMemberDetailsUrl(staffMember.id))
.get(SHARED_ELEMENTS.header)
.should("be.visible")
.contains(permissionName)
.should("not.exist");
}); });
}, },
); );

View file

@ -7157,6 +7157,9 @@
"context": "label", "context": "label",
"string": "External app" "string": "External app"
}, },
"nBzIBG": {
"string": "Delete permission group"
},
"nEWp+k": { "nEWp+k": {
"context": "quantity of ordered products", "context": "quantity of ordered products",
"string": "Quantity" "string": "Quantity"

View file

@ -130,6 +130,7 @@ export const defaultListSettings: AppListViewSettings = {
}, },
[ListViews.PERMISSION_GROUP_LIST]: { [ListViews.PERMISSION_GROUP_LIST]: {
rowNumber: PAGINATE_BY, rowNumber: PAGINATE_BY,
columns: ["name", "members"],
}, },
[ListViews.VOUCHER_LIST]: { [ListViews.VOUCHER_LIST]: {
rowNumber: PAGINATE_BY, rowNumber: PAGINATE_BY,

View file

@ -22,6 +22,7 @@ const props: PermissonGroupDetailsPageProps = {
members: users, members: users,
onAssign: () => undefined, onAssign: () => undefined,
onSort: () => undefined, onSort: () => undefined,
onDelete: () => undefined,
onSubmit: () => new Promise(resolve => resolve(undefined)), onSubmit: () => new Promise(resolve => resolve(undefined)),
onUnassign: () => undefined, onUnassign: () => undefined,
permissionGroup, permissionGroup,

View file

@ -66,6 +66,7 @@ export interface PermissonGroupDetailsPageProps
permissionsExceeded: boolean; permissionsExceeded: boolean;
saveButtonBarState: "loading" | "success" | "error" | "default"; saveButtonBarState: "loading" | "success" | "error" | "default";
onAssign: () => void; onAssign: () => void;
onDelete: () => void;
onUnassign: (ids: string[]) => void; onUnassign: (ids: string[]) => void;
onSubmit: (data: PermissionGroupDetailsPageFormData) => SubmitPromise; onSubmit: (data: PermissionGroupDetailsPageFormData) => SubmitPromise;
} }
@ -77,6 +78,7 @@ export const PermissionGroupDetailsPage: React.FC<
errors, errors,
members, members,
onSubmit, onSubmit,
onDelete,
permissionGroup, permissionGroup,
permissions, permissions,
permissionsExceeded, permissionsExceeded,
@ -190,6 +192,7 @@ export const PermissionGroupDetailsPage: React.FC<
<div> <div>
<Savebar <Savebar
onCancel={() => navigate(permissionGroupListUrl())} onCancel={() => navigate(permissionGroupListUrl())}
onDelete={onDelete}
onSubmit={submit} onSubmit={submit}
state={saveButtonBarState} state={saveButtonBarState}
disabled={disabled} disabled={disabled}

View file

@ -1,176 +0,0 @@
// @ts-strict-ignore
import ResponsiveTable from "@dashboard/components/ResponsiveTable";
import Skeleton from "@dashboard/components/Skeleton";
import { TableButtonWrapper } from "@dashboard/components/TableButtonWrapper/TableButtonWrapper";
import TableCellHeader from "@dashboard/components/TableCellHeader";
import { TablePaginationWithContext } from "@dashboard/components/TablePagination";
import TableRowLink from "@dashboard/components/TableRowLink";
import { PermissionGroupFragment } from "@dashboard/graphql";
import { maybe, renderCollection, stopPropagation } from "@dashboard/misc";
import {
permissionGroupDetailsUrl,
PermissionGroupListUrlSortField,
} from "@dashboard/permissionGroups/urls";
import { ListProps, SortPage } from "@dashboard/types";
import { getArrowDirection } from "@dashboard/utils/sort";
import {
TableBody,
TableCell,
TableFooter,
TableHead,
} from "@material-ui/core";
import { DeleteIcon, IconButton, makeStyles } from "@saleor/macaw-ui";
import React from "react";
import { FormattedMessage } from "react-intl";
const useStyles = makeStyles(
theme => ({
[theme.breakpoints.up("lg")]: {
colActions: {
width: 180,
},
colMembers: {
width: 180,
},
colName: {
width: "auto",
},
},
colActions: {
paddingRight: theme.spacing(),
textAlign: "right",
},
colActionsHeader: {
textAlign: "right",
},
colMembers: {
textAlign: "right",
},
colName: {
paddingLeft: 0,
},
link: {
cursor: "pointer",
},
}),
{ name: "PermissionGroupList" },
);
const numberOfColumns = 3;
interface PermissionGroupListProps
extends ListProps,
SortPage<PermissionGroupListUrlSortField> {
permissionGroups: PermissionGroupFragment[];
onDelete: (id: string) => void;
}
const PermissionGroupList: React.FC<PermissionGroupListProps> = props => {
const { disabled, permissionGroups, onDelete, onSort, sort } = props;
const classes = useStyles(props);
return (
<ResponsiveTable>
<TableHead>
<TableRowLink>
<TableCellHeader
direction={
sort.sort === PermissionGroupListUrlSortField.name
? getArrowDirection(sort.asc)
: undefined
}
arrowPosition="right"
onClick={() => onSort(PermissionGroupListUrlSortField.name)}
className={classes.colName}
>
<FormattedMessage
id="szXISP"
defaultMessage="Permission Group Name"
description="permission group name"
/>
</TableCellHeader>
<TableCellHeader className={classes.colMembers} textAlign="right">
<FormattedMessage id="+a+2ug" defaultMessage="Members" />
</TableCellHeader>
<TableCell className={classes.colActionsHeader}>
<FormattedMessage id="wL7VAE" defaultMessage="Actions" />
</TableCell>
</TableRowLink>
</TableHead>
<TableFooter>
<TableRowLink>
<TablePaginationWithContext
colSpan={numberOfColumns}
disabled={disabled}
/>
</TableRowLink>
</TableFooter>
<TableBody>
{renderCollection(
permissionGroups,
permissionGroup => (
<TableRowLink
className={!!permissionGroup ? classes.link : undefined}
hover={!!permissionGroup}
key={permissionGroup ? permissionGroup.id : "skeleton"}
href={
permissionGroup && permissionGroupDetailsUrl(permissionGroup.id)
}
data-test-id={"id-" + maybe(() => permissionGroup.id)}
>
<TableCell className={classes.colName}>
{permissionGroup ? (
<span data-test-id="name">{permissionGroup.name}</span>
) : (
<Skeleton />
)}
</TableCell>
<TableCell className={classes.colMembers}>
{permissionGroup ? (
<span data-test-id="members">
{permissionGroup.users.length}
</span>
) : (
<Skeleton />
)}
</TableCell>
<TableCell className={classes.colActions}>
{permissionGroup ? (
<>
{permissionGroup.userCanManage && (
<TableButtonWrapper>
<IconButton
variant="secondary"
data-test-id="delete-icon"
color="primary"
onClick={stopPropagation(() =>
onDelete(permissionGroup.id),
)}
>
<DeleteIcon />
</IconButton>
</TableButtonWrapper>
)}
</>
) : (
<Skeleton />
)}
</TableCell>
</TableRowLink>
),
() => (
<TableRowLink>
<TableCell colSpan={numberOfColumns}>
<FormattedMessage
id="CXn88q"
defaultMessage="No permission groups found"
/>
</TableCell>
</TableRowLink>
),
)}
</TableBody>
</ResponsiveTable>
);
};
PermissionGroupList.displayName = "PermissionGroupList";
export default PermissionGroupList;

View file

@ -1,2 +0,0 @@
export { default } from "./PermissionGroupList";
export * from "./PermissionGroupList";

View file

@ -0,0 +1,136 @@
import { useColumns } from "@dashboard/components/Datagrid/ColumnPicker/useColumns";
import Datagrid from "@dashboard/components/Datagrid/Datagrid";
import {
DatagridChangeStateContext,
useDatagridChangeState,
} from "@dashboard/components/Datagrid/hooks/useDatagridChange";
import { useEmptyColumn } from "@dashboard/components/Datagrid/hooks/useEmptyColumn";
import { TablePaginationWithContext } from "@dashboard/components/TablePagination";
import { PermissionGroupFragment } from "@dashboard/graphql";
import useNavigator from "@dashboard/hooks/useNavigator";
import {
permissionGroupDetailsUrl,
PermissionGroupListUrlSortField,
} from "@dashboard/permissionGroups/urls";
import { canBeSorted } from "@dashboard/permissionGroups/views/PermissionGroupList/sort";
import { ListProps, SortPage } from "@dashboard/types";
import { Item } from "@glideapps/glide-data-grid";
import { Box } from "@saleor/macaw-ui/next";
import React, { useCallback, useMemo } from "react";
import { useIntl } from "react-intl";
import {
createGetCellContent,
permissionGroupsListStaticColumnsAdapter,
} from "./datagrid";
import { messages } from "./messages";
interface PermissionGroupListDatagridProps
extends ListProps,
SortPage<PermissionGroupListUrlSortField> {
permissionGroups: PermissionGroupFragment[];
}
export const PermissionGroupListDatagrid = ({
disabled,
onSort,
permissionGroups,
sort,
settings,
onUpdateListSettings,
}: PermissionGroupListDatagridProps) => {
const intl = useIntl();
const datagridState = useDatagridChangeState();
const navigate = useNavigator();
const emptyColumn = useEmptyColumn();
const permissionGroupsListStaticColumns = useMemo(
() => permissionGroupsListStaticColumnsAdapter(intl, sort, emptyColumn),
[intl, sort],
);
const onColumnChange = useCallback(
(picked: string[]) => {
if (onUpdateListSettings) {
onUpdateListSettings("columns", picked.filter(Boolean));
}
},
[onUpdateListSettings],
);
const { handlers, visibleColumns, recentlyAddedColumn } = useColumns({
selectedColumns: settings?.columns ?? [],
staticColumns: permissionGroupsListStaticColumns,
onSave: onColumnChange,
});
const getCellContent = useCallback(
createGetCellContent({
permissionGroups,
columns: visibleColumns,
}),
[permissionGroups, intl, visibleColumns],
);
const handleRowClick = useCallback(
([_, row]: Item) => {
const rowData: PermissionGroupFragment = permissionGroups[row];
if (rowData) {
navigate(permissionGroupDetailsUrl(rowData.id));
}
},
[permissionGroups],
);
const handleRowAnchor = useCallback(
([, row]: Item) => permissionGroupDetailsUrl(permissionGroups[row].id),
[permissionGroups],
);
const handleHeaderClick = useCallback(
(col: number) => {
const columnName = visibleColumns[col]
.id as PermissionGroupListUrlSortField;
if (canBeSorted(columnName)) {
onSort(columnName);
}
},
[visibleColumns, onSort],
);
return (
<DatagridChangeStateContext.Provider value={datagridState}>
<Datagrid
readonly
loading={disabled}
rowMarkers="none"
columnSelect="single"
hasRowHover={true}
freezeColumns={2}
onColumnMoved={handlers.onMove}
onColumnResize={handlers.onResize}
verticalBorder={col => col > 1}
rows={permissionGroups?.length ?? 0}
availableColumns={visibleColumns}
emptyText={intl.formatMessage(messages.empty)}
getCellContent={getCellContent}
getCellError={() => false}
selectionActions={() => null}
menuItems={() => []}
onRowClick={handleRowClick}
onHeaderClicked={handleHeaderClick}
rowAnchor={handleRowAnchor}
recentlyAddedColumn={recentlyAddedColumn}
/>
<Box paddingX={6}>
<TablePaginationWithContext
component="div"
settings={settings}
disabled={disabled}
onUpdateListSettings={onUpdateListSettings}
/>
</Box>
</DatagridChangeStateContext.Provider>
);
};

View file

@ -0,0 +1,61 @@
import { PLACEHOLDER } from "@dashboard/components/Datagrid/const";
import { readonlyTextCell } from "@dashboard/components/Datagrid/customCells/cells";
import { AvailableColumn } from "@dashboard/components/Datagrid/types";
import { PermissionGroupFragment } from "@dashboard/graphql";
import { PermissionGroupListUrlSortField } from "@dashboard/permissionGroups/urls";
import { Sort } from "@dashboard/types";
import { getColumnSortDirectionIcon } from "@dashboard/utils/columns/getColumnSortDirectionIcon";
import { GridCell, Item } from "@glideapps/glide-data-grid";
import { IntlShape } from "react-intl";
import { columnsMessages } from "./messages";
export const permissionGroupsListStaticColumnsAdapter = (
intl: IntlShape,
sort: Sort<PermissionGroupListUrlSortField>,
emptyColumn: AvailableColumn,
) =>
[
emptyColumn,
{
id: "name",
title: intl.formatMessage(columnsMessages.name),
width: 450,
},
{
id: "members",
title: intl.formatMessage(columnsMessages.members),
width: 200,
},
].map(column => ({
...column,
icon: getColumnSortDirectionIcon(sort, column.id),
}));
export const createGetCellContent =
({
permissionGroups,
columns,
}: {
permissionGroups: PermissionGroupFragment[];
columns: AvailableColumn[];
}) =>
([column, row]: Item): GridCell => {
const rowData: PermissionGroupFragment | undefined = permissionGroups[row];
const columnId = columns[column]?.id;
if (!columnId || !rowData) {
return readonlyTextCell("");
}
switch (columnId) {
case "name":
return readonlyTextCell(rowData?.name ?? PLACEHOLDER);
case "members":
return readonlyTextCell(
rowData?.users?.length?.toString() ?? PLACEHOLDER,
);
default:
return readonlyTextCell("");
}
};

View file

@ -0,0 +1 @@
export * from "./PermissionGroupListDatagrid";

View file

@ -0,0 +1,24 @@
import { defineMessages } from "react-intl";
export const columnsMessages = defineMessages({
name: {
id: "szXISP",
defaultMessage: "Permission Group Name",
description: "permission group name",
},
members: {
id: "+a+2ug",
defaultMessage: "Members",
},
});
export const messages = defineMessages({
empty: {
id: "CXn88q",
defaultMessage: "No permission groups found",
},
deletePermissionGroup: {
defaultMessage: "Delete permission group",
id: "nBzIBG",
},
});

View file

@ -19,7 +19,6 @@ const props: PermissionGroupListPageProps = {
...pageListProps.default, ...pageListProps.default,
...sortPageProps, ...sortPageProps,
disabled: false, disabled: false,
onDelete: () => undefined,
sort: { sort: {
...sortPageProps.sort, ...sortPageProps.sort,
sort: PermissionGroupListUrlSortField.name, sort: PermissionGroupListUrlSortField.name,

View file

@ -1,10 +1,11 @@
import { TopNav } from "@dashboard/components/AppLayout/TopNav"; import { TopNav } from "@dashboard/components/AppLayout/TopNav";
import { Button } from "@dashboard/components/Button";
import { ListPageLayout } from "@dashboard/components/Layouts"; import { ListPageLayout } from "@dashboard/components/Layouts";
import { configurationMenuUrl } from "@dashboard/configuration"; import { configurationMenuUrl } from "@dashboard/configuration";
import { PermissionGroupFragment } from "@dashboard/graphql"; import { PermissionGroupFragment } from "@dashboard/graphql";
import useNavigator from "@dashboard/hooks/useNavigator";
import { sectionNames } from "@dashboard/intl"; import { sectionNames } from "@dashboard/intl";
import { Card } from "@material-ui/core"; import { Card } from "@material-ui/core";
import { Button } from "@saleor/macaw-ui/next";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -13,29 +14,30 @@ import {
permissionGroupAddUrl, permissionGroupAddUrl,
PermissionGroupListUrlSortField, PermissionGroupListUrlSortField,
} from "../../urls"; } from "../../urls";
import PermissionGroupList from "../PermissionGroupList"; import { PermissionGroupListDatagrid } from "../PermissionGroupListDatagrid";
export interface PermissionGroupListPageProps export interface PermissionGroupListPageProps
extends PageListProps, extends PageListProps,
SortPage<PermissionGroupListUrlSortField> { SortPage<PermissionGroupListUrlSortField> {
permissionGroups: PermissionGroupFragment[]; permissionGroups: PermissionGroupFragment[];
onDelete: (id: string) => void;
} }
const PermissionGroupListPage: React.FC< const PermissionGroupListPage: React.FC<
PermissionGroupListPageProps PermissionGroupListPageProps
> = listProps => { > = listProps => {
const intl = useIntl(); const intl = useIntl();
const navigate = useNavigator();
return ( return (
<ListPageLayout> <ListPageLayout>
<TopNav <TopNav
withoutBorder
href={configurationMenuUrl} href={configurationMenuUrl}
title={intl.formatMessage(sectionNames.permissionGroups)} title={intl.formatMessage(sectionNames.permissionGroups)}
> >
<Button <Button
variant="primary" variant="primary"
href={permissionGroupAddUrl} onClick={() => navigate(permissionGroupAddUrl)}
data-test-id="create-permission-group" data-test-id="create-permission-group"
> >
<FormattedMessage <FormattedMessage
@ -46,7 +48,7 @@ const PermissionGroupListPage: React.FC<
</Button> </Button>
</TopNav> </TopNav>
<Card> <Card>
<PermissionGroupList {...listProps} /> <PermissionGroupListDatagrid {...listProps} />
</Card> </Card>
</ListPageLayout> </ListPageLayout>
); );

View file

@ -4,6 +4,8 @@ import { Button } from "@dashboard/components/Button";
import { DEFAULT_INITIAL_SEARCH_DATA } from "@dashboard/config"; import { DEFAULT_INITIAL_SEARCH_DATA } from "@dashboard/config";
import { import {
PermissionGroupDetailsQuery, PermissionGroupDetailsQuery,
PermissionGroupErrorFragment,
usePermissionGroupDeleteMutation,
usePermissionGroupDetailsQuery, usePermissionGroupDetailsQuery,
usePermissionGroupUpdateMutation, usePermissionGroupUpdateMutation,
} from "@dashboard/graphql"; } from "@dashboard/graphql";
@ -13,8 +15,9 @@ import useNotifier from "@dashboard/hooks/useNotifier";
import useShop from "@dashboard/hooks/useShop"; import useShop from "@dashboard/hooks/useShop";
import useStateFromProps from "@dashboard/hooks/useStateFromProps"; import useStateFromProps from "@dashboard/hooks/useStateFromProps";
import { commonMessages } from "@dashboard/intl"; import { commonMessages } from "@dashboard/intl";
import { extractMutationErrors } from "@dashboard/misc"; import { extractMutationErrors, getStringOrPlaceholder } from "@dashboard/misc";
import MembersErrorDialog from "@dashboard/permissionGroups/components/MembersErrorDialog"; import MembersErrorDialog from "@dashboard/permissionGroups/components/MembersErrorDialog";
import PermissionGroupDeleteDialog from "@dashboard/permissionGroups/components/PermissionGroupDeleteDialog";
import useStaffMemberSearch from "@dashboard/searches/useStaffMemberSearch"; import useStaffMemberSearch from "@dashboard/searches/useStaffMemberSearch";
import createDialogActionHandlers from "@dashboard/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@dashboard/utils/handlers/dialogActionHandlers";
import createSortHandler from "@dashboard/utils/handlers/sortHandler"; import createSortHandler from "@dashboard/utils/handlers/sortHandler";
@ -33,6 +36,7 @@ import {
permissionGroupDetailsUrl, permissionGroupDetailsUrl,
PermissionGroupDetailsUrlDialog, PermissionGroupDetailsUrlDialog,
PermissionGroupDetailsUrlQueryParams, PermissionGroupDetailsUrlQueryParams,
permissionGroupListUrl,
} from "../../urls"; } from "../../urls";
import { import {
arePermissionsExceeded, arePermissionsExceeded,
@ -127,6 +131,27 @@ export const PermissionGroupDetails: React.FC<PermissionGroupDetailsProps> = ({
params, params,
); );
const [deleteError, setDeleteError] =
React.useState<PermissionGroupErrorFragment>();
const [permissionGroupDelete, permissionGroupDeleteOps] =
usePermissionGroupDeleteMutation({
onCompleted: data => {
if (data?.permissionGroupDelete?.errors?.length === 0) {
notify({
status: "success",
text: intl.formatMessage({
id: "DovGIa",
defaultMessage: "Permission Group Deleted",
}),
});
navigate(permissionGroupListUrl());
} else {
setDeleteError(data?.permissionGroupDelete?.errors?.[0]);
}
},
});
const unassignMembers = () => { const unassignMembers = () => {
setMembersList( setMembersList(
membersList?.filter(m => !listElements.includes(m.id)) ?? [], membersList?.filter(m => !listElements.includes(m.id)) ?? [],
@ -193,6 +218,7 @@ export const PermissionGroupDetails: React.FC<PermissionGroupDetailsProps> = ({
members={membersList} members={membersList}
onAssign={() => openModal("assign")} onAssign={() => openModal("assign")}
onUnassign={ids => openModal("unassign", { ids })} onUnassign={ids => openModal("unassign", { ids })}
onDelete={() => openModal("remove")}
errors={ errors={
permissionGroupUpdateResult?.data?.permissionGroupUpdate?.errors ?? [] permissionGroupUpdateResult?.data?.permissionGroupUpdate?.errors ?? []
} }
@ -219,6 +245,7 @@ export const PermissionGroupDetails: React.FC<PermissionGroupDetailsProps> = ({
} }
onSort={handleSort} onSort={handleSort}
/> />
<AssignMembersDialog <AssignMembersDialog
loading={searchResult.loading} loading={searchResult.loading}
staffMembers={mapEdgesToItems(searchResult?.data?.search) ?? []} staffMembers={mapEdgesToItems(searchResult?.data?.search) ?? []}
@ -235,6 +262,7 @@ export const PermissionGroupDetails: React.FC<PermissionGroupDetailsProps> = ({
closeModal(); closeModal();
}} }}
/> />
<UnassignMembersDialog <UnassignMembersDialog
onConfirm={unassignMembers} onConfirm={unassignMembers}
confirmButtonState={permissionGroupUpdateResult.status} confirmButtonState={permissionGroupUpdateResult.status}
@ -242,12 +270,28 @@ export const PermissionGroupDetails: React.FC<PermissionGroupDetailsProps> = ({
open={params.action === "unassign"} open={params.action === "unassign"}
onClose={closeModal} onClose={closeModal}
/> />
<MembersErrorDialog <MembersErrorDialog
onConfirm={closeModal} onConfirm={closeModal}
confirmButtonState={permissionGroupUpdateResult.status} confirmButtonState={permissionGroupUpdateResult.status}
open={params.action === "unassignError"} open={params.action === "unassignError"}
onClose={closeModal} onClose={closeModal}
/> />
<PermissionGroupDeleteDialog
onConfirm={() =>
permissionGroupDelete({
variables: {
id: data?.permissionGroup?.id ?? "",
},
})
}
error={deleteError}
name={getStringOrPlaceholder(data?.permissionGroup?.name)}
confirmButtonState={permissionGroupDeleteOps.status}
open={params.action === "remove"}
onClose={closeModal}
/>
</> </>
); );
}; };

View file

@ -1,30 +1,20 @@
import { import { usePermissionGroupListQuery } from "@dashboard/graphql";
PermissionGroupErrorFragment,
usePermissionGroupDeleteMutation,
usePermissionGroupListQuery,
} from "@dashboard/graphql";
import useListSettings from "@dashboard/hooks/useListSettings"; import useListSettings from "@dashboard/hooks/useListSettings";
import useNavigator from "@dashboard/hooks/useNavigator"; import useNavigator from "@dashboard/hooks/useNavigator";
import useNotifier from "@dashboard/hooks/useNotifier";
import { usePaginationReset } from "@dashboard/hooks/usePaginationReset"; import { usePaginationReset } from "@dashboard/hooks/usePaginationReset";
import usePaginator, { import usePaginator, {
createPaginationState, createPaginationState,
PaginatorContext, PaginatorContext,
} from "@dashboard/hooks/usePaginator"; } from "@dashboard/hooks/usePaginator";
import { getStringOrPlaceholder } from "@dashboard/misc";
import PermissionGroupDeleteDialog from "@dashboard/permissionGroups/components/PermissionGroupDeleteDialog";
import { ListViews } from "@dashboard/types"; import { ListViews } from "@dashboard/types";
import createDialogActionHandlers from "@dashboard/utils/handlers/dialogActionHandlers";
import createSortHandler from "@dashboard/utils/handlers/sortHandler"; import createSortHandler from "@dashboard/utils/handlers/sortHandler";
import { mapEdgesToItems } from "@dashboard/utils/maps"; import { mapEdgesToItems } from "@dashboard/utils/maps";
import { getSortParams } from "@dashboard/utils/sort"; import { getSortParams } from "@dashboard/utils/sort";
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import PermissionGroupListPage from "../../components/PermissionGroupListPage"; import PermissionGroupListPage from "../../components/PermissionGroupListPage";
import { import {
permissionGroupListUrl, permissionGroupListUrl,
PermissionGroupListUrlDialog,
PermissionGroupListUrlQueryParams, PermissionGroupListUrlQueryParams,
} from "../../urls"; } from "../../urls";
import { getSortQueryVariables } from "./sort"; import { getSortQueryVariables } from "./sort";
@ -37,10 +27,8 @@ export const PermissionGroupList: React.FC<PermissionGroupListProps> = ({
params, params,
}) => { }) => {
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier();
const intl = useIntl();
const { updateListSettings, settings } = useListSettings( const { updateListSettings, settings } = useListSettings(
ListViews.STAFF_MEMBERS_LIST, ListViews.PERMISSION_GROUP_LIST,
); );
usePaginationReset(permissionGroupListUrl, params, settings.rowNumber); usePaginationReset(permissionGroupListUrl, params, settings.rowNumber);
@ -53,7 +41,7 @@ export const PermissionGroupList: React.FC<PermissionGroupListProps> = ({
}), }),
[params, settings.rowNumber], [params, settings.rowNumber],
); );
const { data, loading, refetch } = usePermissionGroupListQuery({ const { data, loading } = usePermissionGroupListQuery({
displayLoader: true, displayLoader: true,
variables: queryVariables, variables: queryVariables,
}); });
@ -70,33 +58,7 @@ export const PermissionGroupList: React.FC<PermissionGroupListProps> = ({
params, params,
); );
const [openModal, closeModal] = createDialogActionHandlers<
PermissionGroupListUrlDialog,
PermissionGroupListUrlQueryParams
>(navigate, permissionGroupListUrl, params);
const permissionGroups = mapEdgesToItems(data?.permissionGroups) ?? []; const permissionGroups = mapEdgesToItems(data?.permissionGroups) ?? [];
const [deleteError, setDeleteError] =
React.useState<PermissionGroupErrorFragment>();
const [permissionGroupDelete] = usePermissionGroupDeleteMutation({
onCompleted: data => {
if (data?.permissionGroupDelete?.errors?.length === 0) {
notify({
status: "success",
text: intl.formatMessage({
id: "DovGIa",
defaultMessage: "Permission Group Deleted",
}),
});
refetch();
setDeleteError(undefined);
closeModal();
} else {
setDeleteError(data?.permissionGroupDelete?.errors?.[0]);
}
},
});
return ( return (
<PaginatorContext.Provider value={paginationValues}> <PaginatorContext.Provider value={paginationValues}>
@ -105,26 +67,9 @@ export const PermissionGroupList: React.FC<PermissionGroupListProps> = ({
settings={settings} settings={settings}
sort={getSortParams(params)} sort={getSortParams(params)}
permissionGroups={permissionGroups} permissionGroups={permissionGroups}
onDelete={id => openModal("remove", { id })}
onUpdateListSettings={updateListSettings} onUpdateListSettings={updateListSettings}
onSort={handleSort} onSort={handleSort}
/> />
<PermissionGroupDeleteDialog
onConfirm={() =>
permissionGroupDelete({
variables: {
id: params?.id ?? "",
},
})
}
error={deleteError}
name={getStringOrPlaceholder(
permissionGroups?.find(group => group.id === params.id)?.name,
)}
confirmButtonState={"default"}
open={params.action === "remove"}
onClose={closeModal}
/>
</PaginatorContext.Provider> </PaginatorContext.Provider>
); );
}; };

View file

@ -15,3 +15,12 @@ export function getSortQueryField(
export const getSortQueryVariables = export const getSortQueryVariables =
createGetSortQueryVariables(getSortQueryField); createGetSortQueryVariables(getSortQueryField);
export function canBeSorted(sort: PermissionGroupListUrlSortField) {
switch (sort) {
case PermissionGroupListUrlSortField.name:
return true;
default:
return false;
}
}