feat(): Translation settings + user configuration + admin hook and js sdk + dashboard (#14355)

* feat(): Translation settings + user configuration

* feat(): Translation settings + user configuration

* Create gentle-bees-grow.md

* add entities end point

* add entities end point

* add admin hook and js sdk method

* update changeset

* fix tests

* fix tests

* rm unnecessary copy

* update dashboard to use the new resources

* update dashboard to use the new resources

* update dashboard to use the new resources

* allow type inference through interface augmentation in the defineConfig of medusa-config

* allow type inference through interface augmentation in the defineConfig of medusa-config

* exclude id and _id props

---------

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2025-12-19 15:29:48 +01:00
committed by GitHub
co-authored by Oli Juhl
parent 797878af26
commit b21a599d11
26 changed files with 1041 additions and 260 deletions
@@ -0,0 +1,90 @@
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
import { ContainerRegistrationKeys } from "@medusajs/framework/utils"
import { HttpTypes } from "@medusajs/types"
export const GET = async (
req: AuthenticatedMedusaRequest<
undefined,
HttpTypes.AdminTranslationEntitiesParams
>,
res: MedusaResponse<HttpTypes.AdminTranslationEntitiesResponse>
) => {
const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
const { type, id } = req.validatedQuery
const {
data: [translationSettings],
} = await query.graph(
{
entity: "translation_settings",
fields: ["*"],
filters: {
entity_type: type,
},
},
{
cache: { enable: true },
}
)
const translatableFields = translationSettings?.fields ?? []
const filters: Record<string, unknown> = {}
if (id) {
filters.id = id
}
const { data: entities = [], metadata } = await query
.graph(
{
entity: type,
fields: ["id", ...translatableFields],
filters,
pagination: req.queryConfig.pagination,
},
{
cache: { enable: true },
}
)
.catch((e) => {
const normalizedMessage = e.message.toLowerCase()
if (
normalizedMessage.includes("service with alias") &&
normalizedMessage.includes("was not found")
) {
return { data: [], metadata: { count: 0, skip: 0, take: 0 } }
}
throw e
})
let aggregatedData =
entities as HttpTypes.AdminTranslationEntitiesResponse["data"]
if (aggregatedData.length) {
const { data: translations } = await query.graph({
entity: "translations",
fields: ["*"],
filters: {
reference_id: aggregatedData.map((entity) => entity.id),
},
})
// aggregate data - include all translations for all locales
aggregatedData = aggregatedData.map((entity) => {
entity.translations = translations.filter(
(translation) => translation.reference_id === entity.id
)
return entity
})
}
return res.json({
data: aggregatedData,
count: metadata?.count ?? 0,
offset: metadata?.skip ?? 0,
limit: metadata?.take ?? 0,
})
}
@@ -6,6 +6,7 @@ import {
import {
AdminBatchTranslations,
AdminGetTranslationsParams,
AdminTranslationEntitiesParams,
AdminTranslationSettingsParams,
AdminTranslationStatistics,
} from "./validators"
@@ -43,4 +44,14 @@ export const adminTranslationsRoutesMiddlewares: MiddlewareRoute[] = [
validateAndTransformQuery(AdminTranslationSettingsParams, {}),
],
},
{
method: ["GET"],
matcher: "/admin/translations/entities",
middlewares: [
validateAndTransformQuery(
AdminTranslationEntitiesParams,
QueryConfig.listTransformQueryConfig
),
],
},
]
@@ -25,12 +25,12 @@ export const GET = async (
const translationService = req.scope.resolve<ITranslationModuleService>(
Modules.TRANSLATION
)
const translatable_fields = translationService.getTranslatableFields(
const translatableFields = await translationService.getTranslatableFields(
req.validatedQuery.entity_type
)
res.json({
translatable_fields,
translatable_fields: translatableFields,
})
}
@@ -71,3 +71,16 @@ export type AdminTranslationSettingsParamsType = z.infer<
export const AdminTranslationSettingsParams = z.object({
entity_type: z.string().optional(),
})
export type AdminTranslationEntitiesParamsType = z.infer<
typeof AdminTranslationEntitiesParams
>
export const AdminTranslationEntitiesParams = createFindParams({
limit: 20,
offset: 0,
}).merge(
z.object({
type: z.string(),
id: z.union([z.string(), z.array(z.string())]).optional(),
})
)