@skillcdn/console 0.1.12 → 0.1.14
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 +6 -4
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +260 -6
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/format.d.ts +7 -1
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +22 -0
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +69 -2
- package/dist/cli/help.js.map +1 -1
- package/dist/components/calendar.d.ts +15 -0
- package/dist/components/calendar.d.ts.map +1 -1
- package/dist/components/calendar.js +57 -30
- package/dist/components/calendar.js.map +1 -1
- package/dist/components/decision-list.d.ts.map +1 -1
- package/dist/components/decision-list.js +1 -1
- package/dist/components/decision-list.js.map +1 -1
- package/dist/components/skills.d.ts.map +1 -1
- package/dist/components/skills.js +1 -1
- package/dist/components/skills.js.map +1 -1
- package/dist/components/work.d.ts +4 -0
- package/dist/components/work.d.ts.map +1 -1
- package/dist/components/work.js +8 -3
- package/dist/components/work.js.map +1 -1
- package/dist/connect-page.d.ts.map +1 -1
- package/dist/connect-page.js +1 -1
- package/dist/connect-page.js.map +1 -1
- package/dist/console.css +35 -1
- package/dist/console.d.ts +3 -2
- package/dist/console.d.ts.map +1 -1
- package/dist/console.js +24 -58
- package/dist/console.js.map +1 -1
- package/dist/dates.d.ts +4 -0
- package/dist/dates.d.ts.map +1 -1
- package/dist/dates.js +26 -0
- package/dist/dates.js.map +1 -1
- package/dist/i18n/en.d.ts +7 -19
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +10 -22
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/ko.d.ts.map +1 -1
- package/dist/i18n/ko.js +10 -22
- package/dist/i18n/ko.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/router.d.ts +4 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +10 -2
- package/dist/router.js.map +1 -1
- package/docs/specs/cli.md +15 -2
- package/docs/specs/rest.md +13 -13
- package/package.json +1 -1
- package/skills/building-a-console/SKILL.md +2 -2
- package/skills/working-the-board/SKILL.md +5 -1
- package/src/cli/cli.ts +333 -5
- package/src/cli/format.ts +27 -0
- package/src/cli/help.ts +86 -1
- package/src/components/calendar.tsx +219 -91
- package/src/components/decision-list.tsx +0 -1
- package/src/components/skills.tsx +0 -1
- package/src/components/work.tsx +66 -46
- package/src/connect-page.tsx +0 -1
- package/src/console.tsx +22 -74
- package/src/dates.ts +28 -0
- package/src/i18n/en.ts +10 -28
- package/src/i18n/ko.ts +10 -28
- package/src/index.ts +5 -0
- package/src/router.ts +15 -5
- package/src/styles/console.css +35 -1
package/src/console.tsx
CHANGED
|
@@ -91,6 +91,7 @@ import {
|
|
|
91
91
|
signInFailureOf,
|
|
92
92
|
taskHref,
|
|
93
93
|
withoutSignInParam,
|
|
94
|
+
workHref,
|
|
94
95
|
} from "./router.js";
|
|
95
96
|
import { projectPath } from "./routes.js";
|
|
96
97
|
import { errorWords, useAction } from "./use-action.js";
|
|
@@ -332,13 +333,12 @@ function holdsToken(data: ConsoleData): boolean {
|
|
|
332
333
|
}
|
|
333
334
|
|
|
334
335
|
/**
|
|
335
|
-
* The pages a console that holds a token does not offer: the tokens themselves and
|
|
336
|
-
*
|
|
336
|
+
* The pages a console that holds a token does not offer: the tokens themselves, and the
|
|
337
|
+
* approval of an agent's connection, which makes one; a person's own doing on the console's
|
|
338
|
+
* own pages, signed in. Everything else a person may do, their agent may (ADR-0021).
|
|
337
339
|
*/
|
|
338
340
|
export function onlyOnOwnPages(route: Route): boolean {
|
|
339
341
|
return (
|
|
340
|
-
route.name === "new-project" ||
|
|
341
|
-
route.name === "settings" ||
|
|
342
342
|
route.name === "agents" ||
|
|
343
343
|
route.name === "new-token" ||
|
|
344
344
|
route.name === "person-agents" ||
|
|
@@ -351,28 +351,6 @@ function NotWithToken() {
|
|
|
351
351
|
return <EmptyState title={words.title} body={words.body} />;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
-
/**
|
|
355
|
-
* Where a console that holds a token keeps the person's choice of language: the browser's own
|
|
356
|
-
* storage, which may be absent or refuse, and then the browser's languages decide.
|
|
357
|
-
*/
|
|
358
|
-
const LANGUAGE_KEY = "sc-language";
|
|
359
|
-
|
|
360
|
-
function storedLanguage(): string | undefined {
|
|
361
|
-
try {
|
|
362
|
-
return globalThis.localStorage?.getItem(LANGUAGE_KEY) ?? undefined;
|
|
363
|
-
} catch {
|
|
364
|
-
return undefined;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
function storeLanguage(tag: string): void {
|
|
369
|
-
try {
|
|
370
|
-
globalThis.localStorage?.setItem(LANGUAGE_KEY, tag);
|
|
371
|
-
} catch {
|
|
372
|
-
// A browser that keeps nothing: the choice holds for this page.
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
354
|
/** A link that reads as a button: where a form is, for instance. */
|
|
377
355
|
function LinkButton(props: {
|
|
378
356
|
readonly href: string;
|
|
@@ -397,18 +375,16 @@ function ProjectsPage(props: {
|
|
|
397
375
|
const { data, components, navigation, making } = props;
|
|
398
376
|
const { busy, error, act } = useAction();
|
|
399
377
|
const href = (project: RestProject) => projectHref(project.key);
|
|
400
|
-
const configures = !holdsToken(data);
|
|
401
378
|
return (
|
|
402
379
|
<>
|
|
403
380
|
<div className="sc-page-head">
|
|
404
381
|
<h1 className="sc-page-title">{words.title}</h1>
|
|
405
|
-
{!making &&
|
|
382
|
+
{!making && (
|
|
406
383
|
<LinkButton href={PATHS.newProject} variant="primary">
|
|
407
384
|
{words.newProject}
|
|
408
385
|
</LinkButton>
|
|
409
386
|
)}
|
|
410
387
|
</div>
|
|
411
|
-
<p className="sc-lead">{words.lead}</p>
|
|
412
388
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
413
389
|
{making && (
|
|
414
390
|
<section className="sc-panel sc-panel-form" aria-label={words.form.aria}>
|
|
@@ -435,11 +411,7 @@ function ProjectsPage(props: {
|
|
|
435
411
|
<EmptyState
|
|
436
412
|
title={words.empty.title}
|
|
437
413
|
body={words.empty.body}
|
|
438
|
-
action={
|
|
439
|
-
configures ? (
|
|
440
|
-
<LinkButton href={PATHS.newProject}>{words.newProject}</LinkButton>
|
|
441
|
-
) : undefined
|
|
442
|
-
}
|
|
414
|
+
action={<LinkButton href={PATHS.newProject}>{words.newProject}</LinkButton>}
|
|
443
415
|
/>
|
|
444
416
|
}
|
|
445
417
|
/>
|
|
@@ -668,7 +640,6 @@ function ProjectPage(props: {
|
|
|
668
640
|
{words.board.writeTask}
|
|
669
641
|
</LinkButton>
|
|
670
642
|
</div>
|
|
671
|
-
<p className="sc-lead">{calendar.lead}</p>
|
|
672
643
|
{data.tasks.length > 0 && (
|
|
673
644
|
<BoardFilters
|
|
674
645
|
filter={route.filter}
|
|
@@ -718,7 +689,6 @@ function ProjectPage(props: {
|
|
|
718
689
|
{open.length > 0 && (
|
|
719
690
|
<section className="sc-task-section" aria-label={calendar.workload.title}>
|
|
720
691
|
<h2 className="sc-section-title">{calendar.workload.title}</h2>
|
|
721
|
-
<p className="sc-lead">{calendar.workload.lead}</p>
|
|
722
692
|
<Workload
|
|
723
693
|
tasks={shown}
|
|
724
694
|
today={now}
|
|
@@ -747,7 +717,6 @@ function ProjectPage(props: {
|
|
|
747
717
|
</LinkButton>
|
|
748
718
|
)}
|
|
749
719
|
</div>
|
|
750
|
-
<p className="sc-lead">{roadmap.lead}</p>
|
|
751
720
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
752
721
|
{making && (
|
|
753
722
|
<section className="sc-panel sc-panel-form" aria-label={roadmap.setGoalAria}>
|
|
@@ -966,17 +935,14 @@ function ProjectPage(props: {
|
|
|
966
935
|
}
|
|
967
936
|
if (route.name === "members") {
|
|
968
937
|
const me = data.me?.person ?? undefined;
|
|
969
|
-
const configures = owner
|
|
938
|
+
const configures = owner;
|
|
970
939
|
const members = words.projects.members;
|
|
971
940
|
return (
|
|
972
941
|
<>
|
|
973
942
|
<div className="sc-page-head">
|
|
974
943
|
<h1 className="sc-page-title">{members.title}</h1>
|
|
975
944
|
</div>
|
|
976
|
-
<p className="sc-lead">
|
|
977
|
-
{project.visibility === "workspace" ? members.leadWorkspace : members.leadPrivate}{" "}
|
|
978
|
-
{members.leadRoles}
|
|
979
|
-
</p>
|
|
945
|
+
<p className="sc-lead">{words.vocabulary.visibility[project.visibility]}</p>
|
|
980
946
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
981
947
|
<components.MemberList
|
|
982
948
|
members={data.members}
|
|
@@ -1017,11 +983,6 @@ function ProjectPage(props: {
|
|
|
1017
983
|
<div className="sc-page-head">
|
|
1018
984
|
<h1 className="sc-page-title">{settings.title}</h1>
|
|
1019
985
|
</div>
|
|
1020
|
-
<p className="sc-lead">
|
|
1021
|
-
{settings.leadBefore}
|
|
1022
|
-
<code>{project.key}</code>
|
|
1023
|
-
{settings.leadAfter}
|
|
1024
|
-
</p>
|
|
1025
986
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
1026
987
|
<section className="sc-panel sc-panel-form" aria-label={settings.aria}>
|
|
1027
988
|
<ProjectForm
|
|
@@ -1110,9 +1071,6 @@ function PersonAgentsPage(props: {
|
|
|
1110
1071
|
</h1>
|
|
1111
1072
|
<LinkButton href={PATHS.people}>{words.nav.people}</LinkButton>
|
|
1112
1073
|
</div>
|
|
1113
|
-
<p className="sc-lead">
|
|
1114
|
-
{words.people.agentsLead(person?.name ?? person?.login ?? words.feed.someone)}
|
|
1115
|
-
</p>
|
|
1116
1074
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
1117
1075
|
{tokens === undefined ? (
|
|
1118
1076
|
<div className="sc-loading">
|
|
@@ -1136,7 +1094,12 @@ function PersonAgentsPage(props: {
|
|
|
1136
1094
|
}
|
|
1137
1095
|
|
|
1138
1096
|
/** What is on the person's plate, across their projects: read when the page is opened. */
|
|
1139
|
-
function WorkPage(props: {
|
|
1097
|
+
function WorkPage(props: {
|
|
1098
|
+
readonly data: ConsoleData;
|
|
1099
|
+
readonly components: ConsoleComponents;
|
|
1100
|
+
/** A day of the week shown at the top, from the address; today's week when it names none. */
|
|
1101
|
+
readonly week: string | undefined;
|
|
1102
|
+
}) {
|
|
1140
1103
|
const words = useWords();
|
|
1141
1104
|
const { data, components } = props;
|
|
1142
1105
|
const [work, setWork] = useState<RestWork | undefined>(undefined);
|
|
@@ -1163,7 +1126,6 @@ function WorkPage(props: { readonly data: ConsoleData; readonly components: Cons
|
|
|
1163
1126
|
<div className="sc-page-head">
|
|
1164
1127
|
<h1 className="sc-page-title">{words.work.title}</h1>
|
|
1165
1128
|
</div>
|
|
1166
|
-
<p className="sc-lead">{words.work.lead}</p>
|
|
1167
1129
|
{problem !== undefined && <Callout tone="danger">{problem}</Callout>}
|
|
1168
1130
|
{work === undefined ? (
|
|
1169
1131
|
problem === undefined && (
|
|
@@ -1176,8 +1138,10 @@ function WorkPage(props: { readonly data: ConsoleData; readonly components: Cons
|
|
|
1176
1138
|
) : (
|
|
1177
1139
|
<components.WorkList
|
|
1178
1140
|
work={work}
|
|
1141
|
+
week={props.week}
|
|
1179
1142
|
taskHref={(projectKey, task) => taskHref(projectKey, task.number)}
|
|
1180
1143
|
decisionHref={(projectKey, decisionId) => decisionHref(projectKey, decisionId)}
|
|
1144
|
+
weekHref={workHref}
|
|
1181
1145
|
/>
|
|
1182
1146
|
)}
|
|
1183
1147
|
</>
|
|
@@ -1196,20 +1160,17 @@ function WorkspacePage(props: {
|
|
|
1196
1160
|
const { busy, error, act } = useAction();
|
|
1197
1161
|
|
|
1198
1162
|
if (route.name === "work") {
|
|
1199
|
-
return <WorkPage data={data} components={components} />;
|
|
1163
|
+
return <WorkPage data={data} components={components} week={route.week} />;
|
|
1200
1164
|
}
|
|
1201
1165
|
if (route.name === "categories") {
|
|
1202
1166
|
const me = data.me?.person ?? undefined;
|
|
1203
|
-
const administrator = me?.role === "admin"
|
|
1167
|
+
const administrator = me?.role === "admin";
|
|
1204
1168
|
const categories = words.categories;
|
|
1205
1169
|
return (
|
|
1206
1170
|
<>
|
|
1207
1171
|
<div className="sc-page-head">
|
|
1208
1172
|
<h1 className="sc-page-title">{categories.title}</h1>
|
|
1209
1173
|
</div>
|
|
1210
|
-
<p className="sc-lead">
|
|
1211
|
-
{categories.lead} {categories.onlyAdmin}
|
|
1212
|
-
</p>
|
|
1213
1174
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
1214
1175
|
<components.CategoryList
|
|
1215
1176
|
categories={data.categories}
|
|
@@ -1232,20 +1193,18 @@ function WorkspacePage(props: {
|
|
|
1232
1193
|
}
|
|
1233
1194
|
empty={<EmptyState title={categories.empty.title} body={categories.empty.body} />}
|
|
1234
1195
|
/>
|
|
1235
|
-
{administrator && <p className="sc-muted">{categories.inUse}</p>}
|
|
1236
1196
|
</>
|
|
1237
1197
|
);
|
|
1238
1198
|
}
|
|
1239
1199
|
|
|
1240
1200
|
if (route.name === "people") {
|
|
1241
1201
|
const me = data.me?.person ?? undefined;
|
|
1242
|
-
const administrator = me?.role === "admin"
|
|
1202
|
+
const administrator = me?.role === "admin";
|
|
1243
1203
|
return (
|
|
1244
1204
|
<>
|
|
1245
1205
|
<div className="sc-page-head">
|
|
1246
1206
|
<h1 className="sc-page-title">{words.people.title}</h1>
|
|
1247
1207
|
</div>
|
|
1248
|
-
<p className="sc-lead">{words.people.lead}</p>
|
|
1249
1208
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
1250
1209
|
<components.PeopleList
|
|
1251
1210
|
people={data.people}
|
|
@@ -1281,7 +1240,6 @@ function WorkspacePage(props: {
|
|
|
1281
1240
|
</LinkButton>
|
|
1282
1241
|
)}
|
|
1283
1242
|
</div>
|
|
1284
|
-
<p className="sc-lead">{agents.lead}</p>
|
|
1285
1243
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
1286
1244
|
{fresh !== undefined && (
|
|
1287
1245
|
<NewToken token={fresh.token} secret={fresh.secret} onDone={() => setFresh(undefined)} />
|
|
@@ -1334,10 +1292,7 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
1334
1292
|
const title = data.me?.workspace.name ?? fallbackTitle;
|
|
1335
1293
|
const viaToken = holdsToken(data);
|
|
1336
1294
|
// The language: the person's choice, else the browser's, else the first the console speaks.
|
|
1337
|
-
|
|
1338
|
-
// browser instead.
|
|
1339
|
-
const [ownChoice, setOwnChoice] = useState<string | undefined>(storedLanguage);
|
|
1340
|
-
const chosen = viaToken ? (ownChoice ?? data.me?.language) : data.me?.language;
|
|
1295
|
+
const chosen = data.me?.language;
|
|
1341
1296
|
const pack = useMemo(
|
|
1342
1297
|
() =>
|
|
1343
1298
|
chooseLanguage(
|
|
@@ -1485,7 +1440,7 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
1485
1440
|
label: words.nav.members,
|
|
1486
1441
|
current: route.name === "members",
|
|
1487
1442
|
},
|
|
1488
|
-
...(project?.role === "owner"
|
|
1443
|
+
...(project?.role === "owner"
|
|
1489
1444
|
? [
|
|
1490
1445
|
{
|
|
1491
1446
|
href: projectHref(projectKey, "settings"),
|
|
@@ -1591,14 +1546,7 @@ export function createConsole(config: ConsoleConfig = {}): ConsoleApp {
|
|
|
1591
1546
|
label: candidate.label,
|
|
1592
1547
|
current: candidate.tag === pack.tag,
|
|
1593
1548
|
}))}
|
|
1594
|
-
onLanguage={(tag) => {
|
|
1595
|
-
if (viaToken) {
|
|
1596
|
-
storeLanguage(tag);
|
|
1597
|
-
setOwnChoice(tag);
|
|
1598
|
-
} else {
|
|
1599
|
-
void data.actions.updateMe({ language: tag }).catch(() => undefined);
|
|
1600
|
-
}
|
|
1601
|
-
}}
|
|
1549
|
+
onLanguage={(tag) => void data.actions.updateMe({ language: tag }).catch(() => undefined)}
|
|
1602
1550
|
person={data.me.person}
|
|
1603
1551
|
live={projectKey === undefined ? undefined : data.live}
|
|
1604
1552
|
wide={
|
package/src/dates.ts
CHANGED
|
@@ -113,6 +113,17 @@ export function weekdays(firstDay = 1): number[] {
|
|
|
113
113
|
return Array.from({ length: 7 }, (_, index) => ((firstDay - 1 + index) % 7) + 1);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/** The seven days of the week `day` is in, from the day the week begins on (1 for Monday, 7 for Sunday). */
|
|
117
|
+
export function weekOf(day: string, firstDay = 1): string[] {
|
|
118
|
+
const date = dateOf(day);
|
|
119
|
+
if (Number.isNaN(date.getTime())) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
const weekday = date.getDay() === 0 ? 7 : date.getDay();
|
|
123
|
+
const first = addDays(day, -((weekday - firstDay + 7) % 7));
|
|
124
|
+
return Array.from({ length: 7 }, (_, index) => addDays(first, index));
|
|
125
|
+
}
|
|
126
|
+
|
|
116
127
|
/** A day as people read one in a language: the month and the day, with the year when it is not this year's. */
|
|
117
128
|
export function formatDay(day: string, language?: string, now: Date = new Date()): string {
|
|
118
129
|
const date = dateOf(day);
|
|
@@ -126,6 +137,23 @@ export function formatDay(day: string, language?: string, now: Date = new Date()
|
|
|
126
137
|
});
|
|
127
138
|
}
|
|
128
139
|
|
|
140
|
+
/** A stretch of days as people read one: from a day to a day, with the year. */
|
|
141
|
+
export function formatDays(from: string, to: string, language?: string): string {
|
|
142
|
+
const start = dateOf(from);
|
|
143
|
+
const end = dateOf(to);
|
|
144
|
+
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
|
|
145
|
+
return `${from} - ${to}`;
|
|
146
|
+
}
|
|
147
|
+
const format = new Intl.DateTimeFormat(language, {
|
|
148
|
+
month: "short",
|
|
149
|
+
day: "numeric",
|
|
150
|
+
year: "numeric",
|
|
151
|
+
});
|
|
152
|
+
return typeof format.formatRange === "function"
|
|
153
|
+
? format.formatRange(start, end)
|
|
154
|
+
: `${format.format(start)} - ${format.format(end)}`;
|
|
155
|
+
}
|
|
156
|
+
|
|
129
157
|
/** A month as people read one: the month and the year. */
|
|
130
158
|
export function formatMonth(month: string, language?: string): string {
|
|
131
159
|
const date = dateOf(`${month}-01`);
|
package/src/i18n/en.ts
CHANGED
|
@@ -89,7 +89,7 @@ export const en = {
|
|
|
89
89
|
},
|
|
90
90
|
notWithToken: {
|
|
91
91
|
title: "Done on the console's own pages",
|
|
92
|
-
body: "This console holds a token, which acts as you on the board
|
|
92
|
+
body: "This console holds a token, which acts as you on the board, configuring included. Agents are connected, and tokens made and removed, on the organization's console, signed in.",
|
|
93
93
|
},
|
|
94
94
|
you: "(you)",
|
|
95
95
|
nobody: "Nobody",
|
|
@@ -143,7 +143,6 @@ export const en = {
|
|
|
143
143
|
projects: {
|
|
144
144
|
title: "Projects",
|
|
145
145
|
newProject: "New project",
|
|
146
|
-
lead: "A project holds its board, its documents, its skills and its people. What you may see and change is decided per project: an owner configures it, a member works on it.",
|
|
147
146
|
empty: {
|
|
148
147
|
title: "No projects yet",
|
|
149
148
|
body: "Make the first one: what it is for, and who is in it. Or ask an owner to add you to theirs.",
|
|
@@ -172,11 +171,6 @@ export const en = {
|
|
|
172
171
|
members: {
|
|
173
172
|
title: "Members",
|
|
174
173
|
list: "Members",
|
|
175
|
-
leadWorkspace:
|
|
176
|
-
"Everyone of the workspace is a member of this project; those listed here are its owners and the people named besides.",
|
|
177
|
-
leadPrivate: "Only those listed here are in this project.",
|
|
178
|
-
leadRoles:
|
|
179
|
-
"An owner configures the project; a member works on it. A workspace administrator is an owner of every project.",
|
|
180
174
|
since: "since",
|
|
181
175
|
roleOf: (name: string) => `Role of ${name}`,
|
|
182
176
|
addAria: "Add a member",
|
|
@@ -193,9 +187,6 @@ export const en = {
|
|
|
193
187
|
settings: {
|
|
194
188
|
title: "Settings",
|
|
195
189
|
aria: "Project settings",
|
|
196
|
-
leadBefore: "The key, ",
|
|
197
|
-
leadAfter:
|
|
198
|
-
", is what addresses and the command say, and does not change. The skills address names a repository served by SkillCDN; empty, the organization's skills are shown.",
|
|
199
190
|
onlyOwner: {
|
|
200
191
|
title: "Only an owner may change the project",
|
|
201
192
|
body: "Ask one of its owners, or a workspace administrator.",
|
|
@@ -305,8 +296,6 @@ export const en = {
|
|
|
305
296
|
waiting: "Waiting",
|
|
306
297
|
answered: "Answered",
|
|
307
298
|
record: "The record",
|
|
308
|
-
recordLead:
|
|
309
|
-
"Every decision answered, newest first: what was asked, what was chosen, by whom. Open one for its context, its rationale and what followed.",
|
|
310
299
|
openRecord: "Open",
|
|
311
300
|
waitingForPerson: "Waiting for a person.",
|
|
312
301
|
options: "Options",
|
|
@@ -337,7 +326,6 @@ export const en = {
|
|
|
337
326
|
|
|
338
327
|
calendar: {
|
|
339
328
|
title: "Calendar",
|
|
340
|
-
lead: "The tasks on their days: planned from a start to a due day, a task lies across them; due on a day alone, it sits on it. One with no day waits at the bottom to be given one.",
|
|
341
329
|
grid: "The month",
|
|
342
330
|
legend: { title: "Category colours" },
|
|
343
331
|
startsOnly: "Starts that day, with no due day yet",
|
|
@@ -349,9 +337,15 @@ export const en = {
|
|
|
349
337
|
nothingOverdue: "Nothing is overdue.",
|
|
350
338
|
unscheduled: "No day set",
|
|
351
339
|
allScheduled: "Every open task has a day.",
|
|
340
|
+
week: {
|
|
341
|
+
title: "The week",
|
|
342
|
+
previous: "The week before",
|
|
343
|
+
next: "The week after",
|
|
344
|
+
thisWeek: "This week",
|
|
345
|
+
nothing: "Nothing is planned this week.",
|
|
346
|
+
},
|
|
352
347
|
workload: {
|
|
353
348
|
title: "Who has what",
|
|
354
|
-
lead: "The open tasks of each person, and what of them is late or due within the week.",
|
|
355
349
|
person: "Person",
|
|
356
350
|
open: "Open",
|
|
357
351
|
inProgress: "In progress",
|
|
@@ -363,7 +357,6 @@ export const en = {
|
|
|
363
357
|
|
|
364
358
|
roadmap: {
|
|
365
359
|
title: "Roadmap",
|
|
366
|
-
lead: "What the project works towards: each goal with the day it is meant to be reached by, and how far its tasks are. Progress is read from the board as it stands.",
|
|
367
360
|
setGoal: "Set a goal",
|
|
368
361
|
setGoalAria: "Set a goal",
|
|
369
362
|
editAria: "Change the goal",
|
|
@@ -402,7 +395,6 @@ export const en = {
|
|
|
402
395
|
|
|
403
396
|
work: {
|
|
404
397
|
title: "My work",
|
|
405
|
-
lead: "What is on your plate across your projects: the open tasks assigned to you, by the day they are due, and the decisions that wait for a person.",
|
|
406
398
|
loading: "Loading your work",
|
|
407
399
|
couldNotLoad: "Your work could not be loaded.",
|
|
408
400
|
empty: {
|
|
@@ -420,8 +412,6 @@ export const en = {
|
|
|
420
412
|
|
|
421
413
|
categories: {
|
|
422
414
|
title: "Categories",
|
|
423
|
-
lead: "The kinds of work tasks are sorted into, the same in every project. A task carries one, the board is narrowed by one, and an administrator keeps the list.",
|
|
424
|
-
onlyAdmin: "An administrator adds, changes and removes them; everyone else reads them here.",
|
|
425
415
|
list: "Categories",
|
|
426
416
|
add: "Add a category",
|
|
427
417
|
addAria: "Add a category",
|
|
@@ -429,7 +419,6 @@ export const en = {
|
|
|
429
419
|
title: "No categories",
|
|
430
420
|
body: "An administrator adds the first one here.",
|
|
431
421
|
},
|
|
432
|
-
inUse: "A category tasks are sorted into cannot be removed until they are moved out of it.",
|
|
433
422
|
form: {
|
|
434
423
|
name: "Name",
|
|
435
424
|
key: "Key",
|
|
@@ -543,10 +532,8 @@ export const en = {
|
|
|
543
532
|
title: "No skills address yet",
|
|
544
533
|
body: "This console has no address for the organization's skills. Whoever runs it names a repository served by SkillCDN in its configuration.",
|
|
545
534
|
},
|
|
546
|
-
servedBy: "
|
|
535
|
+
servedBy: "Served by",
|
|
547
536
|
at: "at",
|
|
548
|
-
howLoaded:
|
|
549
|
-
". An agent loads one through its SkillCDN connection; a person reads it at its page.",
|
|
550
537
|
status: {
|
|
551
538
|
indexing: "SkillCDN is still indexing the repository. Look again in a moment.",
|
|
552
539
|
failed: "SkillCDN could not index the repository. What it found is on the address's page.",
|
|
@@ -624,12 +611,9 @@ export const en = {
|
|
|
624
611
|
people: {
|
|
625
612
|
title: "People",
|
|
626
613
|
list: "People",
|
|
627
|
-
lead: "Everyone who has signed in. An administrator configures the workspace and says what each person is; a member works in the projects they are in. What a person may do, their agents may do.",
|
|
628
614
|
roleOf: (name: string) => `Role of ${name}`,
|
|
629
615
|
agents: "Agents",
|
|
630
616
|
agentsOf: (name: string) => `Agents of ${name}`,
|
|
631
|
-
agentsLead: (name: string) =>
|
|
632
|
-
`What works here as ${name}, each with a token of its own. Disconnecting one takes its token away at once.`,
|
|
633
617
|
loadingAgents: "Loading the agents",
|
|
634
618
|
noAgent: "No agent is connected",
|
|
635
619
|
onlyAdmin: {
|
|
@@ -642,7 +626,6 @@ export const en = {
|
|
|
642
626
|
title: "Agents",
|
|
643
627
|
makeByHand: "Make a token by hand",
|
|
644
628
|
makeAria: "Make a token",
|
|
645
|
-
lead: "What works here as you: each agent you connected, with a token of its own that nobody sees. What you may do, it may do; disconnect it here when that is over. A script or a console of your own holds a token the same way, made by hand.",
|
|
646
629
|
empty: {
|
|
647
630
|
title: "No agent is connected yet",
|
|
648
631
|
body: "Tell your agent to connect to this console, as below, and it shows up here.",
|
|
@@ -677,14 +660,13 @@ export const en = {
|
|
|
677
660
|
connect: {
|
|
678
661
|
title: "Connect an agent",
|
|
679
662
|
aria: "Connect",
|
|
680
|
-
lead: "Your agent showed you a code when it was told to connect to this console. Type it here, and say whether the agent may work as you.",
|
|
681
663
|
codeAria: "The code",
|
|
682
664
|
codeLabel: "The code your agent showed",
|
|
683
665
|
continue: "Continue",
|
|
684
666
|
lookingUp: "Looking the code up",
|
|
685
667
|
notACode: "That is not a code: eight letters and digits, in two groups.",
|
|
686
668
|
noSuchCode:
|
|
687
|
-
"No agent asks to connect with this code. A code is good for
|
|
669
|
+
"No agent asks to connect with this code. A code is good for thirty minutes and for one approval; ask your agent for a new one.",
|
|
688
670
|
couldNotAsk: "The console could not be asked.",
|
|
689
671
|
asks: {
|
|
690
672
|
title: "An agent asks to connect as you",
|
package/src/i18n/ko.ts
CHANGED
|
@@ -62,7 +62,7 @@ export const ko: Messages = {
|
|
|
62
62
|
},
|
|
63
63
|
notWithToken: {
|
|
64
64
|
title: "콘솔 자체 페이지에서 하는 일입니다",
|
|
65
|
-
body: "이 콘솔은 토큰으로 당신을 대신해 보드를
|
|
65
|
+
body: "이 콘솔은 토큰으로 당신을 대신해 보드를 쓰며, 설정도 그렇게 합니다. 에이전트 연결과 토큰 관리는 조직 콘솔에 로그인해서 합니다.",
|
|
66
66
|
},
|
|
67
67
|
you: "(나)",
|
|
68
68
|
nobody: "없음",
|
|
@@ -116,7 +116,6 @@ export const ko: Messages = {
|
|
|
116
116
|
projects: {
|
|
117
117
|
title: "프로젝트",
|
|
118
118
|
newProject: "새 프로젝트",
|
|
119
|
-
lead: "프로젝트는 보드, 문서, 스킬, 사람들을 가집니다. 무엇을 보고 바꿀 수 있는지는 프로젝트마다 정해집니다. 소유자는 설정하고, 멤버는 일합니다.",
|
|
120
119
|
empty: {
|
|
121
120
|
title: "아직 프로젝트가 없습니다",
|
|
122
121
|
body: "첫 프로젝트를 만드세요. 무엇을 위한 것인지, 누가 함께하는지. 또는 소유자에게 추가를 요청하세요.",
|
|
@@ -144,11 +143,6 @@ export const ko: Messages = {
|
|
|
144
143
|
members: {
|
|
145
144
|
title: "멤버",
|
|
146
145
|
list: "멤버",
|
|
147
|
-
leadWorkspace:
|
|
148
|
-
"워크스페이스의 모두가 이 프로젝트의 멤버입니다. 여기 목록은 소유자와 따로 지정된 사람들입니다.",
|
|
149
|
-
leadPrivate: "여기 목록에 있는 사람만 이 프로젝트에 속합니다.",
|
|
150
|
-
leadRoles:
|
|
151
|
-
"소유자는 프로젝트를 설정하고, 멤버는 프로젝트에서 일합니다. 워크스페이스 관리자는 모든 프로젝트의 소유자입니다.",
|
|
152
146
|
since: "부터",
|
|
153
147
|
roleOf: (name) => `${name}의 역할`,
|
|
154
148
|
addAria: "멤버 추가",
|
|
@@ -165,9 +159,6 @@ export const ko: Messages = {
|
|
|
165
159
|
settings: {
|
|
166
160
|
title: "설정",
|
|
167
161
|
aria: "프로젝트 설정",
|
|
168
|
-
leadBefore: "키 ",
|
|
169
|
-
leadAfter:
|
|
170
|
-
"는 주소와 명령이 부르는 이름이며 바뀌지 않습니다. 스킬 주소는 SkillCDN이 제공하는 저장소를 가리킵니다. 비우면 조직의 스킬이 보입니다.",
|
|
171
162
|
onlyOwner: {
|
|
172
163
|
title: "소유자만 프로젝트를 바꿀 수 있습니다",
|
|
173
164
|
body: "소유자나 워크스페이스 관리자에게 요청하세요.",
|
|
@@ -277,8 +268,6 @@ export const ko: Messages = {
|
|
|
277
268
|
waiting: "대기 중",
|
|
278
269
|
answered: "답변됨",
|
|
279
270
|
record: "기록",
|
|
280
|
-
recordLead:
|
|
281
|
-
"답변된 모든 결정, 최신순. 무엇을 물었고, 무엇을 골랐고, 누가 골랐는지. 맥락과 근거, 그 뒤에 일어난 일은 각 결정을 열어 봅니다.",
|
|
282
271
|
openRecord: "열기",
|
|
283
272
|
waitingForPerson: "사람을 기다리는 중입니다.",
|
|
284
273
|
options: "선택지",
|
|
@@ -309,7 +298,6 @@ export const ko: Messages = {
|
|
|
309
298
|
|
|
310
299
|
calendar: {
|
|
311
300
|
title: "캘린더",
|
|
312
|
-
lead: "작업을 날짜 위에 놓고 봅니다. 시작일과 기한이 있는 작업은 그 기간에 걸쳐 놓이고, 기한만 있는 작업은 그날에 놓입니다. 날짜가 없는 작업은 아래에서 날짜를 기다립니다.",
|
|
313
301
|
grid: "이 달",
|
|
314
302
|
legend: { title: "카테고리 색" },
|
|
315
303
|
startsOnly: "그날 시작, 기한은 아직 없음",
|
|
@@ -321,9 +309,15 @@ export const ko: Messages = {
|
|
|
321
309
|
nothingOverdue: "기한이 지난 작업이 없습니다.",
|
|
322
310
|
unscheduled: "날짜 없음",
|
|
323
311
|
allScheduled: "열린 작업마다 날짜가 있습니다.",
|
|
312
|
+
week: {
|
|
313
|
+
title: "이 주",
|
|
314
|
+
previous: "이전 주",
|
|
315
|
+
next: "다음 주",
|
|
316
|
+
thisWeek: "이번 주",
|
|
317
|
+
nothing: "이 주에 잡힌 작업이 없습니다.",
|
|
318
|
+
},
|
|
324
319
|
workload: {
|
|
325
320
|
title: "누가 무엇을",
|
|
326
|
-
lead: "사람마다 열린 작업과, 그중 늦은 것과 일주일 안에 마감인 것.",
|
|
327
321
|
person: "사람",
|
|
328
322
|
open: "열림",
|
|
329
323
|
inProgress: "진행 중",
|
|
@@ -335,7 +329,6 @@ export const ko: Messages = {
|
|
|
335
329
|
|
|
336
330
|
roadmap: {
|
|
337
331
|
title: "로드맵",
|
|
338
|
-
lead: "프로젝트가 향하는 것. 목표마다 달성 목표일과, 그 아래 작업들이 어디까지 왔는지. 진행은 보드의 현재 상태에서 그대로 읽습니다.",
|
|
339
332
|
setGoal: "목표 세우기",
|
|
340
333
|
setGoalAria: "목표 세우기",
|
|
341
334
|
editAria: "목표 바꾸기",
|
|
@@ -374,7 +367,6 @@ export const ko: Messages = {
|
|
|
374
367
|
|
|
375
368
|
work: {
|
|
376
369
|
title: "내 작업",
|
|
377
|
-
lead: "내 프로젝트들에 걸쳐 내게 놓인 일. 내게 배정된 열린 작업을 기한순으로, 그리고 사람을 기다리는 결정.",
|
|
378
370
|
loading: "내 작업을 불러오는 중",
|
|
379
371
|
couldNotLoad: "내 작업을 불러올 수 없습니다.",
|
|
380
372
|
empty: {
|
|
@@ -392,8 +384,6 @@ export const ko: Messages = {
|
|
|
392
384
|
|
|
393
385
|
categories: {
|
|
394
386
|
title: "카테고리",
|
|
395
|
-
lead: "작업을 나누는 일의 종류이며, 모든 프로젝트에서 같습니다. 작업은 하나를 가지고, 보드는 하나로 좁혀 보며, 관리자가 목록을 관리합니다.",
|
|
396
|
-
onlyAdmin: "관리자가 추가하고 바꾸고 제거합니다. 다른 사람은 여기서 읽습니다.",
|
|
397
387
|
list: "카테고리",
|
|
398
388
|
add: "카테고리 추가",
|
|
399
389
|
addAria: "카테고리 추가",
|
|
@@ -401,7 +391,6 @@ export const ko: Messages = {
|
|
|
401
391
|
title: "카테고리가 없습니다",
|
|
402
392
|
body: "관리자가 여기서 첫 카테고리를 추가합니다.",
|
|
403
393
|
},
|
|
404
|
-
inUse: "작업이 속해 있는 카테고리는 그 작업들을 옮기기 전에는 제거할 수 없습니다.",
|
|
405
394
|
form: {
|
|
406
395
|
name: "이름",
|
|
407
396
|
key: "키",
|
|
@@ -511,10 +500,8 @@ export const ko: Messages = {
|
|
|
511
500
|
title: "아직 스킬 주소가 없습니다",
|
|
512
501
|
body: "이 콘솔에는 조직의 스킬 주소가 없습니다. 운영자가 설정에서 SkillCDN이 제공하는 저장소를 지정합니다.",
|
|
513
502
|
},
|
|
514
|
-
servedBy: "
|
|
503
|
+
servedBy: "제공:",
|
|
515
504
|
at: "주소:",
|
|
516
|
-
howLoaded:
|
|
517
|
-
". 에이전트는 SkillCDN 연결을 통해 스킬을 불러오고, 사람은 해당 페이지에서 읽습니다.",
|
|
518
505
|
status: {
|
|
519
506
|
indexing: "SkillCDN이 아직 저장소를 색인하고 있습니다. 잠시 후 다시 보세요.",
|
|
520
507
|
failed: "SkillCDN이 저장소를 색인하지 못했습니다. 찾은 내용은 주소의 페이지에 있습니다.",
|
|
@@ -592,12 +579,9 @@ export const ko: Messages = {
|
|
|
592
579
|
people: {
|
|
593
580
|
title: "사람들",
|
|
594
581
|
list: "사람들",
|
|
595
|
-
lead: "로그인한 모든 사람. 관리자는 워크스페이스를 설정하고 각 사람의 역할을 정합니다. 멤버는 속한 프로젝트에서 일합니다. 사람이 할 수 있는 일은 그 사람의 에이전트도 할 수 있습니다.",
|
|
596
582
|
roleOf: (name) => `${name}의 역할`,
|
|
597
583
|
agents: "에이전트",
|
|
598
584
|
agentsOf: (name) => `${name}의 에이전트`,
|
|
599
|
-
agentsLead: (name) =>
|
|
600
|
-
`${name}(으)로 여기서 일하는 것들입니다. 각각 고유한 토큰을 가집니다. 연결을 끊으면 토큰이 즉시 사라집니다.`,
|
|
601
585
|
loadingAgents: "에이전트를 불러오는 중",
|
|
602
586
|
noAgent: "연결된 에이전트가 없습니다",
|
|
603
587
|
onlyAdmin: {
|
|
@@ -610,7 +594,6 @@ export const ko: Messages = {
|
|
|
610
594
|
title: "에이전트",
|
|
611
595
|
makeByHand: "토큰 직접 만들기",
|
|
612
596
|
makeAria: "토큰 만들기",
|
|
613
|
-
lead: "나로서 여기서 일하는 것들입니다. 연결한 각 에이전트는 아무도 볼 수 없는 고유한 토큰을 가집니다. 내가 할 수 있는 일은 에이전트도 할 수 있습니다. 더 쓰지 않으면 여기서 연결을 끊으세요. 내 스크립트나 콘솔도 직접 만든 토큰으로 같은 방식으로 일합니다.",
|
|
614
597
|
empty: {
|
|
615
598
|
title: "아직 연결된 에이전트가 없습니다",
|
|
616
599
|
body: "아래처럼 에이전트에게 이 콘솔에 연결하라고 말하면 여기에 나타납니다.",
|
|
@@ -645,14 +628,13 @@ export const ko: Messages = {
|
|
|
645
628
|
connect: {
|
|
646
629
|
title: "에이전트 연결",
|
|
647
630
|
aria: "연결",
|
|
648
|
-
lead: "에이전트에게 이 콘솔에 연결하라고 말하면 코드를 보여 줍니다. 그 코드를 여기에 입력하고, 에이전트가 나로서 일해도 되는지 답하세요.",
|
|
649
631
|
codeAria: "코드",
|
|
650
632
|
codeLabel: "에이전트가 보여 준 코드",
|
|
651
633
|
continue: "계속",
|
|
652
634
|
lookingUp: "코드를 찾는 중",
|
|
653
635
|
notACode: "코드가 아닙니다. 영문자와 숫자 여덟 자, 두 묶음입니다.",
|
|
654
636
|
noSuchCode:
|
|
655
|
-
"이 코드로 연결을 요청한 에이전트가 없습니다. 코드는
|
|
637
|
+
"이 코드로 연결을 요청한 에이전트가 없습니다. 코드는 30분 동안, 한 번의 승인에만 유효합니다. 에이전트에게 새 코드를 요청하세요.",
|
|
656
638
|
couldNotAsk: "콘솔에 물어볼 수 없습니다.",
|
|
657
639
|
asks: {
|
|
658
640
|
title: "에이전트가 나로서 연결하기를 요청합니다",
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,8 @@ export {
|
|
|
16
16
|
export {
|
|
17
17
|
Calendar,
|
|
18
18
|
type CalendarProps,
|
|
19
|
+
Week,
|
|
20
|
+
type WeekProps,
|
|
19
21
|
type WeekSegment,
|
|
20
22
|
Workload,
|
|
21
23
|
type WorkloadProps,
|
|
@@ -156,6 +158,7 @@ export {
|
|
|
156
158
|
daysBetween,
|
|
157
159
|
firstDayOfWeek,
|
|
158
160
|
formatDay,
|
|
161
|
+
formatDays,
|
|
159
162
|
formatMonth,
|
|
160
163
|
formatWeekday,
|
|
161
164
|
type GridDay,
|
|
@@ -165,6 +168,7 @@ export {
|
|
|
165
168
|
monthOf,
|
|
166
169
|
today,
|
|
167
170
|
weekdays,
|
|
171
|
+
weekOf,
|
|
168
172
|
} from "./dates.js";
|
|
169
173
|
export { DocsPage, type DocsPageProps } from "./docs-page.js";
|
|
170
174
|
export {
|
|
@@ -204,5 +208,6 @@ export {
|
|
|
204
208
|
type TaskFormKind,
|
|
205
209
|
taskHref,
|
|
206
210
|
withoutSignInParam,
|
|
211
|
+
workHref,
|
|
207
212
|
} from "./router.js";
|
|
208
213
|
export { errorWords, useAction } from "./use-action.js";
|