From 6b259260a23f3ba03d25b6d83c9f2badc03aab31 Mon Sep 17 00:00:00 2001 From: Alex Tideman Date: Tue, 27 Aug 2024 12:25:39 -0500 Subject: [PATCH] Workflow Execution Page - Bring into the Light (#2269) * WIP: Pause event history UI updates on polling * Remove LabsMode and add all tabs for new WorkflowExecution page. Support desc/asc order * WIP: Vertical compact graph * Add vertical compact graph code * WIP: Vertical compact updates * Better boxes * WIP: vertical * Vertical compact looking better * Posts with flag * Remove sine wave * WIP death to compact * Remimagining it * Get the Timeline dark/light mode * Better margin * Cleanup * Add tag * Add bg to expanded row, add thin class to keep rows same height * Clean up types * Make timeline axis sticky, move to paginationTable, better borders * Get the graph in the fixed table. Expanded cell needs to be wider * Small tweaks * Use new paginated table, add maxHeight and split variant * Add back lines and dots * Add status to compact view * Get everything cleaned up, figure out compact view on open, show all group events in full mode as well * Add pending nexus operations and pending activities to the top of all view * Fix types * Make the attributes in a better order, lets call it done * Fix tests, delete unused files. * Remove old timeline helpers * Fix Local Activity label * Small color fixes * Add retry badge, and Failed/Pending only filter * Better attributes, show duration always * Add event ids on groups * Add tooltips * More cleanup * Dynamic width of history graph up to 300, other style fixes * Fix tests * Tweak dot strokeWidths, remove zoom, update snaps * Check for pending nexus attempt * Use operation and endpoint for checking isNexusPending * Bump to test * Debug Nexus stuff * Finalize * Only show pending activity/nexus for group filter * Dont use CodeBlock for row snippet, remove thin class and codemirror classes --- package.json | 4 +- pnpm-lock.yaml | 122 +--- src/lib/components/bottom-nav-settings.svelte | 18 - .../event/event-detail-pills.svelte | 40 -- .../event/event-details-full.svelte | 130 ++-- .../event/event-details-row-expanded.svelte | 108 +--- .../components/event/event-details-row.svelte | 178 +++--- .../components/event/event-empty-row.svelte | 20 +- .../event/event-group-details.svelte | 5 +- .../event/event-history-timeline-helpers.ts | 133 ---- .../event/event-history-timeline.svelte | 569 ------------------ .../components/event/event-summary-row.svelte | 269 +++++---- .../event/event-summary-table.svelte | 143 +++-- src/lib/components/event/event-summary.svelte | 203 +++++-- .../event/pending-activity-summary-row.svelte | 92 +++ .../event/pending-nexus-summary-row.svelte | 86 +++ .../lines-and-dots/constants.test.ts | 91 --- .../components/lines-and-dots/constants.ts | 99 +-- .../lines-and-dots/end-time-interval.svelte | 26 +- .../lines-and-dots/event-status-filter.svelte | 38 ++ .../lines-and-dots/event-type-filter.svelte | 52 +- .../lines-and-dots/input-and-results.svelte | 4 +- .../svg/compact-graph-row.svelte | 99 --- .../lines-and-dots/svg/compact-graph.svelte | 206 ------- .../components/lines-and-dots/svg/dot.svelte | 25 +- .../svg/event-detail-row.svelte | 142 ----- .../svg/event-details-row.svelte | 73 --- .../lines-and-dots/svg/graph-widget.svelte | 18 +- .../svg/group-details-row.svelte | 6 +- .../svg/history-graph-row-visual.svelte | 93 ++- .../svg/history-graph-row.svelte | 90 --- .../lines-and-dots/svg/history-graph.svelte | 158 ++--- .../svg/history-row-payload-detail.svelte | 37 -- .../components/lines-and-dots/svg/line.svelte | 10 +- .../components/lines-and-dots/svg/text.svelte | 34 +- .../lines-and-dots/svg/timeline-axis.svelte | 51 +- .../svg/timeline-graph-row.svelte | 6 +- .../lines-and-dots/svg/timeline-graph.svelte | 189 ++++-- .../lines-and-dots/svg/workflow-row.svelte | 40 +- .../lines-and-dots/workflow-callback.svelte | 10 +- .../lines-and-dots/workflow-error.svelte | 45 +- src/lib/components/side-nav.svelte | 18 - src/lib/holocene/code-block.svelte | 1 + src/lib/holocene/empty-state.svelte | 2 +- src/lib/holocene/icon/paths.ts | 8 + src/lib/holocene/icon/svg/flag.svelte | 10 + src/lib/holocene/icon/svg/pause.svelte | 8 + src/lib/holocene/icon/svg/play.svelte | 7 + src/lib/holocene/icon/svg/table.svelte | 14 + src/lib/holocene/pagination.svelte | 4 +- .../table/paginated-table/index.svelte | 52 +- .../table/paginated-table/paginated.svelte | 4 +- .../toggle-button/toggle-button.svelte | 28 +- src/lib/i18n/locales/en/common.ts | 2 + src/lib/i18n/locales/en/events.ts | 19 +- src/lib/layouts/workflow-header.svelte | 41 +- .../layouts/workflow-history-layout-v2.svelte | 176 ------ .../layouts/workflow-history-layout.svelte | 191 +++--- src/lib/layouts/workflow-padded-layout.svelte | 13 +- src/lib/layouts/workflow-run-layout.svelte | 79 +-- .../workflow-execution.test.ts.snap | 19 + ...flow-execution.write-disabled.test.ts.snap | 19 + src/lib/models/event-groups/get-group-name.ts | 16 +- .../models/event-groups/group-events.test.ts | 1 + .../get-event-categorization.test.ts | 17 + .../event-history/get-event-categorization.ts | 20 +- src/lib/models/workflow-execution.ts | 4 +- src/lib/pages/workflow-history-compact.svelte | 5 - .../pages/workflow-history-event-group.svelte | 53 +- src/lib/pages/workflow-history-event.svelte | 30 +- src/lib/pages/workflow-history-feed.svelte | 5 - src/lib/stores/events.ts | 5 +- src/lib/stores/filters.ts | 1 + src/lib/theme/plugin.ts | 4 + src/lib/types/events.ts | 9 +- src/lib/types/index.ts | 2 + src/lib/types/workflows.ts | 3 + src/lib/utilities/format-camel-case.ts | 1 + src/lib/utilities/format-event-attributes.ts | 21 +- src/lib/utilities/get-failed-or-pending.ts | 39 ++ .../get-single-attribute-for-event.test.ts | 37 +- .../get-single-attribute-for-event.ts | 88 ++- src/lib/utilities/is-pending-activity.ts | 12 +- src/lib/utilities/pending-activities.ts | 29 +- .../[run]/history/compact/+page.svelte | 32 +- .../[run]/history/feed/+page.svelte | 30 +- .../[workflow]/[run]/history/+page.svelte | 22 +- tests/e2e/workflows.spec.ts | 9 +- tests/integration/storageState.json | 12 +- .../workflow-event-history.spec.ts | 43 +- 90 files changed, 1836 insertions(+), 3191 deletions(-) delete mode 100644 src/lib/components/event/event-detail-pills.svelte delete mode 100644 src/lib/components/event/event-history-timeline-helpers.ts delete mode 100644 src/lib/components/event/event-history-timeline.svelte create mode 100644 src/lib/components/event/pending-activity-summary-row.svelte create mode 100644 src/lib/components/event/pending-nexus-summary-row.svelte delete mode 100644 src/lib/components/lines-and-dots/constants.test.ts create mode 100644 src/lib/components/lines-and-dots/event-status-filter.svelte delete mode 100644 src/lib/components/lines-and-dots/svg/compact-graph-row.svelte delete mode 100644 src/lib/components/lines-and-dots/svg/compact-graph.svelte delete mode 100644 src/lib/components/lines-and-dots/svg/event-detail-row.svelte delete mode 100644 src/lib/components/lines-and-dots/svg/event-details-row.svelte delete mode 100644 src/lib/components/lines-and-dots/svg/history-graph-row.svelte delete mode 100644 src/lib/components/lines-and-dots/svg/history-row-payload-detail.svelte create mode 100644 src/lib/holocene/icon/svg/flag.svelte create mode 100644 src/lib/holocene/icon/svg/pause.svelte create mode 100644 src/lib/holocene/icon/svg/play.svelte create mode 100644 src/lib/holocene/icon/svg/table.svelte delete mode 100644 src/lib/layouts/workflow-history-layout-v2.svelte delete mode 100644 src/lib/pages/workflow-history-compact.svelte delete mode 100644 src/lib/pages/workflow-history-feed.svelte create mode 100644 src/lib/utilities/get-failed-or-pending.ts diff --git a/package.json b/package.json index cd0b95d5d..7711b0558 100644 --- a/package.json +++ b/package.json @@ -109,12 +109,10 @@ "mdast-util-to-hast": "^13.2.0", "monaco-editor": "^0.50.0", "remark-stringify": "^10.0.3", - "sanitize-html": "^2.12.1", "tailwind-merge": "^1.14.0", "unist-util-remove": "^4.0.0", "url-pattern": "^1.0.3", - "uuid": "^9.0.0", - "vis-timeline": "^7.7.3" + "uuid": "^9.0.0" }, "devDependencies": { "@axe-core/playwright": "^4.9.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eaa639cea..4d656ba1d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,9 +104,6 @@ dependencies: remark-stringify: specifier: ^10.0.3 version: 10.0.3 - sanitize-html: - specifier: ^2.12.1 - version: 2.12.1 tailwind-merge: specifier: ^1.14.0 version: 1.14.0 @@ -119,9 +116,6 @@ dependencies: uuid: specifier: ^9.0.0 version: 9.0.0 - vis-timeline: - specifier: ^7.7.3 - version: 7.7.3(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)(keycharm@0.4.0)(moment@2.30.1)(propagating-hammerjs@2.0.1)(uuid@9.0.0)(vis-data@7.1.9)(vis-util@5.0.7)(xss@1.0.14) devDependencies: '@axe-core/playwright': @@ -2530,13 +2524,6 @@ packages: engines: {node: '>=10.0.0'} dev: true - /@egjs/hammerjs@2.0.17: - resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} - engines: {node: '>=0.8.0'} - dependencies: - '@types/hammerjs': 2.0.45 - dev: false - /@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0): resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} peerDependencies: @@ -5576,10 +5563,6 @@ packages: '@types/node': 18.15.3 dev: true - /@types/hammerjs@2.0.45: - resolution: {integrity: sha512-qkcUlZmX6c4J8q45taBKTL3p+LbITgyx7qhlPYOdOHZB7B31K0mXbP5YA7i7SgDeEGuI9MnumiKPEMrxg8j3KQ==} - dev: false - /@types/hast@2.3.5: resolution: {integrity: sha512-SvQi0L/lNpThgPoleH53cdjB3y9zpLlVjRbqB3rH8hx1jiRSBGAhyjV3H+URFjNVRqt2EdYNrbZE5IsGlNfpRg==} dependencies: @@ -7426,6 +7409,7 @@ packages: /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: true /commander@3.0.2: resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} @@ -7460,10 +7444,6 @@ packages: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} dev: true - /component-emitter@1.3.1: - resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} - dev: false - /compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -7684,10 +7664,6 @@ packages: hasBin: true dev: true - /cssfilter@0.0.10: - resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} - dev: false - /cssnano-preset-default@5.2.13(postcss@8.4.31): resolution: {integrity: sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==} engines: {node: ^10 || ^12 || >=14.0} @@ -7925,6 +7901,7 @@ packages: /deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + dev: true /default-browser-id@3.0.0: resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} @@ -8154,6 +8131,7 @@ packages: domelementtype: 2.3.0 domhandler: 5.0.3 entities: 4.4.0 + dev: true /domelementtype@1.3.1: resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} @@ -8161,6 +8139,7 @@ packages: /domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: true /domexception@4.0.0: resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} @@ -8194,6 +8173,7 @@ packages: engines: {node: '>= 4'} dependencies: domelementtype: 2.3.0 + dev: true /domutils@1.7.0: resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==} @@ -8216,6 +8196,7 @@ packages: dom-serializer: 2.0.0 domelementtype: 2.3.0 domhandler: 5.0.3 + dev: true /dotenv-expand@10.0.0: resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} @@ -8949,6 +8930,7 @@ packages: /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + dev: true /escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} @@ -10506,6 +10488,7 @@ packages: domhandler: 5.0.3 domutils: 3.0.1 entities: 4.4.0 + dev: true /http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} @@ -10879,6 +10862,7 @@ packages: /is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} + dev: true /is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -11871,10 +11855,6 @@ packages: resolution: {integrity: sha512-7n6wXq4gNgBELfDCpzKc+mRrZFs7D+wgfF5WRFLNAr4DA/qtr9Js8uOAVAfHhuLMfAcQ0pRKqbpjx+TcJVdE1Q==} dev: false - /keycharm@0.4.0: - resolution: {integrity: sha512-TyQTtsabOVv3MeOpR92sIKk/br9wxS+zGj4BG7CR8YbK4jM3tyIBaF0zhzeBUMx36/Q/iQLOKKOT+3jOQtemRQ==} - dev: false - /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -13057,10 +13037,6 @@ packages: engines: {node: '>= 8'} dev: true - /moment@2.30.1: - resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} - dev: false - /monaco-editor@0.50.0: resolution: {integrity: sha512-8CclLCmrRRh+sul7C08BmPBP3P8wVWfBHomsTcndxg5NRCEPfu/mc2AGU8k37ajjDVXcXFc12ORAMUkmk+lkFA==} dev: false @@ -13113,6 +13089,7 @@ packages: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + dev: true /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -13600,10 +13577,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /parse-srcset@1.0.2: - resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} - dev: false - /parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} dev: true @@ -13722,6 +13695,7 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -14273,6 +14247,7 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.2.0 + dev: true /prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} @@ -14424,14 +14399,6 @@ packages: sisteransi: 1.0.5 dev: true - /propagating-hammerjs@2.0.1(@egjs/hammerjs@2.0.17): - resolution: {integrity: sha512-PH3zG5whbSxMocphXJzVtvKr+vWAgfkqVvtuwjSJ/apmEACUoiw6auBAT5HYXpZOR0eGcTAfYG5Yl8h91O5Elg==} - peerDependencies: - '@egjs/hammerjs': ^2.0.17 - dependencies: - '@egjs/hammerjs': 2.0.17 - dev: false - /property-information@6.2.0: resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==} @@ -15188,17 +15155,6 @@ packages: rimraf: 2.7.1 dev: true - /sanitize-html@2.12.1: - resolution: {integrity: sha512-Plh+JAn0UVDpBRP/xEjsk+xDCoOvMBwQUf/K+/cBAVuTbtX8bj2VB7S1sL1dssVpykqp0/KPSesHrqXtokVBpA==} - dependencies: - deepmerge: 4.3.1 - escape-string-regexp: 4.0.0 - htmlparser2: 8.0.1 - is-plain-object: 5.0.0 - parse-srcset: 1.0.2 - postcss: 8.4.33 - dev: false - /saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -17066,51 +17022,6 @@ packages: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - /vis-data@7.1.9(uuid@9.0.0)(vis-util@5.0.7): - resolution: {integrity: sha512-COQsxlVrmcRIbZMMTYwD+C2bxYCFDNQ2EHESklPiInbD/Pk3JZ6qNL84Bp9wWjYjAzXfSlsNaFtRk+hO9yBPWA==} - peerDependencies: - uuid: ^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - vis-util: ^5.0.1 - dependencies: - uuid: 9.0.0 - vis-util: 5.0.7(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1) - dev: false - - /vis-timeline@7.7.3(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1)(keycharm@0.4.0)(moment@2.30.1)(propagating-hammerjs@2.0.1)(uuid@9.0.0)(vis-data@7.1.9)(vis-util@5.0.7)(xss@1.0.14): - resolution: {integrity: sha512-hGMzTttdOFWaw1PPlJuCXU2/4UjnsIxT684Thg9fV6YU1JuKZJs3s3BrJgZ4hO3gu5i1hsMe1YIi96o+eNT0jg==} - peerDependencies: - '@egjs/hammerjs': ^2.0.0 - component-emitter: ^1.3.0 - keycharm: ^0.2.0 || ^0.3.0 || ^0.4.0 - moment: ^2.24.0 - propagating-hammerjs: ^1.4.0 || ^2.0.0 - uuid: ^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - vis-data: ^6.3.0 || ^7.0.0 - vis-util: ^5.0.1 - xss: ^1.0.0 - dependencies: - '@egjs/hammerjs': 2.0.17 - component-emitter: 1.3.1 - keycharm: 0.4.0 - moment: 2.30.1 - propagating-hammerjs: 2.0.1(@egjs/hammerjs@2.0.17) - uuid: 9.0.0 - vis-data: 7.1.9(uuid@9.0.0)(vis-util@5.0.7) - vis-util: 5.0.7(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1) - xss: 1.0.14 - dev: false - - /vis-util@5.0.7(@egjs/hammerjs@2.0.17)(component-emitter@1.3.1): - resolution: {integrity: sha512-E3L03G3+trvc/X4LXvBfih3YIHcKS2WrP0XTdZefr6W6Qi/2nNCqZfe4JFfJU6DcQLm6Gxqj2Pfl+02859oL5A==} - engines: {node: '>=8'} - peerDependencies: - '@egjs/hammerjs': ^2.0.0 - component-emitter: ^1.3.0 || ^2.0.0 - dependencies: - '@egjs/hammerjs': 2.0.17 - component-emitter: 1.3.1 - dev: false - /vite-node@0.23.4(@types/node@18.15.3): resolution: {integrity: sha512-8VuDGwTWIvwPYcbw8ZycMlwAwqCmqZfLdFrDK75+o+6bWYpede58k6AAXN9ioU+icW82V4u1MzkxLVhhIoQ9xA==} engines: {node: '>=v14.16.0'} @@ -17636,15 +17547,6 @@ packages: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} dev: true - /xss@1.0.14: - resolution: {integrity: sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==} - engines: {node: '>= 0.10.0'} - hasBin: true - dependencies: - commander: 2.20.3 - cssfilter: 0.0.10 - dev: false - /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} diff --git a/src/lib/components/bottom-nav-settings.svelte b/src/lib/components/bottom-nav-settings.svelte index af8d144e8..ae7b85726 100644 --- a/src/lib/components/bottom-nav-settings.svelte +++ b/src/lib/components/bottom-nav-settings.svelte @@ -8,7 +8,6 @@ import { translate } from '$lib/i18n/translate'; import { authUser } from '$lib/stores/auth-user'; import { dataEncoder } from '$lib/stores/data-encoder'; - import { labsMode } from '$lib/stores/labs-mode'; import { useDarkMode } from '$lib/utilities/dark-mode'; import { viewDataEncoderSettings } from './data-encoder-settings.svelte'; @@ -17,15 +16,6 @@ export let logout: () => void; export let userEmaiLink = ''; - $: labsHoverText = `${translate('common.labs')} ${ - $labsMode - ? `${translate('common.on')} - ${translate('common.experimental')}` - : translate('common.off') - }`; - $: labsText = `${translate('common.labs')} ${ - $labsMode ? translate('common.on') : translate('common.off') - }`; - $: hasCodecServer = $dataEncoder?.endpoint; const onCodecServerClick = () => { @@ -59,14 +49,6 @@ label={$useDarkMode ? translate('common.night') : translate('common.day')} icon={$useDarkMode ? 'moon' : 'sun'} /> - ($labsMode = !$labsMode)} - tooltip={labsHoverText} - label={labsText} - icon="labs" - active={$labsMode} - data-testid="labs-mode-button" - /> {#if $authUser.accessToken}
- import { createEventDispatcher } from 'svelte'; - - import PillContainer from '$lib/holocene/pill-container/pill-container.svelte'; - import Pill from '$lib/holocene/pill-container/pill.svelte'; - import { translate } from '$lib/i18n/translate'; - import type { AttributeGrouping } from '$lib/utilities/format-event-attributes'; - import { attributeGroupingProperties } from '$lib/utilities/format-event-attributes'; - - export let attributeGrouping: AttributeGrouping; - - const dispatch = createEventDispatcher(); - - $: pillCount = Object.values(attributeGrouping).reduce((count, value) => { - if (value.length) { - count += 1; - } - return count; - }, 0); - - -{#if pillCount > 1} -
- - {#each Object.entries(attributeGrouping) as [key, value] (key)} - {#if value.length} - dispatch('pillChange', { key })} - >{translate(attributeGroupingProperties[key].label)} - {/if} - {/each} - -
-{/if} - - diff --git a/src/lib/components/event/event-details-full.svelte b/src/lib/components/event/event-details-full.svelte index 6a79f8d41..979f0201d 100644 --- a/src/lib/components/event/event-details-full.svelte +++ b/src/lib/components/event/event-details-full.svelte @@ -1,57 +1,99 @@ -{#if compact && isEventGroup(event)} -
- -
- - {#each eventDetails as [key, value] (key)} - {#if attributeGrouping[activePill]?.includes(key)} - - {/if} +{#if showEventGroup} +
+
+ {#each group.eventList as groupEvent} + {@const attributes = formatAttributes(groupEvent)} + {@const details = Object.entries(attributes)} +
+
+
+ {groupEvent.id} + {spaceBetweenCapitalLetters(groupEvent.name)} +
+
+ {formatDate(groupEvent.eventTime, $timeFormat, { + relative: $relativeTime, + })} +
+
+ {#each details as [key, value] (key)} + + {/each} +
{/each} + {#if pendingEvent} + {@const details = Object.entries(pendingEvent)} +
+
+
+ Pending {isPendingActivity(pendingEvent) + ? 'Activity' + : 'Nexus Operation'} +
+
+ {#each details as [key, value] (key)} + + {/each} +
+ {/if}
+ {#if childWorkflowEvent} + + {/if}
-{:else} -
- - {#each eventDetails as [key, value] (key)} - {#if attributeGrouping[activePill]?.includes(key)} - - {/if} - {/each} +{:else if event} + {@const attributes = formatAttributes(event)} + {@const details = Object.entries(attributes)} +
+
+ {#each details as [key, value] (key)} + + {/each} +
{/if} + + diff --git a/src/lib/components/event/event-details-row-expanded.svelte b/src/lib/components/event/event-details-row-expanded.svelte index b3831d7fe..73fb299cd 100644 --- a/src/lib/components/event/event-details-row-expanded.svelte +++ b/src/lib/components/event/event-details-row-expanded.svelte @@ -2,7 +2,6 @@ import { page } from '$app/stores'; import CodeBlock from '$lib/holocene/code-block.svelte'; - import Copyable from '$lib/holocene/copyable/index.svelte'; import Link from '$lib/holocene/link.svelte'; import { translate } from '$lib/i18n/translate'; import { format } from '$lib/utilities/format-camel-case'; @@ -11,7 +10,6 @@ getCodeBlockValue, getStackTrace, shouldDisplayAsExecutionLink, - shouldDisplayAsPlainText, shouldDisplayAsTaskQueueLink, shouldDisplayChildWorkflowLink, } from '$lib/utilities/get-single-attribute-for-event'; @@ -23,7 +21,7 @@ import PayloadDecoder from './payload-decoder.svelte'; export let key: string; - export let value: string | Record; + export let value: string | number | Record; export let attributes: CombinedAttributes; export let inline = false; @@ -32,19 +30,15 @@ $: stackTrace = getStackTrace(codeBlockValue); -
+
{#if typeof value === 'object'} -
-
+
+

{format(key)}

{#if value?.payloads} {#if stackTrace && !inline} -
+

{translate('workflows.call-stack-tab')}

{format(key)}

-
- + - - {value} - - + {value} +
{:else if shouldDisplayChildWorkflowLink(key, attributes)}

{format(key)}

-
- + - - {value} - - + {value} +
{:else if shouldDisplayAsTaskQueueLink(key)}

{format(key)}

-
- - - {value} - - +
+ + {value} +
{:else}

{format(key)}

- {value} + {value}

{/if}
diff --git a/src/lib/components/event/event-details-row.svelte b/src/lib/components/event/event-details-row.svelte index 05ca89c54..19af8881f 100644 --- a/src/lib/components/event/event-details-row.svelte +++ b/src/lib/components/event/event-details-row.svelte @@ -1,7 +1,6 @@ -
- {#if typeof value === 'object'} -
-

+{#if key} +

+ {#if showKey} +

{format(key)}

- - - -
- {:else if shouldDisplayAsExecutionLink(key)} -
-

{format(key)}

-
- - + +
+
{decodedValue}
+
+
+
+ {:else if shouldDisplayAsExecutionLink(key)} +
+
+ - {value} - - + + {value} + + +
-
- {:else if shouldDisplayChildWorkflowLink(key, attributes)} -
-

{format(key)}

-
- - +
+ - {value} - - + + {value} + + +
-
- {:else if shouldDisplayAsTaskQueueLink(key)} -
-

{format(key)}

-
- - +
+ - {value} - - + + {value} + + +
-
- {:else} -
-

{format(key)}

-

- {value} -

-
- {/if} -
+ {:else} +
+

+ {value} +

+
+ {/if} +
+{/if} diff --git a/src/lib/components/event/event-empty-row.svelte b/src/lib/components/event/event-empty-row.svelte index aa2a0a825..2bced3ab2 100644 --- a/src/lib/components/event/event-empty-row.svelte +++ b/src/lib/components/event/event-empty-row.svelte @@ -8,18 +8,8 @@ export let content = translate('events.empty-state-description'); - - - {#if loading} - - {:else} - - {/if} - - - - +{#if loading} + +{:else} + +{/if} diff --git a/src/lib/components/event/event-group-details.svelte b/src/lib/components/event/event-group-details.svelte index 5f7cde587..03c16e0ff 100644 --- a/src/lib/components/event/event-group-details.svelte +++ b/src/lib/components/event/event-group-details.svelte @@ -23,15 +23,14 @@ {#each [...eventGroup.events].reverse() as [id, eventInGroup] (id)} onGroupClick(id)} > - - + {:else} + - - - {#if !expanded} - - {/if} - - {#if expanded} - - + {/if} diff --git a/src/lib/components/event/event-summary-table.svelte b/src/lib/components/event/event-summary-table.svelte index 59a677eda..1537d10ef 100644 --- a/src/lib/components/event/event-summary-table.svelte +++ b/src/lib/components/event/event-summary-table.svelte @@ -1,61 +1,106 @@ -
- +

({ - stackSubgroups: true, - maxHeight, - min: startOfMinute(new Date(workflow.startTime)), - max: workflow?.endTime - ? endOfMinute(new Date(workflow?.endTime)) - : Date.now(), - moment: function (date) { - return moment(date).utcOffset(offset); - }, - horizontalScroll: true, - verticalScroll: true, - zoomKey: 'ctrlKey' as TimelineOptionsZoomKey, - orientation: { - axis: 'both', - item: 'center', - }, - tooltip: { - delay: 0, - overflowMethod: 'flip' as TimelineOptionsTooltipOverflow, - followMouse: false, - template: tooltipTemplate, - }, - rollingMode: { - follow: false, - }, - format: { - majorLabels: { - millisecond: 'D MMMM HH:mm:ss', - second: 'D MMMM HH:mm', - minute: 'ddd D MMMM', - hour: 'ddd D MMMM', - weekday: 'MMMM YYYY', - day: 'MMMM YYYY', - week: 'MMMM YYYY', - month: 'YYYY', - year: '', - }, - }, - xss: { - disabled: true, - filterOptions: { - whiteList: { - div: ['class'], - }, - }, - }, -}); - -export const tooltipTemplate = (item, _parsedItems): string => { - if (!item?.data?.eventList) return workflowExecutionTooltipTemplate(item); - if (item?.data.eventList.length === 1) - return singleEventTooltipTemplate(item); - return groupEventTooltipTemplate(item); -}; - -const workflowExecutionTooltipTemplate = (item): string => { - return `

-
Start
-
${formatDate(item.start, get(timeFormat), { - relative: get(relativeTime), - })} -
-
-
-
End
-
${formatDate(item.end, get(timeFormat), { - relative: get(relativeTime), - })}
-
-
Duration
${formatDistanceAbbreviated( - { - start: item.start, - end: item.end, - includeMilliseconds: true, - }, - )}
-
-
`; -}; - -const singleEventTooltipTemplate = (item): string => { - return `
-
Event Time
-
${formatDate(item.start, get(timeFormat), { - relative: get(relativeTime), - })} -
-
-
- `; -}; - -const groupEventTooltipTemplate = (item): string => { - return `
-
Start
-
${formatDate(item.start, get(timeFormat), { - relative: get(relativeTime), - })} -
-
-
-
End
-
${formatDate(item.end, get(timeFormat), { - relative: get(relativeTime), - })}
-
-
Duration
${formatDistanceAbbreviated( - { - start: item.start, - end: item.end, - includeMilliseconds: true, - }, - )}
-
-
`; -}; diff --git a/src/lib/components/event/event-history-timeline.svelte b/src/lib/components/event/event-history-timeline.svelte deleted file mode 100644 index 898676f0c..000000000 --- a/src/lib/components/event/event-history-timeline.svelte +++ /dev/null @@ -1,569 +0,0 @@ - - -
-
-
- - timeline?.zoomIn(1)} - >+ - timeline?.zoomOut(1)}>- - timeline?.focus('workflow')}>Fit - -
-
-
- {#if !timeline} - - {/if} -
-
- - diff --git a/src/lib/components/event/event-summary-row.svelte b/src/lib/components/event/event-summary-row.svelte index f2cdf29bb..6fd00fc12 100644 --- a/src/lib/components/event/event-summary-row.svelte +++ b/src/lib/components/event/event-summary-row.svelte @@ -1,32 +1,43 @@
- - - {event.id} - + {#if !compact} + + + {event.id} + + + {/if} + +
+ +

+ {displayName} +

+
+ {#if pendingAttempt} +
+ + {pendingAttempt} + {#if hasPendingActivity} + / {hasPendingActivity.maximumAttempts || '∞'} + {/if} +
+ {/if} +
+
-
- {#if showElapsedTimeDiff} -

- {#if elapsedTime} - {descending ? '-' : '+'}{elapsedTime} - {/if} -

+
+ {#if isEventGroup(event)} +
+
+ {#each event.eventList as groupEvent} + + {groupEvent.id} + + {/each} +
{#if duration && duration !== '0ms'} -
+
-

+

{duration}

{/if} - {:else} -

- {formatDate(event?.eventTime, $timeFormat, { +

+ {:else} +
+

+ {#if elapsedTime} + +{elapsedTime} + {/if} +

+

+ {formatDate(currentEvent?.eventTime, $timeFormat, { relative: $relativeTime, })}

- {/if} -
-
-
-
- {#if compact && failure} - - {/if} - {#if compact && canceled} - - {/if} - {#if compact && terminated} - - {/if} -
-
-

- {isEventGroup(event) - ? event.displayName - : isLocalActivityMarkerEvent(event) - ? 'LocalActivity' - : event.name} -

- {#if expanded} -
- -
- {/if}
-
+ {/if}
-
-
-
-
- -
-
-
- +
+
- - - - - - - -
{translate('workflows.event-history')}
- - - -
- -
-
+ translate('common.go-to-page', { page })} + {updating} + items={filteredForStatus(items)} + let:visibleItems + variant="split" + maxHeight="calc(100vh - 200px)" +> + {#if !compact} + + {/if} +
+ {#each visibleItems as event, index} + {#if isEventGroup(event)} + + {:else if isPendingActivity(event)} + + isPendingActivity(event) && g?.pendingActivity?.id === event.id, + )} + {expandAll} + /> + {:else if isPendingNexusOperation(event)} + + isPendingNexusOperation(event) && + g?.pendingNexusOperation?.scheduledEventId === + event.scheduledEventId, + )} + {expandAll} + /> + {:else} + isEvent(event) && g.eventIds.has(event.id))} + {compact} + {expandAll} + {initialItem} + /> + {/if} + {:else} + + {/each} +
+
diff --git a/src/lib/components/event/event-summary.svelte b/src/lib/components/event/event-summary.svelte index e2588bbd7..07afee949 100644 --- a/src/lib/components/event/event-summary.svelte +++ b/src/lib/components/event/event-summary.svelte @@ -1,82 +1,161 @@ - - - {#each visibleItems as event, index (`${event.id}-${event.timestamp}`)} - setActiveRowIndex(index)} - /> - {:else} - - {/each} - - +
+
+
+ + All + Compact + JSON + +
+
+ {#if $eventViewType !== 'json'} + + {reverseSort ? 'Desc' : 'Asc'} + + + {/if} + + ($pauseLiveUpdates = !$pauseLiveUpdates)} + /> + (showDownloadPrompt = true)} + /> + +
+
+ {#if $eventViewType !== 'json'} +
+ + +
+ {/if} +
+{#if $eventViewType === 'json'} +
+ +
+{:else} +
+ +
+{/if} + diff --git a/src/lib/components/event/pending-activity-summary-row.svelte b/src/lib/components/event/pending-activity-summary-row.svelte new file mode 100644 index 000000000..fe3d18891 --- /dev/null +++ b/src/lib/components/event/pending-activity-summary-row.svelte @@ -0,0 +1,92 @@ + + + + + + {event.activityId} + + + +
+ +

+ Pending Activity +

+
+ + {event.attempt} / {event.maximumAttempts || '∞'} +
+
+ + +{#if expanded} + + + + + +{/if} + + diff --git a/src/lib/components/event/pending-nexus-summary-row.svelte b/src/lib/components/event/pending-nexus-summary-row.svelte new file mode 100644 index 000000000..c580e8069 --- /dev/null +++ b/src/lib/components/event/pending-nexus-summary-row.svelte @@ -0,0 +1,86 @@ + + + + + + {event.scheduledEventId || ''} + + + +
+
+ +

Pending Nexus Operation

+ {#if event.attempt} +
+ + {event.attempt} +
+ {/if} +
+
+ + + +{#if expanded} + + + + + +{/if} + + diff --git a/src/lib/components/lines-and-dots/constants.test.ts b/src/lib/components/lines-and-dots/constants.test.ts deleted file mode 100644 index ff3b71fbe..000000000 --- a/src/lib/components/lines-and-dots/constants.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { describe, expect, test } from 'vitest'; - -import { - CompactConfig, - HistoryConfig, - TimelineConfig, - timelineTextPosition, -} from './constants'; - -describe('timelineTextPosition', () => { - test('should calculate the correct text position for Compact', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([17, 85], 100, 1000, false, CompactConfig); - expect(textPosition).toEqual([121, 100]); - expect(textIndex).toEqual(1); - expect(textAnchor).toEqual('start'); - expect(backdrop).toEqual(false); - }); - test('should calculate the correct text position for Timline', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([17, 85], 100, 1000, false, TimelineConfig); - expect(textPosition).toEqual([103, 100]); - expect(textIndex).toEqual(1); - expect(textAnchor).toEqual('start'); - expect(backdrop).toEqual(false); - }); - test('should calculate the correct text position for History', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([17, 85], 100, 1000, false, HistoryConfig); - expect(textPosition).toEqual([94, 100]); - expect(textIndex).toEqual(1); - expect(textAnchor).toEqual('start'); - expect(backdrop).toEqual(false); - }); - test('should calculate the correct middle text position with backdrop for Compact with wide range of points', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([37, 99, 490], 200, 500, false, CompactConfig); - expect(textPosition).toEqual([135, 200]); - expect(textIndex).toEqual(1); - expect(textAnchor).toEqual('start'); - expect(backdrop).toEqual(true); - }); - test('should calculate the correct start text position for Compact with wide range of points', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([37, 99, 113], 500, 1200, false, CompactConfig); - expect(textPosition).toEqual([149, 500]); - expect(textIndex).toEqual(2); - expect(textAnchor).toEqual('start'); - expect(backdrop).toEqual(false); - }); - test('should calculate the correct end text position for Compact with wide range of points', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([983, 1000, 1119], 500, 1200, false, CompactConfig); - expect(textPosition).toEqual([947, 500]); - expect(textIndex).toEqual(0); - expect(textAnchor).toEqual('end'); - expect(backdrop).toEqual(false); - }); - test('should calculate the correct midde text position for Pending with single point', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([281], 500, 1200, true, CompactConfig); - expect(textPosition).toEqual([317, 500]); - expect(textIndex).toEqual(0); - expect(textAnchor).toEqual('start'); - expect(backdrop).toEqual(true); - }); - test('should calculate the correct midde text position for Pending with double points', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([281, 1000], 500, 1200, true, CompactConfig); - expect(textPosition).toEqual([317, 500]); - expect(textIndex).toEqual(0); - expect(textAnchor).toEqual('start'); - expect(backdrop).toEqual(true); - }); - test('should calculate the correct midde text position for Pending with double points close to each other', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([281, 312], 500, 1200, true, CompactConfig); - expect(textPosition).toEqual([348, 500]); - expect(textIndex).toEqual(1); - expect(textAnchor).toEqual('start'); - expect(backdrop).toEqual(true); - }); - test('should calculate the correct end text position for Pending with double points close to each other at the end', () => { - const { textPosition, textIndex, textAnchor, backdrop } = - timelineTextPosition([1123, 1187], 500, 1200, true, CompactConfig); - expect(textPosition).toEqual([1087, 500]); - expect(textIndex).toEqual(0); - expect(textAnchor).toEqual('end'); - expect(backdrop).toEqual(false); - }); -}); diff --git a/src/lib/components/lines-and-dots/constants.ts b/src/lib/components/lines-and-dots/constants.ts index 988451041..de6cf2ea0 100644 --- a/src/lib/components/lines-and-dots/constants.ts +++ b/src/lib/components/lines-and-dots/constants.ts @@ -3,12 +3,14 @@ import type { EventGroup, EventGroups, } from '$lib/models/event-groups/event-groups'; +import { isEvent } from '$lib/models/event-history'; +import type { EventSortOrder } from '$lib/stores/event-view'; import type { EventClassification, EventTypeCategory, PendingActivity, WorkflowEvent, - WorkflowEvents, + WorkflowEventWithPending, } from '$lib/types/events'; import type { WorkflowStatus } from '$lib/types/workflows'; import { @@ -16,7 +18,10 @@ import { formatGroupAttributes, formatPendingAttributes, } from '$lib/utilities/format-event-attributes'; -import { isAssociatedPendingActivity } from '$lib/utilities/pending-activities'; +import { + getGroupForEventOrPendingEvent, + isAssociatedPendingActivity, +} from '$lib/utilities/pending-activities'; export const DetailsChildTimelineHeight = 200; @@ -31,24 +36,17 @@ const baseRadius = 6; export const minCompactWidth = 200; -export const CompactConfig: GraphConfig = { - height: baseRadius * 9, - gutter: baseRadius * 7, - radius: baseRadius * 4, - fontSizeRatio: baseRadius * 4, -}; - export const TimelineConfig: GraphConfig = { height: baseRadius * 5, - gutter: baseRadius * 4, + gutter: baseRadius * 8, radius: baseRadius * 2, fontSizeRatio: baseRadius * 4, }; export const HistoryConfig: GraphConfig = { - height: baseRadius * 5, + height: 32, gutter: baseRadius * 2, - radius: baseRadius * 1, + radius: 4, fontSizeRatio: baseRadius * 4, }; @@ -150,10 +148,10 @@ const isConsecutiveGroup = (group: EventGroup): boolean => { }; const getOpenGroups = ( - event: WorkflowEvent | PendingActivity, + event: WorkflowEventWithPending, groups: EventGroups, ): number => { - const group = groups.find((g) => g.eventIds.has(event.id)); + const group = getGroupForEventOrPendingEvent(groups, event); if (group.level !== undefined) return group.level; const pendingGroups = groups @@ -178,64 +176,14 @@ const getOpenGroups = ( return group.level; }; -const allEventsInGroupHeight = ( - id: string, - history: WorkflowEvents, - groups: EventGroups, -): number => { - const event = history.find((event) => event.id === id); - const group = groups.find((group) => group.eventIds.has(id)); - if (group) { - return group.eventList.reduce( - (sum, event) => - (sum += getEventDetailsBoxHeight(event, group.pendingActivity)), - 0, - ); - } - if (event) return getEventDetailsBoxHeight(event); - return 0; -}; - -export const activeEventsHeightAboveGroup = ( - activeEvents: string[], - event: WorkflowEvent, - history: WorkflowEvents, - groups: EventGroups, -) => { - return activeEvents - .filter((id) => parseInt(id) < parseInt(event.id)) - .map((id) => { - return allEventsInGroupHeight(id, history, groups); - }) - .reduce((acc, height) => acc + height, 0); -}; - -export const getVisualWidth = ( - history: WorkflowEvents, - groups: EventGroups, - maxWidth: number, -) => { - let maxOffset = 0; - if (!history.length) return maxWidth; - history.forEach((event) => { - const group = groups.find((g) => g.eventIds.has(event.id)); - if (group) { - const offset = getOpenGroups(event, groups); - if (offset > maxOffset) { - maxOffset = offset; - } - } - }); - return Math.min(maxWidth, (maxOffset + 2) * 2 * HistoryConfig.radius); -}; - export const getNextDistanceAndOffset = ( - history: WorkflowEvents, - event: WorkflowEvent, + history: WorkflowEventWithPending[], + event: WorkflowEventWithPending, groups: EventGroups, height: number, + sort: EventSortOrder, ): { nextDistance: number; offset: number } => { - const group = groups.find((g) => g.eventIds.has(event.id)); + const group = getGroupForEventOrPendingEvent(groups, event); let nextDistance = 0; let offset = 0; @@ -247,9 +195,9 @@ export const getNextDistanceAndOffset = ( return { nextDistance, offset }; } - const currentIndex = group.eventList.indexOf(event); - const nextEvent = group.eventList[currentIndex + 1]; - if (event.category !== 'workflow') { + const currentIndex = isEvent(event) && group.eventList.indexOf(event); + const nextEvent = isEvent(event) && group.eventList[currentIndex + 1]; + if (!isEvent(event) || event.category !== 'workflow') { offset = getOpenGroups(event, groups); } @@ -260,10 +208,11 @@ export const getNextDistanceAndOffset = ( let diff = 0; if (nextEvent) { diff = parseInt(nextEvent.id) - parseInt(event.id); - } else if (group.isPending) { + } else if (group.isPending && isEvent(event)) { diff = history.length - parseInt(event.id) + 2; } - nextDistance = diff * height; + const distance = diff * height; + nextDistance = sort === 'ascending' ? distance : -distance; return { nextDistance, offset }; }; @@ -324,10 +273,12 @@ export const activeGroupsHeightAboveGroup = ( group: EventGroup, groups: EventGroups, width: number, + sort: EventSortOrder, ) => { return activeGroups .filter((id) => { - return parseInt(id) < parseInt(group.id); + if (sort === 'ascending') return parseInt(id) < parseInt(group.id); + return parseInt(id) > parseInt(group.id); }) .map((id) => { const group = groups.find((group) => group.id === id); diff --git a/src/lib/components/lines-and-dots/end-time-interval.svelte b/src/lib/components/lines-and-dots/end-time-interval.svelte index 459a640f8..b8695d7f2 100644 --- a/src/lib/components/lines-and-dots/end-time-interval.svelte +++ b/src/lib/components/lines-and-dots/end-time-interval.svelte @@ -1,14 +1,21 @@ diff --git a/src/lib/components/lines-and-dots/event-status-filter.svelte b/src/lib/components/lines-and-dots/event-status-filter.svelte new file mode 100644 index 000000000..1cc918848 --- /dev/null +++ b/src/lib/components/lines-and-dots/event-status-filter.svelte @@ -0,0 +1,38 @@ + + +
+ {#each options as option} +
+ +
e.key === 'Enter' && onOptionClick} + > + {option.label} +
+
+ {/each} +
diff --git a/src/lib/components/lines-and-dots/event-type-filter.svelte b/src/lib/components/lines-and-dots/event-type-filter.svelte index aa1b59707..5c2acea80 100644 --- a/src/lib/components/lines-and-dots/event-type-filter.svelte +++ b/src/lib/components/lines-and-dots/event-type-filter.svelte @@ -1,6 +1,7 @@ -
+
diff --git a/src/lib/components/lines-and-dots/svg/compact-graph-row.svelte b/src/lib/components/lines-and-dots/svg/compact-graph-row.svelte deleted file mode 100644 index c7a1f6597..000000000 --- a/src/lib/components/lines-and-dots/svg/compact-graph-row.svelte +++ /dev/null @@ -1,99 +0,0 @@ - - - - 1 - ? 'retry' - : 'pending' - : group.category} - classification={aggregateRow ? undefined : group.lastEvent.classification} - {active} - strokeWidth={radius * 2} - pending={isPending} - /> - - - {#if aggregateRow}{count}{/if} - {group?.displayName} - - - {#if aggregateRow} - - - {:else} - - {/if} - - - diff --git a/src/lib/components/lines-and-dots/svg/compact-graph.svelte b/src/lib/components/lines-and-dots/svg/compact-graph.svelte deleted file mode 100644 index c1371ddf5..000000000 --- a/src/lib/components/lines-and-dots/svg/compact-graph.svelte +++ /dev/null @@ -1,206 +0,0 @@ - - - - {#each timeGroups as groups, startIndex} - {#each getNameGroups(groups) as nameGroup, groupIndex} - {@const group = nameGroup[0]} - {@const startY = getStartYOfGroup( - getNameGroups(groups), - groupIndex, - startIndex, - )} - {@const expanded = exandedGroups.includes( - groupNameWithIndex(group.name, startIndex), - )} - onRowClick(nameGroup, startIndex, startY)} - {expanded} - /> - {#if expanded} - {#each nameGroup as group, index} - {@const y = startY + (index + 1) * height} - onEventClick(group, startIndex, y)} - /> - {/each} - {/if} - {/each} - {:else} - - {/each} - {#if activeGroup} - {#key activeGroup.id} - - {/key} - {/if} - diff --git a/src/lib/components/lines-and-dots/svg/dot.svelte b/src/lib/components/lines-and-dots/svg/dot.svelte index 432f4da03..3c11769f6 100644 --- a/src/lib/components/lines-and-dots/svg/dot.svelte +++ b/src/lib/components/lines-and-dots/svg/dot.svelte @@ -1,4 +1,7 @@ + {#if icon} + + {/if} diff --git a/src/lib/components/lines-and-dots/svg/graph-widget.svelte b/src/lib/components/lines-and-dots/svg/graph-widget.svelte index 4698cb646..2eca35227 100644 --- a/src/lib/components/lines-and-dots/svg/graph-widget.svelte +++ b/src/lib/components/lines-and-dots/svg/graph-widget.svelte @@ -2,19 +2,15 @@ import { groupEvents } from '$lib/models/event-groups'; import { fetchAllEvents } from '$lib/services/events-service'; import { fetchWorkflow } from '$lib/services/workflow-service'; - import type { EventView, WorkflowEvents } from '$lib/types/events'; + import type { WorkflowEvents } from '$lib/types/events'; import type { WorkflowExecution } from '$lib/types/workflows'; - import CompactGraph from './compact-graph.svelte'; - import HistoryGraph from './history-graph.svelte'; import TimelineGraph from './timeline-graph.svelte'; export let namespace: string; export let workflowId: string; export let runId = ''; export let height = 400; - export let width: number; - export let view: EventView = 'timeline'; const getWorkflowAndEventHistory = async () => { const [workflow, history] = await Promise.all([ @@ -31,13 +27,6 @@ const pendingActivities = workflow?.pendingActivities ?? []; return groupEvents(history, 'ascending', pendingActivities); }; - - const views = { - compact: CompactGraph, - timeline: TimelineGraph, - history: HistoryGraph, - json: HistoryGraph, - }; {#await getWorkflowAndEventHistory() then { workflow, history }} @@ -45,12 +34,9 @@ class="cursor-pointer overflow-auto {$$restProps.class}" style="height: {height}px;" > -
diff --git a/src/lib/components/lines-and-dots/svg/group-details-row.svelte b/src/lib/components/lines-and-dots/svg/group-details-row.svelte index ae27824dd..7f9b5facd 100644 --- a/src/lib/components/lines-and-dots/svg/group-details-row.svelte +++ b/src/lib/components/lines-and-dots/svg/group-details-row.svelte @@ -66,7 +66,7 @@ staticCodeBlockHeight * codeBlockAttributes.length - textHeight, ); - $: title = group.name; + $: title = group.displayName; $: attributes = mergeEventGroupDetails(group); $: codeBlockAttributes = Object.entries(attributes).filter( ([, value]) => typeof value === 'object', @@ -79,7 +79,7 @@ group && group.eventList.find(isChildWorkflowExecutionStartedEvent); - + @@ -162,7 +162,7 @@ runId={childWorkflowStartedEvent.attributes.workflowExecution.runId} height={childTimelineHeight} width={childTimelineWidth} - class="overflow-x-hidden rounded-br rounded-tr border-b-4 border-r-4 border-t-4 border-black bg-black" + class="overflow-x-hidden rounded-br rounded-tr border-b-2 border-r-2 border-t-2 border-subtle bg-primary" /> {/key} diff --git a/src/lib/components/lines-and-dots/svg/history-graph-row-visual.svelte b/src/lib/components/lines-and-dots/svg/history-graph-row-visual.svelte index 2daebf4a9..8c36bc21d 100644 --- a/src/lib/components/lines-and-dots/svg/history-graph-row-visual.svelte +++ b/src/lib/components/lines-and-dots/svg/history-graph-row-visual.svelte @@ -3,9 +3,13 @@ EventGroup, EventGroups, } from '$lib/models/event-groups/event-groups'; - import { setSingleActiveEvent } from '$lib/stores/active-events'; - import type { WorkflowEvent, WorkflowEvents } from '$lib/types/events'; - import { isPendingActivity } from '$lib/utilities/is-pending-activity'; + import { isEvent } from '$lib/models/event-history'; + import { eventFilterSort } from '$lib/stores/event-view'; + import type { WorkflowEventWithPending } from '$lib/types/events'; + import { + isPendingActivity, + isPendingNexusOperation, + } from '$lib/utilities/is-pending-activity'; import { getNextDistanceAndOffset, @@ -16,17 +20,15 @@ import Dot from './dot.svelte'; import Line from './line.svelte'; - export let event: WorkflowEvent; + export let event: WorkflowEventWithPending; export let group: EventGroup; - export let history: WorkflowEvents; + export let history: WorkflowEventWithPending[]; export let groups: EventGroups; export let index: number; - export let activeEvents: string[] = []; - export let canvasWidth: number; - export let zoomLevel: number = 1; const { height, radius } = HistoryConfig; + const strokeWidth = radius / 2; $: y = index * height + height / 2; $: ({ nextDistance, offset } = getNextDistanceAndOffset( @@ -34,74 +36,69 @@ event, groups, height, + $eventFilterSort, )); - $: zoomY = y * zoomLevel; - $: zoomNextDistance = offset > 0 && nextDistance * zoomLevel; + $: zoomNextDistance = offset > 0 && nextDistance; - $: classification = isPendingActivity(event) - ? 'pending' - : event?.classification; - - const strokeWidth = radius / 2; + $: classification = + isPendingActivity(event) || isPendingNexusOperation(event) + ? 'pending' + : event?.classification; - $: width = canvasWidth * zoomLevel; - $: horizontalOffset = offset * 2 * radius; - $: nextIsPending = group?.lastEvent.id === event?.id && group.isPending; - $: eventInViewBox = horizontalOffset <= width; - $: isActive = - !activeEvents.length || - activeEvents.includes(event.id) || - !!activeEvents.find((id) => group?.eventIds.has(id)); + $: horizontalOffset = offset * 1.75 * radius; + $: nextIsPending = + isEvent(event) && group?.lastEvent.id === event?.id && group?.isPending; $: connectLine = - isPendingActivity(event) || offset === 0 + isPendingActivity(event) || isPendingNexusOperation(event) || offset === 0 ? false : !isMiddleEvent(event, groups); - $: category = isPendingActivity(event) - ? 'pending' - : nextIsPending - ? event?.category - : ''; + $: category = + isPendingActivity(event) || isPendingNexusOperation(event) + ? 'pending' + : nextIsPending + ? event?.category + : ''; + $: reverseSort = $eventFilterSort === 'descending'; - setSingleActiveEvent(event)} - on:keypress={() => setSingleActiveEvent(event)} - class="relative cursor-pointer" -> + {#if connectLine} {/if} - {#if eventInViewBox} + {#if !reverseSort} {/if} - {#if eventInViewBox && zoomNextDistance} + {#if zoomNextDistance} 1 ? 'retry' : 'pending' : category} - active={isActive} pending={nextIsPending} /> {/if} + {#if reverseSort} + + {/if} diff --git a/src/lib/components/lines-and-dots/svg/history-graph-row.svelte b/src/lib/components/lines-and-dots/svg/history-graph-row.svelte deleted file mode 100644 index fd47acc86..000000000 --- a/src/lib/components/lines-and-dots/svg/history-graph-row.svelte +++ /dev/null @@ -1,90 +0,0 @@ - - - setActiveEvent(event, group)} - on:keypress={() => setActiveEvent(event, group)} - class="relative cursor-pointer" -> - - -
-
- {event.id} -
- - {spaceBetweenCapitalLetters(event?.name)} - {#if group && group.displayName && showDetails}{group.displayName}{/if} -
-
- {#if showTimestamp} - {formatDate(event?.eventTime, $timeFormat, { - relative: $relativeTime, - })} - {/if} -
-
-
- - diff --git a/src/lib/components/lines-and-dots/svg/history-graph.svelte b/src/lib/components/lines-and-dots/svg/history-graph.svelte index 7b0e1b004..05b1f135d 100644 --- a/src/lib/components/lines-and-dots/svg/history-graph.svelte +++ b/src/lib/components/lines-and-dots/svg/history-graph.svelte @@ -1,123 +1,83 @@ - +
diff --git a/src/lib/components/lines-and-dots/svg/history-row-payload-detail.svelte b/src/lib/components/lines-and-dots/svg/history-row-payload-detail.svelte deleted file mode 100644 index 71290b93e..000000000 --- a/src/lib/components/lines-and-dots/svg/history-row-payload-detail.svelte +++ /dev/null @@ -1,37 +0,0 @@ - - -{#if typeof value === 'object'} - {#if value?.payloads} - - {#key decodedValue} - {decodedValue.slice(1, 20)} - {/key} - - {:else if key === 'searchAttributes'} - - {#key decodedValue} - {decodedValue.slice(1, 20)} - {/key} - - {:else} - - {#key decodedValue} - {decodedValue.slice(1, 20)} - {/key} - - {/if} -{/if} diff --git a/src/lib/components/lines-and-dots/svg/line.svelte b/src/lib/components/lines-and-dots/svg/line.svelte index 704e7058d..a3e812428 100644 --- a/src/lib/components/lines-and-dots/svg/line.svelte +++ b/src/lib/components/lines-and-dots/svg/line.svelte @@ -4,7 +4,6 @@ export let status: string | undefined = undefined; export let category: string | undefined = undefined; export let classification: string | undefined = undefined; - export let active = true; export let scheduling = false; export let pending = false; export let strokeWidth: number = 2; @@ -16,7 +15,6 @@ .line { cursor: pointer; - opacity: 0.15; + opacity: 1; outline: none; stroke: #444ce7; } - .active { - opacity: 1; - } - .none { stroke: #141414; opacity: 0.65; @@ -118,7 +112,7 @@ @keyframes dash { from { - stroke-dashoffset: 1000; + stroke-dashoffset: 200; } to { diff --git a/src/lib/components/lines-and-dots/svg/text.svelte b/src/lib/components/lines-and-dots/svg/text.svelte index 64765be0d..f0ea0dc60 100644 --- a/src/lib/components/lines-and-dots/svg/text.svelte +++ b/src/lib/components/lines-and-dots/svg/text.svelte @@ -8,7 +8,6 @@ export let point: [number, number] = [0, 0]; export let category: string | undefined = undefined; - export let active = true; export let fontSize = '14px'; export let fontWeight = '400'; export let textAnchor = 'start'; @@ -25,31 +24,25 @@ $: showIcon = icon && config; $: textWidth = textElement?.getBBox()?.width || 0; $: backdropWidth = showIcon ? textWidth + 36 : textWidth + 12; - $: textX = showIcon && textAnchor === 'start' ? x + config.radius * 1.5 : x; + $: textX = showIcon && textAnchor === 'start' ? x + config.radius * 2 : x; {#if backdrop} {/if} {#if showIcon && textAnchor === 'start'} - + {/if} {/if} diff --git a/src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte b/src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte index 298f5447a..931ec2917 100644 --- a/src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte +++ b/src/lib/components/lines-and-dots/svg/timeline-graph-row.svelte @@ -89,7 +89,6 @@ endPoint={[nextPoint, y]} category={group.category} classification={group.lastEvent.classification} - {active} strokeWidth={radius * 2} scheduling={index === 0 && group.lastEvent.classification === 'Completed'} @@ -105,7 +104,6 @@ : 'pending' : group.category} classification={group.lastEvent.classification} - {active} pending strokeWidth={radius * 2} /> @@ -113,11 +111,9 @@ {#if showText} {group?.displayName} @@ -126,7 +122,7 @@ {/each} diff --git a/src/lib/components/lines-and-dots/svg/timeline-graph.svelte b/src/lib/components/lines-and-dots/svg/timeline-graph.svelte index 78f49b293..a05cc3533 100644 --- a/src/lib/components/lines-and-dots/svg/timeline-graph.svelte +++ b/src/lib/components/lines-and-dots/svg/timeline-graph.svelte @@ -1,7 +1,15 @@ - - - - - - {#each groups as group, index (group.id)} - {@const y = - (index + 1) * height + - activeGroupsHeightAboveGroup(activeGroups, group, groups, canvasWidth)} - {#key group.eventList.length} - - {/key} - {#if activeGroups.includes(group.id)} - - {/if} - {/each} - - +
+ + +
+
+

+ {formatDate(startTime, $timeFormat)} +

+

+ {formatDate(endTime, $timeFormat)} +

+
+
+ + + + + + {#each filteredGroups as group, index (group.id)} + {@const y = + (index + 2) * height + + activeGroupsHeightAboveGroup( + activeGroups, + group, + filteredGroups, + canvasWidth, + $eventFilterSort, + )} + {#if y > scrollY - 2 * height && y < scrollY + viewportHeight * height} + {#key group.eventList.length} + + {/key} + {/if} + {#if activeGroups.includes(group.id)} + + {/if} + {/each} + +
+
+ + diff --git a/src/lib/components/lines-and-dots/svg/workflow-row.svelte b/src/lib/components/lines-and-dots/svg/workflow-row.svelte index 8084f215f..ea272231d 100644 --- a/src/lib/components/lines-and-dots/svg/workflow-row.svelte +++ b/src/lib/components/lines-and-dots/svg/workflow-row.svelte @@ -2,21 +2,19 @@ import Icon from '$lib/holocene/icon/icon.svelte'; import type { WorkflowExecution } from '$lib/types/workflows'; - import { CompactConfig } from '../constants'; + import { TimelineConfig } from '../constants'; import Dot from './dot.svelte'; import Line from './line.svelte'; - import Text from './text.svelte'; export let workflow: WorkflowExecution; export let length: number; export let y: number; - export let active = true; - const { radius, height } = CompactConfig; + const { radius, height, gutter } = TimelineConfig; - $: start = 2 * radius; - $: end = start + length; + $: start = gutter; + $: end = start + length - 2 * gutter; @@ -24,25 +22,10 @@ startPoint={[start, y]} endPoint={[end, y]} classification={workflow.status} - {active} strokeWidth={radius * 2} + pending={workflow.isRunning} /> - - - {workflow.name} - - + + +