Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
fe19db7
chore: rename fetchLogs to load
Jun 18, 2026
94b04f7
chore: rename overviewSortModel to sortModel
Jun 18, 2026
6efeb00
load patch
Jun 18, 2026
41f2678
chore: rename logs to items$
Jun 18, 2026
eb4ed78
feat: make logsOverveiwModel extend overviewModel
Jun 18, 2026
d20f115
chore: fix spelling mistake
Jun 18, 2026
aa2af05
feat: create FilterableOverviewPageModel
Jun 19, 2026
5936b8e
feat: migrate datapassesOverviewModel
Jun 19, 2026
37ec014
feat: migrate environmentsOverviewModel
Jun 19, 2026
6a2806a
feat: migrate LhcFillsOverviewModel
Jun 19, 2026
855e4a0
feat: migrate LhcPeriodsOverviewModel
Jun 19, 2026
81c0e06
feat: migrate LogsOverviewModel
Jun 19, 2026
4e55f37
feat: migrate QCFlagTypesOverviewModel
Jun 19, 2026
7f5f857
feat: migrate RunsOverviewModel
Jun 19, 2026
218af8f
feat: migrate AnchoredSimulationPassesOverviewModel
Jun 19, 2026
9dcd8fa
feat: migrate SimulationPassesPerLhcPeriodOverviewModel
Jun 19, 2026
1fcdf9e
Merge branch 'main' into improv/O2B-1595/add-filterable-overview-page…
Jun 19, 2026
db4490f
patch-up reset of runs
Jun 19, 2026
8a7dfa0
chore: add jsdoc arguments for FilterablePageOverviewModel constructor
Jun 19, 2026
130d00b
chore: remove needless resetFilters from runsOverviewModel
Jun 19, 2026
eb060a9
chore: remove useless commands from LhcPeriodsOverviewModel
Jun 19, 2026
26a337e
remove debounce functionallity from logsOverviewModel
Jun 19, 2026
1b4d532
prevent multiple fetches from repeated observations
Jun 19, 2026
6317575
remove debounce functionallity from EnvironmentsOverviewModel
Jun 19, 2026
8059d2c
remove debounce functionallity from EnvironmentsOverviewModel
Jun 19, 2026
33c084b
fix eslint issues
Jun 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions lib/public/models/FilterableOverviewPageModel.js
Comment thread
graduta marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

import { buildUrl } from '/js/src/index.js';
import { OverviewPageModel } from './OverviewModel.js';
import { FilteringModel } from '../components/Filters/common/FilteringModel.js';

/**
* Base model for a filterable overview page
*
* @template T the type of data displayed in the overview page
*/
export class FilterableOverviewPageModel extends OverviewPageModel {
/**
* Constructor
* @param {QueryRouter} router router that controls the application's page navigation
* @param {string} pageIdentifier string that indicates what page this model represents
* @param {Object<string, FilterModel>} filters the filters with their label and model
*/
constructor(router, pageIdentifier, filters) {
super();
this._filteringModel = new FilteringModel(router, filters, this._warnings);

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.visualChange$.bubbleTo(this);
this._filteringModel.observe(() => this._applyFilters());
this._sortModel.unobserve(this._sortModelCallback);
this._sortModel.observe(() => this._applyFilters());
Comment thread
graduta marked this conversation as resolved.
this._debouncedLoad = (_time) => {}; // Abstract, does nothing on purpose
this._fetchInstantly = true;
}

/**
* Builds a url string from filters and a base string
*
* @param {string} base the base string from which the endpoint will be built
* @return {string}
*/
buildRootEndpoint(base) {
return buildUrl(base, { filter: this.getFilterParams() });
}

/**
* Sets the fetchInstantly boolean
* @param {boolean} bool the value to set
* @return {void}
*/
set fetchInstantly(bool) {
this._fetchInstantly = bool;
}

/**
* Returns all filtering, sorting and pagination settings to their default values
* @param {boolean} [fetch = true] whether to refetch all data after filters have been reset
* @return {void}
*/
reset(fetch = true) {
super.reset();
this.resetFiltering(fetch);
}

/**
* Reset all filtering models
* @param {boolean} fetch Whether to refetch all data after filters have been reset
* @param {boolean} [clearUrl=false] if true filters will be removed from the url
* @return {void}
*/
resetFiltering(fetch = true, clearUrl = false) {
this._filteringModel.reset(false, clearUrl);

if (fetch) {
this._applyFilters(true);
}
}

/**
* Checks if any filter value has been modified from their default (empty)
* @return {Boolean} If any filter is active
*/
isAnyFilterActive() {
return this._filteringModel.isAnyFilterActive();
}

/**
* Apply the current filtering and update the remote data list
*
* @param {boolean} now if true, filtering will be applied now without debouncing
*
* @return {void}
*/
_applyFilters() {
this._pagination.silentlySetCurrentPage(1);
this._fetchInstantly ? this.load() : this._debouncedLoad();
}

/**
* Set underlying FilteringModel's filters from the query parameters in the URL
*
* @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters
*/
setFilterFromURL(notify) {
this._filteringModel.setFilterFromURL(notify);
}

/**
* Return the filtering model
*
* @return {FilteringModel} the filtering model
*/
get filteringModel() {
return this._filteringModel;
}

/**
* Return filter params of base model
*
* @return {object} filter
*/
getFilterParams() {
return this._filteringModel.normalized;
}
}
7 changes: 5 additions & 2 deletions lib/public/models/OverviewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ export class OverviewPageModel extends Observable {
super();
this._warnings = new Map();
this._sortModel = new SortModel();
this._sortModel.observe(() => {

this._sortModelCallback = () => {
this._pagination.silentlySetCurrentPage(1);
this.load();
});
};

this._sortModel.observe(this._sortModelCallback);
this._sortModel.visualChange$.bubbleTo(this);

// Single page data handling
Expand Down
56 changes: 4 additions & 52 deletions lib/public/views/DataPasses/DataPassesOverviewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,77 +11,29 @@
* or submit itself to any jurisdiction.
*/
import { SelectionModel } from '../../components/common/selection/SelectionModel.js';
import { FilteringModel } from '../../components/Filters/common/FilteringModel.js';
import { TextTokensFilterModel } from '../../components/Filters/common/filters/TextTokensFilterModel.js';
import { NON_PHYSICS_PRODUCTIONS_NAMES_WORDS } from '../../domain/enums/NonPhysicsProductionsNamesWords.js';
import { OverviewPageModel } from '../../models/OverviewModel.js';
import { FilterableOverviewPageModel } from '../../models/FilterableOverviewPageModel.js';

/**
* Data Passes overview model
*/
export class DataPassesOverviewModel extends OverviewPageModel {
export class DataPassesOverviewModel extends FilterableOverviewPageModel {
/**
* Constructor
* @param {QueryRouter} router router that controls the application's page navigation
* @param {string} pageIdentifier string that indicates what page this model represents
*/
constructor(router, pageIdentifier) {
super();
this._filteringModel = new FilteringModel(
super(
router,
pageIdentifier,
{
names: new TextTokensFilterModel(),
permittedNonPhysicsNames: new SelectionModel({
availableOptions: NON_PHYSICS_PRODUCTIONS_NAMES_WORDS.map((word) => ({ label: word.toUpperCase(), value: word })),
}),
},
this._warnings,
);

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.visualChange$.bubbleTo(this);
this._filteringModel.observe(() => {
this._pagination.currentPage = 1;
this.load();
});
}

/**
* Return filter params of base model
*
* @return {object} filter
*/
getFilterParams() {
return this._filteringModel.normalized;
}

/**
* Set underlying FilteringModel's filters from the query parameters in the URL
*
* @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters
*/
setFilterFromURL(notify) {
this._filteringModel.setFilterFromURL(notify);
}

/**
* Reset this model to its default
*
* @param {boolean} _fetch Whether to refetch all data after filters have been reset
* @param {boolean} [clearUrl=false] if true filters will be removed from the url
* @return {void}
*/
reset(_fetch = true, clearUrl = false) {
this._filteringModel.reset(false, clearUrl);
super.reset();
}

/**
* Return the filtering model
*
* @return {FilteringModel} the filtering model
*/
get filteringModel() {
return this._filteringModel;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,26 @@
* or submit itself to any jurisdiction.
*/

import { buildUrl } from '/js/src/index.js';
import { FilteringModel } from '../../../components/Filters/common/FilteringModel.js';
import { OverviewPageModel } from '../../../models/OverviewModel.js';
import { TimeRangeInputModel } from '../../../components/Filters/common/filters/TimeRangeInputModel.js';
import { RawTextFilterModel } from '../../../components/Filters/common/filters/RawTextFilterModel.js';
import { debounce } from '../../../utilities/debounce.js';
import { coloredEnvironmentStatusComponent } from '../ColoredEnvironmentStatusComponent.js';
import { StatusAcronym } from '../../../domain/enums/statusAcronym.mjs';
import { SelectionModel } from '../../../components/common/selection/SelectionModel.js';
import { FilterableOverviewPageModel } from '../../../models/FilterableOverviewPageModel.js';

/**
* Environment overview page model
*/
export class EnvironmentOverviewModel extends OverviewPageModel {
export class EnvironmentOverviewModel extends FilterableOverviewPageModel {
/**
* Constructor
* @param {Model} model global model
* @param {string} pageIdentifier string that indicates what page this model represents
*/
constructor(model, pageIdentifier) {
super();

this._filteringModel = new FilteringModel(
super(
model.router,
pageIdentifier,
{
created: new TimeRangeInputModel(),
runNumbers: new RawTextFilterModel(),
Expand All @@ -48,35 +44,14 @@ export class EnvironmentOverviewModel extends OverviewPageModel {
}),
ids: new RawTextFilterModel(),
},
this._warnings,
);

this._filteringModel.pageIdentifier = pageIdentifier;
this._filteringModel.observe(() => this._applyFilters(true));
this._filteringModel.visualChange$?.bubbleTo(this);

const updateDebounceTime = () => {
this._debouncedLoad = debounce(this.load.bind(this), model.inputDebounceTime);
};

model.appConfiguration$.observe(() => updateDebounceTime());
updateDebounceTime();
}

/**
* @inheritDoc
*/
getRootEndpoint() {
return buildUrl('/api/environments', { filter: this.filteringModel.normalized });
}

/**
* Set underlying FilteringModel's filters from the query parameters in the URL
*
* @param {boolean} notify if the FilteringModel should notify it's observers after finishing setting the filters
*/
setFilterFromURL(notify) {
this._filteringModel.setFilterFromURL(notify);
return this.buildRootEndpoint('/api/environments');
}

/**
Expand All @@ -87,57 +62,4 @@ export class EnvironmentOverviewModel extends OverviewPageModel {
get environments() {
return this.items;
}

/**
* Returns all filtering, sorting and pagination settings to their default values
* @param {boolean} [fetch = true] whether to refetch all data after filters have been reset
* @return {void}
*/
reset(fetch = true) {
super.reset();
this.resetFiltering(fetch);
}

/**
* Reset all filtering models
* @param {boolean} fetch Whether to refetch all data after filters have been reset
* @param {boolean} [clearUrl=false] if true filters will be removed from the url
* @return {void}
*/
resetFiltering(fetch = true, clearUrl = false) {
this._filteringModel.reset(false, clearUrl);

if (fetch) {
this._applyFilters(true);
}
}

/**
* Checks if any filter value has been modified from their default (empty)
* @return {Boolean} If any filter is active
*/
isAnyFilterActive() {
return this._filteringModel.isAnyFilterActive();
}

/**
* Return the filtering model
*
* @return {FilteringModel} the filtering model
*/
get filteringModel() {
return this._filteringModel;
}

/**
* Apply the current filtering and update the remote data list
*
* @param {boolean} now if true, filtering will be applied now without debouncing
*
* @return {void}
*/
_applyFilters(now = false) {
this._pagination.currentPage = 1;
now ? this.load() : this._debouncedLoad(true);
}
}
Loading