Release v1.3 (#19)

Co-authored-by: shyallegro <support@allegro.ai>
This commit is contained in:
shyallegro
2022-03-15 15:46:26 +02:00
committed by GitHub
parent ce07f6973e
commit 07d90efe15
379 changed files with 19274 additions and 22526 deletions

View File

@@ -3,7 +3,7 @@
## Building the UI from source
### Prerequisite
* a linux machine
* Node 12 with latest npm
* Node 16 with latest npm
* clone the project to your local machine
### build

30356
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "ClearML-webapp",
"version": "1.2.0",
"version": "1.3.0",
"license": "",
"scripts": {
"ng": "ng",
@@ -20,82 +20,84 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^12.2.13",
"@angular/cdk": "^12.2.13",
"@angular/common": "^12.2.13",
"@angular/compiler": "^12.2.13",
"@angular/core": "^12.2.13",
"@angular/forms": "^12.2.13",
"@angular/material": "^12.2.13",
"@angular/platform-browser": "^12.2.13",
"@angular/platform-browser-dynamic": "^12.2.13",
"@angular/platform-server": "^12.2.13",
"@angular/router": "^12.2.13",
"@angular/service-worker": "^12.2.13",
"@aws-sdk/client-s3": "^3.41.0",
"@aws-sdk/s3-request-presigner": "^3.41.0",
"@ngrx/effects": "^12.5.1",
"@ngrx/entity": "^12.5.1",
"@ngrx/router-store": "^12.5.1",
"@ngrx/store": "^12.5.1",
"@angular/animations": "^13.1.1",
"@angular/cdk": "^13.1.1",
"@angular/common": "^13.1.1",
"@angular/compiler": "^13.1.1",
"@angular/core": "^13.1.1",
"@angular/forms": "^13.1.1",
"@angular/material": "^13.1.1",
"@angular/platform-browser": "^13.1.1",
"@angular/platform-browser-dynamic": "^13.1.1",
"@angular/platform-server": "^13.1.1",
"@angular/router": "^13.1.1",
"@angular/service-worker": "^13.1.1",
"@aws-sdk/client-s3": "^3.45.0",
"@aws-sdk/s3-request-presigner": "^3.45.0",
"@ngneat/dag": "^1.1.0",
"@ngrx/effects": "^13.0.2",
"@ngrx/entity": "^13.0.2",
"@ngrx/router-store": "^13.0.2",
"@ngrx/store": "^13.0.2",
"ace-builds": "^1.4.13",
"angular-google-tag-manager": "^1.4.3",
"angular-resizable-element": "^4.0.0",
"angular-split": "^5.0.0",
"angular-google-tag-manager": "^1.5.0",
"angular-resizable-element": "^5.0.0",
"angular-split": "^13.1.0",
"ansi-to-html": "^0.7.2",
"bootstrap": "^4.6.1",
"britecharts": "^2.18.0",
"curved-arrows": "^0.1.0",
"d3-selection": "^1.4.2",
"diff": "^5.0.0",
"filesize": "^8.0.6",
"has-ansi": "^5.0.1",
"hocon-parser": "^1.0.1",
"jwt-decode": "^3.1.2",
"lodash": "^4.17.21",
"lucene": "^2.1.1",
"ngx-clipboard": "^14.0.2",
"ngx-color-picker": "^11.0.0",
"ngx-filesize": "^2.0.16",
"ngx-markdown-editor": "^3.3.3",
"ngx-clipboard": "^15.0.1",
"ngx-color-picker": "^12.0.0",
"ngx-markdown-editor": "^4.0.0",
"ngx-window-token": "^6.0.0",
"object-hash": "^2.2.0",
"primeicons": "^5.0.0",
"primeng": "^12.2.2",
"primeng": "^13.0.4",
"process": "^0.11.10",
"rxjs": "^6.6.7",
"rxjs": "^7.5.1",
"string-to-color": "^2.2.2",
"tslib": "^2.3.1",
"url": "^0.11.0",
"uuid": "^8.3.2",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~12.2.1",
"@angular-devkit/core": "^12.2.1",
"@angular-devkit/schematics": "^12.2.1",
"@angular-devkit/schematics-cli": "^0.1102.6",
"@angular-eslint/builder": "^12.0.0",
"@angular-eslint/eslint-plugin": "^12.0.0",
"@angular-eslint/eslint-plugin-template": "^12.0.0",
"@angular-eslint/schematics": "12.3.1",
"@angular-eslint/template-parser": "^12.0.0",
"@angular/cli": "^12.2.1",
"@angular/compiler-cli": "^12.2.1",
"@angular/language-service": "^12.2.1",
"@fortawesome/fontawesome-free": "^5.15.3",
"@ngrx/schematics": "^12.4.0",
"@ngrx/store-devtools": "^12.4.0",
"@schematics/schematics": "^0.1102.6",
"@types/d3-selection": "^2.0.0",
"@types/lodash": "^4.14.168",
"@types/node": "^14.14.41",
"@types/plotly.js": "^1.54.14",
"@types/uuid": "^8.3.0",
"@typescript-eslint/eslint-plugin": "4.28.2",
"@typescript-eslint/parser": "4.28.2",
"codelyzer": "^6.0.1",
"eslint": "^7.26.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jsdoc": "32.3.0",
"@angular-devkit/build-angular": "^13.1.2",
"@angular-devkit/core": "^13.1.2",
"@angular-devkit/schematics": "^13.1.2",
"@angular-devkit/schematics-cli": "^13.1.2",
"@angular-eslint/builder": "^13.0.1",
"@angular-eslint/eslint-plugin": "^13.0.1",
"@angular-eslint/eslint-plugin-template": "^13.0.1",
"@angular-eslint/schematics": "13.0.1",
"@angular-eslint/template-parser": "^13.0.1",
"@angular/cli": "^13.1.2",
"@angular/compiler-cli": "^13.1.1",
"@angular/language-service": "^13.1.1",
"@fortawesome/fontawesome-free": "^5.15.4",
"@ngrx/schematics": "^13.0.2",
"@ngrx/store-devtools": "^13.0.2",
"@types/d3-selection": "^1.4.3",
"@types/lodash": "^4.14.178",
"@types/node": "^16.11.19",
"@types/plotly.js": "^1.54.20",
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "5.9.0",
"@typescript-eslint/parser": "5.9.0",
"codelyzer": "^6.0.2",
"eslint": "^8.6.0",
"eslint-plugin-import": "2.25.4",
"eslint-plugin-jsdoc": "37.5.1",
"eslint-plugin-prefer-arrow": "1.2.3",
"ts-node": "~9.1.1",
"typescript": "^4.3.5",
"webpack-bundle-analyzer": "^4.4.0"
"typescript": "^4.5.4"
}
}

View File

@@ -14,7 +14,7 @@ import {selectSelectedProject} from '@common/core/reducers/projects.reducer';
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} from 'rxjs/operators';
import {distinctUntilChanged, filter, map, tap, withLatestFrom} 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';
@@ -23,17 +23,19 @@ import {formatStaticCrumb} from '@common/layout/breadcrumbs/breadcrumbs-common.u
import {ServerUpdatesService} from '@common/shared/services/server-updates.service';
import {selectAvailableUpdates} from './core/reducers/view.reducer';
import {UPDATE_SERVER_PATH} from './app.constants';
import {firstLogin, plotlyReady, setScaleFactor, visibilityChanged} from '@common/core/actions/layout.actions';
import {aceReady, firstLogin, plotlyReady, setScaleFactor, visibilityChanged} from '@common/core/actions/layout.actions';
import {UiUpdatesService} from '@common/shared/services/ui-updates.service';
import {UsageStatsService} from './core/services/usage-stats.service';
import {dismissSurvey} from './core/actions/layout.actions';
import {getScaleFactor} from '@common/shared/utils/shared-utils';
import {getScaleFactor, loadExternalLibrary} from '@common/shared/utils/shared-utils';
import {User} from './business-logic/model/users/user';
import {ConfigurationService} from '@common/shared/services/configuration.service';
import {GoogleTagManagerService} from 'angular-google-tag-manager';
import {selectIsSharedAndNotOwner} from './features/experiments/reducers';
import {TipsService} from '@common/shared/services/tips.service';
import {USER_PREFERENCES_KEY} from '@common/user-preferences';
import {selectIsPipelines} from '@common/experiments-compare/reducers';
import {Environment} from '../environments/base';
@Component({
selector: 'sm-root',
@@ -65,6 +67,7 @@ export class AppComponent implements OnInit, OnDestroy {
public hideUpdate: boolean;
public showSurvey: boolean;
private plotlyURL: string;
private environment: Environment;
@HostListener('document:visibilitychange') onVisibilityChange() {
this.store.dispatch(visibilityChanged({visible: !document.hidden}));
@@ -99,7 +102,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.selectedProjectFromUrl$ = this.store.select(selectRouterParams)
.pipe(
filter((params: Params) => !!params),
map(params => get('projectId', params) || null)
map(params => params?.projectId || null)
);
if (ConfigurationService.globalEnvironment.GTM_ID) {
@@ -112,6 +115,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.hideUpdate = env.hideUpdateNotice;
this.showSurvey = env.showSurvey;
this.plotlyURL = env.plotlyURL;
this.environment = env;
});
this.router.events
.pipe(filter(event => event instanceof NavigationEnd))
@@ -131,7 +135,7 @@ export class AppComponent implements OnInit, OnDestroy {
filter(user => !!user?.id),
distinctUntilChanged((prev, next) => prev?.id === next?.id)
)
.subscribe(() => {
.subscribe(() => {
this.store.dispatch(getAllSystemProjects());
this.store.dispatch(getTutorialBucketCredentials());
this.store.dispatch(termsOfUseAccepted());
@@ -144,7 +148,7 @@ export class AppComponent implements OnInit, OnDestroy {
loginTime = Date.now();
localStorage.setItem(USER_PREFERENCES_KEY.firstLogin, `${loginTime}`);
}
});
});
this.selectedProjectFromUrl$.subscribe((projectId: string) => {
this.store.dispatch(setSelectedProjectId({projectId}));
@@ -164,19 +168,22 @@ export class AppComponent implements OnInit, OnDestroy {
}
});
this.breadcrumbsSubscription = this.store.select(selectBreadcrumbsStrings)
.pipe(filter(names => !!names))
.subscribe(
(names) => {
this.breadcrumbsStrings = prepareNames(names);
this.updateTitle();
}
);
this.breadcrumbsSubscription = this.store.select(selectBreadcrumbsStrings).pipe(
filter(names => !!names),
withLatestFrom(this.store.select(selectIsPipelines))
).subscribe(
([names, isPipeLines]) => {
this.breadcrumbsStrings = prepareNames(names, isPipeLines);
this.updateTitle();
}
);
if (window.localStorage.getItem('disableHidpi') !== 'true') {
this.setScale();
}
this.loadPlotly();
loadExternalLibrary(this.store, this.environment.plotlyURL, plotlyReady);
loadExternalLibrary(this.store, '/assets/ace-builds/ace.js', aceReady);
}
private setScale() {
@@ -241,35 +248,4 @@ export class AppComponent implements OnInit, OnDestroy {
get guestUser(): boolean {
return !this.currentUser || this.currentUser?.role === 'guest';
}
public loadPlotly(): void {
const init = () => {
const script: HTMLScriptElement = document.createElement('script');
script.type = 'text/javascript';
script.src = this.plotlyURL;
script.onerror = () => console.error(`Error loading plotly.js library from ${this.plotlyURL}`);
script.crossOrigin = 'use-credentials';
const head: HTMLHeadElement = document.getElementsByTagName('head')[0];
head.appendChild(script);
let counter = 600;
const fn = () => {
const plotly = (window as any).Plotly;
if (plotly) {
this.store.dispatch(plotlyReady());
} else if (counter > 0) {
counter --;
setTimeout(fn, 100);
} else {
throw new Error(`Error loading plotly.js library from ${this.plotlyURL}. Timeout.`);
}
};
fn();
};
setTimeout(init);
}
}

View File

@@ -49,6 +49,32 @@ export const routes: Routes = [
},
]
},
{
path: 'pipelines',
// canActivate: [RolePermissionsGuard],
data: {search: true},
loadChildren: () => import('@common/pipelines/pipelines.module').then(m => m.PipelinesModule),
},
{
path: 'pipelines',
// canActivate: [RolePermissionsGuard],
data: {search: true},
children: [
{
path: ':projectId',
children: [
{path: 'pipelines', loadChildren: () => import('./features/projects/projects.module').then(m => m.ProjectsModule)},
{
path: 'experiments', loadChildren: () => import('@common/pipelines-controller/pipelines-controller.module').then(m => m.PipelinesControllerModule)
},
{
path: 'compare-experiments',
loadChildren: () => import('./webapp-common/experiments-compare/experiments-compare.module').then(m => m.ExperimentsCompareModule)
},
]
},
]
},
{path: 'workers-and-queues', loadChildren: () => import('./features/workers-and-queues/workers-and-queues.module').then(m => m.WorkersAndQueuesModule)},
{path: '404', loadChildren: () => import('./features/not-found/not-found.module').then(m => m.NotFoundModule)},
{path: '**', loadChildren: () => import('./features/not-found/not-found.module').then(m => m.NotFoundModule)},

View File

@@ -0,0 +1,109 @@
/**
* pipelines
* 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.
*/
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/member-ordering */
import {HTTP} from '../../app.constants';
import {SmApiRequestsService} from "./api-requests.service";
import { Inject, Injectable, Optional } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
HttpResponse, HttpEvent } from '@angular/common/http';
import { CustomHttpUrlEncodingCodec } from '../encoder';
import { Observable } from 'rxjs';
import { PipelinesStartPipelineRequest } from '../model/pipelines/pipelinesStartPipelineRequest';
import { PipelinesStartPipelineResponse } from '../model/pipelines/pipelinesStartPipelineResponse';
import { BASE_PATH, COLLECTION_FORMATS } from '../variables';
import { Configuration } from '../configuration';
@Injectable()
export class ApiPipelinesService {
protected basePath = HTTP.API_BASE_URL;
public defaultHeaders = new HttpHeaders();
public configuration = new Configuration();
constructor(protected apiRequest: SmApiRequestsService, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
if (basePath) {
this.basePath = basePath;
}
if (configuration) {
this.configuration = configuration;
this.basePath = basePath || configuration.basePath || this.basePath;
}
}
/**
* @param consumes string[] mime-types
* @return true: consumes contains 'multipart/form-data', false: otherwise
*/
private canConsumeForm(consumes: string[]): boolean {
const form = 'multipart/form-data';
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
}
/**
*
* Start a pipeline
* @param request request body
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public pipelinesStartPipeline(request: PipelinesStartPipelineRequest, options?: any, observe: any = 'body', reportProgress: boolean = false ): Observable<any> {
if (request === null || request === undefined) {
throw new Error('Required parameter request was null or undefined when calling pipelinesStartPipeline.');
}
let headers = this.defaultHeaders;
if (options && options.async_enable) {
headers = headers.set(this.configuration.asyncHeader, '1');
}
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected != undefined) {
headers = headers.set("Accept", httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = [
];
const httpContentTypeSelected:string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected != undefined) {
headers = headers.set("Content-Type", httpContentTypeSelected);
}
return this.apiRequest.post<PipelinesStartPipelineResponse>(`${this.basePath}/pipelines.start_pipeline`,
request,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}
}

View File

@@ -59,6 +59,10 @@ import { ProjectsValidateDeleteResponse } from '../model/projects/projectsValida
import { BASE_PATH, COLLECTION_FORMATS } from '../variables';
import { Configuration } from '../configuration';
import {ProjectsGetModelMetadataKeysResponse} from '~/business-logic/model/projects/projectsGetModelMetadataKeysResponse';
import {ProjectsGetModelMetadataKeysRequest} from '~/business-logic/model/projects/projectsGetModelMetadataKeysRequest';
import {ProjectsGetProjectTagsResponse} from '~/business-logic/model/projects/projectsGetProjectTagsResponse';
import {ProjectsGetProjectTagsRequest} from '~/business-logic/model/projects/projectsGetProjectTagsRequest';
@Injectable()
@@ -408,6 +412,53 @@ export class ApiProjectsService {
);
}
/**
*
* Get a list of all metadata keys used in models within the given project.
* @param request request body
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public projectsGetModelMetadataKeys(request: ProjectsGetModelMetadataKeysRequest, options?: any, observe: any = 'body', reportProgress: boolean = false ): Observable<any> {
if (request === null || request === undefined) {
throw new Error('Required parameter request was null or undefined when calling projectsGetModelMetadataKeys.');
}
let headers = this.defaultHeaders;
if (options && options.async_enable) {
headers = headers.set(this.configuration.asyncHeader, '1');
}
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected != undefined) {
headers = headers.set("Accept", httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = [
];
const httpContentTypeSelected:string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected != undefined) {
headers = headers.set("Content-Type", httpContentTypeSelected);
}
return this.apiRequest.post<ProjectsGetModelMetadataKeysResponse>(`${this.basePath}/projects.get_model_metadata_keys`,
request,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
*
* Get user and system tags used for the models under the specified projects
@@ -453,6 +504,51 @@ export class ApiProjectsService {
);
}
/**
*
* Get user and system tags used for the specified projects and their children
* @param request request body
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public projectsGetProjectTags(request: ProjectsGetProjectTagsRequest, options?: any, observe: any = 'body', reportProgress: boolean = false ): Observable<any> {
if (request === null || request === undefined) {
throw new Error('Required parameter request was null or undefined when calling projectsGetProjectTags.');
}
let headers = this.defaultHeaders;
if (options && options.async_enable) {
headers = headers.set(this.configuration.asyncHeader, '1');
}
// to determine the Accept header
const httpHeaderAccepts: string[] = [
'application/json'
];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected != undefined) {
headers = headers.set("Accept", httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = [
];
const httpContentTypeSelected:string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected != undefined) {
headers = headers.set("Content-Type", httpContentTypeSelected);
}
return this.apiRequest.post<ProjectsGetProjectTagsResponse>(`${this.basePath}/projects.get_project_tags`,
request,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
*
* Get unique parent tasks for the tasks in the specified projects

View File

@@ -15,6 +15,7 @@ import {ApiWorkersService} from './api-services/workers.service';
import {ApiServerService} from './api-services/server.service';
import {ApiOrganizationService} from './api-services/organization.service';
import {ApiLoginService} from './api-services/login.service';
import {ApiPipelinesService} from '~/business-logic/api-services/pipelines.service';
@NgModule({
imports : [CommonModule, HttpClientModule],
@@ -34,7 +35,8 @@ import {ApiLoginService} from './api-services/login.service';
ApiUsersService,
ApiServerService,
ApiOrganizationService,
ApiLoginService
ApiLoginService,
ApiPipelinesService
]
})
export class BusinessLogicModule {

View File

@@ -25,4 +25,5 @@ export interface CredentialKey {
*
*/
last_used_from?: string;
label?: string; // (nir) until BE will implement
}

View File

@@ -1,8 +1,10 @@
import {MetadataItem} from '../queues/metadataItem';
/**
* models
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* OpenAPI spec version: 2.14
* OpenAPI spec version: 2.12
*
*
* NOTE: This class is auto generated by the swagger code generator program.
@@ -34,7 +36,7 @@ export interface ModelsEditRequest {
*/
tags?: Array<string>;
/**
* System tags list. This field is reserved for system use, please don\'t use it.
* System tags list. This field is reserved for system use, please don't use it.
*/
system_tags?: Array<string>;
/**
@@ -44,7 +46,7 @@ export interface ModelsEditRequest {
/**
* Json[d] object representing the model design. Should be identical to the network design of the task which created the model
*/
design?: object;
design?: any;
/**
* Json object
*/
@@ -69,4 +71,5 @@ export interface ModelsEditRequest {
* Iteration (used to update task statistics)
*/
iteration?: number;
metadata?: object;
}

View File

@@ -0,0 +1,2 @@
export * from '././pipelinesStartPipelineRequest';
export * from '././pipelinesStartPipelineResponse';

View File

@@ -0,0 +1,28 @@
/**
* pipelines
* 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 PipelinesStartPipelineRequest {
/**
* ID of the task on which the pipeline will be based
*/
task: string;
/**
* Queue ID in which the created pipeline task will be enqueued
*/
queue?: string;
/**
* Task arguments, key/value to be placed in the hyperparameters Args section
*/
args?: object;
}

View File

@@ -0,0 +1,24 @@
/**
* pipelines
* 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 PipelinesStartPipelineResponse {
/**
* ID of the new pipeline task
*/
pipeline?: string;
/**
* True if the task was successfuly enqueued
*/
enqueued?: boolean;
}

View File

@@ -1,4 +1,5 @@
import {ProjectsGetAllResponseSingleSubProjects} from '~/business-logic/model/projects/projectsGetAllResponseSingleSubProjects';
import {Stats} from '~/business-logic/model/projects/stats';
/**
* projects
@@ -51,6 +52,7 @@ export interface Project {
* The default output destination URL for new tasks under this project
*/
default_output_destination?: string;
stats?: Stats;
/**
* Last project update time. Reflects the last time the project metadata was changed or a task in this project has changed status
*/

View File

@@ -0,0 +1,32 @@
/**
* projects
* 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 ProjectsGetModelMetadataKeysRequest {
/**
* Project ID
*/
project: string;
/**
* If set to \'true\' and the project field is set then the result includes metadate keys from the subproject models
*/
include_subprojects?: boolean;
/**
* Page number
*/
page?: number;
/**
* Page size
*/
page_size?: number;
}

View File

@@ -0,0 +1,28 @@
/**
* projects
* 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 ProjectsGetModelMetadataKeysResponse {
/**
* A list of model keys
*/
keys?: Array<string>;
/**
* Remaining results
*/
remaining?: number;
/**
* Total number of results
*/
total?: number;
}

View File

@@ -0,0 +1,26 @@
/**
* projects
* 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 { ProjectsGetProjectTagsRequestFilter } from '././projectsGetProjectTagsRequestFilter';
export interface ProjectsGetProjectTagsRequest {
/**
* If set to \'true\' then the list of the system tags is also returned. The default value is \'false\'
*/
include_system?: boolean;
/**
* The list of projects under which the tags are searched. If not passed or empty then all the projects are searched
*/
projects?: Array<string>;
filter?: ProjectsGetProjectTagsRequestFilter;
}

View File

@@ -0,0 +1,27 @@
/**
* projects
* 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.
*/
/**
* Filter on entities to collect tags from
*/
export interface ProjectsGetProjectTagsRequestFilter {
/**
* The list of tag values to filter by. Use \'null\' value to specify empty tags. Use \'__Snot\' value to specify that the following value should be excluded
*/
tags?: Array<string>;
/**
* The list of system tag values to filter by. Use \'null\' value to specify empty system tags. Use \'__Snot\' value to specify that the following value should be excluded
*/
system_tags?: Array<string>;
}

View File

@@ -0,0 +1,24 @@
/**
* projects
* 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 ProjectsGetProjectTagsResponse {
/**
* The list of unique tag values
*/
tags?: Array<string>;
/**
* The list of unique system tag values. Returned only if \'include_system\' is set to \'true\' in the request
*/
system_tags?: Array<string>;
}

View File

@@ -17,9 +17,19 @@ export interface StatsStatusCount {
/**
* Total run time of all tasks in project (in seconds)
*/
completed_tasks?: number;
running_tasks?: number;
total_tasks?: number;
total_runtime?: number;
/**
* Number of tasks
*/
total_tasks?: number;
/**
* Number of tasks completed in the last 24 hours
*/
completed_tasks_24h?: number;
/**
* The most recent started time of a task
*/
last_task_run?: number;
status_count?: StatsStatusCountStatusCount;
}

View File

@@ -2,7 +2,7 @@
* projects
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* OpenAPI spec version: 2.14
* OpenAPI spec version: 999.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
@@ -20,6 +20,10 @@ export interface StatsStatusCountStatusCount {
* Number of \'created\' tasks in project
*/
created?: number;
/**
* Number of \'completed\' tasks in project
*/
completed?: number;
/**
* Number of \'queued\' tasks in project
*/

View File

@@ -82,17 +82,13 @@ export const localStorageReducer = (reducer: ActionReducer<any>): ActionReducer<
const savedState = JSON.parse(localStorage.getItem(key));
nextState = merge(nextState, savedState);
}
if (state === nextState) {
return nextState;
}
if (actionsPrefix && !actionsPrefix.some(ap => action.type.startsWith(ap))) {
return nextState;
}
localStorage.setItem(key, JSON.stringify(pick(syncedKeys, nextState)));
return nextState;
};

View File

@@ -21,18 +21,16 @@ const _statsReducer = createReducer(initialState,
on(setUsageStats, (state: UsageStatState, newState) => ({...state, ...newState}))
);
export function usageStatsReducer(state = initialState, action: Action): UsageStatState {
return _statsReducer(state, action);
}
export const usageStatsReducer = (state = initialState, action: Action) => _statsReducer(state, action);
export const selectSendStats = state => state[userStatsFeatureKey];
export const selectSendStats = state => state.userStatsFeatureKey;
export const selectAllowed = createSelector(selectSendStats, (state: UsageStatState) => state.allowed);
export const selectCurrentVersion = createSelector(selectSendStats, (state: UsageStatState) => state.currVersion);
export const selectAllowedVersion = createSelector(selectSendStats, (state: UsageStatState) => state.allowedVersion);
export const selectAllowed = createSelector(selectSendStats, (state) => state?.allowed);
export const selectCurrentVersion = createSelector(selectSendStats, (state) => state?.currVersion);
export const selectAllowedVersion = createSelector(selectSendStats, (state) => state?.allowedVersion);
export const selectPromptUser = createSelector(
selectCurrentVersion,
selectAllowedVersion,
selectAllowed,
(currentVer: string, allowedVer: string, allowed: boolean) => !allowed && currentVer !== allowedVer
(currentVer, allowedVer, allowed) => !allowed && currentVer !== allowedVer
);

View File

@@ -3,7 +3,7 @@ import {createReducer, createSelector, on} from '@ngrx/store';
import {initUsers, users, usersReducerFunctions, UsersState} from '@common/core/reducers/users-reducer';
import {setCurrentUser} from '../actions/users.action';
export const selectHasDataFeature = createSelector(users, () => false);
export const selectHasDataFeature = createSelector(users, state => false);
export const selectHasUserManagement = createSelector(users, () => false);
export const usersReducer = createReducer<UsersState>(initUsers,
@@ -16,7 +16,7 @@ export const usersReducer = createReducer<UsersState>(initUsers,
}))
);
export const selectFeatures = createSelector(users, () => []);
export const selectFeatures = createSelector(users, (state) => []);
// eslint-disable-next-line @typescript-eslint/naming-convention
export const selectTermsOfUse = createSelector(users, () => ({accept_required: null}));
export const selectInvitesPending = createSelector(users, () => []);
export const selectTermsOfUse = createSelector(users, state => ({accept_required: null}));
export const selectInvitesPending = createSelector(users, state => []);

View File

@@ -20,7 +20,7 @@ const initViewState: ViewState = {
export const views = state => state.views as ViewState;
export const selectAvailableUpdates = createSelector(views, state => state.availableUpdates);
export const selectShowSurvey = createSelector(views, state => state.showSurvey);
export const selectUserSettingsNotificationPath = createSelector(views, () => '');
export const selectUserSettingsNotificationPath = createSelector(views, (state) => '');
export function viewReducer(viewState: ViewState = initViewState, action) {

View File

@@ -19,7 +19,7 @@ export class UsageStatsService {
if (!ConfigurationService.globalEnvironment.demo) {
this.store.select(selectPromptUser)
.pipe(filter(prompt => prompt))
.pipe(filter(prompt => !!prompt))
.subscribe(() => {
const dialogRef = this.dialog.open(ConfirmDialogComponent,
{

View File

@@ -8,6 +8,7 @@ export enum sourceTypesEnum {
}
export interface IExecutionForm {
artifacts?: any[];
source: {
repository: string;
tag?: string;

View File

@@ -1,5 +1,7 @@
import {TaskStatusEnum} from '../../../business-logic/model/tasks/taskStatusEnum';
import {ExperimentTableColFieldsEnum} from './experiments.model';
import {TaskTypeEnum} from '~/business-logic/model/tasks/taskTypeEnum';
import {Model} from '~/business-logic/model/models/model';
export type experimentSectionsEnum =
'MODEL_INPUT'
@@ -32,13 +34,15 @@ export const EXPERIMENTS_TABLE_COL_FIELDS = {
PROJECT : 'project.name' as ExperimentTableColFieldsEnum,
METRIC : 'project.name' as ExperimentTableColFieldsEnum,
HYPER_PARAM : 'project.name' as ExperimentTableColFieldsEnum,
PARENT : 'parent.name' as ExperimentTableColFieldsEnum
PARENT : 'parent.name' as ExperimentTableColFieldsEnum,
VERSION : 'hyperparams.properties.version' as ExperimentTableColFieldsEnum
};
export enum ExperimentTagsEnum {
Development = 'development',
Hidden = 'archived',
Shared = 'shared'
Shared = 'shared',
Pipeline = 'pipeline'
}
export const EXPERIMENTS_TAGS = {
@@ -56,3 +60,5 @@ export const EXPERIMENTS_STATUS_LABELS = {
};
export const DevWarningEnabled = false;
export const excludeTypes = [];

View File

@@ -6,7 +6,6 @@ import { CommonModule } from '@angular/common';
import { LoginRoutingModule } from './login-routing.module';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import {NgxFilesizeModule} from 'ngx-filesize';
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {SignupComponent} from './signup/signup.component';
@@ -14,8 +13,8 @@ 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 '../../webapp-common/login/login/login.component';
import {SharedPipesModule} from '../../webapp-common/shared/pipes/shared-pipes.module';
import {LoginComponent} from '@common/login/login/login.component';
import {SharedPipesModule} from '@common/shared/pipes/shared-pipes.module';
@NgModule({
declarations: [LoginComponent, SignupComponent],
@@ -26,7 +25,6 @@ import {SharedPipesModule} from '../../webapp-common/shared/pipes/shared-pipes.m
FormsModule,
MatAutocompleteModule,
HttpClientModule,
NgxFilesizeModule,
MatProgressSpinnerModule,
MatCheckboxModule,
MatFormFieldModule,

View File

@@ -8,10 +8,19 @@
[class.hide-item]="sharedView"
activeFeature="models" [archivedMode]="isArchived"></sm-project-context-navbar>
<div class="d-flex justify-content-end align-items-center right-buttons">
<sm-clear-filters-button
[tableFilters]="tableFilters"
(clearTableFilters)="clearTableFilters.emit(tableFilters)"
></sm-clear-filters-button>
<sm-model-custom-cols-menu
[hidden]="minimizedView || sharedView"
[disabled]="minimizedView || sharedView"
[isLoading]="isLoadingMetadataKeys"
[metadataKeys]="metadataKeys"
[tableCols]="tableCols"
(removeColFromList)="removeColFromList.emit($event)"
(selectedTableColsChanged)="selectedTableColsChanged.emit($event)"
(selectMetadataKeysActiveChanged)="selectMetadataKeysActiveChanged.emit($event)"
(addOrRemoveMetadataKeyFromColumns)="addOrRemoveMetadataKeyFromColumns.emit($event)"
></sm-model-custom-cols-menu>
<sm-refresh-button
[autoRefreshState]="autoRefreshState"

View File

@@ -1,10 +1,11 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {FilterMetadata} from "primeng/api/filtermetadata";
import {FilterMetadata} from 'primeng/api/filtermetadata';
import {ISmCol} from '@common/shared/ui-components/data/table/table.consts';
@Component({
selector : 'sm-model-header',
selector: 'sm-model-header',
templateUrl: './model-header.component.html',
styleUrls : ['./model-header.component.scss']
styleUrls: ['./model-header.component.scss']
})
export class ModelHeaderComponent {
private _tableCols: any;
@@ -17,21 +18,26 @@ export class ModelHeaderComponent {
get tableCols() {
return this._tableCols;
}
@Input() isArchived: boolean;
@Input() hideArchiveToggle: boolean;
@Input() hideCreateNewButton: boolean;
@Input() disableCreateNewButton: boolean;
@Input() autoRefreshState: boolean;
@Input() metadataKeys: string[];
@Input() isLoadingMetadataKeys: any;
@Input() sharedView: boolean;
@Input() tableFilters: { [s: string]: FilterMetadata };
@Output() isArchivedChanged = new EventEmitter<boolean>();
@Output() isArchivedChanged = new EventEmitter<boolean>();
@Output() addModelClicked = new EventEmitter();
@Output() refreshListClicked = new EventEmitter();
@Output() setAutoRefresh = new EventEmitter();
@Output() refreshListClicked = new EventEmitter();
@Output() setAutoRefresh = new EventEmitter();
@Output() selectedTableColsChanged = new EventEmitter();
@Output() clearTableFilters = new EventEmitter<{ [s: string]: FilterMetadata }>();
@Output() clearTableFilters = new EventEmitter<{ [s: string]: FilterMetadata }>();
@Output() selectMetadataKeysActiveChanged = new EventEmitter();
@Output() addOrRemoveMetadataKeyFromColumns = new EventEmitter<{ key: string; show: boolean }>();
@Output() removeColFromList = new EventEmitter<ISmCol['id']>();
archivedChanged(value: boolean) {

View File

@@ -37,4 +37,4 @@ export const projectsReducer = (state: IProjectsState = projectsInitState, actio
export const projects = state => state.projects as IProjectsState;
export const selectShowHidden = createSelector(projects, () => false);
export const selectShowHidden = createSelector(projects, (state) => false);

View File

@@ -1,3 +1,6 @@
<sm-dialog-template>
<sm-admin-dialog-template [newCredential]="data.credentials"></sm-admin-dialog-template>
<sm-admin-dialog-template
[newCredential]="(newCredential$ | async) || {}"
(onCreateCredentials)="onCreateCredentials($event)"
></sm-admin-dialog-template>
</sm-dialog-template>

View File

@@ -1,16 +1,27 @@
import {Component, Inject, OnInit} from '@angular/core';
import {Component, Inject} from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import {Store} from '@ngrx/store';
import {createCredential} from '@common/core/actions/common-auth.actions';
import {OrganizationGetUserCompaniesResponseCompanies} from '~/business-logic/model/organization/organizationGetUserCompaniesResponseCompanies';
import {Observable} from 'rxjs';
import {CredentialKeyExt, selectNewCredential} from '@common/core/reducers/common-auth-reducer';
@Component({
selector: 'sm-create-credential-dialog',
templateUrl: './create-credential-dialog.component.html',
styleUrls: ['./create-credential-dialog.component.scss']
})
export class CreateCredentialDialogComponent implements OnInit {
export class CreateCredentialDialogComponent {
public newCredential$: Observable<CredentialKeyExt>;
constructor(@Inject(MAT_DIALOG_DATA) public data: {credentials: any; workspace?: string}) {}
ngOnInit() {
constructor(
@Inject(MAT_DIALOG_DATA) public data: {credentials: any; workspace?: OrganizationGetUserCompaniesResponseCompanies},
private store: Store
) {
this.newCredential$ = this.store.select(selectNewCredential);
}
onCreateCredentials({label}) {
this.store.dispatch(createCredential({workspace: this.data.workspace, label}));
}
}

View File

@@ -3,10 +3,11 @@ import {Observable, Subscription} from 'rxjs';
import {CredentialKeyExt, selectCredentials, selectNewCredential} from '@common/core/reducers/common-auth-reducer';
import {selectCurrentUser} from '@common/core/reducers/users-reducer';
import {filter, take} from 'rxjs/operators';
import {credentialRevoked, getAllCredentials} from '@common/core/actions/common-auth.actions';
import {credentialRevoked, getAllCredentials, resetCredential} from '@common/core/actions/common-auth.actions';
import {Store} from '@ngrx/store';
import { createCredential } from '@common/core/actions/common-auth.actions';
import {GetCurrentUserResponseUserObject} from '~/business-logic/model/users/getCurrentUserResponseUserObject';
import {MatDialog} from '@angular/material/dialog';
import {CreateCredentialDialogComponent} from '~/features/settings/containers/admin/create-credential-dialog/create-credential-dialog.component';
@Component({
selector: 'sm-user-credentials',
@@ -19,7 +20,7 @@ export class UserCredentialsComponent implements OnInit, OnDestroy {
private newCredentialSub: Subscription;
creatingCredentials = false;
private user: GetCurrentUserResponseUserObject;
constructor(private store: Store) { }
constructor(private store: Store, private dialog: MatDialog) { }
ngOnInit(): void {
this.store.select(selectCurrentUser)
@@ -38,7 +39,15 @@ export class UserCredentialsComponent implements OnInit, OnDestroy {
createCredential() {
this.creatingCredentials = true;
this.store.dispatch(createCredential({workspace: this.user.company, openCredentialsPopup: true}));
this.dialog.open(CreateCredentialDialogComponent, {
data: {workspace : this.user.company},
width: '816px'
}
).afterClosed().subscribe(() => {
this.creatingCredentials = false;
this.store.dispatch(resetCredential());
});
// this.store.dispatch(createCredential({workspace: this.user.company, openCredentialsPopup: true}));
}
onCredentialRevoked(accessKey) {

View File

@@ -4,7 +4,7 @@ import { SettingsRoutingModule } from './settings-routing.module';
import { SettingsComponent } from '../settings/settings.component';
import {SMMaterialModule} from '../../webapp-common/shared/material/material.module';
import {SMSharedModule} from '@common/shared/shared.module';
import {ReactiveFormsModule} from '@angular/forms';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {SharedModule} from '~/shared/shared.module';
import {MatExpansionModule} from '@angular/material/expansion';
import {WebappConfigurationComponent} from '@common/settings/webapp-configuration/webapp-configuration.component';
@@ -47,7 +47,10 @@ import {CreateCredentialDialogComponent} from '~/features/settings/containers/ad
SettingsRoutingModule,
SMMaterialModule,
SMSharedModule,
ReactiveFormsModule, SharedModule, MatExpansionModule,
ReactiveFormsModule,
SharedModule,
MatExpansionModule,
FormsModule,
],
exports: [
UserCredentialsComponent,

View File

@@ -21,12 +21,14 @@ export const selectBreadcrumbsStringsBase = createSelector(
(project, experiment, model, projects) =>
({project, experiment, model, projects}) as IBreadcrumbs);
export const prepareNames = (data: IBreadcrumbs) => {
const project = prepareLinkData(data.project, true);
export function prepareNames(data: IBreadcrumbs, noSubProjects?: boolean) {
const project = prepareLinkData(data.project, true);
if (data.project) {
const subProjects = [];
const subProjectsNames = data.project?.name?.split('/');
let subProjectsNames = [data.project?.name];
if (!noSubProjects) {
subProjectsNames = data.project?.name?.split('/');
}
let currentName = '';
subProjectsNames.forEach(name => {
currentName += currentName ? ('/' + name) : name;
@@ -37,11 +39,11 @@ export const prepareNames = (data: IBreadcrumbs) => {
].find(proj => currentName === proj.name);
subProjects.push(foundProject);
});
const subProjectsLinks = subProjects.map(subProject => ({
name: subProject?.name.substring(subProject?.name.lastIndexOf('/') + 1),
url: `projects/${subProject?.id}/projects`
const subProjectsLinks = subProjects.map(proj => ({
name: proj?.name.substring(proj?.name.lastIndexOf('/') + 1),
url: (noSubProjects || (proj?.name === data.project?.name && data.project?.sub_projects?.length===0)) ? '' : `projects/${proj?.id}/projects`
})) as { name: string; url: string }[];
project.name = project.name.substring(project.name.lastIndexOf('/') + 1);
project.name = project?.name.substring(project.name.lastIndexOf('/') + 1);
project.subCrumbs = subProjectsLinks;
}
const task = prepareLinkData(data.task);

View File

@@ -12,27 +12,39 @@
<ng-container *ngIf="currentUser">
<a class="item d-block" #rlaHome="routerLinkActive" routerLink="/dashboard" routerLinkActive (click)="resetSearch()"
smTooltip="DASHBOARD" showDelay="0" matTooltipPosition="right">
smTooltip="DASHBOARD" [matTooltipShowDelay]="0" matTooltipPosition="right">
<div class="item-icon">
<i [class]="'al-icon al-ico-home al-color ' + (rlaHome.isActive ? 'neon-yellow': 'blue-300')" ></i>
</div>
<div class="caption">dashboard</div>
</a>
<a class="item d-block" smTooltip="PROJECTS" showDelay="0" matTooltipPosition="right" routerLink="/projects"
<a class="item d-block" smTooltip="PROJECTS" [matTooltipShowDelay]="0" matTooltipPosition="right" routerLink="/projects"
[routerLinkActive] #rlaProjects="routerLinkActive">
<div class="item-icon">
<i [class]="'al-icon al-ico-projects al-color ' + (rlaProjects.isActive ? 'neon-yellow': 'blue-300')" ></i>
</div>
<div class="caption">projects</div>
</a>
<a class="item d-block"
routerLink="/pipelines"
routerLinkActive
#rlaDatasets="routerLinkActive"
smTooltip="PIPELINES"
[matTooltipShowDelay]="0"
matTooltipPosition="right">
<div class="item-icon">
<i [class]="'al-icon al-ico-pipelines al-color ' + (rlaDatasets.isActive ? 'neon-yellow': 'blue-300')"></i>
</div>
<div class="caption">pipelines</div>
</a>
<a class="item d-block"
*smCheckPermission="true"
routerLink="/workers-and-queues"
routerLinkActive
#rlaQueues="routerLinkActive"
smTooltip="WORKERS & QUEUES"
showDelay="0"
[matTooltipShowDelay]="0"
matTooltipPosition="right">
<div class="item-icon">
<i [class]="'al-icon al-ico-queues al-color ' + (rlaQueues.isActive ? 'neon-yellow': 'blue-300')" ></i>
@@ -43,7 +55,9 @@
</ng-container>
<div *ngIf="currentUser" class="account">
<a *ngIf="environment.whiteLabelLink" class="item d-block" target="_blank"
[smTooltip]="environment.whiteLabelLink.tooltip" showDelay="0" matTooltipPosition="right"
[smTooltip]="environment.whiteLabelLink.tooltip"
[matTooltipShowDelay]="0"
matTooltipPosition="right"
[href]="environment.whiteLabelLink.link">
<div class="item-icon"
[style.background-image]="'url(' + environment.whiteLabelLink.logo + ')'"
@@ -53,7 +67,9 @@
<div class="caption">Ignite</div>
</a>
<a class="item d-block" href="https://github.com/allegroai/clearml" target="_blank"
smTooltip="GitHub Repository" showDelay="0" matTooltipPosition="right">
smTooltip="GitHub Repository"
[matTooltipShowDelay]="0"
matTooltipPosition="right">
<div class="item-icon">
<i class="fab fa-github fa-24 al-color blue-300"></i>
</div>

View File

@@ -1,16 +1,18 @@
import {TaskStatusEnum} from '../../business-logic/model/tasks/taskStatusEnum';
import {TaskTypeEnum} from '../../business-logic/model/tasks/taskTypeEnum';
import {TaskStatusEnum} from '~/business-logic/model/tasks/taskStatusEnum';
import {TaskTypeEnum} from '~/business-logic/model/tasks/taskTypeEnum';
export enum EntityTypeEnum {
experiment = 'experiment',
model = 'model',
project = 'project',
controller = 'pipeline run'
}
export enum CircleTypeEnum {
completed = 'completed',
running = 'running',
pending = 'pending',
failed = 'failed',
empty = 'empty',
'model-labels' = 'model-labels'
}

View File

@@ -2,7 +2,7 @@
@font-face {
font-family: '#{$icomoon-font-family}';
src: url('./#{$icomoon-font-family}.ttf?mmpkhb') format('truetype');
src: url('./#{$icomoon-font-family}.ttf?dn2wcr') format('truetype');
font-weight: normal;
font-style: normal;
font-display: block;
@@ -1086,41 +1086,96 @@
content: $al-ico-no-code;
}
}
.al-ico-automation {
&:before {
content: $al-ico-automation;
}
}
.al-ico-calendar-checked {
&:before {
content: $al-ico-calendar-checked;
}
}
.al-ico-no-source {
&:before {
content: $al-ico-no-source;
}
}
.al-ico-arrow-up {
&:before {
content: $al-ico-arrow-up;
}
}
.al-ico-arrow-down {
&:before {
content: $al-ico-arrow-down;
}
}
.al-ico-error-circle {
&:before {
content: $al-ico-error-circle;
}
}
.al-ico-pipelines {
&:before {
content: $al-ico-pipelines;
}
}
.al-ico-console {
&:before {
content: $al-ico-console;
}
}
.al-ico-link-arrow {
&:before {
content: $al-ico-link-arrow;
}
}
.al-ico-broken-file {
&:before {
content: $al-ico-broken-file;
}
}
.al-ico-run {
&:before {
content: $al-ico-run;
}
}
.al-ico-status-draft {
&:before {
content: $al-ico-status-draft;
}
}
.al-ico-status-published {
&:before {
content: $al-ico-status-published;
}
}
.al-ico-status-aborted-sec {
&:before {
content: $al-ico-status-aborted-sec;
}
}
.al-ico-status-pending {
&:before {
content: $al-ico-status-pending;
}
}
.al-ico-status-skiped {
&:before {
content: $al-ico-status-skiped;
}
}
.al-ico-status-cached {
&:before {
content: $al-ico-status-cached;
}
}
.al-ico-status-executed {
&:before {
content: $al-ico-status-executed;
}
}
.al-ico-status-running {
&:before {
content: $al-ico-status-running;
}
}
.al-ico-status-completed {
&:before {
content: $al-ico-status-completed;
}
}
.al-ico-status-published {
&:before {
content: $al-ico-status-published;
}
}
.al-ico-status-failed {
&:before {
content: $al-ico-status-failed;
@@ -1131,9 +1186,14 @@
content: $al-ico-status-aborted;
}
}
.al-ico-status-aborted-sec {
.al-ico-status-completed {
&:before {
content: $al-ico-status-aborted-sec;
content: $al-ico-status-completed;
}
}
.al-ico-status-queued {
&:before {
content: $al-ico-enqueue;
}
}

View File

@@ -209,14 +209,25 @@ $al-ico-youtube: "\e9a8";
$al-ico-lock: "\e9a9";
$al-ico-lock-open: "\e9aa";
$al-ico-no-code: "\e9ab";
$al-ico-automation: "\e9ac";
$al-ico-calendar-checked: "\e9ad";
$al-ico-no-source: "\e9ae";
$al-ico-arrow-up: "\e9b1";
$al-ico-arrow-down: "\e9b2";
$al-ico-error-circle: "\e9b4";
$al-ico-pipelines: "\e9b5";
$al-ico-console: "\e9bc";
$al-ico-link-arrow: "\e9bf";
$al-ico-broken-file: "\e9c0";
$al-ico-run: "\e9c1";
$al-ico-status-draft: "\e902";
$al-ico-status-pending: "\e903";
$al-ico-status-running: "\e904";
$al-ico-status-completed: "\e905";
$al-ico-status-published: "\e906";
$al-ico-status-aborted-sec: "\e918";
$al-ico-status-pending: "\e903";
$al-ico-status-skiped: "\e9bd";
$al-ico-status-cached: "\e9be";
$al-ico-status-executed: "\e9ac";
$al-ico-status-running: "\e904";
$al-ico-status-failed: "\e907";
$al-ico-status-aborted: "\e917";
$al-ico-status-aborted-sec: "\e918";
$al-ico-status-completed: "\e905";

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 816 B

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 400 400">
<path d="M206 141.49h-18a4 4 0 0 0-4 4v32a4 4 0 0 0 4 4h24a4 4 0 0 0 4-4v-26Zm0 5.63 4.37 4.37H206Zm6 30.37h-24v-32h14v6a4 4 0 0 0 4 4h6Zm-6.34-12.83-2.83 2.83 2.83 2.83a2 2 0 0 1-2.83 2.83l-2.83-2.83-2.83 2.83a2 2 0 0 1-2.83-2.83l2.83-2.83-2.83-2.83a2 2 0 1 1 2.78-2.88v.05l2.83 2.83 2.83-2.83a2 2 0 0 1 2.88 2.78s0 0-.05 0" fill="#5a658e"/>
<text transform="translate(32 208)" font-size="16" fill="#5a658e" font-family="'Heebo', sans-serif" font-weight="500">This source is not specified in this Framegroup</text>
<text transform="translate(127 240)" font-size="12" fill="#5a658e" font-family="'Heebo', sans-serif">Changes cannot be applied</text>
<text transform="translate(36 258)" font-size="12" fill="#5a658e" font-family="'Heebo', sans-serif">Choose an available source or go back to the version browser</text>
</svg>

After

Width:  |  Height:  |  Size: 913 B

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 242.15">
<title>no-code dark</title>
<path fill="#39405f"
d="M20.82,242.15H279.18A20.84,20.84,0,0,0,300,221.33V20.82A20.84,20.84,0,0,0,279.18,0H20.82A20.84,20.84,0,0,0,0,20.82V221.33A20.84,20.84,0,0,0,20.82,242.15Zm258.36-10.72H20.82a10.2,10.2,0,0,1-10.11-10.1V68.88H289.29V221.63a9.93,9.93,0,0,1-10.06,9.8h-.05ZM20.82,11H279.18a10.2,10.2,0,0,1,10.11,10.1V58.18H10.71V20.82a9.93,9.93,0,0,1,10-9.82Zm9.79,27.24a5.67,5.67,0,0,1-1.53-3.68,5.65,5.65,0,0,1,1.53-3.67,6,6,0,0,1,7.66,0,5.65,5.65,0,0,1,1.53,3.67,5.22,5.22,0,0,1-5.21,5.21,6.42,6.42,0,0,1-4-1.5Zm28.77,0a5.67,5.67,0,0,1-1.53-3.68,5.65,5.65,0,0,1,1.53-3.67,6,6,0,0,1,7.66,0,5.65,5.65,0,0,1,1.53,3.67,5.22,5.22,0,0,1-5.2,5.21,7.28,7.28,0,0,1-4-1.5Zm29.08,0a5.67,5.67,0,0,1-1.53-3.68,5.65,5.65,0,0,1,1.53-3.67c1.85-1.84,5.52-1.84,7.66,0a5.65,5.65,0,0,1,1.53,3.67,5.22,5.22,0,0,1-5.2,5.21,6.59,6.59,0,0,1-4-1.5ZM208.87,146.8l-8.33,8.34-18.75,18.75-8.33-8.34,18.73-18.75L173.45,128l8.34-8.33,18.75,18.75Zm-90.68-27.08L99.45,138.47l-8.33,8.33,8.33,8.34,18.74,18.75,8.33-8.34L107.79,146.8,126.54,128Zm16.5,69,11.5,2.51,19.05-86.32-11.52-2.54Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,94 @@
<svg xmlns="http://www.w3.org/2000/svg" width="487" height="434" viewBox="0 0 487 434">
<g style="opacity:.996">
<path data-name="connector" d="M-72.842-2.432h31.272c12.026 0 16.185 7.754 16.185 15.728V43.33" transform="translate(444.116 27.577)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
<path d="m936.044 346.708 3.429 3.429 3.429-3.429" transform="translate(-520.743 -279.229)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
<g data-name="connector">
<path data-name="connector" d="M-72.842-2.432h31.272c12.026 0 16.185 7.754 16.185 15.728V43.33" transform="translate(328.76 181.343)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
<path data-name="connector-head" d="m936.044 346.708 3.429 3.429 3.429-3.429" transform="translate(-636.099 -125.463)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
</g>
<g data-name="connector">
<path data-name="connector" d="M-25.386-2.432h-31.271c-12.026 0-16.184 7.754-16.184 15.728V43.33" transform="translate(259.337 27.577)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
<path data-name="connector-head" d="m942.9 346.708-3.429 3.429-3.429-3.429" transform="translate(-752.978 -279.229)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
</g>
<g data-name="connector">
<path data-name="connector" d="M-25.386-2.432h-31.271c-12.026 0-16.184 7.754-16.184 15.728V43.33" transform="translate(141.266 181.343)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
<path data-name="connector-head" d="m942.9 346.708-3.429 3.429-3.429-3.429" transform="translate(-871.049 -125.463)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
</g>
<g data-name="connector">
<path data-name="connector" transform="translate(185.899 127.427)" style="fill:none;stroke:#5a658e;stroke-width:2px" d="M0 0v21.527"/>
<path data-name="connector-head" d="m936.044 346.708 3.429 3.429 3.429-3.429" transform="translate(-753.574 -200.856)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
</g>
<g data-name="connector">
<path data-name="connector" transform="translate(303.596 279.194)" style="fill:none;stroke:#5a658e;stroke-width:2px" d="M0 0v24.386"/>
<path data-name="connector-head" d="m936.044 346.708 3.429 3.429 3.429-3.429" transform="translate(-635.877 -46.23)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
</g>
<g data-name="connector">
<path data-name="connector" transform="translate(303.596 356.194)" style="fill:none;stroke:#5a658e;stroke-width:2px" d="M0 0v24.386"/>
<path data-name="connector-head" d="m936.044 346.708 3.429 3.429 3.429-3.429" transform="translate(-635.877 30.77)" style="fill:none;stroke:#5a658e;stroke-width:2px"/>
</g>
<g transform="translate(231.301 -3)">
<path data-name="step" d="M4 0h129a4 4 0 0 1 4 4v29H0V4a4 4 0 0 1 4-4z" transform="translate(2.699 3)" style="fill:rgba(0,154,255,.2)"/>
<path d="M0 0h137v13a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V0z" transform="translate(2.699 36)" style="fill:#009aff"/>
<rect width="26" height="4" rx="2" transform="translate(105.699 43)" style="fill:#153856"/>
<path d="M7.72 12.3a4.576 4.576 0 1 1 4.58-4.58 4.581 4.581 0 0 1-4.58 4.58m0 1.144A5.72 5.72 0 1 0 2 7.72a5.72 5.72 0 0 0 5.72 5.72m2.344-7.96-3.48 3.48-1.2-1.2-.809.809 2 2 4.289-4.289z" transform="translate(9.843 36.144)" style="fill:#153856"/>
<rect width="55" height="4" rx="2" transform="translate(34.699 17)" style="fill:#009aff"/>
<circle cx="8" cy="8" r="8" transform="translate(10.699 11)" style="fill:#0099fe"/>
</g>
<g data-name="step" transform="translate(347.301 71)">
<path data-name="step" d="M4 0h129a4 4 0 0 1 4 4v29H0V4a4 4 0 0 1 4-4z" transform="translate(2.699 3)" style="fill:rgba(0,154,255,.2)"/>
<path data-name="step-status" d="M0 0h137v13a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V0z" transform="translate(2.699 36)" style="fill:#009aff"/>
<rect data-name="time" width="26" height="4" rx="2" transform="translate(105.699 43)" style="fill:#153856"/>
<path data-name="ico-status-completed" d="M7.72 12.3a4.576 4.576 0 1 1 4.58-4.58 4.581 4.581 0 0 1-4.58 4.58m0 1.144A5.72 5.72 0 1 0 2 7.72a5.72 5.72 0 0 0 5.72 5.72m2.344-7.96-3.48 3.48-1.2-1.2-.809.809 2 2 4.289-4.289z" transform="translate(9.843 36.144)" style="fill:#153856"/>
<rect data-name="title" width="55" height="4" rx="2" transform="translate(34.699 17)" style="fill:#009aff"/>
<circle data-name="ico-object-type" cx="8" cy="8" r="8" transform="translate(10.699 11)" style="fill:#0099fe"/>
</g>
<g data-name="step" transform="translate(115.301 71)">
<path data-name="step" d="M4 0h129a4 4 0 0 1 4 4v29H0V4a4 4 0 0 1 4-4z" transform="translate(2.699 3)" style="fill:rgba(0,154,255,.2)"/>
<path data-name="step-status" d="M0 0h137v13a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V0z" transform="translate(2.699 36)" style="fill:#009aff"/>
<rect data-name="time" width="26" height="4" rx="2" transform="translate(105.699 43)" style="fill:#153856"/>
<path data-name="ico-status-completed" d="M7.72 12.3a4.576 4.576 0 1 1 4.58-4.58 4.581 4.581 0 0 1-4.58 4.58m0 1.144A5.72 5.72 0 1 0 2 7.72a5.72 5.72 0 0 0 5.72 5.72m2.344-7.96-3.48 3.48-1.2-1.2-.809.809 2 2 4.289-4.289z" transform="translate(9.843 36.144)" style="fill:#153856"/>
<rect data-name="title" width="55" height="4" rx="2" transform="translate(34.699 17)" style="fill:#009aff"/>
<circle data-name="ico-object-type" cx="8" cy="8" r="8" transform="translate(10.699 11)" style="fill:#0099fe"/>
</g>
<g data-name="step" transform="translate(115.301 150)">
<path data-name="step" d="M4 0h129a4 4 0 0 1 4 4v29H0V4a4 4 0 0 1 4-4z" transform="translate(2.699 3)" style="fill:rgba(0,154,255,.2)"/>
<path data-name="step-status" d="M0 0h137v13a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V0z" transform="translate(2.699 36)" style="fill:#009aff"/>
<rect data-name="time" width="26" height="4" rx="2" transform="translate(105.699 43)" style="fill:#153856"/>
<path data-name="ico-status-completed" d="M7.72 12.3a4.576 4.576 0 1 1 4.58-4.58 4.581 4.581 0 0 1-4.58 4.58m0 1.144A5.72 5.72 0 1 0 2 7.72a5.72 5.72 0 0 0 5.72 5.72m2.344-7.96-3.48 3.48-1.2-1.2-.809.809 2 2 4.289-4.289z" transform="translate(9.843 36.144)" style="fill:#153856"/>
<rect data-name="title" width="55" height="4" rx="2" transform="translate(34.699 17)" style="fill:#009aff"/>
<circle data-name="ico-object-type" cx="8" cy="8" r="8" transform="translate(10.699 11)" style="fill:#0099fe"/>
</g>
<g data-name="step" transform="translate(231.301 225)">
<path data-name="step" d="M4 0h129a4 4 0 0 1 4 4v29H0V4a4 4 0 0 1 4-4z" transform="translate(2.699 3)" style="fill:rgba(0,154,255,.2)"/>
<path data-name="step-status" d="M0 0h137v13a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V0z" transform="translate(2.699 36)" style="fill:#009aff"/>
<rect data-name="time" width="26" height="4" rx="2" transform="translate(105.699 43)" style="fill:#153856"/>
<path data-name="ico-status-completed" d="M7.72 12.3a4.576 4.576 0 1 1 4.58-4.58 4.581 4.581 0 0 1-4.58 4.58m0 1.144A5.72 5.72 0 1 0 2 7.72a5.72 5.72 0 0 0 5.72 5.72m2.344-7.96-3.48 3.48-1.2-1.2-.809.809 2 2 4.289-4.289z" transform="translate(9.843 36.144)" style="fill:#153856"/>
<rect data-name="title" width="55" height="4" rx="2" transform="translate(34.699 17)" style="fill:#009aff"/>
<circle data-name="ico-object-type" cx="8" cy="8" r="8" transform="translate(10.699 11)" style="fill:#0099fe"/>
</g>
<g data-name="step" transform="translate(231.301 303)">
<path data-name="step" d="M4 0h129a4 4 0 0 1 4 4v29H0V4a4 4 0 0 1 4-4z" transform="translate(2.699 3)" style="fill:rgba(0,154,255,.2)"/>
<path data-name="step-status" d="M0 0h137v13a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V0z" transform="translate(2.699 36)" style="fill:#009aff"/>
<rect data-name="time" width="26" height="4" rx="2" transform="translate(105.699 43)" style="fill:#153856"/>
<path data-name="ico-status-completed" d="M7.72 12.3a4.576 4.576 0 1 1 4.58-4.58 4.581 4.581 0 0 1-4.58 4.58m0 1.144A5.72 5.72 0 1 0 2 7.72a5.72 5.72 0 0 0 5.72 5.72m2.344-7.96-3.48 3.48-1.2-1.2-.809.809 2 2 4.289-4.289z" transform="translate(9.843 36.144)" style="fill:#153856"/>
<rect data-name="title" width="55" height="4" rx="2" transform="translate(34.699 17)" style="fill:#009aff"/>
<circle data-name="ico-object-type" cx="8" cy="8" r="8" transform="translate(10.699 11)" style="fill:#0099fe"/>
</g>
<g data-name="step" transform="translate(231.301 381)">
<path data-name="step" d="M4 0h129a4 4 0 0 1 4 4v29H0V4a4 4 0 0 1 4-4z" transform="translate(2.699 3)" style="fill:rgba(20,170,140,.2)"/>
<path data-name="step-status" d="M0 0h137v13a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V0z" transform="translate(2.699 36)" style="fill:#14a98b"/>
<rect data-name="time" width="26" height="4" rx="2" transform="translate(105.699 43)" style="fill:#193a3e"/>
<path d="M7.72 12.3a4.576 4.576 0 1 1 4.58-4.58 4.582 4.582 0 0 1-4.58 4.58m0 1.144A5.72 5.72 0 1 0 2 7.72a5.72 5.72 0 0 0 5.72 5.72m-.153-8.384 2.26 2.26a.572.572 0 0 1 0 .809l-2.26 2.26a.572.572 0 0 1-.976-.4V5.461a.572.572 0 0 1 .976-.4" transform="translate(9.843 36.144)" style="fill:#193b3f"/>
<rect data-name="title" width="55" height="4" rx="2" transform="translate(34.699 17)" style="fill:#14a98b"/>
<circle data-name="ico-object-type" cx="8" cy="8" r="8" transform="translate(10.699 11)" style="fill:#14a88a"/>
</g>
<g data-name="step" transform="translate(-2.699 225)">
<path data-name="step" d="M4 0h129a4 4 0 0 1 4 4v29H0V4a4 4 0 0 1 4-4z" transform="translate(2.699 3)" style="fill:rgba(158,84,204,.2)"/>
<path data-name="step-status" d="M0 0h137v13a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V0z" transform="translate(2.699 36)" style="fill:#9e54cc"/>
<rect data-name="time" width="26" height="4" rx="2" transform="translate(105.699 43)" style="fill:#34294c"/>
<path d="M7.72 12.3a4.576 4.576 0 1 1 4.58-4.58 4.582 4.582 0 0 1-4.58 4.58m0 1.144A5.72 5.72 0 1 0 2 7.72a5.72 5.72 0 0 0 5.72 5.72m2.86-8.009H4.86v1.145h5.72zm0 1.716H4.86v1.146h5.72zm0 1.716H4.86v1.144h5.72z" transform="translate(9.843 36.144)" style="fill:#352a4c"/>
<rect data-name="title" width="55" height="4" rx="2" transform="translate(34.699 17)" style="fill:#9b51c9"/>
<circle data-name="ico-object-type" cx="8" cy="8" r="8" transform="translate(10.699 11)" style="fill:#9c52ca"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,8 +5,8 @@
[placeholder]="searchPlaceholder$ | async"
[hideIcons]="true"
[minimumChars]="minChars"
(valueChanged)="onSearchValueChanged($event)"
(focusout)="onSearchFocusOut()"
(valueChanged)="onSearchValueChanged($event)"
>
<i
class="regexp al-ico-regex pointer"

View File

@@ -1,5 +1,5 @@
import {Component, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute, Router, NavigationEnd} from '@angular/router';
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute, NavigationEnd, Router} from '@angular/router';
import {Store} from '@ngrx/store';
import {SetIsSearching, setSearchQuery} from '../../common-search.actions';
import {ICommonSearchState, selectIsSearching, selectPlaceholder, selectSearchQuery} from '../../common-search.reducer';
@@ -10,7 +10,8 @@ import {SearchComponent} from '../../../shared/ui-components/inputs/search/searc
@Component({
selector : 'sm-common-search',
templateUrl: './common-search.component.html',
styleUrls : ['./common-search.component.scss']
styleUrls : ['./common-search.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CommonSearchComponent implements OnInit {
public searchQuery$: Observable<ICommonSearchState['searchQuery']>;
@@ -26,7 +27,7 @@ export class CommonSearchComponent implements OnInit {
private queryString: string;
minChars = 3;
constructor(private store: Store<any>, private router: Router, private route: ActivatedRoute) {}
constructor(private store: Store<any>, private router: Router, private route: ActivatedRoute, private cdr: ChangeDetectorRef) {}
ngOnInit() {
this.searchQuery$ = this.store.select(selectSearchQuery).pipe(tap(searchQuery => this.regExp = searchQuery?.regExp));
@@ -39,9 +40,10 @@ export class CommonSearchComponent implements OnInit {
setTimeout(this.setSearchActive.bind(this));
}
onSearchValueChanged(query) {
onSearchValueChanged(query: string) {
this.queryString = query;
this.store.dispatch(setSearchQuery({query, regExp: this.regExp}));
this.cdr.detectChanges();
this.store.dispatch(setSearchQuery({query: this.regExp? this.queryString: this.queryString.trim(), regExp: this.regExp}));
}
openSearch() {
@@ -66,6 +68,7 @@ export class CommonSearchComponent implements OnInit {
}
}
this.searchActive = showSearch;
this.cdr.detectChanges();
}
clearSearch() {

View File

@@ -1,4 +1,4 @@
@use '~@angular/material' as mat;
@use '@angular/material' as mat;
@import "angular-notifier/styles.scss";
@import "angular-notifier/styles/themes/theme-material.scss";
@import "shared/ui-components/styles/notifications";
@@ -39,6 +39,7 @@ $sm-theme: mat.define-light-theme($sm-theme-primary, $sm-theme-accent, $sm-theme
@include mat.form-field-color($light-theme);
@include mat.progress-spinner-theme($light-theme);
@include mat.progress-bar-theme($light-theme);
.dark-theme {
@include mat.core-theme($dark-theme);
@@ -51,7 +52,6 @@ $sm-theme: mat.define-light-theme($sm-theme-primary, $sm-theme-accent, $sm-theme
@include mat.datepicker-color($light-theme);
@include mat.pseudo-checkbox-color($light-theme);
@include mat.divider-color($light-theme);
@include mat.progress-bar-theme($light-theme);
.mat-checkbox-frame,
.mat-radio-outer-circle {
@@ -71,6 +71,7 @@ $sm-theme: mat.define-light-theme($sm-theme-primary, $sm-theme-accent, $sm-theme
.light-theme .mat-radio-button.mat-radio-disabled .mat-radio-inner-circle {
background-color: transparent !important;
}
.link {
&:hover {
text-decoration: underline;
@@ -92,7 +93,6 @@ $sm-theme: mat.define-light-theme($sm-theme-primary, $sm-theme-accent, $sm-theme
@include mat.datepicker-color($light-theme);
@include mat.pseudo-checkbox-color($light-theme);
@include mat.divider-color($light-theme);
@include mat.progress-bar-theme($light-theme);
.mat-checkbox-frame,
.mat-radio-outer-circle {
@@ -159,17 +159,31 @@ h4.al-header {
h5.al-header {
font-weight: normal;
}
span.highlight-text{
span.highlight-text {
background: $neon-yellow-betterinchrome;
&.current-match{
border: 1px solid darken($neon-yellow-betterinchrome, 5%);
border-radius: 4px;
padding: 0 2px;
&.current-match {
background: #f5d655;
border: 1px solid darken(#f5d655, 15%);
}
}
hr {
border-top: 1px solid rgba(0, 0, 0, .1);
}
.pointer {
cursor: pointer;
}
.cursor-default {
cursor: default;
}
.pointer-events-none {
pointer-events: none;
}
@@ -272,14 +286,17 @@ button {
.color-neon-yellow {
color: $neon-yellow;
}
.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 {
color: $neon-green;
}
@@ -287,6 +304,7 @@ button {
.border-radius {
border-radius: 4px;
}
.grabbing {
cursor: grab;
@@ -758,6 +776,6 @@ button.btn.button-outline-dark {
}
.ace_placeholder {
font-family: SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;
font-family: SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
color: $blue-grey !important;
}

View File

@@ -24,11 +24,11 @@ export const ICONS = {
DATASET: 'fa-puzzle-piece',
TASK: 'fa-briefcase',
MODEL: 'fa-cube',
SHOW: 'fa-eye',
SHOW: 'al-ico-show',
ARCHIVE: 'al-ico-archive',
RESTORE: 'al-ico-restore',
COMPARE: 'al-ico-compare',
HIDE: 'fa-eye-slash',
HIDE: 'al-ico-hide',
COMPLETED: 'fa-circle',
ABORTED: 'fa-circle',
UNKNOWN: 'fa-question-circle',
@@ -54,7 +54,7 @@ export const ICONS = {
LOG: 'fa-file-text-o',
METRICS: 'fa-chart-area',
TOKEN: 'fa-key',
EDIT: 'fa-pencil-square-o',
EDIT: 'al-ico-edit',
EDITABLE: 'fa-pencil',
RESET: 'al-ico-reset',
CLONE: 'al-ico-clone',
@@ -65,6 +65,7 @@ export const ICONS = {
SHARE: 'al-ico-shared-item',
ARROW_DOWN: 'al-ico-ico-chevron-down',
ARROW_UP: 'al-ico-ico-chevron-up',
RUN: 'al-ico-run',
};
export type IconNames = keyof typeof ICONS;

View File

@@ -10,7 +10,7 @@ export const updateS3Credential = createAction(
);
export const createCredential = createAction(
AUTH_PREFIX + 'CREATE_CREDENTIAL (API)',
props<{workspace: GetCurrentUserResponseUserObjectCompany; openCredentialsPopup?: boolean}>()
props<{workspace: GetCurrentUserResponseUserObjectCompany; openCredentialsPopup?: boolean; label?: string}>()
);
export const addCredential = createAction(
AUTH_PREFIX + 'ADD_CREDENTIAL',

View File

@@ -1,4 +1,4 @@
import {MessageSeverityEnum, VIEW_PREFIX} from '../../../app.constants';
import {MessageSeverityEnum, VIEW_PREFIX} from '~/app.constants';
import {createAction, props} from '@ngrx/store';
import {omit} from 'lodash/fp';
import {HttpErrorResponse} from '@angular/common/http';
@@ -37,12 +37,12 @@ export const setBackdrop = createAction(
export const activeLoader = createAction(
VIEW_PREFIX + '[activate loader]',
(endpoint: string) => ({endpoint})
(endpoint: string) => ({endpoint, noPreferences: true})
);
export const deactivateLoader = createAction(
VIEW_PREFIX + '[deactivate loader]',
(endpoint: string) => ({endpoint})
(endpoint: string) => ({endpoint, noPreferences: true})
);

View File

@@ -1,22 +1,23 @@
import {createAction, props} from '@ngrx/store';
import {Project} from '../../../business-logic/model/projects/project';
import {ProjectsUpdateRequest} from '../../../business-logic/model/projects/projectsUpdateRequest';
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 {Project} from '~/business-logic/model/projects/project';
import {ProjectsUpdateRequest} from '~/business-logic/model/projects/projectsUpdateRequest';
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 {TasksResetManyResponse} from '../../../business-logic/model/tasks/tasksResetManyResponse';
import {TasksEnqueueManyResponse} from '../../../business-logic/model/tasks/tasksEnqueueManyResponse';
import {TasksArchiveManyResponse} from '../../../business-logic/model/tasks/tasksArchiveManyResponse';
import {TasksPublishManyResponse} from '../../../business-logic/model/tasks/tasksPublishManyResponse';
import {TasksStopManyResponse} from '../../../business-logic/model/tasks/tasksStopManyResponse';
import {EntityTypeEnum} from '../../../shared/constants/non-common-consts';
import {TasksResetManyResponse} from '~/business-logic/model/tasks/tasksResetManyResponse';
import {TasksEnqueueManyResponse} from '~/business-logic/model/tasks/tasksEnqueueManyResponse';
import {TasksArchiveManyResponse} from '~/business-logic/model/tasks/tasksArchiveManyResponse';
import {TasksPublishManyResponse} from '~/business-logic/model/tasks/tasksPublishManyResponse';
import {TasksStopManyResponse} from '~/business-logic/model/tasks/tasksStopManyResponse';
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
import {MetricColumn} from '@common/shared/utils/tableParamEncode';
import {ProjectStatsGraphData} from '@common/core/reducers/projects.reducer';
export const PROJECTS_PREFIX = '[ROOT_PROJECTS] ';
export const SET_PROJECTS = PROJECTS_PREFIX + 'SET_PROJECTS';
export const RESET_PROJECTS = PROJECTS_PREFIX + 'RESET_PROJECTS';
export const REFETCH_PROJECTS = PROJECTS_PREFIX + 'REFETCH_PROJECTS';
export const SET_LAST_UPDATE = PROJECTS_PREFIX + 'SET_LAST_UPDATE';
export const RESET_SELECTED_PROJECT = PROJECTS_PREFIX + 'RESET_SELECTED_PROJECT';
export const RESET_PROJECT_SELECTION = PROJECTS_PREFIX + 'RESET_PROJECT_SELECTION';
@@ -31,6 +32,8 @@ export const getAllSystemProjects = createAction(
PROJECTS_PREFIX + 'GET_PROJECTS'
);
export const updateProject = createAction(
UPDATE_PROJECT,
props<{ id: string; changes: Partial<ProjectsUpdateRequest> }>()
@@ -42,20 +45,25 @@ export const setAllProjects = createAction(
);
export const resetProjects = createAction(RESET_PROJECTS);
export const refetchProjects = createAction(REFETCH_PROJECTS);
export const setLastUpdate = createAction(
SET_LAST_UPDATE,
props<{ lastUpdate: string }>());
export const updateProjectCompleted = createAction(
PROJECTS_PREFIX + 'UPDATE_PROJECT_COMPLETED'
PROJECTS_PREFIX + 'UPDATE_PROJECT_COMPLETED',
props<{id: string; changes: Partial<Project>}>()
);
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 }>()
@@ -87,6 +95,10 @@ export const getCompanyTags = createAction(
PROJECTS_PREFIX + '[get company tags]'
);
export const getProjectsTags = createAction(
PROJECTS_PREFIX + '[get projects tags]'
);
export const setTagsFilterByProject = createAction(
PROJECTS_PREFIX + '[set tags filter by project]',
props<{ tagsFilterByProject: boolean }>()
@@ -102,6 +114,16 @@ export const setCompanyTags = createAction(
props<{ tags: string[]; systemTags: string[] }>()
);
export const setAllProjectTags = createAction(
PROJECTS_PREFIX + '[set all projects tags]',
props<{ tags: string[]; systemTags: string[] }>()
);
export const addAllProjectTags = createAction(
PROJECTS_PREFIX + '[add all projects tags]',
props<{ tags: string[]; systemTags: string[] }>()
);
export const openTagColorsMenu = createAction(
PROJECTS_PREFIX + '[open tag colors]'
);

View File

@@ -4,7 +4,7 @@ import {ApiAuthService} from '~/business-logic/api-services/auth.service';
import * as authActions from '../actions/common-auth.actions';
import {requestFailed} from '../actions/http.actions';
import {activeLoader, deactivateLoader, setServerError} from '../actions/layout.actions';
import {catchError, filter, finalize, map, mergeMap, switchMap, take, tap, throttleTime, withLatestFrom} from 'rxjs/operators';
import {catchError, filter, finalize, map, mergeMap, switchMap, throttleTime, withLatestFrom} from 'rxjs/operators';
import {AuthGetCredentialsResponse} from '~/business-logic/model/auth/authGetCredentialsResponse';
import {select, Store} from '@ngrx/store';
import {selectCurrentUser} from '../reducers/users-reducer';
@@ -15,8 +15,6 @@ import {EMPTY, of} from 'rxjs';
import {SignResponse} from '@common/settings/admin/base-admin.service';
import {S3AccessResolverComponent} from '@common/layout/s3-access-resolver/s3-access-resolver.component';
import {MatDialog} from '@angular/material/dialog';
import {CreateCredentialDialogComponent} from '~/features/settings/containers/admin/create-credential-dialog/create-credential-dialog.component';
import {resetCredential} from '../actions/common-auth.actions';
@Injectable()
export class CommonAuthEffects {
@@ -29,8 +27,7 @@ export class CommonAuthEffects {
private store: Store<any>,
private adminService: AdminService,
private matDialog: MatDialog
) {
}
) {}
activeLoader = createEffect(() => this.actions.pipe(
ofType(authActions.getAllCredentials, authActions.createCredential),
@@ -64,8 +61,7 @@ export class CommonAuthEffects {
createCredential = createEffect(() => this.actions.pipe(
ofType(authActions.createCredential),
mergeMap(action => this.credentialsApi.authCreateCredentials({}).pipe(
tap( ({credentials}) => action.openCredentialsPopup && this.openCredentialsPopup(credentials, action)),
mergeMap(action => this.credentialsApi.authCreateCredentials({label: action.label}).pipe(
mergeMap(({credentials}) => [
authActions.addCredential({newCredential: credentials, workspaceId: action.workspace?.id}),
deactivateLoader(action.type)
@@ -141,11 +137,4 @@ export class CommonAuthEffects {
);
})
));
openCredentialsPopup(credentials, action): void {
this.matDialog.open(CreateCredentialDialogComponent,
{data: {credentials, ...(action.workspace && {workspace: action.workspace.name})}}
).afterClosed().pipe(take(1)).subscribe(() => this.store.dispatch(resetCredential()));
}
}

View File

@@ -5,13 +5,13 @@ import {ApiProjectsService} from '~/business-logic/api-services/projects.service
import * as actions from '../actions/projects.actions';
import {
fetchGraphData, getAllSystemProjects,
getCompanyTags,
getCompanyTags, getProjectsTags,
getTags,
openMoreInfoPopup,
openTagColorsMenu,
openTagColorsMenu, refetchProjects,
resetProjects, resetProjectSelection,
setCompanyTags,
setGraphData, setLastUpdate,
setGraphData, setLastUpdate, setAllProjectTags,
setTags
} from '../actions/projects.actions';
@@ -104,8 +104,8 @@ export class ProjectsEffects {
switchMap((action) =>
this.projectsApi.projectsUpdate({project: action.id, ...action.changes})
.pipe(
mergeMap(() => [
actions.updateProjectCompleted()
mergeMap(res => [
actions.updateProjectCompleted({id: action.id, changes: res?.fields || action.changes})
]),
catchError(err => [
requestFailed(err),
@@ -123,6 +123,7 @@ export class ProjectsEffects {
})
), {dispatch: false});
//getAll but not projects'
getAllTags = createEffect(() => this.actions$.pipe(
ofType(getCompanyTags),
// eslint-disable-next-line @typescript-eslint/naming-convention
@@ -134,6 +135,17 @@ export class ProjectsEffects {
)
));
getProjectsTags = createEffect(() => this.actions$.pipe(
ofType(getProjectsTags),
// eslint-disable-next-line @typescript-eslint/naming-convention
switchMap(() => this.projectsApi.projectsGetProjectTags({filter: {system_tags: ['pipeline']}})
.pipe(
map((res: OrganizationGetTagsResponse) => setAllProjectTags({tags: res.tags, systemTags: res.system_tags})),
catchError(error => [requestFailed(error)])
)
)
));
getTagsEffect = createEffect(() => this.actions$.pipe(
ofType(getTags),
withLatestFrom(this.store.select(selectRouterParams).pipe(
@@ -212,7 +224,7 @@ export class ProjectsEffects {
));
resetRootProjects = createEffect(() => this.actions$.pipe(
ofType(setActiveWorkspace),
ofType(setActiveWorkspace, refetchProjects),
mergeMap(() => [
resetProjects(),
getAllSystemProjects()

View File

@@ -1,11 +1,12 @@
import {Injectable} from '@angular/core';
import {ActivatedRoute, Params, Router} from '@angular/router';
import {ActivatedRoute, NavigationExtras, Params, Router} from '@angular/router';
import {Actions, createEffect, ofType} from '@ngrx/effects';
import {uniq} from 'lodash/fp';
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 {from} from 'rxjs';
@Injectable()
@@ -34,22 +35,21 @@ export class RouterEffects {
setTableParams = createEffect(() => this.actions$.pipe(
ofType(setURLParams),
map((action) => {
tap((action) => {
const firstUpdate = !this.route.snapshot.queryParams.order;
this.router.navigate(
[],
{
relativeTo: this.route,
replaceUrl: firstUpdate,
queryParamsHandling: action.update ? 'merge' : '',
queryParams: {
...(action.columns && {columns: uniq(action.columns)}),
...(action.orders && {order: encodeOrder(action.orders)}),
...(action.filters && {filter: encodeFilters(action.filters)}),
...(action.isArchived && {archive: true}),
...(action.isDeep && {deep: true})
}
});
const extra = {
// relativeTo: this.route,
...(firstUpdate && {replaceUrl: true}),
...(action.update && {queryParamsHandling: 'merge'}),
queryParams: {
...(action.columns && {columns: uniq(action.columns)}),
...(action.orders && {order: encodeOrder(action.orders)}),
...(action.filters && {filter: encodeFilters(action.filters)}),
...(action.isArchived !== undefined && {archive: action.isArchived ? 'true' : null}),
...(action.isDeep && {deep: true})
}
} as NavigationExtras;
this.router.navigate([], extra);
})
), {dispatch: false});

View File

@@ -3,6 +3,10 @@ import {merge, pick} from 'lodash/fp';
import {setPreferences} from '../actions/users.actions';
import {UserPreferences} from '@common/user-preferences';
interface extAction extends Action {
noPreferences?: boolean;
}
const firstRun = {};
export function createUserPrefReducer(
@@ -11,7 +15,7 @@ export function createUserPrefReducer(
actionsPrefix: string[],
userPreferences: UserPreferences,
reducer: ActionReducer<any>
): ActionReducer<any, Action> {
): ActionReducer<any, extAction> {
if (firstRun[key] === undefined) {
firstRun[key] = true;
@@ -32,7 +36,7 @@ export function createUserPrefReducer(
}
// filter unchanged state.
if (state === nextState) {
if (action.noPreferences || state === nextState) {
return nextState;
}

View File

@@ -9,7 +9,7 @@ import {
updateAllCredentials,
updateS3Credential
} from '../actions/common-auth.actions';
import {CredentialKey} from '../../../business-logic/model/auth/credentialKey';
import {CredentialKey} from '~/business-logic/model/auth/credentialKey';
import {inBucket} from '@common/settings/admin/base-admin.service';
import {filter, map, timeoutWith} from 'rxjs/operators';
@@ -66,8 +66,10 @@ export const selectSignedUrl = url => createSelector(selectAuth, state => state.
export const getSignedUrlOrOrigin$ = (url: string, store: Store) => store.pipe(
select(selectSignedUrl(url)),
filter(signed => !!signed?.signed),
map(signed => signed?.signed || url),
timeoutWith(600, store.select(selectSignedUrl(url)).pipe(map(signed => signed?.signed || url))),
map(signed => signed?.signed),
timeoutWith(900, store.select(selectSignedUrl(url))
.pipe(map(signed => signed?.signed || url))
),
);

View File

@@ -1,11 +1,12 @@
import {createSelector} from '@ngrx/store';
import * as projectsActions from '../actions/projects.actions';
import {
addAllProjectTags,
setAllProjects,
setCompanyTags,
setGraphData,
setLastUpdate,
setMetricVariant,
setMetricVariant, setAllProjectTags,
setTagColors,
setTags,
setTagsFilterByProject,
@@ -35,6 +36,7 @@ export interface RootProjects {
archive: boolean;
deep: boolean;
projectTags: string[];
allProjectsTags: string[];
companyTags: string[];
systemTags: string[];
tagsColors: { [tag: string]: TagColor };
@@ -50,6 +52,7 @@ const initRootProjects: RootProjects = {
archive: false,
deep: false,
projectTags: [],
allProjectsTags: [],
companyTags: [],
systemTags: [],
tagsColors: {},
@@ -69,6 +72,7 @@ export const selectIsDeepMode = createSelector(projects, state => state.deep);
export const selectTagsFilterByProject = createSelector(projects, state => state.tagsFilterByProject);
export const selectProjectTags = createSelector(projects, state => state.projectTags);
export const selectCompanyTags = createSelector(projects, state => state.companyTags);
export const selectAllProjectsTagsTags = createSelector(projects, state => state.allProjectsTags);
// eslint-disable-next-line @typescript-eslint/naming-convention
export const selectProjectSystemTags = createSelector(projects, state => getSystemTags({system_tags: state.systemTags} as ITableExperiment));
export const selectTagsColors = createSelector(projects, state => state.tagsColors);
@@ -117,10 +121,18 @@ export const projectsReducer = (state: RootProjects = initRootProjects, action)
}
case projectsActions.setSelectedProject.type:
return {...state, selectedProject: action.project};
case projectsActions.deletedProjectFromRoot.type:
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))};
case projectsActions.resetSelectedProject.type:
return {...state, selectedProject: initRootProjects.selectedProject};
case projectsActions.updateProject.type: {
return {...state, selectedProject: {...state.selectedProject, ...(action as ReturnType<typeof projectsActions.updateProject>).changes}};
case projectsActions.updateProjectCompleted.type: {
const payload = action as ReturnType<typeof projectsActions.updateProjectCompleted>;
return {
...state,
selectedProject: {...state.selectedProject, ...payload.changes},
projects: state.projects.map(project => project.id === payload.id ? project : {...project, ...payload.changes})
};
}
case projectsActions.setArchive.type:
return {...state, archive: action.archive};
@@ -132,6 +144,10 @@ export const projectsReducer = (state: RootProjects = initRootProjects, action)
return {...state, tagsFilterByProject: action.tagsFilterByProject};
case setCompanyTags.type:
return {...state, companyTags: action.tags, systemTags: action.systemTags};
case setAllProjectTags.type:
return {...state, allProjectsTags: action.tags};
case addAllProjectTags.type:
return {...state, allProjectsTags: Array.from(new Set(state.allProjectsTags.concat(action.tags))).sort()};
case setTagColors.type:
return {...state, tagsColors: {...state.tagsColors, [action.tag]: action.colors}};
case setMetricVariant.type: {

View File

@@ -1,17 +1,17 @@
import {Injectable} from '@angular/core';
import {act, Actions, Effect, ofType} from '@ngrx/effects';
import {Actions, createEffect, ofType} from '@ngrx/effects';
import {activeLoader, deactivateLoader} from '../core/actions/layout.actions';
import {
SearchActivate, SearchClear, searchExperiments, searchModels, searchProjects, searchSetTerm, searchStart, SetExperimentsResults, SetModelsResults, SetProjectsResults
} from './dashboard-search.actions';
import {EXPERIMENT_SEARCH_ONLY_FIELDS, SEARCH_ACTIONS, SEARCH_PAGE_SIZE} from './dashboard-search.consts';
import {ApiProjectsService} from '../../business-logic/api-services/projects.service';
import {ApiProjectsService} from '~/business-logic/api-services/projects.service';
import {requestFailed} from '../core/actions/http.actions';
import {Store} from '@ngrx/store';
import {selectActiveSearch} from './dashboard-search.reducer';
import {ProjectsGetAllExRequest} from '../../business-logic/model/projects/projectsGetAllExRequest';
import {ApiTasksService} from '../../business-logic/api-services/tasks.service';
import {ApiModelsService} from '../../business-logic/api-services/models.service';
import {ProjectsGetAllExRequest} from '~/business-logic/model/projects/projectsGetAllExRequest';
import {ApiTasksService} from '~/business-logic/api-services/tasks.service';
import {ApiModelsService} from '~/business-logic/api-services/models.service';
import {catchError, mergeMap, map, switchMap, withLatestFrom} from 'rxjs/operators';
import {escapeRegex} from '../shared/utils/shared-utils';
@@ -27,14 +27,12 @@ export class DashboardSearchEffects {
}
/* eslint-disable @typescript-eslint/naming-convention */
@Effect()
activeLoader = this.actions.pipe(
activeLoader = createEffect(() => this.actions.pipe(
ofType(SEARCH_ACTIONS.SEARCH_PROJECTS, SEARCH_ACTIONS.SEARCH_MODELS, SEARCH_ACTIONS.SEARCH_EXPERIMENTS),
map(action => activeLoader(action.type))
);
));
// add actions for each search
@Effect()
startSearch = this.actions.pipe(
startSearch = createEffect(() => this.actions.pipe(
ofType(searchStart.type),
withLatestFrom(this.store.select(selectActiveSearch)),
mergeMap(([action, active]: [ReturnType<typeof searchStart>, boolean]) => {
@@ -49,10 +47,9 @@ export class DashboardSearchEffects {
actionsToFire.push(searchModels(action));
return actionsToFire;
})
);
));
@Effect()
searchProjects = this.actions.pipe(
searchProjects = createEffect(() => this.actions.pipe(
ofType(searchProjects.type),
switchMap((action: ReturnType<typeof searchProjects>) => this.projectsApi.projectsGetAllEx({
_any_: {
@@ -67,10 +64,9 @@ export class DashboardSearchEffects {
}).pipe(
mergeMap(res => [new SetProjectsResults(res.projects), deactivateLoader(action.type)]),
catchError(error => [deactivateLoader(action.type), requestFailed(error)])))
);
));
@Effect()
searchModels = this.actions.pipe(
searchModels = createEffect(() => this.actions.pipe(
ofType(searchModels.type),
switchMap((action: ReturnType<typeof searchModels>) => this.modelsApi.modelsGetAllEx({
_any_: {
@@ -84,10 +80,9 @@ export class DashboardSearchEffects {
}).pipe(
mergeMap(res => [new SetModelsResults(res.models), deactivateLoader(action.type)]),
catchError(error => [deactivateLoader(action.type), requestFailed(error)])))
);
));
@Effect()
searchExperiments = this.actions.pipe(
searchExperiments = createEffect(() => this.actions.pipe(
ofType(searchExperiments.type),
switchMap((action: ReturnType<typeof searchExperiments>) => this.experimentsApi.tasksGetAllEx({
_any_: {
@@ -98,9 +93,9 @@ export class DashboardSearchEffects {
size: SEARCH_PAGE_SIZE,
only_fields: EXPERIMENT_SEARCH_ONLY_FIELDS,
type: ['__$not', 'annotation_manual', '__$not', 'annotation', '__$not', 'dataset_import'],
system_tags: ['-archived']
system_tags: ['-archived', '-pipeline']
}).pipe(
mergeMap(res => [new SetExperimentsResults(res.tasks), deactivateLoader(action.type)]),
catchError(error => [deactivateLoader(action.type), requestFailed(error)])))
);
));
}

View File

@@ -1,5 +1,5 @@
import {Injectable} from '@angular/core';
import {ApiProjectsService} from '../../business-logic/api-services/projects.service';
import {ApiProjectsService} from '~/business-logic/api-services/projects.service';
import {Actions, createEffect, ofType} from '@ngrx/effects';
import {requestFailed} from '../core/actions/http.actions';
import {activeLoader, deactivateLoader} from '../core/actions/layout.actions';
@@ -10,23 +10,21 @@ import {
setRecentProjects,
} from './common-dashboard.actions';
import {CARDS_IN_ROW} from './common-dashboard.const';
import {ApiTasksService} from '../../business-logic/api-services/tasks.service';
import {ProjectsGetAllExRequest} from '../../business-logic/model/projects/projectsGetAllExRequest';
import {ApiTasksService} from '~/business-logic/api-services/tasks.service';
import {ProjectsGetAllExRequest} from '~/business-logic/model/projects/projectsGetAllExRequest';
import {catchError, mergeMap, map, switchMap, withLatestFrom} from 'rxjs/operators';
import {ApiLoginService} from '../../business-logic/api-services/login.service';
import {MatDialog} from '@angular/material/dialog';
import {ConfirmDialogComponent} from '../shared/ui-components/overlay/confirm-dialog/confirm-dialog.component';
import {ApiLoginService} from '~/business-logic/api-services/login.service';
import {Store} from '@ngrx/store';
import {ErrorService} from '../shared/services/error.service';
import {selectCurrentUser, selectShowOnlyUserWork} from '../core/reducers/users-reducer';
@Injectable()
export class CommonDashboardEffects {
constructor(private actions: Actions, private projectsApi: ApiProjectsService,
private tasksApi: ApiTasksService, private loginApi: ApiLoginService,
private errorService: ErrorService, private store: Store<any>,
private dialog: MatDialog) {
}
constructor(
private actions: Actions, private projectsApi: ApiProjectsService,
private tasksApi: ApiTasksService, private loginApi: ApiLoginService,
private errorService: ErrorService, private store: Store<any>,
) {}
/* eslint-disable @typescript-eslint/naming-convention */
activeLoader = createEffect(() => this.actions.pipe(
ofType(getRecentProjects, getRecentExperiments),
@@ -62,7 +60,7 @@ export class CommonDashboardEffects {
status: ['published', 'closed', 'failed', 'stopped', 'in_progress', 'completed'],
type: ['__$not', 'annotation_manual', '__$not', 'annotation', '__$not', 'dataset_import'],
only_fields: ['type', 'status', 'created', 'name', 'id', 'last_update', 'started', 'project.name'],
system_tags: ['-archived'],
system_tags: ['-archived', '-pipeline'],
user: showOnlyUserWork ? [user.id] : null,
})
.pipe(

View File

@@ -15,24 +15,26 @@ import {CommonExperimentSharedModule} from '../experiments/shared/common-experim
import {CommonProjectsModule} from '../projects/common-projects.module';
import {SharedModule} from '../../shared/shared.module';
import { WelcomeMessageComponent } from './dumb/welcome-message/welcome-message.component';
import {FormsModule} from '@angular/forms';
@NgModule({
declarations: [DashboardProjectsComponent, DashboardExperimentsComponent, RecentExperimentTableComponent, WelcomeMessageComponent],
exports : [DashboardProjectsComponent, DashboardExperimentsComponent],
imports: [
CommonModule,
SMSharedModule,
ExperimentsCommonModule,
ExperimentSharedModule,
CommonSearchModule,
ProjectsSharedModule,
CommonExperimentSharedModule,
EffectsModule.forFeature([CommonDashboardEffects]),
CommonLayoutModule,
ExperimentSharedModule,
CommonProjectsModule,
SharedModule
]
imports: [
CommonModule,
SMSharedModule,
ExperimentsCommonModule,
ExperimentSharedModule,
CommonSearchModule,
ProjectsSharedModule,
CommonExperimentSharedModule,
EffectsModule.forFeature([CommonDashboardEffects]),
CommonLayoutModule,
ExperimentSharedModule,
CommonProjectsModule,
SharedModule,
FormsModule
]
})
export class CommonDashboardModule {
}

View File

@@ -44,7 +44,6 @@ export class DashboardProjectsComponent implements OnInit, AfterViewInit, OnDest
}
ngAfterViewInit() {
this.width.emit(this.header.nativeElement.getBoundingClientRect().width);
window.setTimeout(() => this.width.emit(this.header.nativeElement.getBoundingClientRect().width));
this.sub = fromEvent(window, 'resize')
.pipe(throttleTime(50))

View File

@@ -45,22 +45,27 @@
</div>
<div *ngIf="step.subNote" class="sub-note"><i class="mr-1 fas fa-info-circle info"></i>{{step.subNote}}</div>
</div>
<div class="step-container">
<div class="step-header sub-note">Complete the clearml configuration information as prompted.</div>
<div *ngIf="!accessKey ; else config" class="code empty-config">
<div>
<button class="mb-2 btn btn-neon" [disabled]="creatingCredentials" (click)="createCredentials()">CREATE NEW
CREDENTIALS
</button>
</div>
<div class="step-container cred-step" [class.first-step]="!credentialsCreated" [class.has-label]="credentialsLabel">
<div class="step-header">Complete the clearml configuration information as prompted.</div>
<div *ngIf="!credentialsCreated" class="d-flex align-items-end">
<mat-form-field appearance="outline"
class="label-input"
floatLabel="always">
<mat-label>Label (optional)</mat-label>
<input matInput [(ngModel)]="credentialsLabel" [disabled]="credentialsCreated" placeholder="Credentials label" name="credentials">
</mat-form-field>
<button class="mb-2 btn btn-neon create-cred-button" (click)="createCredentials()">CREATE NEW
CREDENTIALS
</button>
</div>
<ng-template #config>
<div class="cred-visible" [class.invisible]="!accessKey">
<div class="code">
<div #content class="content"><span class="variable">api</span> {{ '{' }}<ng-container *ngIf="community && workspace.name">
<span class="comment">{{'# ' + workspace.name}}</span></ng-container>
<span class="">{{'# ' + workspace.name}}</span></ng-container>
<span class="variable">web_server</span><span class="operation">:</span> <span class="string">{{WEB_SERVER_URL}}</span>
<span class="variable">api_server</span><span class="operation">:</span> <span class="string">{{API_BASE_URL}}</span>
<ng-container *ngIf="fileBaseUrl"> <span class="variable">files_server</span><span class="operation">:</span> <span class="string">{{fileBaseUrl}}</span>
<ng-container *ngIf="fileBaseUrl"> <span class="variable">files_server</span><span class="operation">:</span> <span class="string">{{fileBaseUrl}}</span><ng-container *ngIf="credentialsLabel">
<span>{{'# ' + credentialsLabel}}</span></ng-container>
</ng-container> <span class="variable">credentials</span> {{ '{' }}
<span class="string">"access_key"</span> <span class="operation">=</span> <span class="string">"{{accessKey}}"</span>
<span class="string">"secret_key"</span> <span class="operation">=</span> <span class="string">"{{secretKey}}"</span>
@@ -72,8 +77,8 @@
[copyIcon]="'far fa-lg fa-copy'"
[clipboardText]="content.textContent"></sm-copy-clipboard>
</div>
</ng-template>
<div class="sub-note"><i class="mr-1 fas fa-info-circle info"></i>Manage your app credentials in the <a target="_blank" href="settings/workspace-configuration">workspace settings page</a></div>
</div>
</div>
<div class="step-container" *ngIf="!queue">
<div class="step">3. Integrate</div>

View File

@@ -58,8 +58,8 @@
}
.steps-content {
padding: 10px 32px;
.step-container{
padding: 0 32px 10px 32px;
.step-container:not(:first-child){
margin: 20px 0;
}
@@ -71,7 +71,7 @@
}
.step-header {
color: $blue-500;
margin-bottom: 1px;
margin-bottom: 4px;
width: 530px;
}
@@ -104,12 +104,12 @@
}
.content {
padding: 16px;
padding: 14px 16px;
overflow: auto;
margin-right: 16px;
white-space: pre;
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 12px;
font-size: 11px;
line-height: 18px;
}
@@ -138,11 +138,38 @@
}
}
.empty-config {
height: 190px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.cred-step {
height: 238px;
transition: height 1s ease;
&.has-label {
height: 272px;
}
&.first-step {
height: 90px;
}
}
.cred-visible {
visibility: visible;
opacity: 1;
transition: opacity 1s ease;
&.invisible {
opacity: 0;
visibility: hidden;
}
}
.label-input {
flex: 1;
padding-right: 12px;
}
.create-cred-button {
margin-top: 18px;
height: 36px;
padding: 0px 28px;
}
}

View File

@@ -3,7 +3,7 @@ import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
import {setSelectedWorkspaceTab} from '@common/core/actions/users.actions';
import {Subscription} from 'rxjs';
import {selectActiveWorkspace} from '@common/core/reducers/users-reducer';
import {filter, tap} from 'rxjs/operators';
import {filter} from 'rxjs/operators';
import {Store} from '@ngrx/store';
import {createCredential, resetCredential} from '@common/core/actions/common-auth.actions';
import {selectNewCredential} from '@common/core/reducers/common-auth-reducer';
@@ -25,7 +25,7 @@ export class WelcomeMessageComponent implements OnInit, OnDestroy {
public step: number = 1;
accessKey: string;
secretKey: string;
creatingCredentials = false;
credentialsCreated = false;
private workspacesSub: Subscription;
public workspace: GetCurrentUserResponseUserObjectCompany;
@@ -62,6 +62,7 @@ export class WelcomeMessageComponent implements OnInit, OnDestroy {
doNotShowAgain: boolean;
public gettingStartedContext: GettingStartedContext;
docsLink: string;
credentialsLabel: string;
constructor(
private store: Store<any>,
@@ -99,7 +100,6 @@ export class WelcomeMessageComponent implements OnInit, OnDestroy {
this.newCredentialSub = this.store.select(selectNewCredential)
.pipe(
tap(() => this.creatingCredentials = false),
filter(credential => credential && Object.keys(credential).length > 0)
).subscribe(credential => {
this.accessKey = credential.access_key;
@@ -118,9 +118,9 @@ export class WelcomeMessageComponent implements OnInit, OnDestroy {
}
createCredentials() {
this.creatingCredentials = true;
this.credentialsCreated = true;
this.store.dispatch(setSelectedWorkspaceTab({workspace: {id: this.workspace.id}}));
this.store.dispatch(createCredential({workspace: this.workspace}));
this.store.dispatch(createCredential({workspace: this.workspace, label: this.credentialsLabel}));
}
ngOnDestroy(): void {

View File

@@ -44,7 +44,7 @@
</div>
</div>
<div class="no-images no-output" [class.dark]="isDarkTheme" *ngIf="shouldShowNoImagesForExperiment(experimentId)">
<svg class="mb-3 w-100" xmlns="http://www.w3.org/2000/svg" width="300" height="150" viewBox="0 0 300 150">
<svg class="mb-3 w-100" xmlns="http://www.w3.org/2000/svg" width="400" height="200" viewBox="0 0 300 150">
<path opacity="0.1"
d="M72.67,79.36a5.39,5.39,0,0,1-1.45,4.32,1.17,1.17,0,0,1-.6.34,1.13,1.13,0,0,1-1.31-.88,1.11,1.11,0,0,1,.28-1,3.19,3.19,0,0,0,.89-2.36c-.22-1.09-1.66-1.73-1.68-1.74A1.12,1.12,0,0,1,69.65,76C69.76,76,72.22,77.07,72.67,79.36ZM46.19,78.1a1.38,1.38,0,0,0-1.06,1.61L47.3,90.38a1.38,1.38,0,0,0,1.61,1.06l4-.82L50.19,77.29Zm30.87.39c-.91-4.54-5.23-7.07-5.41-7.18a1.13,1.13,0,1,0-1.16,1.94s3.63,2.13,4.34,5.68-1.8,7-1.82,7a1.12,1.12,0,0,0,.25,1.56,1.11,1.11,0,0,0,.86.2,1.12,1.12,0,0,0,.68-.43C75,87.09,78,83,77.06,78.49Zm-3.57-12a1.12,1.12,0,0,0-1,2,12.48,12.48,0,0,1,2.91,2.24,13.87,13.87,0,0,1,3.88,7.28,14.19,14.19,0,0,1-.78,8.27,13,13,0,0,1-1.83,3.22,1.11,1.11,0,0,0,1.06,1.82h0a1,1,0,0,0,.63-.36,16.47,16.47,0,0,0,3.13-13.38A16.18,16.18,0,0,0,73.49,66.53Zm-9.28,1a1.35,1.35,0,0,0-1.6-1.06h0a1.45,1.45,0,0,0-.71.4L52.2,76.93l2.7,13.24,12.82,5.52a1.36,1.36,0,0,0,1.79-.7,1.33,1.33,0,0,0,.09-.81ZM261.4,76.66l-3.77,21.62-8.28-8.4-.47,2.7a4.13,4.13,0,0,1-4.76,3.35l-25.67-4.48a4.14,4.14,0,0,1-3.35-4.76l2.36-13.51c0-.12,0-.24.08-.35a6.17,6.17,0,1,1,10-3.71,5.62,5.62,0,0,1-.5,1.55l4.49.79a6.37,6.37,0,0,1,.06-1.63,6.15,6.15,0,1,1,11.63,3.65l4.63.81a4,4,0,0,1,3.4,4.53c0,.08,0,.15-.05.23l-.48,2.7ZM225.28,68.1a3.7,3.7,0,0,0-3.52-3.87h-.19a3.79,3.79,0,1,0,3.71,3.87Zm16.29,3A3.7,3.7,0,0,0,238,67.24h-.19a3.79,3.79,0,1,0,3.72,3.86Zm53.2-20.19L281,129.18a17.25,17.25,0,0,1-20,14l-78.27-13.81a17,17,0,0,1-11.13-7.08,17.86,17.86,0,0,1-1-1.69H130.44a17.86,17.86,0,0,1-1,1.69,17,17,0,0,1-11.13,7.08L40.09,143.16a17.25,17.25,0,0,1-20-14L6.26,50.86a17.26,17.26,0,0,1,14-20h0L94.63,17.77A17.24,17.24,0,0,1,110.76,6.58h79.47a17.24,17.24,0,0,1,16.13,11.19l74.38,13.11a17.25,17.25,0,0,1,14,20ZM120.22,119.58h-9.47a17.21,17.21,0,0,1-17.19-17.19V25.1L21.81,37.75a9.55,9.55,0,0,0-7.74,11.06l13.76,78.06a9.57,9.57,0,0,0,11.06,7.71L117,120.81A9.68,9.68,0,0,0,120.22,119.58Zm69.82-7a9.54,9.54,0,0,0,9.52-9.52V24.13a9.53,9.53,0,0,0-9.5-9.55h-79a9.51,9.51,0,0,0-9.51,9.51v79a9.53,9.53,0,0,0,9.51,9.52Zm95.52-70.94a9.49,9.49,0,0,0-6.17-3.93L207.56,25.1v77.33a17.23,17.23,0,0,1-17.21,17.15h-9.49a9.66,9.66,0,0,0,3.28,1.23l78.15,13.77a9.58,9.58,0,0,0,11.07-7.75l13.78-78.06a9.44,9.44,0,0,0-1.58-7.09Zm-109,.43c1.09.64,1,2.34,1,2.34l-.14,37.87a3.33,3.33,0,0,1-3.36,3.3h0l-48.13-.16a3.37,3.37,0,0,1-3.37-3.35l.2-37.39a3.3,3.3,0,0,1,2.11-3l.18-.08h49.68s1.76-.15,1.83.53ZM160.49,53.34a3.8,3.8,0,0,0,7.59,0,3.7,3.7,0,0,0-3.67-3.76h-.12A3.79,3.79,0,0,0,160.49,53.34ZM171.6,74.93l-8.55-9.46-.19-.19a2.49,2.49,0,0,0-3.52.16v0l-4.2,4.63-9.19-10.63a3.05,3.05,0,0,0-1.59-1,2.75,2.75,0,0,0-2.66.95h0l-13.13,15v4.13l43,.14Z"/>
</svg>

View File

@@ -52,7 +52,6 @@ sm-debug-images-view {
transform: translateY(-50%) translateX(-50%);
display: block;
color: $cloudy-blue-two;
font-size: 1.75rem;
font-weight: 500;
line-height: 1.2;

View File

@@ -1,7 +1,7 @@
import {Action, createAction, props} from '@ngrx/store';
import {ISmAction} from '../../core/models/actions';
import {IExperimentSettings} from '../../experiments/reducers/common-experiment-output.reducer';
import {ScalarKeyEnum} from '../../../business-logic/model/events/scalarKeyEnum';
import {ExperimentSettings} from '../../experiments/reducers/common-experiment-output.reducer';
import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum';
export const EXPERIMENTS_COMPARE_METRICS_CHARTS_ = 'EXPERIMENTS_COMPARE_METRICS_CHARTS_';
@@ -68,7 +68,7 @@ export class SetExperimentPlots implements Action {
export class SetExperimentSettings implements Action {
readonly type = UPDATE_EXPERIMENT_SETTINGS;
constructor(public payload: { id: Array<string>; changes: Partial<IExperimentSettings>}) {
constructor(public payload: { id: Array<string>; changes: Partial<ExperimentSettings>}) {
}
}

View File

@@ -298,16 +298,25 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase
}
}
public find(text: string) {
if (text) {
this.findAllOccurrences(text);
this.foundIndex = -1;
this.findNext();
} else if (this.searchText !== text) {
this.foundPaths = [];
this.selectedPath = null;
public find(value: string) {
const searchBackward = value === null;
if (this.searchText !== value && !searchBackward) {
this.resetSearch();
if (value.length > 0) {
this.findAllOccurrences(value);
}
this.searchText = value;
}
this.searchText = text;
if (value?.length > 0 || value === null) {
searchBackward ? this.findPrev() : this.findNext();
}
}
public resetSearch() {
this.foundPaths = [];
this.selectedPath = null;
this.foundIndex = -1;
}
findAllOccurrences(text) {

View File

@@ -69,31 +69,23 @@
<sm-portal outletId="searchDiff">
<div class="btn-group mr-2" role="group">
<sm-search [value]="searchText"
[minimumChars]="1"
[debounceTime]="300"
(keydown.enter)="findNext()"
(valueChanged)="find($event)"
></sm-search>
<button class="btn btn-secondary prev" smTooltip="Previous occurrence" [disabled]="foundPaths.length === 0 " (click)="findPrev()">
<i class="fas fa-chevron-up"></i>
</button>
<button class="btn btn-secondary next" smTooltip="Next occurrence" [disabled]="foundPaths.length === 0 " (click)="findNext()">
<i class="fas fa-chevron-down"></i>
</button>
</div>
<span [class.hidden]="searchText.length === 0 "> Match {{foundPaths.length === 0 ? '0' : foundIndex + 1}} / {{foundPaths.length}}</span>
<sm-search class="light-theme"
[value]="searchText"
[minimumChars]="1"
[debounceTime]="300"
[enableNavigation]="true"
[searchCounterIndex]="foundIndex"
[searchResultsCount]="foundPaths.length"
(valueChanged)="find($event)"
></sm-search>
</sm-portal>
<sm-portal outletId="nextDiff">
<button class="btn btn-secondary btn-arrow mr-3" smTooltip="Previous diff" (click)="goToNextDiff('up')">
<i class="fas fa-arrow-up"></i>
<i class="al-icon al-ico-arrow-up sm"></i>
</button>
<button class="btn btn-secondary btn-arrow" smTooltip="Next diff" (click)="goToNextDiff('down')">
<i class="fas fa-arrow-down"></i>
<i class="al-icon al-ico-arrow-down sm"></i>
</button>
</sm-portal>

View File

@@ -9,7 +9,7 @@
(keydown.escape)="clearMetricSearch(); searchMetric.value= ''"
placeholder="Search metric"
[smTooltip]="selectedMetric?.name"
[showDelay]="500"
[matTooltipShowDelay]="500"
[value]="(!metrics || listOpen) ? '' : selectedMetric?.name"
(input)="updateMetricsList($event)"
>

View File

@@ -1,17 +1,17 @@
import {Component, HostListener, OnDestroy, OnInit, ElementRef, ViewChild} from '@angular/core';
import {combineLatest, Observable, Subscription} from 'rxjs';
import {select, Store} from '@ngrx/store';
import {IExperimentInfoState} from '../../../../features/experiments/reducers/experiment-info.reducer';
import {IExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer';
import {distinctUntilChanged, filter, map} from 'rxjs/operators';
import {selectRouterParams} from '../../../core/reducers/router-reducer';
import {selectRouterParams} from '@common/core/reducers/router-reducer';
import {get, has} from 'lodash/fp';
import {SetExperimentSettings, SetSelectedExperiments} from '../../actions/experiments-compare-charts.actions';
import {selectRefreshing, selectScalarsGraphHyperParams, selectScalarsGraphMetrics, selectScalarsGraphShowIdenticalHyperParams, selectScalarsGraphTasks, selectMetricValueType, selectSelectedSettigsHyperParams, selectSelectedSettigsMetric} from '../../reducers';
import {selectRefreshing, selectScalarsGraphHyperParams, selectScalarsGraphMetrics, selectScalarsGraphShowIdenticalHyperParams, selectScalarsGraphTasks, selectMetricValueType, selectSelectedSettingsHyperParams, selectSelectedSettingsMetric} from '../../reducers';
import {getExperimentsHyperParams, setShowIdenticalHyperParams, setvalueType} from '../../actions/experiments-compare-scalars-graph.actions';
import {GroupedHyperParams, MetricOption, MetricValueType, SelectedMetric, VariantOption} from '../../reducers/experiments-compare-charts.reducer';
import {MatRadioChange} from '@angular/material/radio';
import {selectPlotlyReady} from '../../../core/reducers/view.reducer';
import {ExtFrame} from '../../../shared/experiment-graphs/single-graph/plotly-graph-base';
import {selectPlotlyReady} from '@common/core/reducers/view.reducer';
import {ExtFrame} from '@common/shared/experiment-graphs/single-graph/plotly-graph-base';
export const _filter = (opt: VariantOption[], value: string): VariantOption[] => {
@@ -69,8 +69,8 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
constructor(private store: Store<IExperimentInfoState>) {
this.metrics$ = this.store.pipe(select(selectScalarsGraphMetrics));
this.hyperParams$ = this.store.pipe(select(selectScalarsGraphHyperParams));
this.selectedHyperParams$ = this.store.pipe(select(selectSelectedSettigsHyperParams));
this.selectedMetric$ = this.store.pipe(select(selectSelectedSettigsMetric));
this.selectedHyperParams$ = this.store.pipe(select(selectSelectedSettingsHyperParams));
this.selectedMetric$ = this.store.pipe(select(selectSelectedSettingsMetric));
this.selectShowIdenticalHyperParams$ = this.store.pipe(select(selectScalarsGraphShowIdenticalHyperParams));
this.selectRefreshing$ = this.store.select(selectRefreshing);
this.experiments$ = this.store.pipe(select(selectScalarsGraphTasks));
@@ -94,7 +94,7 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
this.hyperParamsSubscription = combineLatest([this.selectedHyperParams$, this.hyperParams$, this.selectShowIdenticalHyperParams$])
.pipe(
filter(([selectedParams, allParams, filterActive]) => !!allParams),
filter(([, allParams]) => !!allParams),
)
.subscribe(([selectedParams, allParams, showIdentical]) => {
this.showIdenticalParamsActive = showIdentical;
@@ -161,7 +161,7 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
this.listOpen = false;
}
selectedParamsChanged({param, value}) {
selectedParamsChanged({param}) {
const newSelectedParamsList = this.selectedHyperParams.includes(param) ? this.selectedHyperParams.filter(i => i !== param) : [...this.selectedHyperParams, param];
this.updateServer(this.selectedMetric, newSelectedParamsList);
}

View File

@@ -1,41 +1,40 @@
<div class="d-flex h-100">
<div class="list-container">
<sm-graph-settings-bar
[verticalLayout]="true"
[smoothWeight]="smoothWeight$ | async"
[xAxisType]="xAxisType$ | async"
[groupBy]="groupBy"
[groupByOptions]="groupByOptions"
(changeWeight)="changeSmoothness($event)"
(toggleSettings)="toggleSettingsBar()"
(changeXAxisType)="changeXAxisType($event)"
(changeGroupBy)="changeGroupBy($event)"
></sm-graph-settings-bar>
<sm-selectable-grouped-filter-list
[list]="graphList"
[selected]="selectedGraph"
[checkedList]="listOfHidden | async"
[searchTerm]="searchTerm$ | async"
(itemSelect)="metricSelected($event)"
(hiddenChanged)="hiddenListChanged($event)"
(searchTermChanged)="searchTermChanged($event)"
>
</sm-selectable-grouped-filter-list>
</div>
<div class="graphs-container h-100">
<mat-drawer-container autosize>
<mat-drawer opened="true" mode="side">
<div class="list-container">
<sm-graph-settings-bar
class="drawer-settings-bar"
[verticalLayout]="true"
[smoothWeight]="smoothWeight$ | async"
[xAxisType]="xAxisType$ | async"
[groupBy]="groupBy"
[groupByOptions]="groupByOptions"
(changeWeight)="changeSmoothness($event)"
(toggleSettings)="toggleSettingsBar()"
(changeXAxisType)="changeXAxisType($event)"
(changeGroupBy)="changeGroupBy($event)"
></sm-graph-settings-bar>
<sm-selectable-grouped-filter-list
[list]="graphList"
[selected]="selectedGraph"
[checkedList]="listOfHidden | async"
[searchTerm]="searchTerm$ | async"
(itemSelect)="metricSelected($event)"
(hiddenChanged)="hiddenListChanged($event)"
(searchTermChanged)="searchTermChanged($event)"
>
</sm-selectable-grouped-filter-list>
</div>
</mat-drawer>
<mat-drawer-content>
<sm-experiment-graphs
[metrics]="graphs"
[hiddenList]="listOfHidden | async"
[isGroupGraphs]="false"
[isCompare]="true"
[showSettings]="showSettingsBar$ | async"
[smoothWeight]="(smoothWeight$ | async)"
[xAxisType]="xAxisType$ | async"
(resetGraphs)="resetMetrics()"
(changeWeight)="changeSmoothness($event)"
(changeXAxisType)="changeXAxisType($event)"
(toggleSettings)="toggleSettingsBar()"
>
</sm-experiment-graphs>
</div>
</div>
</mat-drawer-content>
</mat-drawer-container>

View File

@@ -1,22 +1,50 @@
.toggle-all {
font-size: 10px;
padding-right: 2px;
cursor: pointer;
}
@import "variables";
.list-container {
$list-width: 300px;
:host {
display: flex;
flex-direction: column;
width: 340px;
//padding: 20px 24px 0 24px;
border-right: 1px solid #efefef;
}
.graphs-container {
flex: 1;
padding: 0 !important;
}
height: 100%;
sm-graph-settings-bar {
padding: 24px;
border-bottom: 1px solid #efefef;
mat-drawer {
background-color: $white;
}
mat-drawer-container {
width: 100%;
}
.drawer-settings-bar {
height: unset;
padding: 24px;
border-bottom: 1px solid $blue-100;
}
.toggle-all {
font-size: 10px;
padding-right: 2px;
cursor: pointer;
}
.list-container {
display: flex;
position: relative;
flex-direction: column;
height: 100%;
width: $list-width;
overflow-y: auto;
overflow-x: hidden;
border-right: 1px solid #efefef;
}
.graphs-container {
position: relative;
width: 100%;
height: 100%;
padding: 0 !important;
}
sm-experiment-graphs {
height: calc(100% - 64px);
}
}

View File

@@ -68,31 +68,23 @@
<sm-portal outletId="searchDiff">
<div class="btn-group mr-2" role="group">
<sm-search [value]="searchText"
[minimumChars]="1"
[debounceTime]="300"
(keydown.enter)="findNext()"
(valueChanged)="find($event)"
></sm-search>
<button class="btn btn-secondary prev" smTooltip="Previous occurrence" [disabled]="foundPaths.length === 0 " (click)="findPrev()">
<i class="fas fa-chevron-up"></i>
</button>
<button class="btn btn-secondary next" smTooltip="Next occurrence" [disabled]="foundPaths.length === 0 " (click)="findNext()">
<i class="fas fa-chevron-down"></i>
</button>
</div>
<span [class.hidden]="searchText.length === 0 "> Match {{foundPaths.length === 0 ? '0' : foundIndex + 1}} / {{foundPaths.length}}</span>
<sm-search class="light-theme"
[value]="searchText"
[minimumChars]="1"
[debounceTime]="300"
[enableNavigation]="true"
[searchCounterIndex]="foundIndex"
[searchResultsCount]="foundPaths.length"
(valueChanged)="find($event)"
></sm-search>
</sm-portal>
<sm-portal outletId="nextDiff">
<button class="btn btn-secondary btn-arrow mr-3" smTooltip="Previous diff" (click)="goToNextDiff('up')">
<i class="fas fa-arrow-up"></i>
<i class="al-icon al-ico-arrow-up sm"></i>
</button>
<button class="btn btn-secondary btn-arrow" smTooltip="Next diff" (click)="goToNextDiff('down')">
<i class="fas fa-arrow-down"></i>
<i class="al-icon al-ico-arrow-down sm"></i>
</button>
</sm-portal>

View File

@@ -1,7 +1,7 @@
<div class="d-flex h-100">
<div class="list-container">
<sm-selectable-filter-list
checkAllIcon="fa-eye"
checkAllIcon="al-ico-show"
placeholder="Find plots"
[list]="graphList"
[selected]="selectedGraph"

View File

@@ -42,6 +42,7 @@
[parents]="parent$ | async"
[noMoreExperiments]="noMoreExperiments$ | async"
[systemTags]="systemTags$ | async"
[entityType]="entityTypes.experiment"
(tagsMenuOpened)="refreshTagsList()"
(typesMenuOpened)="refreshTypesList()"
(experimentsSelectionChanged)="experimentsSelectionChanged($event)"

View File

@@ -15,13 +15,13 @@ import {
selectSelectedExperimentsForCompareAdd
} from '../../reducers';
import {BehaviorSubject, combineLatest, Observable, Subscription} from 'rxjs';
import {Task} from '../../../../business-logic/model/tasks/task';
import {Task} from '~/business-logic/model/tasks/task';
import {Params} from '@angular/router';
import {selectRouterParams} from '../../../core/reducers/router-reducer';
import {selectRouterParams} from '@common/core/reducers/router-reducer';
import {distinctUntilChanged, distinctUntilKeyChanged, filter, map} from 'rxjs/operators';
import {compareLimitations} from '../../../shared/entity-page/footer-items/compare-footer-item';
import {compareLimitations} from '@common/shared/entity-page/footer-items/compare-footer-item';
import {MatDialogRef} from '@angular/material/dialog';
import {ITableExperiment} from '../../../experiments/shared/common-experiment-model.model';
import {ITableExperiment} from '@common/experiments/shared/common-experiment-model.model';
import {
selectActiveParentsFilter,
selectExperimentsList,
@@ -34,21 +34,24 @@ import {
selectExperimentsUsers,
selectHyperParamsOptions,
selectNoMoreExperiments,
selectTableFilters
} from '../../../experiments/reducers';
selectTableFilters, selectTableSortFields
} from '@common/experiments/reducers';
import {get, isEqual, unionBy} from 'lodash/fp';
import {ColHeaderTypeEnum, ISmCol, TableSortOrderEnum} from '../../../shared/ui-components/data/table/table.consts';
import {filterArchivedExperiments} from '../../../experiments/shared/common-experiments.utils';
import {InitSearch} from '../../../common-search/common-search.actions';
import {ColHeaderTypeEnum, ISmCol, TableSortOrderEnum} from '@common/shared/ui-components/data/table/table.consts';
import {filterArchivedExperiments} from '@common/experiments/shared/common-experiments.utils';
import {InitSearch} from '@common/common-search/common-search.actions';
import * as experimentsActions from '../../../experiments/actions/common-experiments-view.actions';
import {resetExperiments, resetGlobalFilter} from '../../../experiments/actions/common-experiments-view.actions';
import {User} from '../../../../business-logic/model/users/user';
import {selectProjectSystemTags, selectRootProjects} from '../../../core/reducers/projects.reducer';
import {resetExperiments, resetGlobalFilter} from '@common/experiments/actions/common-experiments-view.actions';
import {User} from '~/business-logic/model/users/user';
import {selectProjectSystemTags, selectRootProjects} from '@common/core/reducers/projects.reducer';
import {SortMeta} from 'primeng/api';
import {Project} from '../../../../business-logic/model/projects/project';
import {addMessage} from '../../../core/actions/layout.actions';
import {MESSAGES_SEVERITY} from '../../../../app.constants';
import {ProjectsGetTaskParentsResponseParents} from '../../../../business-logic/model/projects/projectsGetTaskParentsResponseParents';
import {Project} from '~/business-logic/model/projects/project';
import {addMessage} from '@common/core/actions/layout.actions';
import {MESSAGES_SEVERITY} from '~/app.constants';
import {ProjectsGetTaskParentsResponseParents} from '~/business-logic/model/projects/projectsGetTaskParentsResponseParents';
import {FilterMetadata} from 'primeng/api/filtermetadata';
import {INITIAL_EXPERIMENT_TABLE_COLS} from '@common/experiments/experiment.consts';
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
export const allowAddExperiment$ = (selectRouterParams$: Observable<Params>) => selectRouterParams$.pipe(
distinctUntilKeyChanged('ids'),
@@ -64,6 +67,8 @@ export const allowAddExperiment$ = (selectRouterParams$: Observable<Params>) =>
styleUrls: ['./select-experiments-for-compare.component.scss']
})
export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy {
public tableCols = INITIAL_EXPERIMENT_TABLE_COLS;
public entityTypes = EntityTypeEnum;
public experimentsResults$: Observable<Task[]>;
public selectedExperimentsIds: string[] = [];
private paramsSubscription: Subscription;
@@ -78,7 +83,7 @@ export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy {
public experiments$: Observable<any>;
private projectId: string;
public users$: Observable<User[]>;
public tableFilters$: Observable<{ [p: string]: { value: any; matchMode: string } }>;
public tableFilters$: Observable<{ [columnId: string]: FilterMetadata }>;
public tags$: Observable<string[]>;
public systemTags$: Observable<string[]>;
public types$: Observable<string[]>;
@@ -119,14 +124,13 @@ export class SelectExperimentsForCompareComponent implements OnInit, OnDestroy {
this.types$ = this.store.select(selectExperimentsTypes);
this.systemTags$ = this.store.select(selectProjectSystemTags);
this.noMoreExperiments$ = this.store.select(selectNoMoreExperiments);
this.tableSortFields$ = this.store.select(selectCompareAddTableSortFields);
this.tableSortFields$ = this.store.select(selectTableSortFields);
this.hyperParamsOptions$ = this.store.select(selectHyperParamsOptions);
this.activeParentsFilter$ = this.store.select(selectActiveParentsFilter);
this.tableCols$ = combineLatest([this.columns$, this.metricTableCols$, this.resizedCols$])
.pipe(
filter(([tableCols,,]) => !!tableCols),
map(([tableCols, metricCols, resizedCols]) =>
tableCols
(tableCols.length > 0 ? tableCols: this.tableCols)
.concat(metricCols.map(col => ({...col, metric: true})))
.map(col => ({
...col,

View File

@@ -1,7 +1,7 @@
import {ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {EXPERIMENTS_STATUS_LABELS} from '../../../../features/experiments/shared/experiments.const';
import {IExperimentDetail} from '../../../../features/experiments-compare/experiments-compare-models';
import {TIME_FORMAT_STRING} from '../../../constants';
import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core';
import {EXPERIMENTS_STATUS_LABELS} from '~/features/experiments/shared/experiments.const';
import {IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models';
import {TIME_FORMAT_STRING} from '@common/constants';
@Component({
selector: 'sm-experiment-compare-general-data',
@@ -24,6 +24,6 @@ export class ExperimentCompareGeneralDataComponent {
}
buildUrl() {
return `/projects/${this.experiment.project ? this.experiment.project.id : '*'}/experiments/${this.experiment.id}`;
return ['../../', 'experiments', this.experiment.id];
}
}

View File

@@ -21,29 +21,12 @@
border-left-color: transparent !important;
}
}
.btn-group sm-search {
width: 200px;
.search-input-container {
.search-input input{
border: 1px solid $blue-280;
border-right: none;
border-radius: 4px 0 0 4px !important;
padding-left: 6px !important;
}
i.fa {
border-top: 1px solid $blue-280;
border-bottom: 1px solid $blue-280;
border-right: 1px solid $blue-280;
}
}
}
}
::ng-deep .btn-arrow {
display: inline-flex;
align-items: center;
justify-content: center;
width: 42px;
}

View File

@@ -1,12 +1,12 @@
import {Component, ElementRef, HostListener, Input, OnInit, ViewChild} from '@angular/core';
import {PlotlyGraphBase} from '../../../shared/experiment-graphs/single-graph/plotly-graph-base';
import {PlotlyGraphBase} from '@common/shared/experiment-graphs/single-graph/plotly-graph-base';
import {debounceTime, filter} from 'rxjs/operators';
import {ColorHashService} from '../../../shared/services/color-hash/color-hash.service';
import {ColorHashService} from '@common/shared/services/color-hash/color-hash.service';
import {get, getOr, isEqual, max, min, uniq, cloneDeep} from 'lodash/fp';
import {MetricValueType, SelectedMetric} from '../../reducers/experiments-compare-charts.reducer';
import {Task} from '../../../../business-logic/model/tasks/task';
import {Task} from '~/business-logic/model/tasks/task';
import {select} from 'd3-selection';
import {sortCol} from '../../../shared/utils/tableParamEncode';
import {sortCol} from '@common/shared/utils/tableParamEncode';
import {Store} from '@ngrx/store';
import {Axis, Color, ColorScale} from 'plotly.js';
@@ -292,10 +292,10 @@ export class ParallelCoordinatesGraphComponent extends PlotlyGraphBase implement
graph.selectAll('.axis-title').text((d: any) => this.wrap(d.key)).append('title').text(d => (d as any).key);
graph.selectAll('.axis .tick text').text((d: string) => this.wrap(d)).append('title').text((d: string) => d);
graph.selectAll('.axis .tick text').style('pointer-events', 'auto');
graph.selectAll('.tick').on('mouseover', (event, d) => {
const tick = d as unknown as SVGGElement;
graph.selectAll('.tick').on('mouseover', (d, i, e) => {
const tick = e[i] as unknown as SVGGElement;
const axis = tick.parentNode as SVGGElement;
if (axis.lastChild !== tick) {
if (axis && axis.lastChild !== tick) {
axis.removeChild(tick);
axis.appendChild(tick);
}

View File

@@ -1,19 +1,19 @@
import {Injectable} from '@angular/core';
import {act, Actions, Effect, ofType} from '@ngrx/effects';
import {Actions, createEffect, ofType} from '@ngrx/effects';
import {Store} from '@ngrx/store';
import {IExperimentCompareChartsState} from '../reducers/experiments-compare-charts.reducer';
import * as chartActions from '../actions/experiments-compare-charts.actions';
import {GetMultiPlotCharts, GetMultiScalarCharts, setAxisCache} from '../actions/experiments-compare-charts.actions';
import {GetMultiPlotCharts, GetMultiScalarCharts} from '../actions/experiments-compare-charts.actions';
import {activeLoader, deactivateLoader, setServerError} from '../../core/actions/layout.actions';
import {catchError, debounceTime, mergeMap, map, withLatestFrom} from 'rxjs/operators';
import {ApiTasksService} from '../../../business-logic/api-services/tasks.service';
import {ApiAuthService} from '../../../business-logic/api-services/auth.service';
import {BlTasksService} from '../../../business-logic/services/tasks.service';
import {ApiEventsService} from '../../../business-logic/api-services/events.service';
import {ApiTasksService} from '~/business-logic/api-services/tasks.service';
import {ApiAuthService} from '~/business-logic/api-services/auth.service';
import {BlTasksService} from '~/business-logic/services/tasks.service';
import {ApiEventsService} from '~/business-logic/api-services/events.service';
import {requestFailed} from '../../core/actions/http.actions';
import {selectCompareHistogramCacheAxisType, selectCompareSelectedSettingsxAxisType} from '../reducers';
import {setRefreshing} from '../actions/compare-header.actions';
import {ScalarKeyEnum} from '../../../business-logic/model/events/scalarKeyEnum';
import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum';
@Injectable()
@@ -23,14 +23,12 @@ export class ExperimentsCompareChartsEffects {
private authApi: ApiAuthService, private taskBl: BlTasksService, private eventsApi: ApiEventsService) {
}
@Effect()
activeLoader = this.actions$.pipe(
activeLoader = createEffect(() => this.actions$.pipe(
ofType(chartActions.GET_MULTI_SCALAR_CHARTS, chartActions.GET_MULTI_PLOT_CHARTS),
map(action => activeLoader(action.type))
);
));
@Effect()
getMultiScalarCharts = this.actions$.pipe(
getMultiScalarCharts = createEffect(() => this.actions$.pipe(
ofType<GetMultiScalarCharts>(chartActions.GET_MULTI_SCALAR_CHARTS),
debounceTime(200),
withLatestFrom(this.store.select(selectCompareSelectedSettingsxAxisType), this.store.select(selectCompareHistogramCacheAxisType)),
@@ -39,7 +37,7 @@ export class ExperimentsCompareChartsEffects {
[ScalarKeyEnum.IsoTime, ScalarKeyEnum.Timestamp].includes(axisType) &&
prevAxisType !== axisType
) {
return [setRefreshing({payload: false}), deactivateLoader(action.type), setAxisCache({axis: axisType})];
return [setRefreshing({payload: false}), deactivateLoader(action.type)];
}
return this.eventsApi.eventsMultiTaskScalarMetricsIterHistogram({
tasks: action.payload.taskIds,
@@ -57,10 +55,9 @@ export class ExperimentsCompareChartsEffects {
])
);
})
);
));
@Effect()
getMultiPlotCharts = this.actions$.pipe(
getMultiPlotCharts = createEffect(() => this.actions$.pipe(
ofType<GetMultiPlotCharts>(chartActions.GET_MULTI_PLOT_CHARTS),
debounceTime(200),
mergeMap((action) =>
@@ -77,6 +74,6 @@ export class ExperimentsCompareChartsEffects {
])
)
)
);
));
}

View File

@@ -21,7 +21,7 @@ import {selectRouterParams} from '../../core/reducers/router-reducer';
import {selectAppVisible} from '../../core/reducers/view.reducer';
import {MINIMUM_ONLY_FIELDS} from '../../experiments/experiment.consts';
import * as exSelectors from '../../experiments/reducers';
import {selectExperimentsMetricsCols, selectExperimentsTableCols} from '../../experiments/reducers';
import {selectExperimentsMetricsCols, selectExperimentsTableCols, selectTableSortFields} from '../../experiments/reducers';
import {selectSelectedProjectId} from '../../core/reducers/projects.reducer';
import {addMultipleSortColumns} from '../../shared/utils/shared-utils';
@@ -70,7 +70,7 @@ export class SelectCompareHeaderEffects {
tableSortChange = createEffect(() => this.actions.pipe(
ofType(compareAddDialogTableSortChanged),
withLatestFrom(
this.store.select(selectCompareAddTableSortFields),
this.store.select(selectTableSortFields),
this.store.select(selectSelectedProjectId),
this.store.select(selectExperimentsTableCols),
this.store.select(selectExperimentsMetricsCols),
@@ -93,7 +93,7 @@ export class SelectCompareHeaderEffects {
id: action.tasksIds ? action.tasksIds : tasksIds,
only_fields: [...new Set([...MINIMUM_ONLY_FIELDS,
...flatten(cols.filter(col => col.id !== 'selected' && !col.hidden).map(col => col.getter || col.id)),
...(metricCols ? flatten(metricCols.map(col => col.getter || col.id)) : [])])]
...(metricCols ? flatten(metricCols.map(col => col.getter || col.id)) : [])])] as string[]
}).pipe(
mergeMap((res) => [setSearchExperimentsForCompareResults({payload: [...res?.tasks]}), deactivateLoader(action.type)]),
)

View File

@@ -12,8 +12,8 @@ import {
import {createReducer, on} from '@ngrx/store';
import {Params} from '@angular/router';
import {ITableExperiment} from '../../experiments/shared/common-experiment-model.model';
import {commonExperimentsInitialState} from '../../experiments/reducers/common-experiments-view.reducer';
import {SortMeta} from 'primeng/api';
import {FilterMetadata} from 'primeng/api/filtermetadata';
export interface CompareHeaderState {
searchResultsExperiments: ITableExperiment[];
@@ -27,8 +27,8 @@ export interface CompareHeaderState {
navigationPreferences: Params;
experimentsUpdateTime: { [key: string]: Date };
projectColumnsSortOrder: { [projectId: string]: SortMeta[] };
projectColumnFilters: { [projectId: string]: { [columnId: string]: { value: any; matchMode: string } } };
};
projectColumnFilters: { [projectId: string]: { [columnId: string]: FilterMetadata } };
}
export const initialState: CompareHeaderState = {
@@ -67,7 +67,7 @@ const _compareHeader = createReducer(initialState,
on(resetSelectCompareHeader, () => ({...initialState})),
on(compareAddDialogSetTableSort, (state, action) => {
let orders = action.orders.filter(order => action.colIds.includes(order.field));
orders = orders.length > 0 ? orders : commonExperimentsInitialState.tableOrders;
orders = orders.length > 0 ? orders : null;
return {...state, projectColumnsSortOrder: {...state.projectColumnsSortOrder, [action.projectId]: orders}};
}),
on(compareAddTableFilterInit, (state, action) => ({

View File

@@ -1,4 +1,4 @@
import {Task} from '../../../business-logic/model/tasks/task';
import {Task} from '~/business-logic/model/tasks/task';
import {
RESET_EXPERIMENT_METRICS,
SET_EXPERIMENT_HISTOGRAM,
@@ -8,8 +8,8 @@ import {
setAxisCache,
UPDATE_EXPERIMENT_SETTINGS
} from '../actions/experiments-compare-charts.actions';
import {ScalarKeyEnum} from '../../../business-logic/model/events/scalarKeyEnum';
import {GroupByCharts} from '../../experiments/reducers/common-experiment-output.reducer';
import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum';
import {ExperimentSettings} from '../../experiments/reducers/common-experiment-output.reducer';
import {IMultiplot} from '@common/tasks/tasks.utils';
export type MetricValueType = 'min_value' | 'max_value' | 'value';
@@ -42,23 +42,15 @@ export interface IExperimentCompareChartsState {
metricsHistogramCharts: any;
cachedAxisType: ScalarKeyEnum;
metricsPlotsCharts: IMultiplot;
settingsList: Array<IExperimentCompareSettings>;
settingsList: Array<ExperimentCompareSettings>;
searchTerm: string;
showSettingsBar: boolean;
selectedExperiments: Array<string>;
}
export interface IExperimentCompareSettings {
export interface ExperimentCompareSettings extends Omit<ExperimentSettings, 'id' | 'selectedMetric'> {
id: Array<Task['id']>;
hiddenMetricsScalar: Array<string>;
hiddenMetricsPlot: Array<string>;
selectedHyperParams: Array<string>;
selectedMetric: SelectedMetric;
selectedScalar: string;
selectedPlot: string;
smoothWeight: number;
xAxisType: ScalarKeyEnum;
groupBy: GroupByCharts;
}
export const initialState: IExperimentCompareChartsState = {
@@ -85,13 +77,21 @@ export function experimentsCompareChartsReducer(state: IExperimentCompareChartsS
case SET_EXPERIMENT_PLOTS:
return {...state, metricsPlotsCharts: action.payload};
case UPDATE_EXPERIMENT_SETTINGS: {
let newSettings;
const isExperimentExists = state.settingsList.find((setting) => setting.id.join() === action.payload.id.join());
if (isExperimentExists) {
newSettings = state.settingsList.map(setting => setting.id.join() === action.payload.id.join() ? {...setting, ...action.payload.changes} : setting);
let newSettings: ExperimentCompareSettings[];
const changes = {...action.payload.changes, lastModified: (new Date()).getTime()} as ExperimentCompareSettings;
const ids = action.payload.id.join();
const experimentExists = state.settingsList.find((setting) => setting.id.join() === ids);
const discardBefore = new Date()
discardBefore.setMonth(discardBefore.getMonth() - 6);
if (experimentExists) {
newSettings = state.settingsList
.filter(setting => discardBefore < new Date(setting.lastModified || 1648771200000))
.map(setting => setting.id.join() === ids ? {...setting, ...changes} : setting);
} else {
newSettings = state.settingsList.slice();
newSettings.push({id: action.payload.id, ...action.payload.changes});
newSettings = [
...state.settingsList.filter(setting => discardBefore < new Date(setting.lastModified || 1648771200000)),
{id: action.payload.id, ...changes}
];
}
return {...state, settingsList: newSettings};
}

View File

@@ -1,22 +1,18 @@
import {ActionReducerMap, createSelector} from '@ngrx/store';
import {ExperimentCompareDetailsState, experimentsCompareDetailsReducer} from './experiments-compare-details.reducer';
import {experimentsCompareChartsReducer, GroupedHyperParams, IExperimentCompareChartsState, IExperimentCompareSettings, MetricOption, MetricValueType} from './experiments-compare-charts.reducer';
import {experimentsCompareChartsReducer, GroupedHyperParams, IExperimentCompareChartsState, ExperimentCompareSettings, MetricOption, MetricValueType} from './experiments-compare-charts.reducer';
import {experimentsCompareMetricsValuesReducer, IExperimentCompareMetricsValuesState, MetricSortBy} from './experiments-compare-metrics-values.reducer';
import {experimentsCompareDebugImagesReducer} from './experiments-compare-debug-images.reducer';
import {get} from 'lodash/fp';
import {Task} from '../../../business-logic/model/tasks/task';
import {Task} from '~/business-logic/model/tasks/task';
import {compareHeader, CompareHeaderState} from './compare-header.reducer';
import {IExperimentDetail} from '../../../features/experiments-compare/experiments-compare-models';
import {ScalarKeyEnum} from '../../../business-logic/model/events/scalarKeyEnum';
import {IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models';
import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum';
import {scalarsGraphReducer, ScalarsGraphState} from './experiments-compare-scalars-graph.reducer';
import {ExperimentParams} from '../shared/experiments-compare-details.model';
import {ExperimentCompareParamsState, experimentsCompareParamsReducer} from './experiments-compare-params.reducer';
import {GroupByCharts} from '../../experiments/reducers/common-experiment-output.reducer';
import {ITableExperiment} from '../../experiments/shared/common-experiment-model.model';
import {selectSelectedProjectId} from '../../core/reducers/projects.reducer';
import {selectRouterConfig} from '../../core/reducers/router-reducer';
import {TABLE_SORT_ORDER} from '../../shared/ui-components/data/table/table.consts';
import { EXPERIMENTS_TABLE_COL_FIELDS } from '../../../features/experiments/shared/experiments.const';
export const experimentsCompareReducers: ActionReducerMap<any, any> = {
details : experimentsCompareDetailsReducer,
@@ -44,21 +40,22 @@ export const selectExperimentIdsParams = createSelector(selectExperimentsParams,
// select experiments for compare and header
export const selectCompareHeader = createSelector(experimentsCompare, (state): CompareHeaderState => state ? state.compareHeader : {});
export const selectCompareHeader = createSelector(experimentsCompare, state => (state?.compareHeader ?? {}) as CompareHeaderState);
export const selectIsCompare = createSelector(selectRouterConfig, (config): boolean => config?.includes('compare-experiments'));
export const selectIsPipelines = createSelector(selectRouterConfig, (config): boolean => config?.[0] === 'pipelines');
export const selectCompareAddTableSortFields = createSelector(selectCompareHeader, selectSelectedProjectId,
(state, projectId) => state.projectColumnsSortOrder?.[projectId] || [{field: EXPERIMENTS_TABLE_COL_FIELDS.LAST_UPDATE, order: TABLE_SORT_ORDER.DESC}]);
(state, projectId) => state.projectColumnsSortOrder?.[projectId] || null);
export const selectCompareAddTableFilters = createSelector(selectCompareHeader, selectSelectedProjectId,
(state, projectId) => state.projectColumnFilters?.[projectId] || {});
export const selectSelectedExperimentsForCompareAdd = createSelector(selectCompareHeader, (state): ITableExperiment[] => state ? state.searchResultsExperiments : []);
export const selectExperimentsForCompareSearchTerm = createSelector(selectCompareHeader, (state) => state?.searchTerm);
export const selectShowAddExperimentsForCompare = createSelector(selectCompareHeader, (state) => state?.showSearch);
export const selectHideIdenticalFields = createSelector(selectCompareHeader, (state) => state?.hideIdenticalRows);
export const selectShowScalarsOptions = createSelector(selectCompareHeader, (state) => state?.showScalarOptions);
export const selectRefreshing = createSelector(selectCompareHeader, (state) => state ? {refreshing: state.refreshing, autoRefresh: state.autoRefresh} : {refreshing: false, autoRefresh: false});
export const selectExperimentsUpdateTime = createSelector(selectCompareHeader, (state) => state ? state.experimentsUpdateTime : {});
export const selectNavigationPreferences = createSelector(selectCompareHeader, (state) => state ? state.navigationPreferences : {});
export const selectSelectedExperimentsForCompareAdd = createSelector(selectCompareHeader, state => state?.searchResultsExperiments);
export const selectExperimentsForCompareSearchTerm = createSelector(selectCompareHeader, state => state?.searchTerm);
export const selectShowAddExperimentsForCompare = createSelector(selectCompareHeader, state => state?.showSearch);
export const selectHideIdenticalFields = createSelector(selectCompareHeader, state => state?.hideIdenticalRows);
export const selectShowScalarsOptions = createSelector(selectCompareHeader, state => state?.showScalarOptions);
export const selectRefreshing = createSelector(selectCompareHeader, state => state ? {refreshing: state.refreshing, autoRefresh: state.autoRefresh} : {refreshing: false, autoRefresh: false});
export const selectExperimentsUpdateTime = createSelector(selectCompareHeader, state => state ? state.experimentsUpdateTime : {});
export const selectNavigationPreferences = createSelector(selectCompareHeader, state => state ? state.navigationPreferences : {});
// Metric Values
export const compareMetricsValues = createSelector(experimentsCompare, (state): IExperimentCompareMetricsValuesState => state ? state.metricsValues : {});
@@ -68,30 +65,30 @@ export const selectCompareMetricsValuesSortConfig = createSelector(compareMetric
// Charts
export const compareCharts = createSelector(experimentsCompare, (state): IExperimentCompareChartsState => state ? state.charts : {});
export const selectSelectedExperiments = createSelector(compareCharts, (state): Array<string> => state ? state.selectedExperiments : []);
export const selectCompareHistogramCacheAxisType = createSelector(compareCharts, (state) => state.cachedAxisType);
export const selectCompareHistogramCacheAxisType = createSelector(compareCharts, state => state.cachedAxisType);
export const selectCompareTasksPlotCharts = createSelector(compareCharts, state => state.metricsPlotsCharts);
export const selectSelectedExperimentSettings = createSelector(compareCharts, selectSelectedExperiments,
(output, currentExperiments): IExperimentCompareSettings => output.settingsList && output.settingsList.find((setting) => currentExperiments && setting.id.join() === currentExperiments.join()));
(output, currentExperiments): ExperimentCompareSettings => output.settingsList && output.settingsList.find((setting) => currentExperiments && setting.id.join() === currentExperiments.join()));
export const selectSelectedSettingsHiddenPlot = createSelector(selectSelectedExperimentSettings,
(settings): Array<string> => get('hiddenMetricsPlot', settings) || []);
(settings): Array<string> => settings?.hiddenMetricsPlot || []);
export const selectSelectedSettigsHyperParams = createSelector(selectSelectedExperimentSettings,
(settings): Array<string> => get('selectedHyperParams', settings) || []);
export const selectSelectedSettingsHyperParams = createSelector(selectSelectedExperimentSettings,
(settings): Array<string> => settings?.selectedHyperParams || []);
export const selectSelectedSettigsMetric = createSelector(selectSelectedExperimentSettings,
(settings) => get('selectedMetric', settings) || null);
export const selectSelectedSettingsMetric = createSelector(selectSelectedExperimentSettings,
(settings) => settings?.selectedMetric || null);
export const selectSelectedSettingsHiddenScalar = createSelector(selectSelectedExperimentSettings,
(settings): Array<string> => get('hiddenMetricsScalar', settings) || []);
(settings): Array<string> => settings?.hiddenMetricsScalar || []);
export const selectExperimentMetricsSearchTerm = createSelector(compareCharts, (state) => state.searchTerm);
export const selectCompareSelectedSettingsSmoothWeight = createSelector(selectSelectedExperimentSettings,
(settings): number => get('smoothWeight', settings) || 0);
(settings): number => settings?.smoothWeight || 0);
export const selectCompareSelectedSettingsxAxisType = createSelector(selectSelectedExperimentSettings,
(settings): ScalarKeyEnum => get('xAxisType', settings) || ScalarKeyEnum.Iter);
settings => settings?.xAxisType ?? ScalarKeyEnum.Iter as ScalarKeyEnum);
export const selectCompareSelectedSettingsGroupBy = createSelector(selectSelectedExperimentSettings,
(settings): GroupByCharts => settings?.groupBy || GroupByCharts.None);

View File

@@ -1,10 +1,10 @@
import {Action, createAction, props} from '@ngrx/store';
import {ISelectedExperiment} from '../../../features/experiments/shared/experiment-info.model';
import {IExperimentSettings} from '../reducers/common-experiment-output.reducer';
import {ScalarKeyEnum} from '../../../business-logic/model/events/scalarKeyEnum';
import {MetricsPlotEvent} from '../../../business-logic/model/events/metricsPlotEvent';
import {EventsScalarMetricsIterRawRequest} from '../../../business-logic/model/events/eventsScalarMetricsIterRawRequest';
import {EventsScalarMetricsIterRawResponse} from '../../../business-logic/model/events/eventsScalarMetricsIterRawResponse';
import {ISelectedExperiment} from '~/features/experiments/shared/experiment-info.model';
import {ExperimentSettings} from '../reducers/common-experiment-output.reducer';
import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum';
import {MetricsPlotEvent} from '~/business-logic/model/events/metricsPlotEvent';
import {EventsScalarMetricsIterRawRequest} from '~/business-logic/model/events/eventsScalarMetricsIterRawRequest';
import {EventsScalarMetricsIterRawResponse} from '~/business-logic/model/events/eventsScalarMetricsIterRawResponse';
export const EXPERIMENTS_OUTPUT_PREFIX = 'EXPERIMENTS_OUTPUT_';
@@ -114,7 +114,7 @@ export const setExperimentLog = createAction(
export class SetExperimentSettings implements Action {
readonly type = UPDATE_EXPERIMENT_SETTINGS;
constructor(public payload: { id: string; changes: Partial<IExperimentSettings> }) {
constructor(public payload: { id: string; changes: Partial<ExperimentSettings> }) {
}
}

View File

@@ -1,14 +1,11 @@
import {Action, createAction, props} from '@ngrx/store';
import {Task} from '../../../business-logic/model/tasks/task';
import {IExperimentInfo, ISelectedExperiment} from '../../../features/experiments/shared/experiment-info.model';
import {Model} from '../../../business-logic/model/models/model';
import {Task} from '~/business-logic/model/tasks/task';
import {IExperimentInfo, ISelectedExperiment} from '~/features/experiments/shared/experiment-info.model';
import {ITableExperiment} from '../shared/common-experiment-model.model';
import {ParamsItem} from '../../../business-logic/model/tasks/paramsItem';
import {ConfigurationItem} from '../../../business-logic/model/tasks/configurationItem';
import {IExperimentInfoState} from '../../../features/experiments/reducers/experiment-info.reducer';
import {experimentSectionsEnum} from '../../../features/experiments/shared/experiments.const';
import {ParamsItem} from '~/business-logic/model/tasks/paramsItem';
import {ConfigurationItem} from '~/business-logic/model/tasks/configurationItem';
import {IExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer';
import {ActivatedRoute} from '@angular/router';
import {ITask} from '../../../business-logic/model/al-task';
export const EXPERIMENTS_INFO_PREFIX = 'EXPERIMENTS_INFO_';
export const GET_EXPERIMENT_INFO = EXPERIMENTS_INFO_PREFIX + 'GET_EXPERIMENT_INFO';
@@ -113,7 +110,21 @@ export const setExperimentSaving = createAction(
EXPERIMENTS_INFO_PREFIX + 'SET_SAVING', props<{ saving: boolean }>());
export const getExperimentConfigurationObj = createAction(
EXPERIMENTS_INFO_PREFIX + 'GET_CONFIGURATION_OBJ');
EXPERIMENTS_INFO_PREFIX + 'GET_CONFIGURATION_OBJ',
);
export const getPipelineConfigurationObj = createAction(
EXPERIMENTS_INFO_PREFIX + 'GET_PIPELINE_CONFIGURATION_OBJ',
);
export const getSelectedPipelineStep = createAction(
EXPERIMENTS_INFO_PREFIX + 'GET_PIPELINE_STEP',
props<{ id:string }>()
);
export const setSelectedPipelineStep = createAction(
EXPERIMENTS_INFO_PREFIX + 'SET_PIPELINE_STEP',
props<{ step:IExperimentInfo }>()
);
export const updateExperimentAtPath = createAction(
EXPERIMENTS_INFO_PREFIX + 'UPDATE_EXPERIMENT_AT_PATH',
@@ -167,7 +178,6 @@ export class DeactivateEdit implements Action {
export class SetExperimentFormErrors implements Action {
readonly type = SET_EXPERIMENT_FORM_ERRORS;
constructor(public payload: { [key: string]: any } | null) {
}
}

View File

@@ -1,8 +1,10 @@
import {Action, createAction, props} from '@ngrx/store';
import {ISelectedExperiment} from '../../../features/experiments/shared/experiment-info.model';
import {Project} from '../../../business-logic/model/projects/project';
import {Queue} from '../../../business-logic/model/queues/queue';
import {ISelectedExperiment} from '~/features/experiments/shared/experiment-info.model';
import {Project} from '~/business-logic/model/projects/project';
import {Queue} from '~/business-logic/model/queues/queue';
import {CloneExperimentPayload, ITableExperiment} from '../shared/common-experiment-model.model';
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
import { PipelinesStartPipelineRequest } from '~/business-logic/model/pipelines/pipelinesStartPipelineRequest';
export const EXPERIMENTS_INFO_PREFIX = 'EXPERIMENTS_INFO_';
@@ -19,6 +21,21 @@ export const stopClicked = createAction(
EXPERIMENTS_INFO_PREFIX + '[stop experiments]',
props<{ selectedEntities: ISelectedExperiment[] }>()
);
export const startPipeline = createAction(
EXPERIMENTS_INFO_PREFIX + '[start pipeline]',
props<PipelinesStartPipelineRequest>()
);
export const getControllerForStartPipelineDialog = createAction(
EXPERIMENTS_INFO_PREFIX + '[Get Controller For Start Pipeline]',
props<{task:string}>()
);
export const setControllerForStartPipelineDialog = createAction(
EXPERIMENTS_INFO_PREFIX + '[Set Controller For Start Pipeline]',
props<{task:Task}>()
);
export const changeProjectRequested = createAction(
EXPERIMENTS_INFO_PREFIX + '[change project requested]',
@@ -42,14 +59,9 @@ export const addTag = createAction(
props<{ experiments: Partial<ITableExperiment>[]; tag: string }>()
);
export const getAllTasksChildren = createAction(
export const abortAllChildren = createAction(
EXPERIMENTS_INFO_PREFIX + '[get all tasks children]',
props<{ experiments: string[]}>()
);
export const setAllTasksChildren = createAction(
EXPERIMENTS_INFO_PREFIX + '[set all tasks children]',
props<{ experiments: ITableExperiment[]}>()
props<{ experiments: ISelectedExperiment[]}>()
);
export const removeTag = createAction(
@@ -78,10 +90,10 @@ export const enqueueClicked = createAction(
export const archiveSelectedExperiments = createAction(
EXPERIMENTS_INFO_PREFIX + '[archive selected experiments]',
props<{ selectedEntities: ISelectedExperiment[]; skipUndo?: boolean }>()
props<{ selectedEntities: ISelectedExperiment[]; skipUndo?: boolean; entityType?: EntityTypeEnum }>()
);
export const restoreSelectedExperiments = createAction(
EXPERIMENTS_INFO_PREFIX + '[restore selected experiments]',
props<{ selectedEntities: ISelectedExperiment[]; skipUndo?: boolean }>()
props<{ selectedEntities: ISelectedExperiment[]; skipUndo?: boolean; entityType?: EntityTypeEnum }>()
);

View File

@@ -1,13 +1,13 @@
import {createAction, props} from '@ngrx/store';
import {ITableExperiment} from '../shared/common-experiment-model.model';
import {ISmCol} from '../../shared/ui-components/data/table/table.consts';
import {MetricVariantResult} from '../../../business-logic/model/projects/metricVariantResult';
import {MetricVariantResult} from '~/business-logic/model/projects/metricVariantResult';
import {TableFilter} from '../../shared/utils/tableParamEncode';
import {User} from '../../../business-logic/model/users/user';
import {ProjectsGetTaskParentsResponseParents} from '../../../business-logic/model/projects/projectsGetTaskParentsResponseParents';
import {User} from '~/business-logic/model/users/user';
import {ProjectsGetTaskParentsResponseParents} from '~/business-logic/model/projects/projectsGetTaskParentsResponseParents';
import {SortMeta} from 'primeng/api';
import {CountAvailableAndIsDisableSelectedFiltered} from '@common/shared/entity-page/items.utils';
import {TasksEnqueueManyResponseSucceeded} from '../../../business-logic/model/tasks/tasksEnqueueManyResponseSucceeded';
import {TasksEnqueueManyResponseSucceeded} from '~/business-logic/model/tasks/tasksEnqueueManyResponseSucceeded';
import {EXPERIMENTS_INFO_PREFIX} from '@common/experiments/actions/common-experiments-menu.actions';
export const EXPERIMENTS_PREFIX = 'EXPERIMENTS_';
@@ -18,6 +18,11 @@ export const getExperimentsWithPageSize = createAction(EXPERIMENTS_PREFIX + ' [g
props<{pageSize: number}>());
export const getNextExperiments = createAction(EXPERIMENTS_PREFIX + '[get next experiments]');
export const setTableCols = createAction(
EXPERIMENTS_PREFIX + ' [set table cols]',
props<{ cols: ISmCol[]}>()
);
export const refreshExperiments = createAction(
EXPERIMENTS_PREFIX + ' [refresh experiment]',
props<{ hideLoader: boolean; autoRefresh?: boolean}>()
@@ -25,7 +30,7 @@ export const refreshExperiments = createAction(
export const setExperiments = createAction(
EXPERIMENTS_PREFIX + ' [set experiments]',
props<{experiments: ITableExperiment[]}>()
props<{experiments: ITableExperiment[], noPreferences?: boolean}>()
);
export const setExperimentInPlace = createAction(
@@ -63,6 +68,8 @@ export const setSelectedExperiments = createAction(
props<{experiments: ITableExperiment[]}>()
);
export const updateUrlParams = createAction(EXPERIMENTS_PREFIX + '[update URL params from state]');
export const setSelectedExperiment = createAction(
EXPERIMENTS_PREFIX + ' [set selected experiment]',
props<{experiment: ITableExperiment}>()
@@ -83,10 +90,14 @@ export const toggleColHidden = createAction(
props<{columnId: string; projectId: string}>()
);
export const setHiddenColumns = createAction(
EXPERIMENTS_PREFIX + 'SET_HIDDEN_COLS',
export const setVisibleColumnsForProject = createAction(
EXPERIMENTS_PREFIX + 'SET_HIDDEN_COLS_FOR_PROJECT',
props<{ visibleColumns: string[]; projectId: string }>()
);
export const setHiddenCols = createAction(
EXPERIMENTS_PREFIX + 'SET_HIDDEN_COLS',
props<{ hiddenCols: { [key: string]: boolean } }>()
);
export const setUsers = createAction(
EXPERIMENTS_PREFIX + 'SET_USERS',
@@ -109,7 +120,7 @@ export const getFilteredUsers = createAction(EXPERIMENTS_PREFIX + 'GET_FILTERED_
export const tableFilterChanged = createAction(
EXPERIMENTS_PREFIX + '[table filter changed]',
props<{filter: TableFilter; projectId: string}>()
props<{filters: TableFilter[]; projectId: string}>()
);
export const tableSortChanged = createAction(
@@ -186,7 +197,7 @@ export const setColumnWidth = createAction(
export const setColsOrderForProject = createAction(
EXPERIMENTS_PREFIX + ' [set cols order]',
props<{ cols: string[]; project: string; fromUrl?: boolean }>()
props<{ cols: string[]; project: string;}>()
);
export const clearHyperParamsCols = createAction(
@@ -199,13 +210,6 @@ export const resetSortOrder = createAction(
props<{sortIndex: number; projectId: string}>()
);
export const setArchive = createAction(
EXPERIMENTS_PREFIX + 'SET_ARCHIVE',
props<{ archive: boolean }>()
);
export const afterSetArchive = createAction(EXPERIMENTS_PREFIX + 'AFTER_SET_ARCHIVE');
export const setSplitSize = createAction(EXPERIMENTS_PREFIX + 'SET_SPLIT_SIZE', props<{ splitSize: number }>());
export const hyperParamSelectedInfoExperiments = createAction(

View File

@@ -11,7 +11,6 @@ import {ExperimentHeaderComponent} from './dumb/experiment-header/experiment-hea
import {ExperimentInfoHeaderComponent} from './dumb/experiment-info-header/experiment-info-header.component';
import {ExperimentInfoGeneralComponent} from './containers/experiment-info-general/experiment-info-general.component';
import {ExperimentGeneralInfoComponent} from './dumb/experiment-general-info/experiment-general-info.component';
import {ExperimentNetworkDesignFormComponent} from './dumb/experiment-network-design-form/experiment-network-design-form.component';
import {ExperimentModelsFormViewComponent} from './dumb/experiment-models-form-view/experiment-models-form-view.component';
import {ExperimentExecutionSourceCodeComponent} from './dumb/experiment-execution-source-code/experiment-execution-source-code.component';
import {ExperimentExecutionParametersComponent} from './dumb/experiment-execution-parameters/experiment-execution-parameters.component';
@@ -21,7 +20,7 @@ import {ModelAutoPopulateDialogComponent} from './dumb/model-auto-populate-dialo
import {ExperimentTableCardComponent} from './dumb/experiment-table-card/experiment-table-card.component';
import {SMSharedModule} from '../shared/shared.module';
import {CommonLayoutModule} from '../layout/layout.module';
import {ExperimentSharedModule} from '../../features/experiments/shared/experiment-shared.module';
import {ExperimentSharedModule} from '~/features/experiments/shared/experiment-shared.module';
import {CommonExperimentSharedModule} from './shared/common-experiment-shared.module';
import {RouterModule} from '@angular/router';
import {SMMaterialModule} from '../shared/material/material.module';
@@ -47,7 +46,7 @@ import {NoUnderscorePipe} from '../shared/pipes/no-underscore.pipe';
import {ExperimentHyperParamsNavbarComponent} from './dumb/experiment-hyper-params-navbar/experiment-hyper-params-navbar.component';
import {ExperimentInfoTaskModelComponent} from './containers/experiment-info-task-model/experiment-info-task-model.component';
import {ExperimentInfoHyperParametersFormContainerComponent} from './containers/experiment-info-hyper-parameters-form-container/experiment-info-hyper-parameters-form-container.component';
import {SharedModule} from '../../shared/shared.module';
import {SharedModule} from '~/shared/shared.module';
import {CommonDeleteDialogModule} from '../shared/entity-page/entity-delete/common-delete-dialog.module';
import {ExperimentInfoEditDescriptionComponent} from './dumb/experiment-info-edit-description/experiment-info-edit-description.component';
import {ExperimentOutputLogModule} from './shared/experiment-output-log/experiment-output-log.module';
@@ -71,7 +70,6 @@ import { GetVariantWithoutRoundPipe } from './dumb/experiments-table/hyper-param
ExperimentInfoTaskModelComponent,
ExperimentInfoGeneralComponent,
ExperimentGeneralInfoComponent,
ExperimentNetworkDesignFormComponent,
ExperimentModelsFormViewComponent,
ExperimentOutputModelViewComponent,
ExperimentExecutionSourceCodeComponent,
@@ -98,7 +96,7 @@ import { GetVariantWithoutRoundPipe } from './dumb/experiments-table/hyper-param
ExperimentInfoHeaderComponent,
ExperimentExecutionSourceCodeComponent,
SelectMetricForCustomColComponent,
ExperimentExecutionParametersComponent,ExperimentsTableComponent],
ExperimentExecutionParametersComponent, ExperimentsTableComponent, ExperimentHeaderComponent],
imports: [
AngularSplitModule,
ScrollingModule,

View File

@@ -59,13 +59,12 @@
>
<button extra-buttons
*ngIf="formData.diff && editable && !showExtraDataSpinner"
class="btn-dark-fill mr-3 flex-1"
class="btn-dark-fill terminal mr-3 flex-1"
(click)="diffSection.editModeChanged(true)">EDIT</button>
<button extra-buttons
*ngIf="formData.diff && editable && !showExtraDataSpinner"
class="btn-dark-fill mr-3 flex-1"
class="btn-dark-fill terminal mr-3 flex-1"
(click)="discardDiff()">
<i class="p-1 fa fa-trash"></i>
DISCARD DIFFS
</button>
</sm-scroll-textarea>
@@ -90,13 +89,12 @@
[formData]="formData.requirements?.pip">
<button extra-buttons
*ngIf="formData?.requirements?.pip && editable && !showExtraDataSpinner"
class="btn-dark-fill mr-3 flex-1"
class="btn-dark-fill terminal mr-3 flex-1"
(click)="requirementsSection.editModeChanged(true)">EDIT</button>
<button extra-buttons
*ngIf="formData.requirements?.pip && editable && !showExtraDataSpinner"
class="btn-dark-fill mr-3 flex-1"
class="btn-dark-fill terminal mr-3 flex-1"
(click)="clearInstalledPackages()">
<i class="p-1 fa fa-trash"></i>
CLEAR
</button>
</sm-scroll-textarea>
@@ -144,13 +142,12 @@
[formData]="formData?.container?.setup_shell_script">
<button extra-buttons
*ngIf="formData?.container?.setup_shell_script && editable && !showExtraDataSpinner"
class="btn-dark-fill mr-3 flex-1"
class="btn-dark-fill terminal mr-3 flex-1"
(click)="containerSetupShellSection.editModeChanged(true)">EDIT</button>
<button extra-buttons
*ngIf="formData.container?.setup_shell_script && editable && !showExtraDataSpinner"
class="btn-dark-fill mr-3 flex-1"
class="btn-dark-fill terminal mr-3 flex-1"
(click)="clearSetupShellScript()">
<i class="p-1 fa fa-trash"></i>
CLEAR
</button>
</sm-scroll-textarea>

View File

@@ -68,12 +68,6 @@
padding: 5px 15px;
}
.btn-dark-fill {
background-color: $blue-600;
color: #a7b2d8;
margin: 0 6px !important;
}
.copy-textarea {
position: absolute;
right: 32px;

View File

@@ -1,5 +1,6 @@
<sm-overlay [backdropActive]="backdropActive$|async"></sm-overlay>
<sm-editable-section #parameterSection
class="light-theme"
*ngIf="(selectedSectionHyperParams$| async).length>0 || propSection"
[editable]="(!isExample) && ((editable$ | async) || propSection)"
[disableSave]="!executionParamsForm?.hyperParameters?.form?.valid"
@@ -10,14 +11,15 @@
<sm-section-header [label]="(selectedSection | replaceViaMapPipe:sectionReplaceMap) | uppercase "></sm-section-header>
<sm-search search-button
#search
class="table-search dark-theme"
[enableJumpToNextResult]="true"
[minimumChars]="0"
class="table-search"
[value]="searchedText"
[enableNavigation]="true"
[minimumChars]="1"
[debounceTime]="0"
[expandOnHover]="true"
[searchResultsCount]="searchResultsCount"
[searchCounterIndex]="executionParamsForm.matchIndex"
(valueChanged)="searchTable($event)"
(jumpToResult)="executionParamsForm.jumpToResult($event)"
></sm-search>
<sm-experiment-execution-parameters
#executionParamsForm
@@ -29,6 +31,6 @@
(formDataChanged)="onFormValuesChanged($event)"
(searchCounterChanged)="searchCounterChanged($event)"
(resetSearch)="search.clear(false)"
(scrollToResultCounterChanged)="scrollIndexCounterChanged($event)"
(scrollToResultCounterReset)="scrollIndexCounterReset()"
></sm-experiment-execution-parameters>
</sm-editable-section>

View File

@@ -15,8 +15,9 @@
height: calc(100% - 42px);
}
sm-search.table-search {
padding-right: 2px;
border-radius: 4px;
color: #a7b2d8 !important;
color: $blue-280 !important;
background-color: $blue-600 !important;
}
}

View File

@@ -7,11 +7,11 @@ import {
selectIsSelectedExperimentInDev
} from '../../reducers';
import {ICommonExperimentInfoState} from '../../reducers/common-experiment-info.reducer';
import {IExperimentInfo} from '../../../../features/experiments/shared/experiment-info.model';
import {selectBackdropActive} from '../../../core/reducers/view.reducer';
import {IExperimentInfo} from '~/features/experiments/shared/experiment-info.model';
import {selectBackdropActive} from '@common/core/reducers/view.reducer';
import {Observable, Subscription} from 'rxjs';
import {selectIsExperimentEditable, selectSelectedExperiment} from '../../../../features/experiments/reducers';
import {selectRouterConfig} from '../../../core/reducers/router-reducer';
import {selectIsExperimentEditable, selectSelectedExperiment} from '~/features/experiments/reducers';
import {selectRouterConfig} from '@common/core/reducers/router-reducer';
import {
ActivateEdit,
CancelExperimentEdit,
@@ -21,11 +21,11 @@ import {
SetExperimentFormErrors,
updateExperimentAtPath
} from '../../actions/common-experiments-info.actions';
import {ParamsItem} from '../../../../business-logic/model/tasks/paramsItem';
import {ParamsItem} from '~/business-logic/model/tasks/paramsItem';
import {HELP_TEXTS} from '../../shared/common-experiments.const';
import {Router} from '@angular/router';
import {ExperimentExecutionParametersComponent} from '../../dumb/experiment-execution-parameters/experiment-execution-parameters.component';
import {isReadOnly} from '../../../shared/utils/shared-utils';
import {isReadOnly} from '@common/shared/utils/shared-utils';
@Component({
selector : 'sm-experiment-info-hyper-parameters-form-container',
@@ -112,9 +112,16 @@ export class ExperimentInfoHyperParametersFormContainerComponent implements OnIn
this.store.dispatch(new DeactivateEdit());
}
searchTable($event: string) {
this.searchedText = $event;
this.cdr.detectChanges();
searchTable(value: string) {
const searchBackward = value === null;
if (this.searchedText !== value && !searchBackward) {
this.searchedText = value;
this.scrollIndexCounter = -1;
this.searchResultsCount = 0;
this.executionParamsForm.resetIndex();
this.cdr.detectChanges();
}
this.executionParamsForm.jumpToNextResult(!searchBackward)
}
searchCounterChanged(count: number) {
@@ -122,8 +129,8 @@ export class ExperimentInfoHyperParametersFormContainerComponent implements OnIn
this.cdr.detectChanges();
}
scrollIndexCounterChanged(counterIndex: number) {
this.scrollIndexCounter = counterIndex;
scrollIndexCounterReset() {
this.scrollIndexCounter = -1;
this.cdr.detectChanges();
}
}

View File

@@ -26,20 +26,16 @@
</sm-experiment-models-form-view>
</sm-editable-section>
<sm-editable-section class="editable-design"
#prototext
[saving]="saving"
[editable]="false"
[disableInEditMode]="true"
containerClass="h-100"
(cancelClicked)="cancelModelChange()">
<sm-section-header *ngIf="model?.id" label="MODEL CONFIGURATION"></sm-section-header>
<sm-experiment-network-design-form
#networkDesignForm
*ngIf="model?.id"
<sm-scroll-textarea
class="flex-grow-1"
[editable]="false"
[formData]="inputDesign"
>
</sm-experiment-network-design-form>
></sm-scroll-textarea>
</sm-editable-section>
</ng-template>

Some files were not shown because too many files have changed in this diff Show More