@skillcdn/console 0.1.18 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +1 -1
  2. package/SKILLCDN.md +1 -1
  3. package/dist/api.d.ts +1 -1
  4. package/dist/api.d.ts.map +1 -1
  5. package/dist/api.js +1 -1
  6. package/dist/api.js.map +1 -1
  7. package/dist/cli/cli.d.ts +1 -1
  8. package/dist/cli/cli.d.ts.map +1 -1
  9. package/dist/cli/cli.js +353 -39
  10. package/dist/cli/cli.js.map +1 -1
  11. package/dist/cli/credentials.d.ts +102 -3
  12. package/dist/cli/credentials.d.ts.map +1 -1
  13. package/dist/cli/credentials.js +177 -8
  14. package/dist/cli/credentials.js.map +1 -1
  15. package/dist/cli/directory.d.ts +6 -0
  16. package/dist/cli/directory.d.ts.map +1 -1
  17. package/dist/cli/directory.js +37 -6
  18. package/dist/cli/directory.js.map +1 -1
  19. package/dist/cli/format.d.ts +10 -1
  20. package/dist/cli/format.d.ts.map +1 -1
  21. package/dist/cli/format.js +106 -2
  22. package/dist/cli/format.js.map +1 -1
  23. package/dist/cli/help.d.ts.map +1 -1
  24. package/dist/cli/help.js +42 -20
  25. package/dist/cli/help.js.map +1 -1
  26. package/dist/client.d.ts +21 -1
  27. package/dist/client.d.ts.map +1 -1
  28. package/dist/client.js +14 -1
  29. package/dist/client.js.map +1 -1
  30. package/dist/components/board.d.ts +9 -1
  31. package/dist/components/board.d.ts.map +1 -1
  32. package/dist/components/board.js +82 -5
  33. package/dist/components/board.js.map +1 -1
  34. package/dist/components/comments.d.ts.map +1 -1
  35. package/dist/components/comments.js +12 -4
  36. package/dist/components/comments.js.map +1 -1
  37. package/dist/components/event-feed.d.ts.map +1 -1
  38. package/dist/components/event-feed.js +4 -0
  39. package/dist/components/event-feed.js.map +1 -1
  40. package/dist/components/goals.d.ts +17 -1
  41. package/dist/components/goals.d.ts.map +1 -1
  42. package/dist/components/goals.js +34 -9
  43. package/dist/components/goals.js.map +1 -1
  44. package/dist/components/markdown.d.ts +6 -0
  45. package/dist/components/markdown.d.ts.map +1 -1
  46. package/dist/components/markdown.js +7 -0
  47. package/dist/components/markdown.js.map +1 -1
  48. package/dist/components/pictures.d.ts +68 -0
  49. package/dist/components/pictures.d.ts.map +1 -0
  50. package/dist/components/pictures.js +213 -0
  51. package/dist/components/pictures.js.map +1 -0
  52. package/dist/components/projects.d.ts +12 -0
  53. package/dist/components/projects.d.ts.map +1 -1
  54. package/dist/components/projects.js +15 -0
  55. package/dist/components/projects.js.map +1 -1
  56. package/dist/components/task-view.d.ts +3 -0
  57. package/dist/components/task-view.d.ts.map +1 -1
  58. package/dist/components/task-view.js +6 -4
  59. package/dist/components/task-view.js.map +1 -1
  60. package/dist/console.css +282 -3
  61. package/dist/console.d.ts.map +1 -1
  62. package/dist/console.js +124 -10
  63. package/dist/console.js.map +1 -1
  64. package/dist/data.d.ts +16 -1
  65. package/dist/data.d.ts.map +1 -1
  66. package/dist/data.js +47 -2
  67. package/dist/data.js.map +1 -1
  68. package/dist/i18n/en.d.ts +52 -0
  69. package/dist/i18n/en.d.ts.map +1 -1
  70. package/dist/i18n/en.js +50 -2
  71. package/dist/i18n/en.js.map +1 -1
  72. package/dist/i18n/ko.d.ts.map +1 -1
  73. package/dist/i18n/ko.js +50 -2
  74. package/dist/i18n/ko.js.map +1 -1
  75. package/dist/index.d.ts +5 -4
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +5 -4
  78. package/dist/index.js.map +1 -1
  79. package/dist/router.d.ts +25 -6
  80. package/dist/router.d.ts.map +1 -1
  81. package/dist/router.js +38 -7
  82. package/dist/router.js.map +1 -1
  83. package/dist/rules.js +5 -5
  84. package/dist/rules.js.map +1 -1
  85. package/dist/schemas.d.ts +158 -0
  86. package/dist/schemas.d.ts.map +1 -1
  87. package/dist/schemas.js +78 -0
  88. package/dist/schemas.js.map +1 -1
  89. package/dist/vocabulary.d.ts +2 -2
  90. package/dist/vocabulary.d.ts.map +1 -1
  91. package/dist/vocabulary.js +3 -0
  92. package/dist/vocabulary.js.map +1 -1
  93. package/docs/specs/cli.md +17 -9
  94. package/docs/specs/rest.md +22 -4
  95. package/package.json +1 -1
  96. package/skills/working-the-board/SKILL.md +10 -4
  97. package/src/api.ts +13 -0
  98. package/src/cli/cli.ts +441 -42
  99. package/src/cli/credentials.ts +276 -14
  100. package/src/cli/directory.ts +43 -6
  101. package/src/cli/format.ts +138 -2
  102. package/src/cli/help.ts +44 -20
  103. package/src/client.ts +60 -0
  104. package/src/components/board.tsx +154 -8
  105. package/src/components/comments.tsx +20 -10
  106. package/src/components/event-feed.tsx +4 -0
  107. package/src/components/goals.tsx +173 -106
  108. package/src/components/markdown.tsx +19 -0
  109. package/src/components/pictures.tsx +389 -0
  110. package/src/components/projects.tsx +68 -0
  111. package/src/components/task-view.tsx +43 -2
  112. package/src/console.tsx +259 -4
  113. package/src/data.ts +72 -1
  114. package/src/i18n/en.ts +53 -2
  115. package/src/i18n/ko.ts +53 -2
  116. package/src/index.ts +27 -0
  117. package/src/router.ts +57 -9
  118. package/src/rules.ts +5 -5
  119. package/src/schemas.ts +97 -0
  120. package/src/styles/console.css +282 -3
  121. package/src/vocabulary.ts +3 -0
package/dist/console.css CHANGED
@@ -2166,16 +2166,110 @@ table {
2166
2166
  font-size: var(--sc-text-sm);
2167
2167
  }
2168
2168
 
2169
- /* A picture in a comment is seen where it is, no taller than a screen's worth. */
2170
- .sc-comment-picture img,
2169
+ /* A picture in a comment is a thumbnail, no taller than a few lines, that opens large over the
2170
+ page; a picture that only comes over https stays where it is, as small. */
2171
+ .sc-picture-thumb {
2172
+ display: inline-block;
2173
+ padding: 0;
2174
+ border: 0;
2175
+ border-radius: var(--sc-radius-md);
2176
+ background: none;
2177
+ line-height: 0;
2178
+ cursor: zoom-in;
2179
+ }
2180
+
2181
+ .sc-picture-thumb:focus-visible {
2182
+ outline: 2px solid var(--sc-color-accent);
2183
+ outline-offset: 2px;
2184
+ }
2185
+
2186
+ .sc-picture-thumb img,
2171
2187
  .sc-comment .sc-prose img {
2172
2188
  display: block;
2189
+ width: auto;
2173
2190
  max-width: 100%;
2174
- max-height: 24rem;
2191
+ height: auto;
2192
+ max-height: 10rem;
2175
2193
  border: var(--sc-border);
2176
2194
  border-radius: var(--sc-radius-md);
2177
2195
  }
2178
2196
 
2197
+ .sc-prose .sc-picture-thumb {
2198
+ margin: var(--sc-space-2) 0;
2199
+ }
2200
+
2201
+ /* The picture large, over the page: a bar with its name and the ways to zoom and to close, the
2202
+ stage it moves on, and a hint. The page under it is dimmed and does not scroll. */
2203
+ .sc-overlay {
2204
+ position: fixed;
2205
+ z-index: 100;
2206
+ display: grid;
2207
+ grid-template-rows: auto minmax(0, 1fr) auto;
2208
+ inset: 0;
2209
+ background: color-mix(in srgb, var(--sc-color-bg) 90%, transparent);
2210
+ backdrop-filter: blur(12px);
2211
+ }
2212
+
2213
+ .sc-overlay-bar {
2214
+ display: flex;
2215
+ align-items: center;
2216
+ justify-content: space-between;
2217
+ gap: var(--sc-space-3);
2218
+ padding: var(--sc-space-3) var(--sc-space-4);
2219
+ }
2220
+
2221
+ .sc-overlay-name {
2222
+ min-width: 0;
2223
+ overflow: hidden;
2224
+ color: var(--sc-color-text);
2225
+ font-size: var(--sc-text-sm);
2226
+ text-overflow: ellipsis;
2227
+ white-space: nowrap;
2228
+ }
2229
+
2230
+ .sc-overlay-actions {
2231
+ display: flex;
2232
+ flex-shrink: 0;
2233
+ gap: var(--sc-space-1);
2234
+ }
2235
+
2236
+ .sc-overlay-stage {
2237
+ position: relative;
2238
+ display: grid;
2239
+ place-items: center;
2240
+ overflow: hidden;
2241
+ cursor: grab;
2242
+ touch-action: none;
2243
+ user-select: none;
2244
+ }
2245
+
2246
+ .sc-overlay-stage[data-dragging="true"] {
2247
+ cursor: grabbing;
2248
+ }
2249
+
2250
+ .sc-overlay-picture {
2251
+ width: auto;
2252
+ max-width: 100%;
2253
+ height: auto;
2254
+ max-height: 100%;
2255
+ transform-origin: center center;
2256
+ will-change: transform;
2257
+ }
2258
+
2259
+ .sc-overlay-hint {
2260
+ margin: 0;
2261
+ padding: var(--sc-space-2) var(--sc-space-4) var(--sc-space-3);
2262
+ color: var(--sc-color-text-muted);
2263
+ font-size: var(--sc-text-xs);
2264
+ text-align: center;
2265
+ }
2266
+
2267
+ @media (max-width: 40rem) {
2268
+ .sc-overlay-hint {
2269
+ display: none;
2270
+ }
2271
+ }
2272
+
2179
2273
  .sc-comment-files {
2180
2274
  display: grid;
2181
2275
  gap: var(--sc-space-2);
@@ -3680,3 +3774,188 @@ table {
3680
3774
  grid-template-columns: minmax(6rem, 8rem) minmax(16rem, 1fr);
3681
3775
  }
3682
3776
  }
3777
+
3778
+ /* A card is dragged to another column by its grip, which shows on the card under the pointer
3779
+ and always to a finger; the column under the dragged card says it would take it, and a ghost
3780
+ of the card follows the pointer. The keyboard keeps the select. */
3781
+ .sc-card {
3782
+ position: relative;
3783
+ }
3784
+
3785
+ .sc-card-grip {
3786
+ position: absolute;
3787
+ top: var(--sc-space-1);
3788
+ right: var(--sc-space-1);
3789
+ display: inline-flex;
3790
+ align-items: center;
3791
+ justify-content: center;
3792
+ width: 1.5rem;
3793
+ height: 1.5rem;
3794
+ padding: 0;
3795
+ border: 0;
3796
+ border-radius: var(--sc-radius-sm);
3797
+ background: none;
3798
+ color: var(--sc-color-text-faint);
3799
+ font-size: var(--sc-text-sm);
3800
+ letter-spacing: -0.15em;
3801
+ cursor: grab;
3802
+ opacity: 0;
3803
+ touch-action: none;
3804
+ transition: opacity var(--sc-transition);
3805
+ }
3806
+
3807
+ .sc-card:hover .sc-card-grip,
3808
+ .sc-card:focus-within .sc-card-grip,
3809
+ .sc-card.sc-card-dragging .sc-card-grip {
3810
+ opacity: 1;
3811
+ }
3812
+
3813
+ @media (pointer: coarse) {
3814
+ .sc-card-grip {
3815
+ opacity: 1;
3816
+ }
3817
+ }
3818
+
3819
+ .sc-card:has(.sc-card-grip) .sc-card-title {
3820
+ padding-right: 1.75rem;
3821
+ }
3822
+
3823
+ .sc-card-dragging {
3824
+ opacity: 0.5;
3825
+ }
3826
+
3827
+ .sc-board-dragging {
3828
+ user-select: none;
3829
+ }
3830
+
3831
+ .sc-column-over {
3832
+ outline: 2px solid var(--sc-color-accent);
3833
+ outline-offset: -2px;
3834
+ }
3835
+
3836
+ .sc-drag-ghost {
3837
+ position: fixed;
3838
+ top: 0;
3839
+ left: 0;
3840
+ z-index: 50;
3841
+ max-width: 18rem;
3842
+ padding: var(--sc-space-2) var(--sc-space-3);
3843
+ border: 1px solid var(--sc-color-accent);
3844
+ border-radius: var(--sc-radius-lg);
3845
+ background: var(--sc-color-bg-raised);
3846
+ box-shadow: var(--sc-glow);
3847
+ color: var(--sc-color-text);
3848
+ font-size: var(--sc-text-sm);
3849
+ pointer-events: none;
3850
+ }
3851
+
3852
+ /* A goal's page reads as the board does: the facts in a row at its head, then a switch between
3853
+ the views of its tasks, then the view, which takes the rest of the height as the board does. */
3854
+ .sc-goal-page {
3855
+ display: flex;
3856
+ flex: 1 1 0;
3857
+ flex-direction: column;
3858
+ gap: var(--sc-space-4);
3859
+ min-height: 0;
3860
+ }
3861
+
3862
+ .sc-goal-header {
3863
+ display: grid;
3864
+ gap: var(--sc-space-3);
3865
+ }
3866
+
3867
+ .sc-goal-progress {
3868
+ display: grid;
3869
+ grid-template-columns: minmax(0, 20rem) auto;
3870
+ align-items: center;
3871
+ gap: var(--sc-space-3);
3872
+ font-size: var(--sc-text-sm);
3873
+ }
3874
+
3875
+ .sc-facts-row {
3876
+ display: flex;
3877
+ flex-wrap: wrap;
3878
+ align-items: center;
3879
+ gap: var(--sc-space-2) var(--sc-space-5);
3880
+ margin: 0;
3881
+ font-size: var(--sc-text-sm);
3882
+ }
3883
+
3884
+ .sc-facts-row > div {
3885
+ display: flex;
3886
+ align-items: center;
3887
+ gap: var(--sc-space-2);
3888
+ }
3889
+
3890
+ .sc-facts-row dt {
3891
+ color: var(--sc-color-text-muted);
3892
+ }
3893
+
3894
+ .sc-facts-row dd {
3895
+ margin: 0;
3896
+ }
3897
+
3898
+ .sc-goal-about-summary {
3899
+ color: var(--sc-color-text-muted);
3900
+ font-size: var(--sc-text-sm);
3901
+ cursor: pointer;
3902
+ }
3903
+
3904
+ .sc-goal-about .sc-prose {
3905
+ max-width: var(--sc-width-prose);
3906
+ margin-top: var(--sc-space-3);
3907
+ }
3908
+
3909
+ .sc-views {
3910
+ display: flex;
3911
+ flex-wrap: wrap;
3912
+ gap: var(--sc-space-1);
3913
+ }
3914
+
3915
+ .sc-view {
3916
+ padding: var(--sc-space-1) var(--sc-space-3);
3917
+ border-radius: var(--sc-radius-full);
3918
+ color: var(--sc-color-text-muted);
3919
+ font-size: var(--sc-text-sm);
3920
+ text-decoration: none;
3921
+ }
3922
+
3923
+ .sc-view:hover {
3924
+ background: var(--sc-color-bg-inset);
3925
+ color: var(--sc-color-text);
3926
+ }
3927
+
3928
+ .sc-view-current {
3929
+ background: var(--sc-color-bg-inset);
3930
+ color: var(--sc-color-text);
3931
+ font-weight: var(--sc-weight-medium);
3932
+ }
3933
+
3934
+ .sc-goal-tasks-view {
3935
+ display: flex;
3936
+ flex: 1 1 0;
3937
+ flex-direction: column;
3938
+ min-height: 0;
3939
+ }
3940
+
3941
+ .sc-goal-view-list {
3942
+ display: block;
3943
+ }
3944
+
3945
+ /* The done and dropped columns lead to the archive (ADR-0029), beside their count. */
3946
+ .sc-column-meta {
3947
+ display: inline-flex;
3948
+ align-items: center;
3949
+ gap: var(--sc-space-2);
3950
+ }
3951
+
3952
+ .sc-column-archive {
3953
+ color: var(--sc-color-text-muted);
3954
+ font-size: var(--sc-text-xs);
3955
+ text-decoration: none;
3956
+ }
3957
+
3958
+ .sc-column-archive:hover {
3959
+ color: var(--sc-color-text);
3960
+ text-decoration: underline;
3961
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../src/console.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../src/console.tsx"],"names":[],"mappings":"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"}
package/dist/console.js CHANGED
@@ -9,9 +9,10 @@ import { ConnectWords } from "./components/connect.js";
9
9
  import { DecisionForm } from "./components/decision-form.js";
10
10
  import { DecisionCard, DecisionList } from "./components/decision-list.js";
11
11
  import { EventFeed } from "./components/event-feed.js";
12
- import { GoalForm, GoalList, GoalView } from "./components/goals.js";
12
+ import { GoalForm, GoalList, GoalView, goalMonth } from "./components/goals.js";
13
+ import { PAGE_SIZE } from "./components/paged.js";
13
14
  import { ListingForm, PeopleList } from "./components/people.js";
14
- import { MemberList, ProjectForm, ProjectList, ProjectMark, } from "./components/projects.js";
15
+ import { MemberList, PackTokenForm, ProjectForm, ProjectList, ProjectMark, } from "./components/projects.js";
15
16
  import { GoalTimeline } from "./components/roadmap.js";
16
17
  import { RulesForm, RulesView } from "./components/rules.js";
17
18
  import { isPlainClick, Shell, } from "./components/shell.js";
@@ -21,7 +22,7 @@ import { TaskForm } from "./components/task-form.js";
21
22
  import { TaskList } from "./components/task-list.js";
22
23
  import { TaskView } from "./components/task-view.js";
23
24
  import { NewToken, TokenForm, TokenList } from "./components/tokens.js";
24
- import { Button, Callout, CategoryBadge, EmptyState, personName, Spinner, } from "./components/ui.js";
25
+ import { Button, Callout, CategoryBadge, EmptyState, personName, Spinner, StateBadge, Time, } from "./components/ui.js";
25
26
  import { WorkList } from "./components/work.js";
26
27
  import { ConnectPage } from "./connect-page.js";
27
28
  import { useConsoleData } from "./data.js";
@@ -199,13 +200,85 @@ function ProjectsPage(props) {
199
200
  navigation.replace(projectHref(made.key));
200
201
  }), onCancel: () => navigation.back(PATHS.projects) }) })), _jsx(components.ProjectList, { projects: data.projects, projectHref: href, onOpen: (project) => navigation.go(href(project)), empty: _jsx(EmptyState, { title: words.empty.title, body: words.empty.body, action: _jsx(LinkButton, { href: PATHS.newProject, children: words.newProject }) }) })] }));
201
202
  }
203
+ /**
204
+ * The archive of the board (ADR-0029): the tasks put away, newest first, a page at a time from
205
+ * the server, each brought back from here by whoever may work in the project.
206
+ */
207
+ function ArchivePage(props) {
208
+ const words = useWords();
209
+ const { project, data } = props;
210
+ const key = project.key;
211
+ const { busy, error, act } = useAction();
212
+ const [items, setItems] = useState([]);
213
+ const [more, setMore] = useState(false);
214
+ const [loaded, setLoaded] = useState(false);
215
+ const { archivedTasks } = data.actions;
216
+ const feedLength = data.events.length;
217
+ // The first page, read again whenever the project's feed grows: something was put away or brought back.
218
+ // biome-ignore lint/correctness/useExhaustiveDependencies: the feed's length is what triggers the read
219
+ useEffect(() => {
220
+ const controller = new AbortController();
221
+ archivedTasks({ limit: PAGE_SIZE, offset: 0 }, controller.signal)
222
+ .then((page) => {
223
+ if (!controller.signal.aborted) {
224
+ setItems(page.items);
225
+ setMore(page.more);
226
+ setLoaded(true);
227
+ }
228
+ })
229
+ .catch(() => undefined);
230
+ return () => controller.abort();
231
+ }, [archivedTasks, feedLength]);
232
+ const onMore = () => void archivedTasks({ limit: PAGE_SIZE, offset: items.length })
233
+ .then((page) => {
234
+ setItems((current) => [...current, ...page.items]);
235
+ setMore(page.more);
236
+ })
237
+ .catch(() => undefined);
238
+ const archive = words.archive;
239
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "sc-page-head", children: [_jsx("h1", { className: "sc-page-title", children: archive.title }), _jsx(LinkButton, { href: projectHref(key), children: words.nav.board })] }), _jsx("p", { className: "sc-lead", children: archive.lead }), error !== undefined && _jsx(Callout, { tone: "danger", children: error }), !loaded ? (_jsx(Spinner, { label: archive.loading })) : items.length === 0 ? (_jsx(EmptyState, { title: archive.empty.title, body: archive.empty.body })) : (_jsxs(_Fragment, { children: [_jsx("ul", { className: "sc-task-rows", "aria-label": archive.title, children: items.map((task) => (_jsxs("li", { className: "sc-task-row", children: [_jsxs("a", { className: "sc-task-row-title", href: taskHref(key, task.number), children: [_jsxs("span", { className: "sc-card-number", children: ["#", task.number] }), " ", task.title] }), _jsxs("span", { className: "sc-task-row-meta", children: [_jsx(StateBadge, { state: task.state }), task.archivedAt !== null && (_jsxs("span", { className: "sc-muted", children: [archive.since, " ", _jsx(Time, { iso: task.archivedAt })] })), _jsx(Button, { size: "sm", variant: "ghost", disabled: busy, onClick: () => void act(async () => {
240
+ await data.actions.restoreTask(task.id);
241
+ setItems((current) => current.filter((candidate) => candidate.id !== task.id));
242
+ }), children: archive.restore })] })] }, task.id))) }), more && (_jsx("div", { className: "sc-show-more", children: _jsx(Button, { variant: "secondary", size: "sm", onClick: onMore, children: archive.more }) }))] }))] }));
243
+ }
202
244
  function TaskPage(props) {
203
245
  const words = useWords();
204
246
  const { route, project, data, components, navigation, busy, error, act } = props;
205
247
  const key = project.key;
206
- const task = route.number === undefined
248
+ const current = route.number === undefined
207
249
  ? data.tasks.find((candidate) => candidate.id === route.id)
208
250
  : data.tasks.find((candidate) => candidate.number === route.number);
251
+ // A task put away is not among the board's (ADR-0029): it is asked for by itself.
252
+ const [fetched, setFetched] = useState(undefined);
253
+ const [missing, setMissing] = useState(undefined);
254
+ const { fetchTask } = data.actions;
255
+ const wanted = current === undefined && data.projectLoaded
256
+ ? route.number === undefined
257
+ ? route.id
258
+ : String(route.number)
259
+ : undefined;
260
+ useEffect(() => {
261
+ if (wanted === undefined) {
262
+ return;
263
+ }
264
+ const controller = new AbortController();
265
+ fetchTask(wanted, controller.signal)
266
+ .then((found) => {
267
+ if (!controller.signal.aborted) {
268
+ setFetched(found);
269
+ }
270
+ })
271
+ .catch(() => {
272
+ if (!controller.signal.aborted) {
273
+ setMissing(wanted);
274
+ }
275
+ });
276
+ return () => controller.abort();
277
+ }, [wanted, fetchTask]);
278
+ const task = current ??
279
+ (fetched !== undefined && (fetched.id === route.id || fetched.number === route.number)
280
+ ? fetched
281
+ : undefined);
209
282
  const [history, setHistory] = useState(undefined);
210
283
  const [comments, setComments] = useState(undefined);
211
284
  const { taskHistory, taskComments } = data.actions;
@@ -242,6 +315,9 @@ function TaskPage(props) {
242
315
  return () => controller.abort();
243
316
  }, [taskId, taskHistory, taskComments, feedLength]);
244
317
  if (task === undefined) {
318
+ if (wanted !== undefined && missing !== wanted) {
319
+ return _jsx(Spinner, { label: words.common.loading });
320
+ }
245
321
  return (_jsx(EmptyState, { title: words.task.noSuch.title, body: words.task.noSuch.body, action: _jsx(LinkButton, { href: projectHref(key), children: words.nav.board }) }));
246
322
  }
247
323
  const here = taskHref(key, task.number);
@@ -251,7 +327,12 @@ function TaskPage(props) {
251
327
  }), onMove: (target, state) => void act(() => data.actions.updateTask(target.id, { state })), onRaiseDecision: (input) => void act(async () => {
252
328
  await data.actions.raiseDecision(input);
253
329
  navigation.replace(here);
254
- }), onAnswer: (decision, input) => void act(() => data.actions.answerDecision(decision.id, input)), onUpdateDecision: (decision, patch) => void act(() => data.actions.updateDecision(decision.id, patch)), onAbandonRun: (run) => void act(() => data.actions.abandonRun(run.id)), onComment: (draft) => void act(async () => {
330
+ }), onAnswer: (decision, input) => void act(() => data.actions.answerDecision(decision.id, input)), onUpdateDecision: (decision, patch) => void act(() => data.actions.updateDecision(decision.id, patch)), onAbandonRun: (run) => void act(() => data.actions.abandonRun(run.id)), onArchive: (target) => void act(async () => {
331
+ await data.actions.archiveTask(target.id);
332
+ navigation.go(projectHref(key, "archive"));
333
+ }), onRestore: (target) => void act(async () => {
334
+ setFetched(await data.actions.restoreTask(target.id));
335
+ }), onComment: (draft) => void act(async () => {
255
336
  await data.actions.comment(task.id, {
256
337
  body: draft.body,
257
338
  files: draft.files.map((file) => ({
@@ -278,7 +359,7 @@ function ProjectPage(props) {
278
359
  if (route.name === "board") {
279
360
  const me = data.me?.person ?? undefined;
280
361
  const shown = filterTasks(data.tasks, route.filter, me);
281
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "sc-page-head", children: [_jsx("h1", { className: "sc-page-title", children: project.name }), _jsx(LinkButton, { href: newTaskHref(key), variant: "primary", children: words.board.writeTask })] }), project.description.length > 0 && _jsx("p", { className: "sc-lead", children: project.description }), error !== undefined && _jsx(Callout, { tone: "danger", children: error }), data.tasks.length > 0 && (_jsx(BoardFilters, { filter: route.filter, categories: data.categories, goals: data.goals, people: data.people.filter(inWorkspace), me: me, shown: shown.length, total: data.tasks.length, onChange: (filter) => navigation.replace(boardHref(key, filter)) })), _jsx(components.Board, { tasks: shown, taskHref: href, onOpen: (task) => navigation.go(href(task)), onMove: onMove, empty: data.tasks.length === 0 ? (_jsx(EmptyState, { title: words.board.empty.title, body: words.board.empty.body, action: _jsx(LinkButton, { href: newTaskHref(key), children: words.board.writeTask }) })) : undefined })] }));
362
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "sc-page-head", children: [_jsx("h1", { className: "sc-page-title", children: project.name }), _jsx(LinkButton, { href: newTaskHref(key), variant: "primary", children: words.board.writeTask })] }), project.description.length > 0 && _jsx("p", { className: "sc-lead", children: project.description }), error !== undefined && _jsx(Callout, { tone: "danger", children: error }), data.tasks.length > 0 && (_jsx(BoardFilters, { filter: route.filter, categories: data.categories, goals: data.goals, people: data.people.filter(inWorkspace), me: me, shown: shown.length, total: data.tasks.length, onChange: (filter) => navigation.replace(boardHref(key, filter)) })), _jsx(components.Board, { tasks: shown, taskHref: href, onOpen: (task) => navigation.go(href(task)), onMove: onMove, archiveHref: projectHref(key, "archive"), empty: data.tasks.length === 0 ? (_jsx(EmptyState, { title: words.board.empty.title, body: words.board.empty.body, action: _jsx(LinkButton, { href: newTaskHref(key), children: words.board.writeTask }) })) : undefined })] }));
282
363
  }
283
364
  if (route.name === "new-task") {
284
365
  return (_jsxs(_Fragment, { children: [_jsx("div", { className: "sc-page-head", children: _jsx("h1", { className: "sc-page-title", children: words.task.newTitle }) }), error !== undefined && _jsx(Callout, { tone: "danger", children: error }), _jsx("section", { className: "sc-panel sc-panel-form", "aria-label": words.task.newAria, children: _jsx(TaskForm, { people: data.people.filter(inWorkspace), parents: data.tasks, categories: data.categories, goals: data.goals, busy: busy, onSubmit: (input) => void act(async () => {
@@ -327,9 +408,24 @@ function ProjectPage(props) {
327
408
  navigation.replace(here);
328
409
  }), onCancel: () => navigation.back(here) }) })] }));
329
410
  }
330
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "sc-page-head", children: [_jsx("h1", { className: "sc-page-title", children: roadmap.one }), _jsx(LinkButton, { href: projectHref(key, "roadmap"), children: roadmap.all })] }), error !== undefined && _jsx(Callout, { tone: "danger", children: error }), _jsx(GoalView, { goal: goal, tasks: data.tasks, taskHref: href, docHref: toDoc, editHref: owner ? goalHref(key, goal.id, "edit") : undefined, onMove: owner
331
- ? (target, state) => void act(() => data.actions.updateGoal(target.id, { state }))
332
- : undefined, busy: busy })] }));
411
+ const now = today();
412
+ const towards = data.tasks.filter((task) => task.goalId === goal.id);
413
+ const month = route.month ?? goalMonth(goal, now);
414
+ const viewHref = (view) => goalHref(key, goal.id, { view });
415
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "sc-page-head", children: [_jsx("h1", { className: "sc-page-title", children: roadmap.one }), _jsx(LinkButton, { href: projectHref(key, "roadmap"), children: roadmap.all })] }), error !== undefined && _jsx(Callout, { tone: "danger", children: error }), _jsx(GoalView, { goal: goal, tasks: data.tasks, taskHref: href, docHref: toDoc, today: now, editHref: owner ? goalHref(key, goal.id, { form: "edit" }) : undefined, onMove: owner
416
+ ? (target, state) => void act(async () => {
417
+ await data.actions.updateGoal(target.id, { state });
418
+ // A goal closed takes its done and dropped tasks to the archive, if the person says so (ADR-0029).
419
+ const closed = towards.filter((task) => !OPEN_TASK_STATES.includes(task.state)).length;
420
+ if ((state === "done" || state === "dropped") &&
421
+ closed > 0 &&
422
+ window.confirm(roadmap.archiveAsk(closed))) {
423
+ await data.actions.archiveGoalTasks(target.id);
424
+ }
425
+ })
426
+ : undefined, onArchiveTasks: owner && towards.some((task) => !OPEN_TASK_STATES.includes(task.state))
427
+ ? () => void act(() => data.actions.archiveGoalTasks(goal.id))
428
+ : undefined, busy: busy, view: route.view, viewHref: viewHref, board: _jsx(components.Board, { tasks: towards, taskHref: href, onOpen: (task) => navigation.go(href(task)), onMove: onMove, today: now, archiveHref: projectHref(key, "archive"), empty: towards.length === 0 ? _jsx("p", { className: "sc-muted", children: roadmap.noTasks }) : undefined }), calendar: _jsx(components.Calendar, { tasks: towards, month: month, today: now, categories: data.categories, goals: [goal], taskHref: href, goalHref: (target) => goalHref(key, target.id), monthHref: (wanted) => goalHref(key, goal.id, { view: "calendar", month: wanted }) }) })] }));
333
429
  }
334
430
  if (route.name === "docs") {
335
431
  return (_jsx(DocsPage, { project: project, path: route.path, view: route.view, data: data, navigation: navigation }));
@@ -347,6 +443,9 @@ function ProjectPage(props) {
347
443
  const decision = data.decisions.find((candidate) => candidate.id === route.id);
348
444
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "sc-page-head", children: [_jsx("h1", { className: "sc-page-title", children: words.decisions.one }), _jsx(LinkButton, { href: projectHref(key, "decisions"), children: words.decisions.all })] }), error !== undefined && _jsx(Callout, { tone: "danger", children: error }), decision === undefined ? (_jsx(EmptyState, { title: words.decisions.noSuch.title, body: words.decisions.noSuch.body })) : (_jsx(DecisionCard, { decision: decision, task: decision.taskId === null ? undefined : tasksById.get(decision.taskId), taskHref: href, docHref: toDoc, onAnswer: onAnswer, onUpdate: onUpdate, busy: busy }))] }));
349
445
  }
446
+ if (route.name === "archive") {
447
+ return _jsx(ArchivePage, { project: project, data: data });
448
+ }
350
449
  if (route.name === "feed") {
351
450
  return (_jsxs(_Fragment, { children: [_jsx("div", { className: "sc-page-head", children: _jsx("h1", { className: "sc-page-title", children: words.feed.title }) }), _jsx(components.EventFeed, { events: data.events, href: (event) => {
352
451
  const task = event.taskId === null ? undefined : tasksById.get(event.taskId);
@@ -443,7 +542,21 @@ function ProjectSettingsPage(props) {
443
542
  navigation.replace(here);
444
543
  }), onCancel: () => navigation.back(here) })) })] }));
445
544
  }
446
- return (_jsxs(_Fragment, { children: [head, error !== undefined && _jsx(Callout, { tone: "danger", children: error }), _jsx("section", { className: "sc-panel", "aria-label": settings.aria, children: _jsxs("dl", { className: "sc-facts sc-facts-plain", children: [_jsxs("div", { children: [_jsx("dt", { children: form.name }), _jsx("dd", { children: project.name })] }), _jsxs("div", { children: [_jsx("dt", { children: form.key }), _jsx("dd", { children: _jsx("code", { className: "sc-project-key", children: project.key }) })] }), _jsxs("div", { children: [_jsx("dt", { children: form.whoIsMember }), _jsx("dd", { children: words.vocabulary.visibility[project.visibility] })] }), _jsxs("div", { children: [_jsx("dt", { children: form.skillsAddress }), _jsx("dd", { children: project.skillsAddress !== null ? (_jsxs("code", { children: [skills?.source ?? "", project.skillsAddress] })) : skills?.address != null ? (settings.organizationsSkills(skills.address)) : (settings.noSkills) })] }), _jsxs("div", { children: [_jsx("dt", { children: form.symbol }), _jsx("dd", { children: _jsx(ProjectMark, { project: project, size: "sm" }) })] }), project.description.length > 0 && (_jsxs("div", { className: "sc-facts-wide", children: [_jsx("dt", { children: form.description }), _jsx("dd", { children: project.description })] }))] }) }), _jsxs("section", { className: "sc-panel", "aria-label": words.rules.projectRules, children: [_jsx("h2", { className: "sc-section-title", children: words.rules.projectRules }), rules === undefined ? (_jsx(Spinner, { label: words.rules.loading })) : (_jsx(RulesView, { rules: rules.project, scope: "project", docHref: (path) => docHref(key, path), editHref: owner ? projectSettingsHref(key, "rules") : undefined, onArchive: owner
545
+ if (route.form === "pack-token") {
546
+ if (!owner) {
547
+ return _jsx(NothingHere, {});
548
+ }
549
+ return (_jsxs(_Fragment, { children: [head, error !== undefined && _jsx(Callout, { tone: "danger", children: error }), _jsx("section", { className: "sc-panel sc-panel-form", "aria-label": words.projects.packToken.aria, children: _jsx(PackTokenForm, { set: project.packToken !== null, busy: busy, onSubmit: (token) => void act(async () => {
550
+ await data.actions.setPackToken(token);
551
+ navigation.replace(here);
552
+ }), onRemove: project.packToken === null
553
+ ? undefined
554
+ : () => void act(async () => {
555
+ await data.actions.removePackToken();
556
+ navigation.replace(here);
557
+ }), onCancel: () => navigation.back(here) }) })] }));
558
+ }
559
+ return (_jsxs(_Fragment, { children: [head, error !== undefined && _jsx(Callout, { tone: "danger", children: error }), _jsx("section", { className: "sc-panel", "aria-label": settings.aria, children: _jsxs("dl", { className: "sc-facts sc-facts-plain", children: [_jsxs("div", { children: [_jsx("dt", { children: form.name }), _jsx("dd", { children: project.name })] }), _jsxs("div", { children: [_jsx("dt", { children: form.key }), _jsx("dd", { children: _jsx("code", { className: "sc-project-key", children: project.key }) })] }), _jsxs("div", { children: [_jsx("dt", { children: form.whoIsMember }), _jsx("dd", { children: words.vocabulary.visibility[project.visibility] })] }), _jsxs("div", { children: [_jsx("dt", { children: form.skillsAddress }), _jsx("dd", { children: project.skillsAddress !== null ? (_jsxs("code", { children: [skills?.source ?? "", project.skillsAddress] })) : skills?.address != null ? (settings.organizationsSkills(skills.address)) : (settings.noSkills) })] }), _jsxs("div", { children: [_jsx("dt", { children: settings.packToken }), _jsxs("dd", { children: [project.packToken === null ? (_jsx("span", { className: "sc-muted", children: settings.packTokenNone })) : (_jsxs(_Fragment, { children: [settings.packTokenSet, " ", _jsx(Time, { iso: project.packToken.setAt })] })), owner && (_jsxs(_Fragment, { children: [" ", _jsx("a", { href: projectSettingsHref(key, "pack-token"), children: settings.packTokenEdit })] }))] })] }), _jsxs("div", { children: [_jsx("dt", { children: form.symbol }), _jsx("dd", { children: _jsx(ProjectMark, { project: project, size: "sm" }) })] }), project.description.length > 0 && (_jsxs("div", { className: "sc-facts-wide", children: [_jsx("dt", { children: form.description }), _jsx("dd", { children: project.description })] }))] }) }), _jsxs("section", { className: "sc-panel", "aria-label": words.rules.projectRules, children: [_jsx("h2", { className: "sc-section-title", children: words.rules.projectRules }), rules === undefined ? (_jsx(Spinner, { label: words.rules.loading })) : (_jsx(RulesView, { rules: rules.project, scope: "project", docHref: (path) => docHref(key, path), editHref: owner ? projectSettingsHref(key, "rules") : undefined, onArchive: owner
447
560
  ? () => void act(async () => {
448
561
  await data.actions.archiveDocument(RULES_PATH);
449
562
  setRules(await data.actions.projectRules());
@@ -846,6 +959,7 @@ export function createConsole(config = {}) {
846
959
  current: candidate.tag === pack.tag,
847
960
  })), onLanguage: (tag) => void data.actions.updateMe({ language: tag }).catch(() => undefined), person: data.me.person, live: projectKey === undefined ? undefined : data.live, wide: route.name === "board" ||
848
961
  route.name === "calendar" ||
962
+ (route.name === "goal" && route.form === undefined) ||
849
963
  (route.name === "custom" &&
850
964
  pages.some((candidate) => candidate.key === route.page && candidate.wide === true)), onNavigate: (href) => navigation.go(href), onSignOut: viaToken ? undefined : () => void data.actions.signOut(), children: page }));
851
965
  }