@kronor/dtv 0.2.9

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.
Files changed (97) hide show
  1. package/.editorconfig +12 -0
  2. package/.github/copilot-instructions.md +64 -0
  3. package/.github/workflows/ci.yml +51 -0
  4. package/.husky/pre-commit +8 -0
  5. package/README.md +63 -0
  6. package/docs/api/README.md +32 -0
  7. package/docs/api/cell-renderers.md +121 -0
  8. package/docs/api/no-rows-component.md +71 -0
  9. package/docs/api/runtime.md +78 -0
  10. package/e2e/app.spec.ts +6 -0
  11. package/e2e/cell-renderer-setfilterstate.spec.ts +63 -0
  12. package/e2e/filter-sharing.spec.ts +113 -0
  13. package/e2e/filter-url-persistence.spec.ts +36 -0
  14. package/e2e/graphqlMock.ts +144 -0
  15. package/e2e/multi-field-filters.spec.ts +95 -0
  16. package/e2e/pagination.spec.ts +38 -0
  17. package/e2e/payment-request-email-filter.spec.ts +67 -0
  18. package/e2e/save-filter-splitbutton.spec.ts +68 -0
  19. package/e2e/simple-view-email-filter.spec.ts +67 -0
  20. package/e2e/simple-view-transforms.spec.ts +171 -0
  21. package/e2e/simple-view.spec.ts +104 -0
  22. package/e2e/transform-regression.spec.ts +108 -0
  23. package/eslint.config.js +30 -0
  24. package/index.html +17 -0
  25. package/jest.config.js +10 -0
  26. package/package.json +45 -0
  27. package/playwright.config.ts +54 -0
  28. package/public/vite.svg +1 -0
  29. package/src/App.externalRuntime.test.ts +190 -0
  30. package/src/App.tsx +540 -0
  31. package/src/assets/react.svg +1 -0
  32. package/src/components/AIAssistantForm.tsx +241 -0
  33. package/src/components/FilterForm.test.ts +82 -0
  34. package/src/components/FilterForm.tsx +375 -0
  35. package/src/components/PhoneNumberFilter.tsx +102 -0
  36. package/src/components/SavedFilterList.tsx +181 -0
  37. package/src/components/SpeechInput.tsx +67 -0
  38. package/src/components/Table.tsx +119 -0
  39. package/src/components/TablePagination.tsx +40 -0
  40. package/src/components/aiAssistant.test.ts +270 -0
  41. package/src/components/aiAssistant.ts +291 -0
  42. package/src/framework/cell-renderer-components/CurrencyAmount.tsx +30 -0
  43. package/src/framework/cell-renderer-components/LayoutHelpers.tsx +74 -0
  44. package/src/framework/cell-renderer-components/Link.tsx +28 -0
  45. package/src/framework/cell-renderer-components/Mapping.tsx +11 -0
  46. package/src/framework/cell-renderer-components.test.ts +353 -0
  47. package/src/framework/column-definition.tsx +85 -0
  48. package/src/framework/currency.test.ts +46 -0
  49. package/src/framework/currency.ts +62 -0
  50. package/src/framework/data.staticConditions.test.ts +46 -0
  51. package/src/framework/data.test.ts +167 -0
  52. package/src/framework/data.ts +162 -0
  53. package/src/framework/filter-form-state.test.ts +189 -0
  54. package/src/framework/filter-form-state.ts +185 -0
  55. package/src/framework/filter-sharing.test.ts +135 -0
  56. package/src/framework/filter-sharing.ts +118 -0
  57. package/src/framework/filters.ts +194 -0
  58. package/src/framework/graphql.buildHasuraConditions.test.ts +473 -0
  59. package/src/framework/graphql.paginationKey.test.ts +29 -0
  60. package/src/framework/graphql.test.ts +286 -0
  61. package/src/framework/graphql.ts +462 -0
  62. package/src/framework/native-runtime/index.tsx +33 -0
  63. package/src/framework/native-runtime/nativeComponents.test.ts +108 -0
  64. package/src/framework/runtime-reference.test.ts +172 -0
  65. package/src/framework/runtime.ts +15 -0
  66. package/src/framework/saved-filters.test.ts +422 -0
  67. package/src/framework/saved-filters.ts +293 -0
  68. package/src/framework/state.test.ts +86 -0
  69. package/src/framework/state.ts +148 -0
  70. package/src/framework/transform.test.ts +51 -0
  71. package/src/framework/view-parser-initialvalues.test.ts +228 -0
  72. package/src/framework/view-parser.ts +714 -0
  73. package/src/framework/view.test.ts +1805 -0
  74. package/src/framework/view.ts +38 -0
  75. package/src/index.css +6 -0
  76. package/src/main.tsx +99 -0
  77. package/src/views/index.ts +12 -0
  78. package/src/views/payment-requests/components/NoRowsExtendDateRange.tsx +37 -0
  79. package/src/views/payment-requests/components/PaymentMethod.tsx +184 -0
  80. package/src/views/payment-requests/components/PaymentStatusTag.tsx +61 -0
  81. package/src/views/payment-requests/index.ts +1 -0
  82. package/src/views/payment-requests/runtime.tsx +145 -0
  83. package/src/views/payment-requests/view.json +692 -0
  84. package/src/views/payment-requests-initial-values.test.ts +73 -0
  85. package/src/views/request-log/index.ts +2 -0
  86. package/src/views/request-log/runtime.tsx +47 -0
  87. package/src/views/request-log/view.json +123 -0
  88. package/src/views/simple-test-view/index.ts +3 -0
  89. package/src/views/simple-test-view/runtime.tsx +85 -0
  90. package/src/views/simple-test-view/view.json +191 -0
  91. package/src/vite-env.d.ts +1 -0
  92. package/tailwind.config.js +7 -0
  93. package/tsconfig.app.json +26 -0
  94. package/tsconfig.jest.json +6 -0
  95. package/tsconfig.json +7 -0
  96. package/tsconfig.node.json +24 -0
  97. package/vite.config.ts +11 -0
@@ -0,0 +1,286 @@
1
+ import { renderGraphQLQuery, GraphQLQueryAST, generateGraphQLQueryAST } from "./graphql";
2
+ import { ColumnDefinition, fieldAlias, field, queryConfigs } from "./column-definition";
3
+
4
+ describe("renderGraphQLQuery", () => {
5
+ it("renders a simple query with variables and selection set", () => {
6
+ const ast: GraphQLQueryAST = {
7
+ operation: "query",
8
+ name: "GetUsers",
9
+ variables: [
10
+ { name: "conditions", type: "UserBoolExp" },
11
+ { name: "limit", type: "Int" }
12
+ ],
13
+ rootField: "users",
14
+ selectionSet: [
15
+ { field: "id" },
16
+ { field: "name" },
17
+ {
18
+ field: "posts", limit: 5, order_by: [{ createdAt: 'DESC' }], selections: [
19
+ { field: "title" },
20
+ { field: "content" }
21
+ ]
22
+ }
23
+ ]
24
+ };
25
+ const result = renderGraphQLQuery(ast);
26
+ expect(result).toContain("query GetUsers($conditions: UserBoolExp, $limit: Int)");
27
+ expect(result).toContain("users {");
28
+ expect(result).toContain("id");
29
+ expect(result).toContain("name");
30
+ expect(result).toContain("posts(limit: 5, orderBy: [{createdAt: DESC}])");
31
+ expect(result).toContain("title");
32
+ expect(result).toContain("content");
33
+ });
34
+
35
+ it("renders a query with Hasura operators in where", () => {
36
+ const ast: GraphQLQueryAST = {
37
+ operation: "query",
38
+ name: "GetUsersWithFilters",
39
+ variables: [
40
+ { name: "conditions", type: "UserBoolExp" },
41
+ { name: "limit", type: "Int" }
42
+ ],
43
+ rootField: "users",
44
+ selectionSet: [
45
+ { field: "id" },
46
+ { field: "name" },
47
+ {
48
+ field: "posts",
49
+ where: {
50
+ _and: [
51
+ { title: { _ilike: "%graphql%" } },
52
+ { published: { _eq: true } },
53
+ { author_id: { _in: [1, 2, 3] } }
54
+ ]
55
+ },
56
+ limit: 10,
57
+ order_by: [{ createdAt: 'DESC' }],
58
+ selections: [
59
+ { field: "title" },
60
+ { field: "content" }
61
+ ]
62
+ }
63
+ ]
64
+ };
65
+ const result = renderGraphQLQuery(ast);
66
+ expect(result).toContain("query GetUsersWithFilters($conditions: UserBoolExp, $limit: Int)");
67
+ expect(result).toContain("users {");
68
+ expect(result).toContain("id");
69
+ expect(result).toContain("name");
70
+ expect(result).toContain("posts(where: {_and: [title: {_ilike: \"%graphql%\"}, published: {_eq: true}, author_id: {_in: [1,2,3]}]}, limit: 10, orderBy: [{createdAt: DESC}])");
71
+ expect(result).toContain("title");
72
+ expect(result).toContain("content");
73
+ });
74
+ });
75
+
76
+ describe("generateGraphQLQueryAST", () => {
77
+ it("should convert column definitions to a GraphQLQueryAST", () => {
78
+ const columns: ColumnDefinition[] = [
79
+ {
80
+ name: "ID",
81
+ data: [{ type: "field", path: "id" }],
82
+ cellRenderer: () => null,
83
+ },
84
+ {
85
+ name: "Name",
86
+ data: [{ type: "field", path: "name" }],
87
+ cellRenderer: () => null,
88
+ },
89
+ {
90
+ name: "Posts",
91
+ data: [
92
+ {
93
+ type: "queryConfigs",
94
+ configs: [
95
+ {
96
+ field: "posts",
97
+ limit: 5,
98
+ orderBy: { key: "createdAt", direction: "DESC" },
99
+ },
100
+ {
101
+ field: "title",
102
+ },
103
+ ],
104
+ },
105
+ ],
106
+ cellRenderer: () => null,
107
+ },
108
+ ];
109
+
110
+ const ast = generateGraphQLQueryAST("testRoot", columns, "TestBoolExp", "TestOrderBy");
111
+
112
+ expect(ast.operation).toBe("query");
113
+ expect(ast.variables).toEqual([
114
+ { name: "conditions", type: "TestBoolExp" },
115
+ { name: "limit", type: "Int" },
116
+ { name: "orderBy", type: "TestOrderBy" },
117
+ ]);
118
+ expect(ast.rootField).toBe("testRoot(where: $conditions, limit: $limit, orderBy: $orderBy)");
119
+ expect(ast.selectionSet).toEqual([
120
+ { field: "id" },
121
+ { field: "name" },
122
+ {
123
+ field: "posts",
124
+ limit: 5,
125
+ order_by: { createdAt: "DESC" },
126
+ selections: [{ field: "title" }],
127
+ },
128
+ ]);
129
+ });
130
+
131
+ it("should handle nested fields and merge selection sets", () => {
132
+ const columns: ColumnDefinition[] = [
133
+ { name: "ID", data: [{ type: "field", path: "id" }], cellRenderer: () => null },
134
+ { name: "Author Name", data: [{ type: "field", path: "author.name" }], cellRenderer: () => null },
135
+ { name: "Author ID", data: [{ type: "field", path: "author.id" }], cellRenderer: () => null },
136
+ { name: "First Comment", data: [{ type: "field", path: "comments.0.text" }], cellRenderer: () => null },
137
+ { name: "First Commenter", data: [{ type: "field", path: "comments.0.user.name" }], cellRenderer: () => null },
138
+ ];
139
+
140
+ const ast = generateGraphQLQueryAST("testRoot", columns, "TestBoolExp", "TestOrderBy");
141
+
142
+ expect(ast.selectionSet).toEqual([
143
+ { field: "id" },
144
+ {
145
+ field: "author",
146
+ selections: [
147
+ { field: "name" },
148
+ { field: "id" },
149
+ ],
150
+ },
151
+ {
152
+ field: "comments",
153
+ selections: [
154
+ {
155
+ field: "0",
156
+ selections: [
157
+ { field: "text" },
158
+ {
159
+ field: "user",
160
+ selections: [{ field: "name" }],
161
+ },
162
+ ],
163
+ },
164
+ ],
165
+ },
166
+ ]);
167
+ });
168
+
169
+ it("generates GraphQL query with field aliases", () => {
170
+ const columns: ColumnDefinition[] = [
171
+ {
172
+ name: "ID",
173
+ data: [field("id")],
174
+ cellRenderer: () => null,
175
+ },
176
+ {
177
+ name: "Recent Posts",
178
+ data: [
179
+ fieldAlias(
180
+ "recentPosts",
181
+ queryConfigs([
182
+ {
183
+ field: "posts",
184
+ limit: 3,
185
+ orderBy: { key: "created_at", direction: "DESC" },
186
+ },
187
+ {
188
+ field: "title",
189
+ },
190
+ ])
191
+ ),
192
+ ],
193
+ cellRenderer: () => null,
194
+ },
195
+ {
196
+ name: "User Name",
197
+ data: [fieldAlias("userName", field("user.name"))],
198
+ cellRenderer: () => null,
199
+ },
200
+ ];
201
+
202
+ const ast = generateGraphQLQueryAST("testRoot", columns, "TestBoolExp", "TestOrderBy");
203
+
204
+ expect(ast.selectionSet).toEqual([
205
+ { field: "id" },
206
+ {
207
+ field: "posts",
208
+ alias: "recentPosts",
209
+ limit: 3,
210
+ order_by: { created_at: "DESC" },
211
+ selections: [{ field: "title" }],
212
+ },
213
+ {
214
+ field: "user",
215
+ selections: [
216
+ {
217
+ field: "name",
218
+ alias: "userName"
219
+ }
220
+ ],
221
+ },
222
+ ]);
223
+
224
+ const query = renderGraphQLQuery(ast);
225
+ expect(query).toContain("recentPosts: posts(limit: 3, orderBy: {created_at: DESC})");
226
+ expect(query).toContain("userName: name");
227
+ });
228
+
229
+ it("generates GraphQL query with path support for JSON columns", () => {
230
+ const columns: ColumnDefinition[] = [
231
+ {
232
+ name: "ID",
233
+ data: [field("id")],
234
+ cellRenderer: () => null,
235
+ },
236
+ {
237
+ name: "JSON Field Value",
238
+ data: [
239
+ queryConfigs([
240
+ {
241
+ field: "metadata",
242
+ path: "$.user.preferences.theme",
243
+ },
244
+ ])
245
+ ],
246
+ cellRenderer: () => null,
247
+ },
248
+ {
249
+ name: "JSON Array Element",
250
+ data: [
251
+ fieldAlias(
252
+ "firstTag",
253
+ queryConfigs([
254
+ {
255
+ field: "tags",
256
+ path: "$[0]",
257
+ limit: 1,
258
+ },
259
+ ])
260
+ )
261
+ ],
262
+ cellRenderer: () => null,
263
+ },
264
+ ];
265
+
266
+ const ast = generateGraphQLQueryAST("testRoot", columns, "TestBoolExp", "TestOrderBy");
267
+
268
+ expect(ast.selectionSet).toEqual([
269
+ { field: "id" },
270
+ {
271
+ field: "metadata",
272
+ path: "$.user.preferences.theme",
273
+ },
274
+ {
275
+ field: "tags",
276
+ alias: "firstTag",
277
+ path: "$[0]",
278
+ limit: 1,
279
+ },
280
+ ]);
281
+
282
+ const query = renderGraphQLQuery(ast);
283
+ expect(query).toContain('metadata(path: "$.user.preferences.theme")');
284
+ expect(query).toContain('firstTag: tags(limit: 1, path: "$[0]")');
285
+ });
286
+ });