From 459fbcdf998a506d80abb758bc7648126c6c96f8 Mon Sep 17 00:00:00 2001 From: docloulou Date: Tue, 14 Oct 2025 14:13:03 +0200 Subject: [PATCH] feat(medusa,dashboard): Add support for configurable additional columns in entity views (#13566) This pull request enhances the entity column generation logic in the admin views by adding support for including fields from additional GraphQL types, specifically for the `orders` entity. The changes allow more flexible and comprehensive column definitions by pulling in fields from related types (like `OrderDetail`) and updating the filtering and type resolution logic accordingly. **This adding payment_status & fulfillment_status from OrderDetail in view configuration feature** **Entity column generation enhancements:** * Added the `ADDITIONAL_ENTITY_TYPES` mapping to specify extra GraphQL types whose fields should be included for certain entities (currently, `OrderDetail` for `orders`). ([packages/medusa/src/api/admin/views/[entity]/columns/helpers.tsR260-R263](diffhunk://#diff-ce197feb4e4d1273d9ee19126e284b65fdb4367f0871774a75add5c8cd749d02R260-R263)) * Updated the column generation process to collect fields from both the main entity type and any additional types, while properly filtering out arrays and excluded fields. ([packages/medusa/src/api/admin/views/[entity]/columns/helpers.tsR340-R345](diffhunk://#diff-ce197feb4e4d1273d9ee19126e284b65fdb4367f0871774a75add5c8cd749d02R340-R345), [packages/medusa/src/api/admin/views/[entity]/columns/helpers.tsR373-R414](diffhunk://#diff-ce197feb4e4d1273d9ee19126e284b65fdb4367f0871774a75add5c8cd749d02R373-R414)) * Changed field lookup logic to use a unified `entityFields` object and a new `additionalFieldDefinitions` map for extra fields, ensuring correct type info resolution for all columns. ([packages/medusa/src/api/admin/views/[entity]/columns/helpers.tsL344-R354](diffhunk://#diff-ce197feb4e4d1273d9ee19126e284b65fdb4367f0871774a75add5c8cd749d02L344-R354), [packages/medusa/src/api/admin/views/[entity]/columns/helpers.tsL411-R463](diffhunk://#diff-ce197feb4e4d1273d9ee19126e284b65fdb4367f0871774a75add5c8cd749d02L411-R463)) --- .changeset/silly-feet-sniff.md | 6 ++ packages/admin/dashboard/src/lib/common.ts | 13 +++++ .../src/lib/table/cell-renderers.tsx | 12 +++- .../admin/views/[entity]/columns/helpers.ts | 57 ++++++++++++++++++- 4 files changed, 83 insertions(+), 5 deletions(-) create mode 100644 .changeset/silly-feet-sniff.md diff --git a/.changeset/silly-feet-sniff.md b/.changeset/silly-feet-sniff.md new file mode 100644 index 0000000000..982ffda690 --- /dev/null +++ b/.changeset/silly-feet-sniff.md @@ -0,0 +1,6 @@ +--- +"@medusajs/medusa": patch +"@medusajs/dashboard": patch +--- + +feat(medusa,dashboard): Add support for configurable additional columns in entity views diff --git a/packages/admin/dashboard/src/lib/common.ts b/packages/admin/dashboard/src/lib/common.ts index f5c786f1e6..50f9abd405 100644 --- a/packages/admin/dashboard/src/lib/common.ts +++ b/packages/admin/dashboard/src/lib/common.ts @@ -30,3 +30,16 @@ export function cleanNonValues(obj: Record) { return ret } + +/** + * Convert a string to camel case + * @param str + * @returns camel case string + */ +export function toCamelCase(str: string): string { + return /^([a-zA-Z]+)(([A-Z]([a-z]+))+)$/.test(str) + ? str + : str + .toLowerCase() + .replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase()) +} diff --git a/packages/admin/dashboard/src/lib/table/cell-renderers.tsx b/packages/admin/dashboard/src/lib/table/cell-renderers.tsx index d5cdc36fbf..d5f91ec76a 100644 --- a/packages/admin/dashboard/src/lib/table/cell-renderers.tsx +++ b/packages/admin/dashboard/src/lib/table/cell-renderers.tsx @@ -13,6 +13,7 @@ import { DisplayIdCell } from "../../components/table/table-cells/order/display- import { TotalCell } from "../../components/table/table-cells/order/total-cell" import { MoneyAmountCell } from "../../components/table/table-cells/common/money-amount-cell" import { TFunction } from "i18next" +import { toCamelCase } from "../common" export type CellRenderer = ( value: any, @@ -71,10 +72,11 @@ const StatusRenderer: CellRenderer = (value, row, column, t) => { } // Use existing translation keys where available - const getTranslatedStatus = (status: string): string => { + const getTranslatedStatus = (status: string, column: HttpTypes.AdminColumn): string => { if (!t) return status const lowerStatus = status.toLowerCase() + const camelCaseStatus = toCamelCase(lowerStatus) switch (lowerStatus) { case 'active': return t('general.active', 'Active') as string @@ -87,12 +89,18 @@ const StatusRenderer: CellRenderer = (value, row, column, t) => { case 'canceled': return t('orders.status.canceled', 'Canceled') as string default: + if (column.context === 'payment') { + return t(`orders.payment.status.${camelCaseStatus}`, status) as string + } + if (column.context === 'fulfillment') { + return t(`orders.fulfillment.status.${camelCaseStatus}`, status) as string + } // Try generic status translation with fallback return t(`status.${lowerStatus}`, status) as string } } - const translatedValue = getTranslatedStatus(value) + const translatedValue = getTranslatedStatus(value, column) return ( diff --git a/packages/medusa/src/api/admin/views/[entity]/columns/helpers.ts b/packages/medusa/src/api/admin/views/[entity]/columns/helpers.ts index 89c8278be4..3884e36a28 100644 --- a/packages/medusa/src/api/admin/views/[entity]/columns/helpers.ts +++ b/packages/medusa/src/api/admin/views/[entity]/columns/helpers.ts @@ -257,6 +257,10 @@ export const getTypeInfoFromGraphQLType = ( type Entities = keyof typeof ENTITY_MAPPINGS +const ADDITIONAL_ENTITY_TYPES: Partial> = { + orders: ["OrderDetail"], +} + export const DEFAULT_COLUMN_ORDERS: Record> = { orders: { display_id: 100, @@ -333,6 +337,12 @@ export const generateEntityColumns = ( entityMapping.graphqlType ] as GraphQLObjectType + const entityFields = entityType?.getFields?.() ?? {} + const additionalFieldDefinitions = new Map< + string, + ReturnType[string] + >() + const allDirectFields = graphqlSchemaToFields( schemaTypeMap, entityMapping.graphqlType, @@ -341,7 +351,7 @@ export const generateEntityColumns = ( // Filter out problematic fields const directFields = allDirectFields.filter((fieldName) => { - const field = entityType?.getFields()[fieldName] + const field = entityFields[fieldName] if (!field) return true const isArray = isArrayField(field.type) @@ -360,6 +370,48 @@ export const generateEntityColumns = ( directFields.unshift("display_id") } + const additionalTypes = ADDITIONAL_ENTITY_TYPES[entity as Entities] ?? [] + + additionalTypes.forEach((typeName) => { + const additionalType = schemaTypeMap[typeName] as + | GraphQLObjectType + | undefined + if (!additionalType) { + return + } + + const additionalFields = graphqlSchemaToFields( + schemaTypeMap, + typeName, + [] + ) + + additionalFields.forEach((fieldName) => { + if (directFields.includes(fieldName)) { + return + } + + const field = additionalType.getFields()[fieldName] + + if (field) { + const isArray = isArrayField(field.type) + if (isArray) { + return + } + } + + if (shouldExcludeField(fieldName, entityMapping.fieldFilters)) { + return + } + + directFields.push(fieldName) + + if (field) { + additionalFieldDefinitions.set(fieldName, field) + } + }) + }) + const relationMap = extractRelationsFromGQL( new Map(Object.entries(schemaTypeMap)) ) @@ -408,8 +460,7 @@ export const generateEntityColumns = ( const directColumns = directFields.map((fieldName) => { const displayName = formatFieldName(fieldName) - const type = schemaTypeMap[entityMapping.graphqlType] as GraphQLObjectType - const fieldDef = type?.getFields()?.[fieldName] + const fieldDef = entityFields[fieldName] || additionalFieldDefinitions.get(fieldName) const typeInfo = fieldDef ? getTypeInfoFromGraphQLType(fieldDef.type, fieldName) : getTypeInfoFromGraphQLType(null, fieldName)