@quillsql/react 2.12.27 → 2.12.29

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 (155) hide show
  1. package/dist/cjs/Chart.d.ts.map +1 -1
  2. package/dist/cjs/Chart.js +40 -21
  3. package/dist/cjs/ChartBuilder.d.ts +38 -4
  4. package/dist/cjs/ChartBuilder.d.ts.map +1 -1
  5. package/dist/cjs/ChartBuilder.js +66 -25
  6. package/dist/cjs/ChartEditor.d.ts.map +1 -1
  7. package/dist/cjs/ChartEditor.js +66 -26
  8. package/dist/cjs/Context.d.ts +1 -19
  9. package/dist/cjs/Context.d.ts.map +1 -1
  10. package/dist/cjs/Context.js +32 -83
  11. package/dist/cjs/Dashboard.d.ts +6 -1
  12. package/dist/cjs/Dashboard.d.ts.map +1 -1
  13. package/dist/cjs/Dashboard.js +79 -50
  14. package/dist/cjs/ReportBuilder.d.ts +10 -1
  15. package/dist/cjs/ReportBuilder.d.ts.map +1 -1
  16. package/dist/cjs/ReportBuilder.js +331 -99
  17. package/dist/cjs/SQLEditor.d.ts +10 -1
  18. package/dist/cjs/SQLEditor.d.ts.map +1 -1
  19. package/dist/cjs/SQLEditor.js +122 -29
  20. package/dist/cjs/Table.d.ts.map +1 -1
  21. package/dist/cjs/Table.js +21 -11
  22. package/dist/cjs/components/Chart/ChartTooltip.d.ts.map +1 -1
  23. package/dist/cjs/components/Chart/ChartTooltip.js +5 -4
  24. package/dist/cjs/components/Dashboard/DataLoader.d.ts.map +1 -1
  25. package/dist/cjs/components/Dashboard/DataLoader.js +61 -20
  26. package/dist/cjs/components/Dashboard/MetricComponent.d.ts.map +1 -1
  27. package/dist/cjs/components/Dashboard/MetricComponent.js +7 -1
  28. package/dist/cjs/components/Dashboard/TableComponent.d.ts +16 -2
  29. package/dist/cjs/components/Dashboard/TableComponent.d.ts.map +1 -1
  30. package/dist/cjs/components/Dashboard/TableComponent.js +2 -14
  31. package/dist/cjs/components/QuillTable.d.ts +2 -2
  32. package/dist/cjs/components/QuillTable.d.ts.map +1 -1
  33. package/dist/cjs/components/QuillTable.js +7 -5
  34. package/dist/cjs/components/UiComponents.d.ts +3 -3
  35. package/dist/cjs/components/UiComponents.d.ts.map +1 -1
  36. package/dist/cjs/components/UiComponents.js +4 -4
  37. package/dist/cjs/hooks/useDashboard.d.ts +1 -1
  38. package/dist/cjs/hooks/useDashboard.d.ts.map +1 -1
  39. package/dist/cjs/hooks/useDashboard.js +18 -4
  40. package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts +16 -1
  41. package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
  42. package/dist/cjs/internals/ReportBuilder/PivotModal.js +179 -105
  43. package/dist/cjs/utils/columnProcessing.d.ts +1 -0
  44. package/dist/cjs/utils/columnProcessing.d.ts.map +1 -1
  45. package/dist/cjs/utils/columnProcessing.js +8 -1
  46. package/dist/cjs/utils/constants.d.ts +2 -0
  47. package/dist/cjs/utils/constants.d.ts.map +1 -0
  48. package/dist/cjs/utils/constants.js +4 -0
  49. package/dist/cjs/utils/dashboard.d.ts.map +1 -1
  50. package/dist/cjs/utils/dashboard.js +26 -96
  51. package/dist/cjs/utils/dataFetcher.d.ts +1 -1
  52. package/dist/cjs/utils/dataFetcher.d.ts.map +1 -1
  53. package/dist/cjs/utils/dataFetcher.js +63 -15
  54. package/dist/cjs/utils/dates.d.ts +9 -0
  55. package/dist/cjs/utils/dates.d.ts.map +1 -1
  56. package/dist/cjs/utils/dates.js +43 -1
  57. package/dist/cjs/utils/logging.d.ts +2 -0
  58. package/dist/cjs/utils/logging.d.ts.map +1 -0
  59. package/dist/cjs/utils/logging.js +10 -0
  60. package/dist/cjs/utils/monacoAutocomplete.d.ts +20 -0
  61. package/dist/cjs/utils/monacoAutocomplete.d.ts.map +1 -0
  62. package/dist/cjs/utils/monacoAutocomplete.js +145 -0
  63. package/dist/cjs/utils/pivotConstructor.d.ts +6 -0
  64. package/dist/cjs/utils/pivotConstructor.d.ts.map +1 -0
  65. package/dist/cjs/utils/pivotConstructor.js +140 -0
  66. package/dist/cjs/utils/queryConstructor.d.ts +5 -2
  67. package/dist/cjs/utils/queryConstructor.d.ts.map +1 -1
  68. package/dist/cjs/utils/queryConstructor.js +149 -53
  69. package/dist/cjs/utils/queryConstructor.uspec.d.ts +2 -0
  70. package/dist/cjs/utils/queryConstructor.uspec.d.ts.map +1 -0
  71. package/dist/cjs/utils/queryConstructor.uspec.js +225 -0
  72. package/dist/cjs/utils/tableProcessing.d.ts +23 -0
  73. package/dist/cjs/utils/tableProcessing.d.ts.map +1 -1
  74. package/dist/cjs/utils/tableProcessing.js +125 -2
  75. package/dist/esm/Chart.d.ts.map +1 -1
  76. package/dist/esm/Chart.js +40 -21
  77. package/dist/esm/ChartBuilder.d.ts +38 -4
  78. package/dist/esm/ChartBuilder.d.ts.map +1 -1
  79. package/dist/esm/ChartBuilder.js +64 -24
  80. package/dist/esm/ChartEditor.d.ts.map +1 -1
  81. package/dist/esm/ChartEditor.js +66 -26
  82. package/dist/esm/Context.d.ts +1 -19
  83. package/dist/esm/Context.d.ts.map +1 -1
  84. package/dist/esm/Context.js +32 -82
  85. package/dist/esm/Dashboard.d.ts +6 -1
  86. package/dist/esm/Dashboard.d.ts.map +1 -1
  87. package/dist/esm/Dashboard.js +80 -51
  88. package/dist/esm/ReportBuilder.d.ts +10 -1
  89. package/dist/esm/ReportBuilder.d.ts.map +1 -1
  90. package/dist/esm/ReportBuilder.js +333 -101
  91. package/dist/esm/SQLEditor.d.ts +10 -1
  92. package/dist/esm/SQLEditor.d.ts.map +1 -1
  93. package/dist/esm/SQLEditor.js +123 -30
  94. package/dist/esm/Table.d.ts.map +1 -1
  95. package/dist/esm/Table.js +21 -11
  96. package/dist/esm/components/Chart/ChartTooltip.d.ts.map +1 -1
  97. package/dist/esm/components/Chart/ChartTooltip.js +5 -4
  98. package/dist/esm/components/Dashboard/DataLoader.d.ts.map +1 -1
  99. package/dist/esm/components/Dashboard/DataLoader.js +61 -20
  100. package/dist/esm/components/Dashboard/MetricComponent.d.ts.map +1 -1
  101. package/dist/esm/components/Dashboard/MetricComponent.js +7 -1
  102. package/dist/esm/components/Dashboard/TableComponent.d.ts +16 -2
  103. package/dist/esm/components/Dashboard/TableComponent.d.ts.map +1 -1
  104. package/dist/esm/components/Dashboard/TableComponent.js +2 -14
  105. package/dist/esm/components/QuillTable.d.ts +2 -2
  106. package/dist/esm/components/QuillTable.d.ts.map +1 -1
  107. package/dist/esm/components/QuillTable.js +7 -5
  108. package/dist/esm/components/UiComponents.d.ts +3 -3
  109. package/dist/esm/components/UiComponents.d.ts.map +1 -1
  110. package/dist/esm/components/UiComponents.js +4 -4
  111. package/dist/esm/hooks/useDashboard.d.ts +1 -1
  112. package/dist/esm/hooks/useDashboard.d.ts.map +1 -1
  113. package/dist/esm/hooks/useDashboard.js +19 -5
  114. package/dist/esm/internals/ReportBuilder/PivotModal.d.ts +16 -1
  115. package/dist/esm/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
  116. package/dist/esm/internals/ReportBuilder/PivotModal.js +177 -105
  117. package/dist/esm/utils/columnProcessing.d.ts +1 -0
  118. package/dist/esm/utils/columnProcessing.d.ts.map +1 -1
  119. package/dist/esm/utils/columnProcessing.js +6 -0
  120. package/dist/esm/utils/constants.d.ts +2 -0
  121. package/dist/esm/utils/constants.d.ts.map +1 -0
  122. package/dist/esm/utils/constants.js +1 -0
  123. package/dist/esm/utils/dashboard.d.ts.map +1 -1
  124. package/dist/esm/utils/dashboard.js +27 -97
  125. package/dist/esm/utils/dataFetcher.d.ts +1 -1
  126. package/dist/esm/utils/dataFetcher.d.ts.map +1 -1
  127. package/dist/esm/utils/dataFetcher.js +63 -15
  128. package/dist/esm/utils/dates.d.ts +9 -0
  129. package/dist/esm/utils/dates.d.ts.map +1 -1
  130. package/dist/esm/utils/dates.js +39 -0
  131. package/dist/esm/utils/logging.d.ts +2 -0
  132. package/dist/esm/utils/logging.d.ts.map +1 -0
  133. package/dist/esm/utils/logging.js +6 -0
  134. package/dist/esm/utils/monacoAutocomplete.d.ts +20 -0
  135. package/dist/esm/utils/monacoAutocomplete.d.ts.map +1 -0
  136. package/dist/esm/utils/monacoAutocomplete.js +140 -0
  137. package/dist/esm/utils/pivotConstructor.d.ts +6 -0
  138. package/dist/esm/utils/pivotConstructor.d.ts.map +1 -0
  139. package/dist/esm/utils/pivotConstructor.js +136 -0
  140. package/dist/esm/utils/queryConstructor.d.ts +5 -2
  141. package/dist/esm/utils/queryConstructor.d.ts.map +1 -1
  142. package/dist/esm/utils/queryConstructor.js +145 -52
  143. package/dist/esm/utils/queryConstructor.uspec.d.ts +2 -0
  144. package/dist/esm/utils/queryConstructor.uspec.d.ts.map +1 -0
  145. package/dist/esm/utils/queryConstructor.uspec.js +223 -0
  146. package/dist/esm/utils/tableProcessing.d.ts +23 -0
  147. package/dist/esm/utils/tableProcessing.d.ts.map +1 -1
  148. package/dist/esm/utils/tableProcessing.js +122 -2
  149. package/package.json +1 -1
  150. package/dist/cjs/internals/ReportBuilder/PivotModal.spec.d.ts +0 -2
  151. package/dist/cjs/internals/ReportBuilder/PivotModal.spec.d.ts.map +0 -1
  152. package/dist/cjs/internals/ReportBuilder/PivotModal.spec.js +0 -213
  153. package/dist/esm/internals/ReportBuilder/PivotModal.spec.d.ts +0 -2
  154. package/dist/esm/internals/ReportBuilder/PivotModal.spec.d.ts.map +0 -1
  155. package/dist/esm/internals/ReportBuilder/PivotModal.spec.js +0 -211
@@ -12,7 +12,9 @@ import { isNumericColumnType, } from '../../components/ReportBuilder/ast';
12
12
  import { QuillCard } from '../../components/QuillCard';
13
13
  import { cleanPivot, getPossiblePivotFieldOptions, isValidPivot, } from '../../utils/pivotProcessing';
14
14
  import { hashCode } from '../../utils/crypto';
15
- import { getUniqueValuesByColumns } from '../../utils/tableProcessing';
15
+ import { getCountsByColumns, getDateRangeByColumns, getUniqueValuesByColumns, } from '../../utils/tableProcessing';
16
+ import { generatePivotWithSQL } from '../../utils/pivotConstructor';
17
+ import { getDateBucketFromRange, } from '../../utils/dates';
16
18
  const QuillHover = () => {
17
19
  return (_jsx("style", { children: `
18
20
  .quill-hover {
@@ -26,7 +28,7 @@ const QuillHover = () => {
26
28
  }
27
29
  ` }));
28
30
  };
29
- export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField, setPivotColumnField, pivotValueField, setPivotValueField, pivotAggregation, setPivotAggregation, popUpTitle, setPopUpTitle, selectedTable, SelectComponent, ButtonComponent, SecondaryButtonComponent, PopoverComponent, ErrorMessageComponent = QuillErrorMessageComponent, PivotRowContainer = QuillPivotRowContainer, PivotColumnContainer = QuillPivotColumnContainer, LoadingComponent = QuillLoadingComponent, CardComponent = QuillCard, HeaderComponent, LabelComponent, TextComponent, selectedPivotIndex, setSelectedPivotIndex, removePivot, selectPivot, showUpdatePivot, setShowUpdatePivot, data, columns, theme, isOpen, setIsOpen, dateRange, createdPivots, setCreatedPivots, recommendedPivots, setRecommendedPivots, triggerButtonText = 'Pivot', showPivotEditButton = false, showEditOnPivotClick = true, selectPivotOnEdit = false, showTrigger = true, rightAlign = false, parentRef, pivotCountRequest = 6, query, initialUniqueValues, initialSelectedPivotTable, disabled = false, pivotRecommendationsEnabled = true, }) => {
31
+ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField, setPivotColumnField, pivotValueField, setPivotValueField, pivotAggregation, setPivotAggregation, popUpTitle, setPopUpTitle, selectedTable, SelectComponent, ButtonComponent, SecondaryButtonComponent, PopoverComponent, ErrorMessageComponent = QuillErrorMessageComponent, PivotRowContainer = QuillPivotRowContainer, PivotColumnContainer = QuillPivotColumnContainer, LoadingComponent = QuillLoadingComponent, CardComponent = QuillCard, HeaderComponent, LabelComponent, TextComponent, selectedPivotIndex, setSelectedPivotIndex, removePivot, selectPivot, showUpdatePivot, setShowUpdatePivot, data, columns, theme, isOpen, setIsOpen, dateRange, createdPivots, setCreatedPivots, recommendedPivots, setRecommendedPivots, triggerButtonText = 'Pivot', showPivotEditButton = false, showEditOnPivotClick = true, selectPivotOnEdit = false, showTrigger = true, rightAlign = false, parentRef, pivotCountRequest = 6, query, initialUniqueValues, initialSelectedPivotTable, disabled = false, pivotRecommendationsEnabled = true, report, }) => {
30
32
  const [isLoading, setIsLoading] = useState(false);
31
33
  const [selectedPivotType, setSelectedPivotType] = useState('recommended');
32
34
  const [errors, setErrors] = useState([]);
@@ -41,6 +43,7 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
41
43
  const [allowedRowFields, setAllowedRowFields] = useState([]);
42
44
  const [allowedValueFields, setAllowedValueFields] = useState([]);
43
45
  const [uniqueValues, setUniqueValues] = useState(initialUniqueValues);
46
+ const [dateRanges, setDateRanges] = useState({});
44
47
  const getDistinctValues = async () => {
45
48
  if (columns) {
46
49
  const stringColumns = columns.filter((column) => {
@@ -51,9 +54,10 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
51
54
  setAllowedRowFields(possibleColumns.rowFields);
52
55
  setAllowedColumnFields(possibleColumns.columnFields);
53
56
  setAllowedValueFields(possibleColumns.valueFields);
54
- return possibleColumns;
57
+ return { possibleColumns, uniqueValues: {} };
55
58
  }
56
- const newUniqueValues = await getUniqueValuesByColumns(stringColumns, query || '', data.rows || [], client, customFields);
59
+ const smallStringColumns = await getCountsByColumns(stringColumns, query || '', client, customFields);
60
+ const newUniqueValues = await getUniqueValuesByColumns(smallStringColumns, query || '', data.rows || [], client, customFields);
57
61
  if (!uniqueValues ||
58
62
  hashCode(uniqueValues) !== hashCode(newUniqueValues)) {
59
63
  const possibleColumns = getPossiblePivotFieldOptions(columns, newUniqueValues || {});
@@ -61,10 +65,26 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
61
65
  setAllowedColumnFields(possibleColumns.columnFields);
62
66
  setAllowedValueFields(possibleColumns.valueFields);
63
67
  setUniqueValues(newUniqueValues);
64
- return possibleColumns;
68
+ return { possibleColumns, uniqueValues: newUniqueValues };
65
69
  }
66
70
  }
67
- return { rowFields: [], columnFields: [], valueFields: [] };
71
+ return {
72
+ possibleColumns: { rowFields: [], columnFields: [], valueFields: [] },
73
+ uniqueValues: {},
74
+ };
75
+ };
76
+ const getAllDateRangesByColumn = async () => {
77
+ // Don't reprocess dateRanges if they are already gathered
78
+ if (columns) {
79
+ const dateColumns = columns.filter((column) => {
80
+ return column.jsType === 'date';
81
+ });
82
+ if (dateColumns.length === 0) {
83
+ return [];
84
+ }
85
+ const dateRangeByColumn = await getDateRangeByColumns(dateColumns, query || '', client, customFields);
86
+ setDateRanges(dateRangeByColumn || {});
87
+ }
68
88
  };
69
89
  useEffect(() => {
70
90
  const calculatePivotCardSize = () => {
@@ -91,76 +111,62 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
91
111
  }
92
112
  }, [showUpdatePivot, isOpen]);
93
113
  useEffect(() => {
94
- if (pivotRowField && data && columns) {
95
- const pivot = {
96
- rowField: pivotRowField || '',
97
- rowFieldType: columnsToShow[pivotRowField || ''],
98
- columnField: pivotColumnField,
99
- columnFieldType: columnsToShow[pivotColumnField || ''],
100
- valueField: pivotValueField || '',
101
- aggregationType: pivotAggregation || '',
102
- };
103
- const { rows, columns } = generatePivotTable(pivot, data, dateRange, false);
104
- setSamplePivotTable({ pivot: pivot, rows, columns });
105
- }
106
- if ((pivotRowField && data && columns) || initialSelectedPivotTable) {
107
- getDistinctValues();
108
- }
109
- if (initialUniqueValues) {
110
- const possibleColumns = getPossiblePivotFieldOptions(columns, initialUniqueValues);
111
- setAllowedRowFields(possibleColumns.rowFields);
112
- setAllowedColumnFields(possibleColumns.columnFields);
113
- setAllowedValueFields(possibleColumns.valueFields);
114
- setUniqueValues(initialUniqueValues);
115
- }
116
- if (pivotRowField && data && columns) {
117
- const pivot = {
118
- rowField: pivotRowField || '',
119
- rowFieldType: columnsToShow[pivotRowField || ''],
120
- columnField: pivotColumnField,
121
- columnFieldType: columnsToShow[pivotColumnField || ''],
122
- valueField: pivotValueField || '',
123
- aggregationType: pivotAggregation || '',
124
- };
125
- if (initialSelectedPivotTable) {
126
- setSamplePivotTable({
127
- pivot: pivot,
128
- rows: initialSelectedPivotTable.rows,
129
- columns: initialSelectedPivotTable.columns,
130
- });
131
- }
132
- else {
133
- const { rows, columns } = generatePivotTable(pivot, data, dateRange, false);
114
+ const fetchPivotData = async () => {
115
+ if (pivotRowField && data && columns) {
116
+ const pivot = {
117
+ rowField: pivotRowField || '',
118
+ rowFieldType: columnsToShow[pivotRowField || ''],
119
+ columnField: pivotColumnField,
120
+ columnFieldType: columnsToShow[pivotColumnField || ''],
121
+ valueField: pivotValueField || '',
122
+ aggregationType: pivotAggregation || '',
123
+ };
124
+ const { rows, columns } = await generatePivotTable(pivot, data, dateRange, false, -1, undefined, undefined, report, client, uniqueValues);
134
125
  setSamplePivotTable({ pivot: pivot, rows, columns });
135
126
  }
136
- }
127
+ if ((pivotRowField && data && columns) || initialSelectedPivotTable) {
128
+ getDistinctValues();
129
+ }
130
+ if (initialUniqueValues) {
131
+ const possibleColumns = getPossiblePivotFieldOptions(columns, initialUniqueValues);
132
+ setAllowedRowFields(possibleColumns.rowFields);
133
+ setAllowedColumnFields(possibleColumns.columnFields);
134
+ setAllowedValueFields(possibleColumns.valueFields);
135
+ setUniqueValues(initialUniqueValues);
136
+ }
137
+ if (pivotRowField && data && columns) {
138
+ const pivot = {
139
+ rowField: pivotRowField || '',
140
+ rowFieldType: columnsToShow[pivotRowField || ''],
141
+ columnField: pivotColumnField,
142
+ columnFieldType: columnsToShow[pivotColumnField || ''],
143
+ valueField: pivotValueField || '',
144
+ aggregationType: pivotAggregation || '',
145
+ };
146
+ if (initialSelectedPivotTable) {
147
+ setSamplePivotTable({
148
+ pivot: pivot,
149
+ rows: initialSelectedPivotTable.rows,
150
+ columns: initialSelectedPivotTable.columns,
151
+ });
152
+ }
153
+ else {
154
+ const { rows, columns } = await generatePivotTable(pivot, data, dateRange, false, -1, undefined, undefined, report, client, uniqueValues);
155
+ setSamplePivotTable({ pivot: pivot, rows, columns });
156
+ }
157
+ }
158
+ };
159
+ fetchPivotData();
137
160
  }, []);
138
161
  useEffect(() => {
139
- if ((pivotRowField && data && columns) || initialSelectedPivotTable) {
162
+ if (pivotRowField && data && columns) {
140
163
  getDistinctValues();
164
+ getAllDateRangesByColumn();
141
165
  }
142
- }, [initialSelectedPivotTable, columns, data, pivotRowField]);
143
- useEffect(() => {
144
- const pivot = {
145
- rowField: pivotRowField || '',
146
- rowFieldType: columnsToShow[pivotRowField || ''],
147
- columnField: pivotColumnField,
148
- columnFieldType: columnsToShow[pivotColumnField || ''],
149
- valueField: pivotValueField || '',
150
- aggregationType: pivotAggregation || '',
151
- };
152
- if (isValidPivot(pivot) && data && columns) {
153
- const { rows, columns } = generatePivotTable(pivot, data, dateRange, false);
154
- setSamplePivotTable({ pivot: pivot, rows, columns });
166
+ else if (initialSelectedPivotTable) {
167
+ getDistinctValues();
155
168
  }
156
- }, [
157
- data,
158
- columns,
159
- pivotRowField,
160
- pivotColumnField,
161
- pivotValueField,
162
- pivotAggregation,
163
- ]);
169
+ }, [initialSelectedPivotTable, columns, data, pivotRowField]);
164
170
  useEffect(() => {
165
171
  if (!initialUniqueValues) {
166
172
  return;
@@ -181,21 +187,25 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
181
187
  return map;
182
188
  }, {});
183
189
  }, [columns]);
184
- const selectedPivotTable = useMemo(() => {
185
- if (selectedPivotIndex === -1) {
186
- return null;
187
- }
188
- const pivot = createdPivots[selectedPivotIndex];
189
- const { rows, columns } = generatePivotTable(pivot, data, dateRange, false);
190
- return {
191
- pivot: pivot,
192
- rows: rows,
193
- columns: columns,
190
+ const [selectedPivotTable, setSelectedPivotTable] = useState(null);
191
+ useEffect(() => {
192
+ const fetchPivotTables = async () => {
193
+ if (selectedPivotIndex === -1) {
194
+ return null;
195
+ }
196
+ const pivot = createdPivots[selectedPivotIndex];
197
+ const { rows, columns } = await generatePivotTable(pivot, data, dateRange, false, -1, undefined, undefined, report, client, uniqueValues);
198
+ setSelectedPivotTable({
199
+ pivot: pivot,
200
+ rows: rows,
201
+ columns: columns,
202
+ });
194
203
  };
204
+ fetchPivotTables();
195
205
  }, [selectedPivotIndex, data, dateRange, createdPivots]);
196
206
  const onSelectRecommendedPivot = (pivot, index) => {
197
207
  if (showEditOnPivotClick) {
198
- onEditPivot(pivot, index);
208
+ onEditPivot(pivot, index, 'recommended');
199
209
  return;
200
210
  }
201
211
  if (index === selectedPivotIndex && selectedPivotType === 'recommended') {
@@ -208,20 +218,30 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
208
218
  setIsOpen(false);
209
219
  };
210
220
  const onSelectCreatedPivot = (pivot, index) => {
211
- selectPivot(pivot);
221
+ selectPivot(pivot, pivot.columnField ? uniqueValues : undefined, dateRanges[pivot.rowField]?.dateRange, samplePivotTable);
212
222
  setSelectedPivotType('created');
213
223
  setIsOpen(false);
214
224
  setPopUpTitle('Add pivot');
215
225
  };
216
- const onEditPivot = (pivot, index) => {
226
+ const onEditPivot = async (pivot, index, pivotType) => {
217
227
  setIsLoading(false);
218
228
  setPivotRowField(pivot.rowField);
219
229
  setPivotColumnField(pivot.columnField);
220
230
  setPivotValueField(pivot.valueField);
221
231
  setPivotAggregation(pivot.aggregationType);
222
232
  setShowUpdatePivot(true);
233
+ if (pivotType === 'recommended' &&
234
+ index !== null &&
235
+ recommendedPivotTables[index]) {
236
+ setSamplePivotTable(recommendedPivotTables[index]);
237
+ return;
238
+ }
223
239
  if (isValidPivot(pivot)) {
224
- const { rows, columns } = generatePivotTable(pivot, data, dateRange, false);
240
+ let dateBucket = undefined;
241
+ if (pivotRowField && dateRanges[pivotRowField]) {
242
+ dateBucket = getDateBucketFromRange(dateRanges[pivotRowField].dateRange);
243
+ }
244
+ const { rows, columns } = await generatePivotTable(pivot, data, dateRange, false, -1, undefined, dateBucket, report, client, uniqueValues);
225
245
  setSamplePivotTable({ pivot, rows, columns });
226
246
  return;
227
247
  }
@@ -237,6 +257,7 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
237
257
  return;
238
258
  }
239
259
  setIsLoading(true);
260
+ let tempUniqueValues = uniqueValues;
240
261
  let possibleColumns = {
241
262
  rowFields: allowedRowFields,
242
263
  columnFields: allowedColumnFields,
@@ -246,7 +267,9 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
246
267
  allowedColumnFields.length === 0 &&
247
268
  allowedValueFields.length === 0) ||
248
269
  !uniqueValues) {
249
- possibleColumns = await getDistinctValues();
270
+ const distinctValues = await getDistinctValues();
271
+ possibleColumns = distinctValues.possibleColumns;
272
+ tempUniqueValues = distinctValues.uniqueValues;
250
273
  }
251
274
  const cloudBody = {
252
275
  pivotCountRequest,
@@ -266,9 +289,8 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
266
289
  try {
267
290
  const resp = await getDataFromCloud(client, 'pivotai', cloudBody);
268
291
  const recommendedPivots = resp?.data?.pivotTables.map((pivot) => cleanPivot(pivot, possibleColumns)) || [];
269
- setRecommendedPivots(recommendedPivots.map((pivot) => {
270
- if (pivot.columnField &&
271
- columnsToShow[pivot.columnField] === 'date') {
292
+ const cleanedPivots = recommendedPivots.map((pivot) => {
293
+ if (pivot.columnField && columnsToShow[pivot.columnField] === 'date') {
272
294
  const columnField = pivot.columnField;
273
295
  pivot.columnField = pivot.rowField;
274
296
  pivot.rowField = columnField;
@@ -281,7 +303,13 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
281
303
  : undefined,
282
304
  title: generatePivotTitle(pivot),
283
305
  };
306
+ });
307
+ setRecommendedPivots(cleanedPivots);
308
+ const pts = await Promise.all(cleanedPivots.map(async (p) => {
309
+ const { rows, columns } = await generatePivotTable(p, data, dateRange, false, 6, undefined, undefined, report, client, tempUniqueValues);
310
+ return { pivot: p, rows, columns };
284
311
  }));
312
+ setRecommendedPivotTables(pts);
285
313
  setSelectedPivotIndex(-1);
286
314
  }
287
315
  catch (e) {
@@ -323,26 +351,51 @@ export const PivotModal = ({ pivotRowField, setPivotRowField, pivotColumnField,
323
351
  setSamplePivotTable(null);
324
352
  return;
325
353
  }
326
- setTimeout(() => {
327
- const { rows, columns } = generatePivotTable(pivot, data, dateRange, false);
354
+ let dateBucket = undefined;
355
+ if (pivotRowField && dateRanges[pivotRowField]) {
356
+ dateBucket = getDateBucketFromRange(dateRanges[pivotRowField].dateRange);
357
+ }
358
+ setTimeout(async () => {
359
+ const { rows, columns } = await generatePivotTable(pivot, data, dateRange, false, -1, undefined, dateBucket, report, client, uniqueValues);
328
360
  setSamplePivotTable({ pivot, rows, columns });
329
361
  setIsLoading(false);
330
362
  }, 500);
331
363
  };
332
- const recommendedPivotTables = useMemo(() => {
333
- const pts = recommendedPivots.map((p) => {
334
- const { rows, columns } = generatePivotTable(p, data, dateRange, false, 6);
335
- return { pivot: p, rows, columns };
336
- });
337
- return pts;
338
- }, [recommendedPivots, data]);
339
- const createdPivotTables = useMemo(() => {
340
- const pts = createdPivots.map((p) => {
341
- const { rows, columns } = generatePivotTable(p, data, dateRange, false, 6);
342
- return { pivot: p, rows, columns };
343
- });
344
- return pts;
345
- }, [createdPivots, data]);
364
+ const [recommendedPivotTables, setRecommendedPivotTables] = useState([]);
365
+ // useEffect(() => {
366
+ // const fetchPivotTables = async () => {
367
+ // const pts = await Promise.all(
368
+ // recommendedPivots.map(async (p: Pivot) => {
369
+ // const { rows, columns } = await generatePivotTable(
370
+ // p,
371
+ // data,
372
+ // dateRange,
373
+ // false,
374
+ // 6,
375
+ // undefined,
376
+ // undefined,
377
+ // report,
378
+ // client,
379
+ // uniqueValues,
380
+ // );
381
+ // return { pivot: p, rows, columns };
382
+ // }),
383
+ // );
384
+ // setRecommendedPivotTables(pts);
385
+ // };
386
+ // fetchPivotTables();
387
+ // }, [recommendedPivots, dateRange]);
388
+ const [createdPivotTables, setCreatedPivotTables] = useState([]);
389
+ useEffect(() => {
390
+ const fetchPivotTables = async () => {
391
+ const pts = await Promise.all(createdPivots.map(async (p) => {
392
+ const { rows, columns } = await generatePivotTable(p, data, dateRange, false, 6, undefined, undefined, report, client, uniqueValues);
393
+ return { pivot: p, rows, columns };
394
+ }));
395
+ setCreatedPivotTables(pts);
396
+ };
397
+ fetchPivotTables();
398
+ }, [createdPivots, dateRange]);
346
399
  return (_jsx("div", { style: { display: 'flex', flexDirection: 'column' }, children: _jsxs("div", { style: {
347
400
  position: 'relative',
348
401
  display: 'inline-block',
@@ -619,7 +672,7 @@ function determineIntervalThroughOverride(dateBucket, dateRange) {
619
672
  return eachMonthOfInterval(dateRange);
620
673
  }
621
674
  }
622
- function getDateBuckets(dateRange, column, data, dateBucket) {
675
+ export function getDateBuckets(dateRange, column, data, dateBucket) {
623
676
  if (!dateRange) {
624
677
  if (dateBucket) {
625
678
  return determineIntervalThroughOverride(dateBucket, getDateRange(undefined, column, data));
@@ -736,7 +789,26 @@ const fixBigQueryData = (data = []) => {
736
789
  }
737
790
  return newData;
738
791
  };
739
- export function generatePivotTable(pivot, data, dateRange, isComparison, rowLimit = -1, compRange = undefined, dateBucket) {
792
+ export async function generatePivotTable(pivot, data, dateRange, isComparison, rowLimit = -1, compRange = undefined, dateBucket, report, client, uniqueValues) {
793
+ try {
794
+ if (report && report.rowCount && report.rowCount !== data.length) {
795
+ let dateFilter = report
796
+ ? report.filtersApplied.find((f) => f.filterType === 'date_range')
797
+ : undefined;
798
+ const pivotTable = await generatePivotWithSQL(pivot, report, client, dateBucket, dateFilter, pivot.columnField && uniqueValues
799
+ ? Object.keys(uniqueValues[pivot.columnField])
800
+ : undefined);
801
+ if (pivotTable) {
802
+ return pivotTable;
803
+ }
804
+ }
805
+ }
806
+ catch (e) {
807
+ console.error('Error generating pivot table with SQL, using in memory process', e);
808
+ }
809
+ return generatePivotTableInMemory(pivot, data, dateRange, isComparison, rowLimit, compRange);
810
+ }
811
+ export function generatePivotTableInMemory(pivot, data, dateRange, isComparison, rowLimit = -1, compRange = undefined, dateBucket) {
740
812
  // If there is no rowField, aggregate on the valueField
741
813
  if (!pivot.rowField) {
742
814
  return valueFieldAggregation(data, pivot.valueField, pivot.aggregationType, isComparison);
@@ -7,4 +7,5 @@ export declare function convertPostgresColumn(field: {
7
7
  export declare function convertColumnInfoToColumnInternal(columnInfo: ColumnInfo): ColumnInternal;
8
8
  export declare function convertFieldTypeToJSType(fieldType: string): string;
9
9
  export declare function convertFormatToJsType(column: Column): string;
10
+ export declare function processColumnName(columnName: string): string;
10
11
  //# sourceMappingURL=columnProcessing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"columnProcessing.d.ts","sourceRoot":"","sources":["../../../src/utils/columnProcessing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE3D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,cAAc,CAyGjB;AAED,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,UAAU,GACrB,cAAc,CAShB;AA0DD,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAsBlE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAY5D"}
1
+ {"version":3,"file":"columnProcessing.d.ts","sourceRoot":"","sources":["../../../src/utils/columnProcessing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAM3D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,cAAc,CAyGjB;AAED,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,UAAU,GACrB,cAAc,CAShB;AA0DD,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAsBlE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAY5D;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D"}
@@ -1,3 +1,6 @@
1
+ function removeBigQuerySpecialChars(columnName) {
2
+ return columnName.replaceAll('quill_forward_slash', '/');
3
+ }
1
4
  export function convertPostgresColumn(field) {
2
5
  let format;
3
6
  let fieldType;
@@ -200,3 +203,6 @@ export function convertFormatToJsType(column) {
200
203
  return 'string';
201
204
  }
202
205
  }
206
+ export function processColumnName(columnName) {
207
+ return removeBigQuerySpecialChars(columnName);
208
+ }
@@ -0,0 +1,2 @@
1
+ export declare const MAX_COLUMN_ROWS_LIMIT = 500;
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,MAAM,CAAC"}
@@ -0,0 +1 @@
1
+ export const MAX_COLUMN_ROWS_LIMIT = 500;
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/utils/dashboard.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAkC5E;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,GAAG,SAAS,EACxC,gBAAgB,EAAE,GAAG,EACrB,MAAM,CAAC,EAAE,GAAG,EACZ,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,CAAC,CA+C9B;AAwQD,wBAAsB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAI,OAAO,CAAC,GAAG,CAAC,CA0BpF"}
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../../src/utils/dashboard.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAoC5E;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,GAAG,SAAS,EACxC,gBAAgB,EAAE,GAAG,EACrB,MAAM,CAAC,EAAE,GAAG,EACZ,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,CAAC,CAiD9B;AA0KD,wBAAsB,YAAY,CAChC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,GAAG,GACV,OAAO,CAAC,GAAG,CAAC,CA0Bd"}
@@ -1,9 +1,9 @@
1
1
  import { valueFormatter } from './valueFormatter';
2
- import { generatePivotTable, generatePivotTableYAxis, getDateRange, getDateString, } from '../internals/ReportBuilder/PivotModal';
2
+ import { generatePivotTable, generatePivotTableYAxis, } from '../internals/ReportBuilder/PivotModal';
3
3
  import { snakeAndCamelCaseToTitleCase } from './textProcessing';
4
- import { generatePivotQuery } from './queryConstructor';
5
4
  import { getData } from './dataFetcher';
6
- import { differenceInDays } from 'date-fns';
5
+ import { getDateBucketFromRange } from './dates';
6
+ import { generatePivotWithSQL } from './pivotConstructor';
7
7
  const defaultDashboardItem = {
8
8
  id: '',
9
9
  name: '',
@@ -67,8 +67,10 @@ export async function cleanDashboardItem(item, dashboardFilters, client, dateBuc
67
67
  xAxisFormat: item.xAxisFormat,
68
68
  order: item.order,
69
69
  filtersApplied: item.filtersApplied,
70
+ rowCount: parseInt(item.rowCount),
70
71
  sort: item.sort,
71
72
  page: item.page,
73
+ itemQuery: item.itemQuery,
72
74
  };
73
75
  }
74
76
  /**
@@ -118,106 +120,34 @@ async function getPivotTable(report, dashboardFilters, client, dateBucketInitial
118
120
  }
119
121
  const pivot = report?.pivot;
120
122
  const data = report || {};
121
- if (client && client.databaseType.toLowerCase() === 'postgresql') {
123
+ if (pivot && client) {
124
+ if (report.rowCount === 0) {
125
+ return { rows: [], columns: [] };
126
+ }
122
127
  try {
123
- let dateRange = undefined;
124
- let comparisonInterval = undefined;
125
128
  let dateBucket = dateBucketInitial;
126
- if (!dateBucket && pivot.rowFieldType !== 'string' && pivot.rowField) {
127
- let filterDateRange = undefined;
128
- if (dateFilter) {
129
- filterDateRange = {
130
- start: dateFilter.startDate,
131
- end: dateFilter.endDate,
132
- };
133
- }
134
- dateRange = getDateRange(filterDateRange, pivot.rowField, data.rows);
135
- const difference = differenceInDays(dateRange.end, dateRange.start);
136
- if (difference < 14) {
137
- dateBucket = 'day';
138
- }
139
- else if (difference < 60) {
140
- dateBucket = 'week';
141
- }
142
- else if (difference < 365 * 3) {
143
- dateBucket = 'month';
144
- }
145
- else {
146
- dateBucket = 'year';
147
- }
129
+ let filterDateRange = undefined;
130
+ if (dateFilter) {
131
+ filterDateRange = {
132
+ start: dateFilter.startDate,
133
+ end: dateFilter.endDate,
134
+ };
148
135
  }
149
- if (dateFilter && dateFilter && dateFilter.comparisonRange) {
150
- const comparisonRange = differenceInDays(dateFilter?.comparisonRange.endDate, dateFilter?.comparisonRange.startDate);
151
- if (!isNaN(comparisonRange)) {
152
- if (dateBucket === 'month') {
153
- comparisonInterval = comparisonRange / 30 + ' month';
154
- }
155
- else if (dateBucket === 'year') {
156
- comparisonInterval = comparisonRange / 365 + ' year';
157
- }
158
- else {
159
- comparisonInterval = comparisonRange + ' day';
160
- }
161
- }
136
+ else if (report.dateRange) {
137
+ filterDateRange = report.dateRange;
162
138
  }
163
- const sqlQuery = generatePivotQuery(pivot, report.itemQuery, report.rows, dateBucket, comparisonInterval);
164
- if (sqlQuery && report.rows.length > 0) {
165
- const hostedBody = {
166
- metadata: {
167
- preQueries: [sqlQuery],
168
- task: 'query',
169
- orgId: client.customerId || '*',
170
- clientId: client.publicKey,
171
- databaseType: client?.databaseType,
172
- getCustomFields: false,
173
- runQueryConfig: {
174
- overridePost: true,
175
- convertDatatypes: true,
176
- },
177
- },
178
- };
179
- const cloudBody = { ...hostedBody };
180
- const resp = await getData(client, 'query', 'same-origin', hostedBody, cloudBody);
181
- // With our current design we have to remove the second row field but leave the first for comparison purposes.
182
- const rows = resp.queryResults[0].rows;
183
- const columns = resp.queryResults[0].fields
184
- .map((field) => ({
185
- field: field.name,
186
- label: field.name.replace('comparison_', 'comparison '),
187
- }))
188
- .filter((field, index) => field.field !== 'comparison_' + pivot.rowField || index === 0);
189
- if (pivot.rowFieldType !== 'string') {
190
- rows.forEach((row) => {
191
- row[pivot.rowField] = getDateString(row[pivot.rowField], undefined, dateBucket);
192
- });
193
- // add a row for each date in the range that doesn't have a value
194
- if (pivot.rowFieldType !== 'string') {
195
- const dateSet = new Set(rows.map((row) => row[pivot.rowField]));
196
- // create a loop that will go through each formatted date and add a row if it doesn't exist going to the current date
197
- for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1000)) {
198
- const formattedDate = getDateString(date.toDateString(), undefined, dateBucket);
199
- if (!dateSet.has(formattedDate)) {
200
- const newRow = {};
201
- newRow[pivot.rowField] = formattedDate;
202
- rows.push(newRow);
203
- dateSet.add(formattedDate);
204
- }
205
- // order the rows by the date field
206
- rows.sort((a, b) => {
207
- return new Date(a[pivot.rowField]) < new Date(b[pivot.rowField])
208
- ? -1
209
- : 1;
210
- });
211
- }
212
- }
213
- }
214
- return {
215
- rows: rows,
216
- columns: columns,
217
- };
139
+ if (!dateBucket && filterDateRange) {
140
+ dateBucket = getDateBucketFromRange(filterDateRange);
141
+ }
142
+ const pivotTable = await generatePivotWithSQL(pivot, report, client, dateBucket, dateFilter, report.distinctStrings);
143
+ if (pivotTable) {
144
+ return pivotTable;
218
145
  }
146
+ throw new Error('Error generating pivot table');
147
+ }
148
+ catch (e) {
149
+ throw new Error('Error generating pivot table: ' + e);
219
150
  }
220
- catch (e) { }
221
151
  }
222
152
  return pivot && data.rows
223
153
  ? generatePivotTable(pivot, JSON.parse(JSON.stringify(data.rows)), // deep copy
@@ -1,3 +1,3 @@
1
- export declare function getData(client: any, cloudQueryEndpoint: string, noCred: RequestCredentials, hostedRequestBody: any, cloudRequestBody: any, method?: string): Promise<any>;
1
+ export declare function getData(client: any, cloudQueryEndpoint: string, noCred: RequestCredentials, hostedRequestBody: any, cloudRequestBody: any, method?: string, queryParam?: string): Promise<any>;
2
2
  export declare function getDataFromCloud(client: any, cloudQueryEndpoint: string, cloudRequestBody: any, method?: string): Promise<any>;
3
3
  //# sourceMappingURL=dataFetcher.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataFetcher.d.ts","sourceRoot":"","sources":["../../../src/utils/dataFetcher.tsx"],"names":[],"mappings":"AAEA,wBAAsB,OAAO,CAC3B,MAAM,EAAE,GAAG,EACX,kBAAkB,EAAE,MAAM,EAC1B,MAAM,EAAE,kBAAkB,EAC1B,iBAAiB,EAAE,GAAG,EACtB,gBAAgB,EAAE,GAAG,EACrB,MAAM,SAAS,gBAgEhB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,GAAG,EACX,kBAAkB,EAAE,MAAM,EAC1B,gBAAgB,EAAE,GAAG,EACrB,MAAM,SAAS,gBAgChB"}
1
+ {"version":3,"file":"dataFetcher.d.ts","sourceRoot":"","sources":["../../../src/utils/dataFetcher.tsx"],"names":[],"mappings":"AAqBA,wBAAsB,OAAO,CAC3B,MAAM,EAAE,GAAG,EACX,kBAAkB,EAAE,MAAM,EAC1B,MAAM,EAAE,kBAAkB,EAC1B,iBAAiB,EAAE,GAAG,EACtB,gBAAgB,EAAE,GAAG,EACrB,MAAM,SAAS,EACf,UAAU,CAAC,EAAE,MAAM,gBAwGpB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,GAAG,EACX,kBAAkB,EAAE,MAAM,EAC1B,gBAAgB,EAAE,GAAG,EACrB,MAAM,SAAS,gBAgChB"}