@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,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Commander setup for the ChRIS file-browser command group.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { ChRISinode_create, listParams_fromOptions, BrowserType, } from "@fnndsc/cumin";
|
|
7
|
+
/**
|
|
8
|
+
* Lists resources for a given inode path.
|
|
9
|
+
*
|
|
10
|
+
* @param path - The inode path to list resources from.
|
|
11
|
+
* @param options - CLI options for filtering and pagination.
|
|
12
|
+
*/
|
|
13
|
+
async function inodeResources_list(path, options) {
|
|
14
|
+
const chrisInode = await ChRISinode_create(path);
|
|
15
|
+
if (!chrisInode) {
|
|
16
|
+
console.error(`Could not find path '${path}' in the CUBE filesystem.`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const params = listParams_fromOptions({
|
|
20
|
+
...options,
|
|
21
|
+
returnFilter: "limit,offset",
|
|
22
|
+
});
|
|
23
|
+
const browserTypes = [
|
|
24
|
+
BrowserType.Files,
|
|
25
|
+
BrowserType.Links,
|
|
26
|
+
BrowserType.Dirs,
|
|
27
|
+
];
|
|
28
|
+
const fieldOptions = {
|
|
29
|
+
[BrowserType.Files]: options.filefields,
|
|
30
|
+
[BrowserType.Links]: options.linkfields,
|
|
31
|
+
[BrowserType.Dirs]: options.dirfields,
|
|
32
|
+
};
|
|
33
|
+
for (const browserType of browserTypes) {
|
|
34
|
+
const browser = chrisInode.browser_get(browserType);
|
|
35
|
+
if (!browser) {
|
|
36
|
+
console.error(`WARNING: ${browserType} browser is not available`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const resourceGet = browser.resource_get;
|
|
41
|
+
if (!resourceGet) {
|
|
42
|
+
console.error(`WARNING: ${browserType} resource is null`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const resourcesList = await resourceGet.resources_getList(params);
|
|
46
|
+
const resourceFields = await resourceGet.resourceFields_get(resourcesList, fieldOptions[browserType]);
|
|
47
|
+
const results = resourceGet.resources_filterByFields(resourceFields);
|
|
48
|
+
if (results) {
|
|
49
|
+
console.log(`${browserType} resources:`);
|
|
50
|
+
console.table(results.tableData, results.selectedFields);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
console.error(`${browserType} resources: not found or could not be filtered`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.error(`${browserType} resources: not found`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Displays resource fields for a given inode type.
|
|
63
|
+
*
|
|
64
|
+
* @param inodeType - The type of inode (e.g., "file properties").
|
|
65
|
+
* @param dataObj - The object containing resource fields.
|
|
66
|
+
* @returns True if fields were displayed, false otherwise.
|
|
67
|
+
*/
|
|
68
|
+
function inodeFields_list(inodeType, dataObj) {
|
|
69
|
+
if (!dataObj) {
|
|
70
|
+
console.log("No " + inodeType + " at this path");
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (dataObj.fields) {
|
|
74
|
+
console.log(inodeType);
|
|
75
|
+
console.table(dataObj.fields);
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Lists all resource fields for different inode types (files, links, dirs).
|
|
82
|
+
*
|
|
83
|
+
* @param path - The base path for the inode.
|
|
84
|
+
*/
|
|
85
|
+
async function inodeResourceFields_list(path = "") {
|
|
86
|
+
const chrisFiles = await ChRISinode_create(path);
|
|
87
|
+
if (!chrisFiles) {
|
|
88
|
+
console.error(`Could not create ChRISinode for path: ${path}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const fileBrowser = chrisFiles.fileBrowser_get;
|
|
92
|
+
const linkBrowser = chrisFiles.linkBrowser_get;
|
|
93
|
+
const dirBrowser = chrisFiles.dirBrowser_get;
|
|
94
|
+
let fileFields = null;
|
|
95
|
+
if (fileBrowser?.resource_get) {
|
|
96
|
+
fileFields = await fileBrowser.resource_get.resourceFields_get();
|
|
97
|
+
}
|
|
98
|
+
inodeFields_list("file properties", fileFields);
|
|
99
|
+
let linkFields = null;
|
|
100
|
+
if (linkBrowser?.resource_get) {
|
|
101
|
+
linkFields = await linkBrowser.resource_get.resourceFields_get();
|
|
102
|
+
}
|
|
103
|
+
inodeFields_list("link properties", linkFields);
|
|
104
|
+
let dirFields = null;
|
|
105
|
+
if (dirBrowser?.resource_get) {
|
|
106
|
+
dirFields = await dirBrowser.resource_get.resourceFields_get();
|
|
107
|
+
}
|
|
108
|
+
inodeFields_list("dir properties", dirFields);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Sets up the 'fobj' command for interacting with ChRIS filesystem objects.
|
|
112
|
+
*
|
|
113
|
+
* @param program - The Commander.js program instance.
|
|
114
|
+
*/
|
|
115
|
+
export async function fileBrowserCommand_setup(program) {
|
|
116
|
+
const pluginsCommand = program
|
|
117
|
+
.command("fobj")
|
|
118
|
+
.description("Interact with ChRIS file system objects");
|
|
119
|
+
pluginsCommand
|
|
120
|
+
.command("list [path]")
|
|
121
|
+
.description("List filesystem elements")
|
|
122
|
+
.option("-p, --page <size>", "Page size (default 20)")
|
|
123
|
+
.option("-f, --filefields <fields>", "Comma-separated list of fields to display for files")
|
|
124
|
+
.option("-d, --dirfields <fields>", "Comma-separated list of fields to display for dirs")
|
|
125
|
+
.option("-l, --linkfields <fields>", "Comma-separated list of fields to display for links")
|
|
126
|
+
.action(async (path, options) => {
|
|
127
|
+
await inodeResources_list(path, options);
|
|
128
|
+
});
|
|
129
|
+
pluginsCommand
|
|
130
|
+
.command("fieldslist [path]")
|
|
131
|
+
.description("List the filebrowser resource fields")
|
|
132
|
+
.action(async (path) => {
|
|
133
|
+
await inodeResourceFields_list(path);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Commander setup for inode-level filesystem commands.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
/**
|
|
8
|
+
* Sets up the 'inode' command for interacting with ChRIS filesystem resources.
|
|
9
|
+
*
|
|
10
|
+
* @param program - The Commander.js program instance.
|
|
11
|
+
*/
|
|
12
|
+
export declare function inodeCommand_setup(program: Command): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Commander setup for inode-level filesystem commands.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import { FileGroupHandler, FileMemberHandler } from "./fileGroupHandler.js";
|
|
8
|
+
/**
|
|
9
|
+
* Sets up the 'inode' command for interacting with ChRIS filesystem resources.
|
|
10
|
+
*
|
|
11
|
+
* @param program - The Commander.js program instance.
|
|
12
|
+
*/
|
|
13
|
+
export async function inodeCommand_setup(program) {
|
|
14
|
+
const inodeCommand = program
|
|
15
|
+
.command("inode <path>")
|
|
16
|
+
.description("Interact with ChRIS filesystem resources at a specific path")
|
|
17
|
+
.action(async (path, options, command) => {
|
|
18
|
+
const args = command.args.slice(1);
|
|
19
|
+
const subcommand = args[0];
|
|
20
|
+
if (subcommand === "files") {
|
|
21
|
+
const fileGroupHandler = await FileGroupHandler.handler_create("files", path);
|
|
22
|
+
const filesProgram = new Command();
|
|
23
|
+
fileGroupHandler.fileGroupCommand_setup(filesProgram);
|
|
24
|
+
await filesProgram.parseAsync(args);
|
|
25
|
+
}
|
|
26
|
+
else if (subcommand === "file") {
|
|
27
|
+
const fileMemberHandler = await FileMemberHandler.handler_create(path);
|
|
28
|
+
const fileProgram = new Command();
|
|
29
|
+
fileMemberHandler.fileMemberCommand_setup(fileProgram);
|
|
30
|
+
await fileProgram.parseAsync(args);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.error("Usage: chili inode <path> <files|file> [options]");
|
|
34
|
+
command.help();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Base class for resource command-group handlers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import { ChRISPluginGroup, ChRISFeedGroup, ChRISEmbeddedResourceGroup, ChRISPACSGroup } from "@fnndsc/cumin";
|
|
8
|
+
import { CLIoptions } from "../utils/cli.js";
|
|
9
|
+
import { TableOptions } from "../screen/screen.js";
|
|
10
|
+
/**
|
|
11
|
+
* Base handler for groups of ChRIS resources.
|
|
12
|
+
* Provides common functionality for listing and deleting resources.
|
|
13
|
+
*/
|
|
14
|
+
export declare class BaseGroupHandler {
|
|
15
|
+
assetName: string;
|
|
16
|
+
displayOptions: TableOptions;
|
|
17
|
+
chrisObject: ChRISPluginGroup | ChRISFeedGroup | ChRISEmbeddedResourceGroup<unknown> | ChRISPACSGroup;
|
|
18
|
+
constructor(assetName: string, chrisObject: ChRISPluginGroup | ChRISFeedGroup | ChRISEmbeddedResourceGroup<unknown> | ChRISPACSGroup);
|
|
19
|
+
/**
|
|
20
|
+
* Removes duplicate column headers from FilteredResourceData results.
|
|
21
|
+
*
|
|
22
|
+
* @param results - The FilteredResourceData to process.
|
|
23
|
+
* @returns FilteredResourceData with unique headers and corresponding data.
|
|
24
|
+
*/
|
|
25
|
+
private columns_removeDuplicates;
|
|
26
|
+
/**
|
|
27
|
+
* Lists ChRIS resources based on provided CLI options.
|
|
28
|
+
*
|
|
29
|
+
* @param options - CLI options for filtering and pagination.
|
|
30
|
+
*/
|
|
31
|
+
resources_list(options: CLIoptions): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Lists available fields for the current ChRIS resource type.
|
|
34
|
+
*/
|
|
35
|
+
resourceFields_list(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Prompts the user for confirmation before performing an operation.
|
|
38
|
+
*
|
|
39
|
+
* @param ID - The ID of the resource.
|
|
40
|
+
* @param opName - The name of the operation.
|
|
41
|
+
* @returns A Promise resolving to true if confirmed, false otherwise.
|
|
42
|
+
*/
|
|
43
|
+
private operation_confirm;
|
|
44
|
+
/**
|
|
45
|
+
* Prints details of a specific resource by its ID.
|
|
46
|
+
*
|
|
47
|
+
* @param ID - The ID of the resource.
|
|
48
|
+
* @param fields - Optional comma-separated list of fields to display.
|
|
49
|
+
*/
|
|
50
|
+
resource_printGivenID(ID: number, fields?: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Prompts the user to continue an operation after displaying resource info.
|
|
53
|
+
*
|
|
54
|
+
* @param ID - The ID of the resource.
|
|
55
|
+
* @param operation - The name of the operation.
|
|
56
|
+
* @param fields - Optional comma-separated list of fields to display.
|
|
57
|
+
* @returns A Promise resolving to true if confirmed, false otherwise.
|
|
58
|
+
*/
|
|
59
|
+
user_confirmContinuation(ID: number, operation: string, fields?: string): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Generates an "OK" or "Failed" message based on a boolean condition.
|
|
62
|
+
*
|
|
63
|
+
* @param obj - The object to check (truthy implies OK).
|
|
64
|
+
* @param failureNotice - Optional custom failure message.
|
|
65
|
+
* @returns The formatted status message.
|
|
66
|
+
*/
|
|
67
|
+
msg_OKorNot(obj: unknown, failureNotice?: string): string;
|
|
68
|
+
/**
|
|
69
|
+
* Deletes ChRIS resources by their IDs.
|
|
70
|
+
*
|
|
71
|
+
* @param IDs - An array of resource IDs to delete.
|
|
72
|
+
* @param force - If true, bypasses user confirmation.
|
|
73
|
+
* @returns A Promise resolving to true on success, false on failure.
|
|
74
|
+
*/
|
|
75
|
+
resources_delete(IDs: number[], force: boolean): Promise<boolean>;
|
|
76
|
+
/**
|
|
77
|
+
* Retrieves resource IDs based on search options.
|
|
78
|
+
*
|
|
79
|
+
* @param options - CLI options for searching.
|
|
80
|
+
* @returns A Promise resolving to an array of IDs or null if no matches.
|
|
81
|
+
*/
|
|
82
|
+
IDs_getFromSearch(options: CLIoptions): Promise<number[] | null>;
|
|
83
|
+
/**
|
|
84
|
+
* Handles the deletion of resources based on CLI options.
|
|
85
|
+
*
|
|
86
|
+
* @param options - CLI options including search terms and force flag.
|
|
87
|
+
*/
|
|
88
|
+
delete_handle(options: CLIoptions): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Creates a standard list command with all base options.
|
|
91
|
+
* This method provides a consistent set of options across all resource types.
|
|
92
|
+
*
|
|
93
|
+
* @param actionHandler - The async function to execute when the command is invoked.
|
|
94
|
+
* @returns A configured Command object with standard list options.
|
|
95
|
+
*/
|
|
96
|
+
baseListCommand_create(actionHandler: (options: CLIoptions) => Promise<void>): Command;
|
|
97
|
+
/**
|
|
98
|
+
* Sets up the Commander.js commands for resource listing and deletion.
|
|
99
|
+
*
|
|
100
|
+
* @param program - The Commander.js program instance.
|
|
101
|
+
*/
|
|
102
|
+
command_setup(program: Command): void;
|
|
103
|
+
}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Base class for resource command-group handlers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
import { ChRISFeedGroup, record_extract, errorStack, } from "@fnndsc/cumin";
|
|
8
|
+
import { options_toParams } from "../utils/cli.js";
|
|
9
|
+
import { table_display, border_draw } from "../screen/screen.js";
|
|
10
|
+
import * as readline from "readline";
|
|
11
|
+
/**
|
|
12
|
+
* Base handler for groups of ChRIS resources.
|
|
13
|
+
* Provides common functionality for listing and deleting resources.
|
|
14
|
+
*/
|
|
15
|
+
export class BaseGroupHandler {
|
|
16
|
+
constructor(assetName, chrisObject) {
|
|
17
|
+
this.assetName = "";
|
|
18
|
+
this.assetName = assetName;
|
|
19
|
+
this.chrisObject = chrisObject;
|
|
20
|
+
this.displayOptions = {
|
|
21
|
+
title: { title: this.assetName, justification: "center" },
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Removes duplicate column headers from FilteredResourceData results.
|
|
26
|
+
*
|
|
27
|
+
* @param results - The FilteredResourceData to process.
|
|
28
|
+
* @returns FilteredResourceData with unique headers and corresponding data.
|
|
29
|
+
*/
|
|
30
|
+
columns_removeDuplicates(results) {
|
|
31
|
+
const uniqueHeaders = Array.from(new Set(results.selectedFields));
|
|
32
|
+
const uniqueTableData = results.tableData.map((row) => uniqueHeaders.reduce((acc, header) => {
|
|
33
|
+
if (typeof header === "string" && header in row) {
|
|
34
|
+
acc[header] = row[header];
|
|
35
|
+
}
|
|
36
|
+
return acc;
|
|
37
|
+
}, {}));
|
|
38
|
+
return {
|
|
39
|
+
...results,
|
|
40
|
+
selectedFields: uniqueHeaders,
|
|
41
|
+
tableData: uniqueTableData,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Lists ChRIS resources based on provided CLI options.
|
|
46
|
+
*
|
|
47
|
+
* @param options - CLI options for filtering and pagination.
|
|
48
|
+
*/
|
|
49
|
+
async resources_list(options) {
|
|
50
|
+
try {
|
|
51
|
+
// Parse fields to handle column width specifiers (e.g., "name:20")
|
|
52
|
+
const columnWidths = {};
|
|
53
|
+
if (options.fields) {
|
|
54
|
+
const fields = options.fields.split(',').map(f => f.trim());
|
|
55
|
+
const cleanFields = [];
|
|
56
|
+
fields.forEach(field => {
|
|
57
|
+
const parts = field.split(':');
|
|
58
|
+
if (parts.length === 2 && !isNaN(Number(parts[1]))) {
|
|
59
|
+
const fieldName = parts[0];
|
|
60
|
+
const width = Number(parts[1]);
|
|
61
|
+
columnWidths[fieldName] = width;
|
|
62
|
+
cleanFields.push(fieldName);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
cleanFields.push(field);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
options.fields = cleanFields.join(',');
|
|
69
|
+
}
|
|
70
|
+
const params = options_toParams(options);
|
|
71
|
+
const results = await this.chrisObject.asset.resources_listAndFilterByOptions(params);
|
|
72
|
+
if (!results) {
|
|
73
|
+
console.error(`No ${this.assetName} resources found. Perhaps check your current context?`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (results.tableData.length === 0) {
|
|
77
|
+
console.log(`No ${this.assetName} found matching the criteria.`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const uniqueResults = this.columns_removeDuplicates(results);
|
|
81
|
+
// Construct column options based on parsed widths
|
|
82
|
+
const columns = uniqueResults.selectedFields.map(field => {
|
|
83
|
+
const width = columnWidths[field];
|
|
84
|
+
return width ? { width } : {};
|
|
85
|
+
});
|
|
86
|
+
if (options.csv) {
|
|
87
|
+
// CSV Output
|
|
88
|
+
const header = uniqueResults.selectedFields.map(h => `"${h.toUpperCase()}"`).join(',');
|
|
89
|
+
const rows = uniqueResults.tableData.map(row => {
|
|
90
|
+
return uniqueResults.selectedFields.map(field => {
|
|
91
|
+
const val = row[field];
|
|
92
|
+
return `"${String(val !== undefined ? val : '').split('"').join('""')}"`;
|
|
93
|
+
}).join(',');
|
|
94
|
+
}).join('\n');
|
|
95
|
+
console.log(header + '\n' + rows);
|
|
96
|
+
}
|
|
97
|
+
else if (options.table) {
|
|
98
|
+
// Explicit Table format (with borders and title)
|
|
99
|
+
table_display(uniqueResults.tableData, uniqueResults.selectedFields, {
|
|
100
|
+
...this.displayOptions,
|
|
101
|
+
columns: columns,
|
|
102
|
+
typeColors: {
|
|
103
|
+
string: "green",
|
|
104
|
+
number: "yellow",
|
|
105
|
+
boolean: "cyan",
|
|
106
|
+
object: "magenta"
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// Default: Aligned, colorized, borderless list (no title)
|
|
112
|
+
table_display(uniqueResults.tableData, uniqueResults.selectedFields, {
|
|
113
|
+
borderless: true,
|
|
114
|
+
columns: columns,
|
|
115
|
+
typeColors: {
|
|
116
|
+
string: "green",
|
|
117
|
+
number: "yellow",
|
|
118
|
+
boolean: "cyan",
|
|
119
|
+
object: "magenta"
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
console.log(errorStack.stack_search(this.assetName)[0]);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Lists available fields for the current ChRIS resource type.
|
|
131
|
+
*/
|
|
132
|
+
async resourceFields_list() {
|
|
133
|
+
try {
|
|
134
|
+
const results = await this.chrisObject.asset.resourceFields_get();
|
|
135
|
+
if (!results) {
|
|
136
|
+
console.error(`An error occurred while fetching resource fields for ${this.assetName}.`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (results.fields.length === 0) {
|
|
140
|
+
console.log(`No resource fields found for ${this.assetName}.`);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
table_display(results.fields, ["fields"]);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.log(errorStack.stack_search(this.assetName)[0]);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Prompts the user for confirmation before performing an operation.
|
|
152
|
+
*
|
|
153
|
+
* @param ID - The ID of the resource.
|
|
154
|
+
* @param opName - The name of the operation.
|
|
155
|
+
* @returns A Promise resolving to true if confirmed, false otherwise.
|
|
156
|
+
*/
|
|
157
|
+
async operation_confirm(ID, opName) {
|
|
158
|
+
const rl = readline.createInterface({
|
|
159
|
+
input: process.stdin,
|
|
160
|
+
output: process.stdout,
|
|
161
|
+
});
|
|
162
|
+
return new Promise((resolve) => {
|
|
163
|
+
rl.question(`Are you sure you want to ${opName} ${this.assetName} resource id ${ID}? (y/N) `, (answer) => {
|
|
164
|
+
rl.close();
|
|
165
|
+
resolve(answer.toLowerCase() === "y");
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Prints details of a specific resource by its ID.
|
|
171
|
+
*
|
|
172
|
+
* @param ID - The ID of the resource.
|
|
173
|
+
* @param fields - Optional comma-separated list of fields to display.
|
|
174
|
+
*/
|
|
175
|
+
async resource_printGivenID(ID, fields) {
|
|
176
|
+
if (!fields) {
|
|
177
|
+
if (this.chrisObject instanceof ChRISFeedGroup) {
|
|
178
|
+
fields = "id,name,creation_date,owner_username";
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
fields = "";
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
await this.resources_list({
|
|
185
|
+
fields: fields,
|
|
186
|
+
search: `id: ${ID}`,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Prompts the user to continue an operation after displaying resource info.
|
|
191
|
+
*
|
|
192
|
+
* @param ID - The ID of the resource.
|
|
193
|
+
* @param operation - The name of the operation.
|
|
194
|
+
* @param fields - Optional comma-separated list of fields to display.
|
|
195
|
+
* @returns A Promise resolving to true if confirmed, false otherwise.
|
|
196
|
+
*/
|
|
197
|
+
async user_confirmContinuation(ID, operation, fields) {
|
|
198
|
+
await this.resource_printGivenID(ID);
|
|
199
|
+
const confirmed = await this.operation_confirm(ID, operation);
|
|
200
|
+
return confirmed;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Generates an "OK" or "Failed" message based on a boolean condition.
|
|
204
|
+
*
|
|
205
|
+
* @param obj - The object to check (truthy implies OK).
|
|
206
|
+
* @param failureNotice - Optional custom failure message.
|
|
207
|
+
* @returns The formatted status message.
|
|
208
|
+
*/
|
|
209
|
+
msg_OKorNot(obj, failureNotice) {
|
|
210
|
+
let failMessage;
|
|
211
|
+
if (!failureNotice) {
|
|
212
|
+
failMessage = "[ Failed ]";
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
failMessage = failureNotice;
|
|
216
|
+
}
|
|
217
|
+
if (obj) {
|
|
218
|
+
return "[ OK ]";
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
return failMessage;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Deletes ChRIS resources by their IDs.
|
|
226
|
+
*
|
|
227
|
+
* @param IDs - An array of resource IDs to delete.
|
|
228
|
+
* @param force - If true, bypasses user confirmation.
|
|
229
|
+
* @returns A Promise resolving to true on success, false on failure.
|
|
230
|
+
*/
|
|
231
|
+
async resources_delete(IDs, force) {
|
|
232
|
+
let delop = true;
|
|
233
|
+
let confirm = false;
|
|
234
|
+
let title = "";
|
|
235
|
+
let OKorNot = "";
|
|
236
|
+
for (const id of IDs) {
|
|
237
|
+
try {
|
|
238
|
+
const searchResults = await this.chrisObject.asset.resources_listAndFilterByOptions({
|
|
239
|
+
id: id,
|
|
240
|
+
});
|
|
241
|
+
console.log(border_draw(`checking ${this.assetName} id ${id} ... ${this.msg_OKorNot(searchResults)}`));
|
|
242
|
+
if (!force) {
|
|
243
|
+
confirm = await this.user_confirmContinuation(id, "delete");
|
|
244
|
+
if (!confirm) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
delop = await this.chrisObject.asset.resourceItem_delete(id);
|
|
249
|
+
border_draw(`deleting ${this.assetName} id ${id} ... ${this.msg_OKorNot(true)}`);
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
console.error(`${error}`);
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Retrieves resource IDs based on search options.
|
|
260
|
+
*
|
|
261
|
+
* @param options - CLI options for searching.
|
|
262
|
+
* @returns A Promise resolving to an array of IDs or null if no matches.
|
|
263
|
+
*/
|
|
264
|
+
async IDs_getFromSearch(options) {
|
|
265
|
+
const params = options_toParams(options);
|
|
266
|
+
const searchResults = await this.chrisObject.asset.resources_listAndFilterByOptions(params);
|
|
267
|
+
if (!searchResults) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
const queryHits = record_extract(searchResults.tableData, "id");
|
|
271
|
+
return queryHits.hits;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Handles the deletion of resources based on CLI options.
|
|
275
|
+
*
|
|
276
|
+
* @param options - CLI options including search terms and force flag.
|
|
277
|
+
*/
|
|
278
|
+
async delete_handle(options) {
|
|
279
|
+
let nIDs;
|
|
280
|
+
nIDs = await this.IDs_getFromSearch(options);
|
|
281
|
+
if (!nIDs) {
|
|
282
|
+
console.error(`No ${this.assetName} matched the search criteria.`);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (nIDs) {
|
|
286
|
+
await this.resources_delete(nIDs, options.force);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Creates a standard list command with all base options.
|
|
291
|
+
* This method provides a consistent set of options across all resource types.
|
|
292
|
+
*
|
|
293
|
+
* @param actionHandler - The async function to execute when the command is invoked.
|
|
294
|
+
* @returns A configured Command object with standard list options.
|
|
295
|
+
*/
|
|
296
|
+
baseListCommand_create(actionHandler) {
|
|
297
|
+
return new Command("list")
|
|
298
|
+
.description(`list ${this.assetName}`)
|
|
299
|
+
.option("-p, --page <size>", "Page size (default 20)")
|
|
300
|
+
.option("-f, --fields <fields>", `comma-separated list of ${this.assetName} fields to display`)
|
|
301
|
+
.option("-s, --search <searchTerms>", `search for ${this.assetName} using comma-separated key-value pairs`)
|
|
302
|
+
.option("--sort <field>", "Sort by field (name, size, date, owner, etc.)")
|
|
303
|
+
.option("-r, --reverse", "Reverse sort order")
|
|
304
|
+
.option("--table", "Output in table format with headers")
|
|
305
|
+
.option("--csv", "Output in CSV format (overrides --table)")
|
|
306
|
+
.action(actionHandler);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Sets up the Commander.js commands for resource listing and deletion.
|
|
310
|
+
*
|
|
311
|
+
* @param program - The Commander.js program instance.
|
|
312
|
+
*/
|
|
313
|
+
command_setup(program) {
|
|
314
|
+
const command = program
|
|
315
|
+
.command(this.assetName)
|
|
316
|
+
.description(`Interact with a group of ChRIS ${this.assetName}`);
|
|
317
|
+
command.addCommand(this.baseListCommand_create(async (options) => {
|
|
318
|
+
await this.resources_list(options);
|
|
319
|
+
}));
|
|
320
|
+
command
|
|
321
|
+
.command("fieldslist")
|
|
322
|
+
.description(`list the ${this.assetName} resource fields`)
|
|
323
|
+
.action(async () => {
|
|
324
|
+
await this.resourceFields_list();
|
|
325
|
+
});
|
|
326
|
+
command
|
|
327
|
+
.command("delete <searchable>")
|
|
328
|
+
.description(`delete target ${this.assetName} resolved from '++' separated <searchable>, i.e. "id:77++id:33"`)
|
|
329
|
+
.option("-f, --force", `force the deletion without prompting for user confirmation`)
|
|
330
|
+
.action(async (searchable, options) => {
|
|
331
|
+
const searchParts = searchable.split("++").map((part) => part.trim());
|
|
332
|
+
// console.log(`searchParts = ${searchParts}`);
|
|
333
|
+
for (const searchPart of searchParts) {
|
|
334
|
+
const currentOptions = {
|
|
335
|
+
...options,
|
|
336
|
+
search: searchPart,
|
|
337
|
+
};
|
|
338
|
+
await this.delete_handle(currentOptions);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|