Skip to content

Commit ca3b94f

Browse files
committed
refactor
1 parent 3444017 commit ca3b94f

8 files changed

Lines changed: 279 additions & 211 deletions

File tree

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/**
2+
* @license
3+
* Copyright CERN and copyright holders of ALICE O2. This software is
4+
* distributed under the terms of the GNU General Public License v3 (GPL
5+
* Version 3), copied verbatim in the file "COPYING".
6+
*
7+
* See http://alice-o2.web.cern.ch/license for full licensing information.
8+
*
9+
* In applying this license CERN does not waive the privileges and immunities
10+
* granted to it by virtue of its status as an Intergovernmental Organization
11+
* or submit itself to any jurisdiction.
12+
*/
13+
14+
import { Observable } from '/js/src/index.js';
15+
import { createCSVExport, createJSONExport } from '../utilities/export.js';
16+
import pick from '../utilities/pick.js';
17+
18+
/**
19+
* Model handling export configuration and creation
20+
*/
21+
export class DataExportModel extends Observable {
22+
/**
23+
* Constructor
24+
* @param {ObservableData<RemoteData<object[]>>} items$ observable data used as source for export
25+
*/
26+
constructor(items$) {
27+
super();
28+
29+
/** @type {ObservableData<RemoteData<object[]>>} */
30+
this._items$ = items$;
31+
this._items$.bubbleTo(this);
32+
33+
/** @type {string[]} */
34+
this._selectedFields = [];
35+
36+
/** @type {string} */
37+
this._selectedExportType = 'JSON';
38+
39+
/** @type {Observable} */
40+
this._visualChange$ = new Observable();
41+
42+
this._exportName = 'data';
43+
44+
this.columnFormats = null;
45+
}
46+
47+
/**
48+
* Return the current items remote data
49+
*
50+
* @return {RemoteData<T[]>} the items
51+
*/
52+
get items() {
53+
return this._items$.getCurrent();
54+
}
55+
56+
/**
57+
* Observable notified when the export configuration visually changes
58+
* @return {Observable}
59+
*/
60+
get visualChange$() {
61+
return this._visualChange$;
62+
}
63+
64+
/**
65+
* Get export type selected by the user
66+
* @return {string} export type
67+
*/
68+
get selectedExportType() {
69+
return this._selectedExportType;
70+
}
71+
72+
/**
73+
* Set export type
74+
* @param {string} exportType export type
75+
* @return {void}
76+
*/
77+
setSelectedExportType(exportType) {
78+
this._selectedExportType = exportType;
79+
this.notify();
80+
this._visualChange$.notify();
81+
}
82+
83+
/**
84+
* Get selected fields
85+
* @return {string[]} selected fields
86+
*/
87+
get selectedFields() {
88+
return this._selectedFields;
89+
}
90+
91+
/**
92+
* Update selected fields from HTML options list
93+
* @param {HTMLCollection|Array} selectedOptions options collection
94+
* @return {void}
95+
*/
96+
setSelectedFields(selectedOptions) {
97+
this._selectedFields = [];
98+
[...selectedOptions].forEach(({ value }) => this._selectedFields.push(value));
99+
this.notify();
100+
this._visualChange$.notify();
101+
}
102+
103+
/**
104+
* Create export using current items observable
105+
* @return {Promise<void>} void
106+
*/
107+
async createExport() {
108+
this.items.apply({
109+
Success: (items) => {
110+
const { selectedFields } = this;
111+
112+
const formatted = items.map((item) => {
113+
const selectedEntries = Object.entries(pick(item, selectedFields));
114+
const mappedEntries = selectedEntries.map(([key, value]) => {
115+
const formatter = this.columnFormats[key]?.exportFormat || ((v) => v);
116+
return [key, formatter(value, item)];
117+
});
118+
119+
return Object.fromEntries(mappedEntries);
120+
});
121+
122+
this.selectedExportType === 'CSV'
123+
? createCSVExport(formatted, `${this._exportName}.csv`, 'text/csv;charset=utf-8;')
124+
: createJSONExport(formatted, `${this._exportName}.json`, 'application/json');
125+
},
126+
});
127+
}
128+
}

lib/public/views/Runs/Overview/RunsOverviewModel.js

Lines changed: 12 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@
1212
*/
1313

1414
import { buildUrl, RemoteData } from '/js/src/index.js';
15-
import { createCSVExport, createJSONExport } from '../../../utilities/export.js';
1615
import { TagFilterModel } from '../../../components/Filters/common/TagFilterModel.js';
1716
import { debounce } from '../../../utilities/debounce.js';
1817
import { DetectorsFilterModel } from '../../../components/Filters/RunsFilter/DetectorsFilterModel.js';
1918
import { RunTypesFilterModel } from '../../../components/runTypes/RunTypesFilterModel.js';
2019
import { EorReasonFilterModel } from '../../../components/Filters/RunsFilter/EorReasonFilterModel.js';
21-
import pick from '../../../utilities/pick.js';
2220
import { OverviewPageModel } from '../../../models/OverviewModel.js';
2321
import { getRemoteDataSlice } from '../../../utilities/fetch/getRemoteDataSlice.js';
2422
import { CombinationOperator } from '../../../components/Filters/common/CombinationOperatorChoiceModel.js';
@@ -35,6 +33,7 @@ import { RawTextFilterModel } from '../../../components/Filters/common/filters/R
3533
import { RunDefinitionFilterModel } from '../../../components/Filters/RunsFilter/RunDefinitionFilterModel.js';
3634
import { RUN_QUALITIES } from '../../../domain/enums/RunQualities.js';
3735
import { SelectionFilterModel } from '../../../components/Filters/common/filters/SelectionFilterModel.js';
36+
import { DataExportModel } from '../../../models/DataExportModel.js';
3837

3938
/**
4039
* Model representing handlers for runs page
@@ -100,10 +99,21 @@ export class RunsOverviewModel extends OverviewPageModel {
10099
const updateDebounceTime = () => {
101100
this._debouncedLoad = debounce(this.load.bind(this), model.inputDebounceTime);
102101
};
102+
103+
this._exportModel = new DataExportModel(this._observableItems);
104+
103105
model.appConfiguration$.observe(() => updateDebounceTime());
104106
updateDebounceTime();
105107
}
106108

109+
/**
110+
* Get export model
111+
* @return {DataExportModel} export model
112+
*/
113+
get exportModel() {
114+
return this._exportModel;
115+
}
116+
107117
/**
108118
* @inheritdoc
109119
*/
@@ -119,55 +129,6 @@ export class RunsOverviewModel extends OverviewPageModel {
119129
super.load();
120130
}
121131

122-
/**
123-
* Create the export with the variables set in the model, handling errors appropriately
124-
* @param {object[]} runs The source content.
125-
* @param {string} fileName The name of the file including the output format.
126-
* @param {Object<string, Function<*, string>>} exportFormats defines how particular fields of data units will be formated
127-
* @return {void}
128-
*/
129-
async createRunsExport(runs, fileName, exportFormats) {
130-
if (runs.length > 0) {
131-
const selectedRunsFields = this.getSelectedRunsFields() || [];
132-
runs = runs.map((selectedRun) => {
133-
const entries = Object.entries(pick(selectedRun, selectedRunsFields));
134-
const formattedEntries = entries.map(([key, value]) => {
135-
const formatExport = exportFormats[key].exportFormat || ((identity) => identity);
136-
return [key, formatExport(value, selectedRun)];
137-
});
138-
return Object.fromEntries(formattedEntries);
139-
});
140-
this.getSelectedExportType() === 'CSV'
141-
? createCSVExport(runs, `${fileName}.csv`, 'text/csv;charset=utf-8;')
142-
: createJSONExport(runs, `${fileName}.json`, 'application/json');
143-
} else {
144-
this._observableItems.setCurrent(RemoteData.failure([
145-
{
146-
title: 'No data found',
147-
detail: 'No valid runs were found for provided run number(s)',
148-
},
149-
]));
150-
this.notify();
151-
}
152-
}
153-
154-
/**
155-
* Get the field values that will be exported
156-
* @return {Array} the field objects of the current export being created
157-
*/
158-
getSelectedRunsFields() {
159-
return this.selectedRunsFields;
160-
}
161-
162-
/**
163-
* Get the output format of the export
164-
*
165-
* @return {string} the output format
166-
*/
167-
getSelectedExportType() {
168-
return this.selectedExportType;
169-
}
170-
171132
/**
172133
* Returns all filtering, sorting and pagination settings to their default values
173134
* @param {boolean} [fetch = true] whether to refetch all data after filters have been reset
@@ -220,29 +181,6 @@ export class RunsOverviewModel extends OverviewPageModel {
220181
return this._filteringModel;
221182
}
222183

223-
/**
224-
* Set the export type parameter of the current export being created
225-
* @param {string} selectedExportType Received string from the view
226-
* @return {void}
227-
*/
228-
setSelectedExportType(selectedExportType) {
229-
this.selectedExportType = selectedExportType;
230-
this.notify();
231-
}
232-
233-
/**
234-
* Updates the selected fields ID array according to the HTML attributes of the options
235-
*
236-
* @param {HTMLCollection} selectedOptions The currently selected fields by the user,
237-
* according to HTML specification
238-
* @return {undefined}
239-
*/
240-
setSelectedRunsFields(selectedOptions) {
241-
this.selectedRunsFields = [];
242-
[...selectedOptions].map((selectedOption) => this.selectedRunsFields.push(selectedOption.value));
243-
this.notify();
244-
}
245-
246184
/**
247185
* Getter for the trigger values filter Set
248186
* @return {Set} set of trigger filter values

lib/public/views/Runs/Overview/RunsOverviewPage.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
import { h } from '/js/src/index.js';
1515
import { estimateDisplayableRowsCount } from '../../../utilities/estimateDisplayableRowsCount.js';
16-
import { exportRunsTriggerAndModal } from './exportRunsTriggerAndModal.js';
16+
import { exportTriggerAndModal } from './exportTriggerAndModal.js';
1717
import { filtersPanelPopover } from '../../../components/Filters/common/filtersPanelPopover.js';
1818
import { paginationComponent } from '../../../components/Pagination/paginationComponent.js';
1919
import { runsActiveColumns } from '../ActiveColumns/runsActiveColumns.js';
@@ -51,12 +51,14 @@ export const RunsOverviewPage = ({ runs: { overviewModel: runsOverviewModel }, m
5151
PAGE_USED_HEIGHT,
5252
));
5353

54+
runsOverviewModel.exportModel.columnFormats = runsActiveColumns;
55+
5456
return h('', [
5557
h('.flex-row.header-container.g2.pv2', [
5658
filtersPanelPopover(runsOverviewModel, runsActiveColumns),
5759
h('.pl2#runOverviewFilter', runNumbersFilter(runsOverviewModel.filteringModel.get('runNumbers'))),
5860
togglePhysicsOnlyFilter(runsOverviewModel.filteringModel.get('definitions')),
59-
exportRunsTriggerAndModal(runsOverviewModel, modalModel),
61+
exportTriggerAndModal(runsOverviewModel.exportModel, modalModel),
6062
]),
6163
h('.flex-column.w-100', [
6264
table(runsOverviewModel.items, runsActiveColumns),

0 commit comments

Comments
 (0)