@fnndsc/chili 3.2.5
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/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/chefs/chefs.d.ts +15 -0
- package/dist/chefs/chefs.js +195 -0
- package/dist/commands/compute/fields.d.ts +6 -0
- package/dist/commands/compute/fields.js +13 -0
- package/dist/commands/compute/list.d.ts +19 -0
- package/dist/commands/compute/list.js +20 -0
- package/dist/commands/connect/login.d.ts +16 -0
- package/dist/commands/connect/login.js +18 -0
- package/dist/commands/connect/logout.d.ts +6 -0
- package/dist/commands/connect/logout.js +16 -0
- package/dist/commands/feed/comments.d.ts +41 -0
- package/dist/commands/feed/comments.js +45 -0
- package/dist/commands/feed/create.d.ts +13 -0
- package/dist/commands/feed/create.js +40 -0
- package/dist/commands/feed/note.d.ts +21 -0
- package/dist/commands/feed/note.js +24 -0
- package/dist/commands/feeds/delete.d.ts +14 -0
- package/dist/commands/feeds/delete.js +34 -0
- package/dist/commands/feeds/fields.d.ts +6 -0
- package/dist/commands/feeds/fields.js +17 -0
- package/dist/commands/feeds/list.d.ts +17 -0
- package/dist/commands/feeds/list.js +38 -0
- package/dist/commands/feeds/share.d.ts +17 -0
- package/dist/commands/feeds/share.js +19 -0
- package/dist/commands/file/view.d.ts +8 -0
- package/dist/commands/file/view.js +25 -0
- package/dist/commands/files/delete.d.ts +16 -0
- package/dist/commands/files/delete.js +36 -0
- package/dist/commands/files/fields.d.ts +7 -0
- package/dist/commands/files/fields.js +18 -0
- package/dist/commands/files/list.d.ts +11 -0
- package/dist/commands/files/list.js +23 -0
- package/dist/commands/fs/cat.d.ts +15 -0
- package/dist/commands/fs/cat.js +26 -0
- package/dist/commands/fs/cp.d.ts +17 -0
- package/dist/commands/fs/cp.js +26 -0
- package/dist/commands/fs/create.d.ts +15 -0
- package/dist/commands/fs/create.js +83 -0
- package/dist/commands/fs/download.d.ts +25 -0
- package/dist/commands/fs/download.js +235 -0
- package/dist/commands/fs/edit.d.ts +16 -0
- package/dist/commands/fs/edit.js +25 -0
- package/dist/commands/fs/ls.d.ts +18 -0
- package/dist/commands/fs/ls.js +142 -0
- package/dist/commands/fs/mkdir.d.ts +8 -0
- package/dist/commands/fs/mkdir.js +21 -0
- package/dist/commands/fs/mv.d.ts +13 -0
- package/dist/commands/fs/mv.js +73 -0
- package/dist/commands/fs/rm.d.ts +24 -0
- package/dist/commands/fs/rm.js +108 -0
- package/dist/commands/fs/touch.d.ts +16 -0
- package/dist/commands/fs/touch.js +62 -0
- package/dist/commands/fs/upload.d.ts +55 -0
- package/dist/commands/fs/upload.js +221 -0
- package/dist/commands/groups/fields.d.ts +6 -0
- package/dist/commands/groups/fields.js +13 -0
- package/dist/commands/groups/list.d.ts +16 -0
- package/dist/commands/groups/list.js +26 -0
- package/dist/commands/man/doc.d.ts +16 -0
- package/dist/commands/man/doc.js +32 -0
- package/dist/commands/man/topics.d.ts +6 -0
- package/dist/commands/man/topics.js +27 -0
- package/dist/commands/pipeline/fields.d.ts +6 -0
- package/dist/commands/pipeline/fields.js +13 -0
- package/dist/commands/pipeline/run.d.ts +18 -0
- package/dist/commands/pipeline/run.js +33 -0
- package/dist/commands/plugin/readme.d.ts +14 -0
- package/dist/commands/plugin/readme.js +49 -0
- package/dist/commands/plugin/run.d.ts +10 -0
- package/dist/commands/plugin/run.js +29 -0
- package/dist/commands/plugin/search.d.ts +7 -0
- package/dist/commands/plugin/search.js +18 -0
- package/dist/commands/plugininstances/fields.d.ts +6 -0
- package/dist/commands/plugininstances/fields.js +13 -0
- package/dist/commands/plugininstances/list.d.ts +16 -0
- package/dist/commands/plugininstances/list.js +26 -0
- package/dist/commands/pluginmetas/fields.d.ts +6 -0
- package/dist/commands/pluginmetas/fields.js +13 -0
- package/dist/commands/pluginmetas/list.d.ts +16 -0
- package/dist/commands/pluginmetas/list.js +26 -0
- package/dist/commands/plugins/add.d.ts +34 -0
- package/dist/commands/plugins/add.js +374 -0
- package/dist/commands/plugins/delete.d.ts +14 -0
- package/dist/commands/plugins/delete.js +34 -0
- package/dist/commands/plugins/fields.d.ts +6 -0
- package/dist/commands/plugins/fields.js +17 -0
- package/dist/commands/plugins/list.d.ts +17 -0
- package/dist/commands/plugins/list.js +40 -0
- package/dist/commands/plugins/overview.d.ts +6 -0
- package/dist/commands/plugins/overview.js +17 -0
- package/dist/commands/store/list.d.ts +23 -0
- package/dist/commands/store/list.js +48 -0
- package/dist/commands/tags/fields.d.ts +6 -0
- package/dist/commands/tags/fields.js +13 -0
- package/dist/commands/tags/list.d.ts +16 -0
- package/dist/commands/tags/list.js +26 -0
- package/dist/commands/workflows/fields.d.ts +6 -0
- package/dist/commands/workflows/fields.js +13 -0
- package/dist/commands/workflows/list.d.ts +16 -0
- package/dist/commands/workflows/list.js +26 -0
- package/dist/config/colorConfig.d.ts +56 -0
- package/dist/config/colorConfig.js +161 -0
- package/dist/connect/connectHandler.d.ts +15 -0
- package/dist/connect/connectHandler.js +48 -0
- package/dist/context/contextCommand.d.ts +13 -0
- package/dist/context/contextCommand.js +193 -0
- package/dist/controllers/baseController.d.ts +43 -0
- package/dist/controllers/baseController.js +67 -0
- package/dist/controllers/feedController.d.ts +35 -0
- package/dist/controllers/feedController.js +53 -0
- package/dist/controllers/fileController.d.ts +56 -0
- package/dist/controllers/fileController.js +93 -0
- package/dist/controllers/pluginContextController.d.ts +24 -0
- package/dist/controllers/pluginContextController.js +49 -0
- package/dist/controllers/pluginController.d.ts +70 -0
- package/dist/controllers/pluginController.js +98 -0
- package/dist/controllers/pluginMetaController.d.ts +41 -0
- package/dist/controllers/pluginMetaController.js +52 -0
- package/dist/feeds/feedHandler.d.ts +64 -0
- package/dist/feeds/feedHandler.js +203 -0
- package/dist/filesystem/fileGroupHandler.d.ts +92 -0
- package/dist/filesystem/fileGroupHandler.js +318 -0
- package/dist/filesystem/filesystemHandler.d.ts +12 -0
- package/dist/filesystem/filesystemHandler.js +135 -0
- package/dist/filesystem/inodeCommand.d.ts +12 -0
- package/dist/filesystem/inodeCommand.js +37 -0
- package/dist/handlers/baseGroupHandler.d.ts +103 -0
- package/dist/handlers/baseGroupHandler.js +342 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +239 -0
- package/dist/lfs/lfs.d.ts +25 -0
- package/dist/lfs/lfs.js +74 -0
- package/dist/man/man.d.ts +15 -0
- package/dist/man/man.js +31 -0
- package/dist/man/renderer.d.ts +26 -0
- package/dist/man/renderer.js +187 -0
- package/dist/models/feed.d.ts +18 -0
- package/dist/models/feed.js +8 -0
- package/dist/models/listing.d.ts +33 -0
- package/dist/models/listing.js +9 -0
- package/dist/models/plugin.d.ts +27 -0
- package/dist/models/plugin.js +1 -0
- package/dist/models/resource.d.ts +39 -0
- package/dist/models/resource.js +9 -0
- package/dist/pacs/pacsQueryHandler.d.ts +55 -0
- package/dist/pacs/pacsQueryHandler.js +196 -0
- package/dist/pacs/pacsQueryPayload.d.ts +19 -0
- package/dist/pacs/pacsQueryPayload.js +44 -0
- package/dist/pacs/pacsResultRender.d.ts +20 -0
- package/dist/pacs/pacsResultRender.js +141 -0
- package/dist/pacs/pacsRetrieveHandler.d.ts +87 -0
- package/dist/pacs/pacsRetrieveHandler.js +272 -0
- package/dist/pacs/pacsServerHandler.d.ts +15 -0
- package/dist/pacs/pacsServerHandler.js +32 -0
- package/dist/path/pathCommand.d.ts +64 -0
- package/dist/path/pathCommand.js +805 -0
- package/dist/path/pathMapper.d.ts +189 -0
- package/dist/path/pathMapper.js +382 -0
- package/dist/plugins/pluginGroupHandler.d.ts +42 -0
- package/dist/plugins/pluginGroupHandler.js +90 -0
- package/dist/plugins/pluginHandler.d.ts +87 -0
- package/dist/plugins/pluginHandler.js +303 -0
- package/dist/plugins/pluginMetaHandler.d.ts +21 -0
- package/dist/plugins/pluginMetaHandler.js +27 -0
- package/dist/screen/screen.d.ts +214 -0
- package/dist/screen/screen.js +478 -0
- package/dist/utils/admin_prompt.d.ts +42 -0
- package/dist/utils/admin_prompt.js +105 -0
- package/dist/utils/cli.d.ts +67 -0
- package/dist/utils/cli.js +112 -0
- package/dist/utils/docker.d.ts +74 -0
- package/dist/utils/docker.js +155 -0
- package/dist/utils/input_format.d.ts +77 -0
- package/dist/utils/input_format.js +135 -0
- package/dist/utils/sort.d.ts +29 -0
- package/dist/utils/sort.js +63 -0
- package/dist/utils/ui.d.ts +7 -0
- package/dist/utils/ui.js +26 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +14 -0
- package/dist/views/compute.d.ts +17 -0
- package/dist/views/compute.js +40 -0
- package/dist/views/connect.d.ts +13 -0
- package/dist/views/connect.js +35 -0
- package/dist/views/feed.d.ts +44 -0
- package/dist/views/feed.js +110 -0
- package/dist/views/file.d.ts +25 -0
- package/dist/views/file.js +71 -0
- package/dist/views/fs.d.ts +51 -0
- package/dist/views/fs.js +105 -0
- package/dist/views/ls.d.ts +37 -0
- package/dist/views/ls.js +190 -0
- package/dist/views/plugin.d.ts +28 -0
- package/dist/views/plugin.js +71 -0
- package/dist/views/pluginParameters.d.ts +17 -0
- package/dist/views/pluginParameters.js +79 -0
- package/docs/00_intro.adoc +25 -0
- package/docs/01_setup.adoc +63 -0
- package/docs/02_context.adoc +128 -0
- package/docs/03_searchable.adoc +134 -0
- package/docs/10_everyday_examples.adoc +9 -0
- package/docs/11_upload_data.adoc +146 -0
- package/docs/12_create_a_feed.adoc +9 -0
- package/docs/13_run_a_plugin.adoc +271 -0
- package/docs/20_plugins.adoc +16 -0
- package/docs/21_pluginReadme.adoc +123 -0
- package/docs/30_filesystem.adoc +93 -0
- package/docs/31_fileops.adoc +51 -0
- package/docs/32_file_content.adoc +471 -0
- package/docs/_architecture.adoc +48 -0
- package/docs/_deepContext.adoc +84 -0
- package/docs/_roadmap.adoc +42 -0
- package/docs/_searchable.adoc +187 -0
- package/docs/_state.adoc +68 -0
- package/docs/pacs.adoc +101 -0
- package/docs/pathMapper.md +246 -0
- package/package.json +92 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Models for Plugin operations.
|
|
3
|
+
*
|
|
4
|
+
* Defines the data structures for Plugins and Plugin Instances (execution results).
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { ChrisPluginRaw } from './resource.js';
|
|
9
|
+
/**
|
|
10
|
+
* Represents a ChRIS Plugin.
|
|
11
|
+
* Extends the raw resource definition with any view-specific needs.
|
|
12
|
+
*/
|
|
13
|
+
export interface Plugin extends ChrisPluginRaw {
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Represents a running or completed Plugin Instance.
|
|
17
|
+
*/
|
|
18
|
+
export interface PluginInstance {
|
|
19
|
+
id: number;
|
|
20
|
+
title: string;
|
|
21
|
+
status: string;
|
|
22
|
+
plugin_name?: string;
|
|
23
|
+
start_date?: string;
|
|
24
|
+
end_date?: string;
|
|
25
|
+
feed_id?: number;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Models for raw ChRIS resources as returned by the API/Salsa.
|
|
3
|
+
*
|
|
4
|
+
* These interfaces describe the shape of the data objects found in the `tableData`
|
|
5
|
+
* arrays returned by Salsa's listing functions.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Base interface for any ChRIS resource.
|
|
11
|
+
*/
|
|
12
|
+
export interface ChrisResourceRaw {
|
|
13
|
+
url?: string;
|
|
14
|
+
id?: number;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Represents a File, Directory, or Link from the ChRIS filesystem.
|
|
19
|
+
* Note: Fields are optional because 'dirs', 'files', and 'links' endpoints
|
|
20
|
+
* return slightly different subsets of these fields.
|
|
21
|
+
*/
|
|
22
|
+
export interface ChrisFileOrDirRaw extends ChrisResourceRaw {
|
|
23
|
+
fname?: string;
|
|
24
|
+
path?: string;
|
|
25
|
+
fsize?: number;
|
|
26
|
+
owner_username?: string;
|
|
27
|
+
creation_date?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Represents a ChRIS Plugin.
|
|
31
|
+
*/
|
|
32
|
+
export interface ChrisPluginRaw extends ChrisResourceRaw {
|
|
33
|
+
name: string;
|
|
34
|
+
version: string;
|
|
35
|
+
creation_date: string;
|
|
36
|
+
title?: string;
|
|
37
|
+
dock_image?: string;
|
|
38
|
+
public_repo?: string;
|
|
39
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Handler for the PACS query command group.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
/**
|
|
8
|
+
* Handler for PACS queries commands.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PACSQueryGroupHandler {
|
|
11
|
+
private baseGroupHandler;
|
|
12
|
+
private assetName;
|
|
13
|
+
constructor();
|
|
14
|
+
/**
|
|
15
|
+
* Render a decoded PACS query JSON payload into a readable string.
|
|
16
|
+
* Expected structure:
|
|
17
|
+
* [
|
|
18
|
+
* { <study fields>, series: [ { <series fields> }, ... ] },
|
|
19
|
+
* ...
|
|
20
|
+
* ]
|
|
21
|
+
* Falls back gracefully if structure varies.
|
|
22
|
+
*/
|
|
23
|
+
private pacsResult_renderPretty;
|
|
24
|
+
private pacsserverContext_resolve;
|
|
25
|
+
private options_withPACSFilter;
|
|
26
|
+
pacsQueryCommand_setup(program: Command): void;
|
|
27
|
+
/**
|
|
28
|
+
* Registers the `list` subcommand (with PACS-server context filtering).
|
|
29
|
+
*
|
|
30
|
+
* @param parent - The parent `pacsqueries` command.
|
|
31
|
+
*/
|
|
32
|
+
private listCommand_register;
|
|
33
|
+
/**
|
|
34
|
+
* Registers the `fieldslist` subcommand.
|
|
35
|
+
*
|
|
36
|
+
* @param parent - The parent `pacsqueries` command.
|
|
37
|
+
*/
|
|
38
|
+
private fieldsListCommand_register;
|
|
39
|
+
/**
|
|
40
|
+
* Registers the `create <query>` subcommand.
|
|
41
|
+
*
|
|
42
|
+
* @param parent - The parent `pacsqueries` command.
|
|
43
|
+
*/
|
|
44
|
+
private createCommand_register;
|
|
45
|
+
/**
|
|
46
|
+
* Registers the `decode <queryId>` subcommand.
|
|
47
|
+
*
|
|
48
|
+
* @param parent - The parent `pacsqueries` command.
|
|
49
|
+
*/
|
|
50
|
+
private decodeCommand_register;
|
|
51
|
+
/**
|
|
52
|
+
* Build a PACS query payload from JSON or comma-separated key:value pairs.
|
|
53
|
+
*/
|
|
54
|
+
private queryPayload_build;
|
|
55
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Handler for the PACS query command group.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { ChRISPACSQueryGroup, errorStack_getAllOfType, chrisContext, Context, } from "@fnndsc/cumin";
|
|
7
|
+
import { pacsQueries_create, pacsQuery_resultDecode } from "@fnndsc/salsa";
|
|
8
|
+
import { BaseGroupHandler } from "../handlers/baseGroupHandler.js";
|
|
9
|
+
import { border_draw } from "../screen/screen.js";
|
|
10
|
+
import { pacsQueryResult_renderPretty } from "./pacsResultRender.js";
|
|
11
|
+
import { pacsQueryPayload_build } from "./pacsQueryPayload.js";
|
|
12
|
+
/**
|
|
13
|
+
* Handler for PACS queries commands.
|
|
14
|
+
*/
|
|
15
|
+
export class PACSQueryGroupHandler {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.assetName = "pacsqueries";
|
|
18
|
+
const chrisObject = new ChRISPACSQueryGroup();
|
|
19
|
+
this.baseGroupHandler = new BaseGroupHandler(this.assetName, chrisObject);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Render a decoded PACS query JSON payload into a readable string.
|
|
23
|
+
* Expected structure:
|
|
24
|
+
* [
|
|
25
|
+
* { <study fields>, series: [ { <series fields> }, ... ] },
|
|
26
|
+
* ...
|
|
27
|
+
* ]
|
|
28
|
+
* Falls back gracefully if structure varies.
|
|
29
|
+
*/
|
|
30
|
+
pacsResult_renderPretty(payload) {
|
|
31
|
+
return pacsQueryResult_renderPretty(payload);
|
|
32
|
+
}
|
|
33
|
+
async pacsserverContext_resolve(overridePacsserver) {
|
|
34
|
+
if (overridePacsserver && overridePacsserver.length > 0) {
|
|
35
|
+
return overridePacsserver;
|
|
36
|
+
}
|
|
37
|
+
const current = await chrisContext.current_get(Context.PACSserver);
|
|
38
|
+
return current;
|
|
39
|
+
}
|
|
40
|
+
options_withPACSFilter(options, pacsserver) {
|
|
41
|
+
if (!pacsserver) {
|
|
42
|
+
return options;
|
|
43
|
+
}
|
|
44
|
+
const pacsFilter = /^\d+$/.test(pacsserver)
|
|
45
|
+
? `pacs_id:${pacsserver}`
|
|
46
|
+
: `pacs_identifier:${pacsserver}`;
|
|
47
|
+
const searchParts = [];
|
|
48
|
+
if (options.search) {
|
|
49
|
+
searchParts.push(options.search);
|
|
50
|
+
}
|
|
51
|
+
searchParts.push(pacsFilter);
|
|
52
|
+
return { ...options, search: searchParts.join(",") };
|
|
53
|
+
}
|
|
54
|
+
pacsQueryCommand_setup(program) {
|
|
55
|
+
const pacsQueryCommand = program
|
|
56
|
+
.command(this.assetName)
|
|
57
|
+
.description("Interact with PACS queries");
|
|
58
|
+
this.listCommand_register(pacsQueryCommand);
|
|
59
|
+
this.fieldsListCommand_register(pacsQueryCommand);
|
|
60
|
+
this.createCommand_register(pacsQueryCommand);
|
|
61
|
+
this.decodeCommand_register(pacsQueryCommand);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Registers the `list` subcommand (with PACS-server context filtering).
|
|
65
|
+
*
|
|
66
|
+
* @param parent - The parent `pacsqueries` command.
|
|
67
|
+
*/
|
|
68
|
+
listCommand_register(parent) {
|
|
69
|
+
const listCommand = this.baseGroupHandler.baseListCommand_create(async (options) => {
|
|
70
|
+
const pacsserver = await this.pacsserverContext_resolve(options.pacsserver);
|
|
71
|
+
if (!pacsserver) {
|
|
72
|
+
console.log(border_draw("No PACS server in context. Use --pacsserver or set via context."));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const mergedOptions = this.options_withPACSFilter(options, pacsserver);
|
|
76
|
+
await this.baseGroupHandler.resources_list(mergedOptions);
|
|
77
|
+
});
|
|
78
|
+
listCommand.option("--pacsserver <pacsserver>", "PACS server ID or identifier to filter queries");
|
|
79
|
+
parent.addCommand(listCommand);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Registers the `fieldslist` subcommand.
|
|
83
|
+
*
|
|
84
|
+
* @param parent - The parent `pacsqueries` command.
|
|
85
|
+
*/
|
|
86
|
+
fieldsListCommand_register(parent) {
|
|
87
|
+
parent
|
|
88
|
+
.command("fieldslist")
|
|
89
|
+
.description(`list the ${this.assetName} resource fields`)
|
|
90
|
+
.action(async () => {
|
|
91
|
+
await this.baseGroupHandler.resourceFields_list();
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Registers the `create <query>` subcommand.
|
|
96
|
+
*
|
|
97
|
+
* @param parent - The parent `pacsqueries` command.
|
|
98
|
+
*/
|
|
99
|
+
createCommand_register(parent) {
|
|
100
|
+
parent
|
|
101
|
+
.command("create <query>")
|
|
102
|
+
.description("Create a PACS query against the current or specified PACS server. <query> can be JSON or comma-separated key:value pairs.")
|
|
103
|
+
.option("--title <title>", "Title for the PACS query", `Query ${Date.now()}`)
|
|
104
|
+
.option("--description <description>", "Optional description for the PACS query")
|
|
105
|
+
.option("--pacsserver <pacsserver>", "PACS server ID or identifier (overrides context)")
|
|
106
|
+
.action(async (queryInput, options) => {
|
|
107
|
+
const pacsserver = await this.pacsserverContext_resolve(options.pacsserver);
|
|
108
|
+
if (!pacsserver) {
|
|
109
|
+
border_draw("No PACS server in context. Use --pacsserver or set via context.");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const payload = pacsQueryPayload_build(queryInput, options.title, options.description);
|
|
113
|
+
if (!payload) {
|
|
114
|
+
console.log(border_draw("Invalid query format. Provide JSON or comma-separated key:value pairs."));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const result = await pacsQueries_create(pacsserver, payload);
|
|
118
|
+
if (!result.ok) {
|
|
119
|
+
const errors = errorStack_getAllOfType("error");
|
|
120
|
+
if (errors.length) {
|
|
121
|
+
errors.forEach((msg) => console.log(border_draw(msg)));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log(border_draw("Failed to create PACS query."));
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const created = result.value;
|
|
129
|
+
const msg = [
|
|
130
|
+
"Created PACS query",
|
|
131
|
+
`id=${created.id}`,
|
|
132
|
+
`status=${created.status || "unknown"}`,
|
|
133
|
+
`pacs=${pacsserver}`,
|
|
134
|
+
`title="${created.title ?? options.title ?? ""}"`,
|
|
135
|
+
].join(" ");
|
|
136
|
+
console.log(border_draw(msg.trim()));
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Registers the `decode <queryId>` subcommand.
|
|
141
|
+
*
|
|
142
|
+
* @param parent - The parent `pacsqueries` command.
|
|
143
|
+
*/
|
|
144
|
+
decodeCommand_register(parent) {
|
|
145
|
+
parent
|
|
146
|
+
.command("decode <queryId>")
|
|
147
|
+
.description("Decode the result payload of a PACS query")
|
|
148
|
+
.option("--raw", "Print raw decoded JSON if available")
|
|
149
|
+
.action(async (queryId, options) => {
|
|
150
|
+
const idNum = Number(queryId);
|
|
151
|
+
if (Number.isNaN(idNum)) {
|
|
152
|
+
console.log(border_draw("queryId must be a number."));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const result = await pacsQuery_resultDecode(idNum);
|
|
156
|
+
if (!result.ok) {
|
|
157
|
+
const errors = errorStack_getAllOfType("error");
|
|
158
|
+
if (errors.length) {
|
|
159
|
+
errors.forEach((msg) => console.log(border_draw(msg)));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
console.log(border_draw(`Failed to decode PACS query result for ${idNum}.`));
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const decoded = result.value;
|
|
167
|
+
// Prefer JSON, then text, else indicate base64 length
|
|
168
|
+
if (decoded.json !== undefined) {
|
|
169
|
+
if (options.raw) {
|
|
170
|
+
console.log(border_draw(JSON.stringify(decoded.json, null, 2)));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const pretty = this.pacsResult_renderPretty(decoded.json);
|
|
174
|
+
if (pretty) {
|
|
175
|
+
console.log(border_draw(pretty));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
console.log(border_draw(JSON.stringify(decoded.json, null, 2)));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (decoded.text) {
|
|
182
|
+
console.log(border_draw(decoded.text));
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
const len = decoded.raw.length;
|
|
186
|
+
console.log(border_draw(`Decoded payload available (base64 length ${len}), but not printable.`));
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Build a PACS query payload from JSON or comma-separated key:value pairs.
|
|
192
|
+
*/
|
|
193
|
+
queryPayload_build(queryInput, title, description) {
|
|
194
|
+
return pacsQueryPayload_build(queryInput, title, description);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Pure builder for PACS query creation payloads.
|
|
3
|
+
*
|
|
4
|
+
* Accepts a JSON string or comma-separated `key:value` pairs. Dependency-free
|
|
5
|
+
* (type-only import) for easy unit testing.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
import type { PACSQueryCreateData } from "@fnndsc/cumin";
|
|
10
|
+
/**
|
|
11
|
+
* Builds a PACS query payload from either a JSON string or comma-separated
|
|
12
|
+
* `key:value` pairs.
|
|
13
|
+
*
|
|
14
|
+
* @param queryInput - JSON or comma-separated key:value query specification.
|
|
15
|
+
* @param title - Optional query title (defaults to a timestamped title).
|
|
16
|
+
* @param description - Optional query description.
|
|
17
|
+
* @returns The payload, or null if no usable query fields were parsed.
|
|
18
|
+
*/
|
|
19
|
+
export declare function pacsQueryPayload_build(queryInput: string, title?: string, description?: string): PACSQueryCreateData | null;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a PACS query payload from either a JSON string or comma-separated
|
|
3
|
+
* `key:value` pairs.
|
|
4
|
+
*
|
|
5
|
+
* @param queryInput - JSON or comma-separated key:value query specification.
|
|
6
|
+
* @param title - Optional query title (defaults to a timestamped title).
|
|
7
|
+
* @param description - Optional query description.
|
|
8
|
+
* @returns The payload, or null if no usable query fields were parsed.
|
|
9
|
+
*/
|
|
10
|
+
export function pacsQueryPayload_build(queryInput, title, description) {
|
|
11
|
+
let queryObject = {};
|
|
12
|
+
try {
|
|
13
|
+
const parsed = JSON.parse(queryInput);
|
|
14
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
15
|
+
queryObject = parsed;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Fallback to comma-separated key:value pairs
|
|
20
|
+
queryObject = queryInput.split(",").reduce((acc, part) => {
|
|
21
|
+
const [keyRaw, ...rest] = part.split(":");
|
|
22
|
+
if (!keyRaw || rest.length === 0) {
|
|
23
|
+
return acc;
|
|
24
|
+
}
|
|
25
|
+
const key = keyRaw.trim();
|
|
26
|
+
const value = rest.join(":").trim();
|
|
27
|
+
if (key && value) {
|
|
28
|
+
acc[key] = value;
|
|
29
|
+
}
|
|
30
|
+
return acc;
|
|
31
|
+
}, {});
|
|
32
|
+
}
|
|
33
|
+
if (Object.keys(queryObject).length === 0) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const payload = {
|
|
37
|
+
title: title || `Query ${Date.now()}`,
|
|
38
|
+
query: JSON.stringify(queryObject),
|
|
39
|
+
};
|
|
40
|
+
if (description) {
|
|
41
|
+
payload.description = description;
|
|
42
|
+
}
|
|
43
|
+
return payload;
|
|
44
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Pure rendering of PACS query result payloads into a human-readable,
|
|
3
|
+
* indented study/series listing.
|
|
4
|
+
*
|
|
5
|
+
* The CUBE PACS query result is a loosely-typed nested structure; these helpers
|
|
6
|
+
* extract DICOM tag values defensively and format them. Dependency-free for
|
|
7
|
+
* easy unit testing.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Renders a PACS query result payload into a human-readable string.
|
|
13
|
+
*
|
|
14
|
+
* Accepts a single study object or an array of studies; each study may carry a
|
|
15
|
+
* nested series array under `series`/`Series`/`results`/`data`.
|
|
16
|
+
*
|
|
17
|
+
* @param payload - The PACS query result payload.
|
|
18
|
+
* @returns The formatted listing, or null if there is nothing to render.
|
|
19
|
+
*/
|
|
20
|
+
export declare function pacsQueryResult_renderPretty(payload: unknown): string | null;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Pure rendering of PACS query result payloads into a human-readable,
|
|
3
|
+
* indented study/series listing.
|
|
4
|
+
*
|
|
5
|
+
* The CUBE PACS query result is a loosely-typed nested structure; these helpers
|
|
6
|
+
* extract DICOM tag values defensively and format them. Dependency-free for
|
|
7
|
+
* easy unit testing.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
const STUDY_FIELD_ORDER = [
|
|
12
|
+
"AccessionNumber",
|
|
13
|
+
"PatientName",
|
|
14
|
+
"PatientID",
|
|
15
|
+
"PatientBirthDate",
|
|
16
|
+
"PatientSex",
|
|
17
|
+
"StudyDate",
|
|
18
|
+
"StudyDescription",
|
|
19
|
+
"StudyInstanceUID",
|
|
20
|
+
"ModalitiesInStudy",
|
|
21
|
+
"NumberOfStudyRelatedSeries",
|
|
22
|
+
"NumberOfStudyRelatedInstances",
|
|
23
|
+
"RetrieveAETitle",
|
|
24
|
+
"status",
|
|
25
|
+
"QueryRetrieveLevel",
|
|
26
|
+
];
|
|
27
|
+
const SERIES_FIELD_ORDER = [
|
|
28
|
+
"SeriesDescription",
|
|
29
|
+
"Modality",
|
|
30
|
+
"SeriesInstanceUID",
|
|
31
|
+
"NumberOfSeriesRelatedInstances",
|
|
32
|
+
"InstanceNumber",
|
|
33
|
+
"PerformedStationAETitle",
|
|
34
|
+
"RetrieveLevel",
|
|
35
|
+
"status",
|
|
36
|
+
"uid",
|
|
37
|
+
];
|
|
38
|
+
/**
|
|
39
|
+
* Extracts a `{ label, value }` DICOM tag from a value if it has the tag shape.
|
|
40
|
+
*
|
|
41
|
+
* @param val - A candidate tag value.
|
|
42
|
+
* @returns The resolved tag, or null if it is not tag-shaped.
|
|
43
|
+
*/
|
|
44
|
+
function tag_extract(val) {
|
|
45
|
+
if (val && typeof val === "object" && "value" in val) {
|
|
46
|
+
const tagObj = val;
|
|
47
|
+
const label = typeof tagObj.label === "string" && tagObj.label.length ? tagObj.label : "";
|
|
48
|
+
return { label, value: tagObj.value };
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Extracts displayable fields from an object, preferring a given key order and
|
|
54
|
+
* optionally including all remaining scalar/tag keys. De-duplicates by label.
|
|
55
|
+
*
|
|
56
|
+
* @param obj - The source object.
|
|
57
|
+
* @param preferredOrder - Keys to emit first, in order.
|
|
58
|
+
* @param includeAll - Whether to also include remaining keys.
|
|
59
|
+
* @returns The collected fields.
|
|
60
|
+
*/
|
|
61
|
+
function fields_extract(obj, preferredOrder, includeAll) {
|
|
62
|
+
const collected = [];
|
|
63
|
+
const seen = new Set();
|
|
64
|
+
const field_push = (label, value) => {
|
|
65
|
+
if (label && !seen.has(label)) {
|
|
66
|
+
collected.push({ label, value });
|
|
67
|
+
seen.add(label);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const keys_scan = (keys) => {
|
|
71
|
+
for (const key of keys) {
|
|
72
|
+
const val = obj[key];
|
|
73
|
+
if (Array.isArray(val))
|
|
74
|
+
continue;
|
|
75
|
+
const tagVal = tag_extract(val);
|
|
76
|
+
if (tagVal) {
|
|
77
|
+
field_push(tagVal.label || key, tagVal.value);
|
|
78
|
+
}
|
|
79
|
+
else if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
|
|
80
|
+
field_push(key, val);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
keys_scan(preferredOrder);
|
|
85
|
+
if (includeAll) {
|
|
86
|
+
keys_scan(Object.keys(obj));
|
|
87
|
+
}
|
|
88
|
+
return collected;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Renders one study (and its nested series) into indented output lines.
|
|
92
|
+
*
|
|
93
|
+
* @param studyIdx - Zero-based study index.
|
|
94
|
+
* @param studyObj - The study object.
|
|
95
|
+
* @returns The rendered lines for this study.
|
|
96
|
+
*/
|
|
97
|
+
function study_renderLines(studyIdx, studyObj) {
|
|
98
|
+
const lines = [];
|
|
99
|
+
const seriesArr = Array.isArray(studyObj['series']) ? studyObj['series'] :
|
|
100
|
+
Array.isArray(studyObj['Series']) ? studyObj['Series'] :
|
|
101
|
+
Array.isArray(studyObj['results']) ? studyObj['results'] :
|
|
102
|
+
Array.isArray(studyObj['data']) ? studyObj['data'] :
|
|
103
|
+
null;
|
|
104
|
+
const studyFields = fields_extract(studyObj, STUDY_FIELD_ORDER, true);
|
|
105
|
+
lines.push(`Study ${studyIdx + 1}`);
|
|
106
|
+
studyFields.forEach((f) => lines.push(` ${f.label}: ${f.value}`));
|
|
107
|
+
if (seriesArr && seriesArr.length) {
|
|
108
|
+
seriesArr.forEach((series, idx) => {
|
|
109
|
+
if (!series || typeof series !== "object")
|
|
110
|
+
return;
|
|
111
|
+
const seriesFields = fields_extract(series, SERIES_FIELD_ORDER, false);
|
|
112
|
+
lines.push(` Series ${idx + 1}`);
|
|
113
|
+
seriesFields.forEach((f) => lines.push(` ${f.label}: ${f.value}`));
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
lines.push("");
|
|
117
|
+
return lines;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Renders a PACS query result payload into a human-readable string.
|
|
121
|
+
*
|
|
122
|
+
* Accepts a single study object or an array of studies; each study may carry a
|
|
123
|
+
* nested series array under `series`/`Series`/`results`/`data`.
|
|
124
|
+
*
|
|
125
|
+
* @param payload - The PACS query result payload.
|
|
126
|
+
* @returns The formatted listing, or null if there is nothing to render.
|
|
127
|
+
*/
|
|
128
|
+
export function pacsQueryResult_renderPretty(payload) {
|
|
129
|
+
if (!payload || typeof payload !== "object") {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const payloadArray = Array.isArray(payload) ? payload : [payload];
|
|
133
|
+
const lines = [];
|
|
134
|
+
payloadArray.forEach((item, idx) => {
|
|
135
|
+
if (item && typeof item === "object") {
|
|
136
|
+
lines.push(...study_renderLines(idx, item));
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const output = lines.join("\n").trim();
|
|
140
|
+
return output.length ? output : null;
|
|
141
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Handler for the PACS retrieve command group.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
/**
|
|
8
|
+
* Handler for PACS retrieve commands.
|
|
9
|
+
*/
|
|
10
|
+
export declare class PACSRetrieveGroupHandler {
|
|
11
|
+
private assetName;
|
|
12
|
+
/**
|
|
13
|
+
* Setup PACS retrieve commands on the parent command.
|
|
14
|
+
*
|
|
15
|
+
* @param program - Commander program instance.
|
|
16
|
+
*/
|
|
17
|
+
pacsRetrieveCommand_setup(program: Command): void;
|
|
18
|
+
/**
|
|
19
|
+
* Handle the 'pull' command - create a new retrieve.
|
|
20
|
+
*
|
|
21
|
+
* @param queryIdStr - Query ID as string.
|
|
22
|
+
*/
|
|
23
|
+
private retrieve_pull;
|
|
24
|
+
/**
|
|
25
|
+
* Handle the 'report' command - show detailed status.
|
|
26
|
+
*
|
|
27
|
+
* @param queryIdStr - Query ID as string.
|
|
28
|
+
*/
|
|
29
|
+
private retrieve_report;
|
|
30
|
+
/**
|
|
31
|
+
* Handle the 'cancel' command - delete a retrieve.
|
|
32
|
+
*
|
|
33
|
+
* @param retrieveIdStr - Retrieve ID as string.
|
|
34
|
+
*/
|
|
35
|
+
private retrieve_cancel;
|
|
36
|
+
/**
|
|
37
|
+
* Determine overall completion status from series statuses.
|
|
38
|
+
*
|
|
39
|
+
* @param report - The status report.
|
|
40
|
+
* @returns True if all series are pulled.
|
|
41
|
+
*/
|
|
42
|
+
private allSeries_arePulled;
|
|
43
|
+
/**
|
|
44
|
+
* Render a status report into a human-readable string.
|
|
45
|
+
*
|
|
46
|
+
* @param report - The status report.
|
|
47
|
+
* @returns Formatted string.
|
|
48
|
+
*/
|
|
49
|
+
private report_render;
|
|
50
|
+
/**
|
|
51
|
+
* Extract value from a DICOM tag object or return as-is.
|
|
52
|
+
*
|
|
53
|
+
* @param val - Potentially a tag object with {label, value} or a primitive.
|
|
54
|
+
* @returns The extracted value.
|
|
55
|
+
*/
|
|
56
|
+
private tagValue_extract;
|
|
57
|
+
/**
|
|
58
|
+
* Render a single study to the lines array.
|
|
59
|
+
*
|
|
60
|
+
* @param study - Study status.
|
|
61
|
+
* @param studyNum - Study number (1-indexed).
|
|
62
|
+
* @param lines - Output lines array.
|
|
63
|
+
*/
|
|
64
|
+
private study_renderTo;
|
|
65
|
+
/**
|
|
66
|
+
* Render a single series to the lines array.
|
|
67
|
+
*
|
|
68
|
+
* @param series - Series status.
|
|
69
|
+
* @param seriesNum - Series number (1-indexed).
|
|
70
|
+
* @param lines - Output lines array.
|
|
71
|
+
*/
|
|
72
|
+
private series_renderTo;
|
|
73
|
+
/**
|
|
74
|
+
* Generate display string for series status.
|
|
75
|
+
*
|
|
76
|
+
* @param series - Series status.
|
|
77
|
+
* @returns Display string.
|
|
78
|
+
*/
|
|
79
|
+
private series_statusDisplay;
|
|
80
|
+
/**
|
|
81
|
+
* Map retrieve status to display string.
|
|
82
|
+
*
|
|
83
|
+
* @param status - Raw status string.
|
|
84
|
+
* @returns Display-friendly status.
|
|
85
|
+
*/
|
|
86
|
+
private status_mapToDisplay;
|
|
87
|
+
}
|