@hotmeshio/long-tail 0.10.2 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/build/api/bot-accounts.d.ts +4 -0
- package/build/api/bot-accounts.js +3 -1
- package/build/api/escalations/metadata.js +21 -1
- package/build/api/escalations/resolve.d.ts +8 -0
- package/build/api/escalations/resolve.js +82 -3
- package/build/api/roles.d.ts +2 -0
- package/build/api/roles.js +4 -0
- package/build/bin/ltc.js +10 -1
- package/build/index.js +7 -1
- package/build/lib/cli/client.d.ts +4 -1
- package/build/lib/cli/client.js +4 -2
- package/build/lib/db/schemas/023_role_enforce_schema.sql +18 -0
- package/build/lib/typed-resolution.d.ts +35 -0
- package/build/lib/typed-resolution.js +37 -0
- package/build/modules/branding.d.ts +21 -2
- package/build/modules/branding.js +22 -1
- package/build/modules/config.d.ts +1 -0
- package/build/modules/config.js +5 -0
- package/build/routes/bot-accounts.js +3 -1
- package/build/routes/settings.js +21 -0
- package/build/sdk/index.d.ts +4 -0
- package/build/sdk/index.js +14 -0
- package/build/services/escalation/crud.d.ts +18 -6
- package/build/services/escalation/crud.js +18 -2
- package/build/services/escalation/index.d.ts +1 -0
- package/build/services/escalation/index.js +1 -0
- package/build/services/escalation/resolver-validation.d.ts +28 -0
- package/build/services/escalation/resolver-validation.js +95 -0
- package/build/services/escalation/sql.d.ts +12 -2
- package/build/services/escalation/sql.js +22 -2
- package/build/services/iam/bots.d.ts +4 -1
- package/build/services/iam/bots.js +5 -3
- package/build/services/iam/sql.d.ts +2 -2
- package/build/services/iam/sql.js +15 -1
- package/build/services/role/enforcement-cache.d.ts +21 -0
- package/build/services/role/enforcement-cache.js +0 -0
- package/build/services/role/index.js +5 -0
- package/build/services/role/sql.d.ts +12 -2
- package/build/services/role/sql.js +15 -2
- package/build/services/role/types.d.ts +9 -0
- package/build/shared/form-validation/derive-field-label.d.ts +14 -0
- package/build/shared/form-validation/derive-field-label.js +31 -0
- package/build/shared/form-validation/field-validator.d.ts +45 -0
- package/build/shared/form-validation/field-validator.js +214 -0
- package/build/shared/form-validation/index.d.ts +12 -0
- package/build/shared/form-validation/index.js +28 -0
- package/build/shared/form-validation/validate-resolver-payload.d.ts +41 -0
- package/build/shared/form-validation/validate-resolver-payload.js +62 -0
- package/build/shared/form-validation/x-lt-bind.d.ts +41 -0
- package/build/shared/form-validation/x-lt-bind.js +110 -0
- package/build/shared/form-validation/x-lt-help.d.ts +21 -0
- package/build/shared/form-validation/x-lt-help.js +91 -0
- package/build/shared/form-validation/x-lt-show-if.d.ts +7 -0
- package/build/shared/form-validation/x-lt-show-if.js +84 -0
- package/build/system/mcp-servers/admin/schemas.d.ts +3 -0
- package/build/system/mcp-servers/admin/schemas.js +1 -0
- package/build/system/mcp-servers/admin/users.js +3 -1
- package/build/system/mcp-servers/human-queue-schemas.d.ts +4 -4
- package/build/system/mcp-servers/human-queue-schemas.js +4 -1
- package/build/system/mcp-servers/human-queue.js +41 -2
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/sdk.d.ts +6 -1
- package/build/types/startup.d.ts +26 -0
- package/build/types/validation.d.ts +43 -0
- package/build/types/validation.js +28 -0
- package/dashboard/dist/assets/{AdminDashboard-Dy031e9g.js → AdminDashboard-Cma2NGsF.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-Dy031e9g.js.map → AdminDashboard-Cma2NGsF.js.map} +1 -1
- package/dashboard/dist/assets/AgentConfigPage-CbIhM-fa.js +16 -0
- package/dashboard/dist/assets/AgentConfigPage-CbIhM-fa.js.map +1 -0
- package/dashboard/dist/assets/AgentDetailPage-DuLEKzRT.js +4 -0
- package/dashboard/dist/assets/AgentDetailPage-DuLEKzRT.js.map +1 -0
- package/dashboard/dist/assets/AgentsPage-DZO9i7Nl.js +2 -0
- package/dashboard/dist/assets/AgentsPage-DZO9i7Nl.js.map +1 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-DlVoNd8B.js +2 -0
- package/dashboard/dist/assets/AvailableEscalationsPage-DlVoNd8B.js.map +1 -0
- package/dashboard/dist/assets/{BotPicker-2QEIpc-K.js → BotPicker-CidlGr6f.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-2QEIpc-K.js.map → BotPicker-CidlGr6f.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-BMNNTa0D.js +2 -0
- package/dashboard/dist/assets/{CapabilitiesPage-lQJGZ_-t.js.map → CapabilitiesPage-BMNNTa0D.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-CHWP0WI6.js → CollapsibleSection-W9F9lziT.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-CHWP0WI6.js.map → CollapsibleSection-W9F9lziT.js.map} +1 -1
- package/dashboard/dist/assets/ConfirmDeleteModal-BUh-Dzba.js +2 -0
- package/dashboard/dist/assets/{ConfirmDeleteModal-C0x0HcHX.js.map → ConfirmDeleteModal-BUh-Dzba.js.map} +1 -1
- package/dashboard/dist/assets/{CopyableId-uot2mE_g.js → CopyableId-B1mxKfVb.js} +2 -2
- package/dashboard/dist/assets/{CopyableId-uot2mE_g.js.map → CopyableId-B1mxKfVb.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-lkv_7msa.js +2 -0
- package/dashboard/dist/assets/{CountdownTimer-TXsRlTU4.js.map → CountdownTimer-lkv_7msa.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-BKxS-1sA.js → CredentialsPage-DyOgfnPB.js} +2 -2
- package/dashboard/dist/assets/CredentialsPage-DyOgfnPB.js.map +1 -0
- package/dashboard/dist/assets/{CronLabel-Bd2G0Rap.js → CronLabel-geum95dj.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-Bd2G0Rap.js.map → CronLabel-geum95dj.js.map} +1 -1
- package/dashboard/dist/assets/CustomDurationPicker-ClufO2ew.js +2 -0
- package/dashboard/dist/assets/CustomDurationPicker-ClufO2ew.js.map +1 -0
- package/dashboard/dist/assets/DataTable-BTu2AaEl.js +2 -0
- package/dashboard/dist/assets/DataTable-BTu2AaEl.js.map +1 -0
- package/dashboard/dist/assets/{DropZone-DNDEgMpJ.js → DropZone-C3hOjJtC.js} +2 -2
- package/dashboard/dist/assets/{DropZone-DNDEgMpJ.js.map → DropZone-C3hOjJtC.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-g7GO7f8L.js → ElapsedCell-DFOW9T4b.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-g7GO7f8L.js.map → ElapsedCell-DFOW9T4b.js.map} +1 -1
- package/dashboard/dist/assets/EscalationListSchemaPage-_IhqXIQu.js +20 -0
- package/dashboard/dist/assets/EscalationListSchemaPage-_IhqXIQu.js.map +1 -0
- package/dashboard/dist/assets/EscalationSchemaPage-BCC7iscN.js +9 -0
- package/dashboard/dist/assets/EscalationSchemaPage-BCC7iscN.js.map +1 -0
- package/dashboard/dist/assets/EscalationsOverview-CvIdOtoP.js +2 -0
- package/dashboard/dist/assets/EscalationsOverview-CvIdOtoP.js.map +1 -0
- package/dashboard/dist/assets/EventTable-DJWJ7J0m.js +2 -0
- package/dashboard/dist/assets/EventTable-DJWJ7J0m.js.map +1 -0
- package/dashboard/dist/assets/FilterBar-BR3ztZ8y.js +2 -0
- package/dashboard/dist/assets/FilterBar-BR3ztZ8y.js.map +1 -0
- package/dashboard/dist/assets/GraphInvokePage-Cwn-8Glr.js +2 -0
- package/dashboard/dist/assets/GraphInvokePage-Cwn-8Glr.js.map +1 -0
- package/dashboard/dist/assets/HomePage-D8RVntg0.js +2 -0
- package/dashboard/dist/assets/HomePage-D8RVntg0.js.map +1 -0
- package/dashboard/dist/assets/ListToolbar-DuoEdVtK.js +2 -0
- package/dashboard/dist/assets/ListToolbar-DuoEdVtK.js.map +1 -0
- package/dashboard/dist/assets/McpOverview-NXKsGiWU.js +2 -0
- package/dashboard/dist/assets/McpOverview-NXKsGiWU.js.map +1 -0
- package/dashboard/dist/assets/McpQueryDetailPage-BC-iXfIx.js +5 -0
- package/dashboard/dist/assets/McpQueryDetailPage-BC-iXfIx.js.map +1 -0
- package/dashboard/dist/assets/{McpQueryPage-CsKNXUhb.js → McpQueryPage-BPJmFYOY.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-CsKNXUhb.js.map → McpQueryPage-BPJmFYOY.js.map} +1 -1
- package/dashboard/dist/assets/McpRunDetailPage-B49nUXEl.js +2 -0
- package/dashboard/dist/assets/McpRunDetailPage-B49nUXEl.js.map +1 -0
- package/dashboard/dist/assets/McpRunsPage-Ce_XIYpP.js +2 -0
- package/dashboard/dist/assets/McpRunsPage-Ce_XIYpP.js.map +1 -0
- package/dashboard/dist/assets/NamespacePill-LWvZXt_g.js +2 -0
- package/dashboard/dist/assets/NamespacePill-LWvZXt_g.js.map +1 -0
- package/dashboard/dist/assets/OperationsPage-DI7AQO9f.js +2 -0
- package/dashboard/dist/assets/OperationsPage-DI7AQO9f.js.map +1 -0
- package/dashboard/dist/assets/OperatorDashboard-DpXjhs-3.js +2 -0
- package/dashboard/dist/assets/{OperatorDashboard-_axS17fp.js.map → OperatorDashboard-DpXjhs-3.js.map} +1 -1
- package/dashboard/dist/assets/PageHeader-DvEmMMP6.js +2 -0
- package/dashboard/dist/assets/PageHeader-DvEmMMP6.js.map +1 -0
- package/dashboard/dist/assets/PageHeaderWithStats-X0eAmu-x.js +2 -0
- package/dashboard/dist/assets/PageHeaderWithStats-X0eAmu-x.js.map +1 -0
- package/dashboard/dist/assets/{PriorityBadge-B4ykBH7f.js → PriorityBadge-CCERr9vQ.js} +2 -2
- package/dashboard/dist/assets/PriorityBadge-CCERr9vQ.js.map +1 -0
- package/dashboard/dist/assets/ProcessDetailPage-DpYSMRj1.js +2 -0
- package/dashboard/dist/assets/ProcessDetailPage-DpYSMRj1.js.map +1 -0
- package/dashboard/dist/assets/{ProcessesListPage-CoQEi_Su.js → ProcessesListPage-CQ9tSw7U.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-CoQEi_Su.js.map → ProcessesListPage-CQ9tSw7U.js.map} +1 -1
- package/dashboard/dist/assets/RoleDetailPage-DKeQKDkW.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-DKeQKDkW.js.map +1 -0
- package/dashboard/dist/assets/RolePill-CWhoLwef.js +2 -0
- package/dashboard/dist/assets/RolePill-CWhoLwef.js.map +1 -0
- package/dashboard/dist/assets/RolesPage-D-6kIact.js +2 -0
- package/dashboard/dist/assets/RolesPage-D-6kIact.js.map +1 -0
- package/dashboard/dist/assets/RunAsSelector-DzYcpQTm.js +2 -0
- package/dashboard/dist/assets/RunAsSelector-DzYcpQTm.js.map +1 -0
- package/dashboard/dist/assets/StatCard-DBANWIss.js +2 -0
- package/dashboard/dist/assets/StatCard-DBANWIss.js.map +1 -0
- package/dashboard/dist/assets/StatusBadge-BbqghFMi.js +2 -0
- package/dashboard/dist/assets/StatusBadge-BbqghFMi.js.map +1 -0
- package/dashboard/dist/assets/{StickyPagination-Cd83AHd_.js → StickyPagination-BTGfmGV3.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-Cd83AHd_.js.map → StickyPagination-BTGfmGV3.js.map} +1 -1
- package/dashboard/dist/assets/StreamMessageDetail-DqRpzA_6.js +2 -0
- package/dashboard/dist/assets/StreamMessageDetail-DqRpzA_6.js.map +1 -0
- package/dashboard/dist/assets/SwimlaneTimeline-CA106TYo.js +2 -0
- package/dashboard/dist/assets/SwimlaneTimeline-CA106TYo.js.map +1 -0
- package/dashboard/dist/assets/TagInput-CoR4MzsW.js +2 -0
- package/dashboard/dist/assets/TagInput-CoR4MzsW.js.map +1 -0
- package/dashboard/dist/assets/{TaskDetailPage-DnjhW7qv.js → TaskDetailPage-BRg-w2Ev.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-DnjhW7qv.js.map → TaskDetailPage-BRg-w2Ev.js.map} +1 -1
- package/dashboard/dist/assets/TaskQueuePill-Dw3YN8M-.js +2 -0
- package/dashboard/dist/assets/TaskQueuePill-Dw3YN8M-.js.map +1 -0
- package/dashboard/dist/assets/{TasksListPage-DySfZFgs.js → TasksListPage-kB_j9G8o.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-DySfZFgs.js.map → TasksListPage-kB_j9G8o.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BKOl-7Tt.js → TimeAgo-D7dSIY7-.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BKOl-7Tt.js.map → TimeAgo-D7dSIY7-.js.map} +1 -1
- package/dashboard/dist/assets/TimestampCell-BZe6bx18.js +2 -0
- package/dashboard/dist/assets/TimestampCell-BZe6bx18.js.map +1 -0
- package/dashboard/dist/assets/ToolPill-xX-buQtY.js +2 -0
- package/dashboard/dist/assets/ToolPill-xX-buQtY.js.map +1 -0
- package/dashboard/dist/assets/ToolTestPanel-U3NaF_T_.js +2 -0
- package/dashboard/dist/assets/ToolTestPanel-U3NaF_T_.js.map +1 -0
- package/dashboard/dist/assets/TopicDetailPage-BpALvXP1.js +9 -0
- package/dashboard/dist/assets/TopicDetailPage-BpALvXP1.js.map +1 -0
- package/dashboard/dist/assets/TopicsPage-Cy3chaca.js +2 -0
- package/dashboard/dist/assets/{TopicsPage-5yW63ELl.js.map → TopicsPage-Cy3chaca.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-DcXhOSVm.js → UserName-VXM1oHMC.js} +2 -2
- package/dashboard/dist/assets/{UserName-DcXhOSVm.js.map → UserName-VXM1oHMC.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowExecutionPage-BCq2cR1V.js +2 -0
- package/dashboard/dist/assets/WorkflowExecutionPage-BCq2cR1V.js.map +1 -0
- package/dashboard/dist/assets/WorkflowPill-CQ1AmhlC.js +2 -0
- package/dashboard/dist/assets/WorkflowPill-CQ1AmhlC.js.map +1 -0
- package/dashboard/dist/assets/{WorkflowsDashboard-C0Bbrd5M.js → WorkflowsDashboard-BbM69MnB.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-C0Bbrd5M.js.map → WorkflowsDashboard-BbM69MnB.js.map} +1 -1
- package/dashboard/dist/assets/WorkflowsOverview-D5HthpAW.js +2 -0
- package/dashboard/dist/assets/WorkflowsOverview-D5HthpAW.js.map +1 -0
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BcbrYhDI.js → YamlWorkflowDetailPage-CDDVMYWi.js} +10 -10
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BcbrYhDI.js.map → YamlWorkflowDetailPage-CDDVMYWi.js.map} +1 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-FFjWwydj.js +2 -0
- package/dashboard/dist/assets/YamlWorkflowsPage-FFjWwydj.js.map +1 -0
- package/dashboard/dist/assets/{agents-CopQ3t5o.js → agents-BwiSNu73.js} +2 -2
- package/dashboard/dist/assets/{agents-CopQ3t5o.js.map → agents-BwiSNu73.js.map} +1 -1
- package/dashboard/dist/assets/bots-ClgSrxel.js +2 -0
- package/dashboard/dist/assets/bots-ClgSrxel.js.map +1 -0
- package/dashboard/dist/assets/{capabilities-5JRieYUy.js → capabilities-JUaKsby4.js} +2 -2
- package/dashboard/dist/assets/{capabilities-5JRieYUy.js.map → capabilities-JUaKsby4.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-B4rT6tIw.js → controlplane-CuTQ7eUE.js} +2 -2
- package/dashboard/dist/assets/{controlplane-B4rT6tIw.js.map → controlplane-CuTQ7eUE.js.map} +1 -1
- package/dashboard/dist/assets/escalation-columns-CS0c7cAr.js +2 -0
- package/dashboard/dist/assets/escalation-columns-CS0c7cAr.js.map +1 -0
- package/dashboard/dist/assets/index-BBA4AxmL.js +2 -0
- package/dashboard/dist/assets/index-BBA4AxmL.js.map +1 -0
- package/dashboard/dist/assets/index-C-8xXyvr.js +63 -0
- package/dashboard/dist/assets/index-C-8xXyvr.js.map +1 -0
- package/dashboard/dist/assets/index-C1t0YIXC.js +5 -0
- package/dashboard/dist/assets/index-C1t0YIXC.js.map +1 -0
- package/dashboard/dist/assets/index-C9o2UNhC.js +2 -0
- package/dashboard/dist/assets/index-C9o2UNhC.js.map +1 -0
- package/dashboard/dist/assets/index-CBj-vstO.js +2 -0
- package/dashboard/dist/assets/{index-Dd1RxGNw.js.map → index-CBj-vstO.js.map} +1 -1
- package/dashboard/dist/assets/index-CUguKMXZ.js +2 -0
- package/dashboard/dist/assets/index-CUguKMXZ.js.map +1 -0
- package/dashboard/dist/assets/index-Cavwd8UU.js +6 -0
- package/dashboard/dist/assets/index-Cavwd8UU.js.map +1 -0
- package/dashboard/dist/assets/index-CnsPBTXL.js +2 -0
- package/dashboard/dist/assets/index-CnsPBTXL.js.map +1 -0
- package/dashboard/dist/assets/index-CoPWHo_H.js +2 -0
- package/dashboard/dist/assets/index-CoPWHo_H.js.map +1 -0
- package/dashboard/dist/assets/index-CwQVaa7x.js +2 -0
- package/dashboard/dist/assets/index-CwQVaa7x.js.map +1 -0
- package/dashboard/dist/assets/index-DSa-6Ux8.js +2 -0
- package/dashboard/dist/assets/index-DSa-6Ux8.js.map +1 -0
- package/dashboard/dist/assets/index-DeMs_aBT.css +1 -0
- package/dashboard/dist/assets/index-Ikj_NTuy.js +5 -0
- package/dashboard/dist/assets/index-Ikj_NTuy.js.map +1 -0
- package/dashboard/dist/assets/index-Xd1jcHe7.js +2 -0
- package/dashboard/dist/assets/index-Xd1jcHe7.js.map +1 -0
- package/dashboard/dist/assets/{knowledge-B9bmoXOe.js → knowledge-BHBt-6kW.js} +2 -2
- package/dashboard/dist/assets/{knowledge-B9bmoXOe.js.map → knowledge-BHBt-6kW.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-DYMFBOFz.js → mcp-CBcz4BCS.js} +2 -2
- package/dashboard/dist/assets/{mcp-DYMFBOFz.js.map → mcp-CBcz4BCS.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-wloSpyPM.js → mcp-query-C4fKTOYo.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-wloSpyPM.js.map → mcp-query-C4fKTOYo.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-DBXX6TEi.js → pipelines-CmAAH3B6.js} +2 -2
- package/dashboard/dist/assets/{pipelines-DBXX6TEi.js.map → pipelines-CmAAH3B6.js.map} +1 -1
- package/dashboard/dist/assets/role-display-Dvo2lDpU.js +2 -0
- package/dashboard/dist/assets/role-display-Dvo2lDpU.js.map +1 -0
- package/dashboard/dist/assets/task-queues-7-sHKPsN.js +2 -0
- package/dashboard/dist/assets/task-queues-7-sHKPsN.js.map +1 -0
- package/dashboard/dist/assets/{tasks-CD3-C7tP.js → tasks-BAEsqcz2.js} +2 -2
- package/dashboard/dist/assets/{tasks-CD3-C7tP.js.map → tasks-BAEsqcz2.js.map} +1 -1
- package/dashboard/dist/assets/{topics-D8pKi6zA.js → topics-CY0pJ6_o.js} +2 -2
- package/dashboard/dist/assets/{topics-D8pKi6zA.js.map → topics-CY0pJ6_o.js.map} +1 -1
- package/dashboard/dist/assets/{useEventHooks-DV9pLDOW.js → useEventHooks-BlpwRvHO.js} +2 -2
- package/dashboard/dist/assets/{useEventHooks-DV9pLDOW.js.map → useEventHooks-BlpwRvHO.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-DykYhZY9.js → useNamespace-CoNUlZ6Z.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-DykYhZY9.js.map → useNamespace-CoNUlZ6Z.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-By044UAv.js → useYamlActivityEvents-8GUn5Wie.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-By044UAv.js.map → useYamlActivityEvents-8GUn5Wie.js.map} +1 -1
- package/dashboard/dist/assets/{users-mI9goDjj.js → users-uGtDRGxR.js} +2 -2
- package/dashboard/dist/assets/{users-mI9goDjj.js.map → users-uGtDRGxR.js.map} +1 -1
- package/dashboard/dist/assets/{vendor-icons-ihWGa7_d.js → vendor-icons-DKCAtTJ9.js} +135 -130
- package/dashboard/dist/assets/vendor-icons-DKCAtTJ9.js.map +1 -0
- package/dashboard/dist/assets/{workflows-DCUilz68.js → workflows-DoX-AtHN.js} +2 -2
- package/dashboard/dist/assets/{workflows-DCUilz68.js.map → workflows-DoX-AtHN.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-DWNMP1PT.js → yaml-workflows-DM3jVem2.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-DWNMP1PT.js.map → yaml-workflows-DM3jVem2.js.map} +1 -1
- package/dashboard/dist/index.html +3 -3
- package/docs/api/http/escalations.md +15 -1
- package/docs/api/http/roles.md +2 -0
- package/docs/design-principles.md +234 -0
- package/docs/hitl/design.md +228 -0
- package/docs/hitl/form.md +21 -1
- package/docs/hitl/iframe.md +1 -1
- package/docs/hitl/x-lt-display.md +56 -0
- package/docs/hitl/x-lt-layout.md +20 -1
- package/docs/hitl/x-lt-list-schema.md +8 -1
- package/docs/hitl/x-lt-widget.md +23 -0
- package/docs/hitl-guide.md +4 -2
- package/docs/schema-enforcement.md +149 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/AgentConfigPage-CqmtYBbC.js +0 -16
- package/dashboard/dist/assets/AgentConfigPage-CqmtYBbC.js.map +0 -1
- package/dashboard/dist/assets/AgentDetailPage-oYLBrN74.js +0 -4
- package/dashboard/dist/assets/AgentDetailPage-oYLBrN74.js.map +0 -1
- package/dashboard/dist/assets/AgentsPage-CHczRx5N.js +0 -2
- package/dashboard/dist/assets/AgentsPage-CHczRx5N.js.map +0 -1
- package/dashboard/dist/assets/AvailableEscalationsPage-DDVuivEE.js +0 -2
- package/dashboard/dist/assets/AvailableEscalationsPage-DDVuivEE.js.map +0 -1
- package/dashboard/dist/assets/CapabilitiesPage-lQJGZ_-t.js +0 -2
- package/dashboard/dist/assets/ConfirmDeleteModal-C0x0HcHX.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-TXsRlTU4.js +0 -2
- package/dashboard/dist/assets/CredentialsPage-BKxS-1sA.js.map +0 -1
- package/dashboard/dist/assets/CustomDurationPicker-j4bBrDJ6.js +0 -2
- package/dashboard/dist/assets/CustomDurationPicker-j4bBrDJ6.js.map +0 -1
- package/dashboard/dist/assets/DataTable-Byn3oyT9.js +0 -2
- package/dashboard/dist/assets/DataTable-Byn3oyT9.js.map +0 -1
- package/dashboard/dist/assets/EscalationListSchemaPage-CIJ-OgVC.js +0 -20
- package/dashboard/dist/assets/EscalationListSchemaPage-CIJ-OgVC.js.map +0 -1
- package/dashboard/dist/assets/EscalationSchemaPage-C7dHgG8e.js +0 -9
- package/dashboard/dist/assets/EscalationSchemaPage-C7dHgG8e.js.map +0 -1
- package/dashboard/dist/assets/EscalationsOverview-D8NrATg2.js +0 -2
- package/dashboard/dist/assets/EscalationsOverview-D8NrATg2.js.map +0 -1
- package/dashboard/dist/assets/EventTable-DBV1P2ME.js +0 -2
- package/dashboard/dist/assets/EventTable-DBV1P2ME.js.map +0 -1
- package/dashboard/dist/assets/FilterBar-B5Vk5tBF.js +0 -2
- package/dashboard/dist/assets/FilterBar-B5Vk5tBF.js.map +0 -1
- package/dashboard/dist/assets/GraphInvokePage-DbHvggQ_.js +0 -2
- package/dashboard/dist/assets/GraphInvokePage-DbHvggQ_.js.map +0 -1
- package/dashboard/dist/assets/HomePage-BpexnDO_.js +0 -2
- package/dashboard/dist/assets/HomePage-BpexnDO_.js.map +0 -1
- package/dashboard/dist/assets/ListToolbar-KC6LGtKP.js +0 -2
- package/dashboard/dist/assets/ListToolbar-KC6LGtKP.js.map +0 -1
- package/dashboard/dist/assets/McpOverview-BDZC9Hvl.js +0 -2
- package/dashboard/dist/assets/McpOverview-BDZC9Hvl.js.map +0 -1
- package/dashboard/dist/assets/McpQueryDetailPage-CXhgX1pS.js +0 -5
- package/dashboard/dist/assets/McpQueryDetailPage-CXhgX1pS.js.map +0 -1
- package/dashboard/dist/assets/McpRunDetailPage-BM3mUSlH.js +0 -2
- package/dashboard/dist/assets/McpRunDetailPage-BM3mUSlH.js.map +0 -1
- package/dashboard/dist/assets/McpRunsPage-f5hDbpLo.js +0 -2
- package/dashboard/dist/assets/McpRunsPage-f5hDbpLo.js.map +0 -1
- package/dashboard/dist/assets/NamespacePill-C4u6Go1W.js +0 -2
- package/dashboard/dist/assets/NamespacePill-C4u6Go1W.js.map +0 -1
- package/dashboard/dist/assets/OperationsPage-D37cZ8Qh.js +0 -2
- package/dashboard/dist/assets/OperationsPage-D37cZ8Qh.js.map +0 -1
- package/dashboard/dist/assets/OperatorDashboard-_axS17fp.js +0 -2
- package/dashboard/dist/assets/PageHeader-Bxa1XFz0.js +0 -2
- package/dashboard/dist/assets/PageHeader-Bxa1XFz0.js.map +0 -1
- package/dashboard/dist/assets/PageHeaderWithStats-D_sO0MqJ.js +0 -2
- package/dashboard/dist/assets/PageHeaderWithStats-D_sO0MqJ.js.map +0 -1
- package/dashboard/dist/assets/PriorityBadge-B4ykBH7f.js.map +0 -1
- package/dashboard/dist/assets/ProcessDetailPage-D8pAWUXx.js +0 -2
- package/dashboard/dist/assets/ProcessDetailPage-D8pAWUXx.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-ufbypNNR.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-ufbypNNR.js.map +0 -1
- package/dashboard/dist/assets/RolePill-DLwmVMam.js +0 -2
- package/dashboard/dist/assets/RolePill-DLwmVMam.js.map +0 -1
- package/dashboard/dist/assets/RolesPage-CxpXm4Sw.js +0 -2
- package/dashboard/dist/assets/RolesPage-CxpXm4Sw.js.map +0 -1
- package/dashboard/dist/assets/RunAsSelector-BebF8Lib.js +0 -2
- package/dashboard/dist/assets/RunAsSelector-BebF8Lib.js.map +0 -1
- package/dashboard/dist/assets/SlidePanel-BDVDuwIf.js +0 -2
- package/dashboard/dist/assets/SlidePanel-BDVDuwIf.js.map +0 -1
- package/dashboard/dist/assets/StatCard-DrdlUeQz.js +0 -2
- package/dashboard/dist/assets/StatCard-DrdlUeQz.js.map +0 -1
- package/dashboard/dist/assets/StatusBadge-CEQMRmSQ.js +0 -2
- package/dashboard/dist/assets/StatusBadge-CEQMRmSQ.js.map +0 -1
- package/dashboard/dist/assets/StreamMessageDetail-BIXbrZM0.js +0 -2
- package/dashboard/dist/assets/StreamMessageDetail-BIXbrZM0.js.map +0 -1
- package/dashboard/dist/assets/SwimlaneTimeline-CC5qZjYo.js +0 -2
- package/dashboard/dist/assets/SwimlaneTimeline-CC5qZjYo.js.map +0 -1
- package/dashboard/dist/assets/TagInput-C2gi47M8.js +0 -2
- package/dashboard/dist/assets/TagInput-C2gi47M8.js.map +0 -1
- package/dashboard/dist/assets/TaskQueuePill-BPP0Almh.js +0 -2
- package/dashboard/dist/assets/TaskQueuePill-BPP0Almh.js.map +0 -1
- package/dashboard/dist/assets/TimestampCell-DGOsba-A.js +0 -2
- package/dashboard/dist/assets/TimestampCell-DGOsba-A.js.map +0 -1
- package/dashboard/dist/assets/ToolPill-D74TkYB-.js +0 -2
- package/dashboard/dist/assets/ToolPill-D74TkYB-.js.map +0 -1
- package/dashboard/dist/assets/ToolTestPanel-Bez6OyRL.js +0 -2
- package/dashboard/dist/assets/ToolTestPanel-Bez6OyRL.js.map +0 -1
- package/dashboard/dist/assets/TopicDetailPage-BHccgkU_.js +0 -9
- package/dashboard/dist/assets/TopicDetailPage-BHccgkU_.js.map +0 -1
- package/dashboard/dist/assets/TopicsPage-5yW63ELl.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-CDDLled5.js +0 -2
- package/dashboard/dist/assets/WorkflowExecutionPage-CDDLled5.js.map +0 -1
- package/dashboard/dist/assets/WorkflowPill-Fjc2q9U9.js +0 -2
- package/dashboard/dist/assets/WorkflowPill-Fjc2q9U9.js.map +0 -1
- package/dashboard/dist/assets/WorkflowsOverview-D8MkSMex.js +0 -2
- package/dashboard/dist/assets/WorkflowsOverview-D8MkSMex.js.map +0 -1
- package/dashboard/dist/assets/YamlWorkflowsPage-9Ki54d-9.js +0 -2
- package/dashboard/dist/assets/YamlWorkflowsPage-9Ki54d-9.js.map +0 -1
- package/dashboard/dist/assets/bots-CAYJYL9E.js +0 -2
- package/dashboard/dist/assets/bots-CAYJYL9E.js.map +0 -1
- package/dashboard/dist/assets/escalation-columns-BbS5X61l.js +0 -2
- package/dashboard/dist/assets/escalation-columns-BbS5X61l.js.map +0 -1
- package/dashboard/dist/assets/index-B68A3v-S.js +0 -2
- package/dashboard/dist/assets/index-B68A3v-S.js.map +0 -1
- package/dashboard/dist/assets/index-BAi89Xpm.js +0 -2
- package/dashboard/dist/assets/index-BAi89Xpm.js.map +0 -1
- package/dashboard/dist/assets/index-BJ0jjFsI.js +0 -5
- package/dashboard/dist/assets/index-BJ0jjFsI.js.map +0 -1
- package/dashboard/dist/assets/index-BOJMUk4F.js +0 -2
- package/dashboard/dist/assets/index-BOJMUk4F.js.map +0 -1
- package/dashboard/dist/assets/index-BrgYykPV.js +0 -2
- package/dashboard/dist/assets/index-BrgYykPV.js.map +0 -1
- package/dashboard/dist/assets/index-BxgtIqvl.js +0 -2
- package/dashboard/dist/assets/index-BxgtIqvl.js.map +0 -1
- package/dashboard/dist/assets/index-C0cHXaX-.css +0 -1
- package/dashboard/dist/assets/index-CDHDoHYz.js +0 -6
- package/dashboard/dist/assets/index-CDHDoHYz.js.map +0 -1
- package/dashboard/dist/assets/index-CUZJHXew.js +0 -2
- package/dashboard/dist/assets/index-CUZJHXew.js.map +0 -1
- package/dashboard/dist/assets/index-D5n_e59T.js +0 -2
- package/dashboard/dist/assets/index-D5n_e59T.js.map +0 -1
- package/dashboard/dist/assets/index-DIgiIoou.js +0 -63
- package/dashboard/dist/assets/index-DIgiIoou.js.map +0 -1
- package/dashboard/dist/assets/index-Dd1RxGNw.js +0 -2
- package/dashboard/dist/assets/index-iOb3sGsC.js +0 -5
- package/dashboard/dist/assets/index-iOb3sGsC.js.map +0 -1
- package/dashboard/dist/assets/index-mcAkQblr.js +0 -2
- package/dashboard/dist/assets/index-mcAkQblr.js.map +0 -1
- package/dashboard/dist/assets/vendor-icons-ihWGa7_d.js.map +0 -1
package/docs/api/http/roles.md
CHANGED
|
@@ -268,6 +268,7 @@ Returns all roles with metadata and usage counts.
|
|
|
268
268
|
| `metadata_schema` | `object \| null` | JSON Schema declaring the expected shape of `lt_escalations.metadata` for this role. Drives faceted-query key autocomplete and creation-time validation |
|
|
269
269
|
| `properties` | `object` | Free user-owned bag — icons, colors, tags, etc. No reserved keys |
|
|
270
270
|
| `ops_visible` | `boolean` | When `true`, the role appears as a station on the `/operations` view |
|
|
271
|
+
| `enforce_schema` | `boolean` | When `true`, every resolve surface validates submitted payloads against this role's form schema and rejects violations with `422` (`code: schema_validation`) — see [Schema Enforcement](../../schema-enforcement.md) |
|
|
271
272
|
| `parent_role` | `string \| null` | Parent role in the process dependency graph; `null` for root stations |
|
|
272
273
|
| `sla_minutes` | `number \| null` | Target resolution time in minutes (capacity setting) |
|
|
273
274
|
| `target_per_hour` | `number \| null` | Intended throughput — items resolved per hour (capacity setting) |
|
|
@@ -366,6 +367,7 @@ When the update changes `form_schema` or `metadata_schema`, the new pair is snap
|
|
|
366
367
|
| `metadata_schema` | `object \| null` | JSON Schema for `lt_escalations.metadata` |
|
|
367
368
|
| `properties` | `object \| null` | Free user-owned bag |
|
|
368
369
|
| `ops_visible` | `boolean` | Include in the `/operations` view |
|
|
370
|
+
| `enforce_schema` | `boolean` | Turn server-side resolver schema validation on/off |
|
|
369
371
|
| `parent_role` | `string \| null` | Parent in the process dependency graph |
|
|
370
372
|
| `sla_minutes` | `number \| null` | SLA target in minutes |
|
|
371
373
|
| `target_per_hour` | `number \| null` | Throughput target (items per hour) |
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Design Principles
|
|
2
|
+
|
|
3
|
+
The design system behind the dashboard and every generated x-lt-* form. One
|
|
4
|
+
token vocabulary, one value discipline, one form doctrine — the built-in pages
|
|
5
|
+
and the forms customers author render from the same rules.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Tokens are the system
|
|
10
|
+
|
|
11
|
+
Every color, size, radius, and spacing knob flows through a `--lt-*` CSS
|
|
12
|
+
variable declared in `dashboard/src/styles/globals.css`. Nothing paints a raw
|
|
13
|
+
hex. A registered stylesheet (`branding.customCss` / `branding.themes` in
|
|
14
|
+
`start()`) can therefore restyle the entire product — including full dark
|
|
15
|
+
themes — with zero source changes. Midnight is the standing proof: if a color
|
|
16
|
+
escapes the token system, it glows in the dark.
|
|
17
|
+
|
|
18
|
+
Deliberate exceptions, each carrying a stated constraint in code: the
|
|
19
|
+
signature pad (the exported PNG is a document — ink on white), customer
|
|
20
|
+
iframes (their HTML assumes a white canvas), OAuth brand marks, theme-picker
|
|
21
|
+
swatches, and overlay scrims.
|
|
22
|
+
|
|
23
|
+
## 2. Color — the value discipline
|
|
24
|
+
|
|
25
|
+
Chroma is spent, not spread.
|
|
26
|
+
|
|
27
|
+
- **Surfaces are near-neutral.** Hover fills, section bands, and borders
|
|
28
|
+
carry only a whisper of the theme hue. Chroma never lands on a large
|
|
29
|
+
rectangle — a colored slab makes every real accent invisible.
|
|
30
|
+
- **One elevation logic, both polarities.** The page carries the base wash
|
|
31
|
+
(a light theme tint by day, the deep shade at night); sections and sheets
|
|
32
|
+
are distinct surfaces on it (white paper by day, the deeper well at
|
|
33
|
+
night); fields are wells that step AWAY from their surface (darker than
|
|
34
|
+
white by day, lighter than the shade at night). Light is Midnight
|
|
35
|
+
inverted — never a flat white page with white sections.
|
|
36
|
+
- **The accent appears in small doses**: links, buttons, checks, pills,
|
|
37
|
+
section labels, focus states. Because it is scarce, it reads as "act here."
|
|
38
|
+
- **Dark themes are the same principle, inverted** — near-black neutral
|
|
39
|
+
surfaces, the identical accent discipline. Midnight is not a different
|
|
40
|
+
design; it is the same design at night.
|
|
41
|
+
- **Status is information, not decoration.** Text-safe status tokens
|
|
42
|
+
(≥4.5:1) for words; brighter `-graphic` variants for dots, bars, and
|
|
43
|
+
charts (≥3:1).
|
|
44
|
+
- **The focus fill is the one ambient accent moment** — entering a field
|
|
45
|
+
earns the tint.
|
|
46
|
+
|
|
47
|
+
## 3. Text — black speaks, color acts
|
|
48
|
+
|
|
49
|
+
- One neutral near-black ramp shared by every light theme: `#171717` body,
|
|
50
|
+
`#373737` labels, `#646464` helper, `#8C8C8C` low-emphasis meta. Labels are
|
|
51
|
+
never theme-colored — a tinted label is indistinguishable from a link.
|
|
52
|
+
If it's colored, it must be clickable.
|
|
53
|
+
- **11px floor.** No informative text below `text-2xs`. Quaternary tone is
|
|
54
|
+
reserved for large or decorative text (≥3:1).
|
|
55
|
+
- **Headings**: near-black (`#333333`), small caps, weight 300, generous
|
|
56
|
+
sizes — `heading-1` (2.125rem) / `heading-2` (1.5rem) / `heading-3`
|
|
57
|
+
(1.25rem). The size carries hierarchy; the light weight keeps it elegant.
|
|
58
|
+
Mono identifiers (role keys, workflow types, topics) stay code-styled,
|
|
59
|
+
never small-caps.
|
|
60
|
+
|
|
61
|
+
## 4. Fields and controls
|
|
62
|
+
|
|
63
|
+
- **One recipe** (`.field/.input/.select/.textarea`): white body, light
|
|
64
|
+
neutral border, 3px radius (`--lt-radius-field`), border deepens to accent
|
|
65
|
+
and fill takes the theme tint on focus. Every field-like control uses the
|
|
66
|
+
recipe or the tokens — no bespoke field styling.
|
|
67
|
+
- **Width follows content, capped by the measure:**
|
|
68
|
+
- Generated forms hold a readable measure (`max-w-form`, 56rem). A wide
|
|
69
|
+
monitor gets margin, never a 2000px input.
|
|
70
|
+
- Selects size to their content, floored at 16rem for presence — a
|
|
71
|
+
one-word choice never stretches across the page. The floor yields to
|
|
72
|
+
the cell (`min(16rem, 100%)`): CSS lets min-width beat max-width, so
|
|
73
|
+
a bare floor would overflow a narrow column.
|
|
74
|
+
- Number and date inputs hold a hand-sized width (12rem; datetimes
|
|
75
|
+
16rem) — fixed-length values never stretch to the measure.
|
|
76
|
+
- Text, textarea, email, and url fill their cell — prose-length content
|
|
77
|
+
deserves the measure.
|
|
78
|
+
- Widgets follow the same split. Prose surfaces (code editor, markdown,
|
|
79
|
+
rich text, uploads) fill the cell. The signature pad holds its natural
|
|
80
|
+
document proportion (25rem, the 400×150 export) — the PNG is the
|
|
81
|
+
artifact, and stretching the pad stretches the document.
|
|
82
|
+
- **Decisions are never checkboxes.** A decision is an enum opening on an
|
|
83
|
+
explicit disabled **Choose…** placeholder. The user picks; nothing is an
|
|
84
|
+
implicit first option, and there is no way back to unchosen.
|
|
85
|
+
- Checkboxes exist only inside checklists — confirmations of work, not
|
|
86
|
+
choices.
|
|
87
|
+
- **Item length and selection mode determine list geometry.**
|
|
88
|
+
Sentence-length require-all *rituals* read top-down, one per row — the
|
|
89
|
+
vertical stack is deliberate. Short pick-any *tags* (reasons, categories)
|
|
90
|
+
flow horizontally as selectable chips: thumb-sized pills that wrap,
|
|
91
|
+
selection in solid accent. Never stack six two-word items into six
|
|
92
|
+
full-width rows — endless y with an empty x is a dead layout.
|
|
93
|
+
- **Required is marked, everywhere.** Every required input — text, select,
|
|
94
|
+
number, upload, checkbox, or checkbox group — carries the red asterisk at
|
|
95
|
+
its label. A require-all checklist is required by definition and marked
|
|
96
|
+
like the rest. Required or optional is never a guess.
|
|
97
|
+
|
|
98
|
+
## 5. Layout — the canonical shell
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
┌──────────────── Header (full width) ────────────────┐
|
|
102
|
+
│ left nav │ main viewport │ right panel │
|
|
103
|
+
└──────────────── EventFeed (full width) ─────────────┘
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- Header and event-stream footer span the full width. The left nav and the
|
|
107
|
+
global right SlidePanel are flex siblings of the main viewport — content
|
|
108
|
+
narrows when either opens; nothing overlays it. Pages fill the right panel
|
|
109
|
+
via `useShellPanel()`. The DocsDrawer is the full-screen overlay for
|
|
110
|
+
markdown.
|
|
111
|
+
- iPad (768–1366) is the floor target: page padding clamps down, the sidebar
|
|
112
|
+
auto-collapses below 1024, nothing depends on hover alone.
|
|
113
|
+
- Structure comes from typography, whitespace, and divider lines — never
|
|
114
|
+
rounded-bordered cards, never gradient fades. Sections sit on a barely
|
|
115
|
+
sunken band with an accent left rule.
|
|
116
|
+
|
|
117
|
+
## 6. The form doctrine
|
|
118
|
+
|
|
119
|
+
The reference implementation is `examples/workflows/acme-stations` — mimic it.
|
|
120
|
+
|
|
121
|
+
1. **Facts first, as a dictionary.** Read-only work-item facts render as a dense
|
|
122
|
+
label/value spec sheet (`x-lt-display: "dictionary"`), not form rows.
|
|
123
|
+
2. **One explicit decision** gates the form. Until it is made the page shows
|
|
124
|
+
facts, the decision, nothing else — even sign-off waits.
|
|
125
|
+
3. **Linear reveals.** Each outcome fades in exactly the section it needs
|
|
126
|
+
(`x-lt-showIf` value matches). The enter animation makes the
|
|
127
|
+
cause-and-effect visible in time: click Reject, watch the report arrive.
|
|
128
|
+
4. **The left/right law.** Left and Right always render side by side, Left
|
|
129
|
+
first — as dictionary pairs (two-column dictionaries fill row by row, so
|
|
130
|
+
consecutive items share a row) and as inputs (`x-lt-column-group` pairs
|
|
131
|
+
them in one cell, the 2×2).
|
|
132
|
+
5. **Checklists**: standard confirmations may arrive pre-checked
|
|
133
|
+
(formDefaults) — the standard is the default and the resolver unchecks
|
|
134
|
+
what isn't true. The work item's own custom work arrives unchecked; those
|
|
135
|
+
clicks are the record. `x-lt-require-all` guards completion.
|
|
136
|
+
6. **Every input carries a `title` and one instructional `description`
|
|
137
|
+
line — no input goes without.** The anatomy is fixed and identical for
|
|
138
|
+
every input kind: label, instruction, control, in that order. The
|
|
139
|
+
anatomy is a declared column, never an accident of width — the label is
|
|
140
|
+
a block, so a narrow control (a number, a short select) can never ride
|
|
141
|
+
sideways beside it when the instruction line is absent. Inputs that
|
|
142
|
+
share a row carry instructions of similar length so their controls align
|
|
143
|
+
across the row; a bare input beside an instructed one is a consistency
|
|
144
|
+
defect, in both content and alignment. The WHY — reference tables,
|
|
145
|
+
consequences, vocabulary — lives in `x-lt-help` beside the form.
|
|
146
|
+
7. **Sign-off last.** A short audit note with a live counter.
|
|
147
|
+
8. Hidden conditional fields still submit their defaults; resolver contracts
|
|
148
|
+
treat empty as absent.
|
|
149
|
+
|
|
150
|
+
## 7. Copy — the economist tone
|
|
151
|
+
|
|
152
|
+
The escalation `description` is the detail page's title: a short noun
|
|
153
|
+
phrase naming the artifact — "Final QA — ACME-1042 · wgt-8127" —
|
|
154
|
+
never a sentence, never an instruction, never a status report.
|
|
155
|
+
|
|
156
|
+
Say what to do. Speak to the actor, in the imperative, always: "Pick Reject
|
|
157
|
+
to file a report" — never "Reject files a report." The system is never the
|
|
158
|
+
subject of an instruction, and passive voice never appears. One line per
|
|
159
|
+
instruction; consequences ride the same sentence ("Resolve — the widget moves
|
|
160
|
+
on to assembly"). Reference tables over paragraphs. Never preachy, never
|
|
161
|
+
motivational, never "you're the first human — do well." State what a thing is
|
|
162
|
+
and does, never what it lacks.
|
|
163
|
+
|
|
164
|
+
## 8. Motion
|
|
165
|
+
|
|
166
|
+
Motion explains causality; it never decorates. Reveals fade in tied to the
|
|
167
|
+
choice that caused them (200–300ms enter). Errors shake once and settle.
|
|
168
|
+
Panels slide as flex siblings so content reflows rather than being covered.
|
|
169
|
+
Nothing loops, nothing floats.
|
|
170
|
+
|
|
171
|
+
## 9. Accessibility floors
|
|
172
|
+
|
|
173
|
+
- Body and label text ≥4.5:1; large/meta text and graphics ≥3:1.
|
|
174
|
+
- Every input is label-associated; errors and helpers ride
|
|
175
|
+
`aria-describedby`; the errors panel click-focuses the field
|
|
176
|
+
(`data-field-key` is a contract).
|
|
177
|
+
- Disabled forms use `inert` — out of the tab order, not just grayed.
|
|
178
|
+
- `color-scheme` follows the theme so native controls match the surface.
|
|
179
|
+
|
|
180
|
+
## 10. Responsive — geometry follows the container
|
|
181
|
+
|
|
182
|
+
1. **Geometry follows the container, not the viewport.** Side panels, the
|
|
183
|
+
facet drawer, and the nav rail narrow containers below any viewport
|
|
184
|
+
breakpoint — a `md:`/`lg:` variant on a content grid is a defect.
|
|
185
|
+
Viewport variants are lawful only in the shell frame (header, nav rail),
|
|
186
|
+
where the viewport is the container.
|
|
187
|
+
2. **Thresholds are named container tokens** (tailwind `containers`):
|
|
188
|
+
`@dict-inline` 22rem · `@grp-cols` 26rem · `@form-cols` 34rem ·
|
|
189
|
+
`@filters` 72rem · `@dict-pairs` 38rem · `@table` 48rem. Components use
|
|
190
|
+
the names, never raw rem values. A fold threshold is sized for the
|
|
191
|
+
HEAVIEST content its component carries — escaping to the condensed
|
|
192
|
+
format early beats ever letting a bar wrap.
|
|
193
|
+
3. **The dictionary reflow ladder** — the poster child. The same
|
|
194
|
+
label/value pairs render as: two pairs per row at `@dict-pairs`; one
|
|
195
|
+
label|value pair per row at `@dict-inline`; label stacked over value
|
|
196
|
+
below. Pairing order never changes across geometries.
|
|
197
|
+
4. **A table row IS a dictionary.** Below `@table`, tables fold into dense
|
|
198
|
+
console-style cards — identity columns become the title line, the rest
|
|
199
|
+
fold into label/value pairs on the dictionary ladder. **Tables never
|
|
200
|
+
scroll horizontally** — master lists use `layout="fixed"` so a table
|
|
201
|
+
physically cannot outgrow its container. Fixed columns cut both ways:
|
|
202
|
+
**cell content never bleeds into a neighbor** — every cell clips
|
|
203
|
+
(`overflow-hidden` on the `td`) and every text-bearing pill or label
|
|
204
|
+
truncates with an ellipsis (`max-w-full` + `truncate`), carrying the
|
|
205
|
+
full value in `title` for hover reveal.
|
|
206
|
+
5. **The column budget, disclosed both ways.** The floor set — identity,
|
|
207
|
+
owner, urgency, age — always renders. Enrichment columns (workflow,
|
|
208
|
+
metadata facets) return only when the table's container has room
|
|
209
|
+
(`showFrom: '@split' | '@wall'`); below that they fold into card pairs.
|
|
210
|
+
The list is a jumping-off spot: the metadata cell carries the refine
|
|
211
|
+
icons — filter within the role, search across roles, shift+click to AND
|
|
212
|
+
facets — the ELK-style drill the whole product surfaces.
|
|
213
|
+
6. **Refine icons are always visible enough to tap** — half-opacity at
|
|
214
|
+
rest, full on hover. Hover-only affordances do not exist on the floor.
|
|
215
|
+
7. **Disclosure order**: drop priority-3 columns, fold priority-2 into
|
|
216
|
+
pairs, keep priority-1 always.
|
|
217
|
+
8. **Touch parity**: every hover-only affordance has a tap equivalent —
|
|
218
|
+
the iPad floor has no hover.
|
|
219
|
+
9. **The header diet ladder** (below lg): mark-only logo, icon+count links,
|
|
220
|
+
secondary actions fold into the user menu, the nav rail becomes a
|
|
221
|
+
drawer behind a menu button.
|
|
222
|
+
10. **Sticky elements are never containers** — `container-type` breaks
|
|
223
|
+
`position: sticky` on the same element; wrap the geometry element
|
|
224
|
+
instead.
|
|
225
|
+
|
|
226
|
+
## 11. Never
|
|
227
|
+
|
|
228
|
+
Raw hex in components. Chroma on large surfaces. Theme-colored labels.
|
|
229
|
+
Text below 11px. Decisions as checkboxes. Implicit select defaults.
|
|
230
|
+
Full-width one-word inputs. Tag lists stacked as rows. Unmarked required
|
|
231
|
+
fields. Inputs without instruction lines. Passive voice or system-voice
|
|
232
|
+
copy. Horizontal scroll. Viewport breakpoints on content grids. Cards and
|
|
233
|
+
gradient fades. "Back to X" links. Polling. Preachy copy. Customer names —
|
|
234
|
+
the showcase brand is always Acme.
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Design
|
|
2
|
+
|
|
3
|
+
Long-tail ships one design system. The built-in pages and every form generated
|
|
4
|
+
from your schemas render from the same rules, so a form you author with plain
|
|
5
|
+
JSON Schema and `x-lt-*` tokens arrives already styled, responsive, accessible,
|
|
6
|
+
and themed. This page explains the principles in the terms that matter when you
|
|
7
|
+
author schemas and copy, the rules the renderer applies to errors, and how a
|
|
8
|
+
deployment plugs its own stylesheet in through static config.
|
|
9
|
+
|
|
10
|
+
The full internal doctrine lives in
|
|
11
|
+
[`docs/design-principles.md`](../design-principles.md); the reference form
|
|
12
|
+
implementation is `examples/workflows/acme-stations`.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## The principles, from the author's seat
|
|
17
|
+
|
|
18
|
+
### Tokens carry everything
|
|
19
|
+
|
|
20
|
+
Every color, size, radius, and spacing value in the product flows through a
|
|
21
|
+
`--lt-*` CSS variable. Your schemas never mention style — they declare
|
|
22
|
+
structure (`title`, `description`, sections, `x-lt-*` tokens) and the renderer
|
|
23
|
+
supplies the design. This is what makes theming total: a registered stylesheet
|
|
24
|
+
restyles the dashboard and your generated forms in one stroke, including full
|
|
25
|
+
dark themes.
|
|
26
|
+
|
|
27
|
+
### Color means "act here"
|
|
28
|
+
|
|
29
|
+
Surfaces stay near-neutral with a whisper of the theme hue; the saturated
|
|
30
|
+
accent appears only in small doses — links, buttons, checks, focus states.
|
|
31
|
+
Because color is scarce, anything colored reads as actionable. The same rule
|
|
32
|
+
governs your content: labels and copy render near-black, status renders through
|
|
33
|
+
the status tokens, and the accent marks the interactive. A form that "adds
|
|
34
|
+
color" through its copy fights the system; a form that relies on structure gets
|
|
35
|
+
the emphasis for free.
|
|
36
|
+
|
|
37
|
+
### Text: black speaks, color acts
|
|
38
|
+
|
|
39
|
+
Labels resolve from your schema (`title` first, then title-cased keys — see
|
|
40
|
+
[form.md](form.md)) and render in the neutral near-black ramp. Headings are
|
|
41
|
+
small-caps, light-weight, generously sized; section names you declare in
|
|
42
|
+
`x-lt-section-options` render in that voice. Nothing informative renders below
|
|
43
|
+
11px.
|
|
44
|
+
|
|
45
|
+
### Fields behave by declaration
|
|
46
|
+
|
|
47
|
+
- **Width follows content.** Forms hold a readable measure; selects size to
|
|
48
|
+
their options; numbers stay hand-sized; prose fields fill their cell. You
|
|
49
|
+
never set widths.
|
|
50
|
+
- **Decisions are enums.** A decision field renders as a select opening on an
|
|
51
|
+
explicit disabled **Choose…** placeholder — the resolver picks; nothing is
|
|
52
|
+
an implicit default. Model decisions as `enum`, never as booleans.
|
|
53
|
+
- **Checkboxes are confirmations of work**, and they live in checklists.
|
|
54
|
+
Sentence-length require-all rituals render one per row; short pick-any tags
|
|
55
|
+
(reasons, categories) flow as selectable chips. The renderer chooses from
|
|
56
|
+
your item lengths and `x-lt-require-all`; override with `x-lt-variant`.
|
|
57
|
+
- **Required is marked everywhere.** Every field in `required` — and every
|
|
58
|
+
require-all checklist — carries the red asterisk. Declare `required`
|
|
59
|
+
honestly and the form communicates it uniformly.
|
|
60
|
+
|
|
61
|
+
### The form doctrine
|
|
62
|
+
|
|
63
|
+
The shape that makes a resolver fast:
|
|
64
|
+
|
|
65
|
+
1. **Facts first, as a dictionary** — read-only work-item facts render as a dense
|
|
66
|
+
spec sheet (`x-lt-display: "dictionary"`), not as form rows.
|
|
67
|
+
2. **One explicit decision gates the form** — until the outcome is chosen,
|
|
68
|
+
the page shows facts and the decision, nothing else.
|
|
69
|
+
3. **Linear reveals** — each outcome fades in exactly the section it needs
|
|
70
|
+
(`x-lt-showIf`), so cause and effect are visible in time.
|
|
71
|
+
4. **Pairs render side by side** — `x-lt-column-group` keeps Left and Right
|
|
72
|
+
together; two-column dictionaries fill row by row.
|
|
73
|
+
5. **Sign-off last** — a short audit note closes the form.
|
|
74
|
+
|
|
75
|
+
### Responsive comes free
|
|
76
|
+
|
|
77
|
+
Geometry follows the container, not the viewport. Your dictionary reflows from
|
|
78
|
+
paired columns to stacked labels as space narrows; tables fold into dense
|
|
79
|
+
console cards instead of ever scrolling horizontally; the form grid drops to
|
|
80
|
+
one column when a side panel narrows it. Authors declare structure once; every
|
|
81
|
+
width from an iPad to a wall monitor is handled.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Error display
|
|
86
|
+
|
|
87
|
+
Errors follow fixed rules; your schema and copy determine only their content.
|
|
88
|
+
|
|
89
|
+
**At the field.** The first failing check on a visible field renders inline:
|
|
90
|
+
the control's border turns to the status-error token, the field shakes once and
|
|
91
|
+
settles, and the message appears beneath the control. Format guards fire on
|
|
92
|
+
blur; everything else fires on submit. The message rides `aria-describedby`,
|
|
93
|
+
so screen readers announce it with the field.
|
|
94
|
+
|
|
95
|
+
**The errors panel.** A blocked submit opens the right-side panel with the
|
|
96
|
+
full list — one row per issue, showing the field's label (derived exactly as
|
|
97
|
+
the form derives it, so `title` pays off here too) and the message. Clicking a
|
|
98
|
+
row scrolls to and focuses the field. The panel is `aria-live`; the count
|
|
99
|
+
("3 issues to resolve") updates as fixes land.
|
|
100
|
+
|
|
101
|
+
**Server enforcement, same surfaces.** Roles with schema enforcement enabled
|
|
102
|
+
validate the submission server-side and reject invalid payloads with a
|
|
103
|
+
canonical `422` carrying per-field errors. The form maps those onto the same
|
|
104
|
+
inline and panel surfaces — a resolver sees one error language whether the
|
|
105
|
+
check ran in the browser or on the server.
|
|
106
|
+
|
|
107
|
+
**Hidden fields are exempt.** Fields hidden by `x-lt-showIf` at submission
|
|
108
|
+
time are skipped by required validation — an unchosen branch never blocks the
|
|
109
|
+
chosen one.
|
|
110
|
+
|
|
111
|
+
**Error copy is instruction.** An error message states the fix, in the
|
|
112
|
+
imperative, in one line: "Enter a quantity between 1 and 4." It names what to
|
|
113
|
+
do next, never narrates what went wrong at length, and never speaks as the
|
|
114
|
+
system ("invalid input detected"). When you supply custom validation messages,
|
|
115
|
+
write them as the direct instruction the resolver should follow.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Recommendations — write instructions that work
|
|
120
|
+
|
|
121
|
+
The renderer guarantees the anatomy: label, one instruction line, control, in
|
|
122
|
+
that order, for every input. Your job is the words. The tone is a sparse
|
|
123
|
+
economist: say what to do, to the actor, and stop.
|
|
124
|
+
|
|
125
|
+
| Write | In place of |
|
|
126
|
+
|-------|-------------|
|
|
127
|
+
| Pick Reject to file a report | Reject files a report |
|
|
128
|
+
| Confirm each custom item on the widget | Items should be confirmed |
|
|
129
|
+
| Enter the count from the work ticket | Quantity field |
|
|
130
|
+
| Resolve — the widget moves on to final QA | When resolved, the widget will be moved on |
|
|
131
|
+
|
|
132
|
+
- **Every input carries a `title` and one `description` line.** The
|
|
133
|
+
description is the instruction: imperative, actor-addressed, one line.
|
|
134
|
+
Inputs sharing a row should carry instructions of similar length so their
|
|
135
|
+
controls align.
|
|
136
|
+
- **Consequences ride the same sentence.** "Pick Complete to send the widget
|
|
137
|
+
to final QA" tells the actor what to do and what happens, in one
|
|
138
|
+
breath. A second sentence is almost always the start of a paragraph nobody
|
|
139
|
+
reads.
|
|
140
|
+
- **The escalation `description` is a title, not a sentence.** It names the
|
|
141
|
+
artifact — "Addons — ACME-1042 · wgt-8127" — because it becomes the detail
|
|
142
|
+
page's heading and the list's summary line.
|
|
143
|
+
- **The WHY lives in `x-lt-help`.** Reference tables, vocabulary, and
|
|
144
|
+
decision consequences belong in the side panel, in markdown, where the
|
|
145
|
+
resolver can consult them without the form carrying paragraphs. Keep it
|
|
146
|
+
factual; skip the motivation.
|
|
147
|
+
- **Let defaults do the routine work.** Standard confirmations arrive
|
|
148
|
+
pre-checked via `formDefaults` — the resolver unchecks what isn't true.
|
|
149
|
+
The work item's own custom items arrive unchecked; those clicks are the record.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Plugging in a stylesheet
|
|
154
|
+
|
|
155
|
+
A deployment takes control of the design system through the `branding` block
|
|
156
|
+
of the static start config. `customCss` is appended to the dashboard
|
|
157
|
+
stylesheet; `themes` registers full themes that join the header theme picker
|
|
158
|
+
alongside the built-ins. Both are served at `GET /api/settings/custom.css` and
|
|
159
|
+
load before first paint.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { start } from 'long-tail';
|
|
163
|
+
|
|
164
|
+
await start({
|
|
165
|
+
// ...database, workers, roles...
|
|
166
|
+
branding: {
|
|
167
|
+
appName: 'AcmeAdmin',
|
|
168
|
+
|
|
169
|
+
// Targeted overrides — adjust tokens globally.
|
|
170
|
+
customCss: `
|
|
171
|
+
:root {
|
|
172
|
+
--lt-radius-field: 6px;
|
|
173
|
+
--lt-measure-form: 48rem;
|
|
174
|
+
}
|
|
175
|
+
`,
|
|
176
|
+
|
|
177
|
+
// A full registered theme. Author every --lt-* token under the
|
|
178
|
+
// [data-theme] selector; the id becomes the data-theme attribute and
|
|
179
|
+
// the theme appears in the header picker with its swatch.
|
|
180
|
+
themes: [
|
|
181
|
+
{
|
|
182
|
+
id: 'acme-slate',
|
|
183
|
+
label: 'Acme Slate',
|
|
184
|
+
swatch: '#334155',
|
|
185
|
+
dark: true,
|
|
186
|
+
css: `
|
|
187
|
+
[data-theme='acme-slate'] {
|
|
188
|
+
color-scheme: dark;
|
|
189
|
+
--lt-color-scheme: dark;
|
|
190
|
+
|
|
191
|
+
--lt-surface: 15 23 42; /* page wash */
|
|
192
|
+
--lt-surface-raised: 30 41 59; /* header, sheets */
|
|
193
|
+
--lt-surface-sunken: 10 16 30; /* section bands */
|
|
194
|
+
--lt-surface-hover: 40 53 74;
|
|
195
|
+
--lt-surface-border: 51 65 85;
|
|
196
|
+
|
|
197
|
+
--lt-field-bg: 34 46 66; /* fields step lighter than the page */
|
|
198
|
+
--lt-field-border: 71 85 105;
|
|
199
|
+
--lt-field-focus: 41 56 81;
|
|
200
|
+
|
|
201
|
+
--lt-accent: 125 170 255;
|
|
202
|
+
--lt-accent-hover: 155 190 255;
|
|
203
|
+
--lt-heading: 170 200 255;
|
|
204
|
+
|
|
205
|
+
--lt-text-primary: 233 238 248;
|
|
206
|
+
--lt-text-secondary: 185 197 219;
|
|
207
|
+
--lt-text-tertiary: 140 155 182;
|
|
208
|
+
--lt-text-quaternary: 105 120 148;
|
|
209
|
+
}
|
|
210
|
+
`,
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Values are RGB triplets (`15 23 42`, not `#0F172A`) so the system can apply
|
|
218
|
+
alpha through `rgb(var(--lt-*) / <alpha>)`. The bundled Midnight theme
|
|
219
|
+
(`examples/themes/midnight.ts`) is a complete worked example covering every
|
|
220
|
+
token family — surfaces, fields, accent, text ramp, and the status family —
|
|
221
|
+
and is registered through this exact mechanism; deployment themes are
|
|
222
|
+
first-class in the same way.
|
|
223
|
+
|
|
224
|
+
Keep the elevation logic when authoring a theme: the page carries the wash,
|
|
225
|
+
sections are distinct surfaces on it, and fields step away from their surface
|
|
226
|
+
— darker than the sheets in a light theme, lighter than the shade in a dark
|
|
227
|
+
one. A theme that holds those relationships inherits the whole system's
|
|
228
|
+
legibility; the tokens make it a matter of picking six surface values.
|
package/docs/hitl/form.md
CHANGED
|
@@ -4,6 +4,26 @@ The dashboard renders forms automatically from JSON Schema. No frontend code nee
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## Field Labels
|
|
8
|
+
|
|
9
|
+
A field's label resolves in order:
|
|
10
|
+
|
|
11
|
+
1. The `title` keyword — the author's explicit label, always wins.
|
|
12
|
+
2. Snake/kebab keys title-cased: `left_quantity` → `Left Quantity`. All-caps tokens inside a key keep their casing (`po_number` → `Po Number`, `PO_number` → `PO Number`).
|
|
13
|
+
3. Single-token keys pass through unchanged: `PO`, `SKU`, `LEFTQUANTITY`.
|
|
14
|
+
|
|
15
|
+
Declare `title` on every field whose key isn't already a readable label — it is the difference between `LEFTQUANTITY` and `Left Quantity` everywhere the field faces a human: the form, the dictionary display, and the errors panel.
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"properties": {
|
|
20
|
+
"LEFTQUANTITY": { "type": "number", "title": "Left Quantity" }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
7
27
|
## Field Types
|
|
8
28
|
|
|
9
29
|
| JSON Type | Renders As |
|
|
@@ -46,7 +66,7 @@ Use `format` on any `string` field to get a specialized input:
|
|
|
46
66
|
|
|
47
67
|
## Required Fields
|
|
48
68
|
|
|
49
|
-
|
|
69
|
+
Every required input — text, select, number, upload, or checklist group — shows a red asterisk at its label and blocks submission when empty. A checklist with `x-lt-require-all` is required by definition and carries the asterisk too. Required or optional is never a guess.
|
|
50
70
|
|
|
51
71
|
```json
|
|
52
72
|
{
|
package/docs/hitl/iframe.md
CHANGED
|
@@ -54,7 +54,7 @@ const WORKBENCH_FORM_SCHEMA = {
|
|
|
54
54
|
// Workflow side — the wait is a normal conditionLT; the iframe submits the payload
|
|
55
55
|
const design = await conditionLT<{ stl_url: string }>(signalId, {
|
|
56
56
|
role: 'cad-designer',
|
|
57
|
-
description: 'Design the
|
|
57
|
+
description: 'Design the widget for this order.',
|
|
58
58
|
escalation_payload: JSON.stringify({ workbenchId, companyId }),
|
|
59
59
|
});
|
|
60
60
|
if (design) {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Dictionary Display (`x-lt-display`)
|
|
2
|
+
|
|
3
|
+
Read-only facts — order numbers, quantities, product names — render as a dense definition list when dictionary display is requested: labels beside values in a compact grid, a run of consecutive facts merged into one list. This is the display for reference data the resolver reads but never edits.
|
|
4
|
+
|
|
5
|
+
`x-lt-display: "dictionary"` applies at three levels; the nearest wins:
|
|
6
|
+
|
|
7
|
+
| Level | Placement | Applies to |
|
|
8
|
+
|-------|-----------|-----------|
|
|
9
|
+
| Field | on the property | that field |
|
|
10
|
+
| Section | `x-lt-section-options` at the schema root | read-only fields in that section |
|
|
11
|
+
| Schema | at the schema root | every read-only field |
|
|
12
|
+
|
|
13
|
+
Only read-only fields (`readOnly: true`) render as dictionary rows. Editable fields keep their inputs, and content widgets (`markdown`, `attachment`, `image`) keep their block rendering regardless of display settings.
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"x-lt-layout": "two-column",
|
|
18
|
+
"x-lt-display": "dictionary",
|
|
19
|
+
"properties": {
|
|
20
|
+
"po": { "type": "string", "title": "PO", "readOnly": true, "x-lt-section": "The Order" },
|
|
21
|
+
"order_id": { "type": "string", "title": "Order ID", "readOnly": true, "x-lt-section": "The Order" },
|
|
22
|
+
"left_quantity": { "type": "number", "title": "Left Qty", "readOnly": true, "x-lt-section": "The Order" },
|
|
23
|
+
"right_quantity": { "type": "number", "title": "Right Qty","readOnly": true, "x-lt-section": "The Order" },
|
|
24
|
+
"approved": { "type": "boolean", "x-lt-section": "The Decision" }
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The four order facts render as one two-column dictionary under "The Order"; `approved` stays a checkbox.
|
|
30
|
+
|
|
31
|
+
## Section Options (`x-lt-section-options`)
|
|
32
|
+
|
|
33
|
+
Per-section display settings live at the schema root, keyed by section name:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"x-lt-section-options": {
|
|
38
|
+
"The Order": { "display": "dictionary", "columns": 2 }
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| Option | Values | Meaning |
|
|
44
|
+
|--------|--------|---------|
|
|
45
|
+
| `display` | `"dictionary"` | Read-only fields in the section render as dictionary rows |
|
|
46
|
+
| `columns` | `1` \| `2` | Dictionary column count; defaults to 2 in two-column layouts, 1 otherwise |
|
|
47
|
+
|
|
48
|
+
Two-column dictionaries fill **row by row**: consecutive items share a row, so ordering controls pairing — declare `left_quantity` and `right_quantity` together and they render side by side, Left first.
|
|
49
|
+
|
|
50
|
+
## Value formatting
|
|
51
|
+
|
|
52
|
+
Strings and numbers render as-is. Booleans render as Yes / No. Objects and arrays render as compact JSON. Empty values (`null`, `""`) render as an em dash.
|
|
53
|
+
|
|
54
|
+
Labels resolve the same way as form labels: the `title` keyword when present, otherwise the field key with snake/kebab separators title-cased. Declare `title` on every fact — `"PO"`, `"Order ID"` — for labels that read like product copy rather than column names.
|
|
55
|
+
|
|
56
|
+
Presentation tokens (`x-lt-display`, `x-lt-section-options`, `x-lt-column-group`) never affect validation or the submitted payload; a schema renders identically strict with or without them.
|
package/docs/hitl/x-lt-layout.md
CHANGED
|
@@ -58,6 +58,25 @@ Sections are ordered by the first field that carries the section name (respects
|
|
|
58
58
|
|
|
59
59
|
---
|
|
60
60
|
|
|
61
|
+
## Nested Column Groups (`x-lt-column-group`)
|
|
62
|
+
|
|
63
|
+
In a two-column layout, consecutive fields sharing an `x-lt-column-group` name render inside a single grid cell as their own two-column pair — a 2×2 arrangement. One nesting level is supported; the token is ignored when the schema layout is not `two-column`.
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"x-lt-layout": "two-column",
|
|
68
|
+
"properties": {
|
|
69
|
+
"left_quantity": { "type": "number", "title": "Left Qty", "x-lt-column-group": "quantities" },
|
|
70
|
+
"right_quantity": { "type": "number", "title": "Right Qty", "x-lt-column-group": "quantities" },
|
|
71
|
+
"notes": { "type": "string", "format": "textarea" }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The two quantities share one cell of the outer grid (each taking half of it) while `notes` occupies a normal cell beside them.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
61
80
|
## Payload Binding (`x-lt-bind`)
|
|
62
81
|
|
|
63
82
|
The form is flat; the payload the workflow consumes rarely is. A field may declare `x-lt-bind` — the path its value occupies in the resolver payload (dot keys, optional `[n]` indices). The dashboard maps the flat form through the binds on submit, and reverse-maps `envelope.formDefaults` through them to prefill. A field with no bind lands at its own name at the payload root.
|
|
@@ -89,7 +108,7 @@ Only the form is versioned on the role — the payload shape is the workflow's o
|
|
|
89
108
|
|
|
90
109
|
## Help Panel (`x-lt-help`)
|
|
91
110
|
|
|
92
|
-
Schema-level `x-lt-help` carries the form's guidance — checklists, tier tables, callouts, links — as markdown. The dashboard renders it in the side panel beside the form, so the form itself stays a clean title-and-fields surface while the SOP sits one glance to the right. The help text versions with the form: it lives in the same `form_schema` snapshot in `lt_role_schemas`.
|
|
111
|
+
Schema-level `x-lt-help` carries the form's guidance — checklists, tier tables, callouts, links — as markdown. The dashboard renders it in the side panel beside the form, so the form itself stays a clean title-and-fields surface while the SOP sits one glance to the right. When a schema carries `x-lt-help` (or `x-lt-context`), a help icon renders beside the form title; it opens the Instructions view of the side panel. The help text versions with the form: it lives in the same `form_schema` snapshot in `lt_role_schemas`.
|
|
93
112
|
|
|
94
113
|
```json
|
|
95
114
|
{
|
|
@@ -98,6 +98,13 @@ Use when the rows describe **entities** (machines, stations) rather than a queue
|
|
|
98
98
|
}
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
The card's `state` renders as a status chip (a stable hue per token — commonly a subtype or a metadata state facet). The grid wraps to the viewport (wall-screen friendly).
|
|
101
|
+
The card's `state` renders as a status chip (a stable hue per token — commonly a subtype or a metadata state facet). The grid wraps to the viewport (wall-screen friendly). `x-lt-help` renders above the board as in `facet-table`. In the digital-twin pattern — each machine advertising one live pending row — the board is exact by construction; for wider scopes it groups the fetched page, with standard pagination beyond it.
|
|
102
|
+
|
|
103
|
+
Cards are fully interactive (`x-lt-group-by` should be a `metadata.*` path so the facet affordances apply):
|
|
104
|
+
|
|
105
|
+
- **Click** opens the group's latest row in the detail view.
|
|
106
|
+
- **⇧ click** adds the entity's facet to the live filter set — additive, so shift-clicking narrows the board in place and the facet chips row shows each condition with its own remove.
|
|
107
|
+
- **Hovering the card footer** reveals the entity's history as the filtered **table** or **timeline** view (the same view modes the queue offers everywhere else).
|
|
108
|
+
- **Fields bound to a pure `{{metadata.KEY}}` token** carry the same hover pair the table's metadata cells offer: **filter** (narrows within the current role; ⇧ click adds to the current filters) and **search** (the facet across all roles).
|
|
102
109
|
|
|
103
110
|
The reference: `examples/seed-fleet-sim.ts` — one advert per machine, a `format: "age"` "Since" field, and role default pins (see [pinned-views.md](pinned-views.md)).
|
package/docs/hitl/x-lt-widget.md
CHANGED
|
@@ -144,6 +144,29 @@ The field type must be `"object"`. The submitted value is `Record<string, boolea
|
|
|
144
144
|
- `"envelope"` — for item definitions that are render data only (no query cost). The workflow puts them in `conditionLT`'s `envelope` parameter.
|
|
145
145
|
- `"metadata"` — only when items need to be GIN-indexed and searchable as facets. Adds index cost.
|
|
146
146
|
|
|
147
|
+
### Geometry (`x-lt-variant`)
|
|
148
|
+
|
|
149
|
+
Item length and selection mode decide the checklist's shape:
|
|
150
|
+
|
|
151
|
+
| Variant | Shape | The shape for |
|
|
152
|
+
|---------|-------|---------------|
|
|
153
|
+
| `"rows"` | One item per line | Rituals — sentence-length confirmations, read top-down and ticked deliberately |
|
|
154
|
+
| `"chips"` | A wrapping cloud of selectable pills | Tags — short pick-any items (reject reasons, categories); selection shows in solid accent |
|
|
155
|
+
|
|
156
|
+
Set `"x-lt-variant"` explicitly, or let the renderer decide: `x-lt-require-all` always renders rows; otherwise chips when every label is 28 characters or fewer. The submitted value is identical in both shapes.
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"rejectReasons": {
|
|
161
|
+
"type": "object",
|
|
162
|
+
"description": "Check every reason that applies",
|
|
163
|
+
"x-lt-widget": "checklist",
|
|
164
|
+
"x-lt-source": "envelope.reject_reason_items",
|
|
165
|
+
"x-lt-variant": "chips"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
147
170
|
A checklist enforces one of three completion levels:
|
|
148
171
|
|
|
149
172
|
| Level | Declaration | Blocks submission until |
|