@malloydata/render 0.0.58 → 0.0.59-dev230718005248
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/html/table.d.ts +6 -3
- package/dist/html/table.js +92 -69
- package/dist/html/utils.d.ts +2 -0
- package/dist/html/utils.js +14 -1
- package/package.json +2 -2
package/dist/html/table.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { DataColumn, Field
|
|
1
|
+
import { DataColumn, Field } from '@malloydata/malloy';
|
|
2
2
|
import { StyleDefaults } from '../data_styles';
|
|
3
3
|
import { ContainerRenderer } from './container';
|
|
4
4
|
import { Renderer } from '../renderer';
|
|
5
5
|
export declare class HTMLTableRenderer extends ContainerRenderer {
|
|
6
6
|
protected childrenStyleDefaults: StyleDefaults;
|
|
7
7
|
render(table: DataColumn): Promise<HTMLElement>;
|
|
8
|
+
calculatePivotDimensions(table: DataColumn): {
|
|
9
|
+
dimensions: Field[];
|
|
10
|
+
nonDimensions: Field[];
|
|
11
|
+
};
|
|
8
12
|
generatePivotedCells(table: DataColumn, shouldTranspose: boolean): Promise<Map<string, Map<string, HTMLTableCellElement>>>;
|
|
9
|
-
generateNoValueCell(
|
|
10
|
-
tagIsPresent(tags: Tags | undefined, tag: string): boolean;
|
|
13
|
+
generateNoValueCell(field: Field, shouldTranspose: boolean): HTMLTableCellElement;
|
|
11
14
|
createCellAndRender(childRenderer: Renderer, value: DataColumn, shouldTranspose: boolean): Promise<HTMLTableCellElement>;
|
|
12
15
|
createHeaderCell(field: Field, shouldTranspose: boolean): HTMLTableCellElement;
|
|
13
16
|
createCell(childRenderer: Renderer, shouldTranspose: boolean): HTMLTableCellElement;
|
package/dist/html/table.js
CHANGED
|
@@ -59,7 +59,7 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
59
59
|
if (!table.isArray() && !table.isRecord()) {
|
|
60
60
|
throw new Error('Invalid type for Table Renderer');
|
|
61
61
|
}
|
|
62
|
-
const shouldTranspose =
|
|
62
|
+
const shouldTranspose = (0, utils_1.tagIsPresent)(this.tags, 'transpose');
|
|
63
63
|
if (shouldTranspose && table.field.intrinsicFields.length > 20) {
|
|
64
64
|
throw new Error('Transpose limit of 20 columns exceeded.');
|
|
65
65
|
}
|
|
@@ -75,23 +75,23 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
75
75
|
}
|
|
76
76
|
const childRenderer = this.childRenderers[field.name];
|
|
77
77
|
const shouldPivot = childRenderer instanceof HTMLTableRenderer &&
|
|
78
|
-
|
|
78
|
+
(0, utils_1.tagIsPresent)(childRenderer.tags, 'pivot');
|
|
79
79
|
if (shouldPivot) {
|
|
80
80
|
const pivotedFields = new Map();
|
|
81
81
|
let dimensions = undefined;
|
|
82
82
|
let nonDimensions = [];
|
|
83
83
|
for (const row of table) {
|
|
84
84
|
const dc = row.cell(field);
|
|
85
|
+
if (dc.isNull()) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
85
88
|
if (!dc.isArray() && !dc.isRecord()) {
|
|
86
|
-
throw new Error(`
|
|
89
|
+
throw new Error(`Can not pivot field ${field.name}.`);
|
|
87
90
|
}
|
|
88
91
|
if (!dimensions) {
|
|
89
|
-
const
|
|
90
|
-
dimensions =
|
|
91
|
-
nonDimensions =
|
|
92
|
-
if (nonDimensions.length === 0) {
|
|
93
|
-
throw new Error(`Can not pivot ${field.name} since all of its fields are dimensions.`);
|
|
94
|
-
}
|
|
92
|
+
const dimensionsResult = childRenderer.calculatePivotDimensions(dc);
|
|
93
|
+
dimensions = dimensionsResult.dimensions;
|
|
94
|
+
nonDimensions = dimensionsResult.nonDimensions;
|
|
95
95
|
}
|
|
96
96
|
for (const innerRow of dc) {
|
|
97
97
|
const pivotedField = new PivotedField(field, dimensions.map(d => innerRow.cell(d)));
|
|
@@ -101,6 +101,9 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
+
if (!dimensions) {
|
|
105
|
+
throw new Error(`Could not pivot ${field.name}, no data found.`);
|
|
106
|
+
}
|
|
104
107
|
for (const pf of pivotedFields) {
|
|
105
108
|
for (const nonDimension of nonDimensions) {
|
|
106
109
|
columnFields.push(new PivotedColumnField(pf[1], nonDimension));
|
|
@@ -166,69 +169,64 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
166
169
|
rowIndex++;
|
|
167
170
|
}
|
|
168
171
|
cells = [...pivotHeaderCells, ...cells];
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
.get(field.field.name);
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
cells[rowIndex][columnIndex] = childRenderer.generateNoValueCell(childTableRecord, field.field, shouldTranspose);
|
|
193
|
-
}
|
|
194
|
-
columnIndex++;
|
|
195
|
-
// back
|
|
172
|
+
for (const row of table) {
|
|
173
|
+
cells[rowIndex] = [];
|
|
174
|
+
columnIndex = 0;
|
|
175
|
+
let currentPivotedFieldKey = '';
|
|
176
|
+
let pivotedCells = new Map();
|
|
177
|
+
for (const field of columnFields) {
|
|
178
|
+
if (field instanceof PivotedColumnField) {
|
|
179
|
+
const childRenderer = this.childRenderers[field.pivotedField.parentField.name];
|
|
180
|
+
const childTableRecord = row.cell(field.pivotedField.parentField);
|
|
181
|
+
await (0, utils_1.yieldTask)();
|
|
182
|
+
if (field.pivotedField.key !== currentPivotedFieldKey) {
|
|
183
|
+
pivotedCells = await childRenderer.generatePivotedCells(childTableRecord, shouldTranspose);
|
|
184
|
+
currentPivotedFieldKey = field.pivotedField.key;
|
|
185
|
+
}
|
|
186
|
+
const pfKey = field.pivotedField.key;
|
|
187
|
+
if (pivotedCells.has(pfKey) &&
|
|
188
|
+
((_a = pivotedCells.get(pfKey)) === null || _a === void 0 ? void 0 : _a.has(field.field.name))) {
|
|
189
|
+
cells[rowIndex][columnIndex] = pivotedCells
|
|
190
|
+
.get(pfKey)
|
|
191
|
+
.get(field.field.name);
|
|
196
192
|
}
|
|
197
193
|
else {
|
|
198
|
-
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
const childRenderer = this.childRenderers[field.name];
|
|
202
|
-
cells[rowIndex][columnIndex] = await this.createCellAndRender(childRenderer, row.cell(field), shouldTranspose);
|
|
203
|
-
columnIndex++;
|
|
194
|
+
cells[rowIndex][columnIndex] = childRenderer.generateNoValueCell(field.field, shouldTranspose);
|
|
204
195
|
}
|
|
196
|
+
columnIndex++;
|
|
197
|
+
// back
|
|
205
198
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
199
|
+
else {
|
|
200
|
+
if ((0, tags_utils_1.isFieldHidden)(field)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const childRenderer = this.childRenderers[field.name];
|
|
204
|
+
cells[rowIndex][columnIndex] = await this.createCellAndRender(childRenderer, row.cell(field), shouldTranspose);
|
|
205
|
+
columnIndex++;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// TODO(figutierrez): Deal with drill when transpose is on.
|
|
209
|
+
if (!shouldTranspose && this.options.isDrillingEnabled) {
|
|
210
|
+
const drillCell = this.document.createElement('td');
|
|
211
|
+
const drillIcon = (0, utils_1.createDrillIcon)(this.document);
|
|
212
|
+
drillCell.appendChild(drillIcon);
|
|
213
|
+
drillCell.style.cssText = `
|
|
212
214
|
padding: 8px;
|
|
213
215
|
vertical-align: top;
|
|
214
216
|
border-bottom: 1px solid var(--malloy-border-color, #eaeaea);
|
|
215
217
|
width: 25px;
|
|
216
218
|
cursor: pointer
|
|
217
219
|
`;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
rowIndex++;
|
|
220
|
+
drillCell.onclick = () => {
|
|
221
|
+
if (this.options.onDrill) {
|
|
222
|
+
const { drillQuery, drillFilters } = (0, drill_1.getDrillQuery)(row);
|
|
223
|
+
this.options.onDrill(drillQuery, drillIcon, drillFilters);
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
cells[rowIndex][columnIndex] = drillCell;
|
|
227
|
+
columnIndex++;
|
|
228
228
|
}
|
|
229
|
-
|
|
230
|
-
catch (e) {
|
|
231
|
-
throw new Error(`${e.toString()} ${e.stack}`);
|
|
229
|
+
rowIndex++;
|
|
232
230
|
}
|
|
233
231
|
const tableElement = this.document.createElement('table');
|
|
234
232
|
let tableSection = this.document.createElement('thead');
|
|
@@ -253,12 +251,40 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
253
251
|
`;
|
|
254
252
|
return tableElement;
|
|
255
253
|
}
|
|
254
|
+
calculatePivotDimensions(table) {
|
|
255
|
+
if (!table.isArray() && !table.isRecord()) {
|
|
256
|
+
throw new Error(`Could not pivot ${table.field.name}`);
|
|
257
|
+
}
|
|
258
|
+
let dimensions = undefined;
|
|
259
|
+
const userSpecifiedDimensions = (0, utils_1.parseCommaSeparatedParameterTagValue)(this.tags, 'pivotDimensions');
|
|
260
|
+
if (userSpecifiedDimensions) {
|
|
261
|
+
dimensions = table.field.allFields.filter(f => userSpecifiedDimensions.indexOf(f.name) >= 0);
|
|
262
|
+
if (dimensions.length !== userSpecifiedDimensions.length) {
|
|
263
|
+
for (const dim of userSpecifiedDimensions) {
|
|
264
|
+
if (table.field.allFields.filter(f => f.name === dim).length === 0) {
|
|
265
|
+
throw new Error(`Could not pivot ${table.field.name} since ${dim} is not a valid field.`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
dimensions = table.field.dimensions;
|
|
272
|
+
}
|
|
273
|
+
const nonDimensions = table.field.allFields.filter(f => dimensions.indexOf(f) < 0);
|
|
274
|
+
if (nonDimensions.length === 0) {
|
|
275
|
+
throw new Error(`Can not pivot ${table.field.name} since all of its fields are dimensions.`);
|
|
276
|
+
}
|
|
277
|
+
return { dimensions, nonDimensions };
|
|
278
|
+
}
|
|
256
279
|
async generatePivotedCells(table, shouldTranspose) {
|
|
257
280
|
const result = new Map();
|
|
281
|
+
if (table.isNull()) {
|
|
282
|
+
return result;
|
|
283
|
+
}
|
|
258
284
|
if (!table.isArray() && !table.isRecord()) {
|
|
259
285
|
throw new Error(`Could not pivot ${table.field.name}`);
|
|
260
286
|
}
|
|
261
|
-
const dimensions = table
|
|
287
|
+
const { dimensions } = this.calculatePivotDimensions(table);
|
|
262
288
|
for (const row of table) {
|
|
263
289
|
const pf = new PivotedField(table.field, dimensions.map(f => row.cell(f.name)));
|
|
264
290
|
const renderedCells = new Map();
|
|
@@ -266,21 +292,18 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
266
292
|
const childRenderer = this.childRenderers[nonDimension.name];
|
|
267
293
|
renderedCells.set(nonDimension.name, await this.createCellAndRender(childRenderer, row.cell(nonDimension.name), shouldTranspose));
|
|
268
294
|
}
|
|
295
|
+
if (result.has(pf.key)) {
|
|
296
|
+
throw new Error(`Can not pivot ${table.field.name} dimensions lead to non unique pivots.`);
|
|
297
|
+
}
|
|
269
298
|
result.set(pf.key, renderedCells);
|
|
270
299
|
}
|
|
271
300
|
return result;
|
|
272
301
|
}
|
|
273
|
-
generateNoValueCell(
|
|
274
|
-
if (!table.isArray() && !table.isRecord()) {
|
|
275
|
-
throw new Error(`Could not pivot ${table.field.name}`);
|
|
276
|
-
}
|
|
302
|
+
generateNoValueCell(field, shouldTranspose) {
|
|
277
303
|
const cell = this.createCell(this.childRenderers[field.name], shouldTranspose);
|
|
278
304
|
cell.innerHTML = '-';
|
|
279
305
|
return cell;
|
|
280
306
|
}
|
|
281
|
-
tagIsPresent(tags, tag) {
|
|
282
|
-
return tags ? tags.getMalloyTags().properties[tag] === true : false;
|
|
283
|
-
}
|
|
284
307
|
async createCellAndRender(childRenderer, value, shouldTranspose) {
|
|
285
308
|
const cell = this.createCell(childRenderer, shouldTranspose);
|
|
286
309
|
cell.appendChild(await childRenderer.render(value));
|
package/dist/html/utils.d.ts
CHANGED
|
@@ -12,3 +12,5 @@ export declare function createNullElement(document: Document): HTMLElement;
|
|
|
12
12
|
export declare function createDrillIcon(document: Document): HTMLElement;
|
|
13
13
|
export declare function formatTitle(options: RendererOptions, field: Field, renderDef?: RenderDef | undefined, timezone?: string): string;
|
|
14
14
|
export declare function tagIsPresent(tags: Tags | undefined, tagToCheck: string): boolean;
|
|
15
|
+
export declare function parameterTagValue(tags: Tags | undefined, tagToGetValue: string): string | undefined;
|
|
16
|
+
export declare function parseCommaSeparatedParameterTagValue(tags: Tags | undefined, tagToGetValue: string): string[] | undefined;
|
package/dist/html/utils.js
CHANGED
|
@@ -25,7 +25,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
25
25
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
26
26
|
};
|
|
27
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
-
exports.tagIsPresent = exports.formatTitle = exports.createDrillIcon = exports.createNullElement = exports.createErrorElement = exports.yieldTask = exports.normalizeToTimezone = exports.timeToString = exports.getColorScale = void 0;
|
|
28
|
+
exports.parseCommaSeparatedParameterTagValue = exports.parameterTagValue = exports.tagIsPresent = exports.formatTitle = exports.createDrillIcon = exports.createNullElement = exports.createErrorElement = exports.yieldTask = exports.normalizeToTimezone = exports.timeToString = exports.getColorScale = void 0;
|
|
29
29
|
const malloy_1 = require("@malloydata/malloy");
|
|
30
30
|
const startCase_1 = __importDefault(require("lodash/startCase"));
|
|
31
31
|
const luxon_1 = require("luxon");
|
|
@@ -232,4 +232,17 @@ function tagIsPresent(tags, tagToCheck) {
|
|
|
232
232
|
return tagProperty !== undefined && tagProperty !== false;
|
|
233
233
|
}
|
|
234
234
|
exports.tagIsPresent = tagIsPresent;
|
|
235
|
+
function parameterTagValue(tags, tagToGetValue) {
|
|
236
|
+
const tagProperty = tags === null || tags === void 0 ? void 0 : tags.getMalloyTags().properties[tagToGetValue];
|
|
237
|
+
if (typeof tagProperty === 'string') {
|
|
238
|
+
return tagProperty;
|
|
239
|
+
}
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
exports.parameterTagValue = parameterTagValue;
|
|
243
|
+
function parseCommaSeparatedParameterTagValue(tags, tagToGetValue) {
|
|
244
|
+
var _a;
|
|
245
|
+
return (_a = parameterTagValue(tags, tagToGetValue)) === null || _a === void 0 ? void 0 : _a.split(',');
|
|
246
|
+
}
|
|
247
|
+
exports.parseCommaSeparatedParameterTagValue = parseCommaSeparatedParameterTagValue;
|
|
235
248
|
//# sourceMappingURL=utils.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloydata/render",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.59-dev230718005248",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"prepublishOnly": "npm run build"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@malloydata/malloy": "^0.0.
|
|
21
|
+
"@malloydata/malloy": "^0.0.59-dev230718005248",
|
|
22
22
|
"@types/luxon": "^2.4.0",
|
|
23
23
|
"lodash": "^4.17.20",
|
|
24
24
|
"luxon": "^2.4.0",
|