@open-mercato/core 0.6.7-develop.6597.1.b8f069b7fe → 0.6.7-develop.6600.1.49a5df927f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,8 +3,8 @@ const metadata = {
3
3
  requireFeatures: ["attachments.view"],
4
4
  pageTitle: "Attachments",
5
5
  pageTitleKey: "attachments.library.title",
6
- pageGroup: "Storage",
7
- pageGroupKey: "customers.storage.nav.group",
6
+ pageGroup: "Media",
7
+ pageGroupKey: "attachments.nav.group",
8
8
  pagePriority: 20,
9
9
  pageOrder: 110,
10
10
  icon: "archive",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/attachments/backend/storage/attachments/page.meta.ts"],
4
- "sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['attachments.view'],\n pageTitle: 'Attachments',\n pageTitleKey: 'attachments.library.title',\n pageGroup: 'Storage',\n pageGroupKey: 'customers.storage.nav.group',\n pagePriority: 20,\n pageOrder: 110,\n icon: 'archive',\n breadcrumb: [\n { label: 'Attachments', labelKey: 'attachments.library.title' },\n ],\n} as const\n"],
4
+ "sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['attachments.view'],\n pageTitle: 'Attachments',\n pageTitleKey: 'attachments.library.title',\n pageGroup: 'Media',\n pageGroupKey: 'attachments.nav.group',\n pagePriority: 20,\n pageOrder: 110,\n icon: 'archive',\n breadcrumb: [\n { label: 'Attachments', labelKey: 'attachments.library.title' },\n ],\n} as const\n"],
5
5
  "mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,kBAAkB;AAAA,EACpC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,cAAc;AAAA,EACd,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY;AAAA,IACV,EAAE,OAAO,eAAe,UAAU,4BAA4B;AAAA,EAChE;AACF;",
6
6
  "names": []
7
7
  }
@@ -82,7 +82,7 @@ function normalizeGroupWeights(groups) {
82
82
  "staff.nav.group",
83
83
  "entities.nav.group",
84
84
  "directory.nav.group",
85
- "customers.storage.nav.group"
85
+ "attachments.nav.group"
86
86
  ];
87
87
  const groupOrderIndex = new Map(defaultGroupOrder.map((id, index) => [id, index]));
88
88
  groups.sort((a, b) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/lib/backendChrome.tsx"],
4
- "sourcesContent": ["import * as React from 'react'\nimport type { FilterQuery } from '@mikro-orm/core'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { AwilixContainer } from 'awilix'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport type { BackendRouteManifestEntry } from '@open-mercato/shared/modules/registry'\nimport type {\n BackendChromePayload,\n BackendChromeNavGroup,\n BackendChromeNavItem,\n BackendChromeSectionGroup,\n BackendChromeSectionItem,\n} from '@open-mercato/shared/modules/navigation/backendChrome'\nimport {\n buildAdminNav,\n buildSettingsSections,\n computeSettingsPathPrefixes,\n convertToSectionNavGroups,\n type AdminNavItem,\n} from '@open-mercato/ui/backend/utils/nav'\nimport { resolveRegisteredLucideIconNode } from '@open-mercato/ui/backend/icons/lucideRegistry'\nimport { profilePathPrefixes, profileSections } from './profile-sections'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { filterGrantsByEnabledModules } from '@open-mercato/shared/security/enabledModulesRegistry'\nimport {\n getSelectedOrganizationFromRequest,\n resolveFeatureCheckContext,\n} from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { isAllOrganizationsSelection } from '@open-mercato/core/modules/directory/constants'\nimport { Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { CustomEntity } from '@open-mercato/core/modules/entities/data/entities'\nimport { Role } from '@open-mercato/core/modules/auth/data/entities'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n applySidebarPreference,\n loadFirstRoleSidebarPreference,\n loadSidebarPreference,\n} from '@open-mercato/core/modules/auth/services/sidebarPreferencesService'\nimport type { SidebarPreferencesSettings } from '@open-mercato/shared/modules/navigation/sidebarPreferences'\n\ntype TranslationFn = (key: string | undefined, fallback: string) => string\n\ntype RouteModule = {\n id: string\n backendRoutes?: BackendRouteManifestEntry[]\n}\n\nexport function groupBackendRoutesByModule(routes: BackendRouteManifestEntry[]): RouteModule[] {\n return Array.from(\n routes.reduce((grouped, route) => {\n const list = grouped.get(route.moduleId) ?? []\n list.push(route)\n grouped.set(route.moduleId, list)\n return grouped\n }, new Map<string, BackendRouteManifestEntry[]>()),\n ).map(([id, backendRoutes]) => ({ id, backendRoutes }))\n}\n\ntype SerializableSectionItem = {\n id: string\n label: string\n labelKey?: string\n href: string\n icon?: React.ReactNode\n order?: number\n children?: SerializableSectionItem[]\n}\n\ntype SerializableSectionGroup = {\n id: string\n label: string\n labelKey?: string\n order?: number\n items: SerializableSectionItem[]\n}\n\ntype ResolvedNavItem = Omit<BackendChromeNavItem, 'defaultTitle' | 'children'> & {\n defaultTitle: string\n children?: ResolvedNavItem[]\n}\n\ntype ResolveBackendChromePayloadArgs = {\n auth: Exclude<AuthContext, null>\n locale: string\n modules: RouteModule[]\n translate: TranslationFn\n request?: Request\n selectedOrganizationId?: string | null\n selectedTenantId?: string | null\n}\n\nconst settingsSectionOrder: Record<string, number> = {\n system: 1,\n auth: 2,\n 'customer-portal': 3,\n 'data-designer': 4,\n 'module-configs': 5,\n currencies: 6,\n directory: 7,\n 'feature-toggles': 8,\n}\n\ntype NavGroupWithWeight = Omit<BackendChromeNavGroup, 'id' | 'defaultName' | 'items'> & {\n id: string\n defaultName: string\n items: ResolvedNavItem[]\n weight: number\n}\n\nlet renderToStaticMarkupPromise: Promise<typeof import('react-dom/server')> | null = null\n\nasync function serializeIconMarkup(icon: React.ReactNode | undefined): Promise<string | undefined> {\n if (!icon) return undefined\n if (!renderToStaticMarkupPromise) {\n renderToStaticMarkupPromise = import('react-dom/server')\n }\n const { renderToStaticMarkup } = await renderToStaticMarkupPromise\n\n const normalizedIcon = typeof icon === 'string'\n ? resolveRegisteredLucideIconNode(icon, 'size-4')\n : icon\n\n if (!normalizedIcon) return undefined\n\n try {\n const markup = renderToStaticMarkup(<>{normalizedIcon}</>)\n return markup.trim().length > 0 ? markup : undefined\n } catch {\n // Some icon values may be client-only component references after dependency upgrades.\n // Avoid taking down the entire nav payload because one icon cannot be rendered server-side.\n return undefined\n }\n}\n\nasync function serializeNavItem(item: AdminNavItem): Promise<ResolvedNavItem> {\n return {\n id: item.href,\n href: item.href,\n title: item.title,\n defaultTitle: item.defaultTitle,\n enabled: item.enabled,\n hidden: item.hidden,\n pageContext: item.pageContext,\n iconName: typeof item.icon === 'string' ? item.icon : undefined,\n iconMarkup: await serializeIconMarkup(item.icon),\n children: item.children ? await Promise.all(item.children.map((child) => serializeNavItem(child))) : undefined,\n }\n}\n\nfunction normalizeGroupWeights(groups: NavGroupWithWeight[]): NavGroupWithWeight[] {\n const defaultGroupOrder = [\n 'customers.nav.group',\n 'catalog.nav.group',\n 'customers~sales.nav.group',\n 'resources.nav.group',\n 'staff.nav.group',\n 'entities.nav.group',\n 'directory.nav.group',\n 'customers.storage.nav.group',\n ]\n const groupOrderIndex = new Map(defaultGroupOrder.map((id, index) => [id, index]))\n groups.sort((a, b) => {\n const aIndex = groupOrderIndex.get(a.id)\n const bIndex = groupOrderIndex.get(b.id)\n if (aIndex !== undefined || bIndex !== undefined) {\n if (aIndex === undefined) return 1\n if (bIndex === undefined) return -1\n if (aIndex !== bIndex) return aIndex - bIndex\n }\n if (a.weight !== b.weight) return a.weight - b.weight\n return a.name.localeCompare(b.name)\n })\n const defaultGroupCount = defaultGroupOrder.length\n groups.forEach((group, index) => {\n const rank = groupOrderIndex.get(group.id)\n const fallbackWeight = typeof group.weight === 'number' ? group.weight : 10_000\n group.weight =\n (rank !== undefined ? rank : defaultGroupCount + index) * 1_000_000 +\n Math.min(Math.max(fallbackWeight, 0), 999_999)\n })\n return groups\n}\n\nasync function groupEntries(entries: AdminNavItem[]): Promise<NavGroupWithWeight[]> {\n const groupMap = new Map<string, NavGroupWithWeight>()\n for (const entry of entries) {\n const weight = entry.priority ?? entry.order ?? 10_000\n const serializedItem = await serializeNavItem(entry)\n const existing = groupMap.get(entry.groupId)\n if (existing) {\n existing.items.push(serializedItem)\n if (weight < existing.weight) existing.weight = weight\n continue\n }\n groupMap.set(entry.groupId, {\n id: entry.groupId,\n name: entry.group,\n defaultName: entry.groupDefaultName,\n items: [serializedItem],\n weight,\n })\n }\n return normalizeGroupWeights(Array.from(groupMap.values()))\n}\n\nfunction adoptSidebarDefaults(groups: NavGroupWithWeight[]): NavGroupWithWeight[] {\n const adoptItems = (items: ResolvedNavItem[]): ResolvedNavItem[] =>\n items.map((item) => ({\n ...item,\n defaultTitle: item.title,\n children: item.children ? adoptItems(item.children) : undefined,\n }))\n\n return groups.map((group) => ({\n ...group,\n defaultName: group.name,\n items: adoptItems(group.items),\n }))\n}\n\nasync function serializeSectionItem(item: {\n id: string\n label: string\n labelKey?: string\n href: string\n icon?: React.ReactNode\n order?: number\n children?: SerializableSectionItem[]\n}): Promise<BackendChromeSectionItem> {\n return {\n id: item.id,\n label: item.label,\n labelKey: item.labelKey,\n href: item.href,\n order: item.order,\n iconName: typeof item.icon === 'string' ? item.icon : undefined,\n iconMarkup: await serializeIconMarkup(item.icon),\n children: item.children ? await Promise.all(item.children.map((child) => serializeSectionItem(child))) : undefined,\n }\n}\n\nasync function serializeSectionGroups(groups: SerializableSectionGroup[]): Promise<BackendChromeSectionGroup[]> {\n return Promise.all(groups.map(async (group) => ({\n id: group.id,\n label: group.label,\n labelKey: group.labelKey,\n order: group.order,\n items: await Promise.all(group.items.map((item) => serializeSectionItem(item))),\n })))\n}\n\nasync function loadScopedContainer(): Promise<AwilixContainer> {\n return createRequestContainer()\n}\n\nexport async function resolveBackendChromePayload({\n auth,\n locale,\n modules,\n translate,\n request,\n selectedOrganizationId,\n selectedTenantId,\n}: ResolveBackendChromePayloadArgs): Promise<BackendChromePayload> {\n const container = await loadScopedContainer()\n const em = container.resolve('em') as EntityManager\n const rbac = container.resolve('rbacService') as {\n loadAcl: (userId: string, scope: { tenantId: string | null; organizationId: string | null }) => Promise<{\n isSuperAdmin: boolean\n features: string[]\n }>\n userHasAllFeatures: (userId: string, required: string[], scope: { tenantId: string | null; organizationId: string | null }) => Promise<boolean>\n }\n\n let scopedOrganizationId: string | null = auth.orgId ?? null\n let scopedTenantId: string | null = auth.tenantId ?? null\n let allowNavigation = true\n\n try {\n const { organizationId, scope, allowedOrganizationIds } = await resolveFeatureCheckContext({\n container,\n auth,\n request,\n selectedId: selectedOrganizationId,\n tenantId: selectedTenantId,\n })\n scopedOrganizationId = organizationId\n scopedTenantId = scope.tenantId ?? auth.tenantId ?? null\n if (Array.isArray(allowedOrganizationIds) && allowedOrganizationIds.length === 0) {\n allowNavigation = false\n }\n } catch {\n scopedOrganizationId = auth.orgId ?? null\n scopedTenantId = auth.tenantId ?? null\n }\n\n const acl = allowNavigation\n ? await rbac.loadAcl(auth.sub, {\n tenantId: scopedTenantId,\n organizationId: scopedOrganizationId,\n })\n : { isSuperAdmin: false, features: [] }\n\n const rawGrantedFeatures = acl.isSuperAdmin ? ['*'] : acl.features\n const grantedFeatures = filterGrantsByEnabledModules(rawGrantedFeatures)\n const featureChecker = async (features: string[]): Promise<string[]> => {\n if (!allowNavigation || !features.length) return []\n const context = {\n tenantId: scopedTenantId ?? auth.tenantId ?? null,\n organizationId: scopedOrganizationId ?? null,\n }\n const hasAll = await rbac.userHasAllFeatures(auth.sub, features, context)\n if (hasAll) return features\n\n const granted: string[] = []\n for (const feature of features) {\n const hasFeature = await rbac.userHasAllFeatures(auth.sub, [feature], context)\n if (hasFeature) granted.push(feature)\n }\n return granted\n }\n\n let userEntities: Array<{ entityId: string; label: string; href: string }> = []\n if (allowNavigation) {\n try {\n const where: FilterQuery<CustomEntity> = {\n isActive: true,\n showInSidebar: true,\n }\n where.$and = [\n { $or: [{ organizationId: scopedOrganizationId ?? undefined }, { organizationId: null }] },\n { $or: [{ tenantId: scopedTenantId ?? undefined }, { tenantId: null }] },\n ]\n const entities = await em.find(CustomEntity, where, { orderBy: { label: 'asc' } })\n userEntities = entities.map((entity) => ({\n entityId: entity.entityId,\n label: entity.label,\n href: `/backend/entities/user/${encodeURIComponent(entity.entityId)}/records`,\n }))\n } catch {\n userEntities = []\n }\n }\n\n const ctxAuth = {\n roles: auth.roles || [],\n sub: auth.sub,\n tenantId: scopedTenantId,\n orgId: scopedOrganizationId,\n }\n const entries = allowNavigation\n ? await buildAdminNav(\n modules,\n { auth: ctxAuth },\n userEntities,\n translate,\n { checkFeatures: featureChecker },\n )\n : []\n\n let rolePreference: SidebarPreferencesSettings | null = null\n let userPreference: SidebarPreferencesSettings | null = null\n\n if (Array.isArray(auth.roles) && auth.roles.length > 0) {\n const roleRecords = scopedTenantId\n ? await em.find(Role, {\n name: { $in: auth.roles },\n tenantId: scopedTenantId,\n })\n : []\n const roleIds = Array.isArray(roleRecords) ? roleRecords.map((role) => role.id) : []\n if (roleIds.length > 0) {\n rolePreference = await loadFirstRoleSidebarPreference(em, {\n roleIds,\n tenantId: scopedTenantId,\n locale,\n })\n }\n }\n\n const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub\n if (effectiveUserId) {\n userPreference = await loadSidebarPreference(em, {\n userId: effectiveUserId,\n tenantId: scopedTenantId,\n organizationId: scopedOrganizationId,\n locale,\n })\n }\n\n const baseGroups = await groupEntries(entries)\n const groupsWithRole = rolePreference\n ? applySidebarPreference<NavGroupWithWeight>(baseGroups, rolePreference)\n : baseGroups\n const baseForUser = adoptSidebarDefaults(groupsWithRole)\n const appliedGroups = userPreference\n ? applySidebarPreference<NavGroupWithWeight>(baseForUser, userPreference)\n : baseForUser\n\n const settingsSections = await serializeSectionGroups(\n convertToSectionNavGroups(\n buildSettingsSections(entries, settingsSectionOrder),\n translate,\n ),\n )\n\n const requestOrganizationId = request ? getSelectedOrganizationFromRequest(request) : null\n const fallbackOrganizationId = selectedOrganizationId ?? requestOrganizationId ?? auth.orgId ?? null\n const brandOrganizationId = scopedOrganizationId\n ?? (fallbackOrganizationId && !isAllOrganizationsSelection(fallbackOrganizationId) ? fallbackOrganizationId : null)\n\n let brand: BackendChromePayload['brand'] = null\n if (brandOrganizationId && scopedTenantId) {\n try {\n const organization = await findOneWithDecryption(\n em,\n Organization,\n { id: brandOrganizationId, tenant: scopedTenantId, deletedAt: null },\n undefined,\n { tenantId: scopedTenantId, organizationId: brandOrganizationId },\n )\n if (organization?.logoUrl) {\n brand = {\n name: organization.name,\n logo: {\n src: organization.logoUrl,\n alt: `${organization.name} logo`,\n },\n }\n }\n } catch {\n brand = null\n }\n }\n\n return {\n groups: appliedGroups.map(({ weight: _weight, ...group }) => group),\n settingsSections,\n settingsPathPrefixes: computeSettingsPathPrefixes(buildSettingsSections(entries, settingsSectionOrder)),\n profileSections: await serializeSectionGroups(profileSections),\n profilePathPrefixes,\n grantedFeatures,\n roles: Array.isArray(auth.roles) ? auth.roles : [],\n brand,\n }\n}\n"],
4
+ "sourcesContent": ["import * as React from 'react'\nimport type { FilterQuery } from '@mikro-orm/core'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { AwilixContainer } from 'awilix'\nimport type { AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport type { BackendRouteManifestEntry } from '@open-mercato/shared/modules/registry'\nimport type {\n BackendChromePayload,\n BackendChromeNavGroup,\n BackendChromeNavItem,\n BackendChromeSectionGroup,\n BackendChromeSectionItem,\n} from '@open-mercato/shared/modules/navigation/backendChrome'\nimport {\n buildAdminNav,\n buildSettingsSections,\n computeSettingsPathPrefixes,\n convertToSectionNavGroups,\n type AdminNavItem,\n} from '@open-mercato/ui/backend/utils/nav'\nimport { resolveRegisteredLucideIconNode } from '@open-mercato/ui/backend/icons/lucideRegistry'\nimport { profilePathPrefixes, profileSections } from './profile-sections'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { filterGrantsByEnabledModules } from '@open-mercato/shared/security/enabledModulesRegistry'\nimport {\n getSelectedOrganizationFromRequest,\n resolveFeatureCheckContext,\n} from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { isAllOrganizationsSelection } from '@open-mercato/core/modules/directory/constants'\nimport { Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { CustomEntity } from '@open-mercato/core/modules/entities/data/entities'\nimport { Role } from '@open-mercato/core/modules/auth/data/entities'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n applySidebarPreference,\n loadFirstRoleSidebarPreference,\n loadSidebarPreference,\n} from '@open-mercato/core/modules/auth/services/sidebarPreferencesService'\nimport type { SidebarPreferencesSettings } from '@open-mercato/shared/modules/navigation/sidebarPreferences'\n\ntype TranslationFn = (key: string | undefined, fallback: string) => string\n\ntype RouteModule = {\n id: string\n backendRoutes?: BackendRouteManifestEntry[]\n}\n\nexport function groupBackendRoutesByModule(routes: BackendRouteManifestEntry[]): RouteModule[] {\n return Array.from(\n routes.reduce((grouped, route) => {\n const list = grouped.get(route.moduleId) ?? []\n list.push(route)\n grouped.set(route.moduleId, list)\n return grouped\n }, new Map<string, BackendRouteManifestEntry[]>()),\n ).map(([id, backendRoutes]) => ({ id, backendRoutes }))\n}\n\ntype SerializableSectionItem = {\n id: string\n label: string\n labelKey?: string\n href: string\n icon?: React.ReactNode\n order?: number\n children?: SerializableSectionItem[]\n}\n\ntype SerializableSectionGroup = {\n id: string\n label: string\n labelKey?: string\n order?: number\n items: SerializableSectionItem[]\n}\n\ntype ResolvedNavItem = Omit<BackendChromeNavItem, 'defaultTitle' | 'children'> & {\n defaultTitle: string\n children?: ResolvedNavItem[]\n}\n\ntype ResolveBackendChromePayloadArgs = {\n auth: Exclude<AuthContext, null>\n locale: string\n modules: RouteModule[]\n translate: TranslationFn\n request?: Request\n selectedOrganizationId?: string | null\n selectedTenantId?: string | null\n}\n\nconst settingsSectionOrder: Record<string, number> = {\n system: 1,\n auth: 2,\n 'customer-portal': 3,\n 'data-designer': 4,\n 'module-configs': 5,\n currencies: 6,\n directory: 7,\n 'feature-toggles': 8,\n}\n\ntype NavGroupWithWeight = Omit<BackendChromeNavGroup, 'id' | 'defaultName' | 'items'> & {\n id: string\n defaultName: string\n items: ResolvedNavItem[]\n weight: number\n}\n\nlet renderToStaticMarkupPromise: Promise<typeof import('react-dom/server')> | null = null\n\nasync function serializeIconMarkup(icon: React.ReactNode | undefined): Promise<string | undefined> {\n if (!icon) return undefined\n if (!renderToStaticMarkupPromise) {\n renderToStaticMarkupPromise = import('react-dom/server')\n }\n const { renderToStaticMarkup } = await renderToStaticMarkupPromise\n\n const normalizedIcon = typeof icon === 'string'\n ? resolveRegisteredLucideIconNode(icon, 'size-4')\n : icon\n\n if (!normalizedIcon) return undefined\n\n try {\n const markup = renderToStaticMarkup(<>{normalizedIcon}</>)\n return markup.trim().length > 0 ? markup : undefined\n } catch {\n // Some icon values may be client-only component references after dependency upgrades.\n // Avoid taking down the entire nav payload because one icon cannot be rendered server-side.\n return undefined\n }\n}\n\nasync function serializeNavItem(item: AdminNavItem): Promise<ResolvedNavItem> {\n return {\n id: item.href,\n href: item.href,\n title: item.title,\n defaultTitle: item.defaultTitle,\n enabled: item.enabled,\n hidden: item.hidden,\n pageContext: item.pageContext,\n iconName: typeof item.icon === 'string' ? item.icon : undefined,\n iconMarkup: await serializeIconMarkup(item.icon),\n children: item.children ? await Promise.all(item.children.map((child) => serializeNavItem(child))) : undefined,\n }\n}\n\nfunction normalizeGroupWeights(groups: NavGroupWithWeight[]): NavGroupWithWeight[] {\n const defaultGroupOrder = [\n 'customers.nav.group',\n 'catalog.nav.group',\n 'customers~sales.nav.group',\n 'resources.nav.group',\n 'staff.nav.group',\n 'entities.nav.group',\n 'directory.nav.group',\n 'attachments.nav.group',\n ]\n const groupOrderIndex = new Map(defaultGroupOrder.map((id, index) => [id, index]))\n groups.sort((a, b) => {\n const aIndex = groupOrderIndex.get(a.id)\n const bIndex = groupOrderIndex.get(b.id)\n if (aIndex !== undefined || bIndex !== undefined) {\n if (aIndex === undefined) return 1\n if (bIndex === undefined) return -1\n if (aIndex !== bIndex) return aIndex - bIndex\n }\n if (a.weight !== b.weight) return a.weight - b.weight\n return a.name.localeCompare(b.name)\n })\n const defaultGroupCount = defaultGroupOrder.length\n groups.forEach((group, index) => {\n const rank = groupOrderIndex.get(group.id)\n const fallbackWeight = typeof group.weight === 'number' ? group.weight : 10_000\n group.weight =\n (rank !== undefined ? rank : defaultGroupCount + index) * 1_000_000 +\n Math.min(Math.max(fallbackWeight, 0), 999_999)\n })\n return groups\n}\n\nasync function groupEntries(entries: AdminNavItem[]): Promise<NavGroupWithWeight[]> {\n const groupMap = new Map<string, NavGroupWithWeight>()\n for (const entry of entries) {\n const weight = entry.priority ?? entry.order ?? 10_000\n const serializedItem = await serializeNavItem(entry)\n const existing = groupMap.get(entry.groupId)\n if (existing) {\n existing.items.push(serializedItem)\n if (weight < existing.weight) existing.weight = weight\n continue\n }\n groupMap.set(entry.groupId, {\n id: entry.groupId,\n name: entry.group,\n defaultName: entry.groupDefaultName,\n items: [serializedItem],\n weight,\n })\n }\n return normalizeGroupWeights(Array.from(groupMap.values()))\n}\n\nfunction adoptSidebarDefaults(groups: NavGroupWithWeight[]): NavGroupWithWeight[] {\n const adoptItems = (items: ResolvedNavItem[]): ResolvedNavItem[] =>\n items.map((item) => ({\n ...item,\n defaultTitle: item.title,\n children: item.children ? adoptItems(item.children) : undefined,\n }))\n\n return groups.map((group) => ({\n ...group,\n defaultName: group.name,\n items: adoptItems(group.items),\n }))\n}\n\nasync function serializeSectionItem(item: {\n id: string\n label: string\n labelKey?: string\n href: string\n icon?: React.ReactNode\n order?: number\n children?: SerializableSectionItem[]\n}): Promise<BackendChromeSectionItem> {\n return {\n id: item.id,\n label: item.label,\n labelKey: item.labelKey,\n href: item.href,\n order: item.order,\n iconName: typeof item.icon === 'string' ? item.icon : undefined,\n iconMarkup: await serializeIconMarkup(item.icon),\n children: item.children ? await Promise.all(item.children.map((child) => serializeSectionItem(child))) : undefined,\n }\n}\n\nasync function serializeSectionGroups(groups: SerializableSectionGroup[]): Promise<BackendChromeSectionGroup[]> {\n return Promise.all(groups.map(async (group) => ({\n id: group.id,\n label: group.label,\n labelKey: group.labelKey,\n order: group.order,\n items: await Promise.all(group.items.map((item) => serializeSectionItem(item))),\n })))\n}\n\nasync function loadScopedContainer(): Promise<AwilixContainer> {\n return createRequestContainer()\n}\n\nexport async function resolveBackendChromePayload({\n auth,\n locale,\n modules,\n translate,\n request,\n selectedOrganizationId,\n selectedTenantId,\n}: ResolveBackendChromePayloadArgs): Promise<BackendChromePayload> {\n const container = await loadScopedContainer()\n const em = container.resolve('em') as EntityManager\n const rbac = container.resolve('rbacService') as {\n loadAcl: (userId: string, scope: { tenantId: string | null; organizationId: string | null }) => Promise<{\n isSuperAdmin: boolean\n features: string[]\n }>\n userHasAllFeatures: (userId: string, required: string[], scope: { tenantId: string | null; organizationId: string | null }) => Promise<boolean>\n }\n\n let scopedOrganizationId: string | null = auth.orgId ?? null\n let scopedTenantId: string | null = auth.tenantId ?? null\n let allowNavigation = true\n\n try {\n const { organizationId, scope, allowedOrganizationIds } = await resolveFeatureCheckContext({\n container,\n auth,\n request,\n selectedId: selectedOrganizationId,\n tenantId: selectedTenantId,\n })\n scopedOrganizationId = organizationId\n scopedTenantId = scope.tenantId ?? auth.tenantId ?? null\n if (Array.isArray(allowedOrganizationIds) && allowedOrganizationIds.length === 0) {\n allowNavigation = false\n }\n } catch {\n scopedOrganizationId = auth.orgId ?? null\n scopedTenantId = auth.tenantId ?? null\n }\n\n const acl = allowNavigation\n ? await rbac.loadAcl(auth.sub, {\n tenantId: scopedTenantId,\n organizationId: scopedOrganizationId,\n })\n : { isSuperAdmin: false, features: [] }\n\n const rawGrantedFeatures = acl.isSuperAdmin ? ['*'] : acl.features\n const grantedFeatures = filterGrantsByEnabledModules(rawGrantedFeatures)\n const featureChecker = async (features: string[]): Promise<string[]> => {\n if (!allowNavigation || !features.length) return []\n const context = {\n tenantId: scopedTenantId ?? auth.tenantId ?? null,\n organizationId: scopedOrganizationId ?? null,\n }\n const hasAll = await rbac.userHasAllFeatures(auth.sub, features, context)\n if (hasAll) return features\n\n const granted: string[] = []\n for (const feature of features) {\n const hasFeature = await rbac.userHasAllFeatures(auth.sub, [feature], context)\n if (hasFeature) granted.push(feature)\n }\n return granted\n }\n\n let userEntities: Array<{ entityId: string; label: string; href: string }> = []\n if (allowNavigation) {\n try {\n const where: FilterQuery<CustomEntity> = {\n isActive: true,\n showInSidebar: true,\n }\n where.$and = [\n { $or: [{ organizationId: scopedOrganizationId ?? undefined }, { organizationId: null }] },\n { $or: [{ tenantId: scopedTenantId ?? undefined }, { tenantId: null }] },\n ]\n const entities = await em.find(CustomEntity, where, { orderBy: { label: 'asc' } })\n userEntities = entities.map((entity) => ({\n entityId: entity.entityId,\n label: entity.label,\n href: `/backend/entities/user/${encodeURIComponent(entity.entityId)}/records`,\n }))\n } catch {\n userEntities = []\n }\n }\n\n const ctxAuth = {\n roles: auth.roles || [],\n sub: auth.sub,\n tenantId: scopedTenantId,\n orgId: scopedOrganizationId,\n }\n const entries = allowNavigation\n ? await buildAdminNav(\n modules,\n { auth: ctxAuth },\n userEntities,\n translate,\n { checkFeatures: featureChecker },\n )\n : []\n\n let rolePreference: SidebarPreferencesSettings | null = null\n let userPreference: SidebarPreferencesSettings | null = null\n\n if (Array.isArray(auth.roles) && auth.roles.length > 0) {\n const roleRecords = scopedTenantId\n ? await em.find(Role, {\n name: { $in: auth.roles },\n tenantId: scopedTenantId,\n })\n : []\n const roleIds = Array.isArray(roleRecords) ? roleRecords.map((role) => role.id) : []\n if (roleIds.length > 0) {\n rolePreference = await loadFirstRoleSidebarPreference(em, {\n roleIds,\n tenantId: scopedTenantId,\n locale,\n })\n }\n }\n\n const effectiveUserId = auth.isApiKey ? auth.userId : auth.sub\n if (effectiveUserId) {\n userPreference = await loadSidebarPreference(em, {\n userId: effectiveUserId,\n tenantId: scopedTenantId,\n organizationId: scopedOrganizationId,\n locale,\n })\n }\n\n const baseGroups = await groupEntries(entries)\n const groupsWithRole = rolePreference\n ? applySidebarPreference<NavGroupWithWeight>(baseGroups, rolePreference)\n : baseGroups\n const baseForUser = adoptSidebarDefaults(groupsWithRole)\n const appliedGroups = userPreference\n ? applySidebarPreference<NavGroupWithWeight>(baseForUser, userPreference)\n : baseForUser\n\n const settingsSections = await serializeSectionGroups(\n convertToSectionNavGroups(\n buildSettingsSections(entries, settingsSectionOrder),\n translate,\n ),\n )\n\n const requestOrganizationId = request ? getSelectedOrganizationFromRequest(request) : null\n const fallbackOrganizationId = selectedOrganizationId ?? requestOrganizationId ?? auth.orgId ?? null\n const brandOrganizationId = scopedOrganizationId\n ?? (fallbackOrganizationId && !isAllOrganizationsSelection(fallbackOrganizationId) ? fallbackOrganizationId : null)\n\n let brand: BackendChromePayload['brand'] = null\n if (brandOrganizationId && scopedTenantId) {\n try {\n const organization = await findOneWithDecryption(\n em,\n Organization,\n { id: brandOrganizationId, tenant: scopedTenantId, deletedAt: null },\n undefined,\n { tenantId: scopedTenantId, organizationId: brandOrganizationId },\n )\n if (organization?.logoUrl) {\n brand = {\n name: organization.name,\n logo: {\n src: organization.logoUrl,\n alt: `${organization.name} logo`,\n },\n }\n }\n } catch {\n brand = null\n }\n }\n\n return {\n groups: appliedGroups.map(({ weight: _weight, ...group }) => group),\n settingsSections,\n settingsPathPrefixes: computeSettingsPathPrefixes(buildSettingsSections(entries, settingsSectionOrder)),\n profileSections: await serializeSectionGroups(profileSections),\n profilePathPrefixes,\n grantedFeatures,\n roles: Array.isArray(auth.roles) ? auth.roles : [],\n brand,\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.7-develop.6597.1.b8f069b7fe",
3
+ "version": "0.6.7-develop.6600.1.49a5df927f",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -254,16 +254,16 @@
254
254
  "zod": "^4.4.3"
255
255
  },
256
256
  "peerDependencies": {
257
- "@open-mercato/ai-assistant": "0.6.7-develop.6597.1.b8f069b7fe",
258
- "@open-mercato/shared": "0.6.7-develop.6597.1.b8f069b7fe",
259
- "@open-mercato/ui": "0.6.7-develop.6597.1.b8f069b7fe",
257
+ "@open-mercato/ai-assistant": "0.6.7-develop.6600.1.49a5df927f",
258
+ "@open-mercato/shared": "0.6.7-develop.6600.1.49a5df927f",
259
+ "@open-mercato/ui": "0.6.7-develop.6600.1.49a5df927f",
260
260
  "react": "^19.0.0",
261
261
  "react-dom": "^19.0.0"
262
262
  },
263
263
  "devDependencies": {
264
- "@open-mercato/ai-assistant": "0.6.7-develop.6597.1.b8f069b7fe",
265
- "@open-mercato/shared": "0.6.7-develop.6597.1.b8f069b7fe",
266
- "@open-mercato/ui": "0.6.7-develop.6597.1.b8f069b7fe",
264
+ "@open-mercato/ai-assistant": "0.6.7-develop.6600.1.49a5df927f",
265
+ "@open-mercato/shared": "0.6.7-develop.6600.1.49a5df927f",
266
+ "@open-mercato/ui": "0.6.7-develop.6600.1.49a5df927f",
267
267
  "@testing-library/dom": "^10.4.1",
268
268
  "@testing-library/jest-dom": "^6.9.1",
269
269
  "@testing-library/react": "^16.3.1",
@@ -3,8 +3,8 @@ export const metadata = {
3
3
  requireFeatures: ['attachments.view'],
4
4
  pageTitle: 'Attachments',
5
5
  pageTitleKey: 'attachments.library.title',
6
- pageGroup: 'Storage',
7
- pageGroupKey: 'customers.storage.nav.group',
6
+ pageGroup: 'Media',
7
+ pageGroupKey: 'attachments.nav.group',
8
8
  pagePriority: 20,
9
9
  pageOrder: 110,
10
10
  icon: 'archive',
@@ -1,5 +1,4 @@
1
1
  {
2
- "attachments.customers.storage.nav.group": "Speicher",
3
2
  "attachments.errors.activeContentBlocked": "Das Hochladen aktiver Inhalte ist nicht erlaubt.",
4
3
  "attachments.errors.dangerousExecutable": "Ausführbare Dateitypen sind als Anhänge nicht erlaubt.",
5
4
  "attachments.errors.maxUploadSize": "Der Anhang überschreitet die maximal zulässige Upload-Größe.",
@@ -94,6 +93,7 @@
94
93
  "attachments.library.upload.success": "Anhang hochgeladen.",
95
94
  "attachments.library.upload.tagsPlaceholder": "Tags hinzufügen",
96
95
  "attachments.library.upload.title": "Anhang hochladen",
96
+ "attachments.nav.group": "Medien",
97
97
  "attachments.partitions.actions.add": "Partition hinzufügen",
98
98
  "attachments.partitions.actions.cancel": "Abbrechen",
99
99
  "attachments.partitions.actions.create": "Partition erstellen",
@@ -1,5 +1,4 @@
1
1
  {
2
- "attachments.customers.storage.nav.group": "Storage",
3
2
  "attachments.errors.activeContentBlocked": "Active content uploads are not allowed.",
4
3
  "attachments.errors.dangerousExecutable": "Executable file types are not allowed as attachments.",
5
4
  "attachments.errors.maxUploadSize": "Attachment exceeds the maximum upload size.",
@@ -94,6 +93,7 @@
94
93
  "attachments.library.upload.success": "Attachment uploaded.",
95
94
  "attachments.library.upload.tagsPlaceholder": "Add tags",
96
95
  "attachments.library.upload.title": "Upload attachment",
96
+ "attachments.nav.group": "Media",
97
97
  "attachments.partitions.actions.add": "Add partition",
98
98
  "attachments.partitions.actions.cancel": "Cancel",
99
99
  "attachments.partitions.actions.create": "Create partition",
@@ -1,5 +1,4 @@
1
1
  {
2
- "attachments.customers.storage.nav.group": "Almacenamiento",
3
2
  "attachments.errors.activeContentBlocked": "No se permite la carga de contenido activo.",
4
3
  "attachments.errors.dangerousExecutable": "No se permiten archivos ejecutables como adjuntos.",
5
4
  "attachments.errors.maxUploadSize": "El archivo adjunto supera el tamaño máximo de carga permitido.",
@@ -94,6 +93,7 @@
94
93
  "attachments.library.upload.success": "Archivo adjunto subido.",
95
94
  "attachments.library.upload.tagsPlaceholder": "Agregar etiquetas",
96
95
  "attachments.library.upload.title": "Subir archivo adjunto",
96
+ "attachments.nav.group": "Medios",
97
97
  "attachments.partitions.actions.add": "Agregar partición",
98
98
  "attachments.partitions.actions.cancel": "Cancelar",
99
99
  "attachments.partitions.actions.create": "Crear partición",
@@ -1,5 +1,4 @@
1
1
  {
2
- "attachments.customers.storage.nav.group": "Magazyn",
3
2
  "attachments.errors.activeContentBlocked": "Przesyłanie treści aktywnych nie jest dozwolone.",
4
3
  "attachments.errors.dangerousExecutable": "Pliki wykonywalne nie są dozwolone jako załączniki.",
5
4
  "attachments.errors.maxUploadSize": "Załącznik przekracza maksymalny dopuszczalny rozmiar przesyłania.",
@@ -94,6 +93,7 @@
94
93
  "attachments.library.upload.success": "Załącznik przesłany.",
95
94
  "attachments.library.upload.tagsPlaceholder": "Dodaj tagi",
96
95
  "attachments.library.upload.title": "Prześlij załącznik",
96
+ "attachments.nav.group": "Media",
97
97
  "attachments.partitions.actions.add": "Dodaj partycję",
98
98
  "attachments.partitions.actions.cancel": "Anuluj",
99
99
  "attachments.partitions.actions.create": "Utwórz partycję",
@@ -156,7 +156,7 @@ function normalizeGroupWeights(groups: NavGroupWithWeight[]): NavGroupWithWeight
156
156
  'staff.nav.group',
157
157
  'entities.nav.group',
158
158
  'directory.nav.group',
159
- 'customers.storage.nav.group',
159
+ 'attachments.nav.group',
160
160
  ]
161
161
  const groupOrderIndex = new Map(defaultGroupOrder.map((id, index) => [id, index]))
162
162
  groups.sort((a, b) => {
@@ -2607,7 +2607,6 @@
2607
2607
  "customers.schedule.visibility": "Visibility",
2608
2608
  "customers.schedule.visibility.public": "Public",
2609
2609
  "customers.schedule.visibility.team": "Team only",
2610
- "customers.storage.nav.group": "Speicher",
2611
2610
  "customers.tags.manage.addCategory": "Neue Kategorie",
2612
2611
  "customers.tags.manage.addCategoryPlaceholder": "Kategoriename...",
2613
2612
  "customers.tags.manage.addCategoryRequired": "Geben Sie zuerst einen Kategorienamen ein.",
@@ -2607,7 +2607,6 @@
2607
2607
  "customers.schedule.visibility": "Visibility",
2608
2608
  "customers.schedule.visibility.public": "Public",
2609
2609
  "customers.schedule.visibility.team": "Team only",
2610
- "customers.storage.nav.group": "Storage",
2611
2610
  "customers.tags.manage.addCategory": "New category",
2612
2611
  "customers.tags.manage.addCategoryPlaceholder": "Category name...",
2613
2612
  "customers.tags.manage.addCategoryRequired": "Enter a category name first.",
@@ -2607,7 +2607,6 @@
2607
2607
  "customers.schedule.visibility": "Visibility",
2608
2608
  "customers.schedule.visibility.public": "Public",
2609
2609
  "customers.schedule.visibility.team": "Team only",
2610
- "customers.storage.nav.group": "Almacenamiento",
2611
2610
  "customers.tags.manage.addCategory": "Nueva categoría",
2612
2611
  "customers.tags.manage.addCategoryPlaceholder": "Nombre de la categoría...",
2613
2612
  "customers.tags.manage.addCategoryRequired": "Primero introduce un nombre de categoría.",
@@ -2607,7 +2607,6 @@
2607
2607
  "customers.schedule.visibility": "Widoczność",
2608
2608
  "customers.schedule.visibility.public": "Publiczny",
2609
2609
  "customers.schedule.visibility.team": "Tylko zespół",
2610
- "customers.storage.nav.group": "Magazyn",
2611
2610
  "customers.tags.manage.addCategory": "Nowa kategoria",
2612
2611
  "customers.tags.manage.addCategoryPlaceholder": "Nazwa kategorii...",
2613
2612
  "customers.tags.manage.addCategoryRequired": "Najpierw wpisz nazwę kategorii.",