Skip to content

Commit 0d1f1ab

Browse files
MultiSelector Rebased (#535)
* MultiSelector * Fixing multiselector on dates * Fix multi * Fix multi 2 * Fix multi deletion * Fixed styling on parameter select * Cleaning * Option Label * Clean on Multi * Solve smells --------- Co-authored-by: Niels de Jong <[email protected]>
1 parent f8f641b commit 0d1f1ab

File tree

9 files changed

+112
-49
lines changed

9 files changed

+112
-49
lines changed

src/card/settings/custom/CardSettingsContentPropertySelect.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ const NeoCardSettingsContentPropertySelect = ({
237237
value={settings.entityType ? settings.entityType : ''}
238238
defaultValue={''}
239239
placeholder={'Enter a parameter name here...'}
240-
style={{ width: 335, marginLeft: '5px', marginTop: '13px' }}
240+
style={{}}
241241
onChange={(value) => {
242242
setLabelInputText(value);
243243
handleNodeLabelSelectionUpdate(value);
@@ -253,15 +253,14 @@ const NeoCardSettingsContentPropertySelect = ({
253253
value={settings?.entityType || ''}
254254
defaultValue={''}
255255
placeholder={'Enter a parameter name here...'}
256-
style={{ width: 350, marginLeft: '5px', marginTop: '0px' }}
256+
style={{}}
257257
onChange={(value) => {
258258
setLabelInputText(value);
259259
handleNodeLabelSelectionUpdate(value);
260260
handleFreeTextNameSelectionUpdate(value);
261261
}}
262262
/>
263263
<br />
264-
<br />
265264
<div style={{ display: labelInputText ? 'inherit' : 'none' }}>
266265
<NeoCodeEditorComponent
267266
value={queryText}
@@ -301,7 +300,7 @@ const NeoCardSettingsContentPropertySelect = ({
301300
: labelRecords.map((r) => (r._fields ? r._fields[0] : '(no data)'))
302301
}
303302
getOptionLabel={(option) => option || ''}
304-
style={{ width: 350, marginLeft: '5px', marginTop: '13px' }}
303+
style={{ marginTop: '13px' }}
305304
inputValue={labelInputText}
306305
onInputChange={(event, value) => {
307306
setLabelInputText(value);
@@ -344,7 +343,7 @@ const NeoCardSettingsContentPropertySelect = ({
344343
: propertyRecords.map((r) => (r._fields ? r._fields[0] : '(no data)'))
345344
}
346345
getOptionLabel={(option) => (option ? option : '')}
347-
style={{ display: 'inline-block', width: 170, marginLeft: '5px', marginTop: '13px' }}
346+
style={{ display: 'inline-block', width: '65%', marginTop: '13px', marginRight: '5%' }}
348347
inputValue={propertyInputText}
349348
onInputChange={(event, value) => {
350349
setPropertyInputText(value);
@@ -374,13 +373,14 @@ const NeoCardSettingsContentPropertySelect = ({
374373
{overridePropertyDisplayName ? (
375374
<Autocomplete
376375
id='autocomplete-property-display'
376+
size={'small'}
377377
options={
378378
manualPropertyNameSpecification
379379
? [settings.propertyTypeDisplay || settings.propertyType]
380380
: propertyRecords.map((r) => (r._fields ? r._fields[0] : '(no data)'))
381381
}
382382
getOptionLabel={(option) => (option ? option : '')}
383-
style={{ display: 'inline-block', width: 170, marginLeft: '5px', marginTop: '13px' }}
383+
style={{ display: 'inline-block', width: '65%', marginTop: '13px', marginRight: '5%' }}
384384
inputValue={propertyInputDisplayText}
385385
onInputChange={(event, value) => {
386386
setPropertyInputDisplayText(value);
@@ -408,14 +408,14 @@ const NeoCardSettingsContentPropertySelect = ({
408408
) : (
409409
<></>
410410
)}
411-
<NeoField
411+
<TextField
412412
placeholder='number'
413413
label='Number (optional)'
414414
disabled={!settings.propertyType}
415415
value={settings.id}
416-
style={{ width: '170px', marginTop: '13px', marginLeft: '5px' }}
417-
onChange={(value) => {
418-
handleIdSelectionUpdate(value);
416+
style={{ width: '30%', display: 'inline-block', marginTop: '13px' }}
417+
onChange={(e) => {
418+
handleIdSelectionUpdate(e.target.value);
419419
}}
420420
size={'small'}
421421
/>

src/card/view/CardView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ const NeoCardView = ({
138138
}, [JSON.stringify(localParameters)]);
139139

140140
useEffect(() => {
141-
if (!settingsOpen) {
141+
if (!settingsOpen && (selectorChange || type === 'select')) {
142142
setLastRunTimestamp(Date.now());
143143
}
144144
setSelectorChange(false);

src/chart/parameter/ParameterSelectionChart.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const NeoParameterSelectionChart = (props: ChartProps) => {
2727
const setParameterValue = (value) => setGlobalParameter(parameterName, value);
2828
const setParameterDisplayValue = (value) => setGlobalParameter(parameterDisplayName, value);
2929
const allParameters = props.parameters;
30+
const multiSelector = props?.settings?.multiSelector;
3031

3132
// in NeoDash 2.2.1 or earlier, there was no means to have a different display value in the selector. This condition handles that.
3233
const compatibilityMode = !query?.toLowerCase().includes('as display') || false;
@@ -65,6 +66,7 @@ export const NeoParameterSelectionChart = (props: ChartProps) => {
6566
settings={props.settings}
6667
allParameters={allParameters}
6768
compatibilityMode={compatibilityMode}
69+
multiSelector={multiSelector}
6870
/>
6971
);
7072
} else if (type == 'Relationship Property') {
@@ -81,6 +83,7 @@ export const NeoParameterSelectionChart = (props: ChartProps) => {
8183
settings={props.settings}
8284
allParameters={allParameters}
8385
compatibilityMode={compatibilityMode}
86+
multiSelector={multiSelector}
8487
/>
8588
);
8689
} else if (type == 'Date Picker') {
@@ -113,6 +116,7 @@ export const NeoParameterSelectionChart = (props: ChartProps) => {
113116
settings={props.settings}
114117
allParameters={allParameters}
115118
compatibilityMode={compatibilityMode}
119+
multiSelector={multiSelector}
116120
/>
117121
);
118122
}

src/chart/parameter/component/NodePropertyParameterSelect.tsx

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useCallback } from 'react';
22
import { debounce, TextField } from '@mui/material';
33
import Autocomplete from '@mui/material/Autocomplete';
44
import { ParameterSelectProps } from './ParameterSelect';
5+
import { RenderSubValue } from '../../../report/ReportRecordProcessing';
56

67
const NodePropertyParameterSelectComponent = (props: ParameterSelectProps) => {
78
const suggestionsUpdateTimeout =
@@ -11,10 +12,22 @@ const NodePropertyParameterSelectComponent = (props: ParameterSelectProps) => {
1112
? props.settings.defaultValue
1213
: '';
1314

15+
const getInitialValue = (value, multi) => {
16+
if (value && Array.isArray(value)) {
17+
return multi ? value : null;
18+
} else if (value) {
19+
return multi ? [value] : value;
20+
}
21+
return multi ? [] : value;
22+
};
23+
const { multiSelector } = props;
1424
const allParameters = props.allParameters ? props.allParameters : {};
1525
const [extraRecords, setExtraRecords] = React.useState([]);
16-
// const [inputText, setInputText] = React.useState(props.parameterValue);
17-
const [inputDisplayText, setInputDisplayText] = React.useState(props.parameterDisplayValue);
26+
const [inputDisplayText, setInputDisplayText] = React.useState(
27+
props.parameterDisplayValue && multiSelector ? '' : props.parameterDisplayValue
28+
);
29+
const [inputValue, setInputValue] = React.useState(getInitialValue(props.parameterDisplayValue, multiSelector));
30+
1831
const debouncedQueryCallback = useCallback(debounce(props.queryCallback, suggestionsUpdateTimeout), []);
1932
const label = props.settings && props.settings.entityType ? props.settings.entityType : '';
2033
const propertyType = props.settings && props.settings.propertyType ? props.settings.propertyType : '';
@@ -29,50 +42,83 @@ const NodePropertyParameterSelectComponent = (props: ParameterSelectProps) => {
2942

3043
const realValueRowIndex = props.compatibilityMode ? 0 : 1 - displayValueRowIndex;
3144

45+
const handleCrossClick = (isMulti, value) => {
46+
if (isMulti) {
47+
if (value.length == 0 && clearParameterOnFieldClear) {
48+
setInputValue([]);
49+
props.setParameterValue(undefined);
50+
props.setParameterDisplayValue(undefined);
51+
return;
52+
}
53+
if (value.length == 0) {
54+
setInputValue([]);
55+
props.setParameterValue([]);
56+
props.setParameterDisplayValue([]);
57+
58+
}
59+
} else {
60+
if (value && clearParameterOnFieldClear) {
61+
setInputValue(null);
62+
props.setParameterValue(undefined);
63+
props.setParameterDisplayValue(undefined);
64+
return;
65+
}
66+
if (value == null) {
67+
setInputValue(null);
68+
props.setParameterValue(defaultValue);
69+
props.setParameterDisplayValue(defaultValue);
70+
71+
}
72+
}
73+
};
74+
const propagateSelection = (event, newDisplay) => {
75+
const isMulti = Array.isArray(newDisplay);
76+
handleCrossClick(isMulti, newDisplay);
77+
let newValue;
78+
// Multiple and new entry
79+
if (isMulti && inputValue.length < newDisplay.length) {
80+
newValue = Array.isArray(props.parameterValue) ? [...props.parameterValue] : [props.parameterValue];
81+
const newDisplayValue = [...newDisplay].slice(-1)[0];
82+
83+
let val = extraRecords.filter((r) => r._fields[displayValueRowIndex].toString() == newDisplayValue)[0]._fields[
84+
realValueRowIndex
85+
];
86+
87+
newValue.push(val?.low ?? val);
88+
} else if (!isMulti) {
89+
newValue = extraRecords.filter((r) => r._fields[displayValueRowIndex].toString() == newDisplay)[0]._fields[
90+
realValueRowIndex
91+
];
92+
93+
newValue = newValue?.low || newValue;
94+
} else {
95+
let ele = props.parameterDisplayValue.filter((x) => !newDisplay.includes(x))[0];
96+
newValue = [...props.parameterValue];
97+
newValue.splice(props.parameterDisplayValue.indexOf(ele), 1);
98+
}
99+
100+
setInputDisplayText(isMulti ? '' : newDisplay);
101+
setInputValue(newDisplay);
102+
103+
props.setParameterValue(newValue);
104+
props.setParameterDisplayValue(newDisplay);
105+
};
32106
return (
33107
<Autocomplete
34108
id='autocomplete'
35-
options={extraRecords
36-
.map((r) =>
37-
(r._fields && r._fields[displayValueRowIndex] !== null ? r._fields[displayValueRowIndex] : '(no data)')
38-
)
39-
.sort()}
40-
getOptionLabel={(option) => (option ? option.toString() : '')}
41-
style={{ maxWidth: 'calc(100% - 30px)', marginLeft: '15px', marginTop: '6.5px' }}
42-
inputValue={inputDisplayText !== null ? `${inputDisplayText}` : ''}
109+
multiple={multiSelector}
110+
options={extraRecords.map((r) => r?._fields?.[displayValueRowIndex] || '(no data)').sort()}
111+
style={{ maxWidth: 'calc(100% - 30px)', marginLeft: '15px', marginTop: '5px' }}
112+
inputValue={inputDisplayText}
43113
onInputChange={(event, value) => {
44-
setInputDisplayText(value !== null ? `${value}` : '');
114+
setInputDisplayText(value);
45115
debouncedQueryCallback(props.query, { input: `${value}`, ...allParameters }, setExtraRecords);
46116
}}
47117
isOptionEqualToValue={(option, value) => {
48118
return (option && option.toString()) === (value && value.toString());
49119
}}
50-
value={props.parameterDisplayValue !== null ? `${props.parameterDisplayValue}` : ''}
51-
onChange={(event, newDisplayValue) => {
52-
if (newDisplayValue == null && clearParameterOnFieldClear) {
53-
props.setParameterValue(undefined);
54-
props.setParameterDisplayValue(undefined);
55-
return;
56-
}
57-
if (newDisplayValue == null) {
58-
props.setParameterValue(defaultValue);
59-
props.setParameterDisplayValue(defaultValue);
60-
return;
61-
}
62-
63-
let newValue = extraRecords.filter((r) => r._fields[displayValueRowIndex].toString() == newDisplayValue)[0]
64-
._fields[realValueRowIndex];
65-
setInputDisplayText(newDisplayValue);
66-
if (newValue && newValue.low) {
67-
newValue = newValue.low;
68-
}
69-
if (newDisplayValue && newDisplayValue.low) {
70-
newDisplayValue = newDisplayValue.low;
71-
}
72-
73-
props.setParameterValue(newValue);
74-
props.setParameterDisplayValue(newDisplayValue);
75-
}}
120+
value={inputValue}
121+
onChange={propagateSelection}
76122
renderInput={(params) => (
77123
<TextField
78124
{...params}
@@ -82,6 +128,7 @@ const NodePropertyParameterSelectComponent = (props: ParameterSelectProps) => {
82128
variant='outlined'
83129
/>
84130
)}
131+
getOptionLabel={(option) => RenderSubValue(option)}
85132
/>
86133
);
87134
};

src/chart/parameter/component/ParameterSelect.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,8 @@ export interface ParameterSelectProps {
4646
* Create the parameter selector in compatibility mode for NeoDash 2.2.1 or earlier.
4747
*/
4848
compatibilityMode: boolean;
49+
/**
50+
* Add the possibility for multiple selections
51+
*/
52+
multiSelector?: boolean;
4953
}

src/chart/parameter/component/QueryParameterSelect.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const QueryParameterSelectComponent = (props: ParameterSelectProps) => {
1616
settings={props.settings}
1717
allParameters={props.allParameters}
1818
compatibilityMode={props.compatibilityMode}
19+
multiSelector={props.multiSelector}
1920
/>
2021
);
2122
};

src/chart/parameter/component/RelationshipPropertyParameterSelect.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const RelationshipPropertyParameterSelectComponent = (props: ParameterSelectProp
2020
settings={props.settings}
2121
allParameters={props.allParameters}
2222
compatibilityMode={props.compatibilityMode}
23+
multiSelector={props.multiSelector}
2324
/>
2425
);
2526
};

src/chart/table/TableChart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ export const NeoTableChart = (props: ChartProps) => {
264264
}
265265
}}
266266
pageSize={tablePageSize > 0 ? tablePageSize : 5}
267-
rowsPerPageOptions={[5]}
267+
rowsPerPageOptions={rows.length < 5 ? [rows.length, 5] : [5]}
268268
disableSelectionOnClick
269269
components={{
270270
ColumnSortedDescendingIcon: () => <></>,

src/config/ReportConfig.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,12 @@ export const REPORT_TYPES = {
12901290
type: SELECTION_TYPES.COLOR,
12911291
default: '#fafafa',
12921292
},
1293+
multiSelector: {
1294+
label: 'Multiple Selection',
1295+
type: SELECTION_TYPES.LIST,
1296+
values: [true, false],
1297+
default: false,
1298+
},
12931299
overridePropertyDisplayName: {
12941300
label: 'Property Display Name Override',
12951301
type: SELECTION_TYPES.LIST,

0 commit comments

Comments
 (0)