mirror of
https://github.com/clearml/clearml-web
synced 2025-06-26 18:27:02 +00:00
release v1.11
This commit is contained in:
committed by
Shay Halsband
parent
29c68abeb4
commit
28d1702075
@@ -2,11 +2,15 @@
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
not ie <= 11
|
||||
last 2 Chrome versions
|
||||
last 2 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": "error",
|
||||
"no-debugger": "error",
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
@@ -88,7 +90,9 @@
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/template/recommended"
|
||||
],
|
||||
"rules": {}
|
||||
"rules": {
|
||||
"@angular-eslint/template/use-track-by-function": "warn"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,7 +7,6 @@
|
||||
/out-tsc
|
||||
/gen-code
|
||||
/src/__ngcc_entry_points__.json
|
||||
.angular/
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
@@ -30,6 +29,7 @@
|
||||
!.vscode/extensions.json
|
||||
|
||||
# misc
|
||||
/.angular/cache
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
|
||||
18
angular.json
18
angular.json
@@ -47,7 +47,6 @@
|
||||
"node_modules/ngx-markdown-editor/assets/marked.min.js"
|
||||
],
|
||||
"allowedCommonJsDependencies": [
|
||||
"lodash/fp",
|
||||
"ansi-to-html",
|
||||
"has-ansi",
|
||||
"fabric/dist/fabric.min",
|
||||
@@ -66,7 +65,10 @@
|
||||
"britecharts/dist/umd/line.min",
|
||||
"britecharts/dist/umd/tooltip.min",
|
||||
"britecharts/dist/umd/miniTooltip.min",
|
||||
"britecharts/dist/umd/scatterPlot.min"
|
||||
"britecharts/dist/umd/scatterPlot.min",
|
||||
"localforage",
|
||||
"dom-to-image",
|
||||
"ace-builds"
|
||||
],
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
@@ -128,7 +130,10 @@
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "trains-webapp:build"
|
||||
"browserTarget": "trains-webapp:build",
|
||||
"proxyConfig": "proxy.config.js",
|
||||
"liveReload": false,
|
||||
"port": 4300
|
||||
},
|
||||
"configurations": {
|
||||
"appdev": {
|
||||
@@ -292,7 +297,6 @@
|
||||
"src/app/webapp-common/clearml-applications/report-widgets/src/app/webapp-common/assets",
|
||||
"src/app/webapp-common/clearml-applications/report-widgets/src/app/webapp-common/assets/fonts/trains.ttf"
|
||||
],
|
||||
|
||||
"styles": [
|
||||
"src/app/webapp-common/clearml-applications/report-widgets/src/styles.scss",
|
||||
{
|
||||
@@ -311,6 +315,12 @@
|
||||
"@schematics/angular:component": {
|
||||
"prefix": "sm",
|
||||
"style": "scss"
|
||||
},
|
||||
"@angular-eslint/schematics:application": {
|
||||
"setParserOptionsProject": true
|
||||
},
|
||||
"@angular-eslint/schematics:library": {
|
||||
"setParserOptionsProject": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5941
package-lock.json
generated
5941
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
110
package.json
110
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clearml-webapp",
|
||||
"version": "1.10.0",
|
||||
"version": "1.11.0",
|
||||
"license": "",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
@@ -19,54 +19,54 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^15.1.3",
|
||||
"@angular/cdk": "^15.1.3",
|
||||
"@angular/common": "^15.1.3",
|
||||
"@angular/compiler": "^15.1.3",
|
||||
"@angular/core": "^15.1.3",
|
||||
"@angular/forms": "^15.1.3",
|
||||
"@angular/material": "^15.1.3",
|
||||
"@angular/platform-browser": "^15.1.3",
|
||||
"@angular/platform-browser-dynamic": "^15.1.3",
|
||||
"@angular/platform-server": "^15.1.3",
|
||||
"@angular/router": "^15.1.3",
|
||||
"@angular/service-worker": "^15.1.3",
|
||||
"@angular/youtube-player": "^15.1.3",
|
||||
"@aws-sdk/client-s3": "^3.266.1",
|
||||
"@aws-sdk/s3-request-presigner": "^3.266.1",
|
||||
"@angular/animations": "^15.2.8",
|
||||
"@angular/cdk": "^15.2.8",
|
||||
"@angular/common": "^15.2.8",
|
||||
"@angular/compiler": "^15.2.8",
|
||||
"@angular/core": "^15.2.8",
|
||||
"@angular/forms": "^15.2.8",
|
||||
"@angular/material": "^15.2.8",
|
||||
"@angular/platform-browser": "^15.2.8",
|
||||
"@angular/platform-browser-dynamic": "^15.2.8",
|
||||
"@angular/platform-server": "^15.2.8",
|
||||
"@angular/router": "^15.2.8",
|
||||
"@angular/service-worker": "^15.2.8",
|
||||
"@angular/youtube-player": "^15.2.8",
|
||||
"@aws-sdk/client-s3": "^3.317.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.317.0",
|
||||
"@ctrl/ngx-github-buttons": "^8.0.0",
|
||||
"@ngneat/dag": "^2.0.0",
|
||||
"@ngrx/effects": "^15.2.1",
|
||||
"@ngrx/entity": "^15.2.1",
|
||||
"@ngrx/router-store": "^15.2.1",
|
||||
"@ngrx/store": "^15.2.1",
|
||||
"ace-builds": "^1.15.0",
|
||||
"@ngrx/effects": "^15.4.0",
|
||||
"@ngrx/entity": "^15.4.0",
|
||||
"@ngrx/router-store": "^15.4.0",
|
||||
"@ngrx/store": "^15.4.0",
|
||||
"ace-builds": "^1.18.0",
|
||||
"angular-google-tag-manager": "^1.7.0",
|
||||
"angular-resizable-element": "^7.0.2",
|
||||
"angular-split": "^14.1.0",
|
||||
"angular-split": "^15.0.0",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"bootstrap": "^4.6.2",
|
||||
"bootstrap": "^5.2.3",
|
||||
"britecharts": "^2.18.0",
|
||||
"curved-arrows": "^0.1.0",
|
||||
"d3-selection": "^3.0.0",
|
||||
"diff": "^5.1.0",
|
||||
"dom-to-image": "^2.6.0",
|
||||
"filesize": "^10.0.6",
|
||||
"filesize": "^10.0.7",
|
||||
"has-ansi": "^5.0.1",
|
||||
"hocon-parser": "^1.0.1",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"lucene": "^2.1.1",
|
||||
"ngx-clipboard": "^15.1.0",
|
||||
"ngx-color-picker": "^13.0.0",
|
||||
"ngx-clipboard": "^16.0.0",
|
||||
"ngx-color-picker": "^14.0.0",
|
||||
"ngx-device-detector": "^5.0.1",
|
||||
"ngx-markdown-editor": "^5.1.0",
|
||||
"ngx-markdown-editor": "^5.3.0",
|
||||
"ngx-print": "^1.3.1",
|
||||
"ngx-window-token": "^6.0.0",
|
||||
"ngx-window-token": "^7.0.0",
|
||||
"object-hash": "^3.0.0",
|
||||
"primeicons": "^6.0.1",
|
||||
"primeng": "^15.2.0",
|
||||
"primeng": "^15.4.1",
|
||||
"process": "^0.11.10",
|
||||
"rxjs": "^7.8.0",
|
||||
"string-to-color": "^2.2.2",
|
||||
@@ -74,36 +74,36 @@
|
||||
"tslib": "^2.5.0",
|
||||
"url": "^0.11.0",
|
||||
"uuid": "^9.0.0",
|
||||
"zone.js": "~0.12.0"
|
||||
"zone.js": "^0.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^15.1.4",
|
||||
"@angular-devkit/core": "^15.1.4",
|
||||
"@angular-devkit/schematics": "^15.1.4",
|
||||
"@angular-devkit/schematics-cli": "^15.1.4",
|
||||
"@angular-eslint/builder": "^15.2.0",
|
||||
"@angular-eslint/eslint-plugin": "^15.2.0",
|
||||
"@angular-eslint/eslint-plugin-template": "^15.2.0",
|
||||
"@angular-eslint/schematics": "15.2.0",
|
||||
"@angular-eslint/template-parser": "^15.2.0",
|
||||
"@angular/cli": "^15.1.4",
|
||||
"@angular/compiler-cli": "^15.1.3",
|
||||
"@angular/language-service": "^15.1.3",
|
||||
"@fortawesome/fontawesome-free": "^6.3.0",
|
||||
"@ngrx/schematics": "^15.2.1",
|
||||
"@ngrx/store-devtools": "^15.2.1",
|
||||
"@types/d3-selection": "^3.0.4",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/node": "^18.13.0",
|
||||
"@types/plotly.js": "^2.12.13",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.51.0",
|
||||
"@typescript-eslint/parser": "^5.51.0",
|
||||
"@angular-devkit/build-angular": "^15.2.6",
|
||||
"@angular-devkit/core": "^15.2.6",
|
||||
"@angular-devkit/schematics": "^15.2.6",
|
||||
"@angular-devkit/schematics-cli": "^15.2.5",
|
||||
"@angular-eslint/builder": "^15.2.1",
|
||||
"@angular-eslint/eslint-plugin": "^15.2.1",
|
||||
"@angular-eslint/eslint-plugin-template": "^15.2.1",
|
||||
"@angular-eslint/schematics": "15.2.1",
|
||||
"@angular-eslint/template-parser": "^15.2.1",
|
||||
"@angular/cli": "^15.2.6",
|
||||
"@angular/compiler-cli": "^15.2.8",
|
||||
"@angular/language-service": "^15.2.8",
|
||||
"@fortawesome/fontawesome-free": "^6.4.0",
|
||||
"@ngrx/schematics": "^15.4.0",
|
||||
"@ngrx/store-devtools": "^15.4.0",
|
||||
"@types/d3-selection": "^3.0.5",
|
||||
"@types/lodash-es": "^4.17.7",
|
||||
"@types/node": "^18.16.0",
|
||||
"@types/plotly.js": "^2.12.18",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
||||
"@typescript-eslint/parser": "^5.59.1",
|
||||
"codelyzer": "^6.0.2",
|
||||
"eslint": "^8.33.0",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jsdoc": "39.8.0",
|
||||
"eslint-plugin-jsdoc": "41.1.2",
|
||||
"eslint-plugin-prefer-arrow": "1.2.3",
|
||||
"typescript": "~4.9.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,22 +3,19 @@ import {selectCurrentUser} from '@common/core/reducers/users-reducer';
|
||||
import {Component, OnDestroy, OnInit, ViewEncapsulation, HostListener, Renderer2, Injector} from '@angular/core';
|
||||
import {ActivatedRoute, NavigationEnd, Router, Params, RouterEvent} from '@angular/router';
|
||||
import {Title} from '@angular/platform-browser';
|
||||
import {selectLoggedOut} from '@common/core/reducers/view.reducer';
|
||||
import {selectBreadcrumbs, selectLoggedOut} from '@common/core/reducers/view.reducer';
|
||||
import {Store} from '@ngrx/store';
|
||||
import {selectRouterConfig, selectRouterParams, selectRouterUrl} from '@common/core/reducers/router-reducer';
|
||||
import {selectRouterParams, selectRouterUrl} from '@common/core/reducers/router-reducer';
|
||||
import {ApiProjectsService} from './business-logic/api-services/projects.service';
|
||||
import {Project} from './business-logic/model/projects/project';
|
||||
import {getAllSystemProjects, setSelectedProjectId, updateProject} from '@common/core/actions/projects.actions';
|
||||
import {selectSelectedProject} from '@common/core/reducers/projects.reducer';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {getTutorialBucketCredentials} from '@common/core/actions/common-auth.actions';
|
||||
import {termsOfUseAccepted} from '@common/core/actions/users.actions';
|
||||
import {distinctUntilChanged, filter, map, tap, withLatestFrom} from 'rxjs/operators';
|
||||
import {distinctUntilChanged, filter, map, tap} from 'rxjs/operators';
|
||||
import * as routerActions from './webapp-common/core/actions/router.actions';
|
||||
import {combineLatest, Observable, Subscription} from 'rxjs';
|
||||
import {selectBreadcrumbsStrings} from '@common/layout/layout.reducer';
|
||||
import {NestedProjectTypeUrlEnum, prepareNames} from './layout/breadcrumbs/breadcrumbs.utils';
|
||||
import {formatStaticCrumb} from '@common/layout/breadcrumbs/breadcrumbs-common.utils';
|
||||
import {ServerUpdatesService} from '@common/shared/services/server-updates.service';
|
||||
import {selectAvailableUpdates} from './core/reducers/view.reducer';
|
||||
import {UPDATE_SERVER_PATH} from './app.constants';
|
||||
@@ -53,10 +50,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
private selectedProjectFromUrl$: Observable<string>;
|
||||
private breadcrumbsSubscription: Subscription;
|
||||
private selectedCurrentUserSubscription: Subscription;
|
||||
private breadcrumbsStrings;
|
||||
private selectedCurrentUser$: Observable<any>;
|
||||
public showNotification: boolean = true;
|
||||
public showSurvey$: Observable<boolean>;
|
||||
public demo = ConfigurationService.globalEnvironment.demo;
|
||||
public isLoginContext: boolean;
|
||||
public currentUser: User;
|
||||
@@ -67,6 +62,7 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
public showSurvey: boolean;
|
||||
private plotlyURL: string;
|
||||
private environment: Environment;
|
||||
private title = 'ClearML';
|
||||
|
||||
@HostListener('document:visibilitychange') onVisibilityChange() {
|
||||
this.store.dispatch(visibilityChanged({visible: !document.hidden}));
|
||||
@@ -140,7 +136,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
this.gtmService?.pushTag(gtmTag);
|
||||
this.store.dispatch(new routerActions.NavigationEnd());
|
||||
this.updateTitle();
|
||||
});
|
||||
|
||||
this.selectedCurrentUserSubscription = this.selectedCurrentUser$.pipe(
|
||||
@@ -181,16 +176,10 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
|
||||
this.breadcrumbsSubscription = this.store.select(selectBreadcrumbsStrings).pipe(
|
||||
filter(names => !!names),
|
||||
withLatestFrom(this.store.select(selectRouterConfig))
|
||||
).subscribe(
|
||||
([names, routeConf]) => {
|
||||
const projectType = `${routeConf?.[0]}${routeConf?.[1] === 'simple' ? '/' + routeConf?.[1] : ''}`;
|
||||
this.breadcrumbsStrings = prepareNames(names, projectType as NestedProjectTypeUrlEnum);
|
||||
this.updateTitle();
|
||||
}
|
||||
);
|
||||
this.breadcrumbsSubscription = this.store.select(selectBreadcrumbs).subscribe(breadcrumbs => {
|
||||
const crumbs = breadcrumbs.flat().map(breadcrumb=> breadcrumb.name);
|
||||
this.titleService.setTitle(`${this.title ? this.title + '-' : ''} ${crumbs.join(' / ')}`);
|
||||
});
|
||||
|
||||
if (window.localStorage.getItem('disableHidpi') !== 'true') {
|
||||
this.setScale();
|
||||
@@ -228,26 +217,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
return this.router.navigateByUrl('projects');
|
||||
}
|
||||
|
||||
updateTitle() {
|
||||
let route = this.route.snapshot.firstChild;
|
||||
let routeConfig = [];
|
||||
|
||||
while (route) {
|
||||
const path = route.routeConfig.path.split('/').filter((item) => !!item);
|
||||
routeConfig = routeConfig.concat(path);
|
||||
route = route.firstChild;
|
||||
}
|
||||
const crumbs = routeConfig
|
||||
.reduce((acc, config) => {
|
||||
const dynamicCrumb = this.breadcrumbsStrings[config];
|
||||
let crumb = dynamicCrumb ? dynamicCrumb : formatStaticCrumb(config);
|
||||
crumb = Array.isArray(crumb) ? crumb.at(-1) : crumb;
|
||||
return acc.concat(crumb.name);
|
||||
}, [''])
|
||||
.filter(name => !!name && name !== ':project');
|
||||
this.titleService.setTitle(`ClearML - ${crumbs.join(' / ')}`);
|
||||
}
|
||||
|
||||
versionDismissed(version: string) {
|
||||
this.serverUpdatesService.setDismissedVersion(version);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import {ColorHashService} from '@common/shared/services/color-hash/color-hash.se
|
||||
import {SharedModule} from './shared/shared.module';
|
||||
import {ConfigurationService} from '@common/shared/services/configuration.service';
|
||||
import {ProjectsSharedModule} from './features/projects/shared/projects-shared.module';
|
||||
import {MAT_LEGACY_FORM_FIELD_DEFAULT_OPTIONS as MAT_FORM_FIELD_DEFAULT_OPTIONS} from '@angular/material/legacy-form-field';
|
||||
import {MAT_FORM_FIELD_DEFAULT_OPTIONS} from '@angular/material/form-field';
|
||||
import {LoginService} from '~/shared/services/login.service';
|
||||
import {ExperimentSharedModule} from '~/features/experiments/shared/experiment-shared.module';
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import {Routes} from '@angular/router';
|
||||
/*
|
||||
import {AdminComponent} from '@common/settings/admin/admin.component';
|
||||
*/
|
||||
import {ProjectRedirectGuardGuard} from '@common/shared/guards/project-redirect.guard';
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
|
||||
@@ -45,6 +42,11 @@ export const routes: Routes = [
|
||||
loadChildren: () => import('./webapp-common/experiments-compare/experiments-compare.module').then(m => m.ExperimentsCompareModule),
|
||||
data: {entityType: EntityTypeEnum.experiment},
|
||||
},
|
||||
{
|
||||
path: 'compare-models',
|
||||
data: {entityType: EntityTypeEnum.model},
|
||||
loadChildren: () => import('./webapp-common/experiments-compare/experiments-compare.module').then(m => m.ExperimentsCompareModule)
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
@@ -26,4 +26,5 @@ export interface EventsGetMultiTaskPlotsRequest {
|
||||
*/
|
||||
scroll_id?: string;
|
||||
no_scroll?: boolean;
|
||||
model_events?: boolean;
|
||||
}
|
||||
|
||||
@@ -23,4 +23,5 @@ export interface EventsMultiTaskScalarMetricsIterHistogramRequest {
|
||||
*/
|
||||
samples?: number;
|
||||
key?: ScalarKeyEnum;
|
||||
model_events?: boolean;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export interface MetricsPlotEvent {
|
||||
/**
|
||||
* \'plot\'
|
||||
*/
|
||||
type: object;
|
||||
type: any;
|
||||
/**
|
||||
* Task ID (required)
|
||||
*/
|
||||
@@ -41,7 +41,7 @@ export interface MetricsPlotEvent {
|
||||
*/
|
||||
variant?: string;
|
||||
/**
|
||||
* An entire plot (not single datapoint) and it\'s layout. Used for plotting ROC curves, confidence matrices, etc. when evaluating the net.
|
||||
* An entire plot (not single datapoint) and it\'s layout. Used for plotting ROC curves, confidence matrices, etc. when evaluating the net.
|
||||
*/
|
||||
plot_str?: string;
|
||||
/**
|
||||
|
||||
44
src/app/business-logic/model/models/lastMetricsEvent.ts
Normal file
44
src/app/business-logic/model/models/lastMetricsEvent.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* models
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* OpenAPI spec version: 999.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
export interface LastMetricsEvent {
|
||||
/**
|
||||
* Metric name
|
||||
*/
|
||||
metric?: string;
|
||||
/**
|
||||
* Variant name
|
||||
*/
|
||||
variant?: string;
|
||||
/**
|
||||
* Last value reported
|
||||
*/
|
||||
value?: number;
|
||||
/**
|
||||
* Minimum value reported
|
||||
*/
|
||||
min_value?: number;
|
||||
/**
|
||||
* The iteration at which the minimum value was reported
|
||||
*/
|
||||
min_value_iteration?: number;
|
||||
/**
|
||||
* Maximum value reported
|
||||
*/
|
||||
max_value?: number;
|
||||
/**
|
||||
* The iteration at which the maximum value was reported
|
||||
*/
|
||||
max_value_iteration?: number;
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { ModelStats } from '././modelStats';
|
||||
import { LastMetricsEvent } from '././lastMetricsEvent';
|
||||
import { MetadataItem } from '././metadataItem';
|
||||
|
||||
|
||||
@@ -55,11 +57,11 @@ export interface Model {
|
||||
*/
|
||||
comment?: string;
|
||||
/**
|
||||
* User-defined tags list
|
||||
* User-defined tags
|
||||
*/
|
||||
tags?: Array<string>;
|
||||
/**
|
||||
* System tags list. This field is reserved for system use, please don\'t use it.
|
||||
* System tags. This field is reserved for system use, please don\'t use it.
|
||||
*/
|
||||
system_tags?: Array<string>;
|
||||
/**
|
||||
@@ -89,5 +91,14 @@ export interface Model {
|
||||
/**
|
||||
* Model metadata
|
||||
*/
|
||||
metadata?: Array<MetadataItem>;
|
||||
metadata?: { [key: string]: MetadataItem; };
|
||||
/**
|
||||
* Last iteration reported for this model
|
||||
*/
|
||||
last_iteration?: number;
|
||||
/**
|
||||
* Last metric variants (hash to events), one for each metric hash
|
||||
*/
|
||||
last_metrics?: { [key: string]: { [key: string]: LastMetricsEvent; }; };
|
||||
stats?: ModelStats;
|
||||
}
|
||||
|
||||
23
src/app/business-logic/model/models/modelStats.ts
Normal file
23
src/app/business-logic/model/models/modelStats.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* models
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* OpenAPI spec version: 999.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Model statistics
|
||||
*/
|
||||
export interface ModelStats {
|
||||
/**
|
||||
* Number of the model labels
|
||||
*/
|
||||
labels_count?: number;
|
||||
}
|
||||
@@ -21,4 +21,8 @@ export interface ProjectsGetUniqueMetricVariantsRequest {
|
||||
* If set to \'true\' and the project field is set then the result includes metrics/variants from the subproject tasks
|
||||
*/
|
||||
include_subprojects?: boolean;
|
||||
/**
|
||||
* If set to Truethen bring unique metric and variant names from the project models otherwise from the project tasks
|
||||
*/
|
||||
model_metrics?: boolean;
|
||||
}
|
||||
|
||||
@@ -12,20 +12,25 @@
|
||||
|
||||
import { Task } from '././task';
|
||||
import { DebugImagesResponseTaskMetrics } from '././debugImagesResponseTaskMetrics';
|
||||
import { SingleValueTaskMetrics } from '././singleValueTaskMetrics';
|
||||
|
||||
|
||||
export interface ReportsGetTaskDataResponse {
|
||||
/**
|
||||
* List of tasks
|
||||
*/
|
||||
tasks?: Array<Task>;
|
||||
/**
|
||||
* Plot events grouped by tasks and iterations
|
||||
*/
|
||||
plots?: object;
|
||||
/**
|
||||
* Debug image events grouped by tasks and iterations
|
||||
*/
|
||||
debug_images?: Array<DebugImagesResponseTaskMetrics>;
|
||||
scalar_metrics_iter_histogram?: object;
|
||||
/**
|
||||
* List of tasks
|
||||
*/
|
||||
tasks?: Array<Task>;
|
||||
/**
|
||||
* Plots mapped by metric, variant, task and iteration
|
||||
*/
|
||||
plots?: object;
|
||||
/**
|
||||
* Debug image events grouped by tasks and iterations
|
||||
*/
|
||||
debug_images?: Array<DebugImagesResponseTaskMetrics>;
|
||||
scalar_metrics_iter_histogram?: object;
|
||||
/**
|
||||
* Single value metrics grouped by task
|
||||
*/
|
||||
single_value_metrics?: Array<SingleValueTaskMetrics>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* reports
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* OpenAPI spec version: 999.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { SingleValueTaskMetricsValues } from '././singleValueTaskMetricsValues';
|
||||
|
||||
|
||||
export interface SingleValueTaskMetrics {
|
||||
/**
|
||||
* Task ID
|
||||
*/
|
||||
task?: string;
|
||||
values?: Array<SingleValueTaskMetricsValues>;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* reports
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* OpenAPI spec version: 999.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by the swagger code generator program.
|
||||
* https://github.com/swagger-api/swagger-codegen.git
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
export interface SingleValueTaskMetricsValues {
|
||||
metric?: string;
|
||||
variant?: string;
|
||||
value?: number;
|
||||
timestamp?: number;
|
||||
}
|
||||
@@ -25,4 +25,5 @@ export interface TasksDequeueManyRequest {
|
||||
* Extra information regarding status change
|
||||
*/
|
||||
status_message?: string;
|
||||
remove_from_all_queues?: boolean;
|
||||
}
|
||||
|
||||
@@ -25,4 +25,5 @@ export interface TasksDequeueRequest {
|
||||
* Extra information regarding status change
|
||||
*/
|
||||
status_message?: string;
|
||||
remove_from_all_queues?: boolean;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ const syncedKeys = [
|
||||
'projects.selectedProject',
|
||||
'rootProjects.showHidden',
|
||||
'rootProjects.hideExamples',
|
||||
'rootProjects.defaultNestedModeForFeature',
|
||||
'views.availableUpdates',
|
||||
'views.showSurvey',
|
||||
'views.neverShowPopupAgain'
|
||||
@@ -94,7 +95,7 @@ const userPrefMetaFactory = (userPreferences: UserPreferences): MetaReducer<any>
|
||||
(reducer: ActionReducer<any>) =>
|
||||
createUserPrefReducer('users', ['activeWorkspace', 'showOnlyUserWork'], [USERS_PREFIX], userPreferences, reducer),
|
||||
(reducer: ActionReducer<any>) =>
|
||||
createUserPrefReducer('rootProjects', ['tagsColors', 'graphVariant', 'showHidden', 'hideExamples', 'aa'] as (keyof RootProjects)[], [ROOT_PROJECTS_PREFIX], userPreferences, reducer),
|
||||
createUserPrefReducer('rootProjects', ['tagsColors', 'graphVariant', 'showHidden', 'hideExamples', 'defaultNestedModeForFeature'], [ROOT_PROJECTS_PREFIX], userPreferences, reducer),
|
||||
(reducer: ActionReducer<any>) =>
|
||||
createUserPrefReducer('views', ['autoRefresh', 'neverShowPopupAgain', 'redactedArguments', 'hideRedactedArguments'], [VIEW_PREFIX], userPreferences, reducer),
|
||||
localStorageReducer,
|
||||
|
||||
@@ -18,7 +18,7 @@ export const usersReducer = createReducer<UsersState>(initUsers,
|
||||
}))
|
||||
);
|
||||
|
||||
export const selectFeatures = createSelector(users, (state) => []);
|
||||
export const selectFeatures = createSelector(users, (state) => null);
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const selectTermsOfUse = createSelector(users, state => ({accept_required: null}));
|
||||
export const selectInvitesPending = createSelector(users, state => []);
|
||||
|
||||
@@ -3,7 +3,7 @@ import {Store} from '@ngrx/store';
|
||||
import {filter} from 'rxjs/operators';
|
||||
import {updateUsageStats} from '../actions/usage-stats.actions';
|
||||
import {selectPromptUser} from '../reducers/usage-stats.reducer';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component';
|
||||
import {ConfigurationService} from '@common/shared/services/configuration.service';
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {DashboardComponent} from './dashboard.component';
|
||||
import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{path: '', component: DashboardComponent}
|
||||
{path: '', component: DashboardComponent, data:{staticBreadcrumb:[[{
|
||||
name: 'DASHBOARD',
|
||||
type: CrumbTypeEnum.Feature
|
||||
}]]}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
<div header-buttons>
|
||||
<button
|
||||
*smCheckPermission="true"
|
||||
class="btn btn-primary d-flex align-items-center"
|
||||
class="btn btn-cml-primary d-flex align-items-center"
|
||||
(click)="redirectToWorkers()"
|
||||
><i class="al-icon al-ico-queues al-color light-grey-blue sm mr-2"></i>MANAGE WORKERS AND QUEUES</button>
|
||||
><i class="al-icon al-ico-queues al-color light-grey-blue sm me-2"></i>MANAGE WORKERS AND QUEUES</button>
|
||||
</div>
|
||||
</sm-dashboard-experiments>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {filter, skip, take} from 'rxjs/operators';
|
||||
import {setDeep} from '@common/core/actions/projects.actions';
|
||||
import {getRecentProjects, getRecentExperiments} from '@common/dashboard/common-dashboard.actions';
|
||||
import {selectFirstLogin} from '@common/core/reducers/view.reducer';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {WelcomeMessageComponent} from '@common/layout/welcome-message/welcome-message.component';
|
||||
import {firstLogin} from '@common/core/actions/layout.actions';
|
||||
import {IRecentTask, selectRecentTasks} from '@common/dashboard/common-dashboard.reducer';
|
||||
|
||||
@@ -4,13 +4,17 @@ import {SimpleDatasetsComponent} from '@common/datasets/simple-datasets/simple-d
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
import {
|
||||
NestedProjectViewPageComponent
|
||||
} from "@common/nested-project-view/nested-project-view-page/nested-project-view-page.component";
|
||||
} from '@common/nested-project-view/nested-project-view-page/nested-project-view-page.component';
|
||||
import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path : '',
|
||||
component: SimpleDatasetsComponent,
|
||||
data : {search: true}
|
||||
data: {search: true, staticBreadcrumb:[[{
|
||||
name: 'DATASETS',
|
||||
type: CrumbTypeEnum.Feature
|
||||
}]]}
|
||||
},
|
||||
{
|
||||
path: 'simple/:projectId',
|
||||
|
||||
@@ -6,7 +6,8 @@ import {DatasetsRoutingModule} from '~/features/datasets/datasets-routing.module
|
||||
import {DatasetsSharedModule} from '~/features/datasets/shared/datasets-shared.module';
|
||||
import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module';
|
||||
import {SMSharedModule} from '@common/shared/shared.module';
|
||||
import {FeatureNestedProjectViewModule} from "~/features/nested-project-view/feature-nested-project-view.module";
|
||||
import {FeatureNestedProjectViewModule} from '~/features/nested-project-view/feature-nested-project-view.module';
|
||||
import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@@ -18,6 +19,7 @@ import {FeatureNestedProjectViewModule} from "~/features/nested-project-view/fea
|
||||
DatasetsSharedModule,
|
||||
SharedPipesModule,
|
||||
FeatureNestedProjectViewModule,
|
||||
LabeledFormFieldDirective,
|
||||
],
|
||||
declarations: [
|
||||
SimpleDatasetsComponent,
|
||||
|
||||
@@ -1,58 +1,8 @@
|
||||
<nav [overflowTrigger]="splitSize" (smOverflows)="navbarOverflowed($event)" [overflowDelay]="800" [class.minimized]="minimized">
|
||||
<span [routerLink]="['execution']" routerLinkActive #rlaExecution="routerLinkActive" queryParamsHandling="preserve">
|
||||
<sm-navbar-item header="execution" [active]="rlaExecution.isActive" class="small-nav"></sm-navbar-item>
|
||||
</span>
|
||||
<span [routerLink]="['hyper-params/hyper-param/_empty_']" queryParamsHandling="merge">
|
||||
<sm-navbar-item header="configuration"
|
||||
class="small-nav"
|
||||
[active]="(routerConfig$| async)?.includes('hyper-params')"></sm-navbar-item>
|
||||
</span>
|
||||
<span [routerLink]="['artifacts']" routerLinkActive #rlaModel="routerLinkActive" queryParamsHandling="preserve">
|
||||
<sm-navbar-item header="artifacts"
|
||||
class="small-nav"
|
||||
[active]="rlaModel.isActive"></sm-navbar-item>
|
||||
</span>
|
||||
<span [routerLink]="['general']" routerLinkActive #rlaGeneral="routerLinkActive" queryParamsHandling="preserve">
|
||||
<sm-navbar-item header="info"
|
||||
class="small-nav"
|
||||
[active]="rlaGeneral.isActive"></sm-navbar-item>
|
||||
</span>
|
||||
|
||||
<span [matMenuTriggerFor]="results" *ngIf="overflow">
|
||||
<sm-navbar-item header="results"
|
||||
class="small-nav"
|
||||
[multi]="true"
|
||||
[active]="rlaDebug.isActive || rlaPlots.isActive || rlaScalars.isActive || rlaLog.isActive"></sm-navbar-item>
|
||||
</span>
|
||||
<div class="d-inline-block" [style.visibility]="overflow ? 'hidden' : 'visible'">
|
||||
<span [routerLink]="baseInfoRoute.concat(['log'])" routerLinkActive queryParamsHandling="preserve"
|
||||
#rlaLog="routerLinkActive">
|
||||
<sm-navbar-item class="small-nav" header="console" [active]="rlaLog.isActive"></sm-navbar-item>
|
||||
</span>
|
||||
<span [routerLink]="baseInfoRoute.concat(['metrics','scalar'])" routerLinkActive queryParamsHandling="preserve"
|
||||
#rlaScalars="routerLinkActive">
|
||||
<sm-navbar-item class="small-nav" header="Scalars" [active]="rlaScalars.isActive"></sm-navbar-item>
|
||||
</span>
|
||||
<span [routerLink]="baseInfoRoute.concat(['metrics','plots'])" routerLinkActive queryParamsHandling="preserve"
|
||||
#rlaPlots="routerLinkActive">
|
||||
<sm-navbar-item class="small-nav" header="PLOTS" [active]="rlaPlots.isActive"></sm-navbar-item>
|
||||
</span>
|
||||
<span [routerLink]="baseInfoRoute.concat(['debugImages'])" routerLinkActive queryParamsHandling="preserve"
|
||||
#rlaDebug="routerLinkActive">
|
||||
<sm-navbar-item class="small-nav" header="DEBUG SAMPLES" [active]="rlaDebug.isActive"></sm-navbar-item>
|
||||
</span>
|
||||
</div>
|
||||
<mat-menu #results="matMenu">
|
||||
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['log'])" [class.active]="rlaLog.isActive">CONSOLE</button>
|
||||
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['metrics','scalar'])"
|
||||
[class.active]="rlaScalars.isActive">SCALARS
|
||||
</button>
|
||||
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['metrics','plots'])" [class.active]="rlaPlots.isActive">
|
||||
PLOTS
|
||||
</button>
|
||||
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['debugImages'])" [class.active]="rlaDebug.isActive">DEBUG
|
||||
SAMPLES
|
||||
</button>
|
||||
</mat-menu>
|
||||
<div class="tab-nav" [class.minimized]="minimized">
|
||||
<span></span>
|
||||
<sm-router-tab-nav-bar
|
||||
[links]="links"
|
||||
[splitSize]="splitSize"
|
||||
></sm-router-tab-nav-bar>
|
||||
<ng-content select="[refresh]"></ng-content>
|
||||
</nav>
|
||||
</div>
|
||||
@@ -1,31 +1,17 @@
|
||||
@import "variables";
|
||||
$output-tabs-height: 40px;
|
||||
|
||||
nav {
|
||||
height: $output-tabs-height;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
.tab-nav {
|
||||
display: grid;
|
||||
grid-template-columns: 200px 1fr 200px;
|
||||
border-bottom: 1px solid #efefef;
|
||||
padding: 0 48px 0 24px;
|
||||
|
||||
.refresh-position {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&.minimized {
|
||||
grid-template-columns: 0 1fr 60px;
|
||||
}
|
||||
.refreshIcon{
|
||||
margin-right: 10px;
|
||||
}
|
||||
span.disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
.mat-menu-item {
|
||||
padding-left: 22px;
|
||||
&.active {
|
||||
border-left: 6px solid $purple;
|
||||
padding-left: 16px;
|
||||
|
||||
@media(max-width: 1200px) {
|
||||
grid-template-columns: 0 1fr 200px;
|
||||
}
|
||||
}
|
||||
|
||||
sm-router-tab-nav-bar {
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -1,38 +1,38 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {FeaturesEnum} from '~/business-logic/model/users/featuresEnum';
|
||||
import {selectRouterConfig} from '@common/core/reducers/router-reducer';
|
||||
import {Store} from '@ngrx/store';
|
||||
import {ExperimentInfoState} from '../../reducers/experiment-info.reducer';
|
||||
import {Observable} from 'rxjs';
|
||||
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
|
||||
import {Link} from '@common/shared/components/router-tab-nav-bar/router-tab-nav-bar.component';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'sm-experiment-info-navbar',
|
||||
templateUrl: './experiment-info-navbar.component.html',
|
||||
styleUrls: ['./experiment-info-navbar.component.scss']
|
||||
styleUrls: ['./experiment-info-navbar.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class ExperimentInfoNavbarComponent {
|
||||
public featuresEnum = FeaturesEnum;
|
||||
public routerConfig$: Observable<string[]>;
|
||||
public baseInfoRoute: string[];
|
||||
public overflow: boolean;
|
||||
private _minimized: boolean;
|
||||
|
||||
links = [
|
||||
{name: 'execution', url: ['execution']},
|
||||
{name: 'configuration', url: ['hyper-params', 'hyper-param', '_empty_'], activeBy: 'hyper-params'},
|
||||
{name: 'artifacts', url: ['artifacts']},
|
||||
{name: 'info', url: ['general']},
|
||||
{name: 'console', url: ['log'], output: true},
|
||||
{name: 'scalars', url: ['metrics','scalar'], output: true},
|
||||
{name: 'plots', url: ['metrics','plots'], output: true},
|
||||
{name: 'debug samples', url: ['debugImages'], output: true},
|
||||
] as Link[];
|
||||
@Input() set minimized(minimized: boolean) {
|
||||
this.baseInfoRoute = minimized ? ['info-output'] : [];
|
||||
this.links = this.links.map(link => ({
|
||||
...link,
|
||||
url: (link as any).output ? this.baseInfoRoute.concat(link.url) : link.url
|
||||
}));
|
||||
this._minimized = minimized;
|
||||
}
|
||||
get minimized() {
|
||||
get minimized(){
|
||||
return this._minimized;
|
||||
}
|
||||
|
||||
@Input() splitSize: number;
|
||||
|
||||
|
||||
constructor(private store: Store<ExperimentInfoState>) {
|
||||
this.routerConfig$ = this.store.select(selectRouterConfig);
|
||||
}
|
||||
navbarOverflowed($event: boolean) {
|
||||
this.overflow = $event;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import {CommonLayoutModule} from '@common/layout/layout.module';
|
||||
import {DebugImagesModule} from '@common/debug-images/debug-images.module';
|
||||
import {ExperimentInfoExecutionComponent} from '@common/experiments/containers/experiment-info-execution/experiment-info-execution.component';
|
||||
import {MatSidenavModule} from '@angular/material/sidenav';
|
||||
import {MatLegacyListModule as MatListModule} from '@angular/material/legacy-list';
|
||||
import {MatListModule} from '@angular/material/list';
|
||||
import {ExperimentOutputComponent} from './containers/experiment-ouptut/experiment-output.component';
|
||||
import {ExperimentInfoNavbarComponent} from './containers/experiment-info-navbar/experiment-info-navbar.component';
|
||||
import {ExperimentInfoHyperParametersComponent} from '@common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component';
|
||||
@@ -34,7 +34,6 @@ import {ExperimentArtifactsNavbarComponent} from '@common/experiments/dumb/exper
|
||||
import {ExperimentInfoArtifactsComponent} from '@common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component';
|
||||
import {ExperimentInfoHeaderComponent} from '@common/experiments/dumb/experiment-info-header/experiment-info-header.component';
|
||||
import {ExperimentInfoTaskModelComponent} from '@common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component';
|
||||
import {ModelAutoPopulateDialogComponent} from '@common/experiments/dumb/model-auto-populate-dialog/model-auto-populate-dialog.component';
|
||||
import {ExperimentOutputScalarsComponent} from '@common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component';
|
||||
import {ExperimentInfoModelComponent} from '@common/experiments/containers/experiment-info-model/experiment-info-model.component';
|
||||
import {ExperimentInfoHyperParametersFormContainerComponent} from '@common/experiments/containers/experiment-info-hyper-parameters-form-container/experiment-info-hyper-parameters-form-container.component';
|
||||
@@ -50,6 +49,8 @@ import {MAT_AUTOCOMPLETE_SCROLL_STRATEGY} from '@angular/material/autocomplete';
|
||||
import {scrollFactory} from '@common/shared/utils/scroll-factory';
|
||||
import {Overlay} from '@angular/cdk/overlay';
|
||||
import {ExperimentsComponent} from '@common/experiments/experiments.component';
|
||||
import {RouterTabNavBarComponent} from '@common/shared/components/router-tab-nav-bar/router-tab-nav-bar.component';
|
||||
import {MatTabsModule} from '@angular/material/tabs';
|
||||
|
||||
|
||||
@NgModule({
|
||||
@@ -80,6 +81,9 @@ import {ExperimentsComponent} from '@common/experiments/experiments.component';
|
||||
MatProgressSpinnerModule,
|
||||
MatRadioModule,
|
||||
ExperimentSharedModule,
|
||||
RouterTabNavBarComponent,
|
||||
MatTabsModule,
|
||||
RouterTabNavBarComponent,
|
||||
],
|
||||
declarations: [
|
||||
ExperimentsComponent,
|
||||
@@ -97,7 +101,6 @@ import {ExperimentsComponent} from '@common/experiments/experiments.component';
|
||||
ExperimentOutputModelViewComponent,
|
||||
ExperimentExecutionSourceCodeComponent,
|
||||
ExperimentOutputScalarsComponent,
|
||||
ModelAutoPopulateDialogComponent,
|
||||
ExperimentInfoHyperParametersComponent,
|
||||
ExperimentInfoHyperParametersFormContainerComponent,
|
||||
ExperimentArtifactsNavbarComponent,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {ActionReducerMap, createSelector} from '@ngrx/store';
|
||||
import {experimentInfoReducer, ExperimentInfoState, initialState as infoInitialState} from './experiment-info.reducer';
|
||||
import {experimentOutputReducer, ExperimentOutputState, experimentOutputInitState} from '@common/experiments/reducers/experiment-output.reducer';
|
||||
import {experimentOutputReducer, ExperimentOutputState, experimentOutputInitState, ExperimentSettings} from '@common/experiments/reducers/experiment-output.reducer';
|
||||
import {experimentsViewReducer, ExperimentsViewState, experimentsViewInitialState} from '@common/experiments/reducers/experiments-view.reducer';
|
||||
import {IExperimentInfo} from '../shared/experiment-info.model';
|
||||
import {TaskStatusEnum} from '~/business-logic/model/tasks/taskStatusEnum';
|
||||
@@ -59,3 +59,7 @@ export const selectExperimentFormValidity = createSelector(selectExperimentInfoD
|
||||
|
||||
return !error;
|
||||
});
|
||||
|
||||
export const selectSelectedModelSettings = createSelector(experimentOutput, selectSelectedModel,
|
||||
(output, currentModel): ExperimentSettings =>
|
||||
output.settingsList && output.settingsList.find((setting) => currentModel && setting.id === currentModel.id));
|
||||
|
||||
@@ -4,16 +4,13 @@ import {SMSharedModule} from '@common/shared/shared.module';
|
||||
import {ExperimentConverterService} from './services/experiment-converter.service';
|
||||
import { ExperimentMenuComponent } from '@common/experiments/shared/components/experiment-menu/experiment-menu.component';
|
||||
import {ExperimentMenuExtendedComponent} from '../containers/experiment-menu-extended/experiment-menu-extended.component';
|
||||
import {GetParamMetricValuePipe} from '@common/experiments/dumb/experiments-table/hyper-param-metric-column/get-param-metric-value.pipe';
|
||||
import {ExperimentHeaderComponent} from '@common/experiments/dumb/experiment-header/experiment-header.component';
|
||||
import {SelectHyperParamsForCustomColComponent} from '@common/experiments/dumb/select-hyper-params-for-custom-col/select-hyper-params-for-custom-col.component';
|
||||
import {ExperimentExecutionParametersComponent} from '@common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component';
|
||||
import {CloneDialogComponent} from '@common/experiments/shared/components/clone-dialog/clone-dialog.component';
|
||||
import {HyperParamMetricColumnComponent} from '@common/experiments/dumb/experiments-table/hyper-param-metric-column/hyper-param-metric-column.component';
|
||||
import {ExperimentSystemTagsComponent} from '@common/experiments/shared/components/experiments-system-tags/experiment-system-tags.component';
|
||||
import {AbortAllChildrenDialogComponent} from '@common/experiments/shared/components/abort-all-children-dialog/abort-all-children-dialog.component';
|
||||
import {ExperimentsTableComponent} from '@common/experiments/dumb/experiments-table/experiments-table.component';
|
||||
import {GetVariantWithoutRoundPipe} from '@common/experiments/dumb/experiments-table/hyper-param-metric-column/get-variant-without-round.pipe';
|
||||
import {ChangeProjectDialogComponent} from '@common/experiments/shared/components/change-project-dialog/change-project-dialog.component';
|
||||
import {ExperimentOutputPlotsComponent} from '@common/experiments/containers/experiment-output-plots/experiment-output-plots.component';
|
||||
import {ExperimentCustomColsMenuComponent} from '@common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component';
|
||||
@@ -41,6 +38,8 @@ import {EXPERIMENTS_OUTPUT_PREFIX} from '@common/experiments/actions/common-expe
|
||||
import {EXPERIMENTS_INFO_PREFIX} from '@common/experiments/actions/common-experiments-info.actions';
|
||||
import {experimentsReducers} from '~/features/experiments/reducers';
|
||||
import {CommonExperimentConverterService} from '@common/experiments/shared/services/common-experiment-converter.service';
|
||||
import {HyperParamMetricColumnComponent} from '@common/experiments/shared/components/hyper-param-metric-column/hyper-param-metric-column.component';
|
||||
import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive';
|
||||
|
||||
export const experimentSyncedKeys = [
|
||||
'view.projectColumnsSortOrder',
|
||||
@@ -89,9 +88,6 @@ const DECLARATIONS = [
|
||||
AbortAllChildrenDialogComponent,
|
||||
ExperimentExecutionParametersComponent,
|
||||
ExperimentsTableComponent,
|
||||
HyperParamMetricColumnComponent,
|
||||
GetParamMetricValuePipe,
|
||||
GetVariantWithoutRoundPipe,
|
||||
ExperimentHeaderComponent,
|
||||
ExperimentCustomColsMenuComponent,
|
||||
SelectHyperParamsForCustomColComponent,
|
||||
@@ -117,6 +113,8 @@ const DECLARATIONS = [
|
||||
MatProgressSpinnerModule,
|
||||
ScrollingModule,
|
||||
CommonLayoutModule,
|
||||
HyperParamMetricColumnComponent,
|
||||
LabeledFormFieldDirective,
|
||||
],
|
||||
declarations : [...DECLARATIONS],
|
||||
providers : [
|
||||
|
||||
@@ -5,14 +5,14 @@ import { CommonModule } from '@angular/common';
|
||||
|
||||
import { LoginRoutingModule } from './login-routing.module';
|
||||
|
||||
import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/material/legacy-autocomplete';
|
||||
import {MatLegacyProgressSpinnerModule as MatProgressSpinnerModule} from '@angular/material/legacy-progress-spinner';
|
||||
import {MatLegacyCheckboxModule as MatCheckboxModule} from '@angular/material/legacy-checkbox';
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
|
||||
import {MatCheckboxModule} from '@angular/material/checkbox';
|
||||
import {SignupComponent} from './signup/signup.component';
|
||||
import {MatLegacyFormFieldModule as MatFormFieldModule} from '@angular/material/legacy-form-field';
|
||||
import {MatLegacySelectModule as MatSelectModule} from '@angular/material/legacy-select';
|
||||
import {MatLegacyInputModule as MatInputModule} from '@angular/material/legacy-input';
|
||||
import {MatLegacyRadioModule as MatRadioModule} from '@angular/material/legacy-radio';
|
||||
import {MatFormFieldModule} from '@angular/material/form-field';
|
||||
import {MatSelectModule} from '@angular/material/select';
|
||||
import {MatInputModule} from '@angular/material/input';
|
||||
import {MatRadioModule} from '@angular/material/radio';
|
||||
import {LoginComponent} from '@common/login/login/login.component';
|
||||
import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module';
|
||||
import {NtkmeButtonModule} from '@ctrl/ngx-github-buttons';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { NestedProjectViewPageExtendedComponent } from './nested-project-view-page-extended.component';
|
||||
import {StoreModule} from '@ngrx/store';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {MatLegacyDialogModule as MatDialogModule} from '@angular/material/legacy-dialog';
|
||||
import {MatDialogModule} from '@angular/material/dialog';
|
||||
|
||||
describe('PipelinesPageComponent', () => {
|
||||
let component: NestedProjectViewPageExtendedComponent;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {EntityTypeEnum} from "~/shared/constants/non-common-consts";
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
|
||||
export enum EntityTypePluralEnum {
|
||||
pipelines = 'pipelines',
|
||||
@@ -6,13 +6,13 @@ export enum EntityTypePluralEnum {
|
||||
reports = 'reports',
|
||||
}
|
||||
|
||||
export const getEntityTypeFromUrlConf = (conf: string[]): string => {
|
||||
return conf[0];
|
||||
};
|
||||
export const getEntityTypeFromUrlConf = (conf: string[]) => conf[0] as EntityTypePluralEnum;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export const getDatasetUrlPrefix = (entityType)=> 'simple';
|
||||
export const getNestedEntityBaseUrl = (entityType) => entityType;
|
||||
export const isDatasetType = (entityType) => entityType === EntityTypePluralEnum.datasets ;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export const datasetLabel = (entityType) => 'DATASETS' ;
|
||||
|
||||
export const getNestedEntityName = (entityType: string): EntityTypeEnum => {
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonProjectsPageComponent} from '../../webapp-common/projects/containers/projects-page/common-projects-page.component';
|
||||
import {CommonProjectsPageComponent} from '@common/projects/containers/projects-page/common-projects-page.component';
|
||||
import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{path: '', component: CommonProjectsPageComponent}
|
||||
{path: '', component: CommonProjectsPageComponent, data: {
|
||||
staticBreadcrumb: [[{
|
||||
name: 'PROJECTS',
|
||||
type: CrumbTypeEnum.Feature
|
||||
}]]
|
||||
}}
|
||||
];
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import { MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA } from '@angular/material/legacy-dialog';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import {Store} from '@ngrx/store';
|
||||
import {updateCredentialLabel} from '@common/core/actions/common-auth.actions';
|
||||
import {OrganizationGetUserCompaniesResponseCompanies} from '~/business-logic/model/organization/organizationGetUserCompaniesResponseCompanies';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatLegacySlideToggleChange as MatSlideToggleChange } from '@angular/material/legacy-slide-toggle';
|
||||
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
|
||||
import {Store} from '@ngrx/store';
|
||||
import {selectAllowed} from '~/core/reducers/usage-stats.reducer';
|
||||
import {Observable} from 'rxjs';
|
||||
|
||||
@@ -6,7 +6,7 @@ import {filter, take} from 'rxjs/operators';
|
||||
import {createCredential, credentialRevoked, getAllCredentials, resetCredential, updateCredentialLabel} from '@common/core/actions/common-auth.actions';
|
||||
import {Store} from '@ngrx/store';
|
||||
import {GetCurrentUserResponseUserObject} from '~/business-logic/model/users/getCurrentUserResponseUserObject';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {CreateCredentialDialogComponent} from '~/features/settings/containers/admin/create-credential-dialog/create-credential-dialog.component';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -4,6 +4,13 @@ import {ProfileNameComponent} from '@common/settings/admin/profile-name/profile-
|
||||
import {WebappConfigurationComponent} from '@common/settings/webapp-configuration/webapp-configuration.component';
|
||||
import {WorkspaceConfigurationComponent} from '@common/settings/workspace-configuration/workspace-configuration.component';
|
||||
import {SettingsComponent} from './settings.component';
|
||||
import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component';
|
||||
|
||||
const settingsBreadcrumb = {
|
||||
name: 'Settings',
|
||||
url: 'settings',
|
||||
type: CrumbTypeEnum.Feature
|
||||
};
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@@ -17,14 +24,27 @@ const routes: Routes = [
|
||||
},
|
||||
{path: 'profile',
|
||||
component: ProfileNameComponent,
|
||||
data: {
|
||||
staticBreadcrumb:[[settingsBreadcrumb, {
|
||||
name: 'Profile',
|
||||
type: CrumbTypeEnum.SubFeature
|
||||
}]]},
|
||||
},
|
||||
{
|
||||
path: 'webapp-configuration',
|
||||
component: WebappConfigurationComponent,
|
||||
data: {workspaceNeutral: true, staticBreadcrumb:[[settingsBreadcrumb, {
|
||||
name: 'Configuration',
|
||||
type: CrumbTypeEnum.SubFeature
|
||||
}]]},
|
||||
},
|
||||
{
|
||||
path: 'workspace-configuration',
|
||||
component: WorkspaceConfigurationComponent,
|
||||
data: {workspaceNeutral: true, staticBreadcrumb:[[settingsBreadcrumb, {
|
||||
name: 'Workspace',
|
||||
type: CrumbTypeEnum.SubFeature
|
||||
}]]},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import {CreateCredentialDialogComponent} from '~/features/settings/containers/ad
|
||||
import {RedactedArgumentsDialogComponent} from '@common/settings/admin/redacted-arguments-dialog/redacted-arguments-dialog.component';
|
||||
import {LayoutModule} from '~/layout/layout.module';
|
||||
import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module';
|
||||
import {LabeledFormFieldDirective} from '@common/shared/directive/labeled-form-field.directive';
|
||||
|
||||
|
||||
|
||||
@@ -56,6 +57,7 @@ import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module';
|
||||
MatExpansionModule,
|
||||
FormsModule,
|
||||
LayoutModule,
|
||||
LabeledFormFieldDirective,
|
||||
SharedPipesModule
|
||||
],
|
||||
exports: [
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<div class="navbar-header-container">
|
||||
<div class="header-container">
|
||||
<div class="nav-bar-items-container">
|
||||
<span [routerLink]="['workers']" routerLinkActive #rlaWorkers="routerLinkActive">
|
||||
<span [routerLink]="['workers']" routerLinkActive="active" #rlaWorkers="routerLinkActive">
|
||||
<sm-navbar-item direction="top" header="workers" [active]="rlaWorkers.isActive"></sm-navbar-item>
|
||||
</span>
|
||||
<span [routerLink]="['queues']" routerLinkActive #rlaQueues="routerLinkActive">
|
||||
<span [routerLink]="['queues']" routerLinkActive="active" #rlaQueues="routerLinkActive">
|
||||
<sm-navbar-item direction="top" header="queues" [active]="rlaQueues.isActive"></sm-navbar-item>
|
||||
</span>
|
||||
</div>
|
||||
@@ -16,4 +16,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<router-outlet></router-outlet>
|
||||
<router-outlet class="outlet"></router-outlet>
|
||||
@@ -0,0 +1,39 @@
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {OrchestrationComponent} from '@common/workers-and-queues/orchestration.component';
|
||||
import {WorkersComponent} from '@common/workers-and-queues/containers/workers/workers.component';
|
||||
import {QueuesComponent} from '@common/workers-and-queues/containers/queues/queues.component';
|
||||
import {WorkersAndQueuesResolver} from '~/shared/resolvers/workers-and-queues.resolver';
|
||||
import {CrumbTypeEnum} from '@common/layout/breadcrumbs/breadcrumbs.component';
|
||||
|
||||
const wQBreadcrumb = [[{
|
||||
name: 'WORKERS AND QUEUES',
|
||||
type: CrumbTypeEnum.Feature
|
||||
}]];
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: OrchestrationComponent,
|
||||
resolve: {
|
||||
queuesManager: WorkersAndQueuesResolver
|
||||
},
|
||||
children: [
|
||||
{path: '', redirectTo: 'workers', pathMatch: 'full'},
|
||||
{path: 'workers', component: WorkersComponent, data: {staticBreadcrumb: wQBreadcrumb}},
|
||||
{
|
||||
path: 'queues',
|
||||
component: QueuesComponent,
|
||||
data: {staticBreadcrumb: wQBreadcrumb, queuesManager: true}
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild(routes)
|
||||
],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class WorkersAndQueuesRoutingModule {
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {WorkersAndQueuesRoutingModule} from '@common/workers-and-queues/workers-and-queues-routing.module';
|
||||
import {WorkersAndQueuesComponent} from '@common/workers-and-queues/workers-and-queues.component';
|
||||
import {WorkersAndQueuesRoutingModule} from './workers-and-queues-routing.module';
|
||||
import {OrchestrationComponent} from '@common/workers-and-queues/orchestration.component';
|
||||
import {WorkersComponent} from '@common/workers-and-queues/containers/workers/workers.component';
|
||||
import {QueuesComponent} from '@common/workers-and-queues/containers/queues/queues.component';
|
||||
import {SMSharedModule} from '@common/shared/shared.module';
|
||||
@@ -41,7 +41,7 @@ import {QueuesMenuExtendedComponent} from './queues-menu-extended/queues-menu-ex
|
||||
FormsModule,
|
||||
],
|
||||
declarations: [
|
||||
WorkersAndQueuesComponent,
|
||||
OrchestrationComponent,
|
||||
WorkersComponent,
|
||||
WorkersTableComponent,
|
||||
WorkersStatsComponent,
|
||||
|
||||
@@ -20,22 +20,22 @@
|
||||
routerLinkActive="active">
|
||||
</a>
|
||||
<a class="item al-ico-datasets"
|
||||
routerLink="/datasets"
|
||||
routerLinkActive="active"
|
||||
[routerLink]="(defaultNestedModeForFeature$ | async)?.['datasets']? '/datasets/simple/*/projects' : '/datasets'"
|
||||
[class.active]="(baseRouteConfig$ | async) ==='datasets'"
|
||||
smTooltip="DATASETS"
|
||||
[matTooltipShowDelay]="0"
|
||||
matTooltipPosition="right">
|
||||
</a>
|
||||
<a class="item al-ico-pipelines"
|
||||
routerLink="/pipelines"
|
||||
routerLinkActive="active"
|
||||
[routerLink]="(defaultNestedModeForFeature$ | async)?.['pipelines']? '/pipelines/*/projects' : '/pipelines'"
|
||||
[class.active]="(baseRouteConfig$ | async) ==='pipelines'"
|
||||
smTooltip="PIPELINES"
|
||||
[matTooltipShowDelay]="0"
|
||||
matTooltipPosition="right">
|
||||
</a>
|
||||
<a class="item al-ico-reports"
|
||||
routerLink="/reports"
|
||||
routerLinkActive="active"
|
||||
[routerLink]="(defaultNestedModeForFeature$ | async)?.['reports']? '/reports/*/projects' : '/reports'"
|
||||
[class.active]="(baseRouteConfig$ | async) ==='reports'"
|
||||
smTooltip="REPORTS"
|
||||
[matTooltipShowDelay]="0"
|
||||
matTooltipPosition="right">
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import {selectCurrentUser} from '@common/core/reducers/users-reducer';
|
||||
import {AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, ViewChild} from '@angular/core';
|
||||
import {Store} from '@ngrx/store';
|
||||
import {selectSelectedProjectId} from '@common/core/reducers/projects.reducer';
|
||||
import {selectDefaultNestedModeForFeature, selectSelectedProjectId} from '@common/core/reducers/projects.reducer';
|
||||
import {fromEvent, Observable} from 'rxjs';
|
||||
import {ConfigurationService} from '@common/shared/services/configuration.service';
|
||||
import {searchDeactivate} from '@common/dashboard-search/dashboard-search.actions';
|
||||
import {selectRouterConfig} from '@common/core/reducers/router-reducer';
|
||||
import {map} from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector : 'sm-side-nav',
|
||||
@@ -17,13 +19,17 @@ export class SideNavComponent implements AfterViewInit {
|
||||
currentUser: any;
|
||||
environment = ConfigurationService.globalEnvironment;
|
||||
public scrolling: boolean;
|
||||
public defaultNestedModeForFeature$: Observable<{ [p: string]: boolean }>;
|
||||
public baseRouteConfig$: Observable<string>;
|
||||
|
||||
@ViewChild('container') container: ElementRef<HTMLDivElement>;
|
||||
|
||||
|
||||
constructor(public store: Store<any>, private cdr: ChangeDetectorRef) {
|
||||
this.selectedProjectId$ = this.store.select(selectSelectedProjectId);
|
||||
this.defaultNestedModeForFeature$ = this.store.select(selectDefaultNestedModeForFeature);
|
||||
this.store.select(selectCurrentUser).subscribe((res) => this.currentUser = res);
|
||||
this.baseRouteConfig$ = this.store.select(selectRouterConfig).pipe(map(conf => conf?.[0]));
|
||||
|
||||
fromEvent(window, 'resize').subscribe(() => {
|
||||
const scrolling = this.container.nativeElement.scrollHeight > this.container.nativeElement.clientHeight;
|
||||
|
||||
@@ -43,3 +43,5 @@ export const EXPERIMENTS_STATUS_LABELS = {
|
||||
[TaskTypeEnum.Qc] : 'Qc',
|
||||
[TaskTypeEnum.Custom] : 'Custom'
|
||||
};
|
||||
|
||||
export const hideDeleteArtifactsEntities = [EntityTypeEnum.model];
|
||||
|
||||
@@ -3,4 +3,15 @@ import {HTTP} from '~/app.constants';
|
||||
export const isFileserverUrl = (url: string) =>
|
||||
url.startsWith(HTTP.FILE_BASE_URL);
|
||||
|
||||
export const convertToReverseProxy = (url: string) => url;
|
||||
export const convertToReverseProxy = (url: string) => {
|
||||
try {
|
||||
const u = new URL(url);
|
||||
if (!u.pathname.startsWith('/files')) {
|
||||
u.protocol = window.location.protocol;
|
||||
u.host = window.location.host;
|
||||
u.pathname = 'files' + u.pathname;
|
||||
return u.toString();
|
||||
}
|
||||
} catch {}
|
||||
return url;
|
||||
};
|
||||
|
||||
@@ -12,11 +12,10 @@ import {NotifierConfigToken, NotifierService} from './services/notifier.service'
|
||||
/**
|
||||
* Injection Token for notifier options
|
||||
*/
|
||||
export const NotifierOptionsToken: InjectionToken<NotifierOptions>
|
||||
export const notifierOptionsToken: InjectionToken<NotifierOptions>
|
||||
= new InjectionToken<NotifierOptions>('[angular-notifier] Notifier Options');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Factory for a notifier configuration with custom options
|
||||
*
|
||||
@@ -26,9 +25,7 @@ export const NotifierOptionsToken: InjectionToken<NotifierOptions>
|
||||
* @param options - Custom notifier options
|
||||
* @returns - Notifier configuration as result
|
||||
*/
|
||||
export function notifierCustomConfigFactory(options: NotifierOptions): NotifierConfig {
|
||||
return new NotifierConfig(options);
|
||||
}
|
||||
export const notifierCustomConfigFactory = (options: NotifierOptions): NotifierConfig => new NotifierConfig(options);
|
||||
|
||||
/**
|
||||
* Factory for a notifier configuration with default options
|
||||
@@ -38,9 +35,7 @@ export function notifierCustomConfigFactory(options: NotifierOptions): NotifierC
|
||||
*
|
||||
* @returns - Notifier configuration as result
|
||||
*/
|
||||
export function notifierDefaultConfigFactory(): NotifierConfig {
|
||||
return new NotifierConfig({});
|
||||
}
|
||||
export const notifierDefaultConfigFactory = (): NotifierConfig => new NotifierConfig({});
|
||||
|
||||
/**
|
||||
* Notifier module
|
||||
@@ -84,14 +79,14 @@ export class NotifierModule {
|
||||
|
||||
// Provide the options itself upfront (as we need to inject them as dependencies -- see below)
|
||||
{
|
||||
provide: NotifierOptionsToken,
|
||||
provide: notifierOptionsToken,
|
||||
useValue: options
|
||||
},
|
||||
|
||||
// Provide a custom notifier configuration, based on the given notifier options
|
||||
{
|
||||
deps: [
|
||||
NotifierOptionsToken
|
||||
notifierOptionsToken
|
||||
],
|
||||
provide: NotifierConfigToken,
|
||||
useFactory: notifierCustomConfigFactory
|
||||
|
||||
@@ -19,7 +19,6 @@ $notifier-shadow-color: rgba(0, 0, 0, .2) !default;
|
||||
}
|
||||
|
||||
.notifier__notification {
|
||||
|
||||
&-message {
|
||||
display: inline-block;
|
||||
margin: { // Reset paragraph default styles
|
||||
@@ -31,6 +30,8 @@ $notifier-shadow-color: rgba(0, 0, 0, .2) !default;
|
||||
font-size: 15px;
|
||||
.message{
|
||||
white-space: pre-line;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.user-action {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
@font-face {
|
||||
font-family: '#{$icomoon-font-family}';
|
||||
src: url('./#{$icomoon-font-family}.ttf?i5mliw') format('truetype');
|
||||
src: url('./#{$icomoon-font-family}.ttf?s0lnuq') format('truetype');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: block;
|
||||
@@ -24,6 +24,11 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.al-ico-info-circle-outline {
|
||||
&:before {
|
||||
content: $al-ico-info-circle-outline;
|
||||
}
|
||||
}
|
||||
.al-ico-ghost {
|
||||
&:before {
|
||||
content: $al-ico-ghost;
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,7 @@
|
||||
$icomoon-font-family: "trains" !default;
|
||||
$icomoon-font-path: "fonts" !default;
|
||||
|
||||
$al-ico-info-circle-outline: "\e9f0";
|
||||
$al-ico-ghost: "\e9ef";
|
||||
$al-ico-flat-view: "\e9ee";
|
||||
$al-ico-camera: "\e9ed";
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g>
|
||||
<title>background</title>
|
||||
<rect fill="none" id="canvas_background" height="26" width="26" y="-1" x="-1"/>
|
||||
</g>
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<g id="svg_1" fill-rule="evenodd" fill="none">
|
||||
<path id="svg_2" d="m5.874997,0.125l18,0l0,18l-18,0l0,-18z"/>
|
||||
<path id="svg_3" opacity="0.3" d="m17.874997,6.125c-0.148,0.11 -0.315,0 -0.75,0l-10.5,0c-0.435,0 -0.602,0.11 -0.75,0c-0.045,0.565 -0.006,0.764 0,0.75l4.5,4.5l0,3.75c-0.134,0.42 -0.08,0.548 0,0.75l2.25,2.25c0.058,-0.054 0.186,0 0,0c0.407,0 0.478,-0.014 0.75,0c0.023,-0.14 0.134,-0.307 0,-0.75l0,-6l4.5,-4.5c0.006,0.014 0.045,-0.185 0,-0.75z" fill-rule="nonzero" fill="#8492C2"/>
|
||||
</g>
|
||||
</g>
|
||||
<path d="m17.83,6.85l-4.33,4.57v6.06c0,.42-.48.65-.81.39l-2.19-1.75v-4.7l-4.33-4.57c-.36-.31-.1-.85.4-.85h10.86c.5,0,.76.54.4.85Z" fill="#8492c2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 730 B After Width: | Height: | Size: 221 B |
@@ -3,6 +3,7 @@ import {ExtFrame} from '@common/shared/single-graph/plotly-graph-base';
|
||||
import {DebugSample} from '@common/shared/debug-sample/debug-sample.reducer';
|
||||
import {ReportsApiMultiplotsResponse} from '@common/clearml-applications/report-widgets/src/app/app.reducer';
|
||||
import {Task} from '~/business-logic/model/tasks/task';
|
||||
import {SingleValueTaskMetrics} from '~/business-logic/model/reports/singleValueTaskMetrics';
|
||||
|
||||
export const getPlot = createAction('[App] getPlot', props<{
|
||||
tasks: string[];
|
||||
@@ -10,6 +11,7 @@ export const getPlot = createAction('[App] getPlot', props<{
|
||||
metrics: string[];
|
||||
variants: string[];
|
||||
company: string;
|
||||
models: boolean;
|
||||
otherSearchParams?: URLSearchParams;
|
||||
}>());
|
||||
|
||||
@@ -19,6 +21,7 @@ export const getScalar = createAction('[App] getScalar', props<{
|
||||
metrics: string[];
|
||||
variants: string[];
|
||||
company: string;
|
||||
models: boolean;
|
||||
otherSearchParams?: URLSearchParams;
|
||||
}>());
|
||||
export const getSample = createAction('[App] getSample', props<{
|
||||
@@ -37,11 +40,23 @@ export const getParcoords = createAction('[App] getParcoords', props<{
|
||||
company: string;
|
||||
otherSearchParams?: URLSearchParams;
|
||||
}>());
|
||||
export const getSingleValues = createAction('[App] getSingleValues', props<{
|
||||
tasks: string[];
|
||||
company: string;
|
||||
models: boolean;
|
||||
otherSearchParams?: URLSearchParams;
|
||||
}>());
|
||||
export const setPlotData = createAction('[App] setPlot', props<{ data: ReportsApiMultiplotsResponse }>());
|
||||
export const setScalarData = createAction('[App] setScalar', props<{ data: ExtFrame[] }>());
|
||||
export const setSampleData = createAction('[App] setSample', props<{ data: DebugSample }>());
|
||||
export const setSingleValues = createAction('[App] setSingleValues', props<{ data: SingleValueTaskMetrics }>());
|
||||
export const setParallelCoordinateExperiments = createAction('[App] setParcoor', props<{ data: Task[] }>());
|
||||
|
||||
export const reportsPlotlyReady = createAction('[App] plotly ready');
|
||||
export const setSignIsNeeded = createAction('[App] set sign is needed');
|
||||
export const setNoPermissions = createAction('[App] set no permissions');
|
||||
export const setTaskData = createAction('[App] set task data', props<{
|
||||
sourceProject: string;
|
||||
sourceTasks: string[];
|
||||
appId?: string;
|
||||
}>());
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
<ng-container *ngIf="(signIsNeeded$ | async) === false; else signIsNeededTemplate">
|
||||
<ng-container *ngIf="(noPermissions$ | async) === false; else noPermissionsTemplate">
|
||||
|
||||
<a class="webapp-link" [href]="webappLink" target="_blank" [class.dark-theme]="isDarkTheme">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
||||
<path d="m2.67,14.66c-.74,0-1.33-.6-1.33-1.33h0V2.67c0-.74.6-1.33,1.33-1.33h5.33v1.33H2.67v10.67h10.67v-5.33h1.34v5.33c0,.74-.6,1.33-1.34,1.33H2.67Zm4.86-7.14l4.86-4.86h-1.72v-1.33h4v4h-1.33v-1.72l-4.86,4.86-.95-.94Z" fill="#8693be"/>
|
||||
</svg>
|
||||
<span class="webapp-link_tooltip">View original resource</span>
|
||||
</a>
|
||||
<ng-container [ngSwitch]="type">
|
||||
<ng-container *ngSwitchCase="type === 'plot' || type === 'scalar' ? type : ''">
|
||||
<sm-single-graph
|
||||
@@ -33,6 +39,7 @@
|
||||
(imageClicked)="hideMaximize === 'show' && sampleClicked($event)">
|
||||
</sm-debug-image-snippet>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'parcoords'">
|
||||
<sm-parallel-coordinates-graph
|
||||
*ngIf="parcoordsData"
|
||||
@@ -44,6 +51,15 @@
|
||||
[reportMode]="true"
|
||||
></sm-parallel-coordinates-graph>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="'single'">
|
||||
<sm-single-value-summary-table
|
||||
*ngIf="singleValueData && singleValueData[0]"
|
||||
[data]="singleValueData"
|
||||
[experimentName]="singleValueData[0]?.metric"
|
||||
[darkTheme]="isDarkTheme"
|
||||
class="single-value-summary-table"></sm-single-value-summary-table>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
|
||||
@@ -67,3 +67,59 @@
|
||||
padding: 24px;
|
||||
// min-height: 150px;
|
||||
}
|
||||
|
||||
.webapp-link {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
top: 26px;
|
||||
left: 21px;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
visibility: hidden;
|
||||
|
||||
&:hover {
|
||||
svg path {
|
||||
fill: $blue-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:host {
|
||||
&:hover .webapp-link {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.webapp-link_tooltip {
|
||||
display:none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 24px;
|
||||
z-index: 1;
|
||||
padding: 6px 8px;
|
||||
font-size: 12px;
|
||||
text-align: left;
|
||||
color: white;
|
||||
background-color: #6B7488;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
a.webapp-link:hover .webapp-link_tooltip {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.webapp-link.dark-theme {
|
||||
svg path {
|
||||
fill: $blue-300;
|
||||
}
|
||||
&:hover {
|
||||
svg path {
|
||||
fill: $blue-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnInit, ViewChild} from '@angular/core';
|
||||
import {Store} from '@ngrx/store';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {Observable} from 'rxjs';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {Observable, withLatestFrom} from 'rxjs';
|
||||
import {filter, map, switchMap, take} from 'rxjs/operators';
|
||||
import {Environment} from '../environments/base';
|
||||
import {getParcoords, getPlot, getSample, getScalar, reportsPlotlyReady} from './app.actions';
|
||||
import {getParcoords, getPlot, getSample, getScalar, getSingleValues, reportsPlotlyReady} from './app.actions';
|
||||
import {
|
||||
ReportsApiMultiplotsResponse,
|
||||
selectNoPermissions,
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
selectReportsPlotlyReady,
|
||||
selectSampleData,
|
||||
selectSignIsNeeded,
|
||||
selectSingleValuesData,
|
||||
selectTaskData,
|
||||
State
|
||||
} from './app.reducer';
|
||||
import {ExtFrame} from '@common/shared/single-graph/plotly-graph-base';
|
||||
@@ -30,9 +32,10 @@ import {setCurrentDebugImage} from '@common/shared/debug-sample/debug-sample.act
|
||||
import {isFileserverUrl} from '~/shared/utils/url';
|
||||
import {MetricValueType, SelectedMetric} from '@common/experiments-compare/experiments-compare.constants';
|
||||
import {ExtraTask} from '@common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component';
|
||||
import {EventsGetTaskSingleValueMetricsResponseValues} from '~/business-logic/model/events/eventsGetTaskSingleValueMetricsResponseValues';
|
||||
|
||||
|
||||
type WidgetTypes = 'plot' | 'scalar' | 'sample' | 'parcoords';
|
||||
type WidgetTypes = 'plot' | 'scalar' | 'sample' | 'parcoords' | 'single';
|
||||
|
||||
@Component({
|
||||
selector: 'sm-app-root',
|
||||
@@ -59,6 +62,8 @@ export class AppComponent implements OnInit {
|
||||
public externalTool: boolean = false;
|
||||
public parcoordsData: { experiments: ExtraTask[]; params: string[]; metric: SelectedMetric; valueType: MetricValueType };
|
||||
@ViewChild(SingleGraphComponent) 'singleGraph': SingleGraphComponent;
|
||||
public singleValueData: EventsGetTaskSingleValueMetricsResponseValues[];
|
||||
public webappLink: string;
|
||||
|
||||
@HostListener('window:resize')
|
||||
onResize() {
|
||||
@@ -77,6 +82,7 @@ export class AppComponent implements OnInit {
|
||||
this.noPermissions$ = store.select(selectNoPermissions);
|
||||
this.searchParams = new URLSearchParams(window.location.search);
|
||||
this.type = this.searchParams.get('type') as WidgetTypes;
|
||||
this.webappLink = this.buildSourceLink(this.searchParams, '*', null);
|
||||
this.singleGraphHeight = window.innerHeight;
|
||||
this.otherSearchParams = this.getOtherSearchParams();
|
||||
this.isDarkTheme = !this.searchParams.get('light');
|
||||
@@ -91,7 +97,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
private getOtherSearchParams() {
|
||||
const paramsToRemove = ['light', 'type', 'tasks', 'metrics', 'variants', 'iterations', 'company', 'value_type'];
|
||||
const paramsToRemove = ['light', 'type', 'tasks', 'models', 'objects', 'objectType', 'metrics', 'variants', 'iterations', 'company', 'value_type'];
|
||||
const otherSearchParams = new URLSearchParams(window.location.search);
|
||||
paramsToRemove.forEach(key => {
|
||||
otherSearchParams.delete(key);
|
||||
@@ -123,6 +129,9 @@ export class AppComponent implements OnInit {
|
||||
break;
|
||||
case 'parcoords':
|
||||
this.getParallelCoordinate();
|
||||
break;
|
||||
case 'single':
|
||||
this.getSingleValues();
|
||||
}
|
||||
|
||||
window.addEventListener('message', (e) => {
|
||||
@@ -134,6 +143,15 @@ export class AppComponent implements OnInit {
|
||||
this.hideMaximize = 'disabled';
|
||||
}
|
||||
});
|
||||
|
||||
this.store.select(selectTaskData)
|
||||
.pipe(
|
||||
filter(taskData => !!taskData),
|
||||
take(1))
|
||||
.subscribe(({sourceProject, sourceTasks, appId}) => {
|
||||
this.webappLink = appId ? this.buildAppLink(sourceTasks, appId) : this.buildSourceLink(this.searchParams, sourceProject, sourceTasks);
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
/// Merging all variants of same metric to same graph. (single experiment)
|
||||
@@ -169,7 +187,7 @@ export class AppComponent implements OnInit {
|
||||
const merged = this.mergeVariants(metricsPlots as ReportsApiMultiplotsResponse);
|
||||
this.plotData = Object.values(merged)[0].plotParsed;
|
||||
} else {
|
||||
const {merged, } = prepareMultiPlots(metricsPlots);
|
||||
const {merged,} = prepareMultiPlots(metricsPlots);
|
||||
const newGraphs = convertMultiPlots(merged);
|
||||
this.plotData = Object.values(newGraphs)[0]?.[0];
|
||||
}
|
||||
@@ -264,14 +282,31 @@ export class AppComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
activate = () => {
|
||||
this.type !== 'sample' && loadExternalLibrary(this.store, this.environment.plotlyURL, reportsPlotlyReady);
|
||||
private getSingleValues() {
|
||||
this.store.select(selectSingleValuesData)
|
||||
.pipe(
|
||||
filter(singleValueData => !!singleValueData),
|
||||
take(1)
|
||||
).subscribe(singleValueData => {
|
||||
this.singleValueData = singleValueData.values;
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
activate = async () => {
|
||||
this.activated = true;
|
||||
await this.waitForVisibility();
|
||||
this.singleGraphHeight = window.innerHeight;
|
||||
!['sample', 'single'].includes(this.type) && loadExternalLibrary(this.store, this.environment.plotlyURL, reportsPlotlyReady);
|
||||
const models = this.searchParams.has('models') || this.searchParams.get('objectType') === 'model';
|
||||
const objects = this.searchParams.getAll('objects');
|
||||
const queryParams = {
|
||||
tasks: this.searchParams.getAll('tasks'),
|
||||
tasks: objects.length > 0 ? objects : this.searchParams.getAll('tasks'),
|
||||
metrics: this.searchParams.getAll('metrics'),
|
||||
variants: this.searchParams.getAll('variants'),
|
||||
iterations: this.searchParams.getAll('iterations').map(iteration => parseInt(iteration, 10)),
|
||||
company: this.searchParams.get('company') || '',
|
||||
models
|
||||
};
|
||||
|
||||
switch (this.type) {
|
||||
@@ -286,8 +321,11 @@ export class AppComponent implements OnInit {
|
||||
break;
|
||||
case 'parcoords':
|
||||
this.store.dispatch(getParcoords({...queryParams, otherSearchParams: this.otherSearchParams}));
|
||||
break;
|
||||
case 'single':
|
||||
this.store.dispatch(getSingleValues({...queryParams, otherSearchParams: this.otherSearchParams}));
|
||||
break;
|
||||
}
|
||||
this.activated = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -339,4 +377,80 @@ export class AppComponent implements OnInit {
|
||||
const lastMetric = get(experimentWithCurrentMetric.last_metrics, metric) as ExtraTask['last_metrics'];
|
||||
return `${lastMetric.metric}/${lastMetric.variant}`;
|
||||
}
|
||||
|
||||
private buildSourceLink(searchParams: URLSearchParams, project: string, tasks: string[]): string {
|
||||
const isModels = searchParams.has('models') || this.searchParams.get('objectType') === 'model';
|
||||
const objects = searchParams.getAll('objects');
|
||||
let entityIds = objects.length > 0? objects : searchParams.getAll(isModels ? 'models' : 'tasks');
|
||||
if (entityIds.length === 0 && tasks?.length > 0) {
|
||||
entityIds = tasks;
|
||||
}
|
||||
const isCompare = entityIds.length > 1;
|
||||
let url = `${window.location.origin.replace('4201', '4200')}/projects/${project ?? '*'}/`;
|
||||
if (isCompare) {
|
||||
url += `${isModels ? 'compare-models;ids=' : 'compare-experiments;ids='}${entityIds.join(',')}/${this.getComparePath(this.type)}`;
|
||||
} else {
|
||||
url += `${isModels ? 'models/' : 'experiments/'}${entityIds}/${this.getOutputPath(isModels, this.type)}`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
private getOutputPath(isModels: boolean, type: WidgetTypes) {
|
||||
if (isModels) {
|
||||
switch (type) {
|
||||
case 'single':
|
||||
case 'scalar':
|
||||
return 'scalars';
|
||||
case 'plot':
|
||||
return 'plots';
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case 'single':
|
||||
case 'scalar':
|
||||
return 'info-output/metrics/scalar';
|
||||
case 'plot':
|
||||
return 'info-output/metrics/plots';
|
||||
case 'sample':
|
||||
return 'info-output/debugImages';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getComparePath(type: WidgetTypes) {
|
||||
switch (type) {
|
||||
case 'single':
|
||||
case 'scalar':
|
||||
return 'scalars/graph';
|
||||
case 'plot':
|
||||
return 'metrics-plots';
|
||||
case 'parcoords':
|
||||
return 'hyper-params/graph';
|
||||
case 'sample':
|
||||
return 'debug-images';
|
||||
}
|
||||
}
|
||||
|
||||
private buildAppLink(sourceTasks: string[], appId) {
|
||||
const isAutoscaler = appId.includes('autoscaler');
|
||||
return `${window.location.origin.replace('4201', '4200')}/${isAutoscaler ? 'workers-and-queues/autoscalers' : 'applications'}/${appId}/info;experimentId=${sourceTasks[0]}?instancesFilter=All`;
|
||||
}
|
||||
|
||||
private waitForVisibility(): Promise<boolean> {
|
||||
return new Promise(resolve => {
|
||||
if (window.innerHeight > 0) {
|
||||
return resolve(true);
|
||||
}
|
||||
|
||||
const observer = new IntersectionObserver(entities => {
|
||||
if (entities[0].intersectionRatio > 0) {
|
||||
resolve(true);
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ import {
|
||||
getParcoords,
|
||||
getPlot,
|
||||
getSample,
|
||||
getScalar,
|
||||
getScalar, getSingleValues,
|
||||
setNoPermissions, setParallelCoordinateExperiments,
|
||||
setPlotData,
|
||||
setSampleData,
|
||||
setSignIsNeeded
|
||||
setSignIsNeeded, setSingleValues, setTaskData
|
||||
} from './app.actions';
|
||||
import {EMPTY, mergeMap, of, switchMap} from 'rxjs';
|
||||
import {Store} from '@ngrx/store';
|
||||
@@ -50,6 +50,8 @@ export class AppEffects {
|
||||
switchMap(action => this.httpClient.post<{ data: ReportsGetTaskDataResponse }>(`${this.basePath}/reports.get_task_data?${action.otherSearchParams.toString()}`,
|
||||
{
|
||||
id: action.tasks,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
model_events: action.models,
|
||||
plots: {
|
||||
iters: 1,
|
||||
metrics: action.metrics.map(metric => ({metric, variants: action.variants}))
|
||||
@@ -57,7 +59,13 @@ export class AppEffects {
|
||||
},
|
||||
{headers: this.getHeaders(action.company)}
|
||||
)),
|
||||
mergeMap((res) => [setPlotData({data: res.data.plots as unknown as ReportsApiMultiplotsResponse})]),
|
||||
mergeMap((res) => [
|
||||
setPlotData({data: res.data.plots as unknown as ReportsApiMultiplotsResponse}),
|
||||
setTaskData({
|
||||
sourceProject: (res.data.tasks[0]?.project as any).id,
|
||||
sourceTasks: res.data.tasks.map(t => t.id),
|
||||
appId: (res.data.tasks[0] as any)?.application?.app_id?.id
|
||||
})]),
|
||||
catchError(error => [requestFailed(error), ...(error.status === 403 ? [setNoPermissions()] : [])])
|
||||
));
|
||||
|
||||
@@ -67,6 +75,8 @@ export class AppEffects {
|
||||
{
|
||||
id: action.tasks,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
model_events: action.models,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
scalar_metrics_iter_histogram: {
|
||||
metrics: action.metrics.map(metric => ({metric, variants: action.variants}))
|
||||
}
|
||||
@@ -74,7 +84,12 @@ export class AppEffects {
|
||||
{headers: this.getHeaders(action.company)}
|
||||
).pipe(
|
||||
mergeMap(res => [
|
||||
setPlotData({data: res.data.scalar_metrics_iter_histogram as ReportsApiMultiplotsResponse})]
|
||||
setPlotData({data: res.data.scalar_metrics_iter_histogram as ReportsApiMultiplotsResponse}),
|
||||
setTaskData({
|
||||
sourceProject: (res.data.tasks[0]?.project as any).id,
|
||||
sourceTasks: res.data.tasks.map(t => t.id),
|
||||
appId: (res.data.tasks[0] as any)?.application?.app_id?.id
|
||||
})]
|
||||
), catchError(error => [requestFailed(error), ...(error.status === 403 ? [setNoPermissions()] : [])])
|
||||
)
|
||||
)
|
||||
@@ -94,26 +109,46 @@ export class AppEffects {
|
||||
{headers: this.getHeaders(action.company)}
|
||||
).pipe(
|
||||
mergeMap(res => [
|
||||
setSampleData({data: res.data.debug_images?.[0]?.iterations?.[0]?.events[0] as DebugSample})
|
||||
]),
|
||||
setSampleData({data: res.data.debug_images?.[0]?.iterations?.[0]?.events[0] as DebugSample}),
|
||||
setTaskData({sourceProject: (res.data.tasks[0]?.project as any).id, sourceTasks: res.data.tasks.map(t => t.id)})]),
|
||||
catchError(error => [requestFailed(error), ...(error.status === 403 ? [setNoPermissions()] : [])])
|
||||
)
|
||||
))
|
||||
);
|
||||
|
||||
getExperiments$ = createEffect(() => this.actions$.pipe(
|
||||
getParcoords$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(getParcoords),
|
||||
mergeMap((action) => this.httpClient.post<{data: ReportsGetTaskDataResponse}>(`${this.basePath}/reports.get_task_data?${action.otherSearchParams.toString()}`, {
|
||||
mergeMap((action) => this.httpClient.post<{ data: ReportsGetTaskDataResponse }>(`${this.basePath}/reports.get_task_data?${action.otherSearchParams.toString()}`, {
|
||||
id: action.tasks,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
only_fields: ['last_metrics', 'name', 'last_iteration', ...action.variants.map(variant => `hyperparams.${variant}`)]
|
||||
})
|
||||
.pipe(
|
||||
mergeMap(res => [setParallelCoordinateExperiments({data: res.data.tasks as unknown as Task[]})])
|
||||
mergeMap(res => [
|
||||
setParallelCoordinateExperiments({data: res.data.tasks as unknown as Task[]}),
|
||||
setTaskData({sourceProject: (res.data.tasks[0]?.project as any).id, sourceTasks: res.data.tasks.map(t => t.id)})
|
||||
])
|
||||
)
|
||||
))
|
||||
);
|
||||
|
||||
getScalarSingleValue$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(getSingleValues),
|
||||
switchMap((action) => this.httpClient.post<{ data: ReportsGetTaskDataResponse }>(`${this.basePath}/reports.get_task_data?${action.otherSearchParams.toString()}`, {
|
||||
id: action.tasks,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
model_events: action.models,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
single_value_metrics: {}
|
||||
})
|
||||
),
|
||||
mergeMap((res: { data: ReportsGetTaskDataResponse }) => [
|
||||
setSingleValues({data: res.data.single_value_metrics[0]}),
|
||||
setTaskData({sourceProject: (res.data.tasks[0]?.project as any).id, sourceTasks: res.data.tasks.map(t => t.id)})
|
||||
]
|
||||
)
|
||||
));
|
||||
|
||||
signUrl = createEffect(() => this.actions$.pipe(
|
||||
ofType(getSignedUrl),
|
||||
filter(action => !!action.url),
|
||||
|
||||
@@ -8,7 +8,7 @@ import {AppEffects} from './app.effects';
|
||||
import {StoreModule} from '@ngrx/store';
|
||||
import {appReducer} from './app.reducer';
|
||||
import {HttpClientModule} from '@angular/common/http';
|
||||
import {MatLegacyDialogModule as MatDialogModule} from '@angular/material/legacy-dialog';
|
||||
import {MatDialogModule} from '@angular/material/dialog';
|
||||
import {ChooseColorModule} from '@common/shared/ui-components/directives/choose-color/choose-color.module';
|
||||
import {SingleGraphModule} from '@common/shared/single-graph/single-graph.module';
|
||||
import {DebugSampleModule} from '@common/shared/debug-sample/debug-sample.module';
|
||||
@@ -20,6 +20,7 @@ import {authReducer} from '~/features/settings/containers/admin/auth.reducers';
|
||||
import {extCoreModules} from '~/build-specifics';
|
||||
import {SmApiRequestsService} from '~/business-logic/api-services/api-requests.service';
|
||||
import {ParallelCoordinatesGraphComponent} from '@common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component';
|
||||
import {SingleValueSummaryTableComponent} from '@common/shared/single-value-summary-table/single-value-summary-table.component';
|
||||
|
||||
if (!localStorage.getItem('_saved_state_')) {
|
||||
localStorage.setItem('_saved_state_', '{}');
|
||||
@@ -29,19 +30,20 @@ if (!localStorage.getItem('_saved_state_')) {
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule,
|
||||
HttpClientModule,
|
||||
MatDialogModule,
|
||||
ChooseColorModule,
|
||||
SingleGraphModule,
|
||||
DebugSampleModule,
|
||||
ParallelCoordinatesGraphComponent,
|
||||
StoreModule.forRoot({appReducer, auth: authReducer}),
|
||||
EffectsModule.forRoot([AppEffects]),
|
||||
...extCoreModules
|
||||
],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule,
|
||||
HttpClientModule,
|
||||
MatDialogModule,
|
||||
ChooseColorModule,
|
||||
SingleGraphModule,
|
||||
DebugSampleModule,
|
||||
ParallelCoordinatesGraphComponent,
|
||||
StoreModule.forRoot({appReducer, auth: authReducer}),
|
||||
EffectsModule.forRoot([AppEffects]),
|
||||
...extCoreModules,
|
||||
SingleValueSummaryTableComponent
|
||||
],
|
||||
providers: [ApiEventsService, ApiReportsService, SmApiRequestsService, ColorHashService, BaseAdminService],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
import {createReducer, createSelector, on} from '@ngrx/store';
|
||||
import {reportsPlotlyReady, setNoPermissions, setParallelCoordinateExperiments, setPlotData, setSampleData, setSignIsNeeded} from './app.actions';
|
||||
import {reportsPlotlyReady, setNoPermissions, setParallelCoordinateExperiments, setPlotData, setSampleData, setSignIsNeeded, setSingleValues, setTaskData} from './app.actions';
|
||||
import {DebugSample} from '@common/shared/debug-sample/debug-sample.reducer';
|
||||
import {MetricsPlotEvent} from '~/business-logic/model/events/metricsPlotEvent';
|
||||
import {MetricValueType, SelectedMetric} from '@common/experiments-compare/experiments-compare.constants';
|
||||
import {Task} from '~/business-logic/model/tasks/task';
|
||||
import {SingleValueTaskMetrics} from '~/business-logic/model/reports/singleValueTaskMetrics';
|
||||
|
||||
export interface ParCoords {
|
||||
metric: SelectedMetric;
|
||||
valueType: MetricValueType;
|
||||
parameters: string[];
|
||||
}
|
||||
|
||||
export interface ParCoords {metric: SelectedMetric; valueType: MetricValueType; parameters: string[]}
|
||||
export interface ReportsApiMultiplotsResponse {
|
||||
[metric: string]: {
|
||||
[variant: string]: {
|
||||
@@ -25,21 +31,29 @@ export const appFeatureKey = 'app';
|
||||
export interface State {
|
||||
plotData: MetricsPlotEvent[] | ReportsApiMultiplotsResponse;
|
||||
sampleData: DebugSample;
|
||||
singleValuesData: SingleValueTaskMetrics;
|
||||
parallelCoordinateData: Task[];
|
||||
scaleFactor: number;
|
||||
plotlyReady: boolean;
|
||||
signIsNeeded: boolean;
|
||||
noPermissions: boolean;
|
||||
taskData: {
|
||||
sourceProject: string;
|
||||
sourceTasks: string[];
|
||||
appId: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
plotData: null,
|
||||
sampleData: null,
|
||||
singleValuesData: null,
|
||||
parallelCoordinateData: null,
|
||||
scaleFactor: 100,
|
||||
plotlyReady: false,
|
||||
signIsNeeded: false,
|
||||
noPermissions: false
|
||||
noPermissions: false,
|
||||
taskData: null
|
||||
};
|
||||
|
||||
export const appReducer = createReducer(
|
||||
@@ -47,9 +61,13 @@ export const appReducer = createReducer(
|
||||
on(reportsPlotlyReady, (state) => ({...state, plotlyReady: true})),
|
||||
on(setPlotData, (state, action) => ({...state, plotData: action.data as ReportsApiMultiplotsResponse})),
|
||||
on(setSampleData, (state, action) => ({...state, sampleData: action.data})),
|
||||
on(setSingleValues, (state, action) => ({...state, singleValuesData: action.data})),
|
||||
on(setParallelCoordinateExperiments, (state, action) => ({...state, parallelCoordinateData: action.data})),
|
||||
on(setSignIsNeeded, (state) => ({...state, signIsNeeded: true})),
|
||||
on(setNoPermissions, (state) => ({...state, noPermissions: true})),
|
||||
on(setTaskData, (state, action) => ({...state, taskData:
|
||||
{appId: action.appId, sourceTasks: action.sourceTasks, sourceProject: action.sourceProject}})
|
||||
),
|
||||
);
|
||||
|
||||
export const selectFeature = state => state.appReducer as State;
|
||||
@@ -58,6 +76,12 @@ export const selectScaleFactor = createSelector(selectFeature, state => state.sc
|
||||
export const selectReportsPlotlyReady = createSelector(selectFeature, state => state.plotlyReady);
|
||||
export const selectPlotData = createSelector(selectFeature, state => state.plotData);
|
||||
export const selectSampleData = createSelector(selectFeature, state => state.sampleData);
|
||||
export const selectSingleValuesData = createSelector(selectFeature, state => state.singleValuesData);
|
||||
export const selectParallelCoordinateExperiments = createSelector(selectFeature, state => state.parallelCoordinateData);
|
||||
export const selectSignIsNeeded = createSelector(selectFeature, state => state.signIsNeeded);
|
||||
export const selectNoPermissions = createSelector(selectFeature, state => state.noPermissions);
|
||||
export const selectTaskData = createSelector(selectFeature, (state): {
|
||||
sourceProject: string;
|
||||
sourceTasks: string[];
|
||||
appId: string;
|
||||
} => state.taskData);
|
||||
|
||||
@@ -2,7 +2,40 @@
|
||||
// For more information: https://material.angular.io/guide/theming
|
||||
@use '../../../../../../node_modules/@angular/material/index' as mat;
|
||||
// Plus imports for other components in your app.
|
||||
|
||||
$neon-yellow: #d3ff00;
|
||||
$white-primary-text: rgba(white, 0.87);
|
||||
$sm-neon: (
|
||||
50: lighten($neon-yellow, 30%),
|
||||
100: lighten($neon-yellow, 25%),
|
||||
200: lighten($neon-yellow, 20%),
|
||||
300: lighten($neon-yellow, 15%),
|
||||
400: lighten($neon-yellow, 10%),
|
||||
500: $neon-yellow,
|
||||
600: darken($neon-yellow, 10%),
|
||||
700: darken($neon-yellow, 15%),
|
||||
800: darken($neon-yellow, 20%),
|
||||
900: darken($neon-yellow, 25%),
|
||||
A100: $neon-yellow,
|
||||
A200: darken($neon-yellow, 5%),
|
||||
A400: darken($neon-yellow, 10%),
|
||||
A700: darken($neon-yellow, 15%),
|
||||
contrast: (
|
||||
50: $white-primary-text,
|
||||
100: $white-primary-text,
|
||||
200: $white-primary-text,
|
||||
300: $white-primary-text,
|
||||
400: white,
|
||||
500: white,
|
||||
600: white,
|
||||
700: white,
|
||||
800: white,
|
||||
900: white,
|
||||
A100: white,
|
||||
A200: white,
|
||||
A400: white,
|
||||
A700: white,
|
||||
)
|
||||
);
|
||||
// Include the common styles for Angular Material. We include this here so that you only
|
||||
// have to load a single css file for Angular Material in your app.
|
||||
// Be sure that you only ever include this mixin once!
|
||||
@@ -14,9 +47,14 @@
|
||||
$theme-primary: mat.define-palette(mat.$indigo-palette);
|
||||
$theme-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
|
||||
|
||||
$sm-neon-palette-primary: mat.define-palette($sm-neon);
|
||||
$sm-neon-palette-accent: mat.define-palette($sm-neon, A200, A100, A400);
|
||||
// The warn palette is optional (defaults to red).
|
||||
$theme-warn: mat.define-palette(mat.$red-palette);
|
||||
|
||||
$font-family-base: 'Heebo', sans-serif; // Assumes the browser default, typically `16px`
|
||||
$custom-typography: mat.define-typography-config(
|
||||
$font-family: $font-family-base
|
||||
);
|
||||
// Create the theme object. A theme consists of configurations for individual
|
||||
// theming systems such as "color" or "typography".
|
||||
$theme: mat.define-light-theme((
|
||||
@@ -24,13 +62,26 @@ $theme: mat.define-light-theme((
|
||||
primary: $theme-primary,
|
||||
accent: $theme-accent,
|
||||
warn: $theme-warn,
|
||||
)
|
||||
),
|
||||
typography: $custom-typography,
|
||||
density: -2
|
||||
));
|
||||
|
||||
$sm-neon-theme: mat.define-dark-theme((
|
||||
color: (
|
||||
primary: $sm-neon-palette-primary,
|
||||
accent: $sm-neon-palette-accent,
|
||||
),
|
||||
typography: $custom-typography,
|
||||
density: -2
|
||||
));
|
||||
|
||||
// Include theme styles for core and each component used in your app.
|
||||
// Alternatively, you can import and @include the theme mixins for each component
|
||||
// that you are using.
|
||||
@include mat.dialog-theme($theme);
|
||||
@include mat.slider-theme($sm-neon-theme);
|
||||
@include mat.form-field-theme($theme);
|
||||
|
||||
@import "src/app/webapp-common/shared/ui-components/styles/variables";
|
||||
|
||||
@@ -68,7 +119,7 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.mat-dialog-container {
|
||||
.mat-mdc-dialog-container {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
@@ -76,6 +127,10 @@ body {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.align-items-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.h-100 {
|
||||
height: 100%;
|
||||
}
|
||||
@@ -182,6 +237,107 @@ body {
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
sm-debug-image-snippet {
|
||||
.image-var {
|
||||
top: 8px;
|
||||
bottom: unset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.dark-theme .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__input {
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
}
|
||||
.dark-theme {
|
||||
.mdc-text-field--outlined:not(.mdc-text-field--disabled) {
|
||||
.mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing {
|
||||
border-color: $blue-500;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
&:not(.mdc-text-field--focused):hover .mdc-notched-outline {
|
||||
.mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing {
|
||||
border-color: $blue-450;
|
||||
}
|
||||
}
|
||||
|
||||
&.mdc-text-field--focused {
|
||||
.mdc-notched-outline__leading, .mdc-notched-outline__notch, .mdc-notched-outline__trailing {
|
||||
border-color: $blue-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark-theme, .light-theme {
|
||||
.mat-mdc-form-field {
|
||||
--mdc-typography-body1-font-size: 14px;
|
||||
--mdc-typography-body1-line-height: 16px;
|
||||
|
||||
&.mat-form-field-appearance-outline {
|
||||
&.black {
|
||||
background-color: #000;
|
||||
|
||||
.mat-mdc-select-value, .mat-mdc-select-arrow {
|
||||
color: $blue-200;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-mdc-text-field-wrapper {
|
||||
.mat-mdc-form-field-flex {
|
||||
height: 100%;
|
||||
|
||||
.mat-mdc-form-field-infix {
|
||||
min-height: 100%;
|
||||
padding: 5px 0;
|
||||
|
||||
.mat-mdc-input-element {
|
||||
height: 26px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-mdc-form-field-icon-suffix {
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.mat-form-field-appearance-fill {
|
||||
.mdc-text-field--filled:not(.mdc-text-field--disabled) {
|
||||
background-color: transparent;
|
||||
|
||||
.mat-mdc-input-element {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&.mat-focused {
|
||||
.mat-mdc-form-field-focus-overlay {
|
||||
opacity: 5%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mat-mdc-form-field.smooth-input {
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.label-text.smoothing-text {
|
||||
color: $blue-200;
|
||||
}
|
||||
// hide arrows for number inputs
|
||||
input[type=number]::-webkit-inner-spin-button,
|
||||
input[type=number]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
// hide arrows for number inputs (FireFox)
|
||||
input[type=number] {
|
||||
-moz-appearance: textfield !important;
|
||||
}
|
||||
|
||||
/* width */
|
||||
::-webkit-scrollbar {
|
||||
|
||||
@@ -12,94 +12,104 @@
|
||||
@import "shared/ui-components/styles/material-palette";
|
||||
@import "assets/fonts/trains-icons.scss";
|
||||
@import "layout/layout";
|
||||
@import "shared/ui-components/styles/overrides/viewer-iterations-slider";
|
||||
|
||||
// TODO(v15): As of v15 mat.legacy-core no longer includes default typography styles.
|
||||
// The following line adds:
|
||||
// 1. Default typography styles for all components
|
||||
// 2. Styles for typography hierarchy classes (e.g. .mat-headline-1)
|
||||
// If you specify typography styles for the components you use elsewhere, you should delete this line.
|
||||
// If you don't need the default component typographies but still want the hierarchy styles,
|
||||
// you can delete this line and instead use:
|
||||
// `@include mat.legacy-typography-hierarchy(mat.define-legacy-typography-config());`
|
||||
@include mat.all-legacy-component-typographies();
|
||||
@include mat.legacy-core();
|
||||
//@import "../webapp-common/shared/ui-components/styles/material-theme.scss";
|
||||
|
||||
$custom-typography: mat.define-legacy-typography-config(
|
||||
$font-family: $font-family-base
|
||||
@include mat.core();
|
||||
$custom-typography: mat.define-typography-config(
|
||||
$font-family: $font-family-base
|
||||
);
|
||||
|
||||
@include mat.all-legacy-component-typographies($custom-typography);
|
||||
@include mat.typography-hierarchy($custom-typography);
|
||||
@include mat.all-component-typographies($custom-typography);
|
||||
|
||||
$allegro-theme-primary: mat.define-palette($mat-allegro);
|
||||
$allegro-theme-accent: mat.define-palette($mat-allegro, A400, A100, A400);
|
||||
$custom-theme-primary: mat.define-palette(mat.$green-palette);
|
||||
$custom-theme-accent: mat.define-palette(mat.$lime-palette, A400, A100, A400);
|
||||
$custom-theme-warn: mat.define-palette(mat.$purple-palette);
|
||||
$allegro-palette-primary: mat.define-palette($mat-allegro);
|
||||
$allegro-palette-accent: mat.define-palette($mat-allegro, A400, A100, A400);
|
||||
|
||||
$sm-theme-primary: mat.define-palette($sm-purple);
|
||||
$sm-theme-accent: mat.define-palette($sm-purple, A400, A100, A400);
|
||||
$sm-theme-warn: mat.define-palette(mat.$purple-palette);
|
||||
$sm-palette-primary: mat.define-palette($sm-purple);
|
||||
$sm-palette-accent: mat.define-palette($sm-purple, A100, A200, A400);
|
||||
$sm-palette-warn: mat.define-palette(mat.$purple-palette);
|
||||
|
||||
$green-theme: mat.define-light-theme((color: (
|
||||
primary: $custom-theme-primary,
|
||||
accent: $custom-theme-accent,
|
||||
warn: $custom-theme-warn
|
||||
)));
|
||||
$dark-theme: mat.define-dark-theme((color: (
|
||||
primary: $allegro-theme-primary,
|
||||
accent: $allegro-theme-accent
|
||||
)));
|
||||
$light-theme: mat.define-light-theme((
|
||||
$sm-neon-palette-primary: mat.define-palette($sm-neon);
|
||||
$sm-neon-palette-accent: mat.define-palette($sm-neon, A200, A100, A400);
|
||||
|
||||
$dark-theme: mat.define-dark-theme((
|
||||
color: (
|
||||
primary: $allegro-theme-primary,
|
||||
accent: $allegro-theme-accent
|
||||
primary: $allegro-palette-primary,
|
||||
accent: $allegro-palette-accent
|
||||
),
|
||||
typography: $custom-typography,
|
||||
density: -2
|
||||
));
|
||||
|
||||
$sm-theme: mat.define-light-theme((color: (
|
||||
primary: $sm-theme-primary,
|
||||
accent: $sm-theme-accent,
|
||||
warn: $sm-theme-warn
|
||||
)));
|
||||
$light-theme: mat.define-light-theme((
|
||||
color: (
|
||||
primary: $allegro-palette-primary,
|
||||
accent: $allegro-palette-accent
|
||||
),
|
||||
typography: $custom-typography,
|
||||
));
|
||||
|
||||
@include mat.legacy-form-field-color($light-theme);
|
||||
@include mat.legacy-progress-spinner-theme($light-theme);
|
||||
@include mat.legacy-progress-bar-theme($light-theme);
|
||||
$sm-theme: mat.define-light-theme((
|
||||
color: (
|
||||
primary: $sm-palette-primary,
|
||||
accent: $sm-palette-accent,
|
||||
warn: $sm-palette-warn
|
||||
),
|
||||
typography: $custom-typography
|
||||
));
|
||||
|
||||
$sm-neon-theme: mat.define-dark-theme((
|
||||
color: (
|
||||
primary: $sm-neon-palette-primary,
|
||||
accent: $sm-neon-palette-accent,
|
||||
),
|
||||
typography: $custom-typography
|
||||
));
|
||||
|
||||
//@include mat.form-field-theme($light-theme);
|
||||
@include mat.progress-spinner-theme($light-theme);
|
||||
@include mat.progress-bar-theme($light-theme);
|
||||
@include mat.datepicker-color($light-theme);
|
||||
@include mat.tooltip-theme($sm-theme);
|
||||
@include mat.menu-theme($light-theme);
|
||||
@include mat.autocomplete-theme($light-theme);
|
||||
@include mat.select-theme($light-theme);
|
||||
|
||||
.dark-outline {
|
||||
@include mat.menu-color($dark-theme);
|
||||
@include mat.autocomplete-color($dark-theme);
|
||||
@include mat.select-color($dark-theme);
|
||||
}
|
||||
|
||||
.dark-theme {
|
||||
@include mat.legacy-core-theme($dark-theme);
|
||||
@include mat.legacy-button-theme($dark-theme);
|
||||
@include mat.legacy-slide-toggle-color($green-theme);
|
||||
@include mat.legacy-radio-color($green-theme);
|
||||
@include mat.legacy-select-color($dark-theme);
|
||||
@include mat.legacy-menu-color($light-theme);
|
||||
@include mat.legacy-autocomplete-color($light-theme);
|
||||
@include mat.pseudo-checkbox-color($light-theme);
|
||||
@include mat.divider-color($light-theme);
|
||||
// @include mat.all-component-themes($dark-theme);
|
||||
@include mat.core-theme($dark-theme);
|
||||
@include mat.form-field-theme($dark-theme);
|
||||
@include mat.input-theme($dark-theme);
|
||||
@include mat.dialog-theme($dark-theme);
|
||||
@include mat.chips-theme($dark-theme);
|
||||
@include mat.button-theme($dark-theme);
|
||||
@include mat.fab-theme($dark-theme);
|
||||
@include mat.icon-button-theme($dark-theme);
|
||||
@include mat.slide-toggle-theme($sm-neon-theme);
|
||||
@include mat.slider-theme($sm-neon-theme);
|
||||
@include mat.radio-color($dark-theme);
|
||||
@include mat.divider-color($dark-theme);
|
||||
@include mat.checkbox-theme($dark-theme);
|
||||
@include mat.list-theme($dark-theme);
|
||||
|
||||
--mdc-typography-body1-letter-spacing: 0;
|
||||
--mdc-typography-button-letter-spacing: 0;
|
||||
|
||||
.mat-checkbox-frame,
|
||||
.mat-radio-outer-circle {
|
||||
border-color: $blue-400;
|
||||
.mat-mdc-checkbox .mdc-checkbox {
|
||||
--mdc-checkbox-selected-icon-color: #{$purple};
|
||||
--mdc-checkbox-selected-hover-icon-color: #{$purple};
|
||||
--mdc-checkbox-selected-focus-icon-color: #{$purple};
|
||||
}
|
||||
|
||||
.mat-expansion-panel-header-description, .mat-expansion-indicator:after {
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.light-theme .mat-radio-button.mat-radio-disabled .mat-radio-outer-circle,
|
||||
.light-theme .mat-radio-button.mat-radio-disabled .mat-radio-label-content {
|
||||
border-color: $blue-200 !important;
|
||||
color: $blue-200 !important;
|
||||
}
|
||||
|
||||
.light-theme .mat-radio-button.mat-radio-disabled .mat-radio-inner-circle {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.link {
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
@@ -109,50 +119,34 @@ $sm-theme: mat.define-light-theme((color: (
|
||||
}
|
||||
|
||||
.light-theme {
|
||||
@include mat.legacy-core-color($light-theme);
|
||||
@include mat.legacy-button-color($light-theme);
|
||||
@include mat.legacy-slide-toggle-color($sm-theme);
|
||||
// @include mat.radio-color($sm-theme);
|
||||
@include mat.legacy-radio-theme($sm-theme);
|
||||
// @include mat.select-color($light-theme);
|
||||
@include mat.legacy-select-theme($light-theme);
|
||||
@include mat.legacy-menu-color($light-theme);
|
||||
@include mat.legacy-autocomplete-color($light-theme);
|
||||
@include mat.pseudo-checkbox-color($light-theme);
|
||||
@include mat.core-color($light-theme);
|
||||
@include mat.form-field-color($light-theme);
|
||||
@include mat.input-color($light-theme);
|
||||
@include mat.dialog-color($light-theme);
|
||||
@include mat.chips-color($light-theme);
|
||||
@include mat.button-color($light-theme);
|
||||
@include mat.fab-color($light-theme);
|
||||
@include mat.icon-button-color($light-theme);
|
||||
@include mat.slide-toggle-color($sm-theme);
|
||||
@include mat.slider-color($sm-theme);
|
||||
@include mat.radio-color($sm-theme);
|
||||
@include mat.divider-color($light-theme);
|
||||
@include mat.checkbox-color($sm-theme);
|
||||
@include mat.list-color($light-theme);
|
||||
|
||||
--mdc-typography-body1-letter-spacing: 0;
|
||||
--mdc-typography-button-letter-spacing: 0;
|
||||
|
||||
mat-progress-bar {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 0 1px $white, 0 0 0 3px lighten($purple, 30%);
|
||||
--mdc-linear-progress-active-indicator-color: #{lighten($purple, 10%)};
|
||||
--mdc-linear-progress-track-height: 12px;
|
||||
}
|
||||
|
||||
.mat-progress-bar-fill::after {
|
||||
background-color: lighten($purple, 10%);
|
||||
}
|
||||
|
||||
.mat-checkbox-frame,
|
||||
.mat-radio-outer-circle {
|
||||
border-color: $purple;
|
||||
}
|
||||
|
||||
.mat-radio-button.mat-accent.disabled, .mat-radio-button.mat-accent.disabled.mat-radio-checked {
|
||||
.mat-radio-outer-circle, .mat-radio-inner-circle {
|
||||
border-color: $blue-300;
|
||||
}
|
||||
|
||||
.mat-radio-inner-circle {
|
||||
background-color: $blue-300;
|
||||
}
|
||||
}
|
||||
|
||||
.light-theme .mat-radio-button.mat-radio-disabled .mat-radio-outer-circle,
|
||||
.light-theme .mat-radio-button.mat-radio-disabled .mat-radio-label-content {
|
||||
border-color: $blue-200 !important;
|
||||
color: $blue-200 !important;
|
||||
}
|
||||
|
||||
.light-theme .mat-radio-button.mat-radio-disabled .mat-radio-inner-circle {
|
||||
background-color: transparent !important;
|
||||
.mat-mdc-radio-button, .mat-mdc-radio-button.mat-accent {
|
||||
--mdc-radio-disabled-selected-icon-color: #{$blue-300};
|
||||
--mdc-radio-disabled-unselected-icon-color: #{$blue-300};
|
||||
}
|
||||
|
||||
.mat-drawer {
|
||||
@@ -163,6 +157,18 @@ $sm-theme: mat.define-light-theme((color: (
|
||||
color: $blue-300;
|
||||
}
|
||||
|
||||
.mat-mdc-nav-list {
|
||||
--mdc-list-list-item-label-text-size: 13px;
|
||||
--mdc-list-list-item-label-text-weight: 500;
|
||||
--mdc-list-list-item-label-text-color: #{$blue-400};
|
||||
--mdc-list-list-item-selected-label-text-color: white;
|
||||
|
||||
.mat-mdc-list-item.selected {
|
||||
.mdc-list-item__primary-text {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -249,33 +255,33 @@ hr {
|
||||
}
|
||||
}
|
||||
|
||||
// fix for calendar v15 mix with v14
|
||||
.dark-theme, .light-theme {
|
||||
.mat-datepicker-content {
|
||||
.mat-mdc-icon-button.mat-mdc-button-base {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.mat-calendar-body-selected {
|
||||
background-color: $blue-200;
|
||||
}
|
||||
|
||||
.mat-mdc-button:not(:disabled) {
|
||||
color: $blue-700;
|
||||
}
|
||||
|
||||
.mat-calendar-body-label, .mat-calendar-period-button {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mat-calendar-hidden-label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
//// fix for calendar v15 mix with v14
|
||||
//.dark-theme, .light-theme {
|
||||
// .mat-datepicker-content {
|
||||
// .mat-mdc-icon-button.mat-mdc-button-base {
|
||||
// width: 40px;
|
||||
// height: 40px;
|
||||
// padding: 8px;
|
||||
// }
|
||||
//
|
||||
// .mat-calendar-body-selected {
|
||||
// background-color: $blue-200;
|
||||
// }
|
||||
//
|
||||
// .mat-mdc-button:not(:disabled) {
|
||||
// color: $blue-700;
|
||||
// }
|
||||
//
|
||||
// .mat-calendar-body-label, .mat-calendar-period-button {
|
||||
// font-size: 14px;
|
||||
// font-weight: 500;
|
||||
// }
|
||||
//
|
||||
// .mat-calendar-hidden-label {
|
||||
// display: none;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
mat-expansion-panel {
|
||||
box-shadow: unset;
|
||||
@@ -309,31 +315,28 @@ mat-expansion-panel {
|
||||
background: $faint-gray !important;
|
||||
}
|
||||
|
||||
.mat-slide-toggle-label {
|
||||
display: flex !important;
|
||||
}
|
||||
.mat-mdc-radio-button.sm {
|
||||
--mdc-radio-state-layer-size: 16px;
|
||||
|
||||
// Cancel bootstrap css on material component
|
||||
mat-radio-group mat-radio-button label.mat-radio-label {
|
||||
display: inline-flex;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
mat-radio-button.sm {
|
||||
.mat-radio-container,
|
||||
.mat-radio-outer-circle,
|
||||
.mat-radio-inner-circle {
|
||||
width: 16px;
|
||||
.mdc-radio {
|
||||
height: 16px;
|
||||
}
|
||||
.mat-radio-input {
|
||||
height: auto;
|
||||
|
||||
.mdc-radio__background {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
.mdc-radio__inner-circle {
|
||||
top: -2px;
|
||||
left: -2px;
|
||||
}
|
||||
}
|
||||
.mat-radio-ripple{
|
||||
|
||||
.mat-radio-ripple {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
left: calc(50% - 16px);
|
||||
top: calc(50% - 16px);
|
||||
left: calc(50% - 18px);
|
||||
top: calc(50% - 18px);
|
||||
border-radius: 100%;
|
||||
}
|
||||
}
|
||||
@@ -357,12 +360,10 @@ button {
|
||||
|
||||
.background-neon-green {
|
||||
background-color: $neon-green !important;
|
||||
background: $neon-green !important;
|
||||
}
|
||||
|
||||
.background-neon-yellow {
|
||||
background-color: $neon-yellow !important;
|
||||
background: $neon-yellow !important;
|
||||
}
|
||||
|
||||
.color-neon-green {
|
||||
@@ -388,6 +389,7 @@ button {
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.empty-menu {
|
||||
@@ -510,24 +512,27 @@ body .clean-list {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.mat-tooltip {
|
||||
.mat-mdc-tooltip {
|
||||
&.sm-tooltip {
|
||||
background-color: $purple;
|
||||
box-shadow: 0 -2px 8px 0 rgba(0, 0, 0, 0.2);
|
||||
font-family: 'Heebo', sans-serif;
|
||||
font-size: 11px;
|
||||
line-height: 1.55;
|
||||
letter-spacing: 0.3px;
|
||||
color: #ffffff;
|
||||
word-break: break-word;
|
||||
max-width: 400px;
|
||||
--mdc-plain-tooltip-container-color: #{$purple};
|
||||
|
||||
.mdc-tooltip__surface {
|
||||
max-width: 400px;
|
||||
font-size: 11px;
|
||||
line-height: 1.55;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
&.validation {
|
||||
background-color: #ff001f;
|
||||
.mdc-tooltip__surface {
|
||||
--mdc-plain-tooltip-container-color: #{$strong-red};
|
||||
}
|
||||
}
|
||||
|
||||
&.break-line {
|
||||
white-space: pre-line;
|
||||
.mdc-tooltip__surface {
|
||||
white-space: pre-line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,7 +544,7 @@ body .clean-list {
|
||||
// --------------------------------old------------------------------------------
|
||||
@import "shared/ui-components/styles/index";
|
||||
|
||||
.mat-dialog-container {
|
||||
.mat-mdc-dialog-container {
|
||||
box-shadow: none !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
@@ -561,15 +566,21 @@ html {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mat-menu-panel {
|
||||
max-width: none;
|
||||
.mat-mdc-menu-panel.mat-mdc-menu-panel {
|
||||
max-width: 450px;
|
||||
min-width: 114px;
|
||||
min-height: 32px;
|
||||
|
||||
&.custom-columns {
|
||||
width: 370px;
|
||||
}
|
||||
|
||||
sm-checkbox-three-state-list {
|
||||
min-width: 160px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.ico-chk {
|
||||
width: 24px;
|
||||
display: inline-block;
|
||||
@@ -583,24 +594,55 @@ html {
|
||||
background: $blue-25;
|
||||
color: $blue-400;
|
||||
border-bottom: 1px solid $blue-200;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mat-menu-content {
|
||||
.mat-menu-item {
|
||||
.light-theme {
|
||||
.mat-mdc-menu-content {
|
||||
.mat-mdc-menu-item {
|
||||
.mdc-list-item__primary-text {
|
||||
--mdc-list-list-item-label-text-color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mat-mdc-menu-content {
|
||||
padding: 4px 0 !important;
|
||||
|
||||
.mat-mdc-menu-item {
|
||||
margin: 0 4px;
|
||||
width: calc(100% - 8px);
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
--mdc-typography-body1-line-height: 20px;
|
||||
font-size: 14px;
|
||||
--mdc-typography-body1-font-size: 14px;
|
||||
padding: 0 32px 0 12px;
|
||||
border-radius: 4px;
|
||||
> .al-icon {
|
||||
margin-right: 12px;
|
||||
|
||||
.mdc-list-item__primary-text {
|
||||
--mdc-typography-body1-line-height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0 12px;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 4px -4px;
|
||||
margin: 4px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-mdc-list-item {
|
||||
--mdc-list-list-item-label-text-size: 14px;
|
||||
--mdc-list-list-item-label-text-line-height: 40px;
|
||||
--mdc-list-list-item-one-line-container-height: 40px;
|
||||
}
|
||||
|
||||
// hide arrows for number inputs
|
||||
input[type=number]::-webkit-inner-spin-button,
|
||||
input[type=number]::-webkit-outer-spin-button {
|
||||
@@ -641,6 +683,21 @@ as-split {
|
||||
}
|
||||
}
|
||||
|
||||
.dark-theme .light-theme .as-horizontal > .as-split-gutter {
|
||||
background-color: transparent !important;
|
||||
|
||||
.as-split-gutter-icon {
|
||||
background-color: transparent !important;
|
||||
border-left: solid 1px #DEE1E9;
|
||||
border-right: none;
|
||||
background-image: none !important;
|
||||
|
||||
&:hover {
|
||||
border-left: $purple solid 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.notifier__container {
|
||||
ul {
|
||||
margin: 0;
|
||||
@@ -648,10 +705,10 @@ as-split {
|
||||
}
|
||||
|
||||
$type-colors: (
|
||||
string: #ff8400,
|
||||
number: $neon-yellow,
|
||||
boolean: #b938a4,
|
||||
date: #05668D,
|
||||
string: #ff8400,
|
||||
number: $neon-yellow,
|
||||
boolean: #b938a4,
|
||||
date: #05668D,
|
||||
);
|
||||
|
||||
|
||||
@@ -688,25 +745,17 @@ $type-colors: (
|
||||
}
|
||||
}
|
||||
|
||||
.mat-checkbox label {
|
||||
margin: 0;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.image-viewer-dialog {
|
||||
.mat-dialog-container {
|
||||
.mat-mdc-dialog-container {
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
//material menu
|
||||
body .mat-menu-content:not(:empty) {
|
||||
padding: 4px;
|
||||
|
||||
body .mat-mdc-menu-content:not(:empty) {
|
||||
.search-results {
|
||||
overflow: auto;
|
||||
max-width: 222px;
|
||||
}
|
||||
|
||||
.fixed-options-subheader {
|
||||
@@ -717,29 +766,6 @@ body .mat-menu-content:not(:empty) {
|
||||
}
|
||||
}
|
||||
|
||||
body .mat-menu-panel .mat-form-field.tags-menu-input {
|
||||
.mat-form-field-wrapper {
|
||||
padding: 0;
|
||||
|
||||
.mat-form-field-flex {
|
||||
padding: 0 14px;
|
||||
align-items: center;
|
||||
|
||||
.mat-form-field-infix, .mat-form-field-suffix {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
border: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-form-field-underline {
|
||||
bottom: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hyper-parameters-tooltip {
|
||||
white-space: pre-line;
|
||||
text-align: left !important;
|
||||
@@ -823,7 +849,7 @@ button.btn.button-outline-dark {
|
||||
.cdk-drag-preview.form-group-drag {
|
||||
padding: 8px 16px 32px 16px;
|
||||
border-radius: 4px;
|
||||
border: solid 1px #d4d6e0;
|
||||
border: solid 1px $cloudy-blue;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@@ -885,3 +911,22 @@ button.btn.button-outline-dark {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.cml-dialog {
|
||||
border-radius: 4px;
|
||||
|
||||
.mdc-dialog .mdc-dialog__content {
|
||||
padding: 0 32px;
|
||||
max-height: 90vh;
|
||||
}
|
||||
|
||||
.mdc-dialog__actions {
|
||||
padding: 24px 0;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.select-panel-width {
|
||||
min-width: fit-content;
|
||||
max-width: 50vw !important;
|
||||
}
|
||||
|
||||
@@ -108,3 +108,5 @@ export const MESSAGES_SEVERITY = {
|
||||
INFO: 'info' as MessageSeverityEnum,
|
||||
WARN: 'warn' as MessageSeverityEnum
|
||||
};
|
||||
|
||||
export const rootProjectsPageSize = 50;
|
||||
|
||||
@@ -4,7 +4,7 @@ import {ProjectsUpdateRequest} from '~/business-logic/model/projects/projectsUpd
|
||||
import {ModelsPublishManyResponse} from '~/business-logic/model/models/modelsPublishManyResponse';
|
||||
import {ModelsArchiveManyResponse} from '~/business-logic/model/models/modelsArchiveManyResponse';
|
||||
import {ModelsDeleteManyResponse} from '~/business-logic/model/models/modelsDeleteManyResponse';
|
||||
import {archivedSelectedModels} from '@common/models/actions/models-menu.actions';
|
||||
import {archiveSelectedModels} from '@common/models/actions/models-menu.actions';
|
||||
import {TasksResetManyResponse} from '~/business-logic/model/tasks/tasksResetManyResponse';
|
||||
import {TasksEnqueueManyResponse} from '~/business-logic/model/tasks/tasksEnqueueManyResponse';
|
||||
import {TasksArchiveManyResponse} from '~/business-logic/model/tasks/tasksArchiveManyResponse';
|
||||
@@ -14,6 +14,8 @@ import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
import {MetricColumn} from '@common/shared/utils/tableParamEncode';
|
||||
import {ProjectStatsGraphData} from '@common/core/reducers/projects.reducer';
|
||||
import {User} from '~/business-logic/model/users/user';
|
||||
import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle';
|
||||
import {TaskStatusEnum} from '~/business-logic/model/tasks/taskStatusEnum';
|
||||
|
||||
export const PROJECTS_PREFIX = '[ROOT_PROJECTS] ';
|
||||
|
||||
@@ -31,11 +33,6 @@ export const updateProject = createAction(
|
||||
props<{ id: string; changes: Partial<ProjectsUpdateRequest> }>()
|
||||
);
|
||||
|
||||
export const setAllProjects = createAction(
|
||||
PROJECTS_PREFIX + 'SET_PROJECTS',
|
||||
props<{ projects: Project[]; updating?: boolean }>()
|
||||
);
|
||||
|
||||
export const resetProjects = createAction(PROJECTS_PREFIX + 'RESET_PROJECTS');
|
||||
export const refetchProjects = createAction(PROJECTS_PREFIX + 'REFETCH_PROJECTS');
|
||||
|
||||
@@ -56,15 +53,16 @@ export const setSelectedProjectId = createAction(
|
||||
PROJECTS_PREFIX + 'SET_SELECTED_PROJECT_ID',
|
||||
props<{ projectId: string; example?: boolean }>()
|
||||
);
|
||||
export const deletedProjectFromRoot = createAction(
|
||||
PROJECTS_PREFIX + 'DELETE_PROJECT_FROM_ROOT',
|
||||
props<{ project: Project }>()
|
||||
);
|
||||
export const setSelectedProject = createAction(
|
||||
PROJECTS_PREFIX + 'SET_SELECTED_PROJECT',
|
||||
props<{ project: Project }>()
|
||||
);
|
||||
|
||||
export const setProjectAncestors = createAction(
|
||||
PROJECTS_PREFIX + 'SET_PROJECT_ANCESTORS',
|
||||
props<{ projects: Project[] }>()
|
||||
);
|
||||
|
||||
export const setSelectedProjectStats = createAction(
|
||||
PROJECTS_PREFIX + '[set selected project statistics]',
|
||||
props<{ project: Project }>()
|
||||
@@ -99,7 +97,7 @@ export const getCompanyTags = createAction(
|
||||
|
||||
export const getProjectsTags = createAction(
|
||||
PROJECTS_PREFIX + '[get projects tags]',
|
||||
props<{entity: string}>()
|
||||
props<{ entity: string }>()
|
||||
);
|
||||
|
||||
export const setTagsFilterByProject = createAction(
|
||||
@@ -119,7 +117,7 @@ export const setCompanyTags = createAction(
|
||||
|
||||
export const setMainPageTagsFilter = createAction(
|
||||
PROJECTS_PREFIX + '[set main page tags filters]',
|
||||
props<{ tags: string[] }>()
|
||||
props<{ tags: string[]; feature: string }>()
|
||||
);
|
||||
|
||||
export const setMainPageTagsFilterMatchMode = createAction(
|
||||
@@ -134,7 +132,7 @@ export const addProjectTags = createAction(
|
||||
|
||||
export const openTagColorsMenu = createAction(
|
||||
PROJECTS_PREFIX + '[open tag colors]',
|
||||
props<{tags: string[]}>()
|
||||
props<{ tags: string[] }>()
|
||||
);
|
||||
|
||||
export const setTagColors = createAction(
|
||||
@@ -144,7 +142,12 @@ export const setTagColors = createAction(
|
||||
|
||||
export const openMoreInfoPopup = createAction(
|
||||
PROJECTS_PREFIX + '[open more info popup]',
|
||||
props<{ parentAction: ReturnType<typeof archivedSelectedModels>; operationName: string; entityType: EntityTypeEnum; res: ModelsPublishManyResponse | ModelsArchiveManyResponse | ModelsDeleteManyResponse | TasksResetManyResponse | TasksEnqueueManyResponse | TasksArchiveManyResponse | TasksPublishManyResponse | TasksStopManyResponse }>()
|
||||
props<{
|
||||
parentAction: ReturnType<typeof archiveSelectedModels>;
|
||||
operationName: string;
|
||||
entityType: EntityTypeEnum;
|
||||
res: ModelsPublishManyResponse | ModelsArchiveManyResponse | ModelsDeleteManyResponse | TasksResetManyResponse | TasksEnqueueManyResponse | TasksArchiveManyResponse | TasksPublishManyResponse | TasksStopManyResponse
|
||||
}>()
|
||||
);
|
||||
|
||||
export const setMetricVariant = createAction(
|
||||
@@ -153,6 +156,11 @@ export const setMetricVariant = createAction(
|
||||
);
|
||||
export const fetchGraphData = createAction(PROJECTS_PREFIX + '[fetch stats for project graph]');
|
||||
|
||||
export const toggleState = createAction(
|
||||
PROJECTS_PREFIX + '[toggle state]',
|
||||
props<{ state: TaskStatusEnum }>()
|
||||
);
|
||||
|
||||
export const setGraphData = createAction(
|
||||
PROJECTS_PREFIX + '[set project stats]',
|
||||
props<{ stats: ProjectStatsGraphData[] }>()
|
||||
@@ -193,4 +201,16 @@ export const setDefaultNestedModeForFeature = createAction(
|
||||
props<{ feature: string; isNested: boolean }>()
|
||||
);
|
||||
|
||||
export const resetTablesFilterProjectsOptions = createAction(
|
||||
PROJECTS_PREFIX + ' [reset tables filter projects options]'
|
||||
);
|
||||
|
||||
export const getTablesFilterProjectsOptions = createAction(
|
||||
PROJECTS_PREFIX + ' [get tables filter projects options]',
|
||||
props<{ searchString: string; loadMore: boolean }>()
|
||||
);
|
||||
|
||||
export const setTablesFilterProjectsOptions = createAction(
|
||||
PROJECTS_PREFIX + ' [set tables filter projects options]',
|
||||
props<{ projects: Partial<ProjectsGetAllResponseSingle>[]; scrollId: string; loadMore?: boolean }>()
|
||||
);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import {ISmAction} from '../models/actions';
|
||||
import {NAVIGATION_PREFIX, NAVIGATION_ACTIONS} from '~/app.constants';
|
||||
import {NAVIGATION_ACTIONS, NAVIGATION_PREFIX} from '~/app.constants';
|
||||
import {Action, createAction, props} from '@ngrx/store';
|
||||
import {Params} from '@angular/router';
|
||||
import {FilterMetadata} from 'primeng/api/filtermetadata';
|
||||
import {SortMeta} from 'primeng/api';
|
||||
import {CrumbTypeEnum, IBreadcrumbsLink} from "@common/layout/breadcrumbs/breadcrumbs.component";
|
||||
|
||||
export const BREADCRUMBS_PREFIX = 'BREADCRUMBS_';
|
||||
|
||||
|
||||
// TODO: remove this action...
|
||||
@@ -14,23 +17,21 @@ export class NavigateTo implements ISmAction {
|
||||
url: string;
|
||||
params?: Params;
|
||||
unGuard?: boolean;
|
||||
}) {}
|
||||
}) {
|
||||
}
|
||||
}
|
||||
|
||||
export class NavigationEnd implements Action {
|
||||
readonly type = NAVIGATION_ACTIONS.NAVIGATION_END;
|
||||
}
|
||||
|
||||
export class SetRouterSegments implements Action {
|
||||
readonly type = NAVIGATION_ACTIONS.SET_ROUTER_SEGMENT;
|
||||
|
||||
constructor(public payload: {
|
||||
export const setRouterSegments = createAction(
|
||||
NAVIGATION_ACTIONS.SET_ROUTER_SEGMENT, props<{
|
||||
url: string;
|
||||
params: Params;
|
||||
queryParams: Params;
|
||||
config: string[];
|
||||
}) {}
|
||||
}
|
||||
}>());
|
||||
|
||||
export const setURLParams = createAction(
|
||||
NAVIGATION_PREFIX + 'SET_URL_PARAMS',
|
||||
@@ -44,3 +45,14 @@ export const setURLParams = createAction(
|
||||
version?: string;
|
||||
}>()
|
||||
);
|
||||
|
||||
export const setBreadcrumbs = createAction(
|
||||
BREADCRUMBS_PREFIX + 'SET_BREADCRUMBS',
|
||||
props<{ breadcrumbs: IBreadcrumbsLink[][]}>()
|
||||
);
|
||||
|
||||
export const setTypeBreadcrumbs = createAction(
|
||||
BREADCRUMBS_PREFIX + 'SET_TYPE_BREADCRUMBS',
|
||||
props<{ breadcrumb: IBreadcrumbsLink; type?: CrumbTypeEnum }>()
|
||||
);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import {AdminService} from '~/shared/services/admin.service';
|
||||
import {selectDontShowAgainForBucketEndpoint, selectS3BucketCredentialsBucketCredentials, selectSignedUrl} from '@common/core/reducers/common-auth-reducer';
|
||||
import {EMPTY, of} from 'rxjs';
|
||||
import {S3AccessResolverComponent} from '@common/layout/s3-access-resolver/s3-access-resolver.component';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {setCredentialLabel} from '../actions/common-auth.actions';
|
||||
import {SignResponse} from '@common/settings/admin/base-admin-utils';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {bufferTime, filter, map, mergeMap, switchMap, take} from 'rxjs/operators
|
||||
import {ApiTasksService} from '~/business-logic/api-services/tasks.service';
|
||||
import {EMPTY, Observable, of} from 'rxjs';
|
||||
import {ApiModelsService} from '~/business-logic/api-services/models.service';
|
||||
import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog, MatDialogRef} from '@angular/material/dialog';
|
||||
import {AlertDialogComponent} from '../../shared/ui-components/overlay/alert-dialog/alert-dialog.component';
|
||||
import {NotifierService} from '../../angular-notifier';
|
||||
import {requestFailed} from '@common/core/actions/http.actions';
|
||||
|
||||
@@ -3,26 +3,23 @@ import {Store} from '@ngrx/store';
|
||||
import {Actions, createEffect, ofType} from '@ngrx/effects';
|
||||
import {ApiProjectsService} from '~/business-logic/api-services/projects.service';
|
||||
import * as actions from '../actions/projects.actions';
|
||||
import {setShowHidden} from '../actions/projects.actions';
|
||||
import {catchError, expand, filter, map, mergeMap, reduce, switchMap, withLatestFrom} from 'rxjs/operators';
|
||||
import {setProjectAncestors, setShowHidden, setTablesFilterProjectsOptions} from '../actions/projects.actions';
|
||||
import {catchError, debounceTime, filter, map, mergeMap, switchMap, withLatestFrom} from 'rxjs/operators';
|
||||
import {requestFailed} from '../actions/http.actions';
|
||||
import {activeLoader, deactivateLoader, setServerError} from '../actions/layout.actions';
|
||||
import {setSelectedModels} from '../../models/actions/models-view.actions';
|
||||
import {TagColorMenuComponent} from '../../shared/ui-components/tags/tag-color-menu/tag-color-menu.component';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {ApiOrganizationService} from '~/business-logic/api-services/organization.service';
|
||||
import {OrganizationGetTagsResponse} from '~/business-logic/model/organization/organizationGetTagsResponse';
|
||||
import {selectRouterParams} from '../reducers/router-reducer';
|
||||
import {EMPTY, forkJoin, from, of} from 'rxjs';
|
||||
import {EMPTY, forkJoin, of} from 'rxjs';
|
||||
import {ProjectsGetTaskTagsResponse} from '~/business-logic/model/projects/projectsGetTaskTagsResponse';
|
||||
import {ProjectsGetModelTagsResponse} from '~/business-logic/model/projects/projectsGetModelTagsResponse';
|
||||
import {
|
||||
selectAllProjectsUsers,
|
||||
selectLastUpdate,
|
||||
selectRootProjects,
|
||||
selectAllProjectsUsers, selectProjectsOptionsScrollId,
|
||||
selectSelectedMetricVariantForCurrProject,
|
||||
selectSelectedProjectId,
|
||||
selectShowHidden
|
||||
selectSelectedProjectId, selectShowHidden,
|
||||
} from '../reducers/projects.reducer';
|
||||
import {
|
||||
OperationErrorDialogComponent
|
||||
@@ -33,30 +30,25 @@ import {ITask} from '~/business-logic/model/al-task';
|
||||
import {TasksGetAllExRequest} from '~/business-logic/model/tasks/tasksGetAllExRequest';
|
||||
import {setSelectedExperiments} from '../../experiments/actions/common-experiments-view.actions';
|
||||
import {setActiveWorkspace} from '@common/core/actions/users.actions';
|
||||
import {ProjectsGetAllExResponse} from '~/business-logic/model/projects/projectsGetAllExResponse';
|
||||
import {Project} from '~/business-logic/model/projects/project';
|
||||
import {ApiUsersService} from '~/business-logic/api-services/users.service';
|
||||
import {get} from 'lodash-es';
|
||||
import {escapeRegExp, get} from 'lodash-es';
|
||||
import {escapeRegex} from '@common/shared/utils/escape-regex';
|
||||
import {ProjectsGetAllExRequest} from '~/business-logic/model/projects/projectsGetAllExRequest';
|
||||
import localForage from 'localforage';
|
||||
import {TIME_IN_MILLI} from '@common/shared/utils/time-util';
|
||||
import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle';
|
||||
import {rootProjectsPageSize} from '@common/constants';
|
||||
|
||||
export const ALL_PROJECTS_OBJECT = {id: '*', name: 'All Experiments'};
|
||||
interface RootCache {
|
||||
time: string;
|
||||
hidden: boolean;
|
||||
projects: Project[];
|
||||
}
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class ProjectsEffects {
|
||||
private pageSize: number = 1000;
|
||||
|
||||
constructor(
|
||||
private actions$: Actions, private projectsApi: ApiProjectsService, private orgApi: ApiOrganizationService,
|
||||
private store: Store<any>, private dialog: MatDialog, private tasksApi: ApiTasksService,
|
||||
private usersApi: ApiUsersService,
|
||||
) {}
|
||||
) {
|
||||
}
|
||||
|
||||
activeLoader = createEffect(() => this.actions$.pipe(
|
||||
ofType(actions.setSelectedProjectId),
|
||||
@@ -64,83 +56,92 @@ export class ProjectsEffects {
|
||||
map(action => activeLoader(action.type))
|
||||
));
|
||||
|
||||
getProjects$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(actions.getAllSystemProjects),
|
||||
withLatestFrom(
|
||||
this.store.select(selectShowHidden),
|
||||
this.store.select(selectLastUpdate),
|
||||
),
|
||||
switchMap(([, showHidden, lastUpdate]) => !lastUpdate ? from(localForage.getItem<RootCache>('rootProjects'))
|
||||
.pipe(
|
||||
map((cache: RootCache) =>
|
||||
[showHidden, lastUpdate,
|
||||
(new Date(cache?.time)).getTime() > (new Date()).getTime() - TIME_IN_MILLI.ONE_HOUR &&
|
||||
cache.projects?.length > 0 &&
|
||||
showHidden === cache.hidden ? cache : null
|
||||
])
|
||||
) : of([showHidden, lastUpdate, null])
|
||||
),
|
||||
switchMap(([showHidden, lastUpdate, cache]: [boolean, string, RootCache]) => {
|
||||
if (cache) {
|
||||
return [
|
||||
actions.setAllProjects({projects: cache.projects, updating: false}),
|
||||
actions.setLastUpdate({lastUpdate: cache.time}),
|
||||
actions.getAllSystemProjects()
|
||||
];
|
||||
}
|
||||
const cacheTime = (new Date()).toISOString();
|
||||
const query = {
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
scroll_id: null,
|
||||
size: this.pageSize,
|
||||
order_by: ['last_update'],
|
||||
...(lastUpdate && {last_update: [lastUpdate, null]}),
|
||||
only_fields: ['name', 'company', 'last_update'],
|
||||
search_hidden: showHidden
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
} as ProjectsGetAllExRequest;
|
||||
return this.projectsApi.projectsGetAllEx(query)
|
||||
.pipe(
|
||||
expand((res: ProjectsGetAllExResponse) => res.scroll_id && res.projects.length >= this.pageSize ?
|
||||
this.projectsApi.projectsGetAllEx({
|
||||
...query,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
scroll_id: res.scroll_id,
|
||||
}) :
|
||||
EMPTY
|
||||
),
|
||||
reduce((acc, res: ProjectsGetAllExResponse) => acc.concat(res.projects), []),
|
||||
withLatestFrom(this.store.select(selectRootProjects)),
|
||||
mergeMap(([projects, rootProjects]) => [
|
||||
actions.setLastUpdate({lastUpdate: cacheTime}),
|
||||
actions.setAllProjects({
|
||||
projects: projects as Project[],
|
||||
updating: rootProjects?.length > 0
|
||||
}),
|
||||
])
|
||||
);
|
||||
}),
|
||||
));
|
||||
|
||||
updateProjectsCache$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(actions.setAllProjects, actions.deletedProjectFromRoot, actions.updateProjectCompleted),
|
||||
withLatestFrom(
|
||||
this.store.select(selectRootProjects),
|
||||
this.store.select(selectLastUpdate),
|
||||
this.store.select(selectShowHidden),
|
||||
),
|
||||
map(([, projects, lastUpdate, hidden]) => localForage.setItem<RootCache>('rootProjects', {
|
||||
time: lastUpdate,
|
||||
hidden,
|
||||
projects
|
||||
}))
|
||||
), {dispatch: false});
|
||||
getTablesFilterProjectsOptions$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(actions.getTablesFilterProjectsOptions),
|
||||
debounceTime(300),
|
||||
withLatestFrom(
|
||||
this.store.select(selectShowHidden),
|
||||
this.store.select(selectProjectsOptionsScrollId),
|
||||
),
|
||||
switchMap(([action, showHidden, scrollId]) => forkJoin([
|
||||
this.projectsApi.projectsGetAllEx({
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
page_size: rootProjectsPageSize,
|
||||
size: rootProjectsPageSize,
|
||||
order_by: ['name'],
|
||||
only_fields: ['name', 'company'],
|
||||
search_hidden: showHidden,
|
||||
_any_: {pattern: escapeRegex(action.searchString), fields: ['name']},
|
||||
scroll_id: !!action.loadMore && scrollId
|
||||
} as ProjectsGetAllExRequest),
|
||||
!action.loadMore && action.searchString?.length > 2 ?
|
||||
this.projectsApi.projectsGetAllEx({
|
||||
page_size: 1,
|
||||
only_fields: ['name', 'company'],
|
||||
search_hidden: showHidden,
|
||||
_any_: {pattern: `^${escapeRegex(action.searchString)}$`, fields: ['name', 'id']},
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
} as ProjectsGetAllExRequest).pipe(map(res => res.projects)) :
|
||||
of([])
|
||||
])
|
||||
.pipe(map(([allProjects, specificProjects]) => ({
|
||||
projects: [
|
||||
...(specificProjects.length > 0 && allProjects.projects.some(project => project.id === specificProjects[0]?.id) ? [] : specificProjects),
|
||||
...allProjects.projects
|
||||
],
|
||||
scrollId: allProjects.scroll_id,
|
||||
loadMore: action.loadMore
|
||||
})
|
||||
))
|
||||
),
|
||||
mergeMap((projects: { projects: ProjectsGetAllResponseSingle[]; scrollId: string }) => [setTablesFilterProjectsOptions({...projects})])
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
resetProjects$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(actions.resetSelectedProject),
|
||||
mergeMap(() => [actions.resetProjectSelection()])
|
||||
));
|
||||
|
||||
resetAncestorProjects$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(actions.setSelectedProjectId),
|
||||
withLatestFrom(this.store.select(selectSelectedProjectId)),
|
||||
filter(([action, prevProjectId]) => action.projectId !== prevProjectId),
|
||||
mergeMap(() => [setProjectAncestors({projects: null})])
|
||||
));
|
||||
|
||||
getAncestorProjects$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(actions.setSelectedProject),
|
||||
filter(action => !!action.project),
|
||||
switchMap(action => {
|
||||
const parts = action.project.name?.split('/');
|
||||
if (!action.project.id || action.project.id === ALL_PROJECTS_OBJECT.id || parts.length === 1) {
|
||||
return of([{projects: []}, []]);
|
||||
}
|
||||
parts.pop();
|
||||
const escapedParts = parts.map(escapeRegExp);
|
||||
const [simpleProjectNames, projectsNames] = parts.reduce(
|
||||
([simpleNames, names], part, index) => [
|
||||
[...simpleNames, parts.slice(0, index + 1).join('/')],
|
||||
[...names, escapedParts.slice(0, index + 1).join('\\/')],
|
||||
],
|
||||
[[], []]
|
||||
);
|
||||
return this.projectsApi.projectsGetAllEx({
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
_any_: {fields: ['name'], pattern: projectsNames.map(name => `^${name}$`).join('|')},
|
||||
search_hidden: true
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
}).pipe(map(res => [res, simpleProjectNames]));
|
||||
}),
|
||||
switchMap(([res, projectsNames]) => [actions.setProjectAncestors({
|
||||
projects: res?.projects?.filter(project => projectsNames.includes(project.name))
|
||||
.sort((projectA, projectB) => (projectA.name?.split('/').length >= projectB.name?.split('/').length) ? 1 : -1)
|
||||
})]
|
||||
)));
|
||||
|
||||
resetProjectSelections$ = createEffect(() => this.actions$.pipe(
|
||||
ofType(actions.resetProjectSelection),
|
||||
mergeMap(() => [setSelectedExperiments({experiments: []}), setSelectedModels({models: []})])
|
||||
@@ -176,13 +177,16 @@ export class ProjectsEffects {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
switchMap(() => this.orgApi.organizationGetTags({include_system: true})
|
||||
.pipe(
|
||||
map((res: OrganizationGetTagsResponse) => actions.setCompanyTags({tags: res.tags, systemTags: res.system_tags})),
|
||||
map((res: OrganizationGetTagsResponse) => actions.setCompanyTags({
|
||||
tags: res.tags,
|
||||
systemTags: res.system_tags
|
||||
})),
|
||||
catchError(error => [requestFailed(error)])
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
getProjectsTags = createEffect(() => this.actions$.pipe(
|
||||
getProjectsTags = createEffect(() => this.actions$.pipe(
|
||||
ofType(actions.getProjectsTags),
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
switchMap(action => this.projectsApi.projectsGetProjectTags({filter: {system_tags: [action.entity]}})
|
||||
@@ -197,7 +201,7 @@ export class ProjectsEffects {
|
||||
ofType(actions.getTags),
|
||||
withLatestFrom(this.store.select(selectRouterParams).pipe(
|
||||
map(params => (params === null || params?.projectId === '*') ? [] : [params.projectId]))),
|
||||
mergeMap(([action, projects]) => {
|
||||
mergeMap(([action, projects]) => {
|
||||
const ids = action?.projectId ? [action.projectId] : projects;
|
||||
if (ids.length === 0 || !ids[0]) {
|
||||
return EMPTY;
|
||||
@@ -237,7 +241,7 @@ export class ProjectsEffects {
|
||||
ofType(actions.fetchGraphData),
|
||||
withLatestFrom(
|
||||
this.store.select(selectSelectedProjectId),
|
||||
this.store.select(selectSelectedMetricVariantForCurrProject)
|
||||
this.store.select(selectSelectedMetricVariantForCurrProject),
|
||||
),
|
||||
filter(([, , variant]) => !!variant),
|
||||
switchMap(([, projectId, variant]) => {
|
||||
@@ -278,7 +282,6 @@ export class ProjectsEffects {
|
||||
|
||||
resetRootProjects = createEffect(() => this.actions$.pipe(
|
||||
ofType(setActiveWorkspace, actions.refetchProjects, setShowHidden),
|
||||
switchMap(() => from(localForage.removeItem('rootProjects'))),
|
||||
mergeMap(() => [
|
||||
actions.resetProjects(),
|
||||
actions.getAllSystemProjects()
|
||||
|
||||
@@ -5,7 +5,7 @@ import {uniq} from 'lodash-es';
|
||||
import {map, tap} from 'rxjs/operators';
|
||||
import {NAVIGATION_ACTIONS} from '~/app.constants';
|
||||
import {encodeFilters, encodeOrder} from '../../shared/utils/tableParamEncode';
|
||||
import {NavigateTo, NavigationEnd, SetRouterSegments, setURLParams} from '../actions/router.actions';
|
||||
import {NavigateTo, NavigationEnd, setRouterSegments, setURLParams} from '../actions/router.actions';
|
||||
|
||||
|
||||
@Injectable()
|
||||
@@ -29,7 +29,7 @@ export class RouterEffects {
|
||||
|
||||
routerNavigationEnd = createEffect(() => this.actions$.pipe(
|
||||
ofType<NavigationEnd>(NAVIGATION_ACTIONS.NAVIGATION_END),
|
||||
map(() => new SetRouterSegments({url: this.getRouterUrl(), params: this.getRouterParams(), config: this.getRouterConfig(), queryParams: this.route.snapshot.queryParams}))
|
||||
map(() => setRouterSegments({url: this.getRouterUrl(), params: this.getRouterParams(), config: this.getRouterConfig(), queryParams: this.route.snapshot.queryParams}))
|
||||
));
|
||||
|
||||
setTableParams = createEffect(() => this.actions$.pipe(
|
||||
|
||||
@@ -5,9 +5,9 @@ import {Project} from '~/business-logic/model/projects/project';
|
||||
import {getSystemTags} from '~/features/experiments/shared/experiments.utils';
|
||||
import {ITableExperiment} from '../../experiments/shared/common-experiment-model.model';
|
||||
import {MetricColumn} from '@common/shared/utils/tableParamEncode';
|
||||
import {sortByField} from '@common/tasks/tasks.utils';
|
||||
import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle';
|
||||
import {User} from '~/business-logic/model/users/user';
|
||||
import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle';
|
||||
import {selectRouterConfig} from "@common/core/reducers/router-reducer";
|
||||
|
||||
|
||||
export interface ProjectStatsGraphData {
|
||||
@@ -23,6 +23,7 @@ export interface ProjectStatsGraphData {
|
||||
export interface RootProjects {
|
||||
projects: Project[];
|
||||
selectedProject: Project;
|
||||
projectAncestors: Project[];
|
||||
archive: boolean;
|
||||
deep: boolean;
|
||||
projectTags: string[];
|
||||
@@ -32,22 +33,26 @@ export interface RootProjects {
|
||||
tagsFilterByProject: boolean;
|
||||
graphVariant: { [project: string]: MetricColumn };
|
||||
graphData: ProjectStatsGraphData[];
|
||||
hiddenStates: { [state: string]: boolean };
|
||||
lastUpdate: string;
|
||||
users: User[];
|
||||
allUsers: User[];
|
||||
extraUsers: User[];
|
||||
showHidden: boolean;
|
||||
hideExamples: boolean;
|
||||
mainPageTagsFilter: string[];
|
||||
mainPageTagsFilter: { [Feature: string]: string[] };
|
||||
mainPageTagsFilterMatchMode: string;
|
||||
defaultNestedModeForFeature: { [feature: string]: boolean };
|
||||
tablesFilterProjectsOptions: Partial<ProjectsGetAllResponseSingle>[];
|
||||
projectsOptionsScrollId: string;
|
||||
}
|
||||
|
||||
const initRootProjects: RootProjects = {
|
||||
mainPageTagsFilter: [],
|
||||
mainPageTagsFilter: {},
|
||||
mainPageTagsFilterMatchMode: 'AND',
|
||||
projects: null,
|
||||
selectedProject: null,
|
||||
projectAncestors: null,
|
||||
archive: false,
|
||||
deep: false,
|
||||
projectTags: [],
|
||||
@@ -57,25 +62,30 @@ const initRootProjects: RootProjects = {
|
||||
tagsFilterByProject: true,
|
||||
graphVariant: {},
|
||||
graphData: null,
|
||||
hiddenStates: {},
|
||||
lastUpdate: null,
|
||||
users: [],
|
||||
allUsers: [],
|
||||
extraUsers: [],
|
||||
showHidden: false,
|
||||
hideExamples: false,
|
||||
defaultNestedModeForFeature: {}
|
||||
defaultNestedModeForFeature: {},
|
||||
tablesFilterProjectsOptions: null,
|
||||
projectsOptionsScrollId: null
|
||||
};
|
||||
|
||||
export const projects = state => state.rootProjects as RootProjects;
|
||||
export const selectRootProjects = createSelector(projects, (state): Project[] => state.projects);
|
||||
export const selectSelectedProject = createSelector(projects, (state): ProjectsGetAllResponseSingle => state.selectedProject);
|
||||
export const selectSelectedProject = createSelector(projects, state => state.selectedProject);
|
||||
export const selectProjectAncestors = createSelector(projects, state => state.projectAncestors);
|
||||
export const selectSelectedProjectDescription = createSelector(projects, state => state.selectedProject?.description);
|
||||
export const selectSelectedProjectId = createSelector(selectSelectedProject, (selectedProject): string => selectedProject ? selectedProject.id : '');
|
||||
export const selectIsArchivedMode = createSelector(projects, state => state.archive);
|
||||
export const selectIsDeepMode = createSelector(projects, state => state.deep);
|
||||
export const selectTagsFilterByProject = createSelector(projects, state => state.tagsFilterByProject);
|
||||
export const selectTagsFilterByProject = createSelector(projects, selectSelectedProjectId,
|
||||
(state, projectId) => projectId !== '*' && state.tagsFilterByProject);
|
||||
export const selectProjectTags = createSelector(projects, state => state.projectTags);
|
||||
export const selectMainPageTagsFilter = createSelector(projects, state => state.mainPageTagsFilter);
|
||||
export const selectMainPageTagsFilter = createSelector(projects, selectRouterConfig, (state, config) => config?.[0] ? state.mainPageTagsFilter[config?.[0]] : []);
|
||||
export const selectMainPageTagsFilterMatchMode = createSelector(projects, state => state.mainPageTagsFilterMatchMode);
|
||||
export const selectCompanyTags = createSelector(projects, state => state.companyTags);
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
@@ -91,32 +101,17 @@ export const selectSelectedMetricVariantForCurrProject = createSelector(
|
||||
selectSelectedProjectsMetricVariant, selectSelectedProjectId,
|
||||
(projectsVariant, projectId) => projectsVariant[projectId]);
|
||||
export const selectGraphData = createSelector(projects, state => state.graphData);
|
||||
export const selectGraphHiddenStates = createSelector(projects, state => state.hiddenStates);
|
||||
export const selectProjectUsers = createSelector(projects, state => state.extraUsers.length ?
|
||||
Array.from(new Set([...state.users, ...state.extraUsers])) :
|
||||
state.users
|
||||
);
|
||||
export const selectAllProjectsUsers = createSelector(projects, state => state.allUsers);
|
||||
export const selectTablesFilterProjectsOptions = createSelector(projects, state => state.tablesFilterProjectsOptions);
|
||||
|
||||
export const projectsReducer = createReducer(
|
||||
initRootProjects,
|
||||
on(projectsActions.resetProjects, state => ({...state, projects: [], lastUpdate: null})),
|
||||
on(projectsActions.setAllProjects, (state, action) => {
|
||||
let newProjects = state.projects;
|
||||
if (action.updating) {
|
||||
action.projects.forEach(proj => {
|
||||
const index = state.projects.findIndex(stateProject => stateProject.id === proj.id);
|
||||
if (index > -1) {
|
||||
newProjects = [...newProjects.slice(0, index), proj, ...newProjects.slice(index + 1)];
|
||||
} else {
|
||||
newProjects = [...newProjects, proj];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
newProjects = [...(newProjects || []), ...action.projects];
|
||||
}
|
||||
return {...state, projects: sortByField(newProjects, 'name')};
|
||||
|
||||
}),
|
||||
on(projectsActions.setSelectedProjectId, (state, action) => {
|
||||
const projectId = action.projectId;
|
||||
return {
|
||||
@@ -130,6 +125,7 @@ export const projectsReducer = createReducer(
|
||||
selectedProject: action.project,
|
||||
extraUsers: []
|
||||
})),
|
||||
on(projectsActions.setProjectAncestors, (state, action) => ({...state, projectAncestors: action.projects})),
|
||||
on(projectsActions.setSelectedProjectStats, (state, action) => ({
|
||||
...state,
|
||||
selectedProject: {
|
||||
@@ -137,10 +133,6 @@ export const projectsReducer = createReducer(
|
||||
stats: action.project?.stats
|
||||
}
|
||||
})),
|
||||
on(projectsActions.deletedProjectFromRoot, (state, action) => {
|
||||
const projectIdsToDelete = [action.project.id].concat(action.project.sub_projects.map(project => project.id));
|
||||
return {...state, projects: state.projects.filter(project => !projectIdsToDelete.includes(project.id))};
|
||||
}),
|
||||
on(projectsActions.resetSelectedProject, state => ({
|
||||
...state,
|
||||
selectedProject: initRootProjects.selectedProject,
|
||||
@@ -168,7 +160,9 @@ export const projectsReducer = createReducer(
|
||||
...state,
|
||||
projectTags: Array.from(new Set(state.projectTags.concat(action.tags))).sort()
|
||||
})),
|
||||
on(projectsActions.setMainPageTagsFilter, (state, action) => ({...state, mainPageTagsFilter: action.tags})),
|
||||
on(projectsActions.setMainPageTagsFilter, (state, action) => ({
|
||||
...state,
|
||||
mainPageTagsFilter: {...state.mainPageTagsFilter, [action.feature] : action.tags }})),
|
||||
on(projectsActions.setMainPageTagsFilterMatchMode, (state, action) => ({
|
||||
...state,
|
||||
mainPageTagsFilterMatchMode: action.matchMode
|
||||
@@ -181,13 +175,26 @@ export const projectsReducer = createReducer(
|
||||
...state, graphVariant: {...state.graphVariant, [action.projectId]: action.col}
|
||||
})),
|
||||
on(projectsActions.setGraphData, (state, action) => ({...state, graphData: action.stats})),
|
||||
on(projectsActions.toggleState, (state, action) => ({
|
||||
...state,
|
||||
hiddenStates: {...state.hiddenStates, [action.state]: !state.hiddenStates?.[action.state]}
|
||||
})),
|
||||
on(projectsActions.setLastUpdate, (state, action) => ({...state, lastUpdate: action.lastUpdate})),
|
||||
on(projectsActions.setProjectUsers, (state, action) => ({...state, users: action.users, extraUsers: []})),
|
||||
on(projectsActions.setAllProjectUsers, (state, action) => ({...state, allUsers: action.users})),
|
||||
on(projectsActions.setProjectExtraUsers, (state, action) => ({...state, extraUsers: action.users})),
|
||||
on(projectsActions.setShowHidden, (state, action) => ({...state, showHidden: action.show})),
|
||||
on(projectsActions.setHideExamples, (state, action) => ({...state, hideExamples: action.hide})),
|
||||
on(projectsActions.setDefaultNestedModeForFeature, (state, action) => ({...state, defaultNestedModeForFeature: {...state.defaultNestedModeForFeature, [action.feature]:action.isNested}}))
|
||||
on(projectsActions.setDefaultNestedModeForFeature, (state, action) => ({
|
||||
...state,
|
||||
defaultNestedModeForFeature: {...state.defaultNestedModeForFeature, [action.feature]: action.isNested}
|
||||
})),
|
||||
on(projectsActions.resetTablesFilterProjectsOptions, (state) => ({...state, tablesFilterProjectsOptions: null})),
|
||||
on(projectsActions.setTablesFilterProjectsOptions, (state, action) => ({
|
||||
...state,
|
||||
tablesFilterProjectsOptions: action.loadMore ? (state.tablesFilterProjectsOptions || []).concat(action.projects) : action.projects,
|
||||
projectsOptionsScrollId: action.scrollId
|
||||
}))
|
||||
);
|
||||
export const selectShowHiddenUserSelection = createSelector(projects, state => state.showHidden);
|
||||
export const selectShowHidden = createSelector(projects, selectSelectedProject,
|
||||
@@ -195,3 +202,4 @@ export const selectShowHidden = createSelector(projects, selectSelectedProject,
|
||||
|
||||
export const selectHideExamples = createSelector(projects, state => state?.hideExamples);
|
||||
export const selectDefaultNestedModeForFeature = createSelector(projects, state => state?.defaultNestedModeForFeature);
|
||||
export const selectProjectsOptionsScrollId = createSelector(projects, state => state?.projectsOptionsScrollId);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {createSelector, Action} from '@ngrx/store';
|
||||
import {NAVIGATION_ACTIONS} from '../../../app.constants';
|
||||
import {SetRouterSegments} from '../actions/router.actions';
|
||||
import {createReducer, createSelector, on} from '@ngrx/store';
|
||||
import {Params} from '@angular/router';
|
||||
import {setRouterSegments} from '@common/core/actions/router.actions';
|
||||
|
||||
export interface RouterState {
|
||||
url: string;
|
||||
@@ -11,29 +10,23 @@ export interface RouterState {
|
||||
skipNextNavigation: boolean;
|
||||
}
|
||||
|
||||
const initRouter = {
|
||||
url : window.location.pathname,
|
||||
params : null,
|
||||
queryParams : null,
|
||||
config : null,
|
||||
skipNextNavigation: false
|
||||
const initRouter: RouterState = {
|
||||
url: window.location.pathname,
|
||||
params: null,
|
||||
queryParams: null,
|
||||
config: null,
|
||||
skipNextNavigation: false,
|
||||
};
|
||||
|
||||
export const selectRouter = state => state.router as RouterState;
|
||||
export const selectRouterUrl = createSelector(selectRouter, router => router && router.url);
|
||||
export const selectRouterParams = createSelector(selectRouter, router => router && router.params);
|
||||
export const selectRouter = state => state.router as RouterState;
|
||||
export const selectRouterUrl = createSelector(selectRouter, router => router && router.url);
|
||||
export const selectRouterParams = createSelector(selectRouter, router => router && router?.params);
|
||||
export const selectRouterQueryParams = createSelector(selectRouter, router => router && router.queryParams);
|
||||
export const selectRouterConfig = createSelector(selectRouter, router => router && router.config);
|
||||
|
||||
export function routerReducer(state: RouterState = initRouter, action: Action): RouterState {
|
||||
switch (action.type) {
|
||||
case NAVIGATION_ACTIONS.SET_ROUTER_SEGMENT: {
|
||||
const payload = (action as SetRouterSegments).payload;
|
||||
return {...state, params: payload.params, queryParams: payload.queryParams,
|
||||
url: payload.url, config: payload.config};
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
export const routerReducer = createReducer(initRouter,
|
||||
on(setRouterSegments, (state, action) => ({
|
||||
...state, params: action.params, queryParams: action.queryParams,
|
||||
url: action.url, config: action.config
|
||||
})),
|
||||
);
|
||||
|
||||
@@ -2,6 +2,8 @@ import {createReducer, createSelector, on, ReducerTypes} from '@ngrx/store';
|
||||
import * as layoutActions from '../actions/layout.actions';
|
||||
import {apiRequest, requestFailed} from '@common/core/actions/http.actions';
|
||||
import {Ace} from 'ace-builds';
|
||||
import {IBreadcrumbsLink} from '@common/layout/breadcrumbs/breadcrumbs.component';
|
||||
import {setBreadcrumbs, setTypeBreadcrumbs} from '@common/core/actions/router.actions';
|
||||
|
||||
export interface ViewState {
|
||||
loading: { [endpoint: string]: boolean };
|
||||
@@ -24,6 +26,7 @@ export interface ViewState {
|
||||
redactedArguments: { key: string }[];
|
||||
hideRedactedArguments: boolean;
|
||||
showEmbedReportMenu: { show: boolean; position: { x: number; y: number } };
|
||||
breadcrumbs: IBreadcrumbsLink[][];
|
||||
}
|
||||
|
||||
export const initViewState: ViewState = {
|
||||
@@ -49,7 +52,8 @@ export const initViewState: ViewState = {
|
||||
{key: 'AWS_SECRET_ACCESS_KEY'},
|
||||
{key: 'AZURE_STORAGE_KEY'}],
|
||||
hideRedactedArguments: false,
|
||||
showEmbedReportMenu: {show: null, position: null}
|
||||
showEmbedReportMenu: {show: null, position: null},
|
||||
breadcrumbs: [[{}]],
|
||||
};
|
||||
|
||||
export const views = state => state.views as ViewState;
|
||||
@@ -75,6 +79,8 @@ export const selectNeverShowPopups = createSelector(views, (state): string[] =>
|
||||
export const selectRedactedArguments = createSelector(views, (state): { key: string }[] => state.redactedArguments);
|
||||
export const selectHideRedactedArguments = createSelector(views, (state): { key: string }[] => state.hideRedactedArguments ? state.redactedArguments : null);
|
||||
export const selectShowEmbedReportMenu = createSelector(views, state => state.showEmbedReportMenu);
|
||||
export const selectBreadcrumbs = createSelector(views, state => state && state.breadcrumbs);
|
||||
|
||||
|
||||
|
||||
export const viewReducers = [
|
||||
@@ -124,6 +130,14 @@ export const viewReducers = [
|
||||
...state,
|
||||
neverShowPopupAgain: action.reset ? state.neverShowPopupAgain.filter(popups => popups !== action.popupId) : Array.from(new Set([...state.neverShowPopupAgain, action.popupId]))
|
||||
})),
|
||||
on(setBreadcrumbs, (state, action) => ({
|
||||
...state, breadcrumbs: action.breadcrumbs
|
||||
})),
|
||||
on(setTypeBreadcrumbs, (state, action) => ({
|
||||
...state,
|
||||
breadcrumbs: [...state.breadcrumbs?.map(breadcrumbGroup => [...breadcrumbGroup?.map(breadcrumb => breadcrumb.type === action.type ? action.breadcrumb : breadcrumb)
|
||||
])]
|
||||
})),
|
||||
] as ReducerTypes<ViewState, any>[];
|
||||
|
||||
export const viewReducer = createReducer(
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
class="btn btn-cml-primary d-flex align-items-center"
|
||||
data-id="New Project"
|
||||
(click)="openCreateProjectDialog()">
|
||||
<i class="al-icon sm al-ico-add mr-2"></i>NEW PROJECT
|
||||
<i class="al-icon sm al-ico-add me-2"></i>NEW PROJECT
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Component, Output, EventEmitter, AfterViewInit, ViewChild, ElementRef, OnDestroy} from '@angular/core';
|
||||
import {Component, OnInit, Output, EventEmitter, AfterViewInit, ViewChild, ElementRef, OnDestroy} from '@angular/core';
|
||||
import {Router} from '@angular/router';
|
||||
import {MatLegacyDialog as MatDialog, MatLegacyDialogRef as MatDialogRef} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog, MatDialogRef} from '@angular/material/dialog';
|
||||
import {fromEvent, Observable, Subscription} from 'rxjs';
|
||||
import {Store} from '@ngrx/store';
|
||||
import {Project} from '~/business-logic/model/projects/project';
|
||||
@@ -19,7 +19,7 @@ import {trackById} from '@common/shared/utils/forms-track-by';
|
||||
templateUrl: './dashboard-projects.component.html',
|
||||
styleUrls : ['./dashboard-projects.component.scss']
|
||||
})
|
||||
export class DashboardProjectsComponent implements AfterViewInit, OnDestroy {
|
||||
export class DashboardProjectsComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
public recentProjectsList$: Observable<Array<Project>>;
|
||||
private dialog: MatDialogRef<ProjectDialogComponent>;
|
||||
private sub: Subscription;
|
||||
@@ -34,15 +34,18 @@ export class DashboardProjectsComponent implements AfterViewInit, OnDestroy {
|
||||
public router: Router,
|
||||
private matDialog: MatDialog
|
||||
) {
|
||||
this.store.dispatch(resetSelectedProject());
|
||||
this.store.select(selectCurrentUser)
|
||||
.pipe(filter(user => !!user), take(1))
|
||||
.subscribe(() => this.store.dispatch(getRecentProjects()));
|
||||
this.recentProjectsList$ = this.store.select(selectRecentProjects);
|
||||
}
|
||||
|
||||
@ViewChild('header') header: ElementRef<HTMLDivElement>;
|
||||
|
||||
ngOnInit() {
|
||||
this.store.dispatch(resetSelectedProject());
|
||||
this.store.select(selectCurrentUser)
|
||||
.pipe(filter(user => !!user), take(1))
|
||||
.subscribe(() => this.store.dispatch(getRecentProjects()));
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
window.setTimeout(() => this.width.emit(this.header.nativeElement.getBoundingClientRect().width));
|
||||
this.sub = fromEvent(window, 'resize')
|
||||
@@ -56,6 +59,7 @@ export class DashboardProjectsComponent implements AfterViewInit, OnDestroy {
|
||||
|
||||
public openCreateProjectDialog() {
|
||||
this.dialog = this.matDialog.open(ProjectDialogComponent, {
|
||||
panelClass: 'light-theme',
|
||||
data: {
|
||||
mode: 'create',
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="step-part step-footer" [class]="step?.data?.status">
|
||||
<div *ngIf="step?.data?.job_size">{{step.data.job_size | filesize: fileSizeConfigStorage}}</div>
|
||||
<div class="d-flex-center" *ngIf="step?.data?.last_update">
|
||||
<i class="al-icon al-ico-upload sm mr-1"></i>{{step.data.last_update * 1000 | timeAgo}}
|
||||
<i class="al-icon al-ico-upload sm me-1"></i>{{step.data.last_update * 1000 | timeAgo}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -50,10 +50,10 @@ export const routes: Routes = [
|
||||
SimpleDatasetVersionInfoComponent,
|
||||
SimpleDatasetVersionDetailsComponent,
|
||||
SimpleDatasetVersionContentComponent,
|
||||
SimpleDatasetVersionPreviewComponent,
|
||||
DatasetVersionStepComponent,
|
||||
],
|
||||
imports: [
|
||||
SimpleDatasetVersionPreviewComponent,
|
||||
CommonModule,
|
||||
SMSharedModule,
|
||||
AngularSplitModule,
|
||||
@@ -63,6 +63,9 @@ export const routes: Routes = [
|
||||
ExperimentOutputLogModule,
|
||||
DebugImagesModule,
|
||||
RouterModule.forChild(routes),
|
||||
],
|
||||
exports: [
|
||||
SimpleDatasetVersionPreviewComponent,
|
||||
]
|
||||
})
|
||||
export class DatasetVersionModule { }
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
ngxClipboard
|
||||
[cbContent]="command"
|
||||
(cbOnSuccess)="$event.event.stopPropagation(); copied()"
|
||||
>Copy command</div><i class="al-icon al-ico-success sm mr-1" [class.visible]="copySuccess"></i>
|
||||
>Copy command</div><i class="al-icon al-ico-success sm me-1" [class.visible]="copySuccess"></i>
|
||||
</div>
|
||||
</div>
|
||||
</mat-menu>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {ChangeDetectionStrategy, Component, Input, ViewChild} from '@angular/core';
|
||||
import {MatLegacyMenuTrigger as MatMenuTrigger} from '@angular/material/legacy-menu';
|
||||
import {MatMenuTrigger} from '@angular/material/menu';
|
||||
import {ISmCol} from '@common/shared/ui-components/data/table/table.consts';
|
||||
import {fileSizeConfigStorage, FileSizePipe} from '@common/shared/pipes/filesize.pipe';
|
||||
|
||||
|
||||
@@ -20,6 +20,21 @@
|
||||
></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="param">
|
||||
<div class="key">Parent</div>
|
||||
<div class="value" [smTooltip]="entity?.parent?.name" smShowTooltipIfEllipsis>
|
||||
<a
|
||||
*ngIf="entity?.parent?.id; else: empty"
|
||||
class="arr-link"
|
||||
target="_blank"
|
||||
[href]="'/projects/' + entity?.parent?.project.id + '/experiments/' + entity?.parent?.id + '/output/execution'">
|
||||
<div class="d-flex-center">
|
||||
<span class="flex-shrink-1 ellipsis">{{entity?.parent?.name}}</span><i *ngIf="entity?.parent?.id" class="al-icon al-ico-export xs"></i>
|
||||
</div>
|
||||
</a>
|
||||
<ng-template #empty>-</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="param continue">
|
||||
<div class="key">Size</div>
|
||||
<div class="value" [smTooltip]="entity?.runtime?.ds_total_size + ' (original)'" smShowTooltipIfEllipsis>{{($any(entity?.runtime?.ds_total_size) | filesize : fileSizeConfigStorage) || '-'}}<span class="comment">(original)</span></div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
></sm-simple-dataset-version-details>
|
||||
<div class="console-button">
|
||||
<button class="btn btn-cml-primary d-flex align-items-center" (click)="toggleDetails()">
|
||||
<i class="al-icon al-ico-console sm mr-3"></i>DETAILS
|
||||
<i class="al-icon al-ico-console sm me-3"></i>DETAILS
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
@@ -48,7 +48,7 @@
|
||||
<ng-container *ngIf="showLog">
|
||||
<div class="header toggle">
|
||||
<div class="log-name">
|
||||
<i class="al-icon al-ico-console mr-2"></i>
|
||||
<i class="al-icon al-ico-console me-2"></i>
|
||||
<span *ngIf="(selected$ | async) as selected">
|
||||
{{selected?.name}}<ng-container *ngIf="selected?.runtime?.version"> v{{selected.runtime.version}}</ng-container>
|
||||
</span>
|
||||
@@ -64,7 +64,7 @@
|
||||
></sm-button-toggle>
|
||||
<div class="close">
|
||||
<i class="al-icon pointer" [class]="maximizeResults ? 'al-ico-min-panel' : 'al-ico-max-panel'" (click)="toggleResultSize()"></i>
|
||||
<i class="al-icon al-ico-dialog-x pointer ml-4" (click)="openLog(false)"></i>
|
||||
<i class="al-icon al-ico-dialog-x pointer ms-4" (click)="openLog(false)"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div [ngSwitch]="detailsPanelMode" class="content">
|
||||
|
||||
@@ -4,8 +4,8 @@ import {DagManagerUnsortedService} from '@common/shared/services/dag-manager-uns
|
||||
import {experimentDetailsUpdated, getSelectedPipelineStep, setSelectedPipelineStep} from '@common/experiments/actions/common-experiments-info.actions';
|
||||
import {last} from 'lodash-es';
|
||||
import {Store} from '@ngrx/store';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {EditJsonComponent} from '@common/shared/ui-components/overlay/edit-json/edit-json.component';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {EditJsonComponent, EditJsonData} from '@common/shared/ui-components/overlay/edit-json/edit-json.component';
|
||||
import {Task} from '~/business-logic/model/tasks/task';
|
||||
import {CommonExperimentsInfoEffects} from '@common/experiments/effects/common-experiments-info.effects';
|
||||
import {tap} from 'rxjs/operators';
|
||||
@@ -93,8 +93,7 @@ export class SimpleDatasetVersionInfoComponent extends PipelineControllerInfoCom
|
||||
data: {
|
||||
textData: dataset.comment,
|
||||
title: 'EDIT DESCRIPTION',
|
||||
typeJson: false,
|
||||
}
|
||||
} as EditJsonData
|
||||
});
|
||||
editJsonComponent.afterClosed().subscribe(res => {
|
||||
if (res !== undefined) {
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {ExperimentSharedModule} from "~/features/experiments/shared/experiment-shared.module";
|
||||
import {DebugImagesModule} from "@common/debug-images/debug-images.module";
|
||||
import {NgIf} from "@angular/common";
|
||||
|
||||
@Component({
|
||||
selector: 'sm-simple-dataset-version-preview',
|
||||
templateUrl: './simple-dataset-version-preview.component.html',
|
||||
styleUrls: ['./simple-dataset-version-preview.component.scss']
|
||||
styleUrls: ['./simple-dataset-version-preview.component.scss'],
|
||||
imports: [
|
||||
ExperimentSharedModule,
|
||||
DebugImagesModule,
|
||||
NgIf
|
||||
],
|
||||
standalone: true
|
||||
})
|
||||
export class SimpleDatasetVersionPreviewComponent {
|
||||
@Input() selected;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
[users]="users$ | async"
|
||||
[hyperParamsOptions]="hyperParamsOptions$ | async"
|
||||
[activeParentsFilter]="activeParentsFilter$ | async"
|
||||
[parents]="parent$ | async"
|
||||
[parents]="parents$ | async"
|
||||
[experimentTypes]="types$ | async"
|
||||
[tags]="tags$ | async"
|
||||
[systemTags]="systemTags$ | async"
|
||||
@@ -107,7 +107,7 @@
|
||||
[selectedDisableAvailable]="singleRowContext ? getSingleSelectedDisableAvailable(contextExperiment) : (selectedExperimentsDisableAvailable$ | async)"
|
||||
[numSelected]="singleRowContext ? 1 : selectedExperiments.length"
|
||||
[tagsFilterByProject]="tagsFilterByProject$ | async"
|
||||
[projectTags]="projectTags$ | async"
|
||||
[projectTags]="tags$ | async"
|
||||
[companyTags]="companyTags$ | async"
|
||||
[activateFromMenuButton]="false"
|
||||
[minimizedView]="true"
|
||||
|
||||
@@ -9,7 +9,7 @@ import {EXPERIMENTS_TABLE_COL_FIELDS} from '~/features/experiments/shared/experi
|
||||
import {Store} from '@ngrx/store';
|
||||
import {SmSyncStateSelectorService} from '@common/core/services/sync-state-selector.service';
|
||||
import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {RefreshService} from '@common/core/services/refresh.service';
|
||||
import {take} from 'rxjs/operators';
|
||||
import {ExperimentsViewState} from '@common/experiments/reducers/experiments-view.reducer';
|
||||
@@ -50,7 +50,7 @@ export class SimpleDatasetVersionsComponent extends ControllersComponent impleme
|
||||
if (!this.route.snapshot.firstChild?.params.versionId) {
|
||||
this.store.dispatch(experimentsActions.experimentSelectionChanged({
|
||||
experiment: this.firstExperiment,
|
||||
project: this.selectedProject,
|
||||
project: this.selectedProjectId,
|
||||
replaceURL: true
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div>
|
||||
Use ClearML Data from CLI or in your Python code.<br>
|
||||
Run these code snippets for a quick example (Requires ClearML 1.7 or above).<br>
|
||||
For more details see the <a [class.dark]="showButton" href="https://clear.ml/docs/latest/docs/clearml_data/clearml_data" target="_blank">documentation</a>
|
||||
For more details see the <a [class.dark]="showButton" href="https://clear.ml/docs/latest/docs/clearml_data" target="_blank">documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navbar">
|
||||
@@ -38,4 +38,4 @@
|
||||
</div>
|
||||
<div class="diagram"><i class="i-datasets-empty-state"></i></div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
>{{project.name | shortProjectName}}</span>
|
||||
<i *ngIf="!hideProjectPathIcon && (project.name | cleanProjectPath: false)" [smTooltip]="project.name |
|
||||
cleanProjectPath:false"
|
||||
class="al-icon al-ico-project-path sm ml-2"></i></span>
|
||||
class="al-icon al-ico-project-path sm ms-2"></i></span>
|
||||
</sm-inline-edit>
|
||||
<sm-pipeline-card-menu
|
||||
class="menu-wrapper"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
>
|
||||
<sm-button-toggle
|
||||
left-items
|
||||
class="ml-3"
|
||||
class="ms-3"
|
||||
[value]="!!projectId"
|
||||
[options]="[
|
||||
{value: false, icon: 'al-ico-flat-view', label: 'List view'},
|
||||
@@ -20,7 +20,7 @@
|
||||
<button
|
||||
class="btn btn-cml-primary d-flex align-items-center"
|
||||
(click)="createDataset()">
|
||||
<i class="al-icon al-ico-add sm mr-2"></i>NEW DATASET
|
||||
<i class="al-icon al-ico-add sm me-2" data-id="NewDatasetButton"></i>NEW DATASET
|
||||
</button>
|
||||
</sm-projects-header>
|
||||
<ng-container
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<div class="metric-bar" [class.minimized]="minimized"
|
||||
*ngIf="!thereAreNoMetrics(experimentId) && !disableStatusRefreshFilter">
|
||||
<label>Metric:</label>
|
||||
<mat-form-field appearance="outline" [ngClass]="{'dark thin': isDarkTheme}">
|
||||
<mat-form-field appearance="outline" class="no-bottom" [ngClass]="{'dark thin': isDarkTheme}">
|
||||
<mat-select
|
||||
#metricSelect
|
||||
(selectionChange)="selectMetric($event, experimentId)"
|
||||
|
||||
@@ -15,7 +15,7 @@ import {select, Store} from '@ngrx/store';
|
||||
import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer';
|
||||
import {AdminService} from '~/shared/services/admin.service';
|
||||
import {selectS3BucketCredentials} from '../core/reducers/common-auth-reducer';
|
||||
import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import * as debugActions from './debug-images-actions';
|
||||
import {fetchExperiments, getDebugImagesMetrics, resetDebugImages} from './debug-images-actions';
|
||||
import {
|
||||
@@ -316,7 +316,7 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
|
||||
this.createEmbedCode({metrics: [metric], variants: [variant], domRect: rect}, experimentId),
|
||||
imageSources: sources, index, snippetsMetaData: iterationSnippets, isAllMetrics
|
||||
},
|
||||
panelClass: ['image-viewer-dialog'],
|
||||
panelClass: ['image-viewer-dialog', 'light-theme'],
|
||||
height: '100%',
|
||||
maxHeight: 'auto',
|
||||
width: '100%',
|
||||
@@ -418,7 +418,8 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
|
||||
createEmbedCode(event: { metrics?: string[]; variants?: string[]; domRect: DOMRect }, experimentId: string) {
|
||||
this.reportEmbed.createCode({
|
||||
type: 'sample',
|
||||
tasks: [experimentId],
|
||||
objects: [experimentId],
|
||||
objectType: 'task',
|
||||
...event
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import {DebugImagesEffects} from './debug-images-effects';
|
||||
import {debugSamplesReducer} from './debug-images-reducer';
|
||||
import {DebugImagesViewComponent} from './debug-images-view/debug-images-view.component';
|
||||
import {DebugImagesComponent} from './debug-images.component';
|
||||
import {MatLegacySliderModule as MatSliderModule} from '@angular/material/legacy-slider';
|
||||
import {MatSliderModule} from '@angular/material/slider';
|
||||
import {ExperimentGraphsModule} from '../shared/experiment-graphs/experiment-graphs.module';
|
||||
import {DebugSampleModule} from '@common/shared/debug-sample/debug-sample.module';
|
||||
import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module';
|
||||
|
||||
@@ -4,6 +4,7 @@ import {Params} from '@angular/router';
|
||||
import {ISmCol} from '../../shared/ui-components/data/table/table.consts';
|
||||
import {SortMeta} from 'primeng/api';
|
||||
import {TableFilter} from '../../shared/utils/tableParamEncode';
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
|
||||
export const EXPERIMENTS_COMPARE_SELECT_EXPERIMENT_ = 'EXPERIMENTS_COMPARE_SELECT_EXPERIMENT_';
|
||||
|
||||
@@ -22,7 +23,7 @@ export const SET_NAVIGATION_PREFERENCES = EXPERIMENTS_COMPARE_SELECT_EXPERIMENT_
|
||||
|
||||
export const setHideIdenticalFields = createAction(SET_HIDE_IDENTICAL_ROWS, props<{payload: boolean}>());
|
||||
export const setExperimentsUpdateTime = createAction(SET_EXPERIMENTS_UPDATE_TIME, props<{ payload: {[key: string]: Date}}>());
|
||||
export const refreshIfNeeded = createAction(REFRESH_IF_NEEDED, props<{ payload: boolean; autoRefresh?: boolean }>());
|
||||
export const refreshIfNeeded = createAction(REFRESH_IF_NEEDED, props<{ payload: boolean; autoRefresh?: boolean; entityType: string }>());
|
||||
export const toggleShowScalarOptions = createAction(TOGGLE_SHOW_SACLARS_OPTIONS);
|
||||
export const setSearchExperimentsForCompareResults = createAction(SET_SELECT_EXPERIMENTS_FOR_COMPARE, props<{ payload: Array<Task> }>());
|
||||
export const setShowSearchExperimentsForCompare = createAction(SET_SHOW_SEARCH_EXPERIMENTS_FOR_COMPARE, props<{ payload: boolean }>());
|
||||
@@ -50,7 +51,7 @@ export const compareAddDialogSetTableSort = createAction(
|
||||
EXPERIMENTS_COMPARE_SELECT_EXPERIMENT_ + ' [set table sort]',
|
||||
props<{ orders: SortMeta[]; projectId: string; colIds: string[] }>()
|
||||
);
|
||||
export const refetchExperimentRequested = createAction(REFETCH_EXPERIMENT_REQUESTED, props<{ autoRefresh: boolean }>());
|
||||
export const refetchExperimentRequested = createAction(REFETCH_EXPERIMENT_REQUESTED, props<{ autoRefresh: boolean; entity: EntityTypeEnum }>());
|
||||
export const setNavigationPreferences = createAction(SET_NAVIGATION_PREFERENCES, props<{ navigationPreferences: Params }>());
|
||||
export const setAddTableViewArchived = createAction(
|
||||
EXPERIMENTS_COMPARE_SELECT_EXPERIMENT_ + '[show archived in add table]',
|
||||
|
||||
@@ -2,6 +2,7 @@ import {createAction, props} from '@ngrx/store';
|
||||
import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum';
|
||||
import {EventsGetMultiTaskPlotsResponse} from '~/business-logic/model/events/eventsGetMultiTaskPlotsResponse';
|
||||
import {ExperimentCompareSettings} from '@common/experiments-compare/reducers/experiments-compare-charts.reducer';
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
|
||||
|
||||
export const EXPERIMENTS_COMPARE_METRICS_CHARTS_ = 'EXPERIMENTS_COMPARE_METRICS_CHARTS_';
|
||||
@@ -14,12 +15,12 @@ export const SET_EXPERIMENT_PLOTS = EXPERIMENTS_COMPARE_METRICS_CH
|
||||
|
||||
export const getMultiScalarCharts = createAction(
|
||||
EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'GET_MULTI_SCALAR_CHARTS',
|
||||
props<{ taskIds: string[]; autoRefresh?: boolean; cached?: boolean }>()
|
||||
props<{ taskIds: string[]; entity: EntityTypeEnum; autoRefresh?: boolean; cached?: boolean }>()
|
||||
);
|
||||
|
||||
export const getMultiPlotCharts = createAction(
|
||||
EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'GET_MULTI_PLOT_CHARTS',
|
||||
props<{ taskIds: Array<string>; autoRefresh?: boolean }>()
|
||||
props<{ taskIds: Array<string>; entity: EntityTypeEnum; autoRefresh?: boolean }>()
|
||||
);
|
||||
|
||||
export const setSelectedExperiments = createAction(
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import {createAction, props} from '@ngrx/store';
|
||||
import {IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models';
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
import {ModelDetail, ModelDetails} from '@common/experiments-compare/shared/experiments-compare-details.model';
|
||||
|
||||
export const resetState = createAction('[experiment compare details] RESET_STATE');
|
||||
export const setExperiments = createAction('[experiment compare details] SET_EXPERIMENTS', props<{experiments: IExperimentDetail[]}>());
|
||||
export const experimentListUpdated = createAction('[experiment compare details] EXPERIMENT_LIST_UPDATED', props<{ids: string[]}>());
|
||||
export const setModels = createAction('[experiment compare details] SET_MODELS', props<{models: ModelDetail[]}>());
|
||||
export const experimentListUpdated = createAction('[experiment compare details] EXPERIMENT_LIST_UPDATED', props<{ids: string[]; entity: EntityTypeEnum}>());
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import {createAction, props} from '@ngrx/store';
|
||||
import {Task} from '~/business-logic/model/tasks/task';
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
|
||||
export const EXPERIMENTS_COMPARE_METRICS_VALUES_ = 'EXPERIMENTS_COMPARE_METRICS_VALUES_';
|
||||
|
||||
export const getComparedExperimentsMetricsValues = createAction(
|
||||
EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'GET_COMPARED_EXPERIMENTS_METRICS_VALUES',
|
||||
props<{ taskIds: string[]; autoRefresh?: boolean }>()
|
||||
props<{ taskIds: string[]; entity: EntityTypeEnum; autoRefresh?: boolean }>()
|
||||
);
|
||||
export const setComparedExperiments = createAction(
|
||||
EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'SET_COMPARED_EXPERIMENTS',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {createAction, props} from '@ngrx/store';
|
||||
import {ExperimentParams} from '../shared/experiments-compare-details.model';
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
|
||||
export const resetState = createAction('[experiment compare params] RESET_STATE');
|
||||
export const setExperiments = createAction('[experiment compare params] SET_EXPERIMENTS', props<{experiments: ExperimentParams[]}>());
|
||||
export const experimentListUpdated = createAction('[experiment compare params] EXPERIMENT_LIST_UPDATED', props<{ids: string[]}>());
|
||||
export const experimentListUpdated = createAction('[experiment compare params] EXPERIMENT_LIST_UPDATED', props<{ids: string[]; entity: EntityTypeEnum}>());
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import * as detailsActions from '../actions/experiments-compare-details.actions';
|
||||
import * as paramsActions from '../actions/experiments-compare-params.actions';
|
||||
import {
|
||||
ExperimentCompareTree,
|
||||
ExperimentCompareTreeSection,
|
||||
IExperimentDetail
|
||||
} from '~/features/experiments-compare/experiments-compare-models';
|
||||
import {ExperimentCompareTree, ExperimentCompareTreeSection, IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models';
|
||||
import {get, has, isEmpty, isEqual} from 'lodash-es';
|
||||
import {treeBuilderService} from '../services/tree-builder.service';
|
||||
import {isArrayOrderNotImportant} from '../jsonToDiffConvertor';
|
||||
@@ -20,13 +16,14 @@ import {Observable, Subscription} from 'rxjs';
|
||||
import {FlatTreeControl} from '@angular/cdk/tree';
|
||||
import {CdkVirtualScrollViewport} from '@angular/cdk/scrolling';
|
||||
import {selectRouterParams} from '../../core/reducers/router-reducer';
|
||||
import {distinctUntilChanged, filter, map, take, tap} from 'rxjs/operators';
|
||||
import {distinctUntilChanged, filter, map, take} from 'rxjs/operators';
|
||||
import {selectHideIdenticalFields} from '../reducers';
|
||||
import {refetchExperimentRequested} from '../actions/compare-header.actions';
|
||||
import {RENAME_MAP} from '../experiments-compare.constants';
|
||||
import {selectHasDataFeature} from '~/core/reducers/users.reducer';
|
||||
import {ListRange} from '@angular/cdk/collections';
|
||||
import {RefreshService} from '@common/core/services/refresh.service';
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
|
||||
export type NextDiffDirectionEnum = 'down' | 'up';
|
||||
|
||||
@@ -76,8 +73,8 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase
|
||||
public experimentTags: { [experimentId: string]: string[] } = {};
|
||||
private timeoutIndex: number;
|
||||
private originalScrolledElement: EventTarget;
|
||||
private taskIds: string;
|
||||
private treeCardBody: HTMLDivElement;
|
||||
protected entityType = EntityTypeEnum.experiment;
|
||||
@ViewChildren('treeCardBody') treeCardBodies: QueryList<ElementRef<HTMLDivElement>>;
|
||||
|
||||
get baseExperiment(): IExperimentDetail {
|
||||
@@ -89,7 +86,7 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase
|
||||
@HostListener('window:resize')
|
||||
afterResize() {
|
||||
window.setTimeout(() => {
|
||||
this.nativeWidth = Math.max(this.treeCardBody.getBoundingClientRect().width, 410);
|
||||
this.nativeWidth = Math.max(this.treeCardBody?.getBoundingClientRect().width, 410);
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
@@ -130,7 +127,7 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase
|
||||
|
||||
this.refreshingSubscription = this.refresh.tick
|
||||
.pipe(filter(auto => auto !== null))
|
||||
.subscribe(auto => this.store.dispatch(refetchExperimentRequested({autoRefresh: auto})));
|
||||
.subscribe(auto => this.store.dispatch(refetchExperimentRequested({autoRefresh: auto, entity: this.entityType})));
|
||||
|
||||
this.hideIdenticalFieldsSub.add(this.hasDataFeature$.subscribe(hasData => this.hasDataFeature = hasData));
|
||||
|
||||
@@ -141,7 +138,7 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase
|
||||
.pipe(filter(list => list.first), take(1))
|
||||
.subscribe((list: QueryList<ElementRef<HTMLDivElement>>) => {
|
||||
this.treeCardBody = list.first.nativeElement;
|
||||
this.nativeWidth = Math.max(this.treeCardBody.getBoundingClientRect().width, 410);
|
||||
this.afterResize();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user