@skillcdn/console 0.1.13 → 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 +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.map +1 -1
- package/dist/console.js +13 -13
- 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 +8 -20
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/ko.d.ts.map +1 -1
- package/dist/i18n/ko.js +8 -20
- 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/package.json +1 -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 +11 -25
- package/src/dates.ts +28 -0
- package/src/i18n/en.ts +8 -26
- package/src/i18n/ko.ts +8 -26
- 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";
|
|
@@ -384,7 +385,6 @@ function ProjectsPage(props: {
|
|
|
384
385
|
</LinkButton>
|
|
385
386
|
)}
|
|
386
387
|
</div>
|
|
387
|
-
<p className="sc-lead">{words.lead}</p>
|
|
388
388
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
389
389
|
{making && (
|
|
390
390
|
<section className="sc-panel sc-panel-form" aria-label={words.form.aria}>
|
|
@@ -640,7 +640,6 @@ function ProjectPage(props: {
|
|
|
640
640
|
{words.board.writeTask}
|
|
641
641
|
</LinkButton>
|
|
642
642
|
</div>
|
|
643
|
-
<p className="sc-lead">{calendar.lead}</p>
|
|
644
643
|
{data.tasks.length > 0 && (
|
|
645
644
|
<BoardFilters
|
|
646
645
|
filter={route.filter}
|
|
@@ -690,7 +689,6 @@ function ProjectPage(props: {
|
|
|
690
689
|
{open.length > 0 && (
|
|
691
690
|
<section className="sc-task-section" aria-label={calendar.workload.title}>
|
|
692
691
|
<h2 className="sc-section-title">{calendar.workload.title}</h2>
|
|
693
|
-
<p className="sc-lead">{calendar.workload.lead}</p>
|
|
694
692
|
<Workload
|
|
695
693
|
tasks={shown}
|
|
696
694
|
today={now}
|
|
@@ -719,7 +717,6 @@ function ProjectPage(props: {
|
|
|
719
717
|
</LinkButton>
|
|
720
718
|
)}
|
|
721
719
|
</div>
|
|
722
|
-
<p className="sc-lead">{roadmap.lead}</p>
|
|
723
720
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
724
721
|
{making && (
|
|
725
722
|
<section className="sc-panel sc-panel-form" aria-label={roadmap.setGoalAria}>
|
|
@@ -945,10 +942,7 @@ function ProjectPage(props: {
|
|
|
945
942
|
<div className="sc-page-head">
|
|
946
943
|
<h1 className="sc-page-title">{members.title}</h1>
|
|
947
944
|
</div>
|
|
948
|
-
<p className="sc-lead">
|
|
949
|
-
{project.visibility === "workspace" ? members.leadWorkspace : members.leadPrivate}{" "}
|
|
950
|
-
{members.leadRoles}
|
|
951
|
-
</p>
|
|
945
|
+
<p className="sc-lead">{words.vocabulary.visibility[project.visibility]}</p>
|
|
952
946
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
953
947
|
<components.MemberList
|
|
954
948
|
members={data.members}
|
|
@@ -989,11 +983,6 @@ function ProjectPage(props: {
|
|
|
989
983
|
<div className="sc-page-head">
|
|
990
984
|
<h1 className="sc-page-title">{settings.title}</h1>
|
|
991
985
|
</div>
|
|
992
|
-
<p className="sc-lead">
|
|
993
|
-
{settings.leadBefore}
|
|
994
|
-
<code>{project.key}</code>
|
|
995
|
-
{settings.leadAfter}
|
|
996
|
-
</p>
|
|
997
986
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
998
987
|
<section className="sc-panel sc-panel-form" aria-label={settings.aria}>
|
|
999
988
|
<ProjectForm
|
|
@@ -1082,9 +1071,6 @@ function PersonAgentsPage(props: {
|
|
|
1082
1071
|
</h1>
|
|
1083
1072
|
<LinkButton href={PATHS.people}>{words.nav.people}</LinkButton>
|
|
1084
1073
|
</div>
|
|
1085
|
-
<p className="sc-lead">
|
|
1086
|
-
{words.people.agentsLead(person?.name ?? person?.login ?? words.feed.someone)}
|
|
1087
|
-
</p>
|
|
1088
1074
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
1089
1075
|
{tokens === undefined ? (
|
|
1090
1076
|
<div className="sc-loading">
|
|
@@ -1108,7 +1094,12 @@ function PersonAgentsPage(props: {
|
|
|
1108
1094
|
}
|
|
1109
1095
|
|
|
1110
1096
|
/** What is on the person's plate, across their projects: read when the page is opened. */
|
|
1111
|
-
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
|
+
}) {
|
|
1112
1103
|
const words = useWords();
|
|
1113
1104
|
const { data, components } = props;
|
|
1114
1105
|
const [work, setWork] = useState<RestWork | undefined>(undefined);
|
|
@@ -1135,7 +1126,6 @@ function WorkPage(props: { readonly data: ConsoleData; readonly components: Cons
|
|
|
1135
1126
|
<div className="sc-page-head">
|
|
1136
1127
|
<h1 className="sc-page-title">{words.work.title}</h1>
|
|
1137
1128
|
</div>
|
|
1138
|
-
<p className="sc-lead">{words.work.lead}</p>
|
|
1139
1129
|
{problem !== undefined && <Callout tone="danger">{problem}</Callout>}
|
|
1140
1130
|
{work === undefined ? (
|
|
1141
1131
|
problem === undefined && (
|
|
@@ -1148,8 +1138,10 @@ function WorkPage(props: { readonly data: ConsoleData; readonly components: Cons
|
|
|
1148
1138
|
) : (
|
|
1149
1139
|
<components.WorkList
|
|
1150
1140
|
work={work}
|
|
1141
|
+
week={props.week}
|
|
1151
1142
|
taskHref={(projectKey, task) => taskHref(projectKey, task.number)}
|
|
1152
1143
|
decisionHref={(projectKey, decisionId) => decisionHref(projectKey, decisionId)}
|
|
1144
|
+
weekHref={workHref}
|
|
1153
1145
|
/>
|
|
1154
1146
|
)}
|
|
1155
1147
|
</>
|
|
@@ -1168,7 +1160,7 @@ function WorkspacePage(props: {
|
|
|
1168
1160
|
const { busy, error, act } = useAction();
|
|
1169
1161
|
|
|
1170
1162
|
if (route.name === "work") {
|
|
1171
|
-
return <WorkPage data={data} components={components} />;
|
|
1163
|
+
return <WorkPage data={data} components={components} week={route.week} />;
|
|
1172
1164
|
}
|
|
1173
1165
|
if (route.name === "categories") {
|
|
1174
1166
|
const me = data.me?.person ?? undefined;
|
|
@@ -1179,9 +1171,6 @@ function WorkspacePage(props: {
|
|
|
1179
1171
|
<div className="sc-page-head">
|
|
1180
1172
|
<h1 className="sc-page-title">{categories.title}</h1>
|
|
1181
1173
|
</div>
|
|
1182
|
-
<p className="sc-lead">
|
|
1183
|
-
{categories.lead} {categories.onlyAdmin}
|
|
1184
|
-
</p>
|
|
1185
1174
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
1186
1175
|
<components.CategoryList
|
|
1187
1176
|
categories={data.categories}
|
|
@@ -1204,7 +1193,6 @@ function WorkspacePage(props: {
|
|
|
1204
1193
|
}
|
|
1205
1194
|
empty={<EmptyState title={categories.empty.title} body={categories.empty.body} />}
|
|
1206
1195
|
/>
|
|
1207
|
-
{administrator && <p className="sc-muted">{categories.inUse}</p>}
|
|
1208
1196
|
</>
|
|
1209
1197
|
);
|
|
1210
1198
|
}
|
|
@@ -1217,7 +1205,6 @@ function WorkspacePage(props: {
|
|
|
1217
1205
|
<div className="sc-page-head">
|
|
1218
1206
|
<h1 className="sc-page-title">{words.people.title}</h1>
|
|
1219
1207
|
</div>
|
|
1220
|
-
<p className="sc-lead">{words.people.lead}</p>
|
|
1221
1208
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
1222
1209
|
<components.PeopleList
|
|
1223
1210
|
people={data.people}
|
|
@@ -1253,7 +1240,6 @@ function WorkspacePage(props: {
|
|
|
1253
1240
|
</LinkButton>
|
|
1254
1241
|
)}
|
|
1255
1242
|
</div>
|
|
1256
|
-
<p className="sc-lead">{agents.lead}</p>
|
|
1257
1243
|
{error !== undefined && <Callout tone="danger">{error}</Callout>}
|
|
1258
1244
|
{fresh !== undefined && (
|
|
1259
1245
|
<NewToken token={fresh.token} secret={fresh.secret} onDone={() => setFresh(undefined)} />
|
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
|
@@ -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,7 +660,6 @@ 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",
|
package/src/i18n/ko.ts
CHANGED
|
@@ -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,7 +628,6 @@ export const ko: Messages = {
|
|
|
645
628
|
connect: {
|
|
646
629
|
title: "에이전트 연결",
|
|
647
630
|
aria: "연결",
|
|
648
|
-
lead: "에이전트에게 이 콘솔에 연결하라고 말하면 코드를 보여 줍니다. 그 코드를 여기에 입력하고, 에이전트가 나로서 일해도 되는지 답하세요.",
|
|
649
631
|
codeAria: "코드",
|
|
650
632
|
codeLabel: "에이전트가 보여 준 코드",
|
|
651
633
|
continue: "계속",
|
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";
|
package/src/router.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { isFolderPath, isSignInFailure, SIGN_IN_PARAM, type SignInFailure } from "./api.js";
|
|
2
|
-
import { isMonth } from "./dates.js";
|
|
2
|
+
import { isDay, isMonth } from "./dates.js";
|
|
3
3
|
|
|
4
4
|
// The addresses of the default console (ADR-0010): the router is a function from a URL to a
|
|
5
5
|
// route, and the hrefs below are its inverse. A project's pages live under `/projects/<key>`,
|
|
6
6
|
// the word the REST API uses; an address names what it shows (a task by its number, a decision
|
|
7
7
|
// by its id, a document by its path, a goal by its id), every form has one, and the query says
|
|
8
|
-
// how a page is shown (`?edit`, `?ask`, `?new`, `?version=`, `?q=`, `?month=`, and the
|
|
9
|
-
// filters). The old addresses are taken to the new.
|
|
8
|
+
// how a page is shown (`?edit`, `?ask`, `?new`, `?version=`, `?q=`, `?month=`, `?week=`, and the
|
|
9
|
+
// board's filters). The old addresses are taken to the new.
|
|
10
10
|
|
|
11
11
|
/** How a task's page is shown: as it is, or with one of its forms open. */
|
|
12
12
|
export type TaskFormKind = "edit" | "ask";
|
|
@@ -77,7 +77,8 @@ export type Route =
|
|
|
77
77
|
| { readonly name: "agents" }
|
|
78
78
|
| { readonly name: "new-token" }
|
|
79
79
|
/** What is on the person's plate across their projects. */
|
|
80
|
-
|
|
80
|
+
/** What is on the person's plate: a day of the week shown at the top, or today's when the address names none. */
|
|
81
|
+
| { readonly name: "work"; readonly week: string | undefined }
|
|
81
82
|
/** The categories tasks are sorted into; an administrator keeps them here. */
|
|
82
83
|
| { readonly name: "categories" }
|
|
83
84
|
/** Where a person approves an agent's connection, by the code it showed, or types one. */
|
|
@@ -206,7 +207,11 @@ export function matchRoute(pathname: string, search = ""): Route {
|
|
|
206
207
|
return { name: "new-project" };
|
|
207
208
|
}
|
|
208
209
|
if (path === PATHS.work) {
|
|
209
|
-
|
|
210
|
+
const week = params.get("week");
|
|
211
|
+
if (week !== null && !isDay(week)) {
|
|
212
|
+
return NOT_FOUND;
|
|
213
|
+
}
|
|
214
|
+
return { name: "work", week: week ?? undefined };
|
|
210
215
|
}
|
|
211
216
|
if (path === PATHS.people) {
|
|
212
217
|
return { name: "people" };
|
|
@@ -377,6 +382,11 @@ export function decisionHref(key: string, id: string): string {
|
|
|
377
382
|
return `${PATHS.project}/${key}/decisions/${id}`;
|
|
378
383
|
}
|
|
379
384
|
|
|
385
|
+
/** Where the person's own work is, with the week of a day at the top, or this week's when none is named. */
|
|
386
|
+
export function workHref(week?: string): string {
|
|
387
|
+
return week === undefined ? PATHS.work : `${PATHS.work}?week=${week}`;
|
|
388
|
+
}
|
|
389
|
+
|
|
380
390
|
/** Where a project's calendar is, on a month, or on this one when none is named, narrowed as the filter says. */
|
|
381
391
|
export function calendarHref(key: string, month?: string, filter: BoardFilter = {}): string {
|
|
382
392
|
const base = projectHref(key, "calendar");
|
package/src/styles/console.css
CHANGED
|
@@ -2974,10 +2974,31 @@ table {
|
|
|
2974
2974
|
flex: 1 1 10rem;
|
|
2975
2975
|
}
|
|
2976
2976
|
|
|
2977
|
-
/*
|
|
2977
|
+
/* One week on its own, the only row there is: its days are taller than a month's. */
|
|
2978
|
+
.sc-week .sc-calendar-cell {
|
|
2979
|
+
height: 9rem;
|
|
2980
|
+
}
|
|
2981
|
+
|
|
2982
|
+
/* A project's mark before a task on a day: the cell's own gap keeps it off the title. */
|
|
2983
|
+
.sc-calendar-task .sc-mark,
|
|
2984
|
+
.sc-calendar-bar .sc-mark {
|
|
2985
|
+
flex: none;
|
|
2986
|
+
margin-right: var(--sc-space-1);
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
.sc-calendar-task .sc-mark {
|
|
2990
|
+
margin-right: 0;
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
/* What is on a person's plate: the week across the page, the lists below it at reading width. */
|
|
2978
2994
|
.sc-work {
|
|
2979
2995
|
display: grid;
|
|
2980
2996
|
gap: var(--sc-space-6);
|
|
2997
|
+
}
|
|
2998
|
+
|
|
2999
|
+
.sc-work-lists {
|
|
3000
|
+
display: grid;
|
|
3001
|
+
gap: var(--sc-space-6);
|
|
2981
3002
|
max-width: var(--sc-width-prose);
|
|
2982
3003
|
}
|
|
2983
3004
|
|
|
@@ -3068,6 +3089,19 @@ table {
|
|
|
3068
3089
|
border: 0;
|
|
3069
3090
|
}
|
|
3070
3091
|
|
|
3092
|
+
.sc-week .sc-calendar-cell {
|
|
3093
|
+
height: 4.5rem;
|
|
3094
|
+
}
|
|
3095
|
+
|
|
3096
|
+
/* A bar is a line here, too thin for a mark; a task on its day keeps its mark as its dot. */
|
|
3097
|
+
.sc-calendar-bar .sc-mark {
|
|
3098
|
+
display: none;
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
.sc-calendar-task .sc-mark {
|
|
3102
|
+
margin: 0;
|
|
3103
|
+
}
|
|
3104
|
+
|
|
3071
3105
|
.sc-feed-item {
|
|
3072
3106
|
grid-template-columns: 1fr;
|
|
3073
3107
|
gap: var(--sc-space-1);
|