@skillcdn/console 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/api.d.ts +4 -4
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +4 -4
- package/dist/api.js.map +1 -1
- package/dist/cli/cli.d.ts +4 -0
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +201 -25
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +15 -11
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +59 -26
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +1 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/pack.d.ts +7 -2
- package/dist/cli/pack.d.ts.map +1 -1
- package/dist/cli/pack.js +16 -2
- package/dist/cli/pack.js.map +1 -1
- package/dist/client.d.ts +20 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +17 -3
- package/dist/client.js.map +1 -1
- package/dist/compat.d.ts +28 -6
- package/dist/compat.d.ts.map +1 -1
- package/dist/compat.js +55 -14
- package/dist/compat.js.map +1 -1
- package/dist/components/board.d.ts +12 -1
- package/dist/components/board.d.ts.map +1 -1
- package/dist/components/board.js +57 -7
- package/dist/components/board.js.map +1 -1
- package/dist/components/calendar.d.ts +17 -7
- package/dist/components/calendar.d.ts.map +1 -1
- package/dist/components/calendar.js +89 -38
- package/dist/components/calendar.js.map +1 -1
- package/dist/components/decision-form.d.ts +12 -4
- package/dist/components/decision-form.d.ts.map +1 -1
- package/dist/components/decision-form.js +24 -6
- package/dist/components/decision-form.js.map +1 -1
- package/dist/components/decision-list.d.ts +4 -0
- package/dist/components/decision-list.d.ts.map +1 -1
- package/dist/components/decision-list.js +9 -6
- package/dist/components/decision-list.js.map +1 -1
- package/dist/components/documents.d.ts.map +1 -1
- package/dist/components/documents.js +3 -3
- package/dist/components/documents.js.map +1 -1
- package/dist/components/event-feed.d.ts.map +1 -1
- package/dist/components/event-feed.js +63 -8
- package/dist/components/event-feed.js.map +1 -1
- package/dist/components/my-decisions.d.ts +20 -0
- package/dist/components/my-decisions.d.ts.map +1 -0
- package/dist/components/my-decisions.js +36 -0
- package/dist/components/my-decisions.js.map +1 -0
- package/dist/components/people.d.ts.map +1 -1
- package/dist/components/people.js +1 -1
- package/dist/components/people.js.map +1 -1
- package/dist/components/picker.d.ts +39 -0
- package/dist/components/picker.d.ts.map +1 -0
- package/dist/components/picker.js +155 -0
- package/dist/components/picker.js.map +1 -0
- package/dist/components/projects.d.ts.map +1 -1
- package/dist/components/projects.js +3 -3
- package/dist/components/projects.js.map +1 -1
- package/dist/components/roadmap.js +1 -1
- package/dist/components/roadmap.js.map +1 -1
- package/dist/components/runs.d.ts.map +1 -1
- package/dist/components/runs.js +1 -1
- package/dist/components/runs.js.map +1 -1
- package/dist/components/shell.d.ts.map +1 -1
- package/dist/components/shell.js +36 -1
- package/dist/components/shell.js.map +1 -1
- package/dist/components/task-form.d.ts +18 -4
- package/dist/components/task-form.d.ts.map +1 -1
- package/dist/components/task-form.js +56 -13
- package/dist/components/task-form.js.map +1 -1
- package/dist/components/task-list.js +2 -2
- package/dist/components/task-list.js.map +1 -1
- package/dist/components/task-view.d.ts +7 -1
- package/dist/components/task-view.d.ts.map +1 -1
- package/dist/components/task-view.js +7 -6
- package/dist/components/task-view.js.map +1 -1
- package/dist/components/ui.d.ts +17 -0
- package/dist/components/ui.d.ts.map +1 -1
- package/dist/components/ui.js +26 -11
- package/dist/components/ui.js.map +1 -1
- package/dist/components/work.d.ts.map +1 -1
- package/dist/components/work.js +5 -3
- package/dist/components/work.js.map +1 -1
- package/dist/console.css +1794 -433
- package/dist/console.d.ts.map +1 -1
- package/dist/console.js +93 -10
- package/dist/console.js.map +1 -1
- package/dist/data.d.ts +21 -1
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +24 -1
- package/dist/data.js.map +1 -1
- package/dist/i18n/en.d.ts +45 -3
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +52 -10
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/ko.d.ts.map +1 -1
- package/dist/i18n/ko.js +54 -12
- package/dist/i18n/ko.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +2 -0
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +2 -0
- package/dist/limits.js.map +1 -1
- package/dist/router.d.ts +9 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +12 -0
- package/dist/router.js.map +1 -1
- package/dist/routes.d.ts +3 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +3 -1
- package/dist/routes.js.map +1 -1
- package/dist/rules.js +1 -1
- package/dist/rules.js.map +1 -1
- package/dist/schemas.d.ts +252 -12
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +27 -10
- package/dist/schemas.js.map +1 -1
- package/dist/vocabulary.d.ts +2 -0
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +2 -0
- package/dist/vocabulary.js.map +1 -1
- package/docs/specs/cli.md +14 -13
- package/docs/specs/rest.md +24 -19
- package/package.json +2 -2
- package/skills/building-a-console/SKILL.md +4 -4
- package/skills/building-a-console/references/the-default-console.md +4 -4
- package/skills/building-a-console/references/the-look-from-a-website.md +5 -5
- package/skills/deploying-a-console/SKILL.md +2 -2
- package/skills/deploying-a-console/references/resources.md +1 -1
- package/skills/working-the-board/SKILL.md +8 -6
- package/skills/working-the-board/references/terms.md +3 -3
- package/src/api.ts +7 -0
- package/src/cli/cli.ts +254 -25
- package/src/cli/format.ts +22 -11
- package/src/cli/help.ts +63 -26
- package/src/cli/main.ts +1 -0
- package/src/cli/pack.ts +17 -1
- package/src/client.ts +44 -11
- package/src/compat.ts +63 -14
- package/src/components/board.tsx +124 -25
- package/src/components/calendar.tsx +258 -117
- package/src/components/decision-form.tsx +71 -23
- package/src/components/decision-list.tsx +30 -3
- package/src/components/documents.tsx +27 -11
- package/src/components/event-feed.tsx +116 -33
- package/src/components/my-decisions.tsx +138 -0
- package/src/components/people.tsx +3 -1
- package/src/components/picker.tsx +297 -0
- package/src/components/projects.tsx +7 -5
- package/src/components/roadmap.tsx +1 -1
- package/src/components/runs.tsx +5 -1
- package/src/components/shell.tsx +36 -1
- package/src/components/task-form.tsx +149 -63
- package/src/components/task-list.tsx +3 -3
- package/src/components/task-view.tsx +71 -56
- package/src/components/ui.tsx +89 -11
- package/src/components/work.tsx +6 -4
- package/src/console.tsx +157 -29
- package/src/data.ts +61 -1
- package/src/i18n/en.ts +54 -10
- package/src/i18n/ko.ts +56 -12
- package/src/index.ts +19 -1
- package/src/limits.ts +2 -0
- package/src/router.ts +18 -1
- package/src/routes.ts +3 -1
- package/src/rules.ts +1 -1
- package/src/schemas.ts +29 -9
- package/src/styles/console.css +1794 -433
- package/src/vocabulary.ts +3 -0
package/src/components/board.tsx
CHANGED
|
@@ -20,7 +20,6 @@ import { useWords } from "../i18n/index.js";
|
|
|
20
20
|
import type { BoardFilter } from "../router.js";
|
|
21
21
|
import { isPlainClick } from "./shell.js";
|
|
22
22
|
import {
|
|
23
|
-
Avatar,
|
|
24
23
|
Badge,
|
|
25
24
|
Button,
|
|
26
25
|
CategoryBadge,
|
|
@@ -28,6 +27,7 @@ import {
|
|
|
28
27
|
DueBadge,
|
|
29
28
|
PriorityBadge,
|
|
30
29
|
personName,
|
|
30
|
+
Workers,
|
|
31
31
|
} from "./ui.js";
|
|
32
32
|
|
|
33
33
|
// The board: one column per state, the tasks in it, the sooner due first and the newest after.
|
|
@@ -59,8 +59,17 @@ export interface BoardProps {
|
|
|
59
59
|
readonly onEdit?: ((task: RestTask) => void) | undefined;
|
|
60
60
|
/** Called when a task is put away from its card's menu (ADR-0029, ADR-0030). Left out, the menu offers nothing of it. */
|
|
61
61
|
readonly onArchive?: ((task: RestTask) => void) | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* The columns folded to a strip until a person opens them, with their count and the way to open
|
|
64
|
+
* them; a folded column still takes a card dragged onto it. What is finished, by default, so that
|
|
65
|
+
* the work at hand has the room; `[]` folds none.
|
|
66
|
+
*/
|
|
67
|
+
readonly folded?: readonly TaskState[] | undefined;
|
|
62
68
|
}
|
|
63
69
|
|
|
70
|
+
/** The columns a board folds unless told otherwise: the work that is over. */
|
|
71
|
+
export const FOLDED_STATES: readonly TaskState[] = ["done", "dropped"];
|
|
72
|
+
|
|
64
73
|
/** How far a mouse travels on a card before the press is a drag and not a click. */
|
|
65
74
|
const DRAG_SLACK = 4;
|
|
66
75
|
/**
|
|
@@ -160,12 +169,12 @@ export function TaskCard(props: TaskCardProps) {
|
|
|
160
169
|
<DueBadge dueOn={task.dueOn} state={task.state} today={props.today} />
|
|
161
170
|
)}
|
|
162
171
|
{task.openDecisions > 0 && (
|
|
163
|
-
<Badge tone="warning" title={words.board.decisionsTitle}>
|
|
172
|
+
<Badge tone="warning" kind="count" title={words.board.decisionsTitle}>
|
|
164
173
|
{words.board.decisions(task.openDecisions)}
|
|
165
174
|
</Badge>
|
|
166
175
|
)}
|
|
167
176
|
<span className="sc-card-spacer" />
|
|
168
|
-
|
|
177
|
+
<Workers workers={task.workers} size="sm" />
|
|
169
178
|
</div>
|
|
170
179
|
</article>
|
|
171
180
|
);
|
|
@@ -364,6 +373,19 @@ export function Board(props: BoardProps) {
|
|
|
364
373
|
const { onMove } = props;
|
|
365
374
|
const board = useRef<HTMLDivElement>(null);
|
|
366
375
|
const [drag, setDrag] = useState<Drag | null>(null);
|
|
376
|
+
// The foldable columns a person has opened on this board; the others of them stay folded.
|
|
377
|
+
const [opened, setOpened] = useState<ReadonlySet<TaskState>>(() => new Set());
|
|
378
|
+
const foldable = props.folded ?? FOLDED_STATES;
|
|
379
|
+
const toggle = (state: TaskState) =>
|
|
380
|
+
setOpened((before) => {
|
|
381
|
+
const after = new Set(before);
|
|
382
|
+
if (after.has(state)) {
|
|
383
|
+
after.delete(state);
|
|
384
|
+
} else {
|
|
385
|
+
after.add(state);
|
|
386
|
+
}
|
|
387
|
+
return after;
|
|
388
|
+
});
|
|
367
389
|
// What the pointer's release reads, so that the move is made outside a state update.
|
|
368
390
|
const current = useRef<Drag | null>(null);
|
|
369
391
|
current.current = drag;
|
|
@@ -511,38 +533,65 @@ export function Board(props: BoardProps) {
|
|
|
511
533
|
>
|
|
512
534
|
{TASK_STATES.map((state) => {
|
|
513
535
|
const tasks = props.tasks.filter((task) => task.state === state).sort(byDue);
|
|
536
|
+
const name = words.vocabulary.state[state];
|
|
537
|
+
const canFold = foldable.includes(state);
|
|
538
|
+
const folded = canFold && !opened.has(state);
|
|
514
539
|
return (
|
|
515
540
|
<section
|
|
516
541
|
key={state}
|
|
517
542
|
className={cx(
|
|
518
543
|
"sc-column",
|
|
519
544
|
`sc-column-${state}`,
|
|
545
|
+
folded && "sc-column-folded",
|
|
520
546
|
dragging?.over === state && "sc-column-over",
|
|
521
547
|
)}
|
|
522
|
-
aria-label={
|
|
548
|
+
aria-label={name}
|
|
523
549
|
data-column={state}
|
|
524
550
|
>
|
|
525
551
|
<header className="sc-column-header">
|
|
526
|
-
<h2 className="sc-column-title">{
|
|
552
|
+
<h2 className="sc-column-title">{name}</h2>
|
|
527
553
|
<span className="sc-column-count">{tasks.length}</span>
|
|
554
|
+
{canFold && (
|
|
555
|
+
<button
|
|
556
|
+
type="button"
|
|
557
|
+
className="sc-column-toggle"
|
|
558
|
+
aria-expanded={!folded}
|
|
559
|
+
aria-label={folded ? words.board.unfold(name) : words.board.fold(name)}
|
|
560
|
+
title={folded ? words.board.unfold(name) : words.board.fold(name)}
|
|
561
|
+
onClick={() => toggle(state)}
|
|
562
|
+
>
|
|
563
|
+
<svg viewBox="0 0 16 16" aria-hidden="true">
|
|
564
|
+
<path
|
|
565
|
+
d={folded ? "M6 4l4 4-4 4" : "M10 4l-4 4 4 4"}
|
|
566
|
+
fill="none"
|
|
567
|
+
stroke="currentColor"
|
|
568
|
+
strokeWidth="1.5"
|
|
569
|
+
strokeLinecap="round"
|
|
570
|
+
strokeLinejoin="round"
|
|
571
|
+
/>
|
|
572
|
+
</svg>
|
|
573
|
+
</button>
|
|
574
|
+
)}
|
|
528
575
|
</header>
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
576
|
+
{!folded && (
|
|
577
|
+
<div className="sc-column-body">
|
|
578
|
+
{tasks.map((task) => (
|
|
579
|
+
<TaskCard
|
|
580
|
+
key={task.id}
|
|
581
|
+
task={task}
|
|
582
|
+
href={props.taskHref(task)}
|
|
583
|
+
onOpen={props.onOpen}
|
|
584
|
+
today={props.today}
|
|
585
|
+
onPress={onMove === undefined ? undefined : press}
|
|
586
|
+
dragging={dragging?.task.id === task.id}
|
|
587
|
+
editHref={props.editHref?.(task)}
|
|
588
|
+
onEdit={props.onEdit}
|
|
589
|
+
onArchive={props.onArchive}
|
|
590
|
+
/>
|
|
591
|
+
))}
|
|
592
|
+
{tasks.length === 0 && state === "idea" && props.empty}
|
|
593
|
+
</div>
|
|
594
|
+
)}
|
|
546
595
|
</section>
|
|
547
596
|
);
|
|
548
597
|
})}
|
|
@@ -571,23 +620,59 @@ export function Board(props: BoardProps) {
|
|
|
571
620
|
);
|
|
572
621
|
}
|
|
573
622
|
|
|
574
|
-
/** What
|
|
623
|
+
/** What a task is found by: its title, its number, its owner and its workers, its category. */
|
|
624
|
+
function wordsOf(task: RestTask): string {
|
|
625
|
+
return [
|
|
626
|
+
task.title,
|
|
627
|
+
`#${task.number}`,
|
|
628
|
+
personName(task.owner),
|
|
629
|
+
task.owner.login,
|
|
630
|
+
...task.workers.flatMap((worker) => [personName(worker), worker.login]),
|
|
631
|
+
task.category?.name ?? "",
|
|
632
|
+
]
|
|
633
|
+
.join("\n")
|
|
634
|
+
.toLowerCase();
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* What the filter keeps of the board: a category or none, a goal or none, a person, one's own,
|
|
639
|
+
* and the tasks that contain every word typed, whatever the case.
|
|
640
|
+
*/
|
|
575
641
|
export function filterTasks(
|
|
576
642
|
tasks: readonly RestTask[],
|
|
577
643
|
filter: BoardFilter,
|
|
578
644
|
me?: RestPerson | undefined,
|
|
579
645
|
): RestTask[] {
|
|
646
|
+
const wanted =
|
|
647
|
+
filter.words === undefined
|
|
648
|
+
? []
|
|
649
|
+
: filter.words
|
|
650
|
+
.toLowerCase()
|
|
651
|
+
.split(/\s+/)
|
|
652
|
+
.filter((word) => word.length > 0);
|
|
580
653
|
return tasks.filter((task) => {
|
|
654
|
+
if (wanted.length > 0) {
|
|
655
|
+
const found = wordsOf(task);
|
|
656
|
+
if (!wanted.every((word) => found.includes(word))) {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
581
660
|
if (filter.category !== undefined && (task.category?.key ?? "") !== filter.category) {
|
|
582
661
|
return false;
|
|
583
662
|
}
|
|
584
663
|
if (filter.goal !== undefined && (task.goalId ?? "") !== filter.goal) {
|
|
585
664
|
return false;
|
|
586
665
|
}
|
|
587
|
-
if (
|
|
666
|
+
if (
|
|
667
|
+
filter.person !== undefined &&
|
|
668
|
+
!task.workers.some((worker) => worker.id === filter.person)
|
|
669
|
+
) {
|
|
588
670
|
return false;
|
|
589
671
|
}
|
|
590
|
-
if (
|
|
672
|
+
if (
|
|
673
|
+
filter.mine === true &&
|
|
674
|
+
(me === undefined || !task.workers.some((worker) => worker.id === me.id))
|
|
675
|
+
) {
|
|
591
676
|
return false;
|
|
592
677
|
}
|
|
593
678
|
return true;
|
|
@@ -627,6 +712,20 @@ export function BoardFilters(props: BoardFiltersProps) {
|
|
|
627
712
|
aria-label={words.aria}
|
|
628
713
|
onSubmit={(event) => event.preventDefault()}
|
|
629
714
|
>
|
|
715
|
+
<label className="sc-field sc-field-inline sc-filters-words">
|
|
716
|
+
<span className="sc-visually-hidden">{words.words}</span>
|
|
717
|
+
<input
|
|
718
|
+
className="sc-input"
|
|
719
|
+
type="search"
|
|
720
|
+
placeholder={words.words}
|
|
721
|
+
value={filter.words ?? ""}
|
|
722
|
+
onChange={(event) =>
|
|
723
|
+
event.target.value.trim() === ""
|
|
724
|
+
? change({}, "words")
|
|
725
|
+
: change({ words: event.target.value })
|
|
726
|
+
}
|
|
727
|
+
/>
|
|
728
|
+
</label>
|
|
630
729
|
<label className="sc-field sc-field-inline">
|
|
631
730
|
<span className="sc-visually-hidden">{words.anyCategory}</span>
|
|
632
731
|
<select
|