mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-19 17:58:43 -05:00
chore: update types and export HyperCubeHandler (#1779)
* chore: updating types index.d.ts for HyperCubeHanlder * chore: fix dependencies * chore: remove nudleus dependecies and fixing comments * chore: disable no-relative-package import * chore: fix comments * chore: update types for data-property and hypercube-handler * chore: convert more types in data-property-handler to object * chore: fix more comments * chore: make all types private * chore: update lockfile * chore: make a correction * chore: fix the classes example import path --------- Co-authored-by: caele <tsm@qlik.com>
This commit is contained in:
committed by
GitHub
parent
af5566f40c
commit
ccf66ebc50
@@ -1,6 +1,7 @@
|
|||||||
import hypercube from './hypercube';
|
import hypercube from './hypercube';
|
||||||
import utils from './utils';
|
import utils from './utils';
|
||||||
import helpers from './helpers';
|
import helpers from './helpers';
|
||||||
|
import arrayUtil from './array-util';
|
||||||
|
|
||||||
const getType = async ({ halo, name, version }) => {
|
const getType = async ({ halo, name, version }) => {
|
||||||
const { types } = halo;
|
const { types } = halo;
|
||||||
@@ -118,4 +119,7 @@ const conversion = {
|
|||||||
*/
|
*/
|
||||||
hypercube,
|
hypercube,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { utils, arrayUtil };
|
||||||
|
|
||||||
export default conversion;
|
export default conversion;
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ export {
|
|||||||
useEmitter,
|
useEmitter,
|
||||||
onTakeSnapshot,
|
onTakeSnapshot,
|
||||||
onContextMenu,
|
onContextMenu,
|
||||||
|
HyperCubeHandler,
|
||||||
|
DataPropertyHandler,
|
||||||
} from '@nebula.js/supernova';
|
} from '@nebula.js/supernova';
|
||||||
|
|
||||||
// component internals
|
// component internals
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"version": "6.0.0-alpha.2",
|
"version": "6.0.0-alpha.2",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@nebula.js/conversion": "^6.0.0-alpha.2",
|
||||||
"extend": "3.0.2",
|
"extend": "3.0.2",
|
||||||
"node-event-emitter": "0.0.1"
|
"node-event-emitter": "0.0.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,17 +34,16 @@ describe('DataPropertyHandler', () => {
|
|||||||
describe('getDimensions()', () => {
|
describe('getDimensions()', () => {
|
||||||
test('should return null when dimension is undefined', () => {
|
test('should return null when dimension is undefined', () => {
|
||||||
jest.spyOn(handler, 'getDimensions').mockReturnValue([]);
|
jest.spyOn(handler, 'getDimensions').mockReturnValue([]);
|
||||||
const dimension = handler.getDimension(undefined);
|
const dimension = handler.getDimension({});
|
||||||
expect(dimension).toBeFalsy();
|
expect(dimension).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return dimension when it exists in getDimensions()', () => {
|
test('should return dimension when it exists in getDimensions()', () => {
|
||||||
jest.spyOn(handler, 'getDimensions').mockReturnValue([{ qDef: { cId: 'dim1' } }]);
|
jest.spyOn(handler, 'getDimensions').mockReturnValue([{ qDef: { cId: 'dim1' } }]);
|
||||||
jest.spyOn(handler, 'getAlternativeDimensions').mockReturnValue([{ qDef: { cId: 'altDim1' } }]);
|
jest.spyOn(handler, 'getAlternativeDimensions').mockReturnValue([{ qDef: { cId: 'altDim1' } }]);
|
||||||
|
const dimension = handler.getDimension({ id: 'dim1' });
|
||||||
const dimension = handler.getDimension('dim1');
|
|
||||||
expect(dimension).toEqual({ qDef: { cId: 'dim1' } });
|
expect(dimension).toEqual({ qDef: { cId: 'dim1' } });
|
||||||
const alternativeDimension = handler.getDimension('altDim1');
|
const alternativeDimension = handler.getDimension({ id: 'altDim1' });
|
||||||
expect(alternativeDimension).toEqual({ qDef: { cId: 'altDim1' } });
|
expect(alternativeDimension).toEqual({ qDef: { cId: 'altDim1' } });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -52,7 +51,7 @@ describe('DataPropertyHandler', () => {
|
|||||||
describe('getMeasure()', () => {
|
describe('getMeasure()', () => {
|
||||||
test('should return null when both measures and alternative measures are empty', () => {
|
test('should return null when both measures and alternative measures are empty', () => {
|
||||||
jest.spyOn(handler, 'getMeasures').mockReturnValue([]);
|
jest.spyOn(handler, 'getMeasures').mockReturnValue([]);
|
||||||
const measure = handler.getMeasure(undefined);
|
const measure = handler.getMeasure({});
|
||||||
expect(measure).toBeFalsy();
|
expect(measure).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -60,8 +59,8 @@ describe('DataPropertyHandler', () => {
|
|||||||
jest.spyOn(handler, 'getMeasures').mockReturnValue([{ qDef: { cId: 'measure1' } }]);
|
jest.spyOn(handler, 'getMeasures').mockReturnValue([{ qDef: { cId: 'measure1' } }]);
|
||||||
jest.spyOn(handler, 'getAlternativeMeasures').mockReturnValue([{ qDef: { cId: 'altMeasure1' } }]);
|
jest.spyOn(handler, 'getAlternativeMeasures').mockReturnValue([{ qDef: { cId: 'altMeasure1' } }]);
|
||||||
|
|
||||||
const measure = handler.getMeasure('measure1');
|
const measure = handler.getMeasure({ id: 'measure1' });
|
||||||
const alternativeMeasure = handler.getMeasure('altMeasure1');
|
const alternativeMeasure = handler.getMeasure({ id: 'altMeasure1' });
|
||||||
expect(measure).toEqual({ qDef: { cId: 'measure1' } });
|
expect(measure).toEqual({ qDef: { cId: 'measure1' } });
|
||||||
expect(alternativeMeasure).toEqual({ qDef: { cId: 'altMeasure1' } });
|
expect(alternativeMeasure).toEqual({ qDef: { cId: 'altMeasure1' } });
|
||||||
});
|
});
|
||||||
@@ -75,31 +74,26 @@ describe('DataPropertyHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should create a dimension with default properties when no field is provided', () => {
|
test('should create a dimension with default properties when no field is provided', () => {
|
||||||
const result = handler.createFieldDimension(null, null, { customDefault: 'value' });
|
const fieldDimension = { field: '', label: '', defaults: { customDefault: 'value' } };
|
||||||
|
const result = handler.createFieldDimension(fieldDimension);
|
||||||
|
|
||||||
expect(result.qDef.qFieldDefs).toEqual([null]);
|
expect(result.qDef.qFieldDefs).toEqual(['']);
|
||||||
expect(result.qDef.qFieldLabels).toEqual(['']);
|
expect(result.qDef.qFieldLabels).toEqual(['']);
|
||||||
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
||||||
expect(result.qDef.autoSort).toBe(true);
|
expect(result.qDef.autoSort).toBe(true);
|
||||||
expect(result.someProperty).toBe('defaultValue');
|
expect(result.someProperty).toBe('defaultValue');
|
||||||
expect(result.customDefault).toBe('value');
|
expect(result.customDefault).toBe('value');
|
||||||
});
|
expect(result.qOtherTotalSpec).toEqual({});
|
||||||
|
|
||||||
test('should create a library dimension with default properties', () => {
|
|
||||||
const result = handler.createLibraryDimension('libraryId', { customDefault: 'value' });
|
|
||||||
|
|
||||||
expect(result.qLibraryId).toBe('libraryId');
|
|
||||||
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
|
||||||
expect(result.qDef.autoSort).toBe(true);
|
|
||||||
expect(result.someProperty).toBe('defaultValue');
|
|
||||||
expect(result.customDefault).toBe('value');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should create a dimension with provided field and label', () => {
|
test('should create a dimension with provided field and label', () => {
|
||||||
const result = handler.createFieldDimension('fieldName', 'fieldLabel', { customDefault: 'value' });
|
const fieldDimension = { field: 'fieldName', label: 'fieldLabel' };
|
||||||
|
const result = handler.createFieldDimension(fieldDimension);
|
||||||
|
|
||||||
expect(result.qDef.qFieldDefs).toEqual(['fieldName']);
|
expect(result.qDef.qFieldDefs).toEqual(['fieldName']);
|
||||||
expect(result.qDef.qFieldLabels).toEqual(['fieldLabel']);
|
expect(result.qDef.qFieldLabels).toEqual(['fieldLabel']);
|
||||||
|
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
||||||
|
expect(result.qDef.autoSort).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -110,21 +104,17 @@ describe('DataPropertyHandler', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should delete qFieldDefs and qFieldLabels from the dimension', () => {
|
test('should create dimension and delete qFieldDefs and qFieldLabels from it', () => {
|
||||||
const result = handler.createLibraryDimension('libraryId', {});
|
const libraryDimension = { id: 'libraryId', defaults: { customDefault: 'value' } };
|
||||||
|
const result = handler.createLibraryDimension(libraryDimension);
|
||||||
expect(result.qDef.qFieldDefs).toBeUndefined();
|
|
||||||
expect(result.qDef.qFieldLabels).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should create a library dimension with default properties', () => {
|
|
||||||
const result = handler.createLibraryDimension('libraryId', { customDefault: 'value' });
|
|
||||||
|
|
||||||
expect(result.qLibraryId).toBe('libraryId');
|
expect(result.qLibraryId).toBe('libraryId');
|
||||||
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
expect(result.qDef.qSortCriterias).toEqual(sortingProperties);
|
||||||
expect(result.qDef.autoSort).toBe(true);
|
|
||||||
expect(result.someProperty).toBe('defaultValue');
|
expect(result.someProperty).toBe('defaultValue');
|
||||||
expect(result.customDefault).toBe('value');
|
expect(result.customDefault).toBe('value');
|
||||||
|
expect(result.qDef.autoSort).toBe(true);
|
||||||
|
expect(result.qDef.qFieldDefs).toBeUndefined();
|
||||||
|
expect(result.qDef.qFieldLabels).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -136,7 +126,12 @@ describe('DataPropertyHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should create a measure with provided expression and label', () => {
|
test('should create a measure with provided expression and label', () => {
|
||||||
const result = handler.createExpressionMeasure('SUM(Sales)', 'Total Sales', { customDefault: 'value' });
|
const expressionMeasure = {
|
||||||
|
expression: 'SUM(Sales)',
|
||||||
|
label: 'Total Sales',
|
||||||
|
defaults: { customDefault: 'value' },
|
||||||
|
};
|
||||||
|
const result = handler.createExpressionMeasure(expressionMeasure);
|
||||||
|
|
||||||
expect(result.qDef.qDef).toBe('SUM(Sales)');
|
expect(result.qDef.qDef).toBe('SUM(Sales)');
|
||||||
expect(result.qDef.qLabel).toBe('Total Sales');
|
expect(result.qDef.qLabel).toBe('Total Sales');
|
||||||
@@ -146,14 +141,16 @@ describe('DataPropertyHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should initialize qDef and qNumFormat if not provided', () => {
|
test('should initialize qDef and qNumFormat if not provided', () => {
|
||||||
const result = handler.createExpressionMeasure('SUM(Sales)', 'Total Sales', {});
|
const expressionMeasure = { expression: 'SUM(Sales)', label: 'Total Sales', defaults: {} };
|
||||||
|
const result = handler.createExpressionMeasure(expressionMeasure);
|
||||||
|
|
||||||
expect(result.qDef).toBeDefined();
|
expect(result.qDef).toBeDefined();
|
||||||
expect(result.qDef.qNumFormat).toBeDefined();
|
expect(result.qDef.qNumFormat).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should handle empty defaults gracefully', () => {
|
test('should handle empty defaults gracefully', () => {
|
||||||
const result = handler.createExpressionMeasure('SUM(Sales)', 'Total Sales', null);
|
const expressionMeasure = { expression: 'SUM(Sales)', label: 'Total Sales' };
|
||||||
|
const result = handler.createExpressionMeasure(expressionMeasure);
|
||||||
|
|
||||||
expect(result.qDef.qDef).toBe('SUM(Sales)');
|
expect(result.qDef.qDef).toBe('SUM(Sales)');
|
||||||
expect(result.qDef.qLabel).toBe('Total Sales');
|
expect(result.qDef.qLabel).toBe('Total Sales');
|
||||||
@@ -170,7 +167,8 @@ describe('DataPropertyHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should create a library measure with provided id and defaults', () => {
|
test('should create a library measure with provided id and defaults', () => {
|
||||||
const result = handler.createLibraryMeasure('libraryId', { customDefault: 'value' });
|
const libraryMeasure = { id: 'libraryId', defaults: { customDefault: 'value' } };
|
||||||
|
const result = handler.createLibraryMeasure(libraryMeasure);
|
||||||
|
|
||||||
expect(result.qLibraryId).toBe('libraryId');
|
expect(result.qLibraryId).toBe('libraryId');
|
||||||
expect(result.qDef.qNumFormat).toBeDefined();
|
expect(result.qDef.qNumFormat).toBeDefined();
|
||||||
@@ -180,14 +178,16 @@ describe('DataPropertyHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should initialize qDef and qNumFormat if not provided', () => {
|
test('should initialize qDef and qNumFormat if not provided', () => {
|
||||||
const result = handler.createLibraryMeasure('libraryId', {});
|
const libraryMeasure = { id: 'libraryId', defaults: {} };
|
||||||
|
const result = handler.createLibraryMeasure(libraryMeasure);
|
||||||
|
|
||||||
expect(result.qDef).toBeDefined();
|
expect(result.qDef).toBeDefined();
|
||||||
expect(result.qDef.qNumFormat).toBeDefined();
|
expect(result.qDef.qNumFormat).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should delete qDef.qDef and qDef.qLabel from the measure', () => {
|
test('should delete qDef.qDef and qDef.qLabel from the measure', () => {
|
||||||
const result = handler.createLibraryMeasure('libraryId', {});
|
const libraryMeasure = { id: 'libraryId', defaults: {} };
|
||||||
|
const result = handler.createLibraryMeasure(libraryMeasure);
|
||||||
|
|
||||||
expect(result.qDef.qDef).toBeUndefined();
|
expect(result.qDef.qDef).toBeUndefined();
|
||||||
expect(result.qDef.qLabel).toBeUndefined();
|
expect(result.qDef.qLabel).toBeUndefined();
|
||||||
@@ -195,14 +195,7 @@ describe('DataPropertyHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('maxMeasures', () => {
|
describe('maxMeasures', () => {
|
||||||
let galaxy;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
galaxy = {
|
|
||||||
flags: {
|
|
||||||
isEnabled: jest.fn().mockReturnValue(false),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
handler = new HyperCubeHandler({
|
handler = new HyperCubeHandler({
|
||||||
measureDefinition: { max: 0 },
|
measureDefinition: { max: 0 },
|
||||||
dimensionDefinition: { max: 0 },
|
dimensionDefinition: { max: 0 },
|
||||||
@@ -221,15 +214,6 @@ describe('DataPropertyHandler', () => {
|
|||||||
expect(result).toBe(5);
|
expect(result).toBe(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should pass properties to measureDefinition.max when feature flag is enabled', () => {
|
|
||||||
handler.measureDefinition.max = jest.fn().mockReturnValue(5);
|
|
||||||
galaxy.flags.isEnabled.mockReturnValue(true);
|
|
||||||
handler.properties = { someProperty: 'value' };
|
|
||||||
|
|
||||||
const result = handler.maxMeasures();
|
|
||||||
expect(result).toBe(5);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return measureDefinition.max when it is a valid number', () => {
|
test('should return measureDefinition.max when it is a valid number', () => {
|
||||||
handler.measureDefinition.max = 8;
|
handler.measureDefinition.max = 8;
|
||||||
|
|
||||||
@@ -260,14 +244,7 @@ describe('DataPropertyHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('maxDimensions', () => {
|
describe('maxDimensions', () => {
|
||||||
let galaxy;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
galaxy = {
|
|
||||||
flags: {
|
|
||||||
isEnabled: jest.fn().mockReturnValue(false),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
handler = new HyperCubeHandler({
|
handler = new HyperCubeHandler({
|
||||||
measureDefinition: { max: 0 },
|
measureDefinition: { max: 0 },
|
||||||
dimensionDefinition: { max: 0 },
|
dimensionDefinition: { max: 0 },
|
||||||
@@ -282,15 +259,6 @@ describe('DataPropertyHandler', () => {
|
|||||||
expect(result).toBe(5);
|
expect(result).toBe(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should pass properties to dimensionDefinition.max when feature flag is enabled', () => {
|
|
||||||
handler.dimensionDefinition.max = jest.fn().mockReturnValue(10);
|
|
||||||
galaxy.flags.isEnabled.mockReturnValue(true);
|
|
||||||
handler.properties = { someProperty: 'value' };
|
|
||||||
|
|
||||||
const result = handler.maxDimensions();
|
|
||||||
expect(result).toBe(10);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should return dimensionDefinition.max when it is a valid number', () => {
|
test('should return dimensionDefinition.max when it is a valid number', () => {
|
||||||
handler.dimensionDefinition.max = 8;
|
handler.dimensionDefinition.max = 8;
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,38 @@
|
|||||||
import extend from 'extend';
|
import extend from 'extend';
|
||||||
// eslint-disable-next-line import/no-relative-packages
|
import { findFieldById, initializeDim, useMasterNumberFormat } from './utils/field-helper/field-utils';
|
||||||
import isEnabled from '../../../nucleus/src/flags/flags';
|
|
||||||
import { findFieldById, useMasterNumberFormat } from './utils/field-helper/field-utils';
|
|
||||||
import { INITIAL_SORT_CRITERIAS } from './utils/constants';
|
import { INITIAL_SORT_CRITERIAS } from './utils/constants';
|
||||||
import { notSupportedError } from './utils/hypercube-helper/hypercube-utils';
|
import { notSupportedError } from './utils/hypercube-helper/hypercube-utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @class DataPropertyHandler
|
||||||
|
* @description A class to handle data properties for dimensions and measures in a data model.
|
||||||
|
* @param {object} opts - Parameters to add a hypercube handlers
|
||||||
|
* @param {qix.Doc} opts.app
|
||||||
|
* @param {object} opts.dimensionDefinition
|
||||||
|
* @param {object} opts.measureDefinition
|
||||||
|
* @param {object} opts.dimensionProperties
|
||||||
|
* @param {object} opts.measureProperties
|
||||||
|
* @param {object} opts.globalChangeListeners
|
||||||
|
* @entry
|
||||||
|
* @export
|
||||||
|
* @example
|
||||||
|
* import DataPropertyHandler from '@nebula.js/stardust';
|
||||||
|
*
|
||||||
|
* class PivotHyperCubeHandler extends DataPropertyHandler {
|
||||||
|
*
|
||||||
|
* addDimensionAsFirstRow: (hypercube: HyperCubeDef, dimension: NxDimension) => {
|
||||||
|
* const dimensions = this.getDimensions().length;
|
||||||
|
* const { qInterColumnSortOrder } = hypercube;
|
||||||
|
*
|
||||||
|
* if(dimensions !== 0 && dimensions < this.maxDimensions()) {
|
||||||
|
* hypercube.qNoOfLeftDims = 1;
|
||||||
|
* qInterColumnSortOrder?.unshift(dimensions);
|
||||||
|
* dimensions.splice(0, 0, dimension);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
class DataPropertyHandler {
|
class DataPropertyHandler {
|
||||||
constructor(opts) {
|
constructor(opts) {
|
||||||
const options = opts || {};
|
const options = opts || {};
|
||||||
@@ -18,20 +46,85 @@ class DataPropertyHandler {
|
|||||||
this.app = options.app;
|
this.app = options.app;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @typeof {object} LibraryDimension
|
||||||
|
* @property {string} id
|
||||||
|
* @property {qix.NxDimension=} defaults
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @typeof {object} FieldDimension
|
||||||
|
* @property {string} field
|
||||||
|
* @property {string=} label
|
||||||
|
* @property {qix.NxDimension=} defaults
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @typeof {object} LibraryMeasure
|
||||||
|
* @property {string} id
|
||||||
|
* @property {qix.NxMeasure=} defaults
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @typeof {object} ExpressionMeasure
|
||||||
|
* @property {string} expression
|
||||||
|
* @property {string=} label
|
||||||
|
* @property {qix.NxMeasure=} defaults
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the properties for the handler.
|
||||||
|
* @private
|
||||||
|
* @param {object=} properties - The properties object to set.
|
||||||
|
* @description Updates the handler's properties and analysis type flag.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.setProperties({ metaData: { isAnalysisType: true } });
|
||||||
|
*/
|
||||||
setProperties(properties) {
|
setProperties(properties) {
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
this.isAnalysisType = this.properties?.metaData?.isAnalysisType;
|
this.isAnalysisType = this.properties?.metaData?.isAnalysisType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the global change listeners.
|
||||||
|
* @private
|
||||||
|
* @param {Function[]} arr - Array of listener functions.
|
||||||
|
* @description Assigns global change listeners to the handler.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.setGlobalChangeListeners([listener1, listener2]);
|
||||||
|
*/
|
||||||
setGlobalChangeListeners(arr) {
|
setGlobalChangeListeners(arr) {
|
||||||
this.globalChangeListeners = arr;
|
this.globalChangeListeners = arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {object=} layout - The layout object to set.
|
||||||
|
* @description Sets the layout for the handler.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.setLayout(layoutObj);
|
||||||
|
*/
|
||||||
setLayout(layout) {
|
setLayout(layout) {
|
||||||
this.layout = layout;
|
this.layout = layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
static type() {
|
/**
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @description Throws an error indicating the method must be overridden.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* DataPropertyHandler.type(); // Throws error
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
type() {
|
||||||
throw new Error('Must override this method');
|
throw new Error('Must override this method');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,56 +132,138 @@ class DataPropertyHandler {
|
|||||||
// ---------------DIMENSION---------------
|
// ---------------DIMENSION---------------
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
|
|
||||||
static getDimensions() {
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {Array} Empty array.
|
||||||
|
* @description Returns the default dimension array.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
getDimensions() {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getDimension(id) {
|
/**
|
||||||
|
* Gets a dimension by id from dimensions or alternative dimensions.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryDimension} libraryDimension
|
||||||
|
* @returns {qix.NxDimension} - The found dimension.
|
||||||
|
* @description Searches for a dimension by id in both main and alternative dimensions.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* const dim = handler.getDimension({ id: 'dimId' });
|
||||||
|
*/
|
||||||
|
getDimension(libraryDimension) {
|
||||||
const dimensions = this.getDimensions();
|
const dimensions = this.getDimensions();
|
||||||
const alternativeDimensions = this.getAlternativeDimensions();
|
const alternativeDimensions = this.getAlternativeDimensions();
|
||||||
|
|
||||||
return findFieldById(dimensions, id) ?? findFieldById(alternativeDimensions, id);
|
return findFieldById(dimensions, libraryDimension.id) ?? findFieldById(alternativeDimensions, libraryDimension.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static getAlternativeDimensions() {
|
/**
|
||||||
|
* Throws an error indicating the method must be implemented in subclasses.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
getAlternativeDimensions() {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
static addDimension() {
|
/**
|
||||||
|
* Throws an error indicating addDimension is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
addDimension() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static addDimensions() {
|
/**
|
||||||
|
* Throws an error indicating addDimensions is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
addDimensions() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static removeDimension() {
|
/**
|
||||||
|
* Throws an error indicating removeDimension is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
removeDimension() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static removeDimensions() {
|
/**
|
||||||
|
* Throws an error indicating removeDimensions is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
removeDimensions() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static autoSortDimension() {
|
/**
|
||||||
|
* Throws an error indicating autoSortDimension is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
autoSortDimension() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static replaceDimension() {
|
/**
|
||||||
|
* Throws an error indicating replaceDimension is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
replaceDimension() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static getSorting() {
|
/**
|
||||||
|
* Throws an error indicating getSorting is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
getSorting() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
createLibraryDimension(id, defaults) {
|
/**
|
||||||
const dimension = extend(true, {}, this.dimensionProperties || {}, defaults || {});
|
* Creates a type of library dimension with a field definition.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryDimension} libraryDimension
|
||||||
|
* @returns {qix.NxDimension} The created dimension object.
|
||||||
|
* @description Initializes a dimension and applying default properties and sort criteria.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* const dim = handler.createLibraryDimension({ id:'dimId', { qDef: { cId: 'dim1' } }});
|
||||||
|
*/
|
||||||
|
createLibraryDimension(libraryDimension) {
|
||||||
|
let dimension = extend(true, {}, this.dimensionProperties || {}, libraryDimension.defaults || {});
|
||||||
|
|
||||||
dimension.qDef = dimension.qDef ?? {};
|
dimension = initializeDim(dimension);
|
||||||
dimension.qOtherTotalSpec = dimension.qOtherTotalSpec ?? {};
|
|
||||||
|
|
||||||
dimension.qLibraryId = id;
|
dimension.qLibraryId = libraryDimension.id;
|
||||||
dimension.qDef.autoSort = true;
|
dimension.qDef.autoSort = true;
|
||||||
dimension.qDef.qSortCriterias = INITIAL_SORT_CRITERIAS;
|
dimension.qDef.qSortCriterias = INITIAL_SORT_CRITERIAS;
|
||||||
|
|
||||||
@@ -98,87 +273,201 @@ class DataPropertyHandler {
|
|||||||
return dimension;
|
return dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
createFieldDimension(field, label, defaults) {
|
/**
|
||||||
const dimension = extend(true, {}, this.dimensionProperties || {}, defaults || {});
|
* Creates a type of field dimension with a field definition.
|
||||||
|
* @private
|
||||||
|
* @param {FieldDimension} fieldDimension
|
||||||
|
* @returns {qix.NxDimension} The created dimension object.
|
||||||
|
* @description Initializes a dimension with field definitions, labels, and default properties.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.createFieldDimension({field: 'currentField', label: 'label'});
|
||||||
|
*/
|
||||||
|
createFieldDimension(fieldDimension) {
|
||||||
|
let dimension = extend(true, {}, this.dimensionProperties || {}, fieldDimension.defaults || {});
|
||||||
|
|
||||||
dimension.qDef = dimension.qDef ?? {};
|
dimension = initializeDim(dimension);
|
||||||
dimension.qOtherTotalSpec = dimension.qOtherTotalSpec ?? {};
|
|
||||||
|
|
||||||
if (!field) {
|
if (!fieldDimension.field) {
|
||||||
dimension.qDef.qFieldDefs = [];
|
dimension.qDef.qFieldDefs = [];
|
||||||
dimension.qDef.qFieldLabels = [];
|
dimension.qDef.qFieldLabels = [];
|
||||||
dimension.qDef.qSortCriterias = [];
|
dimension.qDef.qSortCriterias = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
dimension.qDef.qFieldDefs = [field];
|
dimension.qDef.qFieldDefs = [fieldDimension.field];
|
||||||
dimension.qDef.qFieldLabels = label ? [label] : [''];
|
dimension.qDef.qFieldLabels = fieldDimension.label ? [fieldDimension.label] : [''];
|
||||||
dimension.qDef.qSortCriterias = INITIAL_SORT_CRITERIAS;
|
dimension.qDef.qSortCriterias = INITIAL_SORT_CRITERIAS;
|
||||||
|
|
||||||
dimension.qDef.autoSort = true;
|
dimension.qDef.autoSort = true;
|
||||||
|
|
||||||
return dimension;
|
return dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
addFieldDimension(field, label, defaults) {
|
/**
|
||||||
const dimension = this.createFieldDimension(field, label, defaults);
|
* Adds a field dimension to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {FieldDimension} fieldDimension
|
||||||
|
* @returns {Promise<qix.NxDimension=>} The result of addDimension.
|
||||||
|
* @description Creates and adds a field dimension.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addFieldDimension({field: 'currentField', label: 'label'});
|
||||||
|
*/
|
||||||
|
addFieldDimension(fieldDimension) {
|
||||||
|
const dimension = this.createFieldDimension(fieldDimension);
|
||||||
return this.addDimension(dimension);
|
return this.addDimension(dimension);
|
||||||
}
|
}
|
||||||
|
|
||||||
addFieldDimensions(args) {
|
/**
|
||||||
const dimensions = args.map(({ field, label, defaults }) => this.createFieldDimension(field, label, defaults));
|
* @private
|
||||||
|
* @param {FieldDimension[]} fieldDimensions - Array of field dimension.
|
||||||
|
* @returns {Promise<qix.NxDimension[]>} The result of addDimensions.
|
||||||
|
* @description Creates and adds multiple field dimensions.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addFieldDimensions([{ field: 'A', label: 'AA' }, { field: 'B', label: 'BB' }]);
|
||||||
|
*/
|
||||||
|
addFieldDimensions(fieldDimensions) {
|
||||||
|
const dimensions = fieldDimensions.map((fieldDimension) => this.createFieldDimension(fieldDimension));
|
||||||
return this.addDimensions(dimensions);
|
return this.addDimensions(dimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
addLibraryDimension(id, defaults) {
|
/**
|
||||||
const dimension = this.createLibraryDimension(id, defaults);
|
* Adds a library dimension to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryDimension} libraryDimension
|
||||||
|
* @returns {Promise<qix.NxDimension=>} The result of addDimension.
|
||||||
|
* @description Creates and adds a library dimension.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addLibraryDimension({ id: 'A'});
|
||||||
|
*/
|
||||||
|
addLibraryDimension(libraryDimension) {
|
||||||
|
const dimension = this.createLibraryDimension(libraryDimension);
|
||||||
return this.addDimension(dimension);
|
return this.addDimension(dimension);
|
||||||
}
|
}
|
||||||
|
|
||||||
addLibraryDimensions(args) {
|
/**
|
||||||
const dimensions = args.map(({ id, defaults }) => this.createLibraryDimension(id, defaults));
|
* Adds multiple library dimensions to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryDimension[]} libraryDimensions - Array of library dimension.
|
||||||
|
* @returns {Promise<qix.NxDimension[]>} The result of addDimensions.
|
||||||
|
* @description Creates and adds multiple library dimensions.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addLibraryDimensions([{ id: 'A' }, { id: 'B', defaults: { ... } }]);
|
||||||
|
*/
|
||||||
|
addLibraryDimensions(libraryDimensions) {
|
||||||
|
const dimensions = libraryDimensions.map((libraryDimension) => this.createLibraryDimension(libraryDimension));
|
||||||
const result = this.addDimensions(dimensions);
|
const result = this.addDimensions(dimensions);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async addAltLibraryDimensions(args) {
|
/**
|
||||||
const dimensions = args.map(({ id }) => this.createLibraryDimension(id));
|
* Adds multiple alternative library dimensions to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryDimension[]} libraryDimensions - Array of library dimension.
|
||||||
|
* @returns {Promise<qix.NxDimension[]>} The result of addDimensions.
|
||||||
|
* @description Creates and adds multiple alternative library dimensions.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* await handler.addAltLibraryDimensions([{ id: 'A' }, { id: 'B', defaults: { ... } }]);
|
||||||
|
*/
|
||||||
|
async addAltLibraryDimensions(libraryDimensions) {
|
||||||
|
const dimensions = libraryDimensions.map((libraryDimension) => this.createLibraryDimension(libraryDimension));
|
||||||
return this.addDimensions(dimensions, true);
|
return this.addDimensions(dimensions, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async addAltFieldDimensions(args) {
|
/**
|
||||||
const dimensions = args.map(({ field }) => this.createFieldDimension(field));
|
* Adds multiple alternative field dimensions to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {FieldDimension[]} fieldDimensions - Array of field dimension.
|
||||||
|
* @returns {Promise<qix.NxDimension[]>} The result of addDimensions.
|
||||||
|
* @description Creates and adds multiple alternative field dimensions.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* await handler.addAltFieldDimensions([{ field: 'A', label: 'Label A' }, { field: 'B', label: 'Label B' }]);
|
||||||
|
*/
|
||||||
|
async addAltFieldDimensions(fieldDimensions) {
|
||||||
|
const dimensions = fieldDimensions.map((fieldDimension) => this.createFieldDimension(fieldDimension));
|
||||||
return this.addDimensions(dimensions, true);
|
return this.addDimensions(dimensions, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
addAlternativeFieldDimension(field, label, defaults) {
|
/**
|
||||||
const dimension = this.createFieldDimension(field, label, defaults);
|
* Adds an alternative field dimension to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {FieldDimension} fieldDimension
|
||||||
|
* @returns {Promise<qix.NxDimension=>} The result of addDimension.
|
||||||
|
* @description Creates and adds an alternative field dimension.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addAlternativeFieldDimension({ field: 'A', label: 'Label A' });
|
||||||
|
*/
|
||||||
|
addAlternativeFieldDimension(fieldDimension) {
|
||||||
|
const dimension = this.createFieldDimension(fieldDimension);
|
||||||
return this.addDimension(dimension, true);
|
return this.addDimension(dimension, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
addAlternativeLibraryDimension(id, defaults) {
|
/**
|
||||||
const dimension = this.createLibraryDimension(id, defaults);
|
* Adds an alternative library dimension to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryDimension} libraryDimension
|
||||||
|
* @returns {Promise<qix.NxDimension=>} The result of addDimension.
|
||||||
|
* @description Creates and adds an alternative library dimension.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addAlternativeLibraryDimension([{ id: 'A' }, { id: 'B', defaults: { ... } }]);
|
||||||
|
*/
|
||||||
|
addAlternativeLibraryDimension(libraryDimension) {
|
||||||
|
const dimension = this.createLibraryDimension(libraryDimension);
|
||||||
return this.addDimension(dimension, true);
|
return this.addDimension(dimension, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minimum number of dimensions allowed.
|
||||||
|
* @private
|
||||||
|
* @returns {number} The minimum number of dimensions.
|
||||||
|
* @description Returns the minimum number of dimensions allowed by the handler.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* const min = handler.minDimensions();
|
||||||
|
*/
|
||||||
minDimensions() {
|
minDimensions() {
|
||||||
if (typeof this.dimensionDefinition.min === 'function') {
|
if (typeof this.dimensionDefinition.min === 'function') {
|
||||||
return this.dimensionDefinition.min.call(null, this.properties, this);
|
return this.dimensionDefinition.min.call(null, this.properties, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.dimensionDefinition.min || 0;
|
return this.dimensionDefinition.min || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum number of dimensions allowed.
|
||||||
|
* @private
|
||||||
|
* @param {number} [decrement=0] - The number to decrement from the current number of measures.
|
||||||
|
* @returns {number} The maximum number of dimensions allowed.
|
||||||
|
* @description Checks if the max property is a function and calls it with the current number of measures, or returns a default value.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* const max = handler.maxDimensions();
|
||||||
|
*/
|
||||||
maxDimensions(decrement = 0) {
|
maxDimensions(decrement = 0) {
|
||||||
const measureLength = this.getMeasures().length - decrement;
|
const measureLength = this.getMeasures().length - decrement;
|
||||||
|
|
||||||
if (typeof this.dimensionDefinition.max === 'function') {
|
if (typeof this.dimensionDefinition.max === 'function') {
|
||||||
const dimParams = isEnabled('PS_21371_ANALYSIS_TYPES') ? [measureLength, this.properties] : [measureLength];
|
const dimParams = [measureLength];
|
||||||
return this.dimensionDefinition.max?.apply(null, dimParams);
|
return this.dimensionDefinition.max?.apply(null, dimParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Number.isNaN(+this.dimensionDefinition.max) ? 10000 : this.dimensionDefinition.max;
|
return Number.isNaN(+this.dimensionDefinition.max) ? 10000 : this.dimensionDefinition.max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a new dimension can be added.
|
||||||
|
* @private
|
||||||
|
* @returns {boolean} True if a new dimension can be added, false otherwise.
|
||||||
|
* @description Returns whether the handler can add another dimension.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* if (handler.canAddDimension()) { handler.addFieldDimension('A'); }
|
||||||
|
*/
|
||||||
canAddDimension() {
|
canAddDimension() {
|
||||||
return this.getDimensions().length < this.maxDimensions();
|
return this.getDimensions().length < this.maxDimensions();
|
||||||
}
|
}
|
||||||
@@ -187,80 +476,183 @@ class DataPropertyHandler {
|
|||||||
// ----------------MEASURE----------------
|
// ----------------MEASURE----------------
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
|
|
||||||
getMeasure(id) {
|
/**
|
||||||
const measures = this.getMeasures();
|
* @private
|
||||||
const alternativeMeasures = this.getAlternativeMeasures();
|
* @returns {Array} Empty array.
|
||||||
|
* @description Returns the default measure array.
|
||||||
return findFieldById(measures, id) ?? findFieldById(alternativeMeasures, id);
|
* @memberof DataPropertyHandler
|
||||||
}
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
static getMeasures() {
|
getMeasures() {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
static getAlternativeMeasures() {
|
/**
|
||||||
|
* Throws an error indicating the method must be implemented in subclasses.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
getAlternativeMeasures() {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
static addMeasure() {
|
/**
|
||||||
|
* Throws an error indicating addMeasure is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
addMeasure() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static addMeasures() {
|
/**
|
||||||
|
* Throws an error indicating addMeasures is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
addMeasures() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static removeMeasure() {
|
/**
|
||||||
|
* Throws an error indicating removeMeasure is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
removeMeasure() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static removeMeasures() {
|
/**
|
||||||
|
* Throws an error indicating removeMeasures is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
removeMeasures() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static autoSortMeasure() {
|
/**
|
||||||
|
* Throws an error indicating autoSortMeasure is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
autoSortMeasure() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static replaceMeasure() {
|
/**
|
||||||
|
* Throws an error indicating replaceMeasure is not supported in the base class.
|
||||||
|
* @private
|
||||||
|
* @throws {Error}
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
replaceMeasure() {
|
||||||
throw notSupportedError;
|
throw notSupportedError;
|
||||||
}
|
}
|
||||||
|
|
||||||
createExpressionMeasure(expression, label, defaults) {
|
/**
|
||||||
const measure = extend(true, {}, this.measureProperties || {}, defaults || {});
|
* Gets a measure by id from measures or alternative measures.
|
||||||
|
* @private
|
||||||
|
* @param {string} libraryDimension - The measure id to find.
|
||||||
|
* @returns {qix.NxMeasure} The found measure or undefined.
|
||||||
|
* @description Searches for a measure by id in both main and alternative measures.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* const measure = handler.getMeasure('measId');
|
||||||
|
*/
|
||||||
|
getMeasure(libraryDimension) {
|
||||||
|
const measures = this.getMeasures();
|
||||||
|
const alternativeMeasures = this.getAlternativeMeasures();
|
||||||
|
|
||||||
|
return findFieldById(measures, libraryDimension.id) ?? findFieldById(alternativeMeasures, libraryDimension.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an expression measure.
|
||||||
|
* @private
|
||||||
|
* @param {ExpressionMeasure} expressionMeasure
|
||||||
|
* @returns {Promise<qix.NxMeasure=>} The created measure object.
|
||||||
|
* @description Initializes a measure with an expression, label, and default properties.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* const meas = handler.createExpressionMeasure({ expression: 'Sum(Sales)', label: 'Total Sales' });
|
||||||
|
*/
|
||||||
|
createExpressionMeasure(expressionMeasure) {
|
||||||
|
const measure = extend(true, {}, this.measureProperties || {}, expressionMeasure.defaults || {});
|
||||||
|
|
||||||
measure.qDef = measure.qDef ?? {};
|
measure.qDef = measure.qDef ?? {};
|
||||||
measure.qDef.qNumFormat = measure.qDef.qNumFormat ?? {};
|
measure.qDef.qNumFormat = measure.qDef.qNumFormat ?? {};
|
||||||
|
|
||||||
measure.qDef.qDef = expression;
|
measure.qDef.qDef = expressionMeasure.expression;
|
||||||
measure.qDef.qLabel = label;
|
measure.qDef.qLabel = expressionMeasure.label;
|
||||||
measure.qDef.autoSort = true;
|
measure.qDef.autoSort = true;
|
||||||
|
|
||||||
return measure;
|
return measure;
|
||||||
}
|
}
|
||||||
|
|
||||||
addExpressionMeasure(expression, label, defaults) {
|
/**
|
||||||
const measure = this.createExpressionMeasure(expression, label, defaults);
|
* Adds an expression measure to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {ExpressionMeasure} expressionMeasure
|
||||||
|
* @returns {Promise<qix.NxMeasure=>} The result of addMeasure.
|
||||||
|
* @description Creates and adds an expression measure.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addExpressionMeasure({ expression: 'Sum(Sales)', label: 'Total Sales' });
|
||||||
|
*/
|
||||||
|
addExpressionMeasure(expressionMeasure) {
|
||||||
|
const measure = this.createExpressionMeasure(expressionMeasure);
|
||||||
return this.addMeasure(measure);
|
return this.addMeasure(measure);
|
||||||
}
|
}
|
||||||
|
|
||||||
addExpressionMeasures(args) {
|
/**
|
||||||
const measures = args.map(({ expression, label, defaults }) =>
|
* Adds multiple expression measures to the handler.
|
||||||
this.createExpressionMeasure(expression, label, defaults)
|
* @private
|
||||||
);
|
* @param {ExpressionMeasure[]} expressionMeasures - Array of expression measure.
|
||||||
|
* @returns {Promise<qix.NxMeasure[]>} The result of addMeasures.
|
||||||
|
* @description Creates and adds multiple expression measures.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addExpressionMeasures([{ expression: 'Sum(A)' }, { expression: 'Sum(B)', label: 'B' }]);
|
||||||
|
*/
|
||||||
|
addExpressionMeasures(expressionMeasures) {
|
||||||
|
const measures = expressionMeasures.map((expressionMeasure) => this.createExpressionMeasure(expressionMeasure));
|
||||||
return this.addMeasures(measures);
|
return this.addMeasures(measures);
|
||||||
}
|
}
|
||||||
|
|
||||||
createLibraryMeasure(id, defaults) {
|
/**
|
||||||
const measure = extend(true, {}, this.measureProperties || {}, defaults || {});
|
* Creates a library measure.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryMeasure} libraryMeasure
|
||||||
|
* @returns {qix.NxMeasure} The created measure object.
|
||||||
|
* @description Initializes a library measure with default properties.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* const meas = handler.createLibraryMeasure({ id: 'measId', defaults: { qDef: { ... } } });
|
||||||
|
*/
|
||||||
|
createLibraryMeasure(libraryMeasure) {
|
||||||
|
const measure = extend(true, {}, this.measureProperties || {}, libraryMeasure.defaults || {});
|
||||||
|
|
||||||
measure.qDef = measure.qDef ?? {};
|
measure.qDef = measure.qDef ?? {};
|
||||||
measure.qDef.qNumFormat = measure.qDef.qNumFormat ?? {};
|
measure.qDef.qNumFormat = measure.qDef.qNumFormat ?? {};
|
||||||
|
|
||||||
if (isEnabled('MASTER_MEASURE_FORMAT')) {
|
useMasterNumberFormat(measure.qDef);
|
||||||
useMasterNumberFormat(measure.qDef);
|
|
||||||
}
|
|
||||||
|
|
||||||
measure.qLibraryId = id;
|
measure.qLibraryId = libraryMeasure.id;
|
||||||
measure.qDef.autoSort = true;
|
measure.qDef.autoSort = true;
|
||||||
|
|
||||||
delete measure.qDef.qDef;
|
delete measure.qDef.qDef;
|
||||||
@@ -269,36 +661,105 @@ class DataPropertyHandler {
|
|||||||
return measure;
|
return measure;
|
||||||
}
|
}
|
||||||
|
|
||||||
addLibraryMeasure(id, defaults) {
|
/**
|
||||||
const measure = this.createLibraryMeasure(id, defaults);
|
* Adds a library measure to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryMeasure} libraryMeasure
|
||||||
|
* @returns {Promise<qix.NxMeasure=>} The result of addMeasure.
|
||||||
|
* @description Creates and adds a library measure.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addLibraryMeasure({ id: 'measId', defaults: { qDef: { ... } } });
|
||||||
|
*/
|
||||||
|
addLibraryMeasure(libraryMeasure) {
|
||||||
|
const measure = this.createLibraryMeasure(libraryMeasure);
|
||||||
return this.addMeasure(measure);
|
return this.addMeasure(measure);
|
||||||
}
|
}
|
||||||
|
|
||||||
addLibraryMeasures(args) {
|
/**
|
||||||
const measures = args.map(({ id, defaults }) => this.createLibraryMeasure(id, defaults));
|
* Adds multiple library measures to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryMeasure[]} libraryMeasures - Array of library measure.
|
||||||
|
* @returns {Promise<qix.NxMeasure[]>} The result of addMeasures.
|
||||||
|
* @description Creates and adds multiple library measures.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addLibraryMeasures([{ id: 'A' }, { id: 'B', defaults: { qDef: { ... } } }]);
|
||||||
|
*/
|
||||||
|
addLibraryMeasures(libraryMeasures) {
|
||||||
|
const measures = libraryMeasures.map((libraryMeasure) => this.createLibraryMeasure(libraryMeasure));
|
||||||
return this.addMeasures(measures);
|
return this.addMeasures(measures);
|
||||||
}
|
}
|
||||||
|
|
||||||
addAltLibraryMeasures(args) {
|
/**
|
||||||
const measures = args.map(({ id }) => this.createLibraryMeasure(id));
|
* Adds multiple alternative library measures to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryMeasure[]} libraryMeasures - Array of library measure.
|
||||||
|
* @returns {Promise<qix.NxMeasure[]>} The result of addMeasures.
|
||||||
|
* @description Creates and adds multiple alternative library measures.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addAltLibraryMeasures([{ id: 'A' }, { id: 'B' }]);
|
||||||
|
*/
|
||||||
|
addAltLibraryMeasures(libraryMeasures) {
|
||||||
|
const measures = libraryMeasures.map((libraryMeasure) => this.createLibraryMeasure(libraryMeasure));
|
||||||
return this.addMeasures(measures, true);
|
return this.addMeasures(measures, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
addAltExpressionMeasures(args) {
|
/**
|
||||||
const measures = args.map(({ expression }) => this.createExpressionMeasure(expression));
|
* Adds multiple alternative expression measures to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {ExpressionMeasure[]} expressionMeasures - Array of expression measure.
|
||||||
|
* @returns {Promise<qix.NxMeasure[]>} The result of addMeasures.
|
||||||
|
* @description Creates and adds multiple alternative expression measures.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addAltExpressionMeasures([{ expression: 'Sum(A)' }, { expression: 'Sum(B)' }]);
|
||||||
|
*/
|
||||||
|
addAltExpressionMeasures(libraryMeasures) {
|
||||||
|
const measures = libraryMeasures.map((expressionMeasure) => this.createExpressionMeasure(expressionMeasure));
|
||||||
return this.addMeasures(measures, true);
|
return this.addMeasures(measures, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
addAlternativeExpressionMeasure(expression, label, defaults) {
|
/**
|
||||||
const measure = this.createExpressionMeasure(expression, label, defaults);
|
* Adds an alternative expression measure to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {ExpressionMeasure} expressionMeasure
|
||||||
|
* @returns {Promise<qix.NxMeasure=>} The result of addMeasure.
|
||||||
|
* @description Creates and adds an alternative expression measure.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addAlternativeExpressionMeasure({ expression: 'Sum(Sales)', label: 'Total Sales'});
|
||||||
|
*/
|
||||||
|
addAlternativeExpressionMeasure(expressionMeasure) {
|
||||||
|
const measure = this.createExpressionMeasure(expressionMeasure);
|
||||||
return this.addMeasure(measure, true);
|
return this.addMeasure(measure, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
addAlternativeLibraryMeasure(id, defaults) {
|
/**
|
||||||
const measure = this.createLibraryMeasure(id, defaults);
|
* Adds an alternative library measure to the handler.
|
||||||
|
* @private
|
||||||
|
* @param {LibraryMeasure} libraryMeasure
|
||||||
|
* @returns {qix.NxMeasure=} The result of addMeasure.
|
||||||
|
* @description Creates and adds an alternative library measure.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.addAlternativeLibraryMeasure({ id: 'measId', defaults: { qDef: { ... } } });
|
||||||
|
*/
|
||||||
|
addAlternativeLibraryMeasure(libraryMeasure) {
|
||||||
|
const measure = this.createLibraryMeasure(libraryMeasure);
|
||||||
return this.addMeasure(measure, true);
|
return this.addMeasure(measure, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minimum number of measures allowed.
|
||||||
|
* @private
|
||||||
|
* @returns {number} The minimum number of measures.
|
||||||
|
* @description Returns the minimum number of measures allowed by the handler.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* const min = handler.minMeasures();
|
||||||
|
*/
|
||||||
minMeasures() {
|
minMeasures() {
|
||||||
if (typeof this.measureDefinition.min === 'function') {
|
if (typeof this.measureDefinition.min === 'function') {
|
||||||
return this.measureDefinition.min.call(null, this.properties, this);
|
return this.measureDefinition.min.call(null, this.properties, this);
|
||||||
@@ -306,24 +767,51 @@ class DataPropertyHandler {
|
|||||||
return this.measureDefinition.min || 0;
|
return this.measureDefinition.min || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the maximum number of measures allowed.
|
||||||
|
* @private
|
||||||
|
* @param {number} [decrement=0] - The number to decrement from the current number of dimensions.
|
||||||
|
* @returns {number} The maximum number of measures allowed.
|
||||||
|
* @description Checks if the max property is a function and calls it with the current number of dimensions, or returns a default value.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* const max = handler.maxMeasures();
|
||||||
|
*/
|
||||||
maxMeasures(decrement = 0) {
|
maxMeasures(decrement = 0) {
|
||||||
if (typeof this.measureDefinition.max === 'function') {
|
if (typeof this.measureDefinition.max === 'function') {
|
||||||
const dimLength = this.getDimensions().length - decrement;
|
const dimLength = this.getDimensions().length - decrement;
|
||||||
const measureParams = isEnabled('PS_21371_ANALYSIS_TYPES') ? [dimLength, this.properties] : [dimLength];
|
const measureParams = [dimLength];
|
||||||
return this.measureDefinition.max.apply(null, measureParams);
|
return this.measureDefinition.max.apply(null, measureParams);
|
||||||
}
|
}
|
||||||
return Number.isNaN(+this.measureDefinition.max) ? 10000 : this.measureDefinition.max;
|
return Number.isNaN(+this.measureDefinition.max) ? 10000 : this.measureDefinition.max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a new measure can be added.
|
||||||
|
* @private
|
||||||
|
* @returns {boolean} True if a new measure can be added, false otherwise.
|
||||||
|
* @description Returns whether the handler can add another measure.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* if (handler.canAddMeasure()) { handler.addExpressionMeasure('Sum(A)'); }
|
||||||
|
*/
|
||||||
canAddMeasure() {
|
canAddMeasure() {
|
||||||
return this.getMeasures().length < this.maxMeasures();
|
return this.getMeasures().length < this.maxMeasures();
|
||||||
// return this.getMeasures().length < 10000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
// ---------------OTHERS------------------
|
// ---------------OTHERS------------------
|
||||||
// ---------------------------------------
|
// ---------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls all global change listeners with the current properties, handler, and layout.
|
||||||
|
* @private
|
||||||
|
* @param {object} layout - The layout object to pass to listeners.
|
||||||
|
* @description Invokes all registered global change listeners.
|
||||||
|
* @memberof DataPropertyHandler
|
||||||
|
* @example
|
||||||
|
* handler.updateGlobalChangeListeners(layoutObj);
|
||||||
|
*/
|
||||||
updateGlobalChangeListeners(layout) {
|
updateGlobalChangeListeners(layout) {
|
||||||
if (this.globalChangeListeners) {
|
if (this.globalChangeListeners) {
|
||||||
(this.globalChangeListeners || []).forEach((func) => {
|
(this.globalChangeListeners || []).forEach((func) => {
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
// eslint-disable-next-line import/no-relative-packages
|
import { utils, arrayUtil } from '@nebula.js/conversion';
|
||||||
import utils from '../../../conversion/src/utils';
|
|
||||||
import DataPropertyHandler from './data-property-handler';
|
import DataPropertyHandler from './data-property-handler';
|
||||||
import * as hcUtils from './utils/hypercube-helper/hypercube-utils';
|
import * as hcUtils from './utils/hypercube-helper/hypercube-utils';
|
||||||
import getAutoSortLibraryDimension from './utils/field-helper/get-sorted-library-field';
|
import getAutoSortLibraryDimension from './utils/field-helper/get-sorted-library-field';
|
||||||
import getAutoSortFieldDimension from './utils/field-helper/get-sorted-field';
|
import getAutoSortDimension from './utils/field-helper/get-sorted-field';
|
||||||
import { initializeField, initializeId } from './utils/field-helper/field-utils';
|
import { initializeDim, initializeId } from './utils/field-helper/field-utils';
|
||||||
import addMainDimension from './utils/hypercube-helper/add-main-dimension';
|
import addMainDimension from './utils/hypercube-helper/add-main-dimension';
|
||||||
import addMainMeasure from './utils/hypercube-helper/add-main-measure';
|
import addMainMeasure from './utils/hypercube-helper/add-main-measure';
|
||||||
import removeMainDimension from './utils/hypercube-helper/remove-main-dimension';
|
import removeMainDimension from './utils/hypercube-helper/remove-main-dimension';
|
||||||
@@ -13,18 +12,55 @@ import removeMainMeasure from './utils/hypercube-helper/remove-main-measure';
|
|||||||
import removeAlternativeDimension from './utils/hypercube-helper/remove-alternative-dimension';
|
import removeAlternativeDimension from './utils/hypercube-helper/remove-alternative-dimension';
|
||||||
import reinsertMainDimension from './utils/hypercube-helper/reinsert-main-dimension';
|
import reinsertMainDimension from './utils/hypercube-helper/reinsert-main-dimension';
|
||||||
import reinsertMainMeasure from './utils/hypercube-helper/reinsert-main-measure';
|
import reinsertMainMeasure from './utils/hypercube-helper/reinsert-main-measure';
|
||||||
// eslint-disable-next-line import/no-relative-packages
|
|
||||||
import arrayUtil from '../../../conversion/src/array-util';
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HyperCubeHandler for managing hypercube data structure.
|
||||||
|
* @private
|
||||||
|
* @class HyperCubeHandler
|
||||||
|
* @description This class provides methods to handle hypercube properties, dimensions, and measures.
|
||||||
|
* @param {object} opts Parameters to add a hypercube handlers
|
||||||
|
* @param {qix.Doc} opts.app
|
||||||
|
* @param {object} opts.dimensionDefinition
|
||||||
|
* @param {object} opts.measureDefinition
|
||||||
|
* @param {object} opts.dimensionProperties
|
||||||
|
* @param {object} opts.measureProperties
|
||||||
|
* @param {object} opts.globalChangeListeners
|
||||||
|
* @param {object} opts.path
|
||||||
|
* @entry
|
||||||
|
* @export
|
||||||
|
* @example
|
||||||
|
* import { HyperCubeHandler } from '@nebula.js/stardust';
|
||||||
|
*
|
||||||
|
* class PivotHyperCubeHandler extends HyperCubeHandler {
|
||||||
|
*
|
||||||
|
* adjustPseudoDimOrder: (pseudoIdx?: number) => {
|
||||||
|
* const numberOfDims = this.getDimensions().length;
|
||||||
|
* const interColumnSortOrder = this.hcProperties.qInterColumnSortOrder;
|
||||||
|
*
|
||||||
|
* if (!interColumnSortOrder) {
|
||||||
|
* return;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* interColumnSortOrder.splice(pseudoIdx || 0, 1);
|
||||||
|
* interColumnSortOrder.push(numberOfDims);
|
||||||
|
* interColumnSortOrder.splice((pseudoIdx || -1) + 1, 0, -1);
|
||||||
|
* };
|
||||||
|
* }
|
||||||
|
*/
|
||||||
class HyperCubeHandler extends DataPropertyHandler {
|
class HyperCubeHandler extends DataPropertyHandler {
|
||||||
constructor(opts) {
|
constructor(opts) {
|
||||||
super(opts);
|
super(opts);
|
||||||
this.path = opts.path;
|
this.path = opts.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {object=} properties
|
||||||
|
* @returns early return if properties is falsy
|
||||||
|
*/
|
||||||
setProperties(properties) {
|
setProperties(properties) {
|
||||||
if (!properties) {
|
if (!properties) {
|
||||||
return {};
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.setProperties(properties);
|
super.setProperties(properties);
|
||||||
@@ -32,7 +68,7 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
this.hcProperties = this.path ? utils.getValue(properties, `${this.path}.qHyperCubeDef`) : properties.qHyperCubeDef;
|
this.hcProperties = this.path ? utils.getValue(properties, `${this.path}.qHyperCubeDef`) : properties.qHyperCubeDef;
|
||||||
|
|
||||||
if (!this.hcProperties) {
|
if (!this.hcProperties) {
|
||||||
return {};
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hcUtils.setDefaultProperties(this);
|
hcUtils.setDefaultProperties(this);
|
||||||
@@ -41,32 +77,76 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
// Set auto-sort property (compatibility 0.85 -> 0.9), can probably be removed in 1.0
|
// Set auto-sort property (compatibility 0.85 -> 0.9), can probably be removed in 1.0
|
||||||
this.hcProperties.qDimensions = hcUtils.setFieldProperties(this.hcProperties.qDimensions);
|
this.hcProperties.qDimensions = hcUtils.setFieldProperties(this.hcProperties.qDimensions);
|
||||||
this.hcProperties.qMeasures = hcUtils.setFieldProperties(this.hcProperties.qMeasures);
|
this.hcProperties.qMeasures = hcUtils.setFieldProperties(this.hcProperties.qMeasures);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// ----------- DIMENSIONS -----------
|
// ----------- DIMENSIONS -----------
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {qix.NxDimension[]} dimensions
|
||||||
|
* @description Returns the dimensions of the hypercube.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const dimensions = hyperCubeHandler.getDimensions();
|
||||||
|
*/
|
||||||
getDimensions() {
|
getDimensions() {
|
||||||
return this.hcProperties ? this.hcProperties.qDimensions : [];
|
return this.hcProperties ? this.hcProperties.qDimensions : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {qix.NxDimension[]} alternative dimensions
|
||||||
|
* @description Returns the alternative dimensions of the hypercube.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const alternativeDimensions = hyperCubeHandler.getAlternativeDimensions();
|
||||||
|
*/
|
||||||
getAlternativeDimensions() {
|
getAlternativeDimensions() {
|
||||||
return this.hcProperties?.qLayoutExclude?.qHyperCubeDef?.qDimensions ?? [];
|
return this.hcProperties?.qLayoutExclude?.qHyperCubeDef?.qDimensions ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {string} cId
|
||||||
|
* @returns {qix.NxDimensionInfo} dimension layout
|
||||||
|
* @description Returns the dimension layout of the hypercube for a given cId.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const dimensionLayout = hyperCubeHandler.getDimensionLayout(cId);
|
||||||
|
*/
|
||||||
getDimensionLayout(cId) {
|
getDimensionLayout(cId) {
|
||||||
return this.getDimensionLayouts().filter((item) => cId === item.cId)[0];
|
return this.getDimensionLayouts().filter((item) => cId === item.cId)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {qix.NxDimensionInfo[]} dimension layouts
|
||||||
|
* @description Returns the dimension layouts of the hypercube.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const dimensionLayouts = hyperCubeHandler.getDimensionLayouts();
|
||||||
|
*/
|
||||||
getDimensionLayouts() {
|
getDimensionLayouts() {
|
||||||
const hc = hcUtils.getHyperCube(this.layout, this.path);
|
const hc = hcUtils.getHyperCube(this.layout, this.path);
|
||||||
return hc ? hc.qDimensionInfo : [];
|
return hc ? hc.qDimensionInfo : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {qix.NxDimension} dimension
|
||||||
|
* @param {boolean} alternative
|
||||||
|
* @param {number=} idx
|
||||||
|
* @returns {qix.NxDimension} dimension
|
||||||
|
* @description Adds a dimension to the hypercube and updates the orders of the dimensions.
|
||||||
|
* If the dimension is an alternative, it will be added to the alternative dimensions.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const dimension = hyperCubeHandler.addDimension(dimension, alternative, idx);
|
||||||
|
*/
|
||||||
addDimension(dimension, alternative, idx) {
|
addDimension(dimension, alternative, idx) {
|
||||||
const dim = initializeField(dimension);
|
const dim = initializeDim(dimension);
|
||||||
|
|
||||||
if (hcUtils.isDimensionAlternative(this, alternative)) {
|
if (hcUtils.isDimensionAlternative(this, alternative)) {
|
||||||
return hcUtils.addAlternativeDimension(this, dim, idx);
|
return hcUtils.addAlternativeDimension(this, dim, idx);
|
||||||
@@ -75,6 +155,18 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
return addMainDimension(this, dim, idx);
|
return addMainDimension(this, dim, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {qix.NxDimension[]} dimensions
|
||||||
|
* @param {boolean} alternative
|
||||||
|
* @returns {qix.NxDimension[]} added dimensions
|
||||||
|
* @description Adds multiple dimensions to the hypercube.
|
||||||
|
* If the dimensions are alternatives, they will be added to the alternative dimensions.
|
||||||
|
* If the total number of dimensions exceeds the limit, it will stop adding dimensions.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const addedDimensions = await hyperCubeHandler.addDimensions(dimensions, alternative);
|
||||||
|
*/
|
||||||
async addDimensions(dimensions, alternative = false) {
|
async addDimensions(dimensions, alternative = false) {
|
||||||
const existingDimensions = this.getDimensions();
|
const existingDimensions = this.getDimensions();
|
||||||
const initialLength = existingDimensions.length;
|
const initialLength = existingDimensions.length;
|
||||||
@@ -87,7 +179,7 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
return addedDimensions;
|
return addedDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
const dim = initializeField(dimension);
|
const dim = initializeDim(dimension);
|
||||||
|
|
||||||
if (hcUtils.isDimensionAlternative(this, alternative)) {
|
if (hcUtils.isDimensionAlternative(this, alternative)) {
|
||||||
const altDim = await hcUtils.addAlternativeDimension(this, dim);
|
const altDim = await hcUtils.addAlternativeDimension(this, dim);
|
||||||
@@ -101,6 +193,16 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
return addedDimensions;
|
return addedDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {number} idx
|
||||||
|
* @param {boolean} alternative
|
||||||
|
* @description Removes a dimension from the hypercube by index.
|
||||||
|
* If the dimension is an alternative, it will be removed from the alternative dimensions.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* hyperCubeHandler.removeDimension(idx, alternative);
|
||||||
|
*/
|
||||||
removeDimension(idx, alternative) {
|
removeDimension(idx, alternative) {
|
||||||
if (alternative) {
|
if (alternative) {
|
||||||
removeAlternativeDimension(this, idx);
|
removeAlternativeDimension(this, idx);
|
||||||
@@ -109,6 +211,18 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
removeMainDimension(this, idx);
|
removeMainDimension(this, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {number[]} indexes
|
||||||
|
* @param {boolean} alternative
|
||||||
|
* @returns {qix.NxDimension[]} deleted dimensions
|
||||||
|
* @description Removes multiple dimensions from the hypercube by indexes.
|
||||||
|
* If the dimensions are alternatives, they will be removed from the alternative dimensions.
|
||||||
|
* If the indexes are empty, it will return an empty array.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const deletedDimensions = await hyperCubeHandler.removeDimensions(indexes, alternative);
|
||||||
|
*/
|
||||||
async removeDimensions(indexes, alternative) {
|
async removeDimensions(indexes, alternative) {
|
||||||
const altDimensions = this.getAlternativeDimensions();
|
const altDimensions = this.getAlternativeDimensions();
|
||||||
const dimensions = this.getDimensions();
|
const dimensions = this.getDimensions();
|
||||||
@@ -137,10 +251,31 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
return deletedDimensions;
|
return deletedDimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces a dimension in the hypercube.
|
||||||
|
* @private
|
||||||
|
* @param {number} index - The index of the dimension to replace.
|
||||||
|
* @param {qix.NxDimension} dimension - The new dimension to replace the old one.
|
||||||
|
* @returns {Promise<qix.NxDimension>} replaced dimension.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const replacedDimension = await hyperCubeHandler.replaceDimension(index, newDimension);
|
||||||
|
*/
|
||||||
replaceDimension(index, dimension) {
|
replaceDimension(index, dimension) {
|
||||||
return this.autoSortDimension(dimension).then(() => hcUtils.replaceDimensionOrder(this, index, dimension));
|
return this.autoSortDimension(dimension).then(() => hcUtils.replaceDimensionOrder(this, index, dimension));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reinserts a dimension into the hypercube.
|
||||||
|
* @private
|
||||||
|
* @param {qix.NxDimension} dimension - The dimension to reinsert.
|
||||||
|
* @param {boolean} alternative - Whether the dimension is an alternative.
|
||||||
|
* @param {number} idx - The index to insert the dimension at.
|
||||||
|
* @returns {Promise<qix.NxDimension>} The reinserted dimension.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* await hyperCubeHandler.reinsertDimension(dimension, alternative, idx);
|
||||||
|
*/
|
||||||
reinsertDimension(dimension, alternative, idx) {
|
reinsertDimension(dimension, alternative, idx) {
|
||||||
const dim = initializeId(dimension);
|
const dim = initializeId(dimension);
|
||||||
|
|
||||||
@@ -153,19 +288,26 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
return reinsertMainDimension(this, dim, idx);
|
return reinsertMainDimension(this, dim, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves a dimension within the hypercube.
|
||||||
|
* @private
|
||||||
|
* @param {number} fromIndex - The current index of the dimension.
|
||||||
|
* @param {number} toIndex - The new index of the dimension.
|
||||||
|
* @returns {Promise<qix.NxDimension[]>} updated dimensions.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* await hyperCubeHandler.moveDimension(fromIndex, toIndex);
|
||||||
|
*/
|
||||||
moveDimension(fromIndex, toIndex) {
|
moveDimension(fromIndex, toIndex) {
|
||||||
const dimensions = this.getDimensions();
|
const dimensions = this.getDimensions();
|
||||||
const altDimensions = this.getAlternativeDimensions();
|
const altDimensions = this.getAlternativeDimensions();
|
||||||
|
|
||||||
if (fromIndex < dimensions.length && toIndex < dimensions.length) {
|
if (fromIndex < dimensions.length && toIndex < dimensions.length) {
|
||||||
// Move within main dimensions
|
|
||||||
return Promise.resolve(arrayUtil.move(dimensions, fromIndex, toIndex));
|
return Promise.resolve(arrayUtil.move(dimensions, fromIndex, toIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromIndex < dimensions.length && toIndex >= dimensions.length) {
|
if (fromIndex < dimensions.length && toIndex >= dimensions.length) {
|
||||||
return hcUtils.moveDimensionFromMainToAlternative(fromIndex, toIndex, dimensions, altDimensions);
|
return hcUtils.moveDimensionFromMainToAlternative(fromIndex, toIndex, dimensions, altDimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromIndex >= dimensions.length && toIndex < dimensions.length) {
|
if (fromIndex >= dimensions.length && toIndex < dimensions.length) {
|
||||||
return Promise.resolve(hcUtils.moveMeasureFromAlternativeToMain(fromIndex, toIndex, dimensions, altDimensions));
|
return Promise.resolve(hcUtils.moveMeasureFromAlternativeToMain(fromIndex, toIndex, dimensions, altDimensions));
|
||||||
}
|
}
|
||||||
@@ -173,45 +315,112 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
return Promise.resolve(hcUtils.moveDimensionWithinAlternative(fromIndex, toIndex, dimensions, altDimensions));
|
return Promise.resolve(hcUtils.moveDimensionWithinAlternative(fromIndex, toIndex, dimensions, altDimensions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {qix.NxDimension} dimension
|
||||||
|
* @returns {qix.NxDimension} dimension with auto-sort properties
|
||||||
|
* @description Automatically sorts the dimension based on its properties.
|
||||||
|
* If the dimension has a qLibraryId, it will use the library dimension auto-sort.
|
||||||
|
* Otherwise, it will use the field dimension auto-sort.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const sortedDimension = hyperCubeHandler.autoSortDimension(dimension);
|
||||||
|
*/
|
||||||
autoSortDimension(dimension) {
|
autoSortDimension(dimension) {
|
||||||
if (dimension.qLibraryId) {
|
if (dimension.qLibraryId) {
|
||||||
return getAutoSortLibraryDimension(this, dimension);
|
return getAutoSortLibraryDimension(this, dimension);
|
||||||
}
|
}
|
||||||
return getAutoSortFieldDimension(this, dimension);
|
return getAutoSortDimension(this, dimension);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// ------------ MEASURES ------------
|
// ------------ MEASURES ------------
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {qix.NxMeasure[]} measures
|
||||||
|
* @description Returns the measures of the hypercube.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const measures = hyperCubeHandler.getMeasures();
|
||||||
|
*/
|
||||||
getMeasures() {
|
getMeasures() {
|
||||||
return this.hcProperties ? this.hcProperties.qMeasures : [];
|
return this.hcProperties ? this.hcProperties.qMeasures : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {qix.NxMeasure[]} alternative measures
|
||||||
|
* @description Returns the alternative measures of the hypercube.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const alternativeMeasures = hyperCubeHandler.getAlternativeMeasures();
|
||||||
|
*/
|
||||||
getAlternativeMeasures() {
|
getAlternativeMeasures() {
|
||||||
return this.hcProperties?.qLayoutExclude?.qHyperCubeDef?.qMeasures ?? [];
|
return this.hcProperties?.qLayoutExclude?.qHyperCubeDef?.qMeasures ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {qix.NxMeasureInfo[]} measure layouts
|
||||||
|
* @description Returns the measure layouts of the hypercube.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const measureLayouts = hyperCubeHandler.getMeasureLayouts();
|
||||||
|
*/
|
||||||
getMeasureLayouts() {
|
getMeasureLayouts() {
|
||||||
const hc = hcUtils.getHyperCube(this.layout, this.path);
|
const hc = hcUtils.getHyperCube(this.layout, this.path);
|
||||||
return hc ? hc.qMeasureInfo : [];
|
return hc ? hc.qMeasureInfo : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {string} cId
|
||||||
|
* @returns {object} measure layout
|
||||||
|
* @description Returns the measure layout of the hypercube for a given cId.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const measureLayout = hyperCubeHandler.getMeasureLayout(cId);
|
||||||
|
*/
|
||||||
getMeasureLayout(cId) {
|
getMeasureLayout(cId) {
|
||||||
return this.getMeasureLayouts().filter((item) => cId === item.cId)[0];
|
return this.getMeasureLayouts().filter((item) => cId === item.cId)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {qix.NxMeasure} measure
|
||||||
|
* @param {boolean} alternative
|
||||||
|
* @param {number=} idx
|
||||||
|
* @returns {Promise<qix.NxMeasure>} measure
|
||||||
|
* @description Adds a measure to the hypercube.
|
||||||
|
* If the measure is an alternative, it will be added to the alternative measures.
|
||||||
|
* If the total number of measures exceeds the limit, it will stop adding measures.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const measure = hyperCubeHandler.addMeasure(measure, alternative, idx);
|
||||||
|
*/
|
||||||
addMeasure(measure, alternative, idx) {
|
addMeasure(measure, alternative, idx) {
|
||||||
const measures = this.getAlternativeMeasure();
|
|
||||||
const meas = initializeId(measure);
|
const meas = initializeId(measure);
|
||||||
|
|
||||||
if (hcUtils.isMeasureAlternative(this, measures, alternative)) {
|
if (hcUtils.isMeasureAlternative(this, alternative)) {
|
||||||
return hcUtils.addAlternativeMeasure(this, meas, idx);
|
const hcMeasures = this.hcProperties.qLayoutExclude.qHyperCubeDef.qMeasures;
|
||||||
|
return hcUtils.addAlternativeMeasure(meas, hcMeasures, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return addMainMeasure(this, meas, idx);
|
return addMainMeasure(this, meas, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {qix.NxMeasure} measure
|
||||||
|
* @returns {Promise<qix.NxMeasure>} measure with auto-sort properties
|
||||||
|
* @description Automatically sorts the measure based on its properties.
|
||||||
|
* It sets the qSortByLoadOrder and qSortByNumeric properties.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const sortedMeasure = hyperCubeHandler.autoSortMeasure(measure);
|
||||||
|
*/
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
autoSortMeasure(measure) {
|
autoSortMeasure(measure) {
|
||||||
const meas = measure;
|
const meas = measure;
|
||||||
@@ -222,6 +431,18 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
return Promise.resolve(meas);
|
return Promise.resolve(meas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {qix.NxMeasure[]} measures
|
||||||
|
* @param {boolean} alternative
|
||||||
|
* @returns {qix.NxMeasure[]} added measures
|
||||||
|
* @description Adds multiple measures to the hypercube.
|
||||||
|
* If the measures are alternatives, they will be added to the alternative measures.
|
||||||
|
* If the total number of measures exceeds the limit, it will stop adding measures.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const addedMeasures = await hyperCubeHandler.addMeasures(measures, alternative);
|
||||||
|
*/
|
||||||
addMeasures(measures, alternative = false) {
|
addMeasures(measures, alternative = false) {
|
||||||
const existingMeasures = this.getMeasures();
|
const existingMeasures = this.getMeasures();
|
||||||
const addedMeasures = [];
|
const addedMeasures = [];
|
||||||
@@ -234,7 +455,7 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
|
|
||||||
const meas = initializeId(measure);
|
const meas = initializeId(measure);
|
||||||
|
|
||||||
if (hcUtils.isMeasureAlternative(this, existingMeasures, alternative)) {
|
if (hcUtils.isMeasureAlternative(this, alternative)) {
|
||||||
hcUtils.addAlternativeMeasure(this, meas);
|
hcUtils.addAlternativeMeasure(this, meas);
|
||||||
addedMeasures.push(meas);
|
addedMeasures.push(meas);
|
||||||
} else if (existingMeasures.length < this.maxMeasures()) {
|
} else if (existingMeasures.length < this.maxMeasures()) {
|
||||||
@@ -246,6 +467,16 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
return addedMeasures;
|
return addedMeasures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {number} idx
|
||||||
|
* @param {boolean} alternative
|
||||||
|
* @description Removes a measure from the hypercube by index.
|
||||||
|
* If the measure is an alternative, it will be removed from the alternative measures.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* hyperCubeHandler.removeMeasure(idx, alternative);
|
||||||
|
*/
|
||||||
removeMeasure(idx, alternative) {
|
removeMeasure(idx, alternative) {
|
||||||
if (alternative) {
|
if (alternative) {
|
||||||
hcUtils.removeAltMeasureByIndex(this, idx);
|
hcUtils.removeAltMeasureByIndex(this, idx);
|
||||||
@@ -253,13 +484,25 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
removeMainMeasure(this, idx);
|
removeMainMeasure(this, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {number[]} indexes
|
||||||
|
* @param {boolean} alternative
|
||||||
|
* @returns {Promise<number[]>} deleted measures
|
||||||
|
* @description Removes multiple measures from the hypercube by indexes.
|
||||||
|
* If the measures are alternatives, they will be removed from the alternative measures.
|
||||||
|
* If the indexes are empty, it will return an empty array.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const deletedMeasures = await hyperCubeHandler.removeMeasures(indexes, alternative);
|
||||||
|
*/
|
||||||
async removeMeasures(indexes, alternative) {
|
async removeMeasures(indexes, alternative) {
|
||||||
const measures = this.getMeasures();
|
const measures = this.getMeasures();
|
||||||
const altMeasures = this.getAlternativeMeasures();
|
const altMeasures = this.getAlternativeMeasures();
|
||||||
|
|
||||||
if (indexes.length === 0) return [];
|
|
||||||
let deletedMeasures = [];
|
let deletedMeasures = [];
|
||||||
|
|
||||||
|
if (indexes.length === 0) return deletedMeasures;
|
||||||
|
|
||||||
if (alternative && altMeasures.length > 0) {
|
if (alternative && altMeasures.length > 0) {
|
||||||
// Keep the original deleted order
|
// Keep the original deleted order
|
||||||
deletedMeasures = hcUtils.getDeletedFields(altMeasures, indexes);
|
deletedMeasures = hcUtils.getDeletedFields(altMeasures, indexes);
|
||||||
@@ -278,21 +521,52 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
return deletedMeasures;
|
return deletedMeasures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {number} index
|
||||||
|
* @param {qix.NxMeasure} measure
|
||||||
|
* @returns {Promise<qix.NxMeasure>} replaced measure
|
||||||
|
* @description Replaces a measure in the hypercube.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const updatedMeasure = await hyperCubeHandler.replaceMeasure(index, measure);
|
||||||
|
*/
|
||||||
replaceMeasure(index, measure) {
|
replaceMeasure(index, measure) {
|
||||||
return this.autoSortMeasure(measure).then(() => hcUtils.replaceMeasureToColumnOrder(this, index, measure));
|
return this.autoSortMeasure(measure).then(() => hcUtils.replaceMeasureToColumnOrder(this, index, measure));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {qix.NxMeasure} measure
|
||||||
|
* @param {boolean} alternative
|
||||||
|
* @param {number} idx
|
||||||
|
* @returns {Promise<qix.NxMeasure>} reinserted measure
|
||||||
|
* @description Reinserts a measure into the hypercube.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const reinsertedMeasure = await hyperCubeHandler.reinsertMeasure(measure, alternative, idx);
|
||||||
|
*/
|
||||||
reinsertMeasure(measure, alternative, idx) {
|
reinsertMeasure(measure, alternative, idx) {
|
||||||
const measures = this.getAlternativeMeasures();
|
|
||||||
const meas = initializeId(measure);
|
const meas = initializeId(measure);
|
||||||
|
|
||||||
if (hcUtils.isMeasureAlternative(this, measures, alternative)) {
|
if (hcUtils.isMeasureAlternative(this, alternative)) {
|
||||||
return hcUtils.addAlternativeMeasure(this, meas, idx);
|
return hcUtils.addAlternativeMeasure(this, meas, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return reinsertMainMeasure(this, meas, idx);
|
return reinsertMainMeasure(this, meas, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves a measure within the hypercube.
|
||||||
|
* @private
|
||||||
|
* @param {number} fromIndex
|
||||||
|
* @param {number} toIndex
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
* @description Move measure from one index to another
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const result = await hyperCubeHandler.moveMeasure(0, 1);
|
||||||
|
*/
|
||||||
moveMeasure(fromIndex, toIndex) {
|
moveMeasure(fromIndex, toIndex) {
|
||||||
const measures = this.getMeasures();
|
const measures = this.getMeasures();
|
||||||
const altMeasures = this.getAlternativeMeasures();
|
const altMeasures = this.getAlternativeMeasures();
|
||||||
@@ -317,31 +591,74 @@ class HyperCubeHandler extends DataPropertyHandler {
|
|||||||
// ------------ OTHERS---- ----------
|
// ------------ OTHERS---- ----------
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
||||||
setSorting(ar) {
|
/**
|
||||||
if (ar && ar.length === this.hcProperties.qInterColumnSortOrder.length) {
|
* Sets the sorting order for the hypercube.
|
||||||
this.hcProperties.qInterColumnSortOrder = ar;
|
* @private
|
||||||
|
* @param {number[]} arr - The new sorting order.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const newSortingOrder = [2, 0, 1];
|
||||||
|
* hyperCubeHandler.setSorting(newSortingOrder);
|
||||||
|
*/
|
||||||
|
setSorting(arr) {
|
||||||
|
if (arr && arr.length === this.hcProperties.qInterColumnSortOrder.length) {
|
||||||
|
this.hcProperties.qInterColumnSortOrder = arr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the sorting order for the hypercube.
|
||||||
|
* @private
|
||||||
|
* @returns {number[]} The current sorting order.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const currentSortingOrder = hyperCubeHandler.getSorting();
|
||||||
|
*/
|
||||||
getSorting() {
|
getSorting() {
|
||||||
return this.hcProperties.qInterColumnSortOrder;
|
return this.hcProperties.qInterColumnSortOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the sorting order for the hypercube.
|
||||||
|
* @private
|
||||||
|
* @param {number} fromIdx - The index to move from.
|
||||||
|
* @param {number} toIdx - The index to move to.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
* @example
|
||||||
|
* const newSortingOrder = hyperCubeHandler.changeSorting(0, 1);
|
||||||
|
*/
|
||||||
changeSorting(fromIdx, toIdx) {
|
changeSorting(fromIdx, toIdx) {
|
||||||
utils.move(this.hcProperties.qInterColumnSortOrder, fromIdx, toIdx);
|
utils.move(this.hcProperties.qInterColumnSortOrder, fromIdx, toIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the hypercube is in straight mode or pivot mode.
|
||||||
|
* @private
|
||||||
|
* @returns {string} 'S' for straight mode, 'P' for pivot mode
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
*/
|
||||||
IsHCInStraightMode() {
|
IsHCInStraightMode() {
|
||||||
return this.hcProperties.qMode === 'S';
|
return this.hcProperties.qMode === 'S';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {boolean} value
|
||||||
|
* @description This flag indicates whether we enabled HC modifier and have at least one script
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
*/
|
||||||
setHCEnabled(value) {
|
setHCEnabled(value) {
|
||||||
// this flag indicate whether we enabled HC modifier and have at least one script
|
|
||||||
if (this.hcProperties) {
|
if (this.hcProperties) {
|
||||||
this.hcProperties.isHCEnabled = value;
|
this.hcProperties.isHCEnabled = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the dynamic scripts for the hypercube.
|
||||||
|
* @private
|
||||||
|
* @returns {Array} The dynamic scripts.
|
||||||
|
* @memberof HyperCubeHandler
|
||||||
|
*/
|
||||||
getDynamicScripts() {
|
getDynamicScripts() {
|
||||||
return this.hcProperties?.qDynamicScript || [];
|
return this.hcProperties?.qDynamicScript || [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,3 +12,16 @@ export const INITIAL_SORT_CRITERIAS = [
|
|||||||
qSortByAscii: 1,
|
qSortByAscii: 1,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const uid = () => {
|
||||||
|
const idGen = [
|
||||||
|
[10, 31],
|
||||||
|
[0, 31],
|
||||||
|
[0, 31],
|
||||||
|
[0, 31],
|
||||||
|
[0, 31],
|
||||||
|
[0, 31],
|
||||||
|
];
|
||||||
|
const toChar = ([min, max]) => min + ((Math.random() * (max - min)) | 0).toString(32);
|
||||||
|
return idGen.map(toChar).join('');
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import getAutoSortFieldDimension from '../get-sorted-field';
|
import getAutoSortDimension from '../get-sorted-field';
|
||||||
import findFieldInExpandedList from '../find-field-in-expandedList';
|
import findFieldInExpandedList from '../find-field-in-expandedList';
|
||||||
import { setAutoSort } from '../field-utils';
|
import { setAutoSort } from '../field-utils';
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ jest.mock('../field-utils', () => ({
|
|||||||
setAutoSort: jest.fn(),
|
setAutoSort: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('getAutoSortFieldDimension', () => {
|
describe('getAutoSortDimension', () => {
|
||||||
let self;
|
let self;
|
||||||
let dimension;
|
let dimension;
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ describe('getAutoSortFieldDimension', () => {
|
|||||||
const fieldList = [{ qName: 'field1' }];
|
const fieldList = [{ qName: 'field1' }];
|
||||||
self.app.getFieldList.mockResolvedValue(fieldList);
|
self.app.getFieldList.mockResolvedValue(fieldList);
|
||||||
|
|
||||||
const result = await getAutoSortFieldDimension(self, dimension);
|
const result = await getAutoSortDimension(self, dimension);
|
||||||
|
|
||||||
expect(self.app.getFieldList).toHaveBeenCalled();
|
expect(self.app.getFieldList).toHaveBeenCalled();
|
||||||
expect(findFieldInExpandedList).toHaveBeenCalledWith('field1', fieldList);
|
expect(findFieldInExpandedList).toHaveBeenCalledWith('field1', fieldList);
|
||||||
@@ -45,7 +45,7 @@ describe('getAutoSortFieldDimension', () => {
|
|||||||
self.app.getFieldList.mockResolvedValue(fieldList);
|
self.app.getFieldList.mockResolvedValue(fieldList);
|
||||||
findFieldInExpandedList.mockReturnValue(field);
|
findFieldInExpandedList.mockReturnValue(field);
|
||||||
|
|
||||||
await getAutoSortFieldDimension(self, dimension);
|
await getAutoSortDimension(self, dimension);
|
||||||
|
|
||||||
expect(setAutoSort).toHaveBeenCalledWith([field], dimension, self);
|
expect(setAutoSort).toHaveBeenCalledWith([field], dimension, self);
|
||||||
});
|
});
|
||||||
@@ -54,7 +54,7 @@ describe('getAutoSortFieldDimension', () => {
|
|||||||
self.app.getFieldList.mockResolvedValue([]);
|
self.app.getFieldList.mockResolvedValue([]);
|
||||||
findFieldInExpandedList.mockReturnValue(null);
|
findFieldInExpandedList.mockReturnValue(null);
|
||||||
|
|
||||||
await getAutoSortFieldDimension(self, dimension);
|
await getAutoSortDimension(self, dimension);
|
||||||
|
|
||||||
expect(setAutoSort).not.toHaveBeenCalled();
|
expect(setAutoSort).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -62,7 +62,7 @@ describe('getAutoSortFieldDimension', () => {
|
|||||||
test('should handle empty field list', async () => {
|
test('should handle empty field list', async () => {
|
||||||
self.app.getFieldList.mockResolvedValue([]);
|
self.app.getFieldList.mockResolvedValue([]);
|
||||||
|
|
||||||
const result = await getAutoSortFieldDimension(self, dimension);
|
const result = await getAutoSortDimension(self, dimension);
|
||||||
|
|
||||||
expect(result).toBe(dimension);
|
expect(result).toBe(dimension);
|
||||||
expect(setAutoSort).not.toHaveBeenCalled();
|
expect(setAutoSort).not.toHaveBeenCalled();
|
||||||
@@ -72,7 +72,7 @@ describe('getAutoSortFieldDimension', () => {
|
|||||||
dimension.qDef.qFieldDefs = undefined;
|
dimension.qDef.qFieldDefs = undefined;
|
||||||
self.app.getFieldList.mockResolvedValue([]);
|
self.app.getFieldList.mockResolvedValue([]);
|
||||||
|
|
||||||
const result = await getAutoSortFieldDimension(self, dimension);
|
const result = await getAutoSortDimension(self, dimension);
|
||||||
|
|
||||||
expect(result).toBe(dimension);
|
expect(result).toBe(dimension);
|
||||||
expect(setAutoSort).not.toHaveBeenCalled();
|
expect(setAutoSort).not.toHaveBeenCalled();
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
// eslint-disable-next-line import/no-relative-packages
|
import { AUTOCALENDAR_NAME, uid } from '../constants';
|
||||||
import uid from '../../../../../nucleus/src/object/uid';
|
|
||||||
import { AUTOCALENDAR_NAME } from '../constants';
|
|
||||||
|
|
||||||
export const getField = (expression) => {
|
export const getField = (expression) => {
|
||||||
let exp = expression;
|
let exp = expression;
|
||||||
@@ -33,7 +31,7 @@ export const initializeId = (field) => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const initializeField = (field) => ({
|
export const initializeDim = (field) => ({
|
||||||
...initializeId(field),
|
...initializeId(field),
|
||||||
qOtherTotalSpec: field.qOtherTotalSpec ?? {},
|
qOtherTotalSpec: field.qOtherTotalSpec ?? {},
|
||||||
});
|
});
|
||||||
@@ -62,6 +60,13 @@ export const setAutoSort = (fields, dimension, self) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isDateField = (field) =>
|
||||||
|
field?.qDerivedFieldData && (field?.qTags?.indexOf('$date') > -1 || field?.qTags?.indexOf('$timestamp') > -1);
|
||||||
|
|
||||||
|
export const isGeoField = (field) => field.qTags.indexOf('$geoname') > -1;
|
||||||
|
|
||||||
|
export const trimAutoCalendarName = (fieldName) => (fieldName ? fieldName.split(AUTOCALENDAR_NAME).join('') : '');
|
||||||
|
|
||||||
export const useMasterNumberFormat = (formatting) => {
|
export const useMasterNumberFormat = (formatting) => {
|
||||||
const format = formatting;
|
const format = formatting;
|
||||||
format.quarantine = {
|
format.quarantine = {
|
||||||
@@ -71,10 +76,3 @@ export const useMasterNumberFormat = (formatting) => {
|
|||||||
format.qNumFormat = null;
|
format.qNumFormat = null;
|
||||||
format.isCustomFormatted = undefined;
|
format.isCustomFormatted = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isDateField = (field) =>
|
|
||||||
field?.qDerivedFieldData && (field?.qTags?.indexOf('$date') > -1 || field?.qTags?.indexOf('$timestamp') > -1);
|
|
||||||
|
|
||||||
export const isGeoField = (field) => field.qTags.indexOf('$geoname') > -1;
|
|
||||||
|
|
||||||
export const trimAutoCalendarName = (fieldName) => (fieldName ? fieldName.split(AUTOCALENDAR_NAME).join('') : '');
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import findFieldInExpandedList from './find-field-in-expandedList';
|
import findFieldInExpandedList from './find-field-in-expandedList';
|
||||||
import { setAutoSort } from './field-utils';
|
import { setAutoSort } from './field-utils';
|
||||||
|
|
||||||
function getAutoSortFieldDimension(self, dimension) {
|
function getAutoSortDimension(self, dimension) {
|
||||||
return self.app.getFieldList().then((fieldList) => {
|
return self.app.getFieldList().then((fieldList) => {
|
||||||
const field = dimension?.qDef?.qFieldDefs && findFieldInExpandedList(dimension.qDef.qFieldDefs[0], fieldList);
|
const field = dimension?.qDef?.qFieldDefs && findFieldInExpandedList(dimension.qDef.qFieldDefs[0], fieldList);
|
||||||
if (field) {
|
if (field) {
|
||||||
@@ -11,4 +11,4 @@ function getAutoSortFieldDimension(self, dimension) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default getAutoSortFieldDimension;
|
export default getAutoSortDimension;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ describe('addMainMeasure', () => {
|
|||||||
|
|
||||||
const result = await addMainMeasure(self, newMeasure, index);
|
const result = await addMainMeasure(self, newMeasure, index);
|
||||||
|
|
||||||
expect(result).toEqual(newMeasure);
|
expect(result).toBeUndefined();
|
||||||
expect(self.autoSortMeasure).not.toHaveBeenCalledWith(newMeasure);
|
expect(self.autoSortMeasure).not.toHaveBeenCalledWith(newMeasure);
|
||||||
expect(self.hcProperties.qInterColumnSortOrder).toEqual([1, 0, 2]);
|
expect(self.hcProperties.qInterColumnSortOrder).toEqual([1, 0, 2]);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
// eslint-disable-next-line import/no-relative-packages
|
import { uid } from '../../constants';
|
||||||
import uid from '../../../../../../nucleus/src/object/uid';
|
|
||||||
import * as hcUtils from '../hypercube-utils';
|
import * as hcUtils from '../hypercube-utils';
|
||||||
|
|
||||||
jest.mock('../../../../../../nucleus/src/object/uid', () => jest.fn());
|
jest.mock('../../constants', () => ({
|
||||||
|
uid: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('replaceDimensionToColumnOrder', () => {
|
describe('replaceDimensionToColumnOrder', () => {
|
||||||
let self;
|
let self;
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ function addMainMeasure(self, measure, index) {
|
|||||||
|
|
||||||
return self.autoSortMeasure(measure).then(() => {
|
return self.autoSortMeasure(measure).then(() => {
|
||||||
addMeasureToColumnSortOrder(self, measures);
|
addMeasureToColumnSortOrder(self, measures);
|
||||||
return addMeasureToColumnOrder(self, measure).then(() => measure);
|
addMeasureToColumnOrder(self, measure).then(() => measure);
|
||||||
|
return measure;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return measure;
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
export default addMainMeasure;
|
export default addMainMeasure;
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
// eslint-disable-next-line import/no-relative-packages
|
import { arrayUtil, utils } from '@nebula.js/conversion';
|
||||||
import getValue from '../../../../../conversion/src/utils';
|
import { TOTAL_MAX, uid } from '../constants';
|
||||||
// eslint-disable-next-line import/no-relative-packages
|
|
||||||
import arrayUtil from '../../../../../conversion/src/array-util';
|
|
||||||
import { TOTAL_MAX } from '../constants';
|
|
||||||
// eslint-disable-next-line import/no-relative-packages
|
|
||||||
import uid from '../../../../../nucleus/src/object/uid';
|
|
||||||
|
|
||||||
export const notSupportedError = new Error('Not supported in this object, need to implement in subclass.');
|
export const notSupportedError = new Error('Not supported in this object, need to implement in subclass.');
|
||||||
|
|
||||||
@@ -33,7 +28,7 @@ export const getHyperCube = (layout, path) => {
|
|||||||
if (!layout) {
|
if (!layout) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return path && getValue(layout, path) ? getValue(layout, path).qHyperCube : layout.qHyperCube;
|
return path && utils.getValue(layout, path) ? utils.getValue(layout, path).qHyperCube : layout.qHyperCube;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function setDefaultProperties(self) {
|
export function setDefaultProperties(self) {
|
||||||
@@ -241,7 +236,8 @@ export function isTotalMeasureExceeded(self, measures) {
|
|||||||
return altMeasures.length + measures.length >= TOTAL_MAX.MEASURES;
|
return altMeasures.length + measures.length >= TOTAL_MAX.MEASURES;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isMeasureAlternative(self, measures, alternative) {
|
export function isMeasureAlternative(self, alternative) {
|
||||||
|
const measures = self.getMeasures();
|
||||||
return alternative || (self.maxMeasures() <= measures.length && measures.length < TOTAL_MAX.MEASURES);
|
return alternative || (self.maxMeasures() <= measures.length && measures.length < TOTAL_MAX.MEASURES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import generator from './generator';
|
import generator from './generator';
|
||||||
import JSONPatch from './json-patch';
|
import JSONPatch from './json-patch';
|
||||||
|
|
||||||
|
export { default as HyperCubeHandler } from './handler/hypercube-handler';
|
||||||
|
export { default as DataPropertyHandler } from './handler/data-property-handler';
|
||||||
export { generator, JSONPatch };
|
export { generator, JSONPatch };
|
||||||
|
|
||||||
// core hooks
|
// core hooks
|
||||||
|
|||||||
@@ -4473,6 +4473,7 @@ __metadata:
|
|||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@nebula.js/supernova@workspace:apis/supernova"
|
resolution: "@nebula.js/supernova@workspace:apis/supernova"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
"@nebula.js/conversion": "npm:^6.0.0-alpha.2"
|
||||||
extend: "npm:3.0.2"
|
extend: "npm:3.0.2"
|
||||||
node-event-emitter: "npm:0.0.1"
|
node-event-emitter: "npm:0.0.1"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
|
|||||||
Reference in New Issue
Block a user