@contractspec/example.workflow-system 3.7.7 → 3.8.2

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 (37) hide show
  1. package/README.md +3 -0
  2. package/dist/browser/handlers/index.js +43 -43
  3. package/dist/browser/handlers/workflow.handlers.js +43 -43
  4. package/dist/browser/index.js +572 -183
  5. package/dist/browser/shared/demo-scenario.js +213 -0
  6. package/dist/browser/ui/WorkflowDashboard.visualizations.js +239 -0
  7. package/dist/browser/ui/hooks/index.js +0 -47
  8. package/dist/browser/ui/hooks/useWorkflowList.js +5 -3
  9. package/dist/browser/ui/index.js +5 -3
  10. package/dist/browser/ui/renderers/index.js +409 -73
  11. package/dist/browser/ui/renderers/workflow.markdown.js +409 -73
  12. package/dist/browser/visualizations/catalog.js +132 -0
  13. package/dist/browser/visualizations/index.js +133 -0
  14. package/dist/browser/visualizations/selectors.js +195 -0
  15. package/dist/example.test.d.ts +1 -0
  16. package/dist/handlers/index.js +43 -43
  17. package/dist/handlers/workflow.handlers.js +43 -43
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +572 -183
  20. package/dist/shared/demo-scenario.d.ts +43 -0
  21. package/dist/shared/demo-scenario.js +214 -0
  22. package/dist/ui/WorkflowDashboard.visualizations.d.ts +4 -0
  23. package/dist/ui/WorkflowDashboard.visualizations.js +240 -0
  24. package/dist/ui/hooks/index.js +0 -47
  25. package/dist/ui/hooks/useWorkflowList.d.ts +2 -1
  26. package/dist/ui/hooks/useWorkflowList.js +5 -3
  27. package/dist/ui/index.js +5 -3
  28. package/dist/ui/renderers/index.js +409 -73
  29. package/dist/ui/renderers/workflow.markdown.js +409 -73
  30. package/dist/visualizations/catalog.d.ts +11 -0
  31. package/dist/visualizations/catalog.js +133 -0
  32. package/dist/visualizations/index.d.ts +2 -0
  33. package/dist/visualizations/index.js +134 -0
  34. package/dist/visualizations/selectors.d.ts +11 -0
  35. package/dist/visualizations/selectors.js +196 -0
  36. package/dist/visualizations/selectors.test.d.ts +1 -0
  37. package/package.json +69 -8
package/dist/index.js CHANGED
@@ -716,9 +716,19 @@ function rowToApproval(row) {
716
716
  };
717
717
  }
718
718
  function createWorkflowHandlers(db) {
719
+ function normalizeSql(sql) {
720
+ let placeholderIndex = 0;
721
+ return sql.replace(/\?/g, () => `$${++placeholderIndex}`);
722
+ }
723
+ async function queryRows(sql, params = []) {
724
+ return (await db.query(normalizeSql(sql), params)).rows;
725
+ }
726
+ async function execute(sql, params = []) {
727
+ await db.execute(normalizeSql(sql), params);
728
+ }
719
729
  async function listDefinitions(input) {
720
730
  const { projectId, status, search, limit = 20, offset = 0 } = input;
721
- let whereClause = "WHERE projectId = ?";
731
+ let whereClause = 'WHERE "projectId" = ?';
722
732
  const params = [projectId];
723
733
  if (status && status !== "all") {
724
734
  whereClause += " AND status = ?";
@@ -728,9 +738,9 @@ function createWorkflowHandlers(db) {
728
738
  whereClause += " AND name LIKE ?";
729
739
  params.push(`%${search}%`);
730
740
  }
731
- const countResult = (await db.query(`SELECT COUNT(*) as count FROM workflow_definition ${whereClause}`, params)).rows;
741
+ const countResult = await queryRows(`SELECT COUNT(*) as count FROM workflow_definition ${whereClause}`, params);
732
742
  const total = countResult[0]?.count ?? 0;
733
- const rows = (await db.query(`SELECT * FROM workflow_definition ${whereClause} ORDER BY updatedAt DESC LIMIT ? OFFSET ?`, [...params, limit, offset])).rows;
743
+ const rows = await queryRows(`SELECT * FROM workflow_definition ${whereClause} ORDER BY "updatedAt" DESC LIMIT ? OFFSET ?`, [...params, limit, offset]);
734
744
  return {
735
745
  definitions: rows.map(rowToDefinition),
736
746
  total
@@ -739,7 +749,7 @@ function createWorkflowHandlers(db) {
739
749
  async function createDefinition(input, context) {
740
750
  const id = generateId("wfdef");
741
751
  const now = new Date().toISOString();
742
- await db.execute(`INSERT INTO workflow_definition (id, projectId, organizationId, name, description, type, status, createdAt, updatedAt)
752
+ await execute(`INSERT INTO workflow_definition (id, "projectId", "organizationId", name, description, type, status, "createdAt", "updatedAt")
743
753
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
744
754
  id,
745
755
  context.projectId,
@@ -751,15 +761,15 @@ function createWorkflowHandlers(db) {
751
761
  now,
752
762
  now
753
763
  ]);
754
- const rows = (await db.query(`SELECT * FROM workflow_definition WHERE id = ?`, [id])).rows;
764
+ const rows = await queryRows(`SELECT * FROM workflow_definition WHERE id = ?`, [id]);
755
765
  return rowToDefinition(rows[0]);
756
766
  }
757
767
  async function addStep(input) {
758
768
  const id = generateId("wfstep");
759
769
  const now = new Date().toISOString();
760
- const maxOrderResult = (await db.query(`SELECT MAX(stepOrder) as maxOrder FROM workflow_step WHERE definitionId = ?`, [input.definitionId])).rows;
770
+ const maxOrderResult = await queryRows(`SELECT MAX("stepOrder") as maxOrder FROM workflow_step WHERE "definitionId" = ?`, [input.definitionId]);
761
771
  const nextOrder = (maxOrderResult[0]?.maxOrder ?? 0) + 1;
762
- await db.execute(`INSERT INTO workflow_step (id, definitionId, name, description, stepOrder, type, requiredRoles, autoApproveCondition, timeoutHours, createdAt)
772
+ await execute(`INSERT INTO workflow_step (id, "definitionId", name, description, "stepOrder", type, "requiredRoles", "autoApproveCondition", "timeoutHours", "createdAt")
763
773
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
764
774
  id,
765
775
  input.definitionId,
@@ -772,11 +782,11 @@ function createWorkflowHandlers(db) {
772
782
  input.timeoutHours ?? null,
773
783
  now
774
784
  ]);
775
- const rows = (await db.query(`SELECT * FROM workflow_step WHERE id = ?`, [id])).rows;
785
+ const rows = await queryRows(`SELECT * FROM workflow_step WHERE id = ?`, [id]);
776
786
  return rowToStep(rows[0]);
777
787
  }
778
788
  async function getSteps(definitionId) {
779
- const rows = (await db.query(`SELECT * FROM workflow_step WHERE definitionId = ? ORDER BY stepOrder`, [definitionId])).rows;
789
+ const rows = await queryRows(`SELECT * FROM workflow_step WHERE "definitionId" = ? ORDER BY "stepOrder"`, [definitionId]);
780
790
  return rows.map(rowToStep);
781
791
  }
782
792
  async function listInstances(input) {
@@ -788,10 +798,10 @@ function createWorkflowHandlers(db) {
788
798
  limit = 20,
789
799
  offset = 0
790
800
  } = input;
791
- let whereClause = "WHERE projectId = ?";
801
+ let whereClause = 'WHERE "projectId" = ?';
792
802
  const params = [projectId];
793
803
  if (definitionId) {
794
- whereClause += " AND definitionId = ?";
804
+ whereClause += ' AND "definitionId" = ?';
795
805
  params.push(definitionId);
796
806
  }
797
807
  if (status && status !== "all") {
@@ -799,12 +809,12 @@ function createWorkflowHandlers(db) {
799
809
  params.push(status);
800
810
  }
801
811
  if (requestedBy) {
802
- whereClause += " AND requestedBy = ?";
812
+ whereClause += ' AND "requestedBy" = ?';
803
813
  params.push(requestedBy);
804
814
  }
805
- const countResult = (await db.query(`SELECT COUNT(*) as count FROM workflow_instance ${whereClause}`, params)).rows;
815
+ const countResult = await queryRows(`SELECT COUNT(*) as count FROM workflow_instance ${whereClause}`, params);
806
816
  const total = countResult[0]?.count ?? 0;
807
- const rows = (await db.query(`SELECT * FROM workflow_instance ${whereClause} ORDER BY startedAt DESC LIMIT ? OFFSET ?`, [...params, limit, offset])).rows;
817
+ const rows = await queryRows(`SELECT * FROM workflow_instance ${whereClause} ORDER BY "startedAt" DESC LIMIT ? OFFSET ?`, [...params, limit, offset]);
808
818
  return {
809
819
  instances: rows.map(rowToInstance),
810
820
  total
@@ -813,9 +823,9 @@ function createWorkflowHandlers(db) {
813
823
  async function startInstance(input, context) {
814
824
  const id = generateId("wfinst");
815
825
  const now = new Date().toISOString();
816
- const steps = (await db.query(`SELECT * FROM workflow_step WHERE definitionId = ? ORDER BY stepOrder LIMIT 1`, [input.definitionId])).rows;
826
+ const steps = await queryRows(`SELECT * FROM workflow_step WHERE "definitionId" = ? ORDER BY "stepOrder" LIMIT 1`, [input.definitionId]);
817
827
  const firstStepId = steps[0]?.id ?? null;
818
- await db.execute(`INSERT INTO workflow_instance (id, projectId, definitionId, status, currentStepId, data, requestedBy, startedAt)
828
+ await execute(`INSERT INTO workflow_instance (id, "projectId", "definitionId", status, "currentStepId", data, "requestedBy", "startedAt")
819
829
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
820
830
  id,
821
831
  context.projectId,
@@ -827,36 +837,32 @@ function createWorkflowHandlers(db) {
827
837
  now
828
838
  ]);
829
839
  if (firstStepId) {
830
- await db.execute(`INSERT INTO workflow_approval (id, instanceId, stepId, status, createdAt)
840
+ await execute(`INSERT INTO workflow_approval (id, "instanceId", "stepId", status, "createdAt")
831
841
  VALUES (?, ?, ?, ?, ?)`, [generateId("wfappr"), id, firstStepId, "PENDING", now]);
832
842
  }
833
- const rows = (await db.query(`SELECT * FROM workflow_instance WHERE id = ?`, [id])).rows;
843
+ const rows = await queryRows(`SELECT * FROM workflow_instance WHERE id = ?`, [id]);
834
844
  return rowToInstance(rows[0]);
835
845
  }
836
846
  async function approveStep(input, context) {
837
847
  const now = new Date().toISOString();
838
- const instances = (await db.query(`SELECT * FROM workflow_instance WHERE id = ?`, [
839
- input.instanceId
840
- ])).rows;
848
+ const instances = await queryRows(`SELECT * FROM workflow_instance WHERE id = ?`, [input.instanceId]);
841
849
  if (!instances[0]) {
842
850
  throw new Error("NOT_FOUND");
843
851
  }
844
852
  const instance = instances[0];
845
- await db.execute(`UPDATE workflow_approval SET status = 'APPROVED', actorId = ?, comment = ?, decidedAt = ?
846
- WHERE instanceId = ? AND stepId = ? AND status = 'PENDING'`, [
853
+ await execute(`UPDATE workflow_approval SET status = 'APPROVED', "actorId" = ?, comment = ?, "decidedAt" = ?
854
+ WHERE "instanceId" = ? AND "stepId" = ? AND status = 'PENDING'`, [
847
855
  context.actorId,
848
856
  input.comment ?? null,
849
857
  now,
850
858
  input.instanceId,
851
859
  instance.currentStepId
852
860
  ]);
853
- const currentStep = (await db.query(`SELECT * FROM workflow_step WHERE id = ?`, [
854
- instance.currentStepId
855
- ])).rows;
856
- const nextSteps = (await db.query(`SELECT * FROM workflow_step WHERE definitionId = ? AND stepOrder > ? ORDER BY stepOrder LIMIT 1`, [instance.definitionId, currentStep[0]?.stepOrder ?? 0])).rows;
861
+ const currentStep = await queryRows(`SELECT * FROM workflow_step WHERE id = ?`, [instance.currentStepId]);
862
+ const nextSteps = await queryRows(`SELECT * FROM workflow_step WHERE "definitionId" = ? AND "stepOrder" > ? ORDER BY "stepOrder" LIMIT 1`, [instance.definitionId, currentStep[0]?.stepOrder ?? 0]);
857
863
  if (nextSteps[0]) {
858
- await db.execute(`UPDATE workflow_instance SET currentStepId = ? WHERE id = ?`, [nextSteps[0].id, input.instanceId]);
859
- await db.execute(`INSERT INTO workflow_approval (id, instanceId, stepId, status, createdAt)
864
+ await execute(`UPDATE workflow_instance SET "currentStepId" = ? WHERE id = ?`, [nextSteps[0].id, input.instanceId]);
865
+ await execute(`INSERT INTO workflow_approval (id, "instanceId", "stepId", status, "createdAt")
860
866
  VALUES (?, ?, ?, ?, ?)`, [
861
867
  generateId("wfappr"),
862
868
  input.instanceId,
@@ -865,37 +871,31 @@ function createWorkflowHandlers(db) {
865
871
  now
866
872
  ]);
867
873
  } else {
868
- await db.execute(`UPDATE workflow_instance SET status = 'COMPLETED', currentStepId = NULL, completedAt = ? WHERE id = ?`, [now, input.instanceId]);
874
+ await execute(`UPDATE workflow_instance SET status = 'COMPLETED', "currentStepId" = NULL, "completedAt" = ? WHERE id = ?`, [now, input.instanceId]);
869
875
  }
870
- const updated = (await db.query(`SELECT * FROM workflow_instance WHERE id = ?`, [
871
- input.instanceId
872
- ])).rows;
876
+ const updated = await queryRows(`SELECT * FROM workflow_instance WHERE id = ?`, [input.instanceId]);
873
877
  return rowToInstance(updated[0]);
874
878
  }
875
879
  async function rejectStep(input, context) {
876
880
  const now = new Date().toISOString();
877
- const instances = (await db.query(`SELECT * FROM workflow_instance WHERE id = ?`, [
878
- input.instanceId
879
- ])).rows;
881
+ const instances = await queryRows(`SELECT * FROM workflow_instance WHERE id = ?`, [input.instanceId]);
880
882
  if (!instances[0]) {
881
883
  throw new Error("NOT_FOUND");
882
884
  }
883
- await db.execute(`UPDATE workflow_approval SET status = 'REJECTED', actorId = ?, comment = ?, decidedAt = ?
884
- WHERE instanceId = ? AND stepId = ? AND status = 'PENDING'`, [
885
+ await execute(`UPDATE workflow_approval SET status = 'REJECTED', "actorId" = ?, comment = ?, "decidedAt" = ?
886
+ WHERE "instanceId" = ? AND "stepId" = ? AND status = 'PENDING'`, [
885
887
  context.actorId,
886
888
  input.reason,
887
889
  now,
888
890
  input.instanceId,
889
891
  instances[0].currentStepId
890
892
  ]);
891
- await db.execute(`UPDATE workflow_instance SET status = 'REJECTED', completedAt = ? WHERE id = ?`, [now, input.instanceId]);
892
- const updated = (await db.query(`SELECT * FROM workflow_instance WHERE id = ?`, [
893
- input.instanceId
894
- ])).rows;
893
+ await execute(`UPDATE workflow_instance SET status = 'REJECTED', "completedAt" = ? WHERE id = ?`, [now, input.instanceId]);
894
+ const updated = await queryRows(`SELECT * FROM workflow_instance WHERE id = ?`, [input.instanceId]);
895
895
  return rowToInstance(updated[0]);
896
896
  }
897
897
  async function getApprovals(instanceId) {
898
- const rows = (await db.query(`SELECT * FROM workflow_approval WHERE instanceId = ? ORDER BY createdAt`, [instanceId])).rows;
898
+ const rows = await queryRows(`SELECT * FROM workflow_approval WHERE "instanceId" = ? ORDER BY "createdAt"`, [instanceId]);
899
899
  return rows.map(rowToApproval);
900
900
  }
901
901
  return {
@@ -1993,8 +1993,9 @@ var WorkflowSystemPresentations = {
1993
1993
  import { useTemplateRuntime } from "@contractspec/lib.example-shared-ui";
1994
1994
  import { useCallback, useEffect, useState } from "react";
1995
1995
  "use client";
1996
- function useWorkflowList(projectId = "local-project") {
1997
- const { handlers } = useTemplateRuntime();
1996
+ function useWorkflowList(projectIdOverride) {
1997
+ const { handlers, projectId: runtimeProjectId } = useTemplateRuntime();
1998
+ const projectId = projectIdOverride ?? runtimeProjectId;
1998
1999
  const workflow = handlers.workflow;
1999
2000
  const [definitions, setDefinitions] = useState([]);
2000
2001
  const [instances, setInstances] = useState([]);
@@ -2015,7 +2016,7 @@ function useWorkflowList(projectId = "local-project") {
2015
2016
  } finally {
2016
2017
  setLoading(false);
2017
2018
  }
2018
- }, [handlers, projectId]);
2019
+ }, [projectId, workflow]);
2019
2020
  useEffect(() => {
2020
2021
  fetchData();
2021
2022
  }, [fetchData]);
@@ -2024,6 +2025,7 @@ function useWorkflowList(projectId = "local-project") {
2024
2025
  activeDefinitions: definitions.filter((d) => d.status === "ACTIVE").length,
2025
2026
  totalInstances: instances.length,
2026
2027
  pendingInstances: instances.filter((i) => i.status === "PENDING").length,
2028
+ inProgressInstances: instances.filter((i) => i.status === "IN_PROGRESS").length,
2027
2029
  completedInstances: instances.filter((i) => i.status === "COMPLETED").length,
2028
2030
  rejectedInstances: instances.filter((i) => i.status === "REJECTED").length
2029
2031
  };
@@ -2040,115 +2042,450 @@ function useWorkflowList(projectId = "local-project") {
2040
2042
  // src/ui/hooks/index.ts
2041
2043
  "use client";
2042
2044
 
2043
- // src/ui/renderers/workflow.markdown.ts
2044
- var mockWorkflowDefinitions = [
2045
+ // src/shared/demo-scenario.ts
2046
+ var WORKFLOW_SYSTEM_DEMO_PROJECT_ID = "workflow-system-demo";
2047
+ var WORKFLOW_SYSTEM_DEMO_ORGANIZATION_ID = "org_demo";
2048
+ var WORKFLOW_SYSTEM_DEMO_DEFINITIONS = [
2045
2049
  {
2046
- id: "wf-1",
2047
- name: "Purchase Approval",
2050
+ id: "wf_expense",
2051
+ name: "Expense Approval",
2052
+ description: "Approve non-trivial spend before finance releases budget.",
2048
2053
  type: "APPROVAL",
2054
+ status: "ACTIVE",
2055
+ createdAt: "2026-03-10T09:00:00.000Z",
2056
+ updatedAt: "2026-03-20T08:15:00.000Z",
2049
2057
  steps: [
2050
2058
  {
2051
- id: "s1",
2059
+ id: "wfstep_expense_manager",
2052
2060
  name: "Manager Review",
2053
- order: 1,
2054
- requiredRoles: ["manager"]
2061
+ description: "Validate business value and team budget.",
2062
+ stepOrder: 1,
2063
+ type: "APPROVAL",
2064
+ requiredRoles: ["manager"],
2065
+ createdAt: "2026-03-10T09:00:00.000Z"
2055
2066
  },
2056
2067
  {
2057
- id: "s2",
2068
+ id: "wfstep_expense_finance",
2058
2069
  name: "Finance Review",
2059
- order: 2,
2060
- requiredRoles: ["finance"]
2061
- },
2062
- { id: "s3", name: "Final Approval", order: 3, requiredRoles: ["admin"] }
2063
- ],
2064
- status: "ACTIVE"
2070
+ description: "Confirm ledger coding and spending threshold.",
2071
+ stepOrder: 2,
2072
+ type: "APPROVAL",
2073
+ requiredRoles: ["finance"],
2074
+ createdAt: "2026-03-10T09:10:00.000Z"
2075
+ }
2076
+ ]
2065
2077
  },
2066
2078
  {
2067
- id: "wf-2",
2068
- name: "Leave Request",
2069
- type: "APPROVAL",
2079
+ id: "wf_vendor",
2080
+ name: "Vendor Onboarding",
2081
+ description: "Sequence security, procurement, and legal before activation.",
2082
+ type: "SEQUENTIAL",
2083
+ status: "ACTIVE",
2084
+ createdAt: "2026-03-08T11:00:00.000Z",
2085
+ updatedAt: "2026-03-19T13:10:00.000Z",
2070
2086
  steps: [
2071
2087
  {
2072
- id: "s1",
2073
- name: "Supervisor Approval",
2074
- order: 1,
2075
- requiredRoles: ["supervisor"]
2088
+ id: "wfstep_vendor_security",
2089
+ name: "Security Check",
2090
+ description: "Review data access and integration scope.",
2091
+ stepOrder: 1,
2092
+ type: "APPROVAL",
2093
+ requiredRoles: ["security"],
2094
+ createdAt: "2026-03-08T11:00:00.000Z"
2076
2095
  },
2077
- { id: "s2", name: "HR Review", order: 2, requiredRoles: ["hr"] }
2078
- ],
2079
- status: "ACTIVE"
2096
+ {
2097
+ id: "wfstep_vendor_procurement",
2098
+ name: "Procurement Check",
2099
+ description: "Validate pricing, procurement policy, and owner.",
2100
+ stepOrder: 2,
2101
+ type: "APPROVAL",
2102
+ requiredRoles: ["procurement"],
2103
+ createdAt: "2026-03-08T11:05:00.000Z"
2104
+ },
2105
+ {
2106
+ id: "wfstep_vendor_legal",
2107
+ name: "Legal Sign-off",
2108
+ description: "Approve terms before the vendor goes live.",
2109
+ stepOrder: 3,
2110
+ type: "APPROVAL",
2111
+ requiredRoles: ["legal"],
2112
+ createdAt: "2026-03-08T11:10:00.000Z"
2113
+ }
2114
+ ]
2080
2115
  },
2081
2116
  {
2082
- id: "wf-3",
2083
- name: "Document Review",
2084
- type: "SEQUENTIAL",
2117
+ id: "wf_policy_exception",
2118
+ name: "Policy Exception",
2119
+ description: "Escalate a temporary exception through team lead and compliance.",
2120
+ type: "APPROVAL",
2121
+ status: "DRAFT",
2122
+ createdAt: "2026-03-15T07:30:00.000Z",
2123
+ updatedAt: "2026-03-18T11:20:00.000Z",
2085
2124
  steps: [
2086
- { id: "s1", name: "Author Review", order: 1, requiredRoles: ["author"] },
2087
- { id: "s2", name: "Peer Review", order: 2, requiredRoles: ["reviewer"] },
2088
- { id: "s3", name: "Publish", order: 3, requiredRoles: ["publisher"] }
2089
- ],
2090
- status: "DRAFT"
2125
+ {
2126
+ id: "wfstep_policy_lead",
2127
+ name: "Team Lead Review",
2128
+ description: "Check urgency and expected blast radius.",
2129
+ stepOrder: 1,
2130
+ type: "APPROVAL",
2131
+ requiredRoles: ["team-lead"],
2132
+ createdAt: "2026-03-15T07:30:00.000Z"
2133
+ },
2134
+ {
2135
+ id: "wfstep_policy_compliance",
2136
+ name: "Compliance Review",
2137
+ description: "Accept or reject the exception request.",
2138
+ stepOrder: 2,
2139
+ type: "APPROVAL",
2140
+ requiredRoles: ["compliance"],
2141
+ createdAt: "2026-03-15T07:40:00.000Z"
2142
+ }
2143
+ ]
2091
2144
  }
2092
2145
  ];
2093
- var mockWorkflowInstances = [
2146
+ var WORKFLOW_SYSTEM_DEMO_INSTANCES = [
2094
2147
  {
2095
- id: "inst-1",
2096
- definitionId: "wf-1",
2097
- definitionName: "Purchase Approval",
2148
+ id: "wfinst_expense_open",
2149
+ definitionId: "wf_expense",
2098
2150
  status: "IN_PROGRESS",
2099
- currentStepId: "s2",
2100
- startedAt: "2024-01-15T10:00:00Z",
2101
- requestedBy: "John Doe"
2151
+ currentStepId: "wfstep_expense_finance",
2152
+ data: {
2153
+ amount: 4200,
2154
+ currency: "EUR",
2155
+ vendor: "Nimbus AI"
2156
+ },
2157
+ requestedBy: "sarah@contractspec.io",
2158
+ startedAt: "2026-03-20T08:00:00.000Z",
2159
+ approvals: [
2160
+ {
2161
+ id: "wfappr_expense_manager",
2162
+ stepId: "wfstep_expense_manager",
2163
+ status: "APPROVED",
2164
+ actorId: "manager.demo",
2165
+ comment: "Approved for the Q2 automation budget.",
2166
+ decidedAt: "2026-03-20T08:15:00.000Z",
2167
+ createdAt: "2026-03-20T08:05:00.000Z"
2168
+ },
2169
+ {
2170
+ id: "wfappr_expense_finance",
2171
+ stepId: "wfstep_expense_finance",
2172
+ status: "PENDING",
2173
+ createdAt: "2026-03-20T08:15:00.000Z"
2174
+ }
2175
+ ]
2102
2176
  },
2103
2177
  {
2104
- id: "inst-2",
2105
- definitionId: "wf-1",
2106
- definitionName: "Purchase Approval",
2178
+ id: "wfinst_vendor_done",
2179
+ definitionId: "wf_vendor",
2107
2180
  status: "COMPLETED",
2108
- currentStepId: null,
2109
- startedAt: "2024-01-10T09:00:00Z",
2110
- completedAt: "2024-01-12T14:00:00Z",
2111
- requestedBy: "Jane Smith"
2181
+ data: {
2182
+ vendor: "Acme Cloud",
2183
+ riskTier: "medium"
2184
+ },
2185
+ requestedBy: "leo@contractspec.io",
2186
+ startedAt: "2026-03-19T09:30:00.000Z",
2187
+ completedAt: "2026-03-19T13:10:00.000Z",
2188
+ approvals: [
2189
+ {
2190
+ id: "wfappr_vendor_security",
2191
+ stepId: "wfstep_vendor_security",
2192
+ status: "APPROVED",
2193
+ actorId: "security.demo",
2194
+ comment: "SOC2 scope is acceptable.",
2195
+ decidedAt: "2026-03-19T10:10:00.000Z",
2196
+ createdAt: "2026-03-19T09:35:00.000Z"
2197
+ },
2198
+ {
2199
+ id: "wfappr_vendor_procurement",
2200
+ stepId: "wfstep_vendor_procurement",
2201
+ status: "APPROVED",
2202
+ actorId: "procurement.demo",
2203
+ comment: "Commercial terms match the preferred vendor tier.",
2204
+ decidedAt: "2026-03-19T11:25:00.000Z",
2205
+ createdAt: "2026-03-19T10:15:00.000Z"
2206
+ },
2207
+ {
2208
+ id: "wfappr_vendor_legal",
2209
+ stepId: "wfstep_vendor_legal",
2210
+ status: "APPROVED",
2211
+ actorId: "legal.demo",
2212
+ comment: "MSA redlines are complete.",
2213
+ decidedAt: "2026-03-19T13:05:00.000Z",
2214
+ createdAt: "2026-03-19T11:30:00.000Z"
2215
+ }
2216
+ ]
2112
2217
  },
2113
2218
  {
2114
- id: "inst-3",
2115
- definitionId: "wf-2",
2116
- definitionName: "Leave Request",
2117
- status: "PENDING",
2118
- currentStepId: "s1",
2119
- startedAt: "2024-01-16T08:00:00Z",
2120
- requestedBy: "Bob Wilson"
2219
+ id: "wfinst_policy_rejected",
2220
+ definitionId: "wf_policy_exception",
2221
+ status: "REJECTED",
2222
+ currentStepId: "wfstep_policy_compliance",
2223
+ data: {
2224
+ policy: "Model rollout freeze",
2225
+ durationDays: 14
2226
+ },
2227
+ requestedBy: "maya@contractspec.io",
2228
+ startedAt: "2026-03-18T10:00:00.000Z",
2229
+ completedAt: "2026-03-18T11:20:00.000Z",
2230
+ approvals: [
2231
+ {
2232
+ id: "wfappr_policy_lead",
2233
+ stepId: "wfstep_policy_lead",
2234
+ status: "APPROVED",
2235
+ actorId: "lead.demo",
2236
+ comment: "Escalation justified for the release train.",
2237
+ decidedAt: "2026-03-18T10:30:00.000Z",
2238
+ createdAt: "2026-03-18T10:05:00.000Z"
2239
+ },
2240
+ {
2241
+ id: "wfappr_policy_compliance",
2242
+ stepId: "wfstep_policy_compliance",
2243
+ status: "REJECTED",
2244
+ actorId: "compliance.demo",
2245
+ comment: "Exception exceeds the allowed blast radius.",
2246
+ decidedAt: "2026-03-18T11:15:00.000Z",
2247
+ createdAt: "2026-03-18T10:35:00.000Z"
2248
+ }
2249
+ ]
2250
+ }
2251
+ ];
2252
+
2253
+ // src/visualizations/catalog.ts
2254
+ import {
2255
+ defineVisualization,
2256
+ VisualizationRegistry
2257
+ } from "@contractspec/lib.contracts-spec/visualizations";
2258
+ var INSTANCE_LIST_REF = {
2259
+ key: "workflow.instance.list",
2260
+ version: "1.0.0"
2261
+ };
2262
+ var META = {
2263
+ version: "1.0.0",
2264
+ domain: "workflow",
2265
+ stability: "experimental",
2266
+ owners: ["@example.workflow-system"],
2267
+ tags: ["workflow", "visualization", "operations"]
2268
+ };
2269
+ var WorkflowInstanceStatusVisualization = defineVisualization({
2270
+ meta: {
2271
+ ...META,
2272
+ key: "workflow-system.visualization.instance-status",
2273
+ title: "Instance Status Breakdown",
2274
+ description: "Distribution of workflow instance states.",
2275
+ goal: "Surface the current workload mix.",
2276
+ context: "Workflow operations overview."
2277
+ },
2278
+ source: { primary: INSTANCE_LIST_REF, resultPath: "data" },
2279
+ visualization: {
2280
+ kind: "pie",
2281
+ nameDimension: "status",
2282
+ valueMeasure: "instances",
2283
+ dimensions: [
2284
+ { key: "status", label: "Status", dataPath: "status", type: "category" }
2285
+ ],
2286
+ measures: [
2287
+ {
2288
+ key: "instances",
2289
+ label: "Instances",
2290
+ dataPath: "instances",
2291
+ format: "number"
2292
+ }
2293
+ ],
2294
+ table: { caption: "Workflow instance counts by status." }
2295
+ }
2296
+ });
2297
+ var WorkflowThroughputVisualization = defineVisualization({
2298
+ meta: {
2299
+ ...META,
2300
+ key: "workflow-system.visualization.throughput",
2301
+ title: "Run Throughput",
2302
+ description: "Daily workflow instance starts.",
2303
+ goal: "Show operational throughput over time.",
2304
+ context: "Workflow trend monitoring."
2305
+ },
2306
+ source: { primary: INSTANCE_LIST_REF, resultPath: "data" },
2307
+ visualization: {
2308
+ kind: "cartesian",
2309
+ variant: "line",
2310
+ xDimension: "day",
2311
+ yMeasures: ["instances"],
2312
+ dimensions: [{ key: "day", label: "Day", dataPath: "day", type: "time" }],
2313
+ measures: [
2314
+ {
2315
+ key: "instances",
2316
+ label: "Instances",
2317
+ dataPath: "instances",
2318
+ format: "number",
2319
+ color: "#0f766e"
2320
+ }
2321
+ ],
2322
+ table: { caption: "Daily workflow instance starts." }
2323
+ }
2324
+ });
2325
+ var WorkflowActiveMetricVisualization = defineVisualization({
2326
+ meta: {
2327
+ ...META,
2328
+ key: "workflow-system.visualization.active-work",
2329
+ title: "Active Work",
2330
+ description: "Current in-flight or pending workflow instances.",
2331
+ goal: "Expose active operational workload.",
2332
+ context: "Workflow workload comparison."
2333
+ },
2334
+ source: { primary: INSTANCE_LIST_REF, resultPath: "data" },
2335
+ visualization: {
2336
+ kind: "metric",
2337
+ measure: "value",
2338
+ measures: [
2339
+ { key: "value", label: "Instances", dataPath: "value", format: "number" }
2340
+ ],
2341
+ table: { caption: "Active workflow count." }
2121
2342
  }
2343
+ });
2344
+ var WorkflowCompletedMetricVisualization = defineVisualization({
2345
+ meta: {
2346
+ ...META,
2347
+ key: "workflow-system.visualization.completed-work",
2348
+ title: "Completed Work",
2349
+ description: "Completed workflow instances in the current sample.",
2350
+ goal: "Show output against active workload.",
2351
+ context: "Workflow workload comparison."
2352
+ },
2353
+ source: { primary: INSTANCE_LIST_REF, resultPath: "data" },
2354
+ visualization: {
2355
+ kind: "metric",
2356
+ measure: "value",
2357
+ measures: [
2358
+ { key: "value", label: "Instances", dataPath: "value", format: "number" }
2359
+ ],
2360
+ table: { caption: "Completed workflow count." }
2361
+ }
2362
+ });
2363
+ var WorkflowVisualizationSpecs = [
2364
+ WorkflowInstanceStatusVisualization,
2365
+ WorkflowThroughputVisualization,
2366
+ WorkflowActiveMetricVisualization,
2367
+ WorkflowCompletedMetricVisualization
2122
2368
  ];
2369
+ var WorkflowVisualizationRegistry = new VisualizationRegistry([
2370
+ ...WorkflowVisualizationSpecs
2371
+ ]);
2372
+ var WorkflowVisualizationRefs = WorkflowVisualizationSpecs.map((spec) => ({
2373
+ key: spec.meta.key,
2374
+ version: spec.meta.version
2375
+ }));
2376
+
2377
+ // src/visualizations/selectors.ts
2378
+ function toDayKey(value) {
2379
+ const date = value instanceof Date ? value : new Date(value);
2380
+ return date.toISOString().slice(0, 10);
2381
+ }
2382
+ function createWorkflowVisualizationSections(instances) {
2383
+ const statusCounts = new Map;
2384
+ const throughput = new Map;
2385
+ let activeCount = 0;
2386
+ let completedCount = 0;
2387
+ for (const instance of instances) {
2388
+ statusCounts.set(instance.status, (statusCounts.get(instance.status) ?? 0) + 1);
2389
+ const day = toDayKey(instance.startedAt);
2390
+ throughput.set(day, (throughput.get(day) ?? 0) + 1);
2391
+ if (instance.status === "PENDING" || instance.status === "IN_PROGRESS") {
2392
+ activeCount += 1;
2393
+ }
2394
+ if (instance.status === "COMPLETED") {
2395
+ completedCount += 1;
2396
+ }
2397
+ }
2398
+ const primaryItems = [
2399
+ {
2400
+ key: "workflow-status",
2401
+ spec: WorkflowInstanceStatusVisualization,
2402
+ data: {
2403
+ data: Array.from(statusCounts.entries()).map(([status, count]) => ({
2404
+ status,
2405
+ instances: count
2406
+ }))
2407
+ },
2408
+ title: "Instance Status Breakdown",
2409
+ description: "Status mix across workflow instances.",
2410
+ height: 260
2411
+ },
2412
+ {
2413
+ key: "workflow-throughput",
2414
+ spec: WorkflowThroughputVisualization,
2415
+ data: {
2416
+ data: Array.from(throughput.entries()).sort(([left], [right]) => left.localeCompare(right)).map(([day, count]) => ({ day, instances: count }))
2417
+ },
2418
+ title: "Run Throughput",
2419
+ description: "Daily workflow starts from current instances."
2420
+ }
2421
+ ];
2422
+ const comparisonItems = [
2423
+ {
2424
+ key: "workflow-active",
2425
+ spec: WorkflowActiveMetricVisualization,
2426
+ data: { data: [{ value: activeCount }] },
2427
+ title: "Active Work",
2428
+ description: "Pending and in-progress workflows.",
2429
+ height: 200
2430
+ },
2431
+ {
2432
+ key: "workflow-completed",
2433
+ spec: WorkflowCompletedMetricVisualization,
2434
+ data: { data: [{ value: completedCount }] },
2435
+ title: "Completed Work",
2436
+ description: "Completed workflows in the current sample.",
2437
+ height: 200
2438
+ }
2439
+ ];
2440
+ return {
2441
+ primaryItems,
2442
+ comparisonItems
2443
+ };
2444
+ }
2445
+ // src/ui/renderers/workflow.markdown.ts
2446
+ var workflowDefinitions = WORKFLOW_SYSTEM_DEMO_DEFINITIONS;
2447
+ var workflowInstances = WORKFLOW_SYSTEM_DEMO_INSTANCES;
2448
+ var workflowDefinitionById = new Map(workflowDefinitions.map((definition) => [definition.id, definition]));
2449
+ function formatDate(value) {
2450
+ return new Date(value).toISOString().slice(0, 10);
2451
+ }
2123
2452
  var workflowDashboardMarkdownRenderer = {
2124
2453
  target: "markdown",
2125
2454
  render: async (desc) => {
2126
2455
  if (desc.source.type !== "component" || desc.source.componentKey !== "WorkflowDashboard") {
2127
2456
  throw new Error("workflowDashboardMarkdownRenderer: not WorkflowDashboard");
2128
2457
  }
2129
- const definitions = mockWorkflowDefinitions;
2130
- const instances = mockWorkflowInstances;
2458
+ const definitions = workflowDefinitions;
2459
+ const instances = workflowInstances;
2460
+ const visualizations = createWorkflowVisualizationSections(instances);
2131
2461
  const activeDefinitions = definitions.filter((d) => d.status === "ACTIVE");
2132
- const pendingInstances = instances.filter((i) => i.status === "PENDING");
2133
- const inProgressInstances = instances.filter((i) => i.status === "IN_PROGRESS");
2134
- const completedInstances = instances.filter((i) => i.status === "COMPLETED");
2462
+ const awaitingActionInstances = instances.filter((i) => i.status === "PENDING" || i.status === "IN_PROGRESS");
2135
2463
  const lines = [
2136
2464
  "# Workflow Dashboard",
2137
2465
  "",
2138
- "> Workflow and approval management overview",
2466
+ "> Seeded workflow and approval overview for the sandbox demo.",
2139
2467
  "",
2140
2468
  "## Summary",
2141
2469
  "",
2142
2470
  "| Metric | Value |",
2143
2471
  "|--------|-------|",
2144
2472
  `| Active Workflows | ${activeDefinitions.length} |`,
2145
- `| Pending Approvals | ${pendingInstances.length} |`,
2146
- `| In Progress | ${inProgressInstances.length} |`,
2147
- `| Completed | ${completedInstances.length} |`,
2148
- "",
2149
- "## Active Workflow Definitions",
2473
+ `| Awaiting Action | ${awaitingActionInstances.length} |`,
2474
+ `| Completed | ${instances.filter((i) => i.status === "COMPLETED").length} |`,
2475
+ `| Rejected | ${instances.filter((i) => i.status === "REJECTED").length} |`,
2150
2476
  ""
2151
2477
  ];
2478
+ lines.push("## Visualization Overview");
2479
+ lines.push("");
2480
+ for (const item of [
2481
+ ...visualizations.primaryItems,
2482
+ ...visualizations.comparisonItems
2483
+ ]) {
2484
+ lines.push(`- **${item.title}** via \`${item.spec.meta.key}\``);
2485
+ }
2486
+ lines.push("");
2487
+ lines.push("## Active Workflow Definitions");
2488
+ lines.push("");
2152
2489
  if (activeDefinitions.length === 0) {
2153
2490
  lines.push("_No active workflow definitions._");
2154
2491
  } else {
@@ -2167,8 +2504,9 @@ var workflowDashboardMarkdownRenderer = {
2167
2504
  lines.push("| Workflow | Requested By | Status | Started |");
2168
2505
  lines.push("|----------|--------------|--------|---------|");
2169
2506
  for (const inst of instances.slice(0, 10)) {
2170
- const startedDate = new Date(inst.startedAt).toLocaleDateString();
2171
- lines.push(`| ${inst.definitionName} | ${inst.requestedBy} | ${inst.status} | ${startedDate} |`);
2507
+ const startedDate = formatDate(inst.startedAt);
2508
+ const definitionName = workflowDefinitionById.get(inst.definitionId)?.name ?? inst.definitionId;
2509
+ lines.push(`| ${definitionName} | ${inst.requestedBy} | ${inst.status} | ${startedDate} |`);
2172
2510
  }
2173
2511
  }
2174
2512
  return {
@@ -2184,7 +2522,7 @@ var workflowDefinitionListMarkdownRenderer = {
2184
2522
  if (desc.source.type !== "component" || desc.source.componentKey !== "WorkflowDefinitionList") {
2185
2523
  throw new Error("workflowDefinitionListMarkdownRenderer: not WorkflowDefinitionList");
2186
2524
  }
2187
- const definitions = mockWorkflowDefinitions;
2525
+ const definitions = workflowDefinitions;
2188
2526
  const lines = [
2189
2527
  "# Workflow Definitions",
2190
2528
  "",
@@ -2199,7 +2537,7 @@ var workflowDefinitionListMarkdownRenderer = {
2199
2537
  lines.push("### Steps");
2200
2538
  lines.push("");
2201
2539
  for (const step of def.steps) {
2202
- lines.push(`${step.order}. **${step.name}** - Roles: ${step.requiredRoles.join(", ")}`);
2540
+ lines.push(`${step.stepOrder}. **${step.name}** - Roles: ${step.requiredRoles.join(", ")}`);
2203
2541
  }
2204
2542
  lines.push("");
2205
2543
  }
@@ -2216,7 +2554,7 @@ var workflowInstanceDetailMarkdownRenderer = {
2216
2554
  if (desc.source.type !== "component" || desc.source.componentKey !== "WorkflowInstanceDetail") {
2217
2555
  throw new Error("workflowInstanceDetailMarkdownRenderer: not WorkflowInstanceDetail");
2218
2556
  }
2219
- const instance = mockWorkflowInstances[0];
2557
+ const instance = workflowInstances.find((workflowInstance) => workflowInstance.status === "IN_PROGRESS") ?? workflowInstances[0];
2220
2558
  if (!instance) {
2221
2559
  return {
2222
2560
  mimeType: "text/markdown",
@@ -2225,14 +2563,14 @@ var workflowInstanceDetailMarkdownRenderer = {
2225
2563
  No workflow instances available.`
2226
2564
  };
2227
2565
  }
2228
- const definition = mockWorkflowDefinitions.find((d) => d.id === instance.definitionId);
2566
+ const definition = workflowDefinitions.find((d) => d.id === instance.definitionId);
2229
2567
  const lines = [
2230
- `# Workflow: ${instance.definitionName}`,
2568
+ `# Workflow: ${definition?.name ?? instance.definitionId}`,
2231
2569
  "",
2232
2570
  `**Instance ID:** ${instance.id}`,
2233
2571
  `**Status:** ${instance.status}`,
2234
2572
  `**Requested By:** ${instance.requestedBy}`,
2235
- `**Started:** ${new Date(instance.startedAt).toLocaleString()}`,
2573
+ `**Started:** ${formatDate(instance.startedAt)}`,
2236
2574
  "",
2237
2575
  "## Steps Progress",
2238
2576
  ""
@@ -2253,7 +2591,7 @@ No workflow instances available.`
2253
2591
  lines.push("## Actions");
2254
2592
  lines.push("");
2255
2593
  lines.push("- **Approve** - Move to next step");
2256
- lines.push("- **Reject** - Reject and return");
2594
+ lines.push("- **Reject** - End the workflow with a rejection outcome");
2257
2595
  lines.push("- **Delegate** - Assign to another approver");
2258
2596
  return {
2259
2597
  mimeType: "text/markdown",
@@ -2262,6 +2600,51 @@ No workflow instances available.`
2262
2600
  };
2263
2601
  }
2264
2602
  };
2603
+ // src/ui/WorkflowDashboard.visualizations.tsx
2604
+ import {
2605
+ ComparisonView,
2606
+ VisualizationCard,
2607
+ VisualizationGrid
2608
+ } from "@contractspec/lib.design-system";
2609
+ import { jsxDEV } from "react/jsx-dev-runtime";
2610
+ "use client";
2611
+ function WorkflowVisualizationOverview({
2612
+ instances
2613
+ }) {
2614
+ const { primaryItems, comparisonItems } = createWorkflowVisualizationSections(instances);
2615
+ return /* @__PURE__ */ jsxDEV("section", {
2616
+ className: "space-y-4",
2617
+ children: [
2618
+ /* @__PURE__ */ jsxDEV("div", {
2619
+ children: [
2620
+ /* @__PURE__ */ jsxDEV("h3", {
2621
+ className: "font-semibold text-lg",
2622
+ children: "Workflow Visualizations"
2623
+ }, undefined, false, undefined, this),
2624
+ /* @__PURE__ */ jsxDEV("p", {
2625
+ className: "text-muted-foreground text-sm",
2626
+ children: "Contract-backed charts for workflow health and throughput."
2627
+ }, undefined, false, undefined, this)
2628
+ ]
2629
+ }, undefined, true, undefined, this),
2630
+ /* @__PURE__ */ jsxDEV(VisualizationGrid, {
2631
+ children: primaryItems.map((item) => /* @__PURE__ */ jsxDEV(VisualizationCard, {
2632
+ data: item.data,
2633
+ description: item.description,
2634
+ height: item.height,
2635
+ spec: item.spec,
2636
+ title: item.title
2637
+ }, item.key, false, undefined, this))
2638
+ }, undefined, false, undefined, this),
2639
+ /* @__PURE__ */ jsxDEV(ComparisonView, {
2640
+ description: "Shared comparison surface for active versus completed work.",
2641
+ items: comparisonItems,
2642
+ title: "Workload Comparison"
2643
+ }, undefined, false, undefined, this)
2644
+ ]
2645
+ }, undefined, true, undefined, this);
2646
+ }
2647
+
2265
2648
  // src/ui/WorkflowDashboard.tsx
2266
2649
  import {
2267
2650
  Button,
@@ -2271,7 +2654,7 @@ import {
2271
2654
  StatCardGroup
2272
2655
  } from "@contractspec/lib.design-system";
2273
2656
  import { useState as useState2 } from "react";
2274
- import { jsxDEV } from "react/jsx-dev-runtime";
2657
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
2275
2658
  "use client";
2276
2659
  var STATUS_COLORS = {
2277
2660
  ACTIVE: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
@@ -2291,151 +2674,148 @@ function WorkflowDashboard() {
2291
2674
  { id: "instances", label: "Instances", icon: "\uD83D\uDD04" }
2292
2675
  ];
2293
2676
  if (loading) {
2294
- return /* @__PURE__ */ jsxDEV(LoaderBlock, {
2677
+ return /* @__PURE__ */ jsxDEV2(LoaderBlock, {
2295
2678
  label: "Loading Workflows..."
2296
2679
  }, undefined, false, undefined, this);
2297
2680
  }
2298
2681
  if (error) {
2299
- return /* @__PURE__ */ jsxDEV(ErrorState, {
2682
+ return /* @__PURE__ */ jsxDEV2(ErrorState, {
2300
2683
  title: "Failed to load Workflows",
2301
2684
  description: error.message,
2302
2685
  onRetry: refetch,
2303
2686
  retryLabel: "Retry"
2304
2687
  }, undefined, false, undefined, this);
2305
2688
  }
2306
- return /* @__PURE__ */ jsxDEV("div", {
2689
+ return /* @__PURE__ */ jsxDEV2("div", {
2307
2690
  className: "space-y-6",
2308
2691
  children: [
2309
- /* @__PURE__ */ jsxDEV("div", {
2692
+ /* @__PURE__ */ jsxDEV2("div", {
2310
2693
  className: "flex items-center justify-between",
2311
2694
  children: [
2312
- /* @__PURE__ */ jsxDEV("h2", {
2695
+ /* @__PURE__ */ jsxDEV2("h2", {
2313
2696
  className: "font-bold text-2xl",
2314
2697
  children: "Workflow System"
2315
2698
  }, undefined, false, undefined, this),
2316
- /* @__PURE__ */ jsxDEV(Button, {
2317
- onClick: () => alert("Create workflow modal"),
2318
- children: [
2319
- /* @__PURE__ */ jsxDEV("span", {
2320
- className: "mr-2",
2321
- children: "+"
2322
- }, undefined, false, undefined, this),
2323
- " New Workflow"
2324
- ]
2325
- }, undefined, true, undefined, this)
2699
+ /* @__PURE__ */ jsxDEV2(Button, {
2700
+ onClick: () => void refetch(),
2701
+ children: "Refresh"
2702
+ }, undefined, false, undefined, this)
2326
2703
  ]
2327
2704
  }, undefined, true, undefined, this),
2328
- /* @__PURE__ */ jsxDEV(StatCardGroup, {
2705
+ /* @__PURE__ */ jsxDEV2(StatCardGroup, {
2329
2706
  children: [
2330
- /* @__PURE__ */ jsxDEV(StatCard, {
2707
+ /* @__PURE__ */ jsxDEV2(StatCard, {
2331
2708
  label: "Workflows",
2332
2709
  value: stats.totalDefinitions,
2333
2710
  hint: `${stats.activeDefinitions} active`
2334
2711
  }, undefined, false, undefined, this),
2335
- /* @__PURE__ */ jsxDEV(StatCard, {
2712
+ /* @__PURE__ */ jsxDEV2(StatCard, {
2336
2713
  label: "Instances",
2337
2714
  value: stats.totalInstances,
2338
2715
  hint: "total runs"
2339
2716
  }, undefined, false, undefined, this),
2340
- /* @__PURE__ */ jsxDEV(StatCard, {
2341
- label: "Pending",
2342
- value: stats.pendingInstances,
2343
- hint: "awaiting action"
2717
+ /* @__PURE__ */ jsxDEV2(StatCard, {
2718
+ label: "Awaiting Action",
2719
+ value: stats.pendingInstances + stats.inProgressInstances,
2720
+ hint: "open approvals"
2344
2721
  }, undefined, false, undefined, this),
2345
- /* @__PURE__ */ jsxDEV(StatCard, {
2722
+ /* @__PURE__ */ jsxDEV2(StatCard, {
2346
2723
  label: "Completed",
2347
2724
  value: stats.completedInstances,
2348
2725
  hint: "finished"
2349
2726
  }, undefined, false, undefined, this)
2350
2727
  ]
2351
2728
  }, undefined, true, undefined, this),
2352
- /* @__PURE__ */ jsxDEV("nav", {
2729
+ /* @__PURE__ */ jsxDEV2(WorkflowVisualizationOverview, {
2730
+ instances
2731
+ }, undefined, false, undefined, this),
2732
+ /* @__PURE__ */ jsxDEV2("nav", {
2353
2733
  className: "flex gap-1 rounded-lg bg-muted p-1",
2354
2734
  role: "tablist",
2355
- children: tabs.map((tab) => /* @__PURE__ */ jsxDEV(Button, {
2735
+ children: tabs.map((tab) => /* @__PURE__ */ jsxDEV2(Button, {
2356
2736
  type: "button",
2357
2737
  role: "tab",
2358
2738
  "aria-selected": activeTab === tab.id,
2359
2739
  onClick: () => setActiveTab(tab.id),
2360
2740
  className: `flex flex-1 items-center justify-center gap-2 rounded-md px-4 py-2 font-medium text-sm transition-colors ${activeTab === tab.id ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
2361
2741
  children: [
2362
- /* @__PURE__ */ jsxDEV("span", {
2742
+ /* @__PURE__ */ jsxDEV2("span", {
2363
2743
  children: tab.icon
2364
2744
  }, undefined, false, undefined, this),
2365
2745
  tab.label
2366
2746
  ]
2367
2747
  }, tab.id, true, undefined, this))
2368
2748
  }, undefined, false, undefined, this),
2369
- /* @__PURE__ */ jsxDEV("div", {
2749
+ /* @__PURE__ */ jsxDEV2("div", {
2370
2750
  className: "min-h-[400px]",
2371
2751
  role: "tabpanel",
2372
2752
  children: [
2373
- activeTab === "definitions" && /* @__PURE__ */ jsxDEV("div", {
2753
+ activeTab === "definitions" && /* @__PURE__ */ jsxDEV2("div", {
2374
2754
  className: "rounded-lg border border-border",
2375
- children: /* @__PURE__ */ jsxDEV("table", {
2755
+ children: /* @__PURE__ */ jsxDEV2("table", {
2376
2756
  className: "w-full",
2377
2757
  children: [
2378
- /* @__PURE__ */ jsxDEV("thead", {
2758
+ /* @__PURE__ */ jsxDEV2("thead", {
2379
2759
  className: "border-border border-b bg-muted/30",
2380
- children: /* @__PURE__ */ jsxDEV("tr", {
2760
+ children: /* @__PURE__ */ jsxDEV2("tr", {
2381
2761
  children: [
2382
- /* @__PURE__ */ jsxDEV("th", {
2762
+ /* @__PURE__ */ jsxDEV2("th", {
2383
2763
  className: "px-4 py-3 text-left font-medium text-sm",
2384
2764
  children: "Name"
2385
2765
  }, undefined, false, undefined, this),
2386
- /* @__PURE__ */ jsxDEV("th", {
2766
+ /* @__PURE__ */ jsxDEV2("th", {
2387
2767
  className: "px-4 py-3 text-left font-medium text-sm",
2388
2768
  children: "Type"
2389
2769
  }, undefined, false, undefined, this),
2390
- /* @__PURE__ */ jsxDEV("th", {
2770
+ /* @__PURE__ */ jsxDEV2("th", {
2391
2771
  className: "px-4 py-3 text-left font-medium text-sm",
2392
2772
  children: "Status"
2393
2773
  }, undefined, false, undefined, this),
2394
- /* @__PURE__ */ jsxDEV("th", {
2774
+ /* @__PURE__ */ jsxDEV2("th", {
2395
2775
  className: "px-4 py-3 text-left font-medium text-sm",
2396
2776
  children: "Created"
2397
2777
  }, undefined, false, undefined, this)
2398
2778
  ]
2399
2779
  }, undefined, true, undefined, this)
2400
2780
  }, undefined, false, undefined, this),
2401
- /* @__PURE__ */ jsxDEV("tbody", {
2781
+ /* @__PURE__ */ jsxDEV2("tbody", {
2402
2782
  className: "divide-y divide-border",
2403
2783
  children: [
2404
- definitions.map((def) => /* @__PURE__ */ jsxDEV("tr", {
2784
+ definitions.map((def) => /* @__PURE__ */ jsxDEV2("tr", {
2405
2785
  className: "hover:bg-muted/50",
2406
2786
  children: [
2407
- /* @__PURE__ */ jsxDEV("td", {
2787
+ /* @__PURE__ */ jsxDEV2("td", {
2408
2788
  className: "px-4 py-3",
2409
2789
  children: [
2410
- /* @__PURE__ */ jsxDEV("div", {
2790
+ /* @__PURE__ */ jsxDEV2("div", {
2411
2791
  className: "font-medium",
2412
2792
  children: def.name
2413
2793
  }, undefined, false, undefined, this),
2414
- /* @__PURE__ */ jsxDEV("div", {
2794
+ /* @__PURE__ */ jsxDEV2("div", {
2415
2795
  className: "text-muted-foreground text-sm",
2416
2796
  children: def.description
2417
2797
  }, undefined, false, undefined, this)
2418
2798
  ]
2419
2799
  }, undefined, true, undefined, this),
2420
- /* @__PURE__ */ jsxDEV("td", {
2800
+ /* @__PURE__ */ jsxDEV2("td", {
2421
2801
  className: "px-4 py-3 font-mono text-sm",
2422
2802
  children: def.type
2423
2803
  }, undefined, false, undefined, this),
2424
- /* @__PURE__ */ jsxDEV("td", {
2804
+ /* @__PURE__ */ jsxDEV2("td", {
2425
2805
  className: "px-4 py-3",
2426
- children: /* @__PURE__ */ jsxDEV("span", {
2806
+ children: /* @__PURE__ */ jsxDEV2("span", {
2427
2807
  className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[def.status] ?? ""}`,
2428
2808
  children: def.status
2429
2809
  }, undefined, false, undefined, this)
2430
2810
  }, undefined, false, undefined, this),
2431
- /* @__PURE__ */ jsxDEV("td", {
2811
+ /* @__PURE__ */ jsxDEV2("td", {
2432
2812
  className: "px-4 py-3 text-muted-foreground text-sm",
2433
2813
  children: def.createdAt.toLocaleDateString()
2434
2814
  }, undefined, false, undefined, this)
2435
2815
  ]
2436
2816
  }, def.id, true, undefined, this)),
2437
- definitions.length === 0 && /* @__PURE__ */ jsxDEV("tr", {
2438
- children: /* @__PURE__ */ jsxDEV("td", {
2817
+ definitions.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
2818
+ children: /* @__PURE__ */ jsxDEV2("td", {
2439
2819
  colSpan: 4,
2440
2820
  className: "px-4 py-8 text-center text-muted-foreground",
2441
2821
  children: "No workflow definitions found"
@@ -2446,63 +2826,63 @@ function WorkflowDashboard() {
2446
2826
  ]
2447
2827
  }, undefined, true, undefined, this)
2448
2828
  }, undefined, false, undefined, this),
2449
- activeTab === "instances" && /* @__PURE__ */ jsxDEV("div", {
2829
+ activeTab === "instances" && /* @__PURE__ */ jsxDEV2("div", {
2450
2830
  className: "rounded-lg border border-border",
2451
- children: /* @__PURE__ */ jsxDEV("table", {
2831
+ children: /* @__PURE__ */ jsxDEV2("table", {
2452
2832
  className: "w-full",
2453
2833
  children: [
2454
- /* @__PURE__ */ jsxDEV("thead", {
2834
+ /* @__PURE__ */ jsxDEV2("thead", {
2455
2835
  className: "border-border border-b bg-muted/30",
2456
- children: /* @__PURE__ */ jsxDEV("tr", {
2836
+ children: /* @__PURE__ */ jsxDEV2("tr", {
2457
2837
  children: [
2458
- /* @__PURE__ */ jsxDEV("th", {
2838
+ /* @__PURE__ */ jsxDEV2("th", {
2459
2839
  className: "px-4 py-3 text-left font-medium text-sm",
2460
2840
  children: "Instance ID"
2461
2841
  }, undefined, false, undefined, this),
2462
- /* @__PURE__ */ jsxDEV("th", {
2842
+ /* @__PURE__ */ jsxDEV2("th", {
2463
2843
  className: "px-4 py-3 text-left font-medium text-sm",
2464
2844
  children: "Status"
2465
2845
  }, undefined, false, undefined, this),
2466
- /* @__PURE__ */ jsxDEV("th", {
2846
+ /* @__PURE__ */ jsxDEV2("th", {
2467
2847
  className: "px-4 py-3 text-left font-medium text-sm",
2468
2848
  children: "Requested By"
2469
2849
  }, undefined, false, undefined, this),
2470
- /* @__PURE__ */ jsxDEV("th", {
2850
+ /* @__PURE__ */ jsxDEV2("th", {
2471
2851
  className: "px-4 py-3 text-left font-medium text-sm",
2472
2852
  children: "Started"
2473
2853
  }, undefined, false, undefined, this)
2474
2854
  ]
2475
2855
  }, undefined, true, undefined, this)
2476
2856
  }, undefined, false, undefined, this),
2477
- /* @__PURE__ */ jsxDEV("tbody", {
2857
+ /* @__PURE__ */ jsxDEV2("tbody", {
2478
2858
  className: "divide-y divide-border",
2479
2859
  children: [
2480
- instances.map((inst) => /* @__PURE__ */ jsxDEV("tr", {
2860
+ instances.map((inst) => /* @__PURE__ */ jsxDEV2("tr", {
2481
2861
  className: "hover:bg-muted/50",
2482
2862
  children: [
2483
- /* @__PURE__ */ jsxDEV("td", {
2863
+ /* @__PURE__ */ jsxDEV2("td", {
2484
2864
  className: "px-4 py-3 font-mono text-sm",
2485
2865
  children: inst.id
2486
2866
  }, undefined, false, undefined, this),
2487
- /* @__PURE__ */ jsxDEV("td", {
2867
+ /* @__PURE__ */ jsxDEV2("td", {
2488
2868
  className: "px-4 py-3",
2489
- children: /* @__PURE__ */ jsxDEV("span", {
2869
+ children: /* @__PURE__ */ jsxDEV2("span", {
2490
2870
  className: `inline-flex rounded-full px-2 py-0.5 font-medium text-xs ${STATUS_COLORS[inst.status] ?? ""}`,
2491
2871
  children: inst.status
2492
2872
  }, undefined, false, undefined, this)
2493
2873
  }, undefined, false, undefined, this),
2494
- /* @__PURE__ */ jsxDEV("td", {
2874
+ /* @__PURE__ */ jsxDEV2("td", {
2495
2875
  className: "px-4 py-3 text-sm",
2496
2876
  children: inst.requestedBy
2497
2877
  }, undefined, false, undefined, this),
2498
- /* @__PURE__ */ jsxDEV("td", {
2878
+ /* @__PURE__ */ jsxDEV2("td", {
2499
2879
  className: "px-4 py-3 text-muted-foreground text-sm",
2500
2880
  children: inst.startedAt.toLocaleDateString()
2501
2881
  }, undefined, false, undefined, this)
2502
2882
  ]
2503
2883
  }, inst.id, true, undefined, this)),
2504
- instances.length === 0 && /* @__PURE__ */ jsxDEV("tr", {
2505
- children: /* @__PURE__ */ jsxDEV("td", {
2884
+ instances.length === 0 && /* @__PURE__ */ jsxDEV2("tr", {
2885
+ children: /* @__PURE__ */ jsxDEV2("td", {
2506
2886
  colSpan: 4,
2507
2887
  className: "px-4 py-8 text-center text-muted-foreground",
2508
2888
  children: "No workflow instances found"
@@ -3027,6 +3407,7 @@ var WorkflowSystemFeature = defineFeature({
3027
3407
  targets: ["react", "markdown"]
3028
3408
  }
3029
3409
  ],
3410
+ visualizations: WorkflowVisualizationRefs,
3030
3411
  capabilities: {
3031
3412
  requires: [
3032
3413
  { key: "identity", version: "1.0.0" },
@@ -3061,11 +3442,16 @@ export {
3061
3442
  workflowDashboardMarkdownRenderer,
3062
3443
  useWorkflowList,
3063
3444
  mockDataStore,
3445
+ createWorkflowVisualizationSections,
3064
3446
  createWorkflowHandlers,
3065
3447
  createStateMachineEngine,
3066
3448
  createInitialState,
3067
3449
  buildStateMachineDefinition,
3450
+ WorkflowVisualizationSpecs,
3451
+ WorkflowVisualizationRegistry,
3452
+ WorkflowVisualizationRefs,
3068
3453
  WorkflowUpdatedEvent,
3454
+ WorkflowThroughputVisualization,
3069
3455
  WorkflowSystemPresentations,
3070
3456
  WorkflowSystemFeature,
3071
3457
  WorkflowStepModel,
@@ -3073,12 +3459,15 @@ export {
3073
3459
  WorkflowPublishedEvent,
3074
3460
  WorkflowMetricsPresentation,
3075
3461
  WorkflowListPresentation,
3462
+ WorkflowInstanceStatusVisualization,
3076
3463
  WorkflowInstanceModel,
3077
3464
  WorkflowDetailPresentation,
3078
3465
  WorkflowDesignerPresentation,
3079
3466
  WorkflowDefinitionModel,
3080
3467
  WorkflowDashboard,
3081
3468
  WorkflowCreatedEvent,
3469
+ WorkflowCompletedMetricVisualization,
3470
+ WorkflowActiveMetricVisualization,
3082
3471
  UpdateWorkflowInputModel,
3083
3472
  UpdateWorkflowContract,
3084
3473
  TriggerTypeEnum,