@shipfox/client-workflows 19.0.0 → 21.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +43 -0
- package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
- package/dist/components/job-detail/job-detail-view.js +231 -42
- package/dist/components/job-detail/job-detail-view.js.map +1 -1
- package/dist/components/job-detail/step-attempt-log-panel.d.ts +7 -1
- package/dist/components/job-detail/step-attempt-log-panel.d.ts.map +1 -1
- package/dist/components/job-detail/step-attempt-log-panel.js +37 -10
- package/dist/components/job-detail/step-attempt-log-panel.js.map +1 -1
- package/dist/components/step-list/step-list-model.d.ts +1 -0
- package/dist/components/step-list/step-list-model.d.ts.map +1 -1
- package/dist/components/step-list/step-list-model.js +1 -1
- package/dist/components/step-list/step-list-model.js.map +1 -1
- package/dist/components/step-list/step-list.d.ts +2 -1
- package/dist/components/step-list/step-list.d.ts.map +1 -1
- package/dist/components/step-list/step-list.js +24 -7
- package/dist/components/step-list/step-list.js.map +1 -1
- package/dist/components/workflow-run-duration-label.d.ts +8 -7
- package/dist/components/workflow-run-duration-label.d.ts.map +1 -1
- package/dist/components/workflow-run-duration-label.js +15 -31
- package/dist/components/workflow-run-duration-label.js.map +1 -1
- package/dist/components/workflow-run-list/job-status-strip.d.ts +9 -1
- package/dist/components/workflow-run-list/job-status-strip.d.ts.map +1 -1
- package/dist/components/workflow-run-list/job-status-strip.js +22 -11
- package/dist/components/workflow-run-list/job-status-strip.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-filters.js +1 -1
- package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-states.js +2 -2
- package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-list-view.js +34 -22
- package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.d.ts +3 -3
- package/dist/components/workflow-run-list/workflow-run-row.d.ts.map +1 -1
- package/dist/components/workflow-run-list/workflow-run-row.js +22 -16
- package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
- package/dist/components/workflow-run-summary/workflow-run-summary.js +8 -35
- package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.js +1 -1
- package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.js +1 -1
- package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
- package/dist/components/workflow-run-view/workflow-run-view.js +43 -36
- package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
- package/dist/components/workflow-source-panel/workflow-source-content.js +1 -1
- package/dist/components/workflow-source-panel/workflow-source-content.js.map +1 -1
- package/dist/components/workflow-status/status-visuals.d.ts.map +1 -1
- package/dist/components/workflow-status/status-visuals.js +0 -9
- package/dist/components/workflow-status/status-visuals.js.map +1 -1
- package/dist/components/workflow-status/workflow-status-icon.d.ts.map +1 -1
- package/dist/components/workflow-status/workflow-status-icon.js +0 -11
- package/dist/components/workflow-status/workflow-status-icon.js.map +1 -1
- package/dist/core/entities/workflow-run.d.ts +10 -55
- package/dist/core/entities/workflow-run.d.ts.map +1 -1
- package/dist/core/entities/workflow-run.js +1 -94
- package/dist/core/entities/workflow-run.js.map +1 -1
- package/dist/core/workflow-run.d.ts +2 -2
- package/dist/core/workflow-run.d.ts.map +1 -1
- package/dist/core/workflow-run.js +1 -1
- package/dist/core/workflow-run.js.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
- package/dist/hooks/api/workflow-run-mapper.js +3 -1
- package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
- package/dist/hooks/api/workflow-runs.js +1 -0
- package/dist/hooks/api/workflow-runs.js.map +1 -1
- package/dist/pages/project-workflows-page.d.ts.map +1 -1
- package/dist/pages/project-workflows-page.js +3 -2
- package/dist/pages/project-workflows-page.js.map +1 -1
- package/dist/pages/workflow-job-detail-page.d.ts.map +1 -1
- package/dist/pages/workflow-job-detail-page.js +3 -2
- package/dist/pages/workflow-job-detail-page.js.map +1 -1
- package/dist/pages/workflow-run-detail-page.js +2 -1
- package/dist/pages/workflow-run-detail-page.js.map +1 -1
- package/dist/pages/workflow-run-list-page.d.ts.map +1 -1
- package/dist/pages/workflow-run-list-page.js +9 -11
- package/dist/pages/workflow-run-list-page.js.map +1 -1
- package/dist/routes/job-detail.d.ts +1 -1
- package/dist/routes/job-detail.js +1 -1
- package/dist/routes/job-detail.js.map +1 -1
- package/dist/routes/run-detail.d.ts +1 -1
- package/dist/routes/run-detail.js +1 -1
- package/dist/routes/run-detail.js.map +1 -1
- package/dist/routes/runs.d.ts +1 -1
- package/dist/routes/runs.js +1 -1
- package/dist/routes/runs.js.map +1 -1
- package/dist/routes/workflows.d.ts +3 -0
- package/dist/routes/workflows.js +3 -0
- package/dist/routes/workflows.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/components/job-detail/job-detail-view.tsx +263 -47
- package/src/components/job-detail/step-attempt-log-panel.test.tsx +30 -12
- package/src/components/job-detail/step-attempt-log-panel.tsx +68 -10
- package/src/components/job-graph/job-graph.stories.tsx +1 -1
- package/src/components/job-graph/job-node.stories.tsx +1 -1
- package/src/components/step-list/step-list-model.ts +1 -1
- package/src/components/step-list/step-list.test.tsx +29 -1
- package/src/components/step-list/step-list.tsx +28 -9
- package/src/components/workflow-run-duration-label.tsx +21 -44
- package/src/components/workflow-run-list/job-status-strip.tsx +25 -12
- package/src/components/workflow-run-list/workflow-run-filters.tsx +1 -1
- package/src/components/workflow-run-list/workflow-run-list-states.tsx +2 -2
- package/src/components/workflow-run-list/workflow-run-list-view.test.tsx +101 -4
- package/src/components/workflow-run-list/workflow-run-list-view.tsx +28 -22
- package/src/components/workflow-run-list/workflow-run-list.stories.tsx +9 -20
- package/src/components/workflow-run-list/workflow-run-row.tsx +24 -19
- package/src/components/workflow-run-summary/workflow-run-summary.stories.tsx +2 -40
- package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +75 -22
- package/src/components/workflow-run-summary/workflow-run-summary.tsx +7 -31
- package/src/components/workflow-run-view/run-workspace-nav.tsx +1 -1
- package/src/components/workflow-run-view/workflow-run-states.tsx +1 -4
- package/src/components/workflow-run-view/workflow-run-view.stories.tsx +140 -0
- package/src/components/workflow-run-view/workflow-run-view.test.tsx +38 -7
- package/src/components/workflow-run-view/workflow-run-view.tsx +45 -37
- package/src/components/workflow-source-panel/workflow-source-content.tsx +2 -2
- package/src/components/workflow-status/status-visuals.ts +0 -4
- package/src/components/workflow-status/workflow-status-icon.stories.tsx +0 -1
- package/src/components/workflow-status/workflow-status-icon.tsx +0 -18
- package/src/core/entities/workflow-run.ts +9 -136
- package/src/core/workflow-run.test.ts +2 -0
- package/src/core/workflow-run.ts +0 -8
- package/src/hooks/api/workflow-run-mapper.ts +2 -0
- package/src/hooks/api/workflow-runs.ts +1 -1
- package/src/pages/project-workflows-page.tsx +3 -2
- package/src/pages/workflow-job-detail-page.test.tsx +32 -0
- package/src/pages/workflow-job-detail-page.tsx +5 -1
- package/src/pages/workflow-run-detail-page.tsx +1 -1
- package/src/pages/workflow-run-list-page.tsx +9 -11
- package/src/pages/workflow-run-pages.test.tsx +26 -0
- package/src/routes/job-detail.tsx +1 -1
- package/src/routes/run-detail.tsx +1 -1
- package/src/routes/runs.tsx +1 -1
- package/src/routes/workflows.tsx +1 -0
- package/test/fixtures/workflow-run.ts +30 -3
- package/tsconfig.build.tsbuildinfo +1 -1
- package/src/core/entities/workflow-run-display.test.ts +0 -187
|
@@ -12,7 +12,7 @@ const SKELETON_ROW_COUNT = 8;
|
|
|
12
12
|
* per the design system's rule against animating frequently-updating data.
|
|
13
13
|
*/ export function WorkflowRunListSkeleton() {
|
|
14
14
|
return /*#__PURE__*/ _jsx("div", {
|
|
15
|
-
className: "@container divide-y divide-border-neutral-base
|
|
15
|
+
className: "@container divide-y divide-border-neutral-base",
|
|
16
16
|
role: "status",
|
|
17
17
|
"aria-label": "Loading runs",
|
|
18
18
|
children: Array.from({
|
|
@@ -27,7 +27,7 @@ const SKELETON_ROW_COUNT = 8;
|
|
|
27
27
|
className: "h-12 w-[220px] max-w-[40%]"
|
|
28
28
|
}),
|
|
29
29
|
/*#__PURE__*/ _jsx(Skeleton, {
|
|
30
|
-
className: "ml-auto hidden h-12 w-96 @min-[
|
|
30
|
+
className: "ml-auto hidden h-12 w-96 @min-[1200px]:block"
|
|
31
31
|
}),
|
|
32
32
|
/*#__PURE__*/ _jsx(Skeleton, {
|
|
33
33
|
className: "h-12 w-48"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-list-states.tsx"],"sourcesContent":["import type {QueryLoadErrorQuery} 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 {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {Link} from '@tanstack/react-router';\n\nconst SKELETON_ROW_COUNT = 8;\n\n/**\n * Placeholder rows at the real row height, so the list does not resize under the cursor when\n * the first page lands. Only the initial load renders these: a refetch keeps the rows it has,\n * per the design system's rule against animating frequently-updating data.\n */\nexport function WorkflowRunListSkeleton() {\n return (\n <div\n className=\"@container divide-y divide-border-neutral-base
|
|
1
|
+
{"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-list-states.tsx"],"sourcesContent":["import type {QueryLoadErrorQuery} 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 {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Text} from '@shipfox/react-ui/typography';\nimport {Link} from '@tanstack/react-router';\n\nconst SKELETON_ROW_COUNT = 8;\n\n/**\n * Placeholder rows at the real row height, so the list does not resize under the cursor when\n * the first page lands. Only the initial load renders these: a refetch keeps the rows it has,\n * per the design system's rule against animating frequently-updating data.\n */\nexport function WorkflowRunListSkeleton() {\n return (\n <div\n className=\"@container divide-y divide-border-neutral-base\"\n role=\"status\"\n aria-label=\"Loading runs\"\n >\n {Array.from({length: SKELETON_ROW_COUNT}).map((_, index) => (\n <div\n // biome-ignore lint/suspicious/noArrayIndexKey: skeleton row, stable position\n key={index}\n className=\"flex items-center gap-inline px-row py-row @min-[976px]:h-44 @min-[976px]:py-0\"\n >\n <Skeleton className=\"size-14 shrink-0 rounded-full\" />\n <Skeleton className=\"h-12 w-[220px] max-w-[40%]\" />\n <Skeleton className=\"ml-auto hidden h-12 w-96 @min-[1200px]:block\" />\n <Skeleton className=\"h-12 w-48\" />\n <Skeleton className=\"h-12 w-48\" />\n </div>\n ))}\n </div>\n );\n}\n\n/**\n * Slim non-blocking banner shown when a background refetch fails after a prior success,\n * so the already-loaded rows stay on screen with the retry inline rather than being\n * replaced by a full-placeholder error.\n */\nexport function WorkflowRunListStaleError({query}: {query: QueryLoadErrorQuery}) {\n return (\n <div className=\"pb-[8px]\">\n <Callout role=\"alert\" type=\"error\">\n <div className=\"flex items-center justify-between gap-inline\">\n <Text size=\"xs\">Could not refresh workflow runs.</Text>\n <Button\n type=\"button\"\n size=\"2xs\"\n variant=\"secondary\"\n isLoading={query.isFetching}\n onClick={() => {\n void query.refetch();\n }}\n >\n Retry\n </Button>\n </div>\n </Callout>\n </div>\n );\n}\n\nexport function WorkflowRunListEmpty({\n workspaceSlug,\n projectSlug,\n}: {\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n}) {\n return (\n <EmptyState\n icon=\"pulseLine\"\n title=\"No runs yet\"\n description=\"Runs from this project's workflows appear here the moment one is launched.\"\n action={\n workspaceSlug && projectSlug ? (\n <Button asChild type=\"button\" size=\"sm\" variant=\"primary\">\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/workflows\"\n params={{workspaceSlug, projectSlug}}\n >\n View workflows\n </Link>\n </Button>\n ) : null\n }\n />\n );\n}\n\n/**\n * The filtered-empty state, deliberately distinct from the unfiltered one: someone who\n * filtered their way to nothing needs a way back out, not an onboarding call to action.\n *\n * Its reset is worded as its outcome rather than repeating the toolbar's \"Clear filters\"\n * verbatim, so the two controls on screen read as one action offered twice rather than two\n * different ones. It is also the only reset within reach below `md`, where the toolbar's\n * lives inside the filter sheet.\n */\nexport function WorkflowRunListNoMatches({\n onClear,\n hasNextPage,\n isFetchingNextPage,\n isFetchNextPageError,\n onLoadMore,\n}: {\n onClear: () => void;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n isFetchNextPageError: boolean;\n onLoadMore?: () => void;\n}) {\n return (\n <div className=\"flex flex-col gap-inline\">\n {isFetchNextPageError ? (\n <Callout role=\"alert\" type=\"error\">\n Could not load more workflow runs. Try again to continue searching older runs.\n </Callout>\n ) : null}\n <EmptyState\n icon=\"filterOffLine\"\n title={hasNextPage ? 'No matches in loaded history' : 'No matching runs'}\n description={\n hasNextPage\n ? 'No loaded run matches these filters. Load more to search further back.'\n : 'No run matches these filters.'\n }\n action={\n <div className=\"flex flex-wrap justify-center gap-inline\">\n {hasNextPage && onLoadMore ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"primary\"\n isLoading={isFetchingNextPage}\n onClick={onLoadMore}\n >\n Load more runs\n </Button>\n ) : null}\n <Button type=\"button\" size=\"sm\" variant=\"secondary\" onClick={onClear}>\n Show all runs\n </Button>\n </div>\n }\n />\n </div>\n );\n}\n\nexport function WorkflowRunListLoadMore({\n hasNextPage,\n isFetchingNextPage,\n isFetchNextPageError,\n onLoadMore,\n}: {\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n isFetchNextPageError: boolean;\n onLoadMore?: () => void;\n}) {\n if (!hasNextPage || !onLoadMore) return null;\n\n return (\n <div className=\"flex flex-col items-center gap-inline border-t border-border-neutral-base py-row\">\n {isFetchNextPageError ? (\n <Callout role=\"alert\" type=\"error\">\n Could not load more workflow runs. Try again.\n </Callout>\n ) : null}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"secondary\"\n isLoading={isFetchingNextPage}\n onClick={onLoadMore}\n >\n Load more runs\n </Button>\n </div>\n );\n}\n"],"names":["Button","Callout","EmptyState","Skeleton","Text","Link","SKELETON_ROW_COUNT","WorkflowRunListSkeleton","div","className","role","aria-label","Array","from","length","map","_","index","WorkflowRunListStaleError","query","type","size","variant","isLoading","isFetching","onClick","refetch","WorkflowRunListEmpty","workspaceSlug","projectSlug","icon","title","description","action","asChild","to","params","WorkflowRunListNoMatches","onClear","hasNextPage","isFetchingNextPage","isFetchNextPageError","onLoadMore","WorkflowRunListLoadMore"],"mappings":";AACA,SAAQA,MAAM,QAAO,2BAA2B;AAChD,SAAQC,OAAO,QAAO,4BAA4B;AAClD,SAAQC,UAAU,QAAO,gCAAgC;AACzD,SAAQC,QAAQ,QAAO,6BAA6B;AACpD,SAAQC,IAAI,QAAO,+BAA+B;AAClD,SAAQC,IAAI,QAAO,yBAAyB;AAE5C,MAAMC,qBAAqB;AAE3B;;;;CAIC,GACD,OAAO,SAASC;IACd,qBACE,KAACC;QACCC,WAAU;QACVC,MAAK;QACLC,cAAW;kBAEVC,MAAMC,IAAI,CAAC;YAACC,QAAQR;QAAkB,GAAGS,GAAG,CAAC,CAACC,GAAGC,sBAChD,MAACT;gBAGCC,WAAU;;kCAEV,KAACN;wBAASM,WAAU;;kCACpB,KAACN;wBAASM,WAAU;;kCACpB,KAACN;wBAASM,WAAU;;kCACpB,KAACN;wBAASM,WAAU;;kCACpB,KAACN;wBAASM,WAAU;;;eAPfQ;;AAYf;AAEA;;;;CAIC,GACD,OAAO,SAASC,0BAA0B,EAACC,KAAK,EAA+B;IAC7E,qBACE,KAACX;QAAIC,WAAU;kBACb,cAAA,KAACR;YAAQS,MAAK;YAAQU,MAAK;sBACzB,cAAA,MAACZ;gBAAIC,WAAU;;kCACb,KAACL;wBAAKiB,MAAK;kCAAK;;kCAChB,KAACrB;wBACCoB,MAAK;wBACLC,MAAK;wBACLC,SAAQ;wBACRC,WAAWJ,MAAMK,UAAU;wBAC3BC,SAAS;4BACP,KAAKN,MAAMO,OAAO;wBACpB;kCACD;;;;;;AAOX;AAEA,OAAO,SAASC,qBAAqB,EACnCC,aAAa,EACbC,WAAW,EAIZ;IACC,qBACE,KAAC3B;QACC4B,MAAK;QACLC,OAAM;QACNC,aAAY;QACZC,QACEL,iBAAiBC,4BACf,KAAC7B;YAAOkC,OAAO;YAACd,MAAK;YAASC,MAAK;YAAKC,SAAQ;sBAC9C,cAAA,KAACjB;gBACC8B,IAAG;gBACHC,QAAQ;oBAACR;oBAAeC;gBAAW;0BACpC;;aAID;;AAIZ;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASQ,yBAAyB,EACvCC,OAAO,EACPC,WAAW,EACXC,kBAAkB,EAClBC,oBAAoB,EACpBC,UAAU,EAOX;IACC,qBACE,MAAClC;QAAIC,WAAU;;YACZgC,qCACC,KAACxC;gBAAQS,MAAK;gBAAQU,MAAK;0BAAQ;iBAGjC;0BACJ,KAAClB;gBACC4B,MAAK;gBACLC,OAAOQ,cAAc,iCAAiC;gBACtDP,aACEO,cACI,2EACA;gBAENN,sBACE,MAACzB;oBAAIC,WAAU;;wBACZ8B,eAAeG,2BACd,KAAC1C;4BACCoB,MAAK;4BACLC,MAAK;4BACLC,SAAQ;4BACRC,WAAWiB;4BACXf,SAASiB;sCACV;6BAGC;sCACJ,KAAC1C;4BAAOoB,MAAK;4BAASC,MAAK;4BAAKC,SAAQ;4BAAYG,SAASa;sCAAS;;;;;;;AAQlF;AAEA,OAAO,SAASK,wBAAwB,EACtCJ,WAAW,EACXC,kBAAkB,EAClBC,oBAAoB,EACpBC,UAAU,EAMX;IACC,IAAI,CAACH,eAAe,CAACG,YAAY,OAAO;IAExC,qBACE,MAAClC;QAAIC,WAAU;;YACZgC,qCACC,KAACxC;gBAAQS,MAAK;gBAAQU,MAAK;0BAAQ;iBAGjC;0BACJ,KAACpB;gBACCoB,MAAK;gBACLC,MAAK;gBACLC,SAAQ;gBACRC,WAAWiB;gBACXf,SAASiB;0BACV;;;;AAKP"}
|
|
@@ -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":"
|
|
1
|
+
{"version":3,"file":"workflow-run-list-view.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-list/workflow-run-list-view.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,YAAY,CAAC;AAMzD,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,KAAK,EACL,aAAa,EACb,WAAW,EACX,SAAS,EACT,MAAqB,EACrB,eAAe,EACf,cAAc,EACd,WAAmB,EACnB,kBAA0B,EAC1B,oBAA4B,EAC5B,UAAU,GACX,EAAE,wBAAwB,+BAkE1B"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Panel, PanelBody, PanelHeader } from '@shipfox/react-ui/panel';
|
|
2
3
|
import { TimeTickerProvider } from '@shipfox/react-ui/time-ticker';
|
|
3
4
|
import { Header } from '@shipfox/react-ui/typography';
|
|
4
5
|
import { cn } from '@shipfox/react-ui/utils';
|
|
@@ -37,7 +38,7 @@ export function WorkflowRunListView({ runs, query, workspaceSlug, projectSlug, c
|
|
|
37
38
|
reducedMotionIntervalMs: 10_000,
|
|
38
39
|
children: /*#__PURE__*/ _jsxs("section", {
|
|
39
40
|
"aria-labelledby": headingId,
|
|
40
|
-
className: cn('flex min-h-0 min-w-0 flex-1 flex-col
|
|
41
|
+
className: cn('flex min-h-0 min-w-0 flex-1 flex-col', className),
|
|
41
42
|
children: [
|
|
42
43
|
/*#__PURE__*/ _jsx(Header, {
|
|
43
44
|
id: headingId,
|
|
@@ -45,27 +46,38 @@ export function WorkflowRunListView({ runs, query, workspaceSlug, projectSlug, c
|
|
|
45
46
|
className: "sr-only",
|
|
46
47
|
children: "Workflow runs"
|
|
47
48
|
}),
|
|
48
|
-
/*#__PURE__*/
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
49
|
+
/*#__PURE__*/ _jsxs(Panel, {
|
|
50
|
+
className: "min-h-0 flex-1",
|
|
51
|
+
children: [
|
|
52
|
+
/*#__PURE__*/ _jsx(PanelHeader, {
|
|
53
|
+
className: "flex-wrap",
|
|
54
|
+
children: /*#__PURE__*/ _jsx(WorkflowRunFilters, {
|
|
55
|
+
search: currentSearch,
|
|
56
|
+
facets: facets,
|
|
57
|
+
onChange: handleFiltersChange,
|
|
58
|
+
onClear: handleClearFilters,
|
|
59
|
+
hasActiveFilters: hasActiveFilters
|
|
60
|
+
})
|
|
61
|
+
}),
|
|
62
|
+
/*#__PURE__*/ _jsx(PanelBody, {
|
|
63
|
+
className: "min-h-0 flex-1",
|
|
64
|
+
children: /*#__PURE__*/ _jsx(WorkflowRunListContent, {
|
|
65
|
+
query: query,
|
|
66
|
+
totalRuns: runs.length,
|
|
67
|
+
runs: filteredRuns,
|
|
68
|
+
workspaceSlug: workspaceSlug,
|
|
69
|
+
projectSlug: projectSlug,
|
|
70
|
+
hasActiveFilters: hasActiveFilters,
|
|
71
|
+
onClearFilters: handleClearFilters,
|
|
72
|
+
hasNextPage: hasNextPage,
|
|
73
|
+
isFetchingNextPage: isFetchingNextPage,
|
|
74
|
+
isFetchNextPageError: isFetchNextPageError,
|
|
75
|
+
...onLoadMore ? {
|
|
76
|
+
onLoadMore
|
|
77
|
+
} : {}
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
]
|
|
69
81
|
})
|
|
70
82
|
]
|
|
71
83
|
})
|
|
@@ -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 {Header} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useId, useMemo, useState} from 'react';\nimport {\n applyWorkflowRunFilterPatch,\n clearWorkflowRunFilters,\n hasWorkflowRunFilters,\n type WorkflowRunFilterPatch,\n type WorkflowRunsSearch,\n} from '#routes/inputs.js';\nimport {runMatchesFilters, workflowRunFacets} from './run-display.js';\nimport type {WorkflowRunListViewProps} from './types.js';\nimport {WorkflowRunFilters} from './workflow-run-filters.js';\nimport {WorkflowRunListContent} from './workflow-run-list-content.js';\n\nconst EMPTY_SEARCH: WorkflowRunsSearch = {};\n\nexport function WorkflowRunListView({\n runs,\n query,\n workspaceSlug,\n projectSlug,\n className,\n search = EMPTY_SEARCH,\n onFiltersChange,\n onClearFilters,\n hasNextPage = false,\n isFetchingNextPage = false,\n isFetchNextPageError = false,\n onLoadMore,\n}: WorkflowRunListViewProps) {\n const headingId = useId();\n const [localSearch, setLocalSearch] = useState<WorkflowRunsSearch>(search);\n const currentSearch = onFiltersChange ? search : localSearch;\n\n const filteredRuns = useMemo(\n () => runs.filter((run) => runMatchesFilters(run, currentSearch)),\n [runs, currentSearch],\n );\n const facets = useMemo(() => workflowRunFacets(runs, currentSearch), [runs, currentSearch]);\n const hasActiveFilters = hasWorkflowRunFilters(currentSearch);\n\n function handleFiltersChange(patch: WorkflowRunFilterPatch) {\n if (onFiltersChange) onFiltersChange(patch);\n else setLocalSearch((previous) => applyWorkflowRunFilterPatch(previous, patch));\n }\n\n function handleClearFilters() {\n // Uncontrolled, the view owns the filters, so it clears them itself and still reports the\n // change; a caller that passes only `onClearFilters` would otherwise see nothing happen.\n if (!onFiltersChange) setLocalSearch(clearWorkflowRunFilters);\n else if (!onClearFilters) onFiltersChange(CLEAR_ALL_FILTERS);\n onClearFilters?.();\n }\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <section\n aria-labelledby={headingId}\n className={cn('flex min-h-0 min-w-0 flex-1 flex-col
|
|
1
|
+
{"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-list-view.tsx"],"sourcesContent":["import {Panel, PanelBody, PanelHeader} from '@shipfox/react-ui/panel';\nimport {TimeTickerProvider} from '@shipfox/react-ui/time-ticker';\nimport {Header} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {useId, useMemo, useState} from 'react';\nimport {\n applyWorkflowRunFilterPatch,\n clearWorkflowRunFilters,\n hasWorkflowRunFilters,\n type WorkflowRunFilterPatch,\n type WorkflowRunsSearch,\n} from '#routes/inputs.js';\nimport {runMatchesFilters, workflowRunFacets} from './run-display.js';\nimport type {WorkflowRunListViewProps} from './types.js';\nimport {WorkflowRunFilters} from './workflow-run-filters.js';\nimport {WorkflowRunListContent} from './workflow-run-list-content.js';\n\nconst EMPTY_SEARCH: WorkflowRunsSearch = {};\n\nexport function WorkflowRunListView({\n runs,\n query,\n workspaceSlug,\n projectSlug,\n className,\n search = EMPTY_SEARCH,\n onFiltersChange,\n onClearFilters,\n hasNextPage = false,\n isFetchingNextPage = false,\n isFetchNextPageError = false,\n onLoadMore,\n}: WorkflowRunListViewProps) {\n const headingId = useId();\n const [localSearch, setLocalSearch] = useState<WorkflowRunsSearch>(search);\n const currentSearch = onFiltersChange ? search : localSearch;\n\n const filteredRuns = useMemo(\n () => runs.filter((run) => runMatchesFilters(run, currentSearch)),\n [runs, currentSearch],\n );\n const facets = useMemo(() => workflowRunFacets(runs, currentSearch), [runs, currentSearch]);\n const hasActiveFilters = hasWorkflowRunFilters(currentSearch);\n\n function handleFiltersChange(patch: WorkflowRunFilterPatch) {\n if (onFiltersChange) onFiltersChange(patch);\n else setLocalSearch((previous) => applyWorkflowRunFilterPatch(previous, patch));\n }\n\n function handleClearFilters() {\n // Uncontrolled, the view owns the filters, so it clears them itself and still reports the\n // change; a caller that passes only `onClearFilters` would otherwise see nothing happen.\n if (!onFiltersChange) setLocalSearch(clearWorkflowRunFilters);\n else if (!onClearFilters) onFiltersChange(CLEAR_ALL_FILTERS);\n onClearFilters?.();\n }\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <section\n aria-labelledby={headingId}\n className={cn('flex min-h-0 min-w-0 flex-1 flex-col', className)}\n >\n {/* The tab strip above already reads \"Runs\", so the page heading is for structure and\n assistive tech rather than a second visible title competing with it. */}\n <Header id={headingId} variant=\"h1\" className=\"sr-only\">\n Workflow runs\n </Header>\n\n <Panel className=\"min-h-0 flex-1\">\n <PanelHeader className=\"flex-wrap\">\n <WorkflowRunFilters\n search={currentSearch}\n facets={facets}\n onChange={handleFiltersChange}\n onClear={handleClearFilters}\n hasActiveFilters={hasActiveFilters}\n />\n </PanelHeader>\n <PanelBody className=\"min-h-0 flex-1\">\n <WorkflowRunListContent\n query={query}\n totalRuns={runs.length}\n runs={filteredRuns}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n hasActiveFilters={hasActiveFilters}\n onClearFilters={handleClearFilters}\n hasNextPage={hasNextPage}\n isFetchingNextPage={isFetchingNextPage}\n isFetchNextPageError={isFetchNextPageError}\n {...(onLoadMore ? {onLoadMore} : {})}\n />\n </PanelBody>\n </Panel>\n </section>\n </TimeTickerProvider>\n );\n}\n\nconst CLEAR_ALL_FILTERS: WorkflowRunFilterPatch = {\n search: undefined,\n status: undefined,\n branch: undefined,\n actor: undefined,\n event: undefined,\n after: undefined,\n before: undefined,\n};\n"],"names":["Panel","PanelBody","PanelHeader","TimeTickerProvider","Header","cn","useId","useMemo","useState","applyWorkflowRunFilterPatch","clearWorkflowRunFilters","hasWorkflowRunFilters","runMatchesFilters","workflowRunFacets","WorkflowRunFilters","WorkflowRunListContent","EMPTY_SEARCH","WorkflowRunListView","runs","query","workspaceSlug","projectSlug","className","search","onFiltersChange","onClearFilters","hasNextPage","isFetchingNextPage","isFetchNextPageError","onLoadMore","headingId","localSearch","setLocalSearch","currentSearch","filteredRuns","filter","run","facets","hasActiveFilters","handleFiltersChange","patch","previous","handleClearFilters","CLEAR_ALL_FILTERS","intervalMs","reducedMotionIntervalMs","section","aria-labelledby","id","variant","onChange","onClear","totalRuns","length","undefined","status","branch","actor","event","after","before"],"mappings":";AAAA,SAAQA,KAAK,EAAEC,SAAS,EAAEC,WAAW,QAAO,0BAA0B;AACtE,SAAQC,kBAAkB,QAAO,gCAAgC;AACjE,SAAQC,MAAM,QAAO,+BAA+B;AACpD,SAAQC,EAAE,QAAO,0BAA0B;AAC3C,SAAQC,KAAK,EAAEC,OAAO,EAAEC,QAAQ,QAAO,QAAQ;AAC/C,SACEC,2BAA2B,EAC3BC,uBAAuB,EACvBC,qBAAqB,QAGhB,oBAAoB;AAC3B,SAAQC,iBAAiB,EAAEC,iBAAiB,QAAO,mBAAmB;AAEtE,SAAQC,kBAAkB,QAAO,4BAA4B;AAC7D,SAAQC,sBAAsB,QAAO,iCAAiC;AAEtE,MAAMC,eAAmC,CAAC;AAE1C,OAAO,SAASC,oBAAoB,EAClCC,IAAI,EACJC,KAAK,EACLC,aAAa,EACbC,WAAW,EACXC,SAAS,EACTC,SAASP,YAAY,EACrBQ,eAAe,EACfC,cAAc,EACdC,cAAc,KAAK,EACnBC,qBAAqB,KAAK,EAC1BC,uBAAuB,KAAK,EAC5BC,UAAU,EACe;IACzB,MAAMC,YAAYxB;IAClB,MAAM,CAACyB,aAAaC,eAAe,GAAGxB,SAA6Be;IACnE,MAAMU,gBAAgBT,kBAAkBD,SAASQ;IAEjD,MAAMG,eAAe3B,QACnB,IAAMW,KAAKiB,MAAM,CAAC,CAACC,MAAQxB,kBAAkBwB,KAAKH,iBAClD;QAACf;QAAMe;KAAc;IAEvB,MAAMI,SAAS9B,QAAQ,IAAMM,kBAAkBK,MAAMe,gBAAgB;QAACf;QAAMe;KAAc;IAC1F,MAAMK,mBAAmB3B,sBAAsBsB;IAE/C,SAASM,oBAAoBC,KAA6B;QACxD,IAAIhB,iBAAiBA,gBAAgBgB;aAChCR,eAAe,CAACS,WAAahC,4BAA4BgC,UAAUD;IAC1E;IAEA,SAASE;QACP,0FAA0F;QAC1F,yFAAyF;QACzF,IAAI,CAAClB,iBAAiBQ,eAAetB;aAChC,IAAI,CAACe,gBAAgBD,gBAAgBmB;QAC1ClB;IACF;IAEA,qBACE,KAACtB;QAAmByC,YAAY;QAAMC,yBAAyB;kBAC7D,cAAA,MAACC;YACCC,mBAAiBjB;YACjBR,WAAWjB,GAAG,wCAAwCiB;;8BAItD,KAAClB;oBAAO4C,IAAIlB;oBAAWmB,SAAQ;oBAAK3B,WAAU;8BAAU;;8BAIxD,MAACtB;oBAAMsB,WAAU;;sCACf,KAACpB;4BAAYoB,WAAU;sCACrB,cAAA,KAACR;gCACCS,QAAQU;gCACRI,QAAQA;gCACRa,UAAUX;gCACVY,SAAST;gCACTJ,kBAAkBA;;;sCAGtB,KAACrC;4BAAUqB,WAAU;sCACnB,cAAA,KAACP;gCACCI,OAAOA;gCACPiC,WAAWlC,KAAKmC,MAAM;gCACtBnC,MAAMgB;gCACNd,eAAeA;gCACfC,aAAaA;gCACbiB,kBAAkBA;gCAClBb,gBAAgBiB;gCAChBhB,aAAaA;gCACbC,oBAAoBA;gCACpBC,sBAAsBA;gCACrB,GAAIC,aAAa;oCAACA;gCAAU,IAAI,CAAC,CAAC;;;;;;;;AAOjD;AAEA,MAAMc,oBAA4C;IAChDpB,QAAQ+B;IACRC,QAAQD;IACRE,QAAQF;IACRG,OAAOH;IACPI,OAAOJ;IACPK,OAAOL;IACPM,QAAQN;AACV"}
|
|
@@ -12,9 +12,9 @@ export declare function WorkflowRunRowList({ runs, workspaceSlug, projectSlug, }
|
|
|
12
12
|
* drops beneath. The numeric columns are fixed-width so duration and time form real columns
|
|
13
13
|
* down the list rather than tracking each row's name length.
|
|
14
14
|
*
|
|
15
|
-
* The
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* The 976px threshold keeps identity and provenance on one line; below it, provenance drops
|
|
16
|
+
* beneath the identity. The 1200px threshold keeps the full job preview and numeric columns
|
|
17
|
+
* readable together; below it, the strip is hidden so the numeric columns remain aligned.
|
|
18
18
|
*/
|
|
19
19
|
export declare function WorkflowRunRow({ run, workspaceSlug, projectSlug, }: {
|
|
20
20
|
run: WorkflowRunListItem;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-run-row.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-list/workflow-run-row.tsx"],"names":[],"mappings":"AAiBA,OAAO,EACL,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"workflow-run-row.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-list/workflow-run-row.tsx"],"names":[],"mappings":"AAiBA,OAAO,EACL,KAAK,mBAAmB,EAIzB,MAAM,uBAAuB,CAAC;AAI/B,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,aAAa,EACb,WAAW,GACZ,EAAE;IACD,IAAI,EAAE,mBAAmB,EAAE,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,+BAaA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,EAC7B,GAAG,EACH,aAAa,EACb,WAAW,GACZ,EAAE;IACD,GAAG,EAAE,mBAAmB,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,+BAgGA"}
|
|
@@ -10,15 +10,15 @@ import { useWorkflowRunDurationAccessibleLabel, WorkflowRunDurationLabel } from
|
|
|
10
10
|
import { formatWorkflowRunNumberLabel, WorkflowRunNumberLabel } from '#components/workflow-run-number-label.js';
|
|
11
11
|
import { getWorkflowStatusVisual } from '#components/workflow-status/status-visuals.js';
|
|
12
12
|
import { WorkflowStatusIcon } from '#components/workflow-status/workflow-status-icon.js';
|
|
13
|
-
import { workflowRunActor, workflowRunBranchLabel, workflowRunCommitLabel
|
|
13
|
+
import { workflowRunActor, workflowRunBranchLabel, workflowRunCommitLabel } from '#core/workflow-run.js';
|
|
14
14
|
import { withoutWorkflowRunSelectionSearch } from '#core/workflow-run-url-state.js';
|
|
15
|
-
import { JobStatusStrip, jobStatusSummary } from './job-status-strip.js';
|
|
15
|
+
import { JOB_STATUS_STRIP_WIDTH, JobStatusStrip, jobStatusSummary } from './job-status-strip.js';
|
|
16
16
|
export function WorkflowRunRowList({ runs, workspaceSlug, projectSlug }) {
|
|
17
|
-
return(// A container, not the viewport, drives the row's breakpoints.
|
|
18
|
-
//
|
|
19
|
-
//
|
|
17
|
+
return(// A container, not the viewport, drives the row's breakpoints. What a row can afford is its
|
|
18
|
+
// own width; keying off the viewport would keep the job strip hidden on a wide screen or
|
|
19
|
+
// crush it on a narrow one.
|
|
20
20
|
/*#__PURE__*/ _jsx("ul", {
|
|
21
|
-
className: "@container divide-y divide-border-neutral-base
|
|
21
|
+
className: "@container divide-y divide-border-neutral-base",
|
|
22
22
|
children: runs.map((run)=>/*#__PURE__*/ _jsx("li", {
|
|
23
23
|
children: /*#__PURE__*/ _jsx(WorkflowRunRow, {
|
|
24
24
|
run: run,
|
|
@@ -36,13 +36,15 @@ export function WorkflowRunRowList({ runs, workspaceSlug, projectSlug }) {
|
|
|
36
36
|
* drops beneath. The numeric columns are fixed-width so duration and time form real columns
|
|
37
37
|
* down the list rather than tracking each row's name length.
|
|
38
38
|
*
|
|
39
|
-
* The
|
|
40
|
-
*
|
|
41
|
-
*
|
|
39
|
+
* The 976px threshold keeps identity and provenance on one line; below it, provenance drops
|
|
40
|
+
* beneath the identity. The 1200px threshold keeps the full job preview and numeric columns
|
|
41
|
+
* readable together; below it, the strip is hidden so the numeric columns remain aligned.
|
|
42
42
|
*/ export function WorkflowRunRow({ run, workspaceSlug, projectSlug }) {
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
43
|
+
const duration = run.runAttempt.displayDuration;
|
|
44
|
+
const hasStarted = run.jobs.hasStartedJobExecution;
|
|
45
|
+
const durationLabel = useWorkflowRunDurationAccessibleLabel(duration, hasStarted);
|
|
46
|
+
const status = run.runAttempt.status;
|
|
47
|
+
const statusLabel = getWorkflowStatusVisual(status).label;
|
|
46
48
|
const runNumberLabel = formatWorkflowRunNumberLabel(run);
|
|
47
49
|
const branch = workflowRunBranchLabel(run);
|
|
48
50
|
const commit = workflowRunCommitLabel(run);
|
|
@@ -50,7 +52,7 @@ export function WorkflowRunRowList({ runs, workspaceSlug, projectSlug }) {
|
|
|
50
52
|
const body = /*#__PURE__*/ _jsxs(_Fragment, {
|
|
51
53
|
children: [
|
|
52
54
|
/*#__PURE__*/ _jsx(WorkflowStatusIcon, {
|
|
53
|
-
status:
|
|
55
|
+
status: status,
|
|
54
56
|
size: 14,
|
|
55
57
|
className: "shrink-0"
|
|
56
58
|
}),
|
|
@@ -95,7 +97,10 @@ export function WorkflowRunRowList({ runs, workspaceSlug, projectSlug }) {
|
|
|
95
97
|
className: "flex shrink-0 items-center gap-cluster",
|
|
96
98
|
children: [
|
|
97
99
|
/*#__PURE__*/ _jsx("span", {
|
|
98
|
-
className: "hidden w-
|
|
100
|
+
className: "hidden w-max shrink-0 @min-[1200px]:flex",
|
|
101
|
+
style: {
|
|
102
|
+
minWidth: JOB_STATUS_STRIP_WIDTH
|
|
103
|
+
},
|
|
99
104
|
children: /*#__PURE__*/ _jsx(JobStatusStrip, {
|
|
100
105
|
jobs: run.jobs
|
|
101
106
|
})
|
|
@@ -103,7 +108,8 @@ export function WorkflowRunRowList({ runs, workspaceSlug, projectSlug }) {
|
|
|
103
108
|
/*#__PURE__*/ _jsx("span", {
|
|
104
109
|
className: "flex w-64 justify-end",
|
|
105
110
|
children: /*#__PURE__*/ _jsx(WorkflowRunDurationLabel, {
|
|
106
|
-
duration:
|
|
111
|
+
duration: duration,
|
|
112
|
+
hasStarted: hasStarted
|
|
107
113
|
})
|
|
108
114
|
}),
|
|
109
115
|
/*#__PURE__*/ _jsx(Code, {
|
|
@@ -119,7 +125,7 @@ export function WorkflowRunRowList({ runs, workspaceSlug, projectSlug }) {
|
|
|
119
125
|
});
|
|
120
126
|
// Rows run edge to edge inside the list's scroll container, which would clip the standard
|
|
121
127
|
// outset focus ring, so this one is inset per the design system's focus-ring rule.
|
|
122
|
-
const rowClassName = 'flex w-full min-w-0 items-center gap-inline px-row py-row text-left transition-colors hover:bg-background-
|
|
128
|
+
const rowClassName = 'flex w-full min-w-0 items-center gap-inline px-row py-row text-left transition-colors hover:bg-background-neutral-hover focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)] focus-visible:outline-none @min-[976px]:h-44 @min-[976px]:py-0';
|
|
123
129
|
// Optimistic manual runs (temp-<uuid>) have no detail page until the canonical row
|
|
124
130
|
// replaces them on the next poll, so they render non-interactively instead of as a link
|
|
125
131
|
// that would navigate to a workflow run id the detail route rejects.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-row.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {\n useWorkflowRunDurationAccessibleLabel,\n WorkflowRunDurationLabel,\n} from '#components/workflow-run-duration-label.js';\nimport {\n formatWorkflowRunNumberLabel,\n WorkflowRunNumberLabel,\n} from '#components/workflow-run-number-label.js';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport {\n type WorkflowRunListItem,\n workflowRunActor,\n workflowRunBranchLabel,\n workflowRunCommitLabel,\n workflowRunListItemDisplay,\n} from '#core/workflow-run.js';\nimport {withoutWorkflowRunSelectionSearch} from '#core/workflow-run-url-state.js';\nimport {JobStatusStrip, jobStatusSummary} from './job-status-strip.js';\n\nexport function WorkflowRunRowList({\n runs,\n workspaceSlug,\n projectSlug,\n}: {\n runs: WorkflowRunListItem[];\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n}) {\n return (\n // A container, not the viewport, drives the row's breakpoints. The list is capped at\n // 1120px inside a wider page, so what a row can afford is its own width; keying off the\n // viewport would keep the job strip hidden on a wide screen or crush it on a narrow one.\n <ul className=\"@container divide-y divide-border-neutral-base border-t border-border-neutral-base\">\n {runs.map((run) => (\n <li key={run.id}>\n <WorkflowRunRow run={run} workspaceSlug={workspaceSlug} projectSlug={projectSlug} />\n </li>\n ))}\n </ul>\n );\n}\n\n/**\n * One run at full width.\n *\n * A single 44px line once the list is at least 976px wide, reflowing to two lines below that:\n * the identity and the numerics keep their places on line one, and the provenance metadata\n * drops beneath. The numeric columns are fixed-width so duration and time form real columns\n * down the list rather than tracking each row's name length.\n *\n * The thresholds are the container widths the spec's viewport breakpoints produce, given a\n * column capped at 1120px with 24px of page padding on each side: a 1280px viewport leaves\n * the row 1072px, and a 1024px viewport leaves it 976px.\n */\nexport function WorkflowRunRow({\n run,\n workspaceSlug,\n projectSlug,\n}: {\n run: WorkflowRunListItem;\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n}) {\n const display = workflowRunListItemDisplay(run);\n const durationLabel = useWorkflowRunDurationAccessibleLabel(display.duration);\n const statusLabel = getWorkflowStatusVisual(display.status).label;\n const runNumberLabel = formatWorkflowRunNumberLabel(run);\n const branch = workflowRunBranchLabel(run);\n const commit = workflowRunCommitLabel(run);\n const actor = workflowRunActor(run);\n\n const body = (\n <>\n <WorkflowStatusIcon status={display.status} size={14} className=\"shrink-0\" />\n\n <div className=\"flex min-w-0 flex-1 flex-col gap-tight @min-[976px]:flex-row @min-[976px]:items-center @min-[976px]:gap-cluster\">\n <span className=\"flex min-w-0 items-center gap-inline @min-[976px]:flex-1\">\n <Code variant=\"label\" bold className=\"truncate text-foreground-neutral-base\">\n {run.name}\n </Code>\n {run.number !== null ? <WorkflowRunNumberLabel run={run} /> : null}\n </span>\n\n <span className=\"flex min-w-0 flex-wrap items-center gap-inline text-foreground-neutral-subtle @min-[976px]:flex-nowrap @min-[976px]:shrink-0\">\n {run.triggerDisplayLabel ? <TriggerLabel run={run} /> : null}\n {branch ? <BranchLabel branch={branch} isPullRequest={branch.startsWith('#')} /> : null}\n {commit ? <CommitLabel commit={commit} /> : null}\n {actor ? <ActorLabel actor={actor} /> : null}\n </span>\n </div>\n\n <span className=\"flex shrink-0 items-center gap-cluster\">\n {/* Fixed at the strip's worst case (see MAX_VISIBLE_JOBS) so the overflow count cannot\n paint over the duration, and kept even when a run has no jobs planned yet, so the\n numerics stay in line down the list instead of stepping in and out. */}\n <span className=\"hidden w-160 @min-[1040px]:flex\">\n <JobStatusStrip jobs={run.jobs} />\n </span>\n <span className=\"flex w-64 justify-end\">\n <WorkflowRunDurationLabel duration={display.duration} />\n </span>\n <Code\n variant=\"label\"\n className=\"w-64 shrink-0 text-right tabular-nums text-foreground-neutral-muted\"\n >\n <RelativeTime value={run.createdAt} />\n </Code>\n </span>\n </>\n );\n\n // Rows run edge to edge inside the list's scroll container, which would clip the standard\n // outset focus ring, so this one is inset per the design system's focus-ring rule.\n const rowClassName =\n 'flex w-full min-w-0 items-center gap-inline px-row py-row text-left transition-colors hover:bg-background-components-hover focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)] focus-visible:outline-none @min-[976px]:h-44 @min-[976px]:py-0';\n\n // Optimistic manual runs (temp-<uuid>) have no detail page until the canonical row\n // replaces them on the next poll, so they render non-interactively instead of as a link\n // that would navigate to a workflow run id the detail route rejects.\n if (run.isTemporary || !workspaceSlug || !projectSlug) {\n return <div className={rowClassName}>{body}</div>;\n }\n\n return (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId: run.id}}\n search={\n ((previous: Record<string, unknown>) =>\n withoutWorkflowRunSelectionSearch(previous)) as never\n }\n // An aria-label is the link's whole accessible name, so anything inside the row that\n // carries its own label (the status glyph, the job strip) goes unspoken unless it is\n // curated in here. The job breakdown is the reason this list is worth its width, so it\n // belongs in what a tabbing user hears, not only in browse mode.\n aria-label={[\n run.name,\n runNumberLabel,\n statusLabel,\n durationLabel,\n run.triggerLabel,\n branch ? `branch ${branch}` : undefined,\n actor ? `by ${actor}` : undefined,\n run.jobs.total > 0 ? jobStatusSummary(run.jobs) : undefined,\n ]\n .filter((part): part is string => Boolean(part))\n .join(', ')}\n className={rowClassName}\n >\n {body}\n </Link>\n );\n}\n\nfunction TriggerLabel({run}: {run: WorkflowRunListItem}) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex min-w-0 max-w-[140px] items-center gap-tight outline-none\">\n <TriggerSourceIcon\n provider={run.triggerProvider}\n source={run.triggerSource}\n aria-hidden=\"true\"\n className=\"size-12 shrink-0 text-foreground-neutral-muted\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate\">\n {run.triggerDisplayLabel}\n </Text>\n </span>\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 );\n}\n\nfunction BranchLabel({branch, isPullRequest}: {branch: string; isPullRequest: boolean}) {\n return (\n <MetadataChip\n icon={isPullRequest ? 'gitPullRequestLine' : 'gitBranchLine'}\n title={isPullRequest ? `Pull request ${branch}` : `Branch ${branch}`}\n className=\"max-w-[180px]\"\n >\n {branch}\n </MetadataChip>\n );\n}\n\nfunction CommitLabel({commit}: {commit: string}) {\n return (\n <MetadataChip icon=\"gitCommitLine\" title={`Commit ${commit}`}>\n {commit}\n </MetadataChip>\n );\n}\n\nfunction ActorLabel({actor}: {actor: string}) {\n return (\n <MetadataChip\n icon=\"userLine\"\n title={`Triggered by ${actor}`}\n // Dropped once the row is two lines, where the provenance line has to stay readable on\n // a phone.\n className=\"hidden max-w-[120px] @min-[976px]:flex\"\n >\n {actor}\n </MetadataChip>\n );\n}\n\n/**\n * A ref, SHA, or handle: monospace because it is content a user copies or pattern-matches,\n * with the icon carrying the kind so the value itself never needs a written label.\n */\nfunction MetadataChip({\n icon,\n title,\n className,\n children,\n}: {\n icon: IconName;\n title: string;\n className?: string | undefined;\n children: string;\n}) {\n return (\n <span className={cn('flex min-w-0 shrink-0 items-center gap-tight', className)} title={title}>\n <Icon name={icon} className=\"size-12 shrink-0 text-foreground-neutral-muted\" aria-hidden />\n <Code as=\"span\" variant=\"label\" className=\"min-w-0 truncate\">\n {children}\n </Code>\n </span>\n );\n}\n"],"names":["TriggerSourceIcon","Icon","RelativeTime","Tooltip","TooltipContent","TooltipTrigger","Code","Text","cn","Link","useWorkflowRunDurationAccessibleLabel","WorkflowRunDurationLabel","formatWorkflowRunNumberLabel","WorkflowRunNumberLabel","getWorkflowStatusVisual","WorkflowStatusIcon","workflowRunActor","workflowRunBranchLabel","workflowRunCommitLabel","workflowRunListItemDisplay","withoutWorkflowRunSelectionSearch","JobStatusStrip","jobStatusSummary","WorkflowRunRowList","runs","workspaceSlug","projectSlug","ul","className","map","run","li","WorkflowRunRow","id","display","durationLabel","duration","statusLabel","status","label","runNumberLabel","branch","commit","actor","body","size","div","span","variant","bold","name","number","triggerDisplayLabel","TriggerLabel","BranchLabel","isPullRequest","startsWith","CommitLabel","ActorLabel","jobs","value","createdAt","rowClassName","isTemporary","to","params","workflowRunId","search","previous","aria-label","triggerLabel","undefined","total","filter","part","Boolean","join","asChild","provider","triggerProvider","source","triggerSource","aria-hidden","as","MetadataChip","icon","title","children"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/workflow-run-list/workflow-run-row.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {Icon, type IconName} from '@shipfox/react-ui/icon';\nimport {RelativeTime} from '@shipfox/react-ui/relative-time';\nimport {Tooltip, TooltipContent, TooltipTrigger} from '@shipfox/react-ui/tooltip';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport {\n useWorkflowRunDurationAccessibleLabel,\n WorkflowRunDurationLabel,\n} from '#components/workflow-run-duration-label.js';\nimport {\n formatWorkflowRunNumberLabel,\n WorkflowRunNumberLabel,\n} from '#components/workflow-run-number-label.js';\nimport {getWorkflowStatusVisual} from '#components/workflow-status/status-visuals.js';\nimport {WorkflowStatusIcon} from '#components/workflow-status/workflow-status-icon.js';\nimport {\n type WorkflowRunListItem,\n workflowRunActor,\n workflowRunBranchLabel,\n workflowRunCommitLabel,\n} from '#core/workflow-run.js';\nimport {withoutWorkflowRunSelectionSearch} from '#core/workflow-run-url-state.js';\nimport {JOB_STATUS_STRIP_WIDTH, JobStatusStrip, jobStatusSummary} from './job-status-strip.js';\n\nexport function WorkflowRunRowList({\n runs,\n workspaceSlug,\n projectSlug,\n}: {\n runs: WorkflowRunListItem[];\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n}) {\n return (\n // A container, not the viewport, drives the row's breakpoints. What a row can afford is its\n // own width; keying off the viewport would keep the job strip hidden on a wide screen or\n // crush it on a narrow one.\n <ul className=\"@container divide-y divide-border-neutral-base\">\n {runs.map((run) => (\n <li key={run.id}>\n <WorkflowRunRow run={run} workspaceSlug={workspaceSlug} projectSlug={projectSlug} />\n </li>\n ))}\n </ul>\n );\n}\n\n/**\n * One run at full width.\n *\n * A single 44px line once the list is at least 976px wide, reflowing to two lines below that:\n * the identity and the numerics keep their places on line one, and the provenance metadata\n * drops beneath. The numeric columns are fixed-width so duration and time form real columns\n * down the list rather than tracking each row's name length.\n *\n * The 976px threshold keeps identity and provenance on one line; below it, provenance drops\n * beneath the identity. The 1200px threshold keeps the full job preview and numeric columns\n * readable together; below it, the strip is hidden so the numeric columns remain aligned.\n */\nexport function WorkflowRunRow({\n run,\n workspaceSlug,\n projectSlug,\n}: {\n run: WorkflowRunListItem;\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n}) {\n const duration = run.runAttempt.displayDuration;\n const hasStarted = run.jobs.hasStartedJobExecution;\n const durationLabel = useWorkflowRunDurationAccessibleLabel(duration, hasStarted);\n const status = run.runAttempt.status;\n const statusLabel = getWorkflowStatusVisual(status).label;\n const runNumberLabel = formatWorkflowRunNumberLabel(run);\n const branch = workflowRunBranchLabel(run);\n const commit = workflowRunCommitLabel(run);\n const actor = workflowRunActor(run);\n\n const body = (\n <>\n <WorkflowStatusIcon status={status} size={14} className=\"shrink-0\" />\n\n <div className=\"flex min-w-0 flex-1 flex-col gap-tight @min-[976px]:flex-row @min-[976px]:items-center @min-[976px]:gap-cluster\">\n <span className=\"flex min-w-0 items-center gap-inline @min-[976px]:flex-1\">\n <Code variant=\"label\" bold className=\"truncate text-foreground-neutral-base\">\n {run.name}\n </Code>\n {run.number !== null ? <WorkflowRunNumberLabel run={run} /> : null}\n </span>\n\n <span className=\"flex min-w-0 flex-wrap items-center gap-inline text-foreground-neutral-subtle @min-[976px]:flex-nowrap @min-[976px]:shrink-0\">\n {run.triggerDisplayLabel ? <TriggerLabel run={run} /> : null}\n {branch ? <BranchLabel branch={branch} isPullRequest={branch.startsWith('#')} /> : null}\n {commit ? <CommitLabel commit={commit} /> : null}\n {actor ? <ActorLabel actor={actor} /> : null}\n </span>\n </div>\n\n <span className=\"flex shrink-0 items-center gap-cluster\">\n {/* Reserve the API preview's full width so the overflow count cannot paint over the\n duration, and keep it even when a run has no jobs planned yet so the numerics stay in\n line down the list instead of stepping in and out. The max-content width expands if\n the payload ever exceeds the current API preview bound. */}\n <span\n className=\"hidden w-max shrink-0 @min-[1200px]:flex\"\n style={{minWidth: JOB_STATUS_STRIP_WIDTH}}\n >\n <JobStatusStrip jobs={run.jobs} />\n </span>\n <span className=\"flex w-64 justify-end\">\n <WorkflowRunDurationLabel duration={duration} hasStarted={hasStarted} />\n </span>\n <Code\n variant=\"label\"\n className=\"w-64 shrink-0 text-right tabular-nums text-foreground-neutral-muted\"\n >\n <RelativeTime value={run.createdAt} />\n </Code>\n </span>\n </>\n );\n\n // Rows run edge to edge inside the list's scroll container, which would clip the standard\n // outset focus ring, so this one is inset per the design system's focus-ring rule.\n const rowClassName =\n 'flex w-full min-w-0 items-center gap-inline px-row py-row text-left transition-colors hover:bg-background-neutral-hover focus-visible:shadow-[inset_0_0_0_2px_var(--color-primary-500)] focus-visible:outline-none @min-[976px]:h-44 @min-[976px]:py-0';\n\n // Optimistic manual runs (temp-<uuid>) have no detail page until the canonical row\n // replaces them on the next poll, so they render non-interactively instead of as a link\n // that would navigate to a workflow run id the detail route rejects.\n if (run.isTemporary || !workspaceSlug || !projectSlug) {\n return <div className={rowClassName}>{body}</div>;\n }\n\n return (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId: run.id}}\n search={\n ((previous: Record<string, unknown>) =>\n withoutWorkflowRunSelectionSearch(previous)) as never\n }\n // An aria-label is the link's whole accessible name, so anything inside the row that\n // carries its own label (the status glyph, the job strip) goes unspoken unless it is\n // curated in here. The job breakdown is the reason this list is worth its width, so it\n // belongs in what a tabbing user hears, not only in browse mode.\n aria-label={[\n run.name,\n runNumberLabel,\n statusLabel,\n durationLabel,\n run.triggerLabel,\n branch ? `branch ${branch}` : undefined,\n actor ? `by ${actor}` : undefined,\n run.jobs.total > 0 ? jobStatusSummary(run.jobs) : undefined,\n ]\n .filter((part): part is string => Boolean(part))\n .join(', ')}\n className={rowClassName}\n >\n {body}\n </Link>\n );\n}\n\nfunction TriggerLabel({run}: {run: WorkflowRunListItem}) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex min-w-0 max-w-[140px] items-center gap-tight outline-none\">\n <TriggerSourceIcon\n provider={run.triggerProvider}\n source={run.triggerSource}\n aria-hidden=\"true\"\n className=\"size-12 shrink-0 text-foreground-neutral-muted\"\n />\n <Text as=\"span\" size=\"xs\" className=\"min-w-0 truncate\">\n {run.triggerDisplayLabel}\n </Text>\n </span>\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 );\n}\n\nfunction BranchLabel({branch, isPullRequest}: {branch: string; isPullRequest: boolean}) {\n return (\n <MetadataChip\n icon={isPullRequest ? 'gitPullRequestLine' : 'gitBranchLine'}\n title={isPullRequest ? `Pull request ${branch}` : `Branch ${branch}`}\n className=\"max-w-[180px]\"\n >\n {branch}\n </MetadataChip>\n );\n}\n\nfunction CommitLabel({commit}: {commit: string}) {\n return (\n <MetadataChip icon=\"gitCommitLine\" title={`Commit ${commit}`}>\n {commit}\n </MetadataChip>\n );\n}\n\nfunction ActorLabel({actor}: {actor: string}) {\n return (\n <MetadataChip\n icon=\"userLine\"\n title={`Triggered by ${actor}`}\n // Dropped once the row is two lines, where the provenance line has to stay readable on\n // a phone.\n className=\"hidden max-w-[120px] @min-[976px]:flex\"\n >\n {actor}\n </MetadataChip>\n );\n}\n\n/**\n * A ref, SHA, or handle: monospace because it is content a user copies or pattern-matches,\n * with the icon carrying the kind so the value itself never needs a written label.\n */\nfunction MetadataChip({\n icon,\n title,\n className,\n children,\n}: {\n icon: IconName;\n title: string;\n className?: string | undefined;\n children: string;\n}) {\n return (\n <span className={cn('flex min-w-0 shrink-0 items-center gap-tight', className)} title={title}>\n <Icon name={icon} className=\"size-12 shrink-0 text-foreground-neutral-muted\" aria-hidden />\n <Code as=\"span\" variant=\"label\" className=\"min-w-0 truncate\">\n {children}\n </Code>\n </span>\n );\n}\n"],"names":["TriggerSourceIcon","Icon","RelativeTime","Tooltip","TooltipContent","TooltipTrigger","Code","Text","cn","Link","useWorkflowRunDurationAccessibleLabel","WorkflowRunDurationLabel","formatWorkflowRunNumberLabel","WorkflowRunNumberLabel","getWorkflowStatusVisual","WorkflowStatusIcon","workflowRunActor","workflowRunBranchLabel","workflowRunCommitLabel","withoutWorkflowRunSelectionSearch","JOB_STATUS_STRIP_WIDTH","JobStatusStrip","jobStatusSummary","WorkflowRunRowList","runs","workspaceSlug","projectSlug","ul","className","map","run","li","WorkflowRunRow","id","duration","runAttempt","displayDuration","hasStarted","jobs","hasStartedJobExecution","durationLabel","status","statusLabel","label","runNumberLabel","branch","commit","actor","body","size","div","span","variant","bold","name","number","triggerDisplayLabel","TriggerLabel","BranchLabel","isPullRequest","startsWith","CommitLabel","ActorLabel","style","minWidth","value","createdAt","rowClassName","isTemporary","to","params","workflowRunId","search","previous","aria-label","triggerLabel","undefined","total","filter","part","Boolean","join","asChild","provider","triggerProvider","source","triggerSource","aria-hidden","as","MetadataChip","icon","title","children"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-run-summary.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-summary/workflow-run-summary.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"workflow-run-summary.d.ts","sourceRoot":"","sources":["../../../src/components/workflow-run-summary/workflow-run-summary.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAC1B,MAAM,uBAAuB,CAAC;AAa/B,MAAM,WAAW,uBAAuB;IACtC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,GAAG,EAAE,iBAAiB,CAAC;IACvB,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,aAAa,EACb,WAAW,EACX,GAAG,EACH,UAAkB,EAClB,QAAQ,EACR,YAAoB,EACpB,OAAO,EACP,aAAa,GACd,EAAE,uBAAuB,+BAiIzB"}
|
|
@@ -8,22 +8,18 @@ import { useIsTextTruncated } from '@shipfox/react-ui/hooks';
|
|
|
8
8
|
import { RelativeTime } from '@shipfox/react-ui/relative-time';
|
|
9
9
|
import { TimeTickerProvider } from '@shipfox/react-ui/time-ticker';
|
|
10
10
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@shipfox/react-ui/tooltip';
|
|
11
|
-
import {
|
|
11
|
+
import { Header, Text } from '@shipfox/react-ui/typography';
|
|
12
12
|
import { useId } from 'react';
|
|
13
13
|
import { WorkflowRunNumberLabel } from '#components/workflow-run-number-label.js';
|
|
14
|
-
import { isWorkflowRunTerminal, WORKFLOW_RUN_STATUSES
|
|
14
|
+
import { isWorkflowRunTerminal, WORKFLOW_RUN_STATUSES } from '#core/workflow-run.js';
|
|
15
15
|
import { WorkflowRunDurationLabel } from '../workflow-run-duration-label.js';
|
|
16
16
|
import { getWorkflowStatusVisual } from '../workflow-status/status-visuals.js';
|
|
17
17
|
import { WorkflowRunAttemptSwitcher } from './workflow-run-attempt-switcher.js';
|
|
18
|
-
const STATUS_BADGE_LABEL_WIDTH_CH = Math.max(...
|
|
19
|
-
...WORKFLOW_RUN_STATUSES,
|
|
20
|
-
'queued'
|
|
21
|
-
].map((status)=>getWorkflowStatusVisual(status).label.length));
|
|
18
|
+
const STATUS_BADGE_LABEL_WIDTH_CH = Math.max(...WORKFLOW_RUN_STATUSES.map((status)=>getWorkflowStatusVisual(status).label.length));
|
|
22
19
|
const RERUN_BUTTON_SURFACE_CLASS_NAME = 'bg-background-neutral-base hover:bg-background-neutral-hover active:bg-background-neutral-pressed';
|
|
23
20
|
export function WorkflowRunSummary({ workspaceSlug, projectSlug, run, cancelling = false, onCancel, rerunPending = false, onRerun, latestAttempt }) {
|
|
24
21
|
const headingId = useId();
|
|
25
|
-
const
|
|
26
|
-
const status = getWorkflowStatusVisual(display.status);
|
|
22
|
+
const status = getWorkflowStatusVisual(run.runAttempt.status);
|
|
27
23
|
const action = workflowRunActionForRun(run);
|
|
28
24
|
const hasAction = canRenderWorkflowRunAction(action, onCancel, onRerun);
|
|
29
25
|
const attemptSwitcher = latestAttempt && latestAttempt > 1 && workspaceSlug && projectSlug ? {
|
|
@@ -31,17 +27,15 @@ export function WorkflowRunSummary({ workspaceSlug, projectSlug, run, cancelling
|
|
|
31
27
|
projectSlug,
|
|
32
28
|
latestAttempt
|
|
33
29
|
} : null;
|
|
34
|
-
const displayDuration =
|
|
35
|
-
|
|
36
|
-
// and the graph already say which one it is.
|
|
37
|
-
const blockingJob = display.status === 'queued' && run.jobs.length > 1 ? workflowRunBlockingJob(run.jobs) : null;
|
|
30
|
+
const displayDuration = run.runAttempt.displayDuration;
|
|
31
|
+
const hasStarted = run.hasStartedJobExecution;
|
|
38
32
|
const { ref: headingTextRef, isTruncated: isHeadingTruncated } = useIsTextTruncated(run.name);
|
|
39
33
|
return /*#__PURE__*/ _jsx(TimeTickerProvider, {
|
|
40
34
|
intervalMs: 1000,
|
|
41
35
|
reducedMotionIntervalMs: 10_000,
|
|
42
36
|
children: /*#__PURE__*/ _jsx("section", {
|
|
43
37
|
"aria-labelledby": headingId,
|
|
44
|
-
className: "
|
|
38
|
+
className: "px-row py-row",
|
|
45
39
|
children: /*#__PURE__*/ _jsxs("div", {
|
|
46
40
|
className: "grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-cluster gap-y-inline overflow-hidden max-[480px]:grid-cols-1",
|
|
47
41
|
children: [
|
|
@@ -169,31 +163,10 @@ export function WorkflowRunSummary({ workspaceSlug, projectSlug, run, cancelling
|
|
|
169
163
|
/*#__PURE__*/ _jsx(MetadataSeparator, {}),
|
|
170
164
|
/*#__PURE__*/ _jsx(WorkflowRunDurationLabel, {
|
|
171
165
|
duration: displayDuration,
|
|
166
|
+
hasStarted: hasStarted,
|
|
172
167
|
className: "text-foreground-neutral-subtle"
|
|
173
168
|
})
|
|
174
169
|
]
|
|
175
|
-
}) : null,
|
|
176
|
-
blockingJob ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
177
|
-
children: [
|
|
178
|
-
/*#__PURE__*/ _jsx(MetadataSeparator, {}),
|
|
179
|
-
/*#__PURE__*/ _jsxs("span", {
|
|
180
|
-
className: "flex min-w-0 items-center gap-tight",
|
|
181
|
-
children: [
|
|
182
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
183
|
-
as: "span",
|
|
184
|
-
size: "xs",
|
|
185
|
-
className: "shrink-0",
|
|
186
|
-
children: "waiting on"
|
|
187
|
-
}),
|
|
188
|
-
/*#__PURE__*/ _jsx(Code, {
|
|
189
|
-
as: "span",
|
|
190
|
-
variant: "label",
|
|
191
|
-
className: "min-w-0 truncate",
|
|
192
|
-
children: blockingJob.displayName
|
|
193
|
-
})
|
|
194
|
-
]
|
|
195
|
-
})
|
|
196
|
-
]
|
|
197
170
|
}) : null
|
|
198
171
|
]
|
|
199
172
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/workflow-run-summary/workflow-run-summary.tsx"],"sourcesContent":["import {TriggerSourceIcon} from '@shipfox/client-triggers';\nimport {MetadataSeparator} from '@shipfox/client-ui';\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 {Code, Header, Text} from '@shipfox/react-ui/typography';\nimport {useId} from 'react';\nimport {WorkflowRunNumberLabel} from '#components/workflow-run-number-label.js';\nimport {\n isWorkflowRunTerminal,\n type Job,\n WORKFLOW_RUN_STATUSES,\n type WorkflowRunDetail,\n type WorkflowRunRerunMode,\n workflowRunBlockingJob,\n workflowRunDetailDisplay,\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, 'queued' as const].map(\n (status) => getWorkflowStatusVisual(status).label.length,\n ),\n);\nconst RERUN_BUTTON_SURFACE_CLASS_NAME =\n 'bg-background-neutral-base hover:bg-background-neutral-hover active:bg-background-neutral-pressed';\n\ntype WorkflowRunAction = 'cancel' | 'rerun-all' | 'rerun-menu' | 'none';\n\nexport interface WorkflowRunSummaryProps {\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n run: WorkflowRunDetail;\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 workspaceSlug,\n projectSlug,\n run,\n cancelling = false,\n onCancel,\n rerunPending = false,\n onRerun,\n latestAttempt,\n}: WorkflowRunSummaryProps) {\n const headingId = useId();\n const display = workflowRunDetailDisplay(run);\n const status = getWorkflowStatusVisual(display.status);\n const action = workflowRunActionForRun(run);\n const hasAction = canRenderWorkflowRunAction(action, onCancel, onRerun);\n const attemptSwitcher =\n latestAttempt && latestAttempt > 1 && workspaceSlug && projectSlug\n ? {workspaceSlug, projectSlug, latestAttempt}\n : null;\n const displayDuration = display.duration;\n // Named only while the run is waiting and has more than one job: with a single job the rail\n // and the graph already say which one it is.\n const blockingJob =\n display.status === 'queued' && run.jobs.length > 1 ? workflowRunBlockingJob(run.jobs) : null;\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=\"bg-background-neutral-background px-row py-row\"\n >\n <div className=\"grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-cluster gap-y-inline overflow-hidden max-[480px]:grid-cols-1\">\n <div className=\"col-start-1 row-start-1 min-w-0 max-[480px]:col-start-auto max-[480px]:row-start-auto\">\n <div className=\"flex min-w-0 items-center gap-inline\">\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 as=\"h1\" id={headingId} variant=\"h3\" className=\"min-w-0 truncate\">\n <span ref={headingTextRef} className=\"block min-w-0 truncate\">\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 </div>\n\n {hasAction ? (\n <div className=\"col-start-2 row-start-1 flex min-w-max items-center gap-inline justify-self-end max-[480px]:col-start-auto max-[480px]:row-start-auto max-[480px]:justify-self-start\">\n <WorkflowRunActionSlot\n action={action}\n cancelling={cancelling}\n onCancel={onCancel}\n rerunPending={rerunPending}\n onRerun={onRerun}\n />\n </div>\n ) : null}\n\n <div className=\"col-span-2 row-start-2 flex min-w-0 items-center gap-cluster overflow-hidden text-foreground-neutral-subtle max-[480px]:col-span-1 max-[480px]:row-start-auto\">\n {run.number !== null ? (\n <>\n <WorkflowRunNumberLabel run={run} />\n {attemptSwitcher || run.triggerDisplayLabel ? <MetadataSeparator /> : null}\n </>\n ) : null}\n\n {attemptSwitcher ? (\n <WorkflowRunAttemptSwitcher\n workspaceSlug={attemptSwitcher.workspaceSlug}\n projectSlug={attemptSwitcher.projectSlug}\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 cursor-help items-center gap-tight rounded-6 border-0 bg-transparent p-0 text-left text-foreground-neutral-subtle 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 {run.number !== null || attemptSwitcher || run.triggerDisplayLabel ? (\n <MetadataSeparator />\n ) : null}\n <RelativeTime\n value={run.runAttempt.createdAt}\n className=\"shrink-0 whitespace-nowrap text-xs leading-20 text-foreground-neutral-subtle\"\n />\n\n {displayDuration ? (\n <>\n <MetadataSeparator />\n <WorkflowRunDurationLabel\n duration={displayDuration}\n className=\"text-foreground-neutral-subtle\"\n />\n </>\n ) : null}\n\n {blockingJob ? (\n <>\n <MetadataSeparator />\n <span className=\"flex min-w-0 items-center gap-tight\">\n <Text as=\"span\" size=\"xs\" className=\"shrink-0\">\n waiting on\n </Text>\n <Code as=\"span\" variant=\"label\" className=\"min-w-0 truncate\">\n {blockingJob.displayName}\n </Code>\n </span>\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 className={RERUN_BUTTON_SURFACE_CLASS_NAME}\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 className={RERUN_BUTTON_SURFACE_CLASS_NAME}\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 canRenderWorkflowRunAction(\n action: WorkflowRunAction,\n onCancel: (() => void) | undefined,\n onRerun: ((mode: WorkflowRunRerunMode) => void) | undefined,\n): boolean {\n if (action === 'cancel') return onCancel !== undefined;\n if (action === 'rerun-all' || action === 'rerun-menu') return onRerun !== undefined;\n return false;\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"],"names":["TriggerSourceIcon","MetadataSeparator","Badge","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","useIsTextTruncated","RelativeTime","TimeTickerProvider","Tooltip","TooltipContent","TooltipTrigger","Code","Header","Text","useId","WorkflowRunNumberLabel","isWorkflowRunTerminal","WORKFLOW_RUN_STATUSES","workflowRunBlockingJob","workflowRunDetailDisplay","WorkflowRunDurationLabel","getWorkflowStatusVisual","WorkflowRunAttemptSwitcher","STATUS_BADGE_LABEL_WIDTH_CH","Math","max","map","status","label","length","RERUN_BUTTON_SURFACE_CLASS_NAME","WorkflowRunSummary","workspaceSlug","projectSlug","run","cancelling","onCancel","rerunPending","onRerun","latestAttempt","headingId","display","action","workflowRunActionForRun","hasAction","canRenderWorkflowRunAction","attemptSwitcher","displayDuration","duration","blockingJob","jobs","ref","headingTextRef","isTruncated","isHeadingTruncated","name","intervalMs","reducedMotionIntervalMs","section","aria-labelledby","className","div","variant","badge","size","span","style","width","asChild","as","id","WorkflowRunActionSlot","number","triggerDisplayLabel","button","type","aria-label","triggerLabel","provider","triggerProvider","source","triggerSource","aria-hidden","value","runAttempt","createdAt","displayName","isLoading","disabled","onClick","iconRight","align","onSelect","attempt","currentAttempt","hasFailedOrCancelledJobs","undefined","workflowRunHasJobs","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 {MetadataSeparator} from '@shipfox/client-ui';\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 {useId} from 'react';\nimport {WorkflowRunNumberLabel} from '#components/workflow-run-number-label.js';\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);\nconst RERUN_BUTTON_SURFACE_CLASS_NAME =\n 'bg-background-neutral-base hover:bg-background-neutral-hover active:bg-background-neutral-pressed';\n\ntype WorkflowRunAction = 'cancel' | 'rerun-all' | 'rerun-menu' | 'none';\n\nexport interface WorkflowRunSummaryProps {\n workspaceSlug?: string | undefined;\n projectSlug?: string | undefined;\n run: WorkflowRunDetail;\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 workspaceSlug,\n projectSlug,\n run,\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 hasAction = canRenderWorkflowRunAction(action, onCancel, onRerun);\n const attemptSwitcher =\n latestAttempt && latestAttempt > 1 && workspaceSlug && projectSlug\n ? {workspaceSlug, projectSlug, latestAttempt}\n : null;\n const displayDuration = run.runAttempt.displayDuration;\n const hasStarted = run.hasStartedJobExecution;\n const {ref: headingTextRef, isTruncated: isHeadingTruncated} =\n useIsTextTruncated<HTMLSpanElement>(run.name);\n\n return (\n <TimeTickerProvider intervalMs={1000} reducedMotionIntervalMs={10_000}>\n <section aria-labelledby={headingId} className=\"px-row py-row\">\n <div className=\"grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-center gap-x-cluster gap-y-inline overflow-hidden max-[480px]:grid-cols-1\">\n <div className=\"col-start-1 row-start-1 min-w-0 max-[480px]:col-start-auto max-[480px]:row-start-auto\">\n <div className=\"flex min-w-0 items-center gap-inline\">\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 as=\"h1\" id={headingId} variant=\"h3\" className=\"min-w-0 truncate\">\n <span ref={headingTextRef} className=\"block min-w-0 truncate\">\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 </div>\n\n {hasAction ? (\n <div className=\"col-start-2 row-start-1 flex min-w-max items-center gap-inline justify-self-end max-[480px]:col-start-auto max-[480px]:row-start-auto max-[480px]:justify-self-start\">\n <WorkflowRunActionSlot\n action={action}\n cancelling={cancelling}\n onCancel={onCancel}\n rerunPending={rerunPending}\n onRerun={onRerun}\n />\n </div>\n ) : null}\n\n <div className=\"col-span-2 row-start-2 flex min-w-0 items-center gap-cluster overflow-hidden text-foreground-neutral-subtle max-[480px]:col-span-1 max-[480px]:row-start-auto\">\n {run.number !== null ? (\n <>\n <WorkflowRunNumberLabel run={run} />\n {attemptSwitcher || run.triggerDisplayLabel ? <MetadataSeparator /> : null}\n </>\n ) : null}\n\n {attemptSwitcher ? (\n <WorkflowRunAttemptSwitcher\n workspaceSlug={attemptSwitcher.workspaceSlug}\n projectSlug={attemptSwitcher.projectSlug}\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 cursor-help items-center gap-tight rounded-6 border-0 bg-transparent p-0 text-left text-foreground-neutral-subtle 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 {run.number !== null || attemptSwitcher || run.triggerDisplayLabel ? (\n <MetadataSeparator />\n ) : null}\n <RelativeTime\n value={run.runAttempt.createdAt}\n className=\"shrink-0 whitespace-nowrap text-xs leading-20 text-foreground-neutral-subtle\"\n />\n\n {displayDuration ? (\n <>\n <MetadataSeparator />\n <WorkflowRunDurationLabel\n duration={displayDuration}\n hasStarted={hasStarted}\n className=\"text-foreground-neutral-subtle\"\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 className={RERUN_BUTTON_SURFACE_CLASS_NAME}\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 className={RERUN_BUTTON_SURFACE_CLASS_NAME}\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 canRenderWorkflowRunAction(\n action: WorkflowRunAction,\n onCancel: (() => void) | undefined,\n onRerun: ((mode: WorkflowRunRerunMode) => void) | undefined,\n): boolean {\n if (action === 'cancel') return onCancel !== undefined;\n if (action === 'rerun-all' || action === 'rerun-menu') return onRerun !== undefined;\n return false;\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"],"names":["TriggerSourceIcon","MetadataSeparator","Badge","Button","DropdownMenu","DropdownMenuContent","DropdownMenuItem","DropdownMenuTrigger","useIsTextTruncated","RelativeTime","TimeTickerProvider","Tooltip","TooltipContent","TooltipTrigger","Header","Text","useId","WorkflowRunNumberLabel","isWorkflowRunTerminal","WORKFLOW_RUN_STATUSES","WorkflowRunDurationLabel","getWorkflowStatusVisual","WorkflowRunAttemptSwitcher","STATUS_BADGE_LABEL_WIDTH_CH","Math","max","map","status","label","length","RERUN_BUTTON_SURFACE_CLASS_NAME","WorkflowRunSummary","workspaceSlug","projectSlug","run","cancelling","onCancel","rerunPending","onRerun","latestAttempt","headingId","runAttempt","action","workflowRunActionForRun","hasAction","canRenderWorkflowRunAction","attemptSwitcher","displayDuration","hasStarted","hasStartedJobExecution","ref","headingTextRef","isTruncated","isHeadingTruncated","name","intervalMs","reducedMotionIntervalMs","section","aria-labelledby","className","div","variant","badge","size","span","style","width","asChild","as","id","WorkflowRunActionSlot","number","triggerDisplayLabel","button","type","aria-label","triggerLabel","provider","triggerProvider","source","triggerSource","aria-hidden","value","createdAt","duration","isLoading","disabled","onClick","iconRight","align","onSelect","attempt","currentAttempt","hasFailedOrCancelledJobs","undefined","workflowRunHasJobs","jobs","some","job","Array","isArray"],"mappings":"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"}
|
|
@@ -26,7 +26,7 @@ import { JobExecutionTimeText } from '../job-detail/job-execution-time-text.js';
|
|
|
26
26
|
intervalMs: 1000,
|
|
27
27
|
reducedMotionIntervalMs: 10_000,
|
|
28
28
|
children: /*#__PURE__*/ _jsx("aside", {
|
|
29
|
-
className: "flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base
|
|
29
|
+
className: "flex min-h-0 w-full shrink-0 flex-col border-b border-border-neutral-base min-[768px]:w-240 min-[768px]:border-b-0 min-[768px]:border-r",
|
|
30
30
|
children: /*#__PURE__*/ _jsxs(Collapsible, {
|
|
31
31
|
open: mobileOpen,
|
|
32
32
|
onOpenChange: setMobileOpen,
|