fix(cli): batch record delete sends recordIds as query params
The API controller reads recordIds from @Query(), not @Body.
CLI was sending { records: ids } as JSON body, causing:
'expected array, received undefined at "recordIds"'
Fixed: rename deleteRecord→deleteRecords, send recordIds as
repeated query params (?recordIds=rec1&recordIds=rec2).
This commit is contained in:
@@ -115,7 +115,10 @@ function tableCmd(): Command {
|
|||||||
.description('Create a new table')
|
.description('Create a new table')
|
||||||
.requiredOption('--name <name>', 'Table name')
|
.requiredOption('--name <name>', 'Table name')
|
||||||
.option('--base-id <id>', 'Base id (overrides default)')
|
.option('--base-id <id>', 'Base id (overrides default)')
|
||||||
.option('--fields <json>', 'Field definitions JSON array, e.g. \'[{"name":"Title","type":"singleLineText"}]\'')
|
.option(
|
||||||
|
'--fields <json>',
|
||||||
|
'Field definitions JSON array, e.g. \'[{"name":"Title","type":"singleLineText"}]\''
|
||||||
|
)
|
||||||
.action(
|
.action(
|
||||||
run(async (ctx, _args, o) => {
|
run(async (ctx, _args, o) => {
|
||||||
const opts = o as { name: string; baseId?: string; fields?: string };
|
const opts = o as { name: string; baseId?: string; fields?: string };
|
||||||
@@ -126,7 +129,10 @@ function tableCmd(): Command {
|
|||||||
if (ctx.json) printJson(table);
|
if (ctx.json) printJson(table);
|
||||||
else {
|
else {
|
||||||
const t = table as Record<string, unknown>;
|
const t = table as Record<string, unknown>;
|
||||||
printKv([['id', t.id], ['name', t.name]]);
|
printKv([
|
||||||
|
['id', t.id],
|
||||||
|
['name', t.name],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -215,7 +221,10 @@ function fieldCmd(): Command {
|
|||||||
.description('Create a new field')
|
.description('Create a new field')
|
||||||
.requiredOption('--table-id <id>', 'Table id')
|
.requiredOption('--table-id <id>', 'Table id')
|
||||||
.requiredOption('--name <name>', 'Field name')
|
.requiredOption('--name <name>', 'Field name')
|
||||||
.requiredOption('--type <type>', 'Field type (singleLineText, number, singleSelect, link, formula, etc.)')
|
.requiredOption(
|
||||||
|
'--type <type>',
|
||||||
|
'Field type (singleLineText, number, singleSelect, link, formula, etc.)'
|
||||||
|
)
|
||||||
.option('--options <json>', 'Field options JSON (type-specific)')
|
.option('--options <json>', 'Field options JSON (type-specific)')
|
||||||
.action(
|
.action(
|
||||||
run(async (ctx, _args, o) => {
|
run(async (ctx, _args, o) => {
|
||||||
@@ -226,7 +235,11 @@ function fieldCmd(): Command {
|
|||||||
if (ctx.json) printJson(field);
|
if (ctx.json) printJson(field);
|
||||||
else {
|
else {
|
||||||
const f = field as Record<string, unknown>;
|
const f = field as Record<string, unknown>;
|
||||||
printKv([['id', f.id], ['name', f.name], ['type', f.type]]);
|
printKv([
|
||||||
|
['id', f.id],
|
||||||
|
['name', f.name],
|
||||||
|
['type', f.type],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -391,7 +404,10 @@ function recordCmd(): Command {
|
|||||||
.command('update')
|
.command('update')
|
||||||
.description('Batch update records')
|
.description('Batch update records')
|
||||||
.requiredOption('--table-id <id>', 'Table id')
|
.requiredOption('--table-id <id>', 'Table id')
|
||||||
.requiredOption('--records <json>', 'Records JSON, e.g. \'[{"id":"recX","fields":{"Title":"b"}}]\'')
|
.requiredOption(
|
||||||
|
'--records <json>',
|
||||||
|
'Records JSON, e.g. \'[{"id":"recX","fields":{"Title":"b"}}]\''
|
||||||
|
)
|
||||||
.action(
|
.action(
|
||||||
run(async (ctx, _args, o) => {
|
run(async (ctx, _args, o) => {
|
||||||
const opts = o as { tableId: string; records: string };
|
const opts = o as { tableId: string; records: string };
|
||||||
@@ -414,8 +430,7 @@ function recordCmd(): Command {
|
|||||||
.split(',')
|
.split(',')
|
||||||
.map((s) => s.trim())
|
.map((s) => s.trim())
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
const body = { records: ids };
|
const result = await ctx.client.deleteRecords(opts.tableId, ids);
|
||||||
const result = await ctx.client.deleteRecord(opts.tableId, body);
|
|
||||||
if (ctx.json) printJson(result);
|
if (ctx.json) printJson(result);
|
||||||
else process.stdout.write(`✓ ${ids.length} record(s) deleted\n`);
|
else process.stdout.write(`✓ ${ids.length} record(s) deleted\n`);
|
||||||
})
|
})
|
||||||
@@ -488,7 +503,11 @@ function viewCmd(): Command {
|
|||||||
if (ctx.json) printJson(view);
|
if (ctx.json) printJson(view);
|
||||||
else {
|
else {
|
||||||
const v = view as Record<string, unknown>;
|
const v = view as Record<string, unknown>;
|
||||||
printKv([['id', v.id], ['name', v.name], ['type', v.type]]);
|
printKv([
|
||||||
|
['id', v.id],
|
||||||
|
['name', v.name],
|
||||||
|
['type', v.type],
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
+63
-16
@@ -124,8 +124,9 @@ export class Client {
|
|||||||
updateRecordOne(recordId: string, body: unknown) {
|
updateRecordOne(recordId: string, body: unknown) {
|
||||||
return this.call<unknown>('PATCH', `/api/record/${recordId}`, body);
|
return this.call<unknown>('PATCH', `/api/record/${recordId}`, body);
|
||||||
}
|
}
|
||||||
deleteRecord(tableId: string, body: unknown) {
|
deleteRecords(tableId: string, recordIds: string[]) {
|
||||||
return this.call<unknown>('DELETE', `/api/table/${tableId}/record`, body);
|
const qs = recordIds.map((id) => `recordIds=${encodeURIComponent(id)}`).join('&');
|
||||||
|
return this.call<unknown>('DELETE', `/api/table/${tableId}/record?${qs}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- view ----
|
// ---- view ----
|
||||||
@@ -163,23 +164,37 @@ export class Client {
|
|||||||
createWorkflow(baseId: string, body: { name: string; description?: string }) {
|
createWorkflow(baseId: string, body: { name: string; description?: string }) {
|
||||||
return this.call<IWorkflowVo>('POST', `/api/base/${baseId}/workflow`, body);
|
return this.call<IWorkflowVo>('POST', `/api/base/${baseId}/workflow`, body);
|
||||||
}
|
}
|
||||||
updateWorkflow(baseId: string, workflowId: string, body: { name?: string; description?: string }) {
|
updateWorkflow(
|
||||||
|
baseId: string,
|
||||||
|
workflowId: string,
|
||||||
|
body: { name?: string; description?: string }
|
||||||
|
) {
|
||||||
return this.call<IWorkflowVo>('PATCH', `/api/base/${baseId}/workflow/${workflowId}`, body);
|
return this.call<IWorkflowVo>('PATCH', `/api/base/${baseId}/workflow/${workflowId}`, body);
|
||||||
}
|
}
|
||||||
deleteWorkflow(baseId: string, workflowId: string) {
|
deleteWorkflow(baseId: string, workflowId: string) {
|
||||||
return this.call<unknown>('DELETE', `/api/base/${baseId}/workflow/${workflowId}`);
|
return this.call<unknown>('DELETE', `/api/base/${baseId}/workflow/${workflowId}`);
|
||||||
}
|
}
|
||||||
activateWorkflow(baseId: string, workflowId: string) {
|
activateWorkflow(baseId: string, workflowId: string) {
|
||||||
return this.call<{ snapshotId: string }>('POST', `/api/base/${baseId}/workflow/${workflowId}/activate`);
|
return this.call<{ snapshotId: string }>(
|
||||||
|
'POST',
|
||||||
|
`/api/base/${baseId}/workflow/${workflowId}/activate`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
deactivateWorkflow(baseId: string, workflowId: string) {
|
deactivateWorkflow(baseId: string, workflowId: string) {
|
||||||
return this.call<unknown>('POST', `/api/base/${baseId}/workflow/${workflowId}/deactivate`);
|
return this.call<unknown>('POST', `/api/base/${baseId}/workflow/${workflowId}/deactivate`);
|
||||||
}
|
}
|
||||||
testWorkflow(baseId: string, workflowId: string) {
|
testWorkflow(baseId: string, workflowId: string) {
|
||||||
return this.call<{ nodeResults: unknown[] }>('POST', `/api/base/${baseId}/workflow/${workflowId}/test`);
|
return this.call<{ nodeResults: unknown[] }>(
|
||||||
|
'POST',
|
||||||
|
`/api/base/${baseId}/workflow/${workflowId}/test`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
/** PUT /node — whole-graph replacement (delete-all + create-all in a txn). */
|
/** PUT /node — whole-graph replacement (delete-all + create-all in a txn). */
|
||||||
replaceNodes(baseId: string, workflowId: string, body: { nodes: IWorkflowNodeVo[]; edges: IWorkflowEdgeVo[] }) {
|
replaceNodes(
|
||||||
|
baseId: string,
|
||||||
|
workflowId: string,
|
||||||
|
body: { nodes: IWorkflowNodeVo[]; edges: IWorkflowEdgeVo[] }
|
||||||
|
) {
|
||||||
return this.call<IWorkflowVo>('PUT', `/api/base/${baseId}/workflow/${workflowId}/node`, body);
|
return this.call<IWorkflowVo>('PUT', `/api/base/${baseId}/workflow/${workflowId}/node`, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,14 +202,30 @@ export class Client {
|
|||||||
listSecrets(baseId: string, workflowId: string) {
|
listSecrets(baseId: string, workflowId: string) {
|
||||||
return this.call<unknown[]>('GET', `/api/base/${baseId}/workflow/${workflowId}/secret`);
|
return this.call<unknown[]>('GET', `/api/base/${baseId}/workflow/${workflowId}/secret`);
|
||||||
}
|
}
|
||||||
createSecret(baseId: string, workflowId: string, body: { name: string; description?: string; value: string }) {
|
createSecret(
|
||||||
|
baseId: string,
|
||||||
|
workflowId: string,
|
||||||
|
body: { name: string; description?: string; value: string }
|
||||||
|
) {
|
||||||
return this.call<unknown>('POST', `/api/base/${baseId}/workflow/${workflowId}/secret`, body);
|
return this.call<unknown>('POST', `/api/base/${baseId}/workflow/${workflowId}/secret`, body);
|
||||||
}
|
}
|
||||||
updateSecret(baseId: string, workflowId: string, secretId: string, body: { name?: string; description?: string; value?: string }) {
|
updateSecret(
|
||||||
return this.call<unknown>('PATCH', `/api/base/${baseId}/workflow/${workflowId}/secret/${secretId}`, body);
|
baseId: string,
|
||||||
|
workflowId: string,
|
||||||
|
secretId: string,
|
||||||
|
body: { name?: string; description?: string; value?: string }
|
||||||
|
) {
|
||||||
|
return this.call<unknown>(
|
||||||
|
'PATCH',
|
||||||
|
`/api/base/${baseId}/workflow/${workflowId}/secret/${secretId}`,
|
||||||
|
body
|
||||||
|
);
|
||||||
}
|
}
|
||||||
deleteSecret(baseId: string, workflowId: string, secretId: string) {
|
deleteSecret(baseId: string, workflowId: string, secretId: string) {
|
||||||
return this.call<unknown>('DELETE', `/api/base/${baseId}/workflow/${workflowId}/secret/${secretId}`);
|
return this.call<unknown>(
|
||||||
|
'DELETE',
|
||||||
|
`/api/base/${baseId}/workflow/${workflowId}/secret/${secretId}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- execution history ----
|
// ---- execution history ----
|
||||||
@@ -202,10 +233,16 @@ export class Client {
|
|||||||
return this.call<unknown[]>('GET', `/api/base/${baseId}/workflow/${workflowId}/execution`);
|
return this.call<unknown[]>('GET', `/api/base/${baseId}/workflow/${workflowId}/execution`);
|
||||||
}
|
}
|
||||||
getExecution(baseId: string, workflowId: string, executionId: string) {
|
getExecution(baseId: string, workflowId: string, executionId: string) {
|
||||||
return this.call<unknown>('GET', `/api/base/${baseId}/workflow/${workflowId}/execution/${executionId}`);
|
return this.call<unknown>(
|
||||||
|
'GET',
|
||||||
|
`/api/base/${baseId}/workflow/${workflowId}/execution/${executionId}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
rerunExecution(baseId: string, workflowId: string, executionId: string) {
|
rerunExecution(baseId: string, workflowId: string, executionId: string) {
|
||||||
return this.call<unknown>('POST', `/api/base/${baseId}/workflow/${workflowId}/execution/${executionId}/rerun`);
|
return this.call<unknown>(
|
||||||
|
'POST',
|
||||||
|
`/api/base/${baseId}/workflow/${workflowId}/execution/${executionId}/rerun`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- trigger (manual fire for testing) ----
|
// ---- trigger (manual fire for testing) ----
|
||||||
@@ -243,10 +280,20 @@ export class Client {
|
|||||||
// ---- shared types (mirror backend workflow_node / workflow_edge shapes) ----
|
// ---- shared types (mirror backend workflow_node / workflow_edge shapes) ----
|
||||||
export type WorkflowNodeType = 'trigger' | 'action' | 'control';
|
export type WorkflowNodeType = 'trigger' | 'action' | 'control';
|
||||||
export type WorkflowNodeCategory =
|
export type WorkflowNodeCategory =
|
||||||
| 'recordCreated' | 'recordUpdated' | 'recordCondition' | 'recordCreatedOrUpdated'
|
| 'recordCreated'
|
||||||
| 'formSubmitted' | 'scheduledTime' | 'buttonClick' | 'webhook'
|
| 'recordUpdated'
|
||||||
| 'script' | 'sendEmail' | 'httpRequest'
|
| 'recordCondition'
|
||||||
| 'createRecord' | 'updateRecord' | 'getRecords'
|
| 'recordCreatedOrUpdated'
|
||||||
|
| 'formSubmitted'
|
||||||
|
| 'scheduledTime'
|
||||||
|
| 'buttonClick'
|
||||||
|
| 'webhook'
|
||||||
|
| 'script'
|
||||||
|
| 'sendEmail'
|
||||||
|
| 'httpRequest'
|
||||||
|
| 'createRecord'
|
||||||
|
| 'updateRecord'
|
||||||
|
| 'getRecords'
|
||||||
| 'triggerEnd';
|
| 'triggerEnd';
|
||||||
|
|
||||||
export interface IWorkflowNodeVo {
|
export interface IWorkflowNodeVo {
|
||||||
|
|||||||
Reference in New Issue
Block a user