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