@skillcdn/console 0.3.0 → 0.3.1
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 +3 -3
- package/dist/api.d.ts +2 -2
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +2 -2
- package/dist/api.js.map +1 -1
- package/dist/cli/cli.d.ts +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +185 -28
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/credentials.d.ts +5 -0
- package/dist/cli/credentials.d.ts.map +1 -1
- package/dist/cli/credentials.js +2 -0
- package/dist/cli/credentials.js.map +1 -1
- package/dist/cli/directory.d.ts +7 -0
- package/dist/cli/directory.d.ts.map +1 -1
- package/dist/cli/directory.js +7 -0
- package/dist/cli/directory.js.map +1 -1
- package/dist/cli/format.d.ts +10 -1
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +67 -13
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +30 -13
- package/dist/cli/help.js.map +1 -1
- package/dist/client.d.ts +26 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +14 -1
- package/dist/client.js.map +1 -1
- package/dist/components/calendar.d.ts +5 -1
- package/dist/components/calendar.d.ts.map +1 -1
- package/dist/components/calendar.js +3 -3
- package/dist/components/calendar.js.map +1 -1
- package/dist/components/event-feed.d.ts.map +1 -1
- package/dist/components/event-feed.js +2 -0
- package/dist/components/event-feed.js.map +1 -1
- package/dist/components/pack-connect.d.ts +23 -0
- package/dist/components/pack-connect.d.ts.map +1 -0
- package/dist/components/pack-connect.js +86 -0
- package/dist/components/pack-connect.js.map +1 -0
- package/dist/components/pack-token.d.ts +27 -0
- package/dist/components/pack-token.d.ts.map +1 -0
- package/dist/components/pack-token.js +11 -0
- package/dist/components/pack-token.js.map +1 -0
- package/dist/components/projects.d.ts +13 -0
- package/dist/components/projects.d.ts.map +1 -1
- package/dist/components/projects.js +37 -5
- package/dist/components/projects.js.map +1 -1
- package/dist/components/work.d.ts +3 -1
- package/dist/components/work.d.ts.map +1 -1
- package/dist/components/work.js +1 -1
- package/dist/components/work.js.map +1 -1
- package/dist/components/workspace.d.ts +46 -0
- package/dist/components/workspace.d.ts.map +1 -0
- package/dist/components/workspace.js +124 -0
- package/dist/components/workspace.js.map +1 -0
- package/dist/console.css +156 -0
- package/dist/console.d.ts.map +1 -1
- package/dist/console.js +60 -21
- package/dist/console.js.map +1 -1
- package/dist/data.d.ts +16 -1
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +37 -0
- package/dist/data.js.map +1 -1
- package/dist/dates.d.ts +12 -2
- package/dist/dates.d.ts.map +1 -1
- package/dist/dates.js +20 -2
- package/dist/dates.js.map +1 -1
- package/dist/i18n/en.d.ts +53 -0
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +65 -8
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/ko.d.ts.map +1 -1
- package/dist/i18n/ko.js +60 -7
- package/dist/i18n/ko.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/router.d.ts +4 -4
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +11 -2
- package/dist/router.js.map +1 -1
- package/dist/routes.d.ts +4 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +4 -0
- package/dist/routes.js.map +1 -1
- package/dist/schemas.d.ts +182 -2
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +110 -13
- package/dist/schemas.js.map +1 -1
- package/dist/vocabulary.d.ts +19 -1
- package/dist/vocabulary.d.ts.map +1 -1
- package/dist/vocabulary.js +16 -0
- package/dist/vocabulary.js.map +1 -1
- package/docs/specs/cli.md +16 -11
- package/docs/specs/rest.md +31 -8
- package/package.json +2 -2
- package/skills/building-a-console/SKILL.md +5 -5
- package/skills/building-a-console/references/the-look-from-a-website.md +39 -0
- package/skills/deploying-a-console/SKILL.md +8 -7
- package/skills/working-the-board/SKILL.md +2 -2
- package/skills/working-the-board/references/setting-up.md +1 -1
- package/skills/working-the-board/references/terms.md +2 -0
- package/skills/working-the-board/references/the-sentence.md +1 -1
- package/src/api.ts +16 -0
- package/src/cli/cli.ts +253 -33
- package/src/cli/credentials.ts +7 -0
- package/src/cli/directory.ts +9 -0
- package/src/cli/format.ts +72 -13
- package/src/cli/help.ts +36 -13
- package/src/client.ts +84 -0
- package/src/components/calendar.tsx +8 -2
- package/src/components/event-feed.tsx +2 -0
- package/src/components/pack-connect.tsx +179 -0
- package/src/components/pack-token.tsx +74 -0
- package/src/components/projects.tsx +108 -9
- package/src/components/work.tsx +4 -1
- package/src/components/workspace.tsx +298 -0
- package/src/console.tsx +173 -29
- package/src/data.ts +57 -0
- package/src/dates.ts +23 -2
- package/src/i18n/en.ts +76 -8
- package/src/i18n/ko.ts +67 -7
- package/src/index.ts +16 -0
- package/src/router.ts +17 -5
- package/src/routes.ts +4 -0
- package/src/schemas.ts +129 -12
- package/src/styles/console.css +156 -0
- package/src/vocabulary.ts +25 -0
package/src/i18n/ko.ts
CHANGED
|
@@ -20,7 +20,12 @@ export const ko: Messages = {
|
|
|
20
20
|
role: { admin: "관리자", member: "멤버" },
|
|
21
21
|
status: { active: "활성", deactivated: "비활성화" },
|
|
22
22
|
projectRole: { owner: "소유자", member: "멤버" },
|
|
23
|
-
visibility: { workspace: "워크스페이스의 모두", private: "목록에 있는 사람만" },
|
|
23
|
+
visibility: { workspace: "공개: 워크스페이스의 모두", private: "비공개: 목록에 있는 사람만" },
|
|
24
|
+
peopleVisibility: {
|
|
25
|
+
everyone: "워크스페이스의 모두",
|
|
26
|
+
shared_projects: "같은 프로젝트에 속한 사람만",
|
|
27
|
+
},
|
|
28
|
+
weekStart: { auto: "시스템 기본", monday: "월요일", sunday: "일요일" },
|
|
24
29
|
runStatus: {
|
|
25
30
|
running: "열림",
|
|
26
31
|
waiting: "결정 대기 중",
|
|
@@ -163,6 +168,12 @@ export const ko: Messages = {
|
|
|
163
168
|
chooseSomeone: "선택하세요",
|
|
164
169
|
as: "역할",
|
|
165
170
|
add: "추가",
|
|
171
|
+
open: "공개 프로젝트입니다. 워크스페이스의 모든 구성원이 멤버이고, 소유자는 이 목록에서 지정합니다.",
|
|
172
|
+
addByLoginAria: "로그인으로 멤버 추가",
|
|
173
|
+
login: "로그인",
|
|
174
|
+
addByLogin: "로그인으로 추가",
|
|
175
|
+
lookupHint: "목록에 보이지 않는 사람: 깃 호스트의 로그인이나 주소를 정확히 적습니다.",
|
|
176
|
+
nobodyCalled: (login) => `워크스페이스에 ${login}이라는 사람이 없습니다.`,
|
|
166
177
|
empty: {
|
|
167
178
|
title: "목록에 아무도 없습니다",
|
|
168
179
|
workspace: "워크스페이스의 모두가 속해 있고, 관리자가 소유합니다.",
|
|
@@ -170,11 +181,33 @@ export const ko: Messages = {
|
|
|
170
181
|
},
|
|
171
182
|
},
|
|
172
183
|
packToken: {
|
|
173
|
-
aria: "
|
|
184
|
+
aria: "SkillCDN 토큰",
|
|
185
|
+
intro:
|
|
186
|
+
"비공개 팩은 저장소에 대한 SkillCDN 토큰으로 읽습니다. 공개 팩에는 필요 없습니다. SkillCDN에서 승인한 코드로 연결하거나, 거기서 직접 만든 토큰을 붙여 넣으세요. 콘솔은 토큰을 봉인해 보관하고 누구에게도 보여 주지 않습니다. 조직의 팩을 읽는 프로젝트는 워크스페이스 설정의 토큰을 그대로 쓸 수 있습니다.",
|
|
187
|
+
connectTitle: "SkillCDN에서 승인한 코드로",
|
|
188
|
+
pasteTitle: "직접 만든 토큰으로",
|
|
189
|
+
pasteAria: "토큰 붙여넣기",
|
|
174
190
|
label: "토큰",
|
|
175
|
-
hint: "
|
|
191
|
+
hint: "SkillCDN 계정 페이지에서 팩의 저장소에 대해 만든 토큰입니다.",
|
|
192
|
+
setSince: "토큰이 설정되어 있습니다:",
|
|
176
193
|
placeholder: "scdn_repo_…",
|
|
194
|
+
connect: "SkillCDN에서 연결",
|
|
195
|
+
connectHint:
|
|
196
|
+
"콘솔이 SkillCDN에 코드를 요청합니다. 안내된 페이지를 저장소를 볼 수 있는 계정으로 열어, 코드를 확인하고 승인하세요.",
|
|
197
|
+
connectCode: "코드",
|
|
198
|
+
connectOpen: "SkillCDN 페이지 열기",
|
|
199
|
+
connectWaiting: "SkillCDN에서 승인을 기다리는 중입니다.",
|
|
200
|
+
connectExpires: "코드 만료:",
|
|
201
|
+
connectCancel: "기다리기 중단",
|
|
202
|
+
connectDone: "연결되었습니다. 콘솔이 이제 이 토큰으로 팩을 읽습니다.",
|
|
203
|
+
connectEnded: {
|
|
204
|
+
expired: "승인되기 전에 코드가 만료되었습니다. 다시 연결해 새 코드를 받으세요.",
|
|
205
|
+
declined: "SkillCDN에서 요청이 거절되었거나 코드가 이미 쓰였습니다.",
|
|
206
|
+
refused:
|
|
207
|
+
"SkillCDN이 요청을 거부했습니다. 그 사람이 볼 수 없는 저장소이거나, 공개 팩이라 토큰이 필요 없거나, 토큰을 더 만들 수 없습니다.",
|
|
208
|
+
},
|
|
177
209
|
set: "토큰 넣기",
|
|
210
|
+
replace: "토큰 바꾸기",
|
|
178
211
|
remove: "토큰 빼기",
|
|
179
212
|
},
|
|
180
213
|
settings: {
|
|
@@ -183,10 +216,11 @@ export const ko: Messages = {
|
|
|
183
216
|
edit: "프로젝트 편집",
|
|
184
217
|
organizationsSkills: (address) => `조직의 스킬: ${address}`,
|
|
185
218
|
noSkills: "없음: 콘솔에 조직의 주소가 없습니다.",
|
|
186
|
-
packToken: "
|
|
187
|
-
packTokenNone: "
|
|
219
|
+
packToken: "SkillCDN 토큰",
|
|
220
|
+
packTokenNone: "없음",
|
|
188
221
|
packTokenSet: "설정됨",
|
|
189
222
|
packTokenEdit: "바꾸기",
|
|
223
|
+
packTokenAdd: "등록",
|
|
190
224
|
},
|
|
191
225
|
},
|
|
192
226
|
|
|
@@ -464,6 +498,26 @@ export const ko: Messages = {
|
|
|
464
498
|
noSkillsAddress: "주소 없음: 프로젝트마다 자기 주소를 두거나, 두지 않습니다.",
|
|
465
499
|
skillsFromConfiguration:
|
|
466
500
|
"콘솔을 운영하는 쪽이 설정으로 정합니다. 스킬을 읽어 오는 배포와 조직의 주소.",
|
|
501
|
+
skillsToken: "SkillCDN 토큰",
|
|
502
|
+
skillsTokenIntro:
|
|
503
|
+
"자기 주소도 자기 토큰도 없는 모든 프로젝트가 이 토큰으로 조직의 팩을 읽습니다. 공개 팩에는 필요 없습니다. SkillCDN에서 승인한 코드로 연결하거나, 거기서 직접 만든 토큰을 붙여 넣으세요. 콘솔은 토큰을 봉인해 보관하고 누구에게도 보여 주지 않습니다.",
|
|
504
|
+
workspace: {
|
|
505
|
+
title: "워크스페이스",
|
|
506
|
+
aria: "워크스페이스 설정",
|
|
507
|
+
peopleVisibility: "멤버 공개 범위",
|
|
508
|
+
peopleVisibilityHint:
|
|
509
|
+
"멤버가 사람들 페이지와 선택 목록에서 보는 범위: 워크스페이스의 모두, 또는 같은 프로젝트에 속한 사람만. 관리자는 언제나 모두를 보고, 워크스페이스에 공개된 프로젝트에는 모두가 속합니다.",
|
|
510
|
+
weekStart: "주의 시작 요일",
|
|
511
|
+
weekStartHint:
|
|
512
|
+
"캘린더와 내 작업에서. 시스템 기본은 각 사람의 기기에 설정된 언어와 지역을 따르고, 월요일이나 일요일은 모두에게 같게 적용됩니다.",
|
|
513
|
+
timeZone: "타임존",
|
|
514
|
+
timeZoneHint:
|
|
515
|
+
"콘솔 명령과 에이전트가 시각을 이 타임존으로 찍습니다. 페이지는 각 기기의 타임존으로 보여 줍니다. 없음이면 명령은 UTC로 찍습니다.",
|
|
516
|
+
timeZoneNone: "없음",
|
|
517
|
+
timeZoneDevice: (zone) => `이 기기: ${zone}`,
|
|
518
|
+
timeZoneUseDevice: (zone) => `이 기기의 타임존 쓰기: ${zone}`,
|
|
519
|
+
save: "설정 저장",
|
|
520
|
+
},
|
|
467
521
|
},
|
|
468
522
|
|
|
469
523
|
rules: {
|
|
@@ -527,9 +581,14 @@ export const ko: Messages = {
|
|
|
527
581
|
dueOn: "기한",
|
|
528
582
|
state: "상태",
|
|
529
583
|
color: "색",
|
|
584
|
+
peopleVisibility: "멤버 공개 범위",
|
|
585
|
+
weekStart: "주의 시작 요일",
|
|
586
|
+
timeZone: "타임존",
|
|
587
|
+
packToken: "SkillCDN 토큰",
|
|
530
588
|
},
|
|
531
589
|
event: {
|
|
532
590
|
personJoined: () => "보드에 들어왔습니다",
|
|
591
|
+
workspaceUpdated: (fields) => `워크스페이스의 ${fields}을(를) 바꿨습니다`,
|
|
533
592
|
roleChanged: (login, role) => `${login}을(를) ${role}(으)로 지정했습니다`,
|
|
534
593
|
personListed: (login) => `${login}을(를) 추가했습니다`,
|
|
535
594
|
personUnlisted: (login) => `${login}을(를) 목록에서 뺐습니다`,
|
|
@@ -647,9 +706,9 @@ export const ko: Messages = {
|
|
|
647
706
|
indexing: "SkillCDN이 아직 저장소를 색인하고 있습니다. 잠시 후 다시 보세요.",
|
|
648
707
|
failed: "SkillCDN이 저장소를 색인하지 못했습니다. 찾은 내용은 주소의 페이지에 있습니다.",
|
|
649
708
|
not_found:
|
|
650
|
-
"SkillCDN이 이 주소를 콘솔에 제공하지 않습니다. 그곳에 아무것도 없거나, 비공개 팩인데
|
|
709
|
+
"SkillCDN이 이 주소를 콘솔에 제공하지 않습니다. 그곳에 아무것도 없거나, 비공개 팩인데 읽을 SkillCDN 토큰이 프로젝트에도 워크스페이스에도 없습니다. 소유자가 설정 페이지에서 SkillCDN의 승인 코드로 연결합니다.",
|
|
651
710
|
token_invalid:
|
|
652
|
-
"
|
|
711
|
+
"이 팩을 읽는 SkillCDN 토큰이 SkillCDN에서 더 이상 통하지 않습니다. 만료되었거나 지워졌거나, 만든 사람이 저장소 권한을 잃었습니다. 소유자가 설정 페이지에서 새로 넣습니다.",
|
|
653
712
|
unavailable:
|
|
654
713
|
"SkillCDN에 연결할 수 없습니다. 스킬은 이전 상태 그대로입니다. 나중에 다시 보세요.",
|
|
655
714
|
},
|
|
@@ -727,6 +786,7 @@ export const ko: Messages = {
|
|
|
727
786
|
people: {
|
|
728
787
|
title: "사람들",
|
|
729
788
|
list: "사람들",
|
|
789
|
+
narrowed: "같은 프로젝트에 속한 사람들과 관리자입니다.",
|
|
730
790
|
roleOf: (name) => `${name}의 역할`,
|
|
731
791
|
letIn: "사람 추가",
|
|
732
792
|
letInAria: "사람 추가",
|
package/src/index.ts
CHANGED
|
@@ -82,6 +82,12 @@ export {
|
|
|
82
82
|
goalMonth,
|
|
83
83
|
} from "./components/goals.js";
|
|
84
84
|
export { Markdown, type MarkdownProps } from "./components/markdown.js";
|
|
85
|
+
export {
|
|
86
|
+
PackConnect,
|
|
87
|
+
type PackConnectProps,
|
|
88
|
+
type PackConnectState,
|
|
89
|
+
} from "./components/pack-connect.js";
|
|
90
|
+
export { PackTokenWays, type PackTokenWaysProps } from "./components/pack-token.js";
|
|
85
91
|
export {
|
|
86
92
|
PAGE_SIZE,
|
|
87
93
|
Pager,
|
|
@@ -200,6 +206,16 @@ export {
|
|
|
200
206
|
Time,
|
|
201
207
|
} from "./components/ui.js";
|
|
202
208
|
export { WorkList, type WorkListProps } from "./components/work.js";
|
|
209
|
+
export {
|
|
210
|
+
DEFAULT_PEOPLE_VISIBILITY,
|
|
211
|
+
peopleVisibilityOf,
|
|
212
|
+
timeZoneOf,
|
|
213
|
+
WorkspaceSettingsForm,
|
|
214
|
+
type WorkspaceSettingsFormProps,
|
|
215
|
+
WorkspaceSettingsView,
|
|
216
|
+
type WorkspaceSettingsViewProps,
|
|
217
|
+
weekStartOf,
|
|
218
|
+
} from "./components/workspace.js";
|
|
203
219
|
export { ConnectPage, type ConnectPageProps } from "./connect-page.js";
|
|
204
220
|
export {
|
|
205
221
|
type ConsoleApp,
|
package/src/router.ts
CHANGED
|
@@ -83,8 +83,11 @@ export type Route =
|
|
|
83
83
|
readonly project: string;
|
|
84
84
|
readonly form: "edit" | "rules" | "pack-token" | undefined;
|
|
85
85
|
}
|
|
86
|
-
/** The workspace's settings: its rules, its categories, its skills; or the form the rules are written on. */
|
|
87
|
-
| {
|
|
86
|
+
/** The workspace's settings: its own, its rules, its categories, its skills; or the form the rules, or the settings (ADR-0035), are written on. */
|
|
87
|
+
| {
|
|
88
|
+
readonly name: "workspace-settings";
|
|
89
|
+
readonly form: "rules" | "workspace" | "pack-token" | undefined;
|
|
90
|
+
}
|
|
88
91
|
| { readonly name: "people" }
|
|
89
92
|
/** The form where an administrator lets someone in by login (ADR-0022). */
|
|
90
93
|
| { readonly name: "new-listing" }
|
|
@@ -252,7 +255,16 @@ export function matchRoute(pathname: string, search = ""): Route {
|
|
|
252
255
|
return { name: "categories" };
|
|
253
256
|
}
|
|
254
257
|
if (path === PATHS.settings) {
|
|
255
|
-
return {
|
|
258
|
+
return {
|
|
259
|
+
name: "workspace-settings",
|
|
260
|
+
form: params.has("workspace")
|
|
261
|
+
? "workspace"
|
|
262
|
+
: params.has("rules")
|
|
263
|
+
? "rules"
|
|
264
|
+
: params.has("pack-token")
|
|
265
|
+
? "pack-token"
|
|
266
|
+
: undefined,
|
|
267
|
+
};
|
|
256
268
|
}
|
|
257
269
|
if (path === PATHS.connect) {
|
|
258
270
|
return { name: "connect", code: undefined };
|
|
@@ -423,8 +435,8 @@ export function projectSettingsHref(key: string, form?: "edit" | "rules" | "pack
|
|
|
423
435
|
return form === undefined ? base : `${base}?${form}`;
|
|
424
436
|
}
|
|
425
437
|
|
|
426
|
-
/** Where the workspace's settings are, or the form its rules are written on. */
|
|
427
|
-
export function settingsHref(form?: "rules"): string {
|
|
438
|
+
/** Where the workspace's settings are, or the form its rules, or its own settings, are written on. */
|
|
439
|
+
export function settingsHref(form?: "rules" | "workspace" | "pack-token"): string {
|
|
428
440
|
return form === undefined ? PATHS.settings : `${PATHS.settings}?${form}`;
|
|
429
441
|
}
|
|
430
442
|
|
package/src/routes.ts
CHANGED
|
@@ -9,6 +9,10 @@ export const REST_ROUTES = {
|
|
|
9
9
|
me: "/api/v1/me",
|
|
10
10
|
/** The token a request is made with, for it to give itself up. */
|
|
11
11
|
meToken: "/api/v1/me/token",
|
|
12
|
+
/** The workspace's settings (ADR-0035), changed by an administrator; read through `me`. */
|
|
13
|
+
workspace: "/api/v1/workspace",
|
|
14
|
+
/** The SkillCDN token the organization's pack is read with (ADR-0036), an administrator's; `/connect` under it connects one with a code. */
|
|
15
|
+
workspacePackToken: "/api/v1/workspace/pack-token",
|
|
12
16
|
/** The people of the workspace: everyone who has signed in, and the logins let in that have not. */
|
|
13
17
|
people: "/api/v1/people",
|
|
14
18
|
/** The logins an administrator let in (ADR-0022), made and removed by one. */
|
package/src/schemas.ts
CHANGED
|
@@ -50,6 +50,8 @@ import {
|
|
|
50
50
|
GOAL_STATES,
|
|
51
51
|
LINK_SOURCES,
|
|
52
52
|
MEMBERSHIP_SOURCES,
|
|
53
|
+
PACK_CONNECT_ENDINGS,
|
|
54
|
+
PEOPLE_VISIBILITIES,
|
|
53
55
|
PERSON_ROLES,
|
|
54
56
|
PERSON_STATUSES,
|
|
55
57
|
PROJECT_ICON_TYPES,
|
|
@@ -63,6 +65,7 @@ import {
|
|
|
63
65
|
SKILLS_STATUSES,
|
|
64
66
|
TASK_PRIORITIES,
|
|
65
67
|
TASK_STATES,
|
|
68
|
+
WEEK_STARTS,
|
|
66
69
|
} from "./vocabulary.js";
|
|
67
70
|
|
|
68
71
|
/** A line of text a person wrote: trimmed, bounded, and free of characters that hide. */
|
|
@@ -166,6 +169,18 @@ export const restProviderSchema = z.object({
|
|
|
166
169
|
});
|
|
167
170
|
export type RestProvider = z.infer<typeof restProviderSchema>;
|
|
168
171
|
|
|
172
|
+
/**
|
|
173
|
+
* A time zone's name as the IANA database spells one (`Asia/Seoul`, `UTC`): its shape here; the
|
|
174
|
+
* server knows which names are zones.
|
|
175
|
+
*/
|
|
176
|
+
export const timeZoneName = z
|
|
177
|
+
.string()
|
|
178
|
+
.check(
|
|
179
|
+
z.minLength(1),
|
|
180
|
+
z.maxLength(64),
|
|
181
|
+
z.regex(/^[A-Za-z0-9_+-]+(?:\/[A-Za-z0-9_+-]+)*$/, "must be a time zone name"),
|
|
182
|
+
);
|
|
183
|
+
|
|
169
184
|
/** A language tag as a browser sends one (`en`, `ko-KR`): what the pages speak, by the person's choice. */
|
|
170
185
|
const languageTag = z
|
|
171
186
|
.string()
|
|
@@ -178,22 +193,67 @@ const languageTag = z
|
|
|
178
193
|
export const restMePatchSchema = z.object({ language: z.nullable(languageTag) });
|
|
179
194
|
export type RestMePatch = z.infer<typeof restMePatchSchema>;
|
|
180
195
|
|
|
196
|
+
/**
|
|
197
|
+
* The workspace as `GET /api/v1/me` describes it, and as `PATCH /api/v1/workspace` answers: what
|
|
198
|
+
* the board is called, what the deployment's configuration says of it, and the settings an
|
|
199
|
+
* administrator keeps on the Settings page (ADR-0035).
|
|
200
|
+
*/
|
|
201
|
+
export const restWorkspaceSchema = z.object({
|
|
202
|
+
name: z.string(),
|
|
203
|
+
/** The most days a token may be good for here, or `null` when a person chooses. */
|
|
204
|
+
tokenDaysAtMost: z.nullable(z.int().check(z.positive())),
|
|
205
|
+
/**
|
|
206
|
+
* The organization's skills: the origin of the SkillCDN deployment they are read through,
|
|
207
|
+
* and the address a project without one of its own reads, canonical, or `null` for none.
|
|
208
|
+
*/
|
|
209
|
+
skills: z.object({
|
|
210
|
+
source: z.string(),
|
|
211
|
+
address: z.nullable(z.string()),
|
|
212
|
+
/**
|
|
213
|
+
* The SkillCDN token the organization's pack is read with, by a project that names no
|
|
214
|
+
* address and holds no token of its own (ADR-0036): when it was set, never the token; `null`
|
|
215
|
+
* for none. Optional, so that a console older than it still answers.
|
|
216
|
+
*/
|
|
217
|
+
packToken: z.optional(z.nullable(z.object({ setAt: instant }))),
|
|
218
|
+
}),
|
|
219
|
+
/**
|
|
220
|
+
* Who sees whom on the People page (ADR-0035): everyone, or the people one shares a project
|
|
221
|
+
* with. Read as optional, so that a console older than this setting still answers; `everyone`
|
|
222
|
+
* then, which is what it does.
|
|
223
|
+
*/
|
|
224
|
+
peopleVisibility: z.optional(z.enum(PEOPLE_VISIBILITIES)),
|
|
225
|
+
/** The day the calendars begin a week on: the language's, Monday or Sunday. Optional as above; `auto` then. */
|
|
226
|
+
weekStart: z.optional(z.enum(WEEK_STARTS)),
|
|
227
|
+
/**
|
|
228
|
+
* The workspace's time zone, an IANA name, in which the command prints moments; `null` for
|
|
229
|
+
* none, when they stay as the API gives them, in UTC. Optional as above; none then.
|
|
230
|
+
*/
|
|
231
|
+
timeZone: z.optional(z.nullable(timeZoneName)),
|
|
232
|
+
});
|
|
233
|
+
export type RestWorkspace = z.infer<typeof restWorkspaceSchema>;
|
|
234
|
+
|
|
235
|
+
/** What `PATCH /api/v1/workspace` is sent, by an administrator: the settings to change, at least one. */
|
|
236
|
+
export const restWorkspacePatchSchema = z
|
|
237
|
+
.object({
|
|
238
|
+
peopleVisibility: z.optional(z.enum(PEOPLE_VISIBILITIES)),
|
|
239
|
+
weekStart: z.optional(z.enum(WEEK_STARTS)),
|
|
240
|
+
/** A zone's name, or `null` for none. */
|
|
241
|
+
timeZone: z.optional(z.nullable(timeZoneName)),
|
|
242
|
+
})
|
|
243
|
+
.check(
|
|
244
|
+
z.refine((patch) => Object.values(patch).some((value) => value !== undefined), {
|
|
245
|
+
message: "names nothing to change",
|
|
246
|
+
}),
|
|
247
|
+
);
|
|
248
|
+
export type RestWorkspacePatch = z.infer<typeof restWorkspacePatchSchema>;
|
|
249
|
+
|
|
181
250
|
/**
|
|
182
251
|
* `GET /api/v1/me`: the workspace, who the session cookie says is signed in (or `null`), the
|
|
183
252
|
* language they chose (or `null`), and the identity providers people sign in through, none
|
|
184
253
|
* where nobody can.
|
|
185
254
|
*/
|
|
186
255
|
export const restMeSchema = z.object({
|
|
187
|
-
workspace:
|
|
188
|
-
name: z.string(),
|
|
189
|
-
/** The most days a token may be good for here, or `null` when a person chooses. */
|
|
190
|
-
tokenDaysAtMost: z.nullable(z.int().check(z.positive())),
|
|
191
|
-
/**
|
|
192
|
-
* The organization's skills: the origin of the SkillCDN deployment they are read through,
|
|
193
|
-
* and the address a project without one of its own reads, canonical, or `null` for none.
|
|
194
|
-
*/
|
|
195
|
-
skills: z.object({ source: z.string(), address: z.nullable(z.string()) }),
|
|
196
|
-
}),
|
|
256
|
+
workspace: restWorkspaceSchema,
|
|
197
257
|
person: z.nullable(restPersonSchema),
|
|
198
258
|
/**
|
|
199
259
|
* What the token asking is called by its person, when a token asks: how a console of a
|
|
@@ -329,15 +389,25 @@ export const restProjectPatchSchema = z.object({
|
|
|
329
389
|
});
|
|
330
390
|
export type RestProjectPatch = z.infer<typeof restProjectPatchSchema>;
|
|
331
391
|
|
|
332
|
-
/**
|
|
392
|
+
/**
|
|
393
|
+
* A member of a project, with what they are in it: a person listed in it, or, in a project open
|
|
394
|
+
* to the workspace, anyone of the workspace, who is a member of it without a listing (ADR-0035).
|
|
395
|
+
*/
|
|
333
396
|
export const restMemberSchema = z.object({
|
|
334
397
|
person: restPersonSchema,
|
|
398
|
+
/** What they are in it: an owner as listed or as an administrator, else a member. */
|
|
335
399
|
role: z.enum(PROJECT_ROLES),
|
|
400
|
+
/** Since when: the listing's day, or, for a member without one, the later of the project's making and their joining. */
|
|
336
401
|
addedAt: instant,
|
|
402
|
+
/**
|
|
403
|
+
* Whether a listing holds them in the project. Read as optional, so that a console older than
|
|
404
|
+
* this field still answers; everyone it lists is listed.
|
|
405
|
+
*/
|
|
406
|
+
listed: z.optional(z.boolean()),
|
|
337
407
|
});
|
|
338
408
|
export type RestMember = z.infer<typeof restMemberSchema>;
|
|
339
409
|
|
|
340
|
-
/** `GET /api/v1/projects/<key>/members`:
|
|
410
|
+
/** `GET /api/v1/projects/<key>/members`: the members, by login; everyone of the workspace in a project open to it. */
|
|
341
411
|
export const restMembersSchema = z.object({ items: z.array(restMemberSchema) });
|
|
342
412
|
export type RestMembers = z.infer<typeof restMembersSchema>;
|
|
343
413
|
|
|
@@ -991,6 +1061,53 @@ export const restPackTokenInputSchema = z.object({
|
|
|
991
1061
|
});
|
|
992
1062
|
export type RestPackTokenInput = z.infer<typeof restPackTokenInputSchema>;
|
|
993
1063
|
|
|
1064
|
+
/**
|
|
1065
|
+
* `POST .../pack-token/connect` (ADR-0036): what the person is shown, as the deployment said it,
|
|
1066
|
+
* the code and the page to approve it on, until when, and how often the console asks again. The
|
|
1067
|
+
* secret the console claims the token with stays with the console.
|
|
1068
|
+
*/
|
|
1069
|
+
export const restPackConnectStartedSchema = z.object({
|
|
1070
|
+
code: z.string(),
|
|
1071
|
+
url: z.string(),
|
|
1072
|
+
expiresAt: instant,
|
|
1073
|
+
intervalSeconds: z.int().check(z.positive()),
|
|
1074
|
+
});
|
|
1075
|
+
export type RestPackConnectStarted = z.infer<typeof restPackConnectStartedSchema>;
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* `GET .../pack-token/connect`: how the connection stands. Nothing asked; waiting for the
|
|
1079
|
+
* person, with what they were shown; connected, the token kept and the project as it stands; or
|
|
1080
|
+
* ended short of a token, and why.
|
|
1081
|
+
*/
|
|
1082
|
+
const packConnectNone = z.object({ status: z.literal("none") });
|
|
1083
|
+
const packConnectPending = z.object({
|
|
1084
|
+
status: z.literal("pending"),
|
|
1085
|
+
code: z.string(),
|
|
1086
|
+
url: z.string(),
|
|
1087
|
+
expiresAt: instant,
|
|
1088
|
+
intervalSeconds: z.int().check(z.positive()),
|
|
1089
|
+
});
|
|
1090
|
+
const packConnectEnded = z.object({
|
|
1091
|
+
status: z.literal("ended"),
|
|
1092
|
+
reason: z.enum(PACK_CONNECT_ENDINGS),
|
|
1093
|
+
});
|
|
1094
|
+
export const restPackConnectSchema = z.union([
|
|
1095
|
+
packConnectNone,
|
|
1096
|
+
packConnectPending,
|
|
1097
|
+
z.object({ status: z.literal("connected"), project: restProjectSchema }),
|
|
1098
|
+
packConnectEnded,
|
|
1099
|
+
]);
|
|
1100
|
+
export type RestPackConnect = z.infer<typeof restPackConnectSchema>;
|
|
1101
|
+
|
|
1102
|
+
/** `GET /api/v1/workspace/pack-token/connect`: the same, for the workspace's token, with the workspace as it stands once connected. */
|
|
1103
|
+
export const restWorkspacePackConnectSchema = z.union([
|
|
1104
|
+
packConnectNone,
|
|
1105
|
+
packConnectPending,
|
|
1106
|
+
z.object({ status: z.literal("connected"), workspace: restWorkspaceSchema }),
|
|
1107
|
+
packConnectEnded,
|
|
1108
|
+
]);
|
|
1109
|
+
export type RestWorkspacePackConnect = z.infer<typeof restWorkspacePackConnectSchema>;
|
|
1110
|
+
|
|
994
1111
|
/** `GET .../skills/one?path=&cursor=`: a page of a skill's context, as the pack answers `load_skill` (`RestSkill` of `@skillcdn/core`); `read` is `null` unless `ready`. */
|
|
995
1112
|
export const restSkillLoadSchema = z.object({
|
|
996
1113
|
...packEnvelope,
|
package/src/styles/console.css
CHANGED
|
@@ -1177,6 +1177,7 @@ table {
|
|
|
1177
1177
|
display: grid;
|
|
1178
1178
|
grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
|
|
1179
1179
|
gap: var(--sc-space-4);
|
|
1180
|
+
align-items: start;
|
|
1180
1181
|
}
|
|
1181
1182
|
|
|
1182
1183
|
.sc-input {
|
|
@@ -4130,3 +4131,158 @@ table {
|
|
|
4130
4131
|
.sc-goal-view-list {
|
|
4131
4132
|
display: block;
|
|
4132
4133
|
}
|
|
4134
|
+
|
|
4135
|
+
/* The workspace's settings (ADR-0035): each setting a row, its name beside its value; on the form,
|
|
4136
|
+
its name and its hint beside a control of a bounded width, so that a short choice is not a
|
|
4137
|
+
field as wide as the page. */
|
|
4138
|
+
.sc-settings-list {
|
|
4139
|
+
display: grid;
|
|
4140
|
+
margin: 0;
|
|
4141
|
+
font-size: var(--sc-text-sm);
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
.sc-settings-item {
|
|
4145
|
+
display: grid;
|
|
4146
|
+
grid-template-columns: minmax(8rem, 14rem) minmax(0, 1fr);
|
|
4147
|
+
gap: var(--sc-space-1) var(--sc-space-5);
|
|
4148
|
+
padding: var(--sc-space-3) 0;
|
|
4149
|
+
border-top: var(--sc-border);
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
.sc-settings-item:first-child {
|
|
4153
|
+
padding-top: 0;
|
|
4154
|
+
border-top: 0;
|
|
4155
|
+
}
|
|
4156
|
+
|
|
4157
|
+
.sc-settings-item:last-child {
|
|
4158
|
+
padding-bottom: 0;
|
|
4159
|
+
}
|
|
4160
|
+
|
|
4161
|
+
.sc-settings-item dt {
|
|
4162
|
+
color: var(--sc-color-text-muted);
|
|
4163
|
+
}
|
|
4164
|
+
|
|
4165
|
+
.sc-settings-item dd {
|
|
4166
|
+
margin: 0;
|
|
4167
|
+
}
|
|
4168
|
+
|
|
4169
|
+
.sc-settings-note {
|
|
4170
|
+
margin-left: var(--sc-space-3);
|
|
4171
|
+
color: var(--sc-color-text-muted);
|
|
4172
|
+
}
|
|
4173
|
+
|
|
4174
|
+
.sc-settings-form {
|
|
4175
|
+
gap: 0;
|
|
4176
|
+
}
|
|
4177
|
+
|
|
4178
|
+
.sc-settings-row {
|
|
4179
|
+
display: grid;
|
|
4180
|
+
grid-template-columns: minmax(0, 1fr) minmax(14rem, 20rem);
|
|
4181
|
+
gap: var(--sc-space-3) var(--sc-space-6);
|
|
4182
|
+
align-items: start;
|
|
4183
|
+
padding: var(--sc-space-4) 0;
|
|
4184
|
+
border-top: var(--sc-border);
|
|
4185
|
+
}
|
|
4186
|
+
|
|
4187
|
+
.sc-settings-row:first-child {
|
|
4188
|
+
padding-top: 0;
|
|
4189
|
+
border-top: 0;
|
|
4190
|
+
}
|
|
4191
|
+
|
|
4192
|
+
.sc-settings-label {
|
|
4193
|
+
display: block;
|
|
4194
|
+
font-weight: var(--sc-weight-medium);
|
|
4195
|
+
}
|
|
4196
|
+
|
|
4197
|
+
.sc-settings-hint {
|
|
4198
|
+
max-width: var(--sc-width-prose);
|
|
4199
|
+
margin: var(--sc-space-1) 0 0;
|
|
4200
|
+
color: var(--sc-color-text-muted);
|
|
4201
|
+
font-size: var(--sc-text-sm);
|
|
4202
|
+
}
|
|
4203
|
+
|
|
4204
|
+
.sc-settings-control {
|
|
4205
|
+
display: grid;
|
|
4206
|
+
justify-items: start;
|
|
4207
|
+
gap: var(--sc-space-2);
|
|
4208
|
+
}
|
|
4209
|
+
|
|
4210
|
+
.sc-settings-control .sc-input {
|
|
4211
|
+
width: 100%;
|
|
4212
|
+
}
|
|
4213
|
+
|
|
4214
|
+
.sc-settings-form .sc-form-actions {
|
|
4215
|
+
padding-top: var(--sc-space-4);
|
|
4216
|
+
border-top: var(--sc-border);
|
|
4217
|
+
}
|
|
4218
|
+
|
|
4219
|
+
@media (max-width: 40rem) {
|
|
4220
|
+
.sc-settings-item,
|
|
4221
|
+
.sc-settings-row {
|
|
4222
|
+
grid-template-columns: minmax(0, 1fr);
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
|
|
4226
|
+
/* The pack token (ADR-0028, ADR-0036): what it is for first, then the two ways to one side by
|
|
4227
|
+
side, each a card with its words before its controls, and the code shown large while the
|
|
4228
|
+
page waits for the approval. */
|
|
4229
|
+
.sc-pack-intro {
|
|
4230
|
+
max-width: var(--sc-width-prose);
|
|
4231
|
+
margin: 0 0 var(--sc-space-5);
|
|
4232
|
+
color: var(--sc-color-text-muted);
|
|
4233
|
+
font-size: var(--sc-text-sm);
|
|
4234
|
+
}
|
|
4235
|
+
|
|
4236
|
+
.sc-pack-ways {
|
|
4237
|
+
display: grid;
|
|
4238
|
+
grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
|
|
4239
|
+
gap: var(--sc-space-4);
|
|
4240
|
+
}
|
|
4241
|
+
|
|
4242
|
+
.sc-pack-way {
|
|
4243
|
+
display: grid;
|
|
4244
|
+
align-content: start;
|
|
4245
|
+
gap: var(--sc-space-3);
|
|
4246
|
+
padding: var(--sc-space-4);
|
|
4247
|
+
border: var(--sc-border);
|
|
4248
|
+
border-radius: var(--sc-radius-lg);
|
|
4249
|
+
background: var(--sc-color-sheet);
|
|
4250
|
+
}
|
|
4251
|
+
|
|
4252
|
+
.sc-pack-way-title {
|
|
4253
|
+
font-size: var(--sc-text-md);
|
|
4254
|
+
font-weight: var(--sc-weight-medium);
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
.sc-pack-way .sc-field-hint {
|
|
4258
|
+
margin-top: 0;
|
|
4259
|
+
}
|
|
4260
|
+
|
|
4261
|
+
.sc-pack-connect {
|
|
4262
|
+
display: grid;
|
|
4263
|
+
gap: var(--sc-space-3);
|
|
4264
|
+
}
|
|
4265
|
+
|
|
4266
|
+
.sc-pack-connect-code {
|
|
4267
|
+
display: flex;
|
|
4268
|
+
flex-wrap: wrap;
|
|
4269
|
+
align-items: baseline;
|
|
4270
|
+
gap: var(--sc-space-3);
|
|
4271
|
+
}
|
|
4272
|
+
|
|
4273
|
+
.sc-pack-code {
|
|
4274
|
+
font-size: var(--sc-text-xl);
|
|
4275
|
+
letter-spacing: 0.12em;
|
|
4276
|
+
}
|
|
4277
|
+
|
|
4278
|
+
.sc-pack-connect-waiting {
|
|
4279
|
+
display: flex;
|
|
4280
|
+
align-items: center;
|
|
4281
|
+
gap: var(--sc-space-2);
|
|
4282
|
+
color: var(--sc-color-text-muted);
|
|
4283
|
+
font-size: var(--sc-text-sm);
|
|
4284
|
+
}
|
|
4285
|
+
|
|
4286
|
+
.sc-pack-actions {
|
|
4287
|
+
margin-top: var(--sc-space-5);
|
|
4288
|
+
}
|
package/src/vocabulary.ts
CHANGED
|
@@ -97,6 +97,30 @@ export const PROJECT_VISIBILITIES = ["workspace", "private"] as const;
|
|
|
97
97
|
|
|
98
98
|
export type ProjectVisibility = (typeof PROJECT_VISIBILITIES)[number];
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Who sees whom on the People page and in the pickers (ADR-0035): everyone of the workspace,
|
|
102
|
+
* or only the people one shares a project with; an administrator always sees everyone.
|
|
103
|
+
*/
|
|
104
|
+
export const PEOPLE_VISIBILITIES = ["everyone", "shared_projects"] as const;
|
|
105
|
+
|
|
106
|
+
export type PeopleVisibility = (typeof PEOPLE_VISIBILITIES)[number];
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The day the calendars begin a week on (ADR-0035): as the language of the pages has it, or
|
|
110
|
+
* Monday, or Sunday, for the whole workspace.
|
|
111
|
+
*/
|
|
112
|
+
export const WEEK_STARTS = ["auto", "monday", "sunday"] as const;
|
|
113
|
+
|
|
114
|
+
export type WeekStart = (typeof WEEK_STARTS)[number];
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* How a private pack's connection ended short of a token (ADR-0036): the code expired before
|
|
118
|
+
* anyone approved, the person declined at the deployment, or the deployment refused the request.
|
|
119
|
+
*/
|
|
120
|
+
export const PACK_CONNECT_ENDINGS = ["expired", "declined", "refused"] as const;
|
|
121
|
+
|
|
122
|
+
export type PackConnectEnding = (typeof PACK_CONNECT_ENDINGS)[number];
|
|
123
|
+
|
|
100
124
|
/** What a run is doing: at work, waiting for a person's decision, or over in one of three ways. */
|
|
101
125
|
export const RUN_STATUSES = ["running", "waiting", "finished", "failed", "abandoned"] as const;
|
|
102
126
|
|
|
@@ -153,6 +177,7 @@ export const EVENT_KINDS = [
|
|
|
153
177
|
"person.unlisted",
|
|
154
178
|
"person.deactivated",
|
|
155
179
|
"person.reactivated",
|
|
180
|
+
"workspace.updated",
|
|
156
181
|
"category.created",
|
|
157
182
|
"category.updated",
|
|
158
183
|
"category.removed",
|