mirror of
https://github.com/qlik-oss/nebula.js.git
synced 2025-12-19 09:48:18 -05:00
refactor: limit selection actions in direct query (#1246)
* refactor: compensate for checkboxes in item width * test: search highlight rendering test * refactor: disable some select actions in dq mode * fix: rm test * refactor: add flags fallback to context * refactor: send flags through options instead of context * refactor: rm flags completely
This commit is contained in:
@@ -23,6 +23,7 @@ import { CELL_PADDING_LEFT, ICON_WIDTH, ICON_PADDING, BUTTON_ICON_WIDTH } from '
|
||||
import useTempKeyboard from './components/useTempKeyboard';
|
||||
import ListBoxError from './components/ListBoxError';
|
||||
import useRect from '../../hooks/useRect';
|
||||
import isDirectQueryEnabled from './utils/is-direct-query';
|
||||
|
||||
const PREFIX = 'ListBoxInline';
|
||||
const classes = {
|
||||
@@ -113,6 +114,8 @@ function ListBoxInline({ options, layout }) {
|
||||
const { translator, keyboardNavigation, themeApi, constraints } = useContext(InstanceContext);
|
||||
theme.listBox = addListboxTheme(themeApi);
|
||||
|
||||
const isDirectQuery = isDirectQueryEnabled({ appLayout: app?.layout });
|
||||
|
||||
const containerRef = useRef();
|
||||
const [containerRectRef, containerRect] = useRect();
|
||||
const [searchContainer, searchContainerRef] = useRefWithCallback();
|
||||
@@ -240,6 +243,7 @@ function ListBoxInline({ options, layout }) {
|
||||
model,
|
||||
translator,
|
||||
selectionState,
|
||||
isDirectQuery,
|
||||
});
|
||||
|
||||
const showTitle = true;
|
||||
|
||||
@@ -16,6 +16,7 @@ import * as ListBoxModule from '../ListBox';
|
||||
import * as ListBoxSearchModule from '../components/ListBoxSearch';
|
||||
import * as listboxSelectionToolbarModule from '../interactions/listbox-selection-toolbar';
|
||||
import * as addListboxTheme from '../assets/addListboxTheme';
|
||||
import * as isDirectQueryEnabled from '../utils/is-direct-query';
|
||||
|
||||
const virtualizedModule = require('react-virtualized-auto-sizer');
|
||||
const listboxKeyboardNavigationModule = require('../interactions/keyboard-navigation/keyboard-nav-container');
|
||||
@@ -91,6 +92,7 @@ describe('<ListboxInline />', () => {
|
||||
jest.spyOn(useLayoutModule, 'default').mockImplementation(() => [layout]);
|
||||
jest.spyOn(listboxKeyboardNavigationModule, 'default').mockImplementation(getListboxInlineKeyboardNavigation);
|
||||
jest.spyOn(addListboxTheme, 'default').mockImplementation(() => {});
|
||||
jest.spyOn(isDirectQueryEnabled, 'default').mockImplementation(() => false);
|
||||
|
||||
ActionsToolbarModule.default = ActionsToolbar;
|
||||
ListBoxModule.default = <div className="theListBox" />;
|
||||
@@ -192,6 +194,7 @@ describe('<ListboxInline />', () => {
|
||||
expect(selections.on.mock.calls[0][0]).toBe('activated');
|
||||
expect(selections.on.mock.calls[1][0]).toBe('deactivated');
|
||||
expect(selections.removeListener).not.toHaveBeenCalled();
|
||||
expect(isDirectQueryEnabled.default).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should render properly with search toggle option', async () => {
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
import createListboxSelectionToolbar from '../listbox-selection-toolbar';
|
||||
|
||||
describe('getScrollIndex', () => {
|
||||
let layout;
|
||||
let model;
|
||||
let translator;
|
||||
let selectionState;
|
||||
let isDirectQuery;
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
afterAll(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
isDirectQuery = false;
|
||||
layout = {
|
||||
qListObject: {
|
||||
qDimensionInfo: {
|
||||
qStateCounts: {
|
||||
qOption: 2,
|
||||
qAlternative: 2,
|
||||
qExcluded: 2,
|
||||
qDeselected: 2,
|
||||
},
|
||||
qIsOneAndOnlyOne: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
model = {
|
||||
selectListObjectAll: jest.fn(),
|
||||
selectListObjectPossible: jest.fn(),
|
||||
selectListObjectAlternative: jest.fn(),
|
||||
selectListObjectExcluded: jest.fn(),
|
||||
};
|
||||
translator = {
|
||||
get: jest.fn((t) => t),
|
||||
};
|
||||
selectionState = {
|
||||
clearItemStates: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
const create = (overrides = {}) =>
|
||||
createListboxSelectionToolbar({
|
||||
layout,
|
||||
model,
|
||||
translator,
|
||||
selectionState,
|
||||
isDirectQuery,
|
||||
...overrides,
|
||||
});
|
||||
|
||||
it('should create all actions', () => {
|
||||
const actions = create();
|
||||
expect(actions).toHaveLength(4);
|
||||
|
||||
const [all, possible, alternative, excluded] = actions;
|
||||
|
||||
expect(all).toMatchObject({ key: 'selectAll', label: 'Selection.SelectAll', type: 'menu-icon-button' });
|
||||
expect(possible).toMatchObject({
|
||||
key: 'selectPossible',
|
||||
label: 'Selection.SelectPossible',
|
||||
type: 'menu-icon-button',
|
||||
});
|
||||
expect(alternative).toMatchObject({
|
||||
key: 'selectAlternative',
|
||||
label: 'Selection.SelectAlternative',
|
||||
type: 'menu-icon-button',
|
||||
});
|
||||
expect(excluded).toMatchObject({
|
||||
key: 'selectExcluded',
|
||||
label: 'Selection.SelectExcluded',
|
||||
type: 'menu-icon-button',
|
||||
});
|
||||
|
||||
expect(all.enabled()).toEqual(true);
|
||||
expect(possible.enabled()).toEqual(true);
|
||||
expect(alternative.enabled()).toEqual(true);
|
||||
expect(excluded.enabled()).toEqual(true);
|
||||
});
|
||||
|
||||
it('should not create any actions if single select', () => {
|
||||
layout.qListObject.qDimensionInfo.qIsOneAndOnlyOne = true;
|
||||
const actions = create({ layout });
|
||||
expect(actions).toEqual([]);
|
||||
});
|
||||
|
||||
it('should only create two actions in direct query mode', () => {
|
||||
const actions = create({ isDirectQuery: true });
|
||||
expect(actions).toHaveLength(2);
|
||||
|
||||
const [all, possible] = actions;
|
||||
|
||||
expect(all).toMatchObject({ key: 'selectAll', label: 'Selection.SelectAll', type: 'menu-icon-button' });
|
||||
expect(possible).toMatchObject({
|
||||
key: 'selectPossible',
|
||||
label: 'Selection.SelectPossible',
|
||||
type: 'menu-icon-button',
|
||||
});
|
||||
});
|
||||
|
||||
describe('test each action', () => {
|
||||
let all;
|
||||
let possible;
|
||||
let alternative;
|
||||
let excluded;
|
||||
|
||||
beforeEach(() => {
|
||||
const actions = create();
|
||||
[all, possible, alternative, excluded] = actions;
|
||||
|
||||
expect(selectionState.clearItemStates).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
expect(selectionState.clearItemStates).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('select all', () => {
|
||||
all.action();
|
||||
expect(model.selectListObjectAll).toHaveBeenCalledTimes(1);
|
||||
expect(model.selectListObjectAll).toBeCalledWith('/qListObjectDef');
|
||||
});
|
||||
it('select possible', () => {
|
||||
possible.action();
|
||||
expect(model.selectListObjectPossible).toHaveBeenCalledTimes(1);
|
||||
expect(model.selectListObjectPossible).toBeCalledWith('/qListObjectDef');
|
||||
});
|
||||
it('select alternative', () => {
|
||||
alternative.action();
|
||||
expect(model.selectListObjectAlternative).toHaveBeenCalledTimes(1);
|
||||
expect(model.selectListObjectAlternative).toBeCalledWith('/qListObjectDef');
|
||||
});
|
||||
it('select excluded', () => {
|
||||
excluded.action();
|
||||
expect(model.selectListObjectExcluded).toHaveBeenCalledTimes(1);
|
||||
expect(model.selectListObjectExcluded).toBeCalledWith('/qListObjectDef');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,7 +3,7 @@ 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 }) => {
|
||||
export default ({ layout, model, translator, selectionState, isDirectQuery = false }) => {
|
||||
if (layout.qListObject.qDimensionInfo.qIsOneAndOnlyOne) {
|
||||
return [];
|
||||
}
|
||||
@@ -41,27 +41,31 @@ export default ({ layout, model, translator, selectionState }) => {
|
||||
model.selectListObjectPossible('/qListObjectDef');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'selectAlternative',
|
||||
type: 'menu-icon-button',
|
||||
label: translator.get('Selection.SelectAlternative'),
|
||||
getSvgIconShape: selectAlternative,
|
||||
enabled: canSelectAlternative,
|
||||
action: () => {
|
||||
selectionState.clearItemStates(false);
|
||||
model.selectListObjectAlternative('/qListObjectDef');
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'selectExcluded',
|
||||
type: 'menu-icon-button',
|
||||
label: translator.get('Selection.SelectExcluded'),
|
||||
getSvgIconShape: selectExcluded,
|
||||
enabled: canSelectExcluded,
|
||||
action: () => {
|
||||
selectionState.clearItemStates(false);
|
||||
model.selectListObjectExcluded('/qListObjectDef');
|
||||
},
|
||||
},
|
||||
];
|
||||
isDirectQuery
|
||||
? false
|
||||
: {
|
||||
key: 'selectAlternative',
|
||||
type: 'menu-icon-button',
|
||||
label: translator.get('Selection.SelectAlternative'),
|
||||
getSvgIconShape: selectAlternative,
|
||||
enabled: canSelectAlternative,
|
||||
action: () => {
|
||||
selectionState.clearItemStates(false);
|
||||
model.selectListObjectAlternative('/qListObjectDef');
|
||||
},
|
||||
},
|
||||
isDirectQuery
|
||||
? false
|
||||
: {
|
||||
key: 'selectExcluded',
|
||||
type: 'menu-icon-button',
|
||||
label: translator.get('Selection.SelectExcluded'),
|
||||
getSvgIconShape: selectExcluded,
|
||||
enabled: canSelectExcluded,
|
||||
action: () => {
|
||||
selectionState.clearItemStates(false);
|
||||
model.selectListObjectExcluded('/qListObjectDef');
|
||||
},
|
||||
},
|
||||
].filter(Boolean);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
const { default: isDirectQueryEnabled } = require('../is-direct-query');
|
||||
|
||||
describe('isDirectQuery', () => {
|
||||
const appLayout = { qIsDirectQueryMode: false };
|
||||
|
||||
test('should return false since app is not a DQ app', async () => {
|
||||
const dq = isDirectQueryEnabled({ appLayout });
|
||||
expect(dq).toEqual(false);
|
||||
});
|
||||
|
||||
test('should return true since it is a DQ app', async () => {
|
||||
appLayout.qIsDirectQueryMode = true;
|
||||
const dq = isDirectQueryEnabled({ appLayout });
|
||||
expect(dq).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
export default function isDirectQueryEnabled({ appLayout }) {
|
||||
const isDQ = !!appLayout?.qIsDirectQueryMode;
|
||||
return isDQ;
|
||||
}
|
||||
Reference in New Issue
Block a user