mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-19 09:48:18 -05:00
refactor(filter-pane-handler): Add filter pane handler without messing with dimension creation (#959)
* refactor: support multiple dims in filterpane * refactor: use get dims from handler * refactor: only rm dims on success * fix: correct naming * fix: hard-code to max 1 dim for lo-handler * test: cover new functionality with unit tests * chore: rm yarn lock changes * revert: yarn lock * refactor: introduce handler without breaking dims * fix: ignore parcel env files * fix: ignore parcel env files * fix: end with empty line * fix: be explicit without involving maxDimensions * refactor: remove dims after set props success
This commit is contained in:
126
apis/nucleus/src/object/__tests__/lo-container-handler.spec.js
Normal file
126
apis/nucleus/src/object/__tests__/lo-container-handler.spec.js
Normal file
@@ -0,0 +1,126 @@
|
||||
describe('lo-container-handler', () => {
|
||||
let h;
|
||||
let loc;
|
||||
let def;
|
||||
let handler;
|
||||
|
||||
before(() => {
|
||||
[{ default: handler }] = aw.mock([['**/uid.js', () => () => 'uid']], ['../lo-container-handler.js']);
|
||||
});
|
||||
|
||||
const getMockDim = (cId) => ({
|
||||
qDef: {
|
||||
cId,
|
||||
},
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
loc = {
|
||||
qDef: {},
|
||||
};
|
||||
def = {
|
||||
dimensions: {
|
||||
added: sinon.stub(),
|
||||
removed: sinon.stub(),
|
||||
min: () => 0,
|
||||
max: () => 2,
|
||||
},
|
||||
};
|
||||
|
||||
h = handler({
|
||||
dc: loc,
|
||||
def,
|
||||
properties: 'props',
|
||||
dimensions: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('addDimension should not update dimensions since it is provided from outside', () => {
|
||||
h.addDimension(getMockDim());
|
||||
expect(def.dimensions.added).calledOnce;
|
||||
expect(h.dimensions()).to.deep.equal([]);
|
||||
expect(def.dimensions.added).calledWithExactly(
|
||||
{
|
||||
qDef: {
|
||||
cId: 'uid',
|
||||
qSortCriterias: [{ qSortByAscii: 1, qSortByLoadOrder: 1, qSortByNumeric: 1, qSortByState: 1 }],
|
||||
},
|
||||
},
|
||||
'props'
|
||||
);
|
||||
});
|
||||
|
||||
it('removeDimension should pick correct dimension', () => {
|
||||
const dim1 = getMockDim('id-1');
|
||||
const dim2 = getMockDim('id-2');
|
||||
const dim3 = getMockDim('id-3');
|
||||
h = handler({
|
||||
dc: loc,
|
||||
def,
|
||||
properties: 'props',
|
||||
dimensions: [dim1, dim2, dim3],
|
||||
});
|
||||
h.removeDimension(1);
|
||||
expect(def.dimensions.removed).calledWithExactly(dim2, 'props', 1);
|
||||
});
|
||||
|
||||
it('maxDimensions should call max func', () => {
|
||||
h = handler({
|
||||
dc: loc,
|
||||
def: {
|
||||
dimensions: {
|
||||
max: () => 'max hey hey',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(h.maxDimensions()).to.equal('max hey hey');
|
||||
});
|
||||
|
||||
it('maxDimensions should be read as a number when not a func', () => {
|
||||
h = handler({
|
||||
dc: loc,
|
||||
def: {
|
||||
dimensions: {
|
||||
max: 3,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(h.maxDimensions()).to.equal(3);
|
||||
});
|
||||
|
||||
it('maxMeasures should be 0', () => {
|
||||
h = handler({ dc: loc });
|
||||
expect(h.maxMeasures()).to.equal(0);
|
||||
});
|
||||
|
||||
it('canAddDimension should be true', () => {
|
||||
h = handler({
|
||||
dc: loc,
|
||||
dimensions: [{}, {}, {}],
|
||||
def: {
|
||||
dimensions: {
|
||||
max: 4,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(h.canAddDimension()).to.equal(true);
|
||||
});
|
||||
|
||||
it('canAddDimension should be false', () => {
|
||||
h = handler({
|
||||
dc: loc,
|
||||
dimensions: [{}, {}, {}, {}],
|
||||
def: {
|
||||
dimensions: {
|
||||
max: 4,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(h.canAddDimension()).to.equal(false);
|
||||
});
|
||||
|
||||
it('canAddMeasure should always be false', () => {
|
||||
h = handler({ dc: loc });
|
||||
expect(h.canAddMeasure()).to.equal(false);
|
||||
});
|
||||
});
|
||||
@@ -90,11 +90,13 @@ export default function hcHandler({ dc: hc, def, properties }) {
|
||||
|
||||
hc.qLayoutExclude.qHyperCubeDef.qDimensions.push(dimension);
|
||||
}
|
||||
return dimension;
|
||||
},
|
||||
removeDimension(idx) {
|
||||
const dimension = hc.qDimensions.splice(idx, 1)[0];
|
||||
removeIndex(hc.qInterColumnSortOrder, idx);
|
||||
def.dimensions.removed(dimension, objectProperties, idx);
|
||||
return dimension;
|
||||
},
|
||||
addMeasure(m) {
|
||||
const measure =
|
||||
|
||||
68
apis/nucleus/src/object/lo-container-handler.js
Normal file
68
apis/nucleus/src/object/lo-container-handler.js
Normal file
@@ -0,0 +1,68 @@
|
||||
/* eslint no-param-reassign:0 */
|
||||
|
||||
import uid from './uid';
|
||||
|
||||
const nxDimension = (f) => ({
|
||||
qDef: {
|
||||
qFieldDefs: [f],
|
||||
},
|
||||
});
|
||||
|
||||
export default function loContainerHandler({ dc: loc, def, properties, dimensions }) {
|
||||
const objectProperties = properties;
|
||||
|
||||
const handler = {
|
||||
dimensions() {
|
||||
return dimensions;
|
||||
},
|
||||
measures() {
|
||||
return [];
|
||||
},
|
||||
addDimension(d) {
|
||||
const dimension =
|
||||
typeof d === 'string'
|
||||
? nxDimension(d)
|
||||
: {
|
||||
...d,
|
||||
qDef: d.qDef || {},
|
||||
};
|
||||
|
||||
dimension.qDef.cId = dimension.qDef.cId || uid();
|
||||
dimension.qDef.qSortCriterias = (loc && loc.qDef.qSortCriterias) || [
|
||||
{
|
||||
qSortByState: 1,
|
||||
qSortByLoadOrder: 1,
|
||||
qSortByNumeric: 1,
|
||||
qSortByAscii: 1,
|
||||
},
|
||||
];
|
||||
|
||||
def.dimensions.added(dimension, objectProperties);
|
||||
return dimension;
|
||||
},
|
||||
removeDimension(idx) {
|
||||
const dimension = dimensions[idx];
|
||||
def.dimensions.removed(dimension, objectProperties, idx);
|
||||
return dimension;
|
||||
},
|
||||
// addMeasure() {},
|
||||
// removeMeasure() {},
|
||||
|
||||
maxDimensions() {
|
||||
const { max } = def.dimensions || {};
|
||||
const maxDims = typeof max === 'function' ? max() : max;
|
||||
return maxDims || 0;
|
||||
},
|
||||
maxMeasures() {
|
||||
return 0;
|
||||
},
|
||||
canAddDimension() {
|
||||
return handler.dimensions().length < handler.maxDimensions();
|
||||
},
|
||||
canAddMeasure() {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
return handler;
|
||||
}
|
||||
@@ -43,12 +43,14 @@ export default function loHandler({ dc: lo, def, properties }) {
|
||||
lo[k] = dimension[k];
|
||||
});
|
||||
def.dimensions.added(dimension, objectProperties);
|
||||
return dimension;
|
||||
},
|
||||
removeDimension(idx) {
|
||||
const dimension = lo;
|
||||
delete lo.qDef;
|
||||
delete lo.qLibraryId;
|
||||
def.dimensions.removed(dimension, objectProperties, idx);
|
||||
return dimension;
|
||||
},
|
||||
addMeasure() {},
|
||||
removeMeasure() {},
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
import hcHandler from '@nebula.js/nucleus/src/object/hc-handler';
|
||||
import loHandler from '@nebula.js/nucleus/src/object/lo-handler';
|
||||
import loContainerHandler from '@nebula.js/nucleus/src/object/lo-container-handler';
|
||||
|
||||
import { Typography } from '@mui/material';
|
||||
|
||||
@@ -27,25 +28,39 @@ const getValue = (data, reference, defaultValue) => {
|
||||
};
|
||||
|
||||
export default function DataCube({ setProperties, target, properties }) {
|
||||
const createHandler = target.propertyPath.match('/qHyperCube') ? hcHandler : loHandler;
|
||||
// Store dimensions outside of handler to support filterpanes or other containers
|
||||
// holding list objects, which do not store dimensions in an array (like hc.qDimensions).
|
||||
const [dimensions, setDimensions] = useState([]);
|
||||
|
||||
const supportsMultipleDims = target.dimensions && target.dimensions.max && target.dimensions.max() > 1;
|
||||
const listBoxHandler = supportsMultipleDims ? loContainerHandler : loHandler;
|
||||
|
||||
const createHandler = target.propertyPath.match('/qHyperCube') ? hcHandler : listBoxHandler;
|
||||
const dc = getValue(properties, target.propertyPath);
|
||||
const handler = useMemo(
|
||||
() =>
|
||||
createHandler({
|
||||
def: target,
|
||||
dc: getValue(properties, target.propertyPath),
|
||||
dc,
|
||||
properties,
|
||||
dimensions,
|
||||
}),
|
||||
[properties]
|
||||
[dc, target, properties, dimensions]
|
||||
);
|
||||
|
||||
const onDimensionAdded = (a) => {
|
||||
handler.addDimension(typeof a === 'object' ? { qLibraryId: a.qId } : a);
|
||||
setProperties(properties);
|
||||
const dim = typeof a === 'object' ? { qLibraryId: a.qId } : a;
|
||||
const addedDim = handler.addDimension(dim);
|
||||
setProperties(properties).then(() => {
|
||||
setDimensions([...dimensions, addedDim]);
|
||||
});
|
||||
};
|
||||
|
||||
const onDimensionRemoved = (idx) => {
|
||||
handler.removeDimension(idx);
|
||||
setProperties(properties);
|
||||
setProperties(properties).then(() => {
|
||||
setDimensions([...dimensions.slice(0, idx), ...dimensions.slice(idx + 1)]);
|
||||
});
|
||||
};
|
||||
|
||||
const onMeasureAdded = (a) => {
|
||||
@@ -64,6 +79,7 @@ export default function DataCube({ setProperties, target, properties }) {
|
||||
{target.propertyPath}
|
||||
</Typography>
|
||||
<Fields
|
||||
key="dimensions"
|
||||
onAdded={onDimensionAdded}
|
||||
onRemoved={onDimensionRemoved}
|
||||
canAdd={handler.canAddDimension()}
|
||||
@@ -73,6 +89,7 @@ export default function DataCube({ setProperties, target, properties }) {
|
||||
addLabel="Add dimension"
|
||||
/>
|
||||
<Fields
|
||||
key="measures"
|
||||
onAdded={onMeasureAdded}
|
||||
onRemoved={onMeasureRemoved}
|
||||
canAdd={handler.canAddMeasure()}
|
||||
|
||||
4
examples/dev-mashup/.gitignore
vendored
4
examples/dev-mashup/.gitignore
vendored
@@ -1 +1,3 @@
|
||||
yarn.lock
|
||||
yarn.lock
|
||||
.parcel-cache
|
||||
.cache
|
||||
|
||||
Reference in New Issue
Block a user