@uipath/data-fabric-tool 1.195.0 → 1.197.0-preview.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2 -0
- package/dist/tool.js +6037 -6015
- package/package.json +2 -2
- package/src/commands/choice-sets.spec.ts +262 -13
- package/src/commands/choice-sets.ts +126 -8
- package/src/commands/entities.spec.ts +302 -14
- package/src/commands/entities.ts +111 -9
- package/src/commands/files.spec.ts +108 -3
- package/src/commands/files.ts +45 -2
- package/src/commands/records.spec.ts +323 -0
- package/src/commands/records.ts +120 -18
- package/src/utils/input.spec.ts +127 -0
- package/src/utils/input.ts +30 -1
- package/src/utils/output.spec.ts +22 -9
- package/src/utils/output.ts +27 -9
|
@@ -109,6 +109,7 @@ describe("files upload", () => {
|
|
|
109
109
|
"record-1",
|
|
110
110
|
"attachment",
|
|
111
111
|
expect.any(File),
|
|
112
|
+
undefined,
|
|
112
113
|
);
|
|
113
114
|
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
114
115
|
expect.objectContaining({
|
|
@@ -132,6 +133,7 @@ describe("files upload", () => {
|
|
|
132
133
|
"record-1",
|
|
133
134
|
"attachment",
|
|
134
135
|
expect.objectContaining({ name: "upload" }),
|
|
136
|
+
undefined,
|
|
135
137
|
);
|
|
136
138
|
});
|
|
137
139
|
|
|
@@ -237,22 +239,63 @@ describe("files delete", () => {
|
|
|
237
239
|
it("should delete and return FileDeleted on success", async () => {
|
|
238
240
|
const sdk = mockSdk();
|
|
239
241
|
const program = buildProgram();
|
|
240
|
-
await runCommand(
|
|
242
|
+
await runCommand(
|
|
243
|
+
program,
|
|
244
|
+
"files delete entity-1 record-1 attachment --yes --reason cleanup",
|
|
245
|
+
);
|
|
246
|
+
expect(sdk.entities.deleteAttachment).toHaveBeenCalledWith(
|
|
247
|
+
"entity-1",
|
|
248
|
+
"record-1",
|
|
249
|
+
"attachment",
|
|
250
|
+
undefined,
|
|
251
|
+
);
|
|
252
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
253
|
+
expect.objectContaining({
|
|
254
|
+
Result: "Success",
|
|
255
|
+
Code: "FileDeleted",
|
|
256
|
+
Data: expect.objectContaining({ Reason: "cleanup" }),
|
|
257
|
+
}),
|
|
258
|
+
);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("should accept --confirm as a deprecated alias for --yes", async () => {
|
|
262
|
+
const sdk = mockSdk();
|
|
263
|
+
const program = buildProgram();
|
|
264
|
+
await runCommand(
|
|
265
|
+
program,
|
|
266
|
+
"files delete entity-1 record-1 attachment --confirm --reason cleanup",
|
|
267
|
+
);
|
|
241
268
|
expect(sdk.entities.deleteAttachment).toHaveBeenCalledWith(
|
|
242
269
|
"entity-1",
|
|
243
270
|
"record-1",
|
|
244
271
|
"attachment",
|
|
272
|
+
undefined,
|
|
245
273
|
);
|
|
246
274
|
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
247
275
|
expect.objectContaining({ Result: "Success", Code: "FileDeleted" }),
|
|
248
276
|
);
|
|
249
277
|
});
|
|
250
278
|
|
|
279
|
+
it("should require confirmation: without --yes, exit 1 and SDK not called", async () => {
|
|
280
|
+
const sdk = mockSdk();
|
|
281
|
+
const program = buildProgram();
|
|
282
|
+
await runCommand(
|
|
283
|
+
program,
|
|
284
|
+
"files delete entity-1 record-1 attachment --reason cleanup",
|
|
285
|
+
);
|
|
286
|
+
expect(sdk.entities.deleteAttachment).not.toHaveBeenCalled();
|
|
287
|
+
expect(OutputFormatter.success).not.toHaveBeenCalled();
|
|
288
|
+
expect(process.exitCode).toBe(1);
|
|
289
|
+
});
|
|
290
|
+
|
|
251
291
|
it("should error when delete API fails", async () => {
|
|
252
292
|
const sdk = mockSdk();
|
|
253
293
|
sdk.entities.deleteAttachment.mockRejectedValue(new Error("Forbidden"));
|
|
254
294
|
const program = buildProgram();
|
|
255
|
-
await runCommand(
|
|
295
|
+
await runCommand(
|
|
296
|
+
program,
|
|
297
|
+
"files delete entity-1 record-1 attachment --yes --reason cleanup",
|
|
298
|
+
);
|
|
256
299
|
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
257
300
|
expect.objectContaining({
|
|
258
301
|
Result: "Failure",
|
|
@@ -265,7 +308,10 @@ describe("files delete", () => {
|
|
|
265
308
|
const sdk = mockSdk();
|
|
266
309
|
vi.mocked(connectOrFail).mockResolvedValue(undefined);
|
|
267
310
|
const program = buildProgram();
|
|
268
|
-
await runCommand(
|
|
311
|
+
await runCommand(
|
|
312
|
+
program,
|
|
313
|
+
"files delete entity-1 record-1 attachment --yes --reason cleanup",
|
|
314
|
+
);
|
|
269
315
|
expect(sdk.entities.deleteAttachment).not.toHaveBeenCalled();
|
|
270
316
|
expect(OutputFormatter.success).not.toHaveBeenCalled();
|
|
271
317
|
});
|
|
@@ -328,3 +374,62 @@ describe("files download edge cases", () => {
|
|
|
328
374
|
);
|
|
329
375
|
});
|
|
330
376
|
});
|
|
377
|
+
|
|
378
|
+
describe("files --folder-key forwarding", () => {
|
|
379
|
+
beforeEach(() => {
|
|
380
|
+
vi.clearAllMocks();
|
|
381
|
+
vi.mocked(OutputFormatter.success).mockReset();
|
|
382
|
+
vi.mocked(OutputFormatter.error).mockReset();
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it("should forward --folder-key to uploadAttachment", async () => {
|
|
386
|
+
const sdk = mockSdk();
|
|
387
|
+
mockFs.readFile.mockResolvedValue(new Uint8Array([1, 2, 3]));
|
|
388
|
+
const program = buildProgram();
|
|
389
|
+
await runCommand(
|
|
390
|
+
program,
|
|
391
|
+
"files upload entity-1 record-1 attachment --file /tmp/report.pdf --folder-key folder-guid-1",
|
|
392
|
+
);
|
|
393
|
+
expect(sdk.entities.uploadAttachment).toHaveBeenCalledWith(
|
|
394
|
+
"entity-1",
|
|
395
|
+
"record-1",
|
|
396
|
+
"attachment",
|
|
397
|
+
expect.any(File),
|
|
398
|
+
{ folderKey: "folder-guid-1" },
|
|
399
|
+
);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it("should forward --folder-key to downloadAttachment", async () => {
|
|
403
|
+
const blob = new Blob(["data"]);
|
|
404
|
+
const sdk = mockSdk({
|
|
405
|
+
downloadAttachment: vi.fn().mockResolvedValue(blob),
|
|
406
|
+
});
|
|
407
|
+
mockFs.writeFile.mockResolvedValue(undefined);
|
|
408
|
+
const program = buildProgram();
|
|
409
|
+
await runCommand(
|
|
410
|
+
program,
|
|
411
|
+
"files download entity-1 record-1 attachment --folder-key folder-guid-2",
|
|
412
|
+
);
|
|
413
|
+
expect(sdk.entities.downloadAttachment).toHaveBeenCalledWith(
|
|
414
|
+
"entity-1",
|
|
415
|
+
"record-1",
|
|
416
|
+
"attachment",
|
|
417
|
+
{ folderKey: "folder-guid-2" },
|
|
418
|
+
);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it("should forward --folder-key to deleteAttachment", async () => {
|
|
422
|
+
const sdk = mockSdk();
|
|
423
|
+
const program = buildProgram();
|
|
424
|
+
await runCommand(
|
|
425
|
+
program,
|
|
426
|
+
"files delete entity-1 record-1 attachment --yes --reason cleanup --folder-key folder-guid-3",
|
|
427
|
+
);
|
|
428
|
+
expect(sdk.entities.deleteAttachment).toHaveBeenCalledWith(
|
|
429
|
+
"entity-1",
|
|
430
|
+
"record-1",
|
|
431
|
+
"attachment",
|
|
432
|
+
{ folderKey: "folder-guid-3" },
|
|
433
|
+
);
|
|
434
|
+
});
|
|
435
|
+
});
|
package/src/commands/files.ts
CHANGED
|
@@ -8,23 +8,29 @@ import {
|
|
|
8
8
|
RESULTS,
|
|
9
9
|
} from "@uipath/common";
|
|
10
10
|
import { getFileSystem } from "@uipath/filesystem";
|
|
11
|
-
import type
|
|
11
|
+
import { type Command, Option } from "commander";
|
|
12
12
|
import { readFileBinary } from "../utils/input";
|
|
13
|
-
import { fail } from "../utils/output";
|
|
13
|
+
import { fail, requireDestructiveConfirmation } from "../utils/output";
|
|
14
14
|
import { connectOrFail } from "../utils/sdk-client";
|
|
15
15
|
|
|
16
16
|
interface UploadOptions {
|
|
17
17
|
tenant?: string;
|
|
18
18
|
file?: string;
|
|
19
|
+
folderKey?: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
interface DownloadOptions {
|
|
22
23
|
tenant?: string;
|
|
23
24
|
destination?: string;
|
|
25
|
+
folderKey?: string;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
interface DeleteOptions {
|
|
27
29
|
tenant?: string;
|
|
30
|
+
yes?: boolean;
|
|
31
|
+
confirm?: boolean;
|
|
32
|
+
reason?: string;
|
|
33
|
+
folderKey?: string;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
const FILES_UPLOAD_EXAMPLES: CommandExample[] = [
|
|
@@ -92,6 +98,10 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
92
98
|
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
93
99
|
)
|
|
94
100
|
.option("-f, --file <path>", "Path to the file to upload")
|
|
101
|
+
.option(
|
|
102
|
+
"--folder-key <key>",
|
|
103
|
+
"Folder key (GUID) of the folder containing the entity (for folder-scoped entities)",
|
|
104
|
+
)
|
|
95
105
|
.examples(FILES_UPLOAD_EXAMPLES)
|
|
96
106
|
.trackedAction(
|
|
97
107
|
processContext,
|
|
@@ -131,6 +141,9 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
131
141
|
[fileContent as Uint8Array<ArrayBuffer>],
|
|
132
142
|
fileName,
|
|
133
143
|
),
|
|
144
|
+
options.folderKey !== undefined
|
|
145
|
+
? { folderKey: options.folderKey }
|
|
146
|
+
: undefined,
|
|
134
147
|
),
|
|
135
148
|
);
|
|
136
149
|
|
|
@@ -167,6 +180,10 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
167
180
|
"--destination <path>",
|
|
168
181
|
"Output file path (defaults to <record-id>_<field-name>.bin)",
|
|
169
182
|
)
|
|
183
|
+
.option(
|
|
184
|
+
"--folder-key <key>",
|
|
185
|
+
"Folder key (GUID) of the folder containing the entity (for folder-scoped entities)",
|
|
186
|
+
)
|
|
170
187
|
.examples(FILES_DOWNLOAD_EXAMPLES)
|
|
171
188
|
.trackedAction(
|
|
172
189
|
processContext,
|
|
@@ -184,6 +201,9 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
184
201
|
entityId,
|
|
185
202
|
recordId,
|
|
186
203
|
fieldName,
|
|
204
|
+
options.folderKey !== undefined
|
|
205
|
+
? { folderKey: options.folderKey }
|
|
206
|
+
: undefined,
|
|
187
207
|
),
|
|
188
208
|
);
|
|
189
209
|
|
|
@@ -241,6 +261,18 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
241
261
|
.addOption(
|
|
242
262
|
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
243
263
|
)
|
|
264
|
+
.option("-y, --yes", "Acknowledge this is an irreversible operation")
|
|
265
|
+
.addOption(
|
|
266
|
+
new Option("--confirm", "Deprecated alias for --yes").hideHelp(),
|
|
267
|
+
)
|
|
268
|
+
.option(
|
|
269
|
+
"--reason <reason>",
|
|
270
|
+
"Reason for the deletion — echoed back in the response so the caller can log it",
|
|
271
|
+
)
|
|
272
|
+
.option(
|
|
273
|
+
"--folder-key <key>",
|
|
274
|
+
"Folder key (GUID) of the folder containing the entity (for folder-scoped entities)",
|
|
275
|
+
)
|
|
244
276
|
.examples(FILES_DELETE_EXAMPLES)
|
|
245
277
|
.trackedAction(
|
|
246
278
|
processContext,
|
|
@@ -250,6 +282,13 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
250
282
|
fieldName: string,
|
|
251
283
|
options: DeleteOptions,
|
|
252
284
|
) => {
|
|
285
|
+
const reason = requireDestructiveConfirmation(
|
|
286
|
+
options,
|
|
287
|
+
`delete the file in field '${fieldName}'`,
|
|
288
|
+
'Pass --reason "<text>" to record why the file is being deleted.',
|
|
289
|
+
);
|
|
290
|
+
if (reason === null) return;
|
|
291
|
+
|
|
253
292
|
const sdk = await connectOrFail(options.tenant);
|
|
254
293
|
if (!sdk) return;
|
|
255
294
|
|
|
@@ -258,6 +297,9 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
258
297
|
entityId,
|
|
259
298
|
recordId,
|
|
260
299
|
fieldName,
|
|
300
|
+
options.folderKey !== undefined
|
|
301
|
+
? { folderKey: options.folderKey }
|
|
302
|
+
: undefined,
|
|
261
303
|
),
|
|
262
304
|
);
|
|
263
305
|
|
|
@@ -275,6 +317,7 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
275
317
|
EntityId: entityId,
|
|
276
318
|
RecordId: recordId,
|
|
277
319
|
FieldName: fieldName,
|
|
320
|
+
Reason: reason,
|
|
278
321
|
},
|
|
279
322
|
});
|
|
280
323
|
},
|