@peak-ai/canvas 1.4.22 → 1.4.23
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 +7 -45
- package/.babelrc +0 -14
- package/.eslintcache +0 -1
- package/.eslintignore +0 -5
- package/.eslintrc.js +0 -29
- package/dist/package.json +0 -62
- package/scripts/build.ts +0 -120
- package/src/GrapesjsCanvas.tsx +0 -494
- package/src/constants/index.ts +0 -25
- package/src/declaration.d.ts +0 -1
- package/src/helpers/compiled-table.css +0 -2429
- package/src/helpers/css.ts +0 -2667
- package/src/helpers/date-picker.ts +0 -807
- package/src/helpers/filter-placeholder.ts +0 -18
- 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 -196
- package/src/plugins/helpers/custom-modal.tsx +0 -123
- package/src/plugins/helpers/data-table.tsx +0 -300
- package/src/plugins/helpers/extra.tsx +0 -164
- package/src/plugins/helpers/query-cache-context.tsx +0 -154
- package/src/plugins/helpers/query-cache-singleton.ts +0 -176
- package/src/plugins/helpers/query-cache-utils.ts +0 -226
- package/src/plugins/helpers/query-details-modal.tsx +0 -400
- package/src/plugins/helpers/query-heading-formatter.ts +0 -24
- package/src/plugins/helpers/query-loading-modal.tsx +0 -94
- package/src/plugins/helpers/render-components.tsx +0 -1450
- package/src/plugins/helpers/styled-info-button.tsx +0 -504
- 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 -2465
- 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 -99
- package/src/shadcn/components/ui/filter.tsx +0 -368
- 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 -150
- 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/src/types/images.d.ts +0 -1
- 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/declaration.d.js → declaration.d.js} +0 -0
- /package/{dist/declaration.d.js.map → declaration.d.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}/filter-placeholder.d.ts +0 -0
- /package/{dist/helpers → helpers}/filter-placeholder.js +0 -0
- /package/{dist/helpers → helpers}/filter-placeholder.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-cache-context.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/query-cache-context.js +0 -0
- /package/{dist/plugins → plugins}/helpers/query-cache-context.js.map +0 -0
- /package/{dist/plugins → plugins}/helpers/query-cache-singleton.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/query-cache-singleton.js +0 -0
- /package/{dist/plugins → plugins}/helpers/query-cache-singleton.js.map +0 -0
- /package/{dist/plugins → plugins}/helpers/query-cache-utils.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/query-cache-utils.js +0 -0
- /package/{dist/plugins → plugins}/helpers/query-cache-utils.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-heading-formatter.d.ts +0 -0
- /package/{dist/plugins → plugins}/helpers/query-heading-formatter.js +0 -0
- /package/{dist/plugins → plugins}/helpers/query-heading-formatter.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/plugins → plugins}/helpers/styled-info-button.js +0 -0
- /package/{dist/plugins → plugins}/helpers/styled-info-button.js.map +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/icons/thinking.gif +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
- /package/{dist/types → types}/images.d.js +0 -0
- /package/{dist/types → types}/images.d.js.map +0 -0
|
@@ -1,400 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { CustomModal } from './custom-modal';
|
|
3
|
-
import { Copy, Check, ChevronDown, ChevronUp, X } from 'lucide-react';
|
|
4
|
-
import { formatQueryHeading } from './query-heading-formatter';
|
|
5
|
-
|
|
6
|
-
type CopyButtonProps = {
|
|
7
|
-
onClick: () => void;
|
|
8
|
-
isCopied: boolean;
|
|
9
|
-
variant?: 'default' | 'light';
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
function CopyButton({ onClick, isCopied, variant = 'default' }: CopyButtonProps) {
|
|
13
|
-
const baseClasses = "flex items-center gap-1 px-2 py-1 text-xs border rounded transition-colors";
|
|
14
|
-
const variantClasses = variant === 'light'
|
|
15
|
-
? "bg-gray-50 border-gray-300 hover:bg-gray-100"
|
|
16
|
-
: "bg-gray-100 border-gray-300 hover:bg-gray-200";
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<button
|
|
20
|
-
onClick={onClick}
|
|
21
|
-
className={`${baseClasses} ${variantClasses}`}
|
|
22
|
-
type="button"
|
|
23
|
-
>
|
|
24
|
-
{isCopied ? (
|
|
25
|
-
<>
|
|
26
|
-
<Check className="w-3 h-3 text-green-600" />
|
|
27
|
-
<span className="text-green-600">Copied!</span>
|
|
28
|
-
</>
|
|
29
|
-
) : (
|
|
30
|
-
<>
|
|
31
|
-
<Copy className="w-3 h-3 text-gray-600" />
|
|
32
|
-
<span className="text-gray-600">Copy</span>
|
|
33
|
-
</>
|
|
34
|
-
)}
|
|
35
|
-
</button>
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
type ContentTextProps = {
|
|
40
|
-
children: React.ReactNode;
|
|
41
|
-
hasOverflowHandling?: boolean;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
function ContentText({ children, hasOverflowHandling = true }: ContentTextProps) {
|
|
45
|
-
const overflowClasses = hasOverflowHandling ? "overflow-hidden break-words" : "";
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<pre className={`whitespace-pre-wrap leading-relaxed text-xs text-gray-700 m-0 p-0 ${overflowClasses}`}>
|
|
49
|
-
{children}
|
|
50
|
-
</pre>
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
type ContentBlockProps = {
|
|
55
|
-
title: string;
|
|
56
|
-
children: React.ReactNode;
|
|
57
|
-
copyContent?: string;
|
|
58
|
-
copyId: string;
|
|
59
|
-
copied: Record<string, boolean>;
|
|
60
|
-
onCopy: (content: string, id: string) => void;
|
|
61
|
-
variant?: 'default' | 'bordered';
|
|
62
|
-
copyButtonVariant?: 'default' | 'light';
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
function ContentBlock({
|
|
66
|
-
title,
|
|
67
|
-
children,
|
|
68
|
-
copyContent,
|
|
69
|
-
copyId,
|
|
70
|
-
copied,
|
|
71
|
-
onCopy,
|
|
72
|
-
variant = 'bordered',
|
|
73
|
-
copyButtonVariant = 'default'
|
|
74
|
-
}: ContentBlockProps) {
|
|
75
|
-
const containerClasses = variant === 'bordered'
|
|
76
|
-
? "rounded-lg p-3"
|
|
77
|
-
: "bg-white border border-gray-200 rounded-lg p-4";
|
|
78
|
-
|
|
79
|
-
const containerStyle = variant === 'bordered'
|
|
80
|
-
? { border: '1px solid #E9EAF5' }
|
|
81
|
-
: {};
|
|
82
|
-
|
|
83
|
-
const titleClasses = variant === 'bordered'
|
|
84
|
-
? "text-sm font-medium text-gray-600"
|
|
85
|
-
: "font-semibold text-sm text-gray-500 m-0";
|
|
86
|
-
|
|
87
|
-
return (
|
|
88
|
-
<div className={containerClasses} style={containerStyle}>
|
|
89
|
-
<div className="flex justify-between items-start mb-2">
|
|
90
|
-
<span className={titleClasses}>{title}</span>
|
|
91
|
-
{copyContent && (
|
|
92
|
-
<CopyButton
|
|
93
|
-
onClick={() => onCopy(copyContent, copyId)}
|
|
94
|
-
isCopied={copied[copyId] || false}
|
|
95
|
-
variant={copyButtonVariant}
|
|
96
|
-
/>
|
|
97
|
-
)}
|
|
98
|
-
</div>
|
|
99
|
-
{children}
|
|
100
|
-
</div>
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
type QueryDetailsModalProps = {
|
|
105
|
-
isOpen: boolean;
|
|
106
|
-
onClose: () => void;
|
|
107
|
-
isLoading: boolean;
|
|
108
|
-
error: string;
|
|
109
|
-
sqlQuery: string | string[];
|
|
110
|
-
queryHeadings?: string[];
|
|
111
|
-
tableButtonExplanations?: Array<{
|
|
112
|
-
action: string,
|
|
113
|
-
explanation: string,
|
|
114
|
-
operationSummary?: string,
|
|
115
|
-
operationDescription?: string,
|
|
116
|
-
buttonClassName?: string,
|
|
117
|
-
buttonStyle?: Record<string, unknown>,
|
|
118
|
-
formFields?: Record<string, unknown>;
|
|
119
|
-
jsonBody?: unknown;
|
|
120
|
-
requestUrl?: string;
|
|
121
|
-
}>;
|
|
122
|
-
onRetry: () => void;
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
export function QueryDetailsModal({
|
|
126
|
-
isOpen,
|
|
127
|
-
onClose,
|
|
128
|
-
isLoading,
|
|
129
|
-
error,
|
|
130
|
-
sqlQuery,
|
|
131
|
-
queryHeadings = [],
|
|
132
|
-
tableButtonExplanations = [],
|
|
133
|
-
onRetry
|
|
134
|
-
}: QueryDetailsModalProps) {
|
|
135
|
-
const [copied, setCopied] = useState<{ [key: string]: boolean }>({});
|
|
136
|
-
const [expandedButtons, setExpandedButtons] = useState<{ [key: string]: boolean }>({});
|
|
137
|
-
|
|
138
|
-
// Reset expanded state when modal closes
|
|
139
|
-
useEffect(() => {
|
|
140
|
-
if (!isOpen) {
|
|
141
|
-
setExpandedButtons({});
|
|
142
|
-
}
|
|
143
|
-
}, [isOpen]);
|
|
144
|
-
|
|
145
|
-
async function copyToClipboard(queryToCopy?: string, copyId?: string) {
|
|
146
|
-
let textToCopy = queryToCopy;
|
|
147
|
-
|
|
148
|
-
if (!textToCopy) {
|
|
149
|
-
if (Array.isArray(sqlQuery)) {
|
|
150
|
-
textToCopy = sqlQuery.filter(q => q && typeof q === 'string').join('\n\n-- Next Query --\n\n');
|
|
151
|
-
} else if (typeof sqlQuery === 'string') {
|
|
152
|
-
textToCopy = sqlQuery;
|
|
153
|
-
} else {
|
|
154
|
-
textToCopy = '';
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (!textToCopy) {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const id = copyId || 'main';
|
|
163
|
-
|
|
164
|
-
try {
|
|
165
|
-
await navigator.clipboard.writeText(textToCopy);
|
|
166
|
-
setCopied(prev => ({ ...prev, [id]: true }));
|
|
167
|
-
setTimeout(() => setCopied(prev => ({ ...prev, [id]: false })), 2000);
|
|
168
|
-
} catch (err) {
|
|
169
|
-
// Silently fail if clipboard API is not available
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function toggleButtonExpansion(buttonIndex: number) {
|
|
174
|
-
setExpandedButtons(prev => ({
|
|
175
|
-
...prev,
|
|
176
|
-
[buttonIndex]: !prev[buttonIndex]
|
|
177
|
-
}));
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function renderTableButtonExplanations() {
|
|
181
|
-
if (!tableButtonExplanations || tableButtonExplanations.length === 0) {
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function hasValidJsonBody(jsonBody: unknown): boolean {
|
|
186
|
-
return jsonBody !== null && jsonBody !== undefined && jsonBody !== '';
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function hasValidFormFields(formFields: Record<string, unknown> | undefined): boolean {
|
|
190
|
-
return formFields !== null && formFields !== undefined && Object.keys(formFields || {}).length > 0;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return (
|
|
194
|
-
<div className="mb-6">
|
|
195
|
-
{tableButtonExplanations.map((button, index) => (
|
|
196
|
-
<div key={index} className="mb-3 border border-gray-200 rounded-lg">
|
|
197
|
-
<div className="w-full px-4 py-3 flex items-center justify-between rounded-lg">
|
|
198
|
-
<div className="flex items-center">
|
|
199
|
-
<button
|
|
200
|
-
onClick={() => toggleButtonExpansion(index)}
|
|
201
|
-
className={button.buttonClassName || "flex items-center justify-center px-3 rounded text-xs font-medium"}
|
|
202
|
-
style={{
|
|
203
|
-
height: '35px',
|
|
204
|
-
width: 'fit-content',
|
|
205
|
-
minWidth: 'fit-content',
|
|
206
|
-
backgroundColor: (button.buttonStyle?.backgroundColor as string),
|
|
207
|
-
color: (button.buttonStyle?.color as string),
|
|
208
|
-
border: (button.buttonStyle?.border as string),
|
|
209
|
-
...(button.buttonStyle as React.CSSProperties || {})
|
|
210
|
-
, ...button.buttonStyle as React.CSSProperties || {},
|
|
211
|
-
display: 'flex',
|
|
212
|
-
alignItems: 'center',
|
|
213
|
-
justifyContent: 'center'
|
|
214
|
-
}}
|
|
215
|
-
>
|
|
216
|
-
{button.action}
|
|
217
|
-
</button>
|
|
218
|
-
<div className="ml-3 flex flex-col">
|
|
219
|
-
{button.operationSummary && (
|
|
220
|
-
<span className="text-xs text-gray-700 font-medium">
|
|
221
|
-
{button.operationSummary}
|
|
222
|
-
</span>
|
|
223
|
-
)}
|
|
224
|
-
</div>
|
|
225
|
-
</div>
|
|
226
|
-
{expandedButtons[index] ? (
|
|
227
|
-
<ChevronUp
|
|
228
|
-
className="w-4 h-4 text-gray-500 transition-transform cursor-pointer"
|
|
229
|
-
onClick={() => toggleButtonExpansion(index)}
|
|
230
|
-
/>
|
|
231
|
-
) : (
|
|
232
|
-
<ChevronDown
|
|
233
|
-
className="w-4 h-4 text-gray-500 transition-transform cursor-pointer"
|
|
234
|
-
onClick={() => toggleButtonExpansion(index)}
|
|
235
|
-
/>
|
|
236
|
-
)}
|
|
237
|
-
</div>
|
|
238
|
-
|
|
239
|
-
{expandedButtons[index] && (
|
|
240
|
-
<div className="px-4 pb-3 border-t border-gray-200">
|
|
241
|
-
<div className="mt-2 space-y-3">
|
|
242
|
-
{/* Description Block */}
|
|
243
|
-
{button.operationDescription && (
|
|
244
|
-
<ContentBlock
|
|
245
|
-
title="Description"
|
|
246
|
-
copyId={`description-${index}`}
|
|
247
|
-
copied={copied}
|
|
248
|
-
onCopy={copyToClipboard}
|
|
249
|
-
variant="bordered"
|
|
250
|
-
>
|
|
251
|
-
<ContentText>
|
|
252
|
-
{button.operationDescription}
|
|
253
|
-
</ContentText>
|
|
254
|
-
</ContentBlock>
|
|
255
|
-
)}
|
|
256
|
-
|
|
257
|
-
{(button.requestUrl || button.explanation) && (
|
|
258
|
-
<ContentBlock
|
|
259
|
-
title="URL"
|
|
260
|
-
copyContent={button.requestUrl || button.explanation}
|
|
261
|
-
copyId={`url-${index}`}
|
|
262
|
-
copied={copied}
|
|
263
|
-
onCopy={copyToClipboard}
|
|
264
|
-
variant="bordered"
|
|
265
|
-
>
|
|
266
|
-
<ContentText>
|
|
267
|
-
{button.requestUrl || button.explanation}
|
|
268
|
-
</ContentText>
|
|
269
|
-
</ContentBlock>
|
|
270
|
-
)}
|
|
271
|
-
|
|
272
|
-
{(hasValidJsonBody(button.jsonBody) || hasValidFormFields(button.formFields)) && (
|
|
273
|
-
<ContentBlock
|
|
274
|
-
title="Payload"
|
|
275
|
-
copyContent={JSON.stringify(
|
|
276
|
-
hasValidJsonBody(button.jsonBody) ? button.jsonBody : button.formFields,
|
|
277
|
-
null,
|
|
278
|
-
2
|
|
279
|
-
)}
|
|
280
|
-
copyId={`payload-${index}`}
|
|
281
|
-
copied={copied}
|
|
282
|
-
onCopy={copyToClipboard}
|
|
283
|
-
variant="bordered"
|
|
284
|
-
>
|
|
285
|
-
<ContentText>
|
|
286
|
-
{hasValidJsonBody(button.jsonBody)
|
|
287
|
-
? JSON.stringify(button.jsonBody, null, 2)
|
|
288
|
-
: JSON.stringify(button.formFields, null, 2)}
|
|
289
|
-
</ContentText>
|
|
290
|
-
</ContentBlock>
|
|
291
|
-
)}
|
|
292
|
-
</div>
|
|
293
|
-
</div>
|
|
294
|
-
)}
|
|
295
|
-
</div>
|
|
296
|
-
))}
|
|
297
|
-
</div>
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function renderModalContent() {
|
|
302
|
-
if (isLoading) {
|
|
303
|
-
return (
|
|
304
|
-
<div className="flex flex-col items-center justify-center py-12">
|
|
305
|
-
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-purple-600 mb-4"></div>
|
|
306
|
-
<span className="text-xs text-gray-600">Fetching query details from semantic layer...</span>
|
|
307
|
-
<span className="text-xs text-gray-400 mt-2">This may take a few moments</span>
|
|
308
|
-
</div>
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
if (error) {
|
|
313
|
-
return (
|
|
314
|
-
<div className="text-red-600 p-4 bg-red-50 rounded-lg border border-red-200 m-6">
|
|
315
|
-
<p className="font-medium mb-2 text-xs">Unable to fetch query details</p>
|
|
316
|
-
<p className="text-xs mb-3">{error}</p>
|
|
317
|
-
<button
|
|
318
|
-
onClick={onRetry}
|
|
319
|
-
className="px-4 py-2 bg-red-100 hover:bg-red-200 rounded text-xs font-medium transition-colors"
|
|
320
|
-
type="button"
|
|
321
|
-
>
|
|
322
|
-
Retry
|
|
323
|
-
</button>
|
|
324
|
-
</div>
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (!sqlQuery || (Array.isArray(sqlQuery) && sqlQuery.length === 0)) {
|
|
329
|
-
return (
|
|
330
|
-
<div className="text-gray-600 p-6">
|
|
331
|
-
<p className="text-xs">No query details available</p>
|
|
332
|
-
</div>
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Handle multiple queries
|
|
337
|
-
if (Array.isArray(sqlQuery)) {
|
|
338
|
-
return (
|
|
339
|
-
<div className="p-6 space-y-4">
|
|
340
|
-
{sqlQuery
|
|
341
|
-
.filter(query => query && typeof query === 'string' && query.trim())
|
|
342
|
-
.map((query, index) => {
|
|
343
|
-
|
|
344
|
-
const rawHeading = queryHeadings[index] || `Query ${index + 1}`;
|
|
345
|
-
const heading = formatQueryHeading(rawHeading);
|
|
346
|
-
|
|
347
|
-
return (
|
|
348
|
-
<ContentBlock
|
|
349
|
-
key={index}
|
|
350
|
-
title={heading}
|
|
351
|
-
copyContent={query}
|
|
352
|
-
copyId={`query-${index}`}
|
|
353
|
-
copied={copied}
|
|
354
|
-
onCopy={copyToClipboard}
|
|
355
|
-
variant="default"
|
|
356
|
-
copyButtonVariant="light"
|
|
357
|
-
>
|
|
358
|
-
<ContentText hasOverflowHandling={false}>
|
|
359
|
-
{query}
|
|
360
|
-
</ContentText>
|
|
361
|
-
</ContentBlock>
|
|
362
|
-
);
|
|
363
|
-
})}
|
|
364
|
-
{renderTableButtonExplanations()}
|
|
365
|
-
</div>
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
return (
|
|
370
|
-
<div className="p-6 space-y-4">
|
|
371
|
-
<ContentBlock
|
|
372
|
-
title={formatQueryHeading(queryHeadings[0] || "Query details")}
|
|
373
|
-
copyContent={typeof sqlQuery === 'string' ? sqlQuery : ''}
|
|
374
|
-
copyId="single"
|
|
375
|
-
copied={copied}
|
|
376
|
-
onCopy={copyToClipboard}
|
|
377
|
-
variant="default"
|
|
378
|
-
copyButtonVariant="light"
|
|
379
|
-
>
|
|
380
|
-
<ContentText hasOverflowHandling={false}>
|
|
381
|
-
{sqlQuery}
|
|
382
|
-
</ContentText>
|
|
383
|
-
</ContentBlock>
|
|
384
|
-
{renderTableButtonExplanations()}
|
|
385
|
-
</div>
|
|
386
|
-
);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
return (
|
|
390
|
-
<CustomModal
|
|
391
|
-
isOpen={isOpen}
|
|
392
|
-
onClose={onClose}
|
|
393
|
-
title="How was this metric calculated?"
|
|
394
|
-
>
|
|
395
|
-
{renderModalContent()}
|
|
396
|
-
</CustomModal>
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
export default QueryDetailsModal;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility function to format query headings for display
|
|
3
|
-
* Converts technical query keys into presentable headings
|
|
4
|
-
*/
|
|
5
|
-
export function formatQueryHeading(heading: string): string {
|
|
6
|
-
if (!heading) {
|
|
7
|
-
return 'Query details';
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
let formatted = heading.replace(/_[a-z-]+-[a-z0-9]+$/i, '');
|
|
11
|
-
|
|
12
|
-
formatted = formatted.replace(/_/g, ' ');
|
|
13
|
-
|
|
14
|
-
formatted = formatted.replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
15
|
-
|
|
16
|
-
const componentRegex = /\b(table|chart|card|button|text|image|list|modal|dropdown|tabs|header|footer|nav|menu|pagination|search|filter|sort|pagination)\b/gi;
|
|
17
|
-
formatted = formatted.replace(componentRegex, '').trim();
|
|
18
|
-
|
|
19
|
-
formatted = formatted.replace(/\b\w/g, l => l.toUpperCase());
|
|
20
|
-
|
|
21
|
-
formatted = formatted.replace(/\s+/g, ' ').trim();
|
|
22
|
-
|
|
23
|
-
return formatted || 'Query details';
|
|
24
|
-
}
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import React, { useEffect } from 'react';
|
|
2
|
-
import { X } from 'lucide-react';
|
|
3
|
-
import thinking from '../../shadcn/components/icons/thinking.gif';
|
|
4
|
-
|
|
5
|
-
type QueryLoadingModalProps = {
|
|
6
|
-
isOpen: boolean;
|
|
7
|
-
onClose: () => void;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function QueryLoadingModal({ isOpen, onClose }: QueryLoadingModalProps) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
useEffect(() => {
|
|
14
|
-
function handleEscapeKey(event: KeyboardEvent) {
|
|
15
|
-
if (event.key === 'Escape' && isOpen) {
|
|
16
|
-
onClose();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (isOpen) {
|
|
21
|
-
document.addEventListener('keydown', handleEscapeKey);
|
|
22
|
-
document.body.style.overflow = 'hidden';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return () => {
|
|
26
|
-
document.removeEventListener('keydown', handleEscapeKey);
|
|
27
|
-
document.body.style.overflow = 'unset';
|
|
28
|
-
};
|
|
29
|
-
}, [isOpen, onClose]);
|
|
30
|
-
|
|
31
|
-
function handleBackdropClick(event: React.MouseEvent<HTMLDivElement>) {
|
|
32
|
-
if (event.target === event.currentTarget) {
|
|
33
|
-
onClose();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!isOpen) {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<div
|
|
43
|
-
className="fixed inset-0 z-[9999] flex items-center justify-center p-4"
|
|
44
|
-
style={{ backgroundColor: 'rgba(0, 0, 0, 0.3)' }}
|
|
45
|
-
onClick={handleBackdropClick}
|
|
46
|
-
>
|
|
47
|
-
<div
|
|
48
|
-
className="relative bg-white rounded-[16px] shadow-[0px_8px_16px_-4px_rgba(0,0,0,0.1)] w-[481px] h-[258px] flex items-center justify-center p-6"
|
|
49
|
-
onClick={(e) => e.stopPropagation()}
|
|
50
|
-
>
|
|
51
|
-
<button
|
|
52
|
-
onClick={onClose}
|
|
53
|
-
className="absolute top-4 right-4 transition-colors duration-200 hover:bg-gray-100 rounded p-1 flex items-center justify-center"
|
|
54
|
-
type="button"
|
|
55
|
-
aria-label="Close modal"
|
|
56
|
-
style={{
|
|
57
|
-
width: '24px',
|
|
58
|
-
height: '24px'
|
|
59
|
-
}}
|
|
60
|
-
>
|
|
61
|
-
<X
|
|
62
|
-
size={12}
|
|
63
|
-
className="text-gray-600"
|
|
64
|
-
style={{
|
|
65
|
-
opacity: 1,
|
|
66
|
-
transform: 'rotate(0deg)'
|
|
67
|
-
}}
|
|
68
|
-
/>
|
|
69
|
-
</button>
|
|
70
|
-
<div className="flex flex-col items-center space-y-4">
|
|
71
|
-
<div
|
|
72
|
-
className="flex flex-col justify-center items-center"
|
|
73
|
-
style={{ margin: '16px', gap: '16px' }}
|
|
74
|
-
>
|
|
75
|
-
<img
|
|
76
|
-
src={thinking}
|
|
77
|
-
alt="Thinking..."
|
|
78
|
-
style={{
|
|
79
|
-
width: '24px',
|
|
80
|
-
height: '24px'
|
|
81
|
-
}}
|
|
82
|
-
/>
|
|
83
|
-
</div>
|
|
84
|
-
<h3 className="text-xl font-semibold text-[#020D21]">
|
|
85
|
-
Thinking...
|
|
86
|
-
</h3>
|
|
87
|
-
<p className="text-base font-medium text-[#687387]">
|
|
88
|
-
Generating query for this component
|
|
89
|
-
</p>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
);
|
|
94
|
-
}
|