@taskmark/ui 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/app/globals.css +25 -0
- package/app/layout.tsx +15 -5
- package/app/setup/page.tsx +1 -1
- package/bin/lib/resolve-board.mjs +1 -4
- package/components/board/app-bar.tsx +3 -0
- package/components/board/board-screen.tsx +61 -117
- package/components/board/changelog-panel.tsx +26 -0
- package/components/board/epic-list.tsx +2 -0
- package/components/board/list-view-switcher.tsx +7 -3
- package/components/board/markdown-content.tsx +21 -1
- package/components/board/mermaid-diagram.tsx +88 -0
- package/components/board/metric-stat-card.tsx +4 -4
- package/components/board/overall-tree-list.tsx +467 -0
- package/components/board/overall-work-items-list.tsx +5 -1
- package/components/board/points-heatmap.tsx +183 -0
- package/components/board/project-status-metrics-strip.tsx +5 -22
- package/components/board/static-board-app.tsx +29 -94
- package/components/board/status-badge.tsx +8 -0
- package/components/board/story-list.tsx +2 -0
- package/components/board/task-list.tsx +5 -1
- package/components/board/work-item-detail-body.tsx +123 -8
- package/components/board/work-items-list.tsx +2 -0
- package/components/theme-provider.tsx +39 -0
- package/components/theme-toggle.tsx +27 -0
- package/components/ui/sonner.tsx +2 -2
- package/dist/prod-next/BUILD_ID +1 -1
- package/dist/prod-next/build-manifest.json +6 -6
- package/dist/prod-next/react-loadable-manifest.json +391 -1
- package/dist/prod-next/server/app/_global-error/page.js +2 -2
- package/dist/prod-next/server/app/_global-error/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/app/_global-error.html +1 -1
- package/dist/prod-next/server/app/_global-error.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/prod-next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found/page.js +2 -2
- package/dist/prod-next/server/app/_not-found/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/app/_not-found.html +1 -1
- package/dist/prod-next/server/app/_not-found.rsc +19 -17
- package/dist/prod-next/server/app/_not-found.segments/_full.segment.rsc +19 -17
- package/dist/prod-next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found.segments/_index.segment.rsc +8 -6
- package/dist/prod-next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/prod-next/server/app/api/taskmark-reload/route.js +1 -1
- package/dist/prod-next/server/app/api/taskmark-reload/route.js.nft.json +1 -1
- package/dist/prod-next/server/app/board/page.js +2 -2
- package/dist/prod-next/server/app/board/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/board/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/app/favicon.ico/route.js +1 -1
- package/dist/prod-next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/dist/prod-next/server/app/page.js +2 -2
- package/dist/prod-next/server/app/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/app/setup/page.js +2 -2
- package/dist/prod-next/server/app/setup/page.js.nft.json +1 -1
- package/dist/prod-next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/dist/prod-next/server/chunks/102.js +90 -0
- package/dist/prod-next/server/chunks/11.js +1 -0
- package/dist/prod-next/server/chunks/1286.js +1 -0
- package/dist/prod-next/server/chunks/1412.js +38 -0
- package/dist/prod-next/server/chunks/1605.js +1 -0
- package/dist/prod-next/server/chunks/169.js +1 -0
- package/dist/prod-next/server/chunks/18.js +86 -0
- package/dist/prod-next/server/chunks/2.js +1 -0
- package/dist/prod-next/server/chunks/2022.js +1 -0
- package/dist/prod-next/server/chunks/2156.js +1 -0
- package/dist/prod-next/server/chunks/2157.js +1 -0
- package/dist/prod-next/server/chunks/2325.js +82 -0
- package/dist/prod-next/server/chunks/2838.js +1 -0
- package/dist/prod-next/server/chunks/2897.js +79 -0
- package/dist/prod-next/server/chunks/3227.js +1 -0
- package/dist/prod-next/server/chunks/3266.js +1 -0
- package/dist/prod-next/server/chunks/{192.js → 3307.js} +5 -5
- package/dist/prod-next/server/chunks/3387.js +19 -0
- package/dist/prod-next/server/chunks/3428.js +32 -0
- package/dist/prod-next/server/chunks/3479.js +1 -0
- package/dist/prod-next/server/chunks/367.js +115 -0
- package/dist/prod-next/server/chunks/3698.js +93 -0
- package/dist/prod-next/server/chunks/3709.js +148 -0
- package/dist/prod-next/server/chunks/41.js +1 -0
- package/dist/prod-next/server/chunks/4107.js +62 -0
- package/dist/prod-next/server/chunks/4569.js +34 -0
- package/dist/prod-next/server/chunks/{741.js → 4741.js} +1 -1
- package/dist/prod-next/server/chunks/4755.js +153 -0
- package/dist/prod-next/server/chunks/5002.js +1 -0
- package/dist/prod-next/server/chunks/5112.js +1 -0
- package/dist/prod-next/server/chunks/5289.js +8 -0
- package/dist/prod-next/server/chunks/5318.js +1 -0
- package/dist/prod-next/server/chunks/5452.js +23 -0
- package/dist/prod-next/server/chunks/5453.js +1 -0
- package/dist/prod-next/server/chunks/5749.js +27 -0
- package/dist/prod-next/server/chunks/5782.js +36 -0
- package/dist/prod-next/server/chunks/6163.js +104 -0
- package/dist/prod-next/server/chunks/6169.js +64 -0
- package/dist/prod-next/server/chunks/6208.js +172 -0
- package/dist/prod-next/server/chunks/6399.js +24 -0
- package/dist/prod-next/server/chunks/6496.js +1 -0
- package/dist/prod-next/server/chunks/6823.js +215 -0
- package/dist/prod-next/server/chunks/6888.js +1 -0
- package/dist/prod-next/server/chunks/6980.js +1 -0
- package/dist/prod-next/server/chunks/7245.js +77 -0
- package/dist/prod-next/server/chunks/7307.js +1 -0
- package/dist/prod-next/server/chunks/7372.js +287 -0
- package/dist/prod-next/server/chunks/7384.js +226 -0
- package/dist/prod-next/server/chunks/7516.js +1 -0
- package/dist/prod-next/server/chunks/7531.js +24 -0
- package/dist/prod-next/server/chunks/7591.js +1 -0
- package/dist/prod-next/server/chunks/7755.js +138 -0
- package/dist/prod-next/server/chunks/7916.js +1 -0
- package/dist/prod-next/server/chunks/8078.js +94 -0
- package/dist/prod-next/server/chunks/8253.js +41 -0
- package/dist/prod-next/server/chunks/8635.js +1 -0
- package/dist/prod-next/server/chunks/8688.js +1 -0
- package/dist/prod-next/server/chunks/8872.js +1 -0
- package/dist/prod-next/server/chunks/9006.js +1 -0
- package/dist/prod-next/server/chunks/9018.js +1 -0
- package/dist/prod-next/server/chunks/9047.js +1 -0
- package/dist/prod-next/server/chunks/9108.js +1 -0
- package/dist/prod-next/server/chunks/9280.js +256 -0
- package/dist/prod-next/server/chunks/9419.js +1 -0
- package/dist/prod-next/server/chunks/9430.js +1 -0
- package/dist/prod-next/server/chunks/9586.js +1 -0
- package/dist/prod-next/server/chunks/9775.js +1 -0
- package/dist/prod-next/server/chunks/992.js +1 -0
- package/dist/prod-next/server/chunks/9926.js +1 -0
- package/dist/prod-next/server/chunks/9984.js +8 -0
- package/dist/prod-next/server/middleware-build-manifest.js +1 -1
- package/dist/prod-next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/prod-next/server/pages/404.html +1 -1
- package/dist/prod-next/server/pages/500.html +1 -1
- package/dist/prod-next/server/server-reference-manifest.js +1 -1
- package/dist/prod-next/server/server-reference-manifest.json +1 -1
- package/dist/prod-next/server/webpack-runtime.js +1 -1
- package/dist/prod-next/static/chunks/1213.e5c6e70a79b5f7e6.js +24 -0
- package/dist/prod-next/static/chunks/1519.2f596e5f5af9ef57.js +62 -0
- package/dist/prod-next/static/chunks/1759-f5b8fb456f8fb420.js +1 -0
- package/dist/prod-next/static/chunks/1974.885c9a133b86d8a4.js +32 -0
- package/dist/prod-next/static/chunks/2280.6a7f540787704698.js +1 -0
- package/dist/prod-next/static/chunks/2521.7f745f50d30076e7.js +77 -0
- package/dist/prod-next/static/chunks/2585.4d6aa847c780c666.js +1 -0
- package/dist/prod-next/static/chunks/2589.1aad68c09021b1ac.js +1 -0
- package/dist/prod-next/static/chunks/2600.45ba17a0f756fc31.js +1 -0
- package/dist/prod-next/static/chunks/2619.9aac8983f30c7c8a.js +1 -0
- package/dist/prod-next/static/chunks/26d302b2.9f6383e42abdfe16.js +122 -0
- package/dist/prod-next/static/chunks/2768.305914f7900745b6.js +1 -0
- package/dist/prod-next/static/chunks/2931.c2acdbf72808b646.js +41 -0
- package/dist/prod-next/static/chunks/3012-838f69b72a0dc1b3.js +1 -0
- package/dist/prod-next/static/chunks/3016.406e568aa95ff867.js +1 -0
- package/dist/prod-next/static/chunks/3022.972047558a20553a.js +172 -0
- package/dist/prod-next/static/chunks/3064.3a2a1e7cd4fdca5f.js +1 -0
- package/dist/prod-next/static/chunks/3174.03fbed7b7d7a8256.js +1 -0
- package/dist/prod-next/static/chunks/3189.b048866768087750.js +1 -0
- package/dist/prod-next/static/chunks/3217.1a053843c58b70b5.js +24 -0
- package/dist/prod-next/static/chunks/3308.30b95d524f9c1daf.js +74 -0
- package/dist/prod-next/static/chunks/331.fc5d78e1e91daf43.js +1 -0
- package/dist/prod-next/static/chunks/3510.5d4d1c79533e080c.js +1 -0
- package/dist/prod-next/static/chunks/364.ce5400a9dd70b9dc.js +1 -0
- package/dist/prod-next/static/chunks/3661-1f08d73aaffb011d.js +1 -0
- package/dist/prod-next/static/chunks/370.57cfa27da8567918.js +1 -0
- package/dist/prod-next/static/chunks/3789.c418b69121761983.js +1 -0
- package/dist/prod-next/static/chunks/3794-c66b3d8325973459.js +32 -0
- package/dist/prod-next/static/chunks/3831.25ae62d10dccc27a.js +1 -0
- package/dist/prod-next/static/chunks/395.b41e9d76613d37b5.js +90 -0
- package/dist/prod-next/static/chunks/3a7aa434.93dbd20997cfd24f.js +82 -0
- package/dist/prod-next/static/chunks/4020.3cc19c463c49f969.js +23 -0
- package/dist/prod-next/static/chunks/4035.0acc428926d5c8dd.js +1 -0
- package/dist/prod-next/static/chunks/405.0902e4f6eb7bd9a2.js +215 -0
- package/dist/prod-next/static/chunks/4159.49ae537ff687bdc6.js +138 -0
- package/dist/prod-next/static/chunks/4208.384b381ca2757643.js +287 -0
- package/dist/prod-next/static/chunks/4263.ffa8d9bd8a0faaae.js +1 -0
- package/dist/prod-next/static/chunks/4561.d1a3aaca8bae3224.js +34 -0
- package/dist/prod-next/static/chunks/4592.d0f37bc216b9d988.js +93 -0
- package/dist/prod-next/static/chunks/4799.0dc7aa21bff2fd2a.js +1 -0
- package/dist/prod-next/static/chunks/4bd1b696-e356ca5ba0218e27.js +1 -0
- package/dist/prod-next/static/chunks/514.b804c51b26f5e126.js +1 -0
- package/dist/prod-next/static/chunks/5270.28592864d38e881c.js +1 -0
- package/dist/prod-next/static/chunks/52733464.3870f99cc446f9ff.js +1 -0
- package/dist/prod-next/static/chunks/5354.b559c717a607dc5c.js +1 -0
- package/dist/prod-next/static/chunks/5448.d3972d9fb464b54f.js +38 -0
- package/dist/prod-next/static/chunks/587.d52737d7288c11b4.js +1 -0
- package/dist/prod-next/static/chunks/5909.9e37f7b495b11995.js +115 -0
- package/dist/prod-next/static/chunks/5949.5504b3545fcc3d34.js +104 -0
- package/dist/prod-next/static/chunks/6322-4e97920c006f7933.js +1 -0
- package/dist/prod-next/static/chunks/6361.893d04ac34fa1b49.js +148 -0
- package/dist/prod-next/static/chunks/6774.8cd53427dbf32cac.js +86 -0
- package/dist/prod-next/static/chunks/6968.b80277c724dbc96e.js +1 -0
- package/dist/prod-next/static/chunks/7113.4b9e7ea870aa300a.js +8 -0
- package/dist/prod-next/static/chunks/7236.55a9728d35f5b8a6.js +1 -0
- package/dist/prod-next/static/chunks/7390.dde9b5bc2f6e24b8.js +1 -0
- package/dist/prod-next/static/chunks/7806.a903780fcfa3a30e.js +1 -0
- package/dist/prod-next/static/chunks/7997.be57e92e583fe635.js +1 -0
- package/dist/prod-next/static/chunks/8216.64a72d4d35ea7be0.js +1 -0
- package/dist/prod-next/static/chunks/830.5d5274d7ad1cb58e.js +1 -0
- package/dist/prod-next/static/chunks/8378.fa91de3406f554c9.js +226 -0
- package/dist/prod-next/static/chunks/8501.cd06aa1b0c7e1c6a.js +79 -0
- package/dist/prod-next/static/chunks/8663.6ec5792fb4952e45.js +27 -0
- package/dist/prod-next/static/chunks/872.96937e758ddce860.js +1 -0
- package/dist/prod-next/static/chunks/8803.75bde095fe3613f5.js +1 -0
- package/dist/prod-next/static/chunks/8863.72f5dbb820a0e4c3.js +1 -0
- package/dist/prod-next/static/chunks/90542734.f7a7b2972ef5a749.js +1 -0
- package/dist/prod-next/static/chunks/9379.5bc9c9343ec5a16c.js +64 -0
- package/dist/prod-next/static/chunks/9389.906fe7aa9cd6a170.js +1 -0
- package/dist/prod-next/static/chunks/9472.8818ee52cfa931a4.js +94 -0
- package/dist/prod-next/static/chunks/966.d6babbf8119162cc.js +1 -0
- package/dist/prod-next/static/chunks/9884.d4ac1a961b3366f1.js +36 -0
- package/dist/prod-next/static/chunks/9909.67cf9940b125243b.js +1 -0
- package/dist/prod-next/static/chunks/app/_global-error/page-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/app/_not-found/page-799e445a538b0024.js +1 -0
- package/dist/prod-next/static/chunks/app/api/taskmark-reload/route-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/app/board/page-5c181f45738daf1c.js +1 -0
- package/dist/prod-next/static/chunks/app/layout-21782e6d13a6f275.js +1 -0
- package/dist/prod-next/static/chunks/app/page-51bfe4356fe233e3.js +1 -0
- package/dist/prod-next/static/chunks/app/setup/page-3ccfba00c10f9b17.js +1 -0
- package/dist/prod-next/static/chunks/d3ac728e.7964f816a1ca64e5.js +1 -0
- package/dist/prod-next/static/chunks/e413bedd.3a12a8cb02e28fdf.js +153 -0
- package/dist/prod-next/static/chunks/ea233666.f00b64a7d99b4950.js +62 -0
- package/dist/prod-next/static/chunks/framework-711ef29bc66f648c.js +1 -0
- package/dist/prod-next/static/chunks/main-app-dd26d4f9d120646e.js +1 -0
- package/dist/prod-next/static/chunks/{main-bb33c46a9c25dee8.js → main-df4bcaed74f274eb.js} +2 -2
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/app-error-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/forbidden-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/global-error-45a0cf77e03361ed.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/not-found-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/unauthorized-8be5492b3b872a4c.js +1 -0
- package/dist/prod-next/static/chunks/webpack-713747aaa9716c4c.js +1 -0
- package/dist/prod-next/static/css/cb78d4b0062d9a3f.css +1 -0
- package/dist/public/taskmark-snapshot.json +1 -1
- package/lib/taskmark/board-index.ts +101 -0
- package/lib/taskmark/build-snapshot.ts +28 -7
- package/lib/taskmark/derive-parents.test.ts +23 -0
- package/lib/taskmark/derive-parents.ts +323 -0
- package/lib/taskmark/detail-load.ts +55 -7
- package/lib/taskmark/detail-types.ts +10 -2
- package/lib/taskmark/dev-reload-token.ts +1 -1
- package/lib/taskmark/discover.ts +4 -7
- package/lib/taskmark/epic-types.ts +2 -1
- package/lib/taskmark/flat-work-item-types.ts +1 -4
- package/lib/taskmark/identity.ts +3 -3
- package/lib/taskmark/item-types.ts +2 -1
- package/lib/taskmark/list-filters.test.ts +23 -0
- package/lib/taskmark/list-filters.ts +7 -2
- package/lib/taskmark/list-view-mode.test.ts +45 -0
- package/lib/taskmark/list-view-mode.ts +19 -8
- package/lib/taskmark/load-changelog.test.ts +32 -0
- package/lib/taskmark/load-changelog.ts +18 -0
- package/lib/taskmark/overall-tree.test.ts +196 -0
- package/lib/taskmark/overall-tree.ts +194 -0
- package/lib/taskmark/parse-detail.ts +5 -5
- package/lib/taskmark/parse-epics.ts +19 -16
- package/lib/taskmark/parse-flat-lists.ts +32 -28
- package/lib/taskmark/parse-items.ts +47 -9
- package/lib/taskmark/parse-stories.ts +18 -15
- package/lib/taskmark/points-calendar.test.ts +72 -0
- package/lib/taskmark/points-calendar.ts +86 -0
- package/lib/taskmark/project-metrics.ts +11 -7
- package/lib/taskmark/snapshot-types.ts +2 -0
- package/lib/taskmark/story-types.ts +2 -1
- package/lib/taskmark/table-sort.ts +4 -3
- package/lib/taskmark/timing.ts +29 -18
- package/lib/taskmark/validate.ts +1 -1
- package/lib/theme-cookie.test.ts +27 -0
- package/lib/theme-cookie.ts +43 -0
- package/package.json +3 -1
- package/public/taskmark-snapshot.json +1 -1
- package/dist/prod-next/server/chunks/463.js +0 -1
- package/dist/prod-next/server/chunks/54.js +0 -19
- package/dist/prod-next/server/chunks/57.js +0 -8
- package/dist/prod-next/server/chunks/724.js +0 -1
- package/dist/prod-next/static/chunks/4bd1b696-deb4a0a1da1923b0.js +0 -1
- package/dist/prod-next/static/chunks/613-6f794154d28bb75a.js +0 -1
- package/dist/prod-next/static/chunks/636-626c380f021b95c8.js +0 -1
- package/dist/prod-next/static/chunks/669-8103441c67b185da.js +0 -1
- package/dist/prod-next/static/chunks/701-df3ee5f1cf837b1a.js +0 -1
- package/dist/prod-next/static/chunks/794-25668765560cb197.js +0 -32
- package/dist/prod-next/static/chunks/909.932f2af3be7f1e89.js +0 -1
- package/dist/prod-next/static/chunks/app/_global-error/page-a1e3320be3da9be1.js +0 -1
- package/dist/prod-next/static/chunks/app/_not-found/page-0b3785af737e7968.js +0 -1
- package/dist/prod-next/static/chunks/app/api/taskmark-reload/route-a1e3320be3da9be1.js +0 -1
- package/dist/prod-next/static/chunks/app/board/page-636f60191db62f52.js +0 -1
- package/dist/prod-next/static/chunks/app/layout-856e8a282e69e7d0.js +0 -1
- package/dist/prod-next/static/chunks/app/page-562a33b50da7665b.js +0 -1
- package/dist/prod-next/static/chunks/app/setup/page-4cf527b758b1d51e.js +0 -1
- package/dist/prod-next/static/chunks/framework-b29f9083d3cda3b2.js +0 -1
- package/dist/prod-next/static/chunks/main-app-bfb36455d24b3e5a.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/app-error-a1e3320be3da9be1.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/forbidden-a1e3320be3da9be1.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/global-error-dc53ab29e0491fe4.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/not-found-a1e3320be3da9be1.js +0 -1
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/unauthorized-a1e3320be3da9be1.js +0 -1
- package/dist/prod-next/static/chunks/webpack-d33b8a6298c94a64.js +0 -1
- package/dist/prod-next/static/css/2e6ec4c80894e3c0.css +0 -1
- /package/dist/prod-next/static/{yyRnYAFQrJjF5_b5ZIeqh → EI1zQaa_kQ7DqUSE4o3Qo}/_buildManifest.js +0 -0
- /package/dist/prod-next/static/{yyRnYAFQrJjF5_b5ZIeqh → EI1zQaa_kQ7DqUSE4o3Qo}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import type { ContributorIdentity } from "@/lib/taskmark/identity"
|
|
2
|
+
import type { EpicSummary, ProjectEpicList } from "@/lib/taskmark/epic-types"
|
|
3
|
+
import type {
|
|
4
|
+
EpicWorkItemsList,
|
|
5
|
+
WorkItemsViewRow,
|
|
6
|
+
} from "@/lib/taskmark/flat-work-item-types"
|
|
7
|
+
import type { ItemSummary, StoryItemList } from "@/lib/taskmark/item-types"
|
|
8
|
+
import { isGeneralEpic } from "@/lib/taskmark/general-epic"
|
|
9
|
+
import {
|
|
10
|
+
matchesWorkItemSearch,
|
|
11
|
+
type TimeframeFilterState,
|
|
12
|
+
} from "@/lib/taskmark/list-filters"
|
|
13
|
+
import { passesTimeframeFilter } from "@/lib/taskmark/timeframe-filters"
|
|
14
|
+
|
|
15
|
+
export type OverallTreeNode = {
|
|
16
|
+
kind: "epic" | "story" | "task" | "bug"
|
|
17
|
+
id: string
|
|
18
|
+
title: string
|
|
19
|
+
status: string
|
|
20
|
+
size: string
|
|
21
|
+
points: number | null
|
|
22
|
+
tags: string[]
|
|
23
|
+
reporters: ContributorIdentity[]
|
|
24
|
+
resolvers: ContributorIdentity[]
|
|
25
|
+
created: string
|
|
26
|
+
updated: string
|
|
27
|
+
completedAt: string
|
|
28
|
+
filePath: string
|
|
29
|
+
children: OverallTreeNode[]
|
|
30
|
+
workItemCount: number
|
|
31
|
+
doneWorkItemCount: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function isOverallNodeComplete(status: string): boolean {
|
|
35
|
+
const normalized = status.trim().toLowerCase()
|
|
36
|
+
return (
|
|
37
|
+
normalized === "done" ||
|
|
38
|
+
normalized === "shelved" ||
|
|
39
|
+
normalized === "cancelled"
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function timestamp(value: string): number {
|
|
44
|
+
const parsed = Date.parse(value)
|
|
45
|
+
return Number.isFinite(parsed) ? parsed : 0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Incomplete first, then created/updated newest-first, then id. */
|
|
49
|
+
export function compareOverallNodes(
|
|
50
|
+
a: Pick<OverallTreeNode, "status" | "created" | "updated" | "id">,
|
|
51
|
+
b: Pick<OverallTreeNode, "status" | "created" | "updated" | "id">
|
|
52
|
+
): number {
|
|
53
|
+
const completion = Number(isOverallNodeComplete(a.status)) -
|
|
54
|
+
Number(isOverallNodeComplete(b.status))
|
|
55
|
+
if (completion !== 0) return completion
|
|
56
|
+
const created = timestamp(b.created) - timestamp(a.created)
|
|
57
|
+
if (created !== 0) return created
|
|
58
|
+
const updated = timestamp(b.updated) - timestamp(a.updated)
|
|
59
|
+
if (updated !== 0) return updated
|
|
60
|
+
return a.id.localeCompare(b.id)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function itemNode(item: ItemSummary): OverallTreeNode {
|
|
64
|
+
return {
|
|
65
|
+
kind: item.type,
|
|
66
|
+
id: item.id,
|
|
67
|
+
title: item.title,
|
|
68
|
+
status: item.status,
|
|
69
|
+
size: item.size,
|
|
70
|
+
points: item.points,
|
|
71
|
+
tags: item.tags,
|
|
72
|
+
reporters: item.reporters,
|
|
73
|
+
resolvers: item.resolvers,
|
|
74
|
+
created: item.created,
|
|
75
|
+
updated: item.updated,
|
|
76
|
+
completedAt: item.completedAt,
|
|
77
|
+
filePath: item.filePath,
|
|
78
|
+
children: [],
|
|
79
|
+
workItemCount: 0,
|
|
80
|
+
doneWorkItemCount: 0,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function workItemNode(
|
|
85
|
+
row: WorkItemsViewRow,
|
|
86
|
+
storyItems: StoryItemList | undefined
|
|
87
|
+
): OverallTreeNode {
|
|
88
|
+
const children =
|
|
89
|
+
row.kind === "story"
|
|
90
|
+
? (storyItems?.items ?? []).map(itemNode).sort(compareOverallNodes)
|
|
91
|
+
: []
|
|
92
|
+
return {
|
|
93
|
+
kind: row.kind,
|
|
94
|
+
id: row.id,
|
|
95
|
+
title: row.title,
|
|
96
|
+
status: row.status,
|
|
97
|
+
size: row.size,
|
|
98
|
+
points: row.points,
|
|
99
|
+
tags: row.tags,
|
|
100
|
+
reporters: row.reporters,
|
|
101
|
+
resolvers: row.resolvers,
|
|
102
|
+
created: row.created,
|
|
103
|
+
updated: row.updated,
|
|
104
|
+
completedAt: row.completedAt,
|
|
105
|
+
filePath: row.filePath,
|
|
106
|
+
children,
|
|
107
|
+
workItemCount: row.workItemCount,
|
|
108
|
+
doneWorkItemCount: row.doneWorkItemCount,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function epicNode(
|
|
113
|
+
epic: EpicSummary,
|
|
114
|
+
workItems: EpicWorkItemsList | undefined,
|
|
115
|
+
itemsByStory: Record<string, StoryItemList>
|
|
116
|
+
): OverallTreeNode {
|
|
117
|
+
const children = (workItems?.rows ?? [])
|
|
118
|
+
.map((row) => workItemNode(row, itemsByStory[`${epic.id}::${row.id}`]))
|
|
119
|
+
.sort(compareOverallNodes)
|
|
120
|
+
return {
|
|
121
|
+
kind: "epic",
|
|
122
|
+
id: epic.id,
|
|
123
|
+
title: epic.title,
|
|
124
|
+
status: epic.status,
|
|
125
|
+
size: epic.size,
|
|
126
|
+
points: epic.points,
|
|
127
|
+
tags: epic.tags,
|
|
128
|
+
reporters: epic.reporters,
|
|
129
|
+
resolvers: epic.resolvers,
|
|
130
|
+
created: epic.created,
|
|
131
|
+
updated: epic.updated,
|
|
132
|
+
completedAt: epic.completedAt,
|
|
133
|
+
filePath: epic.filePath,
|
|
134
|
+
children,
|
|
135
|
+
workItemCount: epic.workItemCount,
|
|
136
|
+
doneWorkItemCount: epic.doneWorkItemCount,
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function buildOverallTree(
|
|
141
|
+
epicList: ProjectEpicList,
|
|
142
|
+
workItemsByEpic: Record<string, EpicWorkItemsList>,
|
|
143
|
+
itemsByStory: Record<string, StoryItemList>
|
|
144
|
+
): OverallTreeNode[] {
|
|
145
|
+
return epicList.epics
|
|
146
|
+
.filter((epic) => !(isGeneralEpic(epic) && epic.workItemCount === 0))
|
|
147
|
+
.map((epic) => epicNode(epic, workItemsByEpic[epic.id], itemsByStory))
|
|
148
|
+
.sort(compareOverallNodes)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export type OverallTreeFilters = {
|
|
152
|
+
query: string
|
|
153
|
+
hideCompleted: boolean
|
|
154
|
+
timeframe: TimeframeFilterState
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Retain a node when it matches itself or has a matching descendant. This
|
|
159
|
+
* preserves hierarchy context for search, completed filtering, and timeframe.
|
|
160
|
+
*/
|
|
161
|
+
export function filterOverallTree(
|
|
162
|
+
nodes: readonly OverallTreeNode[],
|
|
163
|
+
filters: OverallTreeFilters
|
|
164
|
+
): OverallTreeNode[] {
|
|
165
|
+
return nodes.flatMap((node) => {
|
|
166
|
+
const children = filterOverallTree(node.children, filters)
|
|
167
|
+
const selfMatches =
|
|
168
|
+
matchesWorkItemSearch(filters.query, node) &&
|
|
169
|
+
(!filters.hideCompleted || !isOverallNodeComplete(node.status)) &&
|
|
170
|
+
passesTimeframeFilter(filters.timeframe, node.completedAt)
|
|
171
|
+
if (!selfMatches && children.length === 0) return []
|
|
172
|
+
return [{ ...node, children }]
|
|
173
|
+
})
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function collectExpandableAncestorIds(
|
|
177
|
+
nodes: readonly OverallTreeNode[]
|
|
178
|
+
): string[] {
|
|
179
|
+
return nodes.flatMap((node) => [
|
|
180
|
+
...(node.children.length > 0 ? [node.id] : []),
|
|
181
|
+
...collectExpandableAncestorIds(node.children),
|
|
182
|
+
])
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Only a search reveals matches by expanding their ancestors. Toggle filters
|
|
187
|
+
* such as hide-completed and timeframe keep whatever the user has open.
|
|
188
|
+
*/
|
|
189
|
+
export function searchRevealIds(
|
|
190
|
+
nodes: readonly OverallTreeNode[],
|
|
191
|
+
query: string
|
|
192
|
+
): string[] {
|
|
193
|
+
return query.trim() ? collectExpandableAncestorIds(nodes) : []
|
|
194
|
+
}
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
extractFrontmatter,
|
|
6
6
|
} from "@/lib/taskmark/frontmatter"
|
|
7
7
|
import { asContributorList } from "@/lib/taskmark/identity"
|
|
8
|
-
import {
|
|
8
|
+
import { readActualTimingFromWorkLog } from "@/lib/taskmark/timing"
|
|
9
9
|
import type {
|
|
10
10
|
CommitRow,
|
|
11
11
|
EpicDetail,
|
|
@@ -85,6 +85,7 @@ function resolveKind(
|
|
|
85
85
|
|
|
86
86
|
function buildMeta(
|
|
87
87
|
frontmatter: Record<string, unknown>,
|
|
88
|
+
raw: string,
|
|
88
89
|
filePath: string,
|
|
89
90
|
kind: WorkItemKind
|
|
90
91
|
): WorkItemMeta | null {
|
|
@@ -92,7 +93,7 @@ function buildMeta(
|
|
|
92
93
|
const title = asString(frontmatter.title)
|
|
93
94
|
if (!id || !title) return null
|
|
94
95
|
|
|
95
|
-
const timing =
|
|
96
|
+
const timing = readActualTimingFromWorkLog(raw)
|
|
96
97
|
return {
|
|
97
98
|
id,
|
|
98
99
|
title,
|
|
@@ -101,11 +102,9 @@ function buildMeta(
|
|
|
101
102
|
priority: asString(frontmatter.priority, "medium"),
|
|
102
103
|
size: asString(frontmatter.size, "—"),
|
|
103
104
|
points: asNumberOrNull(frontmatter.points),
|
|
104
|
-
estimateMinutes: timing.estimateMinutes,
|
|
105
105
|
actualMinutes: timing.actualMinutes,
|
|
106
106
|
actualMs: timing.actualMs,
|
|
107
107
|
tags: asStringArray(frontmatter.tags),
|
|
108
|
-
owner: asString(frontmatter.owner),
|
|
109
108
|
reporters: asContributorList(frontmatter.reporters),
|
|
110
109
|
resolvers: asContributorList(frontmatter.resolvers),
|
|
111
110
|
blocked: asBool(frontmatter.blocked),
|
|
@@ -147,7 +146,7 @@ export function parseWorkItemDetailFromRaw(
|
|
|
147
146
|
|
|
148
147
|
const id = asString(frontmatter.id)
|
|
149
148
|
const kind = resolveKind(frontmatter, id, hint)
|
|
150
|
-
const meta = buildMeta(frontmatter, filePath, kind)
|
|
149
|
+
const meta = buildMeta(frontmatter, raw, filePath, kind)
|
|
151
150
|
if (!meta) {
|
|
152
151
|
return {
|
|
153
152
|
ok: false,
|
|
@@ -169,6 +168,7 @@ export function parseWorkItemDetailFromRaw(
|
|
|
169
168
|
successMetrics: getSection(sections, "Success metrics"),
|
|
170
169
|
storiesMarkdown: getSection(sections, "Stories"),
|
|
171
170
|
children: [],
|
|
171
|
+
promptFeedback: [],
|
|
172
172
|
commits: parseCommits(getSection(sections, "Commits")),
|
|
173
173
|
workLog: parseWorkLog(getSection(sections, "Work log")),
|
|
174
174
|
}
|
|
@@ -8,15 +8,14 @@ import type {
|
|
|
8
8
|
ProjectEpicList,
|
|
9
9
|
} from "@/lib/taskmark/epic-types"
|
|
10
10
|
import {
|
|
11
|
-
asNumberOrNull,
|
|
12
11
|
asString,
|
|
13
12
|
asStringArray,
|
|
14
13
|
extractFrontmatter,
|
|
15
14
|
} from "@/lib/taskmark/frontmatter"
|
|
16
15
|
import { asContributorList } from "@/lib/taskmark/identity"
|
|
17
|
-
import { readTimingFields } from "@/lib/taskmark/timing"
|
|
18
16
|
import { sortEpicsGeneralFirst } from "@/lib/taskmark/general-epic"
|
|
19
|
-
import {
|
|
17
|
+
import { deriveParentRollup } from "@/lib/taskmark/derive-parents"
|
|
18
|
+
import type { BoardIndex } from "@/lib/taskmark/board-index"
|
|
20
19
|
|
|
21
20
|
function listEpicMarkdownFiles(boardPath: string): string[] {
|
|
22
21
|
const epicsDir = path.join(boardPath, "epics")
|
|
@@ -41,7 +40,8 @@ function listEpicMarkdownFiles(boardPath: string): string[] {
|
|
|
41
40
|
|
|
42
41
|
function parseEpicFile(
|
|
43
42
|
filePath: string,
|
|
44
|
-
project: DiscoveredProject
|
|
43
|
+
project: DiscoveredProject,
|
|
44
|
+
index?: BoardIndex
|
|
45
45
|
): { epic?: EpicSummary; error?: EpicParseError } {
|
|
46
46
|
let raw: string
|
|
47
47
|
try {
|
|
@@ -96,24 +96,26 @@ function parseEpicFile(
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
const
|
|
99
|
+
const derived = deriveParentRollup(project.boardPath, id, "epic", index)
|
|
100
100
|
|
|
101
101
|
return {
|
|
102
102
|
epic: {
|
|
103
103
|
id,
|
|
104
104
|
title,
|
|
105
|
-
status:
|
|
105
|
+
status: derived.status,
|
|
106
106
|
priority: asString(frontmatter.priority, "medium"),
|
|
107
|
-
size:
|
|
108
|
-
points:
|
|
109
|
-
|
|
107
|
+
size: derived.size,
|
|
108
|
+
points: derived.points,
|
|
109
|
+
actualMinutes: derived.actualMinutes,
|
|
110
|
+
actualMs: derived.actualMs,
|
|
110
111
|
tags: asStringArray(frontmatter.tags),
|
|
111
112
|
reporters: asContributorList(frontmatter.reporters),
|
|
112
|
-
resolvers:
|
|
113
|
+
resolvers: derived.resolvers,
|
|
113
114
|
created: asString(frontmatter.created),
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
updated: asString(frontmatter.updated),
|
|
116
|
+
completedAt: derived.completedAt,
|
|
117
|
+
workItemCount: derived.leafCount,
|
|
118
|
+
doneWorkItemCount: derived.doneLeafCount,
|
|
117
119
|
filePath,
|
|
118
120
|
project: {
|
|
119
121
|
id: project.id,
|
|
@@ -127,14 +129,15 @@ function parseEpicFile(
|
|
|
127
129
|
|
|
128
130
|
/** Parse all epics under a project's board root (nested taskmark/ or flat *-taskmark). */
|
|
129
131
|
export function parseEpicsForProject(
|
|
130
|
-
project: DiscoveredProject
|
|
132
|
+
project: DiscoveredProject,
|
|
133
|
+
index?: BoardIndex
|
|
131
134
|
): ProjectEpicList {
|
|
132
135
|
const files = listEpicMarkdownFiles(project.boardPath)
|
|
133
136
|
const epics: EpicSummary[] = []
|
|
134
137
|
const errors: EpicParseError[] = []
|
|
135
138
|
|
|
136
139
|
for (const filePath of files) {
|
|
137
|
-
const result = parseEpicFile(filePath, project)
|
|
140
|
+
const result = parseEpicFile(filePath, project, index)
|
|
138
141
|
if (result.epic) epics.push(result.epic)
|
|
139
142
|
if (result.error) errors.push(result.error)
|
|
140
143
|
}
|
|
@@ -149,5 +152,5 @@ export function parseEpicsForProject(
|
|
|
149
152
|
export function parseEpicsForProjects(
|
|
150
153
|
projects: DiscoveredProject[]
|
|
151
154
|
): ProjectEpicList[] {
|
|
152
|
-
return projects.map(parseEpicsForProject)
|
|
155
|
+
return projects.map((project) => parseEpicsForProject(project))
|
|
153
156
|
}
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
WorkItemsViewRow,
|
|
12
12
|
} from "@/lib/taskmark/flat-work-item-types"
|
|
13
13
|
import { compareByStatusThenPriority } from "@/lib/taskmark/list-view-mode"
|
|
14
|
+
import type { BoardIndex } from "@/lib/taskmark/board-index"
|
|
14
15
|
import { parseEpicsForProject } from "@/lib/taskmark/parse-epics"
|
|
15
16
|
import { parseItemsForEpic, parseItemsForStory } from "@/lib/taskmark/parse-items"
|
|
16
17
|
import { parseStoriesForEpic } from "@/lib/taskmark/parse-stories"
|
|
@@ -19,9 +20,10 @@ import { parseStoriesForEpic } from "@/lib/taskmark/parse-stories"
|
|
|
19
20
|
* Flat table of every epic, story, and task/bug on the active board.
|
|
20
21
|
*/
|
|
21
22
|
export function parseAllWorkItemsForProject(
|
|
22
|
-
project: DiscoveredProject
|
|
23
|
+
project: DiscoveredProject,
|
|
24
|
+
index?: BoardIndex
|
|
23
25
|
): FlatWorkItemList {
|
|
24
|
-
const epicList = parseEpicsForProject(project)
|
|
26
|
+
const epicList = parseEpicsForProject(project, index)
|
|
25
27
|
const rows: FlatWorkItemRow[] = []
|
|
26
28
|
const errors: FlatWorkItemList["errors"] = epicList.errors.map((e) => ({
|
|
27
29
|
filePath: e.filePath,
|
|
@@ -37,7 +39,6 @@ export function parseAllWorkItemsForProject(
|
|
|
37
39
|
priority: epic.priority,
|
|
38
40
|
size: epic.size,
|
|
39
41
|
points: epic.points,
|
|
40
|
-
estimateMinutes: epic.estimateMinutes,
|
|
41
42
|
actualMinutes: epic.actualMinutes,
|
|
42
43
|
actualMs: epic.actualMs,
|
|
43
44
|
epicId: epic.id,
|
|
@@ -48,7 +49,7 @@ export function parseAllWorkItemsForProject(
|
|
|
48
49
|
project: epic.project,
|
|
49
50
|
})
|
|
50
51
|
|
|
51
|
-
const storyList = parseStoriesForEpic(project, epic.id)
|
|
52
|
+
const storyList = parseStoriesForEpic(project, epic.id, index)
|
|
52
53
|
for (const err of storyList.errors) {
|
|
53
54
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
54
55
|
}
|
|
@@ -62,7 +63,6 @@ export function parseAllWorkItemsForProject(
|
|
|
62
63
|
priority: story.priority,
|
|
63
64
|
size: story.size,
|
|
64
65
|
points: story.points,
|
|
65
|
-
estimateMinutes: story.estimateMinutes,
|
|
66
66
|
actualMinutes: story.actualMinutes,
|
|
67
67
|
actualMs: story.actualMs,
|
|
68
68
|
epicId: epic.id,
|
|
@@ -73,7 +73,7 @@ export function parseAllWorkItemsForProject(
|
|
|
73
73
|
project: story.project,
|
|
74
74
|
})
|
|
75
75
|
|
|
76
|
-
const items = parseItemsForStory(project, epic.id, story.id)
|
|
76
|
+
const items = parseItemsForStory(project, epic.id, story.id, index)
|
|
77
77
|
for (const err of items.errors) {
|
|
78
78
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
79
79
|
}
|
|
@@ -86,7 +86,6 @@ export function parseAllWorkItemsForProject(
|
|
|
86
86
|
priority: item.priority,
|
|
87
87
|
size: item.size,
|
|
88
88
|
points: item.points,
|
|
89
|
-
estimateMinutes: item.estimateMinutes,
|
|
90
89
|
actualMinutes: item.actualMinutes,
|
|
91
90
|
actualMs: item.actualMs,
|
|
92
91
|
epicId: epic.id,
|
|
@@ -99,7 +98,7 @@ export function parseAllWorkItemsForProject(
|
|
|
99
98
|
}
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
const epicItems = parseItemsForEpic(project, epic.id)
|
|
101
|
+
const epicItems = parseItemsForEpic(project, epic.id, index)
|
|
103
102
|
for (const err of epicItems.errors) {
|
|
104
103
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
105
104
|
}
|
|
@@ -112,7 +111,6 @@ export function parseAllWorkItemsForProject(
|
|
|
112
111
|
priority: item.priority,
|
|
113
112
|
size: item.size,
|
|
114
113
|
points: item.points,
|
|
115
|
-
estimateMinutes: item.estimateMinutes,
|
|
116
114
|
actualMinutes: item.actualMinutes,
|
|
117
115
|
actualMs: item.actualMs,
|
|
118
116
|
epicId: epic.id,
|
|
@@ -130,9 +128,10 @@ export function parseAllWorkItemsForProject(
|
|
|
130
128
|
|
|
131
129
|
/** All stories across every epic, with epic id/title for UI tags. */
|
|
132
130
|
export function parseAllStoriesForProject(
|
|
133
|
-
project: DiscoveredProject
|
|
131
|
+
project: DiscoveredProject,
|
|
132
|
+
index?: BoardIndex
|
|
134
133
|
): ProjectStoriesFlatList {
|
|
135
|
-
const epicList = parseEpicsForProject(project)
|
|
134
|
+
const epicList = parseEpicsForProject(project, index)
|
|
136
135
|
const stories: StoryWithEpicRow[] = []
|
|
137
136
|
const errors: ProjectStoriesFlatList["errors"] = epicList.errors.map((e) => ({
|
|
138
137
|
filePath: e.filePath,
|
|
@@ -140,7 +139,7 @@ export function parseAllStoriesForProject(
|
|
|
140
139
|
}))
|
|
141
140
|
|
|
142
141
|
for (const epic of epicList.epics) {
|
|
143
|
-
const storyList = parseStoriesForEpic(project, epic.id)
|
|
142
|
+
const storyList = parseStoriesForEpic(project, epic.id, index)
|
|
144
143
|
for (const err of storyList.errors) {
|
|
145
144
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
146
145
|
}
|
|
@@ -152,7 +151,6 @@ export function parseAllStoriesForProject(
|
|
|
152
151
|
priority: story.priority,
|
|
153
152
|
size: story.size,
|
|
154
153
|
points: story.points,
|
|
155
|
-
estimateMinutes: story.estimateMinutes,
|
|
156
154
|
actualMinutes: story.actualMinutes,
|
|
157
155
|
actualMs: story.actualMs,
|
|
158
156
|
epicId: epic.id,
|
|
@@ -170,9 +168,10 @@ export function parseAllStoriesForProject(
|
|
|
170
168
|
|
|
171
169
|
/** All tasks/bugs across the board, with epic and story UI tags. */
|
|
172
170
|
export function parseAllTasksForProject(
|
|
173
|
-
project: DiscoveredProject
|
|
171
|
+
project: DiscoveredProject,
|
|
172
|
+
index?: BoardIndex
|
|
174
173
|
): ProjectTasksFlatList {
|
|
175
|
-
const epicList = parseEpicsForProject(project)
|
|
174
|
+
const epicList = parseEpicsForProject(project, index)
|
|
176
175
|
const items: TaskWithParentsRow[] = []
|
|
177
176
|
const errors: ProjectTasksFlatList["errors"] = epicList.errors.map((e) => ({
|
|
178
177
|
filePath: e.filePath,
|
|
@@ -180,13 +179,13 @@ export function parseAllTasksForProject(
|
|
|
180
179
|
}))
|
|
181
180
|
|
|
182
181
|
for (const epic of epicList.epics) {
|
|
183
|
-
const storyList = parseStoriesForEpic(project, epic.id)
|
|
182
|
+
const storyList = parseStoriesForEpic(project, epic.id, index)
|
|
184
183
|
for (const err of storyList.errors) {
|
|
185
184
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
186
185
|
}
|
|
187
186
|
|
|
188
187
|
for (const story of storyList.stories) {
|
|
189
|
-
const storyItems = parseItemsForStory(project, epic.id, story.id)
|
|
188
|
+
const storyItems = parseItemsForStory(project, epic.id, story.id, index)
|
|
190
189
|
for (const err of storyItems.errors) {
|
|
191
190
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
192
191
|
}
|
|
@@ -199,7 +198,6 @@ export function parseAllTasksForProject(
|
|
|
199
198
|
priority: item.priority,
|
|
200
199
|
size: item.size,
|
|
201
200
|
points: item.points,
|
|
202
|
-
estimateMinutes: item.estimateMinutes,
|
|
203
201
|
actualMinutes: item.actualMinutes,
|
|
204
202
|
actualMs: item.actualMs,
|
|
205
203
|
epicId: epic.id,
|
|
@@ -212,7 +210,7 @@ export function parseAllTasksForProject(
|
|
|
212
210
|
}
|
|
213
211
|
}
|
|
214
212
|
|
|
215
|
-
const epicItems = parseItemsForEpic(project, epic.id)
|
|
213
|
+
const epicItems = parseItemsForEpic(project, epic.id, index)
|
|
216
214
|
for (const err of epicItems.errors) {
|
|
217
215
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
218
216
|
}
|
|
@@ -225,7 +223,6 @@ export function parseAllTasksForProject(
|
|
|
225
223
|
priority: item.priority,
|
|
226
224
|
size: item.size,
|
|
227
225
|
points: item.points,
|
|
228
|
-
estimateMinutes: item.estimateMinutes,
|
|
229
226
|
actualMinutes: item.actualMinutes,
|
|
230
227
|
actualMs: item.actualMs,
|
|
231
228
|
epicId: epic.id,
|
|
@@ -249,13 +246,14 @@ export function parseAllTasksForProject(
|
|
|
249
246
|
export function parseWorkItemsForEpic(
|
|
250
247
|
project: DiscoveredProject,
|
|
251
248
|
epicId: string,
|
|
252
|
-
epicTitle?: string | null
|
|
249
|
+
epicTitle?: string | null,
|
|
250
|
+
index?: BoardIndex
|
|
253
251
|
): EpicWorkItemsList {
|
|
254
252
|
const rows: WorkItemsViewRow[] = []
|
|
255
253
|
const errors: EpicWorkItemsList["errors"] = []
|
|
256
254
|
const title = epicTitle ?? null
|
|
257
255
|
|
|
258
|
-
const storyList = parseStoriesForEpic(project, epicId)
|
|
256
|
+
const storyList = parseStoriesForEpic(project, epicId, index)
|
|
259
257
|
for (const err of storyList.errors) {
|
|
260
258
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
261
259
|
}
|
|
@@ -269,7 +267,6 @@ export function parseWorkItemsForEpic(
|
|
|
269
267
|
priority: story.priority,
|
|
270
268
|
size: story.size,
|
|
271
269
|
points: story.points,
|
|
272
|
-
estimateMinutes: story.estimateMinutes,
|
|
273
270
|
actualMinutes: story.actualMinutes,
|
|
274
271
|
actualMs: story.actualMs,
|
|
275
272
|
epicId,
|
|
@@ -278,6 +275,7 @@ export function parseWorkItemsForEpic(
|
|
|
278
275
|
reporters: story.reporters,
|
|
279
276
|
resolvers: story.resolvers,
|
|
280
277
|
created: story.created,
|
|
278
|
+
updated: story.updated,
|
|
281
279
|
completedAt: story.completedAt,
|
|
282
280
|
workItemCount: story.workItemCount,
|
|
283
281
|
doneWorkItemCount: story.doneWorkItemCount,
|
|
@@ -286,7 +284,7 @@ export function parseWorkItemsForEpic(
|
|
|
286
284
|
})
|
|
287
285
|
}
|
|
288
286
|
|
|
289
|
-
const epicItems = parseItemsForEpic(project, epicId)
|
|
287
|
+
const epicItems = parseItemsForEpic(project, epicId, index)
|
|
290
288
|
for (const err of epicItems.errors) {
|
|
291
289
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
292
290
|
}
|
|
@@ -299,7 +297,6 @@ export function parseWorkItemsForEpic(
|
|
|
299
297
|
priority: item.priority,
|
|
300
298
|
size: item.size,
|
|
301
299
|
points: item.points,
|
|
302
|
-
estimateMinutes: item.estimateMinutes,
|
|
303
300
|
actualMinutes: item.actualMinutes,
|
|
304
301
|
actualMs: item.actualMs,
|
|
305
302
|
epicId,
|
|
@@ -308,6 +305,7 @@ export function parseWorkItemsForEpic(
|
|
|
308
305
|
reporters: item.reporters,
|
|
309
306
|
resolvers: item.resolvers,
|
|
310
307
|
created: item.created,
|
|
308
|
+
updated: item.updated,
|
|
311
309
|
completedAt: item.completedAt,
|
|
312
310
|
workItemCount: 0,
|
|
313
311
|
doneWorkItemCount: 0,
|
|
@@ -331,9 +329,10 @@ export function parseWorkItemsForEpic(
|
|
|
331
329
|
* (excludes tasks/bugs that live under a story). Sorted by status then priority.
|
|
332
330
|
*/
|
|
333
331
|
export function parseWorkItemsViewForProject(
|
|
334
|
-
project: DiscoveredProject
|
|
332
|
+
project: DiscoveredProject,
|
|
333
|
+
index?: BoardIndex
|
|
335
334
|
): WorkItemsViewList {
|
|
336
|
-
const epicList = parseEpicsForProject(project)
|
|
335
|
+
const epicList = parseEpicsForProject(project, index)
|
|
337
336
|
const rows: WorkItemsViewRow[] = []
|
|
338
337
|
const errors: WorkItemsViewList["errors"] = epicList.errors.map((e) => ({
|
|
339
338
|
filePath: e.filePath,
|
|
@@ -341,7 +340,12 @@ export function parseWorkItemsViewForProject(
|
|
|
341
340
|
}))
|
|
342
341
|
|
|
343
342
|
for (const epic of epicList.epics) {
|
|
344
|
-
const epicWorkItems = parseWorkItemsForEpic(
|
|
343
|
+
const epicWorkItems = parseWorkItemsForEpic(
|
|
344
|
+
project,
|
|
345
|
+
epic.id,
|
|
346
|
+
epic.title,
|
|
347
|
+
index
|
|
348
|
+
)
|
|
345
349
|
for (const err of epicWorkItems.errors) {
|
|
346
350
|
errors.push({ filePath: err.filePath, message: err.message })
|
|
347
351
|
}
|