@open-mercato/core 0.6.7-develop.6592.1.7f69fa2454 → 0.6.7-develop.6594.1.5581f765f4
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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/generated/entities/custom_entity/index.js +2 -0
- package/dist/generated/entities/custom_entity/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +1 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
- package/dist/modules/attachments/lib/imageSafety.js.map +2 -2
- package/dist/modules/auth/api/features.js +14 -0
- package/dist/modules/auth/api/features.js.map +2 -2
- package/dist/modules/entities/api/entities.js +20 -0
- package/dist/modules/entities/api/entities.js.map +2 -2
- package/dist/modules/entities/api/entity-settings.js +89 -0
- package/dist/modules/entities/api/entity-settings.js.map +7 -0
- package/dist/modules/entities/api/records.js +46 -25
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js +13 -4
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/create/page.js +27 -2
- package/dist/modules/entities/backend/entities/user/create/page.js.map +2 -2
- package/dist/modules/entities/data/entities.js +4 -0
- package/dist/modules/entities/data/entities.js.map +2 -2
- package/dist/modules/entities/lib/entityAcl.js +17 -4
- package/dist/modules/entities/lib/entityAcl.js.map +3 -3
- package/dist/modules/entities/lib/install-from-ce.js +2 -0
- package/dist/modules/entities/lib/install-from-ce.js.map +2 -2
- package/dist/modules/entities/lib/recordFeatures.js +24 -0
- package/dist/modules/entities/lib/recordFeatures.js.map +7 -0
- package/dist/modules/entities/lib/register.js +3 -0
- package/dist/modules/entities/lib/register.js.map +2 -2
- package/dist/modules/entities/lib/restrictedEntityFeatures.js +62 -0
- package/dist/modules/entities/lib/restrictedEntityFeatures.js.map +7 -0
- package/dist/modules/entities/migrations/Migration20260716120000.js +13 -0
- package/dist/modules/entities/migrations/Migration20260716120000.js.map +7 -0
- package/generated/entities/custom_entity/index.ts +1 -0
- package/generated/entity-fields-registry.ts +1 -0
- package/package.json +8 -7
- package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +2 -2
- package/src/modules/attachments/lib/imageSafety.ts +2 -2
- package/src/modules/auth/api/features.ts +17 -0
- package/src/modules/entities/api/entities.ts +28 -0
- package/src/modules/entities/api/entity-settings.ts +103 -0
- package/src/modules/entities/api/records.ts +70 -29
- package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +12 -3
- package/src/modules/entities/backend/entities/user/create/page.tsx +33 -1
- package/src/modules/entities/data/entities.ts +6 -0
- package/src/modules/entities/i18n/de.json +3 -0
- package/src/modules/entities/i18n/en.json +3 -0
- package/src/modules/entities/i18n/es.json +3 -0
- package/src/modules/entities/i18n/pl.json +3 -0
- package/src/modules/entities/lib/entityAcl.ts +27 -5
- package/src/modules/entities/lib/install-from-ce.ts +2 -0
- package/src/modules/entities/lib/recordFeatures.ts +48 -0
- package/src/modules/entities/lib/register.ts +4 -0
- package/src/modules/entities/lib/restrictedEntityFeatures.ts +98 -0
- package/src/modules/entities/migrations/.snapshot-open-mercato.json +10 -0
- package/src/modules/entities/migrations/Migration20260716120000.ts +13 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/entities/api/records.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport type { QueryEngine, QueryOptions, Where, Sort } from '@open-mercato/shared/lib/query/types'\nimport { normalizeExportFormat, serializeExport, defaultExportFilename, ensureColumns } from '@open-mercato/shared/lib/crud/exporters'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { resolveOrganizationScope, getSelectedOrganizationFromRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { SYSTEM_ENTITY_RECORDS_BLOCKED_CODE, isOrmBackedSystemEntityId } from '@open-mercato/shared/lib/data/engine'\nimport { parseBooleanToken, parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\nimport { parseCommaSeparatedList } from '@open-mercato/shared/lib/string'\nimport { setRecordCustomFields } from '../lib/helpers'\nimport { CustomFieldValue } from '../data/entities'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\nimport { assertEntityAclForRequest } from '../lib/entityAcl'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('entities').child({ component: 'records' })\n\nlet declaredCustomEntityIds: Set<string> | null = null\nfunction isDeclaredCustomEntity(entityId: string): boolean {\n if (declaredCustomEntityIds === null) {\n try {\n const mods = getModules() as Array<{ customEntities?: Array<{ id?: string }> }>\n if (Array.isArray(mods) && mods.length) {\n const ids = new Set<string>()\n for (const mod of mods) {\n for (const spec of mod?.customEntities ?? []) {\n if (spec?.id) ids.add(spec.id)\n }\n }\n declaredCustomEntityIds = ids\n }\n } catch {}\n }\n return declaredCustomEntityIds?.has(entityId) ?? false\n}\n\nconst CUSTOM_ENTITY_RECORD_RESOURCE_KIND = 'entities.record'\n\ntype RecordsEntityKind = 'system' | 'custom' | 'unknown'\n\n// This surface manages doc-storage records, which exist for CUSTOM entities only.\n// Module-declared ids backed by a registered ORM table are system entities \u2014 their\n// records live in their own module tables/APIs, and stray doc rows for them poisoned\n// read-path classification platform-wide (#2939) \u2014 so they are rejected outright. The\n// previous fallback that classified an entity by the mere presence of\n// `custom_entities_storage` rows is gone: within the allowed set, declaration (ce.ts)\n// or an active `custom_entities` registration is authoritative.\nasync function classifyRecordsEntity(em: any, entityId: string): Promise<RecordsEntityKind> {\n if (isOrmBackedSystemEntityId(em, entityId)) return 'system'\n if (isDeclaredCustomEntity(entityId)) return 'custom'\n try {\n const { CustomEntity } = await import('../data/entities')\n // Any registration row \u2014 active or soft-deleted \u2014 proves the id is a custom\n // entity. Records persist beyond the definition's soft delete (TC-ENTITIES-006)\n // and must stay readable/deletable, e.g. for the restore flow and cleanup.\n const found = await em.findOne(CustomEntity as any, { entityId })\n if (found) return 'custom'\n } catch {}\n return 'unknown'\n}\n\nfunction systemEntityRecordsRejection(entityId: string) {\n return NextResponse.json(\n { error: 'Records are available for custom entities only', code: SYSTEM_ENTITY_RECORDS_BLOCKED_CODE, entityId },\n { status: 400 },\n )\n}\n\nasync function readCustomEntityRecordUpdatedAt(\n em: any,\n input: { entityType: string; entityId: string; organizationId: string | null },\n): Promise<string | null> {\n try {\n const db = em.getKysely()\n let query = db\n .selectFrom('custom_entities_storage' as any)\n .select(['updated_at' as any])\n .where('entity_type' as any, '=', input.entityType)\n .where('entity_id' as any, '=', input.entityId)\n query = input.organizationId === null\n ? query.where('organization_id' as any, 'is', null as any)\n : query.where('organization_id' as any, '=', input.organizationId)\n const row = await query.executeTakeFirst()\n const value = (row as any)?.updated_at\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'string' && value.length > 0) return value\n return null\n } catch {\n return null\n }\n}\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['entities.records.view'] },\n POST: { requireAuth: true, requireFeatures: ['entities.records.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['entities.records.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['entities.records.manage'] },\n}\n\nconst DEFAULT_EXPORT_PAGE_SIZE = 1000\n\nconst listRecordsQuerySchema = z\n .object({\n entityId: z.string().min(1),\n page: z.coerce.number().int().min(1).optional(),\n pageSize: z.coerce.number().int().min(1).max(100).optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n search: z.string().optional(),\n searchFields: z.string().optional(),\n withDeleted: z.coerce.boolean().optional(),\n format: z.enum(['csv', 'json', 'xml', 'markdown']).optional(),\n exportScope: z.enum(['full']).optional(),\n export_scope: z.enum(['full']).optional(),\n all: z.coerce.boolean().optional(),\n full: z.coerce.boolean().optional(),\n })\n .passthrough()\n\nconst recordItemSchema = z.record(z.string(), z.any())\n\nconst listRecordsResponseSchema = z.object({\n items: z.array(recordItemSchema),\n total: z.number(),\n page: z.number(),\n pageSize: z.number(),\n totalPages: z.number(),\n})\n\nexport async function GET(req: Request) {\n const url = new URL(req.url)\n const entityId = url.searchParams.get('entityId') || ''\n if (!entityId) return NextResponse.json({ error: 'entityId is required' }, { status: 400 })\n\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const requestedExport = normalizeExportFormat(url.searchParams.get('format'))\n const exportScopeRaw = (url.searchParams.get('exportScope') || url.searchParams.get('export_scope') || '').toLowerCase()\n const exportFullRequested = requestedExport != null && (exportScopeRaw === 'full' || parseBooleanWithDefault(url.searchParams.get('full'), false))\n const exportAll = parseBooleanWithDefault(url.searchParams.get('all'), false)\n const noPagination = exportAll || requestedExport != null\n const page = noPagination ? 1 : Math.max(parseInt(url.searchParams.get('page') || '1', 10) || 1, 1)\n const basePageSize = Math.min(Math.max(parseInt(url.searchParams.get('pageSize') || '50', 10) || 50, 1), 100)\n const pageSize = noPagination ? Math.max(basePageSize, DEFAULT_EXPORT_PAGE_SIZE) : basePageSize\n const sortField = url.searchParams.get('sortField') || 'id'\n const sortDir = (url.searchParams.get('sortDir') || 'asc').toLowerCase() === 'desc' ? 'desc' : 'asc'\n const withDeleted = parseBooleanWithDefault(url.searchParams.get('withDeleted'), false)\n const searchTerm = (url.searchParams.get('search') || '').trim()\n const searchFields = parseCommaSeparatedList(url.searchParams.get('searchFields'))\n\n const qpEntries: Array<[string, string]> = []\n for (const [key, val] of url.searchParams.entries()) {\n if (['entityId','page','pageSize','sortField','sortDir','withDeleted','format','exportScope','export_scope','all','full','search','searchFields'].includes(key)) continue\n qpEntries.push([key, val])\n }\n\n try {\n const { resolve } = await createRequestContainer()\n const qe = resolve('queryEngine') as QueryEngine\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as RbacService\n const scope = await resolveOrganizationScope({ em, rbac, auth, selectedId: getSelectedOrganizationFromRequest(req) })\n let organizationIds: string[] | null = scope.filterIds\n // Module-declared custom entities (ce.ts) carry frozen system-style ids and are never\n // registered in `custom_entities`, so classification checks the declared registry plus\n // active registrations. System (table-backed) ids are rejected above; for the allowed\n // set `isCustomEntity` drives mapRow's cf_ stripping so the edit form reads back values.\n const entityKind = await classifyRecordsEntity(em, entityId)\n if (entityKind === 'system') return systemEntityRecordsRejection(entityId)\n const isCustomEntity = entityKind === 'custom'\n await assertEntityAclForRequest({ auth, entityId, action: 'view', isCustomEntity, rbac })\n if (organizationIds && organizationIds.length === 0) {\n return NextResponse.json({ items: [], total: 0, page, pageSize, totalPages: 0 })\n }\n const normalizeCustomEntityValue = (value: unknown) => {\n if (Array.isArray(value)) {\n return value.map((entry) => {\n if (typeof entry !== 'string') return entry\n const parsed = parseBooleanToken(entry)\n return parsed === null ? entry : parsed\n })\n }\n if (typeof value !== 'string') return value\n const parsed = parseBooleanToken(value)\n return parsed === null ? value : parsed\n }\n const mapRow = (row: any) => {\n if (!isCustomEntity || !row || typeof row !== 'object') return row\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(row)) {\n if (k.startsWith('cf_')) out[k.replace(/^cf_/, '')] = normalizeCustomEntityValue(v)\n else out[k] = v\n }\n return out\n }\n const mapFullRow = (row: any) => {\n if (!row || typeof row !== 'object') return row\n return { ...(row as Record<string, unknown>) }\n }\n // Build filters with awareness of custom-entity mode\n const filtersObj: Where<any> = {}\n const buildFilter = (key: string, val: string, allowAnyKey: boolean) => {\n if (key.startsWith('cf_')) {\n if (key.endsWith('In')) {\n const base = key.slice(0, -2)\n const values = parseCommaSeparatedList(val)\n ;(filtersObj as any)[base] = { $in: values }\n } else {\n if (val.includes(',')) {\n const values = parseCommaSeparatedList(val)\n ;(filtersObj as any)[key] = { $in: values }\n } else {\n const parsed = parseBooleanToken(val)\n ;(filtersObj as any)[key] = parsed === null ? val : parsed\n }\n }\n } else if (allowAnyKey) {\n if (val.includes(',')) {\n const values = parseCommaSeparatedList(val)\n ;(filtersObj as any)[key] = { $in: values }\n } else {\n const parsed = parseBooleanToken(val)\n ;(filtersObj as any)[key] = parsed === null ? val : parsed\n }\n } else {\n if (['id', 'created_at', 'updated_at', 'deleted_at', 'name', 'title', 'email'].includes(key)) {\n ;(filtersObj as any)[key] = val\n }\n }\n }\n\n if (organizationIds && organizationIds.length) {\n (filtersObj as any).organization_id = { $in: organizationIds }\n }\n const qopts: QueryOptions = {\n tenantId: auth.tenantId!,\n includeCustomFields: true,\n page: { page, pageSize },\n sort: [{ field: sortField as any, dir: sortDir as any }] as Sort[],\n filters: filtersObj as any,\n withDeleted,\n }\n if (organizationIds && organizationIds.length) {\n qopts.organizationIds = organizationIds\n }\n // Allowed entities are doc-storage-backed by definition (system ids were rejected\n // above) \u2014 direct the engine to doc storage explicitly so reads stay deterministic\n // even before the first record exists.\n if (isCustomEntity) qopts.forceCustomEntityStorage = true\n for (const [k, v] of qpEntries) buildFilter(k, v, isCustomEntity)\n // Server-side full-result search: match the term against the requested fields\n // (defaults to `id`) before pagination so totals/exports stay consistent with\n // the active search instead of filtering only the current client page (#3229).\n if (searchTerm) {\n const fields = searchFields.length ? searchFields : ['id']\n const pattern = `%${searchTerm}%`\n const orClauses = fields.map((field) => ({ [field]: { $ilike: pattern } }))\n ;(filtersObj as any).$or = orClauses\n }\n const res = await qe.query(entityId as any, qopts)\n const rawItems = res.items || []\n const viewPageItems = rawItems.map(mapRow)\n const fullPageItems = rawItems.map(mapFullRow)\n\n // Expose `updated_at` on custom-entity records. The query engine returns only\n // the `doc` fields + `id`, dropping the base `updated_at` column \u2014 which made\n // optimistic locking impossible end-to-end (no version for the edit page to\n // round-trip as the lock header). Batch-read it from storage and merge it in.\n if (isCustomEntity && viewPageItems.length) {\n try {\n const recordIds = viewPageItems\n .map((it: any) => it?.id)\n .filter((v: any): v is string => typeof v === 'string' && v.length > 0)\n if (recordIds.length) {\n const db = em.getKysely()\n const rows = await db\n .selectFrom('custom_entities_storage' as any)\n .select(['entity_id' as any, 'updated_at' as any])\n .where('entity_type' as any, '=', entityId)\n .where('entity_id' as any, 'in', recordIds as any)\n .execute()\n const updatedById = new Map<string, string>()\n for (const row of rows as any[]) {\n const value = row?.updated_at\n const iso = value instanceof Date ? value.toISOString() : (typeof value === 'string' && value.length > 0 ? value : null)\n if (iso && row?.entity_id) updatedById.set(String(row.entity_id), iso)\n }\n for (const item of viewPageItems as any[]) {\n const iso = updatedById.get(String(item?.id))\n if (iso) {\n item.updated_at = iso\n item.updatedAt = iso\n }\n }\n }\n } catch { /* best-effort: locking simply will not engage if storage is unavailable */ }\n }\n\n const total = typeof res.total === 'number' ? res.total : rawItems.length\n const effectivePageSize = res.pageSize || pageSize\n const payload = {\n items: viewPageItems,\n total,\n page: res.page || page,\n pageSize: effectivePageSize,\n totalPages: Math.ceil(total / (effectivePageSize || 1)),\n }\n\n if (requestedExport) {\n let exportItems: any[] = exportFullRequested ? [...fullPageItems] : [...viewPageItems]\n if (total > exportItems.length) {\n let nextPage = 2\n while (exportItems.length < total) {\n const nextRes = await qe.query(entityId as any, {\n ...qopts,\n page: { page: nextPage, pageSize },\n })\n const nextRawItems = nextRes.items || []\n if (!nextRawItems.length) break\n const nextViewItems = nextRawItems.map(mapRow)\n const nextFullItems = nextRawItems.map(mapFullRow)\n const nextBatch = exportFullRequested ? nextFullItems : nextViewItems\n exportItems.push(...nextBatch)\n if (nextBatch.length < pageSize) break\n nextPage += 1\n }\n }\n const prepared = {\n columns: ensureColumns(exportItems),\n rows: exportItems,\n }\n const filenameBase = exportFullRequested ? `${entityId || 'records'}_full` : entityId || 'records'\n const serialized = serializeExport(prepared, requestedExport)\n const filename = defaultExportFilename(filenameBase, requestedExport)\n return new Response(serialized.body, {\n headers: {\n 'content-type': serialized.contentType,\n 'content-disposition': `attachment; filename=\"${filename}\"`,\n },\n })\n }\n\n return NextResponse.json(payload)\n } catch (e) {\n if (isCrudHttpError(e)) return NextResponse.json(e.body, { status: e.status })\n logger.error('Records GET failed', { err: e })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nconst postBodySchema = z.object({\n entityId: z.string().min(1),\n recordId: z.string().min(1).optional(),\n values: z.record(z.string(), z.any()).default({}),\n})\n\nconst putBodySchema = z.object({\n entityId: z.string().min(1),\n recordId: z.string().min(1),\n values: z.record(z.string(), z.any()).default({}),\n})\n\nconst mutationResponseSchema = z.object({\n ok: z.literal(true),\n item: z\n .object({\n entityId: z.string(),\n recordId: z.string(),\n })\n .optional(),\n})\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n let json: unknown\n try { json = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const parsed = postBodySchema.safeParse(json)\n if (!parsed.success) return NextResponse.json({ error: 'Validation failed', details: parsed.error.flatten() }, { status: 400 })\n const { entityId } = parsed.data\n let { recordId, values } = parsed.data as { recordId?: string; values: Record<string, any> }\n\n try {\n const { resolve } = await createRequestContainer()\n const de = resolve('dataEngine') as any\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as RbacService\n const scope = await resolveOrganizationScope({ em, rbac, auth, selectedId: getSelectedOrganizationFromRequest(req) })\n const targetOrgId = scope.selectedId ?? auth.orgId\n if (!targetOrgId) return NextResponse.json({ error: 'Organization context is required' }, { status: 400 })\n const entityKind = await classifyRecordsEntity(em, entityId)\n if (entityKind === 'system') return systemEntityRecordsRejection(entityId)\n const isCustomEntity = entityKind === 'custom'\n await assertEntityAclForRequest({ auth, entityId, action: 'manage', isCustomEntity, rbac })\n // Strip reserved record/system columns the edit form echoes back from the loaded record\n // (`id`, plus `updated_at`/`updatedAt` used for optimistic locking). They are not custom\n // fields; without this they validate as cf_id / cf_updated_at / cf_updatedAt and are\n // rejected as \"Unknown custom field\", which fails EVERY custom-entity edit-form save.\n for (const reservedKey of ['id', 'created_at', 'createdAt', 'updated_at', 'updatedAt', 'deleted_at', 'deletedAt']) {\n delete (values as any)[reservedKey]\n }\n const norm = normalizeValues(values)\n\n // Validate against custom field definitions\n try {\n const { validateCustomFieldValuesServer } = await import('../lib/validation')\n const check = await validateCustomFieldValuesServer(em, { entityId, organizationId: targetOrgId, tenantId: auth.tenantId!, values: norm, rejectUndeclaredKeys: true })\n if (!check.ok) return NextResponse.json({ error: 'Validation failed', fields: check.fieldErrors }, { status: 400 })\n } catch { /* ignore if helper missing */ }\n\n const normalizedRecordId = (() => {\n const raw = String(recordId || '').trim()\n if (!raw) return undefined\n const low = raw.toLowerCase()\n if (low === 'create' || low === 'new' || low === 'null' || low === 'undefined') return undefined\n // Enforce UUID only; any non-uuid is ignored so we generate one in the DE\n const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n return uuid.test(raw) ? raw : undefined\n })()\n const { id } = await de.createCustomEntityRecord({\n entityId,\n recordId: normalizedRecordId,\n organizationId: targetOrgId,\n tenantId: auth.tenantId!,\n values: norm,\n })\n\n return NextResponse.json({ ok: true, item: { entityId, recordId: id } })\n } catch (e) {\n if (isCrudHttpError(e)) return NextResponse.json(e.body, { status: e.status })\n logger.error('Records POST failed', { err: e })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\n// Avoid zod here to prevent runtime import issues in some environments\nfunction parsePutBody(json: any): { ok: true; data: { entityId: string; recordId: string; values: Record<string, any> } } | { ok: false; error: string } {\n if (!json || typeof json !== 'object') return { ok: false, error: 'Invalid JSON' }\n const entityId = typeof json.entityId === 'string' && json.entityId.length ? json.entityId : ''\n const recordId = typeof json.recordId === 'string' && json.recordId.length ? json.recordId : ''\n const values = (json.values && typeof json.values === 'object') ? json.values as Record<string, any> : {}\n if (!entityId || !recordId) return { ok: false, error: 'entityId and recordId are required' }\n return { ok: true, data: { entityId, recordId, values } }\n}\n\nexport async function PUT(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n let json: any\n try { json = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const parsed = parsePutBody(json)\n if (!parsed.ok) return NextResponse.json({ error: parsed.error }, { status: 400 })\n const { entityId, recordId, values } = parsed.data\n\n try {\n const container = await createRequestContainer()\n const { resolve } = container\n const de = resolve('dataEngine') as any\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as RbacService\n const scope = await resolveOrganizationScope({ em, rbac, auth, selectedId: getSelectedOrganizationFromRequest(req) })\n const targetOrgId = scope.selectedId ?? auth.orgId\n if (!targetOrgId) return NextResponse.json({ error: 'Organization context is required' }, { status: 400 })\n const entityKind = await classifyRecordsEntity(em, entityId)\n if (entityKind === 'system') return systemEntityRecordsRejection(entityId)\n const isCustomEntity = entityKind === 'custom'\n await assertEntityAclForRequest({ auth, entityId, action: 'manage', isCustomEntity, rbac })\n // Strip reserved record/system columns the edit form echoes back from the loaded record\n // (`id`, plus `updated_at`/`updatedAt` used for optimistic locking). They are not custom\n // fields; without this they validate as cf_id / cf_updated_at / cf_updatedAt and are\n // rejected as \"Unknown custom field\", which fails EVERY custom-entity edit-form save.\n for (const reservedKey of ['id', 'created_at', 'createdAt', 'updated_at', 'updatedAt', 'deleted_at', 'deletedAt']) {\n delete (values as any)[reservedKey]\n }\n const norm = normalizeValues(values)\n\n // Validate against custom field definitions\n try {\n const { validateCustomFieldValuesServer } = await import('../lib/validation')\n const check = await validateCustomFieldValuesServer(em, { entityId, organizationId: targetOrgId, tenantId: auth.tenantId!, values: norm, rejectUndeclaredKeys: true })\n if (!check.ok) return NextResponse.json({ error: 'Validation failed', fields: check.fieldErrors }, { status: 400 })\n } catch { /* ignore if helper missing */ }\n\n // Normalize recordId: if blank/sentinel/non-uuid => create instead of update\n const uuidRe = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n const rid = String(recordId || '').trim()\n const low = rid.toLowerCase()\n const isSentinel = !rid || low === 'create' || low === 'new' || low === 'null' || low === 'undefined'\n const isUuid = uuidRe.test(rid)\n if (isSentinel || !isUuid) {\n const created = await de.createCustomEntityRecord({\n entityId,\n recordId: undefined,\n organizationId: targetOrgId,\n tenantId: auth.tenantId!,\n values: norm,\n })\n return NextResponse.json({ ok: true, item: { entityId, recordId: created.id } })\n }\n\n try {\n const currentUpdatedAt = await readCustomEntityRecordUpdatedAt(em, {\n entityType: entityId,\n entityId: rid,\n organizationId: targetOrgId,\n })\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: CUSTOM_ENTITY_RECORD_RESOURCE_KIND,\n resourceId: rid,\n current: currentUpdatedAt,\n request: req,\n })\n } catch (lockError) {\n if (isCrudHttpError(lockError)) {\n return NextResponse.json(lockError.body, { status: lockError.status })\n }\n throw lockError\n }\n\n await de.updateCustomEntityRecord({\n entityId,\n recordId: rid,\n organizationId: targetOrgId,\n tenantId: auth.tenantId!,\n values: norm,\n })\n return NextResponse.json({ ok: true, item: { entityId, recordId: rid } })\n } catch (e) {\n if (isCrudHttpError(e)) return NextResponse.json(e.body, { status: e.status })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nconst deleteBodySchema = z.object({\n entityId: z.string().min(1),\n recordId: z.string().min(1),\n})\n\nexport async function DELETE(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const url = new URL(req.url)\n const qpEntityId = url.searchParams.get('entityId')\n const qpRecordId = url.searchParams.get('recordId')\n let payload: any = qpEntityId && qpRecordId ? { entityId: qpEntityId, recordId: qpRecordId } : null\n if (!payload) {\n try { payload = await req.json() } catch { payload = null }\n }\n const parsed = deleteBodySchema.safeParse(payload)\n if (!parsed.success) return NextResponse.json({ error: 'Validation failed', details: parsed.error.flatten() }, { status: 400 })\n const { entityId, recordId } = parsed.data\n\n try {\n const container = await createRequestContainer()\n const { resolve } = container\n const de = resolve('dataEngine') as any\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as RbacService\n const scope = await resolveOrganizationScope({ em, rbac, auth, selectedId: getSelectedOrganizationFromRequest(req) })\n const targetOrgId = scope.selectedId ?? auth.orgId\n if (!targetOrgId) return NextResponse.json({ error: 'Organization context is required' }, { status: 400 })\n const entityKind = await classifyRecordsEntity(em, entityId)\n if (entityKind === 'system') return systemEntityRecordsRejection(entityId)\n const isCustomEntity = entityKind === 'custom'\n await assertEntityAclForRequest({ auth, entityId, action: 'manage', isCustomEntity, rbac })\n\n try {\n const currentUpdatedAt = await readCustomEntityRecordUpdatedAt(em, {\n entityType: entityId,\n entityId: recordId,\n organizationId: targetOrgId,\n })\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: CUSTOM_ENTITY_RECORD_RESOURCE_KIND,\n resourceId: recordId,\n current: currentUpdatedAt,\n request: req,\n })\n } catch (lockError) {\n if (isCrudHttpError(lockError)) {\n return NextResponse.json(lockError.body, { status: lockError.status })\n }\n throw lockError\n }\n\n await de.deleteCustomEntityRecord({ entityId, recordId, organizationId: targetOrgId, tenantId: auth.tenantId!, soft: true })\n return NextResponse.json({ ok: true })\n } catch (e) {\n if (isCrudHttpError(e)) return NextResponse.json(e.body, { status: e.status })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nfunction normalizeValues(input: Record<string, any>): Record<string, any> {\n const out: Record<string, any> = {}\n for (const [k, v] of Object.entries(input || {})) {\n const key = k.startsWith('cf_') ? k.replace(/^cf_/, '') : k\n out[key] = v\n }\n return out\n}\n\nconst deleteResponseSchema = z.object({\n ok: z.literal(true),\n})\n\nconst errorSchema = z.object({\n error: z.string(),\n}).passthrough()\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Entities',\n summary: 'CRUD operations on entity records',\n methods: {\n GET: {\n summary: 'List records',\n description:\n 'Returns paginated records for the supplied entity. Supports custom field filters, exports, and soft-delete toggles.',\n query: listRecordsQuerySchema,\n responses: [\n {\n status: 200,\n description: 'Paginated records',\n schema: listRecordsResponseSchema,\n },\n {\n status: 400,\n description: 'Missing entity id',\n schema: errorSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: errorSchema,\n },\n {\n status: 500,\n description: 'Unexpected failure',\n schema: errorSchema,\n },\n ],\n },\n POST: {\n summary: 'Create record',\n description:\n 'Creates a record for the given entity. When `recordId` is omitted or not a UUID the data engine will generate one automatically.',\n requestBody: {\n contentType: 'application/json',\n schema: postBodySchema,\n },\n responses: [\n {\n status: 200,\n description: 'Record created',\n schema: mutationResponseSchema,\n },\n {\n status: 400,\n description: 'Validation failure',\n schema: errorSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: errorSchema,\n },\n {\n status: 500,\n description: 'Unexpected failure',\n schema: errorSchema,\n },\n ],\n },\n PUT: {\n summary: 'Update record',\n description:\n 'Updates an existing record. If the provided recordId is not a UUID the record will be created instead to support optimistic flows.',\n requestBody: {\n contentType: 'application/json',\n schema: putBodySchema,\n },\n responses: [\n {\n status: 200,\n description: 'Record updated',\n schema: mutationResponseSchema,\n },\n {\n status: 400,\n description: 'Validation failure',\n schema: errorSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: errorSchema,\n },\n {\n status: 500,\n description: 'Unexpected failure',\n schema: errorSchema,\n },\n ],\n },\n DELETE: {\n summary: 'Delete record',\n description: 'Soft deletes the specified record within the current tenant/org scope.',\n requestBody: {\n contentType: 'application/json',\n schema: deleteBodySchema,\n },\n responses: [\n {\n status: 200,\n description: 'Record deleted',\n schema: deleteResponseSchema,\n },\n {\n status: 400,\n description: 'Missing entity id or record id',\n schema: errorSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: errorSchema,\n },\n {\n status: 404,\n description: 'Record not found',\n schema: errorSchema,\n },\n {\n status: 500,\n description: 'Unexpected failure',\n schema: errorSchema,\n },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport type { QueryEngine, QueryOptions, Where, Sort } from '@open-mercato/shared/lib/query/types'\nimport { normalizeExportFormat, serializeExport, defaultExportFilename, ensureColumns } from '@open-mercato/shared/lib/crud/exporters'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { resolveOrganizationScope, getSelectedOrganizationFromRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { SYSTEM_ENTITY_RECORDS_BLOCKED_CODE, isOrmBackedSystemEntityId } from '@open-mercato/shared/lib/data/engine'\nimport { parseBooleanToken, parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\nimport { parseCommaSeparatedList } from '@open-mercato/shared/lib/string'\nimport { setRecordCustomFields } from '../lib/helpers'\nimport { CustomFieldValue } from '../data/entities'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { getModules } from '@open-mercato/shared/lib/i18n/server'\nimport { assertEntityAclForRequest } from '../lib/entityAcl'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('entities').child({ component: 'records' })\n\nlet declaredCustomEntityRestricted: Map<string, boolean> | null = null\nfunction loadDeclaredCustomEntities(): Map<string, boolean> {\n if (declaredCustomEntityRestricted === null) {\n try {\n const mods = getModules() as Array<{ customEntities?: Array<{ id?: string; accessRestricted?: boolean }> }>\n const map = new Map<string, boolean>()\n for (const mod of mods ?? []) {\n for (const spec of mod?.customEntities ?? []) {\n if (spec?.id) map.set(spec.id, spec.accessRestricted === true)\n }\n }\n // Cache even when empty so we don't rebuild on every request (and fall back\n // to the DB lookup unnecessarily). Only a thrown getModules() leaves it null\n // so a genuinely-uninitialized registry is retried.\n declaredCustomEntityRestricted = map\n } catch {}\n }\n return declaredCustomEntityRestricted ?? new Map<string, boolean>()\n}\nfunction isDeclaredCustomEntity(entityId: string): boolean {\n return loadDeclaredCustomEntities().has(entityId)\n}\n\ntype RecordsEntityScope = { tenantId: string | null; organizationId: string | null }\n\n// Resolve the CustomEntity registration that applies to THIS caller, most-specific\n// first (org+tenant \u2192 tenant-global \u2192 instance-global), mirroring the overlay\n// precedence used by the entity-definitions list. Scoping matters because the\n// row's `access_restricted` flag is a security control: an unscoped lookup could\n// read another tenant's row for a colliding entityId (e.g. `user:vendors`) and\n// mis-decide the restriction. Returns null when the caller's scope has no row.\nasync function findScopedCustomEntity(em: any, CustomEntity: any, entityId: string, scope: RecordsEntityScope) {\n const { tenantId, organizationId } = scope\n const candidates: Array<Record<string, unknown>> = [\n { entityId, organizationId, tenantId },\n { entityId, organizationId: null, tenantId },\n { entityId, organizationId: null, tenantId: null },\n ]\n const seen = new Set<string>()\n for (const where of candidates) {\n const key = JSON.stringify(where)\n if (seen.has(key)) continue\n seen.add(key)\n const row = await em.findOne(CustomEntity as any, where)\n if (row) return row\n }\n return null\n}\n\nconst CUSTOM_ENTITY_RECORD_RESOURCE_KIND = 'entities.record'\n\ntype RecordsEntityKind = 'system' | 'custom' | 'unknown'\n\n// `restricted` is meaningful only when `kind === 'custom'`; it drives the\n// per-entity ACL gate in `assertEntityAclForRequest`.\ntype RecordsEntityClassification = { kind: RecordsEntityKind; restricted: boolean }\n\n// This surface manages doc-storage records, which exist for CUSTOM entities only.\n// Module-declared ids backed by a registered ORM table are system entities \u2014 their\n// records live in their own module tables/APIs, and stray doc rows for them poisoned\n// read-path classification platform-wide (#2939) \u2014 so they are rejected outright. The\n// previous fallback that classified an entity by the mere presence of\n// `custom_entities_storage` rows is gone: within the allowed set, declaration (ce.ts)\n// or an active `custom_entities` registration is authoritative.\nasync function classifyRecordsEntity(em: any, entityId: string, scope: RecordsEntityScope): Promise<RecordsEntityClassification> {\n if (isOrmBackedSystemEntityId(em, entityId)) return { kind: 'system', restricted: false }\n const declared = loadDeclaredCustomEntities()\n if (declared.has(entityId)) return { kind: 'custom', restricted: declared.get(entityId) === true }\n try {\n const { CustomEntity } = await import('../data/entities')\n // Restriction is decided from the row that applies to THIS caller's scope so\n // a colliding entityId in another tenant can't flip the flag.\n const scoped = await findScopedCustomEntity(em, CustomEntity, entityId, scope)\n if (scoped) return { kind: 'custom', restricted: (scoped as any).accessRestricted === true }\n // No in-scope registration: preserve the historical custom-vs-unknown\n // classification (any registration row \u2014 active or soft-deleted \u2014 proves the\n // id is custom; records persist beyond soft delete, TC-ENTITIES-006). A row\n // outside the caller's scope never marks the entity restricted for them, and\n // the record query is itself tenant/org-scoped, so this cannot leak data.\n const anyRow = await em.findOne(CustomEntity as any, { entityId })\n if (anyRow) return { kind: 'custom', restricted: false }\n } catch {}\n return { kind: 'unknown', restricted: false }\n}\n\nfunction systemEntityRecordsRejection(entityId: string) {\n return NextResponse.json(\n { error: 'Records are available for custom entities only', code: SYSTEM_ENTITY_RECORDS_BLOCKED_CODE, entityId },\n { status: 400 },\n )\n}\n\nasync function readCustomEntityRecordUpdatedAt(\n em: any,\n input: { entityType: string; entityId: string; organizationId: string | null },\n): Promise<string | null> {\n try {\n const db = em.getKysely()\n let query = db\n .selectFrom('custom_entities_storage' as any)\n .select(['updated_at' as any])\n .where('entity_type' as any, '=', input.entityType)\n .where('entity_id' as any, '=', input.entityId)\n query = input.organizationId === null\n ? query.where('organization_id' as any, 'is', null as any)\n : query.where('organization_id' as any, '=', input.organizationId)\n const row = await query.executeTakeFirst()\n const value = (row as any)?.updated_at\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'string' && value.length > 0) return value\n return null\n } catch {\n return null\n }\n}\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['entities.records.view'] },\n POST: { requireAuth: true, requireFeatures: ['entities.records.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['entities.records.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['entities.records.manage'] },\n}\n\nconst DEFAULT_EXPORT_PAGE_SIZE = 1000\n\nconst listRecordsQuerySchema = z\n .object({\n entityId: z.string().min(1),\n page: z.coerce.number().int().min(1).optional(),\n pageSize: z.coerce.number().int().min(1).max(100).optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n search: z.string().optional(),\n searchFields: z.string().optional(),\n withDeleted: z.coerce.boolean().optional(),\n format: z.enum(['csv', 'json', 'xml', 'markdown']).optional(),\n exportScope: z.enum(['full']).optional(),\n export_scope: z.enum(['full']).optional(),\n all: z.coerce.boolean().optional(),\n full: z.coerce.boolean().optional(),\n })\n .passthrough()\n\nconst recordItemSchema = z.record(z.string(), z.any())\n\nconst listRecordsResponseSchema = z.object({\n items: z.array(recordItemSchema),\n total: z.number(),\n page: z.number(),\n pageSize: z.number(),\n totalPages: z.number(),\n})\n\nexport async function GET(req: Request) {\n const url = new URL(req.url)\n const entityId = url.searchParams.get('entityId') || ''\n if (!entityId) return NextResponse.json({ error: 'entityId is required' }, { status: 400 })\n\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const requestedExport = normalizeExportFormat(url.searchParams.get('format'))\n const exportScopeRaw = (url.searchParams.get('exportScope') || url.searchParams.get('export_scope') || '').toLowerCase()\n const exportFullRequested = requestedExport != null && (exportScopeRaw === 'full' || parseBooleanWithDefault(url.searchParams.get('full'), false))\n const exportAll = parseBooleanWithDefault(url.searchParams.get('all'), false)\n const noPagination = exportAll || requestedExport != null\n const page = noPagination ? 1 : Math.max(parseInt(url.searchParams.get('page') || '1', 10) || 1, 1)\n const basePageSize = Math.min(Math.max(parseInt(url.searchParams.get('pageSize') || '50', 10) || 50, 1), 100)\n const pageSize = noPagination ? Math.max(basePageSize, DEFAULT_EXPORT_PAGE_SIZE) : basePageSize\n const sortField = url.searchParams.get('sortField') || 'id'\n const sortDir = (url.searchParams.get('sortDir') || 'asc').toLowerCase() === 'desc' ? 'desc' : 'asc'\n const withDeleted = parseBooleanWithDefault(url.searchParams.get('withDeleted'), false)\n const searchTerm = (url.searchParams.get('search') || '').trim()\n const searchFields = parseCommaSeparatedList(url.searchParams.get('searchFields'))\n\n const qpEntries: Array<[string, string]> = []\n for (const [key, val] of url.searchParams.entries()) {\n if (['entityId','page','pageSize','sortField','sortDir','withDeleted','format','exportScope','export_scope','all','full','search','searchFields'].includes(key)) continue\n qpEntries.push([key, val])\n }\n\n try {\n const { resolve } = await createRequestContainer()\n const qe = resolve('queryEngine') as QueryEngine\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as RbacService\n const scope = await resolveOrganizationScope({ em, rbac, auth, selectedId: getSelectedOrganizationFromRequest(req) })\n let organizationIds: string[] | null = scope.filterIds\n // Module-declared custom entities (ce.ts) carry frozen system-style ids and are never\n // registered in `custom_entities`, so classification checks the declared registry plus\n // active registrations. System (table-backed) ids are rejected above; for the allowed\n // set `isCustomEntity` drives mapRow's cf_ stripping so the edit form reads back values.\n const { kind: entityKind, restricted: isRestricted } = await classifyRecordsEntity(em, entityId, { tenantId: auth.tenantId ?? null, organizationId: scope.selectedId ?? auth.orgId ?? null })\n if (entityKind === 'system') return systemEntityRecordsRejection(entityId)\n const isCustomEntity = entityKind === 'custom'\n await assertEntityAclForRequest({ auth, entityId, action: 'view', isCustomEntity, isRestricted, rbac })\n if (organizationIds && organizationIds.length === 0) {\n return NextResponse.json({ items: [], total: 0, page, pageSize, totalPages: 0 })\n }\n const normalizeCustomEntityValue = (value: unknown) => {\n if (Array.isArray(value)) {\n return value.map((entry) => {\n if (typeof entry !== 'string') return entry\n const parsed = parseBooleanToken(entry)\n return parsed === null ? entry : parsed\n })\n }\n if (typeof value !== 'string') return value\n const parsed = parseBooleanToken(value)\n return parsed === null ? value : parsed\n }\n const mapRow = (row: any) => {\n if (!isCustomEntity || !row || typeof row !== 'object') return row\n const out: Record<string, unknown> = {}\n for (const [k, v] of Object.entries(row)) {\n if (k.startsWith('cf_')) out[k.replace(/^cf_/, '')] = normalizeCustomEntityValue(v)\n else out[k] = v\n }\n return out\n }\n const mapFullRow = (row: any) => {\n if (!row || typeof row !== 'object') return row\n return { ...(row as Record<string, unknown>) }\n }\n // Build filters with awareness of custom-entity mode\n const filtersObj: Where<any> = {}\n const buildFilter = (key: string, val: string, allowAnyKey: boolean) => {\n if (key.startsWith('cf_')) {\n if (key.endsWith('In')) {\n const base = key.slice(0, -2)\n const values = parseCommaSeparatedList(val)\n ;(filtersObj as any)[base] = { $in: values }\n } else {\n if (val.includes(',')) {\n const values = parseCommaSeparatedList(val)\n ;(filtersObj as any)[key] = { $in: values }\n } else {\n const parsed = parseBooleanToken(val)\n ;(filtersObj as any)[key] = parsed === null ? val : parsed\n }\n }\n } else if (allowAnyKey) {\n if (val.includes(',')) {\n const values = parseCommaSeparatedList(val)\n ;(filtersObj as any)[key] = { $in: values }\n } else {\n const parsed = parseBooleanToken(val)\n ;(filtersObj as any)[key] = parsed === null ? val : parsed\n }\n } else {\n if (['id', 'created_at', 'updated_at', 'deleted_at', 'name', 'title', 'email'].includes(key)) {\n ;(filtersObj as any)[key] = val\n }\n }\n }\n\n if (organizationIds && organizationIds.length) {\n (filtersObj as any).organization_id = { $in: organizationIds }\n }\n const qopts: QueryOptions = {\n tenantId: auth.tenantId!,\n includeCustomFields: true,\n page: { page, pageSize },\n sort: [{ field: sortField as any, dir: sortDir as any }] as Sort[],\n filters: filtersObj as any,\n withDeleted,\n }\n if (organizationIds && organizationIds.length) {\n qopts.organizationIds = organizationIds\n }\n // Allowed entities are doc-storage-backed by definition (system ids were rejected\n // above) \u2014 direct the engine to doc storage explicitly so reads stay deterministic\n // even before the first record exists.\n if (isCustomEntity) qopts.forceCustomEntityStorage = true\n for (const [k, v] of qpEntries) buildFilter(k, v, isCustomEntity)\n // Server-side full-result search: match the term against the requested fields\n // (defaults to `id`) before pagination so totals/exports stay consistent with\n // the active search instead of filtering only the current client page (#3229).\n if (searchTerm) {\n const fields = searchFields.length ? searchFields : ['id']\n const pattern = `%${searchTerm}%`\n const orClauses = fields.map((field) => ({ [field]: { $ilike: pattern } }))\n ;(filtersObj as any).$or = orClauses\n }\n const res = await qe.query(entityId as any, qopts)\n const rawItems = res.items || []\n const viewPageItems = rawItems.map(mapRow)\n const fullPageItems = rawItems.map(mapFullRow)\n\n // Expose `updated_at` on custom-entity records. The query engine returns only\n // the `doc` fields + `id`, dropping the base `updated_at` column \u2014 which made\n // optimistic locking impossible end-to-end (no version for the edit page to\n // round-trip as the lock header). Batch-read it from storage and merge it in.\n if (isCustomEntity && viewPageItems.length) {\n try {\n const recordIds = viewPageItems\n .map((it: any) => it?.id)\n .filter((v: any): v is string => typeof v === 'string' && v.length > 0)\n if (recordIds.length) {\n const db = em.getKysely()\n const rows = await db\n .selectFrom('custom_entities_storage' as any)\n .select(['entity_id' as any, 'updated_at' as any])\n .where('entity_type' as any, '=', entityId)\n .where('entity_id' as any, 'in', recordIds as any)\n .execute()\n const updatedById = new Map<string, string>()\n for (const row of rows as any[]) {\n const value = row?.updated_at\n const iso = value instanceof Date ? value.toISOString() : (typeof value === 'string' && value.length > 0 ? value : null)\n if (iso && row?.entity_id) updatedById.set(String(row.entity_id), iso)\n }\n for (const item of viewPageItems as any[]) {\n const iso = updatedById.get(String(item?.id))\n if (iso) {\n item.updated_at = iso\n item.updatedAt = iso\n }\n }\n }\n } catch { /* best-effort: locking simply will not engage if storage is unavailable */ }\n }\n\n const total = typeof res.total === 'number' ? res.total : rawItems.length\n const effectivePageSize = res.pageSize || pageSize\n const payload = {\n items: viewPageItems,\n total,\n page: res.page || page,\n pageSize: effectivePageSize,\n totalPages: Math.ceil(total / (effectivePageSize || 1)),\n }\n\n if (requestedExport) {\n let exportItems: any[] = exportFullRequested ? [...fullPageItems] : [...viewPageItems]\n if (total > exportItems.length) {\n let nextPage = 2\n while (exportItems.length < total) {\n const nextRes = await qe.query(entityId as any, {\n ...qopts,\n page: { page: nextPage, pageSize },\n })\n const nextRawItems = nextRes.items || []\n if (!nextRawItems.length) break\n const nextViewItems = nextRawItems.map(mapRow)\n const nextFullItems = nextRawItems.map(mapFullRow)\n const nextBatch = exportFullRequested ? nextFullItems : nextViewItems\n exportItems.push(...nextBatch)\n if (nextBatch.length < pageSize) break\n nextPage += 1\n }\n }\n const prepared = {\n columns: ensureColumns(exportItems),\n rows: exportItems,\n }\n const filenameBase = exportFullRequested ? `${entityId || 'records'}_full` : entityId || 'records'\n const serialized = serializeExport(prepared, requestedExport)\n const filename = defaultExportFilename(filenameBase, requestedExport)\n return new Response(serialized.body, {\n headers: {\n 'content-type': serialized.contentType,\n 'content-disposition': `attachment; filename=\"${filename}\"`,\n },\n })\n }\n\n return NextResponse.json(payload)\n } catch (e) {\n if (isCrudHttpError(e)) return NextResponse.json(e.body, { status: e.status })\n logger.error('Records GET failed', { err: e })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nconst postBodySchema = z.object({\n entityId: z.string().min(1),\n recordId: z.string().min(1).optional(),\n values: z.record(z.string(), z.any()).default({}),\n})\n\nconst putBodySchema = z.object({\n entityId: z.string().min(1),\n recordId: z.string().min(1),\n values: z.record(z.string(), z.any()).default({}),\n})\n\nconst mutationResponseSchema = z.object({\n ok: z.literal(true),\n item: z\n .object({\n entityId: z.string(),\n recordId: z.string(),\n })\n .optional(),\n})\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n let json: unknown\n try { json = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const parsed = postBodySchema.safeParse(json)\n if (!parsed.success) return NextResponse.json({ error: 'Validation failed', details: parsed.error.flatten() }, { status: 400 })\n const { entityId } = parsed.data\n let { recordId, values } = parsed.data as { recordId?: string; values: Record<string, any> }\n\n try {\n const { resolve } = await createRequestContainer()\n const de = resolve('dataEngine') as any\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as RbacService\n const scope = await resolveOrganizationScope({ em, rbac, auth, selectedId: getSelectedOrganizationFromRequest(req) })\n const targetOrgId = scope.selectedId ?? auth.orgId\n if (!targetOrgId) return NextResponse.json({ error: 'Organization context is required' }, { status: 400 })\n const { kind: entityKind, restricted: isRestricted } = await classifyRecordsEntity(em, entityId, { tenantId: auth.tenantId ?? null, organizationId: scope.selectedId ?? auth.orgId ?? null })\n if (entityKind === 'system') return systemEntityRecordsRejection(entityId)\n const isCustomEntity = entityKind === 'custom'\n await assertEntityAclForRequest({ auth, entityId, action: 'manage', isCustomEntity, isRestricted, rbac })\n // Strip reserved record/system columns the edit form echoes back from the loaded record\n // (`id`, plus `updated_at`/`updatedAt` used for optimistic locking). They are not custom\n // fields; without this they validate as cf_id / cf_updated_at / cf_updatedAt and are\n // rejected as \"Unknown custom field\", which fails EVERY custom-entity edit-form save.\n for (const reservedKey of ['id', 'created_at', 'createdAt', 'updated_at', 'updatedAt', 'deleted_at', 'deletedAt']) {\n delete (values as any)[reservedKey]\n }\n const norm = normalizeValues(values)\n\n // Validate against custom field definitions\n try {\n const { validateCustomFieldValuesServer } = await import('../lib/validation')\n const check = await validateCustomFieldValuesServer(em, { entityId, organizationId: targetOrgId, tenantId: auth.tenantId!, values: norm, rejectUndeclaredKeys: true })\n if (!check.ok) return NextResponse.json({ error: 'Validation failed', fields: check.fieldErrors }, { status: 400 })\n } catch { /* ignore if helper missing */ }\n\n const normalizedRecordId = (() => {\n const raw = String(recordId || '').trim()\n if (!raw) return undefined\n const low = raw.toLowerCase()\n if (low === 'create' || low === 'new' || low === 'null' || low === 'undefined') return undefined\n // Enforce UUID only; any non-uuid is ignored so we generate one in the DE\n const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n return uuid.test(raw) ? raw : undefined\n })()\n const { id } = await de.createCustomEntityRecord({\n entityId,\n recordId: normalizedRecordId,\n organizationId: targetOrgId,\n tenantId: auth.tenantId!,\n values: norm,\n })\n\n return NextResponse.json({ ok: true, item: { entityId, recordId: id } })\n } catch (e) {\n if (isCrudHttpError(e)) return NextResponse.json(e.body, { status: e.status })\n logger.error('Records POST failed', { err: e })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\n// Avoid zod here to prevent runtime import issues in some environments\nfunction parsePutBody(json: any): { ok: true; data: { entityId: string; recordId: string; values: Record<string, any> } } | { ok: false; error: string } {\n if (!json || typeof json !== 'object') return { ok: false, error: 'Invalid JSON' }\n const entityId = typeof json.entityId === 'string' && json.entityId.length ? json.entityId : ''\n const recordId = typeof json.recordId === 'string' && json.recordId.length ? json.recordId : ''\n const values = (json.values && typeof json.values === 'object') ? json.values as Record<string, any> : {}\n if (!entityId || !recordId) return { ok: false, error: 'entityId and recordId are required' }\n return { ok: true, data: { entityId, recordId, values } }\n}\n\nexport async function PUT(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n let json: any\n try { json = await req.json() } catch { return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 }) }\n const parsed = parsePutBody(json)\n if (!parsed.ok) return NextResponse.json({ error: parsed.error }, { status: 400 })\n const { entityId, recordId, values } = parsed.data\n\n try {\n const container = await createRequestContainer()\n const { resolve } = container\n const de = resolve('dataEngine') as any\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as RbacService\n const scope = await resolveOrganizationScope({ em, rbac, auth, selectedId: getSelectedOrganizationFromRequest(req) })\n const targetOrgId = scope.selectedId ?? auth.orgId\n if (!targetOrgId) return NextResponse.json({ error: 'Organization context is required' }, { status: 400 })\n const { kind: entityKind, restricted: isRestricted } = await classifyRecordsEntity(em, entityId, { tenantId: auth.tenantId ?? null, organizationId: scope.selectedId ?? auth.orgId ?? null })\n if (entityKind === 'system') return systemEntityRecordsRejection(entityId)\n const isCustomEntity = entityKind === 'custom'\n await assertEntityAclForRequest({ auth, entityId, action: 'manage', isCustomEntity, isRestricted, rbac })\n // Strip reserved record/system columns the edit form echoes back from the loaded record\n // (`id`, plus `updated_at`/`updatedAt` used for optimistic locking). They are not custom\n // fields; without this they validate as cf_id / cf_updated_at / cf_updatedAt and are\n // rejected as \"Unknown custom field\", which fails EVERY custom-entity edit-form save.\n for (const reservedKey of ['id', 'created_at', 'createdAt', 'updated_at', 'updatedAt', 'deleted_at', 'deletedAt']) {\n delete (values as any)[reservedKey]\n }\n const norm = normalizeValues(values)\n\n // Validate against custom field definitions\n try {\n const { validateCustomFieldValuesServer } = await import('../lib/validation')\n const check = await validateCustomFieldValuesServer(em, { entityId, organizationId: targetOrgId, tenantId: auth.tenantId!, values: norm, rejectUndeclaredKeys: true })\n if (!check.ok) return NextResponse.json({ error: 'Validation failed', fields: check.fieldErrors }, { status: 400 })\n } catch { /* ignore if helper missing */ }\n\n // Normalize recordId: if blank/sentinel/non-uuid => create instead of update\n const uuidRe = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n const rid = String(recordId || '').trim()\n const low = rid.toLowerCase()\n const isSentinel = !rid || low === 'create' || low === 'new' || low === 'null' || low === 'undefined'\n const isUuid = uuidRe.test(rid)\n if (isSentinel || !isUuid) {\n const created = await de.createCustomEntityRecord({\n entityId,\n recordId: undefined,\n organizationId: targetOrgId,\n tenantId: auth.tenantId!,\n values: norm,\n })\n return NextResponse.json({ ok: true, item: { entityId, recordId: created.id } })\n }\n\n try {\n const currentUpdatedAt = await readCustomEntityRecordUpdatedAt(em, {\n entityType: entityId,\n entityId: rid,\n organizationId: targetOrgId,\n })\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: CUSTOM_ENTITY_RECORD_RESOURCE_KIND,\n resourceId: rid,\n current: currentUpdatedAt,\n request: req,\n })\n } catch (lockError) {\n if (isCrudHttpError(lockError)) {\n return NextResponse.json(lockError.body, { status: lockError.status })\n }\n throw lockError\n }\n\n await de.updateCustomEntityRecord({\n entityId,\n recordId: rid,\n organizationId: targetOrgId,\n tenantId: auth.tenantId!,\n values: norm,\n })\n return NextResponse.json({ ok: true, item: { entityId, recordId: rid } })\n } catch (e) {\n if (isCrudHttpError(e)) return NextResponse.json(e.body, { status: e.status })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nconst deleteBodySchema = z.object({\n entityId: z.string().min(1),\n recordId: z.string().min(1),\n})\n\nexport async function DELETE(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth || !auth.tenantId) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const url = new URL(req.url)\n const qpEntityId = url.searchParams.get('entityId')\n const qpRecordId = url.searchParams.get('recordId')\n let payload: any = qpEntityId && qpRecordId ? { entityId: qpEntityId, recordId: qpRecordId } : null\n if (!payload) {\n try { payload = await req.json() } catch { payload = null }\n }\n const parsed = deleteBodySchema.safeParse(payload)\n if (!parsed.success) return NextResponse.json({ error: 'Validation failed', details: parsed.error.flatten() }, { status: 400 })\n const { entityId, recordId } = parsed.data\n\n try {\n const container = await createRequestContainer()\n const { resolve } = container\n const de = resolve('dataEngine') as any\n const em = resolve('em') as any\n const rbac = resolve('rbacService') as RbacService\n const scope = await resolveOrganizationScope({ em, rbac, auth, selectedId: getSelectedOrganizationFromRequest(req) })\n const targetOrgId = scope.selectedId ?? auth.orgId\n if (!targetOrgId) return NextResponse.json({ error: 'Organization context is required' }, { status: 400 })\n const { kind: entityKind, restricted: isRestricted } = await classifyRecordsEntity(em, entityId, { tenantId: auth.tenantId ?? null, organizationId: scope.selectedId ?? auth.orgId ?? null })\n if (entityKind === 'system') return systemEntityRecordsRejection(entityId)\n const isCustomEntity = entityKind === 'custom'\n await assertEntityAclForRequest({ auth, entityId, action: 'manage', isCustomEntity, isRestricted, rbac })\n\n try {\n const currentUpdatedAt = await readCustomEntityRecordUpdatedAt(em, {\n entityType: entityId,\n entityId: recordId,\n organizationId: targetOrgId,\n })\n await enforceCommandOptimisticLockWithGuards(container, {\n resourceKind: CUSTOM_ENTITY_RECORD_RESOURCE_KIND,\n resourceId: recordId,\n current: currentUpdatedAt,\n request: req,\n })\n } catch (lockError) {\n if (isCrudHttpError(lockError)) {\n return NextResponse.json(lockError.body, { status: lockError.status })\n }\n throw lockError\n }\n\n await de.deleteCustomEntityRecord({ entityId, recordId, organizationId: targetOrgId, tenantId: auth.tenantId!, soft: true })\n return NextResponse.json({ ok: true })\n } catch (e) {\n if (isCrudHttpError(e)) return NextResponse.json(e.body, { status: e.status })\n return NextResponse.json({ error: 'Internal server error' }, { status: 500 })\n }\n}\n\nfunction normalizeValues(input: Record<string, any>): Record<string, any> {\n const out: Record<string, any> = {}\n for (const [k, v] of Object.entries(input || {})) {\n const key = k.startsWith('cf_') ? k.replace(/^cf_/, '') : k\n out[key] = v\n }\n return out\n}\n\nconst deleteResponseSchema = z.object({\n ok: z.literal(true),\n})\n\nconst errorSchema = z.object({\n error: z.string(),\n}).passthrough()\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Entities',\n summary: 'CRUD operations on entity records',\n methods: {\n GET: {\n summary: 'List records',\n description:\n 'Returns paginated records for the supplied entity. Supports custom field filters, exports, and soft-delete toggles.',\n query: listRecordsQuerySchema,\n responses: [\n {\n status: 200,\n description: 'Paginated records',\n schema: listRecordsResponseSchema,\n },\n {\n status: 400,\n description: 'Missing entity id',\n schema: errorSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: errorSchema,\n },\n {\n status: 500,\n description: 'Unexpected failure',\n schema: errorSchema,\n },\n ],\n },\n POST: {\n summary: 'Create record',\n description:\n 'Creates a record for the given entity. When `recordId` is omitted or not a UUID the data engine will generate one automatically.',\n requestBody: {\n contentType: 'application/json',\n schema: postBodySchema,\n },\n responses: [\n {\n status: 200,\n description: 'Record created',\n schema: mutationResponseSchema,\n },\n {\n status: 400,\n description: 'Validation failure',\n schema: errorSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: errorSchema,\n },\n {\n status: 500,\n description: 'Unexpected failure',\n schema: errorSchema,\n },\n ],\n },\n PUT: {\n summary: 'Update record',\n description:\n 'Updates an existing record. If the provided recordId is not a UUID the record will be created instead to support optimistic flows.',\n requestBody: {\n contentType: 'application/json',\n schema: putBodySchema,\n },\n responses: [\n {\n status: 200,\n description: 'Record updated',\n schema: mutationResponseSchema,\n },\n {\n status: 400,\n description: 'Validation failure',\n schema: errorSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: errorSchema,\n },\n {\n status: 500,\n description: 'Unexpected failure',\n schema: errorSchema,\n },\n ],\n },\n DELETE: {\n summary: 'Delete record',\n description: 'Soft deletes the specified record within the current tenant/org scope.',\n requestBody: {\n contentType: 'application/json',\n schema: deleteBodySchema,\n },\n responses: [\n {\n status: 200,\n description: 'Record deleted',\n schema: deleteResponseSchema,\n },\n {\n status: 400,\n description: 'Missing entity id or record id',\n schema: errorSchema,\n },\n {\n status: 401,\n description: 'Missing authentication',\n schema: errorSchema,\n },\n {\n status: 404,\n description: 'Record not found',\n schema: errorSchema,\n },\n {\n status: 500,\n description: 'Unexpected failure',\n schema: errorSchema,\n },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["parsed"]
|
|
7
7
|
}
|
|
@@ -159,6 +159,7 @@ function EditDefinitionsPage({ params }) {
|
|
|
159
159
|
const labelFieldValue = typeof record?.labelField === "string" && record.labelField.length > 0 ? record.labelField : "name";
|
|
160
160
|
const defaultEditorValue = typeof record?.defaultEditor === "string" ? record.defaultEditor : "";
|
|
161
161
|
const showInSidebarValue = record?.showInSidebar === true;
|
|
162
|
+
const accessRestrictedValue = record?.accessRestricted === true;
|
|
162
163
|
const updatedAtValue = typeof record?.updatedAt === "string" && record.updatedAt.length > 0 ? record.updatedAt : void 0;
|
|
163
164
|
setLabel(labelValue);
|
|
164
165
|
if (record?.source === "code" || record?.source === "custom") setEntitySource(record.source);
|
|
@@ -168,6 +169,7 @@ function EditDefinitionsPage({ params }) {
|
|
|
168
169
|
labelField: labelFieldValue,
|
|
169
170
|
defaultEditor: defaultEditorValue,
|
|
170
171
|
showInSidebar: showInSidebarValue,
|
|
172
|
+
accessRestricted: accessRestrictedValue,
|
|
171
173
|
updatedAt: updatedAtValue
|
|
172
174
|
});
|
|
173
175
|
setEntityFormLoading(false);
|
|
@@ -380,7 +382,8 @@ function EditDefinitionsPage({ params }) {
|
|
|
380
382
|
// Allow empty string in the UI select, treat as undefined later
|
|
381
383
|
defaultEditor: z.union([z.enum(["markdown", "simpleMarkdown", "htmlRichText"]).optional(), z.literal("")]).optional(),
|
|
382
384
|
// Include showInSidebar so CrudForm doesn't strip it on submit
|
|
383
|
-
showInSidebar: z.boolean().optional()
|
|
385
|
+
showInSidebar: z.boolean().optional(),
|
|
386
|
+
accessRestricted: z.boolean().optional()
|
|
384
387
|
});
|
|
385
388
|
const metadataFieldsReadOnly = entitySource === "code";
|
|
386
389
|
const fields = [
|
|
@@ -398,7 +401,13 @@ function EditDefinitionsPage({ params }) {
|
|
|
398
401
|
{ value: "htmlRichText", label: t("entities.userEntities.form.defaultEditor.options.htmlRichText", "HTML Rich Text") }
|
|
399
402
|
]
|
|
400
403
|
},
|
|
401
|
-
...entitySource === "custom" ? [{ id: "showInSidebar", label: t("entities.userEntities.form.showInSidebar.label", "Show in sidebar"), type: "checkbox" }] : []
|
|
404
|
+
...entitySource === "custom" ? [{ id: "showInSidebar", label: t("entities.userEntities.form.showInSidebar.label", "Show in sidebar"), type: "checkbox" }] : [],
|
|
405
|
+
...entitySource === "custom" ? [{
|
|
406
|
+
id: "accessRestricted",
|
|
407
|
+
label: t("entities.userEntities.form.accessRestricted.label", "Restrict record access"),
|
|
408
|
+
type: "checkbox",
|
|
409
|
+
description: t("entities.userEntities.form.accessRestricted.help", "Require an explicit per-entity permission to view or manage this entity\u2019s records. Leave off to allow anyone with the general records permission.")
|
|
410
|
+
}] : []
|
|
402
411
|
];
|
|
403
412
|
const renderFieldDefinitions = React.useCallback(
|
|
404
413
|
() => /* @__PURE__ */ jsx(
|
|
@@ -462,7 +471,7 @@ function EditDefinitionsPage({ params }) {
|
|
|
462
471
|
);
|
|
463
472
|
const definitionsGroup = { id: "definitions", title: t("entities.userEntities.edit.groups.definitions", "Field Definitions"), column: 1, component: renderFieldDefinitions };
|
|
464
473
|
const groups = [
|
|
465
|
-
{ id: "settings", title: t("entities.userEntities.edit.groups.settings", "Entity Settings"), column: 1, fields: entitySource === "custom" ? ["label", "description", "defaultEditor", "showInSidebar"] : ["label", "description", "defaultEditor"] },
|
|
474
|
+
{ id: "settings", title: t("entities.userEntities.edit.groups.settings", "Entity Settings"), column: 1, fields: entitySource === "custom" ? ["label", "description", "defaultEditor", "showInSidebar", "accessRestricted"] : ["label", "description", "defaultEditor"] },
|
|
466
475
|
definitionsGroup
|
|
467
476
|
];
|
|
468
477
|
const handleCrudFormSubmit = React.useCallback(async (vals) => {
|
|
@@ -604,7 +613,7 @@ function buildDefinitionsBatchPayload(options) {
|
|
|
604
613
|
};
|
|
605
614
|
}
|
|
606
615
|
function buildEntityMetadataPayload(entitySource, vals) {
|
|
607
|
-
const partial = entitySource === "custom" ? upsertCustomEntitySchema.pick({ label: true, description: true, labelField: true, defaultEditor: true }).extend({ showInSidebar: z.boolean().optional() }) : upsertCustomEntitySchema.pick({ label: true, description: true, defaultEditor: true });
|
|
616
|
+
const partial = entitySource === "custom" ? upsertCustomEntitySchema.pick({ label: true, description: true, labelField: true, defaultEditor: true }).extend({ showInSidebar: z.boolean().optional(), accessRestricted: z.boolean().optional() }) : upsertCustomEntitySchema.pick({ label: true, description: true, defaultEditor: true });
|
|
608
617
|
const normalized = {
|
|
609
618
|
...vals,
|
|
610
619
|
defaultEditor: typeof vals.defaultEditor === "string" && vals.defaultEditor ? vals.defaultEditor : void 0
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/entities/backend/entities/user/%5BentityId%5D/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport React, { useEffect, useMemo, useState } from 'react'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { invalidateCustomFieldDefs } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport { upsertCustomEntitySchema, upsertCustomFieldDefSchema } from '@open-mercato/core/modules/entities/data/validators'\nimport { z } from 'zod'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport Link from 'next/link'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { loadGeneratedFieldRegistrations } from '@open-mercato/ui/backend/fields/registry'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { createCrudFormError, raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { FieldDefinitionsEditor, type FieldDefinition, type FieldDefinitionError } from '@open-mercato/ui/backend/custom-fields/FieldDefinitionsEditor'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { normalizeCustomFieldOptions } from '@open-mercato/shared/modules/entities/options'\nimport { TranslationManager } from '@open-mercato/core/modules/translations/components/TranslationManager'\n\ntype Def = FieldDefinition\nexport type EntitySource = 'code' | 'custom'\ntype EntitiesListResponse = { items?: Array<Record<string, unknown>> }\ntype FieldsetGroup = { code: string; title?: string; hint?: string }\ntype FieldsetDefinition = { code: string; label: string; icon?: string; description?: string; groups?: FieldsetGroup[] }\ntype DefinitionsManageResponse = { items?: any[]; deletedKeys?: string[]; fieldsets?: FieldsetDefinition[]; settings?: { singleFieldsetPerRecord?: boolean }; version?: string | null }\ntype DefinitionsBatchResponse = { ok?: boolean; version?: string | null }\n\nfunction readVersionToken(value: unknown): string | null {\n return typeof value === 'string' && value.length > 0 ? value : null\n}\n\ntype DefErrors = FieldDefinitionError\n\n\nexport default function EditDefinitionsPage({ params }: { params?: { entityId?: string } }) {\n React.useEffect(() => { loadGeneratedFieldRegistrations().catch(() => {}) }, [])\n const router = useRouter()\n const searchParams = useSearchParams()\n const t = useT()\n const queryClient = useQueryClient()\n const entityId = useMemo(() => decodeURIComponent((params?.entityId as any) || ''), [params])\n const [label, setLabel] = useState('')\n const [entitySource, setEntitySource] = useState<EntitySource>('custom')\n const [entityFormLoading, setEntityFormLoading] = useState(true)\n const [entityInitial, setEntityInitial] = useState<{ label?: string; description?: string; labelField?: string; defaultEditor?: string; showInSidebar?: boolean; updatedAt?: string }>({})\n const [defs, setDefs] = useState<Def[]>([])\n const [defsVersion, setDefsVersion] = useState<string | null>(null)\n const [orderDirty, setOrderDirty] = useState(false)\n const [orderSaving, setOrderSaving] = useState(false)\n const listRef = React.useRef<HTMLDivElement | null>(null)\n const [loading, setLoading] = useState(true)\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [deletedKeys, setDeletedKeys] = useState<string[]>([])\n const [defErrors, setDefErrors] = useState<Record<number, DefErrors>>({})\n const [fieldsets, setFieldsets] = useState<FieldsetDefinition[]>([])\n const [activeFieldset, setActiveFieldset] = useState<string | null>(null)\n const [singleFieldsetPerRecord, setSingleFieldsetPerRecord] = useState(true)\n const [translateDef, setTranslateDef] = useState<{ def: Def; entityId: string } | null>(null)\n\n const translateFields = React.useMemo(() => {\n if (!translateDef) return undefined\n const { def } = translateDef\n const fields: string[] = ['label', 'description']\n const options = normalizeCustomFieldOptions(def.configJson?.options)\n for (const opt of options) {\n if (opt.value) fields.push(`options.${opt.value}.label`)\n }\n return fields\n }, [translateDef])\n\n const translateBaseValues = React.useMemo(() => {\n if (!translateDef) return undefined\n const { def } = translateDef\n const base: Record<string, string> = {}\n if (typeof def.configJson?.label === 'string') base.label = def.configJson.label\n if (typeof def.configJson?.description === 'string') base.description = def.configJson.description\n const options = normalizeCustomFieldOptions(def.configJson?.options)\n for (const opt of options) {\n if (opt.value && opt.label) base[`options.${opt.value}.label`] = opt.label\n }\n return base\n }, [translateDef])\n\n const requestedFieldset = React.useMemo(() => {\n const raw = searchParams?.get('fieldset')\n return raw && raw.trim().length ? raw.trim() : null\n }, [searchParams])\n const embedFieldsetView = React.useMemo(() => searchParams?.get('view') === 'fieldset', [searchParams])\n const normalizeGroupPayload = React.useCallback((value: unknown) => {\n if (!value) return null\n if (typeof value === 'string') {\n const code = value.trim()\n return code ? { code } : null\n }\n if (typeof value !== 'object') return null\n const entry = value as Record<string, unknown>\n const code = typeof entry.code === 'string' ? entry.code.trim() : ''\n if (!code) return null\n const group: FieldsetGroup = { code }\n if (typeof entry.title === 'string' && entry.title.trim()) group.title = entry.title.trim()\n if (typeof entry.hint === 'string' && entry.hint.trim()) group.hint = entry.hint.trim()\n return group\n }, [])\n\n const buildFieldsetPayload = React.useCallback(() => {\n const groupMap = new Map<string, FieldsetGroup[]>()\n defs.forEach((definition) => {\n const code = typeof definition.configJson?.fieldset === 'string' ? definition.configJson.fieldset : null\n if (!code) return\n const normalized = normalizeGroupPayload(definition.configJson?.group)\n if (!normalized) return\n const list = groupMap.get(code) ?? []\n if (!list.some((entry) => entry.code === normalized.code)) {\n list.push(normalized)\n groupMap.set(code, list)\n }\n })\n return fieldsets.map((fs) => ({\n ...fs,\n groups: groupMap.get(fs.code) ?? [],\n }))\n }, [defs, fieldsets, normalizeGroupPayload])\n\n const validateDef = React.useCallback((d: Def): DefErrors => {\n const parsed = upsertCustomFieldDefSchema.safeParse({ entityId, key: d.key, kind: d.kind, configJson: d.configJson, isActive: d.isActive })\n if (parsed.success) return {}\n const errs: DefErrors = {}\n for (const issue of parsed.error.issues) {\n if ((issue.path || []).includes('key')) errs.key = issue.message\n if ((issue.path || []).includes('kind')) errs.kind = issue.message\n }\n return errs\n }, [entityId, requestedFieldset])\n\n const validateAndSetErrorAt = (index: number, d: Def) => {\n const errs = validateDef(d)\n setDefErrors((prev) => ({ ...prev, [index]: errs }))\n return !errs.key && !errs.kind\n }\n\n const validateAll = () => {\n const nextErrors: Record<number, DefErrors> = {}\n defs.forEach((d, i) => {\n nextErrors[i] = validateDef(d)\n })\n setDefErrors(nextErrors)\n return Object.values(nextErrors).every(e => !e.key && !e.kind)\n }\n\n useEffect(() => {\n let mounted = true\n async function load() {\n setLoading(true)\n try {\n const entJson = await readApiResultOrThrow<EntitiesListResponse>(\n '/api/entities/entities',\n undefined,\n { errorMessage: t('entities.userEntities.edit.errors.loadMetadataFailed', 'Failed to load entity metadata'), fallback: { items: [] } },\n )\n const ent = (entJson.items || []).find((x: any) => x.entityId === entityId)\n if (mounted) {\n const record = ent as Record<string, unknown> | undefined\n const labelValue =\n typeof record?.label === 'string' && record.label.trim().length > 0 ? record.label : entityId\n const descriptionValue = typeof record?.description === 'string' ? record.description : ''\n const labelFieldValue =\n typeof record?.labelField === 'string' && record.labelField.length > 0 ? record.labelField : 'name'\n const defaultEditorValue =\n typeof record?.defaultEditor === 'string' ? record.defaultEditor : ''\n const showInSidebarValue = record?.showInSidebar === true\n const updatedAtValue =\n typeof record?.updatedAt === 'string' && record.updatedAt.length > 0 ? record.updatedAt : undefined\n setLabel(labelValue)\n if (record?.source === 'code' || record?.source === 'custom') setEntitySource(record.source)\n setEntityInitial({\n label: labelValue,\n description: descriptionValue,\n labelField: labelFieldValue,\n defaultEditor: defaultEditorValue,\n showInSidebar: showInSidebarValue,\n updatedAt: updatedAtValue,\n })\n setEntityFormLoading(false)\n }\n const json = await readApiResultOrThrow<DefinitionsManageResponse>(\n `/api/entities/definitions.manage?entityId=${encodeURIComponent(entityId)}`,\n undefined,\n { errorMessage: t('entities.userEntities.edit.errors.loadDefinitionsFailed', 'Failed to load entity definitions'), fallback: { items: [], deletedKeys: [] } },\n )\n if (mounted) {\n const loaded: Def[] = (json.items || []).map((d: any) => ({ key: d.key, kind: d.kind, configJson: d.configJson || {}, isActive: d.isActive !== false }))\n loaded.sort(\n (a, b) => Number(a.configJson?.priority ?? 0) - Number(b.configJson?.priority ?? 0)\n )\n setDefs(loaded)\n setDefsVersion(readVersionToken(json.version))\n setDefErrors({})\n setDeletedKeys(Array.isArray(json.deletedKeys) ? json.deletedKeys : [])\n const loadedFieldsets = Array.isArray(json.fieldsets) ? json.fieldsets : []\n setFieldsets(loadedFieldsets)\n setActiveFieldset((prev) => {\n if (requestedFieldset && loadedFieldsets.some((fs) => fs.code === requestedFieldset)) {\n return requestedFieldset\n }\n if (prev && loadedFieldsets.some((fs) => fs.code === prev)) return prev\n return loadedFieldsets[0]?.code ?? null\n })\n setSingleFieldsetPerRecord(json.settings?.singleFieldsetPerRecord !== false)\n }\n } catch (e: any) {\n if (mounted) setError(e.message || t('entities.userEntities.edit.errors.loadFailed', 'Failed to load'))\n } finally {\n if (mounted) setLoading(false)\n }\n }\n if (entityId) load()\n return () => { mounted = false }\n }, [entityId, t])\n\n function addField() {\n setDefs((arr) => [\n ...arr,\n {\n key: '',\n kind: 'text',\n configJson: activeFieldset ? { fieldset: activeFieldset } : {},\n isActive: true,\n },\n ])\n }\n\n async function restoreField(key: string) {\n try {\n const call = await apiCall('/api/entities/definitions.restore', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, key }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, t('entities.userEntities.edit.errors.restoreFieldFailed', 'Failed to restore field'))\n }\n // Reload definitions & deleted keys\n const j2 = await readApiResultOrThrow<DefinitionsManageResponse>(\n `/api/entities/definitions.manage?entityId=${encodeURIComponent(entityId)}`,\n undefined,\n { errorMessage: t('entities.userEntities.edit.errors.reloadDefinitionsFailed', 'Failed to reload field definitions'), fallback: { items: [], deletedKeys: [] } },\n )\n const loaded: Def[] = (j2.items || []).map((d: any) => ({ key: d.key, kind: d.kind, configJson: d.configJson || {}, isActive: d.isActive !== false }))\n loaded.sort(\n (a, b) => Number(a.configJson?.priority ?? 0) - Number(b.configJson?.priority ?? 0)\n )\n setDefs(loaded)\n setDefsVersion(readVersionToken(j2.version))\n setDeletedKeys(Array.isArray(j2.deletedKeys) ? j2.deletedKeys : [])\n flash(t('entities.userEntities.edit.flash.restoredField', 'Restored {{key}}', { key }), 'success')\n await invalidateCustomFieldDefs(queryClient, entityId)\n } catch (e: any) {\n flash(e?.message || t('entities.userEntities.edit.errors.restoreFieldFailed', 'Failed to restore field'), 'error')\n }\n }\n\n async function saveAll() {\n setSaving(true)\n setError(null)\n try {\n if (!validateAll()) {\n flash(t('entities.customFields.errors.validation', 'Please fix validation errors in field definitions.'), 'error')\n throw new Error(t('entities.userEntities.edit.errors.validationFailed', 'Validation failed'))\n }\n const payload = {\n entityId,\n definitions: defs.filter(d => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n }\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(defsVersion),\n () => apiCall<DefinitionsBatchResponse>('/api/entities/definitions.batch', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }),\n )\n if (!call.ok) {\n if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return\n await raiseCrudError(call.response, t('entities.customFields.errors.saveFailed', 'Failed to save field definitions.'))\n }\n setDefsVersion(readVersionToken(call.result?.version))\n await invalidateCustomFieldDefs(queryClient, entityId)\n router.push(`/backend/entities/user?flash=${encodeURIComponent(t('entities.customFields.flash.saved', 'Definitions saved'))}&type=success`)\n } catch (e: any) {\n setError(e.message || t('entities.customFields.errors.saveFailed', 'Failed to save field definitions.'))\n } finally {\n setSaving(false)\n }\n }\n\n async function removeField(idx: number) {\n const def = defs[idx]\n if (!def) return\n if (def.key) {\n try {\n const call = await apiCall<DefinitionsBatchResponse>('/api/entities/definitions', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, key: def.key }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, t('entities.customFields.errors.deleteFailed', 'Failed to delete field.'))\n }\n // Keep the optimistic-lock token in sync after an out-of-band delete so a\n // later Save does not falsely 409 against our own change (issue #3152).\n setDefsVersion(readVersionToken(call.result?.version))\n } catch (error) {\n const message = error instanceof Error ? error.message : t('entities.customFields.errors.deleteFailed', 'Failed to delete field.')\n flash(message, 'error')\n return\n }\n }\n setDefs((arr) => arr.filter((_, i) => i !== idx))\n setOrderDirty(true)\n if (def.key) {\n await invalidateCustomFieldDefs(queryClient, entityId)\n }\n }\n\n const handleFieldsetCodeChange = React.useCallback((previousCode: string, nextCode: string) => {\n if (!previousCode || !nextCode || previousCode === nextCode) return\n setDefs((arr) =>\n arr.map((entry) => {\n const current = typeof entry.configJson?.fieldset === 'string' ? entry.configJson.fieldset : undefined\n if (current !== previousCode) return entry\n const nextConfig = { ...(entry.configJson || {}) }\n nextConfig.fieldset = nextCode\n return { ...entry, configJson: nextConfig }\n })\n )\n setActiveFieldset((current) => (current === previousCode ? nextCode : current))\n }, [])\n\n const handleFieldsetRemoved = React.useCallback((code: string) => {\n if (!code) return\n setDefs((arr) =>\n arr.map((entry) => {\n const current = typeof entry.configJson?.fieldset === 'string' ? entry.configJson.fieldset : undefined\n if (current !== code) return entry\n const nextConfig = { ...(entry.configJson || {}) }\n delete nextConfig.fieldset\n delete nextConfig.group\n return { ...entry, configJson: nextConfig }\n })\n )\n }, [])\n\n async function saveOrderIfDirty() {\n if (!orderDirty) return\n setOrderSaving(true)\n try {\n // Do not save order when there are invalid keys/kinds\n if (!validateAll()) throw new Error(t('entities.userEntities.edit.errors.validationFailed', 'Validation failed'))\n const payload = {\n entityId,\n definitions: defs.filter(d => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n }\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(defsVersion),\n () => apiCall<DefinitionsBatchResponse>('/api/entities/definitions.batch', {\n method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload),\n }),\n )\n if (!call.ok) {\n // A stale reorder auto-save (another tab changed the schema first) returns a\n // 409; surface the shared conflict bar and stop the retry loop instead of a\n // generic flash (issue #3152).\n if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) {\n setOrderDirty(false)\n return\n }\n await raiseCrudError(call.response, t('entities.userEntities.edit.errors.saveOrderFailed', 'Failed to save order'))\n }\n setDefsVersion(readVersionToken(call.result?.version))\n setOrderDirty(false)\n flash(t('entities.userEntities.edit.flash.orderSaved', 'Order saved'), 'success')\n await invalidateCustomFieldDefs(queryClient, entityId)\n } catch (e: any) {\n flash(e?.message || t('entities.userEntities.edit.errors.saveOrderFailed', 'Failed to save order'), 'error')\n } finally {\n setOrderSaving(false)\n }\n }\n\n // Unify loader via CrudForm isLoading; do not return early here\n\n // Schema for inline field-level validation in CrudForm\n const entityFormSchema = upsertCustomEntitySchema\n .pick({ label: true, description: true, defaultEditor: true as any })\n .extend({\n // Allow empty string in the UI select, treat as undefined later\n defaultEditor: z.union([z.enum(['markdown','simpleMarkdown','htmlRichText']).optional(), z.literal('')]).optional(),\n // Include showInSidebar so CrudForm doesn't strip it on submit\n showInSidebar: z.boolean().optional(),\n }) as z.ZodType<Record<string, unknown>>\n\n const metadataFieldsReadOnly = entitySource === 'code'\n const fields: CrudField[] = [\n { id: 'label', label: t('entities.userEntities.form.label.label', 'Label'), type: 'text', required: true, readOnly: metadataFieldsReadOnly },\n { id: 'description', label: t('entities.userEntities.form.description.label', 'Description'), type: 'textarea', readOnly: metadataFieldsReadOnly },\n {\n id: 'defaultEditor',\n label: t('entities.userEntities.form.defaultEditor.label', 'Default Editor (multiline)'),\n type: 'select',\n readOnly: metadataFieldsReadOnly,\n options: [\n { value: '', label: t('entities.userEntities.form.defaultEditor.options.default', 'Default (Markdown)') },\n { value: 'markdown', label: t('entities.userEntities.form.defaultEditor.options.markdown', 'Markdown (UIW)') },\n { value: 'simpleMarkdown', label: t('entities.userEntities.form.defaultEditor.options.simpleMarkdown', 'Simple Markdown') },\n { value: 'htmlRichText', label: t('entities.userEntities.form.defaultEditor.options.htmlRichText', 'HTML Rich Text') },\n ],\n } as any,\n ...(entitySource === 'custom' ? [{ id: 'showInSidebar', label: t('entities.userEntities.form.showInSidebar.label', 'Show in sidebar'), type: 'checkbox' }] : []),\n ]\n const renderFieldDefinitions = React.useCallback(() => (\n <FieldDefinitionsEditor\n definitions={defs}\n errors={defErrors}\n deletedKeys={deletedKeys}\n fieldsets={fieldsets}\n activeFieldset={activeFieldset}\n onActiveFieldsetChange={setActiveFieldset}\n onFieldsetsChange={(next) => {\n setFieldsets(next)\n if (!next.some((fs) => fs.code === activeFieldset)) {\n setActiveFieldset(next[0]?.code ?? null)\n }\n }}\n onFieldsetCodeChange={handleFieldsetCodeChange}\n onFieldsetRemoved={handleFieldsetRemoved}\n singleFieldsetPerRecord={singleFieldsetPerRecord}\n onSingleFieldsetPerRecordChange={setSingleFieldsetPerRecord}\n onAddField={addField}\n onRemoveField={(index) => { void removeField(index) }}\n onDefinitionChange={(index, nextDef) => {\n setDefs((arr) => arr.map((entry, idx) => (idx === index ? nextDef : entry)))\n validateAndSetErrorAt(index, nextDef)\n }}\n onTranslate={(def) => setTranslateDef({ def, entityId })}\n onRestoreField={(key) => { void restoreField(key) }}\n onReorder={(from, to) => {\n setDefs((arr) => {\n const next = [...arr]\n const [moved] = next.splice(from, 1)\n next.splice(to, 0, moved)\n return next\n })\n setOrderDirty(true)\n }}\n orderNotice={orderDirty ? { dirty: true, saving: orderSaving, message: t('entities.userEntities.edit.orderNotice', 'Reordered - will auto-save on blur') } : undefined}\n addButtonLabel={t('entities.customFields.editor.addField', 'Add Field')}\n translate={t}\n listRef={listRef}\n listProps={{\n tabIndex: -1,\n onBlur: (event) => {\n const current = listRef.current\n const next = event.relatedTarget as Node | null\n if (!current) return\n if (!next || !current.contains(next)) {\n void saveOrderIfDirty()\n }\n },\n }}\n />\n ),\n [defs, defErrors, deletedKeys, fieldsets, activeFieldset, singleFieldsetPerRecord, orderDirty, orderSaving, addField, removeField, restoreField, saveOrderIfDirty, t])\n\n const definitionsGroup: CrudFormGroup = { id: 'definitions', title: t('entities.userEntities.edit.groups.definitions', 'Field Definitions'), column: 1, component: renderFieldDefinitions }\n\n const groups: CrudFormGroup[] = [\n { id: 'settings', title: t('entities.userEntities.edit.groups.settings', 'Entity Settings'), column: 1, fields: entitySource === 'custom' ? ['label','description','defaultEditor','showInSidebar'] : ['label','description','defaultEditor'] },\n definitionsGroup,\n ]\n\n const handleCrudFormSubmit = React.useCallback(async (vals: Record<string, unknown>) => {\n if (!entityId) {\n throw createCrudFormError(t('entities.userEntities.edit.errors.invalidEntityId', 'Invalid entity ID'))\n }\n if (!validateAll()) {\n flash(t('entities.customFields.errors.validation', 'Please fix validation errors in field definitions.'), 'error')\n throw createCrudFormError(t('entities.customFields.errors.validation', 'Please fix validation errors in field definitions.'))\n }\n // Code-declared system entities are not registered as custom entities \u2014 their\n // metadata is owned by code and `POST /api/entities/entities` is fail-closed for\n // ORM-backed system ids (#3115). Only their field definitions are user-editable, so\n // skip the registration call and persist definitions below.\n if (shouldRegisterEntityMetadata(entitySource)) {\n const entityPayload = buildEntityMetadataPayload(entitySource, vals)\n if (!entityPayload) throw createCrudFormError(t('entities.userEntities.edit.errors.validationFailed', 'Validation failed'))\n const callEntity = await apiCall('/api/entities/entities', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, ...entityPayload }),\n })\n if (!callEntity.ok) {\n await raiseCrudError(callEntity.response, t('entities.userEntities.edit.errors.saveEntityFailed', 'Failed to save entity'))\n }\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }\n const defsPayload = buildDefinitionsBatchPayload({\n entityId,\n defs,\n fieldsets: buildFieldsetPayload(),\n singleFieldsetPerRecord,\n })\n // Send the aggregate schema version so a concurrent edit is rejected with a 409\n // instead of silently overwriting the other tab (issue #3152). CrudForm's submit\n // catch detects the optimistic-lock conflict and shows the shared conflict bar.\n const callDefs = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(defsVersion),\n () => apiCall<DefinitionsBatchResponse>('/api/entities/definitions.batch', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(defsPayload),\n }),\n )\n if (!callDefs.ok) {\n await raiseCrudError(callDefs.response, t('entities.customFields.errors.saveFailed', 'Failed to save field definitions.'))\n }\n setDefsVersion(readVersionToken(callDefs.result?.version))\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n await invalidateCustomFieldDefs(queryClient, entityId)\n flash(t('entities.customFields.flash.saved', 'Definitions saved'), 'success')\n }, [buildFieldsetPayload, defs, defsVersion, entityId, entitySource, queryClient, singleFieldsetPerRecord, t, validateAll])\n\n if (!entityId) {\n return (\n <Page>\n <PageBody>\n <div className=\"p-6\">\n <Alert variant=\"destructive\">\n <AlertTitle>{t('entities.userEntities.edit.errors.invalidEntityTitle', 'Invalid entity')}</AlertTitle>\n <AlertDescription>{t('entities.userEntities.edit.errors.invalidEntityDescription', 'The requested entity ID is missing or invalid.')}</AlertDescription>\n </Alert>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (embedFieldsetView) {\n return (\n <div className=\"p-4\">\n <CrudForm\n schema={entityFormSchema}\n title={t('entities.userEntities.edit.fieldsetTitle', 'Edit fieldset: {{name}}', { name: requestedFieldset ?? entityId })}\n fields={[]}\n groups={[definitionsGroup]}\n initialValues={entityInitial as any}\n isLoading={entityFormLoading || loading}\n submitLabel={t('entities.userEntities.records.form.submitSave', 'Save')}\n deleteVisible={false}\n backHref={undefined}\n cancelHref={undefined}\n embedded\n onSubmit={handleCrudFormSubmit}\n />\n </div>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n schema={entityFormSchema}\n title={t('entities.userEntities.edit.title', 'Edit Entity: {{entityId}}', { entityId })}\n backHref={entitySource === 'code' ? \"/backend/entities/system\" : \"/backend/entities/user\"}\n fields={fields}\n groups={groups}\n initialValues={entityInitial as any}\n isLoading={entityFormLoading || loading}\n submitLabel={t('entities.userEntities.records.form.submitSave', 'Save')}\n deleteVisible={entitySource === 'custom'}\n extraActions={entitySource === 'custom' ? (\n <Button variant=\"outline\" asChild>\n <Link href={`/backend/entities/user/${encodeURIComponent(entityId)}/records`}>\n {t('entities.userEntities.edit.showRecords', 'Show Records')}\n </Link>\n </Button>\n ) : null}\n cancelHref={entitySource === 'code' ? \"/backend/entities/system\" : \"/backend/entities/user\"}\n successRedirect={entitySource === 'code'\n ? `/backend/entities/system?flash=${encodeURIComponent(t('entities.customFields.flash.saved', 'Definitions saved'))}&type=success`\n : `/backend/entities/user?flash=${encodeURIComponent(t('entities.customFields.flash.saved', 'Definitions saved'))}&type=success`}\n onSubmit={handleCrudFormSubmit}\n onDelete={entitySource === 'custom' ? async () => {\n const callDelete = await apiCall('/api/entities/entities', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ entityId }) })\n if (!callDelete.ok) {\n await raiseCrudError(callDelete.response, t('entities.userEntities.edit.errors.deleteEntityFailed', 'Failed to delete entity'))\n }\n flash(t('entities.userEntities.edit.flash.entityDeleted', 'Entity deleted'), 'success')\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n } : undefined}\n />\n </PageBody>\n <Dialog open={!!translateDef} onOpenChange={(open) => { if (!open) setTranslateDef(null) }}>\n <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{t('translations.manager.translateField', 'Translate field: {{key}}', { key: translateDef?.def.key ?? '' })}</DialogTitle>\n </DialogHeader>\n {translateDef && (\n <TranslationManager\n mode=\"embedded\"\n compact\n entityType=\"entities:custom_field_def\"\n recordId={`${translateDef.entityId}:${translateDef.def.key}`}\n baseValues={translateBaseValues}\n translatableFields={translateFields}\n />\n )}\n </DialogContent>\n </Dialog>\n </Page>\n )\n}\n\nexport function shouldRegisterEntityMetadata(entitySource: EntitySource): boolean {\n return entitySource === 'custom'\n}\n\nexport function buildDefinitionsBatchPayload(options: {\n entityId: string\n defs: Array<Pick<Def, 'key' | 'kind' | 'configJson' | 'isActive'>>\n fieldsets: FieldsetDefinition[]\n singleFieldsetPerRecord: boolean\n}) {\n return {\n entityId: options.entityId,\n definitions: options.defs.filter((d) => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n fieldsets: options.fieldsets,\n singleFieldsetPerRecord: options.singleFieldsetPerRecord,\n }\n}\n\nexport function buildEntityMetadataPayload(\n entitySource: EntitySource,\n vals: Record<string, unknown>,\n): Record<string, unknown> | null {\n const partial = entitySource === 'custom'\n ? upsertCustomEntitySchema\n .pick({ label: true, description: true, labelField: true as any, defaultEditor: true as any })\n .extend({ showInSidebar: z.boolean().optional() }) as unknown as z.ZodTypeAny\n : upsertCustomEntitySchema\n .pick({ label: true, description: true, defaultEditor: true as any }) as unknown as z.ZodTypeAny\n const normalized = {\n ...vals,\n defaultEditor: typeof vals.defaultEditor === 'string' && vals.defaultEditor ? vals.defaultEditor : undefined,\n }\n const parsed = partial.safeParse(normalized)\n return parsed.success ? (parsed.data as Record<string, unknown>) : null\n}\n"],
|
|
5
|
-
"mappings": ";AA0bM,cAoHM,YApHN;AAzbN,OAAO,SAAS,WAAW,SAAS,gBAAgB;AACpD,SAAS,WAAW,uBAAuB;AAC3C,SAAS,sBAAsB;AAC/B,SAAS,gBAAoD;AAC7D,SAAS,aAAa;AACtB,SAAS,SAAS,sBAAsB,mCAAmC;AAC3E,SAAS,iCAAiC;AAC1C,SAAS,6BAA6B;AACtC,SAAS,iCAAiC;AAC1C,SAAS,0BAA0B,kCAAkC;AACrE,SAAS,SAAS;AAClB,SAAS,MAAM,gBAAgB;AAC/B,SAAS,OAAO,kBAAkB,kBAAkB;AACpD,OAAO,UAAU;AACjB,SAAS,cAAc;AACvB,SAAS,uCAAuC;AAEhD,SAAS,qBAAqB,sBAAsB;AACpD,SAAS,8BAA+E;AACxF,SAAS,YAAY;AACrB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,mCAAmC;AAC5C,SAAS,0BAA0B;AAUnC,SAAS,iBAAiB,OAA+B;AACvD,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;AACjE;AAKe,SAAR,oBAAqC,EAAE,OAAO,GAAuC;AAC1F,QAAM,UAAU,MAAM;AAAE,oCAAgC,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAAE,GAAG,CAAC,CAAC;AAC/E,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,gBAAgB;AACrC,QAAM,IAAI,KAAK;AACf,QAAM,cAAc,eAAe;AACnC,QAAM,WAAW,QAAQ,MAAM,mBAAoB,QAAQ,YAAoB,EAAE,GAAG,CAAC,MAAM,CAAC;AAC5F,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,cAAc,eAAe,IAAI,SAAuB,QAAQ;AACvE,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAS,IAAI;AAC/D,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAA6I,CAAC,CAAC;AACzL,QAAM,CAAC,MAAM,OAAO,IAAI,SAAgB,CAAC,CAAC;AAC1C,QAAM,CAAC,aAAa,cAAc,IAAI,SAAwB,IAAI;AAClE,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAClD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AACpD,QAAM,UAAU,MAAM,OAA8B,IAAI;AACxD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAC3C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK;AAC1C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAmB,CAAC,CAAC;AAC3D,QAAM,CAAC,WAAW,YAAY,IAAI,SAAoC,CAAC,CAAC;AACxE,QAAM,CAAC,WAAW,YAAY,IAAI,SAA+B,CAAC,CAAC;AACnE,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAwB,IAAI;AACxE,QAAM,CAAC,yBAAyB,0BAA0B,IAAI,SAAS,IAAI;AAC3E,QAAM,CAAC,cAAc,eAAe,IAAI,SAAgD,IAAI;AAE5F,QAAM,kBAAkB,MAAM,QAAQ,MAAM;AAC1C,QAAI,CAAC,aAAc,QAAO;AAC1B,UAAM,EAAE,IAAI,IAAI;AAChB,UAAMA,UAAmB,CAAC,SAAS,aAAa;AAChD,UAAM,UAAU,4BAA4B,IAAI,YAAY,OAAO;AACnE,eAAW,OAAO,SAAS;AACzB,UAAI,IAAI,MAAO,CAAAA,QAAO,KAAK,WAAW,IAAI,KAAK,QAAQ;AAAA,IACzD;AACA,WAAOA;AAAA,EACT,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,sBAAsB,MAAM,QAAQ,MAAM;AAC9C,QAAI,CAAC,aAAc,QAAO;AAC1B,UAAM,EAAE,IAAI,IAAI;AAChB,UAAM,OAA+B,CAAC;AACtC,QAAI,OAAO,IAAI,YAAY,UAAU,SAAU,MAAK,QAAQ,IAAI,WAAW;AAC3E,QAAI,OAAO,IAAI,YAAY,gBAAgB,SAAU,MAAK,cAAc,IAAI,WAAW;AACvF,UAAM,UAAU,4BAA4B,IAAI,YAAY,OAAO;AACnE,eAAW,OAAO,SAAS;AACzB,UAAI,IAAI,SAAS,IAAI,MAAO,MAAK,WAAW,IAAI,KAAK,QAAQ,IAAI,IAAI;AAAA,IACvE;AACA,WAAO;AAAA,EACT,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,oBAAoB,MAAM,QAAQ,MAAM;AAC5C,UAAM,MAAM,cAAc,IAAI,UAAU;AACxC,WAAO,OAAO,IAAI,KAAK,EAAE,SAAS,IAAI,KAAK,IAAI;AAAA,EACjD,GAAG,CAAC,YAAY,CAAC;AACjB,QAAM,oBAAoB,MAAM,QAAQ,MAAM,cAAc,IAAI,MAAM,MAAM,YAAY,CAAC,YAAY,CAAC;AACtG,QAAM,wBAAwB,MAAM,YAAY,CAAC,UAAmB;AAClE,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAMC,QAAO,MAAM,KAAK;AACxB,aAAOA,QAAO,EAAE,MAAAA,MAAK,IAAI;AAAA,IAC3B;AACA,QAAI,OAAO,UAAU,SAAU,QAAO;AACtC,UAAM,QAAQ;AACd,UAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,KAAK,KAAK,IAAI;AAClE,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,QAAuB,EAAE,KAAK;AACpC,QAAI,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,KAAK,EAAG,OAAM,QAAQ,MAAM,MAAM,KAAK;AAC1F,QAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,KAAK,EAAG,OAAM,OAAO,MAAM,KAAK,KAAK;AACtF,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,uBAAuB,MAAM,YAAY,MAAM;AACnD,UAAM,WAAW,oBAAI,IAA6B;AAClD,SAAK,QAAQ,CAAC,eAAe;AAC3B,YAAM,OAAO,OAAO,WAAW,YAAY,aAAa,WAAW,WAAW,WAAW,WAAW;AACpG,UAAI,CAAC,KAAM;AACX,YAAM,aAAa,sBAAsB,WAAW,YAAY,KAAK;AACrE,UAAI,CAAC,WAAY;AACjB,YAAM,OAAO,SAAS,IAAI,IAAI,KAAK,CAAC;AACpC,UAAI,CAAC,KAAK,KAAK,CAAC,UAAU,MAAM,SAAS,WAAW,IAAI,GAAG;AACzD,aAAK,KAAK,UAAU;AACpB,iBAAS,IAAI,MAAM,IAAI;AAAA,MACzB;AAAA,IACF,CAAC;AACD,WAAO,UAAU,IAAI,CAAC,QAAQ;AAAA,MAC5B,GAAG;AAAA,MACH,QAAQ,SAAS,IAAI,GAAG,IAAI,KAAK,CAAC;AAAA,IACpC,EAAE;AAAA,EACJ,GAAG,CAAC,MAAM,WAAW,qBAAqB,CAAC;AAE3C,QAAM,cAAc,MAAM,YAAY,CAAC,MAAsB;AAC3D,UAAM,SAAS,2BAA2B,UAAU,EAAE,UAAU,KAAK,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,EAAE,YAAY,UAAU,EAAE,SAAS,CAAC;AAC1I,QAAI,OAAO,QAAS,QAAO,CAAC;AAC5B,UAAM,OAAkB,CAAC;AACzB,eAAW,SAAS,OAAO,MAAM,QAAQ;AACvC,WAAK,MAAM,QAAQ,CAAC,GAAG,SAAS,KAAK,EAAG,MAAK,MAAM,MAAM;AACzD,WAAK,MAAM,QAAQ,CAAC,GAAG,SAAS,MAAM,EAAG,MAAK,OAAO,MAAM;AAAA,IAC7D;AACA,WAAO;AAAA,EACT,GAAG,CAAC,UAAU,iBAAiB,CAAC;AAEhC,QAAM,wBAAwB,CAAC,OAAe,MAAW;AACvD,UAAM,OAAO,YAAY,CAAC;AAC1B,iBAAa,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,KAAK,GAAG,KAAK,EAAE;AACnD,WAAO,CAAC,KAAK,OAAO,CAAC,KAAK;AAAA,EAC5B;AAEA,QAAM,cAAc,MAAM;AACxB,UAAM,aAAwC,CAAC;AAC/C,SAAK,QAAQ,CAAC,GAAG,MAAM;AACrB,iBAAW,CAAC,IAAI,YAAY,CAAC;AAAA,IAC/B,CAAC;AACD,iBAAa,UAAU;AACvB,WAAO,OAAO,OAAO,UAAU,EAAE,MAAM,OAAK,CAAC,EAAE,OAAO,CAAC,EAAE,IAAI;AAAA,EAC/D;AAEA,YAAU,MAAM;AACd,QAAI,UAAU;AACd,mBAAe,OAAO;AACpB,iBAAW,IAAI;AACf,UAAI;AACF,cAAM,UAAU,MAAM;AAAA,UACpB;AAAA,UACA;AAAA,UACA,EAAE,cAAc,EAAE,wDAAwD,gCAAgC,GAAG,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,QACvI;AACA,cAAM,OAAO,QAAQ,SAAS,CAAC,GAAG,KAAK,CAAC,MAAW,EAAE,aAAa,QAAQ;AAC1E,YAAI,SAAS;AACX,gBAAM,SAAS;AACf,gBAAM,aACJ,OAAO,QAAQ,UAAU,YAAY,OAAO,MAAM,KAAK,EAAE,SAAS,IAAI,OAAO,QAAQ;AACvF,gBAAM,mBAAmB,OAAO,QAAQ,gBAAgB,WAAW,OAAO,cAAc;AACxF,gBAAM,kBACJ,OAAO,QAAQ,eAAe,YAAY,OAAO,WAAW,SAAS,IAAI,OAAO,aAAa;AAC/F,gBAAM,qBACJ,OAAO,QAAQ,kBAAkB,WAAW,OAAO,gBAAgB;AACrE,gBAAM,qBAAqB,QAAQ,kBAAkB;AACrD,gBAAM,iBACJ,OAAO,QAAQ,cAAc,YAAY,OAAO,UAAU,SAAS,IAAI,OAAO,YAAY;AAC5F,mBAAS,UAAU;AACnB,cAAI,QAAQ,WAAW,UAAU,QAAQ,WAAW,SAAU,iBAAgB,OAAO,MAAM;AAC3F,2BAAiB;AAAA,YACf,OAAO;AAAA,YACP,aAAa;AAAA,YACb,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,eAAe;AAAA,YACf,WAAW;AAAA,UACb,CAAC;AACD,+BAAqB,KAAK;AAAA,QAC5B;AACA,cAAM,OAAO,MAAM;AAAA,UACjB,6CAA6C,mBAAmB,QAAQ,CAAC;AAAA,UACzE;AAAA,UACA,EAAE,cAAc,EAAE,2DAA2D,mCAAmC,GAAG,UAAU,EAAE,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE,EAAE;AAAA,QAC9J;AACA,YAAI,SAAS;AACX,gBAAM,UAAiB,KAAK,SAAS,CAAC,GAAG,IAAI,CAAC,OAAY,EAAE,KAAK,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,EAAE,cAAc,CAAC,GAAG,UAAU,EAAE,aAAa,MAAM,EAAE;AACvJ,iBAAO;AAAA,YACL,CAAC,GAAG,MAAM,OAAO,EAAE,YAAY,YAAY,CAAC,IAAI,OAAO,EAAE,YAAY,YAAY,CAAC;AAAA,UACpF;AACA,kBAAQ,MAAM;AACd,yBAAe,iBAAiB,KAAK,OAAO,CAAC;AAC7C,uBAAa,CAAC,CAAC;AACf,yBAAe,MAAM,QAAQ,KAAK,WAAW,IAAI,KAAK,cAAc,CAAC,CAAC;AACtE,gBAAM,kBAAkB,MAAM,QAAQ,KAAK,SAAS,IAAI,KAAK,YAAY,CAAC;AAC1E,uBAAa,eAAe;AAC5B,4BAAkB,CAAC,SAAS;AAC1B,gBAAI,qBAAqB,gBAAgB,KAAK,CAAC,OAAO,GAAG,SAAS,iBAAiB,GAAG;AACpF,qBAAO;AAAA,YACT;AACA,gBAAI,QAAQ,gBAAgB,KAAK,CAAC,OAAO,GAAG,SAAS,IAAI,EAAG,QAAO;AACnE,mBAAO,gBAAgB,CAAC,GAAG,QAAQ;AAAA,UACrC,CAAC;AACD,qCAA2B,KAAK,UAAU,4BAA4B,KAAK;AAAA,QAC7E;AAAA,MACF,SAAS,GAAQ;AACf,YAAI,QAAS,UAAS,EAAE,WAAW,EAAE,gDAAgD,gBAAgB,CAAC;AAAA,MACxG,UAAE;AACA,YAAI,QAAS,YAAW,KAAK;AAAA,MAC/B;AAAA,IACF;AACA,QAAI,SAAU,MAAK;AACnB,WAAO,MAAM;AAAE,gBAAU;AAAA,IAAM;AAAA,EACjC,GAAG,CAAC,UAAU,CAAC,CAAC;AAEhB,WAAS,WAAW;AAClB,YAAQ,CAAC,QAAQ;AAAA,MACf,GAAG;AAAA,MACH;AAAA,QACE,KAAK;AAAA,QACL,MAAM;AAAA,QACN,YAAY,iBAAiB,EAAE,UAAU,eAAe,IAAI,CAAC;AAAA,QAC7D,UAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAEA,iBAAe,aAAa,KAAa;AACvC,QAAI;AACF,YAAM,OAAO,MAAM,QAAQ,qCAAqC;AAAA,QAC9D,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,UAAU,IAAI,CAAC;AAAA,MACxC,CAAC;AACD,UAAI,CAAC,KAAK,IAAI;AACZ,cAAM,eAAe,KAAK,UAAU,EAAE,wDAAwD,yBAAyB,CAAC;AAAA,MAC1H;AAEA,YAAM,KAAK,MAAM;AAAA,QACf,6CAA6C,mBAAmB,QAAQ,CAAC;AAAA,QACzE;AAAA,QACA,EAAE,cAAc,EAAE,6DAA6D,oCAAoC,GAAG,UAAU,EAAE,OAAO,CAAC,GAAG,aAAa,CAAC,EAAE,EAAE;AAAA,MACjK;AACA,YAAM,UAAiB,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,OAAY,EAAE,KAAK,EAAE,KAAK,MAAM,EAAE,MAAM,YAAY,EAAE,cAAc,CAAC,GAAG,UAAU,EAAE,aAAa,MAAM,EAAE;AACrJ,aAAO;AAAA,QACL,CAAC,GAAG,MAAM,OAAO,EAAE,YAAY,YAAY,CAAC,IAAI,OAAO,EAAE,YAAY,YAAY,CAAC;AAAA,MACpF;AACA,cAAQ,MAAM;AACd,qBAAe,iBAAiB,GAAG,OAAO,CAAC;AAC3C,qBAAe,MAAM,QAAQ,GAAG,WAAW,IAAI,GAAG,cAAc,CAAC,CAAC;AAClE,YAAM,EAAE,kDAAkD,oBAAoB,EAAE,IAAI,CAAC,GAAG,SAAS;AACjG,YAAM,0BAA0B,aAAa,QAAQ;AAAA,IACvD,SAAS,GAAQ;AACf,YAAM,GAAG,WAAW,EAAE,wDAAwD,yBAAyB,GAAG,OAAO;AAAA,IACnH;AAAA,EACF;AAEA,iBAAe,UAAU;AACvB,cAAU,IAAI;AACd,aAAS,IAAI;AACb,QAAI;AACF,UAAI,CAAC,YAAY,GAAG;AAClB,cAAM,EAAE,2CAA2C,oDAAoD,GAAG,OAAO;AACjH,cAAM,IAAI,MAAM,EAAE,sDAAsD,mBAAmB,CAAC;AAAA,MAC9F;AACA,YAAM,UAAU;AAAA,QACd;AAAA,QACA,aAAa,KAAK,OAAO,OAAK,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO;AAAA,UACjD,KAAK,EAAE;AAAA,UACP,MAAM,EAAE;AAAA,UACR,YAAY,EAAE;AAAA,UACd,UAAU,EAAE,aAAa;AAAA,QAC3B,EAAE;AAAA,MACJ;AACA,YAAM,OAAO,MAAM;AAAA,QACjB,0BAA0B,WAAW;AAAA,QACrC,MAAM,QAAkC,mCAAmC;AAAA,UACzE,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,QAC9B,CAAC;AAAA,MACH;AACA,UAAI,CAAC,KAAK,IAAI;AACZ,YAAI,sBAAsB,EAAE,QAAQ,KAAK,QAAQ,MAAM,KAAK,OAAO,GAAG,CAAC,EAAG;AAC1E,cAAM,eAAe,KAAK,UAAU,EAAE,2CAA2C,mCAAmC,CAAC;AAAA,MACvH;AACA,qBAAe,iBAAiB,KAAK,QAAQ,OAAO,CAAC;AACrD,YAAM,0BAA0B,aAAa,QAAQ;AACrD,aAAO,KAAK,gCAAgC,mBAAmB,EAAE,qCAAqC,mBAAmB,CAAC,CAAC,eAAe;AAAA,IAC5I,SAAS,GAAQ;AACf,eAAS,EAAE,WAAW,EAAE,2CAA2C,mCAAmC,CAAC;AAAA,IACzG,UAAE;AACA,gBAAU,KAAK;AAAA,IACjB;AAAA,EACF;AAEA,iBAAe,YAAY,KAAa;AACtC,UAAM,MAAM,KAAK,GAAG;AACpB,QAAI,CAAC,IAAK;AACV,QAAI,IAAI,KAAK;AACX,UAAI;AACF,cAAM,OAAO,MAAM,QAAkC,6BAA6B;AAAA,UAChF,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,EAAE,UAAU,KAAK,IAAI,IAAI,CAAC;AAAA,QACjD,CAAC;AACD,YAAI,CAAC,KAAK,IAAI;AACZ,gBAAM,eAAe,KAAK,UAAU,EAAE,6CAA6C,yBAAyB,CAAC;AAAA,QAC/G;AAGA,uBAAe,iBAAiB,KAAK,QAAQ,OAAO,CAAC;AAAA,MACvD,SAASC,QAAO;AACd,cAAM,UAAUA,kBAAiB,QAAQA,OAAM,UAAU,EAAE,6CAA6C,yBAAyB;AACjI,cAAM,SAAS,OAAO;AACtB;AAAA,MACF;AAAA,IACF;AACA,YAAQ,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,MAAM,MAAM,GAAG,CAAC;AAChD,kBAAc,IAAI;AAClB,QAAI,IAAI,KAAK;AACX,YAAM,0BAA0B,aAAa,QAAQ;AAAA,IACvD;AAAA,EACF;AAEA,QAAM,2BAA2B,MAAM,YAAY,CAAC,cAAsB,aAAqB;AAC7F,QAAI,CAAC,gBAAgB,CAAC,YAAY,iBAAiB,SAAU;AAC7D;AAAA,MAAQ,CAAC,QACP,IAAI,IAAI,CAAC,UAAU;AACjB,cAAM,UAAU,OAAO,MAAM,YAAY,aAAa,WAAW,MAAM,WAAW,WAAW;AAC7F,YAAI,YAAY,aAAc,QAAO;AACrC,cAAM,aAAa,EAAE,GAAI,MAAM,cAAc,CAAC,EAAG;AACjD,mBAAW,WAAW;AACtB,eAAO,EAAE,GAAG,OAAO,YAAY,WAAW;AAAA,MAC5C,CAAC;AAAA,IACH;AACA,sBAAkB,CAAC,YAAa,YAAY,eAAe,WAAW,OAAQ;AAAA,EAChF,GAAG,CAAC,CAAC;AAEL,QAAM,wBAAwB,MAAM,YAAY,CAAC,SAAiB;AAChE,QAAI,CAAC,KAAM;AACX;AAAA,MAAQ,CAAC,QACP,IAAI,IAAI,CAAC,UAAU;AACjB,cAAM,UAAU,OAAO,MAAM,YAAY,aAAa,WAAW,MAAM,WAAW,WAAW;AAC7F,YAAI,YAAY,KAAM,QAAO;AAC7B,cAAM,aAAa,EAAE,GAAI,MAAM,cAAc,CAAC,EAAG;AACjD,eAAO,WAAW;AAClB,eAAO,WAAW;AAClB,eAAO,EAAE,GAAG,OAAO,YAAY,WAAW;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,iBAAe,mBAAmB;AAChC,QAAI,CAAC,WAAY;AACjB,mBAAe,IAAI;AACnB,QAAI;AAEF,UAAI,CAAC,YAAY,EAAG,OAAM,IAAI,MAAM,EAAE,sDAAsD,mBAAmB,CAAC;AAChH,YAAM,UAAU;AAAA,QACd;AAAA,QACA,aAAa,KAAK,OAAO,OAAK,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO;AAAA,UACjD,KAAK,EAAE;AAAA,UACP,MAAM,EAAE;AAAA,UACR,YAAY,EAAE;AAAA,UACd,UAAU,EAAE,aAAa;AAAA,QAC3B,EAAE;AAAA,MACJ;AACA,YAAM,OAAO,MAAM;AAAA,QACjB,0BAA0B,WAAW;AAAA,QACrC,MAAM,QAAkC,mCAAmC;AAAA,UACzE,QAAQ;AAAA,UAAQ,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAAG,MAAM,KAAK,UAAU,OAAO;AAAA,QAC/F,CAAC;AAAA,MACH;AACA,UAAI,CAAC,KAAK,IAAI;AAIZ,YAAI,sBAAsB,EAAE,QAAQ,KAAK,QAAQ,MAAM,KAAK,OAAO,GAAG,CAAC,GAAG;AACxE,wBAAc,KAAK;AACnB;AAAA,QACF;AACA,cAAM,eAAe,KAAK,UAAU,EAAE,qDAAqD,sBAAsB,CAAC;AAAA,MACpH;AACA,qBAAe,iBAAiB,KAAK,QAAQ,OAAO,CAAC;AACrD,oBAAc,KAAK;AACnB,YAAM,EAAE,+CAA+C,aAAa,GAAG,SAAS;AAChF,YAAM,0BAA0B,aAAa,QAAQ;AAAA,IACvD,SAAS,GAAQ;AACf,YAAM,GAAG,WAAW,EAAE,qDAAqD,sBAAsB,GAAG,OAAO;AAAA,IAC7G,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAKA,QAAM,mBAAmB,yBACtB,KAAK,EAAE,OAAO,MAAM,aAAa,MAAM,eAAe,KAAY,CAAC,EACnE,OAAO;AAAA;AAAA,IAEN,eAAe,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,YAAW,kBAAiB,cAAc,CAAC,EAAE,SAAS,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS;AAAA;AAAA,IAElH,eAAe,EAAE,QAAQ,EAAE,SAAS;AAAA,EACtC,CAAC;AAEH,QAAM,yBAAyB,iBAAiB;AAChD,QAAM,SAAsB;AAAA,IAC1B,EAAE,IAAI,SAAS,OAAO,EAAE,0CAA0C,OAAO,GAAG,MAAM,QAAQ,UAAU,MAAM,UAAU,uBAAuB;AAAA,IAC3I,EAAE,IAAI,eAAe,OAAO,EAAE,gDAAgD,aAAa,GAAG,MAAM,YAAY,UAAU,uBAAuB;AAAA,IACjJ;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,kDAAkD,4BAA4B;AAAA,MACvF,MAAM;AAAA,MACN,UAAU;AAAA,MACV,SAAS;AAAA,QACP,EAAE,OAAO,IAAI,OAAO,EAAE,4DAA4D,oBAAoB,EAAE;AAAA,QACxG,EAAE,OAAO,YAAY,OAAO,EAAE,6DAA6D,gBAAgB,EAAE;AAAA,QAC7G,EAAE,OAAO,kBAAkB,OAAO,EAAE,mEAAmE,iBAAiB,EAAE;AAAA,QAC1H,EAAE,OAAO,gBAAgB,OAAO,EAAE,iEAAiE,gBAAgB,EAAE;AAAA,MACvH;AAAA,IACF;AAAA,IACA,GAAI,iBAAiB,WAAW,CAAC,EAAE,IAAI,iBAAiB,OAAO,EAAE,kDAAkD,iBAAiB,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC;AAAA,EAChK;AACA,QAAM,yBAAyB,MAAM;AAAA,IAAY,MAC7C;AAAA,MAAC;AAAA;AAAA,QACC,aAAa;AAAA,QACb,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA,wBAAwB;AAAA,QACxB,mBAAmB,CAAC,SAAS;AAC3B,uBAAa,IAAI;AACjB,cAAI,CAAC,KAAK,KAAK,CAAC,OAAO,GAAG,SAAS,cAAc,GAAG;AAClD,8BAAkB,KAAK,CAAC,GAAG,QAAQ,IAAI;AAAA,UACzC;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,QACtB,mBAAmB;AAAA,QACnB;AAAA,QACA,iCAAiC;AAAA,QACjC,YAAY;AAAA,QACZ,eAAe,CAAC,UAAU;AAAE,eAAK,YAAY,KAAK;AAAA,QAAE;AAAA,QACpD,oBAAoB,CAAC,OAAO,YAAY;AACtC,kBAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,QAAS,QAAQ,QAAQ,UAAU,KAAM,CAAC;AAC3E,gCAAsB,OAAO,OAAO;AAAA,QACtC;AAAA,QACA,aAAa,CAAC,QAAQ,gBAAgB,EAAE,KAAK,SAAS,CAAC;AAAA,QACvD,gBAAgB,CAAC,QAAQ;AAAE,eAAK,aAAa,GAAG;AAAA,QAAE;AAAA,QAClD,WAAW,CAAC,MAAM,OAAO;AACvB,kBAAQ,CAAC,QAAQ;AACf,kBAAM,OAAO,CAAC,GAAG,GAAG;AACpB,kBAAM,CAAC,KAAK,IAAI,KAAK,OAAO,MAAM,CAAC;AACnC,iBAAK,OAAO,IAAI,GAAG,KAAK;AACxB,mBAAO;AAAA,UACT,CAAC;AACD,wBAAc,IAAI;AAAA,QACpB;AAAA,QACA,aAAa,aAAa,EAAE,OAAO,MAAM,QAAQ,aAAa,SAAS,EAAE,0CAA0C,oCAAoC,EAAE,IAAI;AAAA,QAC7J,gBAAgB,EAAE,yCAAyC,WAAW;AAAA,QACtE,WAAW;AAAA,QACX;AAAA,QACA,WAAW;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,CAAC,UAAU;AACjB,kBAAM,UAAU,QAAQ;AACxB,kBAAM,OAAO,MAAM;AACnB,gBAAI,CAAC,QAAS;AACd,gBAAI,CAAC,QAAQ,CAAC,QAAQ,SAAS,IAAI,GAAG;AACpC,mBAAK,iBAAiB;AAAA,YACxB;AAAA,UACF;AAAA,QACF;AAAA;AAAA,IACF;AAAA,IAEJ,CAAC,MAAM,WAAW,aAAa,WAAW,gBAAgB,yBAAyB,YAAY,aAAa,UAAU,aAAa,cAAc,kBAAkB,CAAC;AAAA,EAAC;AAErK,QAAM,mBAAkC,EAAE,IAAI,eAAe,OAAO,EAAE,iDAAiD,mBAAmB,GAAG,QAAQ,GAAG,WAAW,uBAAuB;AAE1L,QAAM,SAA0B;AAAA,IAC9B,EAAE,IAAI,YAAY,OAAO,EAAE,8CAA8C,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,iBAAiB,WAAW,CAAC,SAAQ,eAAc,iBAAgB,eAAe,IAAI,CAAC,SAAQ,eAAc,eAAe,EAAE;AAAA,IAC9O;AAAA,EACF;AAEA,QAAM,uBAAuB,MAAM,YAAY,OAAO,SAAkC;AACtF,QAAI,CAAC,UAAU;AACb,YAAM,oBAAoB,EAAE,qDAAqD,mBAAmB,CAAC;AAAA,IACvG;AACA,QAAI,CAAC,YAAY,GAAG;AAClB,YAAM,EAAE,2CAA2C,oDAAoD,GAAG,OAAO;AACjH,YAAM,oBAAoB,EAAE,2CAA2C,oDAAoD,CAAC;AAAA,IAC9H;AAKA,QAAI,6BAA6B,YAAY,GAAG;AAC9C,YAAM,gBAAgB,2BAA2B,cAAc,IAAI;AACnE,UAAI,CAAC,cAAe,OAAM,oBAAoB,EAAE,sDAAsD,mBAAmB,CAAC;AAC1H,YAAM,aAAa,MAAM,QAAQ,0BAA0B;AAAA,QACzD,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,UAAU,GAAG,cAAc,CAAC;AAAA,MACrD,CAAC;AACD,UAAI,CAAC,WAAW,IAAI;AAClB,cAAM,eAAe,WAAW,UAAU,EAAE,sDAAsD,uBAAuB,CAAC;AAAA,MAC5H;AACA,UAAI;AAAE,eAAO,cAAc,IAAI,MAAM,oBAAoB,CAAC;AAAA,MAAE,QAAQ;AAAA,MAAC;AAAA,IACvE;AACA,UAAM,cAAc,6BAA6B;AAAA,MAC/C;AAAA,MACA;AAAA,MACA,WAAW,qBAAqB;AAAA,MAChC;AAAA,IACF,CAAC;AAID,UAAM,WAAW,MAAM;AAAA,MACrB,0BAA0B,WAAW;AAAA,MACrC,MAAM,QAAkC,mCAAmC;AAAA,QACzE,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,WAAW;AAAA,MAClC,CAAC;AAAA,IACH;AACA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,eAAe,SAAS,UAAU,EAAE,2CAA2C,mCAAmC,CAAC;AAAA,IAC3H;AACA,mBAAe,iBAAiB,SAAS,QAAQ,OAAO,CAAC;AACzD,QAAI;AAAE,aAAO,cAAc,IAAI,MAAM,oBAAoB,CAAC;AAAA,IAAE,QAAQ;AAAA,IAAC;AACrE,UAAM,0BAA0B,aAAa,QAAQ;AACrD,UAAM,EAAE,qCAAqC,mBAAmB,GAAG,SAAS;AAAA,EAC9E,GAAG,CAAC,sBAAsB,MAAM,aAAa,UAAU,cAAc,aAAa,yBAAyB,GAAG,WAAW,CAAC;AAE1H,MAAI,CAAC,UAAU;AACb,WACE,oBAAC,QACC,8BAAC,YACC,8BAAC,SAAI,WAAU,OACb,+BAAC,SAAM,SAAQ,eACb;AAAA,0BAAC,cAAY,YAAE,wDAAwD,gBAAgB,GAAE;AAAA,MACzF,oBAAC,oBAAkB,YAAE,8DAA8D,gDAAgD,GAAE;AAAA,OACvI,GACF,GACF,GACF;AAAA,EAEJ;AAEA,MAAI,mBAAmB;AACrB,WACE,oBAAC,SAAI,WAAU,OACb;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ;AAAA,QACR,OAAO,EAAE,4CAA4C,2BAA2B,EAAE,MAAM,qBAAqB,SAAS,CAAC;AAAA,QACvH,QAAQ,CAAC;AAAA,QACT,QAAQ,CAAC,gBAAgB;AAAA,QACzB,eAAe;AAAA,QACf,WAAW,qBAAqB;AAAA,QAChC,aAAa,EAAE,iDAAiD,MAAM;AAAA,QACtE,eAAe;AAAA,QACf,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,UAAQ;AAAA,QACR,UAAU;AAAA;AAAA,IACZ,GACF;AAAA,EAEJ;AAEA,SACE,qBAAC,QACC;AAAA,wBAAC,YACC;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ;AAAA,QACR,OAAO,EAAE,oCAAoC,6BAA6B,EAAE,SAAS,CAAC;AAAA,QACtF,UAAU,iBAAiB,SAAS,6BAA6B;AAAA,QACjE;AAAA,QACA;AAAA,QACA,eAAe;AAAA,QACf,WAAW,qBAAqB;AAAA,QAChC,aAAa,EAAE,iDAAiD,MAAM;AAAA,QACtE,eAAe,iBAAiB;AAAA,QAChC,cAAc,iBAAiB,WAC7B,oBAAC,UAAO,SAAQ,WAAU,SAAO,MAC/B,8BAAC,QAAK,MAAM,0BAA0B,mBAAmB,QAAQ,CAAC,YAC/D,YAAE,0CAA0C,cAAc,GAC7D,GACF,IACE;AAAA,QACJ,YAAY,iBAAiB,SAAS,6BAA6B;AAAA,QACnE,iBAAiB,iBAAiB,SAC9B,kCAAkC,mBAAmB,EAAE,qCAAqC,mBAAmB,CAAC,CAAC,kBACjH,gCAAgC,mBAAmB,EAAE,qCAAqC,mBAAmB,CAAC,CAAC;AAAA,QACnH,UAAU;AAAA,QACZ,UAAU,iBAAiB,WAAW,YAAY;AAChD,gBAAM,aAAa,MAAM,QAAQ,0BAA0B,EAAE,QAAQ,UAAU,SAAS,EAAE,gBAAgB,mBAAmB,GAAG,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC,EAAE,CAAC;AACpK,cAAI,CAAC,WAAW,IAAI;AAClB,kBAAM,eAAe,WAAW,UAAU,EAAE,wDAAwD,yBAAyB,CAAC;AAAA,UAChI;AACA,gBAAM,EAAE,kDAAkD,gBAAgB,GAAG,SAAS;AACtF,cAAI;AAAE,mBAAO,cAAc,IAAI,MAAM,oBAAoB,CAAC;AAAA,UAAE,QAAQ;AAAA,UAAC;AAAA,QACvE,IAAI;AAAA;AAAA,IACN,GACA;AAAA,IACA,oBAAC,UAAO,MAAM,CAAC,CAAC,cAAc,cAAc,CAAC,SAAS;AAAE,UAAI,CAAC,KAAM,iBAAgB,IAAI;AAAA,IAAE,GACvF,+BAAC,iBAAc,WAAU,0CACvB;AAAA,0BAAC,gBACC,8BAAC,eAAa,YAAE,uCAAuC,4BAA4B,EAAE,KAAK,cAAc,IAAI,OAAO,GAAG,CAAC,GAAE,GAC3H;AAAA,MACC,gBACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAO;AAAA,UACP,YAAW;AAAA,UACX,UAAU,GAAG,aAAa,QAAQ,IAAI,aAAa,IAAI,GAAG;AAAA,UAC1D,YAAY;AAAA,UACZ,oBAAoB;AAAA;AAAA,MACtB;AAAA,OAEJ,GACF;AAAA,KACF;AAEJ;AAEO,SAAS,6BAA6B,cAAqC;AAChF,SAAO,iBAAiB;AAC1B;AAEO,SAAS,6BAA6B,SAK1C;AACD,SAAO;AAAA,IACL,UAAU,QAAQ;AAAA,IAClB,aAAa,QAAQ,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO;AAAA,MAC3D,KAAK,EAAE;AAAA,MACP,MAAM,EAAE;AAAA,MACR,YAAY,EAAE;AAAA,MACd,UAAU,EAAE,aAAa;AAAA,IAC3B,EAAE;AAAA,IACF,WAAW,QAAQ;AAAA,IACnB,yBAAyB,QAAQ;AAAA,EACnC;AACF;AAEO,SAAS,2BACd,cACA,MACgC;AAChC,QAAM,UAAU,iBAAiB,WAC7B,yBACG,KAAK,EAAE,OAAO,MAAM,aAAa,MAAM,YAAY,MAAa,eAAe,KAAY,CAAC,EAC5F,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,IACnD,yBACG,KAAK,EAAE,OAAO,MAAM,aAAa,MAAM,eAAe,KAAY,CAAC;AAC1E,QAAM,aAAa;AAAA,IACjB,GAAG;AAAA,IACH,eAAe,OAAO,KAAK,kBAAkB,YAAY,KAAK,gBAAgB,KAAK,gBAAgB;AAAA,EACrG;AACA,QAAM,SAAS,QAAQ,UAAU,UAAU;AAC3C,SAAO,OAAO,UAAW,OAAO,OAAmC;AACrE;",
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport React, { useEffect, useMemo, useState } from 'react'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { invalidateCustomFieldDefs } from '@open-mercato/ui/backend/utils/customFieldDefs'\nimport { upsertCustomEntitySchema, upsertCustomFieldDefSchema } from '@open-mercato/core/modules/entities/data/validators'\nimport { z } from 'zod'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport Link from 'next/link'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { loadGeneratedFieldRegistrations } from '@open-mercato/ui/backend/fields/registry'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { createCrudFormError, raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { FieldDefinitionsEditor, type FieldDefinition, type FieldDefinitionError } from '@open-mercato/ui/backend/custom-fields/FieldDefinitionsEditor'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { normalizeCustomFieldOptions } from '@open-mercato/shared/modules/entities/options'\nimport { TranslationManager } from '@open-mercato/core/modules/translations/components/TranslationManager'\n\ntype Def = FieldDefinition\nexport type EntitySource = 'code' | 'custom'\ntype EntitiesListResponse = { items?: Array<Record<string, unknown>> }\ntype FieldsetGroup = { code: string; title?: string; hint?: string }\ntype FieldsetDefinition = { code: string; label: string; icon?: string; description?: string; groups?: FieldsetGroup[] }\ntype DefinitionsManageResponse = { items?: any[]; deletedKeys?: string[]; fieldsets?: FieldsetDefinition[]; settings?: { singleFieldsetPerRecord?: boolean }; version?: string | null }\ntype DefinitionsBatchResponse = { ok?: boolean; version?: string | null }\n\nfunction readVersionToken(value: unknown): string | null {\n return typeof value === 'string' && value.length > 0 ? value : null\n}\n\ntype DefErrors = FieldDefinitionError\n\n\nexport default function EditDefinitionsPage({ params }: { params?: { entityId?: string } }) {\n React.useEffect(() => { loadGeneratedFieldRegistrations().catch(() => {}) }, [])\n const router = useRouter()\n const searchParams = useSearchParams()\n const t = useT()\n const queryClient = useQueryClient()\n const entityId = useMemo(() => decodeURIComponent((params?.entityId as any) || ''), [params])\n const [label, setLabel] = useState('')\n const [entitySource, setEntitySource] = useState<EntitySource>('custom')\n const [entityFormLoading, setEntityFormLoading] = useState(true)\n const [entityInitial, setEntityInitial] = useState<{ label?: string; description?: string; labelField?: string; defaultEditor?: string; showInSidebar?: boolean; accessRestricted?: boolean; updatedAt?: string }>({})\n const [defs, setDefs] = useState<Def[]>([])\n const [defsVersion, setDefsVersion] = useState<string | null>(null)\n const [orderDirty, setOrderDirty] = useState(false)\n const [orderSaving, setOrderSaving] = useState(false)\n const listRef = React.useRef<HTMLDivElement | null>(null)\n const [loading, setLoading] = useState(true)\n const [saving, setSaving] = useState(false)\n const [error, setError] = useState<string | null>(null)\n const [deletedKeys, setDeletedKeys] = useState<string[]>([])\n const [defErrors, setDefErrors] = useState<Record<number, DefErrors>>({})\n const [fieldsets, setFieldsets] = useState<FieldsetDefinition[]>([])\n const [activeFieldset, setActiveFieldset] = useState<string | null>(null)\n const [singleFieldsetPerRecord, setSingleFieldsetPerRecord] = useState(true)\n const [translateDef, setTranslateDef] = useState<{ def: Def; entityId: string } | null>(null)\n\n const translateFields = React.useMemo(() => {\n if (!translateDef) return undefined\n const { def } = translateDef\n const fields: string[] = ['label', 'description']\n const options = normalizeCustomFieldOptions(def.configJson?.options)\n for (const opt of options) {\n if (opt.value) fields.push(`options.${opt.value}.label`)\n }\n return fields\n }, [translateDef])\n\n const translateBaseValues = React.useMemo(() => {\n if (!translateDef) return undefined\n const { def } = translateDef\n const base: Record<string, string> = {}\n if (typeof def.configJson?.label === 'string') base.label = def.configJson.label\n if (typeof def.configJson?.description === 'string') base.description = def.configJson.description\n const options = normalizeCustomFieldOptions(def.configJson?.options)\n for (const opt of options) {\n if (opt.value && opt.label) base[`options.${opt.value}.label`] = opt.label\n }\n return base\n }, [translateDef])\n\n const requestedFieldset = React.useMemo(() => {\n const raw = searchParams?.get('fieldset')\n return raw && raw.trim().length ? raw.trim() : null\n }, [searchParams])\n const embedFieldsetView = React.useMemo(() => searchParams?.get('view') === 'fieldset', [searchParams])\n const normalizeGroupPayload = React.useCallback((value: unknown) => {\n if (!value) return null\n if (typeof value === 'string') {\n const code = value.trim()\n return code ? { code } : null\n }\n if (typeof value !== 'object') return null\n const entry = value as Record<string, unknown>\n const code = typeof entry.code === 'string' ? entry.code.trim() : ''\n if (!code) return null\n const group: FieldsetGroup = { code }\n if (typeof entry.title === 'string' && entry.title.trim()) group.title = entry.title.trim()\n if (typeof entry.hint === 'string' && entry.hint.trim()) group.hint = entry.hint.trim()\n return group\n }, [])\n\n const buildFieldsetPayload = React.useCallback(() => {\n const groupMap = new Map<string, FieldsetGroup[]>()\n defs.forEach((definition) => {\n const code = typeof definition.configJson?.fieldset === 'string' ? definition.configJson.fieldset : null\n if (!code) return\n const normalized = normalizeGroupPayload(definition.configJson?.group)\n if (!normalized) return\n const list = groupMap.get(code) ?? []\n if (!list.some((entry) => entry.code === normalized.code)) {\n list.push(normalized)\n groupMap.set(code, list)\n }\n })\n return fieldsets.map((fs) => ({\n ...fs,\n groups: groupMap.get(fs.code) ?? [],\n }))\n }, [defs, fieldsets, normalizeGroupPayload])\n\n const validateDef = React.useCallback((d: Def): DefErrors => {\n const parsed = upsertCustomFieldDefSchema.safeParse({ entityId, key: d.key, kind: d.kind, configJson: d.configJson, isActive: d.isActive })\n if (parsed.success) return {}\n const errs: DefErrors = {}\n for (const issue of parsed.error.issues) {\n if ((issue.path || []).includes('key')) errs.key = issue.message\n if ((issue.path || []).includes('kind')) errs.kind = issue.message\n }\n return errs\n }, [entityId, requestedFieldset])\n\n const validateAndSetErrorAt = (index: number, d: Def) => {\n const errs = validateDef(d)\n setDefErrors((prev) => ({ ...prev, [index]: errs }))\n return !errs.key && !errs.kind\n }\n\n const validateAll = () => {\n const nextErrors: Record<number, DefErrors> = {}\n defs.forEach((d, i) => {\n nextErrors[i] = validateDef(d)\n })\n setDefErrors(nextErrors)\n return Object.values(nextErrors).every(e => !e.key && !e.kind)\n }\n\n useEffect(() => {\n let mounted = true\n async function load() {\n setLoading(true)\n try {\n const entJson = await readApiResultOrThrow<EntitiesListResponse>(\n '/api/entities/entities',\n undefined,\n { errorMessage: t('entities.userEntities.edit.errors.loadMetadataFailed', 'Failed to load entity metadata'), fallback: { items: [] } },\n )\n const ent = (entJson.items || []).find((x: any) => x.entityId === entityId)\n if (mounted) {\n const record = ent as Record<string, unknown> | undefined\n const labelValue =\n typeof record?.label === 'string' && record.label.trim().length > 0 ? record.label : entityId\n const descriptionValue = typeof record?.description === 'string' ? record.description : ''\n const labelFieldValue =\n typeof record?.labelField === 'string' && record.labelField.length > 0 ? record.labelField : 'name'\n const defaultEditorValue =\n typeof record?.defaultEditor === 'string' ? record.defaultEditor : ''\n const showInSidebarValue = record?.showInSidebar === true\n const accessRestrictedValue = record?.accessRestricted === true\n const updatedAtValue =\n typeof record?.updatedAt === 'string' && record.updatedAt.length > 0 ? record.updatedAt : undefined\n setLabel(labelValue)\n if (record?.source === 'code' || record?.source === 'custom') setEntitySource(record.source)\n setEntityInitial({\n label: labelValue,\n description: descriptionValue,\n labelField: labelFieldValue,\n defaultEditor: defaultEditorValue,\n showInSidebar: showInSidebarValue,\n accessRestricted: accessRestrictedValue,\n updatedAt: updatedAtValue,\n })\n setEntityFormLoading(false)\n }\n const json = await readApiResultOrThrow<DefinitionsManageResponse>(\n `/api/entities/definitions.manage?entityId=${encodeURIComponent(entityId)}`,\n undefined,\n { errorMessage: t('entities.userEntities.edit.errors.loadDefinitionsFailed', 'Failed to load entity definitions'), fallback: { items: [], deletedKeys: [] } },\n )\n if (mounted) {\n const loaded: Def[] = (json.items || []).map((d: any) => ({ key: d.key, kind: d.kind, configJson: d.configJson || {}, isActive: d.isActive !== false }))\n loaded.sort(\n (a, b) => Number(a.configJson?.priority ?? 0) - Number(b.configJson?.priority ?? 0)\n )\n setDefs(loaded)\n setDefsVersion(readVersionToken(json.version))\n setDefErrors({})\n setDeletedKeys(Array.isArray(json.deletedKeys) ? json.deletedKeys : [])\n const loadedFieldsets = Array.isArray(json.fieldsets) ? json.fieldsets : []\n setFieldsets(loadedFieldsets)\n setActiveFieldset((prev) => {\n if (requestedFieldset && loadedFieldsets.some((fs) => fs.code === requestedFieldset)) {\n return requestedFieldset\n }\n if (prev && loadedFieldsets.some((fs) => fs.code === prev)) return prev\n return loadedFieldsets[0]?.code ?? null\n })\n setSingleFieldsetPerRecord(json.settings?.singleFieldsetPerRecord !== false)\n }\n } catch (e: any) {\n if (mounted) setError(e.message || t('entities.userEntities.edit.errors.loadFailed', 'Failed to load'))\n } finally {\n if (mounted) setLoading(false)\n }\n }\n if (entityId) load()\n return () => { mounted = false }\n }, [entityId, t])\n\n function addField() {\n setDefs((arr) => [\n ...arr,\n {\n key: '',\n kind: 'text',\n configJson: activeFieldset ? { fieldset: activeFieldset } : {},\n isActive: true,\n },\n ])\n }\n\n async function restoreField(key: string) {\n try {\n const call = await apiCall('/api/entities/definitions.restore', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, key }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, t('entities.userEntities.edit.errors.restoreFieldFailed', 'Failed to restore field'))\n }\n // Reload definitions & deleted keys\n const j2 = await readApiResultOrThrow<DefinitionsManageResponse>(\n `/api/entities/definitions.manage?entityId=${encodeURIComponent(entityId)}`,\n undefined,\n { errorMessage: t('entities.userEntities.edit.errors.reloadDefinitionsFailed', 'Failed to reload field definitions'), fallback: { items: [], deletedKeys: [] } },\n )\n const loaded: Def[] = (j2.items || []).map((d: any) => ({ key: d.key, kind: d.kind, configJson: d.configJson || {}, isActive: d.isActive !== false }))\n loaded.sort(\n (a, b) => Number(a.configJson?.priority ?? 0) - Number(b.configJson?.priority ?? 0)\n )\n setDefs(loaded)\n setDefsVersion(readVersionToken(j2.version))\n setDeletedKeys(Array.isArray(j2.deletedKeys) ? j2.deletedKeys : [])\n flash(t('entities.userEntities.edit.flash.restoredField', 'Restored {{key}}', { key }), 'success')\n await invalidateCustomFieldDefs(queryClient, entityId)\n } catch (e: any) {\n flash(e?.message || t('entities.userEntities.edit.errors.restoreFieldFailed', 'Failed to restore field'), 'error')\n }\n }\n\n async function saveAll() {\n setSaving(true)\n setError(null)\n try {\n if (!validateAll()) {\n flash(t('entities.customFields.errors.validation', 'Please fix validation errors in field definitions.'), 'error')\n throw new Error(t('entities.userEntities.edit.errors.validationFailed', 'Validation failed'))\n }\n const payload = {\n entityId,\n definitions: defs.filter(d => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n }\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(defsVersion),\n () => apiCall<DefinitionsBatchResponse>('/api/entities/definitions.batch', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }),\n )\n if (!call.ok) {\n if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) return\n await raiseCrudError(call.response, t('entities.customFields.errors.saveFailed', 'Failed to save field definitions.'))\n }\n setDefsVersion(readVersionToken(call.result?.version))\n await invalidateCustomFieldDefs(queryClient, entityId)\n router.push(`/backend/entities/user?flash=${encodeURIComponent(t('entities.customFields.flash.saved', 'Definitions saved'))}&type=success`)\n } catch (e: any) {\n setError(e.message || t('entities.customFields.errors.saveFailed', 'Failed to save field definitions.'))\n } finally {\n setSaving(false)\n }\n }\n\n async function removeField(idx: number) {\n const def = defs[idx]\n if (!def) return\n if (def.key) {\n try {\n const call = await apiCall<DefinitionsBatchResponse>('/api/entities/definitions', {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, key: def.key }),\n })\n if (!call.ok) {\n await raiseCrudError(call.response, t('entities.customFields.errors.deleteFailed', 'Failed to delete field.'))\n }\n // Keep the optimistic-lock token in sync after an out-of-band delete so a\n // later Save does not falsely 409 against our own change (issue #3152).\n setDefsVersion(readVersionToken(call.result?.version))\n } catch (error) {\n const message = error instanceof Error ? error.message : t('entities.customFields.errors.deleteFailed', 'Failed to delete field.')\n flash(message, 'error')\n return\n }\n }\n setDefs((arr) => arr.filter((_, i) => i !== idx))\n setOrderDirty(true)\n if (def.key) {\n await invalidateCustomFieldDefs(queryClient, entityId)\n }\n }\n\n const handleFieldsetCodeChange = React.useCallback((previousCode: string, nextCode: string) => {\n if (!previousCode || !nextCode || previousCode === nextCode) return\n setDefs((arr) =>\n arr.map((entry) => {\n const current = typeof entry.configJson?.fieldset === 'string' ? entry.configJson.fieldset : undefined\n if (current !== previousCode) return entry\n const nextConfig = { ...(entry.configJson || {}) }\n nextConfig.fieldset = nextCode\n return { ...entry, configJson: nextConfig }\n })\n )\n setActiveFieldset((current) => (current === previousCode ? nextCode : current))\n }, [])\n\n const handleFieldsetRemoved = React.useCallback((code: string) => {\n if (!code) return\n setDefs((arr) =>\n arr.map((entry) => {\n const current = typeof entry.configJson?.fieldset === 'string' ? entry.configJson.fieldset : undefined\n if (current !== code) return entry\n const nextConfig = { ...(entry.configJson || {}) }\n delete nextConfig.fieldset\n delete nextConfig.group\n return { ...entry, configJson: nextConfig }\n })\n )\n }, [])\n\n async function saveOrderIfDirty() {\n if (!orderDirty) return\n setOrderSaving(true)\n try {\n // Do not save order when there are invalid keys/kinds\n if (!validateAll()) throw new Error(t('entities.userEntities.edit.errors.validationFailed', 'Validation failed'))\n const payload = {\n entityId,\n definitions: defs.filter(d => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n }\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(defsVersion),\n () => apiCall<DefinitionsBatchResponse>('/api/entities/definitions.batch', {\n method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload),\n }),\n )\n if (!call.ok) {\n // A stale reorder auto-save (another tab changed the schema first) returns a\n // 409; surface the shared conflict bar and stop the retry loop instead of a\n // generic flash (issue #3152).\n if (surfaceRecordConflict({ status: call.status, body: call.result }, t)) {\n setOrderDirty(false)\n return\n }\n await raiseCrudError(call.response, t('entities.userEntities.edit.errors.saveOrderFailed', 'Failed to save order'))\n }\n setDefsVersion(readVersionToken(call.result?.version))\n setOrderDirty(false)\n flash(t('entities.userEntities.edit.flash.orderSaved', 'Order saved'), 'success')\n await invalidateCustomFieldDefs(queryClient, entityId)\n } catch (e: any) {\n flash(e?.message || t('entities.userEntities.edit.errors.saveOrderFailed', 'Failed to save order'), 'error')\n } finally {\n setOrderSaving(false)\n }\n }\n\n // Unify loader via CrudForm isLoading; do not return early here\n\n // Schema for inline field-level validation in CrudForm\n const entityFormSchema = upsertCustomEntitySchema\n .pick({ label: true, description: true, defaultEditor: true as any })\n .extend({\n // Allow empty string in the UI select, treat as undefined later\n defaultEditor: z.union([z.enum(['markdown','simpleMarkdown','htmlRichText']).optional(), z.literal('')]).optional(),\n // Include showInSidebar so CrudForm doesn't strip it on submit\n showInSidebar: z.boolean().optional(),\n accessRestricted: z.boolean().optional(),\n }) as z.ZodType<Record<string, unknown>>\n\n const metadataFieldsReadOnly = entitySource === 'code'\n const fields: CrudField[] = [\n { id: 'label', label: t('entities.userEntities.form.label.label', 'Label'), type: 'text', required: true, readOnly: metadataFieldsReadOnly },\n { id: 'description', label: t('entities.userEntities.form.description.label', 'Description'), type: 'textarea', readOnly: metadataFieldsReadOnly },\n {\n id: 'defaultEditor',\n label: t('entities.userEntities.form.defaultEditor.label', 'Default Editor (multiline)'),\n type: 'select',\n readOnly: metadataFieldsReadOnly,\n options: [\n { value: '', label: t('entities.userEntities.form.defaultEditor.options.default', 'Default (Markdown)') },\n { value: 'markdown', label: t('entities.userEntities.form.defaultEditor.options.markdown', 'Markdown (UIW)') },\n { value: 'simpleMarkdown', label: t('entities.userEntities.form.defaultEditor.options.simpleMarkdown', 'Simple Markdown') },\n { value: 'htmlRichText', label: t('entities.userEntities.form.defaultEditor.options.htmlRichText', 'HTML Rich Text') },\n ],\n } as any,\n ...(entitySource === 'custom' ? [{ id: 'showInSidebar', label: t('entities.userEntities.form.showInSidebar.label', 'Show in sidebar'), type: 'checkbox' }] : []),\n ...(entitySource === 'custom' ? [{\n id: 'accessRestricted',\n label: t('entities.userEntities.form.accessRestricted.label', 'Restrict record access'),\n type: 'checkbox',\n description: t('entities.userEntities.form.accessRestricted.help', 'Require an explicit per-entity permission to view or manage this entity\u2019s records. Leave off to allow anyone with the general records permission.'),\n }] : []),\n ]\n const renderFieldDefinitions = React.useCallback(() => (\n <FieldDefinitionsEditor\n definitions={defs}\n errors={defErrors}\n deletedKeys={deletedKeys}\n fieldsets={fieldsets}\n activeFieldset={activeFieldset}\n onActiveFieldsetChange={setActiveFieldset}\n onFieldsetsChange={(next) => {\n setFieldsets(next)\n if (!next.some((fs) => fs.code === activeFieldset)) {\n setActiveFieldset(next[0]?.code ?? null)\n }\n }}\n onFieldsetCodeChange={handleFieldsetCodeChange}\n onFieldsetRemoved={handleFieldsetRemoved}\n singleFieldsetPerRecord={singleFieldsetPerRecord}\n onSingleFieldsetPerRecordChange={setSingleFieldsetPerRecord}\n onAddField={addField}\n onRemoveField={(index) => { void removeField(index) }}\n onDefinitionChange={(index, nextDef) => {\n setDefs((arr) => arr.map((entry, idx) => (idx === index ? nextDef : entry)))\n validateAndSetErrorAt(index, nextDef)\n }}\n onTranslate={(def) => setTranslateDef({ def, entityId })}\n onRestoreField={(key) => { void restoreField(key) }}\n onReorder={(from, to) => {\n setDefs((arr) => {\n const next = [...arr]\n const [moved] = next.splice(from, 1)\n next.splice(to, 0, moved)\n return next\n })\n setOrderDirty(true)\n }}\n orderNotice={orderDirty ? { dirty: true, saving: orderSaving, message: t('entities.userEntities.edit.orderNotice', 'Reordered - will auto-save on blur') } : undefined}\n addButtonLabel={t('entities.customFields.editor.addField', 'Add Field')}\n translate={t}\n listRef={listRef}\n listProps={{\n tabIndex: -1,\n onBlur: (event) => {\n const current = listRef.current\n const next = event.relatedTarget as Node | null\n if (!current) return\n if (!next || !current.contains(next)) {\n void saveOrderIfDirty()\n }\n },\n }}\n />\n ),\n [defs, defErrors, deletedKeys, fieldsets, activeFieldset, singleFieldsetPerRecord, orderDirty, orderSaving, addField, removeField, restoreField, saveOrderIfDirty, t])\n\n const definitionsGroup: CrudFormGroup = { id: 'definitions', title: t('entities.userEntities.edit.groups.definitions', 'Field Definitions'), column: 1, component: renderFieldDefinitions }\n\n const groups: CrudFormGroup[] = [\n { id: 'settings', title: t('entities.userEntities.edit.groups.settings', 'Entity Settings'), column: 1, fields: entitySource === 'custom' ? ['label','description','defaultEditor','showInSidebar','accessRestricted'] : ['label','description','defaultEditor'] },\n definitionsGroup,\n ]\n\n const handleCrudFormSubmit = React.useCallback(async (vals: Record<string, unknown>) => {\n if (!entityId) {\n throw createCrudFormError(t('entities.userEntities.edit.errors.invalidEntityId', 'Invalid entity ID'))\n }\n if (!validateAll()) {\n flash(t('entities.customFields.errors.validation', 'Please fix validation errors in field definitions.'), 'error')\n throw createCrudFormError(t('entities.customFields.errors.validation', 'Please fix validation errors in field definitions.'))\n }\n // Code-declared system entities are not registered as custom entities \u2014 their\n // metadata is owned by code and `POST /api/entities/entities` is fail-closed for\n // ORM-backed system ids (#3115). Only their field definitions are user-editable, so\n // skip the registration call and persist definitions below.\n if (shouldRegisterEntityMetadata(entitySource)) {\n const entityPayload = buildEntityMetadataPayload(entitySource, vals)\n if (!entityPayload) throw createCrudFormError(t('entities.userEntities.edit.errors.validationFailed', 'Validation failed'))\n const callEntity = await apiCall('/api/entities/entities', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ entityId, ...entityPayload }),\n })\n if (!callEntity.ok) {\n await raiseCrudError(callEntity.response, t('entities.userEntities.edit.errors.saveEntityFailed', 'Failed to save entity'))\n }\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }\n const defsPayload = buildDefinitionsBatchPayload({\n entityId,\n defs,\n fieldsets: buildFieldsetPayload(),\n singleFieldsetPerRecord,\n })\n // Send the aggregate schema version so a concurrent edit is rejected with a 409\n // instead of silently overwriting the other tab (issue #3152). CrudForm's submit\n // catch detects the optimistic-lock conflict and shows the shared conflict bar.\n const callDefs = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(defsVersion),\n () => apiCall<DefinitionsBatchResponse>('/api/entities/definitions.batch', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(defsPayload),\n }),\n )\n if (!callDefs.ok) {\n await raiseCrudError(callDefs.response, t('entities.customFields.errors.saveFailed', 'Failed to save field definitions.'))\n }\n setDefsVersion(readVersionToken(callDefs.result?.version))\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n await invalidateCustomFieldDefs(queryClient, entityId)\n flash(t('entities.customFields.flash.saved', 'Definitions saved'), 'success')\n }, [buildFieldsetPayload, defs, defsVersion, entityId, entitySource, queryClient, singleFieldsetPerRecord, t, validateAll])\n\n if (!entityId) {\n return (\n <Page>\n <PageBody>\n <div className=\"p-6\">\n <Alert variant=\"destructive\">\n <AlertTitle>{t('entities.userEntities.edit.errors.invalidEntityTitle', 'Invalid entity')}</AlertTitle>\n <AlertDescription>{t('entities.userEntities.edit.errors.invalidEntityDescription', 'The requested entity ID is missing or invalid.')}</AlertDescription>\n </Alert>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (embedFieldsetView) {\n return (\n <div className=\"p-4\">\n <CrudForm\n schema={entityFormSchema}\n title={t('entities.userEntities.edit.fieldsetTitle', 'Edit fieldset: {{name}}', { name: requestedFieldset ?? entityId })}\n fields={[]}\n groups={[definitionsGroup]}\n initialValues={entityInitial as any}\n isLoading={entityFormLoading || loading}\n submitLabel={t('entities.userEntities.records.form.submitSave', 'Save')}\n deleteVisible={false}\n backHref={undefined}\n cancelHref={undefined}\n embedded\n onSubmit={handleCrudFormSubmit}\n />\n </div>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n schema={entityFormSchema}\n title={t('entities.userEntities.edit.title', 'Edit Entity: {{entityId}}', { entityId })}\n backHref={entitySource === 'code' ? \"/backend/entities/system\" : \"/backend/entities/user\"}\n fields={fields}\n groups={groups}\n initialValues={entityInitial as any}\n isLoading={entityFormLoading || loading}\n submitLabel={t('entities.userEntities.records.form.submitSave', 'Save')}\n deleteVisible={entitySource === 'custom'}\n extraActions={entitySource === 'custom' ? (\n <Button variant=\"outline\" asChild>\n <Link href={`/backend/entities/user/${encodeURIComponent(entityId)}/records`}>\n {t('entities.userEntities.edit.showRecords', 'Show Records')}\n </Link>\n </Button>\n ) : null}\n cancelHref={entitySource === 'code' ? \"/backend/entities/system\" : \"/backend/entities/user\"}\n successRedirect={entitySource === 'code'\n ? `/backend/entities/system?flash=${encodeURIComponent(t('entities.customFields.flash.saved', 'Definitions saved'))}&type=success`\n : `/backend/entities/user?flash=${encodeURIComponent(t('entities.customFields.flash.saved', 'Definitions saved'))}&type=success`}\n onSubmit={handleCrudFormSubmit}\n onDelete={entitySource === 'custom' ? async () => {\n const callDelete = await apiCall('/api/entities/entities', { method: 'DELETE', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ entityId }) })\n if (!callDelete.ok) {\n await raiseCrudError(callDelete.response, t('entities.userEntities.edit.errors.deleteEntityFailed', 'Failed to delete entity'))\n }\n flash(t('entities.userEntities.edit.flash.entityDeleted', 'Entity deleted'), 'success')\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n } : undefined}\n />\n </PageBody>\n <Dialog open={!!translateDef} onOpenChange={(open) => { if (!open) setTranslateDef(null) }}>\n <DialogContent className=\"max-w-2xl max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{t('translations.manager.translateField', 'Translate field: {{key}}', { key: translateDef?.def.key ?? '' })}</DialogTitle>\n </DialogHeader>\n {translateDef && (\n <TranslationManager\n mode=\"embedded\"\n compact\n entityType=\"entities:custom_field_def\"\n recordId={`${translateDef.entityId}:${translateDef.def.key}`}\n baseValues={translateBaseValues}\n translatableFields={translateFields}\n />\n )}\n </DialogContent>\n </Dialog>\n </Page>\n )\n}\n\nexport function shouldRegisterEntityMetadata(entitySource: EntitySource): boolean {\n return entitySource === 'custom'\n}\n\nexport function buildDefinitionsBatchPayload(options: {\n entityId: string\n defs: Array<Pick<Def, 'key' | 'kind' | 'configJson' | 'isActive'>>\n fieldsets: FieldsetDefinition[]\n singleFieldsetPerRecord: boolean\n}) {\n return {\n entityId: options.entityId,\n definitions: options.defs.filter((d) => !!d.key).map((d) => ({\n key: d.key,\n kind: d.kind,\n configJson: d.configJson,\n isActive: d.isActive !== false,\n })),\n fieldsets: options.fieldsets,\n singleFieldsetPerRecord: options.singleFieldsetPerRecord,\n }\n}\n\nexport function buildEntityMetadataPayload(\n entitySource: EntitySource,\n vals: Record<string, unknown>,\n): Record<string, unknown> | null {\n const partial = entitySource === 'custom'\n ? upsertCustomEntitySchema\n .pick({ label: true, description: true, labelField: true as any, defaultEditor: true as any })\n .extend({ showInSidebar: z.boolean().optional(), accessRestricted: z.boolean().optional() }) as unknown as z.ZodTypeAny\n : upsertCustomEntitySchema\n .pick({ label: true, description: true, defaultEditor: true as any }) as unknown as z.ZodTypeAny\n const normalized = {\n ...vals,\n defaultEditor: typeof vals.defaultEditor === 'string' && vals.defaultEditor ? vals.defaultEditor : undefined,\n }\n const parsed = partial.safeParse(normalized)\n return parsed.success ? (parsed.data as Record<string, unknown>) : null\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["fields", "code", "error"]
|
|
7
7
|
}
|