@quillsql/admin 1.3.0 → 1.3.2

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 (192) hide show
  1. package/{lib → dist}/Admin.d.ts +12 -7
  2. package/dist/Admin.d.ts.map +1 -0
  3. package/dist/Admin.js +1384 -0
  4. package/{lib → dist}/AdminProvider.d.ts +41 -27
  5. package/dist/AdminProvider.d.ts.map +1 -0
  6. package/{lib → dist}/AdminProvider.js +105 -90
  7. package/dist/api/ConnectionClient.d.ts +27 -0
  8. package/dist/api/ConnectionClient.d.ts.map +1 -0
  9. package/dist/api/ConnectionClient.js +247 -0
  10. package/dist/components/Banner/index.d.ts +3 -0
  11. package/dist/components/Banner/index.d.ts.map +1 -0
  12. package/dist/components/Banner/index.js +27 -0
  13. package/dist/components/CardSection.d.ts +3 -0
  14. package/dist/components/CardSection.d.ts.map +1 -0
  15. package/dist/components/CardSection.js +9 -0
  16. package/dist/components/CardTitle.d.ts +3 -0
  17. package/dist/components/CardTitle.d.ts.map +1 -0
  18. package/dist/components/CardTitle.js +11 -0
  19. package/dist/components/DashboardSelectPopover.d.ts +11 -0
  20. package/dist/components/DashboardSelectPopover.d.ts.map +1 -0
  21. package/dist/components/DashboardSelectPopover.js +175 -0
  22. package/dist/components/DatabaseSelector.d.ts +11 -0
  23. package/dist/components/DatabaseSelector.d.ts.map +1 -0
  24. package/dist/components/DatabaseSelector.js +22 -0
  25. package/dist/components/DeleteButton.d.ts +3 -0
  26. package/dist/components/DeleteButton.d.ts.map +1 -0
  27. package/dist/components/DeleteButton.js +10 -0
  28. package/{lib → dist}/components/DropDownMenu.d.ts +1 -0
  29. package/dist/components/DropDownMenu.d.ts.map +1 -0
  30. package/dist/components/DropDownMenu.js +39 -0
  31. package/dist/components/DropDownMenuWithLabel.d.ts +12 -0
  32. package/dist/components/DropDownMenuWithLabel.d.ts.map +1 -0
  33. package/dist/components/DropDownMenuWithLabel.js +47 -0
  34. package/{lib → dist}/components/EnvSelectPopover.d.ts +1 -0
  35. package/dist/components/EnvSelectPopover.d.ts.map +1 -0
  36. package/dist/components/EnvSelectPopover.js +205 -0
  37. package/dist/components/InputLabel.d.ts +3 -0
  38. package/dist/components/InputLabel.d.ts.map +1 -0
  39. package/dist/components/InputLabel.js +10 -0
  40. package/{lib → dist}/components/OrgSelect.d.ts +1 -0
  41. package/dist/components/OrgSelect.d.ts.map +1 -0
  42. package/dist/components/OrgSelect.js +193 -0
  43. package/dist/components/SqlViewTile.d.ts +8 -0
  44. package/dist/components/SqlViewTile.d.ts.map +1 -0
  45. package/dist/components/SqlViewTile.js +40 -0
  46. package/dist/components/StepDisplay.d.ts +10 -0
  47. package/dist/components/StepDisplay.d.ts.map +1 -0
  48. package/dist/components/StepDisplay.js +15 -0
  49. package/dist/components/index.d.ts +6 -0
  50. package/dist/components/index.d.ts.map +1 -0
  51. package/dist/forms/client_onboard/ConnectDatabase.d.ts +11 -0
  52. package/dist/forms/client_onboard/ConnectDatabase.d.ts.map +1 -0
  53. package/dist/forms/client_onboard/ConnectDatabase.js +137 -0
  54. package/dist/forms/client_onboard/ConnectSchema.d.ts +13 -0
  55. package/dist/forms/client_onboard/ConnectSchema.d.ts.map +1 -0
  56. package/dist/forms/client_onboard/ConnectSchema.js +171 -0
  57. package/dist/forms/client_onboard/CreateSqlViews.d.ts +15 -0
  58. package/dist/forms/client_onboard/CreateSqlViews.d.ts.map +1 -0
  59. package/dist/forms/client_onboard/CreateSqlViews.js +202 -0
  60. package/dist/hooks/useItemBeingEdited.d.ts +4 -0
  61. package/dist/hooks/useItemBeingEdited.d.ts.map +1 -0
  62. package/dist/hooks/useItemBeingEdited.js +25 -0
  63. package/{lib → dist}/icons/ArrowDownHeadIcon.d.ts +1 -0
  64. package/dist/icons/ArrowDownHeadIcon.d.ts.map +1 -0
  65. package/dist/icons/ArrowDownHeadIcon.js +3 -0
  66. package/dist/icons/XMarkIcon.d.ts +3 -0
  67. package/dist/icons/XMarkIcon.d.ts.map +1 -0
  68. package/dist/icons/XMarkIcon.js +11 -0
  69. package/dist/icons/index.d.ts +2 -0
  70. package/dist/icons/index.d.ts.map +1 -0
  71. package/dist/index.d.ts +7 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/{lib/index.d.ts → dist/index.js} +1 -0
  74. package/{lib → dist}/modals/EditDashboardsModal.d.ts +1 -0
  75. package/dist/modals/EditDashboardsModal.d.ts.map +1 -0
  76. package/dist/modals/EditDashboardsModal.js +91 -0
  77. package/dist/modals/NewDashboardModal.d.ts +19 -0
  78. package/dist/modals/NewDashboardModal.d.ts.map +1 -0
  79. package/dist/modals/NewDashboardModal.js +276 -0
  80. package/{lib → dist}/modals/PromoteDashModal.d.ts +2 -1
  81. package/dist/modals/PromoteDashModal.d.ts.map +1 -0
  82. package/dist/modals/PromoteDashModal.js +123 -0
  83. package/{lib → dist}/modals/PromoteViewModal.d.ts +1 -0
  84. package/dist/modals/PromoteViewModal.d.ts.map +1 -0
  85. package/{lib → dist}/modals/PromoteViewModal.js +13 -16
  86. package/{lib → dist}/modals/ReorderDashboardModal.d.ts +4 -1
  87. package/dist/modals/ReorderDashboardModal.d.ts.map +1 -0
  88. package/{lib → dist}/modals/ReorderDashboardModal.js +53 -55
  89. package/dist/modals/index.d.ts +5 -0
  90. package/dist/modals/index.d.ts.map +1 -0
  91. package/{lib → dist}/primitives/ButtonPrimitive.d.ts +3 -0
  92. package/dist/primitives/ButtonPrimitive.d.ts.map +1 -0
  93. package/dist/primitives/ButtonPrimitive.js +47 -0
  94. package/{lib → dist}/primitives/HeaderPrimitive.d.ts +1 -0
  95. package/dist/primitives/HeaderPrimitive.d.ts.map +1 -0
  96. package/dist/primitives/HeaderPrimitive.js +9 -0
  97. package/{lib → dist}/primitives/ModalPrimitive.d.ts +3 -1
  98. package/dist/primitives/ModalPrimitive.d.ts.map +1 -0
  99. package/{lib → dist}/primitives/ModalPrimitive.js +9 -11
  100. package/{lib → dist}/primitives/SecondaryButtonPrimitive.d.ts +1 -0
  101. package/dist/primitives/SecondaryButtonPrimitive.d.ts.map +1 -0
  102. package/{lib → dist}/primitives/SecondaryButtonPrimitive.js +5 -8
  103. package/{lib → dist}/primitives/SelectPrimitive.d.ts +1 -0
  104. package/dist/primitives/SelectPrimitive.d.ts.map +1 -0
  105. package/{lib → dist}/primitives/SelectPrimitive.js +8 -11
  106. package/{lib → dist}/primitives/TextInputPrimitive.d.ts +2 -0
  107. package/dist/primitives/TextInputPrimitive.d.ts.map +1 -0
  108. package/dist/primitives/TextInputPrimitive.js +24 -0
  109. package/dist/primitives/TogglePrimitive.d.ts +6 -0
  110. package/dist/primitives/TogglePrimitive.d.ts.map +1 -0
  111. package/dist/primitives/TogglePrimitive.js +45 -0
  112. package/dist/primitives/index.d.ts +7 -0
  113. package/dist/primitives/index.d.ts.map +1 -0
  114. package/dist/public_components/CreateEnvironment.d.ts +6 -0
  115. package/dist/public_components/CreateEnvironment.d.ts.map +1 -0
  116. package/dist/public_components/CreateEnvironment.js +129 -0
  117. package/{lib → dist}/public_components/DashboardBuilder.d.ts +2 -1
  118. package/dist/public_components/DashboardBuilder.d.ts.map +1 -0
  119. package/dist/public_components/DashboardBuilder.js +192 -0
  120. package/{lib → dist}/public_components/DashboardManager.d.ts +2 -1
  121. package/dist/public_components/DashboardManager.d.ts.map +1 -0
  122. package/dist/public_components/DashboardManager.js +308 -0
  123. package/{lib → dist}/public_components/SQLViewManager.d.ts +2 -1
  124. package/dist/public_components/SQLViewManager.d.ts.map +1 -0
  125. package/dist/public_components/SQLViewManager.js +394 -0
  126. package/dist/utils/constants.d.ts +26 -0
  127. package/dist/utils/constants.d.ts.map +1 -0
  128. package/dist/utils/constants.js +13 -0
  129. package/dist/utils/databases.d.ts +34 -0
  130. package/dist/utils/databases.d.ts.map +1 -0
  131. package/dist/utils/databases.js +51 -0
  132. package/dist/utils/delay.d.ts +2 -0
  133. package/dist/utils/delay.d.ts.map +1 -0
  134. package/dist/utils/delay.js +3 -0
  135. package/dist/utils/schema.d.ts +22 -0
  136. package/dist/utils/schema.d.ts.map +1 -0
  137. package/dist/utils/schema.js +1 -0
  138. package/dist/utils/table.d.ts +9 -0
  139. package/dist/utils/table.d.ts.map +1 -0
  140. package/dist/utils/table.js +1 -0
  141. package/package.json +19 -26
  142. package/LICENSE +0 -21
  143. package/README.md +0 -10
  144. package/lib/Admin.js +0 -1573
  145. package/lib/Admin.js.map +0 -1
  146. package/lib/AdminProvider.js.map +0 -1
  147. package/lib/components/DashboardSelectPopover.d.ts +0 -9
  148. package/lib/components/DashboardSelectPopover.js +0 -187
  149. package/lib/components/DashboardSelectPopover.js.map +0 -1
  150. package/lib/components/DropDownMenu.js +0 -43
  151. package/lib/components/DropDownMenu.js.map +0 -1
  152. package/lib/components/EnvSelectPopover.js +0 -190
  153. package/lib/components/EnvSelectPopover.js.map +0 -1
  154. package/lib/components/OrgSelect.js +0 -188
  155. package/lib/components/OrgSelect.js.map +0 -1
  156. package/lib/components/index.js +0 -17
  157. package/lib/components/index.js.map +0 -1
  158. package/lib/icons/ArrowDownHeadIcon.js +0 -6
  159. package/lib/icons/ArrowDownHeadIcon.js.map +0 -1
  160. package/lib/icons/index.js +0 -9
  161. package/lib/icons/index.js.map +0 -1
  162. package/lib/index.js +0 -17
  163. package/lib/index.js.map +0 -1
  164. package/lib/modals/EditDashboardsModal.js +0 -94
  165. package/lib/modals/EditDashboardsModal.js.map +0 -1
  166. package/lib/modals/PromoteDashModal.js +0 -126
  167. package/lib/modals/PromoteDashModal.js.map +0 -1
  168. package/lib/modals/PromoteViewModal.js.map +0 -1
  169. package/lib/modals/ReorderDashboardModal.js.map +0 -1
  170. package/lib/modals/index.js +0 -15
  171. package/lib/modals/index.js.map +0 -1
  172. package/lib/primitives/ButtonPrimitive.js +0 -25
  173. package/lib/primitives/ButtonPrimitive.js.map +0 -1
  174. package/lib/primitives/HeaderPrimitive.js +0 -12
  175. package/lib/primitives/HeaderPrimitive.js.map +0 -1
  176. package/lib/primitives/ModalPrimitive.js.map +0 -1
  177. package/lib/primitives/SecondaryButtonPrimitive.js.map +0 -1
  178. package/lib/primitives/SelectPrimitive.js.map +0 -1
  179. package/lib/primitives/TextInputPrimitive.js +0 -26
  180. package/lib/primitives/TextInputPrimitive.js.map +0 -1
  181. package/lib/primitives/index.js +0 -19
  182. package/lib/primitives/index.js.map +0 -1
  183. package/lib/public_components/DashboardBuilder.js +0 -166
  184. package/lib/public_components/DashboardBuilder.js.map +0 -1
  185. package/lib/public_components/DashboardManager.js +0 -255
  186. package/lib/public_components/DashboardManager.js.map +0 -1
  187. package/lib/public_components/SQLViewManager.js +0 -400
  188. package/lib/public_components/SQLViewManager.js.map +0 -1
  189. /package/{lib/components/index.d.ts → dist/components/index.js} +0 -0
  190. /package/{lib/icons/index.d.ts → dist/icons/index.js} +0 -0
  191. /package/{lib/modals/index.d.ts → dist/modals/index.js} +0 -0
  192. /package/{lib/primitives/index.d.ts → dist/primitives/index.js} +0 -0
package/dist/Admin.js ADDED
@@ -0,0 +1,1384 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // @ts-nocheck
3
+ import { useState, useEffect } from 'react';
4
+ import { QuillProvider, useQuill, Chart, Table, SQLEditor, AddToDashboardModal, ChartEditor, useDashboard, } from '@quillsql/react';
5
+ import prismTheme from 'prism-react-renderer/themes/nightOwlLight';
6
+ import Highlight, { defaultProps } from 'prism-react-renderer';
7
+ import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, MeasuringStrategy, TouchSensor, } from '@dnd-kit/core';
8
+ import InputLabel from './components/InputLabel';
9
+ import CardSection from './components/CardSection';
10
+ import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable, defaultAnimateLayoutChanges, } from '@dnd-kit/sortable';
11
+ import { CSS } from '@dnd-kit/utilities';
12
+ import { OrgSelect, DashboardManager } from './components';
13
+ import { AdminProvider, useAdmin } from './AdminProvider';
14
+ import { ButtonPrimitive, HeaderPrimitive, ModalPrimitive, SecondaryButtonPrimitive, SelectPrimitive, TextInputPrimitive, } from './primitives';
15
+ import DashboardBuilder from './public_components/DashboardBuilder';
16
+ import SQLViewManager from './public_components/SQLViewManager';
17
+ import { InitialDateRangeOptions, QUILL_SERVER, defaultDateRange, } from './utils/constants';
18
+ import TogglePrimitive from './primitives/TogglePrimitive';
19
+ const defaultTheme = {
20
+ fontFamily: 'Inter; Helvetica',
21
+ backgroundColor: '#FFFFFF',
22
+ primaryTextColor: '#364153',
23
+ secondaryTextColor: '#6C727F',
24
+ chartLabelFontFamily: 'Inter; Helvetica',
25
+ chartLabelColor: '#666666',
26
+ chartTickColor: '#CCCCCC',
27
+ // chartColors: ["#6269E9", "#E14F62"],
28
+ borderColor: '#E5E7EB',
29
+ primaryButtonColor: '#364153',
30
+ borderWidth: 1,
31
+ labelFontWeight: '500',
32
+ fontSize: 14,
33
+ };
34
+ export function EditFiltersModal({ isOpen, dashboardData, selectedDashboard, client, setIsOpen, onSave, ModalComponent, TextInputComponent, ButtonComponent, HeaderComponent, SelectComponent, dashNames, setSelectedEditDashboard, SecondaryButtonComponent, openAddFilterModal, openEditOrderModal, }) {
35
+ const { state, dispatch } = useAdmin();
36
+ const [selectedDashboardName, setSelectedDashboardName] = useState(selectedDashboard);
37
+ useEffect(() => {
38
+ setSelectedDashboardName(selectedDashboard);
39
+ }, [selectedDashboard]);
40
+ const { data } = useDashboard(selectedDashboard);
41
+ const [newFilters, setNewFilters] = useState([]);
42
+ const [isDateComparison, setIsDateComparison] = useState(state.dateFilter.comparison);
43
+ const [initialRange, setInitialRange] = useState(defaultDateRange);
44
+ const [showDateFilter, setShowDateFilter] = useState(true);
45
+ const [newDateFilter, setNewDateFilter] = useState(null);
46
+ const [selectedTable, setSelectedTable] = useState(null);
47
+ const [field, setField] = useState('');
48
+ useEffect(() => {
49
+ if (data && data.dateFilter) {
50
+ dispatch('SET_DATE_FILTER', {
51
+ ...state.dateFilter,
52
+ comparison: data.dateFilter.comparison,
53
+ });
54
+ }
55
+ }, [state.dateFilter, data]);
56
+ useEffect(() => {
57
+ setIsDateComparison(!!state.dateFilter.comparison);
58
+ }, [state.dateFilter]);
59
+ useEffect(() => {
60
+ if (state.tables.length) {
61
+ setSelectedTable(state.tables[0]);
62
+ setField(state.tables[0].columns.map((elem) => elem.name)[0]);
63
+ }
64
+ }, [state.tables]);
65
+ useEffect(() => {
66
+ if (dashboardData && dashboardData.filters) {
67
+ setNewFilters(dashboardData.filters);
68
+ }
69
+ if (dashboardData && dashboardData.dateFilter) {
70
+ setNewDateFilter(dashboardData.dateFilter);
71
+ }
72
+ }, [dashboardData]);
73
+ const handleAddFilter = async () => {
74
+ setNewFilters([...newFilters, { label: '', field }]);
75
+ };
76
+ const handleSubmitDashboardChanges = async () => {
77
+ if (!selectedDashboardName ||
78
+ newFilters.some((filter) => !filter.label) ||
79
+ (newDateFilter &&
80
+ Object.keys(newDateFilter).length &&
81
+ !newDateFilter.label)) {
82
+ alert('Empty fields');
83
+ return;
84
+ }
85
+ if (newFilters.filter((elem) => !elem.field).length) {
86
+ alert(`no filter field for: ${newFilters.filter((elem) => !elem.field)[0].label}`);
87
+ return;
88
+ }
89
+ const updatedFilters = newFilters.map((filter) => {
90
+ const filterType = getPostgresBasicType(selectedTable.columns.find((col) => col.name === filter.field));
91
+ return {
92
+ table: selectedTable.name,
93
+ field: filter.field,
94
+ labelField: filter.field,
95
+ label: filter.label,
96
+ filterType,
97
+ };
98
+ });
99
+ if (dashNames &&
100
+ dashNames.length > 0 &&
101
+ dashNames.some((dashName) => dashName.name === selectedDashboardName &&
102
+ selectedDashboardName !== selectedDashboard)) {
103
+ alert('Dashboard name already taken!');
104
+ return;
105
+ }
106
+ const fieldsSet = new Set();
107
+ const hasDuplicateField = updatedFilters.some((filter) => {
108
+ if (fieldsSet.has(filter.field)) {
109
+ return true;
110
+ }
111
+ else {
112
+ fieldsSet.add(filter.field);
113
+ return false;
114
+ }
115
+ });
116
+ if (hasDuplicateField ||
117
+ (Object.keys(newDateFilter).length > 0 &&
118
+ updatedFilters.some((filter) => filter.filterType === 'date'))) {
119
+ alert('Maximum of one filter per field');
120
+ return;
121
+ }
122
+ let allValid = true;
123
+ updatedFilters.forEach((filter) => {
124
+ if (filter.filterType !== 'string' && filter.filterType !== 'date') {
125
+ allValid = false;
126
+ console.error(`Invalid filterType found: ${filter.filterType}`);
127
+ }
128
+ });
129
+ if (!allValid) {
130
+ alert('We only support string and filters.');
131
+ return;
132
+ }
133
+ const url = `${QUILL_SERVER}/dashfilter/${client._id}/`;
134
+ const body = {
135
+ newDashboardName: selectedDashboardName,
136
+ filters: updatedFilters,
137
+ dateFilter: {
138
+ ...newDateFilter,
139
+ comparison: isDateComparison,
140
+ primaryRange: initialRange,
141
+ },
142
+ name: selectedDashboard,
143
+ };
144
+ dispatch({ type: 'SET_DATE_FILTER', payload: body.dateFilter });
145
+ const headers = {
146
+ 'Content-Type': 'application/json',
147
+ Authorization: `Bearer `,
148
+ };
149
+ try {
150
+ const response = await fetch(url, {
151
+ method: 'POST',
152
+ headers: headers,
153
+ body: JSON.stringify(body),
154
+ });
155
+ setSelectedEditDashboard(null);
156
+ setIsOpen(false);
157
+ onSave();
158
+ }
159
+ catch (e) {
160
+ console.log('error');
161
+ }
162
+ };
163
+ const handleDeleteFilter = (filter) => {
164
+ setNewFilters(newFilters.filter((f) => f !== filter));
165
+ };
166
+ const handleDeleteDateFilter = async () => {
167
+ setShowDateFilter(false);
168
+ setNewDateFilter({});
169
+ };
170
+ const handleAddDateFilter = async () => {
171
+ setShowDateFilter(true);
172
+ if (dashboardData && dashboardData.dateFilter) {
173
+ setNewDateFilter(dashboardData.dateFilter);
174
+ }
175
+ };
176
+ const handleDeleteDashboard = async () => {
177
+ if (confirm('Are you sure? This action cannot be undone.')) {
178
+ const URL = `${QUILL_SERVER}/dashboard/${selectedDashboard}`;
179
+ const res = await fetch(URL, {
180
+ method: 'DELETE',
181
+ headers: { 'Content-Type': 'application/json' },
182
+ body: JSON.stringify({ clientId: client._id }),
183
+ });
184
+ alert(JSON.stringify(res));
185
+ }
186
+ };
187
+ return (_jsx(ModalComponent, { isOpen: isOpen, close: () => {
188
+ setIsOpen(false);
189
+ setNewFilters([]);
190
+ setIsDateComparison(state.dateFilter.comparison);
191
+ }, style: {
192
+ minWidth: '814px',
193
+ maxWidth: '814px',
194
+ }, children: _jsxs("div", { style: {
195
+ display: 'flex',
196
+ gap: 16,
197
+ flexDirection: 'column',
198
+ width: '100%',
199
+ }, children: [_jsx(HeaderComponent, { label: "Manage dashboard" }), _jsxs("div", { children: [_jsx(InputLabel, { children: "Name" }), _jsx("div", { style: { maxWidth: 230 }, children: _jsx(TextInputComponent, { value: selectedDashboardName, onChange: (e) => setSelectedDashboardName(e.target.value) }) })] }), _jsxs("div", { children: [_jsxs("div", { style: {
200
+ display: 'flex',
201
+ flexDirection: 'column',
202
+ gap: '10px',
203
+ }, children: [_jsx(CardSection, { children: "Date Filter" }), showDateFilter && (_jsx(_Fragment, { children: _jsxs("div", { style: {
204
+ display: 'flex',
205
+ flexDirection: 'row',
206
+ gap: '10px',
207
+ }, children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'column' }, children: [_jsx(InputLabel, { children: "Label" }), _jsx("div", { style: {
208
+ display: 'flex',
209
+ flexDirection: 'row',
210
+ alignItems: 'center',
211
+ }, children: _jsx(TextInputComponent, { value: newDateFilter?.label, onChange: (e) => {
212
+ setNewDateFilter({
213
+ ...newDateFilter,
214
+ label: e.target.value,
215
+ });
216
+ } }) })] }), _jsx("div", { style: {
217
+ display: 'flex',
218
+ flexDirection: 'row',
219
+ gap: '10px',
220
+ }, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column' }, children: [_jsx(InputLabel, { children: "Initial Range" }), _jsx(SelectComponent, { value: initialRange.label, onChange: (e) => {
221
+ setInitialRange(InitialDateRangeOptions.find((table) => table.label === e) ?? initialRange);
222
+ }, options: InitialDateRangeOptions.map((table) => {
223
+ return { label: table.label, value: table.label };
224
+ }) })] }) }), _jsx("div", { style: {
225
+ display: 'flex',
226
+ flexDirection: 'row',
227
+ gap: '10px',
228
+ }, children: _jsxs("div", { style: {
229
+ display: 'flex',
230
+ flexDirection: 'column',
231
+ }, children: [_jsx(InputLabel, { children: "Date Comparison" }), _jsx("div", { style: {
232
+ display: 'flex',
233
+ flexDirection: 'column',
234
+ justifyContent: 'center',
235
+ width: '100%',
236
+ height: '100%',
237
+ minWidth: 230,
238
+ maxWidth: 230,
239
+ width: 230,
240
+ }, children: _jsx(TogglePrimitive, { value: isDateComparison, onClick: () => {
241
+ setIsDateComparison((isDateComparison) => !isDateComparison);
242
+ } }) })] }) }), _jsx("div", { style: {
243
+ display: 'flex',
244
+ flexGrow: 1,
245
+ flexDirection: 'row',
246
+ alignItems: 'end',
247
+ justifyContent: 'end',
248
+ gap: '10px',
249
+ }, children: _jsx("div", { style: {
250
+ display: 'flex',
251
+ flexDirection: 'column',
252
+ justifyContent: 'center',
253
+ }, children: _jsx("div", { onClick: () => handleDeleteDateFilter(), style: {
254
+ height: 38,
255
+ width: 42,
256
+ alignItems: 'center',
257
+ justifyContent: 'center',
258
+ display: 'flex',
259
+ cursor: 'pointer',
260
+ }, children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "#4C5462", width: "20", height: "20", children: _jsx("path", { fillRule: "evenodd", d: "M5.47 5.47a.75.75 0 011.06 0L12 10.94l5.47-5.47a.75.75 0 111.06 1.06L13.06 12l5.47 5.47a.75.75 0 11-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 01-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 010-1.06z", clipRule: "evenodd" }) }) }) }) })] }) })), !showDateFilter && (_jsx("div", { style: { maxWidth: 230 }, children: _jsx(SecondaryButtonComponent, { onClick: handleAddDateFilter, label: "Add date filter +" }) }))] }), _jsx("div", { style: {
261
+ display: 'flex',
262
+ flexDirection: 'row',
263
+ alignItems: 'center',
264
+ justifyContent: 'space-between',
265
+ marginTop: 20,
266
+ }, children: _jsx(CardSection, { children: "Filters" }) }), newFilters.length > 0 && (_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '6px' }, children: newFilters.map((filter, index) => {
267
+ return (_jsxs("div", { style: {
268
+ display: 'flex',
269
+ flexDirection: 'row',
270
+ gap: '10px',
271
+ }, children: [_jsxs("div", { style: {
272
+ display: 'flex',
273
+ flexDirection: 'column',
274
+ maxWidth: 300,
275
+ }, children: [index === 0 && _jsx(InputLabel, { children: "Label" }), _jsx(TextInputComponent, { value: filter.label, onChange: (e) => {
276
+ const updatedFilters = newFilters.map((otherFilter, i) => index === i
277
+ ? { ...otherFilter, label: e.target.value }
278
+ : otherFilter);
279
+ setNewFilters(updatedFilters);
280
+ } })] }), _jsxs("div", { style: {
281
+ display: 'flex',
282
+ flexDirection: 'column',
283
+ maxWidth: 300,
284
+ }, children: [index === 0 && _jsx(InputLabel, { children: "Table" }), _jsx(SelectComponent, { defaultValue: "", value: selectedTable ? selectedTable.name : '', onChange: (e) => setSelectedTable(state.tables.find((table) => table.name === e)), options: state.tables.map((table) => {
285
+ return { label: table.name, value: table.name };
286
+ }) })] }), _jsxs("div", { style: {
287
+ display: 'flex',
288
+ flexDirection: 'column',
289
+ maxWidth: 300,
290
+ }, children: [index === 0 && _jsx(InputLabel, { children: "Field" }), _jsx("div", { style: {
291
+ display: 'flex',
292
+ flexDirection: 'column',
293
+ alignItems: 'center',
294
+ }, children: _jsxs("div", { style: {
295
+ display: 'flex',
296
+ flexDirection: 'row',
297
+ alignItems: 'center',
298
+ }, children: [_jsx(SelectComponent, { defaultValue: "", value: filter && filter.field ? filter.field : '', options: selectedTable?.columns.map((column) => {
299
+ return {
300
+ label: column.name,
301
+ value: column.name,
302
+ };
303
+ }), onChange: (e) => {
304
+ const updatedFilters = newFilters.map((otherFilter, i) => index === i
305
+ ? { ...otherFilter, field: e }
306
+ : otherFilter);
307
+ setNewFilters(updatedFilters);
308
+ } }), _jsx("div", { onClick: () => handleDeleteFilter(filter), style: {
309
+ height: 38,
310
+ width: 42,
311
+ alignItems: 'center',
312
+ justifyContent: 'center',
313
+ display: 'flex',
314
+ cursor: 'pointer',
315
+ }, children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "#4C5462", width: "20", height: "20", children: _jsx("path", { fillRule: "evenodd", d: "M5.47 5.47a.75.75 0 011.06 0L12 10.94l5.47-5.47a.75.75 0 111.06 1.06L13.06 12l5.47 5.47a.75.75 0 11-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 01-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 010-1.06z", clipRule: "evenodd" }) }) })] }) })] })] }));
316
+ }) })), _jsx("div", { style: { height: 12 } }), _jsx(SecondaryButtonComponent, { onClick: handleAddFilter, label: "Add filter +" })] }), _jsx(CardSection, { children: "Chart order" }), _jsx("div", { style: { maxWidth: 230 }, children: _jsx(SecondaryButtonComponent, { onClick: () => openEditOrderModal(selectedDashboardName), label: "Edit chart order" }) }), _jsx(CardSection, { children: "Danger Zone" }), _jsx("div", { style: { maxWidth: 230 }, children: _jsx(SecondaryButtonComponent, { onClick: handleDeleteDashboard, label: "Delete Dashboard" }) }), _jsx("div", { style: { height: 18 } }), _jsx("div", { style: { maxWidth: 230 }, children: _jsx(ButtonComponent, { onClick: handleSubmitDashboardChanges, label: "Save changes" }) })] }) }));
317
+ }
318
+ export function AddFilterModal({ isOpen, selectedDashboard, client, setIsOpen, ModalComponent, TextInputComponent, SelectComponent, HeaderComponent, ButtonComponent, openAddDashboardModal, }) {
319
+ const [selectedTable, setSelectedTable] = useState(null);
320
+ const [name, setName] = useState('');
321
+ const [field, setField] = useState('');
322
+ const [filterType, setFilterType] = useState('string');
323
+ const [dateRange, setDateRange] = useState([new Date(), new Date()]);
324
+ const { state, dispatch } = useAdmin();
325
+ useEffect(() => {
326
+ if (state.tables.length) {
327
+ setSelectedTable(state.tables[0]);
328
+ // setField(tables[0].columns.map((elem) => elem.name));
329
+ setField(state.tables[0].columns[0].name);
330
+ }
331
+ }, [state.tables]);
332
+ const handleAddFilter = async () => {
333
+ if (!selectedTable || !field) {
334
+ return;
335
+ }
336
+ const filterType = getPostgresBasicType(selectedTable.columns.find((col) => col.name === field));
337
+ if (filterType !== 'string' && filterType !== 'date') {
338
+ alert('We only support string and filters.');
339
+ return;
340
+ }
341
+ let responseData;
342
+ const url = `${QUILL_SERVER}/dashfilter/${client._id}/`;
343
+ const body = {
344
+ name: selectedDashboard,
345
+ filter: {
346
+ table: selectedTable.name,
347
+ field: field,
348
+ labelField: field,
349
+ label: name,
350
+ filterType,
351
+ },
352
+ };
353
+ const headers = {
354
+ 'Content-Type': 'application/json',
355
+ Authorization: `Bearer `,
356
+ };
357
+ try {
358
+ const response = await fetch(url, {
359
+ method: 'POST',
360
+ headers: headers,
361
+ body: JSON.stringify(body),
362
+ });
363
+ if (!response.ok) {
364
+ throw new Error(`HTTP error! Status: ${response.status}`);
365
+ }
366
+ responseData = await response.json();
367
+ }
368
+ catch (error) {
369
+ console.error('There was a problem with the fetch operation:', error);
370
+ }
371
+ if (responseData) {
372
+ setIsOpen(false);
373
+ setName('');
374
+ setField('');
375
+ return;
376
+ }
377
+ };
378
+ if (!selectedTable) {
379
+ return null;
380
+ }
381
+ return (_jsx(ModalComponent, { isOpen: isOpen, close: () => setIsOpen(false), children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column' }, children: [_jsx(HeaderComponent, { label: "Add filter" }), _jsx("div", { children: "Label" }), _jsx(TextInputComponent, { value: name, onChange: (e) => setName(e.target.value) }), _jsx("div", { children: "Table" }), _jsx(SelectComponent, { defaultValue: "", value: selectedTable ? selectedTable : '', onChange: (e) => setSelectedTable(e.target.value), QuillOptions: state.tables.map((table) => {
382
+ return { label: table.name, value: table.name };
383
+ }) }), _jsx("div", { children: "Field" }), _jsx(SelectComponent, { defaultValue: "", value: field ? field : '', QuillOptions: selectedTable.columns.map((column) => {
384
+ return { label: column.name, value: column.name };
385
+ }), onChange: (e) => {
386
+ setField(e);
387
+ } }), _jsx(ButtonComponent, { label: "Add filter", onClick: handleAddFilter })] }) }));
388
+ }
389
+ export default function Portal({ publicKey, queryEndpoint, theme = defaultTheme, queryHeaders, withCredentials, environment, organizationId, TextInputComponent, ButtonComponent, SecondaryButtonComponent, ModalComponent, SelectComponent, OrganizationSelectComponent, UserManagementComponent, HeaderComponent, }) {
390
+ return (_jsx(AdminProvider, { publicKey: publicKey, children: _jsx(Navigation, { theme: theme, publicKey: publicKey, queryEndpoint: queryEndpoint, queryHeaders: queryHeaders, withCredentials: withCredentials, TextInputComponent: TextInputComponent || TextInputPrimitive, ButtonComponent: ButtonComponent || ButtonPrimitive, HeaderComponent: HeaderComponent || HeaderPrimitive, SecondaryButtonComponent: SecondaryButtonComponent || SecondaryButtonPrimitive, ModalComponent: ModalComponent || ModalPrimitive, environment: environment, OrganizationSelectComponent: OrganizationSelectComponent, UserManagementComponent: UserManagementComponent, SelectComponent: SelectComponent || SelectPrimitive }) }));
391
+ }
392
+ function Navigation({ TextInputComponent, ButtonComponent, SecondaryButtonComponent, ModalComponent, SelectComponent, OrganizationSelectComponent, UserManagementComponent, HeaderComponent, publicKey, queryEndpoint, queryHeaders, environment, withCredentials, }) {
393
+ const { state, dispatch } = useAdmin();
394
+ // MMTODO: Idk if this is needed
395
+ // useEffect(() => {
396
+ // setEnvironmentContext(environment);
397
+ // }, [environment]);
398
+ if (!state.client) {
399
+ return null;
400
+ }
401
+ const renderComponentBasedOnName = () => {
402
+ switch (state.activeComponent) {
403
+ case 'Dashboards':
404
+ return (_jsx(DashboardManager, { TextInputComponent: TextInputComponent, ButtonComponent: ButtonComponent, SecondaryButtonComponent: SecondaryButtonComponent, ModalComponent: ModalComponent, SelectComponent: SelectComponent, HeaderComponent: HeaderComponent, setReportId: (id) => dispatch({ type: 'SET_REPORT_ID', payload: id }), queryEndpoint: queryEndpoint, queryHeaders: queryHeaders, withCredentials: withCredentials }));
405
+ case 'SQL editor':
406
+ return _jsx(DashboardBuilder, {});
407
+ case 'Report':
408
+ return (_jsx(ReportWrapper, { TextInputComponent: TextInputComponent, ButtonComponent: ButtonComponent, SecondaryButtonComponent: SecondaryButtonComponent, ModalComponent: ModalComponent, SelectComponent: SelectComponent, OrganizationSelectComponent: OrganizationSelectComponent, organizationId: state.organizationId, queryEndpoint: queryEndpoint, queryHeaders: queryHeaders, withCredentials: withCredentials }));
409
+ case 'SQL views':
410
+ return _jsx(SQLViewManager, {});
411
+ default:
412
+ return (_jsx(Dashboards, { TextInputComponent: TextInputComponent, ButtonComponent: ButtonComponent, SecondaryButtonComponent: SecondaryButtonComponent, OrganizationSelectComponent: OrganizationSelectComponent, ModalComponent: ModalComponent, SelectComponent: SelectComponent, HeaderComponent: HeaderComponent, setReportId: (id) => dispatch({ type: 'SET_REPORT_ID', payload: id }), queryEndpoint: queryEndpoint, organizationId: state.organizationId, queryHeaders: queryHeaders, withCredentials: withCredentials }));
413
+ }
414
+ };
415
+ return (_jsxs("div", { style: {
416
+ display: 'flex',
417
+ flexDirection: 'column',
418
+ height: '100vh',
419
+ width: '100vw',
420
+ }, children: [_jsxs("nav", { style: {
421
+ zIndex: 2,
422
+ height: '70px',
423
+ width: '100%',
424
+ display: 'flex',
425
+ flexDirection: 'row',
426
+ justifyContent: 'space-between',
427
+ alignItems: 'center',
428
+ backgroundColor: 'white',
429
+ padding: '0',
430
+ position: 'fixed',
431
+ top: 0,
432
+ left: 0,
433
+ right: 0,
434
+ borderBottomWidth: 1,
435
+ borderTopWidth: 0,
436
+ borderLeftWidth: 0,
437
+ borderRightWidth: 0,
438
+ borderStyle: 'solid',
439
+ borderColor: theme.borderColor,
440
+ }, children: [_jsx("div", { style: {
441
+ paddingTop: '18px',
442
+ paddingLeft: '14px',
443
+ paddingBottom: '18px',
444
+ width: 230,
445
+ }, children: _jsxs("svg", { width: "45", height: "18", viewBox: "0 0 45 18", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("g", { clipPath: "url(#clip0_2489_282)", children: _jsx("path", { d: "M18.634 17.3008H9.196C7.97867 17.3008 6.84933 17.1248 5.808 16.7728C4.78133 16.4061 3.894 15.8781 3.146 15.1888C2.398 14.4994 1.81133 13.6634 1.386 12.6808C0.960667 11.6981 0.748 10.5761 0.748 9.31478C0.748 8.14145 0.960667 7.06345 1.386 6.08078C1.826 5.09811 2.42 4.25478 3.168 3.55078C3.916 2.84678 4.796 2.30411 5.808 1.92278C6.82 1.52678 7.90533 1.32878 9.064 1.32878C10.2227 1.32878 11.308 1.52678 12.32 1.92278C13.332 2.31878 14.212 2.86878 14.96 3.57278C15.708 4.27678 16.2947 5.12011 16.72 6.10278C17.16 7.07078 17.38 8.14145 17.38 9.31478C17.38 9.87211 17.314 10.4148 17.182 10.9428C17.0647 11.4708 16.8813 11.9694 16.632 12.4388C16.3827 12.9081 16.06 13.3334 15.664 13.7148C15.268 14.0814 14.806 14.3821 14.278 14.6168V14.6608H18.634V17.3008ZM4.312 9.31478C4.312 9.98945 4.43667 10.6201 4.686 11.2068C4.93533 11.7934 5.27267 12.3068 5.698 12.7468C6.138 13.1721 6.644 13.5094 7.216 13.7588C7.788 14.0081 8.404 14.1328 9.064 14.1328C9.724 14.1328 10.34 14.0081 10.912 13.7588C11.484 13.5094 11.9827 13.1721 12.408 12.7468C12.848 12.3068 13.1927 11.7934 13.442 11.2068C13.6913 10.6201 13.816 9.98945 13.816 9.31478C13.816 8.64011 13.6913 8.00945 13.442 7.42278C13.1927 6.83611 12.848 6.33011 12.408 5.90478C11.9827 5.46478 11.484 5.12011 10.912 4.87078C10.34 4.62145 9.724 4.49678 9.064 4.49678C8.404 4.49678 7.788 4.62145 7.216 4.87078C6.644 5.12011 6.138 5.46478 5.698 5.90478C5.27267 6.33011 4.93533 6.83611 4.686 7.42278C4.43667 8.00945 4.312 8.64011 4.312 9.31478ZM29.3164 17.3008H26.1484V15.8488H26.1044C25.987 16.0541 25.833 16.2594 25.6424 16.4648C25.4664 16.6701 25.2464 16.8534 24.9824 17.0148C24.7184 17.1761 24.4177 17.3081 24.0804 17.4108C23.743 17.5134 23.3764 17.5648 22.9804 17.5648C22.1444 17.5648 21.4624 17.4401 20.9344 17.1908C20.421 16.9268 20.0177 16.5674 19.7244 16.1128C19.4457 15.6581 19.255 15.1228 19.1524 14.5068C19.0644 13.8908 19.0204 13.2234 19.0204 12.5048V6.60878H22.3204V11.8448C22.3204 12.1528 22.3277 12.4754 22.3424 12.8128C22.3717 13.1354 22.4377 13.4361 22.5404 13.7148C22.6577 13.9934 22.8264 14.2208 23.0464 14.3968C23.281 14.5728 23.611 14.6608 24.0364 14.6608C24.4617 14.6608 24.8064 14.5874 25.0704 14.4408C25.3344 14.2794 25.5324 14.0741 25.6644 13.8248C25.811 13.5608 25.9064 13.2674 25.9504 12.9448C25.9944 12.6221 26.0164 12.2848 26.0164 11.9328V6.60878H29.3164V17.3008ZM30.8172 6.60878H34.1172V17.3008H30.8172V6.60878ZM30.5532 3.24278C30.5532 2.71478 30.7365 2.26745 31.1032 1.90078C31.4845 1.51945 31.9392 1.32878 32.4672 1.32878C32.9952 1.32878 33.4425 1.51945 33.8092 1.90078C34.1905 2.26745 34.3812 2.71478 34.3812 3.24278C34.3812 3.77078 34.1905 4.22545 33.8092 4.60678C33.4425 4.97345 32.9952 5.15678 32.4672 5.15678C31.9392 5.15678 31.4845 4.97345 31.1032 4.60678C30.7365 4.22545 30.5532 3.77078 30.5532 3.24278ZM35.652 0.66878H38.952V17.3008H35.652V0.66878ZM40.4869 0.66878H43.7869V17.3008H40.4869V0.66878Z", fill: "#212121" }) }), _jsx("defs", { children: _jsx("clipPath", { id: "clip0_2489_282", children: _jsx("rect", { width: "45", height: "18", fill: "white" }) }) })] }) }), _jsxs("div", { style: { display: 'flex', flexDirection: 'row' }, children: [_jsx("button", { style: {
446
+ color: '#212121',
447
+ backgroundColor: state.activeComponent === 'Dashboards'
448
+ ? '#2121210A'
449
+ : 'transparent',
450
+ padding: '8px 12px',
451
+ height: '38px',
452
+ marginBottom: '4px',
453
+ fontWeight: 'bold',
454
+ fontSize: '0.875rem',
455
+ borderRadius: '4px',
456
+ transition: 'background-color 0.3s',
457
+ border: 'none',
458
+ outline: 'none',
459
+ },
460
+ // onClick={() => setActiveComponent("Dashboards")}
461
+ onClick: () => dispatch({ type: 'SET_ACTIVE_COMPONENT', payload: 'Dashboards' }), children: "Dashboards" }), _jsx("button", { style: {
462
+ color: '#212121',
463
+ backgroundColor: state.activeComponent === 'SQL editor'
464
+ ? '#2121210A'
465
+ : 'transparent',
466
+ padding: '8px 12px',
467
+ height: '38px',
468
+ marginBottom: '4px',
469
+ fontWeight: 'bold',
470
+ fontSize: '0.875rem',
471
+ borderRadius: '4px',
472
+ transition: 'background-color 0.3s',
473
+ border: 'none',
474
+ outline: 'none',
475
+ },
476
+ // onClick={() => setActiveComponent("SQL editor")}
477
+ onClick: () => dispatch({ type: 'SET_ACTIVE_COMPONENT', payload: 'SQL editor' }), children: "SQL editor" }), _jsx("button", { style: {
478
+ color: '#212121',
479
+ backgroundColor: state.activeComponent === 'SQL views'
480
+ ? '#2121210A'
481
+ : 'transparent',
482
+ padding: '8px 12px',
483
+ height: '38px',
484
+ marginBottom: '4px',
485
+ fontWeight: 'bold',
486
+ fontSize: '0.875rem',
487
+ borderRadius: '4px',
488
+ transition: 'background-color 0.3s',
489
+ border: 'none',
490
+ outline: 'none',
491
+ },
492
+ // onClick={() => setActiveComponent("SQL views")}
493
+ onClick: () => dispatch({ type: 'SET_ACTIVE_COMPONENT', payload: 'SQL views' }), children: "SQL views" })] }), _jsx("div", { style: {
494
+ display: 'flex',
495
+ flexDirection: 'row',
496
+ minHeight: '50px',
497
+ justifyContent: 'flex-end',
498
+ alignItems: 'center',
499
+ paddingRight: '8px',
500
+ width: 230,
501
+ }, children: UserManagementComponent && _jsx(UserManagementComponent, {}) })] }), _jsx("div", { style: {
502
+ display: 'flex',
503
+ flexDirection: 'column',
504
+ height: '100%',
505
+ width: '100%',
506
+ // marginTop: activeComponent !== 'Report' ? '70px' : undefined
507
+ }, children: _jsx(QuillProvider
508
+ // organizationId={'2'}
509
+ // publicKey={client?._id}
510
+ , {
511
+ // organizationId={'2'}
512
+ // publicKey={client?._id}
513
+ organizationId: state.organizationId, queryEndpoint: queryEndpoint, withCredentials: withCredentials, queryHeaders: queryHeaders, publicKey: state.client._id, environment: state.environment, theme: theme, children: renderComponentBasedOnName() }) })] }));
514
+ }
515
+ export const theme = {
516
+ fontFamily: 'Inter; Helvetica',
517
+ backgroundColor: '#FFFFFF',
518
+ primaryTextColor: '#364153',
519
+ secondaryTextColor: '#6C727F',
520
+ chartLabelFontFamily: 'Inter; Helvetica',
521
+ chartLabelColor: '#666666',
522
+ chartTickColor: '#CCCCCC',
523
+ chartColors: ['#6269E9', '#E14F62'],
524
+ borderColor: '#E5E7EB',
525
+ labelFontWeight: 500,
526
+ fontSize: 14,
527
+ borderWidth: 1,
528
+ primaryButtonColor: '#212121',
529
+ primaryButtonTextColor: '#FFFFFF',
530
+ };
531
+ export function convertPostgresColumn(column) {
532
+ let format;
533
+ switch (column.dataTypeID) {
534
+ case 20: // int8
535
+ case 21: // int2
536
+ case 23: // int4
537
+ format = 'whole_number';
538
+ break;
539
+ case 700: // float4
540
+ case 701: // float8
541
+ case 1700: // numeric
542
+ format = 'two_decimal_places';
543
+ break;
544
+ case 1082: // date
545
+ case 1083: // time
546
+ case 1184: // timestamptz
547
+ case 1114: // timestamp
548
+ format = 'MMM_dd_yyyy';
549
+ break;
550
+ case 1043: // varchar
551
+ default:
552
+ format = 'string';
553
+ }
554
+ return {
555
+ label: column.name,
556
+ field: column.name,
557
+ format: format,
558
+ };
559
+ }
560
+ export function getPostgresBasicType(column) {
561
+ let format;
562
+ // first check if column.dataTypeID exists
563
+ if (column.dataTypeID) {
564
+ switch (column.dataTypeID) {
565
+ case 20: // int8
566
+ case 21: // int2
567
+ case 23: // int4
568
+ case 700: // float4
569
+ case 701: // float8
570
+ case 1700: // numeric
571
+ format = 'number';
572
+ break;
573
+ case 1082: // date
574
+ case 1083: // time
575
+ case 1184: // timestamptz
576
+ case 1114: // timestamp
577
+ format = 'date';
578
+ break;
579
+ case 1043: // varchar
580
+ default:
581
+ format = 'string';
582
+ }
583
+ }
584
+ else if (column.fieldType) {
585
+ // if column.dataTypeID doesn't exist, check column.fieldType
586
+ switch (column.fieldType) {
587
+ case 'int8':
588
+ case 'int2':
589
+ case 'int4':
590
+ case 'float4':
591
+ case 'float8':
592
+ case 'numeric':
593
+ format = 'number';
594
+ break;
595
+ case 'date':
596
+ case 'time':
597
+ case 'timestamptz':
598
+ case 'timestamp':
599
+ format = 'date';
600
+ break;
601
+ case 'varchar':
602
+ default:
603
+ format = 'string';
604
+ }
605
+ }
606
+ return format;
607
+ }
608
+ export function classNames(...classes) {
609
+ return classes.filter(Boolean).join(' ');
610
+ }
611
+ export function AddDashboardModal({ selectedDashboard, isOpen, setIsOpen, client, ModalComponent, TextInputComponent, SelectComponent, HeaderComponent, ButtonComponent, dashNames, getDashNames, organizationId, }) {
612
+ const { state, dispatch } = useAdmin();
613
+ const [selectedDashboardName, setSelectedDashboardName] = useState(selectedDashboard?.name);
614
+ // const [tables] = useContext(TablesContext);
615
+ const [selectedTable, setSelectedTable] = useState(null);
616
+ const [name, setName] = useState('');
617
+ const [field, setField] = useState('');
618
+ const [filterType, setFilterType] = useState('string');
619
+ const [dateRange, setDateRange] = useState([new Date(), new Date()]);
620
+ const [newFilters, setNewFilters] = useState([]);
621
+ const [newDateFilter, setNewDateFilter] = useState(null);
622
+ useEffect(() => {
623
+ if (state.tables.length) {
624
+ setSelectedTable(state.tables[0]);
625
+ // setField(tables[0].columns.map((elem) => elem.name));
626
+ setField(state.tables[0].columns[0].name);
627
+ }
628
+ }, [state.tables]);
629
+ const handleDeleteFilter = async (filter) => {
630
+ setNewFilters(newFilters.filter((f) => f !== filter));
631
+ };
632
+ const handleAddDashboardSubmit = async () => {
633
+ if (!selectedDashboardName ||
634
+ newFilters.some((filter) => !filter.label) ||
635
+ (newDateFilter && newDateFilter.label)) {
636
+ alert('Empty labels');
637
+ return;
638
+ }
639
+ if (newFilters.some((filter) => !filter.field)) {
640
+ alert('Empty fields');
641
+ return;
642
+ }
643
+ if (!selectedTable || !field) {
644
+ return;
645
+ }
646
+ if (dashNames &&
647
+ dashNames.length > 0 &&
648
+ dashNames.some((dashName) => dashName.name === selectedDashboardName)) {
649
+ alert('Dashboard name already taken!');
650
+ return;
651
+ }
652
+ let updatedFilters = newFilters.map((filter) => {
653
+ const filterType = getPostgresBasicType(selectedTable.columns.find((col) => col.name === filter.field));
654
+ return {
655
+ table: selectedTable.name,
656
+ field: filter.field,
657
+ labelField: filter.field,
658
+ label: filter.label,
659
+ filterType,
660
+ };
661
+ });
662
+ const fieldsSet = new Set();
663
+ const hasDuplicateField = updatedFilters.some((filter) => {
664
+ if (fieldsSet.has(filter.field)) {
665
+ return true;
666
+ }
667
+ else {
668
+ fieldsSet.add(filter.field);
669
+ return false;
670
+ }
671
+ });
672
+ if (hasDuplicateField) {
673
+ alert('Maximum of one filter per field');
674
+ return;
675
+ }
676
+ let allValid = true;
677
+ updatedFilters.forEach((filter) => {
678
+ if (filter.filterType !== 'string' && filter.filterType !== 'date') {
679
+ allValid = false;
680
+ console.error(`Invalid filterType found: ${filter.filterType}`);
681
+ }
682
+ });
683
+ if (!allValid) {
684
+ alert('We only support string and filters.');
685
+ return;
686
+ }
687
+ if (updatedFilters.filter((filter) => filter.filterType === 'date').length > 1) {
688
+ alert('More than one date filter');
689
+ return;
690
+ }
691
+ let responseData;
692
+ const url = `${QUILL_SERVER}/newdash/${client._id}/`;
693
+ const body = newDateFilter && Object.keys(newDateFilter).length
694
+ ? {
695
+ dateFilter: newDateFilter,
696
+ newDashboardName: selectedDashboardName,
697
+ filters: updatedFilters,
698
+ organizationId,
699
+ }
700
+ : {
701
+ newDashboardName: selectedDashboardName,
702
+ filters: updatedFilters,
703
+ organizationId,
704
+ };
705
+ const headers = {
706
+ 'Content-Type': 'application/json',
707
+ Authorization: `Bearer `,
708
+ };
709
+ try {
710
+ const response = await fetch(url, {
711
+ method: 'POST',
712
+ headers: headers,
713
+ body: JSON.stringify(body),
714
+ });
715
+ if (!response.ok) {
716
+ throw new Error(`HTTP error! Status: ${response.status}`);
717
+ }
718
+ responseData = await response.json();
719
+ }
720
+ catch (e) {
721
+ console.log('error');
722
+ }
723
+ if (responseData) {
724
+ setIsOpen(false);
725
+ setName('');
726
+ setSelectedDashboardName('');
727
+ setNewFilters([]);
728
+ setNewDateFilter(null);
729
+ getDashNames();
730
+ return;
731
+ }
732
+ };
733
+ if (!selectedTable) {
734
+ return _jsx(_Fragment, {});
735
+ }
736
+ const handleAddFilter = async () => {
737
+ setNewFilters([...newFilters, { label: '', field }]);
738
+ };
739
+ return (_jsx(ModalComponent, { isOpen: isOpen, close: () => setIsOpen(false), children: _jsxs("div", { children: [_jsx(TextInputComponent, { placeholder: "Enter Dashboard Name...", onChange: (e) => setSelectedDashboardName(e.target.value), value: selectedDashboardName }), _jsxs("div", { style: {
740
+ display: 'flex',
741
+ flexDirection: 'column',
742
+ alignItems: 'center',
743
+ }, children: [newFilters.map((filter, index) => {
744
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'row' }, children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'column' }, children: [_jsx("h2", { children: "Label" }), _jsx(TextInputComponent, { value: filter.label, onChange: (e) => {
745
+ const updatedFilters = newFilters.map((otherFilter, i) => index === i
746
+ ? { ...otherFilter, label: e.target.value }
747
+ : otherFilter);
748
+ setNewFilters(updatedFilters);
749
+ } })] }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column' }, children: [_jsx("h4", { children: "Field" }), _jsx("div", { style: {
750
+ display: 'flex',
751
+ flexDirection: 'column',
752
+ alignItems: 'center',
753
+ }, children: _jsxs("div", { style: {
754
+ display: 'flex',
755
+ flexDirection: 'row',
756
+ alignItems: 'center',
757
+ }, children: [_jsx(SelectComponent, { defaultValue: "", value: filter && filter.field ? filter.field : '', QuillOptions: selectedTable.columns.map((column) => {
758
+ return { label: column.name, value: column.name };
759
+ }), onChange: (e) => {
760
+ const updatedFilters = newFilters.map((otherFilter, i) => index === i
761
+ ? { ...otherFilter, field: e }
762
+ : otherFilter);
763
+ setNewFilters(updatedFilters);
764
+ } }), _jsx("div", { onClick: () => handleDeleteFilter(filter), style: {
765
+ height: 38,
766
+ width: 42,
767
+ alignItems: 'center',
768
+ justifyContent: 'center',
769
+ display: 'flex',
770
+ }, children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "#4C5462", width: "20", height: "20", children: _jsx("path", { fillRule: "evenodd", d: "M5.47 5.47a.75.75 0 011.06 0L12 10.94l5.47-5.47a.75.75 0 111.06 1.06L13.06 12l5.47 5.47a.75.75 0 11-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 01-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 010-1.06z", clipRule: "evenodd" }) }) })] }) })] })] }, filter.field + index));
771
+ }), _jsx(ButtonComponent, { onClick: handleAddFilter, label: "Add new filter +" }), _jsx(ButtonComponent, { onClick: handleAddDashboardSubmit, label: "Add Dashboard +" })] })] }) }));
772
+ }
773
+ export function TableCell({ table, clickTableCell }) {
774
+ const handleClickTableCell = () => {
775
+ clickTableCell(table);
776
+ };
777
+ return (_jsxs("div", { onClick: handleClickTableCell, style: {
778
+ marginBottom: '54px',
779
+ flex: 1,
780
+ minWidth: '540px',
781
+ maxWidth: '540px',
782
+ cursor: 'pointer',
783
+ }, children: [_jsx("div", { style: { display: 'flex', flexDirection: 'row', alignItems: 'center' }, children: _jsx("h3", { style: { color: '#384151' }, children: table.displayName }) }), _jsx(Highlight, { ...defaultProps, theme: prismTheme, code: table.viewQuery, language: "sql", children: ({ className, style, tokens, getLineProps, getTokenProps }) => (_jsx("pre", { className: className, style: {
784
+ ...style,
785
+ textAlign: 'left',
786
+ margin: '1em 0',
787
+ padding: '0.5em',
788
+ overflow: 'scroll',
789
+ maxHeight: 120,
790
+ maxWidth: 520,
791
+ // lineHeight: "1.3em",
792
+ // height: "1.3em",
793
+ }, children: tokens.map((line, i) => (_jsx("div", { ...getLineProps({ line, key: i }), children: line.map((token, key) => (_jsx("span", { ...getTokenProps({ token, key }) }, key))) }, i))) })) })] }, table.displayName));
794
+ }
795
+ export const SQLEditorComponent = ({ query, setQuery,
796
+ // handleRunQuery,
797
+ theme,
798
+ // defineEditorTheme,
799
+ // setEditorTheme,
800
+ }) => {
801
+ const [isOpen, setIsOpen] = useState(false);
802
+ const [rows, setRows] = useState([]);
803
+ const [columns, setColumns] = useState([]);
804
+ const [fields, setFields] = useState([]);
805
+ // const [activeQuery] = useContext(ActiveQueryContext);
806
+ const { state, dispatch } = useAdmin();
807
+ return (_jsxs("div", { style: {
808
+ background: theme.backgroundColor,
809
+ // maxHeight: 700,
810
+ // width: "100%",
811
+ minWidth: 450,
812
+ // overflowY: "scroll",
813
+ // padding: "20px 30px 20px 20px",
814
+ // marginLeft: 20,
815
+ borderRadius: 6,
816
+ overflow: 'hidden',
817
+ }, children: [_jsx(SQLEditor, { containerStyle: { height: 'calc(100vh - 270px)', width: '100%' }, onChangeQuery: (query) => setQuery(query), onChangeData: (data) => setRows(data), onChangeColumns: (columns) => setColumns(columns), onChangeFields: (fields) => setFields(fields), defaultQuery: state.activeQuery ? state.activeQuery : '' }), rows.length > 0 && (_jsx("button", { style: {
818
+ height: 36,
819
+ marginLeft: 250,
820
+ marginTop: 20,
821
+ background: theme.primaryButtonColor,
822
+ color: theme.backgroundColor,
823
+ display: 'flex',
824
+ borderRadius: 6,
825
+ alignItems: 'center',
826
+ justifyContent: 'center',
827
+ outline: 'none',
828
+ cursor: 'pointer',
829
+ fontFamily: theme.fontFamily,
830
+ fontWeight: theme.buttonFontWeight || 600,
831
+ border: 'none',
832
+ fontSize: 14,
833
+ paddingLeft: 20,
834
+ paddingRight: 20,
835
+ }, onClick: () => setIsOpen(true), children: "Add to dashboard" })), _jsx(AddToDashboardModal, { isOpen: isOpen, setIsOpen: setIsOpen, rows: rows, columns: columns, query: query, showTableFormatQuillOptions: true, showDateFieldQuillOptions: true, showAccessControlQuillOptions: true, fields: fields })] }));
836
+ };
837
+ const SchemaListComponent = ({ schema, theme }) => {
838
+ return (_jsx("div", { style: {
839
+ background: theme.backgroundColor,
840
+ maxHeight: 700,
841
+ width: 300,
842
+ minWidth: 300,
843
+ overflowY: 'scroll',
844
+ // maxHeight: "100%",
845
+ paddingLeft: 20,
846
+ paddingRight: 20,
847
+ }, children: schema.map((elem, index) => (_jsx(SchemaItem, { elem: elem, theme: theme, index: index }, elem.displayName + index))) }));
848
+ };
849
+ function SchemaItem({ elem, theme, index }) {
850
+ const [isOpen, setIsOpen] = useState(index === 0);
851
+ const schemaContainerStyle = {
852
+ display: 'flex',
853
+ flexDirection: 'column',
854
+ // WebkitTouchCallout: "none",
855
+ // WebkitUserSelect: "none",
856
+ // KhtmlUserSelect: "none",
857
+ // MozUserSelect: "none",
858
+ // msUserSelect: "none",
859
+ // userSelect: "none",
860
+ };
861
+ const schemaRowStyle = {
862
+ display: 'flex',
863
+ flexDirection: 'row',
864
+ alignItems: 'center',
865
+ width: '100%',
866
+ justifyContent: 'space-between',
867
+ cursor: 'pointer',
868
+ };
869
+ const schemaRowHoverStyle = {
870
+ background: theme.selectUnderlayColor,
871
+ };
872
+ return (_jsxs("div", { style: schemaContainerStyle, children: [_jsxs("div", { style: { ...schemaRowStyle, ...(isOpen && schemaRowHoverStyle) }, onClick: () => setIsOpen(!isOpen), children: [_jsx("p", { style: {
873
+ marginLeft: theme.padding,
874
+ fontSize: theme.fontSize,
875
+ color: '#384151',
876
+ fontWeight: '500',
877
+ }, children: elem.displayName }), _jsx("div", { style: {
878
+ display: 'flex',
879
+ alignItems: 'center',
880
+ justifyContent: 'center',
881
+ // paddingRight: 25,
882
+ paddingTop: 20,
883
+ paddingBottom: 20,
884
+ paddingLeft: 0,
885
+ cursor: 'pointer',
886
+ }, children: isOpen ? (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "h-5 w-5 text-gray-400", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 8.25l-7.5 7.5-7.5-7.5" }) })) : (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", strokeWidth: 1.5, stroke: "currentColor", className: "h-5 w-5", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 4.5l7.5 7.5-7.5 7.5" }) })) })] }), isOpen ? (_jsx("div", { style: {
887
+ paddingBottom: theme.padding,
888
+ display: 'flex',
889
+ flexDirection: 'column',
890
+ paddingLeft: theme.padding,
891
+ paddingRight: theme.padding,
892
+ }, children: elem.columns.map((elem, index) => (_jsxs("div", { style: {
893
+ paddingTop: theme.padding,
894
+ display: 'flex',
895
+ flexDirection: 'row',
896
+ alignItems: 'center',
897
+ justifyContent: 'space-between',
898
+ }, children: [_jsx("div", { title: elem.displayName, className: "text-gray-500", style: {
899
+ fontSize: 13,
900
+ // color: theme.secondaryFontColor,
901
+ whiteSpace: 'nowrap',
902
+ padding: 0,
903
+ margin: 0,
904
+ textOverflow: 'ellipsis',
905
+ overflow: 'hidden',
906
+ width: 200,
907
+ maxWidth: 200,
908
+ }, children: elem.displayName }), _jsx("div", { className: "text-gray-500", title: elem.displayName, style: {
909
+ fontSize: 13,
910
+ color: theme.secondaryFontColor,
911
+ padding: 0,
912
+ margin: 0,
913
+ }, children: elem.fieldType })] }, elem.displayName + elem.index))) })) : null] }));
914
+ }
915
+ export function defineEditorTheme(monaco, theme) {
916
+ monaco.editor.defineTheme('onedark', {
917
+ base: theme.darkMode ? 'vs-dark' : 'vs',
918
+ inherit: true,
919
+ rules: [
920
+ {
921
+ token: 'comment',
922
+ foreground: '#5d7988',
923
+ fontStyle: 'italic',
924
+ },
925
+ { token: 'constant', foreground: '#e06c75' },
926
+ ],
927
+ colors: {
928
+ 'editor.background': '#F9F9F9',
929
+ },
930
+ });
931
+ }
932
+ export function setEditorTheme(editor, monaco) {
933
+ try {
934
+ monaco.editor.setTheme('onedark');
935
+ }
936
+ catch (e) {
937
+ console.log('ERROR: ', e);
938
+ }
939
+ }
940
+ export function isValidDate(d) {
941
+ return d instanceof Date && !isNaN(d);
942
+ }
943
+ export const isArrayOfValidDates = (arr, field) => arr.every((d) => new Date(d[field]) instanceof Date && !isNaN(new Date(d[field])));
944
+ export function formatDateBuckets(startDate, endDate) {
945
+ // Calculate the distance in hours
946
+ const distanceInHours = Math.abs(differenceInHours(endDate, startDate));
947
+ // Check if the distance is less than or equal to one hour
948
+ if (distanceInHours <= 1) {
949
+ return {
950
+ unit: 'hour',
951
+ format: 'h a',
952
+ startOf: startOfHour,
953
+ };
954
+ }
955
+ // Calculate the distance in days
956
+ const distanceInDays = Math.abs(differenceInDays(endDate, startDate));
957
+ // Check if the distance is less than or equal to one day
958
+ if (distanceInDays <= 1) {
959
+ return {
960
+ unit: 'day',
961
+ format: 'MMM d',
962
+ startOf: startOfDay,
963
+ };
964
+ }
965
+ // Calculate the distance in months
966
+ const distanceInMonths = Math.abs(differenceInMonths(endDate, startDate));
967
+ // Check if the distance is less than or equal to one month
968
+ if (distanceInMonths <= 1) {
969
+ return {
970
+ unit: 'month',
971
+ format: 'MMM yyyy',
972
+ startOf: startOfMonth,
973
+ };
974
+ }
975
+ // Calculate the distance in years
976
+ const distanceInYears = Math.abs(differenceInYears(endDate, startDate));
977
+ // Check if the distance is less than or equal to one year
978
+ if (distanceInYears <= 1) {
979
+ return {
980
+ unit: 'year',
981
+ format: 'yyyy',
982
+ startOf: startOfYear,
983
+ };
984
+ }
985
+ // Otherwise, the distance is more than one year
986
+ return {
987
+ unit: 'year',
988
+ format: 'yyyy',
989
+ startOf: startOfYear,
990
+ };
991
+ }
992
+ const POSTGRES_DATE_TYPES = [
993
+ 'timestamp',
994
+ 'date',
995
+ 'timestamptz',
996
+ 'time',
997
+ 'timetz',
998
+ ];
999
+ const FORMAT_QuillOptionS = [
1000
+ { value: 'whole_number', label: 'whole number' },
1001
+ { value: 'one_decimal_place', label: 'one decimal place' },
1002
+ { value: 'dollar_amount', label: 'dollar amount' },
1003
+ { value: 'MMM_yyyy', label: 'month' },
1004
+ { value: 'MMM_dd-MMM_dd', label: 'week' },
1005
+ { value: 'MMM_dd_yyyy', label: 'day' },
1006
+ { value: 'MMM_dd_hh:mm_ap_pm', label: 'day and time' },
1007
+ { value: 'hh_ap_pm', label: 'hour' },
1008
+ { value: 'percent', label: 'percent' },
1009
+ { value: 'string', label: 'string' },
1010
+ ];
1011
+ function Report({ reportId, saveDashboardItem, isOpen, setIsOpen, isEditQueryOpen, SecondaryButtonComponent, ButtonComponent, deleteReport, updateQuery, OrganizationSelectComponent, ModalComponent, NavigateToDashboardBuilder, }) {
1012
+ const { data, loading, error } = useQuill(reportId);
1013
+ const { state, dispatch } = useAdmin();
1014
+ const downloadCSV = () => {
1015
+ // report.rows
1016
+ if (!data) {
1017
+ return;
1018
+ }
1019
+ const json = data.rows; // JSON data passed as a prop
1020
+ const fields = Object.keys(json[0]); // Assumes all objects have same keys
1021
+ const csvRows = [];
1022
+ // Header row
1023
+ csvRows.push(fields.join(','));
1024
+ // Data rows
1025
+ for (let row of json) {
1026
+ let values = fields.map((field) => JSON.stringify(row[field] || ''));
1027
+ csvRows.push(values.join(','));
1028
+ }
1029
+ // Create CSV string and create a 'blob' with it
1030
+ const csvString = csvRows.join('\r\n');
1031
+ const csvBlob = new Blob([csvString], { type: 'text/csv' });
1032
+ // Create a download link and click it
1033
+ const downloadLink = document.createElement('a');
1034
+ downloadLink.download = 'download.csv';
1035
+ downloadLink.href = URL.createObjectURL(csvBlob);
1036
+ downloadLink.style.display = 'none';
1037
+ document.body.appendChild(downloadLink);
1038
+ downloadLink.click();
1039
+ document.body.removeChild(downloadLink);
1040
+ };
1041
+ const goBack = () => {
1042
+ // setActiveComponent("Dashboards");
1043
+ dispatch({ type: 'SET_ACTIVE_COMPONENT', payload: 'Dashboards' });
1044
+ };
1045
+ if (!data || loading) {
1046
+ return null;
1047
+ }
1048
+ if (error) {
1049
+ return _jsx("div", { children: error });
1050
+ }
1051
+ return (_jsxs("div", { style: { paddingLeft: 40, paddingRight: 40 }, children: [_jsx("div", { style: {
1052
+ // width: 'calc(100vw - 30px)',
1053
+ display: 'flex',
1054
+ position: 'fixed',
1055
+ backgroundColor: 'white',
1056
+ zIndex: 1,
1057
+ left: 0,
1058
+ right: 0,
1059
+ top: 0,
1060
+ flexDirection: 'row',
1061
+ paddingTop: 85,
1062
+ alignItems: 'center',
1063
+ justifyContent: 'space-between',
1064
+ paddingLeft: '30px',
1065
+ paddingRight: '30px',
1066
+ borderBottomWidth: 1,
1067
+ borderTopWidth: 0,
1068
+ borderLeftWidth: 0,
1069
+ borderRightWidth: 0,
1070
+ borderStyle: 'solid',
1071
+ borderColor: theme.borderColor,
1072
+ paddingBottom: 20,
1073
+ boxShadow: '0px 1px 4px 0px rgba(0, 0, 0, 0.07)',
1074
+ // paddingRight: '50px',
1075
+ // position: 'absolute'
1076
+ // // zIndex: 10
1077
+ }, children: _jsxs("div", { style: {
1078
+ display: 'flex',
1079
+ flexDirection: 'row',
1080
+ alignItems: 'flex-end',
1081
+ justifyContent: 'space-between',
1082
+ width: '100%',
1083
+ // marginLeft: '25px'
1084
+ }, children: [_jsxs("div", { style: {
1085
+ display: 'flex',
1086
+ flexDirection: 'row',
1087
+ alignItems: 'center',
1088
+ paddingBottom: 4,
1089
+ }, children: [_jsx(SecondaryButtonComponent, { label: "\u2190 Back", onClick: goBack }), _jsx("h1", { style: {
1090
+ fontSize: '36px',
1091
+ paddingTop: '0px',
1092
+ fontWeight: '600',
1093
+ color: '#384151',
1094
+ margin: 0,
1095
+ paddingLeft: 16,
1096
+ }, children: data.name })] }), _jsxs("div", { style: {
1097
+ display: 'flex',
1098
+ flexDirection: 'row',
1099
+ alignItems: 'center',
1100
+ }, children: [_jsx("div", { style: { width: '20px' } }), _jsx("div", { style: { display: 'flex', flexDirection: 'column' }, children: _jsx("div", { style: {
1101
+ display: 'flex',
1102
+ flexDirection: 'row',
1103
+ alignItems: 'flex-end',
1104
+ gap: 16,
1105
+ }, children: _jsx(OrgSelect, { environment: state.environment, setEnvironment: (env) => dispatch({ type: 'SET_ENVIRONMENT', payload: env }), organizations: state.organizations, organizationId: state.organizationId, setOrganizationId: (orgId) => dispatch({ type: 'SET_ORGANIZATION_ID', payload: orgId }), theme: state.theme }) }) })] })] }) }), _jsx("div", { style: { height: 240 } }), _jsx(Chart, { chartId: reportId, colors: theme.chartColors, containerStyle: {
1106
+ width: 'calc(100vw - 80px)',
1107
+ height: data.chartType === 'table' ? 600 : 400,
1108
+ } }), _jsxs("div", { style: {
1109
+ display: 'flex',
1110
+ alignItems: 'center',
1111
+ gap: 16,
1112
+ marginTop: 20,
1113
+ }, children: [_jsx(SecondaryButtonComponent, { label: "Edit chart", onClick: () => setIsOpen(true) }), state.navigateToDashboardBuilder && (_jsx(SecondaryButtonComponent, { label: "Edit query", onClick: () => {
1114
+ dispatch({ type: 'SET_ACTIVE_QUERY', payload: data.queryString });
1115
+ dispatch({ type: 'SET_ACTIVE_EDIT_ITEM', payload: data });
1116
+ state.navigateToDashboardBuilder();
1117
+ } })), _jsx(SecondaryButtonComponent, { label: "Delete", onClick: deleteReport })] }), data.chartType !== 'table' && (_jsx(Table, { containerStyle: { height: 400, width: '100%', marginTop: 24 }, chartId: reportId })), _jsx(EditVisualizationModal, { isOpen: isOpen, setIsOpen: setIsOpen, report: data, isEditMode: !!state.activeQuery, data: data.rows, query: data.queryString, columns: data.columns, fields: data.fields })] }));
1118
+ }
1119
+ function EditVisualizationModal({ isOpen, setIsOpen, report, data, isEditMode }) {
1120
+ if (!report && !data?.length) {
1121
+ return null;
1122
+ }
1123
+ return (_jsx(_Fragment, { children: isOpen && (_jsxs("div", { className: "inset-0 overflow-y-auto relative", style: { zIndex: 120 }, children: [_jsx("div", { className: "absolute inset-0 bg-black/30", "aria-hidden": "true", onClick: () => setIsOpen(false) }), _jsx("div", { className: "flex min-h-full items-center justify-center p-4", children: _jsx("div", { className: "bg-white px-7 py-7 rounded-lg", children: _jsx(ChartEditor, { isOpen: isOpen, setIsOpen: setIsOpen, isEditMode: isEditMode, chartId: report._id, admin: true }) }) })] })) }));
1124
+ }
1125
+ export function ReportWrapper({ SecondaryButtonComponent, ButtonComponent, ModalComponent, SelectComponent, OrganizationSelectComponent, organizationId, queryEndpoint, queryHeaders, withCredentials, }) {
1126
+ const { state, dispatch } = useAdmin();
1127
+ let [isOpen, setIsOpen] = useState(false);
1128
+ const [isEditQueryOpen, setIsEditQueryOpen] = useState(false);
1129
+ const updateQuery = async (dashboardItemId, query) => {
1130
+ if (!state.client || !dashboardItemId || !query) {
1131
+ return;
1132
+ }
1133
+ let responseData;
1134
+ if (queryEndpoint) {
1135
+ const response = await fetch(queryEndpoint, {
1136
+ method: 'POST',
1137
+ headers: {
1138
+ ...queryHeaders,
1139
+ 'Content-Type': 'application/json',
1140
+ },
1141
+ body: JSON.stringify({
1142
+ metadata: organizationId
1143
+ ? {
1144
+ orgId: organizationId,
1145
+ task: 'edit_query',
1146
+ id: state.reportId,
1147
+ query,
1148
+ }
1149
+ : { task: 'edit_query', id: state.reportId, query },
1150
+ }),
1151
+ credentials: withCredentials ? 'include' : 'omit',
1152
+ });
1153
+ responseData = await response.json();
1154
+ }
1155
+ else {
1156
+ const url = `${QUILL_SERVER}/updatequery/${state.client._id}/${organizationId}/`;
1157
+ const requestBody = {
1158
+ dashboardItemId,
1159
+ query,
1160
+ };
1161
+ const response = await fetch(url, {
1162
+ method: 'POST',
1163
+ headers: {
1164
+ 'Content-Type': 'application/json',
1165
+ Authorization: 'Bearer ',
1166
+ environment: state.environment || undefined,
1167
+ },
1168
+ body: JSON.stringify(requestBody),
1169
+ });
1170
+ responseData = await response.json();
1171
+ }
1172
+ if (responseData) {
1173
+ if (responseData.error) {
1174
+ alert(`Failed to save query. ${typeof responseData.error === 'string'
1175
+ ? responseData.error
1176
+ : responseData.error?.routine === 'errorMissingColumn'
1177
+ ? "A column was referenced that doesn't exist."
1178
+ : responseData.error?.routine
1179
+ ? responseData.error?.routine
1180
+ : 'Error parsing SQL query'}`);
1181
+ return;
1182
+ }
1183
+ setIsEditQueryOpen(false);
1184
+ }
1185
+ };
1186
+ const deleteReport = async () => {
1187
+ if (!state.reportId) {
1188
+ return;
1189
+ }
1190
+ if (!state.client) {
1191
+ return;
1192
+ }
1193
+ if (!confirm('Are you sure?')) {
1194
+ return;
1195
+ }
1196
+ let responseData;
1197
+ if (queryEndpoint) {
1198
+ const response = await fetch(queryEndpoint, {
1199
+ method: 'POST',
1200
+ headers: {
1201
+ ...queryHeaders,
1202
+ 'Content-Type': 'application/json',
1203
+ },
1204
+ body: JSON.stringify({
1205
+ metadata: organizationId
1206
+ ? {
1207
+ orgId: organizationId,
1208
+ task: 'delete',
1209
+ dashboardItemId: state.reportId,
1210
+ clientId: state.client._id,
1211
+ }
1212
+ : {
1213
+ task: 'delete',
1214
+ dashboardItemId: state.reportId,
1215
+ clientId: state.client._id,
1216
+ },
1217
+ }),
1218
+ credentials: withCredentials ? 'include' : 'omit', // If withCredentials is true, set to 'include'. Otherwise, set to 'omit'.
1219
+ });
1220
+ responseData = await response.json(); // If the server returns JSON data
1221
+ }
1222
+ else {
1223
+ const url = `${QUILL_SERVER}/deletedash/${state.client._id}/${organizationId}/`;
1224
+ const requestBody = {
1225
+ dashboardItemId: state.reportId,
1226
+ };
1227
+ const response = await fetch(url, {
1228
+ method: 'POST',
1229
+ headers: {
1230
+ 'Content-Type': 'application/json',
1231
+ environment: state.environment || undefined,
1232
+ },
1233
+ body: JSON.stringify(requestBody),
1234
+ });
1235
+ // To get JSON data from the response:
1236
+ responseData = await response.json();
1237
+ }
1238
+ if (responseData) {
1239
+ dispatch({ type: 'SET_ACTIVE_COMPONENT', payload: 'Dashboards' });
1240
+ }
1241
+ };
1242
+ return (_jsx(Report, { reportId: state.reportId, updateQuery: updateQuery, isOpen: isOpen, setIsOpen: setIsOpen, isEditQueryOpen: isEditQueryOpen, setIsEditQueryOpen: setIsEditQueryOpen, deleteReport: deleteReport, SecondaryButtonComponent: SecondaryButtonComponent, ButtonComponent: ButtonComponent, ModalComponent: ModalComponent, SelectComponent: SelectComponent, OrganizationSelectComponent: OrganizationSelectComponent }));
1243
+ }
1244
+ const measuringConfig = {
1245
+ droppable: {
1246
+ strategy: MeasuringStrategy.Always,
1247
+ },
1248
+ };
1249
+ export function ReorderableList({ initialItems, client, itemMap, ButtonComponent, closeModal, onSave, }) {
1250
+ const [items, setItems] = useState([]);
1251
+ // const [client] = useContext(ClientContext);
1252
+ const sensors = useSensors(useSensor(PointerSensor), useSensor(KeyboardSensor, {
1253
+ coordinateGetter: sortableKeyboardCoordinates,
1254
+ }), useSensor(TouchSensor, {
1255
+ activationConstraint: '',
1256
+ }));
1257
+ useEffect(() => {
1258
+ setItems(initialItems
1259
+ .sort((a, b) => {
1260
+ if (a.order === undefined && b.order === undefined)
1261
+ return 0; // both items don't have the 'order' field
1262
+ if (a.order === undefined)
1263
+ return 1; // only 'a' doesn't have the 'order' field, place 'a' last
1264
+ if (b.order === undefined)
1265
+ return -1; // only 'b' doesn't have the 'order' field, place 'b' last
1266
+ return a.order - b.order; // both items have the 'order' field, sort numerically
1267
+ })
1268
+ .map((elem) => elem._id));
1269
+ }, [initialItems]);
1270
+ const handleSaveChanges = async () => {
1271
+ if (!client) {
1272
+ return;
1273
+ }
1274
+ if (!items.length) {
1275
+ return;
1276
+ }
1277
+ try {
1278
+ const response = await fetch(`${QUILL_SERVER}/dashorder/`, {
1279
+ method: 'POST',
1280
+ headers: {
1281
+ 'Content-Type': 'application/json',
1282
+ },
1283
+ body: JSON.stringify({
1284
+ publicKey: client._id,
1285
+ orderArray: items,
1286
+ }),
1287
+ });
1288
+ if (!response.ok) {
1289
+ const errorData = await response.json();
1290
+ throw new Error(`Error: ${errorData.error || 'Unknown error'}`);
1291
+ }
1292
+ const data = await response.json();
1293
+ onSave();
1294
+ closeModal();
1295
+ }
1296
+ catch (error) {
1297
+ console.error(error.message);
1298
+ }
1299
+ };
1300
+ return (_jsxs("div", { children: [_jsx(DndContext, { sensors: sensors, collisionDetection: closestCenter, onDragEnd: handleDragEnd, measuring: measuringConfig, children: _jsx(SortableContext, { items: items, strategy: verticalListSortingStrategy, children: _jsxs("div", { style: {
1301
+ background: 'white',
1302
+ position: 'fixed',
1303
+ width: '100%',
1304
+ height: 'calc(100% - 40px)',
1305
+ overflowY: 'scroll',
1306
+ overflowX: 'hidden',
1307
+ maxWidth: 700,
1308
+ }, children: [_jsx("div", { style: { height: 80 } }), items.map((id) => (_jsx(SortableItem, { id: id, name: itemMap?.get(id).name }, id))), _jsx("div", { style: { height: 100, width: '100%' } })] }) }) }), _jsx("div", { style: {
1309
+ height: 80,
1310
+ paddingTop: 20,
1311
+ width: '100%',
1312
+ background: 'white',
1313
+ position: 'absolute',
1314
+ bottom: -20,
1315
+ left: 0,
1316
+ right: 0,
1317
+ }, children: _jsx(ButtonComponent, { onClick: handleSaveChanges, label: "Save changes" }) })] }));
1318
+ function handleDragEnd(event) {
1319
+ const { active, over } = event;
1320
+ if (!over?.id || !active?.id) {
1321
+ return;
1322
+ }
1323
+ if (active.id !== over.id) {
1324
+ setItems((items) => {
1325
+ const oldIndex = items.indexOf(active.id);
1326
+ const newIndex = items.indexOf(over.id);
1327
+ return arrayMove(items, oldIndex, newIndex);
1328
+ });
1329
+ }
1330
+ }
1331
+ }
1332
+ const animateLayoutChanges = (args) => args.isSorting || args.wasDragging ? defaultAnimateLayoutChanges(args) : true;
1333
+ function SortableItem({ id, name }) {
1334
+ const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
1335
+ animateLayoutChanges,
1336
+ id: id,
1337
+ });
1338
+ let height = 50;
1339
+ const style = {
1340
+ transform: CSS.Translate.toString(transform),
1341
+ transition,
1342
+ display: 'flex',
1343
+ justifyContent: 'space-between',
1344
+ alignItems: 'center',
1345
+ borderRadius: '10px',
1346
+ border: '1px solid #E7E7E7',
1347
+ boxShadow: '0px 2px 8px 0px rgba(56, 65, 81, 0.08)',
1348
+ cursor: 'grab',
1349
+ userSelect: 'none',
1350
+ marginBottom: 20,
1351
+ background: 'white',
1352
+ };
1353
+ return (_jsx("div", { ref: setNodeRef, style: style, ...attributes, children: _jsxs("div", { style: {
1354
+ cursor: 'pointer',
1355
+ width: '100%',
1356
+ display: 'flex',
1357
+ flexDirection: 'row',
1358
+ alignItems: 'center',
1359
+ justifyContent: 'space-between',
1360
+ height: 260,
1361
+ }, ...listeners, children: [_jsxs("div", { style: {
1362
+ display: 'flex',
1363
+ flexDirection: 'column',
1364
+ justifyContent: 'space-between',
1365
+ height: 260,
1366
+ paddingTop: 20,
1367
+ paddingBottom: 20,
1368
+ width: '100%',
1369
+ }, children: [_jsx("div", { style: {
1370
+ minWidth: 600,
1371
+ width: '100%',
1372
+ paddingLeft: 20,
1373
+ fontSize: 18,
1374
+ fontWeight: '500',
1375
+ }, children: name }), _jsx(Chart, { chartId: id, containerStyle: {
1376
+ height: 180,
1377
+ width: '100%',
1378
+ } })] }), _jsx("div", { style: {
1379
+ display: 'flex',
1380
+ flexDirection: 'column',
1381
+ paddingRight: 20,
1382
+ paddingLeft: 20,
1383
+ }, children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "#6D727E", height: 24, width: 24, children: _jsx("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" }) }) })] }) }));
1384
+ }