mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-25 01:04:14 -05:00
fix: show more button even when list box is not in selection (#1554)
* fix: show more button even when list box is not in selection * fix: failded test case * fix: activate selection if not yet * fix: search * revert: changes for search * fix: remove isInSelection * fix: change enabled check * fix: unit test * fix: unit test * test: add unit test to check existence of more button * fix: change description
This commit is contained in:
@@ -146,7 +146,7 @@ function ActionsToolbar({
|
||||
moreActions = [...newMoreActions, ...more.actions];
|
||||
}
|
||||
|
||||
if (!selections.show && newActions.length === 0) return null;
|
||||
if (!selections.show && newActions.length === 0 && !moreEnabled) return null;
|
||||
|
||||
const handleCloseShowMoreItems = () => {
|
||||
setShowMoreItems(false);
|
||||
|
||||
@@ -121,7 +121,6 @@ function ListBoxInline({ options, layout }) {
|
||||
const isModalMode = useCallback(() => isModal({ app, appSelections }), [app, appSelections]);
|
||||
const isInvalid = layout?.qListObject.qDimensionInfo.qError;
|
||||
const errorText = isInvalid && constraints.active ? 'Visualization.Invalid.Dimension' : 'Visualization.Incomplete';
|
||||
const [isInSelection, setIsInSelection] = useState(false);
|
||||
|
||||
const { handleKeyDown, handleOnMouseEnter, handleOnMouseLeave, globalKeyDown } = useMemo(
|
||||
() =>
|
||||
@@ -162,11 +161,9 @@ function ListBoxInline({ options, layout }) {
|
||||
}
|
||||
const show = () => {
|
||||
setShowToolbar(true);
|
||||
setIsInSelection(true);
|
||||
};
|
||||
const hide = () => {
|
||||
setShowToolbar(false);
|
||||
setIsInSelection(false);
|
||||
if (search === 'toggle') {
|
||||
setShowSearch(false);
|
||||
}
|
||||
@@ -184,7 +181,7 @@ function ListBoxInline({ options, layout }) {
|
||||
selections.on('activated', show);
|
||||
selections.on('deactivated', hide);
|
||||
}
|
||||
setShowToolbar(selections.isActive());
|
||||
setShowToolbar(isPopover || selections.isActive());
|
||||
}
|
||||
|
||||
return () => {
|
||||
@@ -279,7 +276,6 @@ function ListBoxInline({ options, layout }) {
|
||||
selectionState={selectionState}
|
||||
selections={selections}
|
||||
keyboard={keyboard}
|
||||
isInSelection={isInSelection}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@@ -67,7 +67,6 @@ export default function ListBoxHeader({
|
||||
keyboard,
|
||||
autoConfirm,
|
||||
app,
|
||||
isInSelection,
|
||||
}) {
|
||||
const [isToolbarDetached, setIsToolbarDetached] = useState(showDetachedToolbarOnly);
|
||||
const [isLocked, setLocked] = useState(layout?.qListObject?.qDimensionInfo?.qLocked);
|
||||
@@ -99,13 +98,13 @@ export default function ListBoxHeader({
|
||||
(iconData ? BUTTON_ICON_WIDTH : 0);
|
||||
|
||||
const toggleLock = getToggleLock({ isLocked, setLocked, settingLockedState, setSettingLockedState, model });
|
||||
|
||||
const listboxSelectionToolbarItems = createListboxSelectionToolbar({
|
||||
layout,
|
||||
model,
|
||||
translator,
|
||||
selectionState,
|
||||
isDirectQuery,
|
||||
selections,
|
||||
});
|
||||
|
||||
const extraItems =
|
||||
@@ -170,6 +169,7 @@ export default function ListBoxHeader({
|
||||
isDetached: isPopover ? false : isToolbarDetached,
|
||||
showToolbar,
|
||||
containerRef,
|
||||
isPopover,
|
||||
isLocked,
|
||||
extraItems,
|
||||
listboxSelectionToolbarItems,
|
||||
@@ -214,7 +214,7 @@ export default function ListBoxHeader({
|
||||
<DimensionIcon
|
||||
iconData={iconData}
|
||||
iconStyle={iconStyle}
|
||||
disabled={isInSelection && isPopover}
|
||||
disabled={selections.isActive() && isPopover}
|
||||
translator={translator}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
@@ -19,6 +19,7 @@ const selections = {
|
||||
canClear: () => true,
|
||||
canConfirm: () => true,
|
||||
canCancel: () => true,
|
||||
isActive: () => false,
|
||||
};
|
||||
const styles = { content: {}, header: { color: 'red' }, selections: {}, search: {}, background: {} };
|
||||
let rendererInst;
|
||||
@@ -230,4 +231,16 @@ describe('<ListBoxHeader />', () => {
|
||||
// Ensure unlock is visible
|
||||
expect(unlockCoverButtons).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('Should show more button even when it is not in selection mode for popover', async () => {
|
||||
hasSelections.mockReturnValue(true);
|
||||
const testRenderer = await render({ showSearchIcon: true, showLock: true, isPopover: true });
|
||||
const testInstance = testRenderer.root;
|
||||
|
||||
const [actionsToolbar] = testInstance.findAllByType(ActionsToolbar);
|
||||
|
||||
// Check existence.
|
||||
const moreButton = actionsToolbar.props.more;
|
||||
expect(moreButton.enabled).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ describe('getScrollIndex', () => {
|
||||
let translator;
|
||||
let selectionState;
|
||||
let isDirectQuery;
|
||||
let selections;
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
@@ -41,6 +42,11 @@ describe('getScrollIndex', () => {
|
||||
selectionState = {
|
||||
clearItemStates: jest.fn(),
|
||||
};
|
||||
|
||||
selections = {
|
||||
isActive: jest.fn(() => false),
|
||||
begin: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const create = (overrides = {}) =>
|
||||
@@ -50,6 +56,7 @@ describe('getScrollIndex', () => {
|
||||
translator,
|
||||
selectionState,
|
||||
isDirectQuery,
|
||||
selections,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
@@ -122,21 +129,25 @@ describe('getScrollIndex', () => {
|
||||
it('select all', () => {
|
||||
all.action();
|
||||
expect(model.selectListObjectAll).toHaveBeenCalledTimes(1);
|
||||
expect(selections.begin).toHaveBeenCalledTimes(1);
|
||||
expect(model.selectListObjectAll).toBeCalledWith('/qListObjectDef');
|
||||
});
|
||||
it('select possible', () => {
|
||||
possible.action();
|
||||
expect(model.selectListObjectPossible).toHaveBeenCalledTimes(1);
|
||||
expect(selections.begin).toHaveBeenCalledTimes(1);
|
||||
expect(model.selectListObjectPossible).toBeCalledWith('/qListObjectDef');
|
||||
});
|
||||
it('select alternative', () => {
|
||||
alternative.action();
|
||||
expect(model.selectListObjectAlternative).toHaveBeenCalledTimes(1);
|
||||
expect(selections.begin).toHaveBeenCalledTimes(1);
|
||||
expect(model.selectListObjectAlternative).toBeCalledWith('/qListObjectDef');
|
||||
});
|
||||
it('select excluded', () => {
|
||||
excluded.action();
|
||||
expect(model.selectListObjectExcluded).toHaveBeenCalledTimes(1);
|
||||
expect(selections.begin).toHaveBeenCalledTimes(1);
|
||||
expect(model.selectListObjectExcluded).toBeCalledWith('/qListObjectDef');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function getListboxActionProps({
|
||||
},
|
||||
extraItems,
|
||||
more: {
|
||||
enabled: !isLocked,
|
||||
enabled: !isLocked && (showToolbar || selections.isActive()), // show more button even when popover is not in selection mode
|
||||
actions: listboxSelectionToolbarItems,
|
||||
popoverProps: {
|
||||
elevation: 0,
|
||||
@@ -30,7 +30,7 @@ export default function getListboxActionProps({
|
||||
},
|
||||
},
|
||||
selections: {
|
||||
show: showToolbar,
|
||||
show: showToolbar && selections.isActive(),
|
||||
api: selections,
|
||||
onConfirm: () => {
|
||||
keyboard?.focus();
|
||||
|
||||
@@ -3,11 +3,16 @@ import { selectAlternative } from '@nebula.js/ui/icons/select-alternative';
|
||||
import { selectPossible } from '@nebula.js/ui/icons/select-possible';
|
||||
import { selectExcluded } from '@nebula.js/ui/icons/select-excluded';
|
||||
|
||||
export default ({ layout, model, translator, selectionState, isDirectQuery = false }) => {
|
||||
export default ({ layout, model, translator, selectionState, isDirectQuery = false, selections }) => {
|
||||
if (layout.qListObject.qDimensionInfo.qIsOneAndOnlyOne) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const path = '/qListObjectDef';
|
||||
const activateSelection = () => {
|
||||
if (!selections.isActive()) {
|
||||
selections.begin(path);
|
||||
}
|
||||
};
|
||||
const canSelectAll = () =>
|
||||
['qOption', 'qAlternative', 'qExcluded', 'qDeselected'].some(
|
||||
(sc) => layout.qListObject.qDimensionInfo.qStateCounts[sc] > 0
|
||||
@@ -26,8 +31,9 @@ export default ({ layout, model, translator, selectionState, isDirectQuery = fal
|
||||
getSvgIconShape: selectAll,
|
||||
enabled: canSelectAll,
|
||||
action: () => {
|
||||
activateSelection();
|
||||
selectionState.clearItemStates(false);
|
||||
model.selectListObjectAll('/qListObjectDef');
|
||||
model.selectListObjectAll(path);
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -37,8 +43,9 @@ export default ({ layout, model, translator, selectionState, isDirectQuery = fal
|
||||
getSvgIconShape: selectPossible,
|
||||
enabled: canSelectPossible,
|
||||
action: () => {
|
||||
activateSelection();
|
||||
selectionState.clearItemStates(false);
|
||||
model.selectListObjectPossible('/qListObjectDef');
|
||||
model.selectListObjectPossible(path);
|
||||
},
|
||||
},
|
||||
isDirectQuery
|
||||
@@ -50,8 +57,9 @@ export default ({ layout, model, translator, selectionState, isDirectQuery = fal
|
||||
getSvgIconShape: selectAlternative,
|
||||
enabled: canSelectAlternative,
|
||||
action: () => {
|
||||
activateSelection();
|
||||
selectionState.clearItemStates(false);
|
||||
model.selectListObjectAlternative('/qListObjectDef');
|
||||
model.selectListObjectAlternative(path);
|
||||
},
|
||||
},
|
||||
isDirectQuery
|
||||
@@ -63,8 +71,9 @@ export default ({ layout, model, translator, selectionState, isDirectQuery = fal
|
||||
getSvgIconShape: selectExcluded,
|
||||
enabled: canSelectExcluded,
|
||||
action: () => {
|
||||
activateSelection();
|
||||
selectionState.clearItemStates(false);
|
||||
model.selectListObjectExcluded('/qListObjectDef');
|
||||
model.selectListObjectExcluded(path);
|
||||
},
|
||||
},
|
||||
].filter(Boolean);
|
||||
|
||||
@@ -259,6 +259,11 @@ window.getFuncs = function getFuncs() {
|
||||
qListObject: {
|
||||
qDimensionInfo: {
|
||||
qLocked: false,
|
||||
qStateCounts: {
|
||||
qOption: 0,
|
||||
qAlternative: 0,
|
||||
qExcluded: 0,
|
||||
},
|
||||
},
|
||||
qSize: {
|
||||
qcy: 16,
|
||||
|
||||
Reference in New Issue
Block a user