@skillcdn/console 0.4.0 → 0.4.2
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 +20 -2
- package/SKILLCDN.md +7 -5
- package/dist/api.d.ts +5 -4
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +5 -4
- package/dist/api.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +579 -45
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/format.d.ts +34 -3
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +277 -6
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +60 -7
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/plugin-check.d.ts +21 -0
- package/dist/cli/plugin-check.d.ts.map +1 -0
- package/dist/cli/plugin-check.js +374 -0
- package/dist/cli/plugin-check.js.map +1 -0
- package/dist/cli/plugin-cli.d.ts +20 -0
- package/dist/cli/plugin-cli.d.ts.map +1 -0
- package/dist/cli/plugin-cli.js +123 -0
- package/dist/cli/plugin-cli.js.map +1 -0
- package/dist/cli/plugin-init.d.ts +20 -0
- package/dist/cli/plugin-init.d.ts.map +1 -0
- package/dist/cli/plugin-init.js +74 -0
- package/dist/cli/plugin-init.js.map +1 -0
- package/dist/cli/plugin-main.d.ts +3 -0
- package/dist/cli/plugin-main.d.ts.map +1 -0
- package/dist/cli/plugin-main.js +28 -0
- package/dist/cli/plugin-main.js.map +1 -0
- package/dist/client.d.ts +109 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +67 -2
- package/dist/client.js.map +1 -1
- package/dist/compat.d.ts +1 -1
- package/dist/compat.js +2 -2
- package/dist/components/board.d.ts +8 -0
- package/dist/components/board.d.ts.map +1 -1
- package/dist/components/board.js +59 -15
- package/dist/components/board.js.map +1 -1
- package/dist/components/event-feed.d.ts +1 -1
- package/dist/components/event-feed.d.ts.map +1 -1
- package/dist/components/event-feed.js +33 -1
- package/dist/components/event-feed.js.map +1 -1
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +6 -3
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/pack-connect.d.ts +3 -1
- package/dist/components/pack-connect.d.ts.map +1 -1
- package/dist/components/pack-connect.js +4 -4
- package/dist/components/pack-connect.js.map +1 -1
- package/dist/components/pack-token.d.ts +3 -1
- package/dist/components/pack-token.d.ts.map +1 -1
- package/dist/components/pack-token.js +1 -1
- package/dist/components/pack-token.js.map +1 -1
- package/dist/components/people.d.ts.map +1 -1
- package/dist/components/people.js +14 -3
- package/dist/components/people.js.map +1 -1
- package/dist/components/plugin-frame.d.ts +52 -0
- package/dist/components/plugin-frame.d.ts.map +1 -0
- package/dist/components/plugin-frame.js +314 -0
- package/dist/components/plugin-frame.js.map +1 -0
- package/dist/components/plugin-settings.d.ts +38 -0
- package/dist/components/plugin-settings.d.ts.map +1 -0
- package/dist/components/plugin-settings.js +348 -0
- package/dist/components/plugin-settings.js.map +1 -0
- package/dist/components/remote-pictures.d.ts +6 -0
- package/dist/components/remote-pictures.d.ts.map +1 -0
- package/dist/components/remote-pictures.js +8 -0
- package/dist/components/remote-pictures.js.map +1 -0
- package/dist/components/shell.d.ts +2 -0
- package/dist/components/shell.d.ts.map +1 -1
- package/dist/components/shell.js +26 -1
- package/dist/components/shell.js.map +1 -1
- package/dist/components/sign-in.d.ts.map +1 -1
- package/dist/components/sign-in.js +49 -2
- package/dist/components/sign-in.js.map +1 -1
- package/dist/components/ui.d.ts +3 -2
- package/dist/components/ui.d.ts.map +1 -1
- package/dist/components/ui.js +6 -3
- package/dist/components/ui.js.map +1 -1
- package/dist/components/workspace.d.ts +7 -1
- package/dist/components/workspace.d.ts.map +1 -1
- package/dist/components/workspace.js +1 -1
- package/dist/components/workspace.js.map +1 -1
- package/dist/console.css +384 -5
- package/dist/console.d.ts.map +1 -1
- package/dist/console.js +146 -29
- package/dist/console.js.map +1 -1
- package/dist/data.d.ts +11 -2
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +35 -21
- package/dist/data.js.map +1 -1
- package/dist/i18n/en.d.ts +163 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +174 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/ko.d.ts.map +1 -1
- package/dist/i18n/ko.js +154 -1
- package/dist/i18n/ko.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +14 -0
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +14 -0
- package/dist/limits.js.map +1 -1
- package/dist/plugin/args.d.ts +148 -0
- package/dist/plugin/args.d.ts.map +1 -0
- package/dist/plugin/args.js +369 -0
- package/dist/plugin/args.js.map +1 -0
- package/dist/plugin/bridge.d.ts +146 -0
- package/dist/plugin/bridge.d.ts.map +1 -0
- package/dist/plugin/bridge.js +125 -0
- package/dist/plugin/bridge.js.map +1 -0
- package/dist/plugin/capabilities.d.ts +20 -0
- package/dist/plugin/capabilities.d.ts.map +1 -0
- package/dist/plugin/capabilities.js +133 -0
- package/dist/plugin/capabilities.js.map +1 -0
- package/dist/plugin/context.d.ts +374 -0
- package/dist/plugin/context.d.ts.map +1 -0
- package/dist/plugin/context.js +2 -0
- package/dist/plugin/context.js.map +1 -0
- package/dist/plugin/define.d.ts +208 -0
- package/dist/plugin/define.d.ts.map +1 -0
- package/dist/plugin/define.js +482 -0
- package/dist/plugin/define.js.map +1 -0
- package/dist/plugin/definition-error.d.ts +11 -0
- package/dist/plugin/definition-error.d.ts.map +1 -0
- package/dist/plugin/definition-error.js +17 -0
- package/dist/plugin/definition-error.js.map +1 -0
- package/dist/plugin/limits.d.ts +67 -0
- package/dist/plugin/limits.d.ts.map +1 -0
- package/dist/plugin/limits.js +70 -0
- package/dist/plugin/limits.js.map +1 -0
- package/dist/plugin/load-worker.d.ts +7 -0
- package/dist/plugin/load-worker.d.ts.map +1 -0
- package/dist/plugin/load-worker.js +41 -0
- package/dist/plugin/load-worker.js.map +1 -0
- package/dist/plugin/load.d.ts +18 -0
- package/dist/plugin/load.d.ts.map +1 -0
- package/dist/plugin/load.js +62 -0
- package/dist/plugin/load.js.map +1 -0
- package/dist/plugin/manifest.d.ts +237 -0
- package/dist/plugin/manifest.d.ts.map +1 -0
- package/dist/plugin/manifest.js +411 -0
- package/dist/plugin/manifest.js.map +1 -0
- package/dist/plugin/refusals.d.ts +49 -0
- package/dist/plugin/refusals.d.ts.map +1 -0
- package/dist/plugin/refusals.js +79 -0
- package/dist/plugin/refusals.js.map +1 -0
- package/dist/plugin/rest-schemas.d.ts +556 -0
- package/dist/plugin/rest-schemas.d.ts.map +1 -0
- package/dist/plugin/rest-schemas.js +262 -0
- package/dist/plugin/rest-schemas.js.map +1 -0
- package/dist/plugin/sandbox.d.ts +23 -0
- package/dist/plugin/sandbox.d.ts.map +1 -0
- package/dist/plugin/sandbox.js +99 -0
- package/dist/plugin/sandbox.js.map +1 -0
- package/dist/plugin/testing.d.ts +45 -0
- package/dist/plugin/testing.d.ts.map +1 -0
- package/dist/plugin/testing.js +420 -0
- package/dist/plugin/testing.js.map +1 -0
- package/dist/plugin/web-react.d.ts +11 -0
- package/dist/plugin/web-react.d.ts.map +1 -0
- package/dist/plugin/web-react.js +34 -0
- package/dist/plugin/web-react.js.map +1 -0
- package/dist/plugin/web.d.ts +95 -0
- package/dist/plugin/web.d.ts.map +1 -0
- package/dist/plugin/web.js +245 -0
- package/dist/plugin/web.js.map +1 -0
- package/dist/plugin-nav.d.ts +29 -0
- package/dist/plugin-nav.d.ts.map +1 -0
- package/dist/plugin-nav.js +92 -0
- package/dist/plugin-nav.js.map +1 -0
- package/dist/plugin-testing.d.ts +2 -0
- package/dist/plugin-testing.d.ts.map +1 -0
- package/dist/plugin-testing.js +4 -0
- package/dist/plugin-testing.js.map +1 -0
- package/dist/plugin-web-react.d.ts +3 -0
- package/dist/plugin-web-react.d.ts.map +1 -0
- package/dist/plugin-web-react.js +3 -0
- package/dist/plugin-web-react.js.map +1 -0
- package/dist/plugin-web.d.ts +4 -0
- package/dist/plugin-web.d.ts.map +1 -0
- package/dist/plugin-web.js +5 -0
- package/dist/plugin-web.js.map +1 -0
- package/dist/plugin.d.ts +11 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +15 -0
- package/dist/plugin.js.map +1 -0
- package/dist/router.d.ts +28 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +47 -0
- package/dist/router.js.map +1 -1
- package/dist/routes.d.ts +6 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +8 -0
- package/dist/routes.js.map +1 -1
- package/dist/schemas.d.ts +147 -1
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +55 -5
- package/dist/schemas.js.map +1 -1
- package/dist/tokens.d.ts +2 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +101 -0
- package/dist/tokens.js.map +1 -0
- package/dist/vocabulary.d.ts +11 -1
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +24 -0
- package/dist/vocabulary.js.map +1 -1
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +5 -2
- package/dist/web.js.map +1 -1
- package/docs/specs/cli.md +16 -9
- package/docs/specs/plugins.md +487 -0
- package/docs/specs/rest.md +25 -13
- package/package.json +21 -3
- package/skills/building-a-console/SKILL.md +25 -26
- package/skills/building-a-console/references/configuring.md +40 -0
- package/skills/building-a-console/references/the-default-console.md +1 -1
- package/skills/building-a-console/references/the-look-from-a-website.md +5 -5
- package/skills/building-a-plugin/SKILL.md +137 -0
- package/skills/deploying-a-console/SKILL.md +24 -26
- package/skills/deploying-a-console/references/access.md +13 -9
- package/skills/deploying-a-console/references/resources.md +25 -10
- package/skills/deploying-a-console/references/running-it-again.md +15 -0
- package/skills/deploying-a-console/references/sizing.md +2 -0
- package/skills/planning-the-board/SKILL.md +96 -0
- package/skills/planning-the-board/references/a-task.md +36 -0
- package/skills/planning-the-board/references/setting-up.md +44 -0
- package/skills/working-the-board/SKILL.md +43 -34
- package/skills/working-the-board/references/the-pack.md +19 -0
- package/src/api.ts +16 -0
- package/src/cli/cli.ts +736 -45
- package/src/cli/format.ts +356 -9
- package/src/cli/help.ts +71 -6
- package/src/cli/plugin-check.ts +470 -0
- package/src/cli/plugin-cli.ts +148 -0
- package/src/cli/plugin-init.ts +90 -0
- package/src/cli/plugin-main.ts +30 -0
- package/src/client.ts +324 -1
- package/src/compat.ts +2 -2
- package/src/components/board.tsx +62 -14
- package/src/components/event-feed.tsx +42 -1
- package/src/components/markdown.tsx +6 -3
- package/src/components/pack-connect.tsx +10 -7
- package/src/components/pack-token.tsx +4 -1
- package/src/components/people.tsx +17 -7
- package/src/components/plugin-frame.tsx +437 -0
- package/src/components/plugin-settings.tsx +1111 -0
- package/src/components/remote-pictures.ts +19 -0
- package/src/components/shell.tsx +82 -14
- package/src/components/sign-in.tsx +114 -13
- package/src/components/ui.tsx +6 -3
- package/src/components/workspace.tsx +18 -0
- package/src/console.tsx +309 -23
- package/src/data.ts +47 -22
- package/src/i18n/en.ts +183 -1
- package/src/i18n/ko.ts +159 -1
- package/src/index.ts +12 -0
- package/src/limits.ts +14 -0
- package/src/plugin/args.ts +526 -0
- package/src/plugin/bridge.ts +314 -0
- package/src/plugin/capabilities.ts +150 -0
- package/src/plugin/context.ts +416 -0
- package/src/plugin/define.ts +792 -0
- package/src/plugin/definition-error.ts +19 -0
- package/src/plugin/limits.ts +70 -0
- package/src/plugin/load-worker.ts +50 -0
- package/src/plugin/load.ts +82 -0
- package/src/plugin/manifest.ts +561 -0
- package/src/plugin/refusals.ts +94 -0
- package/src/plugin/rest-schemas.ts +354 -0
- package/src/plugin/sandbox.ts +123 -0
- package/src/plugin/testing.ts +612 -0
- package/src/plugin/web-react.ts +45 -0
- package/src/plugin/web.ts +403 -0
- package/src/plugin-nav.ts +132 -0
- package/src/plugin-testing.ts +10 -0
- package/src/plugin-web-react.ts +4 -0
- package/src/plugin-web.ts +35 -0
- package/src/plugin.ts +126 -0
- package/src/router.ts +73 -0
- package/src/routes.ts +9 -0
- package/src/schemas.ts +60 -4
- package/src/styles/console.css +384 -5
- package/src/tokens.ts +101 -0
- package/src/vocabulary.ts +30 -0
- package/src/web.ts +5 -2
- package/template/plugin/.gitignore +2 -0
- package/template/plugin/README.md +26 -0
- package/template/plugin/SKILLCDN.md +13 -0
- package/template/plugin/build.mjs +40 -0
- package/template/plugin/console-plugin.json +50 -0
- package/template/plugin/package.json +27 -0
- package/template/plugin/skills/__key__/SKILL.md +23 -0
- package/template/plugin/src/check.test.ts +34 -0
- package/template/plugin/src/server/index.test.ts +41 -0
- package/template/plugin/src/server/index.ts +72 -0
- package/template/plugin/src/web/index.css +51 -0
- package/template/plugin/src/web/index.ts +115 -0
- package/template/plugin/tsconfig.json +17 -0
- package/skills/working-the-board/references/setting-up.md +0 -3
- /package/skills/{working-the-board → planning-the-board}/references/project-rules.md +0 -0
package/src/console.tsx
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type RestDecisionPatch,
|
|
24
24
|
type RestEvent,
|
|
25
25
|
type RestMyDecisions,
|
|
26
|
+
type RestPluginDetail,
|
|
26
27
|
type RestProject,
|
|
27
28
|
type RestProjectInput,
|
|
28
29
|
type RestProjectPatch,
|
|
@@ -50,6 +51,8 @@ import { MyDecisions } from "./components/my-decisions.js";
|
|
|
50
51
|
import { PackTokenWays } from "./components/pack-token.js";
|
|
51
52
|
import { PAGE_SIZE } from "./components/paged.js";
|
|
52
53
|
import { ListingForm, PeopleList, type PeopleListProps } from "./components/people.js";
|
|
54
|
+
import { PluginFrame, PluginWidgets } from "./components/plugin-frame.js";
|
|
55
|
+
import { PluginSettingsList, PluginSettingsView } from "./components/plugin-settings.js";
|
|
53
56
|
import {
|
|
54
57
|
MemberList,
|
|
55
58
|
type MemberListProps,
|
|
@@ -58,6 +61,7 @@ import {
|
|
|
58
61
|
type ProjectListProps,
|
|
59
62
|
ProjectMark,
|
|
60
63
|
} from "./components/projects.js";
|
|
64
|
+
import { type RemotePictureSrc, RemotePicturesContext } from "./components/remote-pictures.js";
|
|
61
65
|
import { GoalTimeline } from "./components/roadmap.js";
|
|
62
66
|
import { RulesForm, RulesView } from "./components/rules.js";
|
|
63
67
|
import {
|
|
@@ -103,6 +107,7 @@ import {
|
|
|
103
107
|
type Messages,
|
|
104
108
|
useWords,
|
|
105
109
|
} from "./i18n/index.js";
|
|
110
|
+
import { pluginNavItems, pluginPagesAt, pluginWordOf } from "./plugin-nav.js";
|
|
106
111
|
import {
|
|
107
112
|
boardHref,
|
|
108
113
|
calendarHref,
|
|
@@ -120,6 +125,8 @@ import {
|
|
|
120
125
|
PATHS,
|
|
121
126
|
personAgentsHref,
|
|
122
127
|
personWorkHref,
|
|
128
|
+
pluginHref,
|
|
129
|
+
pluginSettingsHref,
|
|
123
130
|
projectHref,
|
|
124
131
|
projectSettingsHref,
|
|
125
132
|
type Route,
|
|
@@ -392,24 +399,45 @@ function ProjectsPage(props: {
|
|
|
392
399
|
readonly data: ConsoleData;
|
|
393
400
|
readonly components: ConsoleComponents;
|
|
394
401
|
readonly navigation: Navigation;
|
|
402
|
+
readonly client: ConsoleClient;
|
|
403
|
+
readonly language: string;
|
|
395
404
|
/** Whether the form for a new project is open: the page is at its address. */
|
|
396
405
|
readonly making: boolean;
|
|
397
406
|
}) {
|
|
398
407
|
const words = useWords().projects;
|
|
399
|
-
const { data, components, navigation,
|
|
408
|
+
const { data, components, navigation, client, language } = props;
|
|
409
|
+
const me = data.me;
|
|
410
|
+
/** The plugins' widgets at a place of this page (ADR-0054), for the person's roles. */
|
|
411
|
+
const widgets = (place: "home:top" | "home:bottom") =>
|
|
412
|
+
me === undefined ? null : (
|
|
413
|
+
<PluginWidgets
|
|
414
|
+
plugins={data.plugins}
|
|
415
|
+
place={place}
|
|
416
|
+
me={me}
|
|
417
|
+
language={language}
|
|
418
|
+
client={client}
|
|
419
|
+
navigation={navigation}
|
|
420
|
+
nameOf={(name) => pluginWordOf(name, language)}
|
|
421
|
+
/>
|
|
422
|
+
);
|
|
400
423
|
const { busy, error, act } = useAction();
|
|
401
424
|
const href = (project: RestProject) => projectHref(project.key);
|
|
425
|
+
// A project is made by an administrator (ADR-0045): a member sees the list alone, the form's
|
|
426
|
+
// address included.
|
|
427
|
+
const administrator = data.me?.person?.role === "admin";
|
|
428
|
+
const making = props.making && administrator;
|
|
402
429
|
return (
|
|
403
430
|
<>
|
|
404
431
|
<div className="sc-page-head">
|
|
405
432
|
<h1 className="sc-page-title">{words.title}</h1>
|
|
406
|
-
{!making && (
|
|
433
|
+
{administrator && !making && (
|
|
407
434
|
<LinkButton href={PATHS.newProject} variant="primary">
|
|
408
435
|
{words.newProject}
|
|
409
436
|
</LinkButton>
|
|
410
437
|
)}
|
|
411
438
|
</div>
|
|
412
439
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
440
|
+
{widgets("home:top")}
|
|
413
441
|
{making && (
|
|
414
442
|
<section className="sc-panel sc-panel-form" aria-label={words.form.aria}>
|
|
415
443
|
<ProjectForm
|
|
@@ -436,15 +464,159 @@ function ProjectsPage(props: {
|
|
|
436
464
|
empty={
|
|
437
465
|
<EmptyState
|
|
438
466
|
title={words.empty.title}
|
|
439
|
-
body={words.empty.body}
|
|
440
|
-
action={
|
|
467
|
+
body={administrator ? words.empty.body : words.empty.bodyMember}
|
|
468
|
+
action={
|
|
469
|
+
administrator ? (
|
|
470
|
+
<LinkButton href={PATHS.newProject}>{words.newProject}</LinkButton>
|
|
471
|
+
) : undefined
|
|
472
|
+
}
|
|
441
473
|
/>
|
|
442
474
|
}
|
|
443
475
|
/>
|
|
476
|
+
{widgets("home:bottom")}
|
|
444
477
|
</>
|
|
445
478
|
);
|
|
446
479
|
}
|
|
447
480
|
|
|
481
|
+
/**
|
|
482
|
+
* A plugin's page (ADR-0054): the sub-tabs of its pages at the level, where it has several, above
|
|
483
|
+
* the frame of the one shown, the first when the address names none. Nothing for a plugin the
|
|
484
|
+
* person has no page of, or that is not on the project.
|
|
485
|
+
*/
|
|
486
|
+
function PluginPage(props: {
|
|
487
|
+
readonly route: Extract<Route, { name: "plugin" }>;
|
|
488
|
+
readonly data: ConsoleData;
|
|
489
|
+
readonly project: RestProject | undefined;
|
|
490
|
+
readonly client: ConsoleClient;
|
|
491
|
+
readonly language: string;
|
|
492
|
+
readonly navigation: Navigation;
|
|
493
|
+
}) {
|
|
494
|
+
const words = useWords();
|
|
495
|
+
const { route, data, project, client, language, navigation } = props;
|
|
496
|
+
const plugin = data.plugins.find(
|
|
497
|
+
(candidate) => candidate.key === route.plugin && candidate.state === "enabled",
|
|
498
|
+
);
|
|
499
|
+
const bound =
|
|
500
|
+
route.level === "workspace" ||
|
|
501
|
+
data.projectPlugins.some((candidate) => candidate.key === route.plugin);
|
|
502
|
+
const pages = plugin === undefined ? [] : pluginPagesAt(plugin, route.level);
|
|
503
|
+
const page = route.page === undefined ? pages[0] : pages.find((p) => p.key === route.page);
|
|
504
|
+
if (plugin === undefined || !bound || page === undefined || data.me === undefined) {
|
|
505
|
+
return <EmptyState title={words.plugins.noPage.title} body={words.plugins.noPage.body} />;
|
|
506
|
+
}
|
|
507
|
+
const projectKey = route.level === "project" ? route.project : undefined;
|
|
508
|
+
return (
|
|
509
|
+
<>
|
|
510
|
+
{pages.length > 1 && (
|
|
511
|
+
<nav className="sc-subtabs" aria-label={pluginWordOf(plugin.name, language)}>
|
|
512
|
+
{pages.map((candidate) => (
|
|
513
|
+
<a
|
|
514
|
+
key={candidate.key}
|
|
515
|
+
href={pluginHref(plugin.key, candidate.key, projectKey)}
|
|
516
|
+
className={candidate.key === page.key ? "sc-tab sc-tab-current" : "sc-tab"}
|
|
517
|
+
aria-current={candidate.key === page.key ? "page" : undefined}
|
|
518
|
+
>
|
|
519
|
+
{pluginWordOf(candidate.name, language)}
|
|
520
|
+
</a>
|
|
521
|
+
))}
|
|
522
|
+
</nav>
|
|
523
|
+
)}
|
|
524
|
+
<PluginFrame
|
|
525
|
+
key={`${plugin.key}:${page.key}:${projectKey ?? ""}`}
|
|
526
|
+
plugin={plugin}
|
|
527
|
+
page={page.key}
|
|
528
|
+
project={project}
|
|
529
|
+
path={route.rest}
|
|
530
|
+
me={data.me}
|
|
531
|
+
language={language}
|
|
532
|
+
client={client}
|
|
533
|
+
navigation={navigation}
|
|
534
|
+
events={project === undefined ? undefined : data.events}
|
|
535
|
+
title={words.plugins.frame(pluginWordOf(page.name, language))}
|
|
536
|
+
/>
|
|
537
|
+
</>
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* The plugins' settings (docs/specs/plugins.md, "The settings pages"): the list, or one plugin
|
|
543
|
+
* whole, read again after every change; for an administrator.
|
|
544
|
+
*/
|
|
545
|
+
function PluginSettingsPage(props: {
|
|
546
|
+
readonly plugin: string | undefined;
|
|
547
|
+
readonly data: ConsoleData;
|
|
548
|
+
readonly client: ConsoleClient;
|
|
549
|
+
readonly language: string;
|
|
550
|
+
readonly navigation: Navigation;
|
|
551
|
+
}) {
|
|
552
|
+
const words = useWords();
|
|
553
|
+
const { data, client, language, navigation } = props;
|
|
554
|
+
const settings = words.plugins.settings;
|
|
555
|
+
const administrator = data.me?.person?.role === "admin";
|
|
556
|
+
const [detail, setDetail] = useState<RestPluginDetail | undefined>(undefined);
|
|
557
|
+
const [failure, setFailure] = useState<string | undefined>(undefined);
|
|
558
|
+
const key = props.plugin;
|
|
559
|
+
const read = useCallback(async () => {
|
|
560
|
+
if (key === undefined) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
try {
|
|
564
|
+
setDetail(await client.plugin(key).get());
|
|
565
|
+
setFailure(undefined);
|
|
566
|
+
} catch (error) {
|
|
567
|
+
setFailure(error instanceof ApiError ? error.message : words.common.somethingWentWrong);
|
|
568
|
+
}
|
|
569
|
+
}, [client, key, words.common.somethingWentWrong]);
|
|
570
|
+
useEffect(() => {
|
|
571
|
+
setDetail(undefined);
|
|
572
|
+
void read();
|
|
573
|
+
}, [read]);
|
|
574
|
+
if (!administrator) {
|
|
575
|
+
return <NothingHere />;
|
|
576
|
+
}
|
|
577
|
+
if (key === undefined) {
|
|
578
|
+
return (
|
|
579
|
+
<>
|
|
580
|
+
<div className="sc-page-head">
|
|
581
|
+
<h1 className="sc-page-title">{settings.title}</h1>
|
|
582
|
+
</div>
|
|
583
|
+
<PluginSettingsList
|
|
584
|
+
plugins={data.plugins}
|
|
585
|
+
language={language}
|
|
586
|
+
href={(plugin) => pluginSettingsHref(plugin.key)}
|
|
587
|
+
/>
|
|
588
|
+
</>
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
if (failure !== undefined) {
|
|
592
|
+
return <EmptyState title={words.common.somethingWentWrong} body={failure} />;
|
|
593
|
+
}
|
|
594
|
+
if (detail === undefined) {
|
|
595
|
+
return (
|
|
596
|
+
<div className="sc-loading">
|
|
597
|
+
<Spinner label={words.common.loading} />
|
|
598
|
+
</div>
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
return (
|
|
602
|
+
<PluginSettingsView
|
|
603
|
+
detail={detail}
|
|
604
|
+
projects={data.projects}
|
|
605
|
+
people={data.people}
|
|
606
|
+
language={language}
|
|
607
|
+
client={client}
|
|
608
|
+
onChanged={async () => {
|
|
609
|
+
await read();
|
|
610
|
+
await data.actions.refreshPlugins();
|
|
611
|
+
}}
|
|
612
|
+
onPurged={() => {
|
|
613
|
+
void data.actions.refreshPlugins();
|
|
614
|
+
navigation.replace(pluginSettingsHref());
|
|
615
|
+
}}
|
|
616
|
+
/>
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
|
|
448
620
|
/**
|
|
449
621
|
* The archive of the board (ADR-0029): the tasks put away, newest first, a page at a time from
|
|
450
622
|
* the server, each brought back from here by whoever may work in the project.
|
|
@@ -738,6 +910,8 @@ function ProjectPage(props: {
|
|
|
738
910
|
readonly data: ConsoleData;
|
|
739
911
|
readonly components: ConsoleComponents;
|
|
740
912
|
readonly navigation: Navigation;
|
|
913
|
+
readonly client: ConsoleClient;
|
|
914
|
+
readonly language: string;
|
|
741
915
|
}) {
|
|
742
916
|
const words = useWords();
|
|
743
917
|
const { route, project, data, components, navigation } = props;
|
|
@@ -1304,6 +1478,18 @@ function ProjectPage(props: {
|
|
|
1304
1478
|
<ProjectSettingsPage route={route} project={project} data={data} navigation={navigation} />
|
|
1305
1479
|
);
|
|
1306
1480
|
}
|
|
1481
|
+
if (route.name === "plugin") {
|
|
1482
|
+
return (
|
|
1483
|
+
<PluginPage
|
|
1484
|
+
route={route}
|
|
1485
|
+
data={data}
|
|
1486
|
+
project={project}
|
|
1487
|
+
client={props.client}
|
|
1488
|
+
language={props.language}
|
|
1489
|
+
navigation={navigation}
|
|
1490
|
+
/>
|
|
1491
|
+
);
|
|
1492
|
+
}
|
|
1307
1493
|
return <NothingHere />;
|
|
1308
1494
|
}
|
|
1309
1495
|
|
|
@@ -1432,6 +1618,7 @@ function ProjectSettingsPage(props: {
|
|
|
1432
1618
|
busy={busy}
|
|
1433
1619
|
onStart={data.actions.connectPackToken}
|
|
1434
1620
|
poll={data.actions.packTokenConnection}
|
|
1621
|
+
claim={data.actions.claimPackTokenConnection}
|
|
1435
1622
|
onCancelConnect={data.actions.cancelPackTokenConnection}
|
|
1436
1623
|
onConnected={() => navigation.replace(here)}
|
|
1437
1624
|
onSubmit={(token) =>
|
|
@@ -1568,9 +1755,10 @@ function WorkspaceSettingsPage(props: {
|
|
|
1568
1755
|
readonly form: "rules" | "workspace" | "pack-token" | undefined;
|
|
1569
1756
|
readonly data: ConsoleData;
|
|
1570
1757
|
readonly navigation: Navigation;
|
|
1758
|
+
readonly language: string;
|
|
1571
1759
|
}) {
|
|
1572
1760
|
const words = useWords();
|
|
1573
|
-
const { form, data, navigation } = props;
|
|
1761
|
+
const { form, data, navigation, language } = props;
|
|
1574
1762
|
const { busy, error, act } = useAction();
|
|
1575
1763
|
const administrator = data.me?.person?.role === "admin";
|
|
1576
1764
|
const workspace = data.me?.workspace;
|
|
@@ -1654,6 +1842,7 @@ function WorkspaceSettingsPage(props: {
|
|
|
1654
1842
|
busy={busy}
|
|
1655
1843
|
onStart={data.actions.connectWorkspacePackToken}
|
|
1656
1844
|
poll={data.actions.workspacePackTokenConnection}
|
|
1845
|
+
claim={data.actions.claimWorkspacePackTokenConnection}
|
|
1657
1846
|
onCancelConnect={data.actions.cancelWorkspacePackTokenConnection}
|
|
1658
1847
|
onConnected={() => navigation.replace(PATHS.settings)}
|
|
1659
1848
|
onSubmit={(token) =>
|
|
@@ -1718,7 +1907,7 @@ function WorkspaceSettingsPage(props: {
|
|
|
1718
1907
|
</a>
|
|
1719
1908
|
)}
|
|
1720
1909
|
</div>
|
|
1721
|
-
<WorkspaceSettingsView workspace={workspace} />
|
|
1910
|
+
<WorkspaceSettingsView workspace={workspace} console={data.me?.console} />
|
|
1722
1911
|
</section>
|
|
1723
1912
|
)}
|
|
1724
1913
|
<section className="sc-panel" aria-label={words.rules.title}>
|
|
@@ -1742,6 +1931,20 @@ function WorkspaceSettingsPage(props: {
|
|
|
1742
1931
|
/>
|
|
1743
1932
|
)}
|
|
1744
1933
|
</section>
|
|
1934
|
+
{administrator && (
|
|
1935
|
+
<section className="sc-panel" aria-label={words.plugins.settings.title}>
|
|
1936
|
+
<h2 className="sc-section-title">{words.plugins.settings.title}</h2>
|
|
1937
|
+
{data.plugins.length === 0 ? (
|
|
1938
|
+
<p className="sc-settings-hint">{words.plugins.settings.empty.body}</p>
|
|
1939
|
+
) : (
|
|
1940
|
+
<PluginSettingsList
|
|
1941
|
+
plugins={data.plugins}
|
|
1942
|
+
language={language}
|
|
1943
|
+
href={(plugin) => pluginSettingsHref(plugin.key)}
|
|
1944
|
+
/>
|
|
1945
|
+
)}
|
|
1946
|
+
</section>
|
|
1947
|
+
)}
|
|
1745
1948
|
<section className="sc-panel" aria-label={words.settings.categories}>
|
|
1746
1949
|
<h2 className="sc-section-title">{words.settings.categories}</h2>
|
|
1747
1950
|
{data.categories.length > 0 && (
|
|
@@ -2163,11 +2366,36 @@ function WorkspacePage(props: {
|
|
|
2163
2366
|
readonly data: ConsoleData;
|
|
2164
2367
|
readonly components: ConsoleComponents;
|
|
2165
2368
|
readonly navigation: Navigation;
|
|
2369
|
+
readonly client: ConsoleClient;
|
|
2370
|
+
readonly language: string;
|
|
2166
2371
|
}) {
|
|
2167
2372
|
const words = useWords();
|
|
2168
|
-
const { route, data, components, navigation } = props;
|
|
2373
|
+
const { route, data, components, navigation, client, language } = props;
|
|
2169
2374
|
const [fresh, setFresh] = useState<RestTokenCreated | undefined>(undefined);
|
|
2170
2375
|
const { busy, error, act } = useAction();
|
|
2376
|
+
if (route.name === "plugin" && route.level === "workspace") {
|
|
2377
|
+
return (
|
|
2378
|
+
<PluginPage
|
|
2379
|
+
route={route}
|
|
2380
|
+
data={data}
|
|
2381
|
+
project={undefined}
|
|
2382
|
+
client={client}
|
|
2383
|
+
language={language}
|
|
2384
|
+
navigation={navigation}
|
|
2385
|
+
/>
|
|
2386
|
+
);
|
|
2387
|
+
}
|
|
2388
|
+
if (route.name === "plugins-settings") {
|
|
2389
|
+
return (
|
|
2390
|
+
<PluginSettingsPage
|
|
2391
|
+
plugin={route.plugin}
|
|
2392
|
+
data={data}
|
|
2393
|
+
client={client}
|
|
2394
|
+
language={language}
|
|
2395
|
+
navigation={navigation}
|
|
2396
|
+
/>
|
|
2397
|
+
);
|
|
2398
|
+
}
|
|
2171
2399
|
|
|
2172
2400
|
if (route.name === "work") {
|
|
2173
2401
|
return <WorkPage data={data} components={components} week={route.week} />;
|
|
@@ -2179,7 +2407,14 @@ function WorkspacePage(props: {
|
|
|
2179
2407
|
return <PersonWorkPage id={route.id} data={data} components={components} week={route.week} />;
|
|
2180
2408
|
}
|
|
2181
2409
|
if (route.name === "workspace-settings") {
|
|
2182
|
-
return
|
|
2410
|
+
return (
|
|
2411
|
+
<WorkspaceSettingsPage
|
|
2412
|
+
form={route.form}
|
|
2413
|
+
data={data}
|
|
2414
|
+
navigation={navigation}
|
|
2415
|
+
language={language}
|
|
2416
|
+
/>
|
|
2417
|
+
);
|
|
2183
2418
|
}
|
|
2184
2419
|
if (route.name === "categories") {
|
|
2185
2420
|
const me = data.me?.person ?? undefined;
|
|
@@ -2334,6 +2569,8 @@ function WorkspacePage(props: {
|
|
|
2334
2569
|
export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
2335
2570
|
const components: ConsoleComponents = { ...DEFAULT_COMPONENTS, ...config.components };
|
|
2336
2571
|
const client = config.client ?? createClient({ baseUrl: config.baseUrl ?? "" });
|
|
2572
|
+
/** Where the pages read a picture from elsewhere (ADR-0048): through this client's console. */
|
|
2573
|
+
const pictureSrc: RemotePictureSrc = (url) => client.pictureUrl(url);
|
|
2337
2574
|
const fallbackTitle = config.title ?? "Console";
|
|
2338
2575
|
const languages = config.languages ?? DEFAULT_LANGUAGES;
|
|
2339
2576
|
const pages = config.pages ?? [];
|
|
@@ -2440,13 +2677,6 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
2440
2677
|
current: route.name === "agents" || route.name === "new-token",
|
|
2441
2678
|
},
|
|
2442
2679
|
]),
|
|
2443
|
-
// The settings are read by everyone: the rules every agent follows, the categories and
|
|
2444
|
-
// what the colours mean, where the skills come from; kept by an administrator.
|
|
2445
|
-
{
|
|
2446
|
-
href: PATHS.settings,
|
|
2447
|
-
label: words.nav.settings,
|
|
2448
|
-
current: route.name === "workspace-settings" || route.name === "categories",
|
|
2449
|
-
},
|
|
2450
2680
|
...pages
|
|
2451
2681
|
.filter((candidate) => candidate.level === "workspace")
|
|
2452
2682
|
.map((candidate) => ({
|
|
@@ -2457,6 +2687,28 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
2457
2687
|
route.level === "workspace" &&
|
|
2458
2688
|
route.page === candidate.key,
|
|
2459
2689
|
})),
|
|
2690
|
+
// The plugins' tabs (ADR-0054): the groups that hold a plugin the person has a page of.
|
|
2691
|
+
...pluginNavItems({
|
|
2692
|
+
plugins: data.plugins,
|
|
2693
|
+
level: "workspace",
|
|
2694
|
+
current: {
|
|
2695
|
+
plugin:
|
|
2696
|
+
route.name === "plugin" && route.level === "workspace" ? route.plugin : undefined,
|
|
2697
|
+
},
|
|
2698
|
+
words,
|
|
2699
|
+
language: pack.tag,
|
|
2700
|
+
}),
|
|
2701
|
+
// The settings are read by everyone: the rules every agent follows, the categories and
|
|
2702
|
+
// what the colours mean, where the skills come from, the plugins; kept by an
|
|
2703
|
+
// administrator. Last, after the organization's own tabs and the plugins'.
|
|
2704
|
+
{
|
|
2705
|
+
href: PATHS.settings,
|
|
2706
|
+
label: words.nav.settings,
|
|
2707
|
+
current:
|
|
2708
|
+
route.name === "workspace-settings" ||
|
|
2709
|
+
route.name === "categories" ||
|
|
2710
|
+
route.name === "plugins-settings",
|
|
2711
|
+
},
|
|
2460
2712
|
];
|
|
2461
2713
|
const nav: NavItem[] =
|
|
2462
2714
|
projectKey === undefined
|
|
@@ -2508,12 +2760,6 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
2508
2760
|
label: words.nav.members,
|
|
2509
2761
|
current: route.name === "members",
|
|
2510
2762
|
},
|
|
2511
|
-
// Read by every member: what the project is, and what its agents are asked (ADR-0023).
|
|
2512
|
-
{
|
|
2513
|
-
href: projectHref(projectKey, "settings"),
|
|
2514
|
-
label: words.nav.settings,
|
|
2515
|
-
current: route.name === "settings",
|
|
2516
|
-
},
|
|
2517
2763
|
...pages
|
|
2518
2764
|
.filter((candidate) => candidate.level === "project")
|
|
2519
2765
|
.map((candidate) => ({
|
|
@@ -2524,6 +2770,24 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
2524
2770
|
route.level === "project" &&
|
|
2525
2771
|
route.page === candidate.key,
|
|
2526
2772
|
})),
|
|
2773
|
+
...pluginNavItems({
|
|
2774
|
+
plugins: data.plugins,
|
|
2775
|
+
level: "project",
|
|
2776
|
+
project: { key: projectKey, plugins: data.projectPlugins },
|
|
2777
|
+
current: {
|
|
2778
|
+
plugin:
|
|
2779
|
+
route.name === "plugin" && route.level === "project" ? route.plugin : undefined,
|
|
2780
|
+
},
|
|
2781
|
+
words,
|
|
2782
|
+
language: pack.tag,
|
|
2783
|
+
}),
|
|
2784
|
+
// Read by every member: what the project is, and what its agents are asked
|
|
2785
|
+
// (ADR-0023). Last, after the organization's own tabs and the plugins'.
|
|
2786
|
+
{
|
|
2787
|
+
href: projectHref(projectKey, "settings"),
|
|
2788
|
+
label: words.nav.settings,
|
|
2789
|
+
current: route.name === "settings",
|
|
2790
|
+
},
|
|
2527
2791
|
];
|
|
2528
2792
|
/** A page of the console's own at the address, or nothing there. */
|
|
2529
2793
|
const customPageOf = (key: string, level: CustomPage["level"]): ReactNode => {
|
|
@@ -2549,6 +2813,8 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
2549
2813
|
data={data}
|
|
2550
2814
|
components={components}
|
|
2551
2815
|
navigation={navigation}
|
|
2816
|
+
client={client}
|
|
2817
|
+
language={pack.tag}
|
|
2552
2818
|
making={route.name === "new-project"}
|
|
2553
2819
|
/>
|
|
2554
2820
|
);
|
|
@@ -2561,6 +2827,8 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
2561
2827
|
data={data}
|
|
2562
2828
|
components={components}
|
|
2563
2829
|
navigation={navigation}
|
|
2830
|
+
client={client}
|
|
2831
|
+
language={pack.tag}
|
|
2564
2832
|
/>
|
|
2565
2833
|
);
|
|
2566
2834
|
} else if (data.projectError !== undefined) {
|
|
@@ -2587,6 +2855,8 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
2587
2855
|
data={data}
|
|
2588
2856
|
components={components}
|
|
2589
2857
|
navigation={navigation}
|
|
2858
|
+
client={client}
|
|
2859
|
+
language={pack.tag}
|
|
2590
2860
|
/>
|
|
2591
2861
|
);
|
|
2592
2862
|
}
|
|
@@ -2619,7 +2889,17 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
2619
2889
|
route.name === "calendar" ||
|
|
2620
2890
|
(route.name === "goal" && route.form === undefined) ||
|
|
2621
2891
|
(route.name === "custom" &&
|
|
2622
|
-
pages.some((candidate) => candidate.key === route.page && candidate.wide === true))
|
|
2892
|
+
pages.some((candidate) => candidate.key === route.page && candidate.wide === true)) ||
|
|
2893
|
+
(route.name === "plugin" &&
|
|
2894
|
+
data.plugins.some(
|
|
2895
|
+
(candidate) =>
|
|
2896
|
+
candidate.key === route.plugin &&
|
|
2897
|
+
pluginPagesAt(candidate, route.level).some(
|
|
2898
|
+
(candidate, index) =>
|
|
2899
|
+
candidate.wide &&
|
|
2900
|
+
(route.page === undefined ? index === 0 : candidate.key === route.page),
|
|
2901
|
+
),
|
|
2902
|
+
))
|
|
2623
2903
|
}
|
|
2624
2904
|
onNavigate={(href) => navigation.go(href)}
|
|
2625
2905
|
onSignOut={viaToken ? undefined : () => void data.actions.signOut()}
|
|
@@ -2628,7 +2908,13 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
2628
2908
|
</components.Shell>
|
|
2629
2909
|
);
|
|
2630
2910
|
}
|
|
2631
|
-
return
|
|
2911
|
+
return (
|
|
2912
|
+
<LanguageContext.Provider value={pack}>
|
|
2913
|
+
<RemotePicturesContext.Provider value={pictureSrc}>
|
|
2914
|
+
{content}
|
|
2915
|
+
</RemotePicturesContext.Provider>
|
|
2916
|
+
</LanguageContext.Provider>
|
|
2917
|
+
);
|
|
2632
2918
|
}
|
|
2633
2919
|
|
|
2634
2920
|
return {
|