@shipfox/client-workflows 22.0.0 → 22.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.
@@ -1,2 +1,2 @@
1
1
  $ shipfox-swc
2
- Successfully compiled: 86 files with swc (531.81ms)
2
+ Successfully compiled: 86 files with swc (218.13ms)
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @shipfox/client-workflows
2
2
 
3
+ ## 22.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 50adc12: Displays live job duration timers in whole seconds.
8
+ - e99205b: Removes the redundant page heading and description from the workflows page.
9
+ - Updated dependencies [e92517f]
10
+ - @shipfox/client-shell@22.0.1
11
+ - @shipfox/client-triggers@22.0.1
12
+ - @shipfox/client-projects@22.0.1
13
+
3
14
  ## 22.0.0
4
15
 
5
16
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"job-execution-time-text.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/job-execution-time-text.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAE5D,wBAAgB,oBAAoB,CAAC,EAAC,IAAI,EAAC,EAAE;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAC,UAIpE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAMrE"}
1
+ {"version":3,"file":"job-execution-time-text.d.ts","sourceRoot":"","sources":["../../../src/components/job-detail/job-execution-time-text.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,uBAAuB,CAAC;AAG5D,wBAAgB,oBAAoB,CAAC,EAAC,IAAI,EAAC,EAAE;IAAC,IAAI,EAAE,gBAAgB,CAAA;CAAC,UAIpE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM,CAErE"}
@@ -1,24 +1,11 @@
1
1
  import { useTimeTick } from '@shipfox/react-ui/time-ticker';
2
- import { formatDuration } from '@shipfox/react-ui/utils';
2
+ import { formatJobExecutionTimeLabel } from '../job-graph/job-duration-format.js';
3
3
  export function JobExecutionTimeText({ time }) {
4
4
  useTimeTick();
5
5
  return formatJobExecutionTime(time);
6
6
  }
7
7
  export function formatJobExecutionTime(time) {
8
- if (time.state === 'live') {
9
- return formatDuration(Date.now() - Date.parse(time.fromIso));
10
- }
11
- return formatElapsedDuration(time.elapsed);
12
- }
13
- function formatElapsedDuration(duration) {
14
- const days = duration.days ?? 0;
15
- const hours = duration.hours ?? 0;
16
- const minutes = duration.minutes ?? 0;
17
- const seconds = duration.seconds ?? 0;
18
- if (days > 0) return hours > 0 ? `${days}d ${hours}h` : `${days}d`;
19
- if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
20
- if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
21
- return `${seconds}s`;
8
+ return formatJobExecutionTimeLabel(time);
22
9
  }
23
10
 
24
11
  //# sourceMappingURL=job-execution-time-text.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/job-detail/job-execution-time-text.tsx"],"sourcesContent":["import {useTimeTick} from '@shipfox/react-ui/time-ticker';\nimport {formatDuration} from '@shipfox/react-ui/utils';\nimport type {JobExecutionTime} from '#core/workflow-run.js';\n\nexport function JobExecutionTimeText({time}: {time: JobExecutionTime}) {\n useTimeTick();\n\n return formatJobExecutionTime(time);\n}\n\nexport function formatJobExecutionTime(time: JobExecutionTime): string {\n if (time.state === 'live') {\n return formatDuration(Date.now() - Date.parse(time.fromIso));\n }\n\n return formatElapsedDuration(time.elapsed);\n}\n\nfunction formatElapsedDuration(duration: {\n days?: number | undefined;\n hours?: number | undefined;\n minutes?: number | undefined;\n seconds?: number | undefined;\n}): string {\n const days = duration.days ?? 0;\n const hours = duration.hours ?? 0;\n const minutes = duration.minutes ?? 0;\n const seconds = duration.seconds ?? 0;\n\n if (days > 0) return hours > 0 ? `${days}d ${hours}h` : `${days}d`;\n if (hours > 0) return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;\n if (minutes > 0) return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;\n return `${seconds}s`;\n}\n"],"names":["useTimeTick","formatDuration","JobExecutionTimeText","time","formatJobExecutionTime","state","Date","now","parse","fromIso","formatElapsedDuration","elapsed","duration","days","hours","minutes","seconds"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAC1D,SAAQC,cAAc,QAAO,0BAA0B;AAGvD,OAAO,SAASC,qBAAqB,EAACC,IAAI,EAA2B;IACnEH;IAEA,OAAOI,uBAAuBD;AAChC;AAEA,OAAO,SAASC,uBAAuBD,IAAsB;IAC3D,IAAIA,KAAKE,KAAK,KAAK,QAAQ;QACzB,OAAOJ,eAAeK,KAAKC,GAAG,KAAKD,KAAKE,KAAK,CAACL,KAAKM,OAAO;IAC5D;IAEA,OAAOC,sBAAsBP,KAAKQ,OAAO;AAC3C;AAEA,SAASD,sBAAsBE,QAK9B;IACC,MAAMC,OAAOD,SAASC,IAAI,IAAI;IAC9B,MAAMC,QAAQF,SAASE,KAAK,IAAI;IAChC,MAAMC,UAAUH,SAASG,OAAO,IAAI;IACpC,MAAMC,UAAUJ,SAASI,OAAO,IAAI;IAEpC,IAAIH,OAAO,GAAG,OAAOC,QAAQ,IAAI,GAAGD,KAAK,EAAE,EAAEC,MAAM,CAAC,CAAC,GAAG,GAAGD,KAAK,CAAC,CAAC;IAClE,IAAIC,QAAQ,GAAG,OAAOC,UAAU,IAAI,GAAGD,MAAM,EAAE,EAAEC,QAAQ,CAAC,CAAC,GAAG,GAAGD,MAAM,CAAC,CAAC;IACzE,IAAIC,UAAU,GAAG,OAAOC,UAAU,IAAI,GAAGD,QAAQ,EAAE,EAAEC,QAAQ,CAAC,CAAC,GAAG,GAAGD,QAAQ,CAAC,CAAC;IAC/E,OAAO,GAAGC,QAAQ,CAAC,CAAC;AACtB"}
1
+ {"version":3,"sources":["../../../src/components/job-detail/job-execution-time-text.tsx"],"sourcesContent":["import {useTimeTick} from '@shipfox/react-ui/time-ticker';\nimport type {JobExecutionTime} from '#core/workflow-run.js';\nimport {formatJobExecutionTimeLabel} from '../job-graph/job-duration-format.js';\n\nexport function JobExecutionTimeText({time}: {time: JobExecutionTime}) {\n useTimeTick();\n\n return formatJobExecutionTime(time);\n}\n\nexport function formatJobExecutionTime(time: JobExecutionTime): string {\n return formatJobExecutionTimeLabel(time);\n}\n"],"names":["useTimeTick","formatJobExecutionTimeLabel","JobExecutionTimeText","time","formatJobExecutionTime"],"mappings":"AAAA,SAAQA,WAAW,QAAO,gCAAgC;AAE1D,SAAQC,2BAA2B,QAAO,sCAAsC;AAEhF,OAAO,SAASC,qBAAqB,EAACC,IAAI,EAA2B;IACnEH;IAEA,OAAOI,uBAAuBD;AAChC;AAEA,OAAO,SAASC,uBAAuBD,IAAsB;IAC3D,OAAOF,4BAA4BE;AACrC"}
@@ -2,7 +2,7 @@ import { humanDuration } from '@shipfox/react-ui/utils';
2
2
  export function formatJobExecutionTimeLabel(time) {
3
3
  switch(time.state){
4
4
  case 'live':
5
- return humanDuration(time.fromIso);
5
+ return humanDuration(time.fromIso) || '0s';
6
6
  case 'fixed':
7
7
  return formatFixedDurationLabel(time.elapsed);
8
8
  default:
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/job-graph/job-duration-format.ts"],"sourcesContent":["import {humanDuration} from '@shipfox/react-ui/utils';\nimport type {\n JobDisplayDuration,\n JobExecutionDisplayStatus,\n JobExecutionTime,\n} from '#core/workflow-run.js';\n\nexport function formatJobExecutionTimeLabel(time: JobExecutionTime): string {\n switch (time.state) {\n case 'live':\n return humanDuration(time.fromIso);\n case 'fixed':\n return formatFixedDurationLabel(time.elapsed);\n default: {\n const exhaustive: never = time;\n return exhaustive;\n }\n }\n}\n\nexport function formatJobDurationAccessibleLabel(\n duration: JobDisplayDuration | null,\n displayStatus?: JobExecutionDisplayStatus,\n): string | undefined {\n if (duration === null) return undefined;\n\n const label = formatJobExecutionTimeLabel(duration);\n switch (duration.kind) {\n case 'queue':\n return duration.state === 'live' ? `queueing ${label}` : `queued ${label}`;\n case 'run':\n if (duration.state !== 'live') return `ran ${label}`;\n if (displayStatus === 'running') return `running ${label}`;\n return displayStatus === 'pending'\n ? `runner assigned ${label}`\n : `execution elapsed ${label}`;\n default: {\n const exhaustive: never = duration;\n return exhaustive;\n }\n }\n}\n\nfunction formatFixedDurationLabel({\n years = 0,\n months = 0,\n weeks = 0,\n days = 0,\n hours = 0,\n minutes = 0,\n seconds = 0,\n}: Extract<JobExecutionTime, {state: 'fixed'}>['elapsed']): string {\n const totalDays = years * 365 + months * 30 + weeks * 7 + days;\n const totalHours = totalDays * 24 + hours;\n\n if (totalHours > 0) return `${totalHours}h ${pad2(minutes)}m`;\n if (minutes > 0) return `${minutes}m ${pad2(seconds)}s`;\n return `${seconds}s`;\n}\n\nfunction pad2(value: number): string {\n return value.toString().padStart(2, '0');\n}\n"],"names":["humanDuration","formatJobExecutionTimeLabel","time","state","fromIso","formatFixedDurationLabel","elapsed","exhaustive","formatJobDurationAccessibleLabel","duration","displayStatus","undefined","label","kind","years","months","weeks","days","hours","minutes","seconds","totalDays","totalHours","pad2","value","toString","padStart"],"mappings":"AAAA,SAAQA,aAAa,QAAO,0BAA0B;AAOtD,OAAO,SAASC,4BAA4BC,IAAsB;IAChE,OAAQA,KAAKC,KAAK;QAChB,KAAK;YACH,OAAOH,cAAcE,KAAKE,OAAO;QACnC,KAAK;YACH,OAAOC,yBAAyBH,KAAKI,OAAO;QAC9C;YAAS;gBACP,MAAMC,aAAoBL;gBAC1B,OAAOK;YACT;IACF;AACF;AAEA,OAAO,SAASC,iCACdC,QAAmC,EACnCC,aAAyC;IAEzC,IAAID,aAAa,MAAM,OAAOE;IAE9B,MAAMC,QAAQX,4BAA4BQ;IAC1C,OAAQA,SAASI,IAAI;QACnB,KAAK;YACH,OAAOJ,SAASN,KAAK,KAAK,SAAS,CAAC,SAAS,EAAES,OAAO,GAAG,CAAC,OAAO,EAAEA,OAAO;QAC5E,KAAK;YACH,IAAIH,SAASN,KAAK,KAAK,QAAQ,OAAO,CAAC,IAAI,EAAES,OAAO;YACpD,IAAIF,kBAAkB,WAAW,OAAO,CAAC,QAAQ,EAAEE,OAAO;YAC1D,OAAOF,kBAAkB,YACrB,CAAC,gBAAgB,EAAEE,OAAO,GAC1B,CAAC,kBAAkB,EAAEA,OAAO;QAClC;YAAS;gBACP,MAAML,aAAoBE;gBAC1B,OAAOF;YACT;IACF;AACF;AAEA,SAASF,yBAAyB,EAChCS,QAAQ,CAAC,EACTC,SAAS,CAAC,EACVC,QAAQ,CAAC,EACTC,OAAO,CAAC,EACRC,QAAQ,CAAC,EACTC,UAAU,CAAC,EACXC,UAAU,CAAC,EAC4C;IACvD,MAAMC,YAAYP,QAAQ,MAAMC,SAAS,KAAKC,QAAQ,IAAIC;IAC1D,MAAMK,aAAaD,YAAY,KAAKH;IAEpC,IAAII,aAAa,GAAG,OAAO,GAAGA,WAAW,EAAE,EAAEC,KAAKJ,SAAS,CAAC,CAAC;IAC7D,IAAIA,UAAU,GAAG,OAAO,GAAGA,QAAQ,EAAE,EAAEI,KAAKH,SAAS,CAAC,CAAC;IACvD,OAAO,GAAGA,QAAQ,CAAC,CAAC;AACtB;AAEA,SAASG,KAAKC,KAAa;IACzB,OAAOA,MAAMC,QAAQ,GAAGC,QAAQ,CAAC,GAAG;AACtC"}
1
+ {"version":3,"sources":["../../../src/components/job-graph/job-duration-format.ts"],"sourcesContent":["import {humanDuration} from '@shipfox/react-ui/utils';\nimport type {\n JobDisplayDuration,\n JobExecutionDisplayStatus,\n JobExecutionTime,\n} from '#core/workflow-run.js';\n\nexport function formatJobExecutionTimeLabel(time: JobExecutionTime): string {\n switch (time.state) {\n case 'live':\n return humanDuration(time.fromIso) || '0s';\n case 'fixed':\n return formatFixedDurationLabel(time.elapsed);\n default: {\n const exhaustive: never = time;\n return exhaustive;\n }\n }\n}\n\nexport function formatJobDurationAccessibleLabel(\n duration: JobDisplayDuration | null,\n displayStatus?: JobExecutionDisplayStatus,\n): string | undefined {\n if (duration === null) return undefined;\n\n const label = formatJobExecutionTimeLabel(duration);\n switch (duration.kind) {\n case 'queue':\n return duration.state === 'live' ? `queueing ${label}` : `queued ${label}`;\n case 'run':\n if (duration.state !== 'live') return `ran ${label}`;\n if (displayStatus === 'running') return `running ${label}`;\n return displayStatus === 'pending'\n ? `runner assigned ${label}`\n : `execution elapsed ${label}`;\n default: {\n const exhaustive: never = duration;\n return exhaustive;\n }\n }\n}\n\nfunction formatFixedDurationLabel({\n years = 0,\n months = 0,\n weeks = 0,\n days = 0,\n hours = 0,\n minutes = 0,\n seconds = 0,\n}: Extract<JobExecutionTime, {state: 'fixed'}>['elapsed']): string {\n const totalDays = years * 365 + months * 30 + weeks * 7 + days;\n const totalHours = totalDays * 24 + hours;\n\n if (totalHours > 0) return `${totalHours}h ${pad2(minutes)}m`;\n if (minutes > 0) return `${minutes}m ${pad2(seconds)}s`;\n return `${seconds}s`;\n}\n\nfunction pad2(value: number): string {\n return value.toString().padStart(2, '0');\n}\n"],"names":["humanDuration","formatJobExecutionTimeLabel","time","state","fromIso","formatFixedDurationLabel","elapsed","exhaustive","formatJobDurationAccessibleLabel","duration","displayStatus","undefined","label","kind","years","months","weeks","days","hours","minutes","seconds","totalDays","totalHours","pad2","value","toString","padStart"],"mappings":"AAAA,SAAQA,aAAa,QAAO,0BAA0B;AAOtD,OAAO,SAASC,4BAA4BC,IAAsB;IAChE,OAAQA,KAAKC,KAAK;QAChB,KAAK;YACH,OAAOH,cAAcE,KAAKE,OAAO,KAAK;QACxC,KAAK;YACH,OAAOC,yBAAyBH,KAAKI,OAAO;QAC9C;YAAS;gBACP,MAAMC,aAAoBL;gBAC1B,OAAOK;YACT;IACF;AACF;AAEA,OAAO,SAASC,iCACdC,QAAmC,EACnCC,aAAyC;IAEzC,IAAID,aAAa,MAAM,OAAOE;IAE9B,MAAMC,QAAQX,4BAA4BQ;IAC1C,OAAQA,SAASI,IAAI;QACnB,KAAK;YACH,OAAOJ,SAASN,KAAK,KAAK,SAAS,CAAC,SAAS,EAAES,OAAO,GAAG,CAAC,OAAO,EAAEA,OAAO;QAC5E,KAAK;YACH,IAAIH,SAASN,KAAK,KAAK,QAAQ,OAAO,CAAC,IAAI,EAAES,OAAO;YACpD,IAAIF,kBAAkB,WAAW,OAAO,CAAC,QAAQ,EAAEE,OAAO;YAC1D,OAAOF,kBAAkB,YACrB,CAAC,gBAAgB,EAAEE,OAAO,GAC1B,CAAC,kBAAkB,EAAEA,OAAO;QAClC;YAAS;gBACP,MAAML,aAAoBE;gBAC1B,OAAOF;YACT;IACF;AACF;AAEA,SAASF,yBAAyB,EAChCS,QAAQ,CAAC,EACTC,SAAS,CAAC,EACVC,QAAQ,CAAC,EACTC,OAAO,CAAC,EACRC,QAAQ,CAAC,EACTC,UAAU,CAAC,EACXC,UAAU,CAAC,EAC4C;IACvD,MAAMC,YAAYP,QAAQ,MAAMC,SAAS,KAAKC,QAAQ,IAAIC;IAC1D,MAAMK,aAAaD,YAAY,KAAKH;IAEpC,IAAII,aAAa,GAAG,OAAO,GAAGA,WAAW,EAAE,EAAEC,KAAKJ,SAAS,CAAC,CAAC;IAC7D,IAAIA,UAAU,GAAG,OAAO,GAAGA,QAAQ,EAAE,EAAEI,KAAKH,SAAS,CAAC,CAAC;IACvD,OAAO,GAAGA,QAAQ,CAAC,CAAC;AACtB;AAEA,SAASG,KAAKC,KAAa;IACzB,OAAOA,MAAMC,QAAQ,GAAGC,QAAQ,CAAC,GAAG;AACtC"}
@@ -52,6 +52,11 @@ function ProjectWorkflowsPageInner({ projectId }) {
52
52
  return /*#__PURE__*/ _jsxs("div", {
53
53
  className: "flex w-full flex-col gap-section",
54
54
  children: [
55
+ /*#__PURE__*/ _jsx(Header, {
56
+ variant: "h1",
57
+ className: "sr-only",
58
+ children: "Workflows"
59
+ }),
55
60
  projectQuery.isPending ? /*#__PURE__*/ _jsxs("div", {
56
61
  className: "flex flex-col gap-cluster",
57
62
  children: [
@@ -73,20 +78,6 @@ function ProjectWorkflowsPageInner({ projectId }) {
73
78
  }) : null,
74
79
  projectQuery.data ? /*#__PURE__*/ _jsxs(_Fragment, {
75
80
  children: [
76
- /*#__PURE__*/ _jsxs("header", {
77
- className: "flex flex-col gap-tight",
78
- children: [
79
- /*#__PURE__*/ _jsx(Header, {
80
- variant: "h2",
81
- children: "Workflows"
82
- }),
83
- /*#__PURE__*/ _jsx(Text, {
84
- size: "sm",
85
- className: "text-foreground-neutral-muted",
86
- children: "Synced workflow definitions for this project source."
87
- })
88
- ]
89
- }),
90
81
  /*#__PURE__*/ _jsx(SourceStrip, {
91
82
  connectionId: projectQuery.data.source.connectionId,
92
83
  externalRepositoryId: projectQuery.data.source.externalRepositoryId,
@@ -148,6 +139,8 @@ function WorkflowDefinitionsList({ definitions, isPending, isError, sync, runErr
148
139
  }
149
140
  if (isError && definitions.length === 0) {
150
141
  return /*#__PURE__*/ _jsx(Panel, {
142
+ role: "region",
143
+ "aria-label": "Workflow definitions",
151
144
  children: /*#__PURE__*/ _jsx(LoadErrorState, {
152
145
  title: "Couldn't load workflows",
153
146
  description: "Definitions could not be loaded. Source metadata remains visible.",
@@ -159,6 +152,8 @@ function WorkflowDefinitionsList({ definitions, isPending, isError, sync, runErr
159
152
  }
160
153
  if (definitions.length === 0) {
161
154
  return /*#__PURE__*/ _jsx(Panel, {
155
+ role: "region",
156
+ "aria-label": "Workflow definitions",
162
157
  children: /*#__PURE__*/ _jsx(WorkflowEmptyState, {
163
158
  sync: sync
164
159
  })
@@ -167,6 +162,8 @@ function WorkflowDefinitionsList({ definitions, isPending, isError, sync, runErr
167
162
  return /*#__PURE__*/ _jsxs(_Fragment, {
168
163
  children: [
169
164
  /*#__PURE__*/ _jsxs(Panel, {
165
+ role: "region",
166
+ "aria-label": "Workflow definitions",
170
167
  children: [
171
168
  /*#__PURE__*/ _jsx("div", {
172
169
  className: "hidden md:block",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/pages/project-workflows-page.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {\n type Definition,\n type DefinitionSyncSummary,\n SourceStrip,\n useDefinitionsInfiniteQuery,\n useProjectQuery,\n} from '@shipfox/client-projects';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {LoadErrorState} from '@shipfox/react-ui/load-error-state';\nimport {Panel} from '@shipfox/react-ui/panel';\nimport {RelativeTime, RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '@shipfox/react-ui/sheet';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {useState} from 'react';\nimport {useFireManualWorkflowMutation} from '#hooks/api/workflow-runs.js';\n\nexport function ProjectWorkflowsPage({projectId}: {projectId: string}) {\n return (\n <RelativeTimeProvider>\n <ProjectWorkflowsPageInner projectId={projectId} />\n </RelativeTimeProvider>\n );\n}\n\nfunction ProjectWorkflowsPageInner({projectId}: {projectId: string}) {\n const projectQuery = useProjectQuery(projectId);\n const definitionsQuery = useDefinitionsInfiniteQuery(projectId);\n const fireManual = useFireManualWorkflowMutation();\n const [selectedDefinition, setSelectedDefinition] = useState<Definition | null>(null);\n const [runError, setRunError] = useState<{definitionId: string; message: string} | null>(null);\n const definitions = definitionsQuery.data?.pages.flatMap((page) => page.definitions) ?? [];\n const sync = definitionsQuery.data?.pages[0]?.sync;\n\n async function handleRun(definition: Definition) {\n setRunError(null);\n if (!definition.manualTrigger) return;\n try {\n await fireManual.mutateAsync({projectId, definitionId: definition.id});\n toast.success('Run queued');\n } catch (error) {\n const message = errorMessage(error, 'Could not queue run.');\n setRunError({definitionId: definition.id, message});\n toast.error(message);\n }\n }\n\n return (\n <div className=\"flex w-full flex-col gap-section\">\n {projectQuery.isPending ? (\n <div className=\"flex flex-col gap-cluster\">\n <Skeleton className=\"h-28 w-1/3\" />\n <Skeleton className=\"h-18 w-1/2\" />\n </div>\n ) : null}\n\n {projectQuery.isError && projectQuery.data === undefined ? (\n projectQuery.error instanceof ApiError && projectQuery.error.status === 404 ? (\n <EmptyState\n icon=\"errorWarningLine\"\n title=\"Project not found\"\n description=\"This project doesn't exist, or you don't have access to it.\"\n />\n ) : (\n <QueryLoadError query={projectQuery} subject=\"project\" />\n )\n ) : null}\n\n {projectQuery.data ? (\n <>\n <header className=\"flex flex-col gap-tight\">\n <Header variant=\"h2\">Workflows</Header>\n <Text size=\"sm\" className=\"text-foreground-neutral-muted\">\n Synced workflow definitions for this project source.\n </Text>\n </header>\n\n <SourceStrip\n connectionId={projectQuery.data.source.connectionId}\n externalRepositoryId={projectQuery.data.source.externalRepositoryId}\n sync={sync}\n isPending={definitionsQuery.isPending}\n />\n\n <WorkflowSyncAlert sync={sync} />\n <WorkflowSyncWarnings sync={sync} />\n\n <WorkflowDefinitionsList\n definitions={definitions}\n isPending={definitionsQuery.isPending}\n isError={definitionsQuery.isError}\n sync={sync ?? null}\n runError={runError}\n runningDefinitionId={\n fireManual.isPending && fireManual.variables\n ? fireManual.variables.definitionId\n : null\n }\n hasNextPage={definitionsQuery.hasNextPage}\n isFetchingNextPage={definitionsQuery.isFetchingNextPage}\n isFetchNextPageError={definitionsQuery.isFetchNextPageError}\n onRetry={() => definitionsQuery.refetch()}\n onLoadMore={() => definitionsQuery.fetchNextPage()}\n onOpenDefinition={setSelectedDefinition}\n onRun={(definition) => {\n void handleRun(definition);\n }}\n />\n </>\n ) : null}\n\n <DefinitionSheet\n definition={selectedDefinition}\n onOpenChange={(open) => {\n if (!open) setSelectedDefinition(null);\n }}\n />\n </div>\n );\n}\n\nfunction WorkflowDefinitionsList({\n definitions,\n isPending,\n isError,\n sync,\n runError,\n runningDefinitionId,\n hasNextPage,\n isFetchingNextPage,\n isFetchNextPageError,\n onRetry,\n onLoadMore,\n onOpenDefinition,\n onRun,\n}: {\n definitions: Definition[];\n isPending: boolean;\n isError: boolean;\n sync: DefinitionSyncSummary | null;\n runError: {definitionId: string; message: string} | null;\n runningDefinitionId: string | null;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n isFetchNextPageError: boolean;\n onRetry: () => void;\n onLoadMore: () => void;\n onOpenDefinition: (definition: Definition) => void;\n onRun: (definition: Definition) => void;\n}) {\n if (isPending) {\n return (\n <Panel role=\"status\" aria-label=\"Loading workflows\" className=\"divide-y\">\n <Skeleton className=\"h-44 w-full rounded-none\" />\n <Skeleton className=\"h-44 w-full rounded-none\" />\n <Skeleton className=\"h-44 w-full rounded-none\" />\n </Panel>\n );\n }\n\n if (isError && definitions.length === 0) {\n return (\n <Panel>\n <LoadErrorState\n title=\"Couldn't load workflows\"\n description=\"Definitions could not be loaded. Source metadata remains visible.\"\n onRetry={onRetry}\n retryLabel=\"Retry loading workflows\"\n variant=\"panel\"\n />\n </Panel>\n );\n }\n\n if (definitions.length === 0) {\n return (\n <Panel>\n <WorkflowEmptyState sync={sync} />\n </Panel>\n );\n }\n\n return (\n <>\n <Panel>\n <div className=\"hidden md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-40\"></TableHead>\n <TableHead>Workflow</TableHead>\n <TableHead className=\"w-180\">Updated</TableHead>\n <TableHead className=\"w-80 text-right\"></TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {definitions.map((definition) => {\n const runErrorMessage =\n runError?.definitionId === definition.id ? runError.message : null;\n const isRunning = runningDefinitionId === definition.id;\n\n return (\n // The workflow-name cell holds a `<button>` so the row is\n // keyboard-reachable (Tab focuses, Enter/Space activates\n // via native button semantics). The TableRow itself is no\n // longer clickable: a row-level onClick would be invisible\n // to keyboard users and require custom keydown handling.\n // The `group` class on the row still drives the Run button\n // reveal on hover or focus-within.\n <TableRow key={definition.id} className=\"group\">\n <TableCell>\n <Icon\n name={sourceIcon(definition.source)}\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden=\"true\"\n />\n </TableCell>\n <TableCell className=\"max-w-260\">\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <button\n type=\"button\"\n onClick={() => onOpenDefinition(definition)}\n className=\"flex min-w-0 flex-col gap-tight rounded-4 text-left outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n <Text size=\"sm\" bold className=\"truncate\">\n {definition.name}\n </Text>\n <Code className=\"truncate text-foreground-neutral-muted\">\n {definition.configPath ?? 'Manual definition'}\n </Code>\n </button>\n {runErrorMessage ? (\n <Text size=\"xs\" className=\"text-tag-error-text\">\n {runErrorMessage}\n </Text>\n ) : null}\n </div>\n </TableCell>\n <TableCell className=\"text-foreground-neutral-muted\">\n <RelativeTime value={definition.updatedAt} />\n </TableCell>\n <TableCell>\n {definition.manualTrigger ? (\n <div className=\"flex justify-end opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100\">\n <Button size=\"xs\" isLoading={isRunning} onClick={() => onRun(definition)}>\n Run\n </Button>\n </div>\n ) : null}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n\n <div className=\"flex flex-col md:hidden\">\n {definitions.map((definition) => {\n const runErrorMessage =\n runError?.definitionId === definition.id ? runError.message : null;\n const isRunning = runningDefinitionId === definition.id;\n\n return (\n <div\n key={definition.id}\n className=\"flex flex-col gap-inline border-b border-border-neutral-base p-panel-compact last:border-b-0\"\n >\n <button\n type=\"button\"\n className=\"flex min-w-0 items-start gap-inline text-left\"\n onClick={() => onOpenDefinition(definition)}\n >\n <Icon\n name={sourceIcon(definition.source)}\n className=\"size-16 shrink-0 text-foreground-neutral-muted\"\n aria-hidden=\"true\"\n />\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"sm\" bold className=\"break-words\">\n {definition.name}\n </Text>\n <Code className=\"break-words text-foreground-neutral-muted\">\n {definition.configPath ?? 'Manual definition'}\n </Code>\n </div>\n </button>\n <div className=\"flex items-center justify-between gap-inline\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n Updated <RelativeTime value={definition.updatedAt} />\n </Text>\n {definition.manualTrigger ? (\n <Button size=\"sm\" isLoading={isRunning} onClick={() => onRun(definition)}>\n Run\n </Button>\n ) : null}\n </div>\n {runErrorMessage ? (\n <Text size=\"xs\" className=\"text-tag-error-text\">\n {runErrorMessage}\n </Text>\n ) : null}\n </div>\n );\n })}\n </div>\n </Panel>\n\n {isFetchNextPageError ? (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <Text size=\"sm\">Could not load more workflows.</Text>\n <Button size=\"sm\" variant=\"secondary\" onClick={onLoadMore}>\n Retry\n </Button>\n </div>\n </Callout>\n ) : null}\n\n {hasNextPage ? (\n <div className=\"flex justify-center\">\n <Button size=\"sm\" variant=\"secondary\" isLoading={isFetchingNextPage} onClick={onLoadMore}>\n Load more\n </Button>\n </div>\n ) : null}\n </>\n );\n}\n\nfunction sourceIcon(source: 'manual' | 'vcs'): IconName {\n return source === 'vcs' ? ('gitBranchLine' as IconName) : ('terminalLine' as IconName);\n}\n\nfunction WorkflowEmptyState({sync}: {sync: DefinitionSyncSummary | null}) {\n const message =\n sync?.status === 'failed' && sync.lastErrorCode === 'no-workflow-files'\n ? 'No workflow files found under .shipfox/workflows/.'\n : sync?.status === 'failed'\n ? (sync.lastErrorMessage ?? 'Workflow definitions could not be synced.')\n : sync?.status === 'syncing'\n ? 'Workflow definitions are being discovered.'\n : sync?.status === 'succeeded'\n ? 'No workflow definitions found.'\n : 'Workflow sync has not reported yet.';\n\n return <EmptyState icon=\"flowChart\" title=\"No workflows\" description={message} variant=\"panel\" />;\n}\n\nfunction WorkflowSyncAlert({sync}: {sync: DefinitionSyncSummary | null | undefined}) {\n if (sync?.status !== 'failed') return null;\n\n return (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-tight\">\n <Text size=\"sm\" bold>\n Workflow sync failed\n </Text>\n <Text size=\"sm\">\n {sync.lastErrorMessage ?? 'The latest workflow sync failed before definitions updated.'}\n </Text>\n </div>\n </Callout>\n );\n}\n\nfunction WorkflowSyncWarnings({sync}: {sync: DefinitionSyncSummary | null | undefined}) {\n if (sync?.status !== 'succeeded' || sync.warnings.length === 0) return null;\n\n const seenKeys = new Map<string, number>();\n const warningItems = sync.warnings.map((warning) => {\n const baseKey = `${warning.code}-${warning.path ?? 'workflow'}-${warning.message}`;\n const occurrence = seenKeys.get(baseKey) ?? 0;\n seenKeys.set(baseKey, occurrence + 1);\n return {key: `${baseKey}-${occurrence}`, warning};\n });\n\n return (\n <Callout role=\"status\" type=\"warning\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Workflow definition warnings\n </Text>\n <ul className=\"flex flex-col gap-tight\">\n {warningItems.map(({key, warning}) => (\n <li key={key}>\n <Text size=\"sm\">{warning.message}</Text>\n {warning.path ? (\n <Code className=\"text-foreground-neutral-muted\">{warning.path}</Code>\n ) : null}\n </li>\n ))}\n </ul>\n </div>\n </Callout>\n );\n}\n\nfunction DefinitionSheet({\n definition,\n onOpenChange,\n}: {\n definition: Definition | null;\n onOpenChange: (open: boolean) => void;\n}) {\n const normalizedJson = definition\n ? JSON.stringify(\n {\n workflow_document: definition.workflowDocument,\n workflow_model: definition.workflowModel,\n },\n null,\n 2,\n )\n : '';\n\n return (\n <Sheet open={Boolean(definition)} onOpenChange={onOpenChange}>\n <SheetContent className=\"w-full sm:max-w-[560px]\">\n {definition ? (\n <>\n <SheetHeader>\n <SheetTitle>{definition.name}</SheetTitle>\n <SheetDescription>\n {definition.configPath ?? 'Manual workflow definition'}\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"gap-group\">\n <div className=\"grid w-full gap-inline\">\n <Metadata label=\"Definition id\" value={definition.id} />\n <Metadata label=\"Source\" value={definition.source} />\n <Metadata label=\"Ref\" value={definition.ref ?? 'Not set'} />\n <Metadata label=\"SHA\" value={definition.sha ?? 'Not set'} />\n </div>\n <div className=\"flex w-full flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Normalized definition\n </Text>\n <pre className=\"max-h-[52vh] w-full overflow-auto rounded-8 border border-border-neutral-base bg-background-neutral-subtle p-panel-compact scrollbar\">\n <Code as=\"code\" className=\"whitespace-pre text-foreground-neutral-base\">\n {normalizedJson}\n </Code>\n </pre>\n </div>\n </SheetBody>\n </>\n ) : null}\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction Metadata({label, value}: {label: string; value: string}) {\n return (\n <div className=\"min-w-0 py-row first:pt-0 last:pb-0\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n {label}\n </Text>\n <Text size=\"sm\" className=\"break-words\">\n {value}\n </Text>\n </div>\n );\n}\n\nfunction errorMessage(error: unknown, fallback: string) {\n if (error instanceof ApiError && error.message) return error.message;\n if (error instanceof Error && error.message) return error.message;\n return fallback;\n}\n"],"names":["ApiError","SourceStrip","useDefinitionsInfiniteQuery","useProjectQuery","QueryLoadError","Button","Callout","EmptyState","Icon","LoadErrorState","Panel","RelativeTime","RelativeTimeProvider","Sheet","SheetBody","SheetContent","SheetDescription","SheetHeader","SheetTitle","Skeleton","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","useState","useFireManualWorkflowMutation","ProjectWorkflowsPage","projectId","ProjectWorkflowsPageInner","projectQuery","definitionsQuery","fireManual","selectedDefinition","setSelectedDefinition","runError","setRunError","definitions","data","pages","flatMap","page","sync","handleRun","definition","manualTrigger","mutateAsync","definitionId","id","success","error","message","errorMessage","div","className","isPending","isError","undefined","status","icon","title","description","query","subject","header","variant","size","connectionId","source","externalRepositoryId","WorkflowSyncAlert","WorkflowSyncWarnings","WorkflowDefinitionsList","runningDefinitionId","variables","hasNextPage","isFetchingNextPage","isFetchNextPageError","onRetry","refetch","onLoadMore","fetchNextPage","onOpenDefinition","onRun","DefinitionSheet","onOpenChange","open","role","aria-label","length","retryLabel","WorkflowEmptyState","map","runErrorMessage","isRunning","name","sourceIcon","aria-hidden","button","type","onClick","bold","configPath","value","updatedAt","isLoading","lastErrorCode","lastErrorMessage","warnings","seenKeys","Map","warningItems","warning","baseKey","code","path","occurrence","get","set","key","ul","li","normalizedJson","JSON","stringify","workflow_document","workflowDocument","workflow_model","workflowModel","Boolean","Metadata","label","ref","sha","pre","as","fallback","Error"],"mappings":";AAAA,SAAQA,QAAQ,QAAO,sBAAsB;AAC7C,SAGEC,WAAW,EACXC,2BAA2B,EAC3BC,eAAe,QACV,2BAA2B;AAClC,SAAQC,cAAc,QAAO,qBAAqB;AAClD,SAAQC,MAAM,QAAO,2BAA2B;AAChD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,IAAI,QAAsB,yBAAyB;AAC3D,SAAQC,cAAc,QAAO,qCAAqC;AAClE,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,YAAY,EAAEC,oBAAoB,QAAO,kCAAkC;AACnF,SACEC,KAAK,EACLC,SAAS,EACTC,YAAY,EACZC,gBAAgB,EAChBC,WAAW,EACXC,UAAU,QACL,0BAA0B;AACjC,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SACEC,KAAK,EACLC,SAAS,EACTC,SAAS,EACTC,SAAS,EACTC,WAAW,EACXC,QAAQ,QACH,0BAA0B;AACjC,SAAQC,KAAK,QAAO,0BAA0B;AAC9C,SAAQC,IAAI,EAAEC,MAAM,EAAEC,IAAI,QAAO,+BAA+B;AAChE,SAAQC,QAAQ,QAAO,QAAQ;AAC/B,SAAQC,6BAA6B,QAAO,8BAA8B;AAE1E,OAAO,SAASC,qBAAqB,EAACC,SAAS,EAAsB;IACnE,qBACE,KAACrB;kBACC,cAAA,KAACsB;YAA0BD,WAAWA;;;AAG5C;AAEA,SAASC,0BAA0B,EAACD,SAAS,EAAsB;IACjE,MAAME,eAAehC,gBAAgB8B;IACrC,MAAMG,mBAAmBlC,4BAA4B+B;IACrD,MAAMI,aAAaN;IACnB,MAAM,CAACO,oBAAoBC,sBAAsB,GAAGT,SAA4B;IAChF,MAAM,CAACU,UAAUC,YAAY,GAAGX,SAAyD;IACzF,MAAMY,cAAcN,iBAAiBO,IAAI,EAAEC,MAAMC,QAAQ,CAACC,OAASA,KAAKJ,WAAW,KAAK,EAAE;IAC1F,MAAMK,OAAOX,iBAAiBO,IAAI,EAAEC,KAAK,CAAC,EAAE,EAAEG;IAE9C,eAAeC,UAAUC,UAAsB;QAC7CR,YAAY;QACZ,IAAI,CAACQ,WAAWC,aAAa,EAAE;QAC/B,IAAI;YACF,MAAMb,WAAWc,WAAW,CAAC;gBAAClB;gBAAWmB,cAAcH,WAAWI,EAAE;YAAA;YACpE3B,MAAM4B,OAAO,CAAC;QAChB,EAAE,OAAOC,OAAO;YACd,MAAMC,UAAUC,aAAaF,OAAO;YACpCd,YAAY;gBAACW,cAAcH,WAAWI,EAAE;gBAAEG;YAAO;YACjD9B,MAAM6B,KAAK,CAACC;QACd;IACF;IAEA,qBACE,MAACE;QAAIC,WAAU;;YACZxB,aAAayB,SAAS,iBACrB,MAACF;gBAAIC,WAAU;;kCACb,KAACxC;wBAASwC,WAAU;;kCACpB,KAACxC;wBAASwC,WAAU;;;iBAEpB;YAEHxB,aAAa0B,OAAO,IAAI1B,aAAaQ,IAAI,KAAKmB,YAC7C3B,aAAaoB,KAAK,YAAYvD,YAAYmC,aAAaoB,KAAK,CAACQ,MAAM,KAAK,oBACtE,KAACxD;gBACCyD,MAAK;gBACLC,OAAM;gBACNC,aAAY;+BAGd,KAAC9D;gBAAe+D,OAAOhC;gBAAciC,SAAQ;iBAE7C;YAEHjC,aAAaQ,IAAI,iBAChB;;kCACE,MAAC0B;wBAAOV,WAAU;;0CAChB,KAAC/B;gCAAO0C,SAAQ;0CAAK;;0CACrB,KAACzC;gCAAK0C,MAAK;gCAAKZ,WAAU;0CAAgC;;;;kCAK5D,KAAC1D;wBACCuE,cAAcrC,aAAaQ,IAAI,CAAC8B,MAAM,CAACD,YAAY;wBACnDE,sBAAsBvC,aAAaQ,IAAI,CAAC8B,MAAM,CAACC,oBAAoB;wBACnE3B,MAAMA;wBACNa,WAAWxB,iBAAiBwB,SAAS;;kCAGvC,KAACe;wBAAkB5B,MAAMA;;kCACzB,KAAC6B;wBAAqB7B,MAAMA;;kCAE5B,KAAC8B;wBACCnC,aAAaA;wBACbkB,WAAWxB,iBAAiBwB,SAAS;wBACrCC,SAASzB,iBAAiByB,OAAO;wBACjCd,MAAMA,QAAQ;wBACdP,UAAUA;wBACVsC,qBACEzC,WAAWuB,SAAS,IAAIvB,WAAW0C,SAAS,GACxC1C,WAAW0C,SAAS,CAAC3B,YAAY,GACjC;wBAEN4B,aAAa5C,iBAAiB4C,WAAW;wBACzCC,oBAAoB7C,iBAAiB6C,kBAAkB;wBACvDC,sBAAsB9C,iBAAiB8C,oBAAoB;wBAC3DC,SAAS,IAAM/C,iBAAiBgD,OAAO;wBACvCC,YAAY,IAAMjD,iBAAiBkD,aAAa;wBAChDC,kBAAkBhD;wBAClBiD,OAAO,CAACvC;4BACN,KAAKD,UAAUC;wBACjB;;;iBAGF;0BAEJ,KAACwC;gBACCxC,YAAYX;gBACZoD,cAAc,CAACC;oBACb,IAAI,CAACA,MAAMpD,sBAAsB;gBACnC;;;;AAIR;AAEA,SAASsC,wBAAwB,EAC/BnC,WAAW,EACXkB,SAAS,EACTC,OAAO,EACPd,IAAI,EACJP,QAAQ,EACRsC,mBAAmB,EACnBE,WAAW,EACXC,kBAAkB,EAClBC,oBAAoB,EACpBC,OAAO,EACPE,UAAU,EACVE,gBAAgB,EAChBC,KAAK,EAeN;IACC,IAAI5B,WAAW;QACb,qBACE,MAAClD;YAAMkF,MAAK;YAASC,cAAW;YAAoBlC,WAAU;;8BAC5D,KAACxC;oBAASwC,WAAU;;8BACpB,KAACxC;oBAASwC,WAAU;;8BACpB,KAACxC;oBAASwC,WAAU;;;;IAG1B;IAEA,IAAIE,WAAWnB,YAAYoD,MAAM,KAAK,GAAG;QACvC,qBACE,KAACpF;sBACC,cAAA,KAACD;gBACCwD,OAAM;gBACNC,aAAY;gBACZiB,SAASA;gBACTY,YAAW;gBACXzB,SAAQ;;;IAIhB;IAEA,IAAI5B,YAAYoD,MAAM,KAAK,GAAG;QAC5B,qBACE,KAACpF;sBACC,cAAA,KAACsF;gBAAmBjD,MAAMA;;;IAGhC;IAEA,qBACE;;0BACE,MAACrC;;kCACC,KAACgD;wBAAIC,WAAU;kCACb,cAAA,MAACvC;;8CACC,KAACI;8CACC,cAAA,MAACC;;0DACC,KAACF;gDAAUoC,WAAU;;0DACrB,KAACpC;0DAAU;;0DACX,KAACA;gDAAUoC,WAAU;0DAAQ;;0DAC7B,KAACpC;gDAAUoC,WAAU;;;;;8CAGzB,KAACtC;8CACEqB,YAAYuD,GAAG,CAAC,CAAChD;wCAChB,MAAMiD,kBACJ1D,UAAUY,iBAAiBH,WAAWI,EAAE,GAAGb,SAASgB,OAAO,GAAG;wCAChE,MAAM2C,YAAYrB,wBAAwB7B,WAAWI,EAAE;wCAEvD,OACE,0DAA0D;wCAC1D,yDAAyD;wCACzD,0DAA0D;wCAC1D,2DAA2D;wCAC3D,yDAAyD;wCACzD,2DAA2D;wCAC3D,mCAAmC;sDACnC,MAAC5B;4CAA6BkC,WAAU;;8DACtC,KAACrC;8DACC,cAAA,KAACd;wDACC4F,MAAMC,WAAWpD,WAAWwB,MAAM;wDAClCd,WAAU;wDACV2C,eAAY;;;8DAGhB,KAAChF;oDAAUqC,WAAU;8DACnB,cAAA,MAACD;wDAAIC,WAAU;;0EACb,MAAC4C;gEACCC,MAAK;gEACLC,SAAS,IAAMlB,iBAAiBtC;gEAChCU,WAAU;;kFAEV,KAAC9B;wEAAK0C,MAAK;wEAAKmC,IAAI;wEAAC/C,WAAU;kFAC5BV,WAAWmD,IAAI;;kFAElB,KAACzE;wEAAKgC,WAAU;kFACbV,WAAW0D,UAAU,IAAI;;;;4DAG7BT,gCACC,KAACrE;gEAAK0C,MAAK;gEAAKZ,WAAU;0EACvBuC;iEAED;;;;8DAGR,KAAC5E;oDAAUqC,WAAU;8DACnB,cAAA,KAAChD;wDAAaiG,OAAO3D,WAAW4D,SAAS;;;8DAE3C,KAACvF;8DACE2B,WAAWC,aAAa,iBACvB,KAACQ;wDAAIC,WAAU;kEACb,cAAA,KAACtD;4DAAOkE,MAAK;4DAAKuC,WAAWX;4DAAWM,SAAS,IAAMjB,MAAMvC;sEAAa;;yDAI1E;;;2CAvCOA,WAAWI,EAAE;oCA2ChC;;;;;kCAKN,KAACK;wBAAIC,WAAU;kCACZjB,YAAYuD,GAAG,CAAC,CAAChD;4BAChB,MAAMiD,kBACJ1D,UAAUY,iBAAiBH,WAAWI,EAAE,GAAGb,SAASgB,OAAO,GAAG;4BAChE,MAAM2C,YAAYrB,wBAAwB7B,WAAWI,EAAE;4BAEvD,qBACE,MAACK;gCAECC,WAAU;;kDAEV,MAAC4C;wCACCC,MAAK;wCACL7C,WAAU;wCACV8C,SAAS,IAAMlB,iBAAiBtC;;0DAEhC,KAACzC;gDACC4F,MAAMC,WAAWpD,WAAWwB,MAAM;gDAClCd,WAAU;gDACV2C,eAAY;;0DAEd,MAAC5C;gDAAIC,WAAU;;kEACb,KAAC9B;wDAAK0C,MAAK;wDAAKmC,IAAI;wDAAC/C,WAAU;kEAC5BV,WAAWmD,IAAI;;kEAElB,KAACzE;wDAAKgC,WAAU;kEACbV,WAAW0D,UAAU,IAAI;;;;;;kDAIhC,MAACjD;wCAAIC,WAAU;;0DACb,MAAC9B;gDAAK0C,MAAK;gDAAKZ,WAAU;;oDAAgC;kEAChD,KAAChD;wDAAaiG,OAAO3D,WAAW4D,SAAS;;;;4CAElD5D,WAAWC,aAAa,iBACvB,KAAC7C;gDAAOkE,MAAK;gDAAKuC,WAAWX;gDAAWM,SAAS,IAAMjB,MAAMvC;0DAAa;iDAGxE;;;oCAELiD,gCACC,KAACrE;wCAAK0C,MAAK;wCAAKZ,WAAU;kDACvBuC;yCAED;;+BApCCjD,WAAWI,EAAE;wBAuCxB;;;;YAIH6B,qCACC,KAAC5E;gBAAQsF,MAAK;gBAAQY,MAAK;0BACzB,cAAA,MAAC9C;oBAAIC,WAAU;;sCACb,KAAC9B;4BAAK0C,MAAK;sCAAK;;sCAChB,KAAClE;4BAAOkE,MAAK;4BAAKD,SAAQ;4BAAYmC,SAASpB;sCAAY;;;;iBAK7D;YAEHL,4BACC,KAACtB;gBAAIC,WAAU;0BACb,cAAA,KAACtD;oBAAOkE,MAAK;oBAAKD,SAAQ;oBAAYwC,WAAW7B;oBAAoBwB,SAASpB;8BAAY;;iBAI1F;;;AAGV;AAEA,SAASgB,WAAW5B,MAAwB;IAC1C,OAAOA,WAAW,QAAS,kBAAgC;AAC7D;AAEA,SAASuB,mBAAmB,EAACjD,IAAI,EAAuC;IACtE,MAAMS,UACJT,MAAMgB,WAAW,YAAYhB,KAAKgE,aAAa,KAAK,sBAChD,uDACAhE,MAAMgB,WAAW,WACdhB,KAAKiE,gBAAgB,IAAI,8CAC1BjE,MAAMgB,WAAW,YACf,+CACAhB,MAAMgB,WAAW,cACf,mCACA;IAEZ,qBAAO,KAACxD;QAAWyD,MAAK;QAAYC,OAAM;QAAeC,aAAaV;QAASc,SAAQ;;AACzF;AAEA,SAASK,kBAAkB,EAAC5B,IAAI,EAAmD;IACjF,IAAIA,MAAMgB,WAAW,UAAU,OAAO;IAEtC,qBACE,KAACzD;QAAQsF,MAAK;QAAQY,MAAK;kBACzB,cAAA,MAAC9C;YAAIC,WAAU;;8BACb,KAAC9B;oBAAK0C,MAAK;oBAAKmC,IAAI;8BAAC;;8BAGrB,KAAC7E;oBAAK0C,MAAK;8BACRxB,KAAKiE,gBAAgB,IAAI;;;;;AAKpC;AAEA,SAASpC,qBAAqB,EAAC7B,IAAI,EAAmD;IACpF,IAAIA,MAAMgB,WAAW,eAAehB,KAAKkE,QAAQ,CAACnB,MAAM,KAAK,GAAG,OAAO;IAEvE,MAAMoB,WAAW,IAAIC;IACrB,MAAMC,eAAerE,KAAKkE,QAAQ,CAAChB,GAAG,CAAC,CAACoB;QACtC,MAAMC,UAAU,GAAGD,QAAQE,IAAI,CAAC,CAAC,EAAEF,QAAQG,IAAI,IAAI,WAAW,CAAC,EAAEH,QAAQ7D,OAAO,EAAE;QAClF,MAAMiE,aAAaP,SAASQ,GAAG,CAACJ,YAAY;QAC5CJ,SAASS,GAAG,CAACL,SAASG,aAAa;QACnC,OAAO;YAACG,KAAK,GAAGN,QAAQ,CAAC,EAAEG,YAAY;YAAEJ;QAAO;IAClD;IAEA,qBACE,KAAC/G;QAAQsF,MAAK;QAASY,MAAK;kBAC1B,cAAA,MAAC9C;YAAIC,WAAU;;8BACb,KAAC9B;oBAAK0C,MAAK;oBAAKmC,IAAI;8BAAC;;8BAGrB,KAACmB;oBAAGlE,WAAU;8BACXyD,aAAanB,GAAG,CAAC,CAAC,EAAC2B,GAAG,EAAEP,OAAO,EAAC,iBAC/B,MAACS;;8CACC,KAACjG;oCAAK0C,MAAK;8CAAM8C,QAAQ7D,OAAO;;gCAC/B6D,QAAQG,IAAI,iBACX,KAAC7F;oCAAKgC,WAAU;8CAAiC0D,QAAQG,IAAI;qCAC3D;;2BAJGI;;;;;AAWrB;AAEA,SAASnC,gBAAgB,EACvBxC,UAAU,EACVyC,YAAY,EAIb;IACC,MAAMqC,iBAAiB9E,aACnB+E,KAAKC,SAAS,CACZ;QACEC,mBAAmBjF,WAAWkF,gBAAgB;QAC9CC,gBAAgBnF,WAAWoF,aAAa;IAC1C,GACA,MACA,KAEF;IAEJ,qBACE,KAACxH;QAAM8E,MAAM2C,QAAQrF;QAAayC,cAAcA;kBAC9C,cAAA,KAAC3E;YAAa4C,WAAU;sBACrBV,2BACC;;kCACE,MAAChC;;0CACC,KAACC;0CAAY+B,WAAWmD,IAAI;;0CAC5B,KAACpF;0CACEiC,WAAW0D,UAAU,IAAI;;;;kCAG9B,MAAC7F;wBAAU6C,WAAU;;0CACnB,MAACD;gCAAIC,WAAU;;kDACb,KAAC4E;wCAASC,OAAM;wCAAgB5B,OAAO3D,WAAWI,EAAE;;kDACpD,KAACkF;wCAASC,OAAM;wCAAS5B,OAAO3D,WAAWwB,MAAM;;kDACjD,KAAC8D;wCAASC,OAAM;wCAAM5B,OAAO3D,WAAWwF,GAAG,IAAI;;kDAC/C,KAACF;wCAASC,OAAM;wCAAM5B,OAAO3D,WAAWyF,GAAG,IAAI;;;;0CAEjD,MAAChF;gCAAIC,WAAU;;kDACb,KAAC9B;wCAAK0C,MAAK;wCAAKmC,IAAI;kDAAC;;kDAGrB,KAACiC;wCAAIhF,WAAU;kDACb,cAAA,KAAChC;4CAAKiH,IAAG;4CAAOjF,WAAU;sDACvBoE;;;;;;;;iBAMT;;;AAIZ;AAEA,SAASQ,SAAS,EAACC,KAAK,EAAE5B,KAAK,EAAiC;IAC9D,qBACE,MAAClD;QAAIC,WAAU;;0BACb,KAAC9B;gBAAK0C,MAAK;gBAAKZ,WAAU;0BACvB6E;;0BAEH,KAAC3G;gBAAK0C,MAAK;gBAAKZ,WAAU;0BACvBiD;;;;AAIT;AAEA,SAASnD,aAAaF,KAAc,EAAEsF,QAAgB;IACpD,IAAItF,iBAAiBvD,YAAYuD,MAAMC,OAAO,EAAE,OAAOD,MAAMC,OAAO;IACpE,IAAID,iBAAiBuF,SAASvF,MAAMC,OAAO,EAAE,OAAOD,MAAMC,OAAO;IACjE,OAAOqF;AACT"}
1
+ {"version":3,"sources":["../../src/pages/project-workflows-page.tsx"],"sourcesContent":["import {ApiError} from '@shipfox/client-api';\nimport {\n type Definition,\n type DefinitionSyncSummary,\n SourceStrip,\n useDefinitionsInfiniteQuery,\n useProjectQuery,\n} from '@shipfox/client-projects';\nimport {QueryLoadError} from '@shipfox/client-ui';\nimport {Button} from '@shipfox/react-ui/button';\nimport {Callout} from '@shipfox/react-ui/callout';\nimport {EmptyState} from '@shipfox/react-ui/empty-state';\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {LoadErrorState} from '@shipfox/react-ui/load-error-state';\nimport {Panel} from '@shipfox/react-ui/panel';\nimport {RelativeTime, RelativeTimeProvider} from '@shipfox/react-ui/relative-time';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '@shipfox/react-ui/sheet';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '@shipfox/react-ui/table';\nimport {toast} from '@shipfox/react-ui/toast';\nimport {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {useState} from 'react';\nimport {useFireManualWorkflowMutation} from '#hooks/api/workflow-runs.js';\n\nexport function ProjectWorkflowsPage({projectId}: {projectId: string}) {\n return (\n <RelativeTimeProvider>\n <ProjectWorkflowsPageInner projectId={projectId} />\n </RelativeTimeProvider>\n );\n}\n\nfunction ProjectWorkflowsPageInner({projectId}: {projectId: string}) {\n const projectQuery = useProjectQuery(projectId);\n const definitionsQuery = useDefinitionsInfiniteQuery(projectId);\n const fireManual = useFireManualWorkflowMutation();\n const [selectedDefinition, setSelectedDefinition] = useState<Definition | null>(null);\n const [runError, setRunError] = useState<{definitionId: string; message: string} | null>(null);\n const definitions = definitionsQuery.data?.pages.flatMap((page) => page.definitions) ?? [];\n const sync = definitionsQuery.data?.pages[0]?.sync;\n\n async function handleRun(definition: Definition) {\n setRunError(null);\n if (!definition.manualTrigger) return;\n try {\n await fireManual.mutateAsync({projectId, definitionId: definition.id});\n toast.success('Run queued');\n } catch (error) {\n const message = errorMessage(error, 'Could not queue run.');\n setRunError({definitionId: definition.id, message});\n toast.error(message);\n }\n }\n\n return (\n <div className=\"flex w-full flex-col gap-section\">\n <Header variant=\"h1\" className=\"sr-only\">\n Workflows\n </Header>\n\n {projectQuery.isPending ? (\n <div className=\"flex flex-col gap-cluster\">\n <Skeleton className=\"h-28 w-1/3\" />\n <Skeleton className=\"h-18 w-1/2\" />\n </div>\n ) : null}\n\n {projectQuery.isError && projectQuery.data === undefined ? (\n projectQuery.error instanceof ApiError && projectQuery.error.status === 404 ? (\n <EmptyState\n icon=\"errorWarningLine\"\n title=\"Project not found\"\n description=\"This project doesn't exist, or you don't have access to it.\"\n />\n ) : (\n <QueryLoadError query={projectQuery} subject=\"project\" />\n )\n ) : null}\n\n {projectQuery.data ? (\n <>\n <SourceStrip\n connectionId={projectQuery.data.source.connectionId}\n externalRepositoryId={projectQuery.data.source.externalRepositoryId}\n sync={sync}\n isPending={definitionsQuery.isPending}\n />\n\n <WorkflowSyncAlert sync={sync} />\n <WorkflowSyncWarnings sync={sync} />\n\n <WorkflowDefinitionsList\n definitions={definitions}\n isPending={definitionsQuery.isPending}\n isError={definitionsQuery.isError}\n sync={sync ?? null}\n runError={runError}\n runningDefinitionId={\n fireManual.isPending && fireManual.variables\n ? fireManual.variables.definitionId\n : null\n }\n hasNextPage={definitionsQuery.hasNextPage}\n isFetchingNextPage={definitionsQuery.isFetchingNextPage}\n isFetchNextPageError={definitionsQuery.isFetchNextPageError}\n onRetry={() => definitionsQuery.refetch()}\n onLoadMore={() => definitionsQuery.fetchNextPage()}\n onOpenDefinition={setSelectedDefinition}\n onRun={(definition) => {\n void handleRun(definition);\n }}\n />\n </>\n ) : null}\n\n <DefinitionSheet\n definition={selectedDefinition}\n onOpenChange={(open) => {\n if (!open) setSelectedDefinition(null);\n }}\n />\n </div>\n );\n}\n\nfunction WorkflowDefinitionsList({\n definitions,\n isPending,\n isError,\n sync,\n runError,\n runningDefinitionId,\n hasNextPage,\n isFetchingNextPage,\n isFetchNextPageError,\n onRetry,\n onLoadMore,\n onOpenDefinition,\n onRun,\n}: {\n definitions: Definition[];\n isPending: boolean;\n isError: boolean;\n sync: DefinitionSyncSummary | null;\n runError: {definitionId: string; message: string} | null;\n runningDefinitionId: string | null;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n isFetchNextPageError: boolean;\n onRetry: () => void;\n onLoadMore: () => void;\n onOpenDefinition: (definition: Definition) => void;\n onRun: (definition: Definition) => void;\n}) {\n if (isPending) {\n return (\n <Panel role=\"status\" aria-label=\"Loading workflows\" className=\"divide-y\">\n <Skeleton className=\"h-44 w-full rounded-none\" />\n <Skeleton className=\"h-44 w-full rounded-none\" />\n <Skeleton className=\"h-44 w-full rounded-none\" />\n </Panel>\n );\n }\n\n if (isError && definitions.length === 0) {\n return (\n <Panel role=\"region\" aria-label=\"Workflow definitions\">\n <LoadErrorState\n title=\"Couldn't load workflows\"\n description=\"Definitions could not be loaded. Source metadata remains visible.\"\n onRetry={onRetry}\n retryLabel=\"Retry loading workflows\"\n variant=\"panel\"\n />\n </Panel>\n );\n }\n\n if (definitions.length === 0) {\n return (\n <Panel role=\"region\" aria-label=\"Workflow definitions\">\n <WorkflowEmptyState sync={sync} />\n </Panel>\n );\n }\n\n return (\n <>\n <Panel role=\"region\" aria-label=\"Workflow definitions\">\n <div className=\"hidden md:block\">\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead className=\"w-40\"></TableHead>\n <TableHead>Workflow</TableHead>\n <TableHead className=\"w-180\">Updated</TableHead>\n <TableHead className=\"w-80 text-right\"></TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {definitions.map((definition) => {\n const runErrorMessage =\n runError?.definitionId === definition.id ? runError.message : null;\n const isRunning = runningDefinitionId === definition.id;\n\n return (\n // The workflow-name cell holds a `<button>` so the row is\n // keyboard-reachable (Tab focuses, Enter/Space activates\n // via native button semantics). The TableRow itself is no\n // longer clickable: a row-level onClick would be invisible\n // to keyboard users and require custom keydown handling.\n // The `group` class on the row still drives the Run button\n // reveal on hover or focus-within.\n <TableRow key={definition.id} className=\"group\">\n <TableCell>\n <Icon\n name={sourceIcon(definition.source)}\n className=\"size-16 text-foreground-neutral-muted\"\n aria-hidden=\"true\"\n />\n </TableCell>\n <TableCell className=\"max-w-260\">\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <button\n type=\"button\"\n onClick={() => onOpenDefinition(definition)}\n className=\"flex min-w-0 flex-col gap-tight rounded-4 text-left outline-none focus-visible:shadow-border-interactive-with-active\"\n >\n <Text size=\"sm\" bold className=\"truncate\">\n {definition.name}\n </Text>\n <Code className=\"truncate text-foreground-neutral-muted\">\n {definition.configPath ?? 'Manual definition'}\n </Code>\n </button>\n {runErrorMessage ? (\n <Text size=\"xs\" className=\"text-tag-error-text\">\n {runErrorMessage}\n </Text>\n ) : null}\n </div>\n </TableCell>\n <TableCell className=\"text-foreground-neutral-muted\">\n <RelativeTime value={definition.updatedAt} />\n </TableCell>\n <TableCell>\n {definition.manualTrigger ? (\n <div className=\"flex justify-end opacity-0 transition-opacity group-hover:opacity-100 group-focus-within:opacity-100\">\n <Button size=\"xs\" isLoading={isRunning} onClick={() => onRun(definition)}>\n Run\n </Button>\n </div>\n ) : null}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n </div>\n\n <div className=\"flex flex-col md:hidden\">\n {definitions.map((definition) => {\n const runErrorMessage =\n runError?.definitionId === definition.id ? runError.message : null;\n const isRunning = runningDefinitionId === definition.id;\n\n return (\n <div\n key={definition.id}\n className=\"flex flex-col gap-inline border-b border-border-neutral-base p-panel-compact last:border-b-0\"\n >\n <button\n type=\"button\"\n className=\"flex min-w-0 items-start gap-inline text-left\"\n onClick={() => onOpenDefinition(definition)}\n >\n <Icon\n name={sourceIcon(definition.source)}\n className=\"size-16 shrink-0 text-foreground-neutral-muted\"\n aria-hidden=\"true\"\n />\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"sm\" bold className=\"break-words\">\n {definition.name}\n </Text>\n <Code className=\"break-words text-foreground-neutral-muted\">\n {definition.configPath ?? 'Manual definition'}\n </Code>\n </div>\n </button>\n <div className=\"flex items-center justify-between gap-inline\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n Updated <RelativeTime value={definition.updatedAt} />\n </Text>\n {definition.manualTrigger ? (\n <Button size=\"sm\" isLoading={isRunning} onClick={() => onRun(definition)}>\n Run\n </Button>\n ) : null}\n </div>\n {runErrorMessage ? (\n <Text size=\"xs\" className=\"text-tag-error-text\">\n {runErrorMessage}\n </Text>\n ) : null}\n </div>\n );\n })}\n </div>\n </Panel>\n\n {isFetchNextPageError ? (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex items-center justify-between gap-cluster\">\n <Text size=\"sm\">Could not load more workflows.</Text>\n <Button size=\"sm\" variant=\"secondary\" onClick={onLoadMore}>\n Retry\n </Button>\n </div>\n </Callout>\n ) : null}\n\n {hasNextPage ? (\n <div className=\"flex justify-center\">\n <Button size=\"sm\" variant=\"secondary\" isLoading={isFetchingNextPage} onClick={onLoadMore}>\n Load more\n </Button>\n </div>\n ) : null}\n </>\n );\n}\n\nfunction sourceIcon(source: 'manual' | 'vcs'): IconName {\n return source === 'vcs' ? ('gitBranchLine' as IconName) : ('terminalLine' as IconName);\n}\n\nfunction WorkflowEmptyState({sync}: {sync: DefinitionSyncSummary | null}) {\n const message =\n sync?.status === 'failed' && sync.lastErrorCode === 'no-workflow-files'\n ? 'No workflow files found under .shipfox/workflows/.'\n : sync?.status === 'failed'\n ? (sync.lastErrorMessage ?? 'Workflow definitions could not be synced.')\n : sync?.status === 'syncing'\n ? 'Workflow definitions are being discovered.'\n : sync?.status === 'succeeded'\n ? 'No workflow definitions found.'\n : 'Workflow sync has not reported yet.';\n\n return <EmptyState icon=\"flowChart\" title=\"No workflows\" description={message} variant=\"panel\" />;\n}\n\nfunction WorkflowSyncAlert({sync}: {sync: DefinitionSyncSummary | null | undefined}) {\n if (sync?.status !== 'failed') return null;\n\n return (\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex flex-col gap-tight\">\n <Text size=\"sm\" bold>\n Workflow sync failed\n </Text>\n <Text size=\"sm\">\n {sync.lastErrorMessage ?? 'The latest workflow sync failed before definitions updated.'}\n </Text>\n </div>\n </Callout>\n );\n}\n\nfunction WorkflowSyncWarnings({sync}: {sync: DefinitionSyncSummary | null | undefined}) {\n if (sync?.status !== 'succeeded' || sync.warnings.length === 0) return null;\n\n const seenKeys = new Map<string, number>();\n const warningItems = sync.warnings.map((warning) => {\n const baseKey = `${warning.code}-${warning.path ?? 'workflow'}-${warning.message}`;\n const occurrence = seenKeys.get(baseKey) ?? 0;\n seenKeys.set(baseKey, occurrence + 1);\n return {key: `${baseKey}-${occurrence}`, warning};\n });\n\n return (\n <Callout role=\"status\" type=\"warning\">\n <div className=\"flex flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Workflow definition warnings\n </Text>\n <ul className=\"flex flex-col gap-tight\">\n {warningItems.map(({key, warning}) => (\n <li key={key}>\n <Text size=\"sm\">{warning.message}</Text>\n {warning.path ? (\n <Code className=\"text-foreground-neutral-muted\">{warning.path}</Code>\n ) : null}\n </li>\n ))}\n </ul>\n </div>\n </Callout>\n );\n}\n\nfunction DefinitionSheet({\n definition,\n onOpenChange,\n}: {\n definition: Definition | null;\n onOpenChange: (open: boolean) => void;\n}) {\n const normalizedJson = definition\n ? JSON.stringify(\n {\n workflow_document: definition.workflowDocument,\n workflow_model: definition.workflowModel,\n },\n null,\n 2,\n )\n : '';\n\n return (\n <Sheet open={Boolean(definition)} onOpenChange={onOpenChange}>\n <SheetContent className=\"w-full sm:max-w-[560px]\">\n {definition ? (\n <>\n <SheetHeader>\n <SheetTitle>{definition.name}</SheetTitle>\n <SheetDescription>\n {definition.configPath ?? 'Manual workflow definition'}\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"gap-group\">\n <div className=\"grid w-full gap-inline\">\n <Metadata label=\"Definition id\" value={definition.id} />\n <Metadata label=\"Source\" value={definition.source} />\n <Metadata label=\"Ref\" value={definition.ref ?? 'Not set'} />\n <Metadata label=\"SHA\" value={definition.sha ?? 'Not set'} />\n </div>\n <div className=\"flex w-full flex-col gap-inline\">\n <Text size=\"sm\" bold>\n Normalized definition\n </Text>\n <pre className=\"max-h-[52vh] w-full overflow-auto rounded-8 border border-border-neutral-base bg-background-neutral-subtle p-panel-compact scrollbar\">\n <Code as=\"code\" className=\"whitespace-pre text-foreground-neutral-base\">\n {normalizedJson}\n </Code>\n </pre>\n </div>\n </SheetBody>\n </>\n ) : null}\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction Metadata({label, value}: {label: string; value: string}) {\n return (\n <div className=\"min-w-0 py-row first:pt-0 last:pb-0\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n {label}\n </Text>\n <Text size=\"sm\" className=\"break-words\">\n {value}\n </Text>\n </div>\n );\n}\n\nfunction errorMessage(error: unknown, fallback: string) {\n if (error instanceof ApiError && error.message) return error.message;\n if (error instanceof Error && error.message) return error.message;\n return fallback;\n}\n"],"names":["ApiError","SourceStrip","useDefinitionsInfiniteQuery","useProjectQuery","QueryLoadError","Button","Callout","EmptyState","Icon","LoadErrorState","Panel","RelativeTime","RelativeTimeProvider","Sheet","SheetBody","SheetContent","SheetDescription","SheetHeader","SheetTitle","Skeleton","Table","TableBody","TableCell","TableHead","TableHeader","TableRow","toast","Code","Header","Text","useState","useFireManualWorkflowMutation","ProjectWorkflowsPage","projectId","ProjectWorkflowsPageInner","projectQuery","definitionsQuery","fireManual","selectedDefinition","setSelectedDefinition","runError","setRunError","definitions","data","pages","flatMap","page","sync","handleRun","definition","manualTrigger","mutateAsync","definitionId","id","success","error","message","errorMessage","div","className","variant","isPending","isError","undefined","status","icon","title","description","query","subject","connectionId","source","externalRepositoryId","WorkflowSyncAlert","WorkflowSyncWarnings","WorkflowDefinitionsList","runningDefinitionId","variables","hasNextPage","isFetchingNextPage","isFetchNextPageError","onRetry","refetch","onLoadMore","fetchNextPage","onOpenDefinition","onRun","DefinitionSheet","onOpenChange","open","role","aria-label","length","retryLabel","WorkflowEmptyState","map","runErrorMessage","isRunning","name","sourceIcon","aria-hidden","button","type","onClick","size","bold","configPath","value","updatedAt","isLoading","lastErrorCode","lastErrorMessage","warnings","seenKeys","Map","warningItems","warning","baseKey","code","path","occurrence","get","set","key","ul","li","normalizedJson","JSON","stringify","workflow_document","workflowDocument","workflow_model","workflowModel","Boolean","Metadata","label","ref","sha","pre","as","fallback","Error"],"mappings":"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"}