@burdenoff/bigconsole-cli 2026.802.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +9 -0
- package/README.md +235 -0
- package/dist/auth/device-code.d.ts +66 -0
- package/dist/auth/device-code.js +239 -0
- package/dist/auth/store.d.ts +46 -0
- package/dist/auth/store.js +90 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +126 -0
- package/dist/commands/auth.d.ts +5 -0
- package/dist/commands/auth.js +352 -0
- package/dist/commands/base.d.ts +47 -0
- package/dist/commands/base.js +100 -0
- package/dist/commands/cli-config.d.ts +6 -0
- package/dist/commands/cli-config.js +79 -0
- package/dist/commands/dashboard.d.ts +5 -0
- package/dist/commands/dashboard.js +220 -0
- package/dist/commands/datasink.d.ts +5 -0
- package/dist/commands/datasink.js +175 -0
- package/dist/commands/drilldown.d.ts +9 -0
- package/dist/commands/drilldown.js +47 -0
- package/dist/commands/index.d.ts +13 -0
- package/dist/commands/index.js +13 -0
- package/dist/commands/parser.d.ts +5 -0
- package/dist/commands/parser.js +181 -0
- package/dist/commands/pipeline.d.ts +5 -0
- package/dist/commands/pipeline.js +142 -0
- package/dist/commands/prompt.d.ts +5 -0
- package/dist/commands/prompt.js +84 -0
- package/dist/commands/share.d.ts +8 -0
- package/dist/commands/share.js +50 -0
- package/dist/commands/template.d.ts +5 -0
- package/dist/commands/template.js +62 -0
- package/dist/commands/widget.d.ts +5 -0
- package/dist/commands/widget.js +164 -0
- package/dist/commands/workflow.d.ts +9 -0
- package/dist/commands/workflow.js +54 -0
- package/dist/commands/workspace.d.ts +9 -0
- package/dist/commands/workspace.js +95 -0
- package/dist/config/index.d.ts +72 -0
- package/dist/config/index.js +151 -0
- package/dist/graphql/client.d.ts +26 -0
- package/dist/graphql/client.js +274 -0
- package/dist/graphql/operations.d.ts +48 -0
- package/dist/graphql/operations.js +654 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/types/index.d.ts +30 -0
- package/dist/types/index.js +7 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/output.d.ts +62 -0
- package/dist/utils/output.js +186 -0
- package/package.json +116 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cli-config commands — manage CLI-level endpoint + auth configuration.
|
|
3
|
+
* Separate from `config` (which will later manage platform-level BigConsole config).
|
|
4
|
+
*/
|
|
5
|
+
import { readConfig, writeConfig, getConfigPath, DEFAULT_CONFIG, KNOWN_CONFIG_KEYS, } from '../config/index.js';
|
|
6
|
+
import { printSuccess, printError, formatDate } from '../utils/output.js';
|
|
7
|
+
import { formatAndOutput, handleCommandError } from './base.js';
|
|
8
|
+
export function registerCLIConfigCommands(program) {
|
|
9
|
+
const cli = program.command('cli-config').description('CLI configuration (endpoints, client ID)');
|
|
10
|
+
cli
|
|
11
|
+
.command('show')
|
|
12
|
+
.description('Show current CLI configuration')
|
|
13
|
+
.option('-f, --format <format>', 'Output format (json, table, yaml)')
|
|
14
|
+
.action((options) => {
|
|
15
|
+
const config = readConfig();
|
|
16
|
+
formatAndOutput(options, config, {
|
|
17
|
+
headers: ['Key', 'Value'],
|
|
18
|
+
rows: Object.entries(config).map(([k, v]) => [k, v == null ? '-' : String(v)]),
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
cli
|
|
22
|
+
.command('path')
|
|
23
|
+
.description('Show CLI config file path')
|
|
24
|
+
.action(() => {
|
|
25
|
+
console.log(getConfigPath());
|
|
26
|
+
});
|
|
27
|
+
cli
|
|
28
|
+
.command('get <key>')
|
|
29
|
+
.description('Get a single config value')
|
|
30
|
+
.action((key) => {
|
|
31
|
+
try {
|
|
32
|
+
if (!KNOWN_CONFIG_KEYS.includes(key)) {
|
|
33
|
+
printError(`Unknown config key: ${key}. Known keys: ${KNOWN_CONFIG_KEYS.join(', ')}`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
const config = readConfig();
|
|
37
|
+
const value = config[key];
|
|
38
|
+
if (value === undefined || value === null) {
|
|
39
|
+
console.log('-');
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
console.log(String(value));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
handleCommandError(error);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
cli
|
|
50
|
+
.command('set <key> <value>')
|
|
51
|
+
.description('Set a config value')
|
|
52
|
+
.action((key, value) => {
|
|
53
|
+
try {
|
|
54
|
+
if (!KNOWN_CONFIG_KEYS.includes(key)) {
|
|
55
|
+
printError(`Unknown config key: ${key}. Known keys: ${KNOWN_CONFIG_KEYS.join(', ')}`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const config = readConfig();
|
|
59
|
+
config[key] = value;
|
|
60
|
+
writeConfig(config);
|
|
61
|
+
printSuccess(`Set ${key} = ${value} (last updated ${formatDate(new Date().toISOString())})`);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
handleCommandError(error);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
cli
|
|
68
|
+
.command('reset')
|
|
69
|
+
.description('Reset to default CLI configuration')
|
|
70
|
+
.action(() => {
|
|
71
|
+
try {
|
|
72
|
+
writeConfig({ ...DEFAULT_CONFIG });
|
|
73
|
+
printSuccess('CLI configuration reset to defaults');
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
handleCommandError(error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard commands — list, get, archive, delete.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
5
|
+
import * as ops from '../graphql/operations.js';
|
|
6
|
+
import { execWorkspace, formatAndOutput, handleCommandError, loadJsonInput } from './base.js';
|
|
7
|
+
import { printSuccess, printError, formatDate, formatStatus, truncate } from '../utils/output.js';
|
|
8
|
+
export function registerDashboardCommands(program) {
|
|
9
|
+
const dash = program.command('dashboard').description('Dashboard operations');
|
|
10
|
+
dash
|
|
11
|
+
.command('list')
|
|
12
|
+
.description('List dashboards in the current workspace')
|
|
13
|
+
.option('--search <term>', 'Search by name')
|
|
14
|
+
.option('--category <c>', 'Filter by category')
|
|
15
|
+
.option('--visibility <v>', 'PRIVATE | WORKSPACE | PUBLIC')
|
|
16
|
+
.option('--include-archived', 'Include archived dashboards')
|
|
17
|
+
.option('--first <n>', 'Page size', (v) => parseInt(v, 10), 25)
|
|
18
|
+
.option('--after <cursor>', 'Cursor for next page')
|
|
19
|
+
.option('-f, --format <format>', 'Output format')
|
|
20
|
+
.action(async (o) => {
|
|
21
|
+
try {
|
|
22
|
+
const d = await execWorkspace(ops.LIST_DASHBOARDS, {
|
|
23
|
+
first: o.first ?? 25,
|
|
24
|
+
after: o.after,
|
|
25
|
+
search: o.search,
|
|
26
|
+
category: o.category ? o.category.toUpperCase() : undefined,
|
|
27
|
+
visibility: o.visibility ? o.visibility.toUpperCase() : undefined,
|
|
28
|
+
includeArchived: o.includeArchived ?? false,
|
|
29
|
+
});
|
|
30
|
+
const items = d.listDashboards.edges.map((e) => e.node);
|
|
31
|
+
formatAndOutput(o, items, {
|
|
32
|
+
headers: ['ID', 'Name', 'Status', 'Visibility', 'Category', 'Updated'],
|
|
33
|
+
rows: items.map((x) => [
|
|
34
|
+
truncate(x.id, 14),
|
|
35
|
+
truncate(x.name, 30),
|
|
36
|
+
formatStatus(x.status),
|
|
37
|
+
x.visibility,
|
|
38
|
+
x.category,
|
|
39
|
+
formatDate(x.updatedAt),
|
|
40
|
+
]),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
handleCommandError(e);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
dash
|
|
48
|
+
.command('get')
|
|
49
|
+
.description('Get a dashboard by ID')
|
|
50
|
+
.argument('<id>')
|
|
51
|
+
.option('-f, --format <format>', 'Output format')
|
|
52
|
+
.action(async (id, o) => {
|
|
53
|
+
try {
|
|
54
|
+
const d = await execWorkspace(ops.GET_DASHBOARD, {
|
|
55
|
+
id,
|
|
56
|
+
});
|
|
57
|
+
if (!d.getDashboard) {
|
|
58
|
+
printError('Dashboard not found');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
formatAndOutput(o, d.getDashboard);
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
handleCommandError(e);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
dash
|
|
68
|
+
.command('archive')
|
|
69
|
+
.description('Archive a dashboard (soft-delete, can be restored)')
|
|
70
|
+
.argument('<id>')
|
|
71
|
+
.action(async (id) => {
|
|
72
|
+
try {
|
|
73
|
+
const d = await execWorkspace(ops.ARCHIVE_DASHBOARD, {
|
|
74
|
+
id,
|
|
75
|
+
});
|
|
76
|
+
printSuccess(`Archived: ${d.archiveDashboard.name} (${d.archiveDashboard.id})`);
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
handleCommandError(e);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
dash
|
|
83
|
+
.command('delete')
|
|
84
|
+
.description('Permanently delete a dashboard')
|
|
85
|
+
.argument('<id>')
|
|
86
|
+
.action(async (id) => {
|
|
87
|
+
try {
|
|
88
|
+
await execWorkspace(ops.DELETE_DASHBOARD, { id });
|
|
89
|
+
printSuccess(`Deleted dashboard ${id}`);
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
handleCommandError(e);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
dash
|
|
96
|
+
.command('create')
|
|
97
|
+
.description('Create a dashboard')
|
|
98
|
+
.requiredOption('--name <name>', 'Dashboard name')
|
|
99
|
+
.requiredOption('--category <cat>', 'Category (e.g. ANALYTICS, OPERATIONS)')
|
|
100
|
+
.option('--description <d>', 'Description')
|
|
101
|
+
.option('--visibility <v>', 'PRIVATE | WORKSPACE | PUBLIC', 'PRIVATE')
|
|
102
|
+
.option('--layout <l>', 'GRID | FREEFORM', 'GRID')
|
|
103
|
+
.option('--no-default-page', 'Skip creating the default page')
|
|
104
|
+
.option('--metadata-file <path>', 'JSON file with custom metadata')
|
|
105
|
+
.option('--metadata-json <json>', 'Inline JSON for custom metadata')
|
|
106
|
+
.option('-f, --format <format>', 'Output format')
|
|
107
|
+
.action(async (o) => {
|
|
108
|
+
try {
|
|
109
|
+
const metadata = loadJsonInput(o.metadataFile, o.metadataJson);
|
|
110
|
+
const input = {
|
|
111
|
+
name: o.name,
|
|
112
|
+
category: o.category.toUpperCase(),
|
|
113
|
+
description: o.description,
|
|
114
|
+
visibility: (o.visibility ?? 'PRIVATE').toUpperCase(),
|
|
115
|
+
layout: (o.layout ?? 'GRID').toUpperCase(),
|
|
116
|
+
createDefaultPage: o.defaultPage !== false,
|
|
117
|
+
metadata,
|
|
118
|
+
};
|
|
119
|
+
const d = await execWorkspace(ops.CREATE_DASHBOARD, { input });
|
|
120
|
+
printSuccess(`Created dashboard: ${d.createBigConsoleDashboard.name} (${d.createBigConsoleDashboard.id})`);
|
|
121
|
+
formatAndOutput(o, d.createBigConsoleDashboard);
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
handleCommandError(e);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
dash
|
|
128
|
+
.command('update')
|
|
129
|
+
.description('Update a dashboard')
|
|
130
|
+
.argument('<id>')
|
|
131
|
+
.option('--name <name>')
|
|
132
|
+
.option('--description <d>')
|
|
133
|
+
.option('--category <cat>')
|
|
134
|
+
.option('--visibility <v>', 'PRIVATE | WORKSPACE | PUBLIC')
|
|
135
|
+
.option('--layout <l>', 'GRID | FREEFORM')
|
|
136
|
+
.option('-f, --format <format>', 'Output format')
|
|
137
|
+
.action(async (id, o) => {
|
|
138
|
+
try {
|
|
139
|
+
const input = { id };
|
|
140
|
+
if (o.name)
|
|
141
|
+
input.name = o.name;
|
|
142
|
+
if (o.description !== undefined)
|
|
143
|
+
input.description = o.description;
|
|
144
|
+
if (o.category)
|
|
145
|
+
input.category = o.category.toUpperCase();
|
|
146
|
+
if (o.visibility)
|
|
147
|
+
input.visibility = o.visibility.toUpperCase();
|
|
148
|
+
if (o.layout)
|
|
149
|
+
input.layout = o.layout.toUpperCase();
|
|
150
|
+
const d = await execWorkspace(ops.UPDATE_DASHBOARD, { input });
|
|
151
|
+
printSuccess(`Updated dashboard ${id}`);
|
|
152
|
+
formatAndOutput(o, d.updateBigConsoleDashboard);
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
handleCommandError(e);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
dash
|
|
159
|
+
.command('import')
|
|
160
|
+
.description('Import a dashboard from a JSON file (dashboard definition)')
|
|
161
|
+
.requiredOption('--file <path>', 'Dashboard JSON file produced by `dashboard export`')
|
|
162
|
+
.option('--name <name>', 'Override dashboard name')
|
|
163
|
+
.option('--visibility <v>', 'Override visibility: PRIVATE | WORKSPACE | PUBLIC')
|
|
164
|
+
.option('--conflict <strategy>', 'Conflict resolution: RENAME | REPLACE | FAIL', 'RENAME')
|
|
165
|
+
.action(async (o) => {
|
|
166
|
+
try {
|
|
167
|
+
const json = readFileSync(o.file, 'utf8');
|
|
168
|
+
const input = {
|
|
169
|
+
json,
|
|
170
|
+
conflictResolution: (o.conflict ?? 'RENAME').toUpperCase(),
|
|
171
|
+
};
|
|
172
|
+
if (o.name)
|
|
173
|
+
input.name = o.name;
|
|
174
|
+
if (o.visibility)
|
|
175
|
+
input.visibility = o.visibility.toUpperCase();
|
|
176
|
+
const d = await execWorkspace(ops.IMPORT_DASHBOARD, {
|
|
177
|
+
input,
|
|
178
|
+
});
|
|
179
|
+
printSuccess(`Imported dashboard: ${d.importDashboard.name} (${d.importDashboard.id})`);
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
handleCommandError(e);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
dash
|
|
186
|
+
.command('export')
|
|
187
|
+
.description('Export a dashboard definition as JSON (stdout or --out file)')
|
|
188
|
+
.argument('<id>')
|
|
189
|
+
.option('--out <path>', 'Write JSON to file instead of stdout')
|
|
190
|
+
.option('--include-comments', 'Include dashboard comments')
|
|
191
|
+
.option('--include-data-refs', 'Include data source references', true)
|
|
192
|
+
.option('--include-webhook-mappings', 'Include webhook mappings')
|
|
193
|
+
.option('--pretty', 'Pretty-print JSON', true)
|
|
194
|
+
.action(async (id, o) => {
|
|
195
|
+
try {
|
|
196
|
+
const options = {
|
|
197
|
+
includeDataSourceRefs: o.includeDataRefs !== false,
|
|
198
|
+
includeWebhookMappings: o.includeWebhookMappings ?? false,
|
|
199
|
+
prettyPrint: o.pretty !== false,
|
|
200
|
+
};
|
|
201
|
+
const d = await execWorkspace(ops.EXPORT_DASHBOARD, {
|
|
202
|
+
id,
|
|
203
|
+
includeComments: o.includeComments ?? false,
|
|
204
|
+
options,
|
|
205
|
+
});
|
|
206
|
+
if (o.out) {
|
|
207
|
+
writeFileSync(o.out, d.exportDashboard, 'utf8');
|
|
208
|
+
printSuccess(`Exported to ${o.out}`);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
process.stdout.write(d.exportDashboard);
|
|
212
|
+
if (!d.exportDashboard.endsWith('\n'))
|
|
213
|
+
process.stdout.write('\n');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
handleCommandError(e);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* datasink commands — list, get (by id OR key), fetch data, delete.
|
|
3
|
+
*/
|
|
4
|
+
import * as ops from '../graphql/operations.js';
|
|
5
|
+
import { execWorkspace, formatAndOutput, handleCommandError, loadJsonInput } from './base.js';
|
|
6
|
+
import { printSuccess, printError, formatDate, formatStatus, truncate } from '../utils/output.js';
|
|
7
|
+
export function registerDataSinkCommands(program) {
|
|
8
|
+
const ds = program.command('datasink').description('DataSink operations');
|
|
9
|
+
ds.command('list')
|
|
10
|
+
.description('List DataSinks in the current workspace')
|
|
11
|
+
.option('--search <term>', 'Search by name')
|
|
12
|
+
.option('--status <s>', 'Filter by status')
|
|
13
|
+
.option('--setup-state <s>', 'Filter by setup state')
|
|
14
|
+
.option('--active <bool>', 'Filter by isActive (true/false)')
|
|
15
|
+
.option('--first <n>', 'Page size', (v) => parseInt(v, 10), 25)
|
|
16
|
+
.option('--after <cursor>', 'Cursor for next page')
|
|
17
|
+
.option('-f, --format <format>', 'Output format')
|
|
18
|
+
.action(async (o) => {
|
|
19
|
+
try {
|
|
20
|
+
const d = await execWorkspace(ops.LIST_DATASINKS, {
|
|
21
|
+
first: o.first ?? 25,
|
|
22
|
+
after: o.after,
|
|
23
|
+
search: o.search,
|
|
24
|
+
status: o.status ? o.status.toUpperCase() : undefined,
|
|
25
|
+
setupState: o.setupState ? o.setupState.toUpperCase() : undefined,
|
|
26
|
+
isActive: o.active === undefined
|
|
27
|
+
? undefined
|
|
28
|
+
: o.active.toLowerCase() === 'true' || o.active === '1',
|
|
29
|
+
});
|
|
30
|
+
const items = d.listDataSinks.edges.map((e) => e.node);
|
|
31
|
+
formatAndOutput(o, items, {
|
|
32
|
+
headers: ['ID', 'Name', 'Key', 'Status', 'Setup', 'Active', 'Updated'],
|
|
33
|
+
rows: items.map((x) => [
|
|
34
|
+
truncate(x.id, 14),
|
|
35
|
+
truncate(x.name ?? '-', 24),
|
|
36
|
+
truncate(x.key, 20),
|
|
37
|
+
formatStatus(x.status),
|
|
38
|
+
x.setupState,
|
|
39
|
+
x.isActive ? 'yes' : 'no',
|
|
40
|
+
formatDate(x.updatedAt),
|
|
41
|
+
]),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
handleCommandError(e);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
ds.command('get')
|
|
49
|
+
.description('Get a DataSink by ID or key')
|
|
50
|
+
.option('--id <id>', 'DataSink ID')
|
|
51
|
+
.option('--key <key>', 'DataSink key')
|
|
52
|
+
.option('-f, --format <format>', 'Output format')
|
|
53
|
+
.action(async (o) => {
|
|
54
|
+
try {
|
|
55
|
+
if (!o.id && !o.key) {
|
|
56
|
+
printError('Provide --id or --key');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
const d = await execWorkspace(ops.GET_DATASINK, {
|
|
60
|
+
id: o.id,
|
|
61
|
+
key: o.key,
|
|
62
|
+
});
|
|
63
|
+
if (!d.getDataSink) {
|
|
64
|
+
printError('DataSink not found');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
formatAndOutput(o, d.getDataSink);
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
handleCommandError(e);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
ds.command('data')
|
|
74
|
+
.description('Fetch the current data payload of a DataSink')
|
|
75
|
+
.option('--id <id>', 'DataSink ID')
|
|
76
|
+
.option('--key <key>', 'DataSink key')
|
|
77
|
+
.option('--path <p>', 'JSONPath-like filter (e.g. items[0].value)')
|
|
78
|
+
.option('--force-refresh', 'Bypass cache')
|
|
79
|
+
.option('-f, --format <format>', 'Output format (json recommended)')
|
|
80
|
+
.action(async (o) => {
|
|
81
|
+
try {
|
|
82
|
+
if (!o.id && !o.key) {
|
|
83
|
+
printError('Provide --id or --key');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
const d = await execWorkspace(ops.GET_DATASINK_DATA, {
|
|
87
|
+
id: o.id,
|
|
88
|
+
key: o.key,
|
|
89
|
+
dataPath: o.path,
|
|
90
|
+
forceRefresh: o.forceRefresh ?? false,
|
|
91
|
+
});
|
|
92
|
+
formatAndOutput({ format: o.format ?? 'json' }, d.getDataSinkData);
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
handleCommandError(e);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
ds.command('delete')
|
|
99
|
+
.description('Delete a DataSink')
|
|
100
|
+
.argument('<id>')
|
|
101
|
+
.action(async (id) => {
|
|
102
|
+
try {
|
|
103
|
+
await execWorkspace(ops.DELETE_DATASINK, { id });
|
|
104
|
+
printSuccess(`Deleted DataSink ${id}`);
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
handleCommandError(e);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
ds.command('create')
|
|
111
|
+
.description('Create a DataSink')
|
|
112
|
+
.requiredOption('--key <key>', 'Unique key within workspace (e.g. sales_metrics_q4)')
|
|
113
|
+
.option('--name <name>', 'Display name')
|
|
114
|
+
.option('--description <d>', 'Description')
|
|
115
|
+
.option('--data-file <path>', 'JSON file with initial payload')
|
|
116
|
+
.option('--data-json <json>', 'Inline JSON for initial payload')
|
|
117
|
+
.option('--config-file <path>', 'JSON file with DataSink config')
|
|
118
|
+
.option('--config-json <json>', 'Inline JSON for DataSink config')
|
|
119
|
+
.option('-f, --format <format>', 'Output format')
|
|
120
|
+
.action(async (o) => {
|
|
121
|
+
try {
|
|
122
|
+
const data = loadJsonInput(o.dataFile, o.dataJson);
|
|
123
|
+
const config = loadJsonInput(o.configFile, o.configJson);
|
|
124
|
+
const input = { key: o.key };
|
|
125
|
+
if (o.name)
|
|
126
|
+
input.name = o.name;
|
|
127
|
+
if (o.description)
|
|
128
|
+
input.description = o.description;
|
|
129
|
+
if (data !== undefined)
|
|
130
|
+
input.data = data;
|
|
131
|
+
if (config !== undefined)
|
|
132
|
+
input.config = config;
|
|
133
|
+
const d = await execWorkspace(ops.CREATE_DATASINK, {
|
|
134
|
+
input,
|
|
135
|
+
});
|
|
136
|
+
printSuccess(`Created DataSink: ${d.createDataSink.key} (${d.createDataSink.id})`);
|
|
137
|
+
formatAndOutput(o, d.createDataSink);
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
handleCommandError(e);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
ds.command('update')
|
|
144
|
+
.description('Update a DataSink')
|
|
145
|
+
.argument('<id>')
|
|
146
|
+
.option('--name <name>')
|
|
147
|
+
.option('--description <d>')
|
|
148
|
+
.option('--active <bool>', 'true / false')
|
|
149
|
+
.option('--data-file <path>', 'JSON file to replace data payload')
|
|
150
|
+
.option('--data-json <json>', 'Inline JSON to replace data payload')
|
|
151
|
+
.option('-f, --format <format>', 'Output format')
|
|
152
|
+
.action(async (id, o) => {
|
|
153
|
+
try {
|
|
154
|
+
const data = loadJsonInput(o.dataFile, o.dataJson);
|
|
155
|
+
const input = { id };
|
|
156
|
+
if (o.name)
|
|
157
|
+
input.name = o.name;
|
|
158
|
+
if (o.description !== undefined)
|
|
159
|
+
input.description = o.description;
|
|
160
|
+
if (o.active !== undefined) {
|
|
161
|
+
input.isActive = o.active.toLowerCase() === 'true' || o.active === '1';
|
|
162
|
+
}
|
|
163
|
+
if (data !== undefined)
|
|
164
|
+
input.data = data;
|
|
165
|
+
const d = await execWorkspace(ops.UPDATE_DATASINK, {
|
|
166
|
+
input,
|
|
167
|
+
});
|
|
168
|
+
printSuccess(`Updated DataSink ${id}`);
|
|
169
|
+
formatAndOutput(o, d.updateDataSink);
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
handleCommandError(e);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drilldown commands — list actions on a widget, delete drilldown config.
|
|
3
|
+
*
|
|
4
|
+
* Drilldown creation is JSON-heavy (parameter mappings, target routes,
|
|
5
|
+
* modal/push/replace navigation). It's deferred to a future pass where we
|
|
6
|
+
* can offer a generator-style UX rather than a flag firehose.
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
export declare function registerDrilldownCommands(program: Command): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drilldown commands — list actions on a widget, delete drilldown config.
|
|
3
|
+
*
|
|
4
|
+
* Drilldown creation is JSON-heavy (parameter mappings, target routes,
|
|
5
|
+
* modal/push/replace navigation). It's deferred to a future pass where we
|
|
6
|
+
* can offer a generator-style UX rather than a flag firehose.
|
|
7
|
+
*/
|
|
8
|
+
import * as ops from '../graphql/operations.js';
|
|
9
|
+
import { execWorkspace, formatAndOutput, handleCommandError } from './base.js';
|
|
10
|
+
import { printSuccess, formatDate, truncate } from '../utils/output.js';
|
|
11
|
+
export function registerDrilldownCommands(program) {
|
|
12
|
+
const dd = program.command('drilldown').description('Widget drilldown actions');
|
|
13
|
+
dd.command('list')
|
|
14
|
+
.description('List widget actions (includes drilldowns)')
|
|
15
|
+
.requiredOption('--widget <id>', 'Widget ID')
|
|
16
|
+
.option('-f, --format <format>', 'Output format')
|
|
17
|
+
.action(async (o) => {
|
|
18
|
+
try {
|
|
19
|
+
const d = await execWorkspace(ops.GET_WIDGET_ACTIONS, { widgetId: o.widget });
|
|
20
|
+
formatAndOutput(o, d.getWidgetActions, {
|
|
21
|
+
headers: ['ID', 'Widget', 'Type', 'Label', 'Created'],
|
|
22
|
+
rows: d.getWidgetActions.map((a) => [
|
|
23
|
+
truncate(a.id, 14),
|
|
24
|
+
truncate(a.widgetId, 14),
|
|
25
|
+
a.type,
|
|
26
|
+
truncate(a.label ?? '-', 24),
|
|
27
|
+
formatDate(a.createdAt),
|
|
28
|
+
]),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
handleCommandError(e);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
dd.command('delete')
|
|
36
|
+
.description('Delete the drilldown configuration from a widget')
|
|
37
|
+
.requiredOption('--widget <id>', 'Widget ID')
|
|
38
|
+
.action(async (o) => {
|
|
39
|
+
try {
|
|
40
|
+
await execWorkspace(ops.DELETE_WIDGET_DRILLDOWN, { widgetId: o.widget });
|
|
41
|
+
printSuccess(`Removed drilldown from widget ${o.widget}`);
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
handleCommandError(e);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { registerAuthCommands } from './auth.js';
|
|
2
|
+
export { registerCLIConfigCommands } from './cli-config.js';
|
|
3
|
+
export { registerWorkspaceCommands } from './workspace.js';
|
|
4
|
+
export { registerDashboardCommands } from './dashboard.js';
|
|
5
|
+
export { registerWidgetCommands } from './widget.js';
|
|
6
|
+
export { registerDataSinkCommands } from './datasink.js';
|
|
7
|
+
export { registerParserCommands } from './parser.js';
|
|
8
|
+
export { registerPipelineCommands } from './pipeline.js';
|
|
9
|
+
export { registerWorkflowCommands } from './workflow.js';
|
|
10
|
+
export { registerDrilldownCommands } from './drilldown.js';
|
|
11
|
+
export { registerShareCommands } from './share.js';
|
|
12
|
+
export { registerTemplateCommands } from './template.js';
|
|
13
|
+
export { registerPromptCommands } from './prompt.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { registerAuthCommands } from './auth.js';
|
|
2
|
+
export { registerCLIConfigCommands } from './cli-config.js';
|
|
3
|
+
export { registerWorkspaceCommands } from './workspace.js';
|
|
4
|
+
export { registerDashboardCommands } from './dashboard.js';
|
|
5
|
+
export { registerWidgetCommands } from './widget.js';
|
|
6
|
+
export { registerDataSinkCommands } from './datasink.js';
|
|
7
|
+
export { registerParserCommands } from './parser.js';
|
|
8
|
+
export { registerPipelineCommands } from './pipeline.js';
|
|
9
|
+
export { registerWorkflowCommands } from './workflow.js';
|
|
10
|
+
export { registerDrilldownCommands } from './drilldown.js';
|
|
11
|
+
export { registerShareCommands } from './share.js';
|
|
12
|
+
export { registerTemplateCommands } from './template.js';
|
|
13
|
+
export { registerPromptCommands } from './prompt.js';
|