@open-mercato/core 0.6.7-develop.6605.1.761dd4c810 → 0.6.7-develop.6621.1.cdbe9dee3d
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/modules/auth/api/session/refresh.js +12 -11
- package/dist/modules/auth/api/session/refresh.js.map +2 -2
- package/dist/modules/auth/lib/rateLimitCheck.js +4 -4
- package/dist/modules/auth/lib/rateLimitCheck.js.map +2 -2
- package/dist/modules/catalog/api/categories/route.js +8 -14
- package/dist/modules/catalog/api/categories/route.js.map +2 -2
- package/dist/modules/catalog/api/tags/route.js +3 -10
- package/dist/modules/catalog/api/tags/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/[id]/visibility/route.js +15 -17
- package/dist/modules/customers/api/interactions/[id]/visibility/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/email-threads/route.js +6 -4
- package/dist/modules/customers/api/people/[id]/email-threads/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/emails/route.js +19 -17
- package/dist/modules/customers/api/people/[id]/emails/route.js.map +2 -2
- package/dist/modules/customers/components/detail/CustomFieldValuesList.js +22 -5
- package/dist/modules/customers/components/detail/CustomFieldValuesList.js.map +2 -2
- package/dist/modules/customers/components/detail/create/CreateDealForm.js +5 -2
- package/dist/modules/customers/components/detail/create/CreateDealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/customFieldUtils.js +10 -3
- package/dist/modules/customers/components/detail/customFieldUtils.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.meta.js +4 -2
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.meta.js +4 -2
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js +3 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/create/page.js +2 -1
- package/dist/modules/entities/backend/entities/user/create/page.js.map +2 -2
- package/dist/modules/entities/data/entities.js.map +1 -1
- package/dist/modules/integrations/api/[id]/credentials/route.js +10 -7
- package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
- package/dist/modules/integrations/api/[id]/health/route.js +6 -4
- package/dist/modules/integrations/api/[id]/health/route.js.map +2 -2
- package/dist/modules/integrations/api/[id]/route.js +4 -2
- package/dist/modules/integrations/api/[id]/route.js.map +2 -2
- package/dist/modules/integrations/api/[id]/state/route.js +7 -5
- package/dist/modules/integrations/api/[id]/state/route.js.map +2 -2
- package/dist/modules/integrations/api/[id]/version/route.js +7 -5
- package/dist/modules/integrations/api/[id]/version/route.js.map +2 -2
- package/dist/modules/integrations/api/logs/route.js +4 -2
- package/dist/modules/integrations/api/logs/route.js.map +2 -2
- package/dist/modules/integrations/api/route.js +4 -2
- package/dist/modules/integrations/api/route.js.map +2 -2
- package/dist/modules/integrations/api/umes-read.js +2 -1
- package/dist/modules/integrations/api/umes-read.js.map +2 -2
- package/dist/modules/integrations/lib/organization-scope.js +12 -0
- package/dist/modules/integrations/lib/organization-scope.js.map +7 -0
- package/dist/modules/payment_gateways/lib/gateway-service.js +10 -1
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
- package/dist/modules/sales/api/document-history/route.js +6 -9
- package/dist/modules/sales/api/document-history/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/accept/route.js +3 -3
- package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
- package/dist/modules/sales/api/returns/[id]/route.js +6 -9
- package/dist/modules/sales/api/returns/[id]/route.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +6 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +6 -4
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/workflows.js +1 -1
- package/dist/modules/sales/workflows.js.map +1 -1
- package/dist/modules/workflows/api/definitions/[id]/route.js +10 -1
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +44 -3
- package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/auth/api/session/refresh.ts +19 -11
- package/src/modules/auth/lib/rateLimitCheck.ts +4 -4
- package/src/modules/catalog/api/categories/route.ts +14 -16
- package/src/modules/catalog/api/tags/route.ts +6 -10
- package/src/modules/catalog/i18n/pl.json +9 -9
- package/src/modules/customer_accounts/i18n/pl.json +129 -129
- package/src/modules/customers/api/interactions/[id]/visibility/route.ts +24 -20
- package/src/modules/customers/api/people/[id]/email-threads/route.ts +10 -6
- package/src/modules/customers/api/people/[id]/emails/route.ts +25 -21
- package/src/modules/customers/components/detail/CustomFieldValuesList.tsx +28 -4
- package/src/modules/customers/components/detail/create/CreateDealForm.tsx +7 -2
- package/src/modules/customers/components/detail/customFieldUtils.ts +15 -3
- package/src/modules/data_sync/i18n/pl.json +68 -68
- package/src/modules/directory/backend/directory/organizations/[id]/edit/page.meta.ts +4 -2
- package/src/modules/directory/backend/directory/tenants/[id]/edit/page.meta.ts +4 -2
- package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +2 -1
- package/src/modules/entities/backend/entities/user/create/page.tsx +1 -0
- package/src/modules/entities/data/entities.ts +1 -1
- package/src/modules/entities/i18n/de.json +2 -0
- package/src/modules/entities/i18n/en.json +2 -0
- package/src/modules/entities/i18n/es.json +2 -0
- package/src/modules/entities/i18n/pl.json +2 -0
- package/src/modules/integrations/api/[id]/credentials/route.ts +10 -7
- package/src/modules/integrations/api/[id]/health/route.ts +6 -4
- package/src/modules/integrations/api/[id]/route.ts +4 -2
- package/src/modules/integrations/api/[id]/state/route.ts +7 -5
- package/src/modules/integrations/api/[id]/version/route.ts +7 -5
- package/src/modules/integrations/api/logs/route.ts +4 -2
- package/src/modules/integrations/api/route.ts +4 -2
- package/src/modules/integrations/api/umes-read.ts +2 -1
- package/src/modules/integrations/i18n/de.json +0 -76
- package/src/modules/integrations/i18n/en.json +0 -76
- package/src/modules/integrations/i18n/es.json +0 -76
- package/src/modules/integrations/i18n/pl.json +0 -76
- package/src/modules/integrations/lib/organization-scope.ts +27 -0
- package/src/modules/payment_gateways/lib/gateway-service.ts +12 -1
- package/src/modules/sales/api/document-history/route.ts +10 -9
- package/src/modules/sales/api/quotes/accept/route.ts +3 -3
- package/src/modules/sales/api/returns/[id]/route.ts +10 -9
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +26 -19
- package/src/modules/sales/components/documents/AddressesSection.tsx +8 -4
- package/src/modules/sales/i18n/pl.json +24 -24
- package/src/modules/sales/workflows.ts +1 -1
- package/src/modules/staff/i18n/pl.json +178 -178
- package/src/modules/workflows/api/definitions/[id]/route.ts +14 -1
- package/src/modules/workflows/i18n/pl.json +128 -128
- package/src/modules/workflows/lib/event-trigger-service.ts +87 -8
|
@@ -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; 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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",
|
|
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','plain']).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 { value: 'plain', label: t('entities.userEntities.form.defaultEditor.options.plain', 'Plain textarea') },\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
|
}
|
|
@@ -48,7 +48,8 @@ function CreateEntityPage() {
|
|
|
48
48
|
{ value: "", label: t("entities.userEntities.form.defaultEditor.options.default", "Default (Markdown)") },
|
|
49
49
|
{ value: "markdown", label: t("entities.userEntities.form.defaultEditor.options.markdown", "Markdown (UIW)") },
|
|
50
50
|
{ value: "simpleMarkdown", label: t("entities.userEntities.form.defaultEditor.options.simpleMarkdown", "Simple Markdown") },
|
|
51
|
-
{ value: "htmlRichText", label: t("entities.userEntities.form.defaultEditor.options.htmlRichText", "HTML Rich Text") }
|
|
51
|
+
{ value: "htmlRichText", label: t("entities.userEntities.form.defaultEditor.options.htmlRichText", "HTML Rich Text") },
|
|
52
|
+
{ value: "plain", label: t("entities.userEntities.form.defaultEditor.options.plain", "Plain textarea") }
|
|
52
53
|
]
|
|
53
54
|
},
|
|
54
55
|
{ id: "showInSidebar", label: t("entities.userEntities.form.showInSidebar.label", "Show in sidebar"), type: "checkbox" },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/entities/backend/entities/user/create/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { CrudForm, type CrudField } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { upsertCustomEntitySchema } from '@open-mercato/core/modules/entities/data/validators'\nimport { useRouter } from 'next/navigation'\nimport { pushWithFlash } from '@open-mercato/ui/backend/utils/flash'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { LoadingMessage } from '@open-mercato/ui/backend/detail'\n\nconst schema = upsertCustomEntitySchema\n\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\n\nexport default function CreateEntityPage() {\n const t = useT()\n const router = useRouter()\n // Pre-fill the restriction toggle from the tenant default-restricted policy so\n // the form reflects the workspace posture; null while loading.\n const [defaultRestricted, setDefaultRestricted] = React.useState<boolean | null>(null)\n React.useEffect(() => {\n let active = true\n ;(async () => {\n const data = await readApiResultOrThrow<{ newEntitiesRestrictedByDefault?: boolean }>(\n '/api/entities/entity-settings',\n undefined,\n { errorMessage: '[internal] Failed to load entity settings', fallback: { newEntitiesRestrictedByDefault: false } },\n ).catch(() => ({ newEntitiesRestrictedByDefault: false }))\n if (active) setDefaultRestricted(data?.newEntitiesRestrictedByDefault === true)\n })()\n return () => { active = false }\n }, [])\n const fields = React.useMemo<CrudField[]>(() => ([\n {\n id: 'entityId',\n label: t('entities.userEntities.form.entityId.label', 'Entity ID'),\n type: 'text',\n required: true,\n placeholder: t('entities.userEntities.form.entityId.placeholder', 'module_name:entity_id'),\n },\n { id: 'label', label: t('entities.userEntities.form.label.label', 'Label'), type: 'text', required: true },\n { id: 'description', label: t('entities.userEntities.form.description.label', 'Description'), type: 'textarea' },\n {\n id: 'defaultEditor',\n label: t('entities.userEntities.form.defaultEditor.label', 'Default Editor (multiline)'),\n type: 'select',\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 unknown as CrudField,\n { id: 'showInSidebar', label: t('entities.userEntities.form.showInSidebar.label', 'Show in sidebar'), type: 'checkbox' } as CrudField,\n {\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 } as CrudField,\n ]), [t])\n\n if (defaultRestricted === null) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('entities.userEntities.form.loading', 'Loading\u2026')} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('entities.userEntities.form.title', 'Create Entity')}\n backHref=\"/backend/entities/user\"\n schema={schema}\n fields={fields}\n initialValues={{ entityId: 'user:your_entity', label: '', showInSidebar: false, accessRestricted: defaultRestricted }}\n submitLabel={t('entities.userEntities.form.submit', 'Create')}\n cancelHref=\"/backend/entities/user\"\n onSubmit={async (vals) => {\n const entityId = await submitCreateEntity({\n values: vals as Record<string, unknown>,\n messages: {\n entityIdRequired: t('entities.userEntities.errors.entityIdRequired', 'Entity ID is required'),\n entityIdExists: t('entities.userEntities.errors.entityIdExists', 'Entity ID already exists'),\n loadFailed: t('entities.userEntities.errors.loadFailed', 'Failed to load entities'),\n },\n })\n try {\n window.dispatchEvent(new Event('om:refresh-sidebar'))\n } catch {}\n const successMessage = t('entities.userEntities.flash.created', 'Entity created')\n pushWithFlash(router, `/backend/entities/user/${encodeURIComponent(entityId)}`, successMessage, 'success')\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\ntype EntityListEntry = {\n entityId?: string\n source?: string\n}\n\ntype FetchCustomEntities = (errorMessage?: string) => Promise<EntityListEntry[]>\n\nasync function defaultFetchCustomEntities(errorMessage?: string): Promise<EntityListEntry[]> {\n const data = await readApiResultOrThrow<{ items?: EntityListEntry[] }>(\n '/api/entities/entities',\n undefined,\n { errorMessage: errorMessage ?? 'Failed to load entities', fallback: { items: [] } },\n )\n return Array.isArray(data?.items) ? data.items! : []\n}\n\ntype CreateEntityRequest = (payload: Record<string, unknown>) => Promise<void>\n\nasync function defaultCreateEntityRequest(payload: Record<string, unknown>) {\n await createCrud('entities/entities', payload)\n}\n\nexport async function submitCreateEntity(options: {\n values: Record<string, unknown>\n fetchEntities?: FetchCustomEntities\n createEntity?: CreateEntityRequest\n messages?: {\n entityIdRequired?: string\n entityIdExists?: string\n loadFailed?: string\n }\n}): Promise<string> {\n const {\n values,\n fetchEntities = defaultFetchCustomEntities,\n createEntity = defaultCreateEntityRequest,\n messages,\n } = options\n const rawEntityId = typeof values.entityId === 'string' ? values.entityId.trim() : ''\n if (!rawEntityId) {\n const message = messages?.entityIdRequired ?? 'Entity ID is required'\n throw createCrudFormError(message, { entityId: message })\n }\n\n const existing = await fetchEntities(messages?.loadFailed)\n const exists = existing.some(\n (entry) => entry?.entityId === rawEntityId && (entry?.source === 'custom' || entry?.source === undefined),\n )\n if (exists) {\n const message = messages?.entityIdExists ?? 'Entity ID already exists'\n throw createCrudFormError(message, { entityId: message })\n }\n\n const payload: Record<string, unknown> = {\n ...values,\n entityId: rawEntityId,\n labelField: 'name',\n defaultEditor:\n typeof (values as Record<string, unknown>).defaultEditor === 'string' &&\n (values as Record<string, unknown>).defaultEditor\n ? (values as Record<string, unknown>).defaultEditor\n : undefined,\n }\n\n await createEntity(payload)\n return rawEntityId\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { CrudForm, type CrudField } from '@open-mercato/ui/backend/CrudForm'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { upsertCustomEntitySchema } from '@open-mercato/core/modules/entities/data/validators'\nimport { useRouter } from 'next/navigation'\nimport { pushWithFlash } from '@open-mercato/ui/backend/utils/flash'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { LoadingMessage } from '@open-mercato/ui/backend/detail'\n\nconst schema = upsertCustomEntitySchema\n\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\n\nexport default function CreateEntityPage() {\n const t = useT()\n const router = useRouter()\n // Pre-fill the restriction toggle from the tenant default-restricted policy so\n // the form reflects the workspace posture; null while loading.\n const [defaultRestricted, setDefaultRestricted] = React.useState<boolean | null>(null)\n React.useEffect(() => {\n let active = true\n ;(async () => {\n const data = await readApiResultOrThrow<{ newEntitiesRestrictedByDefault?: boolean }>(\n '/api/entities/entity-settings',\n undefined,\n { errorMessage: '[internal] Failed to load entity settings', fallback: { newEntitiesRestrictedByDefault: false } },\n ).catch(() => ({ newEntitiesRestrictedByDefault: false }))\n if (active) setDefaultRestricted(data?.newEntitiesRestrictedByDefault === true)\n })()\n return () => { active = false }\n }, [])\n const fields = React.useMemo<CrudField[]>(() => ([\n {\n id: 'entityId',\n label: t('entities.userEntities.form.entityId.label', 'Entity ID'),\n type: 'text',\n required: true,\n placeholder: t('entities.userEntities.form.entityId.placeholder', 'module_name:entity_id'),\n },\n { id: 'label', label: t('entities.userEntities.form.label.label', 'Label'), type: 'text', required: true },\n { id: 'description', label: t('entities.userEntities.form.description.label', 'Description'), type: 'textarea' },\n {\n id: 'defaultEditor',\n label: t('entities.userEntities.form.defaultEditor.label', 'Default Editor (multiline)'),\n type: 'select',\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 { value: 'plain', label: t('entities.userEntities.form.defaultEditor.options.plain', 'Plain textarea') },\n ],\n } as unknown as CrudField,\n { id: 'showInSidebar', label: t('entities.userEntities.form.showInSidebar.label', 'Show in sidebar'), type: 'checkbox' } as CrudField,\n {\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 } as CrudField,\n ]), [t])\n\n if (defaultRestricted === null) {\n return (\n <Page>\n <PageBody>\n <LoadingMessage label={t('entities.userEntities.form.loading', 'Loading\u2026')} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={t('entities.userEntities.form.title', 'Create Entity')}\n backHref=\"/backend/entities/user\"\n schema={schema}\n fields={fields}\n initialValues={{ entityId: 'user:your_entity', label: '', showInSidebar: false, accessRestricted: defaultRestricted }}\n submitLabel={t('entities.userEntities.form.submit', 'Create')}\n cancelHref=\"/backend/entities/user\"\n onSubmit={async (vals) => {\n const entityId = await submitCreateEntity({\n values: vals as Record<string, unknown>,\n messages: {\n entityIdRequired: t('entities.userEntities.errors.entityIdRequired', 'Entity ID is required'),\n entityIdExists: t('entities.userEntities.errors.entityIdExists', 'Entity ID already exists'),\n loadFailed: t('entities.userEntities.errors.loadFailed', 'Failed to load entities'),\n },\n })\n try {\n window.dispatchEvent(new Event('om:refresh-sidebar'))\n } catch {}\n const successMessage = t('entities.userEntities.flash.created', 'Entity created')\n pushWithFlash(router, `/backend/entities/user/${encodeURIComponent(entityId)}`, successMessage, 'success')\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\ntype EntityListEntry = {\n entityId?: string\n source?: string\n}\n\ntype FetchCustomEntities = (errorMessage?: string) => Promise<EntityListEntry[]>\n\nasync function defaultFetchCustomEntities(errorMessage?: string): Promise<EntityListEntry[]> {\n const data = await readApiResultOrThrow<{ items?: EntityListEntry[] }>(\n '/api/entities/entities',\n undefined,\n { errorMessage: errorMessage ?? 'Failed to load entities', fallback: { items: [] } },\n )\n return Array.isArray(data?.items) ? data.items! : []\n}\n\ntype CreateEntityRequest = (payload: Record<string, unknown>) => Promise<void>\n\nasync function defaultCreateEntityRequest(payload: Record<string, unknown>) {\n await createCrud('entities/entities', payload)\n}\n\nexport async function submitCreateEntity(options: {\n values: Record<string, unknown>\n fetchEntities?: FetchCustomEntities\n createEntity?: CreateEntityRequest\n messages?: {\n entityIdRequired?: string\n entityIdExists?: string\n loadFailed?: string\n }\n}): Promise<string> {\n const {\n values,\n fetchEntities = defaultFetchCustomEntities,\n createEntity = defaultCreateEntityRequest,\n messages,\n } = options\n const rawEntityId = typeof values.entityId === 'string' ? values.entityId.trim() : ''\n if (!rawEntityId) {\n const message = messages?.entityIdRequired ?? 'Entity ID is required'\n throw createCrudFormError(message, { entityId: message })\n }\n\n const existing = await fetchEntities(messages?.loadFailed)\n const exists = existing.some(\n (entry) => entry?.entityId === rawEntityId && (entry?.source === 'custom' || entry?.source === undefined),\n )\n if (exists) {\n const message = messages?.entityIdExists ?? 'Entity ID already exists'\n throw createCrudFormError(message, { entityId: message })\n }\n\n const payload: Record<string, unknown> = {\n ...values,\n entityId: rawEntityId,\n labelField: 'name',\n defaultEditor:\n typeof (values as Record<string, unknown>).defaultEditor === 'string' &&\n (values as Record<string, unknown>).defaultEditor\n ? (values as Record<string, unknown>).defaultEditor\n : undefined,\n }\n\n await createEntity(payload)\n return rawEntityId\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/entities/data/entities.ts"],
|
|
4
|
-
"sourcesContent": ["import { Entity, Index, PrimaryKey, Property } from '@mikro-orm/decorators/legacy'\n\n// Definitions of custom fields scoped to an entity type and organization\n@Entity({ tableName: 'custom_field_defs' })\n@Index({\n name: 'cf_defs_entity_tenant_org_idx',\n properties: ['entityId', 'tenantId', 'organizationId'],\n})\n@Index({\n name: 'cf_defs_entity_tenant_idx',\n properties: ['entityId', 'tenantId'],\n})\n@Index({\n name: 'cf_defs_entity_org_idx',\n properties: ['entityId', 'organizationId'],\n})\n@Index({\n name: 'cf_defs_entity_global_idx',\n properties: ['entityId'],\n})\n@Index({\n name: 'cf_defs_entity_key_scope_idx',\n properties: ['entityId', 'key', 'tenantId', 'organizationId'],\n})\nexport class CustomFieldDef {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n // Entity identifier: '<module>:<entity>'\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n // Organization scope (nullable for global)\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n // Tenant scope (nullable for global)\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n // Unique key within entity scope\n @Property({ type: 'text' })\n @Index({ name: 'cf_defs_entity_key_idx' })\n key!: string\n\n // Field kind: text|multiline|integer|float|boolean|select|currency\n @Property({ type: 'text' })\n kind!: string\n\n // Optional select options or metadata in JSON\n @Property({ name: 'config_json', type: 'json', nullable: true })\n configJson?: any\n\n @Property({ name: 'is_active', type: 'boolean', default: true })\n isActive: boolean = true\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'custom_field_entity_configs' })\n@Index({\n name: 'cf_entity_cfgs_entity_scope_idx',\n properties: ['entityId', 'tenantId', 'organizationId'],\n})\n@Index({\n name: 'cf_entity_cfgs_entity_tenant_idx',\n properties: ['entityId', 'tenantId'],\n})\n@Index({\n name: 'cf_entity_cfgs_entity_org_idx',\n properties: ['entityId', 'organizationId'],\n})\nexport class CustomFieldEntityConfig {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'config_json', type: 'jsonb', nullable: true })\n configJson?: Record<string, unknown> | null\n\n @Property({ name: 'is_active', type: 'boolean', default: true })\n isActive: boolean = true\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// User-defined logical entities registry (for dynamic data types)\n@Entity({ tableName: 'custom_entities' })\n@Index({ name: 'custom_entities_unique_idx', properties: ['entityId', 'organizationId', 'tenantId'], options: { unique: true } })\nexport class CustomEntity {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n // Identifier: '<module>:<entity>' (snake_case entity part preferred)\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n @Property({ type: 'text' })\n label!: string\n\n @Property({ type: 'text', nullable: true })\n description?: string | null\n\n // Preferred display label field for relation options (e.g., 'name')\n @Property({ name: 'label_field', type: 'text', nullable: true })\n labelField?: string | null\n\n // Default editor preference for multiline custom fields\n // Allowed: 'markdown' | 'simpleMarkdown' | 'htmlRichText'\n @Property({ name: 'default_editor', type: 'text', nullable: true })\n defaultEditor?: string | null\n\n // Whether to show this entity in the sidebar navigation\n @Property({ name: 'show_in_sidebar', type: 'boolean', default: false })\n showInSidebar: boolean = false\n\n // When true, records require an explicit per-entity ACL grant\n // (entities.records.<entity_id>.view/.manage) beyond the coarse\n // entities.records.* feature. Defaults to unrestricted for backward compat.\n @Property({ name: 'access_restricted', type: 'boolean', default: false })\n accessRestricted: boolean = false\n\n // Note: Per-field UI preferences (list visibility, filter visibility, form editability)\n // are stored in CustomFieldDef.configJson, not at entity level.\n\n // Optional org/tenant scoping\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'is_active', type: 'boolean', default: true })\n isActive: boolean = true\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// Storage for custom entity records (JSONB document store)\n@Entity({ tableName: 'custom_entities_storage' })\n@Index({ name: 'custom_entities_storage_unique_idx', properties: ['entityType', 'entityId', 'organizationId'], options: { unique: true } })\nexport class CustomEntityStorage {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'entity_type', type: 'text' })\n entityType!: string\n\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'doc', type: 'json' })\n doc!: any\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// Values for custom fields (EAV); recordId is a text to support any PK\n@Entity({ tableName: 'custom_field_values' })\n@Index({\n name: 'cf_values_entity_record_tenant_idx',\n properties: ['entityId', 'recordId', 'tenantId'],\n})\nexport class CustomFieldValue {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n // Text to support int/uuid PKs equally\n @Property({ name: 'record_id', type: 'text' })\n recordId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n // Field key for lookup; resolves to a CustomFieldDef\n @Property({ name: 'field_key', type: 'text' })\n @Index({ name: 'cf_values_entity_record_field_idx' })\n fieldKey!: string\n\n // One of the following value columns is used based on kind\n @Property({ name: 'value_text', type: 'text', nullable: true })\n valueText?: string | null\n\n @Property({ name: 'value_multiline', type: 'text', nullable: true })\n valueMultiline?: string | null\n\n @Property({ name: 'value_int', type: 'int', nullable: true })\n valueInt?: number | null\n\n @Property({ name: 'value_float', type: 'float', nullable: true })\n valueFloat?: number | null\n\n @Property({ name: 'value_bool', type: 'boolean', nullable: true })\n valueBool?: boolean | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// Encryption maps declared per entity/tenant/organization\n@Entity({ tableName: 'encryption_maps' })\n@Index({\n name: 'encryption_maps_entity_scope_idx',\n properties: ['entityId', 'tenantId', 'organizationId'],\n})\nexport class EncryptionMap {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'fields_json', type: 'jsonb', nullable: true })\n fieldsJson?: Array<{ field: string; hashField?: string | null }> | null\n\n @Property({ name: 'is_active', type: 'boolean', default: true })\n isActive: boolean = true\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
|
|
4
|
+
"sourcesContent": ["import { Entity, Index, PrimaryKey, Property } from '@mikro-orm/decorators/legacy'\n\n// Definitions of custom fields scoped to an entity type and organization\n@Entity({ tableName: 'custom_field_defs' })\n@Index({\n name: 'cf_defs_entity_tenant_org_idx',\n properties: ['entityId', 'tenantId', 'organizationId'],\n})\n@Index({\n name: 'cf_defs_entity_tenant_idx',\n properties: ['entityId', 'tenantId'],\n})\n@Index({\n name: 'cf_defs_entity_org_idx',\n properties: ['entityId', 'organizationId'],\n})\n@Index({\n name: 'cf_defs_entity_global_idx',\n properties: ['entityId'],\n})\n@Index({\n name: 'cf_defs_entity_key_scope_idx',\n properties: ['entityId', 'key', 'tenantId', 'organizationId'],\n})\nexport class CustomFieldDef {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n // Entity identifier: '<module>:<entity>'\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n // Organization scope (nullable for global)\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n // Tenant scope (nullable for global)\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n // Unique key within entity scope\n @Property({ type: 'text' })\n @Index({ name: 'cf_defs_entity_key_idx' })\n key!: string\n\n // Field kind: text|multiline|integer|float|boolean|select|currency\n @Property({ type: 'text' })\n kind!: string\n\n // Optional select options or metadata in JSON\n @Property({ name: 'config_json', type: 'json', nullable: true })\n configJson?: any\n\n @Property({ name: 'is_active', type: 'boolean', default: true })\n isActive: boolean = true\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'custom_field_entity_configs' })\n@Index({\n name: 'cf_entity_cfgs_entity_scope_idx',\n properties: ['entityId', 'tenantId', 'organizationId'],\n})\n@Index({\n name: 'cf_entity_cfgs_entity_tenant_idx',\n properties: ['entityId', 'tenantId'],\n})\n@Index({\n name: 'cf_entity_cfgs_entity_org_idx',\n properties: ['entityId', 'organizationId'],\n})\nexport class CustomFieldEntityConfig {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'config_json', type: 'jsonb', nullable: true })\n configJson?: Record<string, unknown> | null\n\n @Property({ name: 'is_active', type: 'boolean', default: true })\n isActive: boolean = true\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// User-defined logical entities registry (for dynamic data types)\n@Entity({ tableName: 'custom_entities' })\n@Index({ name: 'custom_entities_unique_idx', properties: ['entityId', 'organizationId', 'tenantId'], options: { unique: true } })\nexport class CustomEntity {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n // Identifier: '<module>:<entity>' (snake_case entity part preferred)\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n @Property({ type: 'text' })\n label!: string\n\n @Property({ type: 'text', nullable: true })\n description?: string | null\n\n // Preferred display label field for relation options (e.g., 'name')\n @Property({ name: 'label_field', type: 'text', nullable: true })\n labelField?: string | null\n\n // Default editor preference for multiline custom fields\n // Allowed: 'markdown' | 'simpleMarkdown' | 'htmlRichText' | 'plain'\n @Property({ name: 'default_editor', type: 'text', nullable: true })\n defaultEditor?: string | null\n\n // Whether to show this entity in the sidebar navigation\n @Property({ name: 'show_in_sidebar', type: 'boolean', default: false })\n showInSidebar: boolean = false\n\n // When true, records require an explicit per-entity ACL grant\n // (entities.records.<entity_id>.view/.manage) beyond the coarse\n // entities.records.* feature. Defaults to unrestricted for backward compat.\n @Property({ name: 'access_restricted', type: 'boolean', default: false })\n accessRestricted: boolean = false\n\n // Note: Per-field UI preferences (list visibility, filter visibility, form editability)\n // are stored in CustomFieldDef.configJson, not at entity level.\n\n // Optional org/tenant scoping\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'is_active', type: 'boolean', default: true })\n isActive: boolean = true\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// Storage for custom entity records (JSONB document store)\n@Entity({ tableName: 'custom_entities_storage' })\n@Index({ name: 'custom_entities_storage_unique_idx', properties: ['entityType', 'entityId', 'organizationId'], options: { unique: true } })\nexport class CustomEntityStorage {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'entity_type', type: 'text' })\n entityType!: string\n\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'doc', type: 'json' })\n doc!: any\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// Values for custom fields (EAV); recordId is a text to support any PK\n@Entity({ tableName: 'custom_field_values' })\n@Index({\n name: 'cf_values_entity_record_tenant_idx',\n properties: ['entityId', 'recordId', 'tenantId'],\n})\nexport class CustomFieldValue {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n // Text to support int/uuid PKs equally\n @Property({ name: 'record_id', type: 'text' })\n recordId!: string\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n // Field key for lookup; resolves to a CustomFieldDef\n @Property({ name: 'field_key', type: 'text' })\n @Index({ name: 'cf_values_entity_record_field_idx' })\n fieldKey!: string\n\n // One of the following value columns is used based on kind\n @Property({ name: 'value_text', type: 'text', nullable: true })\n valueText?: string | null\n\n @Property({ name: 'value_multiline', type: 'text', nullable: true })\n valueMultiline?: string | null\n\n @Property({ name: 'value_int', type: 'int', nullable: true })\n valueInt?: number | null\n\n @Property({ name: 'value_float', type: 'float', nullable: true })\n valueFloat?: number | null\n\n @Property({ name: 'value_bool', type: 'boolean', nullable: true })\n valueBool?: boolean | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n// Encryption maps declared per entity/tenant/organization\n@Entity({ tableName: 'encryption_maps' })\n@Index({\n name: 'encryption_maps_entity_scope_idx',\n properties: ['entityId', 'tenantId', 'organizationId'],\n})\nexport class EncryptionMap {\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'entity_id', type: 'text' })\n entityId!: string\n\n @Property({ name: 'tenant_id', type: 'uuid', nullable: true })\n tenantId?: string | null\n\n @Property({ name: 'organization_id', type: 'uuid', nullable: true })\n organizationId?: string | null\n\n @Property({ name: 'fields_json', type: 'jsonb', nullable: true })\n fieldsJson?: Array<{ field: string; hashField?: string | null }> | null\n\n @Property({ name: 'is_active', type: 'boolean', default: true })\n isActive: boolean = true\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
runIntegrationMutationGuardAfterSuccess,
|
|
21
21
|
runIntegrationMutationGuards
|
|
22
22
|
} from "../../guards.js";
|
|
23
|
+
import { resolveIntegrationsOrganizationId } from "../../../lib/organization-scope.js";
|
|
23
24
|
const idParamsSchema = z.object({ id: z.string().min(1) });
|
|
24
25
|
const metadata = {
|
|
25
26
|
GET: { requireAuth: true, requireFeatures: ["integrations.credentials.manage"] },
|
|
@@ -38,7 +39,8 @@ function resolveParams(ctx) {
|
|
|
38
39
|
}
|
|
39
40
|
async function GET(req, ctx) {
|
|
40
41
|
const auth = await getAuthFromRequest(req);
|
|
41
|
-
|
|
42
|
+
const organizationId = resolveIntegrationsOrganizationId(auth);
|
|
43
|
+
if (!auth?.tenantId || !organizationId) {
|
|
42
44
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
43
45
|
}
|
|
44
46
|
const rawParams = await resolveParams(ctx);
|
|
@@ -52,7 +54,7 @@ async function GET(req, ctx) {
|
|
|
52
54
|
}
|
|
53
55
|
const container = await createRequestContainer();
|
|
54
56
|
const credentialsService = container.resolve("integrationCredentialsService");
|
|
55
|
-
const scope = { organizationId
|
|
57
|
+
const scope = { organizationId, tenantId: auth.tenantId };
|
|
56
58
|
let values;
|
|
57
59
|
let updatedAt;
|
|
58
60
|
try {
|
|
@@ -76,7 +78,8 @@ async function GET(req, ctx) {
|
|
|
76
78
|
}
|
|
77
79
|
async function PUT(req, ctx) {
|
|
78
80
|
const auth = await getAuthFromRequest(req);
|
|
79
|
-
|
|
81
|
+
const organizationId = resolveIntegrationsOrganizationId(auth);
|
|
82
|
+
if (!auth?.tenantId || !organizationId) {
|
|
80
83
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
81
84
|
}
|
|
82
85
|
const rawParams = await resolveParams(ctx);
|
|
@@ -98,7 +101,7 @@ async function PUT(req, ctx) {
|
|
|
98
101
|
container,
|
|
99
102
|
{
|
|
100
103
|
tenantId: auth.tenantId,
|
|
101
|
-
organizationId
|
|
104
|
+
organizationId,
|
|
102
105
|
userId: auth.sub ?? "",
|
|
103
106
|
resourceKind: "integrations.integration",
|
|
104
107
|
resourceId: integration.id,
|
|
@@ -122,7 +125,7 @@ async function PUT(req, ctx) {
|
|
|
122
125
|
payloadData = reparsed.data;
|
|
123
126
|
}
|
|
124
127
|
const credentialsService = container.resolve("integrationCredentialsService");
|
|
125
|
-
const scope = { organizationId
|
|
128
|
+
const scope = { organizationId, tenantId: auth.tenantId };
|
|
126
129
|
const schema = credentialsService.getSchema(integration.id);
|
|
127
130
|
try {
|
|
128
131
|
const currentUpdatedAt = await credentialsService.resolveUpdatedAt(integration.id, scope);
|
|
@@ -164,12 +167,12 @@ async function PUT(req, ctx) {
|
|
|
164
167
|
await emitIntegrationsEvent("integrations.credentials.updated", {
|
|
165
168
|
integrationId: integration.id,
|
|
166
169
|
tenantId: auth.tenantId,
|
|
167
|
-
organizationId
|
|
170
|
+
organizationId,
|
|
168
171
|
userId: auth.sub
|
|
169
172
|
});
|
|
170
173
|
await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
|
|
171
174
|
tenantId: auth.tenantId,
|
|
172
|
-
organizationId
|
|
175
|
+
organizationId,
|
|
173
176
|
userId: auth.sub ?? "",
|
|
174
177
|
resourceKind: "integrations.integration",
|
|
175
178
|
resourceId: integration.id,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/integrations/api/%5Bid%5D/credentials/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getIntegration } from '@open-mercato/shared/modules/integrations/types'\nimport { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { emitIntegrationsEvent } from '../../../events'\nimport { saveCredentialsSchema } from '../../../data/validators'\nimport {\n isCredentialsEncryptionUnavailableError,\n type CredentialsService,\n} from '../../../lib/credentials-service'\nimport { collectCredentialUrlValidationErrors } from '../../../lib/credentials-field-validation'\nimport {\n maskSecretCredentials,\n mergeMaskedSecretCredentials,\n} from '../../../lib/credentials-masking'\nimport {\n resolveUserFeatures,\n runIntegrationMutationGuardAfterSuccess,\n runIntegrationMutationGuards,\n} from '../../guards'\n\nconst idParamsSchema = z.object({ id: z.string().min(1) })\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['integrations.credentials.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['integrations.credentials.manage'] },\n}\n\nexport const openApi = {\n tags: ['Integrations'],\n summary: 'Get or save integration credentials',\n}\n\nfunction resolveParams(ctx: { params?: Promise<{ id?: string }> | { id?: string } }): Promise<{ id?: string } | undefined> | { id?: string } | undefined {\n if (!ctx.params) return undefined\n if (typeof (ctx.params as Promise<unknown>).then === 'function') {\n return ctx.params as Promise<{ id?: string }>\n }\n return ctx.params as { id?: string }\n}\n\nexport async function GET(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,sBAAsB;AAC/B,SAAS,oCAAoC;AAC7C,SAAS,uBAAuB;AAChC,SAAS,6BAA6B;AACtC,SAAS,6BAA6B;AACtC;AAAA,EACE;AAAA,OAEK;AACP,SAAS,4CAA4C;AACrD;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getIntegration } from '@open-mercato/shared/modules/integrations/types'\nimport { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { emitIntegrationsEvent } from '../../../events'\nimport { saveCredentialsSchema } from '../../../data/validators'\nimport {\n isCredentialsEncryptionUnavailableError,\n type CredentialsService,\n} from '../../../lib/credentials-service'\nimport { collectCredentialUrlValidationErrors } from '../../../lib/credentials-field-validation'\nimport {\n maskSecretCredentials,\n mergeMaskedSecretCredentials,\n} from '../../../lib/credentials-masking'\nimport {\n resolveUserFeatures,\n runIntegrationMutationGuardAfterSuccess,\n runIntegrationMutationGuards,\n} from '../../guards'\nimport { resolveIntegrationsOrganizationId } from '../../../lib/organization-scope'\n\nconst idParamsSchema = z.object({ id: z.string().min(1) })\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['integrations.credentials.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['integrations.credentials.manage'] },\n}\n\nexport const openApi = {\n tags: ['Integrations'],\n summary: 'Get or save integration credentials',\n}\n\nfunction resolveParams(ctx: { params?: Promise<{ id?: string }> | { id?: string } }): Promise<{ id?: string } | undefined> | { id?: string } | undefined {\n if (!ctx.params) return undefined\n if (typeof (ctx.params as Promise<unknown>).then === 'function') {\n return ctx.params as Promise<{ id?: string }>\n }\n return ctx.params as { id?: string }\n}\n\nexport async function GET(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {\n const auth = await getAuthFromRequest(req)\n const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const rawParams = await resolveParams(ctx)\n const parsedParams = idParamsSchema.safeParse(rawParams)\n if (!parsedParams.success) {\n return NextResponse.json({ error: 'Invalid integration id' }, { status: 400 })\n }\n\n const integration = getIntegration(parsedParams.data.id)\n if (!integration) {\n return NextResponse.json({ error: 'Integration not found' }, { status: 404 })\n }\n\n const container = await createRequestContainer()\n const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService\n const scope = { organizationId: organizationId, tenantId: auth.tenantId }\n\n let values: Record<string, unknown> | null\n let updatedAt: Date | null\n try {\n values = await credentialsService.resolve(integration.id, scope)\n updatedAt = await credentialsService.resolveUpdatedAt(integration.id, scope)\n } catch (error) {\n if (isCredentialsEncryptionUnavailableError(error)) {\n return NextResponse.json({ error: 'Integration credentials encryption is unavailable' }, { status: 503 })\n }\n throw error\n }\n\n const schema = credentialsService.getSchema(integration.id)\n const { credentials, secretFieldsConfigured } = maskSecretCredentials(schema, values ?? {})\n\n return NextResponse.json({\n integrationId: integration.id,\n schema,\n credentials,\n secretFieldsConfigured,\n updatedAt: updatedAt?.toISOString() ?? null,\n })\n}\n\nexport async function PUT(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {\n const auth = await getAuthFromRequest(req)\n const organizationId = resolveIntegrationsOrganizationId(auth)\n if (!auth?.tenantId || !organizationId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const rawParams = await resolveParams(ctx)\n const parsedParams = idParamsSchema.safeParse(rawParams)\n if (!parsedParams.success) {\n return NextResponse.json({ error: 'Invalid integration id' }, { status: 400 })\n }\n\n const integration = getIntegration(parsedParams.data.id)\n if (!integration) {\n return NextResponse.json({ error: 'Integration not found' }, { status: 404 })\n }\n\n const payload = await req.json().catch(() => null)\n const parsedBody = saveCredentialsSchema.safeParse(payload)\n if (!parsedBody.success) {\n return NextResponse.json({ error: 'Invalid credentials payload', details: parsedBody.error.flatten() }, { status: 422 })\n }\n\n const container = await createRequestContainer()\n const guardResult = await runIntegrationMutationGuards(\n container,\n {\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub ?? '',\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n mutationPayload: parsedBody.data as Record<string, unknown>,\n },\n resolveUserFeatures(auth),\n )\n if (!guardResult.ok) {\n return NextResponse.json(guardResult.errorBody ?? { error: 'Operation blocked by guard' }, { status: guardResult.errorStatus ?? 422 })\n }\n\n let payloadData = parsedBody.data\n if (guardResult.modifiedPayload) {\n const mergedPayload = { ...parsedBody.data, ...guardResult.modifiedPayload }\n const reparsed = saveCredentialsSchema.safeParse(mergedPayload)\n if (!reparsed.success) {\n return NextResponse.json({ error: 'Invalid credentials payload after guard transform', details: reparsed.error.flatten() }, { status: 422 })\n }\n payloadData = reparsed.data\n }\n\n const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService\n const scope = { organizationId: organizationId, tenantId: auth.tenantId }\n const schema = credentialsService.getSchema(integration.id)\n\n try {\n const currentUpdatedAt = await credentialsService.resolveUpdatedAt(integration.id, scope)\n enforceCommandOptimisticLock({\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n current: currentUpdatedAt,\n request: req,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (isCredentialsEncryptionUnavailableError(error)) {\n return NextResponse.json({ error: 'Integration credentials encryption is unavailable' }, { status: 503 })\n }\n throw error\n }\n\n const credentialFieldErrors = collectCredentialUrlValidationErrors(\n schema,\n payloadData.credentials,\n )\n if (Object.keys(credentialFieldErrors).length > 0) {\n return NextResponse.json(\n { error: 'Invalid credentials payload', details: { fieldErrors: credentialFieldErrors } },\n { status: 422 },\n )\n }\n\n try {\n // Secret fields are returned masked on GET; when the client round-trips the\n // mask sentinel it means \"unchanged\", so restore the existing stored secret\n // instead of overwriting it with the placeholder.\n const existing = await credentialsService.resolve(integration.id, scope)\n const credentialsToSave = mergeMaskedSecretCredentials(schema, payloadData.credentials, existing ?? {})\n await credentialsService.save(integration.id, credentialsToSave, scope)\n } catch (error) {\n if (isCredentialsEncryptionUnavailableError(error)) {\n return NextResponse.json({ error: 'Integration credentials encryption is unavailable' }, { status: 503 })\n }\n throw error\n }\n\n await emitIntegrationsEvent('integrations.credentials.updated', {\n integrationId: integration.id,\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub,\n })\n\n await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {\n tenantId: auth.tenantId,\n organizationId,\n userId: auth.sub ?? '',\n resourceKind: 'integrations.integration',\n resourceId: integration.id,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n\n return NextResponse.json({ ok: true })\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
runIntegrationMutationGuardAfterSuccess,
|
|
9
9
|
runIntegrationMutationGuards
|
|
10
10
|
} from "../../guards.js";
|
|
11
|
+
import { resolveIntegrationsOrganizationId } from "../../../lib/organization-scope.js";
|
|
11
12
|
const idParamsSchema = z.object({ id: z.string().min(1) });
|
|
12
13
|
const metadata = {
|
|
13
14
|
POST: { requireAuth: true, requireFeatures: ["integrations.manage"] }
|
|
@@ -18,7 +19,8 @@ const openApi = {
|
|
|
18
19
|
};
|
|
19
20
|
async function POST(req, ctx) {
|
|
20
21
|
const auth = await getAuthFromRequest(req);
|
|
21
|
-
|
|
22
|
+
const organizationId = resolveIntegrationsOrganizationId(auth);
|
|
23
|
+
if (!auth?.tenantId || !organizationId) {
|
|
22
24
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
23
25
|
}
|
|
24
26
|
const rawParams = ctx.params && typeof ctx.params.then === "function" ? await ctx.params : ctx.params;
|
|
@@ -35,7 +37,7 @@ async function POST(req, ctx) {
|
|
|
35
37
|
container,
|
|
36
38
|
{
|
|
37
39
|
tenantId: auth.tenantId,
|
|
38
|
-
organizationId
|
|
40
|
+
organizationId,
|
|
39
41
|
userId: auth.sub ?? "",
|
|
40
42
|
resourceKind: "integrations.integration",
|
|
41
43
|
resourceId: integration.id,
|
|
@@ -52,11 +54,11 @@ async function POST(req, ctx) {
|
|
|
52
54
|
const healthService = container.resolve("integrationHealthService");
|
|
53
55
|
const result = await healthService.runHealthCheck(
|
|
54
56
|
integration.id,
|
|
55
|
-
{ organizationId
|
|
57
|
+
{ organizationId, tenantId: auth.tenantId }
|
|
56
58
|
);
|
|
57
59
|
await runIntegrationMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
|
|
58
60
|
tenantId: auth.tenantId,
|
|
59
|
-
organizationId
|
|
61
|
+
organizationId,
|
|
60
62
|
userId: auth.sub ?? "",
|
|
61
63
|
resourceKind: "integrations.integration",
|
|
62
64
|
resourceId: integration.id,
|