Skip to content

Commit e88c69c

Browse files
[O2B-1151] Auto-fill tags in on-call log template (#1409)
* Rework tags picker * [O2B-1151] Auto-fill tags in on-call log template * First attempt at fixing tests * Fix broken tests * Handle null tags observable and fix label * Reformat code * Explicit tags mapping
1 parent f83fff0 commit e88c69c

19 files changed

Lines changed: 138 additions & 115 deletions

lib/database/seeders/20200511151010-tags.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ module.exports = {
4545
{ text: 'TEST-TAG-18' },
4646
{ text: 'TEST-TAG-19' },
4747
{ text: 'TEST-TAG-20' },
48-
{ text: 'TEST-TAG-21' },
48+
{ text: 'oncall' },
4949
{ text: 'TEST-TAG-22' },
5050
{ text: 'TEST-TAG-23' },
5151
{ text: 'TEST-TAG-24' },

lib/public/components/Filters/common/combinationOperatorChoiceComponent.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { h } from '/js/src/index.js';
1818
*
1919
* @param {CombinationOperatorChoiceModel} combinationOperatorModel the model to store the choice's state
2020
* @param {Object} [configuration] the component's configuration
21-
* @param {Object} [configuration.selectorPrefix] a selector prefix used to generate DOM selectors
21+
* @param {string} [configuration.selectorPrefix] a selector prefix used to generate DOM selectors
2222
* @return {Component} the choice component
2323
*/
2424
export const combinationOperatorChoiceComponent = (combinationOperatorModel, configuration) => {
@@ -29,7 +29,7 @@ export const combinationOperatorChoiceComponent = (combinationOperatorModel, con
2929
return h(
3030
'.form-group-header.flex-row',
3131
// Available options are always an array
32-
combinationOperatorModel.availableOptions.map((option) => h('.form-check.mr2', [
32+
combinationOperatorModel.options.map((option) => h('.form-check.mr2', [
3333
h('input.form-check-input', {
3434
onclick: () => combinationOperatorModel.select(option),
3535
id: `${selectorPrefix}combination-operator-radio-button-${option.value}`,

lib/public/components/common/selection/SelectionModel.js

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* granted to it by virtue of its status as an Intergovernmental Organization
1111
* or submit itself to any jurisdiction.
1212
*/
13-
import { Observable } from '/js/src/index.js';
13+
import { Observable, RemoteData } from '/js/src/index.js';
1414

1515
/**
1616
* @typedef SelectionOption A picker option, with the actual value and its string representation
@@ -42,8 +42,8 @@ export class SelectionModel extends Observable {
4242
const { availableOptions = [], defaultSelection = [], multiple = true, allowEmpty = true } = configuration || {};
4343

4444
/**
45-
* @type {RemoteData|SelectionOption[]}
46-
* @private
45+
* @type {RemoteData<SelectionOption[]>|SelectionOption[]}
46+
* @protected
4747
*/
4848
this._availableOptions = availableOptions;
4949

@@ -132,17 +132,32 @@ export class SelectionModel extends Observable {
132132
}
133133

134134
/**
135-
* Add the given options to the list of selected ones
135+
* Add the given option or value to the list of selected ones
136136
*
137-
* @param {SelectionOption} option the option to select
137+
* @param {SelectionOption|number|string} option the option to select
138138
* @return {void}
139139
*/
140140
select(option) {
141-
if (!this.isSelected(option)) {
141+
let selectOption;
142+
143+
if (typeof option === 'string' || typeof option === 'number') {
144+
if (this._availableOptions instanceof RemoteData) {
145+
selectOption = this._availableOptions.match({
146+
Success: (options) => options.find(({ value }) => value === option),
147+
Other: () => null,
148+
});
149+
} else {
150+
selectOption = this._availableOptions.find(({ value }) => value === option);
151+
}
152+
} else {
153+
selectOption = option;
154+
}
155+
156+
if (selectOption && !this.isSelected(selectOption)) {
142157
if (this._multiple || this._selectedOptions.length === 0) {
143-
this._selectedOptions.push(option);
158+
this._selectedOptions.push(selectOption);
144159
} else {
145-
this._selectedOptions = [option];
160+
this._selectedOptions = [selectOption];
146161
}
147162

148163
this.notify();
@@ -154,27 +169,32 @@ export class SelectionModel extends Observable {
154169
*
155170
* Depending on the selector, this may be a filtered subset of all the available options
156171
*
157-
* @return {RemoteData|SelectionOption[]} the list of options
172+
* @return {RemoteData<SelectionOption[], *>|SelectionOption[]} the list of options
158173
*/
159174
get options() {
160-
return this._availableOptions;
161-
}
162-
163-
/**
164-
* Return the list of all the available options
165-
*
166-
* @return {RemoteData|SelectionOption[]} the list of available options
167-
*/
168-
get availableOptions() {
169-
return this._availableOptions;
175+
/**
176+
* Add the default options to the list of given options
177+
*
178+
* @param {SelectionOption[]} options the options to which default selection should be added
179+
* @return {SelectionOption[]} the options list including default options
180+
*/
181+
const addDefaultToOptions = (options) => [
182+
...options,
183+
...this.optionsSelectedByDefault.filter((defaultOption) => !options.find(({ value }) => defaultOption.value === value)),
184+
];
185+
186+
return this._availableOptions instanceof RemoteData
187+
? this._availableOptions.apply({ Success: addDefaultToOptions })
188+
: addDefaultToOptions(this._availableOptions);
170189
}
171190

172191
/**
173192
* Defines the list of available options
174193
*
175-
* @param {RemoteData|SelectionOption[]} availableOptions the new available options
194+
* @param {RemoteData<SelectionOption[], *>|SelectionOption[]} availableOptions the new available options
195+
* @return {void}
176196
*/
177-
set availableOptions(availableOptions) {
197+
setAvailableOptions(availableOptions) {
178198
this._availableOptions = availableOptions;
179199
this.visualChange$.notify();
180200
}

lib/public/components/common/selection/dropdown/SelectionDropdownModel.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,22 @@ export class SelectionDropdownModel extends SelectionModel {
6161
* @return {RemoteData|SelectionOption[]} the filtered available options
6262
*/
6363
get options() {
64-
if (this._searchInputContent && this.availableOptions) {
64+
if (this._searchInputContent && this._availableOptions) {
6565
// eslint-disable-next-line require-jsdoc
6666
const filter = ({ rawLabel, label, value }) => (rawLabel || label || value)
6767
.toUpperCase()
6868
.includes(this._searchInputContent.toUpperCase());
69-
if (this.availableOptions instanceof RemoteData) {
70-
if (this.availableOptions.isSuccess()) {
71-
return RemoteData.success(this.availableOptions.payload.filter(filter));
72-
} else {
73-
return this.availableOptions;
74-
}
69+
70+
if (this._availableOptions instanceof RemoteData) {
71+
return this._availableOptions.apply({
72+
Success: (availableOptions) => availableOptions.filter(filter),
73+
});
7574
}
76-
return this.availableOptions.filter(filter);
75+
76+
return this._availableOptions.filter(filter);
7777
}
7878

79-
return this.availableOptions;
79+
return this._availableOptions;
8080
}
8181

8282
// eslint-disable-next-line valid-jsdoc

lib/public/components/common/selection/picker/PickerModel.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,6 @@ export class PickerModel extends SelectionModel {
3838
this._collapsed = !defaultExpand;
3939
}
4040

41-
/**
42-
* If the picker is collapsed expand it, else collapse it
43-
*
44-
* @return {void}
45-
*/
46-
toggleCollapse() {
47-
this._collapsed = !this._collapsed;
48-
this.notify();
49-
}
50-
5141
/**
5242
* Reset the model to its default state
5343
*

lib/public/components/common/selection/picker/picker.js

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@
1111
* or submit itself to any jurisdiction.
1212
*/
1313

14-
import { h, iconMinus, iconPlus } from '/js/src/index.js';
14+
import { h } from '/js/src/index.js';
1515

1616
/**
1717
* @typedef PickerConfiguration The configuration of the picker
18-
* @property {number|null} [limit=5] Amount of items to be shown before collapsable block is shown (null will display all the items)
1918
* @property {string} [selector='picker'] if specified, this will be used to customize picker components ids and classes
2019
* @property {number|null} [attributes=null] if specified, picker items will be wrapped within a component with these attributes. If a limit is
2120
* present and the items overflow, the overflowed elements will be wrapped in a separated component with the same attributes
@@ -65,11 +64,11 @@ const mapOptionsToInput = (pickerModel, pickerOptions, selector) => pickerOption
6564
* @returns {Component} A filterable collapsable picker.
6665
*/
6766
export const picker = (pickerOptions, pickerModel, configuration) => {
68-
const { limit = 5, selector = 'picker', attributes = null, outlineSelection = false, placeHolder = null } = configuration || {};
67+
const { selector = 'picker', attributes = null, placeHolder = null } = configuration || {};
6968

7069
const checkboxes = mapOptionsToInput(pickerModel, pickerOptions, selector);
7170

72-
const selectedPills = pickerModel.selectedOptions.length > 0 && outlineSelection
71+
const selectedPills = pickerModel.selectedOptions.length
7372
? h(
7473
'.flex-row.flex-wrap.g2',
7574
pickerModel.selectedOptions.map(({ label, value }) => h(
@@ -96,25 +95,5 @@ export const picker = (pickerOptions, pickerModel, configuration) => {
9695
}
9796
};
9897

99-
const toggleFilters = h(
100-
`button.btn.btn-primary.mv1#${selector}ToggleMore`,
101-
{ onclick: () => pickerModel.toggleCollapse() },
102-
...pickerModel.collapsed ? [iconPlus(), ' More'] : [iconMinus(), ' Less'],
103-
);
104-
105-
let alwaysVisible = applyAttributes(checkboxes);
106-
let collapsable = null;
107-
if (limit && checkboxes.length > limit) {
108-
alwaysVisible = applyAttributes(checkboxes.slice(0, limit));
109-
collapsable = [toggleFilters];
110-
if (!pickerModel.collapsed) {
111-
collapsable.push(applyAttributes(checkboxes.slice(limit)));
112-
}
113-
}
114-
115-
return [
116-
header,
117-
alwaysVisible,
118-
collapsable,
119-
];
98+
return [header, applyAttributes(checkboxes)];
12099
};

lib/public/components/detector/DetectorSelectionDropdownModel.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ export class DetectorSelectionDropdownModel extends SelectionDropdownModel {
3333
_initialize() {
3434
detectorsProvider.getAll().then(
3535
(detectors) => {
36-
this.availableOptions = RemoteData.success(detectors.map(({ name }) => ({ value: name })));
36+
this.setAvailableOptions(RemoteData.success(detectors.map(({ name }) => ({ value: name }))));
3737
},
3838
(errors) => {
39-
this.availableOptions = RemoteData.failure(errors);
39+
this.setAvailableOptions(RemoteData.failure(errors));
4040
},
4141
);
4242
}

lib/public/components/runTypes/RunTypesSelectionDropdownModel.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,8 @@ export class RunTypesSelectionDropdownModel extends SelectionDropdownModel {
3333
*/
3434
_initialize() {
3535
runTypesProvider.getAll().then(
36-
(runTypes) => {
37-
this.availableOptions = RemoteData.success(runTypes.map(runTypeToOption));
38-
},
39-
(errors) => {
40-
this.availableOptions = RemoteData.failure(errors);
41-
},
36+
(runTypes) => this.setAvailableOptions(RemoteData.success(runTypes.map(runTypeToOption))),
37+
(errors) => this.setAvailableOptions(RemoteData.failure(errors)),
4238
);
4339
}
4440
}

lib/public/components/tag/TagPickerModel.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,8 @@ export class TagPickerModel extends PickerModel {
3333
super({ ...configuration || {}, availableOptions: RemoteData.notAsked() });
3434
const { includeArchived = false } = configuration || {};
3535
(includeArchived ? tagsProvider.getAll() : tagsProvider.getNotArchived()).then(
36-
(tags) => {
37-
this.availableOptions = RemoteData.success(tags.map(tagToOption));
38-
},
39-
(errors) => {
40-
this.availableOptions = RemoteData.failure(errors);
41-
},
36+
(tags) => this.setAvailableOptions(RemoteData.success(tags.map(tagToOption))),
37+
(errors) => this.setAvailableOptions(RemoteData.failure(errors)),
4238
);
4339
}
4440
}

lib/public/components/tag/TagSelectionDropdownModel.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,8 @@ export class TagSelectionDropdownModel extends SelectionDropdownModel {
3737
*/
3838
_initialize() {
3939
(this._includeArchived ? tagsProvider.getAll() : tagsProvider.getNotArchived()).then(
40-
(tags) => {
41-
this.availableOptions = RemoteData.success(tags.map(tagToOption));
42-
},
43-
(errors) => {
44-
this.availableOptions = RemoteData.failure(errors);
45-
},
40+
(tags) => this.setAvailableOptions(RemoteData.success(tags.map(tagToOption))),
41+
(errors) => this.setAvailableOptions(RemoteData.failure(errors)),
4642
);
4743
}
4844
}

0 commit comments

Comments
 (0)