@open-mercato/core 0.10.1-develop.7736.1.88e07906bf → 0.10.1-develop.7748.1.d745ba61aa

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 (198) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/api_key/index.js +2 -0
  3. package/dist/generated/entities/api_key/index.js.map +2 -2
  4. package/dist/generated/entities/attachment_partition/index.js +2 -0
  5. package/dist/generated/entities/attachment_partition/index.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +2 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/helpers/integration/attachmentAccessFixtures.js +144 -0
  9. package/dist/helpers/integration/attachmentAccessFixtures.js.map +7 -0
  10. package/dist/modules/api_keys/data/entities.js +7 -0
  11. package/dist/modules/api_keys/data/entities.js.map +2 -2
  12. package/dist/modules/api_keys/migrations/Migration20261012202110_api_keys.js +30 -0
  13. package/dist/modules/api_keys/migrations/Migration20261012202110_api_keys.js.map +7 -0
  14. package/dist/modules/api_keys/services/apiKeyService.js +31 -9
  15. package/dist/modules/api_keys/services/apiKeyService.js.map +2 -2
  16. package/dist/modules/attachments/api/file/[id]/route.js +16 -10
  17. package/dist/modules/attachments/api/file/[id]/route.js.map +2 -2
  18. package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +15 -9
  19. package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
  20. package/dist/modules/attachments/api/library/[id]/route.js +100 -56
  21. package/dist/modules/attachments/api/library/[id]/route.js.map +3 -3
  22. package/dist/modules/attachments/api/library/route.js +56 -17
  23. package/dist/modules/attachments/api/library/route.js.map +2 -2
  24. package/dist/modules/attachments/api/partitions/route.js +2 -0
  25. package/dist/modules/attachments/api/partitions/route.js.map +2 -2
  26. package/dist/modules/attachments/api/route.js +74 -34
  27. package/dist/modules/attachments/api/route.js.map +3 -3
  28. package/dist/modules/attachments/api/transfer/route.js +63 -37
  29. package/dist/modules/attachments/api/transfer/route.js.map +2 -2
  30. package/dist/modules/attachments/data/entities.js +3 -0
  31. package/dist/modules/attachments/data/entities.js.map +2 -2
  32. package/dist/modules/attachments/data/validators.js +41 -0
  33. package/dist/modules/attachments/data/validators.js.map +7 -0
  34. package/dist/modules/attachments/di.js +5 -2
  35. package/dist/modules/attachments/di.js.map +2 -2
  36. package/dist/modules/attachments/generators.js +29 -0
  37. package/dist/modules/attachments/generators.js.map +7 -0
  38. package/dist/modules/attachments/index.js +8 -1
  39. package/dist/modules/attachments/index.js.map +2 -2
  40. package/dist/modules/attachments/lib/access-errors.js +35 -0
  41. package/dist/modules/attachments/lib/access-errors.js.map +7 -0
  42. package/dist/modules/attachments/lib/access-mutation.js +23 -0
  43. package/dist/modules/attachments/lib/access-mutation.js.map +7 -0
  44. package/dist/modules/attachments/lib/access-protection.js +73 -0
  45. package/dist/modules/attachments/lib/access-protection.js.map +7 -0
  46. package/dist/modules/attachments/lib/access-query.js +74 -0
  47. package/dist/modules/attachments/lib/access-query.js.map +7 -0
  48. package/dist/modules/attachments/lib/access-registry.js +87 -0
  49. package/dist/modules/attachments/lib/access-registry.js.map +7 -0
  50. package/dist/modules/attachments/lib/access-runner.js +161 -0
  51. package/dist/modules/attachments/lib/access-runner.js.map +7 -0
  52. package/dist/modules/attachments/lib/access-types.js +1 -0
  53. package/dist/modules/attachments/lib/access-types.js.map +7 -0
  54. package/dist/modules/attachments/lib/attachment-service.js +14 -6
  55. package/dist/modules/attachments/lib/attachment-service.js.map +2 -2
  56. package/dist/modules/attachments/lib/createFromBuffer.js +2 -0
  57. package/dist/modules/attachments/lib/createFromBuffer.js.map +2 -2
  58. package/dist/modules/attachments/lib/partitions.js +3 -2
  59. package/dist/modules/attachments/lib/partitions.js.map +2 -2
  60. package/dist/modules/attachments/lib/scoped-upload-service.js +2 -0
  61. package/dist/modules/attachments/lib/scoped-upload-service.js.map +2 -2
  62. package/dist/modules/attachments/lib/target-access-service.js +12 -3
  63. package/dist/modules/attachments/lib/target-access-service.js.map +2 -2
  64. package/dist/modules/attachments/migrations/Migration20261001120000_attachments.js +38 -0
  65. package/dist/modules/attachments/migrations/Migration20261001120000_attachments.js.map +7 -0
  66. package/dist/modules/attachments/setup.js +10 -0
  67. package/dist/modules/attachments/setup.js.map +2 -2
  68. package/dist/modules/notifications/api/[id]/action/route.js +8 -0
  69. package/dist/modules/notifications/api/[id]/action/route.js.map +2 -2
  70. package/dist/modules/notifications/api/route.js +17 -0
  71. package/dist/modules/notifications/api/route.js.map +2 -2
  72. package/dist/modules/notifications/data/validators.js +1 -1
  73. package/dist/modules/notifications/data/validators.js.map +2 -2
  74. package/dist/modules/notifications/lib/notificationService.js +45 -3
  75. package/dist/modules/notifications/lib/notificationService.js.map +2 -2
  76. package/dist/modules/notifications/lib/routeHelpers.js +27 -0
  77. package/dist/modules/notifications/lib/routeHelpers.js.map +2 -2
  78. package/dist/modules/payment_gateways/lib/gateway-service.js +50 -34
  79. package/dist/modules/payment_gateways/lib/gateway-service.js.map +2 -2
  80. package/dist/modules/payment_gateways/lib/status-machine.js +10 -1
  81. package/dist/modules/payment_gateways/lib/status-machine.js.map +2 -2
  82. package/dist/modules/payment_gateways/lib/webhook-processor.js +1 -1
  83. package/dist/modules/payment_gateways/lib/webhook-processor.js.map +2 -2
  84. package/dist/modules/staff/notifications.js +4 -2
  85. package/dist/modules/staff/notifications.js.map +2 -2
  86. package/dist/modules/workflows/api/portal/tasks/[id]/complete/route.js +1 -1
  87. package/dist/modules/workflows/api/portal/tasks/[id]/complete/route.js.map +2 -2
  88. package/dist/modules/workflows/api/tasks/[id]/complete/route.js +7 -1
  89. package/dist/modules/workflows/api/tasks/[id]/complete/route.js.map +2 -2
  90. package/dist/modules/workflows/backend/tasks/[id]/page.js +2 -1
  91. package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
  92. package/dist/modules/workflows/data/entities.js.map +2 -2
  93. package/dist/modules/workflows/lib/activity-executor.js +18 -4
  94. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  95. package/dist/modules/workflows/lib/activity-types.js +2 -2
  96. package/dist/modules/workflows/lib/activity-types.js.map +2 -2
  97. package/dist/modules/workflows/lib/condition-handler.js +7 -1
  98. package/dist/modules/workflows/lib/condition-handler.js.map +2 -2
  99. package/dist/modules/workflows/lib/duration.js +13 -0
  100. package/dist/modules/workflows/lib/duration.js.map +2 -2
  101. package/dist/modules/workflows/lib/instance-status.js +16 -0
  102. package/dist/modules/workflows/lib/instance-status.js.map +7 -0
  103. package/dist/modules/workflows/lib/step-handler.js +9 -2
  104. package/dist/modules/workflows/lib/step-handler.js.map +2 -2
  105. package/dist/modules/workflows/lib/task-handler.js +16 -8
  106. package/dist/modules/workflows/lib/task-handler.js.map +2 -2
  107. package/dist/modules/workflows/lib/task-quick-action.js +13 -10
  108. package/dist/modules/workflows/lib/task-quick-action.js.map +2 -2
  109. package/dist/modules/workflows/lib/task-sla.js +10 -0
  110. package/dist/modules/workflows/lib/task-sla.js.map +2 -2
  111. package/dist/modules/workflows/lib/transition-handler.js +2 -1
  112. package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
  113. package/dist/modules/workflows/lib/workflow-executor.js +29 -1
  114. package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
  115. package/dist/modules/workflows/notifications.js +4 -0
  116. package/dist/modules/workflows/notifications.js.map +2 -2
  117. package/generated/entities/api_key/index.ts +1 -0
  118. package/generated/entities/attachment_partition/index.ts +1 -0
  119. package/generated/entity-fields-registry.ts +2 -0
  120. package/package.json +7 -7
  121. package/src/helpers/integration/attachmentAccessFixtures.ts +141 -0
  122. package/src/modules/api_keys/data/entities.ts +25 -1
  123. package/src/modules/api_keys/migrations/.snapshot-open-mercato.json +234 -68
  124. package/src/modules/api_keys/migrations/Migration20261012202110_api_keys.ts +47 -0
  125. package/src/modules/api_keys/services/apiKeyService.ts +55 -9
  126. package/src/modules/attachments/api/file/[id]/route.ts +12 -9
  127. package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +10 -8
  128. package/src/modules/attachments/api/library/[id]/route.ts +87 -58
  129. package/src/modules/attachments/api/library/route.ts +40 -11
  130. package/src/modules/attachments/api/partitions/route.ts +2 -0
  131. package/src/modules/attachments/api/route.ts +68 -35
  132. package/src/modules/attachments/api/transfer/route.ts +65 -42
  133. package/src/modules/attachments/data/entities.ts +4 -0
  134. package/src/modules/attachments/data/validators.ts +36 -0
  135. package/src/modules/attachments/di.ts +4 -1
  136. package/src/modules/attachments/generators.ts +27 -0
  137. package/src/modules/attachments/i18n/de.json +4 -0
  138. package/src/modules/attachments/i18n/en.json +4 -0
  139. package/src/modules/attachments/i18n/es.json +4 -0
  140. package/src/modules/attachments/i18n/ko.json +4 -0
  141. package/src/modules/attachments/i18n/pl.json +4 -0
  142. package/src/modules/attachments/index.ts +18 -0
  143. package/src/modules/attachments/lib/access-errors.ts +32 -0
  144. package/src/modules/attachments/lib/access-mutation.ts +26 -0
  145. package/src/modules/attachments/lib/access-protection.ts +83 -0
  146. package/src/modules/attachments/lib/access-query.ts +86 -0
  147. package/src/modules/attachments/lib/access-registry.ts +117 -0
  148. package/src/modules/attachments/lib/access-runner.ts +183 -0
  149. package/src/modules/attachments/lib/access-types.ts +78 -0
  150. package/src/modules/attachments/lib/attachment-service.ts +8 -4
  151. package/src/modules/attachments/lib/createFromBuffer.ts +3 -0
  152. package/src/modules/attachments/lib/partitions.ts +3 -2
  153. package/src/modules/attachments/lib/scoped-upload-service.ts +2 -0
  154. package/src/modules/attachments/lib/target-access-service.ts +10 -3
  155. package/src/modules/attachments/migrations/.snapshot-open-mercato.json +17 -0
  156. package/src/modules/attachments/migrations/Migration20261001120000_attachments.ts +35 -0
  157. package/src/modules/attachments/setup.ts +10 -0
  158. package/src/modules/auth/i18n/de.json +3 -0
  159. package/src/modules/auth/i18n/en.json +3 -0
  160. package/src/modules/auth/i18n/es.json +3 -0
  161. package/src/modules/auth/i18n/ko.json +3 -0
  162. package/src/modules/auth/i18n/pl.json +3 -0
  163. package/src/modules/notifications/api/[id]/action/route.ts +8 -0
  164. package/src/modules/notifications/api/route.ts +17 -0
  165. package/src/modules/notifications/data/validators.ts +1 -1
  166. package/src/modules/notifications/i18n/de.json +2 -0
  167. package/src/modules/notifications/i18n/en.json +2 -0
  168. package/src/modules/notifications/i18n/es.json +2 -0
  169. package/src/modules/notifications/i18n/ko.json +2 -0
  170. package/src/modules/notifications/i18n/pl.json +2 -0
  171. package/src/modules/notifications/lib/notificationService.ts +67 -1
  172. package/src/modules/notifications/lib/routeHelpers.ts +38 -0
  173. package/src/modules/payment_gateways/lib/gateway-service.ts +50 -33
  174. package/src/modules/payment_gateways/lib/status-machine.ts +19 -0
  175. package/src/modules/payment_gateways/lib/webhook-processor.ts +1 -1
  176. package/src/modules/staff/notifications.ts +2 -0
  177. package/src/modules/workflows/AGENTS.md +2 -2
  178. package/src/modules/workflows/api/portal/tasks/[id]/complete/route.ts +5 -1
  179. package/src/modules/workflows/api/tasks/[id]/complete/route.ts +7 -1
  180. package/src/modules/workflows/backend/tasks/[id]/page.tsx +6 -2
  181. package/src/modules/workflows/data/entities.ts +6 -0
  182. package/src/modules/workflows/i18n/de.json +2 -0
  183. package/src/modules/workflows/i18n/en.json +2 -0
  184. package/src/modules/workflows/i18n/es.json +2 -0
  185. package/src/modules/workflows/i18n/ko.json +2 -0
  186. package/src/modules/workflows/i18n/pl.json +2 -0
  187. package/src/modules/workflows/lib/activity-executor.ts +36 -4
  188. package/src/modules/workflows/lib/activity-types.ts +2 -2
  189. package/src/modules/workflows/lib/condition-handler.ts +16 -1
  190. package/src/modules/workflows/lib/duration.ts +25 -0
  191. package/src/modules/workflows/lib/instance-status.ts +29 -0
  192. package/src/modules/workflows/lib/step-handler.ts +16 -1
  193. package/src/modules/workflows/lib/task-handler.ts +18 -10
  194. package/src/modules/workflows/lib/task-quick-action.ts +19 -10
  195. package/src/modules/workflows/lib/task-sla.ts +13 -0
  196. package/src/modules/workflows/lib/transition-handler.ts +2 -1
  197. package/src/modules/workflows/lib/workflow-executor.ts +44 -1
  198. package/src/modules/workflows/notifications.ts +4 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/workflows/api/tasks/%5Bid%5D/complete/route.ts"],
4
- "sourcesContent": ["/**\n * User Task Completion API\n *\n * Endpoints:\n * - POST /api/workflows/tasks/[id]/complete - Complete a user task with form data\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveSingleOrganizationIdOrDeny } from '@open-mercato/core/modules/directory/utils/organizationScopeFilter'\nimport type { TaskHandlerService } from '../../../../lib/task-handler'\nimport { gateTaskAction } from '../../../../lib/task-visibility-request'\nimport {\n workflowsTag,\n completeTaskRequestSchema as openApiCompleteTaskSchema,\n userTaskCompleteResponseSchema,\n workflowErrorSchema,\n} from '../../../openapi'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\n\nconst logger = createLogger('workflows')\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['workflows.tasks.complete'],\n}\n\n// Request body schema\nconst completeTaskSchema = z.object({\n formData: z.record(z.string(), z.any()),\n comments: z.string().optional(),\n /**\n * The decision button the assignee pressed. Optional and additive: a task\n * without decisions completes through the plain form exactly as before.\n */\n decisionId: z.string().min(1).optional(),\n})\n\n/**\n * POST /api/workflows/tasks/[id]/complete\n *\n * Complete a user task with form data\n *\n * Request body:\n * {\n * formData: { [key: string]: any }, // Form field values\n * comments: string (optional) // Optional comments\n * }\n *\n * This endpoint:\n * 1. Validates the task can be completed\n * 2. Validates form data against the task's form schema\n * 3. Updates the task with completion data\n * 4. Merges form data into workflow context\n * 5. Resumes workflow execution\n */\nexport async function POST(\n request: NextRequest,\n { params }: { params: { id: string } }\n) {\n try {\n const container = await createRequestContainer()\n const em = container.resolve('em')\n const auth = await getAuthFromRequest(request)\n\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n const tenantId = auth.tenantId\n const organizationId = resolveSingleOrganizationIdOrDeny(scope, auth)\n\n if (!tenantId || !organizationId) {\n return NextResponse.json(\n { error: 'Missing tenant or organization context' },\n { status: 400 }\n )\n }\n\n // Parse request body\n const body = await request.json()\n const parseResult = completeTaskSchema.safeParse(body)\n\n if (!parseResult.success) {\n return NextResponse.json(\n {\n error: 'Invalid request body',\n details: parseResult.error.format(),\n },\n { status: 400 }\n )\n }\n\n const { formData, comments, decisionId } = parseResult.data\n\n // \u00A76.4 replaces the bare tenant/organization check that used to stand here.\n // The narrowing D-1 keeps `workflows.tasks.complete` on the route and still\n // demands: holding it no longer completes anyone ELSE's task. Refusals are\n // indistinguishable from a nonexistent id unless the caller already sees the\n // row.\n const gate = await gateTaskAction({\n container,\n em,\n auth: { userId: auth.sub, tenantId, roleNames: auth.roles ?? [] },\n taskId: params.id,\n organizationId,\n // Complete is the one act where the gate, not the handler, decides\n // ownership: the handler leaves an OWNERLESS row open to anyone holding\n // the feature, which is exactly the pre-change semantics \u00A76.4 narrows.\n requireOwnership: true,\n })\n\n if (!gate.allowed) {\n return NextResponse.json(gate.refusal.body, { status: gate.refusal.status })\n }\n\n const { UserTask } = await import('../../../../data/entities')\n\n // Call task handler to complete task and resume workflow\n const taskHandler = container.resolve<TaskHandlerService>('taskHandler')\n await taskHandler.completeUserTask(em, container, {\n taskId: params.id,\n formData,\n userId: auth.sub,\n comments,\n decisionId,\n scope: { tenantId, organizationId },\n })\n\n // Fetch updated task\n const updatedTask = await em.findOne(UserTask, {\n id: params.id,\n tenantId,\n organizationId,\n })\n\n return NextResponse.json({\n data: updatedTask,\n message: 'Task completed successfully. Workflow resumed.',\n })\n } catch (error) {\n if (isCrudHttpError(error)) return NextResponse.json(error.body, { status: error.status })\n logger.error('Error completing user task', { err: error })\n\n // Handle specific error codes from task-handler\n if (error instanceof Error) {\n if ((error as { code?: unknown }).code === 'UNKNOWN_DECISION') {\n return NextResponse.json(\n { error: error.message },\n { status: 400 }\n )\n }\n // \"Task is assigned to another user\" matches none of the message arms\n // below, so this refusal used to answer 500. It is a conflict.\n if ((error as { code?: unknown }).code === 'TASK_ASSIGNED_TO_ANOTHER_USER') {\n return NextResponse.json(\n { error: error.message },\n { status: 409 }\n )\n }\n if (error.message.includes('not found')) {\n return NextResponse.json(\n { error: error.message },\n { status: 404 }\n )\n }\n if (error.message.includes('validation')) {\n return NextResponse.json(\n { error: error.message },\n { status: 400 }\n )\n }\n if (error.message.includes('already completed')) {\n return NextResponse.json(\n { error: error.message },\n { status: 409 }\n )\n }\n }\n\n return NextResponse.json(\n {\n error: 'Failed to complete user task',\n details: error instanceof Error ? error.message : String(error),\n },\n { status: 500 }\n )\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: workflowsTag,\n summary: 'Complete user task',\n methods: {\n POST: {\n summary: 'Complete a task with form data',\n description: 'Validates form data against task schema, updates task with completion data, merges form data into workflow context, and resumes workflow execution.',\n requestBody: {\n contentType: 'application/json',\n schema: openApiCompleteTaskSchema,\n },\n responses: [\n { status: 200, description: 'Task completed successfully', schema: userTaskCompleteResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid request body, validation failed, or missing context', schema: workflowErrorSchema },\n { status: 401, description: 'Unauthorized', schema: workflowErrorSchema },\n { status: 403, description: 'The task is visible to the caller but is not theirs to act on \u2014 it has no assignee and no role queue, so it must be reassigned first (\u00A76.4: administration widens seeing, never acting).', schema: workflowErrorSchema },\n { status: 404, description: 'Task not found, or not visible to the caller', schema: workflowErrorSchema },\n { status: 409, description: 'Task already completed', schema: workflowErrorSchema },\n { status: 500, description: 'Internal server error', schema: workflowErrorSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * User Task Completion API\n *\n * Endpoints:\n * - POST /api/workflows/tasks/[id]/complete - Complete a user task with form data\n */\n\nimport { NextRequest, NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveSingleOrganizationIdOrDeny } from '@open-mercato/core/modules/directory/utils/organizationScopeFilter'\nimport type { TaskHandlerService } from '../../../../lib/task-handler'\nimport { gateTaskAction } from '../../../../lib/task-visibility-request'\nimport {\n workflowsTag,\n completeTaskRequestSchema as openApiCompleteTaskSchema,\n userTaskCompleteResponseSchema,\n workflowErrorSchema,\n} from '../../../openapi'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\n\nconst logger = createLogger('workflows')\n\nexport const metadata = {\n requireAuth: true,\n requireFeatures: ['workflows.tasks.complete'],\n}\n\n// Request body schema\nconst completeTaskSchema = z.object({\n formData: z.record(z.string(), z.any()),\n comments: z.string().optional(),\n /**\n * The decision button the assignee pressed. Optional and additive: a task\n * without decisions completes through the plain form exactly as before.\n */\n decisionId: z.string().min(1).optional(),\n})\n\n/**\n * POST /api/workflows/tasks/[id]/complete\n *\n * Complete a user task with form data\n *\n * Request body:\n * {\n * formData: { [key: string]: any }, // Form field values\n * comments: string (optional) // Optional comments\n * }\n *\n * This endpoint:\n * 1. Validates the task can be completed\n * 2. Validates form data against the task's form schema\n * 3. Updates the task with completion data\n * 4. Merges form data into workflow context\n * 5. Resumes workflow execution\n */\nexport async function POST(\n request: NextRequest,\n { params }: { params: { id: string } }\n) {\n try {\n const container = await createRequestContainer()\n const em = container.resolve('em')\n const auth = await getAuthFromRequest(request)\n\n if (!auth) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n const tenantId = auth.tenantId\n const organizationId = resolveSingleOrganizationIdOrDeny(scope, auth)\n\n if (!tenantId || !organizationId) {\n return NextResponse.json(\n { error: 'Missing tenant or organization context' },\n { status: 400 }\n )\n }\n\n // Parse request body\n const body = await request.json()\n const parseResult = completeTaskSchema.safeParse(body)\n\n if (!parseResult.success) {\n return NextResponse.json(\n {\n error: 'Invalid request body',\n details: parseResult.error.format(),\n },\n { status: 400 }\n )\n }\n\n const { formData, comments, decisionId } = parseResult.data\n\n // \u00A76.4 replaces the bare tenant/organization check that used to stand here.\n // The narrowing D-1 keeps `workflows.tasks.complete` on the route and still\n // demands: holding it no longer completes anyone ELSE's task. Refusals are\n // indistinguishable from a nonexistent id unless the caller already sees the\n // row.\n const gate = await gateTaskAction({\n container,\n em,\n auth: { userId: auth.sub, tenantId, roleNames: auth.roles ?? [] },\n taskId: params.id,\n organizationId,\n // Complete is the one act where the gate, not the handler, decides\n // ownership: the handler leaves an OWNERLESS row open to anyone holding\n // the feature, which is exactly the pre-change semantics \u00A76.4 narrows.\n requireOwnership: true,\n })\n\n if (!gate.allowed) {\n return NextResponse.json(gate.refusal.body, { status: gate.refusal.status })\n }\n\n const { UserTask } = await import('../../../../data/entities')\n\n // Call task handler to complete task and resume workflow\n const taskHandler = container.resolve<TaskHandlerService>('taskHandler')\n await taskHandler.completeUserTask(em, container, {\n taskId: params.id,\n formData,\n userId: auth.sub,\n comments,\n decisionId,\n scope: { tenantId, organizationId },\n })\n\n // Fetch updated task\n const updatedTask = await em.findOne(UserTask, {\n id: params.id,\n tenantId,\n organizationId,\n })\n\n return NextResponse.json({\n data: updatedTask,\n message: 'Task completed successfully. Workflow resumed.',\n })\n } catch (error) {\n if (isCrudHttpError(error)) return NextResponse.json(error.body, { status: error.status })\n logger.error('Error completing user task', { err: error })\n\n // Handle specific error codes from task-handler\n if (error instanceof Error) {\n if ((error as { code?: unknown }).code === 'UNKNOWN_DECISION') {\n return NextResponse.json(\n { error: error.message },\n { status: 400 }\n )\n }\n // \"Task is assigned to another user\" matches none of the message arms\n // below, so this refusal used to answer 500. It is a conflict.\n if ((error as { code?: unknown }).code === 'TASK_ASSIGNED_TO_ANOTHER_USER') {\n return NextResponse.json(\n { error: error.message },\n { status: 409 }\n )\n }\n if ((error as { code?: unknown }).code === 'WORKFLOW_NOT_ACTIVE') {\n return NextResponse.json(\n { error: error.message, code: 'WORKFLOW_NOT_ACTIVE' },\n { status: 409 }\n )\n }\n if (error.message.includes('not found')) {\n return NextResponse.json(\n { error: error.message },\n { status: 404 }\n )\n }\n if (error.message.includes('validation')) {\n return NextResponse.json(\n { error: error.message },\n { status: 400 }\n )\n }\n if (error.message.includes('already completed')) {\n return NextResponse.json(\n { error: error.message },\n { status: 409 }\n )\n }\n }\n\n return NextResponse.json(\n {\n error: 'Failed to complete user task',\n details: error instanceof Error ? error.message : String(error),\n },\n { status: 500 }\n )\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: workflowsTag,\n summary: 'Complete user task',\n methods: {\n POST: {\n summary: 'Complete a task with form data',\n description: 'Validates form data against task schema, updates task with completion data, merges form data into workflow context, and resumes workflow execution.',\n requestBody: {\n contentType: 'application/json',\n schema: openApiCompleteTaskSchema,\n },\n responses: [\n { status: 200, description: 'Task completed successfully', schema: userTaskCompleteResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid request body, validation failed, or missing context', schema: workflowErrorSchema },\n { status: 401, description: 'Unauthorized', schema: workflowErrorSchema },\n { status: 403, description: 'The task is visible to the caller but is not theirs to act on \u2014 it has no assignee and no role queue, so it must be reassigned first (\u00A76.4: administration widens seeing, never acting).', schema: workflowErrorSchema },\n { status: 404, description: 'Task not found, or not visible to the caller', schema: workflowErrorSchema },\n { status: 409, description: 'Task already completed, assigned to another user, or its workflow run is no longer active (`code: WORKFLOW_NOT_ACTIVE` \u2014 the run is completed, failed, cancelled, compensating or compensated)', schema: workflowErrorSchema },\n { status: 500, description: 'Internal server error', schema: workflowErrorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -156,7 +156,8 @@ function UserTaskDetailPage({ params }) {
156
156
  refreshTask();
157
157
  } else {
158
158
  const failure = result.result;
159
- flash(failure?.error || t("workflows.tasks.messages.completeFailed"), "error");
159
+ const failureMessage = failure?.code === "WORKFLOW_NOT_ACTIVE" ? t("workflows.tasks.messages.workflowNotActive") : failure?.error || t("workflows.tasks.messages.completeFailed");
160
+ flash(failureMessage, "error");
160
161
  }
161
162
  } catch (err) {
162
163
  logger.error("Error completing task", { err });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/workflows/backend/tasks/%5Bid%5D/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\n/**\n * Task detail \u2014 decision beside context (spec \u00A76.2).\n *\n * > \"Task detail = decision + context side-by-side: left \u2014 instructions, form,\n * > decision buttons; right \u2014 bound entity card(s) with deep links. [\u2026] After\n * > completion: 'next task' \u2014 a one-click claim-next affordance.\"\n *\n * Three things about this page are load-bearing:\n *\n * - **The decision buttons are DERIVED, never stored.** The API re-resolves them\n * per request from the instance's pinned definition\n * (`lib/task-decisions.ts`), so no column carries the button list and a\n * definition that gains a decision immediately offers it. Pressing one both\n * completes the task and selects the outgoing route by the decision's durable\n * `transitionId`; WHICH button was pressed is recorded server-side as part of\n * the completion payload.\n * - **Every write goes through `useGuardedMutation`.** This page cannot use\n * `CrudForm`, which is exactly the case the project rule names, and the\n * mutation context carries `retryLastMutation` so the shared conflict/retry\n * bar can re-run the last attempt.\n * - **Status is never colour-only** \u2014 every badge pairs its design-system token\n * with an icon and a translated label (`lib/work-inbox/presentation.ts`).\n * - **Every affordance is gated by what the SERVER said** (`canComplete` /\n * `canClaim` / `canRelease` / `canReassign`, decided by `lib/task-visibility.ts`\n * and sent on the detail response). The page never re-derives \u00A76.4: a second\n * copy of that rule is how a `workflows.tasks.view_all` administrator came to\n * be offered a Complete button that always answered 409. When an action is\n * unavailable the page states the server's reason and, where \u00A76.4 names one,\n * offers the remedy \u2014 reassignment.\n */\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\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 { Separator } from '@open-mercato/ui/primitives/separator'\nimport { JsonDisplay } from '@open-mercato/ui/backend/JsonDisplay'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { MobileTaskForm } from '../../../components/mobile/MobileTaskForm'\nimport { StatusChip } from '../../../components/work-inbox/StatusChip'\nimport { TaskActionNotice } from '../../../components/work-inbox/TaskActionNotice'\nimport {\n ReassignTaskDialog,\n type ReassignTaskTarget,\n} from '../../../components/work-inbox/ReassignTaskDialog'\nimport { TaskFormFields } from '../../../components/work-inbox/TaskFormFields'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport type { UserTaskDecision, UserTaskResponse, UserTaskStatus } from '../../../data/types'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport {\n TASK_DETAIL_INJECTION_SPOT_ID,\n WORK_INBOX_HREF,\n buildWorkInboxItemHref,\n} from '../../../lib/work-inbox/navigation'\nimport {\n EntityContextPanel,\n bindingsToEntityContextItems,\n} from '../../../components/work-inbox/EntityContextPanel'\nimport {\n WORK_INBOX_OVERDUE_TONE,\n describeTaskActionBlock,\n describeWorkInboxPriority,\n describeWorkInboxStatus,\n} from '../../../lib/work-inbox/presentation'\nimport { normalizeWorkInboxPriority } from '../../../lib/work-inbox/provider'\nimport { flattenTaskText } from '../../../lib/task-resolution'\nimport { readRecordedDecision } from '../../../lib/task-decisions'\nimport { normalizeTaskFormSchema } from '../../../lib/task-form-schema'\n\nconst logger = createLogger('workflows')\n\ntype TaskMutationContext = {\n formId: string\n taskId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n}\n\nfunction decisionButtonVariant(style: UserTaskDecision['style']): 'default' | 'outline' | 'destructive' {\n if (style === 'destructive') return 'destructive'\n if (style === 'secondary') return 'outline'\n return 'default'\n}\n\nexport default function UserTaskDetailPage({ params }: { params: { id: string } }) {\n const router = useRouter()\n const t = useT()\n const queryClient = useQueryClient()\n const isMobile = useIsMobile()\n const [formData, setFormData] = React.useState<Record<string, string | number | boolean>>({})\n const [comments, setComments] = React.useState('')\n const [submitting, setSubmitting] = React.useState(false)\n const [reassignOpen, setReassignOpen] = React.useState(false)\n // Tracks the first required field that failed validation so we can mark the\n // field with aria-invalid + a red ring (Radix Select can't carry HTML\n // `required`, so we enforce constraint validation in JS instead).\n const [invalidField, setInvalidField] = React.useState<string | null>(null)\n\n const { runMutation, retryLastMutation } = useGuardedMutation<TaskMutationContext>({\n contextId: `workflows-task:${params.id}`,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const { data: task, isLoading, error } = useQuery({\n queryKey: ['workflow-task', params.id],\n queryFn: async () => {\n const result = await apiCall<{ data: UserTaskResponse }>(\n `/api/workflows/tasks/${params.id}`\n )\n if (!result.ok) {\n const httpErr = new Error(\n result.status === 404\n ? t('workflows.tasks.detail.notFound', 'Task not found')\n : t('workflows.tasks.detail.loadFailed', 'Failed to load task')\n ) as Error & { status: number }\n httpErr.status = result.status\n throw httpErr\n }\n return result.result?.data ?? null\n },\n })\n\n const mutationContext = React.useMemo<TaskMutationContext>(\n () => ({\n formId: `workflows-task:${params.id}`,\n taskId: params.id,\n resourceKind: 'workflows.user_task',\n resourceId: params.id,\n retryLastMutation,\n }),\n [params.id, retryLastMutation],\n )\n\n // Injection spot for modules that OWN what a task is about (spec \u00A77.6). It\n // is a CONTRACT SURFACE (BACKWARD_COMPATIBILITY.md \u00A76): the id is frozen once\n // a third party mounts a widget on it.\n const taskInjectionContext = React.useMemo(\n () => ({\n taskId: params.id,\n workflowInstanceId: task?.workflowInstanceId ?? null,\n status: task?.status ?? null,\n formSchema: task?.formSchema ?? null,\n formData: task?.formData ?? null,\n retryLastMutation,\n }),\n [params.id, retryLastMutation, task?.formData, task?.formSchema, task?.status, task?.workflowInstanceId],\n )\n\n const refreshTask = React.useCallback(() => {\n queryClient.invalidateQueries({ queryKey: ['workflow-task', params.id] })\n }, [params.id, queryClient])\n\n const handleFieldChange = (fieldName: string, value: string | number | boolean) => {\n setFormData(prev => ({\n ...prev,\n [fieldName]: value,\n }))\n // Clear invalid state once the user touches the offending field.\n if (invalidField === fieldName) setInvalidField(null)\n }\n\n const validateRequiredFields = React.useCallback((): boolean => {\n // Normalized, so a Studio-authored `{ fields: [...] }` schema is validated\n // by the same rule the server enforces (`lib/task-form-schema.ts`).\n const normalizedSchema = normalizeTaskFormSchema(task?.formSchema)\n if (!normalizedSchema?.required) return true\n for (const requiredField of normalizedSchema.required) {\n if (!formData[requiredField] || formData[requiredField] === '') {\n const fieldSchema = normalizedSchema.properties?.[requiredField]\n const fieldLabel = fieldSchema?.title ?? requiredField\n flash(t('workflows.tasks.detail.validation.requiredField', { field: fieldLabel }), 'error')\n setInvalidField(requiredField)\n // Scroll + focus the trigger so the user sees what's missing.\n if (typeof document !== 'undefined') {\n const trigger = document.getElementById(requiredField)\n trigger?.scrollIntoView({ behavior: 'smooth', block: 'center' })\n trigger?.focus()\n }\n return false\n }\n }\n setInvalidField(null)\n return true\n }, [formData, task, t])\n\n const completeTask = React.useCallback(\n async (decisionId?: string) => {\n if (!task) return\n if (!validateRequiredFields()) return\n\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () =>\n apiCall(`/api/workflows/tasks/${params.id}/complete`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n formData,\n comments: comments || undefined,\n ...(decisionId ? { decisionId } : {}),\n }),\n }),\n context: mutationContext,\n mutationPayload: { formData, comments, decisionId },\n })\n\n if (result.ok) {\n flash(t('workflows.tasks.messages.completed'), 'success')\n refreshTask()\n } else {\n const failure = result.result as { error?: string } | null\n flash(failure?.error || t('workflows.tasks.messages.completeFailed'), 'error')\n }\n } catch (err) {\n logger.error('Error completing task', { err })\n flash(t('workflows.tasks.messages.completeFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n },\n [comments, formData, mutationContext, params.id, refreshTask, runMutation, t, task, validateRequiredFields],\n )\n\n const handleSubmit = React.useCallback(\n (event: React.FormEvent) => {\n event.preventDefault()\n void completeTask()\n },\n [completeTask],\n )\n\n const handleClaim = React.useCallback(async () => {\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () => apiCall(`/api/workflows/tasks/${params.id}/claim`, { method: 'POST' }),\n context: mutationContext,\n mutationPayload: { action: 'claim' },\n })\n if (result.ok) {\n flash(t('workflows.tasks.messages.claimed'), 'success')\n refreshTask()\n } else {\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n }\n } catch (err) {\n logger.error('Error claiming task', { err })\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n }, [mutationContext, params.id, refreshTask, runMutation, t])\n\n const handleRelease = React.useCallback(async () => {\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () => apiCall(`/api/workflows/tasks/${params.id}/unclaim`, { method: 'POST' }),\n context: mutationContext,\n mutationPayload: { action: 'unclaim' },\n })\n if (result.ok) {\n flash(t('workflows.workInbox.messages.released'), 'success')\n refreshTask()\n } else {\n flash(t('workflows.workInbox.messages.releaseFailed'), 'error')\n }\n } catch (err) {\n logger.error('Error releasing task', { err })\n flash(t('workflows.workInbox.messages.releaseFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n }, [mutationContext, params.id, refreshTask, runMutation, t])\n\n /**\n * Reassignment is the remedy \u00A76.4 names for every ownership refusal, and the\n * only way to rescue a task authored with no assignee, no queue and no claim.\n *\n * The endpoint honours the optimistic-lock header explicitly (`UserTask` is\n * outside the curated CRUD lock list), so the row's `updatedAt` rides along:\n * two administrators racing to take the same task get a 409 rather than a\n * silent last-write-wins.\n */\n const handleReassign = React.useCallback(\n async (target: ReassignTaskTarget) => {\n if (!task) return\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(task.updatedAt), () =>\n apiCall(`/api/workflows/tasks/${params.id}/reassign`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(target),\n }),\n ),\n context: mutationContext,\n mutationPayload: { action: 'reassign', ...target },\n })\n if (result.ok) {\n setReassignOpen(false)\n flash(t('workflows.tasks.messages.reassigned'), 'success')\n refreshTask()\n } else {\n const failure = result.result as { error?: string } | null\n flash(failure?.error || t('workflows.tasks.messages.reassignFailed'), 'error')\n }\n } catch (err) {\n logger.error('Error reassigning task', { err })\n flash(t('workflows.tasks.messages.reassignFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n },\n [mutationContext, params.id, refreshTask, runMutation, t, task],\n )\n\n const handleNextTask = React.useCallback(async () => {\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () =>\n apiCall<{ data: { id: string } | null }>('/api/workflows/work-inbox/next', {\n method: 'POST',\n }),\n context: mutationContext,\n mutationPayload: { action: 'claim-next' },\n })\n if (!result.ok) {\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n return\n }\n const claimed = result.result?.data ?? null\n if (!claimed) {\n flash(t('workflows.workInbox.messages.nothingClaimable'), 'info')\n return\n }\n flash(t('workflows.tasks.messages.claimed'), 'success')\n router.push(buildWorkInboxItemHref(claimed.id))\n } catch (err) {\n logger.error('Error claiming the next task', { err })\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n }, [mutationContext, router, runMutation, t])\n\n const getStatusBadgeClass = React.useCallback(\n (status: UserTaskStatus) => describeWorkInboxStatus(status).badge,\n [],\n )\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex items-center justify-center py-12\">\n <Spinner />\n <span className=\"ml-3 text-muted-foreground\">{t('workflows.tasks.detail.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.tasks.detail.notFound', 'Task not found')}\n backHref={WORK_INBOX_HREF}\n backLabel={t('workflows.tasks.detail.backToList', 'Back to Tasks')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !task) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={(error as Error | null)?.message ?? t('workflows.tasks.detail.loadFailed', 'Failed to load task')}\n action={\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href={WORK_INBOX_HREF}>{t('workflows.tasks.detail.backToList', 'Back to Tasks')}</Link>\n </Button>\n }\n />\n </PageBody>\n </Page>\n )\n }\n\n const isCompletable = task.status === 'PENDING' || task.status === 'IN_PROGRESS'\n const isOverdue = Boolean(task.dueDate) && new Date(task.dueDate as string) < new Date() && isCompletable\n const statusDescriptor = describeWorkInboxStatus(task.status)\n const priority = normalizeWorkInboxPriority(task.priority)\n const priorityDescriptor = describeWorkInboxPriority(priority)\n const decisions = task.decisions ?? []\n const contextItems = bindingsToEntityContextItems(task.entityBindings, {\n noLink: t('workflows.tasks.detail.records.noLink'),\n })\n const recordedDecisionId = readRecordedDecision(task.formData)\n const recordedDecision = recordedDecisionId\n ? decisions.find((decision) => decision.id === recordedDecisionId) ?? null\n : null\n // A task nobody owns yet, offered to a role queue, is the one this operator\n // can take. An individually assigned task is already theirs to finish.\n //\n // Kept ONLY as the compatibility fallback below \u2014 it is the pre-change\n // behaviour, restored verbatim when the server sends no `canClaim`.\n const legacyClaimable =\n task.status === 'PENDING' &&\n !task.assignedTo &&\n !task.claimedBy &&\n (task.assignedToRoles?.length ?? 0) > 0\n\n /*\n * The server decides; the page renders. `??` is the additive-compatibility\n * fallback for a payload written before these fields existed\n * (BACKWARD_COMPATIBILITY.md \u00A77) \u2014 it restores exactly the pre-change\n * behaviour and is never a second copy of the \u00A76.4 rule. Release and reassign\n * are new affordances with no legacy behaviour to preserve, so an old payload\n * simply does not offer them.\n */\n const canComplete = task.canComplete ?? isCompletable\n const canClaim = task.canClaim ?? legacyClaimable\n const canRelease = task.canRelease ?? false\n const canReassign = task.canReassign ?? false\n const blockDescriptor = canComplete\n ? null\n : describeTaskActionBlock(task.actBlockedReason ?? 'not-workable')\n\n if (isMobile) {\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-4\">\n <FormHeader\n mode=\"detail\"\n backHref={WORK_INBOX_HREF}\n backLabel={t('workflows.tasks.backToList', 'Back to tasks')}\n />\n {blockDescriptor ? (\n <TaskActionNotice\n descriptor={blockDescriptor}\n canReassign={canReassign}\n disabled={submitting}\n onReassign={() => setReassignOpen(true)}\n />\n ) : null}\n <MobileTaskForm\n task={task}\n formData={formData}\n comments={comments}\n submitting={submitting}\n isCompletable={canComplete}\n isOverdue={isOverdue}\n onFieldChange={handleFieldChange}\n onCommentsChange={setComments}\n onSubmit={handleSubmit}\n onCancel={() => router.push(WORK_INBOX_HREF)}\n getStatusBadgeClass={getStatusBadgeClass}\n decisions={decisions}\n onDecision={(decisionId) => void completeTask(decisionId)}\n />\n </div>\n <ReassignTaskDialog\n open={reassignOpen}\n submitting={submitting}\n onOpenChange={setReassignOpen}\n onSubmit={(target) => void handleReassign(target)}\n />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref={WORK_INBOX_HREF}\n backLabel={t('workflows.tasks.backToList', 'Back to tasks')}\n entityTypeLabel={t('workflows.tasks.detail.type', 'User task')}\n title={task.taskName}\n subtitle={task.description || undefined}\n statusBadge={\n <span className=\"inline-flex items-center gap-2\">\n <StatusChip\n descriptor={statusDescriptor}\n label={t(`workflows.tasks.statuses.${task.status}`, task.status)}\n />\n {priorityDescriptor && priority ? (\n <StatusChip\n descriptor={priorityDescriptor}\n label={t(`workflows.workInbox.priorities.${priority}`, priority)}\n />\n ) : null}\n {isOverdue ? (\n <StatusChip\n descriptor={WORK_INBOX_OVERDUE_TONE}\n label={t('workflows.tasks.overdue')}\n />\n ) : null}\n </span>\n }\n />\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Left \u2014 instructions, form, decisions */}\n <div className=\"space-y-6 lg:col-span-2\">\n {isOverdue ? (\n <div className=\"bg-status-error-bg border border-status-error-border rounded-lg p-3\">\n <p className=\"text-sm text-status-error-text font-medium\">\n {t('workflows.tasks.detail.overdueWarning')}\n </p>\n </div>\n ) : null}\n\n {task.description ? (\n <div className=\"rounded-lg border border-border p-4\">\n <h2 className=\"text-sm font-semibold mb-2\">\n {t('workflows.tasks.detail.sections.instructions')}\n </h2>\n <p className=\"text-sm text-muted-foreground whitespace-pre-wrap\">{task.description}</p>\n </div>\n ) : null}\n\n {/*\n Where a module that OWNS the thing a task is about renders it in\n its own vocabulary. The agent orchestrator mounts the proposal\n draft card here (spec \u00A77.6): this page can only walk a task's\n `formSchema` generically, and a proposal rendered that way is a\n key/value dump of the mutation an operator is being asked to\n approve. Additive \u2014 no widget, nothing renders.\n */}\n <InjectionSpot spotId={TASK_DETAIL_INJECTION_SPOT_ID} context={taskInjectionContext} />\n\n {canClaim ? (\n <div className=\"rounded-lg border border-border bg-muted/50 p-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.detail.claimPrompt')}\n </p>\n <Button\n type=\"button\"\n data-testid=\"task-claim\"\n disabled={submitting}\n onClick={() => void handleClaim()}\n >\n {t('workflows.tasks.actions.claim')}\n </Button>\n </div>\n ) : null}\n\n {canRelease ? (\n <div className=\"rounded-lg border border-border bg-muted/50 p-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.detail.releasePrompt')}\n </p>\n <Button\n type=\"button\"\n variant=\"outline\"\n data-testid=\"task-release\"\n disabled={submitting}\n onClick={() => void handleRelease()}\n >\n {t('workflows.tasks.actions.unclaim')}\n </Button>\n </div>\n ) : null}\n\n {blockDescriptor ? (\n <TaskActionNotice\n descriptor={blockDescriptor}\n canReassign={canReassign}\n disabled={submitting}\n onReassign={() => setReassignOpen(true)}\n />\n ) : null}\n\n {/*\n Offered even when the task IS completable: an administrator may\n legitimately hand a row to somebody else, and the endpoint gates\n on visibility rather than ownership precisely so it can.\n */}\n {canComplete && canReassign ? (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n variant=\"outline\"\n data-testid=\"task-reassign\"\n disabled={submitting}\n onClick={() => setReassignOpen(true)}\n >\n {t('workflows.tasks.actions.reassign')}\n </Button>\n </div>\n ) : null}\n\n {canComplete ? (\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <TaskFormFields\n formSchema={task.formSchema}\n values={formData}\n invalidField={invalidField}\n disabled={submitting}\n onFieldChange={handleFieldChange}\n formKey={task.formKey}\n taskId={task.id}\n taskName={task.taskName}\n entityBindings={task.entityBindings}\n decisions={decisions}\n onValuesChange={setFormData}\n />\n\n <Separator />\n\n <div className=\"space-y-2\">\n <label htmlFor=\"comments\" className=\"block text-sm font-medium text-foreground\">\n {t('workflows.tasks.detail.comments')} ({t('workflows.tasks.detail.optional')})\n </label>\n <textarea\n id=\"comments\"\n value={comments}\n onChange={(e) => setComments(e.target.value)}\n rows={3}\n className=\"w-full px-3 py-2 border border-border rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n placeholder={t('workflows.tasks.detail.commentsPlaceholder')}\n />\n </div>\n\n {decisions.length > 0 ? (\n <div className=\"space-y-3\" data-testid=\"task-decisions\">\n <h2 className=\"text-sm font-semibold\">\n {t('workflows.tasks.detail.sections.decisions')}\n </h2>\n <div className=\"flex flex-col gap-3 sm:flex-row sm:flex-wrap\">\n {decisions.map((decision) => (\n <Button\n key={decision.id}\n type=\"button\"\n data-testid={`task-decision-${decision.id}`}\n variant={decisionButtonVariant(decision.style)}\n disabled={submitting}\n onClick={() => void completeTask(decision.id)}\n className=\"w-full sm:w-auto\"\n >\n {flattenTaskText(decision.label) ?? decision.id}\n </Button>\n ))}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-3 pt-4 sm:flex-row sm:items-center\">\n <Button type=\"submit\" data-testid=\"task-complete\" disabled={submitting} className=\"w-full sm:w-auto\">\n {submitting\n ? t('workflows.tasks.detail.submitting')\n : t('workflows.tasks.detail.completeTask')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push(WORK_INBOX_HREF)}\n disabled={submitting}\n className=\"w-full sm:w-auto\"\n >\n {t('common.cancel')}\n </Button>\n </div>\n )}\n </form>\n ) : null}\n\n {task.status === 'COMPLETED' ? (\n <div className=\"space-y-4\">\n {recordedDecisionId ? (\n <div className=\"rounded-lg border border-border p-4\">\n <p className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.detail.decisionTaken')}:{' '}\n <span className=\"text-foreground font-medium\">\n {recordedDecision\n ? flattenTaskText(recordedDecision.label) ?? recordedDecisionId\n : recordedDecisionId}\n </span>\n </p>\n </div>\n ) : null}\n\n {task.formData ? (\n <JsonDisplay\n data={task.formData}\n title={t('workflows.tasks.detail.sections.submittedData')}\n maxInitialDepth={2}\n />\n ) : null}\n\n {task.comments ? (\n <div className=\"bg-muted/50 rounded-lg p-4\">\n <p className=\"text-sm font-medium text-foreground mb-2\">\n {t('workflows.tasks.detail.comments')}:\n </p>\n <p className=\"text-sm text-muted-foreground whitespace-pre-wrap\">{task.comments}</p>\n </div>\n ) : null}\n\n {/* Spec \u00A76.2: keep frontline flow going with one click. */}\n <div className=\"rounded-lg border border-border bg-muted/50 p-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.detail.nextTaskPrompt')}\n </p>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n data-testid=\"task-next\"\n disabled={submitting}\n onClick={() => void handleNextTask()}\n >\n {t('workflows.workInbox.actions.claimNext')}\n </Button>\n <Button asChild variant=\"outline\">\n <Link href={WORK_INBOX_HREF}>{t('workflows.tasks.detail.backToList')}</Link>\n </Button>\n </div>\n </div>\n </div>\n ) : null}\n </div>\n\n {/* Right \u2014 the records this task is about, plus how it got here */}\n <div className=\"space-y-4\">\n <EntityContextPanel\n testId=\"task-context-records\"\n title={t('workflows.tasks.detail.sections.records')}\n items={contextItems}\n emptyLabel={t('workflows.tasks.detail.records.empty')}\n linkLabel={t('workflows.tasks.detail.records.open')}\n />\n\n <div className=\"rounded-lg border border-border p-4 space-y-2\">\n <h2 className=\"text-sm font-semibold\">\n {t('workflows.tasks.detail.sections.taskInfo')}\n </h2>\n <div className=\"space-y-1 text-sm\">\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.fields.createdAt')}:</span>\n <span className=\"ml-2 text-foreground\">{new Date(task.createdAt).toLocaleString()}</span>\n </div>\n {task.dueDate ? (\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.fields.dueDate')}:</span>\n <span\n className={`ml-2 ${isOverdue ? `${WORK_INBOX_OVERDUE_TONE.text} font-medium` : 'text-foreground'}`}\n >\n {new Date(task.dueDate).toLocaleString()}\n </span>\n </div>\n ) : null}\n {task.assignedTo ? (\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.detail.assignedTo')}:</span>\n <span className=\"ml-2 text-foreground\">{task.assignedTo}</span>\n </div>\n ) : null}\n {task.assignedToRoles?.length ? (\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.roles')}:</span>\n <span className=\"ml-2 text-foreground\">{task.assignedToRoles.join(', ')}</span>\n </div>\n ) : null}\n {task.claimedBy ? (\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.claimedBy')}:</span>\n <span className=\"ml-2 text-foreground\">{task.claimedBy}</span>\n </div>\n ) : null}\n <div>\n <span className=\"text-muted-foreground\">\n {t('workflows.tasks.detail.workflowInstance')}:\n </span>\n <Link\n href={`/backend/instances/${task.workflowInstanceId}`}\n className=\"ml-2 text-primary hover:underline text-xs font-mono\"\n >\n {task.workflowInstanceId.slice(0, 8)}...\n </Link>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <ReassignTaskDialog\n open={reassignOpen}\n submitting={submitting}\n onOpenChange={setReassignOpen}\n onSubmit={(target) => void handleReassign(target)}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\n/**\n * Task detail \u2014 decision beside context (spec \u00A76.2).\n *\n * > \"Task detail = decision + context side-by-side: left \u2014 instructions, form,\n * > decision buttons; right \u2014 bound entity card(s) with deep links. [\u2026] After\n * > completion: 'next task' \u2014 a one-click claim-next affordance.\"\n *\n * Three things about this page are load-bearing:\n *\n * - **The decision buttons are DERIVED, never stored.** The API re-resolves them\n * per request from the instance's pinned definition\n * (`lib/task-decisions.ts`), so no column carries the button list and a\n * definition that gains a decision immediately offers it. Pressing one both\n * completes the task and selects the outgoing route by the decision's durable\n * `transitionId`; WHICH button was pressed is recorded server-side as part of\n * the completion payload.\n * - **Every write goes through `useGuardedMutation`.** This page cannot use\n * `CrudForm`, which is exactly the case the project rule names, and the\n * mutation context carries `retryLastMutation` so the shared conflict/retry\n * bar can re-run the last attempt.\n * - **Status is never colour-only** \u2014 every badge pairs its design-system token\n * with an icon and a translated label (`lib/work-inbox/presentation.ts`).\n * - **Every affordance is gated by what the SERVER said** (`canComplete` /\n * `canClaim` / `canRelease` / `canReassign`, decided by `lib/task-visibility.ts`\n * and sent on the detail response). The page never re-derives \u00A76.4: a second\n * copy of that rule is how a `workflows.tasks.view_all` administrator came to\n * be offered a Complete button that always answered 409. When an action is\n * unavailable the page states the server's reason and, where \u00A76.4 names one,\n * offers the remedy \u2014 reassignment.\n */\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\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 { Separator } from '@open-mercato/ui/primitives/separator'\nimport { JsonDisplay } from '@open-mercato/ui/backend/JsonDisplay'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { InjectionSpot } from '@open-mercato/ui/backend/injection/InjectionSpot'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { MobileTaskForm } from '../../../components/mobile/MobileTaskForm'\nimport { StatusChip } from '../../../components/work-inbox/StatusChip'\nimport { TaskActionNotice } from '../../../components/work-inbox/TaskActionNotice'\nimport {\n ReassignTaskDialog,\n type ReassignTaskTarget,\n} from '../../../components/work-inbox/ReassignTaskDialog'\nimport { TaskFormFields } from '../../../components/work-inbox/TaskFormFields'\nimport { useIsMobile } from '@open-mercato/ui/hooks/useIsMobile'\nimport type { UserTaskDecision, UserTaskResponse, UserTaskStatus } from '../../../data/types'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport {\n TASK_DETAIL_INJECTION_SPOT_ID,\n WORK_INBOX_HREF,\n buildWorkInboxItemHref,\n} from '../../../lib/work-inbox/navigation'\nimport {\n EntityContextPanel,\n bindingsToEntityContextItems,\n} from '../../../components/work-inbox/EntityContextPanel'\nimport {\n WORK_INBOX_OVERDUE_TONE,\n describeTaskActionBlock,\n describeWorkInboxPriority,\n describeWorkInboxStatus,\n} from '../../../lib/work-inbox/presentation'\nimport { normalizeWorkInboxPriority } from '../../../lib/work-inbox/provider'\nimport { flattenTaskText } from '../../../lib/task-resolution'\nimport { readRecordedDecision } from '../../../lib/task-decisions'\nimport { normalizeTaskFormSchema } from '../../../lib/task-form-schema'\n\nconst logger = createLogger('workflows')\n\ntype TaskMutationContext = {\n formId: string\n taskId: string\n resourceKind: string\n resourceId: string\n retryLastMutation: () => Promise<boolean>\n}\n\nfunction decisionButtonVariant(style: UserTaskDecision['style']): 'default' | 'outline' | 'destructive' {\n if (style === 'destructive') return 'destructive'\n if (style === 'secondary') return 'outline'\n return 'default'\n}\n\nexport default function UserTaskDetailPage({ params }: { params: { id: string } }) {\n const router = useRouter()\n const t = useT()\n const queryClient = useQueryClient()\n const isMobile = useIsMobile()\n const [formData, setFormData] = React.useState<Record<string, string | number | boolean>>({})\n const [comments, setComments] = React.useState('')\n const [submitting, setSubmitting] = React.useState(false)\n const [reassignOpen, setReassignOpen] = React.useState(false)\n // Tracks the first required field that failed validation so we can mark the\n // field with aria-invalid + a red ring (Radix Select can't carry HTML\n // `required`, so we enforce constraint validation in JS instead).\n const [invalidField, setInvalidField] = React.useState<string | null>(null)\n\n const { runMutation, retryLastMutation } = useGuardedMutation<TaskMutationContext>({\n contextId: `workflows-task:${params.id}`,\n blockedMessage: t('ui.forms.flash.saveBlocked', 'Save blocked by validation'),\n })\n\n const { data: task, isLoading, error } = useQuery({\n queryKey: ['workflow-task', params.id],\n queryFn: async () => {\n const result = await apiCall<{ data: UserTaskResponse }>(\n `/api/workflows/tasks/${params.id}`\n )\n if (!result.ok) {\n const httpErr = new Error(\n result.status === 404\n ? t('workflows.tasks.detail.notFound', 'Task not found')\n : t('workflows.tasks.detail.loadFailed', 'Failed to load task')\n ) as Error & { status: number }\n httpErr.status = result.status\n throw httpErr\n }\n return result.result?.data ?? null\n },\n })\n\n const mutationContext = React.useMemo<TaskMutationContext>(\n () => ({\n formId: `workflows-task:${params.id}`,\n taskId: params.id,\n resourceKind: 'workflows.user_task',\n resourceId: params.id,\n retryLastMutation,\n }),\n [params.id, retryLastMutation],\n )\n\n // Injection spot for modules that OWN what a task is about (spec \u00A77.6). It\n // is a CONTRACT SURFACE (BACKWARD_COMPATIBILITY.md \u00A76): the id is frozen once\n // a third party mounts a widget on it.\n const taskInjectionContext = React.useMemo(\n () => ({\n taskId: params.id,\n workflowInstanceId: task?.workflowInstanceId ?? null,\n status: task?.status ?? null,\n formSchema: task?.formSchema ?? null,\n formData: task?.formData ?? null,\n retryLastMutation,\n }),\n [params.id, retryLastMutation, task?.formData, task?.formSchema, task?.status, task?.workflowInstanceId],\n )\n\n const refreshTask = React.useCallback(() => {\n queryClient.invalidateQueries({ queryKey: ['workflow-task', params.id] })\n }, [params.id, queryClient])\n\n const handleFieldChange = (fieldName: string, value: string | number | boolean) => {\n setFormData(prev => ({\n ...prev,\n [fieldName]: value,\n }))\n // Clear invalid state once the user touches the offending field.\n if (invalidField === fieldName) setInvalidField(null)\n }\n\n const validateRequiredFields = React.useCallback((): boolean => {\n // Normalized, so a Studio-authored `{ fields: [...] }` schema is validated\n // by the same rule the server enforces (`lib/task-form-schema.ts`).\n const normalizedSchema = normalizeTaskFormSchema(task?.formSchema)\n if (!normalizedSchema?.required) return true\n for (const requiredField of normalizedSchema.required) {\n if (!formData[requiredField] || formData[requiredField] === '') {\n const fieldSchema = normalizedSchema.properties?.[requiredField]\n const fieldLabel = fieldSchema?.title ?? requiredField\n flash(t('workflows.tasks.detail.validation.requiredField', { field: fieldLabel }), 'error')\n setInvalidField(requiredField)\n // Scroll + focus the trigger so the user sees what's missing.\n if (typeof document !== 'undefined') {\n const trigger = document.getElementById(requiredField)\n trigger?.scrollIntoView({ behavior: 'smooth', block: 'center' })\n trigger?.focus()\n }\n return false\n }\n }\n setInvalidField(null)\n return true\n }, [formData, task, t])\n\n const completeTask = React.useCallback(\n async (decisionId?: string) => {\n if (!task) return\n if (!validateRequiredFields()) return\n\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () =>\n apiCall(`/api/workflows/tasks/${params.id}/complete`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n formData,\n comments: comments || undefined,\n ...(decisionId ? { decisionId } : {}),\n }),\n }),\n context: mutationContext,\n mutationPayload: { formData, comments, decisionId },\n })\n\n if (result.ok) {\n flash(t('workflows.tasks.messages.completed'), 'success')\n refreshTask()\n } else {\n const failure = result.result as { error?: string; code?: string } | null\n const failureMessage =\n failure?.code === 'WORKFLOW_NOT_ACTIVE'\n ? t('workflows.tasks.messages.workflowNotActive')\n : failure?.error || t('workflows.tasks.messages.completeFailed')\n flash(failureMessage, 'error')\n }\n } catch (err) {\n logger.error('Error completing task', { err })\n flash(t('workflows.tasks.messages.completeFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n },\n [comments, formData, mutationContext, params.id, refreshTask, runMutation, t, task, validateRequiredFields],\n )\n\n const handleSubmit = React.useCallback(\n (event: React.FormEvent) => {\n event.preventDefault()\n void completeTask()\n },\n [completeTask],\n )\n\n const handleClaim = React.useCallback(async () => {\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () => apiCall(`/api/workflows/tasks/${params.id}/claim`, { method: 'POST' }),\n context: mutationContext,\n mutationPayload: { action: 'claim' },\n })\n if (result.ok) {\n flash(t('workflows.tasks.messages.claimed'), 'success')\n refreshTask()\n } else {\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n }\n } catch (err) {\n logger.error('Error claiming task', { err })\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n }, [mutationContext, params.id, refreshTask, runMutation, t])\n\n const handleRelease = React.useCallback(async () => {\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () => apiCall(`/api/workflows/tasks/${params.id}/unclaim`, { method: 'POST' }),\n context: mutationContext,\n mutationPayload: { action: 'unclaim' },\n })\n if (result.ok) {\n flash(t('workflows.workInbox.messages.released'), 'success')\n refreshTask()\n } else {\n flash(t('workflows.workInbox.messages.releaseFailed'), 'error')\n }\n } catch (err) {\n logger.error('Error releasing task', { err })\n flash(t('workflows.workInbox.messages.releaseFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n }, [mutationContext, params.id, refreshTask, runMutation, t])\n\n /**\n * Reassignment is the remedy \u00A76.4 names for every ownership refusal, and the\n * only way to rescue a task authored with no assignee, no queue and no claim.\n *\n * The endpoint honours the optimistic-lock header explicitly (`UserTask` is\n * outside the curated CRUD lock list), so the row's `updatedAt` rides along:\n * two administrators racing to take the same task get a 409 rather than a\n * silent last-write-wins.\n */\n const handleReassign = React.useCallback(\n async (target: ReassignTaskTarget) => {\n if (!task) return\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () =>\n withScopedApiRequestHeaders(buildOptimisticLockHeader(task.updatedAt), () =>\n apiCall(`/api/workflows/tasks/${params.id}/reassign`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(target),\n }),\n ),\n context: mutationContext,\n mutationPayload: { action: 'reassign', ...target },\n })\n if (result.ok) {\n setReassignOpen(false)\n flash(t('workflows.tasks.messages.reassigned'), 'success')\n refreshTask()\n } else {\n const failure = result.result as { error?: string } | null\n flash(failure?.error || t('workflows.tasks.messages.reassignFailed'), 'error')\n }\n } catch (err) {\n logger.error('Error reassigning task', { err })\n flash(t('workflows.tasks.messages.reassignFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n },\n [mutationContext, params.id, refreshTask, runMutation, t, task],\n )\n\n const handleNextTask = React.useCallback(async () => {\n setSubmitting(true)\n try {\n const result = await runMutation({\n operation: () =>\n apiCall<{ data: { id: string } | null }>('/api/workflows/work-inbox/next', {\n method: 'POST',\n }),\n context: mutationContext,\n mutationPayload: { action: 'claim-next' },\n })\n if (!result.ok) {\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n return\n }\n const claimed = result.result?.data ?? null\n if (!claimed) {\n flash(t('workflows.workInbox.messages.nothingClaimable'), 'info')\n return\n }\n flash(t('workflows.tasks.messages.claimed'), 'success')\n router.push(buildWorkInboxItemHref(claimed.id))\n } catch (err) {\n logger.error('Error claiming the next task', { err })\n flash(t('workflows.tasks.messages.claimFailed'), 'error')\n } finally {\n setSubmitting(false)\n }\n }, [mutationContext, router, runMutation, t])\n\n const getStatusBadgeClass = React.useCallback(\n (status: UserTaskStatus) => describeWorkInboxStatus(status).badge,\n [],\n )\n\n if (isLoading) {\n return (\n <Page>\n <PageBody>\n <div className=\"flex items-center justify-center py-12\">\n <Spinner />\n <span className=\"ml-3 text-muted-foreground\">{t('workflows.tasks.detail.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.tasks.detail.notFound', 'Task not found')}\n backHref={WORK_INBOX_HREF}\n backLabel={t('workflows.tasks.detail.backToList', 'Back to Tasks')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error || !task) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage\n label={(error as Error | null)?.message ?? t('workflows.tasks.detail.loadFailed', 'Failed to load task')}\n action={\n <Button asChild variant=\"outline\" size=\"sm\">\n <Link href={WORK_INBOX_HREF}>{t('workflows.tasks.detail.backToList', 'Back to Tasks')}</Link>\n </Button>\n }\n />\n </PageBody>\n </Page>\n )\n }\n\n const isCompletable = task.status === 'PENDING' || task.status === 'IN_PROGRESS'\n const isOverdue = Boolean(task.dueDate) && new Date(task.dueDate as string) < new Date() && isCompletable\n const statusDescriptor = describeWorkInboxStatus(task.status)\n const priority = normalizeWorkInboxPriority(task.priority)\n const priorityDescriptor = describeWorkInboxPriority(priority)\n const decisions = task.decisions ?? []\n const contextItems = bindingsToEntityContextItems(task.entityBindings, {\n noLink: t('workflows.tasks.detail.records.noLink'),\n })\n const recordedDecisionId = readRecordedDecision(task.formData)\n const recordedDecision = recordedDecisionId\n ? decisions.find((decision) => decision.id === recordedDecisionId) ?? null\n : null\n // A task nobody owns yet, offered to a role queue, is the one this operator\n // can take. An individually assigned task is already theirs to finish.\n //\n // Kept ONLY as the compatibility fallback below \u2014 it is the pre-change\n // behaviour, restored verbatim when the server sends no `canClaim`.\n const legacyClaimable =\n task.status === 'PENDING' &&\n !task.assignedTo &&\n !task.claimedBy &&\n (task.assignedToRoles?.length ?? 0) > 0\n\n /*\n * The server decides; the page renders. `??` is the additive-compatibility\n * fallback for a payload written before these fields existed\n * (BACKWARD_COMPATIBILITY.md \u00A77) \u2014 it restores exactly the pre-change\n * behaviour and is never a second copy of the \u00A76.4 rule. Release and reassign\n * are new affordances with no legacy behaviour to preserve, so an old payload\n * simply does not offer them.\n */\n const canComplete = task.canComplete ?? isCompletable\n const canClaim = task.canClaim ?? legacyClaimable\n const canRelease = task.canRelease ?? false\n const canReassign = task.canReassign ?? false\n const blockDescriptor = canComplete\n ? null\n : describeTaskActionBlock(task.actBlockedReason ?? 'not-workable')\n\n if (isMobile) {\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-4\">\n <FormHeader\n mode=\"detail\"\n backHref={WORK_INBOX_HREF}\n backLabel={t('workflows.tasks.backToList', 'Back to tasks')}\n />\n {blockDescriptor ? (\n <TaskActionNotice\n descriptor={blockDescriptor}\n canReassign={canReassign}\n disabled={submitting}\n onReassign={() => setReassignOpen(true)}\n />\n ) : null}\n <MobileTaskForm\n task={task}\n formData={formData}\n comments={comments}\n submitting={submitting}\n isCompletable={canComplete}\n isOverdue={isOverdue}\n onFieldChange={handleFieldChange}\n onCommentsChange={setComments}\n onSubmit={handleSubmit}\n onCancel={() => router.push(WORK_INBOX_HREF)}\n getStatusBadgeClass={getStatusBadgeClass}\n decisions={decisions}\n onDecision={(decisionId) => void completeTask(decisionId)}\n />\n </div>\n <ReassignTaskDialog\n open={reassignOpen}\n submitting={submitting}\n onOpenChange={setReassignOpen}\n onSubmit={(target) => void handleReassign(target)}\n />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <FormHeader\n mode=\"detail\"\n backHref={WORK_INBOX_HREF}\n backLabel={t('workflows.tasks.backToList', 'Back to tasks')}\n entityTypeLabel={t('workflows.tasks.detail.type', 'User task')}\n title={task.taskName}\n subtitle={task.description || undefined}\n statusBadge={\n <span className=\"inline-flex items-center gap-2\">\n <StatusChip\n descriptor={statusDescriptor}\n label={t(`workflows.tasks.statuses.${task.status}`, task.status)}\n />\n {priorityDescriptor && priority ? (\n <StatusChip\n descriptor={priorityDescriptor}\n label={t(`workflows.workInbox.priorities.${priority}`, priority)}\n />\n ) : null}\n {isOverdue ? (\n <StatusChip\n descriptor={WORK_INBOX_OVERDUE_TONE}\n label={t('workflows.tasks.overdue')}\n />\n ) : null}\n </span>\n }\n />\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Left \u2014 instructions, form, decisions */}\n <div className=\"space-y-6 lg:col-span-2\">\n {isOverdue ? (\n <div className=\"bg-status-error-bg border border-status-error-border rounded-lg p-3\">\n <p className=\"text-sm text-status-error-text font-medium\">\n {t('workflows.tasks.detail.overdueWarning')}\n </p>\n </div>\n ) : null}\n\n {task.description ? (\n <div className=\"rounded-lg border border-border p-4\">\n <h2 className=\"text-sm font-semibold mb-2\">\n {t('workflows.tasks.detail.sections.instructions')}\n </h2>\n <p className=\"text-sm text-muted-foreground whitespace-pre-wrap\">{task.description}</p>\n </div>\n ) : null}\n\n {/*\n Where a module that OWNS the thing a task is about renders it in\n its own vocabulary. The agent orchestrator mounts the proposal\n draft card here (spec \u00A77.6): this page can only walk a task's\n `formSchema` generically, and a proposal rendered that way is a\n key/value dump of the mutation an operator is being asked to\n approve. Additive \u2014 no widget, nothing renders.\n */}\n <InjectionSpot spotId={TASK_DETAIL_INJECTION_SPOT_ID} context={taskInjectionContext} />\n\n {canClaim ? (\n <div className=\"rounded-lg border border-border bg-muted/50 p-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.detail.claimPrompt')}\n </p>\n <Button\n type=\"button\"\n data-testid=\"task-claim\"\n disabled={submitting}\n onClick={() => void handleClaim()}\n >\n {t('workflows.tasks.actions.claim')}\n </Button>\n </div>\n ) : null}\n\n {canRelease ? (\n <div className=\"rounded-lg border border-border bg-muted/50 p-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.detail.releasePrompt')}\n </p>\n <Button\n type=\"button\"\n variant=\"outline\"\n data-testid=\"task-release\"\n disabled={submitting}\n onClick={() => void handleRelease()}\n >\n {t('workflows.tasks.actions.unclaim')}\n </Button>\n </div>\n ) : null}\n\n {blockDescriptor ? (\n <TaskActionNotice\n descriptor={blockDescriptor}\n canReassign={canReassign}\n disabled={submitting}\n onReassign={() => setReassignOpen(true)}\n />\n ) : null}\n\n {/*\n Offered even when the task IS completable: an administrator may\n legitimately hand a row to somebody else, and the endpoint gates\n on visibility rather than ownership precisely so it can.\n */}\n {canComplete && canReassign ? (\n <div className=\"flex justify-end\">\n <Button\n type=\"button\"\n variant=\"outline\"\n data-testid=\"task-reassign\"\n disabled={submitting}\n onClick={() => setReassignOpen(true)}\n >\n {t('workflows.tasks.actions.reassign')}\n </Button>\n </div>\n ) : null}\n\n {canComplete ? (\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <TaskFormFields\n formSchema={task.formSchema}\n values={formData}\n invalidField={invalidField}\n disabled={submitting}\n onFieldChange={handleFieldChange}\n formKey={task.formKey}\n taskId={task.id}\n taskName={task.taskName}\n entityBindings={task.entityBindings}\n decisions={decisions}\n onValuesChange={setFormData}\n />\n\n <Separator />\n\n <div className=\"space-y-2\">\n <label htmlFor=\"comments\" className=\"block text-sm font-medium text-foreground\">\n {t('workflows.tasks.detail.comments')} ({t('workflows.tasks.detail.optional')})\n </label>\n <textarea\n id=\"comments\"\n value={comments}\n onChange={(e) => setComments(e.target.value)}\n rows={3}\n className=\"w-full px-3 py-2 border border-border rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n placeholder={t('workflows.tasks.detail.commentsPlaceholder')}\n />\n </div>\n\n {decisions.length > 0 ? (\n <div className=\"space-y-3\" data-testid=\"task-decisions\">\n <h2 className=\"text-sm font-semibold\">\n {t('workflows.tasks.detail.sections.decisions')}\n </h2>\n <div className=\"flex flex-col gap-3 sm:flex-row sm:flex-wrap\">\n {decisions.map((decision) => (\n <Button\n key={decision.id}\n type=\"button\"\n data-testid={`task-decision-${decision.id}`}\n variant={decisionButtonVariant(decision.style)}\n disabled={submitting}\n onClick={() => void completeTask(decision.id)}\n className=\"w-full sm:w-auto\"\n >\n {flattenTaskText(decision.label) ?? decision.id}\n </Button>\n ))}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-3 pt-4 sm:flex-row sm:items-center\">\n <Button type=\"submit\" data-testid=\"task-complete\" disabled={submitting} className=\"w-full sm:w-auto\">\n {submitting\n ? t('workflows.tasks.detail.submitting')\n : t('workflows.tasks.detail.completeTask')}\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => router.push(WORK_INBOX_HREF)}\n disabled={submitting}\n className=\"w-full sm:w-auto\"\n >\n {t('common.cancel')}\n </Button>\n </div>\n )}\n </form>\n ) : null}\n\n {task.status === 'COMPLETED' ? (\n <div className=\"space-y-4\">\n {recordedDecisionId ? (\n <div className=\"rounded-lg border border-border p-4\">\n <p className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.detail.decisionTaken')}:{' '}\n <span className=\"text-foreground font-medium\">\n {recordedDecision\n ? flattenTaskText(recordedDecision.label) ?? recordedDecisionId\n : recordedDecisionId}\n </span>\n </p>\n </div>\n ) : null}\n\n {task.formData ? (\n <JsonDisplay\n data={task.formData}\n title={t('workflows.tasks.detail.sections.submittedData')}\n maxInitialDepth={2}\n />\n ) : null}\n\n {task.comments ? (\n <div className=\"bg-muted/50 rounded-lg p-4\">\n <p className=\"text-sm font-medium text-foreground mb-2\">\n {t('workflows.tasks.detail.comments')}:\n </p>\n <p className=\"text-sm text-muted-foreground whitespace-pre-wrap\">{task.comments}</p>\n </div>\n ) : null}\n\n {/* Spec \u00A76.2: keep frontline flow going with one click. */}\n <div className=\"rounded-lg border border-border bg-muted/50 p-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <p className=\"text-sm text-muted-foreground\">\n {t('workflows.tasks.detail.nextTaskPrompt')}\n </p>\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n data-testid=\"task-next\"\n disabled={submitting}\n onClick={() => void handleNextTask()}\n >\n {t('workflows.workInbox.actions.claimNext')}\n </Button>\n <Button asChild variant=\"outline\">\n <Link href={WORK_INBOX_HREF}>{t('workflows.tasks.detail.backToList')}</Link>\n </Button>\n </div>\n </div>\n </div>\n ) : null}\n </div>\n\n {/* Right \u2014 the records this task is about, plus how it got here */}\n <div className=\"space-y-4\">\n <EntityContextPanel\n testId=\"task-context-records\"\n title={t('workflows.tasks.detail.sections.records')}\n items={contextItems}\n emptyLabel={t('workflows.tasks.detail.records.empty')}\n linkLabel={t('workflows.tasks.detail.records.open')}\n />\n\n <div className=\"rounded-lg border border-border p-4 space-y-2\">\n <h2 className=\"text-sm font-semibold\">\n {t('workflows.tasks.detail.sections.taskInfo')}\n </h2>\n <div className=\"space-y-1 text-sm\">\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.fields.createdAt')}:</span>\n <span className=\"ml-2 text-foreground\">{new Date(task.createdAt).toLocaleString()}</span>\n </div>\n {task.dueDate ? (\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.fields.dueDate')}:</span>\n <span\n className={`ml-2 ${isOverdue ? `${WORK_INBOX_OVERDUE_TONE.text} font-medium` : 'text-foreground'}`}\n >\n {new Date(task.dueDate).toLocaleString()}\n </span>\n </div>\n ) : null}\n {task.assignedTo ? (\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.detail.assignedTo')}:</span>\n <span className=\"ml-2 text-foreground\">{task.assignedTo}</span>\n </div>\n ) : null}\n {task.assignedToRoles?.length ? (\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.roles')}:</span>\n <span className=\"ml-2 text-foreground\">{task.assignedToRoles.join(', ')}</span>\n </div>\n ) : null}\n {task.claimedBy ? (\n <div>\n <span className=\"text-muted-foreground\">{t('workflows.tasks.claimedBy')}:</span>\n <span className=\"ml-2 text-foreground\">{task.claimedBy}</span>\n </div>\n ) : null}\n <div>\n <span className=\"text-muted-foreground\">\n {t('workflows.tasks.detail.workflowInstance')}:\n </span>\n <Link\n href={`/backend/instances/${task.workflowInstanceId}`}\n className=\"ml-2 text-primary hover:underline text-xs font-mono\"\n >\n {task.workflowInstanceId.slice(0, 8)}...\n </Link>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <ReassignTaskDialog\n open={reassignOpen}\n submitting={submitting}\n onOpenChange={setReassignOpen}\n onSubmit={(target) => void handleReassign(target)}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }