@peak-ai/canvas 1.4.11 → 1.4.12-rc.12

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 (184) hide show
  1. package/package.json +6 -44
  2. package/plugins/helpers/styled-info-button.js +2 -0
  3. package/plugins/helpers/styled-info-button.js.map +1 -0
  4. package/.babelrc +0 -14
  5. package/.eslintcache +0 -1
  6. package/.eslintignore +0 -5
  7. package/.eslintrc.js +0 -29
  8. package/dist/package.json +0 -62
  9. package/dist/plugins/helpers/styled-info-button.js +0 -2
  10. package/dist/plugins/helpers/styled-info-button.js.map +0 -1
  11. package/scripts/build.ts +0 -88
  12. package/src/GrapesjsCanvas.tsx +0 -340
  13. package/src/constants/index.ts +0 -27
  14. package/src/helpers/compiled-table.css +0 -2429
  15. package/src/helpers/css.ts +0 -2515
  16. package/src/helpers/date-picker.ts +0 -807
  17. package/src/helpers/index.ts +0 -13
  18. package/src/helpers/merge-json.ts +0 -106
  19. package/src/index.styles.ts +0 -58
  20. package/src/index.ts +0 -9
  21. package/src/plugins/grapejs-plugin.tsx +0 -139
  22. package/src/plugins/helpers/custom-modal.tsx +0 -111
  23. package/src/plugins/helpers/data-table.tsx +0 -300
  24. package/src/plugins/helpers/extra.tsx +0 -164
  25. package/src/plugins/helpers/query-details-modal.tsx +0 -240
  26. package/src/plugins/helpers/query-loading-modal.tsx +0 -36
  27. package/src/plugins/helpers/render-components.tsx +0 -1211
  28. package/src/plugins/helpers/styled-info-button.tsx +0 -320
  29. package/src/public/canvas.css +0 -42
  30. package/src/public/components-css/table/table-output.css +0 -2436
  31. package/src/public/components-css/table/table.css +0 -30
  32. package/src/public/output.css +0 -2336
  33. package/src/public/table.css +0 -135
  34. package/src/shadcn/components/icons/AiAvatarIcon.tsx +0 -47
  35. package/src/shadcn/components/icons/Co_driver Expanding button copy.svg +0 -21
  36. package/src/shadcn/components/icons/ai-avatar.svg +0 -7
  37. package/src/shadcn/components/icons/thinking.gif +0 -0
  38. package/src/shadcn/components/ui/button.tsx +0 -132
  39. package/src/shadcn/components/ui/card.tsx +0 -92
  40. package/src/shadcn/components/ui/chart.tsx +0 -324
  41. package/src/shadcn/components/ui/checkbox.tsx +0 -27
  42. package/src/shadcn/components/ui/component-wrapper.tsx +0 -61
  43. package/src/shadcn/components/ui/date-filter.tsx +0 -816
  44. package/src/shadcn/components/ui/error-container.tsx +0 -125
  45. package/src/shadcn/components/ui/error-wrapper.tsx +0 -124
  46. package/src/shadcn/components/ui/filter.tsx +0 -366
  47. package/src/shadcn/components/ui/hover-card.tsx +0 -36
  48. package/src/shadcn/components/ui/input.tsx +0 -20
  49. package/src/shadcn/components/ui/label.tsx +0 -24
  50. package/src/shadcn/components/ui/pagination.tsx +0 -213
  51. package/src/shadcn/components/ui/scroll-area.tsx +0 -59
  52. package/src/shadcn/components/ui/search.tsx +0 -149
  53. package/src/shadcn/components/ui/separator.tsx +0 -26
  54. package/src/shadcn/components/ui/skeleton.tsx +0 -69
  55. package/src/shadcn/components/ui/table.tsx +0 -196
  56. package/src/shadcn/components/ui/tabs.tsx +0 -55
  57. package/src/shadcn/components/ui/textarea.tsx +0 -18
  58. package/src/shadcn/components/ui/tooltip.tsx +0 -87
  59. package/src/shadcn/utils.ts +0 -6
  60. package/src/types/grapesjs-tailwind.d.ts +0 -61
  61. package/tailwind.config.js +0 -5
  62. package/tooling/tailwind-compiler/index.js +0 -99
  63. package/tooling/tailwind-compiler/package.json +0 -11
  64. package/tooling/tailwind-compiler/yarn.lock +0 -123
  65. package/tsconfig.build.json +0 -15
  66. package/tsconfig.json +0 -8
  67. /package/{dist/GrapesjsCanvas.d.ts → GrapesjsCanvas.d.ts} +0 -0
  68. /package/{dist/GrapesjsCanvas.js → GrapesjsCanvas.js} +0 -0
  69. /package/{dist/GrapesjsCanvas.js.map → GrapesjsCanvas.js.map} +0 -0
  70. /package/{dist/constants → constants}/index.d.ts +0 -0
  71. /package/{dist/constants → constants}/index.js +0 -0
  72. /package/{dist/constants → constants}/index.js.map +0 -0
  73. /package/{dist/helpers → helpers}/compiled-table.css +0 -0
  74. /package/{dist/helpers → helpers}/css.d.ts +0 -0
  75. /package/{dist/helpers → helpers}/css.js +0 -0
  76. /package/{dist/helpers → helpers}/css.js.map +0 -0
  77. /package/{dist/helpers → helpers}/date-picker.d.ts +0 -0
  78. /package/{dist/helpers → helpers}/date-picker.js +0 -0
  79. /package/{dist/helpers → helpers}/date-picker.js.map +0 -0
  80. /package/{dist/helpers → helpers}/index.d.ts +0 -0
  81. /package/{dist/helpers → helpers}/index.js +0 -0
  82. /package/{dist/helpers → helpers}/index.js.map +0 -0
  83. /package/{dist/helpers → helpers}/merge-json.d.ts +0 -0
  84. /package/{dist/helpers → helpers}/merge-json.js +0 -0
  85. /package/{dist/helpers → helpers}/merge-json.js.map +0 -0
  86. /package/{dist/index.d.ts → index.d.ts} +0 -0
  87. /package/{dist/index.js → index.js} +0 -0
  88. /package/{dist/index.js.map → index.js.map} +0 -0
  89. /package/{dist/index.styles.d.ts → index.styles.d.ts} +0 -0
  90. /package/{dist/index.styles.js → index.styles.js} +0 -0
  91. /package/{dist/index.styles.js.map → index.styles.js.map} +0 -0
  92. /package/{dist/plugins → plugins}/grapejs-plugin.d.ts +0 -0
  93. /package/{dist/plugins → plugins}/grapejs-plugin.js +0 -0
  94. /package/{dist/plugins → plugins}/grapejs-plugin.js.map +0 -0
  95. /package/{dist/plugins → plugins}/helpers/custom-modal.d.ts +0 -0
  96. /package/{dist/plugins → plugins}/helpers/custom-modal.js +0 -0
  97. /package/{dist/plugins → plugins}/helpers/custom-modal.js.map +0 -0
  98. /package/{dist/plugins → plugins}/helpers/data-table.d.ts +0 -0
  99. /package/{dist/plugins → plugins}/helpers/data-table.js +0 -0
  100. /package/{dist/plugins → plugins}/helpers/data-table.js.map +0 -0
  101. /package/{dist/plugins → plugins}/helpers/extra.d.ts +0 -0
  102. /package/{dist/plugins → plugins}/helpers/extra.js +0 -0
  103. /package/{dist/plugins → plugins}/helpers/extra.js.map +0 -0
  104. /package/{dist/plugins → plugins}/helpers/query-details-modal.d.ts +0 -0
  105. /package/{dist/plugins → plugins}/helpers/query-details-modal.js +0 -0
  106. /package/{dist/plugins → plugins}/helpers/query-details-modal.js.map +0 -0
  107. /package/{dist/plugins → plugins}/helpers/query-loading-modal.d.ts +0 -0
  108. /package/{dist/plugins → plugins}/helpers/query-loading-modal.js +0 -0
  109. /package/{dist/plugins → plugins}/helpers/query-loading-modal.js.map +0 -0
  110. /package/{dist/plugins → plugins}/helpers/render-components.d.ts +0 -0
  111. /package/{dist/plugins → plugins}/helpers/render-components.js +0 -0
  112. /package/{dist/plugins → plugins}/helpers/render-components.js.map +0 -0
  113. /package/{dist/plugins → plugins}/helpers/styled-info-button.d.ts +0 -0
  114. /package/{dist/shadcn → shadcn}/components/icons/AiAvatarIcon.d.ts +0 -0
  115. /package/{dist/shadcn → shadcn}/components/icons/AiAvatarIcon.js +0 -0
  116. /package/{dist/shadcn → shadcn}/components/icons/AiAvatarIcon.js.map +0 -0
  117. /package/{dist/shadcn → shadcn}/components/ui/button.d.ts +0 -0
  118. /package/{dist/shadcn → shadcn}/components/ui/button.js +0 -0
  119. /package/{dist/shadcn → shadcn}/components/ui/button.js.map +0 -0
  120. /package/{dist/shadcn → shadcn}/components/ui/card.d.ts +0 -0
  121. /package/{dist/shadcn → shadcn}/components/ui/card.js +0 -0
  122. /package/{dist/shadcn → shadcn}/components/ui/card.js.map +0 -0
  123. /package/{dist/shadcn → shadcn}/components/ui/chart.d.ts +0 -0
  124. /package/{dist/shadcn → shadcn}/components/ui/chart.js +0 -0
  125. /package/{dist/shadcn → shadcn}/components/ui/chart.js.map +0 -0
  126. /package/{dist/shadcn → shadcn}/components/ui/checkbox.d.ts +0 -0
  127. /package/{dist/shadcn → shadcn}/components/ui/checkbox.js +0 -0
  128. /package/{dist/shadcn → shadcn}/components/ui/checkbox.js.map +0 -0
  129. /package/{dist/shadcn → shadcn}/components/ui/component-wrapper.d.ts +0 -0
  130. /package/{dist/shadcn → shadcn}/components/ui/component-wrapper.js +0 -0
  131. /package/{dist/shadcn → shadcn}/components/ui/component-wrapper.js.map +0 -0
  132. /package/{dist/shadcn → shadcn}/components/ui/date-filter.d.ts +0 -0
  133. /package/{dist/shadcn → shadcn}/components/ui/date-filter.js +0 -0
  134. /package/{dist/shadcn → shadcn}/components/ui/date-filter.js.map +0 -0
  135. /package/{dist/shadcn → shadcn}/components/ui/error-container.d.ts +0 -0
  136. /package/{dist/shadcn → shadcn}/components/ui/error-container.js +0 -0
  137. /package/{dist/shadcn → shadcn}/components/ui/error-container.js.map +0 -0
  138. /package/{dist/shadcn → shadcn}/components/ui/error-wrapper.d.ts +0 -0
  139. /package/{dist/shadcn → shadcn}/components/ui/error-wrapper.js +0 -0
  140. /package/{dist/shadcn → shadcn}/components/ui/error-wrapper.js.map +0 -0
  141. /package/{dist/shadcn → shadcn}/components/ui/filter.d.ts +0 -0
  142. /package/{dist/shadcn → shadcn}/components/ui/filter.js +0 -0
  143. /package/{dist/shadcn → shadcn}/components/ui/filter.js.map +0 -0
  144. /package/{dist/shadcn → shadcn}/components/ui/hover-card.d.ts +0 -0
  145. /package/{dist/shadcn → shadcn}/components/ui/hover-card.js +0 -0
  146. /package/{dist/shadcn → shadcn}/components/ui/hover-card.js.map +0 -0
  147. /package/{dist/shadcn → shadcn}/components/ui/input.d.ts +0 -0
  148. /package/{dist/shadcn → shadcn}/components/ui/input.js +0 -0
  149. /package/{dist/shadcn → shadcn}/components/ui/input.js.map +0 -0
  150. /package/{dist/shadcn → shadcn}/components/ui/label.d.ts +0 -0
  151. /package/{dist/shadcn → shadcn}/components/ui/label.js +0 -0
  152. /package/{dist/shadcn → shadcn}/components/ui/label.js.map +0 -0
  153. /package/{dist/shadcn → shadcn}/components/ui/pagination.d.ts +0 -0
  154. /package/{dist/shadcn → shadcn}/components/ui/pagination.js +0 -0
  155. /package/{dist/shadcn → shadcn}/components/ui/pagination.js.map +0 -0
  156. /package/{dist/shadcn → shadcn}/components/ui/scroll-area.d.ts +0 -0
  157. /package/{dist/shadcn → shadcn}/components/ui/scroll-area.js +0 -0
  158. /package/{dist/shadcn → shadcn}/components/ui/scroll-area.js.map +0 -0
  159. /package/{dist/shadcn → shadcn}/components/ui/search.d.ts +0 -0
  160. /package/{dist/shadcn → shadcn}/components/ui/search.js +0 -0
  161. /package/{dist/shadcn → shadcn}/components/ui/search.js.map +0 -0
  162. /package/{dist/shadcn → shadcn}/components/ui/separator.d.ts +0 -0
  163. /package/{dist/shadcn → shadcn}/components/ui/separator.js +0 -0
  164. /package/{dist/shadcn → shadcn}/components/ui/separator.js.map +0 -0
  165. /package/{dist/shadcn → shadcn}/components/ui/skeleton.d.ts +0 -0
  166. /package/{dist/shadcn → shadcn}/components/ui/skeleton.js +0 -0
  167. /package/{dist/shadcn → shadcn}/components/ui/skeleton.js.map +0 -0
  168. /package/{dist/shadcn → shadcn}/components/ui/table.d.ts +0 -0
  169. /package/{dist/shadcn → shadcn}/components/ui/table.js +0 -0
  170. /package/{dist/shadcn → shadcn}/components/ui/table.js.map +0 -0
  171. /package/{dist/shadcn → shadcn}/components/ui/tabs.d.ts +0 -0
  172. /package/{dist/shadcn → shadcn}/components/ui/tabs.js +0 -0
  173. /package/{dist/shadcn → shadcn}/components/ui/tabs.js.map +0 -0
  174. /package/{dist/shadcn → shadcn}/components/ui/textarea.d.ts +0 -0
  175. /package/{dist/shadcn → shadcn}/components/ui/textarea.js +0 -0
  176. /package/{dist/shadcn → shadcn}/components/ui/textarea.js.map +0 -0
  177. /package/{dist/shadcn → shadcn}/components/ui/tooltip.d.ts +0 -0
  178. /package/{dist/shadcn → shadcn}/components/ui/tooltip.js +0 -0
  179. /package/{dist/shadcn → shadcn}/components/ui/tooltip.js.map +0 -0
  180. /package/{dist/shadcn → shadcn}/utils.d.ts +0 -0
  181. /package/{dist/shadcn → shadcn}/utils.js +0 -0
  182. /package/{dist/shadcn → shadcn}/utils.js.map +0 -0
  183. /package/{dist/types → types}/grapesjs-tailwind.d.js +0 -0
  184. /package/{dist/types → types}/grapesjs-tailwind.d.js.map +0 -0
@@ -1,300 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { useEffect, useState, Fragment } from 'react';
3
- import {
4
- Table,
5
- TableHeader,
6
- TableRow,
7
- TableHead,
8
- TableBody,
9
- TableCell,
10
- TableHeadSortable,
11
- SortDirection,
12
- } from '../../shadcn/components/ui/table';
13
- import { TableLoader } from '../../shadcn/components/ui/skeleton';
14
- import { ScrollArea, ScrollBar } from '../../shadcn/components/ui/scroll-area';
15
- import {
16
- Pagination,
17
- PaginationContent,
18
- renderPaginationArrows,
19
- } from '../../shadcn/components/ui/pagination';
20
- import { TableButton } from '../../shadcn/components/ui/button';
21
- import { cn } from '../../shadcn/utils';
22
- import { renderNoDataFallback } from './extra'
23
-
24
- type RowAction = {
25
- id: string;
26
- text: string;
27
- variant?: string;
28
- tooltipContent?: string;
29
- className?: string;
30
- };
31
-
32
- export type DataTableProps = {
33
- data: Record<string, any>[];
34
- headerMapper?: Record<string, string>;
35
- className?: string;
36
- isEditable?: boolean;
37
- actions?: RowAction[];
38
- pagination?: {
39
- values?: {
40
- pageNumber: number;
41
- pageSize: number;
42
- };
43
- initialPage?: number;
44
- initialPageSize?: number;
45
- totalCount: number;
46
- pageSizeOptions: number[];
47
- };
48
- isLoading?: boolean;
49
- onRowAction?: (rowIndex: number, actionId: string) => void;
50
- onPageChange?: (pageNumber: number, pageSize: number) => void;
51
- onSort?: (column: string, direction: SortDirection) => void;
52
- sortConfig?: Record<string, SortDirection>;
53
- otherProps?: Record<string, any>;
54
- height?: string | number;
55
- };
56
-
57
- export function DataTable({
58
- data = [],
59
- headerMapper = {},
60
- className = '',
61
- actions = [],
62
- isEditable = false,
63
- pagination,
64
- isLoading = false,
65
- onRowAction,
66
- onPageChange,
67
- onSort,
68
- sortConfig,
69
- otherProps = {},
70
- height,
71
- }: DataTableProps) {
72
-
73
- if (!data || data.length === 0) {
74
- return (
75
- <Fragment>
76
- <div className="flex flex-col overflow-hidden">
77
- <div
78
- data-slot="table-container"
79
- className="aspect-auto w-full"
80
- style={{ height: 'auto', minHeight: '180px' }}
81
- >
82
- {isLoading ? <TableLoader /> : renderNoDataFallback()}
83
- </div>
84
- </div>
85
- </Fragment>
86
- );
87
- }
88
-
89
- const [activeSortColumn, setActiveSortColumn] = useState<string | null>(null);
90
- const [sortDirections, setSortDirections] = useState<Record<string, SortDirection>>({});
91
-
92
- const [pageNumber, setPageNumber] = useState(
93
- Number(pagination?.values?.pageNumber ?? pagination?.initialPage ?? 1),
94
- );
95
- const [pageSize, setPageSize] = useState(
96
- Number(pagination?.values?.pageSize ?? pagination?.initialPageSize ?? 10),
97
- );
98
- const [totalPages, setTotalPages] = useState(
99
- Math.ceil((pagination?.totalCount || 0) / pageSize) || 1,
100
- );
101
-
102
- useEffect(() => {
103
- setPageNumber(Number(pagination?.values?.pageNumber ?? pagination?.initialPage ?? 1));
104
- setPageSize(Number(pagination?.values?.pageSize ?? pagination?.initialPageSize ?? 25));
105
- }, [pagination]);
106
-
107
- useEffect(() => {
108
- setTotalPages(Math.ceil((pagination?.totalCount || 0) / pageSize) || 1);
109
- }, [pagination?.totalCount, pageSize]);
110
-
111
- useEffect(() => {
112
- if (sortConfig) {
113
- setSortDirections(sortConfig);
114
- const first = Object.keys(sortConfig)[0];
115
-
116
- if (first) {
117
- setActiveSortColumn(first);
118
- }
119
- }
120
- }, [sortConfig]);
121
-
122
- useEffect(() => {
123
- if (sortConfig?.sortColumn || sortConfig?.sortDirection) {
124
- sortConfig.sortColumn = null;
125
- sortConfig.sortDirection = null;
126
- }
127
-
128
- setActiveSortColumn(null);
129
- setSortDirections({});
130
- }, []);
131
-
132
- const originalKeys = Object.keys(data[0] || {}).filter((key) => key in headerMapper);
133
- const headers = originalKeys.map((key) => headerMapper[key]);
134
-
135
- if (actions.length > 0) {
136
- headers.push('');
137
- }
138
-
139
- const rows = data.map((datum: any) => originalKeys.map((key) => datum[key]));
140
-
141
- async function handlePageChange(newPage = pageNumber, newSize = pageSize) {
142
- setPageNumber(newPage);
143
- setPageSize(newSize);
144
- onPageChange?.(newPage, newSize);
145
- }
146
-
147
- function handleSortClick(column: string, direction: SortDirection) {
148
- setActiveSortColumn(direction ? column : null);
149
- setSortDirections((prev) => ({
150
- ...prev,
151
- [column]: direction,
152
- }));
153
- onSort?.(column, direction);
154
- }
155
-
156
- function renderActions(rowIndex: number, rowActions: RowAction[]) {
157
- if (!actions.length) {
158
- return null;
159
- }
160
-
161
- return (
162
- <TableCell className="sticky right-0 bg-white">
163
- {rowActions.map((action) => (
164
- <TableButton
165
- key={action.id}
166
- className={action.className}
167
- isEditable={isEditable}
168
- onClick={() => onRowAction?.(rowIndex, action.id)}
169
- variant={action.variant}
170
- text={action.text}
171
- tooltipContent={action.tooltipContent}
172
- disabled={isLoading}
173
- />
174
- ))}
175
- </TableCell>
176
- );
177
- }
178
-
179
- const defaultClasses = `aspect-auto w-full`;
180
- const mergedClasses = className ? cn(defaultClasses, className) : defaultClasses;
181
-
182
- function renderTableComponent() {
183
- if (isLoading || (!data || data.length === 0)) {
184
- return <TableLoader />;
185
- }
186
-
187
- return (
188
- <Table
189
- {...otherProps}
190
- className={`caption-bottom text-sm relative ${mergedClasses}`}
191
- data-slot="table"
192
- >
193
- <TableHeader data-slot="table-header" className="sticky top-0 z-2">
194
- <TableRow>
195
- {headers.map((head: string, idx: number) => {
196
- const isActionColumn = actions.length > 0 && idx === headers.length - 1;
197
- const originalKey = originalKeys[idx];
198
-
199
- if (isActionColumn) {
200
- return (
201
- <TableHead
202
- key={idx}
203
- data-slot={`table-header-${idx}`}
204
- contentEditable={isEditable}
205
- className="sticky right-0 bg-slate-100"
206
- >
207
- {head}
208
- </TableHead>
209
- );
210
- }
211
-
212
- return (
213
- <TableHeadSortable
214
- key={idx}
215
- data-slot={`table-header-${idx}`}
216
- sortDirection={sortDirections[originalKey] || 'asc'}
217
- isActive={activeSortColumn === originalKey}
218
- onSort={(direction) => handleSortClick(originalKey, direction)}
219
- sortable={!isLoading}
220
- isEditable={isEditable}
221
- >
222
- {head}
223
- </TableHeadSortable>
224
- );
225
- })}
226
- </TableRow>
227
- </TableHeader>
228
- <TableBody data-slot="table-body">
229
- {rows.map((row: any[], rIdx: number) => (
230
- <TableRow
231
- key={rIdx}
232
- data-slot={`row-${rIdx}`}
233
- className="hover:bg-muted/50 border-b transition-colors"
234
- >
235
- {row.map((cell: string, cIdx: number) => (
236
- <TableCell
237
- key={cIdx}
238
- data-slot={`cell-${rIdx}-${cIdx}`}
239
- className="p-2 align-middle whitespace-nowrap"
240
- contentEditable={false}
241
- >
242
- {cell === null ? '-' : String(cell)}
243
- </TableCell>
244
- ))}
245
- {renderActions(rIdx, actions)}
246
- </TableRow>
247
- ))}
248
- </TableBody>
249
- </Table>
250
- );
251
- }
252
-
253
- return (
254
- <Fragment>
255
- <div className="flex flex-col h-full overflow-hidden">
256
- <ScrollArea
257
- data-slot="table-container"
258
- className={mergedClasses}
259
- {...(height !== undefined && { style: { height } })}
260
- >
261
- {renderTableComponent()}
262
- <ScrollBar orientation="horizontal" />
263
- </ScrollArea>
264
- </div>
265
- {pagination && pagination.totalCount > 0 && (
266
- <div className="flex-shrink-0 flex items-center justify-between mt-2 w-full overflow-x-auto border-t pt-2">
267
- <div className="flex items-center gap-2 flex-shrink-0">
268
- <label htmlFor="page-size-select" className="text-sm whitespace-nowrap">
269
- Rows per page:
270
- </label>
271
- <select
272
- id="page-size-select"
273
- value={pageSize}
274
- onChange={(e) => handlePageChange(1, Number(e.target.value))}
275
- className="border rounded px-2 py-1 text-sm cursor-pointer"
276
- disabled={isLoading}
277
- >
278
- {pagination.pageSizeOptions.map((size: number) => (
279
- <option key={size} value={size}>
280
- {size}
281
- </option>
282
- ))}
283
- </select>
284
- </div>
285
- <div className="flex items-center gap-1 flex-shrink-0">
286
- <span className="text-xs text-muted-foreground whitespace-nowrap ml-1.5">
287
- {(pageNumber - 1) * pageSize + 1}–
288
- {Math.min(pageNumber * pageSize, pagination.totalCount)} of {pagination.totalCount}
289
- </span>
290
- <Pagination>
291
- <PaginationContent className="gap-0.2 flex-shrink-0">
292
- {renderPaginationArrows(pageNumber, totalPages, isLoading, handlePageChange)}
293
- </PaginationContent>
294
- </Pagination>
295
- </div>
296
- </div>
297
- )}
298
- </Fragment>
299
- );
300
- }
@@ -1,164 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import { JSX } from 'react';
3
-
4
- import { cn } from '../../shadcn/utils';
5
- import { Checkbox } from '../../shadcn/components/ui/checkbox';
6
- import { CircleAlert } from 'lucide-react';
7
- import {
8
- HoverCard,
9
- HoverCardTrigger,
10
- HoverCardContent,
11
- } from '../../shadcn/components/ui/hover-card';
12
- import { Input } from '../../shadcn/components/ui/input';
13
- import { Label } from '../../shadcn/components/ui/label';
14
- import { Separator } from '../../shadcn/components/ui/separator';
15
- import { Textarea } from '../../shadcn/components/ui/textarea';
16
- import { Tooltip, TooltipTrigger, TooltipContent } from '../../shadcn/components/ui/tooltip';
17
-
18
- export function renderNoDataFallback() {
19
- return (
20
- <div className="w-full py-8 flex flex-col items-center justify-center px-6 text-center" style={{ minHeight: '180px' }}>
21
- <CircleAlert className="w-12 h-12 text-gray-400 mb-2" />
22
- <h3 className="text-lg font-medium text-gray-900">No data available</h3>
23
- <p className="mt-2 text-sm text-gray-500 max-w-md">
24
- Check your filters or try a different time range.
25
- </p>
26
- </div>
27
- );
28
- }
29
-
30
- export function renderCheckbox(props: any): JSX.Element {
31
- const { label = '', defaultChecked = false, className, isEditable = false, ...rest } = props;
32
- const defaultClasses = 'flex items-center';
33
- const merged = className ? cn(defaultClasses, className) : defaultClasses;
34
-
35
- return (
36
- <div className={merged} {...rest}>
37
- <Checkbox defaultChecked={defaultChecked} />
38
- {label && (
39
- <Label data-slot="label" contentEditable={isEditable} className="ml-2">
40
- {label}
41
- </Label>
42
- )}
43
- </div>
44
- );
45
- }
46
-
47
- export function renderHoverCard(props: any): JSX.Element {
48
- const {
49
- triggerContent = 'Hover over me',
50
- cardContent = 'Additional information',
51
- className,
52
- isEditable = false,
53
- ...rest
54
- } = props;
55
- const defaultClasses = 'w-[320px] max-w-[320px] shadow rounded-lg';
56
- const merged = className ? cn(defaultClasses, className) : defaultClasses;
57
-
58
- return (
59
- <HoverCard className={merged} {...rest}>
60
- <HoverCardTrigger asChild>
61
- <span data-slot="triggerContent" contentEditable={isEditable}>
62
- {triggerContent}
63
- </span>
64
- </HoverCardTrigger>
65
- <HoverCardContent>
66
- <div data-slot="cardContent" contentEditable={isEditable}>
67
- {cardContent}
68
- </div>
69
- </HoverCardContent>
70
- </HoverCard>
71
- );
72
- }
73
-
74
- export function renderInput(props: any): JSX.Element {
75
- const {
76
- label = '',
77
- placeholder = '',
78
- value = '',
79
- className,
80
- isEditable = false,
81
- ...rest
82
- } = props;
83
- const defaultClasses = 'w-[320px] p-2 border border-gray-300 rounded-md';
84
- const merged = className ? cn(defaultClasses, className) : defaultClasses;
85
-
86
- return (
87
- <div className={`flex flex-col ${merged}`} {...rest}>
88
- {label && (
89
- <Label data-slot="label" contentEditable={isEditable} className="mb-1">
90
- {label}
91
- </Label>
92
- )}
93
- <Input placeholder={placeholder} value={value} />
94
- </div>
95
- );
96
- }
97
-
98
- export function renderLabel(props: any): JSX.Element {
99
- const { text = 'Label', className, isEditable = false, ...rest } = props;
100
- const defaultClasses = 'text-base font-semibold mb-2';
101
- const merged = className ? cn(defaultClasses, className) : defaultClasses;
102
-
103
- return (
104
- <Label data-slot="text" contentEditable={isEditable} className={merged} {...rest}>
105
- {text}
106
- </Label>
107
- );
108
- }
109
-
110
- export function renderSeparator(props: any): JSX.Element {
111
- const { className, ...rest } = props;
112
- const defaultClasses = 'my-4 border-t-2';
113
- const merged = className ? cn(defaultClasses, className) : defaultClasses;
114
-
115
- return <Separator className={merged} {...rest} />;
116
- }
117
-
118
- export function renderTextarea(props: any): JSX.Element {
119
- const {
120
- label = '',
121
- placeholder = '',
122
- value = '',
123
- className,
124
- isEditable = false,
125
- ...rest
126
- } = props;
127
- const defaultClasses = 'w-[320px] p-2 border border-gray-300 rounded-md';
128
- const merged = className ? cn(defaultClasses, className) : defaultClasses;
129
-
130
- return (
131
- <div className={`flex flex-col ${merged}`} {...rest}>
132
- {label && (
133
- <Label data-slot="label" contentEditable={isEditable} className="mb-1">
134
- {label}
135
- </Label>
136
- )}
137
- <Textarea placeholder={placeholder} value={value} />
138
- </div>
139
- );
140
- }
141
-
142
- export function renderTooltip(props: any): JSX.Element {
143
- const {
144
- triggerContent = 'Hover here',
145
- tooltipContent = 'Tooltip information',
146
- className,
147
- isEditable = false,
148
- ...rest
149
- } = props;
150
- const merged = className || '';
151
-
152
- return (
153
- <Tooltip className={merged} {...rest}>
154
- <TooltipTrigger asChild>
155
- <span data-slot="triggerContent" contentEditable={isEditable}>
156
- {triggerContent}
157
- </span>
158
- </TooltipTrigger>
159
- <TooltipContent data-slot="tooltipContent" contentEditable={isEditable}>
160
- {tooltipContent}
161
- </TooltipContent>
162
- </Tooltip>
163
- );
164
- }
@@ -1,240 +0,0 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { CustomModal } from './custom-modal';
3
- import { Copy, Check, ChevronDown } from 'lucide-react';
4
-
5
- type QueryDetailsModalProps = {
6
- isOpen: boolean;
7
- onClose: () => void;
8
- isLoading: boolean;
9
- error: string;
10
- sqlQuery: string | string[];
11
- tableButtonExplanations?: Array<{action: string, explanation: string, operationName?: string, buttonClassName?: string, buttonStyle?: Record<string, unknown>}>;
12
- onRetry: () => void;
13
- };
14
-
15
- export function QueryDetailsModal({
16
- isOpen,
17
- onClose,
18
- isLoading,
19
- error,
20
- sqlQuery,
21
- tableButtonExplanations = [],
22
- onRetry
23
- }: QueryDetailsModalProps) {
24
- const [copied, setCopied] = useState<{ [key: string]: boolean }>({});
25
- const [expandedButtons, setExpandedButtons] = useState<{ [key: string]: boolean }>({});
26
-
27
- // Reset expanded state when modal closes
28
- useEffect(() => {
29
- if (!isOpen) {
30
- setExpandedButtons({});
31
- }
32
- }, [isOpen]);
33
-
34
- async function copyToClipboard(queryToCopy?: string, copyId?: string) {
35
- let textToCopy = queryToCopy;
36
-
37
- if (!textToCopy) {
38
- if (Array.isArray(sqlQuery)) {
39
- textToCopy = sqlQuery.filter(q => q && typeof q === 'string').join('\n\n-- Next Query --\n\n');
40
- } else if (typeof sqlQuery === 'string') {
41
- textToCopy = sqlQuery;
42
- } else {
43
- textToCopy = '';
44
- }
45
- }
46
-
47
- if (!textToCopy) {
48
- return;
49
- }
50
-
51
- const id = copyId || 'main';
52
-
53
- try {
54
- await navigator.clipboard.writeText(textToCopy);
55
- setCopied(prev => ({ ...prev, [id]: true }));
56
- setTimeout(() => setCopied(prev => ({ ...prev, [id]: false })), 2000);
57
- } catch (err) {
58
- // Silently fail if clipboard API is not available
59
- }
60
- }
61
-
62
- function toggleButtonExpansion(buttonIndex: number) {
63
- setExpandedButtons(prev => ({
64
- ...prev,
65
- [buttonIndex]: !prev[buttonIndex]
66
- }));
67
- }
68
-
69
- function renderTableButtonExplanations() {
70
- if (!tableButtonExplanations || tableButtonExplanations.length === 0) {
71
- return null;
72
- }
73
-
74
- return (
75
- <div className="mb-6">
76
- {tableButtonExplanations.map((button, index) => (
77
- <div key={index} className="mb-3 border border-gray-200 rounded-lg">
78
- <div className="w-full px-4 py-3 flex items-center justify-between rounded-lg">
79
- <span className="font-medium text-xs text-gray-500">
80
- What does this button do?
81
- </span>
82
- <div className="flex items-center">
83
- <button
84
- onClick={() => toggleButtonExpansion(index)}
85
- className={button.buttonClassName || "flex items-center px-3 py-1.5 rounded text-xs font-medium"}
86
- style={{
87
- backgroundColor: (button.buttonStyle?.backgroundColor as string) || '#f3f4f6',
88
- color: (button.buttonStyle?.color as string) || '#374151',
89
- border: (button.buttonStyle?.border as string) || '1px solid #d1d5db',
90
- ...(button.buttonStyle as React.CSSProperties || {})
91
- }}
92
- >
93
- {button.action}
94
- </button>
95
- <ChevronDown
96
- className={`ml-2 w-4 h-4 text-gray-500 transition-transform cursor-pointer ${
97
- expandedButtons[index] ? 'rotate-180' : ''
98
- }`}
99
- onClick={() => toggleButtonExpansion(index)}
100
- />
101
- </div>
102
- </div>
103
-
104
- {expandedButtons[index] && (
105
- <div className="px-4 pb-3 border-t border-gray-200">
106
- <p className="text-xs text-gray-700 mt-2">
107
- This button will hit <span className="font-semibold">{button.explanation}</span>
108
- </p>
109
- </div>
110
- )}
111
- </div>
112
- ))}
113
- </div>
114
- );
115
- }
116
-
117
- function renderModalContent() {
118
- if (isLoading) {
119
- return (
120
- <div className="flex flex-col items-center justify-center py-12">
121
- <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-purple-600 mb-4"></div>
122
- <span className="text-xs text-gray-600">Fetching query details from semantic layer...</span>
123
- <span className="text-xs text-gray-400 mt-2">This may take a few moments</span>
124
- </div>
125
- );
126
- }
127
-
128
- if (error) {
129
- return (
130
- <div className="text-red-600 p-4 bg-red-50 rounded-lg border border-red-200 m-6">
131
- <p className="font-medium mb-2 text-xs">Unable to fetch query details</p>
132
- <p className="text-xs mb-3">{error}</p>
133
- <button
134
- onClick={onRetry}
135
- className="px-4 py-2 bg-red-100 hover:bg-red-200 rounded text-xs font-medium transition-colors"
136
- type="button"
137
- >
138
- Retry
139
- </button>
140
- </div>
141
- );
142
- }
143
-
144
- if (!sqlQuery || (Array.isArray(sqlQuery) && sqlQuery.length === 0)) {
145
- return (
146
- <div className="text-gray-600 p-6">
147
- <p className="text-xs">No query details available</p>
148
- </div>
149
- );
150
- }
151
-
152
- // Handle multiple queries
153
- if (Array.isArray(sqlQuery)) {
154
- return (
155
- <div className="p-6 space-y-4">
156
- {sqlQuery
157
- .filter(query => query && typeof query === 'string' && query.trim())
158
- .map((query, index) => (
159
- <div
160
- key={index}
161
- className="bg-white border border-gray-200 rounded-lg p-4 h-28 overflow-y-auto"
162
- >
163
- <div className="flex justify-between items-start mb-3">
164
- <h3 className="font-semibold text-xs text-gray-500 m-0">
165
- Query details
166
- </h3>
167
- <button
168
- onClick={() => copyToClipboard(query, `query-${index}`)}
169
- className="flex items-center gap-2 px-2 py-1 text-xs bg-gray-50 border border-gray-300 rounded hover:bg-gray-100 transition-colors"
170
- type="button"
171
- >
172
- {copied[`query-${index}`] ? (
173
- <>
174
- <Check className="w-3 h-3 text-green-600" />
175
- <span className="text-green-600">Copied!</span>
176
- </>
177
- ) : (
178
- <>
179
- <Copy className="w-3 h-3 text-gray-600" />
180
- <span className="text-gray-600">Copy</span>
181
- </>
182
- )}
183
- </button>
184
- </div>
185
- <pre className="whitespace-pre-wrap leading-relaxed text-xs text-gray-700 m-0 p-0">
186
- {query}
187
- </pre>
188
- </div>
189
- ))}
190
- {renderTableButtonExplanations()}
191
- </div>
192
- );
193
- }
194
-
195
- return (
196
- <div className="p-6 space-y-4">
197
- <div className="bg-white border border-gray-200 rounded-lg p-4 h-28 overflow-y-auto">
198
- <div className="flex justify-between items-start mb-3">
199
- <h3 className="font-semibold text-xs text-gray-500 m-0">
200
- Query details
201
- </h3>
202
- <button
203
- onClick={() => copyToClipboard(undefined, 'single')}
204
- className="flex items-center gap-2 px-2 py-1 text-xs bg-gray-50 border border-gray-300 rounded hover:bg-gray-100 transition-colors"
205
- type="button"
206
- >
207
- {copied.single ? (
208
- <>
209
- <Check className="w-3 h-3 text-green-600" />
210
- <span className="text-green-600">Copied!</span>
211
- </>
212
- ) : (
213
- <>
214
- <Copy className="w-3 h-3 text-gray-600" />
215
- <span className="text-gray-600">Copy</span>
216
- </>
217
- )}
218
- </button>
219
- </div>
220
- <pre className="whitespace-pre-wrap leading-relaxed text-xs text-gray-700 m-0 p-0">
221
- {sqlQuery}
222
- </pre>
223
- </div>
224
- {renderTableButtonExplanations()}
225
- </div>
226
- );
227
- }
228
-
229
- return (
230
- <CustomModal
231
- isOpen={isOpen}
232
- onClose={onClose}
233
- title="How was this metric calculated?"
234
- >
235
- {renderModalContent()}
236
- </CustomModal>
237
- );
238
- }
239
-
240
- export default QueryDetailsModal;