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))
This commit is contained in:
6
.changeset/silly-feet-sniff.md
Normal file
6
.changeset/silly-feet-sniff.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@medusajs/medusa": patch
|
||||
"@medusajs/dashboard": patch
|
||||
---
|
||||
|
||||
feat(medusa,dashboard): Add support for configurable additional columns in entity views
|
||||
@@ -30,3 +30,16 @@ export function cleanNonValues(obj: Record<string, any>) {
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
@@ -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<TData = any> = (
|
||||
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 (
|
||||
<StatusBadge color={getStatusColor(value)}>
|
||||
|
||||
@@ -257,6 +257,10 @@ export const getTypeInfoFromGraphQLType = (
|
||||
|
||||
type Entities = keyof typeof ENTITY_MAPPINGS
|
||||
|
||||
const ADDITIONAL_ENTITY_TYPES: Partial<Record<Entities, string[]>> = {
|
||||
orders: ["OrderDetail"],
|
||||
}
|
||||
|
||||
export const DEFAULT_COLUMN_ORDERS: Record<Entities, Record<string, number>> = {
|
||||
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<GraphQLObjectType["getFields"]>[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)
|
||||
|
||||
Reference in New Issue
Block a user