@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.
- package/package.json +6 -44
- package/plugins/helpers/styled-info-button.js +2 -0
- package/plugins/helpers/styled-info-button.js.map +1 -0
- package/.babelrc +0 -14
- package/.eslintcache +0 -1
- package/.eslintignore +0 -5
- package/.eslintrc.js +0 -29
- package/dist/package.json +0 -62
- package/dist/plugins/helpers/styled-info-button.js +0 -2
- package/dist/plugins/helpers/styled-info-button.js.map +0 -1
- package/scripts/build.ts +0 -88
- package/src/GrapesjsCanvas.tsx +0 -340
- package/src/constants/index.ts +0 -27
- package/src/helpers/compiled-table.css +0 -2429
- package/src/helpers/css.ts +0 -2515
- package/src/helpers/date-picker.ts +0 -807
- package/src/helpers/index.ts +0 -13
- package/src/helpers/merge-json.ts +0 -106
- package/src/index.styles.ts +0 -58
- package/src/index.ts +0 -9
- package/src/plugins/grapejs-plugin.tsx +0 -139
- package/src/plugins/helpers/custom-modal.tsx +0 -111
- package/src/plugins/helpers/data-table.tsx +0 -300
- package/src/plugins/helpers/extra.tsx +0 -164
- package/src/plugins/helpers/query-details-modal.tsx +0 -240
- package/src/plugins/helpers/query-loading-modal.tsx +0 -36
- package/src/plugins/helpers/render-components.tsx +0 -1211
- package/src/plugins/helpers/styled-info-button.tsx +0 -320
- package/src/public/canvas.css +0 -42
- package/src/public/components-css/table/table-output.css +0 -2436
- package/src/public/components-css/table/table.css +0 -30
- package/src/public/output.css +0 -2336
- package/src/public/table.css +0 -135
- package/src/shadcn/components/icons/AiAvatarIcon.tsx +0 -47
- package/src/shadcn/components/icons/Co_driver Expanding button copy.svg +0 -21
- package/src/shadcn/components/icons/ai-avatar.svg +0 -7
- package/src/shadcn/components/icons/thinking.gif +0 -0
- package/src/shadcn/components/ui/button.tsx +0 -132
- package/src/shadcn/components/ui/card.tsx +0 -92
- package/src/shadcn/components/ui/chart.tsx +0 -324
- package/src/shadcn/components/ui/checkbox.tsx +0 -27
- package/src/shadcn/components/ui/component-wrapper.tsx +0 -61
- package/src/shadcn/components/ui/date-filter.tsx +0 -816
- package/src/shadcn/components/ui/error-container.tsx +0 -125
- package/src/shadcn/components/ui/error-wrapper.tsx +0 -124
- package/src/shadcn/components/ui/filter.tsx +0 -366
- package/src/shadcn/components/ui/hover-card.tsx +0 -36
- package/src/shadcn/components/ui/input.tsx +0 -20
- package/src/shadcn/components/ui/label.tsx +0 -24
- package/src/shadcn/components/ui/pagination.tsx +0 -213
- package/src/shadcn/components/ui/scroll-area.tsx +0 -59
- package/src/shadcn/components/ui/search.tsx +0 -149
- package/src/shadcn/components/ui/separator.tsx +0 -26
- package/src/shadcn/components/ui/skeleton.tsx +0 -69
- package/src/shadcn/components/ui/table.tsx +0 -196
- package/src/shadcn/components/ui/tabs.tsx +0 -55
- package/src/shadcn/components/ui/textarea.tsx +0 -18
- package/src/shadcn/components/ui/tooltip.tsx +0 -87
- package/src/shadcn/utils.ts +0 -6
- package/src/types/grapesjs-tailwind.d.ts +0 -61
- package/tailwind.config.js +0 -5
- package/tooling/tailwind-compiler/index.js +0 -99
- package/tooling/tailwind-compiler/package.json +0 -11
- package/tooling/tailwind-compiler/yarn.lock +0 -123
- package/tsconfig.build.json +0 -15
- package/tsconfig.json +0 -8
- /package/{dist/GrapesjsCanvas.d.ts → GrapesjsCanvas.d.ts} +0 -0
- /package/{dist/GrapesjsCanvas.js → GrapesjsCanvas.js} +0 -0
- /package/{dist/GrapesjsCanvas.js.map → GrapesjsCanvas.js.map} +0 -0
- /package/{dist/constants → constants}/index.d.ts +0 -0
- /package/{dist/constants → constants}/index.js +0 -0
- /package/{dist/constants → constants}/index.js.map +0 -0
- /package/{dist/helpers → helpers}/compiled-table.css +0 -0
- /package/{dist/helpers → helpers}/css.d.ts +0 -0
- /package/{dist/helpers → helpers}/css.js +0 -0
- /package/{dist/helpers → helpers}/css.js.map +0 -0
- /package/{dist/helpers → helpers}/date-picker.d.ts +0 -0
- /package/{dist/helpers → helpers}/date-picker.js +0 -0
- /package/{dist/helpers → helpers}/date-picker.js.map +0 -0
- /package/{dist/helpers → helpers}/index.d.ts +0 -0
- /package/{dist/helpers → helpers}/index.js +0 -0
- /package/{dist/helpers → helpers}/index.js.map +0 -0
- /package/{dist/helpers → helpers}/merge-json.d.ts +0 -0
- /package/{dist/helpers → helpers}/merge-json.js +0 -0
- /package/{dist/helpers → helpers}/merge-json.js.map +0 -0
- /package/{dist/index.d.ts → index.d.ts} +0 -0
- /package/{dist/index.js → index.js} +0 -0
- /package/{dist/index.js.map → index.js.map} +0 -0
- /package/{dist/index.styles.d.ts → index.styles.d.ts} +0 -0
- /package/{dist/index.styles.js → index.styles.js} +0 -0
- /package/{dist/index.styles.js.map → index.styles.js.map} +0 -0
- /package/{dist/plugins → plugins}/grapejs-plugin.d.ts +0 -0
- /package/{dist/plugins → plugins}/grapejs-plugin.js +0 -0
- /package/{dist/plugins → plugins}/grapejs-plugin.js.map +0 -0
- /package/{dist/plugins → plugins}/helpers/custom-modal.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/custom-modal.js +0 -0
- /package/{dist/plugins → plugins}/helpers/custom-modal.js.map +0 -0
- /package/{dist/plugins → plugins}/helpers/data-table.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/data-table.js +0 -0
- /package/{dist/plugins → plugins}/helpers/data-table.js.map +0 -0
- /package/{dist/plugins → plugins}/helpers/extra.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/extra.js +0 -0
- /package/{dist/plugins → plugins}/helpers/extra.js.map +0 -0
- /package/{dist/plugins → plugins}/helpers/query-details-modal.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/query-details-modal.js +0 -0
- /package/{dist/plugins → plugins}/helpers/query-details-modal.js.map +0 -0
- /package/{dist/plugins → plugins}/helpers/query-loading-modal.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/query-loading-modal.js +0 -0
- /package/{dist/plugins → plugins}/helpers/query-loading-modal.js.map +0 -0
- /package/{dist/plugins → plugins}/helpers/render-components.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/render-components.js +0 -0
- /package/{dist/plugins → plugins}/helpers/render-components.js.map +0 -0
- /package/{dist/plugins → plugins}/helpers/styled-info-button.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/icons/AiAvatarIcon.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/icons/AiAvatarIcon.js +0 -0
- /package/{dist/shadcn → shadcn}/components/icons/AiAvatarIcon.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/button.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/button.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/button.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/card.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/card.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/card.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/chart.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/chart.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/chart.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/checkbox.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/checkbox.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/checkbox.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/component-wrapper.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/component-wrapper.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/component-wrapper.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/date-filter.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/date-filter.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/date-filter.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/error-container.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/error-container.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/error-container.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/error-wrapper.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/error-wrapper.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/error-wrapper.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/filter.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/filter.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/filter.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/hover-card.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/hover-card.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/hover-card.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/input.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/input.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/input.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/label.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/label.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/label.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/pagination.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/pagination.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/pagination.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/scroll-area.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/scroll-area.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/scroll-area.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/search.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/search.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/search.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/separator.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/separator.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/separator.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/skeleton.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/skeleton.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/skeleton.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/table.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/table.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/table.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/tabs.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/tabs.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/tabs.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/textarea.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/textarea.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/textarea.js.map +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/tooltip.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/tooltip.js +0 -0
- /package/{dist/shadcn → shadcn}/components/ui/tooltip.js.map +0 -0
- /package/{dist/shadcn → shadcn}/utils.d.ts +0 -0
- /package/{dist/shadcn → shadcn}/utils.js +0 -0
- /package/{dist/shadcn → shadcn}/utils.js.map +0 -0
- /package/{dist/types → types}/grapesjs-tailwind.d.js +0 -0
- /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;
|