@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.
Files changed (209) hide show
  1. package/package.json +7 -45
  2. package/.babelrc +0 -14
  3. package/.eslintcache +0 -1
  4. package/.eslintignore +0 -5
  5. package/.eslintrc.js +0 -29
  6. package/dist/package.json +0 -62
  7. package/scripts/build.ts +0 -120
  8. package/src/GrapesjsCanvas.tsx +0 -494
  9. package/src/constants/index.ts +0 -25
  10. package/src/declaration.d.ts +0 -1
  11. package/src/helpers/compiled-table.css +0 -2429
  12. package/src/helpers/css.ts +0 -2667
  13. package/src/helpers/date-picker.ts +0 -807
  14. package/src/helpers/filter-placeholder.ts +0 -18
  15. package/src/helpers/index.ts +0 -13
  16. package/src/helpers/merge-json.ts +0 -106
  17. package/src/index.styles.ts +0 -58
  18. package/src/index.ts +0 -9
  19. package/src/plugins/grapejs-plugin.tsx +0 -196
  20. package/src/plugins/helpers/custom-modal.tsx +0 -123
  21. package/src/plugins/helpers/data-table.tsx +0 -300
  22. package/src/plugins/helpers/extra.tsx +0 -164
  23. package/src/plugins/helpers/query-cache-context.tsx +0 -154
  24. package/src/plugins/helpers/query-cache-singleton.ts +0 -176
  25. package/src/plugins/helpers/query-cache-utils.ts +0 -226
  26. package/src/plugins/helpers/query-details-modal.tsx +0 -400
  27. package/src/plugins/helpers/query-heading-formatter.ts +0 -24
  28. package/src/plugins/helpers/query-loading-modal.tsx +0 -94
  29. package/src/plugins/helpers/render-components.tsx +0 -1450
  30. package/src/plugins/helpers/styled-info-button.tsx +0 -504
  31. package/src/public/canvas.css +0 -42
  32. package/src/public/components-css/table/table-output.css +0 -2436
  33. package/src/public/components-css/table/table.css +0 -30
  34. package/src/public/output.css +0 -2465
  35. package/src/public/table.css +0 -135
  36. package/src/shadcn/components/icons/AiAvatarIcon.tsx +0 -47
  37. package/src/shadcn/components/icons/Co_driver Expanding button copy.svg +0 -21
  38. package/src/shadcn/components/icons/ai-avatar.svg +0 -7
  39. package/src/shadcn/components/icons/thinking.gif +0 -0
  40. package/src/shadcn/components/ui/button.tsx +0 -132
  41. package/src/shadcn/components/ui/card.tsx +0 -92
  42. package/src/shadcn/components/ui/chart.tsx +0 -324
  43. package/src/shadcn/components/ui/checkbox.tsx +0 -27
  44. package/src/shadcn/components/ui/component-wrapper.tsx +0 -61
  45. package/src/shadcn/components/ui/date-filter.tsx +0 -816
  46. package/src/shadcn/components/ui/error-container.tsx +0 -125
  47. package/src/shadcn/components/ui/error-wrapper.tsx +0 -99
  48. package/src/shadcn/components/ui/filter.tsx +0 -368
  49. package/src/shadcn/components/ui/hover-card.tsx +0 -36
  50. package/src/shadcn/components/ui/input.tsx +0 -20
  51. package/src/shadcn/components/ui/label.tsx +0 -24
  52. package/src/shadcn/components/ui/pagination.tsx +0 -213
  53. package/src/shadcn/components/ui/scroll-area.tsx +0 -59
  54. package/src/shadcn/components/ui/search.tsx +0 -150
  55. package/src/shadcn/components/ui/separator.tsx +0 -26
  56. package/src/shadcn/components/ui/skeleton.tsx +0 -69
  57. package/src/shadcn/components/ui/table.tsx +0 -196
  58. package/src/shadcn/components/ui/tabs.tsx +0 -55
  59. package/src/shadcn/components/ui/textarea.tsx +0 -18
  60. package/src/shadcn/components/ui/tooltip.tsx +0 -87
  61. package/src/shadcn/utils.ts +0 -6
  62. package/src/types/grapesjs-tailwind.d.ts +0 -61
  63. package/src/types/images.d.ts +0 -1
  64. package/tailwind.config.js +0 -5
  65. package/tooling/tailwind-compiler/index.js +0 -99
  66. package/tooling/tailwind-compiler/package.json +0 -11
  67. package/tooling/tailwind-compiler/yarn.lock +0 -123
  68. package/tsconfig.build.json +0 -15
  69. package/tsconfig.json +0 -8
  70. /package/{dist/GrapesjsCanvas.d.ts → GrapesjsCanvas.d.ts} +0 -0
  71. /package/{dist/GrapesjsCanvas.js → GrapesjsCanvas.js} +0 -0
  72. /package/{dist/GrapesjsCanvas.js.map → GrapesjsCanvas.js.map} +0 -0
  73. /package/{dist/constants → constants}/index.d.ts +0 -0
  74. /package/{dist/constants → constants}/index.js +0 -0
  75. /package/{dist/constants → constants}/index.js.map +0 -0
  76. /package/{dist/declaration.d.js → declaration.d.js} +0 -0
  77. /package/{dist/declaration.d.js.map → declaration.d.js.map} +0 -0
  78. /package/{dist/helpers → helpers}/compiled-table.css +0 -0
  79. /package/{dist/helpers → helpers}/css.d.ts +0 -0
  80. /package/{dist/helpers → helpers}/css.js +0 -0
  81. /package/{dist/helpers → helpers}/css.js.map +0 -0
  82. /package/{dist/helpers → helpers}/date-picker.d.ts +0 -0
  83. /package/{dist/helpers → helpers}/date-picker.js +0 -0
  84. /package/{dist/helpers → helpers}/date-picker.js.map +0 -0
  85. /package/{dist/helpers → helpers}/filter-placeholder.d.ts +0 -0
  86. /package/{dist/helpers → helpers}/filter-placeholder.js +0 -0
  87. /package/{dist/helpers → helpers}/filter-placeholder.js.map +0 -0
  88. /package/{dist/helpers → helpers}/index.d.ts +0 -0
  89. /package/{dist/helpers → helpers}/index.js +0 -0
  90. /package/{dist/helpers → helpers}/index.js.map +0 -0
  91. /package/{dist/helpers → helpers}/merge-json.d.ts +0 -0
  92. /package/{dist/helpers → helpers}/merge-json.js +0 -0
  93. /package/{dist/helpers → helpers}/merge-json.js.map +0 -0
  94. /package/{dist/index.d.ts → index.d.ts} +0 -0
  95. /package/{dist/index.js → index.js} +0 -0
  96. /package/{dist/index.js.map → index.js.map} +0 -0
  97. /package/{dist/index.styles.d.ts → index.styles.d.ts} +0 -0
  98. /package/{dist/index.styles.js → index.styles.js} +0 -0
  99. /package/{dist/index.styles.js.map → index.styles.js.map} +0 -0
  100. /package/{dist/plugins → plugins}/grapejs-plugin.d.ts +0 -0
  101. /package/{dist/plugins → plugins}/grapejs-plugin.js +0 -0
  102. /package/{dist/plugins → plugins}/grapejs-plugin.js.map +0 -0
  103. /package/{dist/plugins → plugins}/helpers/custom-modal.d.ts +0 -0
  104. /package/{dist/plugins → plugins}/helpers/custom-modal.js +0 -0
  105. /package/{dist/plugins → plugins}/helpers/custom-modal.js.map +0 -0
  106. /package/{dist/plugins → plugins}/helpers/data-table.d.ts +0 -0
  107. /package/{dist/plugins → plugins}/helpers/data-table.js +0 -0
  108. /package/{dist/plugins → plugins}/helpers/data-table.js.map +0 -0
  109. /package/{dist/plugins → plugins}/helpers/extra.d.ts +0 -0
  110. /package/{dist/plugins → plugins}/helpers/extra.js +0 -0
  111. /package/{dist/plugins → plugins}/helpers/extra.js.map +0 -0
  112. /package/{dist/plugins → plugins}/helpers/query-cache-context.d.ts +0 -0
  113. /package/{dist/plugins → plugins}/helpers/query-cache-context.js +0 -0
  114. /package/{dist/plugins → plugins}/helpers/query-cache-context.js.map +0 -0
  115. /package/{dist/plugins → plugins}/helpers/query-cache-singleton.d.ts +0 -0
  116. /package/{dist/plugins → plugins}/helpers/query-cache-singleton.js +0 -0
  117. /package/{dist/plugins → plugins}/helpers/query-cache-singleton.js.map +0 -0
  118. /package/{dist/plugins → plugins}/helpers/query-cache-utils.d.ts +0 -0
  119. /package/{dist/plugins → plugins}/helpers/query-cache-utils.js +0 -0
  120. /package/{dist/plugins → plugins}/helpers/query-cache-utils.js.map +0 -0
  121. /package/{dist/plugins → plugins}/helpers/query-details-modal.d.ts +0 -0
  122. /package/{dist/plugins → plugins}/helpers/query-details-modal.js +0 -0
  123. /package/{dist/plugins → plugins}/helpers/query-details-modal.js.map +0 -0
  124. /package/{dist/plugins → plugins}/helpers/query-heading-formatter.d.ts +0 -0
  125. /package/{dist/plugins → plugins}/helpers/query-heading-formatter.js +0 -0
  126. /package/{dist/plugins → plugins}/helpers/query-heading-formatter.js.map +0 -0
  127. /package/{dist/plugins → plugins}/helpers/query-loading-modal.d.ts +0 -0
  128. /package/{dist/plugins → plugins}/helpers/query-loading-modal.js +0 -0
  129. /package/{dist/plugins → plugins}/helpers/query-loading-modal.js.map +0 -0
  130. /package/{dist/plugins → plugins}/helpers/render-components.d.ts +0 -0
  131. /package/{dist/plugins → plugins}/helpers/render-components.js +0 -0
  132. /package/{dist/plugins → plugins}/helpers/render-components.js.map +0 -0
  133. /package/{dist/plugins → plugins}/helpers/styled-info-button.d.ts +0 -0
  134. /package/{dist/plugins → plugins}/helpers/styled-info-button.js +0 -0
  135. /package/{dist/plugins → plugins}/helpers/styled-info-button.js.map +0 -0
  136. /package/{dist/shadcn → shadcn}/components/icons/AiAvatarIcon.d.ts +0 -0
  137. /package/{dist/shadcn → shadcn}/components/icons/AiAvatarIcon.js +0 -0
  138. /package/{dist/shadcn → shadcn}/components/icons/AiAvatarIcon.js.map +0 -0
  139. /package/{dist/shadcn → shadcn}/components/icons/thinking.gif +0 -0
  140. /package/{dist/shadcn → shadcn}/components/ui/button.d.ts +0 -0
  141. /package/{dist/shadcn → shadcn}/components/ui/button.js +0 -0
  142. /package/{dist/shadcn → shadcn}/components/ui/button.js.map +0 -0
  143. /package/{dist/shadcn → shadcn}/components/ui/card.d.ts +0 -0
  144. /package/{dist/shadcn → shadcn}/components/ui/card.js +0 -0
  145. /package/{dist/shadcn → shadcn}/components/ui/card.js.map +0 -0
  146. /package/{dist/shadcn → shadcn}/components/ui/chart.d.ts +0 -0
  147. /package/{dist/shadcn → shadcn}/components/ui/chart.js +0 -0
  148. /package/{dist/shadcn → shadcn}/components/ui/chart.js.map +0 -0
  149. /package/{dist/shadcn → shadcn}/components/ui/checkbox.d.ts +0 -0
  150. /package/{dist/shadcn → shadcn}/components/ui/checkbox.js +0 -0
  151. /package/{dist/shadcn → shadcn}/components/ui/checkbox.js.map +0 -0
  152. /package/{dist/shadcn → shadcn}/components/ui/component-wrapper.d.ts +0 -0
  153. /package/{dist/shadcn → shadcn}/components/ui/component-wrapper.js +0 -0
  154. /package/{dist/shadcn → shadcn}/components/ui/component-wrapper.js.map +0 -0
  155. /package/{dist/shadcn → shadcn}/components/ui/date-filter.d.ts +0 -0
  156. /package/{dist/shadcn → shadcn}/components/ui/date-filter.js +0 -0
  157. /package/{dist/shadcn → shadcn}/components/ui/date-filter.js.map +0 -0
  158. /package/{dist/shadcn → shadcn}/components/ui/error-container.d.ts +0 -0
  159. /package/{dist/shadcn → shadcn}/components/ui/error-container.js +0 -0
  160. /package/{dist/shadcn → shadcn}/components/ui/error-container.js.map +0 -0
  161. /package/{dist/shadcn → shadcn}/components/ui/error-wrapper.d.ts +0 -0
  162. /package/{dist/shadcn → shadcn}/components/ui/error-wrapper.js +0 -0
  163. /package/{dist/shadcn → shadcn}/components/ui/error-wrapper.js.map +0 -0
  164. /package/{dist/shadcn → shadcn}/components/ui/filter.d.ts +0 -0
  165. /package/{dist/shadcn → shadcn}/components/ui/filter.js +0 -0
  166. /package/{dist/shadcn → shadcn}/components/ui/filter.js.map +0 -0
  167. /package/{dist/shadcn → shadcn}/components/ui/hover-card.d.ts +0 -0
  168. /package/{dist/shadcn → shadcn}/components/ui/hover-card.js +0 -0
  169. /package/{dist/shadcn → shadcn}/components/ui/hover-card.js.map +0 -0
  170. /package/{dist/shadcn → shadcn}/components/ui/input.d.ts +0 -0
  171. /package/{dist/shadcn → shadcn}/components/ui/input.js +0 -0
  172. /package/{dist/shadcn → shadcn}/components/ui/input.js.map +0 -0
  173. /package/{dist/shadcn → shadcn}/components/ui/label.d.ts +0 -0
  174. /package/{dist/shadcn → shadcn}/components/ui/label.js +0 -0
  175. /package/{dist/shadcn → shadcn}/components/ui/label.js.map +0 -0
  176. /package/{dist/shadcn → shadcn}/components/ui/pagination.d.ts +0 -0
  177. /package/{dist/shadcn → shadcn}/components/ui/pagination.js +0 -0
  178. /package/{dist/shadcn → shadcn}/components/ui/pagination.js.map +0 -0
  179. /package/{dist/shadcn → shadcn}/components/ui/scroll-area.d.ts +0 -0
  180. /package/{dist/shadcn → shadcn}/components/ui/scroll-area.js +0 -0
  181. /package/{dist/shadcn → shadcn}/components/ui/scroll-area.js.map +0 -0
  182. /package/{dist/shadcn → shadcn}/components/ui/search.d.ts +0 -0
  183. /package/{dist/shadcn → shadcn}/components/ui/search.js +0 -0
  184. /package/{dist/shadcn → shadcn}/components/ui/search.js.map +0 -0
  185. /package/{dist/shadcn → shadcn}/components/ui/separator.d.ts +0 -0
  186. /package/{dist/shadcn → shadcn}/components/ui/separator.js +0 -0
  187. /package/{dist/shadcn → shadcn}/components/ui/separator.js.map +0 -0
  188. /package/{dist/shadcn → shadcn}/components/ui/skeleton.d.ts +0 -0
  189. /package/{dist/shadcn → shadcn}/components/ui/skeleton.js +0 -0
  190. /package/{dist/shadcn → shadcn}/components/ui/skeleton.js.map +0 -0
  191. /package/{dist/shadcn → shadcn}/components/ui/table.d.ts +0 -0
  192. /package/{dist/shadcn → shadcn}/components/ui/table.js +0 -0
  193. /package/{dist/shadcn → shadcn}/components/ui/table.js.map +0 -0
  194. /package/{dist/shadcn → shadcn}/components/ui/tabs.d.ts +0 -0
  195. /package/{dist/shadcn → shadcn}/components/ui/tabs.js +0 -0
  196. /package/{dist/shadcn → shadcn}/components/ui/tabs.js.map +0 -0
  197. /package/{dist/shadcn → shadcn}/components/ui/textarea.d.ts +0 -0
  198. /package/{dist/shadcn → shadcn}/components/ui/textarea.js +0 -0
  199. /package/{dist/shadcn → shadcn}/components/ui/textarea.js.map +0 -0
  200. /package/{dist/shadcn → shadcn}/components/ui/tooltip.d.ts +0 -0
  201. /package/{dist/shadcn → shadcn}/components/ui/tooltip.js +0 -0
  202. /package/{dist/shadcn → shadcn}/components/ui/tooltip.js.map +0 -0
  203. /package/{dist/shadcn → shadcn}/utils.d.ts +0 -0
  204. /package/{dist/shadcn → shadcn}/utils.js +0 -0
  205. /package/{dist/shadcn → shadcn}/utils.js.map +0 -0
  206. /package/{dist/types → types}/grapesjs-tailwind.d.js +0 -0
  207. /package/{dist/types → types}/grapesjs-tailwind.d.js.map +0 -0
  208. /package/{dist/types → types}/images.d.js +0 -0
  209. /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
- }