zinkee 0.1.39 → 0.1.40

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zinkee",
3
- "version": "0.1.39",
3
+ "version": "0.1.40",
4
4
  "description": "CLI for Zinkee API v2",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,6 +16,7 @@ export interface ApiAutomation {
16
16
  description?: string;
17
17
  status?: string;
18
18
  folderId?: string;
19
+ folder?: { id?: string; name?: string | null; isRoot?: boolean };
19
20
  trigger?: ApiAutomationTrigger;
20
21
  actions?: ApiAutomationAction[];
21
22
  }
@@ -16,6 +16,7 @@ export interface ApiDisplay {
16
16
  widgets?: Array<Record<string, unknown>>;
17
17
  navigationTargets?: Array<Record<string, unknown>>;
18
18
  crossWidgetFilter?: Array<Record<string, unknown>> | null;
19
+ folder?: { id?: string; name?: string | null; isRoot?: boolean };
19
20
  }
20
21
 
21
22
  export interface ApiDisplayTab {
@@ -20,6 +20,7 @@ export interface ApiSchema {
20
20
  highlightedField?: string;
21
21
  fields?: ApiSchemaField[];
22
22
  uniqueFields?: string[];
23
+ folder?: { id?: string; name?: string | null; isRoot?: boolean };
23
24
  }
24
25
 
25
26
  export interface CreateSchemaInput {
@@ -29,7 +29,7 @@ import {
29
29
  import { resolveRuntimeContext } from "../runtime-context.js";
30
30
  import type { JsonObject, JsonValue, RuntimeOverrides } from "../types.js";
31
31
  import { CliError } from "../utils/errors.js";
32
- import { buildJsonSuccess, printTable } from "../utils/output.js";
32
+ import { buildJsonSuccess, folderColumns, FOLDER_TABLE_KEYS, printTable } from "../utils/output.js";
33
33
 
34
34
  interface CommandIo {
35
35
  write(chunk: string): unknown;
@@ -800,12 +800,12 @@ function automationRows(automations: readonly ApiAutomation[]): Record<string, u
800
800
  id: automation.id ?? "",
801
801
  name: automation.name ?? "",
802
802
  status: automation.status ?? "",
803
- folderId: automation.folderId ?? "",
804
803
  triggerType:
805
804
  isJsonObject(automation.trigger) && typeof automation.trigger.type === "string"
806
805
  ? automation.trigger.type
807
806
  : "",
808
807
  actionCount: Array.isArray(automation.actions) ? automation.actions.length : "",
808
+ ...folderColumns(automation.folder),
809
809
  }));
810
810
  }
811
811
 
@@ -1569,7 +1569,7 @@ export function registerAutomationsCommands(
1569
1569
 
1570
1570
  printTable(
1571
1571
  automationRows(data),
1572
- ["id", "name", "status", "folderId", "triggerType", "actionCount"],
1572
+ ["id", "name", "status", "triggerType", "actionCount", ...FOLDER_TABLE_KEYS],
1573
1573
  stdout,
1574
1574
  );
1575
1575
  });
@@ -20,7 +20,7 @@ import { normalizeUuidOrSlug, type NormalizedUuidOrSlug } from "../parsers/selec
20
20
  import { resolveRuntimeContext } from "../runtime-context.js";
21
21
  import type { RuntimeOverrides } from "../types.js";
22
22
  import { CliError } from "../utils/errors.js";
23
- import { buildJsonSuccess, printTable } from "../utils/output.js";
23
+ import { buildJsonSuccess, folderColumns, FOLDER_TABLE_KEYS, printTable } from "../utils/output.js";
24
24
 
25
25
  const DATE_DYNAMIC_OPTIONS =
26
26
  "today, thisWeek, thisMonth, thisQuarter, thisSemester, thisYear, next7Days, next30Days, next6Months, next12Months, last12Months";
@@ -628,6 +628,7 @@ function displayRows(displays: readonly DisplaySummary[]): Record<string, unknow
628
628
  layoutTemplate: display.layoutTemplate ?? "",
629
629
  variableCount: display.variableCount ?? "",
630
630
  widgetCount: display.widgetCount ?? "",
631
+ ...folderColumns(display.folder),
631
632
  }));
632
633
  }
633
634
 
@@ -953,7 +954,11 @@ export function registerDisplaysCommands(
953
954
  emitJson(stdout, "displays list", data);
954
955
  return;
955
956
  }
956
- printTable(displayRows(data), ["id", "name", "layoutTemplate", "variableCount", "widgetCount"], stdout);
957
+ printTable(
958
+ displayRows(data),
959
+ ["id", "name", "layoutTemplate", "variableCount", "widgetCount", ...FOLDER_TABLE_KEYS],
960
+ stdout,
961
+ );
957
962
  });
958
963
 
959
964
  displays
@@ -31,7 +31,7 @@ import {
31
31
  normalizeSchemaFieldUpdatePayload,
32
32
  normalizeSchemaFieldType,
33
33
  } from "../utils/schema-fields.js";
34
- import { buildJsonSuccess, printTable } from "../utils/output.js";
34
+ import { buildJsonSuccess, folderColumns, FOLDER_TABLE_KEYS, printTable } from "../utils/output.js";
35
35
 
36
36
  interface CommandIo {
37
37
  write(chunk: string): unknown;
@@ -284,8 +284,9 @@ function emitSchemasTable(stdout: CommandIo, schemas: readonly ApiSchema[]): voi
284
284
  slug: schema.slug ?? "",
285
285
  auditable: schema.auditable ?? "",
286
286
  commentable: schema.commentable ?? "",
287
+ ...folderColumns(schema.folder),
287
288
  })),
288
- ["id", "name", "slug", "auditable", "commentable"],
289
+ ["id", "name", "slug", "auditable", "commentable", ...FOLDER_TABLE_KEYS],
289
290
  stdout,
290
291
  );
291
292
  }
@@ -274,6 +274,8 @@ describe("getCommandExamples", () => {
274
274
  expect(examples[0]?.response).toContain('"layoutTemplate": "widget_row_tabs"');
275
275
  expect(examples[0]?.response).toContain('"layoutTemplate": "freeform"');
276
276
  expect(examples[0]?.response).toContain('"layoutTemplate": "grid"');
277
+ expect(examples[0]?.response).toContain('"folder"');
278
+ expect(examples[0]?.response).toContain('"isRoot": true');
277
279
  });
278
280
 
279
281
  it("attaches a response body to schemas create and teamspace resources publish", () => {
@@ -2909,21 +2909,36 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
2909
2909
  "name": "Executive Revenue",
2910
2910
  "layoutTemplate": "widget_row_tabs",
2911
2911
  "variableCount": 3,
2912
- "widgetCount": 6
2912
+ "widgetCount": 6,
2913
+ "folder": {
2914
+ "id": "b1a2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
2915
+ "name": "📊 Executive",
2916
+ "isRoot": false
2917
+ }
2913
2918
  },
2914
2919
  {
2915
2920
  "id": "6b7c8d9e-0f12-3456-789a-bcdef0123456",
2916
2921
  "name": "Sales Pipeline",
2917
2922
  "layoutTemplate": "freeform",
2918
2923
  "variableCount": 1,
2919
- "widgetCount": 3
2924
+ "widgetCount": 3,
2925
+ "folder": {
2926
+ "id": "a0b1c2d3-e4f5-4061-8273-8495a6b7c8d9",
2927
+ "name": null,
2928
+ "isRoot": true
2929
+ }
2920
2930
  },
2921
2931
  {
2922
2932
  "id": "ef012345-6789-4abc-8def-0123456789ab",
2923
2933
  "name": "Customer Detail",
2924
2934
  "layoutTemplate": "grid",
2925
2935
  "variableCount": 0,
2926
- "widgetCount": 2
2936
+ "widgetCount": 2,
2937
+ "folder": {
2938
+ "id": "b1a2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
2939
+ "name": "📊 Executive",
2940
+ "isRoot": false
2941
+ }
2927
2942
  }
2928
2943
  ]`,
2929
2944
  },
@@ -3056,7 +3071,12 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
3056
3071
  "targetVariableId": "aaaaaaaa-1111-4111-a111-111111111111",
3057
3072
  "label": "Open customer"
3058
3073
  }
3059
- ]
3074
+ ],
3075
+ "folder": {
3076
+ "id": "b1a2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
3077
+ "name": "📊 Executive",
3078
+ "isRoot": false
3079
+ }
3060
3080
  }`,
3061
3081
  },
3062
3082
  ]),
@@ -2,7 +2,33 @@ import { describe, expect, it } from "vitest";
2
2
 
3
3
  import { getCommandMeta } from "../command-registry.js";
4
4
 
5
- import { buildJsonError, buildJsonSuccess } from "./output.js";
5
+ import { buildJsonError, buildJsonSuccess, folderColumns } from "./output.js";
6
+
7
+ describe("folderColumns", () => {
8
+ it("flattens a named folder into id/name/isRoot columns", () => {
9
+ expect(folderColumns({ id: "f1", name: "Finance", isRoot: false })).toEqual({
10
+ folderId: "f1",
11
+ folderName: "Finance",
12
+ folderIsRoot: "false",
13
+ });
14
+ });
15
+
16
+ it("renders the root folder (null name) as (root)", () => {
17
+ expect(folderColumns({ id: "root-1", name: null, isRoot: true })).toEqual({
18
+ folderId: "root-1",
19
+ folderName: "(root)",
20
+ folderIsRoot: "true",
21
+ });
22
+ });
23
+
24
+ it("leaves every column empty when there is no folder", () => {
25
+ expect(folderColumns(undefined)).toEqual({
26
+ folderId: "",
27
+ folderName: "",
28
+ folderIsRoot: "",
29
+ });
30
+ });
31
+ });
6
32
 
7
33
  describe("buildJsonSuccess", () => {
8
34
  it("wraps data in the standard success envelope", () => {
@@ -59,6 +59,36 @@ export function buildTableColumns(keys: readonly string[]): readonly TableColumn
59
59
  return keys.map((key) => ({ key, label: key }));
60
60
  }
61
61
 
62
+ export interface FolderLocation {
63
+ id?: string;
64
+ name?: string | null;
65
+ isRoot?: boolean;
66
+ }
67
+
68
+ /** Column keys, in order, produced by {@link folderColumns}. Append them to a table's key list. */
69
+ export const FOLDER_TABLE_KEYS = ["folderId", "folderName", "folderIsRoot"] as const;
70
+
71
+ /**
72
+ * Flattens the API `folder` object (`{ id, name, isRoot }`) into the folderId/folderName/folderIsRoot table columns.
73
+ * The root folder arrives with a null name, so folderName renders it as "(root)". A missing folder (e.g. a workspace
74
+ * without a default group) leaves every column empty.
75
+ */
76
+ export function folderColumns(folder: FolderLocation | null | undefined): {
77
+ folderId: string;
78
+ folderName: string;
79
+ folderIsRoot: string;
80
+ } {
81
+ if (!folder) {
82
+ return { folderId: "", folderName: "", folderIsRoot: "" };
83
+ }
84
+
85
+ return {
86
+ folderId: folder.id ?? "",
87
+ folderName: folder.name ?? (folder.isRoot === true ? "(root)" : ""),
88
+ folderIsRoot: folder.isRoot === undefined ? "" : String(folder.isRoot),
89
+ };
90
+ }
91
+
62
92
  export function buildTableRows(
63
93
  rows: readonly Record<string, unknown>[],
64
94
  columns: readonly TableColumn[],