@shipfox/client-workflows 5.0.0 → 6.0.1

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 (121) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +53 -0
  3. package/dist/components/workflow-run-list/types.d.ts +12 -0
  4. package/dist/components/workflow-run-list/types.d.ts.map +1 -1
  5. package/dist/components/workflow-run-list/types.js.map +1 -1
  6. package/dist/components/workflow-run-list/workflow-run-list-view.d.ts +1 -1
  7. package/dist/components/workflow-run-list/workflow-run-list-view.d.ts.map +1 -1
  8. package/dist/components/workflow-run-list/workflow-run-list-view.js +32 -11
  9. package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
  10. package/dist/components/workflow-run-list/workflow-run-list.d.ts +1 -1
  11. package/dist/components/workflow-run-list/workflow-run-list.d.ts.map +1 -1
  12. package/dist/components/workflow-run-list/workflow-run-list.js +7 -2
  13. package/dist/components/workflow-run-list/workflow-run-list.js.map +1 -1
  14. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts +2 -3
  15. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
  16. package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
  17. package/dist/components/workflow-run-view/job-card.d.ts.map +1 -1
  18. package/dist/components/workflow-run-view/job-card.js +9 -8
  19. package/dist/components/workflow-run-view/job-card.js.map +1 -1
  20. package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
  21. package/dist/core/entities/job-execution.d.ts +11 -6
  22. package/dist/core/entities/job-execution.d.ts.map +1 -1
  23. package/dist/core/entities/job-execution.js +0 -19
  24. package/dist/core/entities/job-execution.js.map +1 -1
  25. package/dist/core/entities/job.d.ts +32 -10
  26. package/dist/core/entities/job.d.ts.map +1 -1
  27. package/dist/core/entities/job.js +0 -22
  28. package/dist/core/entities/job.js.map +1 -1
  29. package/dist/core/entities/step-attempt.d.ts +28 -3
  30. package/dist/core/entities/step-attempt.d.ts.map +1 -1
  31. package/dist/core/entities/step-attempt.js +0 -17
  32. package/dist/core/entities/step-attempt.js.map +1 -1
  33. package/dist/core/entities/step.d.ts +6 -6
  34. package/dist/core/entities/step.d.ts.map +1 -1
  35. package/dist/core/entities/step.js +19 -49
  36. package/dist/core/entities/step.js.map +1 -1
  37. package/dist/core/entities/workflow-run-attempt.d.ts +0 -2
  38. package/dist/core/entities/workflow-run-attempt.d.ts.map +1 -1
  39. package/dist/core/entities/workflow-run-attempt.js +0 -12
  40. package/dist/core/entities/workflow-run-attempt.js.map +1 -1
  41. package/dist/core/entities/workflow-run.d.ts +6 -7
  42. package/dist/core/entities/workflow-run.d.ts.map +1 -1
  43. package/dist/core/entities/workflow-run.js +1 -67
  44. package/dist/core/entities/workflow-run.js.map +1 -1
  45. package/dist/core/workflow-run.d.ts +9 -9
  46. package/dist/core/workflow-run.d.ts.map +1 -1
  47. package/dist/core/workflow-run.js +6 -6
  48. package/dist/core/workflow-run.js.map +1 -1
  49. package/dist/feature.d.ts +13 -0
  50. package/dist/feature.d.ts.map +1 -1
  51. package/dist/feature.js +17 -16
  52. package/dist/feature.js.map +1 -1
  53. package/dist/hooks/api/workflow-run-mapper.d.ts +12 -0
  54. package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -0
  55. package/dist/hooks/api/workflow-run-mapper.js +207 -0
  56. package/dist/hooks/api/workflow-run-mapper.js.map +1 -0
  57. package/dist/hooks/api/workflow-runs.d.ts +25 -55
  58. package/dist/hooks/api/workflow-runs.d.ts.map +1 -1
  59. package/dist/hooks/api/workflow-runs.js +95 -51
  60. package/dist/hooks/api/workflow-runs.js.map +1 -1
  61. package/dist/index.d.ts +2 -2
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +1 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/pages/project-workflows-page.d.ts.map +1 -1
  66. package/dist/pages/project-workflows-page.js +14 -14
  67. package/dist/pages/project-workflows-page.js.map +1 -1
  68. package/dist/pages/workflow-run-page.d.ts +3 -1
  69. package/dist/pages/workflow-run-page.d.ts.map +1 -1
  70. package/dist/pages/workflow-run-page.js +21 -14
  71. package/dist/pages/workflow-run-page.js.map +1 -1
  72. package/dist/routes/inputs.d.ts +22 -0
  73. package/dist/routes/inputs.d.ts.map +1 -0
  74. package/dist/routes/inputs.js +76 -0
  75. package/dist/routes/inputs.js.map +1 -0
  76. package/dist/routes/run-detail.d.ts +2 -0
  77. package/dist/routes/run-detail.d.ts.map +1 -1
  78. package/dist/routes/run-detail.js +6 -6
  79. package/dist/routes/run-detail.js.map +1 -1
  80. package/dist/routes/runs.d.ts +2 -0
  81. package/dist/routes/runs.d.ts.map +1 -1
  82. package/dist/routes/runs.js +6 -6
  83. package/dist/routes/runs.js.map +1 -1
  84. package/dist/routes/workflows.js +3 -5
  85. package/dist/routes/workflows.js.map +1 -1
  86. package/dist/tsconfig.test.tsbuildinfo +1 -1
  87. package/package.json +13 -14
  88. package/src/components/workflow-run-list/types.ts +6 -0
  89. package/src/components/workflow-run-list/workflow-run-list-view.tsx +27 -11
  90. package/src/components/workflow-run-list/workflow-run-list.tsx +6 -0
  91. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.test.tsx +5 -6
  92. package/src/components/workflow-run-summary/workflow-run-summary.tsx +3 -3
  93. package/src/components/workflow-run-view/job-card.tsx +20 -11
  94. package/src/components/workflow-run-view/workflow-run-view.test.tsx +3 -3
  95. package/src/components/workflow-run-view/workflow-run-view.tsx +2 -2
  96. package/src/core/entities/job-execution.ts +12 -28
  97. package/src/core/entities/job.ts +44 -45
  98. package/src/core/entities/step-attempt.ts +9 -20
  99. package/src/core/entities/step.ts +38 -66
  100. package/src/core/entities/workflow-run-attempt.ts +0 -14
  101. package/src/core/entities/workflow-run.ts +8 -86
  102. package/src/core/workflow-run.test.ts +13 -11
  103. package/src/core/workflow-run.ts +8 -13
  104. package/src/feature.ts +19 -17
  105. package/src/hooks/api/workflow-run-mapper.ts +246 -0
  106. package/src/hooks/api/workflow-runs.test.tsx +57 -59
  107. package/src/hooks/api/workflow-runs.ts +187 -88
  108. package/src/index.ts +4 -0
  109. package/src/pages/project-workflows-page.test.tsx +1 -1
  110. package/src/pages/project-workflows-page.tsx +31 -26
  111. package/src/pages/workflow-run-page.test.tsx +4 -2
  112. package/src/pages/workflow-run-page.tsx +22 -17
  113. package/src/routes/inputs.test.ts +22 -0
  114. package/src/routes/inputs.ts +58 -0
  115. package/src/routes/run-detail.tsx +12 -8
  116. package/src/routes/runs.tsx +11 -4
  117. package/src/routes/workflows.tsx +3 -3
  118. package/test/fixtures/workflow-run.ts +9 -7
  119. package/test/pages.tsx +20 -5
  120. package/tsconfig.build.tsbuildinfo +1 -1
  121. package/vercel.json +5 -0
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 58 files with swc (549.51ms)
2
+ Successfully compiled: 60 files with swc (551.82ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # @shipfox/client-workflows
2
2
 
3
+ ## 6.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 475ce59: Republishes all public packages after restoring release authorization.
8
+ - 3f8f1cb: Enforces typed route-input and browser-storage boundaries across client features.
9
+ - Updated dependencies [475ce59]
10
+ - Updated dependencies [3f8f1cb]
11
+ - @shipfox/api-definitions-dto@9.0.1
12
+ - @shipfox/api-workflows-dto@9.0.1
13
+ - @shipfox/client-api@6.0.1
14
+ - @shipfox/client-logs@6.0.1
15
+ - @shipfox/client-projects@6.0.1
16
+ - @shipfox/client-shell@6.0.1
17
+ - @shipfox/client-triggers@6.0.1
18
+ - @shipfox/client-ui@6.0.1
19
+ - @shipfox/react-ui@0.3.6
20
+
21
+ ## 6.0.0
22
+
23
+ ### Major Changes
24
+
25
+ - 24be269: Makes checked API adapters the only public business-response boundary and returns package-owned domain models from Agent, Integrations, and Workflows adapters.
26
+
27
+ ### Minor Changes
28
+
29
+ - 401b583: Exposes typed feature-owned navigation and settings contributions and enforces coordinator-owned client composition.
30
+
31
+ ### Patch Changes
32
+
33
+ - d784a07: Enforces checked client API responses and removes stale transport compatibility helpers.
34
+ - 82eda45: Adds validated URL-owned project and workflow run filters for shareable navigation state.
35
+ - 125c90f: Adds checked Projects domain models and resource-owned query cache policy.
36
+ - bb29e41: Converges workflow query caches on transport-independent domain models.
37
+ - Updated dependencies [401b583]
38
+ - Updated dependencies [82eda45]
39
+ - Updated dependencies [125c90f]
40
+ - Updated dependencies [f2d50a8]
41
+ - Updated dependencies [cd90c19]
42
+ - Updated dependencies [24be269]
43
+ - Updated dependencies [c56c124]
44
+ - Updated dependencies [4a6d124]
45
+ - Updated dependencies [c02ac42]
46
+ - @shipfox/client-projects@6.0.0
47
+ - @shipfox/client-shell@6.0.0
48
+ - @shipfox/client-triggers@6.0.0
49
+ - @shipfox/client-api@6.0.0
50
+ - @shipfox/api-definitions-dto@6.0.0
51
+ - @shipfox/api-workflows-dto@9.0.0
52
+ - @shipfox/client-logs@6.0.0
53
+ - @shipfox/client-ui@6.0.0
54
+ - @shipfox/react-ui@0.3.5
55
+
3
56
  ## 5.0.0
4
57
 
5
58
  ### Patch Changes
@@ -6,6 +6,12 @@ export interface WorkflowRunListProps {
6
6
  projectId: string;
7
7
  selectedWorkflowRunId?: string | undefined;
8
8
  className?: string | undefined;
9
+ search?: string;
10
+ statusFilter?: WorkflowRunListStatusFilter;
11
+ onFiltersChange?: (filters: {
12
+ search?: string;
13
+ status?: WorkflowRunListStatusFilter;
14
+ }) => void;
9
15
  }
10
16
  export type WorkflowRunListQuery = QueryLoadErrorQuery & {
11
17
  isPending: boolean;
@@ -17,5 +23,11 @@ export interface WorkflowRunListViewProps {
17
23
  projectId: string;
18
24
  selectedWorkflowRunId?: string | undefined;
19
25
  className?: string | undefined;
26
+ search?: string;
27
+ statusFilter?: WorkflowRunListStatusFilter;
28
+ onFiltersChange?: (filters: {
29
+ search?: string;
30
+ status?: WorkflowRunListStatusFilter;
31
+ }) => void;
20
32
  }
21
33
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-list/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAE/D,MAAM,MAAM,2BAA2B,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,GAAG;IAAC,SAAS,EAAE,OAAO,CAAA;CAAC,CAAC;AAE9E,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,mBAAmB,EAAE,CAAC;IAC5B,KAAK,EAAE,oBAAoB,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-list/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAE/D,MAAM,MAAM,2BAA2B,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,2BAA2B,CAAC;IAC3C,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,2BAA2B,CAAA;KAAC,KAAK,IAAI,CAAC;CAC9F;AAED,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,GAAG;IAAC,SAAS,EAAE,OAAO,CAAA;CAAC,CAAC;AAE9E,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,mBAAmB,EAAE,CAAC;IAC5B,KAAK,EAAE,oBAAoB,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,2BAA2B,CAAC;IAC3C,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,2BAA2B,CAAA;KAAC,KAAK,IAAI,CAAC;CAC9F"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/workflow-run-list/types.ts"],"sourcesContent":["import type {QueryLoadErrorQuery} from '@shipfox/client-ui';\nimport type {WorkflowRunListItem} from '#core/workflow-run.js';\n\nexport type WorkflowRunListStatusFilter = 'all' | 'failed' | 'running';\n\nexport interface WorkflowRunListProps {\n workspaceId: string;\n projectId: string;\n selectedWorkflowRunId?: string | undefined;\n className?: string | undefined;\n}\n\nexport type WorkflowRunListQuery = QueryLoadErrorQuery & {isPending: boolean};\n\nexport interface WorkflowRunListViewProps {\n runs: WorkflowRunListItem[];\n query: WorkflowRunListQuery;\n workspaceId: string;\n projectId: string;\n selectedWorkflowRunId?: string | undefined;\n className?: string | undefined;\n}\n"],"names":[],"mappings":"AAcA,WAOC"}
1
+ {"version":3,"sources":["../../../src/components/workflow-run-list/types.ts"],"sourcesContent":["import type {QueryLoadErrorQuery} from '@shipfox/client-ui';\nimport type {WorkflowRunListItem} from '#core/workflow-run.js';\n\nexport type WorkflowRunListStatusFilter = 'all' | 'failed' | 'running';\n\nexport interface WorkflowRunListProps {\n workspaceId: string;\n projectId: string;\n selectedWorkflowRunId?: string | undefined;\n className?: string | undefined;\n search?: string;\n statusFilter?: WorkflowRunListStatusFilter;\n onFiltersChange?: (filters: {search?: string; status?: WorkflowRunListStatusFilter}) => void;\n}\n\nexport type WorkflowRunListQuery = QueryLoadErrorQuery & {isPending: boolean};\n\nexport interface WorkflowRunListViewProps {\n runs: WorkflowRunListItem[];\n query: WorkflowRunListQuery;\n workspaceId: string;\n projectId: string;\n selectedWorkflowRunId?: string | undefined;\n className?: string | undefined;\n search?: string;\n statusFilter?: WorkflowRunListStatusFilter;\n onFiltersChange?: (filters: {search?: string; status?: WorkflowRunListStatusFilter}) => void;\n}\n"],"names":[],"mappings":"AAiBA,WAUC"}
@@ -1,3 +1,3 @@
1
1
  import type { WorkflowRunListViewProps } from './types.js';
2
- export declare function WorkflowRunListView({ runs, query, workspaceId, projectId, selectedWorkflowRunId, className, }: WorkflowRunListViewProps): import("react").JSX.Element;
2
+ export declare function WorkflowRunListView({ runs, query, workspaceId, projectId, selectedWorkflowRunId, className, search, statusFilter, onFiltersChange, }: WorkflowRunListViewProps): import("react").JSX.Element;
3
3
  //# sourceMappingURL=workflow-run-list-view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-run-list-view.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-list/workflow-run-list-view.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAA8B,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAItF,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,KAAK,EACL,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,SAAS,GACV,EAAE,wBAAwB,+BAyC1B"}
1
+ {"version":3,"file":"workflow-run-list-view.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-list/workflow-run-list-view.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAIzD,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,KAAK,EACL,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,SAAS,EACT,MAAW,EACX,YAAoB,EACpB,eAAe,GAChB,EAAE,wBAAwB,+BAsD1B"}
@@ -5,16 +5,21 @@ import { useState } from 'react';
5
5
  import { runMatchesSearch, runMatchesStatusFilter } from './run-display.js';
6
6
  import { WorkflowRunListContent } from './workflow-run-list-content.js';
7
7
  import { WorkflowRunListHeader } from './workflow-run-list-header.js';
8
- export function WorkflowRunListView({ runs, query, workspaceId, projectId, selectedWorkflowRunId, className }) {
9
- const [search, setSearch] = useState('');
10
- const [statusFilter, setStatusFilter] = useState('all');
8
+ export function WorkflowRunListView({ runs, query, workspaceId, projectId, selectedWorkflowRunId, className, search = '', statusFilter = 'all', onFiltersChange }) {
9
+ const [localSearch, setLocalSearch] = useState(search);
10
+ const [localStatusFilter, setLocalStatusFilter] = useState(statusFilter);
11
+ const currentSearch = onFiltersChange ? search : localSearch;
12
+ const currentStatusFilter = onFiltersChange ? statusFilter : localStatusFilter;
11
13
  const filteredRuns = runs.filter((run)=>{
12
- if (!runMatchesStatusFilter(run.status, statusFilter)) return false;
13
- return runMatchesSearch(run, search);
14
+ if (!runMatchesStatusFilter(run.status, currentStatusFilter)) return false;
15
+ return runMatchesSearch(run, currentSearch);
14
16
  });
15
17
  function handleClearFilters() {
16
- setSearch('');
17
- setStatusFilter('all');
18
+ if (onFiltersChange) onFiltersChange({});
19
+ else {
20
+ setLocalSearch('');
21
+ setLocalStatusFilter('all');
22
+ }
18
23
  }
19
24
  return /*#__PURE__*/ _jsx(TimeTickerProvider, {
20
25
  intervalMs: 1000,
@@ -24,10 +29,26 @@ export function WorkflowRunListView({ runs, query, workspaceId, projectId, selec
24
29
  "aria-label": "Workflow runs",
25
30
  children: [
26
31
  /*#__PURE__*/ _jsx(WorkflowRunListHeader, {
27
- query: search,
28
- onQueryChange: setSearch,
29
- statusFilter: statusFilter,
30
- onStatusFilterChange: setStatusFilter
32
+ query: currentSearch,
33
+ onQueryChange: (next)=>{
34
+ if (onFiltersChange) onFiltersChange({
35
+ ...next ? {
36
+ search: next
37
+ } : {},
38
+ status: currentStatusFilter
39
+ });
40
+ else setLocalSearch(next);
41
+ },
42
+ statusFilter: currentStatusFilter,
43
+ onStatusFilterChange: (next)=>{
44
+ if (onFiltersChange) onFiltersChange({
45
+ ...currentSearch ? {
46
+ search: currentSearch
47
+ } : {},
48
+ status: next
49
+ });
50
+ else setLocalStatusFilter(next);
51
+ }
31
52
  }),
32
53
  /*#__PURE__*/ _jsx(WorkflowRunListContent, {
33
54
  query: query,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-list-view.tsx"],"sourcesContent":["import {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useState} from 'react';\nimport {runMatchesSearch, runMatchesStatusFilter} from './run-display.js';\nimport type {WorkflowRunListStatusFilter, WorkflowRunListViewProps} from './types.js';\nimport {WorkflowRunListContent} from './workflow-run-list-content.js';\nimport {WorkflowRunListHeader} from './workflow-run-list-header.js';\n\nexport function WorkflowRunListView({\n runs,\n query,\n workspaceId,\n projectId,\n selectedWorkflowRunId,\n className,\n}: WorkflowRunListViewProps) {\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<WorkflowRunListStatusFilter>('all');\n\n const filteredRuns = runs.filter((run) => {\n if (!runMatchesStatusFilter(run.status, statusFilter)) return false;\n return runMatchesSearch(run, search);\n });\n\n function handleClearFilters() {\n setSearch('');\n setStatusFilter('all');\n }\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <aside\n className={cn(\n 'flex w-304 shrink-0 flex-col border-r border-border-neutral-base bg-background-subtle-base',\n className,\n )}\n aria-label=\"Workflow runs\"\n >\n <WorkflowRunListHeader\n query={search}\n onQueryChange={setSearch}\n statusFilter={statusFilter}\n onStatusFilterChange={setStatusFilter}\n />\n <WorkflowRunListContent\n query={query}\n totalRuns={runs.length}\n runs={filteredRuns}\n workspaceId={workspaceId}\n projectId={projectId}\n selectedWorkflowRunId={selectedWorkflowRunId}\n onClearFilters={handleClearFilters}\n />\n </aside>\n </TimeTickerProvider>\n );\n}\n"],"names":["TimeTickerProvider","cn","useState","runMatchesSearch","runMatchesStatusFilter","WorkflowRunListContent","WorkflowRunListHeader","WorkflowRunListView","runs","query","workspaceId","projectId","selectedWorkflowRunId","className","search","setSearch","statusFilter","setStatusFilter","filteredRuns","filter","run","status","handleClearFilters","intervalMs","reducedMotionIntervalMs","aside","aria-label","onQueryChange","onStatusFilterChange","totalRuns","length","onClearFilters"],"mappings":";AAAA,SAAQA,kBAAkB,QAAO,gCAAgC;AACjE,SAAQC,EAAE,QAAO,0BAA0B;AAC3C,SAAQC,QAAQ,QAAO,QAAQ;AAC/B,SAAQC,gBAAgB,EAAEC,sBAAsB,QAAO,mBAAmB;AAE1E,SAAQC,sBAAsB,QAAO,iCAAiC;AACtE,SAAQC,qBAAqB,QAAO,gCAAgC;AAEpE,OAAO,SAASC,oBAAoB,EAClCC,IAAI,EACJC,KAAK,EACLC,WAAW,EACXC,SAAS,EACTC,qBAAqB,EACrBC,SAAS,EACgB;IACzB,MAAM,CAACC,QAAQC,UAAU,GAAGb,SAAS;IACrC,MAAM,CAACc,cAAcC,gBAAgB,GAAGf,SAAsC;IAE9E,MAAMgB,eAAeV,KAAKW,MAAM,CAAC,CAACC;QAChC,IAAI,CAAChB,uBAAuBgB,IAAIC,MAAM,EAAEL,eAAe,OAAO;QAC9D,OAAOb,iBAAiBiB,KAAKN;IAC/B;IAEA,SAASQ;QACPP,UAAU;QACVE,gBAAgB;IAClB;IAEA,qBACE,KAACjB;QAAmBuB,YAAY;QAAMC,yBAAyB;kBAC7D,cAAA,MAACC;YACCZ,WAAWZ,GACT,8FACAY;YAEFa,cAAW;;8BAEX,KAACpB;oBACCG,OAAOK;oBACPa,eAAeZ;oBACfC,cAAcA;oBACdY,sBAAsBX;;8BAExB,KAACZ;oBACCI,OAAOA;oBACPoB,WAAWrB,KAAKsB,MAAM;oBACtBtB,MAAMU;oBACNR,aAAaA;oBACbC,WAAWA;oBACXC,uBAAuBA;oBACvBmB,gBAAgBT;;;;;AAK1B"}
1
+ {"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-list-view.tsx"],"sourcesContent":["import {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useState} from 'react';\nimport {runMatchesSearch, runMatchesStatusFilter} from './run-display.js';\nimport type {WorkflowRunListViewProps} from './types.js';\nimport {WorkflowRunListContent} from './workflow-run-list-content.js';\nimport {WorkflowRunListHeader} from './workflow-run-list-header.js';\n\nexport function WorkflowRunListView({\n runs,\n query,\n workspaceId,\n projectId,\n selectedWorkflowRunId,\n className,\n search = '',\n statusFilter = 'all',\n onFiltersChange,\n}: WorkflowRunListViewProps) {\n const [localSearch, setLocalSearch] = useState(search);\n const [localStatusFilter, setLocalStatusFilter] = useState(statusFilter);\n const currentSearch = onFiltersChange ? search : localSearch;\n const currentStatusFilter = onFiltersChange ? statusFilter : localStatusFilter;\n\n const filteredRuns = runs.filter((run) => {\n if (!runMatchesStatusFilter(run.status, currentStatusFilter)) return false;\n return runMatchesSearch(run, currentSearch);\n });\n\n function handleClearFilters() {\n if (onFiltersChange) onFiltersChange({});\n else {\n setLocalSearch('');\n setLocalStatusFilter('all');\n }\n }\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <aside\n className={cn(\n 'flex w-304 shrink-0 flex-col border-r border-border-neutral-base bg-background-subtle-base',\n className,\n )}\n aria-label=\"Workflow runs\"\n >\n <WorkflowRunListHeader\n query={currentSearch}\n onQueryChange={(next) => {\n if (onFiltersChange)\n onFiltersChange({...(next ? {search: next} : {}), status: currentStatusFilter});\n else setLocalSearch(next);\n }}\n statusFilter={currentStatusFilter}\n onStatusFilterChange={(next) => {\n if (onFiltersChange)\n onFiltersChange({...(currentSearch ? {search: currentSearch} : {}), status: next});\n else setLocalStatusFilter(next);\n }}\n />\n <WorkflowRunListContent\n query={query}\n totalRuns={runs.length}\n runs={filteredRuns}\n workspaceId={workspaceId}\n projectId={projectId}\n selectedWorkflowRunId={selectedWorkflowRunId}\n onClearFilters={handleClearFilters}\n />\n </aside>\n </TimeTickerProvider>\n );\n}\n"],"names":["TimeTickerProvider","cn","useState","runMatchesSearch","runMatchesStatusFilter","WorkflowRunListContent","WorkflowRunListHeader","WorkflowRunListView","runs","query","workspaceId","projectId","selectedWorkflowRunId","className","search","statusFilter","onFiltersChange","localSearch","setLocalSearch","localStatusFilter","setLocalStatusFilter","currentSearch","currentStatusFilter","filteredRuns","filter","run","status","handleClearFilters","intervalMs","reducedMotionIntervalMs","aside","aria-label","onQueryChange","next","onStatusFilterChange","totalRuns","length","onClearFilters"],"mappings":";AAAA,SAAQA,kBAAkB,QAAO,gCAAgC;AACjE,SAAQC,EAAE,QAAO,0BAA0B;AAC3C,SAAQC,QAAQ,QAAO,QAAQ;AAC/B,SAAQC,gBAAgB,EAAEC,sBAAsB,QAAO,mBAAmB;AAE1E,SAAQC,sBAAsB,QAAO,iCAAiC;AACtE,SAAQC,qBAAqB,QAAO,gCAAgC;AAEpE,OAAO,SAASC,oBAAoB,EAClCC,IAAI,EACJC,KAAK,EACLC,WAAW,EACXC,SAAS,EACTC,qBAAqB,EACrBC,SAAS,EACTC,SAAS,EAAE,EACXC,eAAe,KAAK,EACpBC,eAAe,EACU;IACzB,MAAM,CAACC,aAAaC,eAAe,GAAGhB,SAASY;IAC/C,MAAM,CAACK,mBAAmBC,qBAAqB,GAAGlB,SAASa;IAC3D,MAAMM,gBAAgBL,kBAAkBF,SAASG;IACjD,MAAMK,sBAAsBN,kBAAkBD,eAAeI;IAE7D,MAAMI,eAAef,KAAKgB,MAAM,CAAC,CAACC;QAChC,IAAI,CAACrB,uBAAuBqB,IAAIC,MAAM,EAAEJ,sBAAsB,OAAO;QACrE,OAAOnB,iBAAiBsB,KAAKJ;IAC/B;IAEA,SAASM;QACP,IAAIX,iBAAiBA,gBAAgB,CAAC;aACjC;YACHE,eAAe;YACfE,qBAAqB;QACvB;IACF;IAEA,qBACE,KAACpB;QAAmB4B,YAAY;QAAMC,yBAAyB;kBAC7D,cAAA,MAACC;YACCjB,WAAWZ,GACT,8FACAY;YAEFkB,cAAW;;8BAEX,KAACzB;oBACCG,OAAOY;oBACPW,eAAe,CAACC;wBACd,IAAIjB,iBACFA,gBAAgB;4BAAC,GAAIiB,OAAO;gCAACnB,QAAQmB;4BAAI,IAAI,CAAC,CAAC;4BAAGP,QAAQJ;wBAAmB;6BAC1EJ,eAAee;oBACtB;oBACAlB,cAAcO;oBACdY,sBAAsB,CAACD;wBACrB,IAAIjB,iBACFA,gBAAgB;4BAAC,GAAIK,gBAAgB;gCAACP,QAAQO;4BAAa,IAAI,CAAC,CAAC;4BAAGK,QAAQO;wBAAI;6BAC7Eb,qBAAqBa;oBAC5B;;8BAEF,KAAC5B;oBACCI,OAAOA;oBACP0B,WAAW3B,KAAK4B,MAAM;oBACtB5B,MAAMe;oBACNb,aAAaA;oBACbC,WAAWA;oBACXC,uBAAuBA;oBACvByB,gBAAgBV;;;;;AAK1B"}
@@ -1,3 +1,3 @@
1
1
  import type { WorkflowRunListProps } from './types.js';
2
- export declare function WorkflowRunList({ workspaceId, projectId, selectedWorkflowRunId, className, }: WorkflowRunListProps): import("react").JSX.Element;
2
+ export declare function WorkflowRunList({ workspaceId, projectId, selectedWorkflowRunId, className, search, statusFilter, onFiltersChange, }: WorkflowRunListProps): import("react").JSX.Element;
3
3
  //# sourceMappingURL=workflow-run-list.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-run-list.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-list/workflow-run-list.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,YAAY,CAAC;AAGrD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,SAAS,GACV,EAAE,oBAAoB,+BAiBtB"}
1
+ {"version":3,"file":"workflow-run-list.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-list/workflow-run-list.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,YAAY,CAAC;AAGrD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,SAAS,EACT,MAAW,EACX,YAAoB,EACpB,eAAe,GAChB,EAAE,oBAAoB,+BAoBtB"}
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useMemo } from 'react';
3
3
  import { useWorkflowRunsInfiniteQuery } from '#hooks/api/workflow-runs.js';
4
4
  import { WorkflowRunListView } from './workflow-run-list-view.js';
5
- export function WorkflowRunList({ workspaceId, projectId, selectedWorkflowRunId, className }) {
5
+ export function WorkflowRunList({ workspaceId, projectId, selectedWorkflowRunId, className, search = '', statusFilter = 'all', onFiltersChange }) {
6
6
  const query = useWorkflowRunsInfiniteQuery(projectId, {});
7
7
  const runs = useMemo(()=>query.data?.pages.flatMap((page)=>page.runs) ?? [], [
8
8
  query.data
@@ -13,7 +13,12 @@ export function WorkflowRunList({ workspaceId, projectId, selectedWorkflowRunId,
13
13
  workspaceId: workspaceId,
14
14
  projectId: projectId,
15
15
  selectedWorkflowRunId: selectedWorkflowRunId,
16
- className: className
16
+ className: className,
17
+ search: search,
18
+ statusFilter: statusFilter,
19
+ ...onFiltersChange ? {
20
+ onFiltersChange
21
+ } : {}
17
22
  });
18
23
  }
19
24
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-list.tsx"],"sourcesContent":["import {useMemo} from 'react';\nimport type {WorkflowRunListItem} from '#core/workflow-run.js';\nimport {useWorkflowRunsInfiniteQuery} from '#hooks/api/workflow-runs.js';\nimport type {WorkflowRunListProps} from './types.js';\nimport {WorkflowRunListView} from './workflow-run-list-view.js';\n\nexport function WorkflowRunList({\n workspaceId,\n projectId,\n selectedWorkflowRunId,\n className,\n}: WorkflowRunListProps) {\n const query = useWorkflowRunsInfiniteQuery(projectId, {});\n const runs = useMemo<WorkflowRunListItem[]>(\n () => query.data?.pages.flatMap((page) => page.runs) ?? [],\n [query.data],\n );\n\n return (\n <WorkflowRunListView\n runs={runs}\n query={query}\n workspaceId={workspaceId}\n projectId={projectId}\n selectedWorkflowRunId={selectedWorkflowRunId}\n className={className}\n />\n );\n}\n"],"names":["useMemo","useWorkflowRunsInfiniteQuery","WorkflowRunListView","WorkflowRunList","workspaceId","projectId","selectedWorkflowRunId","className","query","runs","data","pages","flatMap","page"],"mappings":";AAAA,SAAQA,OAAO,QAAO,QAAQ;AAE9B,SAAQC,4BAA4B,QAAO,8BAA8B;AAEzE,SAAQC,mBAAmB,QAAO,8BAA8B;AAEhE,OAAO,SAASC,gBAAgB,EAC9BC,WAAW,EACXC,SAAS,EACTC,qBAAqB,EACrBC,SAAS,EACY;IACrB,MAAMC,QAAQP,6BAA6BI,WAAW,CAAC;IACvD,MAAMI,OAAOT,QACX,IAAMQ,MAAME,IAAI,EAAEC,MAAMC,QAAQ,CAACC,OAASA,KAAKJ,IAAI,KAAK,EAAE,EAC1D;QAACD,MAAME,IAAI;KAAC;IAGd,qBACE,KAACR;QACCO,MAAMA;QACND,OAAOA;QACPJ,aAAaA;QACbC,WAAWA;QACXC,uBAAuBA;QACvBC,WAAWA;;AAGjB"}
1
+ {"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-list.tsx"],"sourcesContent":["import {useMemo} from 'react';\nimport type {WorkflowRunListItem} from '#core/workflow-run.js';\nimport {useWorkflowRunsInfiniteQuery} from '#hooks/api/workflow-runs.js';\nimport type {WorkflowRunListProps} from './types.js';\nimport {WorkflowRunListView} from './workflow-run-list-view.js';\n\nexport function WorkflowRunList({\n workspaceId,\n projectId,\n selectedWorkflowRunId,\n className,\n search = '',\n statusFilter = 'all',\n onFiltersChange,\n}: WorkflowRunListProps) {\n const query = useWorkflowRunsInfiniteQuery(projectId, {});\n const runs = useMemo<WorkflowRunListItem[]>(\n () => query.data?.pages.flatMap((page) => page.runs) ?? [],\n [query.data],\n );\n\n return (\n <WorkflowRunListView\n runs={runs}\n query={query}\n workspaceId={workspaceId}\n projectId={projectId}\n selectedWorkflowRunId={selectedWorkflowRunId}\n className={className}\n search={search}\n statusFilter={statusFilter}\n {...(onFiltersChange ? {onFiltersChange} : {})}\n />\n );\n}\n"],"names":["useMemo","useWorkflowRunsInfiniteQuery","WorkflowRunListView","WorkflowRunList","workspaceId","projectId","selectedWorkflowRunId","className","search","statusFilter","onFiltersChange","query","runs","data","pages","flatMap","page"],"mappings":";AAAA,SAAQA,OAAO,QAAO,QAAQ;AAE9B,SAAQC,4BAA4B,QAAO,8BAA8B;AAEzE,SAAQC,mBAAmB,QAAO,8BAA8B;AAEhE,OAAO,SAASC,gBAAgB,EAC9BC,WAAW,EACXC,SAAS,EACTC,qBAAqB,EACrBC,SAAS,EACTC,SAAS,EAAE,EACXC,eAAe,KAAK,EACpBC,eAAe,EACM;IACrB,MAAMC,QAAQV,6BAA6BI,WAAW,CAAC;IACvD,MAAMO,OAAOZ,QACX,IAAMW,MAAME,IAAI,EAAEC,MAAMC,QAAQ,CAACC,OAASA,KAAKJ,IAAI,KAAK,EAAE,EAC1D;QAACD,MAAME,IAAI;KAAC;IAGd,qBACE,KAACX;QACCU,MAAMA;QACND,OAAOA;QACPP,aAAaA;QACbC,WAAWA;QACXC,uBAAuBA;QACvBC,WAAWA;QACXC,QAAQA;QACRC,cAAcA;QACb,GAAIC,kBAAkB;YAACA;QAAe,IAAI,CAAC,CAAC;;AAGnD"}
@@ -1,6 +1,5 @@
1
- import type { WorkflowRunRerunModeDto } from '@shipfox/api-workflows-dto';
2
1
  import type { Ref } from 'react';
3
- import { type WorkflowRunDetail } from '#core/workflow-run.js';
2
+ import { type WorkflowRunDetail, type WorkflowRunRerunMode } from '#core/workflow-run.js';
4
3
  export interface WorkflowRunSummaryProps {
5
4
  workspaceId?: string | undefined;
6
5
  projectId?: string | undefined;
@@ -13,7 +12,7 @@ export interface WorkflowRunSummaryProps {
13
12
  cancelling?: boolean | undefined;
14
13
  onCancel?: (() => void) | undefined;
15
14
  rerunPending?: boolean | undefined;
16
- onRerun?: ((mode: WorkflowRunRerunModeDto) => void) | undefined;
15
+ onRerun?: ((mode: WorkflowRunRerunMode) => void) | undefined;
17
16
  latestAttempt?: number | undefined;
18
17
  }
19
18
  export declare function WorkflowRunSummary({ workspaceId, projectId, run, sourceAvailable, sourceOpen, sourcePanelId, sourceButtonRef, onSourceToggle, cancelling, onCancel, rerunPending, onRerun, latestAttempt, }: WorkflowRunSummaryProps): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-run-summary.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-summary/workflow-run-summary.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,4BAA4B,CAAC;AAexE,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAE/B,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAW/B,MAAM,WAAW,uBAAuB;IACtC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,GAAG,EAAE,iBAAiB,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,eAAe,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;IACrD,cAAc,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,uBAAuB,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,WAAW,EACX,SAAS,EACT,GAAG,EACH,eAAuB,EACvB,UAAkB,EAClB,aAAa,EACb,eAAe,EACf,cAAc,EACd,UAAkB,EAClB,QAAQ,EACR,YAAoB,EACpB,OAAO,EACP,aAAa,GACd,EAAE,uBAAuB,+BAqIzB"}
1
+ {"version":3,"file":"workflow-run-summary.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-summary/workflow-run-summary.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAE/B,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAC1B,MAAM,uBAAuB,CAAC;AAW/B,MAAM,WAAW,uBAAuB;IACtC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,GAAG,EAAE,iBAAiB,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,eAAe,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,GAAG,SAAS,CAAC;IACrD,cAAc,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC7D,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,WAAW,EACX,SAAS,EACT,GAAG,EACH,eAAuB,EACvB,UAAkB,EAClB,aAAa,EACb,eAAe,EACf,cAAc,EACd,UAAkB,EAClB,QAAQ,EACR,YAAoB,EACpB,OAAO,EACP,aAAa,GACd,EAAE,uBAAuB,+BAqIzB"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/workflow-run-summary/workflow-run-summary.tsx"],"sourcesContent":["import type {WorkflowRunRerunModeDto} from '@shipfox/api-workflows-dto';\nimport {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {Button} from '@shipfox/react-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport type {Ref} from 'react';\nimport {useId} from 'react';\nimport {\n isWorkflowRunTerminal,\n type Job,\n WORKFLOW_RUN_STATUSES,\n type WorkflowRunDetail,\n} from '#core/workflow-run.js';\nimport {WorkflowRunDurationLabel} from '../workflow-run-duration-label.js';\nimport {getWorkflowStatusVisual} from '../workflow-status/status-visuals.js';\nimport {WorkflowRunAttemptSwitcher} from './workflow-run-attempt-switcher.js';\n\nconst STATUS_BADGE_LABEL_WIDTH_CH = Math.max(\n ...WORKFLOW_RUN_STATUSES.map((status) => getWorkflowStatusVisual(status).label.length),\n);\n\ntype WorkflowRunAction = 'cancel' | 'rerun-all' | 'rerun-menu' | 'none';\n\nexport interface WorkflowRunSummaryProps {\n workspaceId?: string | undefined;\n projectId?: string | undefined;\n run: WorkflowRunDetail;\n sourceAvailable?: boolean | undefined;\n sourceOpen?: boolean | undefined;\n sourcePanelId?: string | undefined;\n sourceButtonRef?: Ref<HTMLButtonElement> | undefined;\n onSourceToggle?: (() => void) | undefined;\n cancelling?: boolean | undefined;\n onCancel?: (() => void) | undefined;\n rerunPending?: boolean | undefined;\n onRerun?: ((mode: WorkflowRunRerunModeDto) => void) | undefined;\n latestAttempt?: number | undefined;\n}\n\nexport function WorkflowRunSummary({\n workspaceId,\n projectId,\n run,\n sourceAvailable = false,\n sourceOpen = false,\n sourcePanelId,\n sourceButtonRef,\n onSourceToggle,\n cancelling = false,\n onCancel,\n rerunPending = false,\n onRerun,\n latestAttempt,\n}: WorkflowRunSummaryProps) {\n const headingId = useId();\n const status = getWorkflowStatusVisual(run.runAttempt.status);\n const action = workflowRunActionForRun(run);\n const attemptSwitcher =\n latestAttempt && latestAttempt > 1 && workspaceId && projectId\n ? {workspaceId, projectId, latestAttempt}\n : null;\n const displayDuration = run.runAttempt.displayDuration;\n const {ref: headingTextRef, isTruncated: isHeadingTruncated} =\n useIsTextTruncated<HTMLSpanElement>(run.name);\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <section\n aria-labelledby={headingId}\n className=\"border-b border-border-neutral-base bg-background-subtle-base px-16 py-8\"\n >\n <div className=\"grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-12 gap-y-4 overflow-hidden\">\n <div className=\"col-start-1 row-start-1 flex min-w-0 items-center gap-8\">\n <Badge variant={status.badge} size=\"xs\">\n <span className=\"text-center\" style={{width: `${STATUS_BADGE_LABEL_WIDTH_CH}ch`}}>\n {status.label}\n </span>\n </Badge>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <Header id={headingId} variant=\"h3\" className=\"min-w-0 truncate\">\n <span\n ref={headingTextRef}\n title={isHeadingTruncated ? run.name : undefined}\n className=\"block min-w-0 truncate\"\n >\n {run.name}\n </span>\n </Header>\n </TooltipTrigger>\n {isHeadingTruncated ? (\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"max-w-[360px] break-words\">\n {run.name}\n </Text>\n </TooltipContent>\n ) : null}\n </Tooltip>\n </div>\n\n <div className=\"col-start-2 row-start-1 flex min-w-max items-center gap-6 justify-self-end\">\n <WorkflowRunActionSlot\n action={action}\n cancelling={cancelling}\n onCancel={onCancel}\n rerunPending={rerunPending}\n onRerun={onRerun}\n />\n {sourceAvailable ? (\n <Button\n ref={sourceButtonRef}\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n aria-controls={sourcePanelId}\n aria-expanded={sourceOpen}\n onClick={onSourceToggle}\n >\n View source\n </Button>\n ) : null}\n </div>\n\n <div className=\"col-span-2 row-start-2 flex min-w-0 items-center gap-12 overflow-hidden text-foreground-neutral-muted\">\n {attemptSwitcher ? (\n <WorkflowRunAttemptSwitcher\n workspaceId={attemptSwitcher.workspaceId}\n projectId={attemptSwitcher.projectId}\n run={run}\n latestAttempt={attemptSwitcher.latestAttempt}\n />\n ) : null}\n\n {run.triggerDisplayLabel ? (\n <>\n {attemptSwitcher ? <MetadataSeparator /> : null}\n <span className=\"min-w-0\">\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={run.triggerLabel}\n className=\"inline-flex max-w-full min-w-0 items-center gap-4 rounded-6 border-0 bg-transparent p-0 text-left text-foreground-neutral-muted outline-none focus-visible:shadow-button-neutral-focus\"\n >\n <TriggerSourceIcon\n provider={run.triggerProvider}\n source={run.triggerSource}\n aria-hidden=\"true\"\n className=\"size-12 shrink-0\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate\">\n {run.triggerDisplayLabel}\n </Text>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"block max-w-[360px] break-words\">\n {run.triggerLabel}\n </Text>\n </TooltipContent>\n </Tooltip>\n </span>\n </>\n ) : null}\n\n {attemptSwitcher || run.triggerDisplayLabel ? <MetadataSeparator /> : null}\n <RelativeTime\n value={run.runAttempt.createdAt}\n className=\"shrink-0 whitespace-nowrap text-xs leading-20 text-foreground-neutral-muted\"\n />\n\n {displayDuration ? (\n <>\n <MetadataSeparator />\n <WorkflowRunDurationLabel\n duration={displayDuration}\n className=\"text-foreground-neutral-muted\"\n />\n </>\n ) : null}\n </div>\n </div>\n </section>\n </TimeTickerProvider>\n );\n}\n\nfunction WorkflowRunActionSlot({\n action,\n cancelling,\n onCancel,\n rerunPending,\n onRerun,\n}: {\n action: WorkflowRunAction;\n cancelling: boolean;\n onCancel?: (() => void) | undefined;\n rerunPending: boolean;\n onRerun?: ((mode: WorkflowRunRerunModeDto) => void) | undefined;\n}) {\n if (action === 'none') return null;\n\n if (action === 'cancel') {\n if (!onCancel) return null;\n\n return (\n <Button\n type=\"button\"\n variant=\"danger\"\n size=\"xs\"\n isLoading={cancelling}\n disabled={cancelling}\n onClick={onCancel}\n >\n Cancel workflow\n </Button>\n );\n }\n\n if (action === 'rerun-all') {\n if (!onRerun) return null;\n\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n isLoading={rerunPending}\n disabled={rerunPending}\n onClick={() => onRerun('all')}\n >\n Re-run workflow\n </Button>\n );\n }\n\n if (!onRerun) return null;\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n iconRight=\"arrowDownSLine\"\n isLoading={rerunPending}\n disabled={rerunPending}\n >\n Re-run jobs\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem disabled={rerunPending} onSelect={() => onRerun('all')}>\n Re-run all jobs\n </DropdownMenuItem>\n <DropdownMenuItem disabled={rerunPending} onSelect={() => onRerun('failed')}>\n Re-run failed jobs\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nfunction workflowRunActionForRun(run: WorkflowRunDetail): WorkflowRunAction {\n if (run.runAttempt.attempt !== run.currentAttempt) return 'none';\n if (!isWorkflowRunTerminal(run.runAttempt.status)) return 'cancel';\n if (run.runAttempt.status === 'succeeded' || !hasFailedOrCancelledJobs(run)) return 'rerun-all';\n return 'rerun-menu';\n}\n\nfunction hasFailedOrCancelledJobs(run: WorkflowRunDetail): boolean {\n if (!workflowRunHasJobs(run)) return false;\n\n return run.jobs.some((job) => job.status === 'failed' || job.status === 'cancelled');\n}\n\nfunction workflowRunHasJobs(run: WorkflowRunDetail): run is WorkflowRunDetail & {jobs: Job[]} {\n return 'jobs' in run && Array.isArray(run.jobs);\n}\n\nfunction MetadataSeparator() {\n return <span aria-hidden=\"true\" className=\"h-12 w-px shrink-0 bg-border-neutral-base\" />;\n}\n"],"names":["TriggerSourceIcon","Badge","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","useIsTextTruncated","RelativeTime","TimeTickerProvider","Tooltip","TooltipContent","TooltipTrigger","Header","Text","useId","isWorkflowRunTerminal","WORKFLOW_RUN_STATUSES","WorkflowRunDurationLabel","getWorkflowStatusVisual","WorkflowRunAttemptSwitcher","STATUS_BADGE_LABEL_WIDTH_CH","Math","max","map","status","label","length","WorkflowRunSummary","workspaceId","projectId","run","sourceAvailable","sourceOpen","sourcePanelId","sourceButtonRef","onSourceToggle","cancelling","onCancel","rerunPending","onRerun","latestAttempt","headingId","runAttempt","action","workflowRunActionForRun","attemptSwitcher","displayDuration","ref","headingTextRef","isTruncated","isHeadingTruncated","name","intervalMs","reducedMotionIntervalMs","section","aria-labelledby","className","div","variant","badge","size","span","style","width","asChild","id","title","undefined","as","WorkflowRunActionSlot","type","aria-controls","aria-expanded","onClick","triggerDisplayLabel","MetadataSeparator","button","aria-label","triggerLabel","provider","triggerProvider","source","triggerSource","aria-hidden","value","createdAt","duration","isLoading","disabled","iconRight","align","onSelect","attempt","currentAttempt","hasFailedOrCancelledJobs","workflowRunHasJobs","jobs","some","job","Array","isArray"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/workflow-run-summary/workflow-run-summary.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {Button} from '@shipfox/react-ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '@shipfox/react-ui/dropdown-menu';\nimport {useIsTextTruncated} from '@shipfox/react-ui/hooks';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Header, Text} from '@shipfox/react-ui/typography';\nimport type {Ref} from 'react';\nimport {useId} from 'react';\nimport {\n isWorkflowRunTerminal,\n type Job,\n WORKFLOW_RUN_STATUSES,\n type WorkflowRunDetail,\n type WorkflowRunRerunMode,\n} from '#core/workflow-run.js';\nimport {WorkflowRunDurationLabel} from '../workflow-run-duration-label.js';\nimport {getWorkflowStatusVisual} from '../workflow-status/status-visuals.js';\nimport {WorkflowRunAttemptSwitcher} from './workflow-run-attempt-switcher.js';\n\nconst STATUS_BADGE_LABEL_WIDTH_CH = Math.max(\n ...WORKFLOW_RUN_STATUSES.map((status) => getWorkflowStatusVisual(status).label.length),\n);\n\ntype WorkflowRunAction = 'cancel' | 'rerun-all' | 'rerun-menu' | 'none';\n\nexport interface WorkflowRunSummaryProps {\n workspaceId?: string | undefined;\n projectId?: string | undefined;\n run: WorkflowRunDetail;\n sourceAvailable?: boolean | undefined;\n sourceOpen?: boolean | undefined;\n sourcePanelId?: string | undefined;\n sourceButtonRef?: Ref<HTMLButtonElement> | undefined;\n onSourceToggle?: (() => void) | undefined;\n cancelling?: boolean | undefined;\n onCancel?: (() => void) | undefined;\n rerunPending?: boolean | undefined;\n onRerun?: ((mode: WorkflowRunRerunMode) => void) | undefined;\n latestAttempt?: number | undefined;\n}\n\nexport function WorkflowRunSummary({\n workspaceId,\n projectId,\n run,\n sourceAvailable = false,\n sourceOpen = false,\n sourcePanelId,\n sourceButtonRef,\n onSourceToggle,\n cancelling = false,\n onCancel,\n rerunPending = false,\n onRerun,\n latestAttempt,\n}: WorkflowRunSummaryProps) {\n const headingId = useId();\n const status = getWorkflowStatusVisual(run.runAttempt.status);\n const action = workflowRunActionForRun(run);\n const attemptSwitcher =\n latestAttempt && latestAttempt > 1 && workspaceId && projectId\n ? {workspaceId, projectId, latestAttempt}\n : null;\n const displayDuration = run.runAttempt.displayDuration;\n const {ref: headingTextRef, isTruncated: isHeadingTruncated} =\n useIsTextTruncated<HTMLSpanElement>(run.name);\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <section\n aria-labelledby={headingId}\n className=\"border-b border-border-neutral-base bg-background-subtle-base px-16 py-8\"\n >\n <div className=\"grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-12 gap-y-4 overflow-hidden\">\n <div className=\"col-start-1 row-start-1 flex min-w-0 items-center gap-8\">\n <Badge variant={status.badge} size=\"xs\">\n <span className=\"text-center\" style={{width: `${STATUS_BADGE_LABEL_WIDTH_CH}ch`}}>\n {status.label}\n </span>\n </Badge>\n\n <Tooltip>\n <TooltipTrigger asChild>\n <Header id={headingId} variant=\"h3\" className=\"min-w-0 truncate\">\n <span\n ref={headingTextRef}\n title={isHeadingTruncated ? run.name : undefined}\n className=\"block min-w-0 truncate\"\n >\n {run.name}\n </span>\n </Header>\n </TooltipTrigger>\n {isHeadingTruncated ? (\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"max-w-[360px] break-words\">\n {run.name}\n </Text>\n </TooltipContent>\n ) : null}\n </Tooltip>\n </div>\n\n <div className=\"col-start-2 row-start-1 flex min-w-max items-center gap-6 justify-self-end\">\n <WorkflowRunActionSlot\n action={action}\n cancelling={cancelling}\n onCancel={onCancel}\n rerunPending={rerunPending}\n onRerun={onRerun}\n />\n {sourceAvailable ? (\n <Button\n ref={sourceButtonRef}\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n aria-controls={sourcePanelId}\n aria-expanded={sourceOpen}\n onClick={onSourceToggle}\n >\n View source\n </Button>\n ) : null}\n </div>\n\n <div className=\"col-span-2 row-start-2 flex min-w-0 items-center gap-12 overflow-hidden text-foreground-neutral-muted\">\n {attemptSwitcher ? (\n <WorkflowRunAttemptSwitcher\n workspaceId={attemptSwitcher.workspaceId}\n projectId={attemptSwitcher.projectId}\n run={run}\n latestAttempt={attemptSwitcher.latestAttempt}\n />\n ) : null}\n\n {run.triggerDisplayLabel ? (\n <>\n {attemptSwitcher ? <MetadataSeparator /> : null}\n <span className=\"min-w-0\">\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={run.triggerLabel}\n className=\"inline-flex max-w-full min-w-0 items-center gap-4 rounded-6 border-0 bg-transparent p-0 text-left text-foreground-neutral-muted outline-none focus-visible:shadow-button-neutral-focus\"\n >\n <TriggerSourceIcon\n provider={run.triggerProvider}\n source={run.triggerSource}\n aria-hidden=\"true\"\n className=\"size-12 shrink-0\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate\">\n {run.triggerDisplayLabel}\n </Text>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"block max-w-[360px] break-words\">\n {run.triggerLabel}\n </Text>\n </TooltipContent>\n </Tooltip>\n </span>\n </>\n ) : null}\n\n {attemptSwitcher || run.triggerDisplayLabel ? <MetadataSeparator /> : null}\n <RelativeTime\n value={run.runAttempt.createdAt}\n className=\"shrink-0 whitespace-nowrap text-xs leading-20 text-foreground-neutral-muted\"\n />\n\n {displayDuration ? (\n <>\n <MetadataSeparator />\n <WorkflowRunDurationLabel\n duration={displayDuration}\n className=\"text-foreground-neutral-muted\"\n />\n </>\n ) : null}\n </div>\n </div>\n </section>\n </TimeTickerProvider>\n );\n}\n\nfunction WorkflowRunActionSlot({\n action,\n cancelling,\n onCancel,\n rerunPending,\n onRerun,\n}: {\n action: WorkflowRunAction;\n cancelling: boolean;\n onCancel?: (() => void) | undefined;\n rerunPending: boolean;\n onRerun?: ((mode: WorkflowRunRerunMode) => void) | undefined;\n}) {\n if (action === 'none') return null;\n\n if (action === 'cancel') {\n if (!onCancel) return null;\n\n return (\n <Button\n type=\"button\"\n variant=\"danger\"\n size=\"xs\"\n isLoading={cancelling}\n disabled={cancelling}\n onClick={onCancel}\n >\n Cancel workflow\n </Button>\n );\n }\n\n if (action === 'rerun-all') {\n if (!onRerun) return null;\n\n return (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n isLoading={rerunPending}\n disabled={rerunPending}\n onClick={() => onRerun('all')}\n >\n Re-run workflow\n </Button>\n );\n }\n\n if (!onRerun) return null;\n\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n iconRight=\"arrowDownSLine\"\n isLoading={rerunPending}\n disabled={rerunPending}\n >\n Re-run jobs\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem disabled={rerunPending} onSelect={() => onRerun('all')}>\n Re-run all jobs\n </DropdownMenuItem>\n <DropdownMenuItem disabled={rerunPending} onSelect={() => onRerun('failed')}>\n Re-run failed jobs\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nfunction workflowRunActionForRun(run: WorkflowRunDetail): WorkflowRunAction {\n if (run.runAttempt.attempt !== run.currentAttempt) return 'none';\n if (!isWorkflowRunTerminal(run.runAttempt.status)) return 'cancel';\n if (run.runAttempt.status === 'succeeded' || !hasFailedOrCancelledJobs(run)) return 'rerun-all';\n return 'rerun-menu';\n}\n\nfunction hasFailedOrCancelledJobs(run: WorkflowRunDetail): boolean {\n if (!workflowRunHasJobs(run)) return false;\n\n return run.jobs.some((job) => job.status === 'failed' || job.status === 'cancelled');\n}\n\nfunction workflowRunHasJobs(run: WorkflowRunDetail): run is WorkflowRunDetail & {jobs: Job[]} {\n return 'jobs' in run && Array.isArray(run.jobs);\n}\n\nfunction MetadataSeparator() {\n return <span aria-hidden=\"true\" className=\"h-12 w-px shrink-0 bg-border-neutral-base\" />;\n}\n"],"names":["TriggerSourceIcon","Badge","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","useIsTextTruncated","RelativeTime","TimeTickerProvider","Tooltip","TooltipContent","TooltipTrigger","Header","Text","useId","isWorkflowRunTerminal","WORKFLOW_RUN_STATUSES","WorkflowRunDurationLabel","getWorkflowStatusVisual","WorkflowRunAttemptSwitcher","STATUS_BADGE_LABEL_WIDTH_CH","Math","max","map","status","label","length","WorkflowRunSummary","workspaceId","projectId","run","sourceAvailable","sourceOpen","sourcePanelId","sourceButtonRef","onSourceToggle","cancelling","onCancel","rerunPending","onRerun","latestAttempt","headingId","runAttempt","action","workflowRunActionForRun","attemptSwitcher","displayDuration","ref","headingTextRef","isTruncated","isHeadingTruncated","name","intervalMs","reducedMotionIntervalMs","section","aria-labelledby","className","div","variant","badge","size","span","style","width","asChild","id","title","undefined","as","WorkflowRunActionSlot","type","aria-controls","aria-expanded","onClick","triggerDisplayLabel","MetadataSeparator","button","aria-label","triggerLabel","provider","triggerProvider","source","triggerSource","aria-hidden","value","createdAt","duration","isLoading","disabled","iconRight","align","onSelect","attempt","currentAttempt","hasFailedOrCancelledJobs","workflowRunHasJobs","jobs","some","job","Array","isArray"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"job-card.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/job-card.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrC,OAAO,EACL,KAAK,GAAG,EACR,KAAK,YAAY,EAIjB,KAAK,kBAAkB,EAIxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAC,KAAK,mBAAmB,EAAoC,MAAM,uBAAuB,CAAC;AAelG,wBAAgB,OAAO,CAAC,EACtB,WAAW,EACX,GAAG,EACH,oBAAoB,EACpB,iBAAiB,EACjB,4BAA4B,EAC5B,uBAAuB,EACvB,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,gBAAgB,GACjB,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,GAAG,CAAC;IACT,oBAAoB,EAAE,YAAY,GAAG,SAAS,CAAC;IAC/C,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7C,4BAA4B,EAAE,CAAC,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzF,uBAAuB,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC/E,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,mBAAmB,KAAK,SAAS,CAAC,GAAG,SAAS,CAAC;IAC/E,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChD,gBAAgB,CAAC,EACb,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,KAAK,IAAI,CAAC,GAC3F,SAAS,CAAC;CACf,+BAkIA"}
1
+ {"version":3,"file":"job-card.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-view/job-card.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrC,OAAO,EAEL,KAAK,GAAG,EACR,KAAK,YAAY,EAKjB,KAAK,kBAAkB,EAIxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAC,KAAK,mBAAmB,EAAoC,MAAM,uBAAuB,CAAC;AAelG,wBAAgB,OAAO,CAAC,EACtB,WAAW,EACX,GAAG,EACH,oBAAoB,EACpB,iBAAiB,EACjB,4BAA4B,EAC5B,uBAAuB,EACvB,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,gBAAgB,GACjB,EAAE;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,GAAG,CAAC;IACT,oBAAoB,EAAE,YAAY,GAAG,SAAS,CAAC;IAC/C,iBAAiB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7C,4BAA4B,EAAE,CAAC,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACzF,uBAAuB,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC/E,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,mBAAmB,KAAK,SAAS,CAAC,GAAG,SAAS,CAAC;IAC/E,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChD,gBAAgB,CAAC,EACb,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,KAAK,IAAI,CAAC,GAC3F,SAAS,CAAC;CACf,+BAkIA"}
@@ -1,5 +1,4 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { agentConfigIssueSchema, stepErrorReasonSchema } from '@shipfox/api-workflows-dto';
3
2
  import { TriggerSourceIcon } from '@shipfox/client-triggers';
4
3
  import { Badge } from '@shipfox/react-ui/badge';
5
4
  import { Button } from '@shipfox/react-ui/button';
@@ -11,7 +10,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/toolt
11
10
  import { Text } from '@shipfox/react-ui/typography';
12
11
  import { Fragment, useId, useRef, useState } from 'react';
13
12
  import { getWorkflowStatusVisual } from '#components/workflow-status/status-visuals.js';
14
- import { WORKFLOW_JOB_STATUSES, workflowRunTriggerDisplayLabel, workflowRunTriggerLabel } from '#core/workflow-run.js';
13
+ import { AGENT_CONFIG_ISSUES, STEP_ERROR_REASONS, WORKFLOW_JOB_STATUSES, workflowRunTriggerDisplayLabel, workflowRunTriggerLabel } from '#core/workflow-run.js';
15
14
  import { StepList } from '../step-list/index.js';
16
15
  import { AgentConfigFailureCallout } from './agent-config-failure-callout.js';
17
16
  import { JobExecutionSwitcher } from './job-execution-switcher.js';
@@ -338,17 +337,19 @@ function StepAttemptDetailPanel({ workspaceId, step, stepId, attempt, attemptErr
338
337
  }
339
338
  function toSelectedAttemptError(step, error) {
340
339
  if (error === null) return null;
341
- const reason = stepErrorReasonSchema.safeParse(error.reason);
342
- const agentConfigIssue = agentConfigIssueSchema.safeParse(error.agentConfigIssue ?? error.agent_config_issue);
340
+ const rawReason = error.reason;
341
+ const parsedReason = typeof rawReason === 'string' && STEP_ERROR_REASONS.has(rawReason) ? rawReason : undefined;
342
+ const rawAgentConfigIssue = error.agentConfigIssue ?? error.agent_config_issue;
343
+ const agentConfigIssue = typeof rawAgentConfigIssue === 'string' && AGENT_CONFIG_ISSUES.has(rawAgentConfigIssue) ? rawAgentConfigIssue : undefined;
343
344
  const exitCode = error.exitCode ?? error.exit_code;
344
- const parsedReason = reason.success ? reason.data : agentConfigIssue.success ? 'agent_config_invalid' : undefined;
345
- if (parsedReason === undefined) return null;
345
+ const resolvedReason = parsedReason ? parsedReason : agentConfigIssue ? 'agent_config_invalid' : undefined;
346
+ if (resolvedReason === undefined) return null;
346
347
  return {
347
348
  message: typeof error.message === 'string' ? error.message : '',
348
349
  exitCode: exitCode === null || typeof exitCode === 'number' ? exitCode : null,
349
350
  signal: typeof error.signal === 'string' ? error.signal : undefined,
350
- reason: parsedReason,
351
- agentConfigIssue: agentConfigIssue.success ? agentConfigIssue.data : undefined,
351
+ reason: resolvedReason,
352
+ agentConfigIssue,
352
353
  category: step.type === 'setup' ? 'setup' : 'user'
353
354
  };
354
355
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/workflow-run-view/job-card.tsx"],"sourcesContent":["import {agentConfigIssueSchema, stepErrorReasonSchema} from '@shipfox/api-workflows-dto';\nimport {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {Button} from '@shipfox/react-ui/button';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {useTimeTick} from '@shipfox/react-ui/time-ticker';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport type {ReactNode} from 'react';\nimport {Fragment, useId, useRef, useState} from 'react';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {\n type Job,\n type JobExecution,\n type JobExecutionTime,\n type Step,\n type StepError,\n type StepSourceLocation,\n WORKFLOW_JOB_STATUSES,\n workflowRunTriggerDisplayLabel,\n workflowRunTriggerLabel,\n} from '#core/workflow-run.js';\nimport {type StepExpandedContext, StepList, type StepListEmptyState} from '../step-list/index.js';\nimport {AgentConfigFailureCallout} from './agent-config-failure-callout.js';\nimport {JobExecutionSwitcher} from './job-execution-switcher.js';\nimport {formatJobExecutionTime, JobExecutionTimeText} from './job-execution-time-text.js';\nimport {StepAttemptLogPanel} from './step-attempt-log-panel.js';\n\nconst STATUS_BADGE_LABEL_WIDTH_CH = Math.max(\n ...WORKFLOW_JOB_STATUSES.map((status) => getWorkflowStatusVisual(status).label.length),\n);\n\ninterface LocalSelectedAttempt {\n jobExecutionId: string | undefined;\n attemptId: string | null;\n}\n\nexport function JobCard({\n workspaceId,\n job,\n selectedJobExecution,\n selectedAttemptId,\n onSelectedJobExecutionChange,\n onSelectedAttemptChange,\n renderExpandedStep,\n sourcePanelId,\n sourceAvailable,\n focusedSourceStepId,\n onOpenStepSource,\n}: {\n workspaceId: string;\n job: Job;\n selectedJobExecution: JobExecution | undefined;\n selectedAttemptId: string | null | undefined;\n onSelectedJobExecutionChange: ((jobExecutionId: string | undefined) => void) | undefined;\n onSelectedAttemptChange: ((attemptId: string | undefined) => void) | undefined;\n renderExpandedStep?: ((context: StepExpandedContext) => ReactNode) | undefined;\n sourcePanelId?: string | undefined;\n sourceAvailable?: boolean | undefined;\n focusedSourceStepId?: string | null | undefined;\n onOpenStepSource?:\n | ((stepId: string, location: StepSourceLocation, trigger: HTMLButtonElement | null) => void)\n | undefined;\n}) {\n const titleId = useId();\n const sourceButtonRef = useRef<HTMLButtonElement>(null);\n const [localSelectedAttempt, setLocalSelectedAttempt] = useState<LocalSelectedAttempt>({\n jobExecutionId: undefined,\n attemptId: null,\n });\n const selectedExecutionStatus = selectedJobExecution?.status ?? job.status;\n const effectiveSelectedAttemptId =\n selectedAttemptId === undefined &&\n localSelectedAttempt.jobExecutionId === selectedJobExecution?.id\n ? localSelectedAttempt.attemptId\n : selectedAttemptId;\n const selectedSourceAction = selectedStepSourceAction(\n selectedJobExecution,\n effectiveSelectedAttemptId,\n );\n const defaultRenderExpandedStep = ({\n step,\n stepId,\n attempt,\n attemptError,\n attemptStatus,\n carriedOver,\n }: StepExpandedContext) =>\n carriedOver ? (\n <CarriedOverStepPanel />\n ) : (\n <StepAttemptDetailPanel\n workspaceId={workspaceId}\n step={step}\n stepId={stepId}\n attempt={attempt}\n attemptError={attemptError}\n attemptStatus={attemptStatus}\n />\n );\n\n function selectAttempt(attemptId: string | undefined) {\n if (selectedAttemptId === undefined) {\n setLocalSelectedAttempt({\n jobExecutionId: selectedJobExecution?.id,\n attemptId: attemptId ?? null,\n });\n }\n\n onSelectedAttemptChange?.(attemptId);\n }\n\n return (\n <section\n aria-labelledby={titleId}\n className=\"flex min-h-0 flex-col rounded-8 border border-border-neutral-base bg-background-components-base\"\n >\n <div className=\"grid min-h-52 min-w-0 grid-cols-1 gap-y-4 px-16 py-12\">\n <div className=\"flex min-w-0 flex-wrap items-center justify-between gap-10\">\n {job.mode === 'listening' &&\n job.jobExecutions.length > 0 &&\n onSelectedJobExecutionChange ? (\n <>\n <Text as=\"h2\" id={titleId} size=\"sm\" bold className=\"sr-only\">\n {job.displayName}\n </Text>\n <div className=\"flex min-w-0 items-center gap-8\">\n <JobStatusBadge status={selectedExecutionStatus} />\n <JobExecutionSwitcher\n job={job}\n selectedJobExecution={selectedJobExecution?.id ?? null}\n onSelectedJobExecutionChange={onSelectedJobExecutionChange}\n variant=\"title\"\n />\n </div>\n </>\n ) : (\n <div className=\"flex min-w-0 items-center gap-8\">\n <JobStatusBadge status={selectedExecutionStatus} />\n <Text\n as=\"h2\"\n id={titleId}\n size=\"sm\"\n bold\n className=\"min-w-0 truncate text-foreground-neutral-base\"\n >\n {job.displayName}\n </Text>\n </div>\n )}\n {sourceAvailable && selectedSourceAction && sourcePanelId && onOpenStepSource ? (\n <div className=\"flex min-w-max items-center gap-6\">\n <Button\n ref={sourceButtonRef}\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n aria-controls={sourcePanelId}\n aria-expanded={focusedSourceStepId === selectedSourceAction.stepId}\n onClick={() =>\n onOpenStepSource(\n selectedSourceAction.stepId,\n selectedSourceAction.location,\n sourceButtonRef.current,\n )\n }\n >\n View source\n </Button>\n </div>\n ) : null}\n </div>\n <JobExecutionMetadata execution={selectedJobExecution} />\n </div>\n <div className=\"min-h-0 border-t border-border-neutral-strong\">\n {selectedJobExecution ? (\n <StepList\n job={job}\n jobExecution={selectedJobExecution}\n selectedAttemptId={selectedAttemptId}\n onSelectedAttemptChange={selectAttempt}\n autoSelectActiveAttempt\n emptyState={emptyStateForJob(job, selectedJobExecution)}\n showHeader={false}\n className=\"rounded-none border-0 bg-transparent\"\n renderExpandedStep={renderExpandedStep ?? defaultRenderExpandedStep}\n />\n ) : (\n <JobExecutionEmptyState job={job} />\n )}\n </div>\n </section>\n );\n}\n\nfunction JobStatusBadge({status}: {status: Job['status'] | JobExecution['status']}) {\n const visual = getWorkflowStatusVisual(status);\n\n return (\n <Badge variant={visual.badge} size=\"xs\">\n <span className=\"text-center\" style={{width: `${STATUS_BADGE_LABEL_WIDTH_CH}ch`}}>\n {visual.label}\n </span>\n </Badge>\n );\n}\n\nfunction JobExecutionEmptyState({job}: {job: Job}) {\n const emptyState = emptyStateForMissingExecution(job);\n\n return (\n <EmptyState\n className=\"min-h-120 px-16 py-20\"\n icon=\"componentLine\"\n title={emptyState.title}\n description={emptyState.description}\n variant=\"compact\"\n />\n );\n}\n\nfunction JobExecutionMetadata({execution}: {execution: JobExecution | undefined}) {\n if (!execution) return null;\n\n const queueTime = execution.queueTime;\n const runTime = execution.runTime;\n const executionStartedAt = execution.startedAt ?? execution.queuedAt ?? execution.createdAt;\n const items = [\n execution.triggerEvents.length > 0 ? {key: 'trigger', kind: 'trigger' as const} : null,\n {key: 'started', kind: 'started' as const, value: executionStartedAt},\n queueTime\n ? {key: 'queue', icon: 'hourglassLine' as const, kind: 'queue' as const, time: queueTime}\n : null,\n runTime ? {key: 'run', icon: 'timerLine' as const, kind: 'run' as const, time: runTime} : null,\n ].filter((item) => item !== null);\n\n if (items.length === 0) return null;\n\n return (\n <div className=\"flex min-w-0 items-center gap-12 overflow-hidden text-foreground-neutral-muted\">\n {items.map((item, index) => (\n <Fragment key={item.key}>\n {index > 0 ? <MetadataSeparator /> : null}\n {item.kind === 'started' ? (\n <RelativeTime\n value={item.value}\n className=\"shrink-0 whitespace-nowrap text-xs leading-20 text-foreground-neutral-muted\"\n />\n ) : item.kind === 'trigger' ? (\n <JobExecutionTriggerMetadata execution={execution} />\n ) : (\n <JobExecutionMetadataItem icon={item.icon} kind={item.kind} time={item.time} />\n )}\n </Fragment>\n ))}\n </div>\n );\n}\n\nfunction JobExecutionTriggerMetadata({execution}: {execution: JobExecution}) {\n const triggerEvent = execution.triggerEvents[0];\n if (!triggerEvent) return null;\n\n const triggerLabel = workflowRunTriggerLabel({\n triggerSource: triggerEvent.source,\n triggerEvent: triggerEvent.event,\n });\n const triggerDisplayLabel = workflowRunTriggerDisplayLabel({\n triggerSource: triggerEvent.source,\n triggerEvent: triggerEvent.event,\n });\n const triggerCount = execution.triggerEvents.length;\n const countLabel = triggerCount > 1 ? ` (${triggerCount})` : '';\n const tooltip = triggerCount > 1 ? `${triggerLabel} (${triggerCount} events)` : triggerLabel;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={tooltip}\n className=\"inline-flex min-w-0 max-w-full cursor-default items-center gap-4 rounded-4 border-0 bg-transparent p-0 text-left text-foreground-neutral-muted outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n <TriggerSourceIcon\n provider={triggerEvent.source}\n source={triggerEvent.source}\n aria-hidden=\"true\"\n className=\"size-12 shrink-0\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate\">\n {triggerDisplayLabel}\n {countLabel}\n </Text>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"block max-w-[360px] break-words\">\n {tooltip}\n </Text>\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction JobExecutionMetadataItem({\n icon,\n kind,\n time,\n}: {\n icon: 'hourglassLine' | 'timerLine';\n kind: 'queue' | 'run';\n time: JobExecutionTime;\n}) {\n useTimeTick();\n\n const tooltip = `${jobExecutionTimeVerb(kind, time)} for ${formatJobExecutionTime(time)}`;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={tooltip}\n className=\"inline-flex min-w-0 cursor-default items-center gap-4 rounded-4 border-0 bg-transparent p-0 text-foreground-neutral-muted outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n <Icon name={icon} className=\"size-12 shrink-0\" aria-hidden=\"true\" />\n <span className=\"shrink-0 text-xs leading-20 text-foreground-neutral-muted tabular-nums\">\n <JobExecutionTimeText time={time} />\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\">\n {tooltip}\n </Text>\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction jobExecutionTimeVerb(kind: 'queue' | 'run', time: JobExecutionTime): string {\n if (kind === 'queue') return time.state === 'live' ? 'Queuing' : 'Queued';\n return time.state === 'live' ? 'Running' : 'Ran';\n}\n\nfunction MetadataSeparator() {\n return <span aria-hidden=\"true\" className=\"h-12 w-px shrink-0 bg-border-neutral-strong\" />;\n}\n\nfunction selectedStepSourceAction(\n jobExecution: JobExecution | undefined,\n selectedAttemptId: string | null | undefined,\n): {stepId: string; location: StepSourceLocation} | null {\n if (!jobExecution || !selectedAttemptId) return null;\n\n for (const step of jobExecution.steps) {\n const selected =\n selectedAttemptId === `carried-over:${step.id}` ||\n step.attempts.some((attempt) => attempt.id === selectedAttemptId);\n if (selected && step.sourceLocation) {\n return {stepId: step.id, location: step.sourceLocation};\n }\n }\n\n return null;\n}\n\nfunction StepAttemptDetailPanel({\n workspaceId,\n step,\n stepId,\n attempt,\n attemptError,\n attemptStatus,\n}: {\n workspaceId: string;\n step: Step;\n stepId: string;\n attempt: number;\n attemptError: Record<string, unknown> | null;\n attemptStatus: string;\n}) {\n const selectedAttemptError = toSelectedAttemptError(step, attemptError) ?? step.error;\n\n return (\n <div className=\"flex min-w-0 flex-col gap-10\">\n {isAgentConfigFailure(step, selectedAttemptError) ? (\n <AgentConfigFailureCallout\n workspaceId={workspaceId}\n config={null}\n error={selectedAttemptError}\n />\n ) : null}\n <StepAttemptLogPanel stepId={stepId} attempt={attempt} attemptStatus={attemptStatus} />\n </div>\n );\n}\n\nfunction toSelectedAttemptError(\n step: Step,\n error: Record<string, unknown> | null,\n): StepError | null {\n if (error === null) return null;\n\n const reason = stepErrorReasonSchema.safeParse(error.reason);\n const agentConfigIssue = agentConfigIssueSchema.safeParse(\n error.agentConfigIssue ?? error.agent_config_issue,\n );\n const exitCode = error.exitCode ?? error.exit_code;\n const parsedReason = reason.success\n ? reason.data\n : agentConfigIssue.success\n ? 'agent_config_invalid'\n : undefined;\n\n if (parsedReason === undefined) return null;\n\n return {\n message: typeof error.message === 'string' ? error.message : '',\n exitCode: exitCode === null || typeof exitCode === 'number' ? exitCode : null,\n signal: typeof error.signal === 'string' ? error.signal : undefined,\n reason: parsedReason,\n agentConfigIssue: agentConfigIssue.success ? agentConfigIssue.data : undefined,\n category: step.type === 'setup' ? 'setup' : 'user',\n };\n}\n\nfunction isAgentConfigFailure(step: Step, error: StepError | null): boolean {\n return step.type === 'agent' && error?.reason === 'agent_config_invalid';\n}\n\nfunction emptyStateForJob(job: Job, jobExecution: JobExecution): StepListEmptyState | undefined {\n if (job.carriedOver) {\n return {\n title: 'Carried over from a previous attempt',\n description: 'This job did not execute in this run.',\n status: 'succeeded',\n };\n }\n\n if (jobExecution.status === 'pending') {\n return {\n title: 'Waiting for this job to start',\n description: 'Steps will appear here once the job starts.',\n status: jobExecution.status,\n };\n }\n\n if (jobExecution.status === 'running') {\n return {\n title: 'Waiting for the first step',\n description: 'This job is running, but no steps have started yet.',\n status: jobExecution.status,\n };\n }\n\n if (jobExecution.status === 'cancelled') {\n return {\n title: 'Cancelled before start',\n description: 'This job was cancelled before any step started.',\n status: jobExecution.status,\n };\n }\n\n if (jobExecution.status === 'succeeded' || jobExecution.status === 'failed') {\n return {\n title: 'No steps recorded',\n description: `Execution #${jobExecution.sequence} finished without recorded steps.`,\n status: jobExecution.status,\n };\n }\n\n return undefined;\n}\n\nfunction emptyStateForMissingExecution(job: Job): StepListEmptyState {\n if (job.carriedOver) {\n return {\n title: 'Carried over from a previous attempt',\n description: 'This job did not execute in this run.',\n status: 'succeeded',\n };\n }\n\n if (job.mode === 'listening' && job.listenerStatus === 'listening') {\n return {\n title: 'Waiting for trigger events',\n description: 'Matching trigger events will create job executions here.',\n status: 'running',\n };\n }\n\n if (job.mode === 'listening' && job.listenerStatus === 'resolved') {\n return {\n title: 'Listener resolved without executions',\n description: 'No matching trigger event created a job execution before the listener stopped.',\n status: job.status,\n };\n }\n\n if (job.status === 'pending') {\n return {\n title: 'Waiting for this job to start',\n description: 'No execution has been created for this job yet.',\n status: 'pending',\n };\n }\n\n if (job.status === 'skipped') {\n return {\n title: 'This job was skipped',\n description: skippedJobDescription(job.statusReason),\n status: 'skipped',\n };\n }\n\n if (job.status === 'cancelled') {\n return {\n title: 'Cancelled before start',\n description: 'This job was cancelled before an execution was created.',\n status: 'cancelled',\n };\n }\n\n return {\n title: 'Execution details unavailable',\n description: 'This job finished, but no job execution record is available.',\n status: job.status,\n };\n}\n\nfunction CarriedOverStepPanel() {\n return (\n <EmptyState\n className=\"min-h-120 rounded-8 border border-border-neutral-base bg-background-components-base px-16 py-20\"\n icon=\"componentLine\"\n title=\"Carried over from a previous attempt\"\n description=\"Not executed in this run.\"\n variant=\"compact\"\n />\n );\n}\n\nfunction skippedJobDescription(reason: Job['statusReason']): string {\n switch (reason) {\n case 'dependency_not_completed':\n return 'A required job did not complete, so this job was skipped.';\n case 'default_gate_rejected':\n return 'A required job did not succeed, so this job was skipped.';\n case 'condition_false':\n case 'condition_rejected':\n return 'The job condition did not match, so this job was skipped.';\n case 'condition_errored':\n return 'The job condition could not be evaluated, so this job was skipped.';\n case 'user_cancelled':\n case 'run_cancelled':\n case 'timed_out':\n case 'runner_lost':\n case 'step_failed':\n case 'unknown':\n case null:\n return 'This job did not start.';\n }\n}\n"],"names":["agentConfigIssueSchema","stepErrorReasonSchema","TriggerSourceIcon","Badge","Button","EmptyState","Icon","RelativeTime","useTimeTick","Tooltip","TooltipContent","TooltipTrigger","Text","Fragment","useId","useRef","useState","getWorkflowStatusVisual","WORKFLOW_JOB_STATUSES","workflowRunTriggerDisplayLabel","workflowRunTriggerLabel","StepList","AgentConfigFailureCallout","JobExecutionSwitcher","formatJobExecutionTime","JobExecutionTimeText","StepAttemptLogPanel","STATUS_BADGE_LABEL_WIDTH_CH","Math","max","map","status","label","length","JobCard","workspaceId","job","selectedJobExecution","selectedAttemptId","onSelectedJobExecutionChange","onSelectedAttemptChange","renderExpandedStep","sourcePanelId","sourceAvailable","focusedSourceStepId","onOpenStepSource","titleId","sourceButtonRef","localSelectedAttempt","setLocalSelectedAttempt","jobExecutionId","undefined","attemptId","selectedExecutionStatus","effectiveSelectedAttemptId","id","selectedSourceAction","selectedStepSourceAction","defaultRenderExpandedStep","step","stepId","attempt","attemptError","attemptStatus","carriedOver","CarriedOverStepPanel","StepAttemptDetailPanel","selectAttempt","section","aria-labelledby","className","div","mode","jobExecutions","as","size","bold","displayName","JobStatusBadge","variant","ref","type","aria-controls","aria-expanded","onClick","location","current","JobExecutionMetadata","execution","jobExecution","autoSelectActiveAttempt","emptyState","emptyStateForJob","showHeader","JobExecutionEmptyState","visual","badge","span","style","width","emptyStateForMissingExecution","icon","title","description","queueTime","runTime","executionStartedAt","startedAt","queuedAt","createdAt","items","triggerEvents","key","kind","value","time","filter","item","index","MetadataSeparator","JobExecutionTriggerMetadata","JobExecutionMetadataItem","triggerEvent","triggerLabel","triggerSource","source","event","triggerDisplayLabel","triggerCount","countLabel","tooltip","asChild","button","aria-label","provider","aria-hidden","jobExecutionTimeVerb","name","state","steps","selected","attempts","some","sourceLocation","selectedAttemptError","toSelectedAttemptError","error","isAgentConfigFailure","config","reason","safeParse","agentConfigIssue","agent_config_issue","exitCode","exit_code","parsedReason","success","data","message","signal","category","sequence","listenerStatus","skippedJobDescription","statusReason"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/workflow-run-view/job-card.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {Badge} from '@shipfox/react-ui/badge';\nimport {Button} from '@shipfox/react-ui/button';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon} from '@shipfox/react-ui/icon';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {useTimeTick} from '@shipfox/react-ui/time-ticker';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Text} from '@shipfox/react-ui/typography';\nimport type {ReactNode} from 'react';\nimport {Fragment, useId, useRef, useState} from 'react';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {\n AGENT_CONFIG_ISSUES,\n type Job,\n type JobExecution,\n type JobExecutionTime,\n STEP_ERROR_REASONS,\n type Step,\n type StepError,\n type StepSourceLocation,\n WORKFLOW_JOB_STATUSES,\n workflowRunTriggerDisplayLabel,\n workflowRunTriggerLabel,\n} from '#core/workflow-run.js';\nimport {type StepExpandedContext, StepList, type StepListEmptyState} from '../step-list/index.js';\nimport {AgentConfigFailureCallout} from './agent-config-failure-callout.js';\nimport {JobExecutionSwitcher} from './job-execution-switcher.js';\nimport {formatJobExecutionTime, JobExecutionTimeText} from './job-execution-time-text.js';\nimport {StepAttemptLogPanel} from './step-attempt-log-panel.js';\n\nconst STATUS_BADGE_LABEL_WIDTH_CH = Math.max(\n ...WORKFLOW_JOB_STATUSES.map((status) => getWorkflowStatusVisual(status).label.length),\n);\n\ninterface LocalSelectedAttempt {\n jobExecutionId: string | undefined;\n attemptId: string | null;\n}\n\nexport function JobCard({\n workspaceId,\n job,\n selectedJobExecution,\n selectedAttemptId,\n onSelectedJobExecutionChange,\n onSelectedAttemptChange,\n renderExpandedStep,\n sourcePanelId,\n sourceAvailable,\n focusedSourceStepId,\n onOpenStepSource,\n}: {\n workspaceId: string;\n job: Job;\n selectedJobExecution: JobExecution | undefined;\n selectedAttemptId: string | null | undefined;\n onSelectedJobExecutionChange: ((jobExecutionId: string | undefined) => void) | undefined;\n onSelectedAttemptChange: ((attemptId: string | undefined) => void) | undefined;\n renderExpandedStep?: ((context: StepExpandedContext) => ReactNode) | undefined;\n sourcePanelId?: string | undefined;\n sourceAvailable?: boolean | undefined;\n focusedSourceStepId?: string | null | undefined;\n onOpenStepSource?:\n | ((stepId: string, location: StepSourceLocation, trigger: HTMLButtonElement | null) => void)\n | undefined;\n}) {\n const titleId = useId();\n const sourceButtonRef = useRef<HTMLButtonElement>(null);\n const [localSelectedAttempt, setLocalSelectedAttempt] = useState<LocalSelectedAttempt>({\n jobExecutionId: undefined,\n attemptId: null,\n });\n const selectedExecutionStatus = selectedJobExecution?.status ?? job.status;\n const effectiveSelectedAttemptId =\n selectedAttemptId === undefined &&\n localSelectedAttempt.jobExecutionId === selectedJobExecution?.id\n ? localSelectedAttempt.attemptId\n : selectedAttemptId;\n const selectedSourceAction = selectedStepSourceAction(\n selectedJobExecution,\n effectiveSelectedAttemptId,\n );\n const defaultRenderExpandedStep = ({\n step,\n stepId,\n attempt,\n attemptError,\n attemptStatus,\n carriedOver,\n }: StepExpandedContext) =>\n carriedOver ? (\n <CarriedOverStepPanel />\n ) : (\n <StepAttemptDetailPanel\n workspaceId={workspaceId}\n step={step}\n stepId={stepId}\n attempt={attempt}\n attemptError={attemptError}\n attemptStatus={attemptStatus}\n />\n );\n\n function selectAttempt(attemptId: string | undefined) {\n if (selectedAttemptId === undefined) {\n setLocalSelectedAttempt({\n jobExecutionId: selectedJobExecution?.id,\n attemptId: attemptId ?? null,\n });\n }\n\n onSelectedAttemptChange?.(attemptId);\n }\n\n return (\n <section\n aria-labelledby={titleId}\n className=\"flex min-h-0 flex-col rounded-8 border border-border-neutral-base bg-background-components-base\"\n >\n <div className=\"grid min-h-52 min-w-0 grid-cols-1 gap-y-4 px-16 py-12\">\n <div className=\"flex min-w-0 flex-wrap items-center justify-between gap-10\">\n {job.mode === 'listening' &&\n job.jobExecutions.length > 0 &&\n onSelectedJobExecutionChange ? (\n <>\n <Text as=\"h2\" id={titleId} size=\"sm\" bold className=\"sr-only\">\n {job.displayName}\n </Text>\n <div className=\"flex min-w-0 items-center gap-8\">\n <JobStatusBadge status={selectedExecutionStatus} />\n <JobExecutionSwitcher\n job={job}\n selectedJobExecution={selectedJobExecution?.id ?? null}\n onSelectedJobExecutionChange={onSelectedJobExecutionChange}\n variant=\"title\"\n />\n </div>\n </>\n ) : (\n <div className=\"flex min-w-0 items-center gap-8\">\n <JobStatusBadge status={selectedExecutionStatus} />\n <Text\n as=\"h2\"\n id={titleId}\n size=\"sm\"\n bold\n className=\"min-w-0 truncate text-foreground-neutral-base\"\n >\n {job.displayName}\n </Text>\n </div>\n )}\n {sourceAvailable && selectedSourceAction && sourcePanelId && onOpenStepSource ? (\n <div className=\"flex min-w-max items-center gap-6\">\n <Button\n ref={sourceButtonRef}\n type=\"button\"\n variant=\"secondary\"\n size=\"xs\"\n aria-controls={sourcePanelId}\n aria-expanded={focusedSourceStepId === selectedSourceAction.stepId}\n onClick={() =>\n onOpenStepSource(\n selectedSourceAction.stepId,\n selectedSourceAction.location,\n sourceButtonRef.current,\n )\n }\n >\n View source\n </Button>\n </div>\n ) : null}\n </div>\n <JobExecutionMetadata execution={selectedJobExecution} />\n </div>\n <div className=\"min-h-0 border-t border-border-neutral-strong\">\n {selectedJobExecution ? (\n <StepList\n job={job}\n jobExecution={selectedJobExecution}\n selectedAttemptId={selectedAttemptId}\n onSelectedAttemptChange={selectAttempt}\n autoSelectActiveAttempt\n emptyState={emptyStateForJob(job, selectedJobExecution)}\n showHeader={false}\n className=\"rounded-none border-0 bg-transparent\"\n renderExpandedStep={renderExpandedStep ?? defaultRenderExpandedStep}\n />\n ) : (\n <JobExecutionEmptyState job={job} />\n )}\n </div>\n </section>\n );\n}\n\nfunction JobStatusBadge({status}: {status: Job['status'] | JobExecution['status']}) {\n const visual = getWorkflowStatusVisual(status);\n\n return (\n <Badge variant={visual.badge} size=\"xs\">\n <span className=\"text-center\" style={{width: `${STATUS_BADGE_LABEL_WIDTH_CH}ch`}}>\n {visual.label}\n </span>\n </Badge>\n );\n}\n\nfunction JobExecutionEmptyState({job}: {job: Job}) {\n const emptyState = emptyStateForMissingExecution(job);\n\n return (\n <EmptyState\n className=\"min-h-120 px-16 py-20\"\n icon=\"componentLine\"\n title={emptyState.title}\n description={emptyState.description}\n variant=\"compact\"\n />\n );\n}\n\nfunction JobExecutionMetadata({execution}: {execution: JobExecution | undefined}) {\n if (!execution) return null;\n\n const queueTime = execution.queueTime;\n const runTime = execution.runTime;\n const executionStartedAt = execution.startedAt ?? execution.queuedAt ?? execution.createdAt;\n const items = [\n execution.triggerEvents.length > 0 ? {key: 'trigger', kind: 'trigger' as const} : null,\n {key: 'started', kind: 'started' as const, value: executionStartedAt},\n queueTime\n ? {key: 'queue', icon: 'hourglassLine' as const, kind: 'queue' as const, time: queueTime}\n : null,\n runTime ? {key: 'run', icon: 'timerLine' as const, kind: 'run' as const, time: runTime} : null,\n ].filter((item) => item !== null);\n\n if (items.length === 0) return null;\n\n return (\n <div className=\"flex min-w-0 items-center gap-12 overflow-hidden text-foreground-neutral-muted\">\n {items.map((item, index) => (\n <Fragment key={item.key}>\n {index > 0 ? <MetadataSeparator /> : null}\n {item.kind === 'started' ? (\n <RelativeTime\n value={item.value}\n className=\"shrink-0 whitespace-nowrap text-xs leading-20 text-foreground-neutral-muted\"\n />\n ) : item.kind === 'trigger' ? (\n <JobExecutionTriggerMetadata execution={execution} />\n ) : (\n <JobExecutionMetadataItem icon={item.icon} kind={item.kind} time={item.time} />\n )}\n </Fragment>\n ))}\n </div>\n );\n}\n\nfunction JobExecutionTriggerMetadata({execution}: {execution: JobExecution}) {\n const triggerEvent = execution.triggerEvents[0];\n if (!triggerEvent) return null;\n\n const triggerLabel = workflowRunTriggerLabel({\n triggerSource: triggerEvent.source,\n triggerEvent: triggerEvent.event,\n });\n const triggerDisplayLabel = workflowRunTriggerDisplayLabel({\n triggerSource: triggerEvent.source,\n triggerEvent: triggerEvent.event,\n });\n const triggerCount = execution.triggerEvents.length;\n const countLabel = triggerCount > 1 ? ` (${triggerCount})` : '';\n const tooltip = triggerCount > 1 ? `${triggerLabel} (${triggerCount} events)` : triggerLabel;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={tooltip}\n className=\"inline-flex min-w-0 max-w-full cursor-default items-center gap-4 rounded-4 border-0 bg-transparent p-0 text-left text-foreground-neutral-muted outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n <TriggerSourceIcon\n provider={triggerEvent.source}\n source={triggerEvent.source}\n aria-hidden=\"true\"\n className=\"size-12 shrink-0\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate\">\n {triggerDisplayLabel}\n {countLabel}\n </Text>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\" className=\"block max-w-[360px] break-words\">\n {tooltip}\n </Text>\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction JobExecutionMetadataItem({\n icon,\n kind,\n time,\n}: {\n icon: 'hourglassLine' | 'timerLine';\n kind: 'queue' | 'run';\n time: JobExecutionTime;\n}) {\n useTimeTick();\n\n const tooltip = `${jobExecutionTimeVerb(kind, time)} for ${formatJobExecutionTime(time)}`;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={tooltip}\n className=\"inline-flex min-w-0 cursor-default items-center gap-4 rounded-4 border-0 bg-transparent p-0 text-foreground-neutral-muted outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n <Icon name={icon} className=\"size-12 shrink-0\" aria-hidden=\"true\" />\n <span className=\"shrink-0 text-xs leading-20 text-foreground-neutral-muted tabular-nums\">\n <JobExecutionTimeText time={time} />\n </span>\n </button>\n </TooltipTrigger>\n <TooltipContent>\n <Text as=\"span\" size=\"xs\">\n {tooltip}\n </Text>\n </TooltipContent>\n </Tooltip>\n );\n}\n\nfunction jobExecutionTimeVerb(kind: 'queue' | 'run', time: JobExecutionTime): string {\n if (kind === 'queue') return time.state === 'live' ? 'Queuing' : 'Queued';\n return time.state === 'live' ? 'Running' : 'Ran';\n}\n\nfunction MetadataSeparator() {\n return <span aria-hidden=\"true\" className=\"h-12 w-px shrink-0 bg-border-neutral-strong\" />;\n}\n\nfunction selectedStepSourceAction(\n jobExecution: JobExecution | undefined,\n selectedAttemptId: string | null | undefined,\n): {stepId: string; location: StepSourceLocation} | null {\n if (!jobExecution || !selectedAttemptId) return null;\n\n for (const step of jobExecution.steps) {\n const selected =\n selectedAttemptId === `carried-over:${step.id}` ||\n step.attempts.some((attempt) => attempt.id === selectedAttemptId);\n if (selected && step.sourceLocation) {\n return {stepId: step.id, location: step.sourceLocation};\n }\n }\n\n return null;\n}\n\nfunction StepAttemptDetailPanel({\n workspaceId,\n step,\n stepId,\n attempt,\n attemptError,\n attemptStatus,\n}: {\n workspaceId: string;\n step: Step;\n stepId: string;\n attempt: number;\n attemptError: Record<string, unknown> | null;\n attemptStatus: string;\n}) {\n const selectedAttemptError = toSelectedAttemptError(step, attemptError) ?? step.error;\n\n return (\n <div className=\"flex min-w-0 flex-col gap-10\">\n {isAgentConfigFailure(step, selectedAttemptError) ? (\n <AgentConfigFailureCallout\n workspaceId={workspaceId}\n config={null}\n error={selectedAttemptError}\n />\n ) : null}\n <StepAttemptLogPanel stepId={stepId} attempt={attempt} attemptStatus={attemptStatus} />\n </div>\n );\n}\n\nfunction toSelectedAttemptError(\n step: Step,\n error: Record<string, unknown> | null,\n): StepError | null {\n if (error === null) return null;\n\n const rawReason = error.reason;\n const parsedReason =\n typeof rawReason === 'string' &&\n STEP_ERROR_REASONS.has(rawReason as StepError['reason'] & string)\n ? (rawReason as NonNullable<StepError['reason']>)\n : undefined;\n const rawAgentConfigIssue = error.agentConfigIssue ?? error.agent_config_issue;\n const agentConfigIssue =\n typeof rawAgentConfigIssue === 'string' &&\n AGENT_CONFIG_ISSUES.has(rawAgentConfigIssue as NonNullable<StepError['agentConfigIssue']>)\n ? (rawAgentConfigIssue as NonNullable<StepError['agentConfigIssue']>)\n : undefined;\n const exitCode = error.exitCode ?? error.exit_code;\n const resolvedReason = parsedReason\n ? parsedReason\n : agentConfigIssue\n ? 'agent_config_invalid'\n : undefined;\n\n if (resolvedReason === undefined) return null;\n\n return {\n message: typeof error.message === 'string' ? error.message : '',\n exitCode: exitCode === null || typeof exitCode === 'number' ? exitCode : null,\n signal: typeof error.signal === 'string' ? error.signal : undefined,\n reason: resolvedReason,\n agentConfigIssue,\n category: step.type === 'setup' ? 'setup' : 'user',\n };\n}\n\nfunction isAgentConfigFailure(step: Step, error: StepError | null): boolean {\n return step.type === 'agent' && error?.reason === 'agent_config_invalid';\n}\n\nfunction emptyStateForJob(job: Job, jobExecution: JobExecution): StepListEmptyState | undefined {\n if (job.carriedOver) {\n return {\n title: 'Carried over from a previous attempt',\n description: 'This job did not execute in this run.',\n status: 'succeeded',\n };\n }\n\n if (jobExecution.status === 'pending') {\n return {\n title: 'Waiting for this job to start',\n description: 'Steps will appear here once the job starts.',\n status: jobExecution.status,\n };\n }\n\n if (jobExecution.status === 'running') {\n return {\n title: 'Waiting for the first step',\n description: 'This job is running, but no steps have started yet.',\n status: jobExecution.status,\n };\n }\n\n if (jobExecution.status === 'cancelled') {\n return {\n title: 'Cancelled before start',\n description: 'This job was cancelled before any step started.',\n status: jobExecution.status,\n };\n }\n\n if (jobExecution.status === 'succeeded' || jobExecution.status === 'failed') {\n return {\n title: 'No steps recorded',\n description: `Execution #${jobExecution.sequence} finished without recorded steps.`,\n status: jobExecution.status,\n };\n }\n\n return undefined;\n}\n\nfunction emptyStateForMissingExecution(job: Job): StepListEmptyState {\n if (job.carriedOver) {\n return {\n title: 'Carried over from a previous attempt',\n description: 'This job did not execute in this run.',\n status: 'succeeded',\n };\n }\n\n if (job.mode === 'listening' && job.listenerStatus === 'listening') {\n return {\n title: 'Waiting for trigger events',\n description: 'Matching trigger events will create job executions here.',\n status: 'running',\n };\n }\n\n if (job.mode === 'listening' && job.listenerStatus === 'resolved') {\n return {\n title: 'Listener resolved without executions',\n description: 'No matching trigger event created a job execution before the listener stopped.',\n status: job.status,\n };\n }\n\n if (job.status === 'pending') {\n return {\n title: 'Waiting for this job to start',\n description: 'No execution has been created for this job yet.',\n status: 'pending',\n };\n }\n\n if (job.status === 'skipped') {\n return {\n title: 'This job was skipped',\n description: skippedJobDescription(job.statusReason),\n status: 'skipped',\n };\n }\n\n if (job.status === 'cancelled') {\n return {\n title: 'Cancelled before start',\n description: 'This job was cancelled before an execution was created.',\n status: 'cancelled',\n };\n }\n\n return {\n title: 'Execution details unavailable',\n description: 'This job finished, but no job execution record is available.',\n status: job.status,\n };\n}\n\nfunction CarriedOverStepPanel() {\n return (\n <EmptyState\n className=\"min-h-120 rounded-8 border border-border-neutral-base bg-background-components-base px-16 py-20\"\n icon=\"componentLine\"\n title=\"Carried over from a previous attempt\"\n description=\"Not executed in this run.\"\n variant=\"compact\"\n />\n );\n}\n\nfunction skippedJobDescription(reason: Job['statusReason']): string {\n switch (reason) {\n case 'dependency_not_completed':\n return 'A required job did not complete, so this job was skipped.';\n case 'default_gate_rejected':\n return 'A required job did not succeed, so this job was skipped.';\n case 'condition_false':\n case 'condition_rejected':\n return 'The job condition did not match, so this job was skipped.';\n case 'condition_errored':\n return 'The job condition could not be evaluated, so this job was skipped.';\n case 'user_cancelled':\n case 'run_cancelled':\n case 'timed_out':\n case 'runner_lost':\n case 'step_failed':\n case 'unknown':\n case null:\n return 'This job did not start.';\n }\n}\n"],"names":["TriggerSourceIcon","Badge","Button","EmptyState","Icon","RelativeTime","useTimeTick","Tooltip","TooltipContent","TooltipTrigger","Text","Fragment","useId","useRef","useState","getWorkflowStatusVisual","AGENT_CONFIG_ISSUES","STEP_ERROR_REASONS","WORKFLOW_JOB_STATUSES","workflowRunTriggerDisplayLabel","workflowRunTriggerLabel","StepList","AgentConfigFailureCallout","JobExecutionSwitcher","formatJobExecutionTime","JobExecutionTimeText","StepAttemptLogPanel","STATUS_BADGE_LABEL_WIDTH_CH","Math","max","map","status","label","length","JobCard","workspaceId","job","selectedJobExecution","selectedAttemptId","onSelectedJobExecutionChange","onSelectedAttemptChange","renderExpandedStep","sourcePanelId","sourceAvailable","focusedSourceStepId","onOpenStepSource","titleId","sourceButtonRef","localSelectedAttempt","setLocalSelectedAttempt","jobExecutionId","undefined","attemptId","selectedExecutionStatus","effectiveSelectedAttemptId","id","selectedSourceAction","selectedStepSourceAction","defaultRenderExpandedStep","step","stepId","attempt","attemptError","attemptStatus","carriedOver","CarriedOverStepPanel","StepAttemptDetailPanel","selectAttempt","section","aria-labelledby","className","div","mode","jobExecutions","as","size","bold","displayName","JobStatusBadge","variant","ref","type","aria-controls","aria-expanded","onClick","location","current","JobExecutionMetadata","execution","jobExecution","autoSelectActiveAttempt","emptyState","emptyStateForJob","showHeader","JobExecutionEmptyState","visual","badge","span","style","width","emptyStateForMissingExecution","icon","title","description","queueTime","runTime","executionStartedAt","startedAt","queuedAt","createdAt","items","triggerEvents","key","kind","value","time","filter","item","index","MetadataSeparator","JobExecutionTriggerMetadata","JobExecutionMetadataItem","triggerEvent","triggerLabel","triggerSource","source","event","triggerDisplayLabel","triggerCount","countLabel","tooltip","asChild","button","aria-label","provider","aria-hidden","jobExecutionTimeVerb","name","state","steps","selected","attempts","some","sourceLocation","selectedAttemptError","toSelectedAttemptError","error","isAgentConfigFailure","config","rawReason","reason","parsedReason","has","rawAgentConfigIssue","agentConfigIssue","agent_config_issue","exitCode","exit_code","resolvedReason","message","signal","category","sequence","listenerStatus","skippedJobDescription","statusReason"],"mappings":"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"}