Przeglądaj źródła

fix(dashboard): Fix data table component overrides

Michael Bromley 3 miesięcy temu
rodzic
commit
2e9f8629e5

+ 46 - 23
packages/dashboard/src/lib/components/data-table/use-generated-columns.tsx

@@ -5,8 +5,14 @@ import {
     getOperationVariablesFields,
     getTypeFieldInfo,
 } from '@/vdb/framework/document-introspection/get-document-structure.js';
+import {
+    generateDisplayComponentKey,
+    getDisplayComponent,
+} from '@/vdb/framework/extension-api/display-component-extensions.js';
 import { BulkAction } from '@/vdb/framework/extension-api/types/index.js';
 import { api } from '@/vdb/graphql/api.js';
+import { usePageBlock } from '@/vdb/hooks/use-page-block.js';
+import { usePage } from '@/vdb/hooks/use-page.js';
 import { TypedDocumentNode } from '@graphql-typed-document-node/core';
 import { Trans, useLingui } from '@lingui/react/macro';
 import { useMutation } from '@tanstack/react-query';
@@ -82,6 +88,8 @@ export function useGeneratedColumns<T extends TypedDocumentNode<any, any>>({
     columns: Array<AccessorKeyColumnDef<any> | AccessorFnColumnDef<any>>;
     customFieldColumnNames: string[];
 } {
+    const { pageId } = usePage();
+    const pageBlock = usePageBlock();
     const columnHelper = createColumnHelper<PaginatedListItemFields<T>>();
     const allBulkActions = useAllBulkActions(bulkActions ?? []);
 
@@ -106,7 +114,7 @@ export function useGeneratedColumns<T extends TypedDocumentNode<any, any>>({
 
         const queryBasedColumns = columnConfigs.map(({ fieldInfo, isCustomField }) => {
             const customConfig = customizeColumns?.[fieldInfo.name as unknown as AllItemFieldKeys<T>] ?? {};
-            const { header, meta, ...customConfigRest } = customConfig;
+            const { header, meta, cell: customCell, ...customConfigRest } = customConfig;
             const enableColumnFilter = fieldInfo.isScalar && !facetedFilters?.[fieldInfo.name];
 
             return columnHelper.accessor(fieldInfo.name as any, {
@@ -118,35 +126,27 @@ export function useGeneratedColumns<T extends TypedDocumentNode<any, any>>({
                 // otherwise the TanStack Table with apply an "auto" function which somehow
                 // prevents certain filters from working.
                 filterFn: 'equalsString',
-                cell: ({ cell, row }) => {
+                cell: cellContext => {
+                    const { cell, row } = cellContext;
                     const cellValue = cell.getValue();
                     const value =
                         cellValue ??
                         (isCustomField ? row.original?.customFields?.[fieldInfo.name] : undefined);
+                    const displayComponentId =
+                        pageId && pageBlock?.blockId
+                            ? generateDisplayComponentKey(pageId, pageBlock.blockId, fieldInfo.name)
+                            : undefined;
 
-                    if (fieldInfo.list && Array.isArray(value)) {
-                        return value.join(', ');
-                    }
-                    if (
-                        (fieldInfo.type === 'DateTime' && typeof value === 'string') ||
-                        value instanceof Date
-                    ) {
-                        return <DisplayComponent id="vendure:dateTime" value={value} />;
-                    }
-                    if (fieldInfo.type === 'Boolean') {
-                        if (cell.column.id === 'enabled') {
-                            return <DisplayComponent id="vendure:booleanBadge" value={value} />;
-                        } else {
-                            return <DisplayComponent id="vendure:booleanCheckbox" value={value} />;
-                        }
-                    }
-                    if (fieldInfo.type === 'Asset') {
-                        return <DisplayComponent id="vendure:asset" value={value} />;
+                    const CustomDisplayComponent =
+                        displayComponentId && getDisplayComponent(displayComponentId);
+
+                    if (CustomDisplayComponent) {
+                        return <CustomDisplayComponent value={value} {...cellContext} />;
                     }
-                    if (value !== null && typeof value === 'object') {
-                        return <DisplayComponent id="vendure:json" value={value} />;
+                    if (typeof customCell === 'function') {
+                        return customCell(cellContext);
                     }
-                    return value;
+                    return <DefaultDisplayComponent value={value} fieldInfo={fieldInfo} />;
                 },
                 header: headerContext => {
                     return (
@@ -264,6 +264,29 @@ function getRowActions(
     };
 }
 
+function DefaultDisplayComponent({ value, fieldInfo }: { value: any; fieldInfo: FieldInfo }) {
+    if (fieldInfo.list && Array.isArray(value)) {
+        return value.join(', ');
+    }
+    if ((fieldInfo.type === 'DateTime' && typeof value === 'string') || value instanceof Date) {
+        return <DisplayComponent id="vendure:dateTime" value={value} />;
+    }
+    if (fieldInfo.type === 'Boolean') {
+        if (fieldInfo.name === 'enabled') {
+            return <DisplayComponent id="vendure:booleanBadge" value={value} />;
+        } else {
+            return <DisplayComponent id="vendure:booleanCheckbox" value={value} />;
+        }
+    }
+    if (fieldInfo.type === 'Asset') {
+        return <DisplayComponent id="vendure:asset" value={value} />;
+    }
+    if (value !== null && typeof value === 'object') {
+        return <DisplayComponent id="vendure:json" value={value} />;
+    }
+    return value;
+}
+
 function DeleteMutationRowAction({
     deleteMutation,
     row,

+ 3 - 14
packages/dashboard/src/lib/framework/component-registry/component-registry.tsx

@@ -1,24 +1,13 @@
-import {
-    DashboardFormComponent,
-    DashboardFormComponentProps,
-} from '@/vdb/framework/form-engine/form-engine-types.js';
+import { DashboardFormComponent } from '@/vdb/framework/form-engine/form-engine-types.js';
 import * as React from 'react';
 import { getDisplayComponent } from '../extension-api/display-component-extensions.js';
 import { getInputComponent } from '../extension-api/input-component-extensions.js';
 
-export interface ComponentRegistryEntry<Props extends Record<string, any>> {
-    component: React.ComponentType<Props>;
-}
-
-// Display component interface (unchanged)
-export interface DataDisplayComponentProps {
+export type DataDisplayComponentProps<T extends Record<string, any> = Record<string, any>> = {
     value: any;
-
-    [key: string]: any;
-}
+} & T;
 
 export type DataDisplayComponent = React.ComponentType<DataDisplayComponentProps>;
-export type { DashboardFormComponentProps as DataInputComponentProps };
 
 // Component registry hook that uses the global registry
 export function useComponentRegistry() {

+ 5 - 2
packages/dashboard/src/lib/framework/extension-api/types/data-table.ts

@@ -1,5 +1,8 @@
+import { DataDisplayComponentProps } from '@/vdb/framework/component-registry/component-registry.js';
 import { Table } from '@tanstack/react-table';
+import { CellContext } from '@tanstack/table-core';
 import { DocumentNode } from 'graphql';
+import React from 'react';
 
 /**
  * @description
@@ -21,7 +24,7 @@ export interface DashboardDataTableDisplayComponent {
      * The React component that will be rendered as the display.
      * It should accept `value` and other standard display props.
      */
-    component: React.ComponentType<{ value: any; [key: string]: any }>;
+    component: React.ComponentType<DataDisplayComponentProps<CellContext<any, any>>>;
 }
 
 export type BulkActionContext<Item extends { id: string } & Record<string, any>> = {
@@ -120,7 +123,7 @@ export type BulkAction = {
  * This allows you to customize aspects of existing data tables in the dashboard.
  *
  * @docsCategory extensions-api
- * @docsPage DataTable
+ * @docsPage DataTables
  * @since 3.4.0
  */
 export interface DashboardDataTableExtensionDefinition {