@fnndsc/chili 3.3.0 → 3.5.0
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/dist/chefs/chefs.js +12 -11
- package/dist/commands/fs/download.d.ts +19 -4
- package/dist/commands/fs/download.js +75 -65
- package/dist/commands/fs/upload.d.ts +20 -4
- package/dist/commands/fs/upload.js +46 -34
- package/dist/commands/man/doc.js +3 -2
- package/dist/commands/plugins/add.js +35 -34
- package/dist/config/colorConfig.js +2 -1
- package/dist/connect/connectHandler.js +7 -6
- package/dist/context/contextCommand.js +3 -2
- package/dist/controllers/fileController.js +4 -3
- package/dist/controllers/pluginController.js +2 -1
- package/dist/feeds/feedHandler.js +19 -18
- package/dist/filesystem/fileGroupHandler.js +28 -27
- package/dist/filesystem/filesystemHandler.js +13 -11
- package/dist/filesystem/inodeCommand.js +2 -1
- package/dist/handlers/baseGroupHandler.d.ts +10 -1
- package/dist/handlers/baseGroupHandler.js +38 -13
- package/dist/index.js +3 -2
- package/dist/lfs/lfs.js +6 -4
- package/dist/man/man.js +4 -3
- package/dist/man/renderer.js +3 -2
- package/dist/pacs/pacsQueryHandler.js +14 -13
- package/dist/pacs/pacsRetrieveHandler.js +13 -12
- package/dist/path/pathCommand.js +23 -22
- package/dist/plugins/pluginGroupHandler.d.ts +18 -0
- package/dist/plugins/pluginGroupHandler.js +44 -4
- package/dist/plugins/pluginHandler.js +23 -22
- package/dist/run.d.ts +13 -0
- package/dist/run.js +28 -13
- package/dist/screen/output.d.ts +88 -0
- package/dist/screen/output.js +95 -0
- package/dist/screen/screen.d.ts +13 -0
- package/dist/screen/screen.js +53 -8
- package/dist/utils/admin_prompt.js +10 -9
- package/dist/utils/docker.js +10 -9
- package/dist/views/pluginParameters.d.ts +10 -0
- package/dist/views/pluginParameters.js +25 -17
- package/docs/pacs.adoc +3 -3
- package/package.json +1 -1
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import { ChRISinode_create, listParams_fromOptions, BrowserType, } from "@fnndsc/cumin";
|
|
7
|
+
import { table_render } from "../screen/screen.js";
|
|
8
|
+
import { chiliErrLog, chiliLog } from "../screen/output.js";
|
|
7
9
|
/**
|
|
8
10
|
* Lists resources for a given inode path.
|
|
9
11
|
*
|
|
@@ -13,7 +15,7 @@ import { ChRISinode_create, listParams_fromOptions, BrowserType, } from "@fnndsc
|
|
|
13
15
|
async function inodeResources_list(path, options) {
|
|
14
16
|
const chrisInode = await ChRISinode_create(path);
|
|
15
17
|
if (!chrisInode) {
|
|
16
|
-
|
|
18
|
+
chiliErrLog(`Could not find path '${path}' in the CUBE filesystem.`);
|
|
17
19
|
return;
|
|
18
20
|
}
|
|
19
21
|
const params = listParams_fromOptions({
|
|
@@ -33,28 +35,28 @@ async function inodeResources_list(path, options) {
|
|
|
33
35
|
for (const browserType of browserTypes) {
|
|
34
36
|
const browser = chrisInode.browser_get(browserType);
|
|
35
37
|
if (!browser) {
|
|
36
|
-
|
|
38
|
+
chiliErrLog(`WARNING: ${browserType} browser is not available`);
|
|
37
39
|
continue;
|
|
38
40
|
}
|
|
39
41
|
try {
|
|
40
42
|
const resourceGet = browser.resource_get;
|
|
41
43
|
if (!resourceGet) {
|
|
42
|
-
|
|
44
|
+
chiliErrLog(`WARNING: ${browserType} resource is null`);
|
|
43
45
|
continue;
|
|
44
46
|
}
|
|
45
47
|
const resourcesList = await resourceGet.resources_getList(params);
|
|
46
48
|
const resourceFields = await resourceGet.resourceFields_get(resourcesList, fieldOptions[browserType]);
|
|
47
49
|
const results = resourceGet.resources_filterByFields(resourceFields);
|
|
48
50
|
if (results) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
chiliLog(`${browserType} resources:`);
|
|
52
|
+
chiliLog(table_render(results.tableData, results.selectedFields));
|
|
51
53
|
}
|
|
52
54
|
else {
|
|
53
|
-
|
|
55
|
+
chiliErrLog(`${browserType} resources: not found or could not be filtered`);
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
catch (error) {
|
|
57
|
-
|
|
59
|
+
chiliErrLog(`${browserType} resources: not found`);
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
}
|
|
@@ -67,12 +69,12 @@ async function inodeResources_list(path, options) {
|
|
|
67
69
|
*/
|
|
68
70
|
function inodeFields_list(inodeType, dataObj) {
|
|
69
71
|
if (!dataObj) {
|
|
70
|
-
|
|
72
|
+
chiliLog("No " + inodeType + " at this path");
|
|
71
73
|
return false;
|
|
72
74
|
}
|
|
73
75
|
if (dataObj.fields) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
chiliLog(inodeType);
|
|
77
|
+
chiliLog(table_render(dataObj.fields, ["fields"]));
|
|
76
78
|
return true;
|
|
77
79
|
}
|
|
78
80
|
return false;
|
|
@@ -85,7 +87,7 @@ function inodeFields_list(inodeType, dataObj) {
|
|
|
85
87
|
async function inodeResourceFields_list(path = "") {
|
|
86
88
|
const chrisFiles = await ChRISinode_create(path);
|
|
87
89
|
if (!chrisFiles) {
|
|
88
|
-
|
|
90
|
+
chiliErrLog(`Could not create ChRISinode for path: ${path}`);
|
|
89
91
|
return;
|
|
90
92
|
}
|
|
91
93
|
const fileBrowser = chrisFiles.fileBrowser_get;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { FileGroupHandler, FileMemberHandler } from "./fileGroupHandler.js";
|
|
8
|
+
import { chiliErrLog } from "../screen/output.js";
|
|
8
9
|
/**
|
|
9
10
|
* Sets up the 'inode' command for interacting with ChRIS filesystem resources.
|
|
10
11
|
*
|
|
@@ -30,7 +31,7 @@ export async function inodeCommand_setup(program) {
|
|
|
30
31
|
await fileProgram.parseAsync(args);
|
|
31
32
|
}
|
|
32
33
|
else {
|
|
33
|
-
|
|
34
|
+
chiliErrLog("Usage: chili inode <path> <files|file> [options]");
|
|
34
35
|
command.help();
|
|
35
36
|
}
|
|
36
37
|
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import { Command } from "commander";
|
|
7
|
-
import { ChRISPluginGroup, ChRISFeedGroup, ChRISEmbeddedResourceGroup, ChRISPACSGroup } from "@fnndsc/cumin";
|
|
7
|
+
import { ChRISPluginGroup, ChRISFeedGroup, ChRISEmbeddedResourceGroup, ChRISPACSGroup, type CommandEnvelope } from "@fnndsc/cumin";
|
|
8
8
|
import { CLIoptions } from "../utils/cli.js";
|
|
9
9
|
import { TableOptions } from "../screen/screen.js";
|
|
10
10
|
/**
|
|
@@ -26,6 +26,15 @@ export declare class BaseGroupHandler {
|
|
|
26
26
|
* Lists available fields for the current ChRIS resource type.
|
|
27
27
|
*/
|
|
28
28
|
resourceFields_list(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Renders available fields for the current ChRIS resource type as an envelope.
|
|
31
|
+
*
|
|
32
|
+
* Sans-I/O counterpart to {@link resourceFields_list} — returns the rendered
|
|
33
|
+
* text instead of printing it, so hosted surfaces can carry it over the wire.
|
|
34
|
+
*
|
|
35
|
+
* @returns An envelope carrying the field listing or an error.
|
|
36
|
+
*/
|
|
37
|
+
resourceFields_render(): Promise<CommandEnvelope>;
|
|
29
38
|
/**
|
|
30
39
|
* Prompts the user for confirmation before performing an operation.
|
|
31
40
|
*
|
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import { Command } from "commander";
|
|
7
|
-
import { ChRISFeedGroup, record_extract, errorStack, } from "@fnndsc/cumin";
|
|
7
|
+
import { ChRISFeedGroup, record_extract, errorStack, envelope_ok, envelope_error, } from "@fnndsc/cumin";
|
|
8
8
|
import { options_toParams } from "../utils/cli.js";
|
|
9
9
|
import { resourceColumns_removeDuplicates } from "../utils/resourceData.js";
|
|
10
|
-
import { table_display, border_draw } from "../screen/screen.js";
|
|
10
|
+
import { table_display, table_render, border_draw } from "../screen/screen.js";
|
|
11
11
|
import * as readline from "readline";
|
|
12
|
+
import { chiliErrLog, chiliLog } from "../screen/output.js";
|
|
12
13
|
/**
|
|
13
14
|
* Base handler for groups of ChRIS resources.
|
|
14
15
|
* Provides common functionality for listing and deleting resources.
|
|
@@ -51,11 +52,11 @@ export class BaseGroupHandler {
|
|
|
51
52
|
const params = options_toParams(options);
|
|
52
53
|
const results = await this.chrisObject.asset.resources_listAndFilterByOptions(params);
|
|
53
54
|
if (!results) {
|
|
54
|
-
|
|
55
|
+
chiliErrLog(`No ${this.assetName} resources found. Perhaps check your current context?`);
|
|
55
56
|
return;
|
|
56
57
|
}
|
|
57
58
|
if (results.tableData.length === 0) {
|
|
58
|
-
|
|
59
|
+
chiliLog(`No ${this.assetName} found matching the criteria.`);
|
|
59
60
|
}
|
|
60
61
|
else {
|
|
61
62
|
const uniqueResults = resourceColumns_removeDuplicates(results);
|
|
@@ -73,7 +74,7 @@ export class BaseGroupHandler {
|
|
|
73
74
|
return `"${String(val !== undefined ? val : '').split('"').join('""')}"`;
|
|
74
75
|
}).join(',');
|
|
75
76
|
}).join('\n');
|
|
76
|
-
|
|
77
|
+
chiliLog(header + '\n' + rows);
|
|
77
78
|
}
|
|
78
79
|
else if (options.table) {
|
|
79
80
|
// Explicit Table format (with borders and title)
|
|
@@ -104,7 +105,7 @@ export class BaseGroupHandler {
|
|
|
104
105
|
}
|
|
105
106
|
}
|
|
106
107
|
catch (error) {
|
|
107
|
-
|
|
108
|
+
chiliLog(errorStack.stack_search(this.assetName)[0]);
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
111
|
/**
|
|
@@ -114,18 +115,42 @@ export class BaseGroupHandler {
|
|
|
114
115
|
try {
|
|
115
116
|
const results = await this.chrisObject.asset.resourceFields_get();
|
|
116
117
|
if (!results) {
|
|
117
|
-
|
|
118
|
+
chiliErrLog(`An error occurred while fetching resource fields for ${this.assetName}.`);
|
|
118
119
|
return;
|
|
119
120
|
}
|
|
120
121
|
if (results.fields.length === 0) {
|
|
121
|
-
|
|
122
|
+
chiliLog(`No resource fields found for ${this.assetName}.`);
|
|
122
123
|
}
|
|
123
124
|
else {
|
|
124
125
|
table_display(results.fields, ["fields"]);
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
catch (error) {
|
|
128
|
-
|
|
129
|
+
chiliLog(errorStack.stack_search(this.assetName)[0]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Renders available fields for the current ChRIS resource type as an envelope.
|
|
134
|
+
*
|
|
135
|
+
* Sans-I/O counterpart to {@link resourceFields_list} — returns the rendered
|
|
136
|
+
* text instead of printing it, so hosted surfaces can carry it over the wire.
|
|
137
|
+
*
|
|
138
|
+
* @returns An envelope carrying the field listing or an error.
|
|
139
|
+
*/
|
|
140
|
+
async resourceFields_render() {
|
|
141
|
+
try {
|
|
142
|
+
const results = await this.chrisObject.asset.resourceFields_get();
|
|
143
|
+
if (!results) {
|
|
144
|
+
return envelope_error('', undefined, `An error occurred while fetching resource fields for ${this.assetName}.\n`);
|
|
145
|
+
}
|
|
146
|
+
if (results.fields.length === 0) {
|
|
147
|
+
return envelope_ok(`No resource fields found for ${this.assetName}.\n`);
|
|
148
|
+
}
|
|
149
|
+
return envelope_ok(table_render(results.fields, ["fields"]));
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
const stacked = errorStack.stack_search(this.assetName)[0];
|
|
153
|
+
return envelope_error('', undefined, `${stacked ?? String(error)}\n`);
|
|
129
154
|
}
|
|
130
155
|
}
|
|
131
156
|
/**
|
|
@@ -219,7 +244,7 @@ export class BaseGroupHandler {
|
|
|
219
244
|
const searchResults = await this.chrisObject.asset.resources_listAndFilterByOptions({
|
|
220
245
|
id: id,
|
|
221
246
|
});
|
|
222
|
-
|
|
247
|
+
chiliLog(border_draw(`checking ${this.assetName} id ${id} ... ${this.msg_OKorNot(searchResults)}`));
|
|
223
248
|
if (!force) {
|
|
224
249
|
confirm = await this.user_confirmContinuation(id, "delete");
|
|
225
250
|
if (!confirm) {
|
|
@@ -230,7 +255,7 @@ export class BaseGroupHandler {
|
|
|
230
255
|
border_draw(`deleting ${this.assetName} id ${id} ... ${this.msg_OKorNot(true)}`);
|
|
231
256
|
}
|
|
232
257
|
catch (error) {
|
|
233
|
-
|
|
258
|
+
chiliErrLog(`${error}`);
|
|
234
259
|
return false;
|
|
235
260
|
}
|
|
236
261
|
}
|
|
@@ -260,7 +285,7 @@ export class BaseGroupHandler {
|
|
|
260
285
|
let nIDs;
|
|
261
286
|
nIDs = await this.IDs_getFromSearch(options);
|
|
262
287
|
if (!nIDs) {
|
|
263
|
-
|
|
288
|
+
chiliErrLog(`No ${this.assetName} matched the search criteria.`);
|
|
264
289
|
return;
|
|
265
290
|
}
|
|
266
291
|
if (nIDs) {
|
|
@@ -310,7 +335,7 @@ export class BaseGroupHandler {
|
|
|
310
335
|
.option("-f, --force", `force the deletion without prompting for user confirmation`)
|
|
311
336
|
.action(async (searchable, options) => {
|
|
312
337
|
const searchParts = searchable.split("++").map((part) => part.trim());
|
|
313
|
-
//
|
|
338
|
+
// chiliLog(`searchParts = ${searchParts}`);
|
|
314
339
|
for (const searchPart of searchParts) {
|
|
315
340
|
const currentOptions = {
|
|
316
341
|
...options,
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import omelette from "omelette";
|
|
13
13
|
import { run } from "./run.js";
|
|
14
|
+
import { chiliErrLog, chiliLog } from "./screen/output.js";
|
|
14
15
|
/**
|
|
15
16
|
* Sets up shell command completion for the standalone chili CLI using omelette.
|
|
16
17
|
* This is a bin-only concern; in-process hosts provide their own completion.
|
|
@@ -50,7 +51,7 @@ function commandCompletion_setup() {
|
|
|
50
51
|
},
|
|
51
52
|
});
|
|
52
53
|
completion.on("man.doc", ({ reply }) => {
|
|
53
|
-
|
|
54
|
+
chiliLog("Autocomplete triggered for man doc command");
|
|
54
55
|
reply([]);
|
|
55
56
|
});
|
|
56
57
|
completion.init();
|
|
@@ -66,7 +67,7 @@ async function main() {
|
|
|
66
67
|
await run(process.argv.slice(2));
|
|
67
68
|
}
|
|
68
69
|
main().catch((error) => {
|
|
69
|
-
|
|
70
|
+
chiliErrLog("An error occurred:", error);
|
|
70
71
|
process.exit(1);
|
|
71
72
|
});
|
|
72
73
|
// Re-export library utilities for consumers that import the package root.
|
package/dist/lfs/lfs.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import * as fs from 'fs';
|
|
10
10
|
import * as path from 'path';
|
|
11
|
+
import { table_render } from "../screen/screen.js";
|
|
12
|
+
import { chiliErrLog, chiliLog } from "../screen/output.js";
|
|
11
13
|
/**
|
|
12
14
|
* Lists the contents of a directory with details.
|
|
13
15
|
*
|
|
@@ -22,10 +24,10 @@ export async function dirContents_list(filepath) {
|
|
|
22
24
|
return { filename: file, "size(KB)": size, created_at: birthtime };
|
|
23
25
|
});
|
|
24
26
|
const detailedFiles = await Promise.all(detailedFilesPromises);
|
|
25
|
-
|
|
27
|
+
chiliLog(table_render(detailedFiles, ["filename", "size(KB)", "created_at"]));
|
|
26
28
|
}
|
|
27
29
|
catch (error) {
|
|
28
|
-
|
|
30
|
+
chiliErrLog("Error occurred while reading the directory!", error);
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
@@ -36,7 +38,7 @@ export async function dirContents_list(filepath) {
|
|
|
36
38
|
export function dir_create(filepath) {
|
|
37
39
|
if (!fs.existsSync(filepath)) {
|
|
38
40
|
fs.mkdirSync(filepath);
|
|
39
|
-
|
|
41
|
+
chiliLog("The directory has been created successfully");
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
@@ -46,7 +48,7 @@ export function dir_create(filepath) {
|
|
|
46
48
|
*/
|
|
47
49
|
export function file_create(filepath) {
|
|
48
50
|
fs.openSync(filepath, "w");
|
|
49
|
-
|
|
51
|
+
chiliLog("An empty file has been created");
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
52
54
|
* Sets up the 'lfs' command group in Commander.
|
package/dist/man/man.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { topics_list } from "../commands/man/topics.js";
|
|
2
2
|
import { manPage_display } from "../commands/man/doc.js";
|
|
3
|
+
import { chiliLog } from "../screen/output.js";
|
|
3
4
|
/**
|
|
4
5
|
* Sets up the 'man' command for displaying ChILI manual and help pages.
|
|
5
6
|
*
|
|
@@ -24,8 +25,8 @@ export function manCommand_setup(program) {
|
|
|
24
25
|
.description("List the available manual page topics")
|
|
25
26
|
.action(async () => {
|
|
26
27
|
const files = await topics_list();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
chiliLog("\n\nThe following topics are available:");
|
|
29
|
+
chiliLog("(read more with 'chili man doc <topic>')\n");
|
|
30
|
+
chiliLog(files.join("\n"));
|
|
30
31
|
});
|
|
31
32
|
}
|
package/dist/man/renderer.js
CHANGED
|
@@ -9,6 +9,7 @@ import chalk from "chalk";
|
|
|
9
9
|
import { convert as adoc_convert } from "asciidoctor";
|
|
10
10
|
import { exec } from "child_process";
|
|
11
11
|
import os from "os";
|
|
12
|
+
import { chiliErrLog } from "../screen/output.js";
|
|
12
13
|
const headingStyles = [
|
|
13
14
|
{ regex: /<h1.*?>(.*?)<\/h1>/g, font: "Standard", color: chalk.magenta },
|
|
14
15
|
{ regex: /<h2.*?>(.*?)<\/h2>/g, font: "Slant", color: chalk.yellow },
|
|
@@ -175,11 +176,11 @@ export async function browser_open(filePath) {
|
|
|
175
176
|
: "xdg-open";
|
|
176
177
|
exec(`${command} ${tempHtmlPath}`, (error) => {
|
|
177
178
|
if (error) {
|
|
178
|
-
|
|
179
|
+
chiliErrLog("Error opening browser:", error);
|
|
179
180
|
}
|
|
180
181
|
});
|
|
181
182
|
}
|
|
182
183
|
catch (error) {
|
|
183
|
-
|
|
184
|
+
chiliErrLog("Error opening documentation in browser:", error instanceof Error ? error.message : String(error));
|
|
184
185
|
}
|
|
185
186
|
}
|
|
@@ -9,6 +9,7 @@ import { BaseGroupHandler } from "../handlers/baseGroupHandler.js";
|
|
|
9
9
|
import { border_draw } from "../screen/screen.js";
|
|
10
10
|
import { pacsQueryResult_renderPretty } from "./pacsResultRender.js";
|
|
11
11
|
import { pacsQueryPayload_build } from "./pacsQueryPayload.js";
|
|
12
|
+
import { chiliLog } from "../screen/output.js";
|
|
12
13
|
/**
|
|
13
14
|
* Handler for PACS queries commands.
|
|
14
15
|
*/
|
|
@@ -69,7 +70,7 @@ export class PACSQueryGroupHandler {
|
|
|
69
70
|
const listCommand = this.baseGroupHandler.baseListCommand_create(async (options) => {
|
|
70
71
|
const pacsserver = await this.pacsserverContext_resolve(options.pacsserver);
|
|
71
72
|
if (!pacsserver) {
|
|
72
|
-
|
|
73
|
+
chiliLog(border_draw("No PACS server in context. Use --pacsserver or set via context."));
|
|
73
74
|
return;
|
|
74
75
|
}
|
|
75
76
|
const mergedOptions = this.options_withPACSFilter(options, pacsserver);
|
|
@@ -111,17 +112,17 @@ export class PACSQueryGroupHandler {
|
|
|
111
112
|
}
|
|
112
113
|
const payload = pacsQueryPayload_build(queryInput, options.title, options.description);
|
|
113
114
|
if (!payload) {
|
|
114
|
-
|
|
115
|
+
chiliLog(border_draw("Invalid query format. Provide JSON or comma-separated key:value pairs."));
|
|
115
116
|
return;
|
|
116
117
|
}
|
|
117
118
|
const result = await pacsQueries_create(pacsserver, payload);
|
|
118
119
|
if (!result.ok) {
|
|
119
120
|
const errors = errorStack_getAllOfType("error");
|
|
120
121
|
if (errors.length) {
|
|
121
|
-
errors.forEach((msg) =>
|
|
122
|
+
errors.forEach((msg) => chiliLog(border_draw(msg)));
|
|
122
123
|
}
|
|
123
124
|
else {
|
|
124
|
-
|
|
125
|
+
chiliLog(border_draw("Failed to create PACS query."));
|
|
125
126
|
}
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
@@ -133,7 +134,7 @@ export class PACSQueryGroupHandler {
|
|
|
133
134
|
`pacs=${pacsserver}`,
|
|
134
135
|
`title="${created.title ?? options.title ?? ""}"`,
|
|
135
136
|
].join(" ");
|
|
136
|
-
|
|
137
|
+
chiliLog(border_draw(msg.trim()));
|
|
137
138
|
});
|
|
138
139
|
}
|
|
139
140
|
/**
|
|
@@ -149,17 +150,17 @@ export class PACSQueryGroupHandler {
|
|
|
149
150
|
.action(async (queryId, options) => {
|
|
150
151
|
const idNum = Number(queryId);
|
|
151
152
|
if (Number.isNaN(idNum)) {
|
|
152
|
-
|
|
153
|
+
chiliLog(border_draw("queryId must be a number."));
|
|
153
154
|
return;
|
|
154
155
|
}
|
|
155
156
|
const result = await pacsQuery_resultDecode(idNum);
|
|
156
157
|
if (!result.ok) {
|
|
157
158
|
const errors = errorStack_getAllOfType("error");
|
|
158
159
|
if (errors.length) {
|
|
159
|
-
errors.forEach((msg) =>
|
|
160
|
+
errors.forEach((msg) => chiliLog(border_draw(msg)));
|
|
160
161
|
}
|
|
161
162
|
else {
|
|
162
|
-
|
|
163
|
+
chiliLog(border_draw(`Failed to decode PACS query result for ${idNum}.`));
|
|
163
164
|
}
|
|
164
165
|
return;
|
|
165
166
|
}
|
|
@@ -167,23 +168,23 @@ export class PACSQueryGroupHandler {
|
|
|
167
168
|
// Prefer JSON, then text, else indicate base64 length
|
|
168
169
|
if (decoded.json !== undefined) {
|
|
169
170
|
if (options.raw) {
|
|
170
|
-
|
|
171
|
+
chiliLog(border_draw(JSON.stringify(decoded.json, null, 2)));
|
|
171
172
|
return;
|
|
172
173
|
}
|
|
173
174
|
const pretty = this.pacsResult_renderPretty(decoded.json);
|
|
174
175
|
if (pretty) {
|
|
175
|
-
|
|
176
|
+
chiliLog(border_draw(pretty));
|
|
176
177
|
}
|
|
177
178
|
else {
|
|
178
|
-
|
|
179
|
+
chiliLog(border_draw(JSON.stringify(decoded.json, null, 2)));
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
else if (decoded.text) {
|
|
182
|
-
|
|
183
|
+
chiliLog(border_draw(decoded.text));
|
|
183
184
|
}
|
|
184
185
|
else {
|
|
185
186
|
const len = decoded.raw.length;
|
|
186
|
-
|
|
187
|
+
chiliLog(border_draw(`Decoded payload available (base64 length ${len}), but not printable.`));
|
|
187
188
|
}
|
|
188
189
|
});
|
|
189
190
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { errorStack_getAllOfType, } from "@fnndsc/cumin";
|
|
7
7
|
import { pacsRetrieve_create, pacsRetrieve_delete, pacsRetrieve_statusForQuery, } from "@fnndsc/salsa";
|
|
8
8
|
import { border_draw } from "../screen/screen.js";
|
|
9
|
+
import { chiliLog } from "../screen/output.js";
|
|
9
10
|
/**
|
|
10
11
|
* Handler for PACS retrieve commands.
|
|
11
12
|
*/
|
|
@@ -52,17 +53,17 @@ export class PACSRetrieveGroupHandler {
|
|
|
52
53
|
async retrieve_pull(queryIdStr) {
|
|
53
54
|
const queryId = Number(queryIdStr);
|
|
54
55
|
if (Number.isNaN(queryId)) {
|
|
55
|
-
|
|
56
|
+
chiliLog(border_draw("Query ID must be a number."));
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
59
|
const result = await pacsRetrieve_create(queryId);
|
|
59
60
|
if (!result.ok) {
|
|
60
61
|
const errors = errorStack_getAllOfType("error");
|
|
61
62
|
if (errors.length) {
|
|
62
|
-
errors.forEach((msg) =>
|
|
63
|
+
errors.forEach((msg) => chiliLog(border_draw(msg)));
|
|
63
64
|
}
|
|
64
65
|
else {
|
|
65
|
-
|
|
66
|
+
chiliLog(border_draw(`Failed to create PACS retrieve for query ${queryId}.`));
|
|
66
67
|
}
|
|
67
68
|
return;
|
|
68
69
|
}
|
|
@@ -73,7 +74,7 @@ export class PACSRetrieveGroupHandler {
|
|
|
73
74
|
`query=${queryId}`,
|
|
74
75
|
`status=${record.status || "created"}`,
|
|
75
76
|
].join(" ");
|
|
76
|
-
|
|
77
|
+
chiliLog(border_draw(msg));
|
|
77
78
|
}
|
|
78
79
|
/**
|
|
79
80
|
* Handle the 'report' command - show detailed status.
|
|
@@ -83,23 +84,23 @@ export class PACSRetrieveGroupHandler {
|
|
|
83
84
|
async retrieve_report(queryIdStr) {
|
|
84
85
|
const queryId = Number(queryIdStr);
|
|
85
86
|
if (Number.isNaN(queryId)) {
|
|
86
|
-
|
|
87
|
+
chiliLog(border_draw("Query ID must be a number."));
|
|
87
88
|
return;
|
|
88
89
|
}
|
|
89
90
|
const result = await pacsRetrieve_statusForQuery(queryId);
|
|
90
91
|
if (!result.ok) {
|
|
91
92
|
const errors = errorStack_getAllOfType("error");
|
|
92
93
|
if (errors.length) {
|
|
93
|
-
errors.forEach((msg) =>
|
|
94
|
+
errors.forEach((msg) => chiliLog(border_draw(msg)));
|
|
94
95
|
}
|
|
95
96
|
else {
|
|
96
|
-
|
|
97
|
+
chiliLog(border_draw(`Failed to generate status report for query ${queryId}.`));
|
|
97
98
|
}
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
101
|
const report = result.value;
|
|
101
102
|
const rendered = this.report_render(report);
|
|
102
|
-
|
|
103
|
+
chiliLog(border_draw(rendered));
|
|
103
104
|
}
|
|
104
105
|
/**
|
|
105
106
|
* Handle the 'cancel' command - delete a retrieve.
|
|
@@ -109,21 +110,21 @@ export class PACSRetrieveGroupHandler {
|
|
|
109
110
|
async retrieve_cancel(retrieveIdStr) {
|
|
110
111
|
const retrieveId = Number(retrieveIdStr);
|
|
111
112
|
if (Number.isNaN(retrieveId)) {
|
|
112
|
-
|
|
113
|
+
chiliLog(border_draw("Retrieve ID must be a number."));
|
|
113
114
|
return;
|
|
114
115
|
}
|
|
115
116
|
const result = await pacsRetrieve_delete(retrieveId);
|
|
116
117
|
if (!result.ok) {
|
|
117
118
|
const errors = errorStack_getAllOfType("error");
|
|
118
119
|
if (errors.length) {
|
|
119
|
-
errors.forEach((msg) =>
|
|
120
|
+
errors.forEach((msg) => chiliLog(border_draw(msg)));
|
|
120
121
|
}
|
|
121
122
|
else {
|
|
122
|
-
|
|
123
|
+
chiliLog(border_draw(`Failed to cancel PACS retrieve ${retrieveId}.`));
|
|
123
124
|
}
|
|
124
125
|
return;
|
|
125
126
|
}
|
|
126
|
-
|
|
127
|
+
chiliLog(border_draw(`PACS retrieve ${retrieveId} cancelled.`));
|
|
127
128
|
}
|
|
128
129
|
/**
|
|
129
130
|
* Determine overall completion status from series statuses.
|