Skip to content

Commit

Permalink
Admin Generator (Future): Allow adding custom grid actions (#1913)
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesricky authored Aug 22, 2024
1 parent 4b267f9 commit b7646db
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 36 deletions.
2 changes: 1 addition & 1 deletion demo/admin/src/products/ProductsGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export function ProductsGrid() {
renderCell: (params) => {
return (
<>
<ProductsGridPreviewAction product={params.row} />
<ProductsGridPreviewAction {...params} />
<IconButton component={StackLink} pageName="edit" payload={params.row.id}>
<Edit color="primary" />
</IconButton>
Expand Down
12 changes: 6 additions & 6 deletions demo/admin/src/products/ProductsGridPreviewAction.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Tooltip } from "@comet/admin";
import { View } from "@comet/admin-icons";
import { Dialog, DialogContent, DialogTitle, IconButton, Typography } from "@mui/material";
import { GridCellParams } from "@mui/x-data-grid-pro";
import { GQLProductsGridFutureFragment } from "@src/products/future/generated/ProductsGrid.generated";
import { GQLProductsListManualFragment } from "@src/products/ProductsGrid.generated";
import React from "react";
import { FormattedMessage } from "react-intl";

type Props = {
product: GQLProductsListManualFragment;
};
type Props = GridCellParams<unknown, GQLProductsListManualFragment | GQLProductsGridFutureFragment>;

export const ProductsGridPreviewAction = ({ product }: Props) => {
export const ProductsGridPreviewAction = ({ row }: Props) => {
const [showDetails, setShowDetails] = React.useState(false);
return (
<>
Expand All @@ -24,9 +24,9 @@ export const ProductsGridPreviewAction = ({ product }: Props) => {
</DialogTitle>
<DialogContent>
<Typography variant="h3" gutterBottom>
{product.title}
{row.title}
</Typography>
<Typography>{product.description}</Typography>
<Typography>{row.description}</Typography>
</DialogContent>
</Dialog>
</>
Expand Down
5 changes: 5 additions & 0 deletions demo/admin/src/products/future/ProductsGrid.cometGen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@ export const ProductsGrid: GridConfig<GQLProduct> = {
{ type: "staticSelect", name: "type", maxWidth: 150, values: [{ value: "Cap", label: "great Cap" }, "Shirt", "Tie"] },
{ type: "date", name: "availableSince", width: 140 },
{ type: "dateTime", name: "createdAt", width: 170 },
{
type: "actions",
width: 116,
component: { name: "ProductsGridPreviewAction", import: "../../ProductsGridPreviewAction" },
},
],
};
3 changes: 3 additions & 0 deletions demo/admin/src/products/future/generated/ProductsGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { GQLProductFilter } from "@src/graphql.generated";
import * as React from "react";
import { useIntl } from "react-intl";

import { ProductsGridPreviewAction } from "../../ProductsGridPreviewAction";
import {
GQLCreateProductMutation,
GQLCreateProductMutationVariables,
Expand Down Expand Up @@ -149,9 +150,11 @@ export function ProductsGrid({ filter, toolbarAction, rowAction }: Props): React
filterable: false,
type: "actions",
align: "right",
width: 116,
renderCell: (params) => {
return (
<>
<ProductsGridPreviewAction {...params} />
{rowAction && rowAction(params)}
<CrudContextMenu
copyData={() => {
Expand Down
66 changes: 42 additions & 24 deletions packages/admin/cms-admin/src/generator/future/generateGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { findInputObjectType } from "./generateGrid/findInputObjectType";
import { generateGqlFieldList } from "./generateGrid/generateGqlFieldList";
import { getForwardedGqlArgs } from "./generateGrid/getForwardedGqlArgs";
import { getPropsForFilterProp } from "./generateGrid/getPropsForFilterProp";
import { GeneratorReturn, GridConfig } from "./generator";
import { ActionsGridColumnConfig, GeneratorReturn, GridColumnConfig, GridConfig } from "./generator";
import { camelCaseToHumanReadable } from "./utils/camelCaseToHumanReadable";
import { findMutationType } from "./utils/findMutationType";
import { findRootBlocks } from "./utils/findRootBlocks";
Expand Down Expand Up @@ -95,7 +95,13 @@ export function generateGrid(
const imports: Imports = [];
const props: Prop[] = [];

const fieldList = generateGqlFieldList({ columns: config.columns.filter((column) => column.name !== "id") }); // exclude id because it's always required
const fieldList = generateGqlFieldList({
columns: config.columns.filter((column) => {
return (
column.type !== "actions" && column.name !== "id" // exclude id because it's always required
);
}),
});

// all root blocks including those we don't have columns for (required for copy/paste)
// this is not configured in the grid config, it's just an heuristics
Expand Down Expand Up @@ -223,7 +229,15 @@ export function generateGrid(
return true;
});

const gridColumnFields = config.columns.map((column) => {
const actionsColumnConfig = config.columns.find((column) => column.type === "actions") as ActionsGridColumnConfig;
const {
component: actionsColumnComponent,
type: actionsColumnType,
headerName: actionsColumnHeaderName,
...restActionsColumnConfig
} = actionsColumnConfig ?? {};

const gridColumnFields = (config.columns.filter((column) => column.type !== "actions") as GridColumnConfig<unknown>[]).map((column) => {
const type = column.type;
const name = String(column.name);

Expand Down Expand Up @@ -366,6 +380,7 @@ export function generateGrid(
${Object.entries(rootBlocks)
.map(([rootBlockKey, rootBlock]) => `import { ${rootBlock.name} } from "${rootBlock.import}";`)
.join("\n")}
${actionsColumnComponent ? `import { ${actionsColumnComponent.name} } from "${actionsColumnComponent.import}";` : ""}
const ${instanceGqlTypePlural}Fragment = gql\`
fragment ${fragmentName} on ${gqlType} {
Expand Down Expand Up @@ -518,28 +533,31 @@ export function generateGrid(
.join(",\n")},
${
showActionsColumn
? `{
field: "actions",
headerName: "",
sortable: false,
filterable: false,
type: "actions",
align: "right",
renderCell: (params) => {
? tsCodeRecordToString({
field: '"actions"',
headerName: actionsColumnHeaderName
? `intl.formatMessage({ id: "${instanceGqlType}.actions", defaultMessage: "${actionsColumnHeaderName}" })`
: `""`,
sortable: "false",
filterable: "false",
type: '"actions"',
align: '"right"',
...restActionsColumnConfig,
renderCell: `(params) => {
return (
<>
${
allowEditing
? forwardRowAction
? `{rowAction && rowAction(params)}`
: `
${actionsColumnComponent?.name ? `<${actionsColumnComponent.name} {...params} />` : ""}${
allowEditing
? forwardRowAction
? `{rowAction && rowAction(params)}`
: `
<IconButton component={StackLink} pageName="edit" payload={params.row.id}>
<Edit color="primary" />
</IconButton>`
: ""
}${
allowCopyPaste || allowDeleting
? `
: ""
}${
allowCopyPaste || allowDeleting
? `
<CrudContextMenu
${
allowCopyPaste
Expand Down Expand Up @@ -595,12 +613,12 @@ export function generateGrid(
refetchQueries={[${instanceGqlTypePlural}Query]}
/>
`
: ""
}
: ""
}
</>
);
},
},`
}`,
})
: ""
}
];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import objectPath from "object-path";

import { GridColumnConfig } from "../generator";
import { ActionsGridColumnConfig, GridColumnConfig } from "../generator";

type FieldsObjectType = { [key: string]: FieldsObjectType | boolean | string };
const recursiveStringify = (obj: FieldsObjectType): string => {
Expand All @@ -21,9 +21,11 @@ const recursiveStringify = (obj: FieldsObjectType): string => {
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function generateGqlFieldList({ columns }: { columns: GridColumnConfig<any>[] }) {
export function generateGqlFieldList({ columns }: { columns: Array<GridColumnConfig<any> | ActionsGridColumnConfig> }) {
const fieldsObject: FieldsObjectType = columns.reduce<FieldsObjectType>((acc, field) => {
objectPath.set(acc, field.name, true);
if (field.type !== "actions") {
objectPath.set(acc, field.name, true);
}
return acc;
}, {});
return recursiveStringify(fieldsObject);
Expand Down
7 changes: 5 additions & 2 deletions packages/admin/cms-admin/src/generator/future/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export type FormConfig<T extends { __typename?: string }> = {

export type TabsConfig = { type: "tabs"; tabs: { name: string; content: GeneratorConfig }[] };

type DataGridSettings = Pick<GridColDef, "headerName" | "width" | "minWidth" | "maxWidth" | "flex">;
export type DataGridSettings = Pick<GridColDef, "headerName" | "width" | "minWidth" | "maxWidth" | "flex">;

export type GridColumnConfig<T> = (
| { type: "text" }
Expand All @@ -79,12 +79,15 @@ export type GridColumnConfig<T> = (
| { type: "staticSelect"; values?: Array<{ value: string; label: string } | string> }
| { type: "block"; block: ImportReference }
) & { name: UsableFields<T> } & DataGridSettings;

export type ActionsGridColumnConfig = { type: "actions"; component?: ImportReference } & DataGridSettings;

export type GridConfig<T extends { __typename?: string }> = {
type: "grid";
gqlType: T["__typename"];
fragmentName?: string;
query?: string;
columns: GridColumnConfig<T>[];
columns: Array<GridColumnConfig<T> | ActionsGridColumnConfig>;
add?: boolean;
edit?: boolean;
delete?: boolean;
Expand Down

0 comments on commit b7646db

Please sign in to comment.