buckaroo-js-core 0.8.0

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 (159) hide show
  1. package/.prettierrc +16 -0
  2. package/CHANGELOG.md +23 -0
  3. package/LICENSE +15 -0
  4. package/README.md +66 -0
  5. package/buckaroo_js/baked_data/colorMap.d.ts +3 -0
  6. package/buckaroo_js/baked_data/colorMap.d.ts.map +1 -0
  7. package/buckaroo_js/baked_data/colorMap.js +520 -0
  8. package/buckaroo_js/baked_data/colorMap.js.map +1 -0
  9. package/buckaroo_js/baked_data/staticData.d.ts +124 -0
  10. package/buckaroo_js/baked_data/staticData.d.ts.map +1 -0
  11. package/buckaroo_js/baked_data/staticData.js +459 -0
  12. package/buckaroo_js/baked_data/staticData.js.map +1 -0
  13. package/buckaroo_js/components/ColumnsEditor.d.ts +19 -0
  14. package/buckaroo_js/components/ColumnsEditor.d.ts.map +1 -0
  15. package/buckaroo_js/components/ColumnsEditor.js +68 -0
  16. package/buckaroo_js/components/ColumnsEditor.js.map +1 -0
  17. package/buckaroo_js/components/CommandUtils.d.ts +22 -0
  18. package/buckaroo_js/components/CommandUtils.d.ts.map +1 -0
  19. package/buckaroo_js/components/CommandUtils.js +17 -0
  20. package/buckaroo_js/components/CommandUtils.js.map +1 -0
  21. package/buckaroo_js/components/DCFCell.d.ts +28 -0
  22. package/buckaroo_js/components/DCFCell.d.ts.map +1 -0
  23. package/buckaroo_js/components/DCFCell.js +120 -0
  24. package/buckaroo_js/components/DCFCell.js.map +1 -0
  25. package/buckaroo_js/components/DFViewerParts/DFViewer.d.ts +29 -0
  26. package/buckaroo_js/components/DFViewerParts/DFViewer.d.ts.map +1 -0
  27. package/buckaroo_js/components/DFViewerParts/DFViewer.js +163 -0
  28. package/buckaroo_js/components/DFViewerParts/DFViewer.js.map +1 -0
  29. package/buckaroo_js/components/DFViewerParts/DFWhole.d.ts +111 -0
  30. package/buckaroo_js/components/DFViewerParts/DFWhole.d.ts.map +1 -0
  31. package/buckaroo_js/components/DFViewerParts/DFWhole.js +17 -0
  32. package/buckaroo_js/components/DFViewerParts/DFWhole.js.map +1 -0
  33. package/buckaroo_js/components/DFViewerParts/Displayer.d.ts +19 -0
  34. package/buckaroo_js/components/DFViewerParts/Displayer.d.ts.map +1 -0
  35. package/buckaroo_js/components/DFViewerParts/Displayer.js +221 -0
  36. package/buckaroo_js/components/DFViewerParts/Displayer.js.map +1 -0
  37. package/buckaroo_js/components/DFViewerParts/HistogramCell.d.ts +20 -0
  38. package/buckaroo_js/components/DFViewerParts/HistogramCell.d.ts.map +1 -0
  39. package/buckaroo_js/components/DFViewerParts/HistogramCell.js +184 -0
  40. package/buckaroo_js/components/DFViewerParts/HistogramCell.js.map +1 -0
  41. package/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.d.ts +5 -0
  42. package/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.d.ts.map +1 -0
  43. package/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.js +18 -0
  44. package/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.js.map +1 -0
  45. package/buckaroo_js/components/DFViewerParts/gridUtils.d.ts +24 -0
  46. package/buckaroo_js/components/DFViewerParts/gridUtils.d.ts.map +1 -0
  47. package/buckaroo_js/components/DFViewerParts/gridUtils.js +230 -0
  48. package/buckaroo_js/components/DFViewerParts/gridUtils.js.map +1 -0
  49. package/buckaroo_js/components/DependentTabs.d.ts +33 -0
  50. package/buckaroo_js/components/DependentTabs.d.ts.map +1 -0
  51. package/buckaroo_js/components/DependentTabs.js +108 -0
  52. package/buckaroo_js/components/DependentTabs.js.map +1 -0
  53. package/buckaroo_js/components/OperationDetail.d.ts +16 -0
  54. package/buckaroo_js/components/OperationDetail.d.ts.map +1 -0
  55. package/buckaroo_js/components/OperationDetail.js +144 -0
  56. package/buckaroo_js/components/OperationDetail.js.map +1 -0
  57. package/buckaroo_js/components/OperationUtils.d.ts +17 -0
  58. package/buckaroo_js/components/OperationUtils.d.ts.map +1 -0
  59. package/buckaroo_js/components/OperationUtils.js +14 -0
  60. package/buckaroo_js/components/OperationUtils.js.map +1 -0
  61. package/buckaroo_js/components/Operations.d.ts +24 -0
  62. package/buckaroo_js/components/Operations.d.ts.map +1 -0
  63. package/buckaroo_js/components/Operations.js +209 -0
  64. package/buckaroo_js/components/Operations.js.map +1 -0
  65. package/buckaroo_js/components/StatusBar.d.ts +12 -0
  66. package/buckaroo_js/components/StatusBar.d.ts.map +1 -0
  67. package/buckaroo_js/components/StatusBar.js +155 -0
  68. package/buckaroo_js/components/StatusBar.js.map +1 -0
  69. package/buckaroo_js/components/WidgetTypes.d.ts +25 -0
  70. package/buckaroo_js/components/WidgetTypes.d.ts.map +1 -0
  71. package/buckaroo_js/components/WidgetTypes.js +3 -0
  72. package/buckaroo_js/components/WidgetTypes.js.map +1 -0
  73. package/buckaroo_js/components/bakedOperationDefaults.d.ts +5 -0
  74. package/buckaroo_js/components/bakedOperationDefaults.d.ts.map +1 -0
  75. package/buckaroo_js/components/bakedOperationDefaults.js +15 -0
  76. package/buckaroo_js/components/bakedOperationDefaults.js.map +1 -0
  77. package/buckaroo_js/components/utils.d.ts +294 -0
  78. package/buckaroo_js/components/utils.d.ts.map +1 -0
  79. package/buckaroo_js/components/utils.js +143 -0
  80. package/buckaroo_js/components/utils.js.map +1 -0
  81. package/buckaroo_js/extension.d.ts +2 -0
  82. package/buckaroo_js/extension.d.ts.map +1 -0
  83. package/buckaroo_js/extension.js +20 -0
  84. package/buckaroo_js/extension.js.map +1 -0
  85. package/buckaroo_js/index.d.ts +25 -0
  86. package/buckaroo_js/index.d.ts.map +1 -0
  87. package/buckaroo_js/index.js +46 -0
  88. package/buckaroo_js/index.js.map +1 -0
  89. package/buckaroo_js/vendor/RechartExtra.d.ts +38 -0
  90. package/buckaroo_js/vendor/RechartExtra.d.ts.map +1 -0
  91. package/buckaroo_js/vendor/RechartExtra.js +17 -0
  92. package/buckaroo_js/vendor/RechartExtra.js.map +1 -0
  93. package/buckaroo_js/vendor/RechartTooltip.d.ts +82 -0
  94. package/buckaroo_js/vendor/RechartTooltip.d.ts.map +1 -0
  95. package/buckaroo_js/vendor/RechartTooltip.js +232 -0
  96. package/buckaroo_js/vendor/RechartTooltip.js.map +1 -0
  97. package/codecov.yml +16 -0
  98. package/eslint.config.mjs +88 -0
  99. package/examples/App.tsx +160 -0
  100. package/examples/CodeBlock.tsx +27 -0
  101. package/examples/CodePenButton.tsx +77 -0
  102. package/examples/ReadmeBlock.tsx +11 -0
  103. package/examples/app.css +29 -0
  104. package/examples/ex/ColumnsEditorEx.tsx +5 -0
  105. package/examples/ex/CommandViewerEx.tsx +20 -0
  106. package/examples/ex/DFViewerEx.tsx +3 -0
  107. package/examples/ex/DFViewerEx_large.tsx +266 -0
  108. package/examples/ex/DFViewerEx_real_summary.tsx +20 -0
  109. package/examples/ex/DFViewerEx_short_data.tsx +22 -0
  110. package/examples/ex/DFViewerEx_string_index.tsx +1012 -0
  111. package/examples/ex/HistogramEx.tsx +67 -0
  112. package/examples/ex/StatusBarEx.tsx +46 -0
  113. package/examples/ex/WidgetDCFCellEx.tsx +6 -0
  114. package/examples/example.css +20 -0
  115. package/examples/index-iframe.hnottml +24 -0
  116. package/examples/index-react18.tsx +8 -0
  117. package/examples/index.html +20 -0
  118. package/examples/jsx-loader.ts +16 -0
  119. package/examples/tsconfig.json +31 -0
  120. package/index.d.ts +2 -0
  121. package/index.d.ts.map +1 -0
  122. package/index.js +7 -0
  123. package/index.js.map +1 -0
  124. package/jest.config.js +24 -0
  125. package/package.json +117 -0
  126. package/screen-animation.gif +0 -0
  127. package/src/buckaroo_js/baked_data/colorMap.ts +523 -0
  128. package/src/buckaroo_js/baked_data/staticData.ts +503 -0
  129. package/src/buckaroo_js/components/ColumnsEditor.tsx +66 -0
  130. package/src/buckaroo_js/components/CommandUtils.ts +40 -0
  131. package/src/buckaroo_js/components/DCFCell.tsx +175 -0
  132. package/src/buckaroo_js/components/DFViewerParts/DFViewer.tsx +215 -0
  133. package/src/buckaroo_js/components/DFViewerParts/DFWhole.ts +190 -0
  134. package/src/buckaroo_js/components/DFViewerParts/Displayer.ts +215 -0
  135. package/src/buckaroo_js/components/DFViewerParts/HistogramCell.tsx +251 -0
  136. package/src/buckaroo_js/components/DFViewerParts/SeriesSummaryTooltip.tsx +20 -0
  137. package/src/buckaroo_js/components/DFViewerParts/gridUtils.ts +290 -0
  138. package/src/buckaroo_js/components/DependentTabs.tsx +134 -0
  139. package/src/buckaroo_js/components/OperationDetail.tsx +203 -0
  140. package/src/buckaroo_js/components/OperationUtils.ts +33 -0
  141. package/src/buckaroo_js/components/Operations.tsx +243 -0
  142. package/src/buckaroo_js/components/StatusBar.tsx +190 -0
  143. package/src/buckaroo_js/components/WidgetTypes.tsx +42 -0
  144. package/src/buckaroo_js/components/bakedOperationDefaults.ts +14 -0
  145. package/src/buckaroo_js/components/utils.ts +60 -0
  146. package/src/buckaroo_js/extension.ts +15 -0
  147. package/src/buckaroo_js/index.ts +34 -0
  148. package/src/buckaroo_js/style/dcf-npm.css +244 -0
  149. package/src/buckaroo_js/style/icons/arrow-down-short-dark.svg +4 -0
  150. package/src/buckaroo_js/style/icons/arrow-down-short.svg +4 -0
  151. package/src/buckaroo_js/style/icons/arrow-up-short-dark.svg +4 -0
  152. package/src/buckaroo_js/style/icons/arrow-up-short.svg +4 -0
  153. package/src/buckaroo_js/style/icons/filter-dark.svg +3 -0
  154. package/src/buckaroo_js/style/icons/filter.svg +3 -0
  155. package/src/buckaroo_js/vendor/RechartExtra.ts +60 -0
  156. package/src/buckaroo_js/vendor/RechartTooltip.tsx +357 -0
  157. package/src/index.tsx +3 -0
  158. package/tsconfig.json +41 -0
  159. package/webpack.config.ts +97 -0
@@ -0,0 +1,290 @@
1
+ import {
2
+ CellClassParams,
3
+ CellRendererSelectorResult,
4
+ ColDef,
5
+ ICellRendererParams
6
+ } from 'ag-grid-community';
7
+ import {BLUE_TO_YELLOW, DIVERGING_RED_WHITE_BLUE} from '../../baked_data/colorMap';
8
+
9
+ import {
10
+ DFWhole,
11
+ DisplayerArgs,
12
+ cellRendererDisplayers,
13
+ ColumnConfig,
14
+ ColorMappingConfig,
15
+ ColorMapRules,
16
+ TooltipConfig,
17
+ ColorWhenNotNullRules,
18
+ DFViewerConfig
19
+ } from './DFWhole';
20
+ import _, {zipObject} from 'lodash';
21
+ import {getTextCellRenderer} from './HistogramCell';
22
+
23
+ import {DFData, SDFMeasure, SDFT} from './DFWhole';
24
+
25
+ import {CellRendererArgs, FormatterArgs, PinnedRowConfig} from './DFWhole';
26
+ import {getBakedDFViewer} from './SeriesSummaryTooltip';
27
+ import {getFormatterFromArgs, getCellRenderer, objFormatter, getFormatter} from './Displayer';
28
+
29
+ // for now colDef stuff with less than 3 implementantions should stay in this file
30
+ // as implementations grow large or with many implmentations, they should move to separate files
31
+ // like displayer
32
+
33
+ export function addToColDef(dispArgs: DisplayerArgs, summary_stats_column: SDFMeasure) {
34
+ const formatter = getFormatterFromArgs(dispArgs);
35
+ if (formatter !== undefined) {
36
+ const colDefExtras: ColDef = {valueFormatter: formatter};
37
+ return colDefExtras;
38
+ }
39
+
40
+ if (_.includes(cellRendererDisplayers, dispArgs.displayer)) {
41
+ const crArgs: CellRendererArgs = dispArgs as CellRendererArgs;
42
+ return {
43
+ cellRenderer: getCellRenderer(crArgs)
44
+ };
45
+ }
46
+ return undefined;
47
+ }
48
+
49
+ export function getHistoIndex(val: number, histogram_edges: number[]): number {
50
+ /*
51
+ np.histogram([1, 2, 3, 4, 10, 20, 30, 40, 300, 300, 400, 500], bins=5)
52
+ ( [ 8, 0, 2, 1, 1],
53
+ [ 1. , 100.8, 200.6, 300.4, 400.2, 500. ])
54
+ The bottom matters for us, those are the endge
55
+
56
+ this means that 8 values are between 1 and 100.8 and 2 values are between 200.6 and 300.4
57
+ */
58
+ if (histogram_edges.length === 0) {
59
+ return 0;
60
+ }
61
+ for (let i = 0; i < histogram_edges.length; i++) {
62
+ if (val <= histogram_edges[i]) {
63
+ return i;
64
+ }
65
+ }
66
+ return histogram_edges.length;
67
+ }
68
+
69
+ export function colorMap(cmr: ColorMapRules, histogram_edges: number[]) {
70
+ // https://colorcet.com/gallery.html#isoluminant
71
+ // https://github.com/holoviz/colorcet/tree/main/assets/CET
72
+ // https://github.com/bokeh/bokeh/blob/ed285b11ab196e72336b47bf12f44e1bef5abed3/src/bokeh/models/mappers.py#L304
73
+ const maps: Record<string, string[]> = {
74
+ BLUE_TO_YELLOW: BLUE_TO_YELLOW,
75
+ DIVERGING_RED_WHITE_BLUE: DIVERGING_RED_WHITE_BLUE
76
+ };
77
+ const cmap = maps[cmr.map_name];
78
+
79
+ function numberToColor(val: number) {
80
+ const histoIndex = getHistoIndex(val, histogram_edges);
81
+ const scaledIndex = Math.round((histoIndex / histogram_edges.length) * cmap.length);
82
+ return cmap[scaledIndex];
83
+ }
84
+
85
+ function cellStyle(params: CellClassParams) {
86
+ const val = cmr.val_column ? params.data[cmr.val_column] : params.value;
87
+ const color = numberToColor(val);
88
+ return {
89
+ backgroundColor: color
90
+ };
91
+ }
92
+
93
+ const retProps = {
94
+ cellStyle: cellStyle
95
+ };
96
+ return retProps;
97
+ }
98
+
99
+ export function colorNotNull(cmr: ColorWhenNotNullRules) {
100
+ function cellStyle(params: CellClassParams) {
101
+ if (params.data === undefined) {
102
+ return {backgroundColor: 'inherit'};
103
+ }
104
+ const val = params.data[cmr.exist_column];
105
+ const valPresent = val && val !== null;
106
+ const isPinned = params.node.rowPinned;
107
+ const color = valPresent && !isPinned ? cmr.conditional_color : 'inherit';
108
+ return {
109
+ backgroundColor: color
110
+ };
111
+ }
112
+
113
+ const retProps = {
114
+ cellStyle: cellStyle
115
+ };
116
+ return retProps;
117
+ }
118
+
119
+ export function getStyler(cmr: ColorMappingConfig, col_name: string, histogram_stats: SDFT) {
120
+ switch (cmr.color_rule) {
121
+ case 'color_map': {
122
+ //block necessary because you cant define varaibles in case blocks
123
+ const statsCol = cmr.val_column || col_name;
124
+ const summary_stats_cell = histogram_stats[statsCol];
125
+
126
+ if (summary_stats_cell && summary_stats_cell.histogram_bins !== undefined) {
127
+ return colorMap(cmr, summary_stats_cell.histogram_bins);
128
+ } else {
129
+ console.log('histogram bins not found for color_map');
130
+ return {};
131
+ }
132
+ }
133
+ case 'color_not_null':
134
+ return colorNotNull(cmr);
135
+ }
136
+ }
137
+
138
+ export function extractPinnedRows(sdf: DFData, prc: PinnedRowConfig[]) {
139
+ return _.map(_.map(prc, 'primary_key_val'), (x) => _.find(sdf, {index: x}));
140
+ }
141
+
142
+ export function getTooltip(ttc: TooltipConfig, single_series_summary_df: DFWhole): Partial<ColDef> {
143
+ switch (ttc.tooltip_type) {
144
+ case 'simple':
145
+ return {tooltipField: ttc.val_column};
146
+
147
+ case 'summary_series':
148
+ return {
149
+ tooltipComponent: getBakedDFViewer(single_series_summary_df),
150
+ tooltipField: 'index',
151
+ tooltipComponentParams: {}
152
+ };
153
+ }
154
+ }
155
+
156
+ export function extractSingleSeriesSummary(
157
+ full_summary_stats_df: DFData,
158
+ col_name: string
159
+ ): DFWhole {
160
+ return {
161
+ dfviewer_config: {
162
+ column_config: [
163
+ {col_name: 'index', displayer_args: {displayer: 'obj'}},
164
+ {col_name: col_name, displayer_args: {displayer: 'obj'}}
165
+ ],
166
+ pinned_rows: []
167
+ },
168
+ data: _.filter(
169
+ _.map(full_summary_stats_df, (row) => _.pick(row, ['index', col_name])),
170
+ {index: 'dtype'}
171
+ )
172
+ };
173
+ }
174
+
175
+ export function dfToAgrid(
176
+ tdf: DFData,
177
+ dfviewer_config: DFViewerConfig,
178
+ full_summary_stats_df: DFData
179
+ ): [ColDef[], unknown[]] {
180
+ //more convienient df format for some formatters
181
+ const hdf = extractSDFT(full_summary_stats_df || []);
182
+
183
+ const retColumns: ColDef[] = dfviewer_config.column_config.map((f: ColumnConfig) => {
184
+ const single_series_summary_df = extractSingleSeriesSummary(
185
+ full_summary_stats_df,
186
+ f.col_name
187
+ );
188
+
189
+ const color_map_config = f.color_map_config
190
+ ? getStyler(f.color_map_config, f.col_name, hdf)
191
+ : {};
192
+
193
+ const tooltip_config = f.tooltip_config
194
+ ? getTooltip(f.tooltip_config, single_series_summary_df)
195
+ : {};
196
+ const colDef: ColDef = {
197
+ field: f.col_name,
198
+ headerName: f.col_name,
199
+ cellDataType: false,
200
+ cellStyle: {}, // necessary for colormapped columns to have a default
201
+ ...addToColDef(f.displayer_args, hdf[f.col_name]),
202
+ ...color_map_config,
203
+ ...tooltip_config,
204
+ ...f.ag_grid_specs
205
+ };
206
+ return colDef;
207
+ });
208
+ return [retColumns, tdf];
209
+ }
210
+
211
+ // this is very similar to the colDef parts of dfToAgrid
212
+ export function getCellRendererSelector(pinned_rows: PinnedRowConfig[]) {
213
+ const anyRenderer: CellRendererSelectorResult = {
214
+ component: getTextCellRenderer(objFormatter)
215
+ };
216
+ return (params: ICellRendererParams<any, any, any>): CellRendererSelectorResult | undefined => {
217
+ if (params.node.rowPinned) {
218
+ const pk = _.get(params.node.data, 'index');
219
+ if (pk === undefined) {
220
+ return anyRenderer; // default renderer
221
+ }
222
+ const maybePrc: PinnedRowConfig | undefined = _.find(pinned_rows, {
223
+ primary_key_val: pk
224
+ });
225
+ if (maybePrc === undefined) {
226
+ return anyRenderer;
227
+ }
228
+ const prc: PinnedRowConfig = maybePrc;
229
+ console.log('params', params);
230
+ const currentCol = params.column?.getColId();
231
+ if (
232
+ (prc.default_renderer_columns === undefined && currentCol === 'index') ||
233
+ _.includes(prc.default_renderer_columns, currentCol)
234
+ ) {
235
+ return anyRenderer;
236
+ }
237
+ const possibCellRenderer = getCellRenderer(prc.displayer_args as CellRendererArgs);
238
+
239
+ if (possibCellRenderer === undefined) {
240
+ const formattedRenderer: CellRendererSelectorResult = {
241
+ component: getTextCellRenderer(
242
+ getFormatter(prc.displayer_args as FormatterArgs)
243
+ )
244
+ };
245
+ return formattedRenderer;
246
+ }
247
+ return {component: possibCellRenderer};
248
+ } else {
249
+ return undefined; // rows that are not pinned don't use a row level cell renderer
250
+ }
251
+ };
252
+ }
253
+
254
+ export function extractSDFT(summaryStatsDf: DFData): SDFT {
255
+ const maybeHistogramBins = _.find(summaryStatsDf, {index: 'histogram_bins'}) || {};
256
+ const maybeHistogramLogBins = _.find(summaryStatsDf, {index: 'histogram_log_bins'}) || {};
257
+ const allColumns: string[] = _.without(
258
+ _.union(_.keys(maybeHistogramBins), _.keys(maybeHistogramLogBins)),
259
+ 'index'
260
+ );
261
+ const vals: SDFMeasure[] = _.map(allColumns, (colName) => {
262
+ return {
263
+ histogram_bins: _.get(maybeHistogramBins, colName, []) as number[],
264
+ histogram_log_bins: _.get(maybeHistogramLogBins, colName, []) as number[]
265
+ };
266
+ });
267
+ return zipObject(allColumns, vals) as SDFT;
268
+ }
269
+
270
+ /*
271
+ I would love for extractSDF to be more elegant like the following function. I just can't quite get it to work
272
+ time to move on
273
+
274
+ export function extractSDFT2(summaryStatsDf:DFData) : SDFT {
275
+ const rows = ['histogram_bins', 'histogram_log_bins']
276
+
277
+ const extracted = _.map(rows, (pk) => {
278
+ return _.find(summaryStatsDf, {'index': pk}) || {}
279
+ })
280
+ const dupKeys: string[][] = _.map(extracted, _.keys);
281
+ const allColumns: string[] = _.without(_.union(...dupKeys), 'index');
282
+ const vals:SDFMeasure[] = _.map(allColumns, (colName) => {
283
+ const pairs = _.map(_.zip(rows, extracted), (rname, row) => {
284
+ return [rname, (_.get(row, colName, []) as number[])];
285
+ })
286
+ return _.fromPairs(pairs) as SDFMeasure;
287
+ });
288
+ return zipObject(allColumns, vals) as SDFT;
289
+ }
290
+ */
@@ -0,0 +1,134 @@
1
+ import React, {useState, CSSProperties, Dispatch, SetStateAction} from 'react';
2
+ import {DFWhole, EmptyDf} from './DFViewerParts/DFWhole';
3
+ import _ from 'lodash';
4
+ import {Operation} from './OperationUtils';
5
+
6
+ export function OperationDisplayer({
7
+ filledOperations,
8
+ style
9
+ }: {
10
+ filledOperations: Operation[];
11
+ style: CSSProperties;
12
+ }): React.JSX.Element {
13
+ const baseStyle: CSSProperties = {margin: '0', textAlign: 'left'};
14
+ const localStyle: CSSProperties = {...baseStyle, ...style};
15
+ return (
16
+ <div className='command-displayer' style={{width: '100%'}}>
17
+ <pre style={localStyle}>{JSON.stringify(filledOperations)}</pre>
18
+ </div>
19
+ );
20
+ }
21
+
22
+ export function PythonDisplayer({
23
+ style,
24
+ generatedPyCode
25
+ }: {
26
+ style: CSSProperties;
27
+ generatedPyCode: string;
28
+ }) {
29
+ const baseStyle: CSSProperties = {margin: '0', textAlign: 'left'};
30
+ const localStyle: CSSProperties = {...baseStyle, ...style};
31
+ return (
32
+ <div className='python-displayer' style={{width: '100%'}}>
33
+ <pre style={localStyle}>{generatedPyCode}</pre>
34
+ </div>
35
+ );
36
+ }
37
+
38
+ export function TransformViewer({
39
+ style,
40
+ transformedDf
41
+ }: {
42
+ style: CSSProperties;
43
+ transformedDf: DFWhole;
44
+ }) {
45
+ return <div className='transform-viewer'>"transformed view"</div>;
46
+ }
47
+ export type OperationResult = {
48
+ transformed_df: DFWhole;
49
+ generated_py_code: string;
50
+ transform_error?: string;
51
+ };
52
+
53
+ export type OrRequesterT = (ops: Operation[]) => void;
54
+ export type getOperationResultSetterT = (
55
+ setter: Dispatch<SetStateAction<OperationResult>>
56
+ ) => OrRequesterT;
57
+
58
+ export const baseOperationResults: OperationResult = {
59
+ transformed_df: EmptyDf,
60
+ generated_py_code: 'default py code'
61
+ };
62
+
63
+ export function TabComponent({
64
+ currentTab,
65
+ _setTab,
66
+ tabName
67
+ }: {
68
+ currentTab: any;
69
+ _setTab: any;
70
+ tabName: any;
71
+ }): JSX.Element {
72
+ return (
73
+ <li
74
+ onClick={() => {
75
+ _setTab(tabName);
76
+ }}
77
+ className={currentTab === tabName ? 'active' : ''}
78
+ >
79
+ {tabName}
80
+ </li>
81
+ );
82
+ }
83
+
84
+ export function DependentTabs({
85
+ filledOperations,
86
+ operationResult
87
+ }: {
88
+ filledOperations: Operation[];
89
+ operationResult: OperationResult;
90
+ }) {
91
+ const [tab, _setTab] = useState('DataFrame');
92
+ const style: CSSProperties = {height: '45vh'};
93
+ return (
94
+ <div className='dependent-tabs' style={{width: '100%'}}>
95
+ <ul className='tabs'>
96
+ <TabComponent currentTab={tab} _setTab={_setTab} tabName={'DataFrame'} />
97
+ <TabComponent currentTab={tab} _setTab={_setTab} tabName={'Python'} />
98
+ <TabComponent currentTab={tab} _setTab={_setTab} tabName={'Operations'} />
99
+ </ul>
100
+ <div className='output-area'>
101
+ {operationResult.transform_error ? (
102
+ <div>
103
+ <h2> error </h2>
104
+ <PythonDisplayer
105
+ style={style}
106
+ generatedPyCode={operationResult.transform_error}
107
+ />
108
+ </div>
109
+ ) : (
110
+ <span></span>
111
+ )}
112
+ {
113
+ {
114
+ Operations: (
115
+ <OperationDisplayer style={style} filledOperations={filledOperations} />
116
+ ),
117
+ Python: (
118
+ <PythonDisplayer
119
+ style={style}
120
+ generatedPyCode={operationResult.generated_py_code}
121
+ />
122
+ ),
123
+ DataFrame: (
124
+ <TransformViewer
125
+ style={style}
126
+ transformedDf={operationResult.transformed_df}
127
+ />
128
+ )
129
+ }[tab]
130
+ }
131
+ </div>
132
+ </div>
133
+ );
134
+ }
@@ -0,0 +1,203 @@
1
+ import _ from 'lodash';
2
+ import {Operation, SettableArg, OperationEventFunc} from './OperationUtils';
3
+ import {ActualArg, CommandArgSpec} from './CommandUtils';
4
+ import {objWithoutNull, replaceAtIdx, replaceAtKey} from './utils';
5
+ import React from 'react';
6
+
7
+ export const OperationDetail = ({
8
+ command,
9
+ setCommand,
10
+ columns,
11
+ commandPatterns
12
+ }: {
13
+ command: Operation;
14
+ setCommand: OperationEventFunc;
15
+ columns: string[];
16
+ commandPatterns: CommandArgSpec;
17
+ }) => {
18
+ if (command === undefined) {
19
+ return <span></span>;
20
+ }
21
+ const commandName = command[0]['symbol'];
22
+ const pattern = commandPatterns[commandName];
23
+
24
+ if (!_.isArray(pattern)) {
25
+ //we shouldn't get here
26
+ return <h2>unknown command {commandName}</h2>;
27
+ } else if (_.isEqual(pattern, [null])) {
28
+ return <div className='operation-detail'></div>;
29
+ } else {
30
+ const fullPattern = pattern as ActualArg[];
31
+ return (
32
+ <div className='operation-detail'>
33
+ <ArgGetters
34
+ command={command}
35
+ fullPattern={fullPattern}
36
+ setCommand={setCommand}
37
+ columns={columns}
38
+ />
39
+ </div>
40
+ );
41
+ }
42
+ return <h2></h2>;
43
+ };
44
+
45
+ export const ArgGetters = ({
46
+ command,
47
+ fullPattern,
48
+ setCommand,
49
+ columns
50
+ }: {
51
+ command: Operation;
52
+ fullPattern: ActualArg[];
53
+ setCommand: OperationEventFunc;
54
+ columns: string[];
55
+ }) => {
56
+ /* reads the argspec and sets up the proper getters/setters */
57
+ const makeArgGetter = (pattern: ActualArg) => {
58
+ const idx = pattern[0];
59
+ const val = command[idx] as SettableArg;
60
+ const valSetter = (newVal: unknown) => {
61
+ const newCommand = replaceAtIdx(command, idx, newVal);
62
+ //console.log('newCommand', newCommand);
63
+ setCommand(newCommand as Operation);
64
+ };
65
+ return (
66
+ <div key={idx}>
67
+ <ArgGetter
68
+ argProps={pattern}
69
+ renderKey={idx}
70
+ val={val}
71
+ setter={valSetter}
72
+ columns={columns}
73
+ />
74
+ </div>
75
+ );
76
+ };
77
+ return <div className='arg-getters'>{fullPattern.map(makeArgGetter)}</div>;
78
+ };
79
+
80
+ const ArgGetter = ({
81
+ argProps,
82
+ val,
83
+ setter,
84
+ columns,
85
+ renderKey
86
+ }: {
87
+ argProps: ActualArg;
88
+ val: SettableArg;
89
+ setter: (arg: SettableArg) => void;
90
+ columns: string[];
91
+ renderKey: number;
92
+ }) => {
93
+ const [_argPos, label, argType, lastArg] = argProps;
94
+
95
+ const defaultShim = (event: {target: {value: SettableArg}}) => setter(event.target.value);
96
+ if (argType === 'enum' && _.isArray(lastArg)) {
97
+ return (
98
+ <fieldset key={renderKey}>
99
+ <label> {label} </label>
100
+ <select defaultValue={val as string} onChange={defaultShim}>
101
+ {lastArg.map((optionVal) => (
102
+ <option key={optionVal} value={optionVal}>
103
+ {optionVal}
104
+ </option>
105
+ ))}
106
+ </select>
107
+ </fieldset>
108
+ );
109
+ } else if (argType === 'type') {
110
+ if (lastArg === 'integer') {
111
+ const valSetterShim = (event: {target: {value: string}}) =>
112
+ setter(parseInt(event.target.value));
113
+ return (
114
+ <fieldset key={renderKey}>
115
+ <label> {label} </label>
116
+ <input
117
+ type='number'
118
+ defaultValue={val as number}
119
+ step='1'
120
+ onChange={valSetterShim}
121
+ />
122
+ </fieldset>
123
+ );
124
+ } else if (lastArg === 'float') {
125
+ const valSetterShim = (event: {target: {value: string}}) =>
126
+ setter(parseFloat(event.target.value));
127
+ return (
128
+ <fieldset key={renderKey}>
129
+ <label> {label} </label>
130
+ <input
131
+ type='number'
132
+ step='0.01'
133
+ defaultValue={val as number}
134
+ onChange={valSetterShim}
135
+ />
136
+ </fieldset>
137
+ );
138
+ } else if (lastArg === 'string') {
139
+ const valSetterShim = (event: {target: {value: string}}) => setter(event.target.value);
140
+ return (
141
+ <fieldset key={renderKey}>
142
+ <label> {label} </label>
143
+ <input type='text' defaultValue={val as string} onChange={valSetterShim} />
144
+ </fieldset>
145
+ );
146
+ } else {
147
+ return (
148
+ <fieldset key={renderKey}>
149
+ <label> {label} </label>
150
+ <input value='dont know' />
151
+ </fieldset>
152
+ );
153
+ }
154
+ } else if (argType === 'colEnum') {
155
+ const widgetRow = columns.map((colName: string) => {
156
+ const colSetter = (event: {target: {value: any}}) => {
157
+ const newColVal = event.target.value;
158
+ if (_.isString(newColVal)) {
159
+ const updatedColDict = replaceAtKey(
160
+ val as Record<string, string>,
161
+ colName,
162
+ newColVal as string
163
+ ); // as Record<string, string>
164
+ setter(objWithoutNull(updatedColDict, ['null']));
165
+ }
166
+ };
167
+ const colVal = _.get(val, colName, 'null');
168
+ if (!_.isArray(lastArg)) {
169
+ return <h3> arg error</h3>;
170
+ }
171
+ return (
172
+ <td key={renderKey + colName}>
173
+ <select defaultValue={colVal} onChange={colSetter}>
174
+ {lastArg.map((optionVal) => (
175
+ <option key={optionVal} value={optionVal}>
176
+ {optionVal}
177
+ </option>
178
+ ))}
179
+ </select>
180
+ </td>
181
+ );
182
+ });
183
+
184
+ return (
185
+ <div className='col-enum' key={renderKey}>
186
+ <table>
187
+ <thead>
188
+ <tr>
189
+ {columns.map((colName) => (
190
+ <th key={colName}>{colName}</th>
191
+ ))}
192
+ </tr>
193
+ </thead>
194
+ <tbody>
195
+ <tr>{widgetRow}</tr>
196
+ </tbody>
197
+ </table>
198
+ </div>
199
+ );
200
+ } else {
201
+ return <h3> unknown argtype </h3>;
202
+ }
203
+ };
@@ -0,0 +1,33 @@
1
+ /*
2
+ used for manipulating the JSON Flavored lisp of operations and commands
3
+ */
4
+ import _ from 'lodash';
5
+ import {SymbolT, ColEnumArgs, SymbolDf, symDf} from './CommandUtils';
6
+
7
+ export const sym = (symbolName: string) => {
8
+ return {symbol: symbolName};
9
+ };
10
+
11
+ export type Atom = number | string | SymbolT | ColEnumArgs;
12
+ export type SettableArg = number | string | ColEnumArgs;
13
+
14
+ export type OperationSingleColumn = [SymbolT, SymbolDf, string];
15
+ export type OperationSingleArg = [SymbolT, SymbolDf, string, Atom];
16
+ export type OperationTwoArg = [SymbolT, SymbolDf, string, Atom, Atom];
17
+ export type Operation = OperationSingleColumn | OperationSingleArg | OperationTwoArg;
18
+
19
+ export type SetOperationFunc = (newCommand: Operation) => void;
20
+ export type SetOperationsFunc = (newCommands: Operation[]) => void;
21
+
22
+ export type OperationDefaultArgs = Record<string, Operation>;
23
+
24
+ //const ArgNames = ['Idx', 'label', 'specName', 'extraSpecArgs'];
25
+ export const bakedOperations: Operation[] = [
26
+ [sym('dropcol'), symDf, 'col1'],
27
+ [sym('fillna'), symDf, 'col2', 5],
28
+ [sym('resample'), symDf, 'month', 'monthly', {}]
29
+ ];
30
+
31
+ //this will become OperationEventFunc
32
+ export type OperationEventFunc = (newCommand: Operation) => void;
33
+ export type NoArgEventFunc = () => void;