zinkee 0.1.29 → 0.1.31
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/.claude/settings.local.json +2 -1
- package/AGENTS.md +13 -0
- package/README.md +24 -0
- package/dist/index.js +161 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api/schemas.ts +14 -0
- package/src/command-registry.ts +7 -0
- package/src/commands/schemas.test.ts +192 -0
- package/src/commands/schemas.ts +92 -3
- package/src/utils/examples.ts +91 -1
package/package.json
CHANGED
package/src/api/schemas.ts
CHANGED
|
@@ -17,7 +17,9 @@ export interface ApiSchema {
|
|
|
17
17
|
slug?: string;
|
|
18
18
|
auditable?: boolean;
|
|
19
19
|
commentable?: boolean;
|
|
20
|
+
highlightedField?: string;
|
|
20
21
|
fields?: ApiSchemaField[];
|
|
22
|
+
uniqueFields?: string[];
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export interface CreateSchemaInput {
|
|
@@ -32,6 +34,11 @@ export interface UpdateSchemaInput {
|
|
|
32
34
|
slug?: string;
|
|
33
35
|
auditable?: boolean;
|
|
34
36
|
commentable?: boolean;
|
|
37
|
+
highlightedField?: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface SetUniqueFieldsInput {
|
|
41
|
+
fieldIds: string[];
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
export interface CreateSchemaFieldInput {
|
|
@@ -84,6 +91,13 @@ export class SchemasApi {
|
|
|
84
91
|
);
|
|
85
92
|
}
|
|
86
93
|
|
|
94
|
+
setUniqueFields(schema: NormalizedUuidOrSlug, input: SetUniqueFieldsInput): Promise<ApiSchema> {
|
|
95
|
+
return this.client.requestJson<ApiSchema>(
|
|
96
|
+
`/api/v2/schemas/${selectorValue(schema)}/unique-fields`,
|
|
97
|
+
jsonOptions(input, "PUT"),
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
87
101
|
deleteSchema(schema: NormalizedUuidOrSlug): Promise<Record<string, unknown>> {
|
|
88
102
|
return this.client.requestJson<Record<string, unknown>>(
|
|
89
103
|
`/api/v2/schemas/${selectorValue(schema)}`,
|
package/src/command-registry.ts
CHANGED
|
@@ -672,6 +672,13 @@ export const commandRegistry = {
|
|
|
672
672
|
supportsRaw: false,
|
|
673
673
|
output: writeOutput,
|
|
674
674
|
},
|
|
675
|
+
"schemas set-unique-fields": {
|
|
676
|
+
command: "schemas set-unique-fields",
|
|
677
|
+
accessLevel: "write",
|
|
678
|
+
supportsExample: true,
|
|
679
|
+
supportsRaw: false,
|
|
680
|
+
output: writeOutput,
|
|
681
|
+
},
|
|
675
682
|
"schemas delete": {
|
|
676
683
|
command: "schemas delete",
|
|
677
684
|
accessLevel: "destructive",
|
|
@@ -213,6 +213,118 @@ describe("schemas commands", () => {
|
|
|
213
213
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
214
214
|
});
|
|
215
215
|
|
|
216
|
+
it("sets unique fields through PUT /unique-fields with the expected body", async () => {
|
|
217
|
+
const configPath = createApiConfig();
|
|
218
|
+
const output = createStdoutBuffer();
|
|
219
|
+
const fetchMock = createFetchMock();
|
|
220
|
+
fetchMock.mockResolvedValueOnce(
|
|
221
|
+
jsonResponse({
|
|
222
|
+
id: "2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e",
|
|
223
|
+
uniqueFields: [
|
|
224
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
225
|
+
"1d2e3f4a-5b6c-7d8e-9f01-23456789abcd",
|
|
226
|
+
],
|
|
227
|
+
}),
|
|
228
|
+
);
|
|
229
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
230
|
+
|
|
231
|
+
await program.parseAsync([
|
|
232
|
+
"node",
|
|
233
|
+
"zinkee",
|
|
234
|
+
"--json",
|
|
235
|
+
"schemas",
|
|
236
|
+
"set-unique-fields",
|
|
237
|
+
"2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e",
|
|
238
|
+
"--field",
|
|
239
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
240
|
+
"--field",
|
|
241
|
+
"1d2e3f4a-5b6c-7d8e-9f01-23456789abcd",
|
|
242
|
+
]);
|
|
243
|
+
|
|
244
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
245
|
+
expect(fetchMock.mock.calls[0]?.[0]).toBe(
|
|
246
|
+
"https://api.zinkee.test/api/v2/schemas/2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e/unique-fields",
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const init = fetchMock.mock.calls[0]?.[1];
|
|
250
|
+
expect(init?.method).toBe("PUT");
|
|
251
|
+
expect(new Headers(init?.headers).get("content-type")).toBe("application/json");
|
|
252
|
+
expect(JSON.parse(String(init?.body))).toEqual({
|
|
253
|
+
fieldIds: [
|
|
254
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
255
|
+
"1d2e3f4a-5b6c-7d8e-9f01-23456789abcd",
|
|
256
|
+
],
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("clears the unique constraint with --clear", async () => {
|
|
261
|
+
const configPath = createApiConfig();
|
|
262
|
+
const output = createStdoutBuffer();
|
|
263
|
+
const fetchMock = createFetchMock();
|
|
264
|
+
fetchMock.mockResolvedValueOnce(
|
|
265
|
+
jsonResponse({ id: "550e8400-e29b-41d4-a716-446655440000", uniqueFields: [] }),
|
|
266
|
+
);
|
|
267
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
268
|
+
|
|
269
|
+
await program.parseAsync([
|
|
270
|
+
"node",
|
|
271
|
+
"zinkee",
|
|
272
|
+
"--json",
|
|
273
|
+
"schemas",
|
|
274
|
+
"set-unique-fields",
|
|
275
|
+
"550e8400-e29b-41d4-a716-446655440000",
|
|
276
|
+
"--clear",
|
|
277
|
+
]);
|
|
278
|
+
|
|
279
|
+
const init = fetchMock.mock.calls[0]?.[1];
|
|
280
|
+
expect(init?.method).toBe("PUT");
|
|
281
|
+
expect(JSON.parse(String(init?.body))).toEqual({ fieldIds: [] });
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("rejects set-unique-fields without fields or --clear", async () => {
|
|
285
|
+
const configPath = createApiConfig();
|
|
286
|
+
const output = createStdoutBuffer();
|
|
287
|
+
const fetchMock = createFetchMock();
|
|
288
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
289
|
+
|
|
290
|
+
await expect(
|
|
291
|
+
program.parseAsync([
|
|
292
|
+
"node",
|
|
293
|
+
"zinkee",
|
|
294
|
+
"schemas",
|
|
295
|
+
"set-unique-fields",
|
|
296
|
+
"550e8400-e29b-41d4-a716-446655440000",
|
|
297
|
+
]),
|
|
298
|
+
).rejects.toThrowError(
|
|
299
|
+
'Provide at least one field via "--field", or pass "--clear" to remove the unique constraint.',
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("blocks set-unique-fields in read-only mode", async () => {
|
|
306
|
+
const configPath = createApiConfig();
|
|
307
|
+
const output = createStdoutBuffer();
|
|
308
|
+
const fetchMock = createFetchMock();
|
|
309
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
310
|
+
|
|
311
|
+
await expect(
|
|
312
|
+
program.parseAsync([
|
|
313
|
+
"node",
|
|
314
|
+
"zinkee",
|
|
315
|
+
"--read-only",
|
|
316
|
+
"schemas",
|
|
317
|
+
"set-unique-fields",
|
|
318
|
+
"550e8400-e29b-41d4-a716-446655440000",
|
|
319
|
+
"--clear",
|
|
320
|
+
]),
|
|
321
|
+
).rejects.toThrowError(
|
|
322
|
+
'Command "schemas set-unique-fields" is not allowed in read-only mode.',
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
expect(fetchMock).not.toHaveBeenCalled();
|
|
326
|
+
});
|
|
327
|
+
|
|
216
328
|
it("creates fields by merging raw JSON with explicit flags", async () => {
|
|
217
329
|
const configPath = createApiConfig();
|
|
218
330
|
const output = createStdoutBuffer();
|
|
@@ -968,4 +1080,84 @@ describe("schemas commands", () => {
|
|
|
968
1080
|
},
|
|
969
1081
|
});
|
|
970
1082
|
});
|
|
1083
|
+
|
|
1084
|
+
it("updates a schema highlighted field by slug after resolving the field id", async () => {
|
|
1085
|
+
const configPath = createApiConfig();
|
|
1086
|
+
const output = createStdoutBuffer();
|
|
1087
|
+
const fetchMock = createFetchMock();
|
|
1088
|
+
mockSchemaLookup(fetchMock);
|
|
1089
|
+
fetchMock.mockResolvedValueOnce(
|
|
1090
|
+
jsonResponse({
|
|
1091
|
+
id: "schema-1",
|
|
1092
|
+
slug: "contacts",
|
|
1093
|
+
fields: [
|
|
1094
|
+
{
|
|
1095
|
+
id: "550e8400-e29b-41d4-a716-446655440001",
|
|
1096
|
+
slug: "email",
|
|
1097
|
+
type: "TextField",
|
|
1098
|
+
label: "Email",
|
|
1099
|
+
},
|
|
1100
|
+
],
|
|
1101
|
+
}),
|
|
1102
|
+
);
|
|
1103
|
+
fetchMock.mockResolvedValueOnce(
|
|
1104
|
+
jsonResponse({
|
|
1105
|
+
id: "schema-1",
|
|
1106
|
+
slug: "contacts",
|
|
1107
|
+
highlightedField: "550e8400-e29b-41d4-a716-446655440001",
|
|
1108
|
+
}),
|
|
1109
|
+
);
|
|
1110
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
1111
|
+
|
|
1112
|
+
await program.parseAsync([
|
|
1113
|
+
"node",
|
|
1114
|
+
"zinkee",
|
|
1115
|
+
"--json",
|
|
1116
|
+
"schemas",
|
|
1117
|
+
"update",
|
|
1118
|
+
"contacts",
|
|
1119
|
+
"--highlighted-field",
|
|
1120
|
+
"email",
|
|
1121
|
+
]);
|
|
1122
|
+
|
|
1123
|
+
expect(fetchMock.mock.calls[2]?.[0]).toBe("https://api.zinkee.test/api/v2/schemas/schema-1");
|
|
1124
|
+
expect(fetchMock.mock.calls[2]?.[1]?.method).toBe("PATCH");
|
|
1125
|
+
expect(JSON.parse(String(fetchMock.mock.calls[2]?.[1]?.body))).toEqual({
|
|
1126
|
+
highlightedField: "550e8400-e29b-41d4-a716-446655440001",
|
|
1127
|
+
});
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
it("updates a schema highlighted field by uuid without extra lookups", async () => {
|
|
1131
|
+
const configPath = createApiConfig();
|
|
1132
|
+
const output = createStdoutBuffer();
|
|
1133
|
+
const fetchMock = createFetchMock();
|
|
1134
|
+
fetchMock.mockResolvedValueOnce(
|
|
1135
|
+
jsonResponse({
|
|
1136
|
+
id: "550e8400-e29b-41d4-a716-446655440000",
|
|
1137
|
+
slug: "contacts",
|
|
1138
|
+
highlightedField: "550e8400-e29b-41d4-a716-446655440001",
|
|
1139
|
+
}),
|
|
1140
|
+
);
|
|
1141
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
1142
|
+
|
|
1143
|
+
await program.parseAsync([
|
|
1144
|
+
"node",
|
|
1145
|
+
"zinkee",
|
|
1146
|
+
"--json",
|
|
1147
|
+
"schemas",
|
|
1148
|
+
"update",
|
|
1149
|
+
"550e8400-e29b-41d4-a716-446655440000",
|
|
1150
|
+
"--highlighted-field",
|
|
1151
|
+
"550e8400-e29b-41d4-a716-446655440001",
|
|
1152
|
+
]);
|
|
1153
|
+
|
|
1154
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
1155
|
+
expect(fetchMock.mock.calls[0]?.[0]).toBe(
|
|
1156
|
+
"https://api.zinkee.test/api/v2/schemas/550e8400-e29b-41d4-a716-446655440000",
|
|
1157
|
+
);
|
|
1158
|
+
expect(fetchMock.mock.calls[0]?.[1]?.method).toBe("PATCH");
|
|
1159
|
+
expect(JSON.parse(String(fetchMock.mock.calls[0]?.[1]?.body))).toEqual({
|
|
1160
|
+
highlightedField: "550e8400-e29b-41d4-a716-446655440001",
|
|
1161
|
+
});
|
|
1162
|
+
});
|
|
971
1163
|
});
|
package/src/commands/schemas.ts
CHANGED
|
@@ -9,11 +9,11 @@ import {
|
|
|
9
9
|
type ApiSchemaField,
|
|
10
10
|
type CreateSchemaFieldInput,
|
|
11
11
|
type CreateSchemaInput,
|
|
12
|
+
type SetUniqueFieldsInput,
|
|
12
13
|
type UpdateSchemaFieldInput,
|
|
13
14
|
type UpdateSchemaInput,
|
|
14
15
|
} from "../api/schemas.js";
|
|
15
|
-
import { ApiClientError } from "../client.js";
|
|
16
|
-
import { ApiClient } from "../client.js";
|
|
16
|
+
import { ApiClientError, ApiClient } from "../client.js";
|
|
17
17
|
import { defaultConfigPath, readRuntimeConfig } from "../config.js";
|
|
18
18
|
import {
|
|
19
19
|
normalizeUuidOrSlug,
|
|
@@ -56,6 +56,12 @@ interface SchemaUpdateCommandOptions {
|
|
|
56
56
|
slug?: string;
|
|
57
57
|
auditable?: boolean;
|
|
58
58
|
commentable?: boolean;
|
|
59
|
+
highlightedField?: NormalizedUuidOrSlug;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
interface SetUniqueFieldsCommandOptions {
|
|
63
|
+
field?: NormalizedUuidOrSlug[];
|
|
64
|
+
clear?: boolean;
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
interface FieldCreateCommandOptions {
|
|
@@ -178,6 +184,13 @@ function parseUuidOrSlugSelector(input: string): NormalizedUuidOrSlug {
|
|
|
178
184
|
}
|
|
179
185
|
}
|
|
180
186
|
|
|
187
|
+
function collectFieldSelectors(
|
|
188
|
+
value: string,
|
|
189
|
+
previous: NormalizedUuidOrSlug[] = [],
|
|
190
|
+
): NormalizedUuidOrSlug[] {
|
|
191
|
+
return [...previous, parseUuidOrSlugSelector(value)];
|
|
192
|
+
}
|
|
193
|
+
|
|
181
194
|
function parseBooleanFlag(input: string): boolean {
|
|
182
195
|
const normalized = input.trim().toLowerCase();
|
|
183
196
|
|
|
@@ -568,6 +581,11 @@ export function registerSchemasCommands(
|
|
|
568
581
|
.option("--slug <slug>", "schema slug")
|
|
569
582
|
.option("--auditable <bool>", "auditable flag", parseBooleanFlag)
|
|
570
583
|
.option("--commentable <bool>", "commentable flag", parseBooleanFlag)
|
|
584
|
+
.option(
|
|
585
|
+
"--highlighted-field <field>",
|
|
586
|
+
"highlighted (main) field uuid or slug",
|
|
587
|
+
parseUuidOrSlugSelector,
|
|
588
|
+
)
|
|
571
589
|
.action(async function action(
|
|
572
590
|
this: Command,
|
|
573
591
|
schema: NormalizedUuidOrSlug,
|
|
@@ -579,10 +597,19 @@ export function registerSchemasCommands(
|
|
|
579
597
|
|
|
580
598
|
const input = buildSchemaUpdateInput(commandOptions);
|
|
581
599
|
|
|
600
|
+
if (commandOptions.highlightedField !== undefined) {
|
|
601
|
+
const resolvedField = await resolveFieldSelector(
|
|
602
|
+
api,
|
|
603
|
+
resolvedSchema,
|
|
604
|
+
commandOptions.highlightedField,
|
|
605
|
+
);
|
|
606
|
+
input.highlightedField = resolvedField.value;
|
|
607
|
+
}
|
|
608
|
+
|
|
582
609
|
if (isEmptyObject(input)) {
|
|
583
610
|
throw new CliError(
|
|
584
611
|
"invalid_cli_usage",
|
|
585
|
-
'Provide at least one schema field to update via "--name", "--slug", "--auditable", or "--
|
|
612
|
+
'Provide at least one schema field to update via "--name", "--slug", "--auditable", "--commentable", or "--highlighted-field".',
|
|
586
613
|
);
|
|
587
614
|
}
|
|
588
615
|
|
|
@@ -596,6 +623,68 @@ export function registerSchemasCommands(
|
|
|
596
623
|
writeLine(stdout, `Updated schema "${data.slug ?? schema.value}".`);
|
|
597
624
|
});
|
|
598
625
|
|
|
626
|
+
schemas
|
|
627
|
+
.command("set-unique-fields")
|
|
628
|
+
.description("Set or clear the composite unique-field constraint on a schema")
|
|
629
|
+
.argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector)
|
|
630
|
+
.option(
|
|
631
|
+
"--field <field>",
|
|
632
|
+
"field uuid or slug to include in the unique constraint (repeatable)",
|
|
633
|
+
collectFieldSelectors,
|
|
634
|
+
[],
|
|
635
|
+
)
|
|
636
|
+
.option("--clear", "clear the unique constraint (sends an empty field list)")
|
|
637
|
+
.action(async function action(
|
|
638
|
+
this: Command,
|
|
639
|
+
schema: NormalizedUuidOrSlug,
|
|
640
|
+
commandOptions: SetUniqueFieldsCommandOptions,
|
|
641
|
+
) {
|
|
642
|
+
const { api, json, readOnly } = createSchemasApi(this, filePath);
|
|
643
|
+
ensureWritable("schemas set-unique-fields", readOnly, "write");
|
|
644
|
+
|
|
645
|
+
const selectors = commandOptions.field ?? [];
|
|
646
|
+
|
|
647
|
+
if (commandOptions.clear && selectors.length > 0) {
|
|
648
|
+
throw new CliError(
|
|
649
|
+
"invalid_cli_usage",
|
|
650
|
+
'Use either "--field" or "--clear", not both.',
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
if (!commandOptions.clear && selectors.length === 0) {
|
|
655
|
+
throw new CliError(
|
|
656
|
+
"invalid_cli_usage",
|
|
657
|
+
'Provide at least one field via "--field", or pass "--clear" to remove the unique constraint.',
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
const resolvedSchema = await resolveSchemaSelector(api, schema);
|
|
662
|
+
const resolvedFields = await Promise.all(
|
|
663
|
+
selectors.map((selector) => resolveFieldSelector(api, resolvedSchema, selector)),
|
|
664
|
+
);
|
|
665
|
+
const input: SetUniqueFieldsInput = {
|
|
666
|
+
fieldIds: resolvedFields.map((field) => field.value),
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
const data = await api.setUniqueFields(resolvedSchema, input);
|
|
670
|
+
|
|
671
|
+
if (json) {
|
|
672
|
+
emitJson(stdout, "schemas set-unique-fields", data, filePath);
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (input.fieldIds.length === 0) {
|
|
677
|
+
writeLine(stdout, `Cleared unique fields on schema "${schema.value}".`);
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const count = input.fieldIds.length;
|
|
682
|
+
writeLine(
|
|
683
|
+
stdout,
|
|
684
|
+
`Set unique fields on schema "${schema.value}" (${count} field${count === 1 ? "" : "s"}).`,
|
|
685
|
+
);
|
|
686
|
+
});
|
|
687
|
+
|
|
599
688
|
schemas
|
|
600
689
|
.command("delete")
|
|
601
690
|
.description("Delete a schema")
|
package/src/utils/examples.ts
CHANGED
|
@@ -228,6 +228,7 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
|
|
|
228
228
|
},
|
|
229
229
|
"auditable": true,
|
|
230
230
|
"commentable": true,
|
|
231
|
+
"highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
231
232
|
"fields": [
|
|
232
233
|
{
|
|
233
234
|
"id": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
@@ -242,7 +243,8 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
|
|
|
242
243
|
"conditionalFormatting": []
|
|
243
244
|
}
|
|
244
245
|
}
|
|
245
|
-
]
|
|
246
|
+
],
|
|
247
|
+
"uniqueFields": []
|
|
246
248
|
}`,
|
|
247
249
|
},
|
|
248
250
|
{
|
|
@@ -259,6 +261,89 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
|
|
|
259
261
|
command: 'zinkee --json schemas update contacts --auditable true',
|
|
260
262
|
raw: `{
|
|
261
263
|
"auditable": true
|
|
264
|
+
}`,
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
description: "Set the highlighted (main) field of a schema.",
|
|
268
|
+
command:
|
|
269
|
+
'zinkee --json schemas update contacts --highlighted-field contact-name',
|
|
270
|
+
raw: `{
|
|
271
|
+
"highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34"
|
|
272
|
+
}`,
|
|
273
|
+
},
|
|
274
|
+
]),
|
|
275
|
+
"schemas set-unique-fields": buildCommandExamples([
|
|
276
|
+
{
|
|
277
|
+
description:
|
|
278
|
+
"Set a composite unique constraint: the listed fields must be unique together across records.",
|
|
279
|
+
command:
|
|
280
|
+
"zinkee --json schemas set-unique-fields contacts --field contact-name --field notes",
|
|
281
|
+
raw: `{
|
|
282
|
+
"fieldIds": [
|
|
283
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
284
|
+
"1d2e3f4a-5b6c-7d8e-9f01-23456789abcd"
|
|
285
|
+
]
|
|
286
|
+
}`,
|
|
287
|
+
response: `{
|
|
288
|
+
"id": "2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e",
|
|
289
|
+
"name": "Contacts",
|
|
290
|
+
"slug": "contacts",
|
|
291
|
+
"folder": {
|
|
292
|
+
"id": "7f4e7c25-d8b2-4c1a-9f3e-6a7b5c8d9e1f",
|
|
293
|
+
"name": "Customers",
|
|
294
|
+
"isRoot": false
|
|
295
|
+
},
|
|
296
|
+
"auditable": true,
|
|
297
|
+
"commentable": true,
|
|
298
|
+
"highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
299
|
+
"fields": [
|
|
300
|
+
{
|
|
301
|
+
"id": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
302
|
+
"type": "TextField",
|
|
303
|
+
"slug": "contact-name",
|
|
304
|
+
"label": "Customer Name",
|
|
305
|
+
"required": true,
|
|
306
|
+
"system": false,
|
|
307
|
+
"config": {
|
|
308
|
+
"textType": "NORMAL",
|
|
309
|
+
"defaultValue": "Unknown",
|
|
310
|
+
"conditionalFormatting": []
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"id": "1d2e3f4a-5b6c-7d8e-9f01-23456789abcd",
|
|
315
|
+
"type": "TextField",
|
|
316
|
+
"slug": "notes",
|
|
317
|
+
"label": "Notes",
|
|
318
|
+
"required": false,
|
|
319
|
+
"system": false,
|
|
320
|
+
"config": {
|
|
321
|
+
"textType": "LONG",
|
|
322
|
+
"defaultValue": null,
|
|
323
|
+
"conditionalFormatting": []
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
],
|
|
327
|
+
"uniqueFields": [
|
|
328
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
329
|
+
"1d2e3f4a-5b6c-7d8e-9f01-23456789abcd"
|
|
330
|
+
]
|
|
331
|
+
}`,
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
description: "Set a single-field unique constraint.",
|
|
335
|
+
command: "zinkee --json schemas set-unique-fields contacts --field contact-name",
|
|
336
|
+
raw: `{
|
|
337
|
+
"fieldIds": [
|
|
338
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34"
|
|
339
|
+
]
|
|
340
|
+
}`,
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
description: "Clear the unique constraint (no field must be unique anymore).",
|
|
344
|
+
command: "zinkee --json schemas set-unique-fields contacts --clear",
|
|
345
|
+
raw: `{
|
|
346
|
+
"fieldIds": []
|
|
262
347
|
}`,
|
|
263
348
|
},
|
|
264
349
|
]),
|
|
@@ -1904,6 +1989,7 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
|
|
|
1904
1989
|
},
|
|
1905
1990
|
"auditable": true,
|
|
1906
1991
|
"commentable": true,
|
|
1992
|
+
"highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
1907
1993
|
"fields": [
|
|
1908
1994
|
{
|
|
1909
1995
|
"id": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
@@ -2212,6 +2298,10 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
|
|
|
2212
2298
|
"conditionalFormatting": []
|
|
2213
2299
|
}
|
|
2214
2300
|
}
|
|
2301
|
+
],
|
|
2302
|
+
"uniqueFields": [
|
|
2303
|
+
"c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
2304
|
+
"1d2e3f4a-5b6c-7d8e-9f01-23456789abcd"
|
|
2215
2305
|
]
|
|
2216
2306
|
}`,
|
|
2217
2307
|
},
|