clearml-web/src/app/webapp-common/select-model/select-model.component.ts
shyallegro 34f2167598
Release v1.13 (#64)
Co-authored-by: shallegro <shay@allego.ai>
2023-11-17 10:24:49 +02:00

202 lines
9.1 KiB
TypeScript
Executable File

import {ChangeDetectionStrategy, Component, EventEmitter, Inject, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {Store} from '@ngrx/store';
import * as actions from './select-model.actions';
import {clearTableFilter, setSelectedModels, showArchive} from './select-model.actions';
import {
selectGlobalFilter, selectModels, selectNoMoreModels, selectSelectedModels, selectSelectedModelsList, selectSelectModelTableFilters, selectShowArchive, selectTableSortFields, selectViewMode
} from './select-model.reducer';
import {combineLatest, Observable, Subscription} from 'rxjs';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {ConfirmDialogComponent} from '../shared/ui-components/overlay/confirm-dialog/confirm-dialog.component';
import {ColHeaderTypeEnum, ISmCol, TableSortOrderEnum} from '../shared/ui-components/data/table/table.consts';
import {SelectedModel, TableModel} from '../models/shared/models.model';
import {MODELS_TABLE_COLS, ModelsViewModesEnum} from '../models/models.consts';
import {FilterMetadata} from 'primeng/api/filtermetadata';
import {selectAllProjectsUsers, selectProjectSystemTags, selectSelectedProject, selectTablesFilterProjectsOptions} from '../core/reducers/projects.reducer';
import {selectMetadataColsForProject, selectMetadataColsOptions, selectModelsFrameworks, selectModelsTags, selectModelTableColumns} from '../models/reducers';
import {User} from '~/business-logic/model/users/user';
import * as modelsActions from '../models/actions/models-view.actions';
import {SortMeta} from 'primeng/api';
import {ModelsTableComponent} from '@common/models/shared/models-table/models-table.component';
import {debounceTime, distinctUntilChanged, map, tap} from 'rxjs/operators';
import {Project} from '~/business-logic/model/projects/models';
import {getTablesFilterProjectsOptions, resetTablesFilterProjectsOptions} from '@common/core/actions/projects.actions';
import {isEqual, unionBy} from 'lodash-es';
import {compareLimitations} from '@common/shared/entity-page/footer-items/compare-footer-item';
import {addMessage} from '@common/core/actions/layout.actions';
import {MESSAGES_SEVERITY} from '@common/constants';
@Component({
selector: 'sm-select-model',
templateUrl: './select-model.component.html',
styleUrls: ['./select-model.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SelectModelComponent implements OnInit, OnDestroy {
public models$: Observable<SelectedModel[]>;
public tableSortFields$: Observable<SortMeta[]>;
public tableSortOrder$: Observable<TableSortOrderEnum>;
public noMoreModels$: Observable<boolean>;
public tableFilters$: Observable<{ [s: string]: FilterMetadata }>;
public searchValue$: Observable<string>;
public selectedModels$: Observable<Array<TableModel>>;
public viewMode$: Observable<ModelsViewModesEnum>;
public users$: Observable<Array<User>>;
public tags$: Observable<string[]>;
public systemTags$: Observable<string[]>;
public tableCols = MODELS_TABLE_COLS;
public selectedProject$: Observable<Project>;
public projectsOptions$: Observable<Project[]>;
public frameworks$: Observable<string[]>;
private subs = new Subscription();
public selectedProject: Project;
private selectedModels: Array<SelectedModel>;
private columns$: Observable<ISmCol[]>;
private metadataTableCols$: Observable<ISmCol[]>;
public tableCols$: Observable<ISmCol[]>;
public metadataColsOptions$: Observable<Record<string, string[]>>;
public showArchive$: Observable<boolean>;
constructor(private store: Store,
public dialogRef: MatDialogRef<ConfirmDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: {
selectionMode: 'multiple' | 'single' | null;
selectedModels: string[];
header: string;
hideShowArchived: boolean;
}) {
// this.models$ = this.store.select(selectModelsList);
this.models$ = combineLatest([
this.store.select(selectModels),
this.store.select(selectSelectedModelsList),
]).pipe(
map(([models, selectedModels]) => unionBy(selectedModels, models, 'id')),
map(models => models?.map(model => ({...model, system_tags: model.system_tags?.map((t => t.replace('archive', ' archive')))})))
);
this.tableSortFields$ = this.store.select(selectTableSortFields);
this.tableFilters$ = this.store.select(selectSelectModelTableFilters);
this.selectedModels$ = this.store.select(selectSelectedModels).pipe(tap(models => this.selectedModels = models));
this.viewMode$ = this.store.select(selectViewMode);
this.searchValue$ = this.store.select(selectGlobalFilter);
this.noMoreModels$ = this.store.select(selectNoMoreModels);
this.showArchive$ = this.store.select(selectShowArchive);
this.users$ = this.store.select(selectAllProjectsUsers);
this.tags$ = this.store.select(selectModelsTags);
this.systemTags$ = this.store.select(selectProjectSystemTags);
this.subs.add(this.store.select(selectSelectedProject).pipe(debounceTime(100))
.subscribe(selectedProject => {
this.selectedProject = selectedProject;
if (selectedProject?.id !== '*') {
this.store.dispatch(actions.tableFilterChanged({col: {id: 'project.name'}, value: [selectedProject.id]}));
}
}));
this.frameworks$ = this.store.select(selectModelsFrameworks);
this.projectsOptions$ = this.store.select(selectTablesFilterProjectsOptions);
this.metadataColsOptions$ = this.store.select(selectMetadataColsOptions);
this.columns$ = this.store.select(selectModelTableColumns);
this.metadataTableCols$ = this.store.select(selectMetadataColsForProject);
this.tableCols$ = combineLatest([this.columns$, this.metadataTableCols$])
.pipe(
map(([tableCols, metricCols]) =>
(tableCols.length > 0 ? tableCols : this.tableCols)
.concat(metricCols.map(col => ({...col, metric: true})))
),
distinctUntilChanged((a, b) => isEqual(a, b)),
map(cols => cols.filter(col => (!col.hidden || col.id === 'project.name')).map(col => ({
...col,
hidden: false,
headerType: col.headerType === ColHeaderTypeEnum.checkBox ? ColHeaderTypeEnum.title : col.headerType,
...(col.id === 'project.name' && {
getter: 'project',
filterable: true,
searchableFilter: true,
sortable: false,
headerType: ColHeaderTypeEnum.sortFilter,
}),
})
)));
}
@ViewChild(ModelsTableComponent) table: ModelsTableComponent;
ngOnInit() {
this.store.dispatch(resetTablesFilterProjectsOptions());
this.store.dispatch(actions.getNextModels());
this.data.selectedModels && this.store.dispatch(actions.getSelectedModels({selectedIds: this.data.selectedModels}));
this.store.dispatch(modelsActions.getAllProjectsFrameworks());
this.store.dispatch(modelsActions.getTagsForAllProjects());
window.setTimeout(() => this.table.table.rowRightClick = new EventEmitter());
}
ngOnDestroy(): void {
this.store.dispatch(resetTablesFilterProjectsOptions());
this.store.dispatch(actions.resetSelectModelState({fullReset: false}));
this.subs.unsubscribe();
}
closeDialog(modelId: string) {
if (modelId) {
return this.dialogRef.close(modelId);
}
return this.dialogRef.close(null);
}
closeDialogMultiple() {
return this.dialogRef.close(this.selectedModels.map(model => model.id));
}
getNextModels() {
this.store.dispatch(actions.getNextModels());
}
sortedChanged(sort: { isShift: boolean; colId: ISmCol['id'] }) {
this.store.dispatch(actions.tableSortChanged({colId: sort.colId, isShift: sort.isShift}));
}
filterChanged(filter: { col: ISmCol; value: string }) {
this.store.dispatch(actions.tableFilterChanged({col: filter.col, value: filter.value}));
}
onSearchValueChanged(value: string) {
this.store.dispatch(actions.globalFilterChanged({filter: value}));
}
modelSelectionChanged(event: { model: SelectedModel }) {
if (this.data.selectionMode !== 'multiple') {
this.closeDialog(event.model?.id);
}
}
modelsSelectionChanged(models: SelectedModel[]) {
if (this.data.selectionMode !== 'multiple') {
return;
}
if (models.length === 0) {
this.store.dispatch(addMessage(MESSAGES_SEVERITY.WARN, 'Compare module should include at least one model'));
return;
}
if (models.length <= compareLimitations) {
this.store.dispatch(setSelectedModels({models}));
} else {
this.store.dispatch(addMessage(MESSAGES_SEVERITY.WARN, compareLimitations + ' or fewer models can be compared'));
}
}
filterSearchChanged({value}: { colId: string; value: { value: string; loadMore?: boolean } }) {
!value.loadMore && this.store.dispatch(resetTablesFilterProjectsOptions());
this.store.dispatch(getTablesFilterProjectsOptions({searchString: value.value || '', loadMore: value.loadMore}));
}
clearFilters() {
this.store.dispatch(clearTableFilter());
}
showArchives($event: boolean) {
this.store.dispatch(showArchive({showArchive: $event}));
}
}