@eyeauras/youtrack-cli 0.5.5 → 0.5.7
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 +63 -56
- package/dist/src/agile-commands.d.ts.map +1 -1
- package/dist/src/agile-commands.js +8 -9
- package/dist/src/agile-commands.js.map +1 -1
- package/dist/src/agile.d.ts.map +1 -1
- package/dist/src/agile.js +9 -15
- package/dist/src/agile.js.map +1 -1
- package/dist/src/article-extras-commands.d.ts.map +1 -1
- package/dist/src/article-extras-commands.js +13 -12
- package/dist/src/article-extras-commands.js.map +1 -1
- package/dist/src/articles-commands.d.ts.map +1 -1
- package/dist/src/articles-commands.js +15 -12
- package/dist/src/articles-commands.js.map +1 -1
- package/dist/src/articles.d.ts.map +1 -1
- package/dist/src/articles.js +13 -14
- package/dist/src/articles.js.map +1 -1
- package/dist/src/attachment-download-commands.d.ts.map +1 -1
- package/dist/src/attachment-download-commands.js +7 -5
- package/dist/src/attachment-download-commands.js.map +1 -1
- package/dist/src/attachment-download.d.ts +1 -0
- package/dist/src/attachment-download.d.ts.map +1 -1
- package/dist/src/attachment-download.js +16 -26
- package/dist/src/attachment-download.js.map +1 -1
- package/dist/src/attachment-form.js +3 -3
- package/dist/src/attachment-form.js.map +1 -1
- package/dist/src/bundle-values-commands.d.ts.map +1 -1
- package/dist/src/bundle-values-commands.js +21 -18
- package/dist/src/bundle-values-commands.js.map +1 -1
- package/dist/src/cli-support.d.ts +5 -5
- package/dist/src/cli-support.d.ts.map +1 -1
- package/dist/src/cli-support.js +28 -26
- package/dist/src/cli-support.js.map +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +52 -34
- package/dist/src/cli.js.map +1 -1
- package/dist/src/client.d.ts +5 -2
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +66 -49
- package/dist/src/client.js.map +1 -1
- package/dist/src/field-catalog-commands.d.ts.map +1 -1
- package/dist/src/field-catalog-commands.js +19 -16
- package/dist/src/field-catalog-commands.js.map +1 -1
- package/dist/src/group-directory-commands.d.ts.map +1 -1
- package/dist/src/group-directory-commands.js +17 -16
- package/dist/src/group-directory-commands.js.map +1 -1
- package/dist/src/issue-attachments-commands.d.ts.map +1 -1
- package/dist/src/issue-attachments-commands.js +9 -8
- package/dist/src/issue-attachments-commands.js.map +1 -1
- package/dist/src/issue-batch.d.ts +2 -0
- package/dist/src/issue-batch.d.ts.map +1 -1
- package/dist/src/issue-batch.js +14 -10
- package/dist/src/issue-batch.js.map +1 -1
- package/dist/src/issue-context-commands.d.ts.map +1 -1
- package/dist/src/issue-context-commands.js +13 -12
- package/dist/src/issue-context-commands.js.map +1 -1
- package/dist/src/issue-context.d.ts.map +1 -1
- package/dist/src/issue-context.js +9 -13
- package/dist/src/issue-context.js.map +1 -1
- package/dist/src/issue-fields-commands.d.ts.map +1 -1
- package/dist/src/issue-fields-commands.js +10 -9
- package/dist/src/issue-fields-commands.js.map +1 -1
- package/dist/src/issue-fields.d.ts +2 -4
- package/dist/src/issue-fields.d.ts.map +1 -1
- package/dist/src/issue-fields.js +39 -100
- package/dist/src/issue-fields.js.map +1 -1
- package/dist/src/issue-query-commands.d.ts.map +1 -1
- package/dist/src/issue-query-commands.js +15 -14
- package/dist/src/issue-query-commands.js.map +1 -1
- package/dist/src/issue-query.d.ts.map +1 -1
- package/dist/src/issue-query.js +7 -10
- package/dist/src/issue-query.js.map +1 -1
- package/dist/src/issue-relations-commands.d.ts.map +1 -1
- package/dist/src/issue-relations-commands.js +17 -16
- package/dist/src/issue-relations-commands.js.map +1 -1
- package/dist/src/issue-relations.js +2 -2
- package/dist/src/issue-relations.js.map +1 -1
- package/dist/src/issue-time-commands.d.ts.map +1 -1
- package/dist/src/issue-time-commands.js +12 -11
- package/dist/src/issue-time-commands.js.map +1 -1
- package/dist/src/issue-time.d.ts.map +1 -1
- package/dist/src/issue-time.js +16 -19
- package/dist/src/issue-time.js.map +1 -1
- package/dist/src/presentation.d.ts +59 -0
- package/dist/src/presentation.d.ts.map +1 -0
- package/dist/src/presentation.js +467 -0
- package/dist/src/presentation.js.map +1 -0
- package/dist/src/time-settings-commands.d.ts.map +1 -1
- package/dist/src/time-settings-commands.js +13 -11
- package/dist/src/time-settings-commands.js.map +1 -1
- package/dist/src/user-directory-commands.d.ts.map +1 -1
- package/dist/src/user-directory-commands.js +14 -12
- package/dist/src/user-directory-commands.js.map +1 -1
- package/package.json +2 -2
package/dist/src/issue-time.js
CHANGED
|
@@ -15,7 +15,7 @@ export async function listWorkItems(connection, options = {}) {
|
|
|
15
15
|
export const getWorkItem = readObjectAt((itemID) => `api/workItems/${encodedID(itemID, "work item ID")}`, workItemFields);
|
|
16
16
|
function timestamp(value, name) {
|
|
17
17
|
if (typeof value !== "number" || !Number.isSafeInteger(value)) {
|
|
18
|
-
throw new Error(`
|
|
18
|
+
throw new Error(`The ${name} must be a safe integer timestamp in milliseconds.`);
|
|
19
19
|
}
|
|
20
20
|
return value;
|
|
21
21
|
}
|
|
@@ -23,46 +23,43 @@ function reference(value, name) {
|
|
|
23
23
|
if (value === null) {
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
26
|
-
const body = mutationBody(value
|
|
26
|
+
const body = mutationBody(value);
|
|
27
27
|
if (typeof body.id !== "string") {
|
|
28
|
-
throw new Error(`
|
|
28
|
+
throw new Error(`The ${name}.id must be text.`);
|
|
29
29
|
}
|
|
30
|
-
return { id: requiredText(body.id, `${name}.id`) };
|
|
30
|
+
return { ...body, id: requiredText(body.id, `${name}.id`) };
|
|
31
31
|
}
|
|
32
|
-
function duration(value) {
|
|
33
|
-
const body = mutationBody(value
|
|
34
|
-
if (Object.
|
|
35
|
-
throw new Error("
|
|
32
|
+
function duration(value, creating) {
|
|
33
|
+
const body = mutationBody(value);
|
|
34
|
+
if (creating && !Object.hasOwn(body, "minutes") && !Object.hasOwn(body, "presentation")) {
|
|
35
|
+
throw new Error("duration requires minutes or presentation.");
|
|
36
36
|
}
|
|
37
|
-
const result = {};
|
|
37
|
+
const result = { ...body };
|
|
38
38
|
if (Object.hasOwn(body, "minutes")) {
|
|
39
39
|
if (typeof body.minutes !== "number" ||
|
|
40
40
|
!Number.isSafeInteger(body.minutes) ||
|
|
41
|
-
body.minutes <
|
|
41
|
+
body.minutes < -2_147_483_648 ||
|
|
42
42
|
body.minutes > 2_147_483_647) {
|
|
43
|
-
throw new Error("
|
|
43
|
+
throw new Error("The duration.minutes must be a signed 32-bit integer.");
|
|
44
44
|
}
|
|
45
45
|
result.minutes = body.minutes;
|
|
46
46
|
}
|
|
47
47
|
if (Object.hasOwn(body, "presentation")) {
|
|
48
48
|
if (typeof body.presentation !== "string") {
|
|
49
|
-
throw new Error("
|
|
49
|
+
throw new Error("The duration.presentation must be text.");
|
|
50
50
|
}
|
|
51
51
|
result.presentation = requiredText(body.presentation, "duration.presentation");
|
|
52
52
|
}
|
|
53
53
|
return result;
|
|
54
54
|
}
|
|
55
55
|
function workItemBody(input, creating) {
|
|
56
|
-
const body = mutationBody(input
|
|
56
|
+
const body = mutationBody(input);
|
|
57
57
|
if (creating && !Object.hasOwn(body, "duration")) {
|
|
58
|
-
throw new Error("
|
|
58
|
+
throw new Error("A new work item requires duration.minutes or duration.presentation.");
|
|
59
59
|
}
|
|
60
|
-
|
|
61
|
-
throw new Error("YouTrack work-item update requires at least one writable field.");
|
|
62
|
-
}
|
|
63
|
-
const result = {};
|
|
60
|
+
const result = { ...body };
|
|
64
61
|
if (Object.hasOwn(body, "duration")) {
|
|
65
|
-
result.duration = duration(body.duration);
|
|
62
|
+
result.duration = duration(body.duration, creating);
|
|
66
63
|
}
|
|
67
64
|
for (const name of ["date", "created", "updated"]) {
|
|
68
65
|
if (Object.hasOwn(body, name)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue-time.js","sourceRoot":"","sources":["../../src/issue-time.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,MAAM,EACN,SAAS,EACT,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,IAAI,EACJ,cAAc,EACd,gBAAgB,EAChB,YAAY,EACZ,YAAY,GAKb,MAAM,aAAa,CAAC;AAErB,MAAM,cAAc,GAAG,iGAAiG,CAAC;AAEzH,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,yBAAyB,CAAC;AACxD,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CACzC,CAAC,OAAe,EAAE,EAAE,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,eAAe,EACzD,YAAY,CACb,CAAC;AACF,MAAM,CAAC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;AAClF,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAC1C,CAAC,OAAe,EAAE,MAAc,EAAE,EAAE,CAClC,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,EAClE,cAAc,CACf,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAsB,EAAE,OAAO,GAAuB,EAAE;IAC1F,OAAO,cAAc,CAAC,UAAU,EAAE,eAAe,EAAE;QACjD,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC;QAChC,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;KACxF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CACrC,CAAC,MAAc,EAAE,EAAE,CAAC,iBAAiB,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,EACxE,cAAc,CACf,CAAC;AAEF,SAAS,SAAS,CAAC,KAAc,EAAE,IAAY;IAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"issue-time.js","sourceRoot":"","sources":["../../src/issue-time.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type CommandDefinition, type HumanView, type ViewContext } from "@eyeauras/cli-factory";
|
|
2
|
+
/** Attach a view; an explicit `--fields` projection shows the generic shape instead. */
|
|
3
|
+
export declare function withView(view: HumanView, definition: CommandDefinition): CommandDefinition;
|
|
4
|
+
export declare const arg: (context: ViewContext, name: string) => string;
|
|
5
|
+
/** A plain ID + NAME table for reference lists such as bundles and groups. */
|
|
6
|
+
export declare function namedTable(header: string, empty: string): HumanView;
|
|
7
|
+
/** A one-line confirmation built from the command's own arguments, for results without data. */
|
|
8
|
+
export declare function done(describe: (context: ViewContext) => string): HumanView;
|
|
9
|
+
export declare const issueTable: HumanView;
|
|
10
|
+
export declare const issueRecord: HumanView;
|
|
11
|
+
export declare const createdIssue: HumanView;
|
|
12
|
+
export declare const updatedIssue: HumanView;
|
|
13
|
+
export declare const countRecord: HumanView;
|
|
14
|
+
export declare const commentTable: HumanView;
|
|
15
|
+
export declare const commentShown: HumanView;
|
|
16
|
+
/** `owner` names the positional argument that identifies the issue or article. */
|
|
17
|
+
export declare const commentAdded: (owner: string) => HumanView;
|
|
18
|
+
export declare const commentUpdated: (owner: string, comment: string) => HumanView;
|
|
19
|
+
export declare const projectTable: HumanView;
|
|
20
|
+
export declare const projectRecord: HumanView;
|
|
21
|
+
export declare const userTable: HumanView;
|
|
22
|
+
export declare const userRecord: HumanView;
|
|
23
|
+
export declare const agileTable: HumanView;
|
|
24
|
+
export declare const agileRecord: HumanView;
|
|
25
|
+
export declare const sprintTable: HumanView;
|
|
26
|
+
export declare const sprintRecord: HumanView;
|
|
27
|
+
export declare const sprintWritten: (verb: string) => HumanView;
|
|
28
|
+
export declare const articleTable: HumanView;
|
|
29
|
+
export declare const articleRecord: HumanView;
|
|
30
|
+
export declare const createdArticle: HumanView;
|
|
31
|
+
export declare const updatedArticle: HumanView;
|
|
32
|
+
export declare const tagTable: HumanView;
|
|
33
|
+
export declare const tagRecord: HumanView;
|
|
34
|
+
export declare const issueTagList: HumanView;
|
|
35
|
+
export declare const tagAdded: HumanView;
|
|
36
|
+
export declare const linkTypeTable: HumanView;
|
|
37
|
+
export declare const linkGroupList: HumanView;
|
|
38
|
+
export declare const linkGroupRecord: HumanView;
|
|
39
|
+
export declare const linkTypeRecord: HumanView;
|
|
40
|
+
export declare const linkedIssueList: HumanView;
|
|
41
|
+
export declare const issueLinked: HumanView;
|
|
42
|
+
export declare const attachmentTable: HumanView;
|
|
43
|
+
export declare const attachmentRecord: HumanView;
|
|
44
|
+
export declare const savedAttachment: HumanView;
|
|
45
|
+
export declare const exportedArticle: HumanView;
|
|
46
|
+
export declare const groupTable: HumanView;
|
|
47
|
+
export declare const groupRecord: HumanView;
|
|
48
|
+
/** A project's custom-field settings wrap the global field under `field`. */
|
|
49
|
+
export declare const projectFieldTable: HumanView;
|
|
50
|
+
export declare const commandApplied: HumanView;
|
|
51
|
+
export declare const fieldTable: HumanView;
|
|
52
|
+
export declare const issueFieldTable: HumanView;
|
|
53
|
+
export declare const issueFieldRecord: HumanView;
|
|
54
|
+
export declare const workItemTable: HumanView;
|
|
55
|
+
export declare const savedQueryTable: HumanView;
|
|
56
|
+
export declare const batchValidated: HumanView;
|
|
57
|
+
export declare const batchApplied: HumanView;
|
|
58
|
+
export declare const uploadedAttachments: HumanView;
|
|
59
|
+
//# sourceMappingURL=presentation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.d.ts","sourceRoot":"","sources":["../../src/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,iBAAiB,EACtB,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,uBAAuB,CAAC;AAK/B,wFAAwF;AACxF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,GAAG,iBAAiB,CAE1F;AAsBD,eAAO,MAAM,GAAG,YAAa,WAAW,QAAQ,MAAM,KAAG,MAA+C,CAAC;AAkBzG,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAMnE;AAED,gGAAgG;AAChG,wBAAgB,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,MAAM,GAAG,SAAS,CAE1E;AAED,eAAO,MAAM,UAAU,WAUrB,CAAC;AAEH,eAAO,MAAM,WAAW,WAiBtB,CAAC;AAYH,eAAO,MAAM,YAAY,WAA0B,CAAC;AACpD,eAAO,MAAM,YAAY,WAA0B,CAAC;AAEpD,eAAO,MAAM,WAAW,WAStB,CAAC;AAEH,eAAO,MAAM,YAAY,WASvB,CAAC;AAaH,eAAO,MAAM,YAAY,WAAmE,CAAC;AAC7F,kFAAkF;AAClF,eAAO,MAAM,YAAY,UAAW,MAAM,KAAG,SACmF,CAAC;AACjI,eAAO,MAAM,cAAc,UAAW,MAAM,WAAW,MAAM,KAAG,SAC0C,CAAC;AAE3G,eAAO,MAAM,YAAY,WAQvB,CAAC;AAEH,eAAO,MAAM,aAAa,WAOxB,CAAC;AAEH,eAAO,MAAM,SAAS,WAQpB,CAAC;AAEH,eAAO,MAAM,UAAU,WAMrB,CAAC;AAEH,eAAO,MAAM,UAAU,WAQrB,CAAC;AAEH,eAAO,MAAM,WAAW,WAStB,CAAC;AAYH,eAAO,MAAM,WAAW,WAUtB,CAAC;AAEH,eAAO,MAAM,YAAY,WAA2F,CAAC;AACrH,eAAO,MAAM,aAAa,SAAU,MAAM,KAAG,SAIzC,CAAC;AAEL,eAAO,MAAM,YAAY,WASvB,CAAC;AAEH,eAAO,MAAM,aAAa,WASxB,CAAC;AAYH,eAAO,MAAM,cAAc,WAA4B,CAAC;AACxD,eAAO,MAAM,cAAc,WAA4B,CAAC;AAExD,eAAO,MAAM,QAAQ,WAAgC,CAAC;AACtD,eAAO,MAAM,SAAS,WAAgH,CAAC;AACvI,eAAO,MAAM,YAAY,WAIvB,CAAC;AACH,eAAO,MAAM,QAAQ,WAGnB,CAAC;AAEH,eAAO,MAAM,aAAa,WAUxB,CAAC;AAWH,eAAO,MAAM,aAAa,WAA8E,CAAC;AACzG,eAAO,MAAM,eAAe,WAM1B,CAAC;AACH,eAAO,MAAM,cAAc,WAQzB,CAAC;AACH,eAAO,MAAM,eAAe,WAI1B,CAAC;AACH,eAAO,MAAM,WAAW,WAItB,CAAC;AAEH,eAAO,MAAM,eAAe,WAS1B,CAAC;AACH,eAAO,MAAM,gBAAgB,WAO3B,CAAC;AACH,eAAO,MAAM,eAAe,WAQ1B,CAAC;AACH,eAAO,MAAM,eAAe,WAY1B,CAAC;AAEH,eAAO,MAAM,UAAU,WAQrB,CAAC;AAEH,eAAO,MAAM,WAAW,WAOtB,CAAC;AAEH,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,WAU5B,CAAC;AAEH,eAAO,MAAM,cAAc,WAOzB,CAAC;AAEH,eAAO,MAAM,UAAU,WASrB,CAAC;AAWH,eAAO,MAAM,eAAe,WAQ1B,CAAC;AACH,eAAO,MAAM,gBAAgB,WAK3B,CAAC;AAEH,eAAO,MAAM,aAAa,WAYxB,CAAC;AAEH,eAAO,MAAM,eAAe,WAS1B,CAAC;AAEH,eAAO,MAAM,cAAc,WAIzB,CAAC;AAKH,eAAO,MAAM,YAAY,WAkBvB,CAAC;AAEH,eAAO,MAAM,mBAAmB,WAQ9B,CAAC"}
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import { listView, offsetFooter, recordView, tableView, } from "@eyeauras/cli-factory";
|
|
2
|
+
/** Attach a view; an explicit `--fields` projection shows the generic shape instead. */
|
|
3
|
+
export function withView(view, definition) {
|
|
4
|
+
return { ...definition, view: { ...view, when: (context) => context.input?.options.fields === undefined } };
|
|
5
|
+
}
|
|
6
|
+
// Every accessor tolerates a projection that left the field out: it simply shows nothing.
|
|
7
|
+
const text = (value) => (typeof value === "string" ? value : undefined);
|
|
8
|
+
const count = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
9
|
+
const instant = (value) => {
|
|
10
|
+
const millis = count(value);
|
|
11
|
+
const date = millis === undefined ? undefined : new Date(millis);
|
|
12
|
+
return date && Number.isFinite(date.getTime()) ? date : undefined;
|
|
13
|
+
};
|
|
14
|
+
const day = (value) => instant(value)?.toISOString().slice(0, 10);
|
|
15
|
+
const yes = (value) => (value === true ? "yes" : undefined);
|
|
16
|
+
const nested = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
17
|
+
const firstLine = (value) => text(value)?.split(/\r?\n/, 1)[0];
|
|
18
|
+
const lines = (value) => {
|
|
19
|
+
const body = text(value);
|
|
20
|
+
return body === undefined || body.trim() === "" ? undefined : body.split(/\r?\n/);
|
|
21
|
+
};
|
|
22
|
+
const key = (item) => text(item?.idReadable) ?? text(item?.id);
|
|
23
|
+
export const arg = (context, name) => text(context.input?.args[name]) ?? "";
|
|
24
|
+
const option = (context, name) => text(context.input?.options[name]);
|
|
25
|
+
const joined = (...parts) => {
|
|
26
|
+
const present = parts.filter((part) => part !== undefined && part !== "");
|
|
27
|
+
return present.length ? present.join(" · ") : undefined;
|
|
28
|
+
};
|
|
29
|
+
/** An offset page continues with `--skip` when it came back full; `--all` already read everything. */
|
|
30
|
+
function pageFooter(rows, context) {
|
|
31
|
+
if (!Array.isArray(rows) || context.input?.options.all === true)
|
|
32
|
+
return undefined;
|
|
33
|
+
return offsetFooter("--skip", rows.length, count(context.input?.options.top), count(context.input?.options.skip));
|
|
34
|
+
}
|
|
35
|
+
const id = { header: "ID", value: (item) => text(item.id) };
|
|
36
|
+
const login = (item) => text(nested(item?.author)?.login);
|
|
37
|
+
const state = (issue) => issue.resolved === undefined ? undefined : issue.resolved === null ? "open" : "resolved";
|
|
38
|
+
/** A plain ID + NAME table for reference lists such as bundles and groups. */
|
|
39
|
+
export function namedTable(header, empty) {
|
|
40
|
+
return tableView({
|
|
41
|
+
columns: [id, { header, value: (item) => text(item.name) }],
|
|
42
|
+
empty,
|
|
43
|
+
footer: pageFooter,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/** A one-line confirmation built from the command's own arguments, for results without data. */
|
|
47
|
+
export function done(describe) {
|
|
48
|
+
return recordView({ title: (_value, context) => describe(context), fields: [] });
|
|
49
|
+
}
|
|
50
|
+
export const issueTable = tableView({
|
|
51
|
+
columns: [
|
|
52
|
+
{ header: "ISSUE", value: key },
|
|
53
|
+
{ header: "SUMMARY", value: (issue) => text(issue.summary), shrink: true },
|
|
54
|
+
{ header: "PROJECT", value: (issue) => text(nested(issue.project)?.shortName) },
|
|
55
|
+
{ header: "STATE", value: state },
|
|
56
|
+
{ header: "UPDATED", value: (issue) => instant(issue.updated), format: "age" },
|
|
57
|
+
],
|
|
58
|
+
empty: "No issues found.",
|
|
59
|
+
footer: pageFooter,
|
|
60
|
+
});
|
|
61
|
+
export const issueRecord = recordView({
|
|
62
|
+
title: (issue) => joined(key(issue), text(issue.summary)),
|
|
63
|
+
fields: [
|
|
64
|
+
{
|
|
65
|
+
label: "Project",
|
|
66
|
+
value: (issue) => joined(text(nested(issue.project)?.shortName), text(nested(issue.project)?.name)),
|
|
67
|
+
},
|
|
68
|
+
{ label: "State", value: state },
|
|
69
|
+
{ label: "Resolved", value: (issue) => instant(issue.resolved) },
|
|
70
|
+
{ label: "Created", value: (issue) => instant(issue.created) },
|
|
71
|
+
{ label: "Updated", value: (issue) => instant(issue.updated) },
|
|
72
|
+
],
|
|
73
|
+
sections: [{ title: () => "Description", lines: (issue) => lines(issue.description) }],
|
|
74
|
+
next: (issue) => {
|
|
75
|
+
const issueID = key(issue);
|
|
76
|
+
return issueID ? [["issues", "comments", "list", issueID]] : [];
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
function writtenIssue(verb) {
|
|
80
|
+
return recordView({
|
|
81
|
+
title: (issue, context) => joined(`${verb} ${key(issue) ?? (arg(context, "issueID") || "the issue")}`, text(issue?.summary)),
|
|
82
|
+
fields: [{ label: "Updated", value: (issue) => instant(issue?.updated) }],
|
|
83
|
+
next: (issue, context) => {
|
|
84
|
+
const issueID = key(issue) ?? arg(context, "issueID");
|
|
85
|
+
return issueID ? [["issues", "get", issueID]] : [];
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
export const createdIssue = writtenIssue("Created");
|
|
90
|
+
export const updatedIssue = writtenIssue("Updated");
|
|
91
|
+
export const countRecord = recordView({
|
|
92
|
+
title: (value, context) => {
|
|
93
|
+
const matches = count(value.count);
|
|
94
|
+
if (matches === undefined)
|
|
95
|
+
return undefined;
|
|
96
|
+
if (matches < 0)
|
|
97
|
+
return "The count is still pending; run it again in a moment.";
|
|
98
|
+
const query = option(context, "query");
|
|
99
|
+
return `${matches} issue${matches === 1 ? "" : "s"} match${matches === 1 ? "es" : ""}${query ? ` "${query}"` : ""}.`;
|
|
100
|
+
},
|
|
101
|
+
fields: [],
|
|
102
|
+
});
|
|
103
|
+
export const commentTable = tableView({
|
|
104
|
+
columns: [
|
|
105
|
+
{ header: "COMMENT", value: (comment) => text(comment.id) },
|
|
106
|
+
{ header: "AUTHOR", value: (comment) => login(comment) },
|
|
107
|
+
{ header: "AGE", value: (comment) => instant(comment.updated ?? comment.created), format: "age" },
|
|
108
|
+
{ header: "TEXT", value: (comment) => firstLine(comment.text), shrink: true },
|
|
109
|
+
],
|
|
110
|
+
empty: "No comments.",
|
|
111
|
+
footer: pageFooter,
|
|
112
|
+
});
|
|
113
|
+
function commentRecord(title) {
|
|
114
|
+
return recordView({
|
|
115
|
+
title,
|
|
116
|
+
fields: [
|
|
117
|
+
{ label: "Author", value: (comment) => login(comment ?? undefined) },
|
|
118
|
+
{ label: "Created", value: (comment) => instant(comment?.created) },
|
|
119
|
+
{ label: "Updated", value: (comment) => instant(comment?.updated) },
|
|
120
|
+
],
|
|
121
|
+
sections: [{ title: () => "Text", lines: (comment) => lines(comment?.text) }],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
export const commentShown = commentRecord((comment) => joined("Comment", text(comment?.id)));
|
|
125
|
+
/** `owner` names the positional argument that identifies the issue or article. */
|
|
126
|
+
export const commentAdded = (owner) => commentRecord((comment, context) => `Added comment ${text(comment?.id) ?? ""} to ${arg(context, owner)}`.replace(/\s+/g, " "));
|
|
127
|
+
export const commentUpdated = (owner, comment) => commentRecord((_value, context) => `Updated comment ${arg(context, comment)} on ${arg(context, owner)}`);
|
|
128
|
+
export const projectTable = tableView({
|
|
129
|
+
columns: [
|
|
130
|
+
id,
|
|
131
|
+
{ header: "KEY", value: (project) => text(project.shortName) },
|
|
132
|
+
{ header: "NAME", value: (project) => text(project.name), shrink: true },
|
|
133
|
+
],
|
|
134
|
+
empty: "No projects.",
|
|
135
|
+
footer: pageFooter,
|
|
136
|
+
});
|
|
137
|
+
export const projectRecord = recordView({
|
|
138
|
+
title: (project) => joined(text(project.shortName), text(project.name)),
|
|
139
|
+
fields: [
|
|
140
|
+
{ label: "ID", value: (project) => text(project.id) },
|
|
141
|
+
{ label: "Description", value: (project) => firstLine(project.description) },
|
|
142
|
+
{ label: "Archived", value: (project) => yes(project.archived) },
|
|
143
|
+
],
|
|
144
|
+
});
|
|
145
|
+
export const userTable = tableView({
|
|
146
|
+
columns: [
|
|
147
|
+
id,
|
|
148
|
+
{ header: "LOGIN", value: (user) => text(user.login) },
|
|
149
|
+
{ header: "NAME", value: (user) => text(user.fullName), shrink: true },
|
|
150
|
+
],
|
|
151
|
+
empty: "No users.",
|
|
152
|
+
footer: pageFooter,
|
|
153
|
+
});
|
|
154
|
+
export const userRecord = recordView({
|
|
155
|
+
title: (user) => joined(text(user.login), text(user.fullName)),
|
|
156
|
+
fields: [
|
|
157
|
+
{ label: "ID", value: (user) => text(user.id) },
|
|
158
|
+
{ label: "Email", value: (user) => text(user.email) },
|
|
159
|
+
],
|
|
160
|
+
});
|
|
161
|
+
export const agileTable = tableView({
|
|
162
|
+
columns: [
|
|
163
|
+
id,
|
|
164
|
+
{ header: "BOARD", value: (agile) => text(agile.name), shrink: true },
|
|
165
|
+
{ header: "CURRENT SPRINT", value: (agile) => text(nested(agile.currentSprint)?.name) },
|
|
166
|
+
],
|
|
167
|
+
empty: "No agile boards.",
|
|
168
|
+
footer: pageFooter,
|
|
169
|
+
});
|
|
170
|
+
export const agileRecord = recordView({
|
|
171
|
+
title: (agile) => text(agile.name),
|
|
172
|
+
fields: [
|
|
173
|
+
{ label: "ID", value: (agile) => text(agile.id) },
|
|
174
|
+
{ label: "Current sprint", value: (agile) => text(nested(agile.currentSprint)?.name) },
|
|
175
|
+
{ label: "Sprint start", value: (agile) => day(nested(agile.currentSprint)?.start) },
|
|
176
|
+
{ label: "Sprint finish", value: (agile) => day(nested(agile.currentSprint)?.finish) },
|
|
177
|
+
{ label: "Valid", value: (agile) => yes(nested(agile.status)?.valid) },
|
|
178
|
+
],
|
|
179
|
+
});
|
|
180
|
+
const sprintFields = [
|
|
181
|
+
{ label: "ID", value: (sprint) => text(sprint?.id) },
|
|
182
|
+
{ label: "Board", value: (sprint) => text(nested(sprint?.agile)?.name) },
|
|
183
|
+
{ label: "Goal", value: (sprint) => firstLine(sprint?.goal) },
|
|
184
|
+
{ label: "Start", value: (sprint) => day(sprint?.start) },
|
|
185
|
+
{ label: "Finish", value: (sprint) => day(sprint?.finish) },
|
|
186
|
+
{ label: "Archived", value: (sprint) => yes(sprint?.archived) },
|
|
187
|
+
{ label: "Default", value: (sprint) => yes(sprint?.isDefault) },
|
|
188
|
+
];
|
|
189
|
+
export const sprintTable = tableView({
|
|
190
|
+
columns: [
|
|
191
|
+
id,
|
|
192
|
+
{ header: "SPRINT", value: (sprint) => text(sprint.name), shrink: true },
|
|
193
|
+
{ header: "START", value: (sprint) => day(sprint.start) },
|
|
194
|
+
{ header: "FINISH", value: (sprint) => day(sprint.finish) },
|
|
195
|
+
{ header: "ARCHIVED", value: (sprint) => yes(sprint.archived) },
|
|
196
|
+
],
|
|
197
|
+
empty: "No sprints.",
|
|
198
|
+
footer: pageFooter,
|
|
199
|
+
});
|
|
200
|
+
export const sprintRecord = recordView({ title: (sprint) => text(sprint?.name), fields: sprintFields });
|
|
201
|
+
export const sprintWritten = (verb) => recordView({
|
|
202
|
+
title: (sprint, context) => `${verb} sprint ${text(sprint?.name) ?? arg(context, "sprint")}`.trim(),
|
|
203
|
+
fields: sprintFields,
|
|
204
|
+
});
|
|
205
|
+
export const articleTable = tableView({
|
|
206
|
+
columns: [
|
|
207
|
+
{ header: "ARTICLE", value: key },
|
|
208
|
+
{ header: "SUMMARY", value: (article) => text(article.summary), shrink: true },
|
|
209
|
+
{ header: "PROJECT", value: (article) => text(nested(article.project)?.shortName) },
|
|
210
|
+
{ header: "UPDATED", value: (article) => instant(article.updated), format: "age" },
|
|
211
|
+
],
|
|
212
|
+
empty: "No articles.",
|
|
213
|
+
footer: pageFooter,
|
|
214
|
+
});
|
|
215
|
+
export const articleRecord = recordView({
|
|
216
|
+
title: (article) => (article ? joined(key(article), text(article.summary)) : "No parent article."),
|
|
217
|
+
fields: [
|
|
218
|
+
{ label: "Project", value: (article) => text(nested(article?.project)?.shortName) },
|
|
219
|
+
{ label: "Parent", value: (article) => key(nested(article?.parentArticle)) },
|
|
220
|
+
{ label: "Created", value: (article) => instant(article?.created) },
|
|
221
|
+
{ label: "Updated", value: (article) => instant(article?.updated) },
|
|
222
|
+
],
|
|
223
|
+
sections: [{ title: () => "Content", lines: (article) => lines(article?.content) }],
|
|
224
|
+
});
|
|
225
|
+
function writtenArticle(verb) {
|
|
226
|
+
return recordView({
|
|
227
|
+
title: (article, context) => joined(`${verb} ${key(article) ?? (arg(context, "article") || "the article")}`, text(article?.summary)),
|
|
228
|
+
fields: [{ label: "Updated", value: (article) => instant(article?.updated) }],
|
|
229
|
+
next: (article) => {
|
|
230
|
+
const articleID = key(article);
|
|
231
|
+
return articleID ? [["article", "get", articleID]] : [];
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
export const createdArticle = writtenArticle("Created");
|
|
236
|
+
export const updatedArticle = writtenArticle("Updated");
|
|
237
|
+
export const tagTable = namedTable("TAG", "No tags.");
|
|
238
|
+
export const tagRecord = recordView({ title: (tag) => text(tag.name), fields: [{ label: "ID", value: (tag) => text(tag.id) }] });
|
|
239
|
+
export const issueTagList = listView({
|
|
240
|
+
line: (tag) => `${text(tag.name) ?? ""} (${text(tag.id) ?? ""})`,
|
|
241
|
+
empty: "No tags.",
|
|
242
|
+
footer: pageFooter,
|
|
243
|
+
});
|
|
244
|
+
export const tagAdded = recordView({
|
|
245
|
+
title: (tag, context) => `Tagged ${arg(context, "issueID")} with ${text(tag?.name) ?? "the tag"}.`,
|
|
246
|
+
fields: [],
|
|
247
|
+
});
|
|
248
|
+
export const linkTypeTable = tableView({
|
|
249
|
+
columns: [
|
|
250
|
+
id,
|
|
251
|
+
{ header: "TYPE", value: (type) => text(type.name) },
|
|
252
|
+
{ header: "OUTWARD", value: (type) => text(type.sourceToTarget) },
|
|
253
|
+
{ header: "INWARD", value: (type) => text(type.targetToSource) },
|
|
254
|
+
{ header: "DIRECTED", value: (type) => yes(type.directed) },
|
|
255
|
+
],
|
|
256
|
+
empty: "No link types.",
|
|
257
|
+
footer: pageFooter,
|
|
258
|
+
});
|
|
259
|
+
/** A link group reads as the phrase YouTrack shows for its direction, then its ID for follow-ups. */
|
|
260
|
+
function linkLabel(group) {
|
|
261
|
+
const type = nested(group.linkType);
|
|
262
|
+
const direction = text(group.direction);
|
|
263
|
+
const label = direction === "OUTWARD" ? text(type?.sourceToTarget)
|
|
264
|
+
: direction === "INWARD" ? text(type?.targetToSource)
|
|
265
|
+
: text(type?.name);
|
|
266
|
+
return `${label ?? text(type?.name) ?? "link"} (${text(group.id) ?? ""})`;
|
|
267
|
+
}
|
|
268
|
+
export const linkGroupList = listView({ line: linkLabel, empty: "No links.", footer: pageFooter });
|
|
269
|
+
export const linkGroupRecord = recordView({
|
|
270
|
+
title: linkLabel,
|
|
271
|
+
fields: [
|
|
272
|
+
{ label: "Direction", value: (group) => text(group.direction) },
|
|
273
|
+
{ label: "Type", value: (group) => text(nested(group.linkType)?.name) },
|
|
274
|
+
],
|
|
275
|
+
});
|
|
276
|
+
export const linkTypeRecord = recordView({
|
|
277
|
+
title: (type) => text(type.name),
|
|
278
|
+
fields: [
|
|
279
|
+
{ label: "ID", value: (type) => text(type.id) },
|
|
280
|
+
{ label: "Outward", value: (type) => text(type.sourceToTarget) },
|
|
281
|
+
{ label: "Inward", value: (type) => text(type.targetToSource) },
|
|
282
|
+
{ label: "Directed", value: (type) => yes(type.directed) },
|
|
283
|
+
],
|
|
284
|
+
});
|
|
285
|
+
export const linkedIssueList = listView({
|
|
286
|
+
line: (issue) => [key(issue), text(issue.summary)].filter(Boolean).join(" "),
|
|
287
|
+
empty: "No linked issues.",
|
|
288
|
+
footer: pageFooter,
|
|
289
|
+
});
|
|
290
|
+
export const issueLinked = recordView({
|
|
291
|
+
title: (issue, context) => joined(`Linked ${arg(context, "issueID")} to ${key(issue) ?? "the issue"}`, text(issue?.summary)),
|
|
292
|
+
fields: [],
|
|
293
|
+
});
|
|
294
|
+
export const attachmentTable = tableView({
|
|
295
|
+
columns: [
|
|
296
|
+
id,
|
|
297
|
+
{ header: "NAME", value: (attachment) => text(attachment.name) },
|
|
298
|
+
{ header: "SIZE", value: (attachment) => count(attachment.size), format: "bytes" },
|
|
299
|
+
{ header: "TYPE", value: (attachment) => text(attachment.mimeType) },
|
|
300
|
+
],
|
|
301
|
+
empty: "No attachments.",
|
|
302
|
+
footer: pageFooter,
|
|
303
|
+
});
|
|
304
|
+
export const attachmentRecord = recordView({
|
|
305
|
+
title: (attachment) => text(attachment.name),
|
|
306
|
+
fields: [
|
|
307
|
+
{ label: "ID", value: (attachment) => text(attachment.id) },
|
|
308
|
+
{ label: "Size", value: (attachment) => count(attachment.size), format: "bytes" },
|
|
309
|
+
{ label: "Type", value: (attachment) => text(attachment.mimeType) },
|
|
310
|
+
],
|
|
311
|
+
});
|
|
312
|
+
export const savedAttachment = recordView({
|
|
313
|
+
title: (file) => `Saved ${text(file.name) ?? "the attachment"}`,
|
|
314
|
+
fields: [
|
|
315
|
+
{ label: "Path", value: (file) => text(file.path) },
|
|
316
|
+
{ label: "Size", value: (file) => count(file.bytes), format: "bytes" },
|
|
317
|
+
{ label: "Type", value: (file) => text(file.contentType) },
|
|
318
|
+
],
|
|
319
|
+
next: () => [["downloads", "list"]],
|
|
320
|
+
});
|
|
321
|
+
export const exportedArticle = recordView({
|
|
322
|
+
title: (file) => `Saved ${text(file.id) ?? "the article"}`,
|
|
323
|
+
fields: [
|
|
324
|
+
{ label: "Path", value: (file) => text(file.path) },
|
|
325
|
+
{ label: "Size", value: (file) => count(file.bytes), format: "bytes" },
|
|
326
|
+
{ label: "SHA-256", value: (file) => text(file.sha256) },
|
|
327
|
+
{
|
|
328
|
+
label: "Note",
|
|
329
|
+
value: (file) => (file.redacted === true ? "URL placeholders replaced parts of the content; do not send it back unchanged" : undefined),
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
next: () => [["downloads", "list"]],
|
|
333
|
+
});
|
|
334
|
+
export const groupTable = tableView({
|
|
335
|
+
columns: [
|
|
336
|
+
id,
|
|
337
|
+
{ header: "GROUP", value: (group) => text(group.name), shrink: true },
|
|
338
|
+
{ header: "USERS", value: (group) => count(group.usersCount) },
|
|
339
|
+
],
|
|
340
|
+
empty: "No groups.",
|
|
341
|
+
footer: pageFooter,
|
|
342
|
+
});
|
|
343
|
+
export const groupRecord = recordView({
|
|
344
|
+
title: (group) => text(group.name),
|
|
345
|
+
fields: [
|
|
346
|
+
{ label: "ID", value: (group) => text(group.id) },
|
|
347
|
+
{ label: "Users", value: (group) => count(group.usersCount) },
|
|
348
|
+
{ label: "All users", value: (group) => yes(group.allUsersGroup) },
|
|
349
|
+
],
|
|
350
|
+
});
|
|
351
|
+
/** A project's custom-field settings wrap the global field under `field`. */
|
|
352
|
+
export const projectFieldTable = tableView({
|
|
353
|
+
columns: [
|
|
354
|
+
id,
|
|
355
|
+
{ header: "FIELD", value: (setting) => text(nested(setting.field)?.name) },
|
|
356
|
+
{ header: "TYPE", value: (setting) => text(nested(nested(setting.field)?.fieldType)?.id) },
|
|
357
|
+
{ header: "EMPTY", value: (setting) => (setting.canBeEmpty === true ? text(setting.emptyFieldText) ?? "allowed" : undefined) },
|
|
358
|
+
{ header: "PUBLIC", value: (setting) => yes(setting.isPublic) },
|
|
359
|
+
],
|
|
360
|
+
empty: "No custom fields.",
|
|
361
|
+
footer: pageFooter,
|
|
362
|
+
});
|
|
363
|
+
export const commandApplied = recordView({
|
|
364
|
+
title: (value, context) => {
|
|
365
|
+
const issues = Array.isArray(value?.issues) ? value.issues.map((issue) => key(nested(issue))).filter(Boolean) : [];
|
|
366
|
+
const query = option(context, "query");
|
|
367
|
+
return `Applied${query ? ` "${query}"` : " the command"} to ${issues.length ? issues.join(", ") : "the selected issues"}.`;
|
|
368
|
+
},
|
|
369
|
+
fields: [],
|
|
370
|
+
});
|
|
371
|
+
export const fieldTable = tableView({
|
|
372
|
+
columns: [
|
|
373
|
+
id,
|
|
374
|
+
{ header: "FIELD", value: (field) => text(field.name) },
|
|
375
|
+
{ header: "TYPE", value: (field) => text(nested(field.fieldType)?.presentation) ?? text(nested(field.fieldType)?.id) },
|
|
376
|
+
{ header: "MULTI", value: (field) => yes(nested(field.fieldType)?.isMultiValue) },
|
|
377
|
+
],
|
|
378
|
+
empty: "No custom fields.",
|
|
379
|
+
footer: pageFooter,
|
|
380
|
+
});
|
|
381
|
+
/** An issue field value as YouTrack would show it: names, logins, periods or plain text. */
|
|
382
|
+
function fieldValue(value, type) {
|
|
383
|
+
if (type === "DateIssueCustomField")
|
|
384
|
+
return day(value);
|
|
385
|
+
if (value === null || value === undefined)
|
|
386
|
+
return undefined;
|
|
387
|
+
if (Array.isArray(value))
|
|
388
|
+
return value.map((item) => fieldValue(item)).filter(Boolean).join(", ");
|
|
389
|
+
const item = nested(value);
|
|
390
|
+
if (item)
|
|
391
|
+
return text(item.name) ?? text(item.login) ?? text(item.presentation) ?? firstLine(item.text);
|
|
392
|
+
return String(value);
|
|
393
|
+
}
|
|
394
|
+
export const issueFieldTable = tableView({
|
|
395
|
+
columns: [
|
|
396
|
+
{ header: "FIELD", value: (field) => text(field.name) },
|
|
397
|
+
{ header: "VALUE", value: (field) => fieldValue(field.value, text(field.$type)), shrink: true },
|
|
398
|
+
id,
|
|
399
|
+
],
|
|
400
|
+
empty: "No fields.",
|
|
401
|
+
footer: pageFooter,
|
|
402
|
+
});
|
|
403
|
+
export const issueFieldRecord = recordView({
|
|
404
|
+
title: (field, context) => (field
|
|
405
|
+
? joined(text(field.name) ?? arg(context, "fieldID"), fieldValue(field.value, text(field.$type)) ?? "empty")
|
|
406
|
+
: `Set ${arg(context, "fieldID")} on ${arg(context, "issueID")}.`),
|
|
407
|
+
fields: [{ label: "ID", value: (field) => text(field?.id) }],
|
|
408
|
+
});
|
|
409
|
+
export const workItemTable = tableView({
|
|
410
|
+
columns: [
|
|
411
|
+
id,
|
|
412
|
+
{ header: "DATE", value: (item) => day(item.date) },
|
|
413
|
+
{ header: "SPENT", value: (item) => text(nested(item.duration)?.presentation) },
|
|
414
|
+
{ header: "AUTHOR", value: (item) => login(item) },
|
|
415
|
+
{ header: "TYPE", value: (item) => text(nested(item.type)?.name) },
|
|
416
|
+
{ header: "ISSUE", value: (item) => key(nested(item.issue)) },
|
|
417
|
+
{ header: "TEXT", value: (item) => firstLine(item.text), shrink: true },
|
|
418
|
+
],
|
|
419
|
+
empty: "No work items.",
|
|
420
|
+
footer: pageFooter,
|
|
421
|
+
});
|
|
422
|
+
export const savedQueryTable = tableView({
|
|
423
|
+
columns: [
|
|
424
|
+
id,
|
|
425
|
+
{ header: "NAME", value: (query) => text(query.name) },
|
|
426
|
+
{ header: "OWNER", value: (query) => text(nested(query.owner)?.login) },
|
|
427
|
+
{ header: "QUERY", value: (query) => text(query.query), shrink: true },
|
|
428
|
+
],
|
|
429
|
+
empty: "No saved searches.",
|
|
430
|
+
footer: pageFooter,
|
|
431
|
+
});
|
|
432
|
+
export const batchValidated = recordView({
|
|
433
|
+
title: (value) => `The manifest is valid: ${count(value.rows) ?? 0} rows (${count(value.create) ?? 0} create, ${count(value.update) ?? 0} update).`,
|
|
434
|
+
fields: [],
|
|
435
|
+
});
|
|
436
|
+
function batchRows(value) {
|
|
437
|
+
return Array.isArray(value.rows) ? value.rows.map((row) => nested(row) ?? {}) : [];
|
|
438
|
+
}
|
|
439
|
+
export const batchApplied = recordView({
|
|
440
|
+
title: (value) => `Batch ${text(value.status) ?? "finished"}: ${count(value.completed) ?? 0} of ${batchRows(value).length} rows completed.`,
|
|
441
|
+
fields: [
|
|
442
|
+
{ label: "Failed", value: (value) => count(value.failed) || undefined },
|
|
443
|
+
{ label: "Uncertain", value: (value) => count(value.uncertain) || undefined },
|
|
444
|
+
{ label: "Unattempted", value: (value) => count(value.unattempted) || undefined },
|
|
445
|
+
{ label: "Failed rows saved", value: (value) => text(nested(value.failedRows)?.path) },
|
|
446
|
+
{ label: "Failed rows not saved", value: (value) => text(nested(value.failedRows)?.error) },
|
|
447
|
+
],
|
|
448
|
+
sections: [{
|
|
449
|
+
title: () => "Rows",
|
|
450
|
+
lines: (value) => batchRows(value).map((row) => [
|
|
451
|
+
`${count(row.row) ?? "?"}`,
|
|
452
|
+
text(row.status) ?? "",
|
|
453
|
+
key(nested(row.result)) ?? text(row.error) ?? "",
|
|
454
|
+
].filter(Boolean).join(" ")),
|
|
455
|
+
}],
|
|
456
|
+
next: (value) => (text(nested(value.failedRows)?.path) ? [["downloads", "list"]] : []),
|
|
457
|
+
});
|
|
458
|
+
export const uploadedAttachments = tableView({
|
|
459
|
+
rows: (value) => value ?? [],
|
|
460
|
+
columns: [
|
|
461
|
+
id,
|
|
462
|
+
{ header: "NAME", value: (attachment) => text(attachment.name) },
|
|
463
|
+
{ header: "SIZE", value: (attachment) => count(attachment.size), format: "bytes" },
|
|
464
|
+
],
|
|
465
|
+
empty: "Uploaded.",
|
|
466
|
+
});
|
|
467
|
+
//# sourceMappingURL=presentation.js.map
|