Browse Source

feat(dashboard): Test selective rendering based on schema data type

Michael Bromley 10 months ago
parent
commit
94c081ae28

+ 31 - 21
packages/dashboard/src/framework/internal/document-introspection/get-document-structure.ts

@@ -1,4 +1,10 @@
-import { DocumentNode, OperationDefinitionNode, FieldNode, FragmentDefinitionNode } from 'graphql';
+import {
+    DocumentNode,
+    OperationDefinitionNode,
+    FieldNode,
+    FragmentDefinitionNode,
+    FragmentSpreadNode,
+} from 'graphql';
 import { schemaInfo } from 'virtual:admin-api-schema';
 
 interface FieldInfo {
@@ -38,8 +44,13 @@ export function getListQueryFields(documentNode: DocumentNode): FieldInfo[] {
                     selection => selection.kind === 'Field' && selection.name.value === 'items',
                 ) as FieldNode;
                 const typeName = getPaginatedListType(fieldInfo.name);
+                if (!typeName) {
+                    throw new Error(`Could not determine type of items in ${fieldInfo.name}`);
+                }
                 for (const item of itemsField.selectionSet?.selections ?? []) {
-                    collectFields(typeName, item, fields, fragments);
+                    if (item.kind === 'Field' || item.kind === 'FragmentSpread') {
+                        collectFields(typeName, item, fields, fragments);
+                    }
                 }
             }
         }
@@ -93,12 +104,29 @@ function getObjectFieldInfo(typeName: string, fieldName: string): FieldInfo {
 
 function collectFields(
     typeName: string,
-    fieldNode: FieldNode,
+    fieldNode: FieldNode | FragmentSpreadNode,
     fields: FieldInfo[],
     fragments: Record<string, FragmentDefinitionNode>,
 ) {
     if (fieldNode.kind === 'Field') {
         fields.push(getObjectFieldInfo(typeName, fieldNode.name.value));
+        if (fieldNode.selectionSet) {
+            fieldNode.selectionSet.selections.forEach(subSelection => {
+                if (subSelection.kind === 'Field') {
+                    collectFields(typeName, subSelection, fields, fragments);
+                } else if (subSelection.kind === 'FragmentSpread') {
+                    const fragmentName = subSelection.name.value;
+                    const fragment = fragments[fragmentName];
+                    if (fragment) {
+                        fragment.selectionSet.selections.forEach(fragmentSelection => {
+                            if (fragmentSelection.kind === 'Field') {
+                                collectFields(typeName, fragmentSelection, fields, fragments);
+                            }
+                        });
+                    }
+                }
+            });
+        }
     }
     if (fieldNode.kind === 'FragmentSpread') {
         const fragmentName = fieldNode.name.value;
@@ -111,22 +139,4 @@ function collectFields(
             });
         }
     }
-
-    if (fieldNode.selectionSet) {
-        fieldNode.selectionSet.selections.forEach(subSelection => {
-            if (subSelection.kind === 'Field') {
-                collectFields(typeName, subSelection, fields, fragments);
-            } else if (subSelection.kind === 'FragmentSpread') {
-                const fragmentName = subSelection.name.value;
-                const fragment = fragments[fragmentName];
-                if (fragment) {
-                    fragment.selectionSet.selections.forEach(fragmentSelection => {
-                        if (fragmentSelection.kind === 'Field') {
-                            collectFields(typeName, fragmentSelection, fields, fragments);
-                        }
-                    });
-                }
-            }
-        });
-    }
 }

+ 11 - 0
packages/dashboard/src/framework/internal/page/list-page.tsx

@@ -3,6 +3,7 @@ import {
     getListQueryFields,
     getQueryName,
 } from '@/framework/internal/document-introspection/get-document-structure.js';
+import { DateTime } from '@/framework/internal/type-rendering/date-time.js';
 import { api } from '@/graphql/api.js';
 import { TypedDocumentNode } from '@graphql-typed-document-node/core';
 import { useQuery } from '@tanstack/react-query';
@@ -53,6 +54,16 @@ export function ListPage<T extends TypedDocumentNode<U>, U extends Record<string
         columnHelper.accessor(field.name as any, {
             header: customizeColumns?.[field.name as keyof ListQueryFields<T>]?.header ?? field.name,
             meta: { type: field.type },
+            cell: ({ cell }) => {
+                const value = cell.getValue();
+                if (field.list && Array.isArray(value)) {
+                    return value.join(', ');
+                }
+                if ((field.type === 'DateTime' && typeof value === 'string') || value instanceof Date) {
+                    return <DateTime value={value} />;
+                }
+                return value;
+            },
         }),
     );
 

+ 6 - 0
packages/dashboard/src/framework/internal/type-rendering/date-time.tsx

@@ -0,0 +1,6 @@
+import { useLingui } from '@lingui/react/macro';
+
+export function DateTime({ value }: { value: string | Date }) {
+    const { i18n } = useLingui();
+    return <div>{i18n.date(value)}</div>;
+}