@izumisy-tailor/tailor-data-viewer 0.3.0 → 0.3.1
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/generator/index.d.mts +0 -2
- package/dist/generator/index.mjs +0 -22
- package/package.json +1 -1
- package/src/component/collection/use-collection.test.ts +0 -1
- package/src/component/collection/use-collection.typetest.ts +6 -3
- package/src/component/field-helpers.test.ts +0 -4
- package/src/component/types.ts +18 -1
- package/src/generator/metadata-generator.ts +0 -63
|
@@ -64,7 +64,6 @@ interface TableMetadata {
|
|
|
64
64
|
readonly name: string;
|
|
65
65
|
readonly pluralForm: string;
|
|
66
66
|
readonly description?: string;
|
|
67
|
-
readonly readAllowedRoles: readonly string[];
|
|
68
67
|
readonly fields: readonly FieldMetadata[];
|
|
69
68
|
/** Relations (manyToOne, oneToOne, and oneToMany) */
|
|
70
69
|
readonly relations?: readonly RelationMetadata[];
|
|
@@ -89,7 +88,6 @@ interface ProcessedTable {
|
|
|
89
88
|
pluralForm: string;
|
|
90
89
|
originalName: string;
|
|
91
90
|
description?: string;
|
|
92
|
-
readAllowedRoles: string[];
|
|
93
91
|
fields: FieldMetadata[];
|
|
94
92
|
relations: RelationMetadata[];
|
|
95
93
|
}
|
package/dist/generator/index.mjs
CHANGED
|
@@ -29,26 +29,6 @@ function toCamelCase(str) {
|
|
|
29
29
|
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
|
-
* Extract allowed roles from gql permission policies
|
|
33
|
-
* Only extracts roles from 'read' action policies with 'allow' permit
|
|
34
|
-
*/
|
|
35
|
-
function extractReadAllowedRoles(gqlPermission) {
|
|
36
|
-
if (!gqlPermission) return [];
|
|
37
|
-
const roles = /* @__PURE__ */ new Set();
|
|
38
|
-
for (const policy of gqlPermission) {
|
|
39
|
-
if (policy.permit !== "allow") continue;
|
|
40
|
-
const actions = policy.actions;
|
|
41
|
-
if (!actions.includes("all") && !actions.includes("read")) continue;
|
|
42
|
-
for (const condition of policy.conditions) {
|
|
43
|
-
if (!Array.isArray(condition) || condition.length < 3) continue;
|
|
44
|
-
const [left, operator, right] = condition;
|
|
45
|
-
if (typeof left === "string" && operator === "in" && typeof right === "object" && right !== null && "user" in right && right.user === "roles") roles.add(left);
|
|
46
|
-
if (typeof right === "string" && operator === "in" && typeof left === "object" && left !== null && "user" in left && left.user === "roles") roles.add(right);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return Array.from(roles);
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
32
|
* Creates a custom generator that extracts table metadata for Data View
|
|
53
33
|
*/
|
|
54
34
|
function dataViewerMetadataGenerator(options = {}) {
|
|
@@ -100,13 +80,11 @@ function dataViewerMetadataGenerator(options = {}) {
|
|
|
100
80
|
};
|
|
101
81
|
fields.push(fieldMetadata);
|
|
102
82
|
}
|
|
103
|
-
const readAllowedRoles = extractReadAllowedRoles(type.permissions.gql);
|
|
104
83
|
return {
|
|
105
84
|
name: toCamelCase(type.name),
|
|
106
85
|
pluralForm: toCamelCase(type.pluralForm),
|
|
107
86
|
originalName: type.name,
|
|
108
87
|
description: type.description,
|
|
109
|
-
readAllowedRoles,
|
|
110
88
|
fields,
|
|
111
89
|
relations
|
|
112
90
|
};
|
package/package.json
CHANGED
|
@@ -22,7 +22,6 @@ import type { TableMetadata } from "../../generator/metadata-generator";
|
|
|
22
22
|
type TestTable = {
|
|
23
23
|
readonly name: "test";
|
|
24
24
|
readonly pluralForm: "tests";
|
|
25
|
-
readonly readAllowedRoles: readonly [];
|
|
26
25
|
readonly fields: readonly [
|
|
27
26
|
{ readonly name: "id"; readonly type: "uuid"; readonly required: true },
|
|
28
27
|
{
|
|
@@ -82,9 +81,13 @@ type AssertNumberField = TestQuery extends {
|
|
|
82
81
|
: never;
|
|
83
82
|
export const assertNumberField: AssertNumberField = true;
|
|
84
83
|
|
|
85
|
-
// ✅ Enum fields produce
|
|
84
|
+
// ✅ Enum fields produce literal union types from enumValues
|
|
86
85
|
type AssertEnumField = TestQuery extends {
|
|
87
|
-
status?: {
|
|
86
|
+
status?: {
|
|
87
|
+
eq?: "active" | "inactive";
|
|
88
|
+
in?: ("active" | "inactive")[];
|
|
89
|
+
nin?: ("active" | "inactive")[];
|
|
90
|
+
};
|
|
88
91
|
}
|
|
89
92
|
? true
|
|
90
93
|
: never;
|
|
@@ -75,7 +75,6 @@ describe("inferColumns()", () => {
|
|
|
75
75
|
const metadata = {
|
|
76
76
|
name: "task",
|
|
77
77
|
pluralForm: "tasks",
|
|
78
|
-
readAllowedRoles: [],
|
|
79
78
|
fields: [
|
|
80
79
|
{ name: "id", type: "uuid", required: true },
|
|
81
80
|
{ name: "title", type: "string", required: true },
|
|
@@ -204,7 +203,6 @@ describe("inferColumns() with metadata", () => {
|
|
|
204
203
|
task: {
|
|
205
204
|
name: "task",
|
|
206
205
|
pluralForm: "tasks",
|
|
207
|
-
readAllowedRoles: [],
|
|
208
206
|
fields: [
|
|
209
207
|
{ name: "id", type: "uuid", required: true },
|
|
210
208
|
{ name: "title", type: "string", required: true },
|
|
@@ -370,7 +368,6 @@ describe("createColumnHelper()", () => {
|
|
|
370
368
|
const metadata = {
|
|
371
369
|
name: "order",
|
|
372
370
|
pluralForm: "orders",
|
|
373
|
-
readAllowedRoles: [],
|
|
374
371
|
fields: [
|
|
375
372
|
{ name: "id", type: "uuid", required: true },
|
|
376
373
|
{ name: "name", type: "string", required: true },
|
|
@@ -390,7 +387,6 @@ describe("createColumnHelper()", () => {
|
|
|
390
387
|
const metadata = {
|
|
391
388
|
name: "order",
|
|
392
389
|
pluralForm: "orders",
|
|
393
|
-
readAllowedRoles: [],
|
|
394
390
|
fields: [
|
|
395
391
|
{ name: "id", type: "uuid", required: true },
|
|
396
392
|
{ name: "name", type: "string", required: true },
|
package/src/component/types.ts
CHANGED
|
@@ -274,6 +274,23 @@ type FieldTypeToTSType = {
|
|
|
274
274
|
enum: string;
|
|
275
275
|
};
|
|
276
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Resolves the value type for a field, narrowing enum fields to their
|
|
279
|
+
* literal union when `enumValues` is present in the metadata.
|
|
280
|
+
*
|
|
281
|
+
* - enum field with `enumValues: readonly ["OPEN", "CLOSED"]` → `"OPEN" | "CLOSED"`
|
|
282
|
+
* - enum field without `enumValues` → `string` (fallback)
|
|
283
|
+
* - all other field types → `FieldTypeToTSType[T]` (unchanged)
|
|
284
|
+
*/
|
|
285
|
+
type ResolveFieldValueType<
|
|
286
|
+
F,
|
|
287
|
+
T extends keyof FieldTypeToTSType,
|
|
288
|
+
> = T extends "enum"
|
|
289
|
+
? F extends { readonly enumValues: readonly (infer V extends string)[] }
|
|
290
|
+
? V
|
|
291
|
+
: string
|
|
292
|
+
: FieldTypeToTSType[T];
|
|
293
|
+
|
|
277
294
|
/**
|
|
278
295
|
* Resolves the value type for a filter operator.
|
|
279
296
|
* `in`/`nin` operators accept arrays, `between` accepts `{ min, max }`,
|
|
@@ -324,7 +341,7 @@ export type BuildQueryVariables<TTable extends TableMetadata> = {
|
|
|
324
341
|
}
|
|
325
342
|
? FieldTypeToFilterConfigType[T] extends infer FCT extends
|
|
326
343
|
FilterConfig["type"]
|
|
327
|
-
? FilterInputForFieldType<FCT,
|
|
344
|
+
? FilterInputForFieldType<FCT, ResolveFieldValueType<F, T>>
|
|
328
345
|
: never
|
|
329
346
|
: never;
|
|
330
347
|
};
|
|
@@ -86,7 +86,6 @@ export interface TableMetadata {
|
|
|
86
86
|
readonly name: string;
|
|
87
87
|
readonly pluralForm: string;
|
|
88
88
|
readonly description?: string;
|
|
89
|
-
readonly readAllowedRoles: readonly string[];
|
|
90
89
|
readonly fields: readonly FieldMetadata[];
|
|
91
90
|
/** Relations (manyToOne, oneToOne, and oneToMany) */
|
|
92
91
|
readonly relations?: readonly RelationMetadata[];
|
|
@@ -112,7 +111,6 @@ interface ProcessedTable {
|
|
|
112
111
|
pluralForm: string;
|
|
113
112
|
originalName: string; // PascalCase name for relation lookup
|
|
114
113
|
description?: string;
|
|
115
|
-
readAllowedRoles: string[];
|
|
116
114
|
fields: FieldMetadata[];
|
|
117
115
|
relations: RelationMetadata[];
|
|
118
116
|
}
|
|
@@ -154,63 +152,6 @@ function toCamelCase(str: string): string {
|
|
|
154
152
|
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
155
153
|
}
|
|
156
154
|
|
|
157
|
-
/**
|
|
158
|
-
* Extract allowed roles from gql permission policies
|
|
159
|
-
* Only extracts roles from 'read' action policies with 'allow' permit
|
|
160
|
-
*/
|
|
161
|
-
function extractReadAllowedRoles(
|
|
162
|
-
gqlPermission?: readonly {
|
|
163
|
-
conditions: readonly unknown[];
|
|
164
|
-
actions: readonly ["all"] | readonly string[];
|
|
165
|
-
permit: "allow" | "deny";
|
|
166
|
-
description?: string;
|
|
167
|
-
}[],
|
|
168
|
-
): string[] {
|
|
169
|
-
if (!gqlPermission) return [];
|
|
170
|
-
|
|
171
|
-
const roles = new Set<string>();
|
|
172
|
-
|
|
173
|
-
for (const policy of gqlPermission) {
|
|
174
|
-
// Only process 'allow' policies that include 'read' action
|
|
175
|
-
if (policy.permit !== "allow") continue;
|
|
176
|
-
const actions = policy.actions as readonly string[];
|
|
177
|
-
if (!actions.includes("all") && !actions.includes("read")) continue;
|
|
178
|
-
|
|
179
|
-
// Extract roles from conditions
|
|
180
|
-
for (const condition of policy.conditions) {
|
|
181
|
-
if (!Array.isArray(condition) || condition.length < 3) continue;
|
|
182
|
-
|
|
183
|
-
const [left, operator, right] = condition;
|
|
184
|
-
|
|
185
|
-
// Check for pattern: ["ROLE_NAME", "in", { user: "roles" }]
|
|
186
|
-
if (
|
|
187
|
-
typeof left === "string" &&
|
|
188
|
-
operator === "in" &&
|
|
189
|
-
typeof right === "object" &&
|
|
190
|
-
right !== null &&
|
|
191
|
-
"user" in right &&
|
|
192
|
-
(right as { user: string }).user === "roles"
|
|
193
|
-
) {
|
|
194
|
-
roles.add(left);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Check for pattern: [{ user: "roles" }, "in", "ROLE_NAME"] (reversed)
|
|
198
|
-
if (
|
|
199
|
-
typeof right === "string" &&
|
|
200
|
-
operator === "in" &&
|
|
201
|
-
typeof left === "object" &&
|
|
202
|
-
left !== null &&
|
|
203
|
-
"user" in left &&
|
|
204
|
-
(left as { user: string }).user === "roles"
|
|
205
|
-
) {
|
|
206
|
-
roles.add(right);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return Array.from(roles);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
155
|
/**
|
|
215
156
|
* Parsed field type from TailorDB
|
|
216
157
|
*/
|
|
@@ -402,15 +343,11 @@ export function dataViewerMetadataGenerator(
|
|
|
402
343
|
fields.push(fieldMetadata);
|
|
403
344
|
}
|
|
404
345
|
|
|
405
|
-
// Extract read allowed roles from gql permission
|
|
406
|
-
const readAllowedRoles = extractReadAllowedRoles(type.permissions.gql);
|
|
407
|
-
|
|
408
346
|
return {
|
|
409
347
|
name: toCamelCase(type.name),
|
|
410
348
|
pluralForm: toCamelCase(type.pluralForm),
|
|
411
349
|
originalName: type.name,
|
|
412
350
|
description: type.description,
|
|
413
|
-
readAllowedRoles,
|
|
414
351
|
fields,
|
|
415
352
|
relations,
|
|
416
353
|
};
|