mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2026-05-25 01:00:13 -04:00
feat: better incomplete view (#453)
Co-authored-by: Miralem Drek <mek@qlik.com>
This commit is contained in:
committed by
GitHub
parent
c8a996b2d5
commit
e9d11e9887
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Unvollständige Visualisierung",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +83,32 @@
|
||||
"value": "Select possible",
|
||||
"comment": "Action text to select possible selections"
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.LayoutError": {
|
||||
"value": "Error",
|
||||
"comment": "Status text shown when a visualization has layout errors"
|
||||
},
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Incomplete visualization",
|
||||
"comment": "Status text shown when a visualization is incomplete"
|
||||
},
|
||||
"Visualization.Incomplete.Dimensions": {
|
||||
"value": "{0} of {1} dimensions",
|
||||
"comment": "Text showing the number of current {0} dimensions over the total {1} number of dimensions"
|
||||
},
|
||||
"Visualization.Incomplete.Measures": {
|
||||
"value": "{0} of {1} measures",
|
||||
"comment": "Text showing the number of current {0} measures over the total {1} number of measures"
|
||||
},
|
||||
"Visualization.Invalid.Dimension": {
|
||||
"value": "Invalid dimension",
|
||||
"comment": "Status text shown when a dimension is not valid"
|
||||
},
|
||||
"Visualization.UnfulfilledCalculationCondition": {
|
||||
"value": "The calculation condition is not fulfilled",
|
||||
"comment": "Message displayed when a calculation condition is not fulfilled"
|
||||
},
|
||||
"Visualization.Invalid.Measure": {
|
||||
"value": "Invalid measure",
|
||||
"comment": "Status text shown when a measure is not valid"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Visualización incompleta",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Visualisation incomplète",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Visualizzazione incompleta",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "未完了のビジュアライゼーション",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "완료되지 않은 시각화",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Onvolledige visualisatie",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Niekompletna wizualizacja",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Visualização incompleta",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Незавершенная визуализация",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Ofullständig visualisering",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "Tamamlanmamış görselleştirme",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "不完整的可视化",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
"comment": "Action text to select possible selections",
|
||||
"version": "UYEx1K96g9h4HCK3GH/6kg=="
|
||||
},
|
||||
"Supernova.Incomplete": {
|
||||
"Visualization.Incomplete": {
|
||||
"value": "視覺化未完成",
|
||||
"comment": "Status text shown when a visualization is incomplete",
|
||||
"version": "SOyzXWKRgL1+6AqW/QkZOA=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,26 +114,112 @@ const handleModal = ({ sn, layout, model }) => {
|
||||
|
||||
const filterData = (d) => (d.qError ? d.qError.qErrorCode === 7005 : true);
|
||||
|
||||
const validateTargets = (translator, layout, { targets }) => {
|
||||
const validateInfo = (min, info, getDescription, translatedError, translatedCalcCond) => {
|
||||
return [...Array(min).keys()].map((i) => {
|
||||
const exists = !!(info && info[i]);
|
||||
const softError = exists && info[i].qError && info[i].qError.qErrorCode === 7005;
|
||||
const error = exists && !softError && info[i].qError;
|
||||
const delimiter = ':';
|
||||
const calcCondMsg = softError && info[i].qCalcCondMsg;
|
||||
const label = `${
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
error ? translatedError : softError ? calcCondMsg || translatedCalcCond : (exists && info[i].qFallbackTitle) || ''
|
||||
}`;
|
||||
const description = `${getDescription(i)}${label.length ? delimiter : ''}`;
|
||||
|
||||
return {
|
||||
description,
|
||||
label,
|
||||
missing: (info && !exists && !error && i >= info.length) || softError,
|
||||
error,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const validateTarget = (translator, layout, properties, def) => {
|
||||
const minD = def.dimensions.min();
|
||||
const minM = def.measures.min();
|
||||
const hc = def.resolveLayout(layout);
|
||||
|
||||
const reqDimErrors = validateInfo(
|
||||
minD,
|
||||
hc.qDimensionInfo,
|
||||
(i) => def.dimensions.description(properties, i),
|
||||
translator.get('Visualization.Invalid.Dimension'),
|
||||
translator.get('Visualization.UnfulfilledCalculationCondition')
|
||||
);
|
||||
const reqMeasErrors = validateInfo(
|
||||
minM,
|
||||
hc.qMeasureInfo,
|
||||
(i) => def.measures.description(properties, i),
|
||||
translator.get('Visualization.Invalid.Measure'),
|
||||
translator.get('Visualization.UnfulfilledCalculationCondition')
|
||||
);
|
||||
return {
|
||||
reqDimErrors,
|
||||
reqMeasErrors,
|
||||
};
|
||||
};
|
||||
|
||||
const validateTargets = async (translator, layout, { targets }, model) => {
|
||||
const layoutErrors = [];
|
||||
const requirementsError = [];
|
||||
targets.forEach((def) => {
|
||||
// Use a flattened requirements structure to combine all targets
|
||||
const allRequirements = {
|
||||
hasErrors: false,
|
||||
d: {
|
||||
title: '',
|
||||
descriptions: [],
|
||||
min: 0,
|
||||
},
|
||||
m: {
|
||||
title: '',
|
||||
descriptions: [],
|
||||
min: 0,
|
||||
},
|
||||
};
|
||||
let loopCacheProperties = null;
|
||||
|
||||
for (let i = 0; i < targets.length; ++i) {
|
||||
const def = targets[i];
|
||||
const minD = def.dimensions.min();
|
||||
const minM = def.measures.min();
|
||||
const hc = def.resolveLayout(layout);
|
||||
const d = (hc.qDimensionInfo || []).filter(filterData);
|
||||
const m = (hc.qMeasureInfo || []).filter(filterData);
|
||||
const d = (hc.qDimensionInfo || []).filter(filterData); // Filter out optional calc conditions
|
||||
const m = (hc.qMeasureInfo || []).filter(filterData); // Filter out optional calc conditions
|
||||
const path = def.layoutPath;
|
||||
|
||||
// layout error
|
||||
if (hc.qError) {
|
||||
layoutErrors.push({ path, error: hc.qError });
|
||||
layoutErrors.push({ title: path, descriptions: [{ message: hc.qError }] });
|
||||
}
|
||||
if (d.length < minD || m.length < minM) {
|
||||
requirementsError.push({ path });
|
||||
allRequirements.hasErrors = true;
|
||||
allRequirements.d.min += minD;
|
||||
allRequirements.m.min += minM;
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const properties = loopCacheProperties || (await model.getProperties());
|
||||
loopCacheProperties = properties;
|
||||
|
||||
const res = validateTarget(translator, layout, properties, def);
|
||||
allRequirements.d.descriptions.push(...res.reqDimErrors);
|
||||
allRequirements.m.descriptions.push(...res.reqMeasErrors);
|
||||
}
|
||||
});
|
||||
const showError = !!(layoutErrors.length || requirementsError.length);
|
||||
const title = requirementsError.length ? translator.get('Supernova.Incomplete') : 'Error';
|
||||
const data = requirementsError.length ? requirementsError : layoutErrors;
|
||||
}
|
||||
const fulfilledDims = allRequirements.d.descriptions.filter((e) => !(e.missing || e.error)).length;
|
||||
allRequirements.d.title = translator.get('Visualization.Incomplete.Dimensions', [
|
||||
fulfilledDims,
|
||||
allRequirements.d.min,
|
||||
]);
|
||||
const fulfilledMeas = allRequirements.m.descriptions.filter((e) => !(e.missing || e.error)).length;
|
||||
allRequirements.m.title = translator.get('Visualization.Incomplete.Measures', [fulfilledMeas, allRequirements.m.min]);
|
||||
|
||||
const showError = !!(layoutErrors.length || allRequirements.hasErrors);
|
||||
const title = allRequirements.hasErrors
|
||||
? translator.get('Visualization.Incomplete')
|
||||
: translator.get('Visualization.LayoutError');
|
||||
const data = allRequirements.hasErrors ? [allRequirements.d, allRequirements.m] : layoutErrors;
|
||||
|
||||
return [showError, { title, data }];
|
||||
};
|
||||
|
||||
@@ -207,8 +293,8 @@ const Cell = forwardRef(({ halo, model, initialSnOptions, initialError, onMount
|
||||
if (initialError || !appLayout) {
|
||||
return undefined;
|
||||
}
|
||||
const validate = (sn) => {
|
||||
const [showError, error] = validateTargets(translator, layout, sn.generator.qae.data);
|
||||
const validate = async (sn) => {
|
||||
const [showError, error] = await validateTargets(translator, layout, sn.generator.qae.data, model);
|
||||
if (showError) {
|
||||
dispatch({ type: 'ERROR', error });
|
||||
} else {
|
||||
|
||||
@@ -1,34 +1,82 @@
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
import React from 'react';
|
||||
import { makeStyles, Grid, Typography } from '@material-ui/core';
|
||||
import { Grid, Typography, IconButton } from '@material-ui/core';
|
||||
import WarningTriangle from '@nebula.js/ui/icons/warning-triangle-2';
|
||||
import Tick from '@nebula.js/ui/icons/tick';
|
||||
import { useTheme } from '@nebula.js/ui/theme';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
contentError: {
|
||||
'&::before': {
|
||||
position: 'absolute',
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
top: 0,
|
||||
left: 0,
|
||||
content: '""',
|
||||
backgroundSize: '14.14px 14.14px',
|
||||
backgroundImage:
|
||||
'linear-gradient(135deg, currentColor 10%, rgba(0,0,0,0) 10%, rgba(0,0,0,0) 50%, currentColor 50%, currentColor 59%, rgba(0,0,0,0) 60%, rgba(0,0,0,0) 103%)',
|
||||
opacity: 0.1,
|
||||
},
|
||||
},
|
||||
}));
|
||||
const DescriptionRow = ({ d }) => {
|
||||
const theme = useTheme();
|
||||
let color = 'inherit';
|
||||
let styleColor = theme.palette.success.main;
|
||||
if (d.missing) {
|
||||
styleColor = theme.palette.warning.main;
|
||||
} else if (d.error) {
|
||||
color = 'error';
|
||||
styleColor = theme.palette.error.main;
|
||||
}
|
||||
const style = { color: styleColor };
|
||||
const Icon = (
|
||||
<IconButton>{d.missing || d.error ? <WarningTriangle style={style} /> : <Tick style={style} />}</IconButton>
|
||||
);
|
||||
return (
|
||||
<Grid item container alignItems="center" wrap="nowrap">
|
||||
<Grid item>{Icon}</Grid>
|
||||
<Grid container item zeroMinWidth wrap="nowrap">
|
||||
<Typography noWrap component="p">
|
||||
<Typography component="span" variant="subtitle2" color={color}>
|
||||
{d.description}
|
||||
</Typography>
|
||||
<Typography component="span"> </Typography>
|
||||
<Typography
|
||||
component="span"
|
||||
variant="subtitle2"
|
||||
color={d.error ? 'error' : 'inherit'}
|
||||
style={{ fontWeight: 400 }}
|
||||
>
|
||||
{d.label}
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
const Descriptions = ({ data }) => {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<Grid item style={{ maxWidth: '80%', overflow: 'hidden' }}>
|
||||
{data.map((e, ix) => {
|
||||
const Rows = e.descriptions.map((d, dix) => <DescriptionRow d={d} key={dix} />);
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
item
|
||||
key={ix}
|
||||
direction="column"
|
||||
style={{
|
||||
paddingBottom: `${theme.spacing(2)}px`,
|
||||
}}
|
||||
>
|
||||
<Typography noWrap key={ix} variant="subtitle1" align="left" color="textSecondary">
|
||||
{e.title}
|
||||
</Typography>
|
||||
{Rows}
|
||||
</Grid>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
export default function Error({ title = 'Error', message = '', data = [] }) {
|
||||
const { contentError } = useStyles();
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
direction="column"
|
||||
alignItems="center"
|
||||
justify="center"
|
||||
className={contentError}
|
||||
style={{ position: 'relative', height: '100%' }}
|
||||
style={{ position: 'relative', height: '100%', width: '100%' }}
|
||||
spacing={1}
|
||||
>
|
||||
<Grid item>
|
||||
@@ -44,14 +92,9 @@ export default function Error({ title = 'Error', message = '', data = [] }) {
|
||||
{message}
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
{data.map((d, ix) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<Typography key={ix} variant="subtitle2" align="center">
|
||||
{d.path} {d.error && '-'} {d.error && d.error.qErrorCode}
|
||||
</Typography>
|
||||
))}
|
||||
</Grid>
|
||||
<Descriptions data={data} />
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
export { Descriptions, DescriptionRow };
|
||||
|
||||
@@ -224,20 +224,26 @@ describe('<Cell />', () => {
|
||||
});
|
||||
|
||||
it('should render requirements', async () => {
|
||||
const localLayout = { visualization: 'sn', foo: { qDimensionInfo: [], qMeasureInfo: [] } };
|
||||
const sn = {
|
||||
generator: {
|
||||
qae: {
|
||||
data: {
|
||||
targets: [
|
||||
{
|
||||
resolveLayout: () => '/foo',
|
||||
resolveLayout: () => localLayout.foo,
|
||||
dimensions: {
|
||||
min: () => 1,
|
||||
max: () => 1,
|
||||
description: (_properties, ix) =>
|
||||
ix === 0
|
||||
? 'Column'
|
||||
: 'Cells - dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd ',
|
||||
},
|
||||
measures: {
|
||||
min: () => 1,
|
||||
max: () => 1,
|
||||
description: () => 'Size',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -251,11 +257,14 @@ describe('<Cell />', () => {
|
||||
}),
|
||||
getSupportedVersion: sandbox.stub().returns('1.0.0'),
|
||||
};
|
||||
await render({ types });
|
||||
const model = {
|
||||
getProperties: async () => {},
|
||||
};
|
||||
await render({ types, model });
|
||||
|
||||
const ftypes = renderer.root.findAllByType(CError);
|
||||
expect(ftypes).to.have.length(1);
|
||||
expect(ftypes[0].props.title).to.equal('Supernova.Incomplete');
|
||||
expect(ftypes[0].props.title).to.equal('Visualization.Incomplete');
|
||||
});
|
||||
|
||||
it('should render hypercube error', async () => {
|
||||
@@ -271,10 +280,15 @@ describe('<Cell />', () => {
|
||||
dimensions: {
|
||||
min: () => 0,
|
||||
max: () => 0,
|
||||
description: (_properties, ix) =>
|
||||
ix === 0
|
||||
? 'Column'
|
||||
: 'Cells - dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd dkslfjd ',
|
||||
},
|
||||
measures: {
|
||||
min: () => 0,
|
||||
max: () => 0,
|
||||
description: () => 'Size',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -292,9 +306,8 @@ describe('<Cell />', () => {
|
||||
|
||||
const ftypes = renderer.root.findAllByType(CError);
|
||||
expect(ftypes).to.have.length(1);
|
||||
expect(ftypes[0].props.title).to.equal('Error');
|
||||
expect(ftypes[0].props.data[0].path).to.equal('/foo');
|
||||
expect(ftypes[0].props.data[0].error).to.deep.equal({ qErrorCode: 1337 });
|
||||
expect(ftypes[0].props.data[0].title).to.equal('/foo');
|
||||
expect(ftypes[0].props.data[0].descriptions[0].message).to.deep.equal({ qErrorCode: 1337 });
|
||||
});
|
||||
|
||||
it('should go modal (selections)', async () => {
|
||||
|
||||
@@ -1,7 +1,33 @@
|
||||
import React from 'react';
|
||||
import { create, act } from 'react-test-renderer';
|
||||
|
||||
const [{ default: Error }] = aw.mock([], ['../Error']);
|
||||
import WarningTriangle from '@nebula.js/ui/icons/warning-triangle-2';
|
||||
import Tick from '@nebula.js/ui/icons/tick';
|
||||
|
||||
const [{ default: Error, Descriptions, DescriptionRow }] = aw.mock(
|
||||
[
|
||||
[
|
||||
require.resolve('@nebula.js/ui/theme'),
|
||||
() => ({
|
||||
useTheme: () => ({
|
||||
spacing: () => 0,
|
||||
palette: {
|
||||
success: {
|
||||
main: 'success',
|
||||
},
|
||||
warning: {
|
||||
maing: 'warning',
|
||||
},
|
||||
error: {
|
||||
main: 'error',
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
],
|
||||
],
|
||||
['../Error']
|
||||
);
|
||||
|
||||
describe('<Error />', () => {
|
||||
let sandbox;
|
||||
@@ -32,18 +58,40 @@ describe('<Error />', () => {
|
||||
});
|
||||
|
||||
it('should render error', async () => {
|
||||
await render('foo', 'bar', [{ path: 'baz', error: { qErrorCode: 1337 } }]);
|
||||
await render('foo', 'bar', [{ title: 'foo', descriptions: [] }]);
|
||||
const title = renderer.root.find((el) => {
|
||||
return el.props['data-tid'] === 'error-title';
|
||||
});
|
||||
expect(title.props.children).to.equal('foo');
|
||||
const message = renderer.root.find((el) => {
|
||||
const msg = renderer.root.find((el) => {
|
||||
return el.props['data-tid'] === 'error-message';
|
||||
});
|
||||
expect(message.props.children).to.equal('bar');
|
||||
const data = renderer.root.find((el) => {
|
||||
return el.props.children && Array.isArray(el.props.children) ? el.props.children[0] === 'baz' : false;
|
||||
});
|
||||
expect(data.props).to.deep.equal({ variant: 'subtitle2', align: 'center', children: ['baz', ' ', '-', ' ', 1337] });
|
||||
expect(msg.props.children).to.equal('bar');
|
||||
});
|
||||
|
||||
it('should render error with descriptions', async () => {
|
||||
const d = [1, 2, 3, 4, 5, 6].map((n) => ({
|
||||
description: `d-${n}`,
|
||||
label: `l-${n}`,
|
||||
missing: n % 3 === 0,
|
||||
error: n % 5 === 0,
|
||||
}));
|
||||
const dims = {
|
||||
title: 'Dimensions',
|
||||
descriptions: d.slice(0, 3),
|
||||
};
|
||||
const meas = {
|
||||
title: 'Measures',
|
||||
descriptions: d.slice(3),
|
||||
};
|
||||
const data = [dims, meas];
|
||||
await render('foo', 'bar', data);
|
||||
const list = renderer.root.findByType(Descriptions);
|
||||
const rows = list.findAllByType(DescriptionRow);
|
||||
expect(rows).to.have.length(6);
|
||||
const w = list.findAllByType(WarningTriangle);
|
||||
const t = list.findAllByType(Tick);
|
||||
expect(w).to.have.length(3);
|
||||
expect(t).to.have.length(3);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('qae', () => {
|
||||
data: {
|
||||
targets: [
|
||||
{
|
||||
path: 'qhc',
|
||||
path: '/qHyperCubeDef',
|
||||
dimensions: {
|
||||
min: () => 3,
|
||||
max: () => 7,
|
||||
@@ -64,7 +64,7 @@ describe('qae', () => {
|
||||
],
|
||||
},
|
||||
}).data.targets[0];
|
||||
expect(t.propertyPath).to.eql('qhc');
|
||||
expect(t.propertyPath).to.eql('/qHyperCubeDef');
|
||||
expect(t.dimensions.min()).to.eql(3);
|
||||
expect(t.dimensions.max()).to.eql(7);
|
||||
expect(t.dimensions.added()).to.equal('a');
|
||||
@@ -79,6 +79,34 @@ describe('qae', () => {
|
||||
expect(t.dimensions.isDefined()).to.equal(true);
|
||||
expect(t.measures.isDefined()).to.equal(true);
|
||||
});
|
||||
it('should throw with incorrect hypercube def', () => {
|
||||
expect(() =>
|
||||
qae({
|
||||
data: {
|
||||
targets: [
|
||||
{
|
||||
path: 'qhc',
|
||||
dimensions: {
|
||||
min: () => 3,
|
||||
max: () => 7,
|
||||
added: () => 'a',
|
||||
description: () => 'Slice',
|
||||
moved: () => 'c',
|
||||
replaced: () => 'd',
|
||||
},
|
||||
measures: {
|
||||
min: 2,
|
||||
max: 4,
|
||||
added: () => 'b',
|
||||
description: () => 'Angle',
|
||||
removed: () => 'e',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
).to.throw('Incorrect definition for qHyperCubeDef at qhc');
|
||||
});
|
||||
it('should resolve layout', () => {
|
||||
const t = qae({
|
||||
data: {
|
||||
|
||||
@@ -66,6 +66,9 @@ const resolveValue = (data, reference, defaultValue) => {
|
||||
function target(def) {
|
||||
const propertyPath = def.path || '/qHyperCubeDef';
|
||||
const layoutPath = propertyPath.slice(0, -3);
|
||||
if (/\/qHyperCube$/.test(layoutPath) === false) {
|
||||
throw new Error(`Incorrect definition for qHyperCubeDef at ${propertyPath}`);
|
||||
}
|
||||
return {
|
||||
propertyPath,
|
||||
layoutPath,
|
||||
|
||||
@@ -146,6 +146,7 @@ const renderFixture = async () => {
|
||||
};
|
||||
return mockedLayout;
|
||||
},
|
||||
getProperties: () => null,
|
||||
on() {},
|
||||
once() {},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user