From 2589a93ff2d079d28cca6a59115a8b621175a572 Mon Sep 17 00:00:00 2001 From: Tobias Linsefors Date: Thu, 16 Mar 2023 16:21:02 +0100 Subject: [PATCH] feat: fetch frequencyMax (#1152) --- .../src/components/listbox/ListBox.jsx | 5 ++++ .../src/components/listbox/ListBoxInline.jsx | 1 + .../src/components/listbox/ListBoxPopover.jsx | 1 + .../grid-list-components.jsx | 3 ++- .../hooks/__tests__/useOnTheFlyModel.test.jsx | 6 ++--- .../listbox/hooks/useFrequencyMax.jsx | 23 +++++++++++++++++++ .../listbox/hooks/useOnTheFlyModel.jsx | 22 +++++++++++++----- .../listbox/utils/frequencyMaxUtil.js | 21 +++++++++++++++++ 8 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 apis/nucleus/src/components/listbox/hooks/useFrequencyMax.jsx create mode 100644 apis/nucleus/src/components/listbox/utils/frequencyMaxUtil.js diff --git a/apis/nucleus/src/components/listbox/ListBox.jsx b/apis/nucleus/src/components/listbox/ListBox.jsx index 0dacfadd1..8e2dce371 100644 --- a/apis/nucleus/src/components/listbox/ListBox.jsx +++ b/apis/nucleus/src/components/listbox/ListBox.jsx @@ -14,11 +14,13 @@ import ListBoxDisclaimer from './components/ListBoxDisclaimer'; import ListBoxFooter from './components/ListBoxFooter'; import getScrollIndex from './interactions/listbox-get-scroll-index'; import getFrequencyAllowed from './components/grid-list-components/frequency-allowed'; +import useFrequencyMax from './hooks/useFrequencyMax'; const DEFAULT_MIN_BATCH_SIZE = 100; export default function ListBox({ model, + app, constraints, layout, selections, @@ -222,6 +224,8 @@ export default function ListBox({ setLast: (last) => setFocusListItem((prevState) => ({ ...prevState, last })), }); + const frequencyMax = useFrequencyMax(app, layout); + const { List, Grid } = getListBoxComponents({ direction, layout, @@ -249,6 +253,7 @@ export default function ListBox({ focusListItems: getFocusState(), setCurrentScrollIndex: currentScrollIndex.set, constraints, + frequencyMax, freqIsAllowed, }); diff --git a/apis/nucleus/src/components/listbox/ListBoxInline.jsx b/apis/nucleus/src/components/listbox/ListBoxInline.jsx index f84d1d7ef..636e960e6 100644 --- a/apis/nucleus/src/components/listbox/ListBoxInline.jsx +++ b/apis/nucleus/src/components/listbox/ListBoxInline.jsx @@ -334,6 +334,7 @@ function ListBoxInline({ options, layout }) { {({ height, width }) => ( { histogram: true, }; const fieldIdentifier = { qLibraryId: '123' }; - const fakeDimLayout = { qDim: { qFieldDefs: ['Volume'] } }; + const fakeDimLayout = { qDim: { qFieldDefs: ['Volume'], qGrouping: 'N' } }; app.getDimension = jest.fn().mockReturnValue({ getLayout: async () => fakeDimLayout }); await render(useOnTheFlyModel, { app, fieldIdentifier, stateName: '$', options }); @@ -138,7 +138,7 @@ describe('useExistingModel', () => { }); test('should use title from qDim', async () => { const fieldIdentifier = { qLibraryId: '123' }; - const fakeDimLayout = { qDim: { qFieldDefs: ['Volume'], title: 'Volume title' } }; + const fakeDimLayout = { qDim: { qFieldDefs: ['Volume'], title: 'Volume title', qGrouping: 'N' } }; app.getDimension = jest.fn().mockReturnValue({ getLayout: async () => fakeDimLayout }); await render(useOnTheFlyModel, { app, fieldIdentifier, stateName: '$' }); @@ -147,7 +147,7 @@ describe('useExistingModel', () => { test('should use title from options if provided', async () => { const options = { title: 'Options title' }; const fieldIdentifier = { qLibraryId: '123' }; - const fakeDimLayout = { qDim: { qFieldDefs: ['Volume'], title: 'Volume title' } }; + const fakeDimLayout = { qDim: { qFieldDefs: ['Volume'], title: 'Volume title', qGrouping: 'N' } }; app.getDimension = jest.fn().mockReturnValue({ getLayout: async () => fakeDimLayout }); await render(useOnTheFlyModel, { app, fieldIdentifier, stateName: '$', options }); diff --git a/apis/nucleus/src/components/listbox/hooks/useFrequencyMax.jsx b/apis/nucleus/src/components/listbox/hooks/useFrequencyMax.jsx new file mode 100644 index 000000000..7b943ccbb --- /dev/null +++ b/apis/nucleus/src/components/listbox/hooks/useFrequencyMax.jsx @@ -0,0 +1,23 @@ +import { useState, useEffect } from 'react'; +import { getFrequencyMax, needToFetchFrequencyMax } from '../utils/frequencyMaxUtil'; + +const useFrequencyMax = (app, layout) => { + const [frequencyMax, setFrequencyMax] = useState(); + + const needFetch = needToFetchFrequencyMax(layout); + + useEffect(() => { + if (!needFetch) { + return; + } + const fetch = async () => { + const newValue = await getFrequencyMax(layout, app); + setFrequencyMax(newValue); + }; + fetch(); + }, [needFetch && layout]); + + return needFetch ? frequencyMax : layout?.frequencyMax; +}; + +export default useFrequencyMax; diff --git a/apis/nucleus/src/components/listbox/hooks/useOnTheFlyModel.jsx b/apis/nucleus/src/components/listbox/hooks/useOnTheFlyModel.jsx index b7a559245..8a8d706ee 100644 --- a/apis/nucleus/src/components/listbox/hooks/useOnTheFlyModel.jsx +++ b/apis/nucleus/src/components/listbox/hooks/useOnTheFlyModel.jsx @@ -2,6 +2,7 @@ import { useState, useEffect, useRef } from 'react'; import extend from 'extend'; import useSessionModel from '../../../hooks/useSessionModel'; import uid from '../../../object/uid'; +import { getFrequencyMaxExpression } from '../utils/frequencyMaxUtil'; export default function useOnTheFlyModel({ app, fieldIdentifier, stateName, options = {} }) { const [fieldDef, setFieldDef] = useState(''); @@ -16,7 +17,11 @@ export default function useOnTheFlyModel({ app, fieldIdentifier, stateName, opti const dim = await app.getDimension(fieldIdentifier.qLibraryId); const dimLayout = await dim.getLayout(); setFallbackTitle(dimLayout.qDim.title); - setFieldDef(dimLayout.qDim.qFieldDefs ? dimLayout.qDim.qFieldDefs[0] : ''); + if (dimLayout.qDim.qGrouping === 'N') { + setFieldDef(dimLayout.qDim.qFieldDefs ? dimLayout.qDim.qFieldDefs[0] : ''); + } else { + setFieldDef({ multiFieldDim: true }); + } setIsFetching(false); } catch (e) { setIsFetching(false); @@ -122,11 +127,16 @@ export default function useOnTheFlyModel({ app, fieldIdentifier, stateName, opti fieldName = fieldIdentifier; } - if (frequencyMode !== 'N' || histogram) { - const field = fieldIdentifier.qLibraryId ? fieldDef : fieldName; - listdef.frequencyMax = { - qValueExpression: `Max(AGGR(Count([${field}]), [${field}]))`, - }; + if (frequencyMode !== 'P' && histogram) { + if (fieldDef?.multiFieldDim) { + listdef.frequencyMax = 'fetch'; + // maybe for all lib dimension to handle if it properties change + } else { + const field = fieldIdentifier.qLibraryId ? fieldDef : fieldName; + listdef.frequencyMax = { + qValueExpression: getFrequencyMaxExpression(field), + }; + } } const [sessionModel] = useSessionModel(listdef, isFetching ? null : app, fieldName, stateName); diff --git a/apis/nucleus/src/components/listbox/utils/frequencyMaxUtil.js b/apis/nucleus/src/components/listbox/utils/frequencyMaxUtil.js new file mode 100644 index 000000000..e8d449974 --- /dev/null +++ b/apis/nucleus/src/components/listbox/utils/frequencyMaxUtil.js @@ -0,0 +1,21 @@ +const escapeField = (field) => { + if (!field) { + return field; + } + return `${field.replace(/\]/g, ']]')}`; +}; + +export const needToFetchFrequencyMax = (layout) => layout?.frequencyMax === 'fetch'; + +export const getFrequencyMaxExpression = (field) => { + const escapedField = escapeField(field); + return `Max(AGGR(Count(${escapedField}), ${escapedField}))`; +}; + +export const getFrequencyMax = async (layout, app) => { + const dimInfo = layout.qListObject.qDimensionInfo; + const field = dimInfo.qGroupFieldDefs[dimInfo.qGroupPos]; + const expression = getFrequencyMaxExpression(field); + const evaluadedExpression = await app.evaluateEx(expression); + return evaluadedExpression.qNumber; +};