zinkee 0.1.30 → 0.1.32
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/README.md +24 -0
- package/dist/index.js +149 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api/schemas.ts +12 -0
- package/src/command-registry.ts +7 -0
- package/src/commands/schemas.test.ts +112 -0
- package/src/commands/schemas.ts +88 -3
- package/src/utils/examples.ts +83 -2
package/README.md
CHANGED
|
@@ -248,6 +248,30 @@ date_format(44b72f55-3fc3-40f4-88bb-343bb4a6270c, "AAAA-MM")
|
|
|
248
248
|
- Functions: `concat`, `if`, `date_format`, `datetime_diff`, arithmetic (`+`,`-`,`*`,`/`)
|
|
249
249
|
- Invalid formulas are created with status `DRAFT` and evaluate to `null`
|
|
250
250
|
|
|
251
|
+
### Set unique fields
|
|
252
|
+
|
|
253
|
+
Define a composite unique constraint: the listed fields must be unique **together**
|
|
254
|
+
across the schema's records. `--field` accepts a field UUID or slug and is repeatable;
|
|
255
|
+
the order you pass them is the order of the constraint.
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Single field must be unique
|
|
259
|
+
zinkee schemas set-unique-fields contacts --field email
|
|
260
|
+
|
|
261
|
+
# Composite: the (contact-name, notes) combination must be unique
|
|
262
|
+
zinkee schemas set-unique-fields contacts --field contact-name --field notes
|
|
263
|
+
|
|
264
|
+
# Remove the unique constraint
|
|
265
|
+
zinkee schemas set-unique-fields contacts --clear
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Notes:
|
|
269
|
+
|
|
270
|
+
- Pass either one or more `--field`, or `--clear` — not both, and not neither.
|
|
271
|
+
- Every `--field` must already exist in the schema, otherwise the command fails.
|
|
272
|
+
- If existing records already violate the requested constraint, the backend rejects
|
|
273
|
+
it with `409 Conflict`.
|
|
274
|
+
|
|
251
275
|
---
|
|
252
276
|
|
|
253
277
|
## Records
|
package/dist/index.js
CHANGED
|
@@ -667,6 +667,13 @@ var commandRegistry = {
|
|
|
667
667
|
supportsRaw: false,
|
|
668
668
|
output: writeOutput
|
|
669
669
|
},
|
|
670
|
+
"schemas set-unique-fields": {
|
|
671
|
+
command: "schemas set-unique-fields",
|
|
672
|
+
accessLevel: "write",
|
|
673
|
+
supportsExample: true,
|
|
674
|
+
supportsRaw: false,
|
|
675
|
+
output: writeOutput
|
|
676
|
+
},
|
|
670
677
|
"schemas delete": {
|
|
671
678
|
command: "schemas delete",
|
|
672
679
|
accessLevel: "destructive",
|
|
@@ -2417,7 +2424,8 @@ var specificExamples = {
|
|
|
2417
2424
|
"conditionalFormatting": []
|
|
2418
2425
|
}
|
|
2419
2426
|
}
|
|
2420
|
-
]
|
|
2427
|
+
],
|
|
2428
|
+
"uniqueFields": []
|
|
2421
2429
|
}`
|
|
2422
2430
|
},
|
|
2423
2431
|
{
|
|
@@ -2436,10 +2444,83 @@ var specificExamples = {
|
|
|
2436
2444
|
}`
|
|
2437
2445
|
},
|
|
2438
2446
|
{
|
|
2439
|
-
description: "Set the highlighted (main) field
|
|
2447
|
+
description: "Set the schema's highlighted (main) field \u2014 the field whose value names each record in the UI (activity-panel title and detail-view record list).",
|
|
2440
2448
|
command: "zinkee --json schemas update contacts --highlighted-field contact-name",
|
|
2441
2449
|
raw: `{
|
|
2442
2450
|
"highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34"
|
|
2451
|
+
}`
|
|
2452
|
+
}
|
|
2453
|
+
]),
|
|
2454
|
+
"schemas set-unique-fields": buildCommandExamples([
|
|
2455
|
+
{
|
|
2456
|
+
description: "Set a composite unique constraint: the listed fields must be unique together across records.",
|
|
2457
|
+
command: "zinkee --json schemas set-unique-fields contacts --field contact-name --field notes",
|
|
2458
|
+
raw: `{
|
|
2459
|
+
"fieldIds": [
|
|
2460
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
2461
|
+
"1d2e3f4a-5b6c-7d8e-9f01-23456789abcd"
|
|
2462
|
+
]
|
|
2463
|
+
}`,
|
|
2464
|
+
response: `{
|
|
2465
|
+
"id": "2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e",
|
|
2466
|
+
"name": "Contacts",
|
|
2467
|
+
"slug": "contacts",
|
|
2468
|
+
"folder": {
|
|
2469
|
+
"id": "7f4e7c25-d8b2-4c1a-9f3e-6a7b5c8d9e1f",
|
|
2470
|
+
"name": "Customers",
|
|
2471
|
+
"isRoot": false
|
|
2472
|
+
},
|
|
2473
|
+
"auditable": true,
|
|
2474
|
+
"commentable": true,
|
|
2475
|
+
"highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
2476
|
+
"fields": [
|
|
2477
|
+
{
|
|
2478
|
+
"id": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
2479
|
+
"type": "TextField",
|
|
2480
|
+
"slug": "contact-name",
|
|
2481
|
+
"label": "Customer Name",
|
|
2482
|
+
"required": true,
|
|
2483
|
+
"system": false,
|
|
2484
|
+
"config": {
|
|
2485
|
+
"textType": "NORMAL",
|
|
2486
|
+
"defaultValue": "Unknown",
|
|
2487
|
+
"conditionalFormatting": []
|
|
2488
|
+
}
|
|
2489
|
+
},
|
|
2490
|
+
{
|
|
2491
|
+
"id": "1d2e3f4a-5b6c-7d8e-9f01-23456789abcd",
|
|
2492
|
+
"type": "TextField",
|
|
2493
|
+
"slug": "notes",
|
|
2494
|
+
"label": "Notes",
|
|
2495
|
+
"required": false,
|
|
2496
|
+
"system": false,
|
|
2497
|
+
"config": {
|
|
2498
|
+
"textType": "LONG",
|
|
2499
|
+
"defaultValue": null,
|
|
2500
|
+
"conditionalFormatting": []
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
],
|
|
2504
|
+
"uniqueFields": [
|
|
2505
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
2506
|
+
"1d2e3f4a-5b6c-7d8e-9f01-23456789abcd"
|
|
2507
|
+
]
|
|
2508
|
+
}`
|
|
2509
|
+
},
|
|
2510
|
+
{
|
|
2511
|
+
description: "Set a single-field unique constraint.",
|
|
2512
|
+
command: "zinkee --json schemas set-unique-fields contacts --field contact-name",
|
|
2513
|
+
raw: `{
|
|
2514
|
+
"fieldIds": [
|
|
2515
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34"
|
|
2516
|
+
]
|
|
2517
|
+
}`
|
|
2518
|
+
},
|
|
2519
|
+
{
|
|
2520
|
+
description: "Clear the unique constraint (no field must be unique anymore).",
|
|
2521
|
+
command: "zinkee --json schemas set-unique-fields contacts --clear",
|
|
2522
|
+
raw: `{
|
|
2523
|
+
"fieldIds": []
|
|
2443
2524
|
}`
|
|
2444
2525
|
}
|
|
2445
2526
|
]),
|
|
@@ -4290,6 +4371,10 @@ var specificExamples = {
|
|
|
4290
4371
|
"conditionalFormatting": []
|
|
4291
4372
|
}
|
|
4292
4373
|
}
|
|
4374
|
+
],
|
|
4375
|
+
"uniqueFields": [
|
|
4376
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
4377
|
+
"1d2e3f4a-5b6c-7d8e-9f01-23456789abcd"
|
|
4293
4378
|
]
|
|
4294
4379
|
}`
|
|
4295
4380
|
}
|
|
@@ -10720,6 +10805,12 @@ var SchemasApi = class {
|
|
|
10720
10805
|
jsonOptions7(input, "PATCH")
|
|
10721
10806
|
);
|
|
10722
10807
|
}
|
|
10808
|
+
setUniqueFields(schema, input) {
|
|
10809
|
+
return this.client.requestJson(
|
|
10810
|
+
`/api/v2/schemas/${selectorValue9(schema)}/unique-fields`,
|
|
10811
|
+
jsonOptions7(input, "PUT")
|
|
10812
|
+
);
|
|
10813
|
+
}
|
|
10723
10814
|
deleteSchema(schema) {
|
|
10724
10815
|
return this.client.requestJson(
|
|
10725
10816
|
`/api/v2/schemas/${selectorValue9(schema)}`,
|
|
@@ -11175,6 +11266,15 @@ function registerRecordsCommands(program, options = {}) {
|
|
|
11175
11266
|
// src/commands/schemas.ts
|
|
11176
11267
|
import { readFileSync as readFileSync9 } from "fs";
|
|
11177
11268
|
import { InvalidArgumentError as InvalidArgumentError9 } from "commander";
|
|
11269
|
+
var HIGHLIGHTED_FIELD_HELP = `
|
|
11270
|
+
Highlighted field:
|
|
11271
|
+
The schema's "main" field. The frontend uses its value as each record's
|
|
11272
|
+
display name, in two places:
|
|
11273
|
+
- Activity panel: the record's title in the activity side panel
|
|
11274
|
+
(the panel with the record's logs and comments).
|
|
11275
|
+
- Detail view: the record's name in the left-hand record list you
|
|
11276
|
+
browse to open each record's form.
|
|
11277
|
+
`;
|
|
11178
11278
|
function getCommandIo11(stdout) {
|
|
11179
11279
|
return stdout ?? process.stdout;
|
|
11180
11280
|
}
|
|
@@ -11248,6 +11348,9 @@ function parseUuidOrSlugSelector9(input) {
|
|
|
11248
11348
|
throw new InvalidArgumentError9(message);
|
|
11249
11349
|
}
|
|
11250
11350
|
}
|
|
11351
|
+
function collectFieldSelectors(value, previous = []) {
|
|
11352
|
+
return [...previous, parseUuidOrSlugSelector9(value)];
|
|
11353
|
+
}
|
|
11251
11354
|
function parseBooleanFlag(input) {
|
|
11252
11355
|
const normalized = input.trim().toLowerCase();
|
|
11253
11356
|
if (["true", "1", "yes", "y", "on"].includes(normalized)) {
|
|
@@ -11509,7 +11612,7 @@ function registerSchemasCommands(program, options = {}) {
|
|
|
11509
11612
|
});
|
|
11510
11613
|
schemas.command("update").description("Update a schema").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector9).option("--name <name>", "schema name").option("--slug <slug>", "schema slug").option("--auditable <bool>", "auditable flag", parseBooleanFlag).option("--commentable <bool>", "commentable flag", parseBooleanFlag).option(
|
|
11511
11614
|
"--highlighted-field <field>",
|
|
11512
|
-
"
|
|
11615
|
+
"its value is used as each record's display name in the UI (field uuid or slug)",
|
|
11513
11616
|
parseUuidOrSlugSelector9
|
|
11514
11617
|
).action(async function action(schema, commandOptions) {
|
|
11515
11618
|
const { api, json, readOnly } = createSchemasApi(this, filePath);
|
|
@@ -11536,6 +11639,49 @@ function registerSchemasCommands(program, options = {}) {
|
|
|
11536
11639
|
return;
|
|
11537
11640
|
}
|
|
11538
11641
|
writeLine11(stdout, `Updated schema "${data.slug ?? schema.value}".`);
|
|
11642
|
+
}).addHelpText("after", HIGHLIGHTED_FIELD_HELP);
|
|
11643
|
+
schemas.command("set-unique-fields").description("Set or clear the composite unique-field constraint on a schema").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector9).option(
|
|
11644
|
+
"--field <field>",
|
|
11645
|
+
"field uuid or slug to include in the unique constraint (repeatable)",
|
|
11646
|
+
collectFieldSelectors,
|
|
11647
|
+
[]
|
|
11648
|
+
).option("--clear", "clear the unique constraint (sends an empty field list)").action(async function action(schema, commandOptions) {
|
|
11649
|
+
const { api, json, readOnly } = createSchemasApi(this, filePath);
|
|
11650
|
+
ensureWritable8("schemas set-unique-fields", readOnly, "write");
|
|
11651
|
+
const selectors = commandOptions.field ?? [];
|
|
11652
|
+
if (commandOptions.clear && selectors.length > 0) {
|
|
11653
|
+
throw new CliError(
|
|
11654
|
+
"invalid_cli_usage",
|
|
11655
|
+
'Use either "--field" or "--clear", not both.'
|
|
11656
|
+
);
|
|
11657
|
+
}
|
|
11658
|
+
if (!commandOptions.clear && selectors.length === 0) {
|
|
11659
|
+
throw new CliError(
|
|
11660
|
+
"invalid_cli_usage",
|
|
11661
|
+
'Provide at least one field via "--field", or pass "--clear" to remove the unique constraint.'
|
|
11662
|
+
);
|
|
11663
|
+
}
|
|
11664
|
+
const resolvedSchema = await resolveSchemaSelector2(api, schema);
|
|
11665
|
+
const resolvedFields = await Promise.all(
|
|
11666
|
+
selectors.map((selector) => resolveFieldSelector(api, resolvedSchema, selector))
|
|
11667
|
+
);
|
|
11668
|
+
const input = {
|
|
11669
|
+
fieldIds: resolvedFields.map((field) => field.value)
|
|
11670
|
+
};
|
|
11671
|
+
const data = await api.setUniqueFields(resolvedSchema, input);
|
|
11672
|
+
if (json) {
|
|
11673
|
+
emitJson11(stdout, "schemas set-unique-fields", data, filePath);
|
|
11674
|
+
return;
|
|
11675
|
+
}
|
|
11676
|
+
if (input.fieldIds.length === 0) {
|
|
11677
|
+
writeLine11(stdout, `Cleared unique fields on schema "${schema.value}".`);
|
|
11678
|
+
return;
|
|
11679
|
+
}
|
|
11680
|
+
const count = input.fieldIds.length;
|
|
11681
|
+
writeLine11(
|
|
11682
|
+
stdout,
|
|
11683
|
+
`Set unique fields on schema "${schema.value}" (${count} field${count === 1 ? "" : "s"}).`
|
|
11684
|
+
);
|
|
11539
11685
|
});
|
|
11540
11686
|
schemas.command("delete").description("Delete a schema").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector9).action(async function action(schema) {
|
|
11541
11687
|
const { api, json, readOnly } = createSchemasApi(this, filePath);
|