@open-mercato/core 0.7.1-develop.7106.1.53fe9dd1b1 → 0.7.1-develop.7112.1.d486e6f1b2

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.
Files changed (39) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/auth/api/users/resend-invite/route.js +1 -1
  3. package/dist/modules/auth/api/users/resend-invite/route.js.map +2 -2
  4. package/dist/modules/business_rules/backend/logs/[id]/page.js +3 -9
  5. package/dist/modules/business_rules/backend/logs/[id]/page.js.map +2 -2
  6. package/dist/modules/business_rules/backend/rules/[id]/page.js +3 -9
  7. package/dist/modules/business_rules/backend/rules/[id]/page.js.map +2 -2
  8. package/dist/modules/business_rules/backend/sets/[id]/page.js +3 -9
  9. package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
  10. package/dist/modules/communication_channels/backend/communication_channels/channels/[id]/page.js +6 -4
  11. package/dist/modules/communication_channels/backend/communication_channels/channels/[id]/page.js.map +2 -2
  12. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  13. package/dist/modules/customers/components/detail/ActivitiesSection.js +4 -12
  14. package/dist/modules/customers/components/detail/ActivitiesSection.js.map +2 -2
  15. package/dist/modules/customers/components/detail/authorUserLookup.js +46 -0
  16. package/dist/modules/customers/components/detail/authorUserLookup.js.map +7 -0
  17. package/dist/modules/query_index/lib/engine.js +2 -1
  18. package/dist/modules/query_index/lib/engine.js.map +2 -2
  19. package/dist/modules/workflows/backend/definitions/[id]/page.js +3 -9
  20. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  21. package/dist/modules/workflows/backend/events/[id]/page.js +3 -9
  22. package/dist/modules/workflows/backend/events/[id]/page.js.map +2 -2
  23. package/package.json +7 -7
  24. package/src/modules/auth/api/users/resend-invite/route.ts +1 -1
  25. package/src/modules/business_rules/backend/logs/[id]/page.tsx +3 -11
  26. package/src/modules/business_rules/backend/rules/[id]/page.tsx +3 -11
  27. package/src/modules/business_rules/backend/sets/[id]/page.tsx +3 -11
  28. package/src/modules/communication_channels/backend/communication_channels/channels/[id]/page.tsx +7 -5
  29. package/src/modules/communication_channels/i18n/de.json +1 -0
  30. package/src/modules/communication_channels/i18n/en.json +1 -0
  31. package/src/modules/communication_channels/i18n/es.json +1 -0
  32. package/src/modules/communication_channels/i18n/ko.json +1 -0
  33. package/src/modules/communication_channels/i18n/pl.json +1 -0
  34. package/src/modules/currencies/backend/currencies/[id]/page.tsx +1 -1
  35. package/src/modules/customers/components/detail/ActivitiesSection.tsx +8 -18
  36. package/src/modules/customers/components/detail/authorUserLookup.ts +85 -0
  37. package/src/modules/query_index/lib/engine.ts +9 -0
  38. package/src/modules/workflows/backend/definitions/[id]/page.tsx +3 -11
  39. package/src/modules/workflows/backend/events/[id]/page.tsx +3 -12
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { useRouter, useParams, usePathname } from "next/navigation";
4
+ import { useRouter, usePathname } from "next/navigation";
5
5
  import { useQuery } from "@tanstack/react-query";
6
6
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
7
7
  import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
@@ -30,18 +30,12 @@ import { TransitionsEditor } from "../../../components/TransitionsEditor.js";
30
30
  import { DefinitionTriggersEditor } from "../../../components/DefinitionTriggersEditor.js";
31
31
  import { MobileDefinitionDetail } from "../../../components/mobile/MobileDefinitionDetail.js";
32
32
  import { useIsMobile } from "@open-mercato/ui/hooks/useIsMobile";
33
- function EditWorkflowDefinitionPage() {
33
+ function EditWorkflowDefinitionPage({ params }) {
34
34
  const router = useRouter();
35
- const params = useParams();
36
35
  const pathname = usePathname();
37
36
  const t = useT();
38
37
  const isMobile = useIsMobile();
39
- let definitionId;
40
- if (params?.slug && Array.isArray(params.slug)) {
41
- definitionId = params.slug[1];
42
- } else if (params?.id) {
43
- definitionId = Array.isArray(params.id) ? params.id[0] : params.id;
44
- }
38
+ const definitionId = params?.id;
45
39
  const { data: definition, isLoading, error } = useQuery({
46
40
  queryKey: ["workflow-definition", definitionId],
47
41
  queryFn: async () => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/workflows/backend/definitions/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter, useParams, usePathname } from 'next/navigation'\nimport { useQuery } from '@tanstack/react-query'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { apiFetch, withScopedApiHeaders } from '@open-mercato/ui/backend/utils/api'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { readJsonSafe } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { formatWorkflowValidationError } from '../../../lib/format-validation-error'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport {\n workflowDefinitionFormSchema,\n createFormGroups,\n createFieldDefinitions,\n parseWorkflowToFormValues,\n buildWorkflowPayload,\n type WorkflowDefinitionFormValues,\n} from '../../../components/formConfig'\nimport { StepsEditor } from '../../../components/StepsEditor'\nimport { TransitionsEditor } from '../../../components/TransitionsEditor'\nimport { DefinitionTriggersEditor } from '../../../components/DefinitionTriggersEditor'\nimport { MobileDefinitionDetail } from '../../../components/mobile/MobileDefinitionDetail'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport type { WorkflowDefinitionTrigger } from '../../../data/entities'\n\nexport default function EditWorkflowDefinitionPage() {\n const router = useRouter()\n const params = useParams()\n const pathname = usePathname()\n const t = useT()\n const isMobile = useIsMobile()\n\n // Handle catch-all route: params.slug = ['definitions', 'uuid']\n let definitionId: string | undefined\n if (params?.slug && Array.isArray(params.slug)) {\n definitionId = params.slug[1] // Second element is the ID\n } else if (params?.id) {\n definitionId = Array.isArray(params.id) ? params.id[0] : params.id\n }\n\n const { data: definition, isLoading, error } = useQuery({\n queryKey: ['workflow-definition', definitionId],\n queryFn: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}`)\n if (!response.ok) {\n const err = new Error(t('workflows.errors.fetchFailed')) as Error & { status?: number }\n err.status = response.status\n throw err\n }\n const result = await response.json()\n return result.data\n },\n enabled: !!definitionId,\n retry: (failureCount, err) => {\n if ((err as { status?: number }).status === 404) return false\n return failureCount < 2\n },\n })\n\n const isNotFound = (error as { status?: number } | null)?.status === 404\n\n const initialValues = React.useMemo(() => {\n if (definition) {\n return parseWorkflowToFormValues(definition)\n }\n return null\n }, [definition])\n\n const [triggers, setTriggers] = React.useState<WorkflowDefinitionTrigger[]>([])\n\n React.useEffect(() => {\n setTriggers(initialValues?.triggers ?? [])\n }, [initialValues])\n\n const source = definition?.source as 'code' | 'code_override' | 'user' | undefined\n const isCodeOnly = source === 'code'\n const isCodeOverride = source === 'code_override'\n\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const mutationContextId = React.useMemo(\n () => `workflows.definitions.detail:${definitionId ?? 'unknown'}`,\n [definitionId],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: mutationContextId,\n })\n\n const handleSubmit = async (values: WorkflowDefinitionFormValues) => {\n const payload = buildWorkflowPayload({ ...values, triggers })\n const optimisticLockHeader = buildOptimisticLockHeader(\n typeof definition?.updatedAt === 'string' ? definition.updatedAt : null,\n )\n\n await runMutation({\n operation: async () => {\n const updateDefinition = () => apiFetch(`/api/workflows/definitions/${definitionId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n const response = Object.keys(optimisticLockHeader).length > 0\n ? await withScopedApiHeaders(optimisticLockHeader, updateDefinition)\n : await updateDefinition()\n if (!response.ok) {\n const errorBody = await readJsonSafe<{\n error?: string\n code?: string\n currentUpdatedAt?: string\n expectedUpdatedAt?: string\n details?: Array<{ path?: Array<string | number>; message?: string }>\n }>(response, null)\n throw Object.assign(\n new Error(formatWorkflowValidationError(errorBody, t('workflows.errors.updateFailed'))),\n { status: response.status, ...(errorBody ?? {}) },\n )\n }\n return response\n },\n mutationPayload: { resourceId: definitionId, operation: 'update' },\n context: {\n formId: mutationContextId,\n resourceKind: 'workflows.definition',\n resourceId: definitionId,\n operation: 'update',\n retryLastMutation,\n },\n })\n\n router.push('/backend/definitions')\n router.refresh()\n }\n\n const handleCustomize = async () => {\n try {\n const result = await runMutation({\n operation: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}/customize`, {\n method: 'POST',\n })\n if (!response.ok) {\n const errorBody = await readJsonSafe<{ error?: string }>(response, null)\n throw new Error(errorBody?.error || t('workflows.errors.updateFailed'))\n }\n return readJsonSafe<{ data?: { id?: string } }>(response, null)\n },\n mutationPayload: { resourceId: definitionId, operation: 'customize' },\n context: {\n formId: mutationContextId,\n resourceKind: 'workflows.definition',\n resourceId: definitionId,\n operation: 'customize',\n retryLastMutation,\n },\n })\n if (result?.data?.id) {\n router.push(`/backend/definitions/${result.data.id}`)\n router.refresh()\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : t('workflows.errors.updateFailed')\n flash(message, 'error')\n }\n }\n\n const handleResetToCode = async () => {\n const confirmed = await confirm({\n title: t('workflows.actions.resetToCode'),\n description: t('workflows.actions.resetConfirm'),\n confirmText: t('workflows.actions.resetToCode'),\n variant: 'destructive',\n })\n if (!confirmed) return\n\n try {\n const result = await runMutation({\n operation: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}/reset-to-code`, {\n method: 'POST',\n })\n if (!response.ok) {\n const errorBody = await readJsonSafe<{ error?: string }>(response, null)\n throw new Error(errorBody?.error || t('workflows.messages.updateFailed'))\n }\n return readJsonSafe<{ data?: { id?: string } }>(response, null)\n },\n mutationPayload: { resourceId: definitionId, operation: 'reset-to-code' },\n context: {\n formId: mutationContextId,\n resourceKind: 'workflows.definition',\n resourceId: definitionId,\n operation: 'reset-to-code',\n retryLastMutation,\n },\n })\n flash(t('workflows.messages.updated'), 'success')\n const codeId = result?.data?.id || `code:${definition?.workflowId}`\n router.push(`/backend/definitions/${codeId}`)\n router.refresh()\n } catch {\n flash(t('workflows.messages.updateFailed'), 'error')\n }\n }\n\n const fields = React.useMemo(() => createFieldDefinitions(t), [t])\n\n const formGroups = React.useMemo(\n () => isMobile ? [] : createFormGroups(t, StepsEditor, TransitionsEditor),\n [t, isMobile]\n )\n\n const navigateToVisualEditor = React.useCallback(() => {\n router.push(`/backend/definitions/visual-editor?id=${definitionId}`)\n }, [router, definitionId])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `workflows.definition` + id\n // explicitly. The resourceKind mirrors the save-time `useGuardedMutation` context\n // and server guard so the held lock matches the conflict surface for the same\n // definition across both the form and visual editors.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'workflows.definition',\n resourceId: definitionId ?? null,\n updatedAt: typeof definition?.updatedAt === 'string' ? definition.updatedAt : null,\n data: (definition ?? null) as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('workflows.edit.loading')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('workflows.errors.notFound', t('workflows.errors.loadFailed'))}\n backHref=\"/backend/definitions\"\n backLabel={t('workflows.backToList')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !definition) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={t('workflows.errors.loadFailed')} />\n <div className=\"mt-4 flex justify-center\">\n <Button asChild variant=\"outline\">\n <a href=\"/backend/definitions\">{t('workflows.backToList')}</a>\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (!initialValues) {\n return null\n }\n\n return (\n <Page>\n <PageBody>\n {isCodeOnly && (\n <Alert status=\"information\" className=\"mb-4\">\n <AlertDescription className=\"flex items-center justify-between\">\n <span>{t('workflows.source.code.readonlyBanner')}</span>\n <Button variant=\"outline\" size=\"sm\" onClick={handleCustomize}>\n {t('workflows.actions.customize')}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n {isCodeOverride && (\n <Alert status=\"warning\" className=\"mb-4\">\n <AlertDescription className=\"flex items-center justify-between\">\n <span>{t('workflows.source.code_override.banner')}</span>\n <Button variant=\"outline\" size=\"sm\" onClick={handleResetToCode}>\n {t('workflows.actions.resetToCode')}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n <div className=\"mb-4 p-4 bg-status-info-bg border border-status-info-border rounded-lg flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-start gap-3\">\n <svg className=\"w-5 h-5 text-status-info-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n <div>\n <p className=\"text-sm font-medium text-status-info-text\">\n {t('workflows.edit.visualEditorAvailable')}\n </p>\n <p className=\"text-xs text-status-info-text mt-0.5\">\n {t('workflows.edit.visualEditorDescription')}\n </p>\n </div>\n </div>\n <Button asChild variant=\"outline\" size=\"sm\" className=\"w-full sm:w-auto border-status-info-border text-status-info-text hover:bg-status-info-bg\">\n <a href={`/backend/definitions/visual-editor?id=${definitionId}`}>\n {t('workflows.actions.openVisualEditor')}\n </a>\n </Button>\n </div>\n <CrudForm\n key={definitionId}\n title={isCodeOnly ? definition?.workflowName || t('workflows.edit.title') : t('workflows.edit.title')}\n backHref=\"/backend/definitions\"\n schema={workflowDefinitionFormSchema}\n fields={fields}\n initialValues={initialValues}\n onSubmit={handleSubmit}\n cancelHref=\"/backend/definitions\"\n groups={formGroups}\n submitLabel={isCodeOnly ? t('workflows.actions.customize') : t('workflows.form.update')}\n {...(isCodeOnly ? { readOnly: true } : {})}\n />\n\n {/* Mobile Steps & Transitions View */}\n {isMobile && initialValues && (\n <div className=\"mt-4\">\n <MobileDefinitionDetail\n values={initialValues}\n onEditStep={navigateToVisualEditor}\n onDeleteStep={navigateToVisualEditor}\n onAddStep={navigateToVisualEditor}\n onEditTransition={navigateToVisualEditor}\n onDeleteTransition={navigateToVisualEditor}\n onAddTransition={navigateToVisualEditor}\n />\n </div>\n )}\n\n {/* Event Triggers Section */}\n <div className=\"mt-8\">\n <DefinitionTriggersEditor\n value={triggers}\n onChange={setTriggers}\n />\n </div>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter, usePathname } from 'next/navigation'\nimport { useQuery } from '@tanstack/react-query'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm } from '@open-mercato/ui/backend/CrudForm'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { apiFetch, withScopedApiHeaders } from '@open-mercato/ui/backend/utils/api'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { readJsonSafe } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { formatWorkflowValidationError } from '../../../lib/format-validation-error'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport {\n workflowDefinitionFormSchema,\n createFormGroups,\n createFieldDefinitions,\n parseWorkflowToFormValues,\n buildWorkflowPayload,\n type WorkflowDefinitionFormValues,\n} from '../../../components/formConfig'\nimport { StepsEditor } from '../../../components/StepsEditor'\nimport { TransitionsEditor } from '../../../components/TransitionsEditor'\nimport { DefinitionTriggersEditor } from '../../../components/DefinitionTriggersEditor'\nimport { MobileDefinitionDetail } from '../../../components/mobile/MobileDefinitionDetail'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport type { WorkflowDefinitionTrigger } from '../../../data/entities'\n\nexport default function EditWorkflowDefinitionPage({ params }: { params?: { id?: string } }) {\n const router = useRouter()\n const pathname = usePathname()\n const t = useT()\n const isMobile = useIsMobile()\n const definitionId = params?.id\n\n const { data: definition, isLoading, error } = useQuery({\n queryKey: ['workflow-definition', definitionId],\n queryFn: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}`)\n if (!response.ok) {\n const err = new Error(t('workflows.errors.fetchFailed')) as Error & { status?: number }\n err.status = response.status\n throw err\n }\n const result = await response.json()\n return result.data\n },\n enabled: !!definitionId,\n retry: (failureCount, err) => {\n if ((err as { status?: number }).status === 404) return false\n return failureCount < 2\n },\n })\n\n const isNotFound = (error as { status?: number } | null)?.status === 404\n\n const initialValues = React.useMemo(() => {\n if (definition) {\n return parseWorkflowToFormValues(definition)\n }\n return null\n }, [definition])\n\n const [triggers, setTriggers] = React.useState<WorkflowDefinitionTrigger[]>([])\n\n React.useEffect(() => {\n setTriggers(initialValues?.triggers ?? [])\n }, [initialValues])\n\n const source = definition?.source as 'code' | 'code_override' | 'user' | undefined\n const isCodeOnly = source === 'code'\n const isCodeOverride = source === 'code_override'\n\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const mutationContextId = React.useMemo(\n () => `workflows.definitions.detail:${definitionId ?? 'unknown'}`,\n [definitionId],\n )\n const { runMutation, retryLastMutation } = useGuardedMutation<Record<string, unknown>>({\n contextId: mutationContextId,\n })\n\n const handleSubmit = async (values: WorkflowDefinitionFormValues) => {\n const payload = buildWorkflowPayload({ ...values, triggers })\n const optimisticLockHeader = buildOptimisticLockHeader(\n typeof definition?.updatedAt === 'string' ? definition.updatedAt : null,\n )\n\n await runMutation({\n operation: async () => {\n const updateDefinition = () => apiFetch(`/api/workflows/definitions/${definitionId}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n const response = Object.keys(optimisticLockHeader).length > 0\n ? await withScopedApiHeaders(optimisticLockHeader, updateDefinition)\n : await updateDefinition()\n if (!response.ok) {\n const errorBody = await readJsonSafe<{\n error?: string\n code?: string\n currentUpdatedAt?: string\n expectedUpdatedAt?: string\n details?: Array<{ path?: Array<string | number>; message?: string }>\n }>(response, null)\n throw Object.assign(\n new Error(formatWorkflowValidationError(errorBody, t('workflows.errors.updateFailed'))),\n { status: response.status, ...(errorBody ?? {}) },\n )\n }\n return response\n },\n mutationPayload: { resourceId: definitionId, operation: 'update' },\n context: {\n formId: mutationContextId,\n resourceKind: 'workflows.definition',\n resourceId: definitionId,\n operation: 'update',\n retryLastMutation,\n },\n })\n\n router.push('/backend/definitions')\n router.refresh()\n }\n\n const handleCustomize = async () => {\n try {\n const result = await runMutation({\n operation: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}/customize`, {\n method: 'POST',\n })\n if (!response.ok) {\n const errorBody = await readJsonSafe<{ error?: string }>(response, null)\n throw new Error(errorBody?.error || t('workflows.errors.updateFailed'))\n }\n return readJsonSafe<{ data?: { id?: string } }>(response, null)\n },\n mutationPayload: { resourceId: definitionId, operation: 'customize' },\n context: {\n formId: mutationContextId,\n resourceKind: 'workflows.definition',\n resourceId: definitionId,\n operation: 'customize',\n retryLastMutation,\n },\n })\n if (result?.data?.id) {\n router.push(`/backend/definitions/${result.data.id}`)\n router.refresh()\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : t('workflows.errors.updateFailed')\n flash(message, 'error')\n }\n }\n\n const handleResetToCode = async () => {\n const confirmed = await confirm({\n title: t('workflows.actions.resetToCode'),\n description: t('workflows.actions.resetConfirm'),\n confirmText: t('workflows.actions.resetToCode'),\n variant: 'destructive',\n })\n if (!confirmed) return\n\n try {\n const result = await runMutation({\n operation: async () => {\n const response = await apiFetch(`/api/workflows/definitions/${definitionId}/reset-to-code`, {\n method: 'POST',\n })\n if (!response.ok) {\n const errorBody = await readJsonSafe<{ error?: string }>(response, null)\n throw new Error(errorBody?.error || t('workflows.messages.updateFailed'))\n }\n return readJsonSafe<{ data?: { id?: string } }>(response, null)\n },\n mutationPayload: { resourceId: definitionId, operation: 'reset-to-code' },\n context: {\n formId: mutationContextId,\n resourceKind: 'workflows.definition',\n resourceId: definitionId,\n operation: 'reset-to-code',\n retryLastMutation,\n },\n })\n flash(t('workflows.messages.updated'), 'success')\n const codeId = result?.data?.id || `code:${definition?.workflowId}`\n router.push(`/backend/definitions/${codeId}`)\n router.refresh()\n } catch {\n flash(t('workflows.messages.updateFailed'), 'error')\n }\n }\n\n const fields = React.useMemo(() => createFieldDefinitions(t), [t])\n\n const formGroups = React.useMemo(\n () => isMobile ? [] : createFormGroups(t, StepsEditor, TransitionsEditor),\n [t, isMobile]\n )\n\n const navigateToVisualEditor = React.useCallback(() => {\n router.push(`/backend/definitions/visual-editor?id=${definitionId}`)\n }, [router, definitionId])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `workflows.definition` + id\n // explicitly. The resourceKind mirrors the save-time `useGuardedMutation` context\n // and server guard so the held lock matches the conflict surface for the same\n // definition across both the form and visual editors.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'workflows.definition',\n resourceId: definitionId ?? null,\n updatedAt: typeof definition?.updatedAt === 'string' ? definition.updatedAt : null,\n data: (definition ?? null) as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('workflows.edit.loading')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('workflows.errors.notFound', t('workflows.errors.loadFailed'))}\n backHref=\"/backend/definitions\"\n backLabel={t('workflows.backToList')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !definition) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={t('workflows.errors.loadFailed')} />\n <div className=\"mt-4 flex justify-center\">\n <Button asChild variant=\"outline\">\n <a href=\"/backend/definitions\">{t('workflows.backToList')}</a>\n </Button>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n if (!initialValues) {\n return null\n }\n\n return (\n <Page>\n <PageBody>\n {isCodeOnly && (\n <Alert status=\"information\" className=\"mb-4\">\n <AlertDescription className=\"flex items-center justify-between\">\n <span>{t('workflows.source.code.readonlyBanner')}</span>\n <Button variant=\"outline\" size=\"sm\" onClick={handleCustomize}>\n {t('workflows.actions.customize')}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n {isCodeOverride && (\n <Alert status=\"warning\" className=\"mb-4\">\n <AlertDescription className=\"flex items-center justify-between\">\n <span>{t('workflows.source.code_override.banner')}</span>\n <Button variant=\"outline\" size=\"sm\" onClick={handleResetToCode}>\n {t('workflows.actions.resetToCode')}\n </Button>\n </AlertDescription>\n </Alert>\n )}\n <div className=\"mb-4 p-4 bg-status-info-bg border border-status-info-border rounded-lg flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex items-start gap-3\">\n <svg className=\"w-5 h-5 text-status-info-icon\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n <div>\n <p className=\"text-sm font-medium text-status-info-text\">\n {t('workflows.edit.visualEditorAvailable')}\n </p>\n <p className=\"text-xs text-status-info-text mt-0.5\">\n {t('workflows.edit.visualEditorDescription')}\n </p>\n </div>\n </div>\n <Button asChild variant=\"outline\" size=\"sm\" className=\"w-full sm:w-auto border-status-info-border text-status-info-text hover:bg-status-info-bg\">\n <a href={`/backend/definitions/visual-editor?id=${definitionId}`}>\n {t('workflows.actions.openVisualEditor')}\n </a>\n </Button>\n </div>\n <CrudForm\n key={definitionId}\n title={isCodeOnly ? definition?.workflowName || t('workflows.edit.title') : t('workflows.edit.title')}\n backHref=\"/backend/definitions\"\n schema={workflowDefinitionFormSchema}\n fields={fields}\n initialValues={initialValues}\n onSubmit={handleSubmit}\n cancelHref=\"/backend/definitions\"\n groups={formGroups}\n submitLabel={isCodeOnly ? t('workflows.actions.customize') : t('workflows.form.update')}\n {...(isCodeOnly ? { readOnly: true } : {})}\n />\n\n {/* Mobile Steps & Transitions View */}\n {isMobile && initialValues && (\n <div className=\"mt-4\">\n <MobileDefinitionDetail\n values={initialValues}\n onEditStep={navigateToVisualEditor}\n onDeleteStep={navigateToVisualEditor}\n onAddStep={navigateToVisualEditor}\n onEditTransition={navigateToVisualEditor}\n onDeleteTransition={navigateToVisualEditor}\n onAddTransition={navigateToVisualEditor}\n />\n </div>\n )}\n\n {/* Event Triggers Section */}\n <div className=\"mt-8\">\n <DefinitionTriggersEditor\n value={triggers}\n onChange={setTriggers}\n />\n </div>\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["error"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import Link from "next/link";
4
- import { useParams, useRouter } from "next/navigation";
4
+ import { useRouter } from "next/navigation";
5
5
  import { useQuery } from "@tanstack/react-query";
6
6
  import { apiFetch } from "@open-mercato/ui/backend/utils/api";
7
7
  import { useT } from "@open-mercato/shared/lib/i18n/context";
@@ -11,16 +11,10 @@ import { FormHeader } from "@open-mercato/ui/backend/forms";
11
11
  import { Spinner } from "@open-mercato/ui/primitives/spinner";
12
12
  import { JsonDisplay } from "@open-mercato/ui/backend/JsonDisplay";
13
13
  import { RecordNotFoundState, ErrorMessage } from "@open-mercato/ui/backend/detail";
14
- function WorkflowEventDetailPage() {
14
+ function WorkflowEventDetailPage({ params }) {
15
15
  const router = useRouter();
16
- const params = useParams();
17
16
  const t = useT();
18
- let eventId;
19
- if (params?.id) {
20
- eventId = Array.isArray(params.id) ? params.id[0] : params.id;
21
- } else if (params?.slug && Array.isArray(params.slug)) {
22
- eventId = params.slug[params.slug.length - 1];
23
- }
17
+ const eventId = params?.id;
24
18
  const { data: event, isLoading, error } = useQuery({
25
19
  queryKey: ["workflows", "events", eventId],
26
20
  queryFn: async () => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/workflows/backend/events/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useParams, useRouter } from 'next/navigation'\nimport { useQuery } from '@tanstack/react-query'\nimport { apiFetch } from '@open-mercato/ui/backend/utils/api'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { JsonDisplay } from '@open-mercato/ui/backend/JsonDisplay'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\n\ntype WorkflowEvent = {\n id: string\n workflowInstanceId: string\n stepInstanceId: string | null\n eventType: string\n eventData: any\n occurredAt: string\n userId: string | null\n tenantId: string\n organizationId: string\n workflowInstance: {\n id: string\n workflowId: string\n version: number\n status: string\n currentStepId: string\n correlationKey: string | null\n startedAt: string | null\n completedAt: string | null\n context: any\n } | null\n}\n\nexport default function WorkflowEventDetailPage() {\n const router = useRouter()\n const params = useParams()\n const t = useT()\n\n // Handle both {id: '17'} and {slug: ['events', '17']} formats\n let eventId: string | undefined\n if (params?.id) {\n eventId = Array.isArray(params.id) ? params.id[0] : params.id\n } else if (params?.slug && Array.isArray(params.slug)) {\n // If slug is ['events', '17'], extract '17'\n eventId = params.slug[params.slug.length - 1]\n }\n\n const { data: event, isLoading, error } = useQuery({\n queryKey: ['workflows', 'events', eventId],\n queryFn: async () => {\n const response = await apiFetch(`/api/workflows/events/${eventId}`)\n\n if (!response.ok) {\n const httpErr = new Error(\n response.status === 404\n ? t('workflows.events.notFound', 'Event not found.')\n : t('workflows.events.messages.loadFailed')\n ) as Error & { status: number }\n httpErr.status = response.status\n throw httpErr\n }\n const result = await response.json()\n return result as WorkflowEvent\n },\n enabled: !!eventId,\n })\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('workflows.common.loading')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n const isNotFound = !isLoading && (error as (Error & { status?: number }) | null)?.status === 404\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('workflows.events.notFound', 'Event not found.')}\n backHref=\"/backend/events\"\n backLabel={t('workflows.events.backToList', 'Back to Events')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !event) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={(error as Error | null)?.message ?? t('workflows.events.messages.loadFailed')}\n action={\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href=\"/backend/events\">{t('workflows.events.backToList', 'Back to Events')}</Link>\n </Button>\n }\n />\n </PageBody>\n </Page>\n )\n }\n\n const getEventTypeBadgeClass = (eventType: string) => {\n if (eventType.includes('STARTED')) return 'bg-blue-100 text-blue-800'\n if (eventType.includes('COMPLETED')) return 'bg-green-100 text-green-800'\n if (eventType.includes('FAILED') || eventType.includes('REJECTED')) return 'bg-red-100 text-red-800'\n if (eventType.includes('CANCELLED')) return 'bg-muted text-foreground'\n if (eventType.includes('ENTERED') || eventType.includes('EXITED')) return 'bg-purple-100 text-purple-800'\n return 'bg-muted text-foreground'\n }\n\n const getStatusBadgeClass = (status: string) => {\n switch (status) {\n case 'COMPLETED':\n return 'bg-green-100 text-green-800'\n case 'RUNNING':\n return 'bg-blue-100 text-blue-800'\n case 'FAILED':\n return 'bg-red-100 text-red-800'\n case 'CANCELLED':\n return 'bg-muted text-foreground'\n default:\n return 'bg-muted text-foreground'\n }\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/events\"\n backLabel={t('workflows.events.backToList', 'Back to events')}\n entityTypeLabel={t('workflows.events.detail.type', 'Workflow event')}\n title={\n <div className=\"flex flex-wrap items-center gap-2\">\n <span>{event.eventType}</span>\n <span className=\"font-mono text-sm text-muted-foreground\">#{event.id.slice(0, 8)}</span>\n </div>\n }\n statusBadge={\n <span\n className={`inline-flex items-center px-3 py-1 rounded text-sm font-medium ${getEventTypeBadgeClass(event.eventType)}`}\n >\n {event.eventType}\n </span>\n }\n />\n\n {/* Event Summary */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {t('workflows.events.detail.summary')}\n </h2>\n <dl className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.fields.occurredAt')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground\">\n {new Date(event.occurredAt).toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.fields.eventType')}\n </dt>\n <dd className=\"mt-1\">\n <span\n className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getEventTypeBadgeClass(\n event.eventType\n )}`}\n >\n {event.eventType}\n </span>\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.fields.userId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.userId || t('common.none')}\n </dd>\n </div>\n {event.stepInstanceId && (\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.detail.stepInstanceId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.stepInstanceId}\n </dd>\n </div>\n )}\n </dl>\n </div>\n\n {/* Workflow Instance Information */}\n {event.workflowInstance && (\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {t('workflows.events.detail.workflowInstance')}\n </h2>\n <dl className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.instanceId')}\n </dt>\n <dd className=\"mt-1\">\n <Link\n href={`/backend/instances/${event.workflowInstance.id}`}\n className=\"text-sm text-primary hover:underline font-mono\"\n >\n {event.workflowInstance.id}\n </Link>\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.status')}\n </dt>\n <dd className=\"mt-1\">\n <span\n className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getStatusBadgeClass(\n event.workflowInstance.status\n )}`}\n >\n {event.workflowInstance.status}\n </span>\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.workflowId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.workflowInstance.workflowId}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.version')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground\">\n {event.workflowInstance.version}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.currentStep')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.workflowInstance.currentStepId}\n </dd>\n </div>\n {event.workflowInstance.correlationKey && (\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.correlationKey')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.workflowInstance.correlationKey}\n </dd>\n </div>\n )}\n {event.workflowInstance.startedAt && (\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.startedAt')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground\">\n {new Date(event.workflowInstance.startedAt).toLocaleString()}\n </dd>\n </div>\n )}\n {event.workflowInstance.completedAt && (\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.completedAt')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground\">\n {new Date(event.workflowInstance.completedAt).toLocaleString()}\n </dd>\n </div>\n )}\n </dl>\n </div>\n )}\n\n {/* Event Data */}\n <JsonDisplay\n data={event.eventData}\n title={t('workflows.events.detail.eventData')}\n />\n\n {/* Workflow Context (if available) */}\n {event.workflowInstance?.context && (\n <JsonDisplay\n data={event.workflowInstance.context}\n title={t('workflows.events.detail.workflowContext')}\n />\n )}\n\n {/* Technical Details */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {t('workflows.events.detail.technicalDetails')}\n </h2>\n <dl className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.detail.tenantId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.tenantId}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.detail.organizationId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.organizationId}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { useQuery } from '@tanstack/react-query'\nimport { apiFetch } from '@open-mercato/ui/backend/utils/api'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { FormHeader } from '@open-mercato/ui/backend/forms'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { JsonDisplay } from '@open-mercato/ui/backend/JsonDisplay'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\n\ntype WorkflowEvent = {\n id: string\n workflowInstanceId: string\n stepInstanceId: string | null\n eventType: string\n eventData: any\n occurredAt: string\n userId: string | null\n tenantId: string\n organizationId: string\n workflowInstance: {\n id: string\n workflowId: string\n version: number\n status: string\n currentStepId: string\n correlationKey: string | null\n startedAt: string | null\n completedAt: string | null\n context: any\n } | null\n}\n\nexport default function WorkflowEventDetailPage({ params }: { params?: { id?: string } }) {\n const router = useRouter()\n const t = useT()\n const eventId = params?.id\n\n const { data: event, isLoading, error } = useQuery({\n queryKey: ['workflows', 'events', eventId],\n queryFn: async () => {\n const response = await apiFetch(`/api/workflows/events/${eventId}`)\n\n if (!response.ok) {\n const httpErr = new Error(\n response.status === 404\n ? t('workflows.events.notFound', 'Event not found.')\n : t('workflows.events.messages.loadFailed')\n ) as Error & { status: number }\n httpErr.status = response.status\n throw httpErr\n }\n const result = await response.json()\n return result as WorkflowEvent\n },\n enabled: !!eventId,\n })\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex h-[50vh] flex-col items-center justify-center gap-2 text-muted-foreground\">\n <Spinner className=\"h-6 w-6\" />\n <span>{t('workflows.common.loading')}</span>\n </div>\n </PageBody>\n </Page>\n )\n }\n\n const isNotFound = !isLoading && (error as (Error & { status?: number }) | null)?.status === 404\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('workflows.events.notFound', 'Event not found.')}\n backHref=\"/backend/events\"\n backLabel={t('workflows.events.backToList', 'Back to Events')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !event) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={(error as Error | null)?.message ?? t('workflows.events.messages.loadFailed')}\n action={\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href=\"/backend/events\">{t('workflows.events.backToList', 'Back to Events')}</Link>\n </Button>\n }\n />\n </PageBody>\n </Page>\n )\n }\n\n const getEventTypeBadgeClass = (eventType: string) => {\n if (eventType.includes('STARTED')) return 'bg-blue-100 text-blue-800'\n if (eventType.includes('COMPLETED')) return 'bg-green-100 text-green-800'\n if (eventType.includes('FAILED') || eventType.includes('REJECTED')) return 'bg-red-100 text-red-800'\n if (eventType.includes('CANCELLED')) return 'bg-muted text-foreground'\n if (eventType.includes('ENTERED') || eventType.includes('EXITED')) return 'bg-purple-100 text-purple-800'\n return 'bg-muted text-foreground'\n }\n\n const getStatusBadgeClass = (status: string) => {\n switch (status) {\n case 'COMPLETED':\n return 'bg-green-100 text-green-800'\n case 'RUNNING':\n return 'bg-blue-100 text-blue-800'\n case 'FAILED':\n return 'bg-red-100 text-red-800'\n case 'CANCELLED':\n return 'bg-muted text-foreground'\n default:\n return 'bg-muted text-foreground'\n }\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref=\"/backend/events\"\n backLabel={t('workflows.events.backToList', 'Back to events')}\n entityTypeLabel={t('workflows.events.detail.type', 'Workflow event')}\n title={\n <div className=\"flex flex-wrap items-center gap-2\">\n <span>{event.eventType}</span>\n <span className=\"font-mono text-sm text-muted-foreground\">#{event.id.slice(0, 8)}</span>\n </div>\n }\n statusBadge={\n <span\n className={`inline-flex items-center px-3 py-1 rounded text-sm font-medium ${getEventTypeBadgeClass(event.eventType)}`}\n >\n {event.eventType}\n </span>\n }\n />\n\n {/* Event Summary */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {t('workflows.events.detail.summary')}\n </h2>\n <dl className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.fields.occurredAt')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground\">\n {new Date(event.occurredAt).toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.fields.eventType')}\n </dt>\n <dd className=\"mt-1\">\n <span\n className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getEventTypeBadgeClass(\n event.eventType\n )}`}\n >\n {event.eventType}\n </span>\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.fields.userId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.userId || t('common.none')}\n </dd>\n </div>\n {event.stepInstanceId && (\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.detail.stepInstanceId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.stepInstanceId}\n </dd>\n </div>\n )}\n </dl>\n </div>\n\n {/* Workflow Instance Information */}\n {event.workflowInstance && (\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {t('workflows.events.detail.workflowInstance')}\n </h2>\n <dl className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.instanceId')}\n </dt>\n <dd className=\"mt-1\">\n <Link\n href={`/backend/instances/${event.workflowInstance.id}`}\n className=\"text-sm text-primary hover:underline font-mono\"\n >\n {event.workflowInstance.id}\n </Link>\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.status')}\n </dt>\n <dd className=\"mt-1\">\n <span\n className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium ${getStatusBadgeClass(\n event.workflowInstance.status\n )}`}\n >\n {event.workflowInstance.status}\n </span>\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.workflowId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.workflowInstance.workflowId}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.version')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground\">\n {event.workflowInstance.version}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.currentStep')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.workflowInstance.currentStepId}\n </dd>\n </div>\n {event.workflowInstance.correlationKey && (\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.correlationKey')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.workflowInstance.correlationKey}\n </dd>\n </div>\n )}\n {event.workflowInstance.startedAt && (\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.startedAt')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground\">\n {new Date(event.workflowInstance.startedAt).toLocaleString()}\n </dd>\n </div>\n )}\n {event.workflowInstance.completedAt && (\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.instances.fields.completedAt')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground\">\n {new Date(event.workflowInstance.completedAt).toLocaleString()}\n </dd>\n </div>\n )}\n </dl>\n </div>\n )}\n\n {/* Event Data */}\n <JsonDisplay\n data={event.eventData}\n title={t('workflows.events.detail.eventData')}\n />\n\n {/* Workflow Context (if available) */}\n {event.workflowInstance?.context && (\n <JsonDisplay\n data={event.workflowInstance.context}\n title={t('workflows.events.detail.workflowContext')}\n />\n )}\n\n {/* Technical Details */}\n <div className=\"rounded-lg border bg-card p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {t('workflows.events.detail.technicalDetails')}\n </h2>\n <dl className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.detail.tenantId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.tenantId}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm font-medium text-muted-foreground\">\n {t('workflows.events.detail.organizationId')}\n </dt>\n <dd className=\"mt-1 text-sm text-foreground font-mono\">\n {event.organizationId}\n </dd>\n </div>\n </dl>\n </div>\n </div>\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.7.1-develop.7106.1.53fe9dd1b1",
3
+ "version": "0.7.1-develop.7112.1.d486e6f1b2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -252,16 +252,16 @@
252
252
  "zod": "^4.4.3"
253
253
  },
254
254
  "peerDependencies": {
255
- "@open-mercato/ai-assistant": "0.7.1-develop.7106.1.53fe9dd1b1",
256
- "@open-mercato/shared": "0.7.1-develop.7106.1.53fe9dd1b1",
257
- "@open-mercato/ui": "0.7.1-develop.7106.1.53fe9dd1b1",
255
+ "@open-mercato/ai-assistant": "0.7.1-develop.7112.1.d486e6f1b2",
256
+ "@open-mercato/shared": "0.7.1-develop.7112.1.d486e6f1b2",
257
+ "@open-mercato/ui": "0.7.1-develop.7112.1.d486e6f1b2",
258
258
  "react": "^19.0.0",
259
259
  "react-dom": "^19.0.0"
260
260
  },
261
261
  "devDependencies": {
262
- "@open-mercato/ai-assistant": "0.7.1-develop.7106.1.53fe9dd1b1",
263
- "@open-mercato/shared": "0.7.1-develop.7106.1.53fe9dd1b1",
264
- "@open-mercato/ui": "0.7.1-develop.7106.1.53fe9dd1b1",
262
+ "@open-mercato/ai-assistant": "0.7.1-develop.7112.1.d486e6f1b2",
263
+ "@open-mercato/shared": "0.7.1-develop.7112.1.d486e6f1b2",
264
+ "@open-mercato/ui": "0.7.1-develop.7112.1.d486e6f1b2",
265
265
  "@testing-library/dom": "^10.4.1",
266
266
  "@testing-library/jest-dom": "^7.0.0",
267
267
  "@testing-library/react": "^16.3.1",
@@ -139,7 +139,7 @@ export async function POST(req: Request) {
139
139
 
140
140
  let base: string
141
141
  try {
142
- base = getSecurityEmailBaseUrl(req.url)
142
+ base = getSecurityEmailBaseUrl(req)
143
143
  } catch (error) {
144
144
  const mapped = mapSecurityEmailUrlError(error, {
145
145
  scope: 'auth.users.resend-invite',
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import Link from 'next/link'
5
- import { useParams, useRouter } from 'next/navigation'
5
+ import { useRouter } from 'next/navigation'
6
6
  import { useQuery } from '@tanstack/react-query'
7
7
  import { apiFetch } from '@open-mercato/ui/backend/utils/api'
8
8
  import { useT } from '@open-mercato/shared/lib/i18n/context'
@@ -36,17 +36,9 @@ type RuleExecutionLog = {
36
36
  organizationId: string | null
37
37
  }
38
38
 
39
- export default function ExecutionLogDetailPage() {
39
+ export default function ExecutionLogDetailPage({ params }: { params?: { id?: string } }) {
40
40
  const router = useRouter()
41
- const params = useParams()
42
-
43
- // Handle catch-all route: params.slug = ['logs', 'id']
44
- let logId: string | undefined
45
- if (params?.slug && Array.isArray(params.slug)) {
46
- logId = params.slug[1] // Second element is the ID
47
- } else if (params?.id) {
48
- logId = Array.isArray(params.id) ? params.id[0] : params.id
49
- }
41
+ const logId = params?.id
50
42
 
51
43
  const t = useT()
52
44
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import Link from 'next/link'
5
- import { useRouter, useParams, usePathname } from 'next/navigation'
5
+ import { useRouter, usePathname } from 'next/navigation'
6
6
  import { useQuery } from '@tanstack/react-query'
7
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
8
8
  import { CrudForm } from '@open-mercato/ui/backend/CrudForm'
@@ -25,18 +25,10 @@ import { ConditionBuilder } from '../../../components/ConditionBuilder'
25
25
  import { ActionBuilder } from '../../../components/ActionBuilder'
26
26
  import { buildRulePayload, parseRuleToFormValues } from '../../../components/utils/formHelpers'
27
27
 
28
- export default function EditBusinessRulePage() {
28
+ export default function EditBusinessRulePage({ params }: { params?: { id?: string } }) {
29
29
  const router = useRouter()
30
- const params = useParams()
31
30
  const pathname = usePathname()
32
-
33
- // Handle catch-all route: params.slug = ['rules', 'uuid']
34
- let ruleId: string | undefined
35
- if (params?.slug && Array.isArray(params.slug)) {
36
- ruleId = params.slug[1] // Second element is the ID
37
- } else if (params?.id) {
38
- ruleId = Array.isArray(params.id) ? params.id[0] : params.id
39
- }
31
+ const ruleId = params?.id
40
32
 
41
33
  const t = useT()
42
34
  const { organizationId, tenantId } = useOrganizationScopeDetail()
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import Link from 'next/link'
5
- import { useRouter, useParams, usePathname } from 'next/navigation'
5
+ import { useRouter, usePathname } from 'next/navigation'
6
6
  import { useQuery, useQueryClient } from '@tanstack/react-query'
7
7
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
8
8
  import { CrudForm } from '@open-mercato/ui/backend/CrudForm'
@@ -53,18 +53,10 @@ type RuleSetDetail = {
53
53
  }>
54
54
  }
55
55
 
56
- export default function EditRuleSetPage() {
56
+ export default function EditRuleSetPage({ params }: { params?: { id?: string } }) {
57
57
  const router = useRouter()
58
- const params = useParams()
59
58
  const pathname = usePathname()
60
-
61
- // Handle catch-all route: params.slug = ['sets', 'uuid']
62
- let setId: string | undefined
63
- if (params?.slug && Array.isArray(params.slug)) {
64
- setId = params.slug[1] // Second element is the ID
65
- } else if (params?.id) {
66
- setId = Array.isArray(params.id) ? params.id[0] : params.id
67
- }
59
+ const setId = params?.id
68
60
 
69
61
  const t = useT()
70
62
  const { organizationId, tenantId } = useOrganizationScopeDetail()
@@ -1,7 +1,6 @@
1
1
  'use client'
2
2
 
3
3
  import * as React from 'react'
4
- import { useParams } from 'next/navigation'
5
4
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
6
5
  import { LoadingMessage, ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'
7
6
  import { Tag } from '@open-mercato/ui/primitives/tag'
@@ -35,10 +34,9 @@ type ChannelHealth = {
35
34
  }>
36
35
  }
37
36
 
38
- export default function ChannelDetailPage() {
37
+ export default function ChannelDetailPage({ params }: { params?: { id?: string } }) {
39
38
  const t = useT()
40
- const params = useParams<{ id: string }>()
41
- const id = (params?.id as string) ?? ''
39
+ const id = params?.id ?? ''
42
40
 
43
41
  const [detail, setDetail] = React.useState<ChannelDetail | null>(null)
44
42
  const [health, setHealth] = React.useState<ChannelHealth | null>(null)
@@ -47,7 +45,11 @@ export default function ChannelDetailPage() {
47
45
  const [notFound, setNotFound] = React.useState(false)
48
46
 
49
47
  React.useEffect(() => {
50
- if (!id) return
48
+ if (!id) {
49
+ setIsLoading(false)
50
+ setErrorMessage(t('communication_channels.errors.missingChannelId', 'No channel selected.'))
51
+ return
52
+ }
51
53
  let cancelled = false
52
54
  async function load() {
53
55
  setIsLoading(true)
@@ -23,6 +23,7 @@
23
23
  "communication_channels.emptyState": "Noch keine gemeinsamen Kanäle. Diese Seite listet gemeinsame, mandantenweite Kanäle auf. Ihr persönliches E-Mail-Postfach ist privat – verbinden und verwalten Sie es unter Profil → Kommunikationskanäle.",
24
24
  "communication_channels.errors.loadDetail": "Kanal konnte nicht geladen werden",
25
25
  "communication_channels.errors.loadList": "Kanäle konnten nicht geladen werden",
26
+ "communication_channels.errors.missingChannelId": "Kein Kanal ausgewählt.",
26
27
  "communication_channels.errors.pollNowPushDriven": "Der Kanal ist Push-gesteuert — Abrufen ist nicht anwendbar. Eingehende Nachrichten kommen über die Push-Verbindung des Anbieters.",
27
28
  "communication_channels.errors.reactionFailed": "Reaktion fehlgeschlagen",
28
29
  "communication_channels.errors.undoBlockedPrimaryConflict": "Ein anderer Kanal ist jetzt für diesen Benutzer als primär festgelegt. Setze ihn auf nicht-primär, bevor du den getrennten Kanal wieder als primär festlegst.",
@@ -23,6 +23,7 @@
23
23
  "communication_channels.emptyState": "No shared channels yet. This page lists shared, tenant-wide channels. Your personal email mailbox is private — connect and manage it under Profile → Communication Channels.",
24
24
  "communication_channels.errors.loadDetail": "Failed to load channel",
25
25
  "communication_channels.errors.loadList": "Failed to load channels",
26
+ "communication_channels.errors.missingChannelId": "No channel selected.",
26
27
  "communication_channels.errors.pollNowPushDriven": "Channel is push-driven — polling does not apply. Inbound messages arrive through the provider push connection.",
27
28
  "communication_channels.errors.reactionFailed": "Reaction failed",
28
29
  "communication_channels.errors.undoBlockedPrimaryConflict": "Another channel is now primary for this user. Set it as non-primary before restoring the disconnected channel as primary.",
@@ -23,6 +23,7 @@
23
23
  "communication_channels.emptyState": "Aún no hay canales compartidos. Esta página muestra los canales compartidos de toda la organización. Tu buzón de correo personal es privado: conéctalo y gestiónalo en Perfil → Canales de comunicación.",
24
24
  "communication_channels.errors.loadDetail": "No se pudo cargar el canal",
25
25
  "communication_channels.errors.loadList": "No se pudieron cargar los canales",
26
+ "communication_channels.errors.missingChannelId": "Ningún canal seleccionado.",
26
27
  "communication_channels.errors.pollNowPushDriven": "El canal funciona con push — el sondeo no aplica. Los mensajes entrantes llegan por la conexión push del proveedor.",
27
28
  "communication_channels.errors.reactionFailed": "La reacción falló",
28
29
  "communication_channels.errors.undoBlockedPrimaryConflict": "Otro canal es ahora el principal para este usuario. Configúralo como no principal antes de restaurar el canal desconectado como principal.",
@@ -23,6 +23,7 @@
23
23
  "communication_channels.emptyState": "아직 공유 채널이 없습니다. 이 페이지에는 공유되는 테넌트 전체 채널이 나열됩니다. 개인 이메일 메일함은 비공개이며, 프로필 → 통신 채널에서 연결하고 관리하세요.",
24
24
  "communication_channels.errors.loadDetail": "채널을 불러오지 못했습니다",
25
25
  "communication_channels.errors.loadList": "채널을 불러오지 못했습니다",
26
+ "communication_channels.errors.missingChannelId": "선택된 채널이 없습니다.",
26
27
  "communication_channels.errors.pollNowPushDriven": "이 채널은 푸시 기반입니다 — 폴링은 적용되지 않습니다. 수신 메시지는 공급자의 푸시 연결로 전달됩니다.",
27
28
  "communication_channels.errors.reactionFailed": "반응 처리에 실패했습니다",
28
29
  "communication_channels.errors.undoBlockedPrimaryConflict": "다른 채널이 현재 이 사용자의 기본 채널로 설정되어 있습니다. 연결이 끊어진 채널을 기본으로 복원하기 전에 해당 채널을 기본이 아닌 채널로 설정하세요.",
@@ -23,6 +23,7 @@
23
23
  "communication_channels.emptyState": "Brak kanałów współdzielonych. Ta strona pokazuje współdzielone kanały obejmujące całą organizację. Twoja osobista skrzynka e-mail jest prywatna — połącz ją i zarządzaj nią w Profil → Kanały komunikacji.",
24
24
  "communication_channels.errors.loadDetail": "Nie udało się załadować kanału",
25
25
  "communication_channels.errors.loadList": "Nie udało się załadować kanałów",
26
+ "communication_channels.errors.missingChannelId": "Nie wybrano kanału.",
26
27
  "communication_channels.errors.pollNowPushDriven": "Kanał działa w trybie push — odpytywanie go nie dotyczy. Wiadomości przychodzące docierają połączeniem push dostawcy.",
27
28
  "communication_channels.errors.reactionFailed": "Reakcja nie powiodła się",
28
29
  "communication_channels.errors.undoBlockedPrimaryConflict": "Inny kanał jest teraz głównym dla tego użytkownika. Ustaw go jako niegłówny, zanim przywrócisz rozłączony kanał jako główny.",
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import * as React from 'react'
4
- import { useRouter, useParams, usePathname } from 'next/navigation'
4
+ import { useRouter, usePathname } from 'next/navigation'
5
5
  import { Page, PageBody } from '@open-mercato/ui/backend/Page'
6
6
  import { CrudForm, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'
7
7
  import { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
@@ -10,6 +10,7 @@ import { Button } from '@open-mercato/ui/primitives/button'
10
10
  import { Kbd } from '@open-mercato/ui/primitives/kbd'
11
11
  import { ActivityTimelineFilters } from './ActivityTimelineFilters'
12
12
  import { ActivityTimeline } from './ActivityTimeline'
13
+ import { resolveAuthorUserNames } from './authorUserLookup'
13
14
  import type { ActivitySummary, InteractionSummary } from './types'
14
15
  import { createLogger } from '@open-mercato/shared/lib/logger'
15
16
 
@@ -314,25 +315,14 @@ export function ActivitiesSection({
314
315
  }
315
316
  if (unresolvedIds.size === 0) return
316
317
 
317
- for (const uid of unresolvedIds) resolvedUserIdsRef.current.add(uid)
318
-
319
318
  const controller = new AbortController()
320
- readApiResultOrThrow<{ items?: Array<Record<string, unknown>> }>(
321
- `/api/auth/users?ids=${[...unresolvedIds].join(',')}`,
322
- { signal: controller.signal },
323
- )
324
- .then((data) => {
325
- const users = Array.isArray(data?.items) ? data.items : []
326
- const nameMap = new Map<string, string>()
327
- for (const user of users) {
328
- const userId = typeof user.id === 'string' ? user.id : null
329
- const name = typeof user.display_name === 'string' && user.display_name.trim()
330
- ? user.display_name.trim()
331
- : typeof user.email === 'string'
332
- ? user.email
333
- : null
334
- if (userId && name) nameMap.set(userId, name)
335
- }
319
+ resolveAuthorUserNames([...unresolvedIds], controller.signal)
320
+ .then(({ names: nameMap, resolvedIds }) => {
321
+ if (controller.signal.aborted) return
322
+ // Only ids the server actually answered for are remembered. Marking an id whose request
323
+ // failed — or one the server silently dropped past its `?ids=` cap — would leave that
324
+ // author blank for the life of the component, even though the next attempt would work.
325
+ for (const uid of resolvedIds) resolvedUserIdsRef.current.add(uid)
336
326
  if (nameMap.size > 0) {
337
327
  setActivities((prev) =>
338
328
  prev.map((a) => {