diff --git a/demo/admin/src/common/MasterMenu.tsx b/demo/admin/src/common/MasterMenu.tsx index 9905291e59..562c8f6691 100644 --- a/demo/admin/src/common/MasterMenu.tsx +++ b/demo/admin/src/common/MasterMenu.tsx @@ -32,7 +32,7 @@ import { ProductsPage } from "@src/products/generated/ProductsPage"; import { ManufacturersPage as ManufacturersHandmadePage } from "@src/products/ManufacturersPage"; import ProductsHandmadePage from "@src/products/ProductsPage"; import ProductTagsPage from "@src/products/tags/ProductTagsPage"; -import { WarningsPage } from "@src/warnings/generated/WarningsPage"; +import { WarningsPage } from "@src/warnings/WarningsPage"; import { FormattedMessage } from "react-intl"; import { Redirect, RouteComponentProps } from "react-router-dom"; diff --git a/demo/admin/src/warnings/WarningsGrid.tsx b/demo/admin/src/warnings/WarningsGrid.tsx new file mode 100644 index 0000000000..1bb90e502c --- /dev/null +++ b/demo/admin/src/warnings/WarningsGrid.tsx @@ -0,0 +1,152 @@ +import { gql, useQuery } from "@apollo/client"; +import { + DataGridToolbar, + GridColDef, + GridFilterButton, + MainContent, + muiGridFilterToGql, + muiGridSortToGql, + ToolbarItem, + useBufferedRowCount, + useDataGridRemote, + usePersistentColumnState, +} from "@comet/admin"; +import { WarningSolid } from "@comet/admin-icons"; +import { Chip } from "@mui/material"; +import { DataGrid, GridToolbarQuickFilter } from "@mui/x-data-grid"; +import { GQLWarningLevel } from "@src/graphql.generated"; +import * as React from "react"; +import { FormattedDate, FormattedTime, useIntl } from "react-intl"; + +import { GQLWarningsGridQuery, GQLWarningsGridQueryVariables, GQLWarningsListFragment } from "./WarningsGrid.generated"; + +const warningsFragment = gql` + fragment WarningsList on Warning { + id + createdAt + updatedAt + type + level + state + } +`; + +const warningsQuery = gql` + query WarningsGrid($offset: Int, $limit: Int, $sort: [WarningSort!], $search: String, $filter: WarningFilter) { + warnings(offset: $offset, limit: $limit, sort: $sort, search: $search, filter: $filter) { + nodes { + ...WarningsList + } + totalCount + } + } + ${warningsFragment} +`; + +function WarningsGridToolbar() { + return ( + + + + + + + + + ); +} + +export function WarningsGrid(): React.ReactElement { + const intl = useIntl(); + const dataGridProps = { + ...useDataGridRemote({ initialFilter: { items: [{ columnField: "state", operatorValue: "is", value: "open" }] } }), + ...usePersistentColumnState("WarningsGrid"), + }; + + const columns: GridColDef[] = [ + { + field: "createdAt", + headerName: intl.formatMessage({ id: "warning.dateTime", defaultMessage: "Date / Time" }), + type: "dateTime", + renderCell: (params) => ( + <> + + + ), + width: 200, + }, + { + field: "level", + headerName: intl.formatMessage({ id: "warning.level", defaultMessage: "Level" }), + type: "singleSelect", + valueOptions: [ + { value: "critical", label: intl.formatMessage({ id: "warning.level.critical", defaultMessage: "Critical" }) }, + { value: "high", label: intl.formatMessage({ id: "warning.level.high", defaultMessage: "High" }) }, + { value: "low", label: intl.formatMessage({ id: "warning.level.low", defaultMessage: "Low" }) }, + ], + width: 150, + renderCell: (params) => { + const colorMapping: Record = { + critical: "error", + high: "warning", + low: "default", + }; + return ( + : undefined} + color={colorMapping[params.value as GQLWarningLevel]} + label={params.value} + /> + ); + }, + }, + { + field: "type", + headerName: intl.formatMessage({ id: "warning.type", defaultMessage: "Type" }), + width: 150, + renderCell: (params) => , + }, + { + field: "state", + headerName: intl.formatMessage({ id: "warning.state", defaultMessage: "State" }), + type: "singleSelect", + valueOptions: [ + { value: "open", label: intl.formatMessage({ id: "warning.state.open", defaultMessage: "Open" }) }, + { value: "resolved", label: intl.formatMessage({ id: "warning.state.resolved", defaultMessage: "Resolved" }) }, + { value: "ignored", label: intl.formatMessage({ id: "warning.state.ignored", defaultMessage: "Ignored" }) }, + ], + width: 150, + }, + ]; + + const { filter: gqlFilter, search: gqlSearch } = muiGridFilterToGql(columns, dataGridProps.filterModel); + + const { data, loading, error } = useQuery(warningsQuery, { + variables: { + filter: gqlFilter, + search: gqlSearch, + offset: dataGridProps.page * dataGridProps.pageSize, + limit: dataGridProps.pageSize, + sort: muiGridSortToGql(dataGridProps.sortModel), + }, + }); + const rowCount = useBufferedRowCount(data?.warnings.totalCount); + if (error) throw error; + const rows = data?.warnings.nodes ?? []; + + return ( + + + + ); +} diff --git a/demo/admin/src/warnings/WarningsPage.tsx b/demo/admin/src/warnings/WarningsPage.tsx new file mode 100644 index 0000000000..f1880abe57 --- /dev/null +++ b/demo/admin/src/warnings/WarningsPage.tsx @@ -0,0 +1,14 @@ +import { Stack } from "@comet/admin"; +import * as React from "react"; +import { useIntl } from "react-intl"; + +import { WarningsGrid } from "./WarningsGrid"; + +export function WarningsPage(): React.ReactElement { + const intl = useIntl(); + return ( + + + + ); +} diff --git a/demo/admin/src/warnings/generated/WarningForm.gql.ts b/demo/admin/src/warnings/generated/WarningForm.gql.ts deleted file mode 100644 index 4faa2364ef..0000000000 --- a/demo/admin/src/warnings/generated/WarningForm.gql.ts +++ /dev/null @@ -1,53 +0,0 @@ -// This file has been generated by comet admin-generator. -// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment. - -import { gql } from "@apollo/client"; - -export const warningFormFragment = gql` - fragment WarningForm on Warning { - type - level - state - } -`; - -export const warningFormQuery = gql` - query WarningForm($id: ID!) { - warning(id: $id) { - id - updatedAt - ...WarningForm - } - } - ${warningFormFragment} -`; - -export const warningFormCheckForChangesQuery = gql` - query WarningFormCheckForChanges($id: ID!) { - warning(id: $id) { - updatedAt - } - } -`; - -export const createWarningMutation = gql` - mutation CreateWarning($input: WarningInput!) { - createWarning(input: $input) { - id - updatedAt - ...WarningForm - } - } - ${warningFormFragment} -`; - -export const updateWarningMutation = gql` - mutation UpdateWarning($id: ID!, $input: WarningUpdateInput!) { - updateWarning(id: $id, input: $input) { - id - updatedAt - ...WarningForm - } - } - ${warningFormFragment} -`; diff --git a/demo/admin/src/warnings/generated/WarningForm.tsx b/demo/admin/src/warnings/generated/WarningForm.tsx deleted file mode 100644 index 1b031ed650..0000000000 --- a/demo/admin/src/warnings/generated/WarningForm.tsx +++ /dev/null @@ -1,182 +0,0 @@ -// This file has been generated by comet admin-generator. -// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment. - -import { useApolloClient, useQuery } from "@apollo/client"; -import { - Field, - filterByFragment, - FinalForm, - FinalFormSaveButton, - FinalFormSelect, - FinalFormSubmitEvent, - Loading, - MainContent, - TextField, - Toolbar, - ToolbarActions, - ToolbarFillSpace, - ToolbarItem, - ToolbarTitleItem, - useFormApiRef, - useStackApi, - useStackSwitchApi, -} from "@comet/admin"; -import { ArrowLeft } from "@comet/admin-icons"; -import { ContentScopeIndicator, queryUpdatedAt, resolveHasSaveConflict, useFormSaveConflict } from "@comet/cms-admin"; -import { IconButton, MenuItem } from "@mui/material"; -import { FormApi } from "final-form"; -import React from "react"; -import { FormattedMessage } from "react-intl"; - -import { createWarningMutation, updateWarningMutation, warningFormFragment, warningFormQuery } from "./WarningForm.gql"; -import { - GQLCreateWarningMutation, - GQLCreateWarningMutationVariables, - GQLUpdateWarningMutation, - GQLUpdateWarningMutationVariables, - GQLWarningFormFragment, - GQLWarningFormQuery, - GQLWarningFormQueryVariables, -} from "./WarningForm.gql.generated"; - -type FormValues = GQLWarningFormFragment; - -interface FormProps { - id?: string; -} - -export function WarningForm({ id }: FormProps): React.ReactElement { - const stackApi = useStackApi(); - const client = useApolloClient(); - const mode = id ? "edit" : "add"; - const formApiRef = useFormApiRef(); - const stackSwitchApi = useStackSwitchApi(); - - const { data, error, loading, refetch } = useQuery( - warningFormQuery, - id ? { variables: { id } } : { skip: true }, - ); - - const initialValues = React.useMemo>( - () => - data?.warning - ? { - ...filterByFragment(warningFormFragment, data.warning), - } - : {}, - [data], - ); - - const saveConflict = useFormSaveConflict({ - checkConflict: async () => { - const updatedAt = await queryUpdatedAt(client, "warning", id); - return resolveHasSaveConflict(data?.warning.updatedAt, updatedAt); - }, - formApiRef, - loadLatestVersion: async () => { - await refetch(); - }, - }); - - const handleSubmit = async (state: FormValues, form: FormApi, event: FinalFormSubmitEvent) => { - if (await saveConflict.checkForConflicts()) { - throw new Error("Conflicts detected"); - } - - const output = { - ...state, - }; - - if (mode === "edit") { - if (!id) { - throw new Error("Missing id in edit mode"); - } - await client.mutate({ - mutation: updateWarningMutation, - variables: { id, input: output }, - }); - } else { - const { data: mutationResponse } = await client.mutate({ - mutation: createWarningMutation, - variables: { input: output }, - }); - if (!event.navigatingBack) { - const id = mutationResponse?.createWarning.id; - if (id) { - setTimeout(() => { - stackSwitchApi.activatePage("edit", id); - }); - } - } - } - }; - - if (error) throw error; - - if (loading) { - return ; - } - - return ( - apiRef={formApiRef} onSubmit={handleSubmit} mode={mode} initialValues={initialValues}> - {({ values }) => ( - <> - {saveConflict.dialogs} - }> - - - - - - - - - - - - - - - } - /> - }> - {(props) => ( - - - - - - - - - - - - )} - - }> - {(props) => ( - - - - - - - - - - - - )} - - - - )} - - ); -} diff --git a/demo/admin/src/warnings/generated/WarningsGrid.tsx b/demo/admin/src/warnings/generated/WarningsGrid.tsx deleted file mode 100644 index b5f7552fdb..0000000000 --- a/demo/admin/src/warnings/generated/WarningsGrid.tsx +++ /dev/null @@ -1,206 +0,0 @@ -// This file has been generated by comet admin-generator. -// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment. -import { gql, useApolloClient, useQuery } from "@apollo/client"; -import { - CrudContextMenu, - DataGridToolbar, - GridColDef, - GridFilterButton, - MainContent, - muiGridFilterToGql, - muiGridSortToGql, - StackLink, - ToolbarActions, - ToolbarFillSpace, - ToolbarItem, - useBufferedRowCount, - useDataGridRemote, - usePersistentColumnState, -} from "@comet/admin"; -import { Add as AddIcon, Edit } from "@comet/admin-icons"; -import { Button, IconButton } from "@mui/material"; -import { DataGridPro, GridToolbarQuickFilter } from "@mui/x-data-grid-pro"; -import * as React from "react"; -import { FormattedMessage, useIntl } from "react-intl"; - -import { - GQLCreateWarningMutation, - GQLCreateWarningMutationVariables, - GQLDeleteWarningMutation, - GQLDeleteWarningMutationVariables, - GQLWarningsGridQuery, - GQLWarningsGridQueryVariables, - GQLWarningsListFragment, -} from "./WarningsGrid.generated"; - -const warningsFragment = gql` - fragment WarningsList on Warning { - id - createdAt - updatedAt - type - level - state - } -`; - -const warningsQuery = gql` - query WarningsGrid($offset: Int, $limit: Int, $sort: [WarningSort!], $search: String, $filter: WarningFilter) { - warnings(offset: $offset, limit: $limit, sort: $sort, search: $search, filter: $filter) { - nodes { - ...WarningsList - } - totalCount - } - } - ${warningsFragment} -`; - -const deleteWarningMutation = gql` - mutation DeleteWarning($id: ID!) { - deleteWarning(id: $id) - } -`; - -const createWarningMutation = gql` - mutation CreateWarning($input: WarningInput!) { - createWarning(input: $input) { - id - } - } -`; - -function WarningsGridToolbar() { - return ( - - - - - - - - - - - - - ); -} - -export function WarningsGrid(): React.ReactElement { - const client = useApolloClient(); - const intl = useIntl(); - const dataGridProps = { ...useDataGridRemote(), ...usePersistentColumnState("WarningsGrid") }; - - const columns: GridColDef[] = [ - { - field: "createdAt", - headerName: intl.formatMessage({ id: "warning.createdAt", defaultMessage: "Created At" }), - type: "dateTime", - valueGetter: ({ value }) => value && new Date(value), - width: 150, - }, - { - field: "updatedAt", - headerName: intl.formatMessage({ id: "warning.updatedAt", defaultMessage: "Updated At" }), - type: "dateTime", - valueGetter: ({ value }) => value && new Date(value), - width: 150, - }, - { field: "type", headerName: intl.formatMessage({ id: "warning.type", defaultMessage: "Type" }), width: 150 }, - { - field: "level", - headerName: intl.formatMessage({ id: "warning.level", defaultMessage: "Level" }), - type: "singleSelect", - valueOptions: [ - { value: "critical", label: intl.formatMessage({ id: "warning.level.critical", defaultMessage: "Critical" }) }, - { value: "high", label: intl.formatMessage({ id: "warning.level.high", defaultMessage: "High" }) }, - { value: "low", label: intl.formatMessage({ id: "warning.level.low", defaultMessage: "Low" }) }, - ], - width: 150, - }, - { - field: "state", - headerName: intl.formatMessage({ id: "warning.state", defaultMessage: "State" }), - type: "singleSelect", - valueOptions: [ - { value: "open", label: intl.formatMessage({ id: "warning.state.open", defaultMessage: "Open" }) }, - { value: "resolved", label: intl.formatMessage({ id: "warning.state.resolved", defaultMessage: "Resolved" }) }, - { value: "ignored", label: intl.formatMessage({ id: "warning.state.ignored", defaultMessage: "Ignored" }) }, - ], - width: 150, - }, - { - field: "actions", - headerName: "", - sortable: false, - filterable: false, - type: "actions", - renderCell: (params) => { - return ( - <> - - - - { - const row = params.row; - return { - type: row.type, - level: row.level, - state: row.state, - }; - }} - onPaste={async ({ input }) => { - await client.mutate({ - mutation: createWarningMutation, - variables: { input }, - }); - }} - onDelete={async () => { - await client.mutate({ - mutation: deleteWarningMutation, - variables: { id: params.row.id }, - }); - }} - refetchQueries={[warningsQuery]} - /> - - ); - }, - }, - ]; - - const { filter: gqlFilter, search: gqlSearch } = muiGridFilterToGql(columns, dataGridProps.filterModel); - - const { data, loading, error } = useQuery(warningsQuery, { - variables: { - filter: gqlFilter, - search: gqlSearch, - offset: dataGridProps.page * dataGridProps.pageSize, - limit: dataGridProps.pageSize, - sort: muiGridSortToGql(dataGridProps.sortModel), - }, - }); - const rowCount = useBufferedRowCount(data?.warnings.totalCount); - if (error) throw error; - const rows = data?.warnings.nodes ?? []; - - return ( - - - - ); -} diff --git a/demo/admin/src/warnings/generated/WarningsPage.tsx b/demo/admin/src/warnings/generated/WarningsPage.tsx deleted file mode 100644 index d639b8e19b..0000000000 --- a/demo/admin/src/warnings/generated/WarningsPage.tsx +++ /dev/null @@ -1,30 +0,0 @@ -// This file has been generated by comet admin-generator. -// You may choose to use this file as scaffold by moving this file out of generated folder and removing this comment. - -import { Stack, StackPage, StackSwitch, StackToolbar } from "@comet/admin"; -import { ContentScopeIndicator } from "@comet/cms-admin"; -import * as React from "react"; -import { useIntl } from "react-intl"; - -import { WarningForm } from "./WarningForm"; -import { WarningsGrid } from "./WarningsGrid"; - -export function WarningsPage(): React.ReactElement { - const intl = useIntl(); - return ( - - - - } /> - - - - {(selectedId) => } - - - - - - - ); -}