release v1.7 (#35)

This commit is contained in:
shyallegro
2022-11-01 12:40:14 +02:00
committed by GitHub
parent b96f723af1
commit 94308aaa45
406 changed files with 11934 additions and 9245 deletions

View File

@@ -26,7 +26,8 @@
"assets": [
"src/assets",
"src/favicon.ico",
"src/env.js",
"src/env.js",
"src/version.json",
"src/app/webapp-common/assets",
{
"glob": "**/*",
@@ -57,7 +58,15 @@
"@aws-crypto/sha256-browser",
"@aws-crypto/crc32",
"@aws-crypto/sha1-browser",
"@aws-crypto/crc32c"
"@aws-crypto/crc32c",
"filesize/lib/filesize.es6",
"hex-rgb",
"britecharts/dist/umd/donut.min",
"britecharts/dist/umd/legend.min",
"britecharts/dist/umd/line.min",
"britecharts/dist/umd/tooltip.min",
"britecharts/dist/umd/miniTooltip.min",
"britecharts/dist/umd/scatterPlot.min"
],
"vendorChunk": true,
"extractLicenses": false,
@@ -88,69 +97,6 @@
}
]
},
"demo": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.demo.ts"
}
]
},
"guest": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.ignite.ts"
}
]
},
"community": {
"budgets": [
{
"type": "anyComponentStyle",
"maximumWarning": "6kb"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.community.ts"
}
]
},
"production": {
"budgets": [
{
@@ -169,6 +115,10 @@
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
},
{
"replace": "src/app/build-specifics/index.ts",
"with": "src/app/build-specifics/index.prod.ts"
}
]
}
@@ -216,6 +166,7 @@
"assets": [
"src/assets",
"src/favicon.ico",
"src/version.json",
"src/app/webapp-common/assets"
]
}
@@ -257,7 +208,6 @@
}
}
},
"defaultProject": "trains-webapp",
"schematics": {
"@schematics/angular:component": {
"prefix": "sm",

12725
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,13 @@
{
"name": "ClearML-webapp",
"version": "1.6.0",
"name": "clearml-webapp",
"version": "1.7.0",
"license": "",
"scripts": {
"ng": "ng",
"start": "npx ng serve --proxy-config proxy.config.js --live-reload false --port 4300",
"hmr": "npx ng serve --proxy-config proxy.config.js --hmr --port 4300",
"build": "node --max_old_space_size=3248 ./node_modules/.bin/ng build --configuration production --source-map --vendor-chunk --crossOrigin=use-credentials",
"build-demo": "node --max_old_space_size=3248 ./node_modules/.bin/ng build --configuration demo --source-map --extract-css=false --crossOrigin=use-credentials",
"build-guest": "node --max_old_space_size=3248 ./node_modules/.bin/ng build --configuration production --configuration guest --source-map --extract-css=false --crossOrigin=use-credentials",
"build-community": "node --max_old_space_size=3248 ./node_modules/.bin/ng build --configuration production --configuration community --source-map --extract-css=false --crossOrigin=use-credentials",
"build-dev": "node ./node_modules/.bin/ng build --extract-css=false --crossOrigin=use-credentials",
"build": "node --max_old_space_size=3248 ./node_modules/.bin/ng build --configuration production --source-map --vendor-chunk",
"build-dev": "node ./node_modules/.bin/ng build --extract-css=false",
"fetch": "./scripts/get-remote-build.sh",
"test": "ng test",
"lint": "ng lint",
@@ -20,28 +17,28 @@
},
"private": true,
"dependencies": {
"@angular/animations": "^13.3.7",
"@angular/cdk": "^13.3.7",
"@angular/common": "^13.3.7",
"@angular/compiler": "^13.3.7",
"@angular/core": "^13.3.7",
"@angular/forms": "^13.3.7",
"@angular/material": "^13.3.7",
"@angular/platform-browser": "^13.3.7",
"@angular/platform-browser-dynamic": "^13.3.7",
"@angular/platform-server": "^13.3.7",
"@angular/router": "^13.3.7",
"@angular/service-worker": "^13.3.7",
"@angular/youtube-player": "^13.3.7",
"@aws-sdk/client-s3": "^3.88.0",
"@aws-sdk/s3-request-presigner": "^3.88.0",
"@angular/animations": "^14.1.0",
"@angular/cdk": "^14.1.0",
"@angular/common": "^14.1.0",
"@angular/compiler": "^14.1.0",
"@angular/core": "^14.1.0",
"@angular/forms": "^14.1.0",
"@angular/material": "^14.1.0",
"@angular/platform-browser": "^14.1.0",
"@angular/platform-browser-dynamic": "^14.1.0",
"@angular/platform-server": "^14.1.0",
"@angular/router": "^14.1.0",
"@angular/service-worker": "^14.1.0",
"@angular/youtube-player": "^14.1.0",
"@aws-sdk/client-s3": "^3.118.1",
"@aws-sdk/s3-request-presigner": "^3.118.1",
"@ngneat/dag": "^2.0.0",
"@ngrx/effects": "^13.2.0",
"@ngrx/entity": "^13.2.0",
"@ngrx/router-store": "^13.2.0",
"@ngrx/store": "^13.2.0",
"ace-builds": "^1.5.0",
"angular-google-tag-manager": "^1.5.0",
"@ngrx/effects": "^14.0.2",
"@ngrx/entity": "^14.0.2",
"@ngrx/router-store": "^14.0.2",
"@ngrx/store": "^14.0.2",
"ace-builds": "^1.6.1",
"angular-google-tag-manager": "^1.6.0",
"angular-resizable-element": "^5.0.0",
"angular-split": "^13.2.0",
"ansi-to-html": "^0.7.2",
@@ -49,8 +46,9 @@
"britecharts": "^2.18.0",
"curved-arrows": "^0.1.0",
"d3-selection": "^3.0.0",
"diff": "^5.0.0",
"filesize": "^8.0.7",
"diff": "^5.1.0",
"dom-to-image": "^2.6.0",
"filesize": "^9.0.11",
"has-ansi": "^5.0.1",
"hocon-parser": "^1.0.1",
"jwt-decode": "^3.1.2",
@@ -62,42 +60,43 @@
"ngx-window-token": "^6.0.0",
"object-hash": "^3.0.0",
"primeicons": "^5.0.0",
"primeng": "^13.4.0",
"primeng": "^14.1.0",
"process": "^0.11.10",
"rxjs": "^7.5.5",
"string-to-color": "^2.2.2",
"tslib": "^2.4.0",
"url": "^0.11.0",
"uuid": "^8.3.2",
"zone.js": "~0.11.5"
"zone.js": "~0.11.6"
},
"devDependencies": {
"@angular-devkit/build-angular": "^13.3.5",
"@angular-devkit/core": "^13.3.5",
"@angular-devkit/schematics": "^13.3.5",
"@angular-devkit/schematics-cli": "^13.3.5",
"@angular-eslint/builder": "^13.2.1",
"@angular-eslint/eslint-plugin": "^13.2.1",
"@angular-eslint/eslint-plugin-template": "^13.2.1",
"@angular-eslint/schematics": "13.2.1",
"@angular-eslint/template-parser": "^13.2.1",
"@angular/cli": "^13.3.5",
"@angular/compiler-cli": "^13.3.7",
"@angular/language-service": "^13.3.7",
"@angular-devkit/build-angular": "^14.1.0",
"@angular-devkit/core": "^14.1.0",
"@angular-devkit/schematics": "^14.1.0",
"@angular-devkit/schematics-cli": "^14.0.3",
"@angular-eslint/builder": "^14.0.2",
"@angular-eslint/eslint-plugin": "^14.0.2",
"@angular-eslint/eslint-plugin-template": "^14.0.2",
"@angular-eslint/schematics": "14.0.2",
"@angular-eslint/template-parser": "^14.0.2",
"@angular/cli": "^14.1.0",
"@angular/compiler-cli": "^14.1.0",
"@angular/language-service": "^14.1.0",
"@fortawesome/fontawesome-free": "^6.1.1",
"@ngrx/schematics": "^13.2.0",
"@ngrx/store-devtools": "^13.2.0",
"@ngrx/schematics": "^14.0.2",
"@ngrx/store-devtools": "^14.0.2",
"@types/d3-selection": "^3.0.2",
"@types/lodash": "^4.14.182",
"@types/node": "^16.11.19",
"@types/plotly.js": "^1.54.20",
"@types/plotly.js": "^1.54.22",
"@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "5.23.0",
"@typescript-eslint/parser": "5.23.0",
"eslint": "^8.15.0",
"@typescript-eslint/eslint-plugin": "^5.30.0",
"@typescript-eslint/parser": "^5.30.0",
"codelyzer": "^6.0.2",
"eslint": "^8.18.0",
"eslint-plugin-import": "2.26.0",
"eslint-plugin-jsdoc": "39.2.9",
"eslint-plugin-jsdoc": "39.3.3",
"eslint-plugin-prefer-arrow": "1.2.3",
"typescript": "~4.6.4"
"typescript": "~4.7.4"
}
}

View File

@@ -8,11 +8,11 @@
<sm-color-picker-wrapper id="color-picker-outlet"></sm-color-picker-wrapper>
<sm-server-notification-dialog-container></sm-server-notification-dialog-container>
<sm-spinner></sm-spinner>
<sm-side-nav *ngIf="currentUser"></sm-side-nav>
<div class="app-container" [class.login-page]="!currentUser"
[class.notifier-open]="update?.active">
<sm-header *ngIf="currentUser" [isLogin]="isLoginContext"
[isShareMode]="isSharedAndNotOwner$ | async"></sm-header>
<router-outlet class="main-router"></router-outlet>
<div class="root-container">
<sm-side-nav *ngIf="currentUser"></sm-side-nav>
<div class="app-container" [class.login-page]="!currentUser" [class.notifier-open]="update?.active">
<sm-header *ngIf="currentUser" [isLogin]="isLoginContext" [isShareMode]="isSharedAndNotOwner$ | async"></sm-header>
<router-outlet class="main-router"></router-outlet>
</div>
</div>
<notifier-container></notifier-container>

View File

@@ -3,40 +3,41 @@
$notifier-height: 30px;
.app-container {
notification-container {
position: relative;
width: 100%;
height: 100%;
&:not(.login-page) {
margin-left: $side-bar-close-width;
}
&.notifier-open {
height: calc(100% - #{$notifier-height});
.main-router + * {
height: calc(100% - #{$top-bar-height});
}
}
.main-router + * {
display: block;
height: calc(100% - #{$top-bar-height});
}
&.login-page {
.main-router + * {
height: 100%;
}
}
}
sm-side-nav {
display: block;
position: fixed;
top: 0;
z-index: 999;
.root-container {
display: flex;
height: 100%;
width: 100%;
.app-container {
flex: 1;
height: 100%;
width: calc(100% - #{$side-bar-close-width});
&.notifier-open {
height: calc(100% - #{$notifier-height});
.main-router + * {
height: calc(100% - #{$top-bar-height});
}
}
.main-router + * {
display: block;
height: calc(100% - #{$top-bar-height});
}
&.login-page {
.main-router + * {
height: 100%;
}
}
}
}
#color-picker-outlet {

View File

@@ -5,7 +5,7 @@ import {ActivatedRoute, NavigationEnd, Router, Params, RouterEvent} from '@angul
import {Title} from '@angular/platform-browser';
import {selectLoggedOut} from '@common/core/reducers/view.reducer';
import {Store} from '@ngrx/store';
import {get} from 'lodash/fp';
import {castArray, get, last} from 'lodash/fp';
import {selectRouterParams, selectRouterUrl} from '@common/core/reducers/router-reducer';
import {ApiProjectsService} from './business-logic/api-services/projects.service';
import {Project} from './business-logic/model/projects/project';
@@ -226,7 +226,7 @@ export class AppComponent implements OnInit, OnDestroy {
const crumbs = routeConfig
.reduce((acc, config) => {
const dynamicCrumb = this.breadcrumbsStrings[config];
return acc.concat(dynamicCrumb ? dynamicCrumb.name : formatStaticCrumb(config).name);
return acc.concat(last(castArray(dynamicCrumb ? dynamicCrumb.name : formatStaticCrumb(config))).name);
}, [''])
.filter(name => !!name);
this.titleService.setTitle(`ClearML - ${crumbs.join(' / ')}`);

View File

@@ -0,0 +1 @@
export const extCoreModules = [];

View File

@@ -0,0 +1,7 @@
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
export const extCoreModules = [
StoreDevtoolsModule.instrument({
maxAge: 50
})
];

View File

@@ -2,7 +2,7 @@
* tasks
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: 1.6
* OpenAPI spec version: 1.7
*
*
* NOTE: This class is auto generated by the swagger code generator program.

View File

@@ -16,7 +16,7 @@ export interface EventsGetMultiTaskPlotsResponse {
/**
* Plots mapping (keyed by task name)
*/
plots?: object;
plots?: any;
/**
* Number of results returned
*/

View File

@@ -16,7 +16,7 @@ export interface EventsGetTaskLogResponse {
/**
* Log items list
*/
events?: Array<object>;
events?: Array<any>;
/**
* Number of log events returned
*/

View File

@@ -95,6 +95,10 @@ export interface ProjectsGetAllExRequest {
size?: number;
stats_with_children?: boolean;
include_stats_filter?: any;
/**
* If true, include project dataset statistic in response
*/
include_dataset_stats?: boolean;
}
export namespace ProjectsGetAllExRequest {
export type StatsForStateEnum = 'active' | 'archived';

View File

@@ -33,4 +33,8 @@ export interface TasksDeleteManyRequest {
* If set to \'true\' then delete output models of the tasks that are not referenced by other tasks. Default value is \'true\'
*/
delete_output_models?: boolean;
/**
* If set to \'true\' then BE will try to delete the extenal artifacts associated with the tasks from the fileserver (if configured to do so)
*/
delete_external_artifacts?: boolean;
}

View File

@@ -33,4 +33,8 @@ export interface TasksResetManyRequest {
* If set to \'true\' then delete output models of the tasks that are not referenced by other tasks. Default value is \'true\'
*/
delete_output_models?: boolean;
/**
* If set to \'true\' then BE will try to delete the extenal artifacts associated with the tasks from the fileserver (if configured to do so)
*/
delete_external_artifacts?: boolean;
}

View File

@@ -25,7 +25,6 @@ export interface GetCurrentUserResponseUserObject {
avatar?: string;
company?: GetCurrentUserResponseUserObjectCompany;
email?: string;
getting_started?: any;
/**
* User preferences
*/

View File

@@ -26,7 +26,6 @@ import {colorSyncedKeys} from '@common/shared/ui-components/directives/choose-co
import {UserPreferences} from '@common/user-preferences';
import {EffectsModule} from '@ngrx/effects';
import {ActionReducer, MetaReducer, StoreModule, USER_PROVIDED_META_REDUCERS} from '@ngrx/store';
import {StoreDevtoolsModule} from '@ngrx/store-devtools';
import {merge, pick} from 'lodash/fp';
import {USERS_PREFIX, VIEW_PREFIX} from '~/app.constants';
import {ProjectsEffects} from '~/core/effects/projects.effects';
@@ -42,6 +41,7 @@ import {usageStatsReducer} from './reducers/usage-stats.reducer';
import {usersReducer} from './reducers/users.reducer';
import {viewReducer} from './reducers/view.reducer';
import {UsageStatsService} from './services/usage-stats.service';
import {extCoreModules} from '~/build-specifics';
export const reducers = {
auth: authReducer,
@@ -96,9 +96,9 @@ const userPrefMetaFactory = (userPreferences: UserPreferences): MetaReducer<any>
(reducer: ActionReducer<any>) =>
createUserPrefReducer('users', ['activeWorkspace', 'showOnlyUserWork'], [USERS_PREFIX], userPreferences, reducer),
(reducer: ActionReducer<any>) =>
createUserPrefReducer('rootProjects', ['tagsColors', 'graphVariant'], [ROOT_PROJECTS_PREFIX], userPreferences, reducer),
createUserPrefReducer('rootProjects', ['tagsColors', 'graphVariant', 'showHidden'], [ROOT_PROJECTS_PREFIX], userPreferences, reducer),
(reducer: ActionReducer<any>) =>
createUserPrefReducer('views', ['autoRefresh', 'neverShowPopupAgain'], [VIEW_PREFIX], userPreferences, reducer),
createUserPrefReducer('views', ['autoRefresh', 'neverShowPopupAgain', 'redactedArguments', 'hideRedactedArguments'], [VIEW_PREFIX], userPreferences, reducer),
localStorageReducer,
(reducer: ActionReducer<any>) =>
createUserPrefReducer('projects', projectSyncedKeys, [PROJECTS_PREFIX], userPreferences, reducer),
@@ -112,6 +112,7 @@ const userPrefMetaFactory = (userPreferences: UserPreferences): MetaReducer<any>
createUserPrefReducer('colorsPreference', colorSyncedKeys, [CHOOSE_COLOR_PREFIX], userPreferences, reducer)
];
@NgModule({
imports: [
StoreModule.forRoot(reducers, {
@@ -124,17 +125,15 @@ const userPrefMetaFactory = (userPreferences: UserPreferences): MetaReducer<any>
}),
EffectsModule.forRoot([
CommonAuthEffects,
LayoutEffects,
CommonUserEffects,
UserEffects,
LayoutEffects,
RouterEffects,
CommonProjectsEffect,
ProjectsEffects
ProjectsEffects,
UserEffects,
]),
StoreDevtoolsModule.instrument({
maxAge: 25 // Retains last 25 states
}),
HttpClientModule,
...extCoreModules
],
providers: [
SmSyncStateSelectorService,

View File

@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import {Actions, createEffect, ofType} from '@ngrx/effects';
import * as actions from '../../webapp-common/core/actions/projects.actions';
import {Store} from '@ngrx/store';
import {selectSelectedProjectId} from '@common/core/reducers/projects.reducer';
import {selectSelectedProjectId, selectShowHidden} from '@common/core/reducers/projects.reducer';
import {catchError, finalize, mergeMap, switchMap, withLatestFrom} from 'rxjs/operators';
import {deactivateLoader} from '@common/core/actions/layout.actions';
import {ALL_PROJECTS_OBJECT} from '@common/core/effects/projects.effects';
@@ -10,7 +10,6 @@ import {requestFailed} from '@common/core/actions/http.actions';
import {ApiProjectsService} from '~/business-logic/api-services/projects.service';
import {selectCurrentUser, selectShowOnlyUserWork} from '@common/core/reducers/users-reducer';
import {ProjectsGetAllExRequest} from '~/business-logic/model/projects/projectsGetAllExRequest';
import {selectShowHidden} from '@common/projects/common-projects.reducer';
@@ -54,9 +53,9 @@ export class ProjectsEffects {
id: [action.projectId],
include_stats: true,
...(!showHidden && {include_stats_filter: {system_tags: ['-pipeline']}}),
...((action.example !== false || this.fetchingExampleExperiment === action.projectId) && {check_own_contents: true}),
...(showOnlyUserWork && {active_users: [user.id]}),
...(showHidden && {search_hidden: true}),
...((action.example !== false || this.fetchingExampleExperiment === action.projectId) && {check_own_contents: true}),
/* eslint-enable @typescript-eslint/naming-convention */
} as ProjectsGetAllExRequest)
.pipe(

View File

@@ -21,6 +21,7 @@ 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, (state) => '');
export const selectActiveWorkspaceReady = createSelector(views, (state) => true);
export function viewReducer(viewState: ViewState = initViewState, action) {

View File

@@ -1,6 +1,5 @@
import {Injectable} from '@angular/core';
import {Actions, createEffect, ofType} from '@ngrx/effects';
import {ApiProjectsService} from '~/business-logic/api-services/projects.service';
import {map, switchMap} from 'rxjs/operators';
import {getResultsCount, setResultsCount} from '@common/dashboard-search/dashboard-search.actions';
import {getEntityStatQuery} from '@common/dashboard-search/dashboard-search.effects';
@@ -11,15 +10,15 @@ import {ApiOrganizationService} from '~/business-logic/api-services/organization
export class DashboardSearchEffects {
constructor(
private actions: Actions,
public projectsApi: ApiProjectsService,
public organizationApi: ApiOrganizationService,
) {
public organizationApi: ApiOrganizationService) {
}
getResultsCount = createEffect(() => this.actions.pipe(
ofType(getResultsCount),
switchMap(action => this.organizationApi.organizationGetEntitiesCount(getEntityStatQuery(action))),
map(({tasks: experiments, ...rest}) =>
switchMap(action => this.organizationApi.organizationGetEntitiesCount({
...getEntityStatQuery(action)
})),
map(({tasks: experiments, ...rest}) =>
setResultsCount({counts: {...rest, experiments}}))
));

View File

@@ -3,8 +3,8 @@ import {CommonModule} from '@angular/common';
import {SMSharedModule} from '@common/shared/shared.module';
import {StoreModule} from '@ngrx/store';
import {EffectsModule} from '@ngrx/effects';
import {DashboardSearchEffects as commonDashboardSearchEffects} from '@common/dashboard-search/dashboard-search.effects';
import {DashboardSearchEffects} from '~/features/dashboard-search/dashboard-search.effects';
import {DashboardSearchEffects as commonDashboardSearchEffects } from '@common/dashboard-search/dashboard-search.effects';
import {DashboardSearchEffects} from '~/features/dashboard/dashboard-search/dashboard-search.effects';
import {ProjectsSharedModule} from '../../projects/shared/projects-shared.module';
import {SharedModule} from '~/shared/shared.module';
import {dashboardSearchReducer} from '@common/dashboard-search/dashboard-search.reducer';

View File

@@ -13,10 +13,9 @@ import {SharedModule} from '~/shared/shared.module';
import {DashboardSearchModule} from './dashboard-search/dashboard-search.module';
import {ProjectDialogModule} from '@common/shared/project-dialog/project-dialog.module';
import {ProjectsSharedModule} from '../projects/shared/projects-shared.module';
import {SearchResultsComponent} from '@common/dashboard-search/dumb/search-results/search-results.component';
import {DashboardSearchBaseComponent} from '@common/dashboard/dashboard-search.component.base';
import {DatasetsModule} from '~/features/datasets/datasets.module';
import {DatasetsSharedModule} from '~/features/datasets/shared/datasets-shared.module';
import {ScrollingModule} from '@angular/cdk/scrolling';
@NgModule({
imports: [
@@ -30,10 +29,10 @@ import {DatasetsSharedModule} from '~/features/datasets/shared/datasets-shared.m
CommonDashboardModule,
SharedModule,
DashboardSearchModule,
DatasetsModule,
DatasetsSharedModule
DatasetsSharedModule,
ScrollingModule
],
declarations : [DashboardComponent, GettingStartedCardComponent, DashboardSearchBaseComponent, SearchResultsPageComponent, SearchResultsComponent]
declarations : [DashboardComponent, GettingStartedCardComponent, DashboardSearchBaseComponent, SearchResultsPageComponent]
})
export class DashboardModule {
}

View File

@@ -8,7 +8,7 @@
</div>
</div>
<div class="page-container">
<sm-search-results
<sm-virtual-grid
[cardTemplate]="
activeLink === searchPages.projects ? ProjectTemplate :
activeLink === searchPages.experiments ? ExperimentTemplate :
@@ -16,15 +16,15 @@
activeLink === searchPages.openDatasets ? openDatasetTemplate :
activeLink === searchPages.pipelines ? PipelineTemplate :
ProjectTemplate"
[results]="getResults()"
[items]="getResults()"
[cardHeight]="getCardHeight()"
[showLoadMoreButton]="getResults().length < resultsCount?.[activeLink]"
(resultClicked)="projectClicked($event)"
(itemClicked)="projectClicked($event)"
(loadMoreClicked)="loadMoreClicked.emit()">
</sm-search-results>
</sm-virtual-grid>
</div>
<ng-template #ProjectTemplate let-project="result">
<ng-template #ProjectTemplate let-project>
<sm-project-card
[project]="project"
(projectCardClicked)="projectClicked($event)"
@@ -32,21 +32,21 @@
></sm-project-card>
</ng-template>
<ng-template #ExperimentTemplate let-experiment="result">
<ng-template #ExperimentTemplate let-experiment>
<sm-experiment-card
[experiment]="experiment"
(experimentCardClicked)="experimentClicked($event)"
></sm-experiment-card>
</ng-template>
<ng-template #ModelsTemplate let-model="result">
<ng-template #ModelsTemplate let-model>
<sm-model-card
[model]="model"
(modelCardClicked)="modelClicked($event)"
></sm-model-card>
</ng-template>
<ng-template #PipelineTemplate let-pipeline="result">
<ng-template #PipelineTemplate let-pipeline>
<sm-pipeline-card
[project]="pipeline"
[hideMenu]="true"
@@ -54,7 +54,7 @@
></sm-pipeline-card>
</ng-template>
<ng-template #openDatasetTemplate let-dataset="result">
<ng-template #openDatasetTemplate let-dataset>
<sm-simple-dataset-card
[hideMenu]="true"
[project]="dataset"

View File

@@ -24,19 +24,11 @@ import {PipelinesControllerModule} from '@common/pipelines-controller/pipelines-
import {DatasetsRoutingModule} from '~/features/datasets/datasets-routing.module';
import {DatasetVersionStepComponent} from '@common/datasets/dataset-version-step/dataset-version-step.component';
import {DatasetsSharedModule} from '~/features/datasets/shared/datasets-shared.module';
import {
SimpleDatasetVersionDetailsComponent
} from '../../webapp-common/datasets/simple-dataset-version-details/simple-dataset-version-details.component';
import {
SimpleDatasetVersionContentComponent
} from '../../webapp-common/datasets/simple-dataset-version-content/simple-dataset-version-content.component';
import {
SimpleDatasetVersionPreviewComponent
} from '../../webapp-common/datasets/simple-dataset-version-preview/simple-dataset-version-preview.component';
import {DebugImagesModule} from '../../webapp-common/debug-images/debug-images.module';
import {
ExperimentOutputLogModule
} from '../../webapp-common/experiments/shared/experiment-output-log/experiment-output-log.module';
import {SimpleDatasetVersionDetailsComponent} from '@common/datasets/simple-dataset-version-details/simple-dataset-version-details.component';
import {SimpleDatasetVersionContentComponent} from '@common/datasets/simple-dataset-version-content/simple-dataset-version-content.component';
import {SimpleDatasetVersionPreviewComponent} from '@common/datasets/simple-dataset-version-preview/simple-dataset-version-preview.component';
import {ExperimentOutputLogModule} from '@common/experiments/shared/experiment-output-log/experiment-output-log.module';
import {DebugImagesModule} from '@common/debug-images/debug-images.module';
@NgModule({
@@ -56,18 +48,18 @@ import {
ExperimentCompareSharedModule,
PipelinesControllerModule,
DatasetsSharedModule,
ExperimentOutputLogModule,
DebugImagesModule,
ExperimentOutputLogModule
],
declarations: [
SimpleDatasetsComponent,
SimpleDatasetVersionsComponent,
SimpleDatasetVersionMenuComponent,
SimpleDatasetVersionInfoComponent,
DatasetVersionStepComponent,
SimpleDatasetVersionDetailsComponent,
SimpleDatasetVersionContentComponent,
SimpleDatasetVersionPreviewComponent,
DatasetVersionStepComponent,
SimpleDatasetVersionDetailsComponent,
],
schemas: [NO_ERRORS_SCHEMA],
exports: []

View File

@@ -1,66 +1,58 @@
<nav (smOverflows)="navbarOverflowed($event)" [overflowTrigger]="splitSize" [overflowDelay]="800"
[class.minimized]="minimized">
<span [routerLink]="['execution']" routerLinkActive="active" #rlaExecution="routerLinkActive"
queryParamsHandling="preserve">
<sm-navbar-item header="execution" [active]="rlaExecution.isActive" class="small-nav"></sm-navbar-item>
</span>
<span [routerLink]="['hyper-params/hyper-param/_empty_']" queryParamsHandling="merge">
<sm-navbar-item header="configuration" class="small-nav" [active]="(routerConfig$| async)?.includes('hyper-params')"></sm-navbar-item>
</span>
<span [routerLink]="['artifacts']" routerLinkActive="active" #rlaModel="routerLinkActive" queryParamsHandling="preserve">
<sm-navbar-item header="artifacts" class="small-nav" [active]="rlaModel.isActive"></sm-navbar-item>
</span>
<span [routerLink]="['general']" routerLinkActive="active" #rlaGeneral="routerLinkActive" queryParamsHandling="preserve">
<sm-navbar-item header="info" class="small-nav" [active]="rlaGeneral.isActive"></sm-navbar-item>
</span>
<nav [overflowTrigger]="splitSize" (smOverflows)="navbarOverflowed($event)" [overflowDelay]="800" [class.minimized]="minimized">
<span [routerLink]="['execution']" routerLinkActive #rlaExecution="routerLinkActive" queryParamsHandling="preserve">
<sm-navbar-item header="execution" [active]="rlaExecution.isActive" class="small-nav"></sm-navbar-item>
</span>
<span [routerLink]="['hyper-params/hyper-param/_empty_']" queryParamsHandling="merge">
<sm-navbar-item header="configuration"
class="small-nav"
[active]="(routerConfig$| async)?.includes('hyper-params')"></sm-navbar-item>
</span>
<span [routerLink]="['artifacts']" routerLinkActive #rlaModel="routerLinkActive" queryParamsHandling="preserve">
<sm-navbar-item header="artifacts"
class="small-nav"
[active]="rlaModel.isActive"></sm-navbar-item>
</span>
<span [routerLink]="['general']" routerLinkActive #rlaGeneral="routerLinkActive" queryParamsHandling="preserve">
<sm-navbar-item header="info"
class="small-nav"
[active]="rlaGeneral.isActive"></sm-navbar-item>
</span>
<span [matMenuTriggerFor]="results" *ngIf="overflow">
<sm-navbar-item
header="results" class="small-nav" [multi]="true"
[active]="rlaDebug.isActive || rlaPlots.isActive || rlaScalars.isActive || rlaLog.isActive"
></sm-navbar-item>
<sm-navbar-item header="results"
class="small-nav"
[multi]="true"
[active]="rlaDebug.isActive || rlaPlots.isActive || rlaScalars.isActive || rlaLog.isActive"></sm-navbar-item>
</span>
<div class="d-inline-block" [style.visibility]="overflow ? 'hidden' : 'visible'">
<span
[routerLink]="baseInfoRoute.concat(['log'])"
routerLinkActive="active"
queryParamsHandling="preserve"
#rlaLog="routerLinkActive"
>
<sm-navbar-item class="small-nav" header="console" [active]="rlaLog.isActive"></sm-navbar-item>
</span>
<span
[routerLink]="baseInfoRoute.concat(['metrics','scalar'])"
routerLinkActive="active"
queryParamsHandling="preserve"
#rlaScalars="routerLinkActive"
>
<sm-navbar-item class="small-nav" header="Scalars" [active]="rlaScalars.isActive"></sm-navbar-item>
</span>
<span
[routerLink]="baseInfoRoute.concat(['metrics','plots'])" routerLinkActive="active"
queryParamsHandling="preserve"
#rlaPlots="routerLinkActive"
>
<sm-navbar-item class="small-nav" header="PLOTS" [active]="rlaPlots.isActive"></sm-navbar-item>
</span>
<span
[routerLink]="baseInfoRoute.concat(['debugImages'])"
routerLinkActive="active"
queryParamsHandling="preserve"
#rlaDebug="routerLinkActive"
>
<sm-navbar-item class="small-nav" header="DEBUG SAMPLES" [active]="rlaDebug.isActive"></sm-navbar-item>
</span>
<span [routerLink]="baseInfoRoute.concat(['log'])" routerLinkActive queryParamsHandling="preserve"
#rlaLog="routerLinkActive">
<sm-navbar-item class="small-nav" header="console" [active]="rlaLog.isActive"></sm-navbar-item>
</span>
<span [routerLink]="baseInfoRoute.concat(['metrics','scalar'])" routerLinkActive queryParamsHandling="preserve"
#rlaScalars="routerLinkActive">
<sm-navbar-item class="small-nav" header="Scalars" [active]="rlaScalars.isActive"></sm-navbar-item>
</span>
<span [routerLink]="baseInfoRoute.concat(['metrics','plots'])" routerLinkActive queryParamsHandling="preserve"
#rlaPlots="routerLinkActive">
<sm-navbar-item class="small-nav" header="PLOTS" [active]="rlaPlots.isActive"></sm-navbar-item>
</span>
<span [routerLink]="baseInfoRoute.concat(['debugImages'])" routerLinkActive queryParamsHandling="preserve"
#rlaDebug="routerLinkActive">
<sm-navbar-item class="small-nav" header="DEBUG SAMPLES" [active]="rlaDebug.isActive"></sm-navbar-item>
</span>
</div>
<mat-menu #results="matMenu">
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['log'])" [class.active]="rlaLog.isActive"
>CONSOLE</button>
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['metrics','scalar'])" [class.active]="rlaScalars.isActive"
>SCALARS</button>
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['metrics','plots'])" [class.active]="rlaPlots.isActive"
>PLOTS</button>
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['debugImages'])" [class.active]="rlaDebug.isActive"
>DEBUG SAMPLES</button>
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['log'])" [class.active]="rlaLog.isActive">CONSOLE</button>
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['metrics','scalar'])"
[class.active]="rlaScalars.isActive">SCALARS
</button>
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['metrics','plots'])" [class.active]="rlaPlots.isActive">
PLOTS
</button>
<button mat-menu-item [routerLink]="baseInfoRoute.concat(['debugImages'])" [class.active]="rlaDebug.isActive">DEBUG
SAMPLES
</button>
</mat-menu>
<ng-content select="[refresh]"></ng-content>
</nav>

View File

@@ -6,8 +6,7 @@ nav {
position: relative;
text-align: center;
border-bottom: 1px solid #efefef;
//overflow: hidden;
padding: 0 24px;
padding: 0 48px 0 24px;
.refresh-position {
position: absolute;

View File

@@ -1,8 +1,8 @@
import {Component, Input} from '@angular/core';
import {FeaturesEnum} from '../../../../business-logic/model/users/featuresEnum';
import {selectRouterConfig} from '../../../../webapp-common/core/reducers/router-reducer';
import {FeaturesEnum} from '~/business-logic/model/users/featuresEnum';
import {selectRouterConfig} from '@common/core/reducers/router-reducer';
import {Store} from '@ngrx/store';
import {IExperimentInfoState} from '../../reducers/experiment-info.reducer';
import {ExperimentInfoState} from '../../reducers/experiment-info.reducer';
import {Observable} from 'rxjs';
@@ -22,14 +22,14 @@ export class ExperimentInfoNavbarComponent {
this.baseInfoRoute = minimized ? ['info-output'] : [];
this._minimized = minimized;
}
get minimized(){
get minimized() {
return this._minimized;
}
@Input() splitSize: number;
constructor(private store: Store<IExperimentInfoState>,) {
constructor(private store: Store<ExperimentInfoState>) {
this.routerConfig$ = this.store.select(selectRouterConfig);
}
navbarOverflowed($event: boolean) {

View File

@@ -38,6 +38,7 @@ export const experimentSyncedKeys = [
'view.hiddenProjectTableCols',
'view.metricsCols',
'view.colsOrder',
'output.scalarsHoverMode',
'info.userKnowledge',
'output.settingsList',
];

View File

@@ -1,17 +1,9 @@
import {commonExperimentInfoReducer, ICommonExperimentInfoState, initialCommonExperimentInfoState} from '../../../webapp-common/experiments/reducers/common-experiment-info.reducer';
import {CommonExperimentInfoState} from '@common/experiments/reducers/common-experiment-info.reducer';
export {
commonExperimentInfoReducer as experimentInfoReducer,
initialCommonExperimentInfoState as initialState,
} from '@common/experiments/reducers/common-experiment-info.reducer';
export interface IExperimentInfoState extends ICommonExperimentInfoState {
export interface ExperimentInfoState extends CommonExperimentInfoState {
errors: { [key: string]: any } | null;
}
export const initialState: IExperimentInfoState = {
...initialCommonExperimentInfoState,
};
export function experimentInfoReducer(state: IExperimentInfoState = initialState, action): IExperimentInfoState {
switch (action.type) {
default:
return commonExperimentInfoReducer(state, action) as IExperimentInfoState;
}
}

View File

@@ -1,9 +1,5 @@
import {commonExperimentsInitialState, commonExperimentsViewReducer, ICommonExperimentsViewState} from '../../../webapp-common/experiments/reducers/common-experiments-view.reducer';
export type IExperimentsViewState = ICommonExperimentsViewState;
export const initialState: IExperimentsViewState = {
...commonExperimentsInitialState,
};
export const experimentsViewReducer = commonExperimentsViewReducer;
export {
commonExperimentsInitialState as initialState,
commonExperimentsViewReducer as experimentsViewReducer,
CommonExperimentsViewState as ExperimentsViewState
} from '../../../webapp-common/experiments/reducers/common-experiments-view.reducer';

View File

@@ -1,6 +1,6 @@
import {ActionReducerMap, createSelector} from '@ngrx/store';
import {experimentsViewReducer, IExperimentsViewState, initialState as viewInitialState} from './experiments-view.reducer';
import {experimentInfoReducer, IExperimentInfoState, initialState as infoInitialState} from './experiment-info.reducer';
import {experimentsViewReducer, ExperimentsViewState, initialState as viewInitialState} from './experiments-view.reducer';
import {experimentInfoReducer, ExperimentInfoState, initialState as infoInitialState} from './experiment-info.reducer';
import {experimentOutputReducer, ExperimentOutputState, initialState as outputInitialState} from './experiment-output.reducer';
import {IExperimentInfo} from '../shared/experiment-info.model';
import {TaskStatusEnum} from '~/business-logic/model/tasks/taskStatusEnum';
@@ -9,8 +9,8 @@ import {selectSelectedModel} from '@common/models/reducers';
import {selectCurrentUser} from '@common/core/reducers/users-reducer';
export interface ExperimentState {
view: IExperimentsViewState;
info: IExperimentInfoState;
view: ExperimentsViewState;
info: ExperimentInfoState;
output: ExperimentOutputState;
}
@@ -23,14 +23,14 @@ export const experimentsReducers: ActionReducerMap<ExperimentState, any> = {
export const experiments = state => state.experiments ?? {} as ExperimentState;
// view selectors.
export const experimentsView = createSelector(experiments, state => (state?.view ?? viewInitialState) as IExperimentsViewState);
export const experimentsView = createSelector(experiments, state => (state?.view ?? viewInitialState) as ExperimentsViewState);
export const selectExperimentsMetricsCols = createSelector(experimentsView, state => state.metricsCols);
export const selectMetricVariants = createSelector(experimentsView, state => state.metricVariants);
export const selectMetricsLoading = createSelector(experimentsView, state => state.metricsLoading);
// info selectors
export const experimentInfo = createSelector(experiments, state => (state?.info ?? infoInitialState) as IExperimentInfoState);
export const experimentInfo = createSelector(experiments, state => (state?.info ?? infoInitialState) as ExperimentInfoState);
export const selectSelectedExperiment = createSelector(experimentInfo, state => state?.selectedExperiment);
export const selectExperimentInfoData = createSelector(experimentInfo, state => state.infoData);
export const selectShowExtraDataSpinner = createSelector(experimentInfo, state => state.showExtraDataSpinner);
@@ -48,7 +48,7 @@ export const selectIsSharedAndNotOwner = createSelector(selectSelectedExperiment
);
export const selectExperimentInfoDataFreeze = createSelector(experimentInfo, (state): IExperimentInfo => state.infoDataFreeze);
export const selectExperimentInfoErrors = createSelector(experimentInfo, (state): IExperimentInfoState['errors'] => state.errors);
export const selectExperimentInfoErrors = createSelector(experimentInfo, (state): ExperimentInfoState['errors'] => state.errors);
export const selectExperimentFormValidity = createSelector(selectExperimentInfoData, selectExperimentInfoErrors,
(infoData, errors): boolean => {
if (!infoData || !errors) {

View File

@@ -1,6 +1,6 @@
export const isDeletableProject = readyForDeletion => (readyForDeletion.experiments.unarchived + readyForDeletion.models.unarchived) === 0;
export const getDeletePopupEntitiesList = (): string => 'experiments or models';
export const popupEntitiesListConst = 'experiments or model';
export const getDeleteProjectPopupStatsBreakdown = (readyForDeletion, statsSubset: 'archived' | 'unarchived' | 'total', experimentCaption): string => `${readyForDeletion.experiments[statsSubset] > 0 ? `${readyForDeletion.experiments[statsSubset]} ${experimentCaption} ` : ''}
${readyForDeletion.models[statsSubset] > 0 ? readyForDeletion.models[statsSubset] + ' models ' : ''}`;

View File

@@ -5,8 +5,9 @@ import {SMSharedModule} from '@common/shared/shared.module';
import {ProjectCardComponent} from '@common/shared/ui-components/panel/project-card/project-card.component';
import {ProjectCardMenuExtendedComponent} from '~/features/projects/containers/project-card-menu-extended/project-card-menu-extended.component';
import {ProjectCardMenuComponent} from '@common/shared/ui-components/panel/project-card-menu/project-card-menu.component';
import {PipelineCardComponent} from '../../../webapp-common/pipelines/pipeline-card/pipeline-card.component';
import {PipelineCardMenuComponent} from '../../../webapp-common/pipelines/pipeline-card-menu/pipeline-card-menu.component';
import {PipelineCardComponent} from '@common/pipelines/pipeline-card/pipeline-card.component';
import {PipelineCardMenuComponent} from '@common/pipelines/pipeline-card-menu/pipeline-card-menu.component';
import {ScrollingModule} from '@angular/cdk/scrolling';
const _declarations = [
ProjectCardComponent,
@@ -21,7 +22,8 @@ const _declarations = [
CommonModule,
FormsModule,
ReactiveFormsModule,
SMSharedModule
SMSharedModule,
ScrollingModule
],
declarations: [..._declarations],
exports: [..._declarations]

View File

@@ -21,6 +21,7 @@ import {UserCredentialsComponent} from '~/features/settings/containers/admin/use
import {UserDataComponent} from '~/features/settings/containers/admin/user-data/user-data.component';
import {UsageStatsComponent} from '~/features/settings/containers/admin/usage-stats/usage-stats.component';
import {CreateCredentialDialogComponent} from '~/features/settings/containers/admin/create-credential-dialog/create-credential-dialog.component';
import {RedactedArgumentsDialogComponent} from '@common/settings/admin/redacted-arguments-dialog/redacted-arguments-dialog.component';
@@ -41,6 +42,7 @@ import {CreateCredentialDialogComponent} from '~/features/settings/containers/ad
ProfileKeyStorageComponent,
WorkspaceConfigurationComponent,
WebappConfigurationComponent,
RedactedArgumentsDialogComponent
],
imports: [
CommonModule,

View File

@@ -1,88 +1,13 @@
import {TableModel} from '@common/models/shared/models.model';
import {IExperimentInfo} from '~/features/experiments/shared/experiment-info.model';
import {Project} from '~/business-logic/model/projects/project';
import {Task} from '~/business-logic/model/tasks/task';
import {selectSelectedTableModel} from '@common/models/reducers';
import {createSelector} from '@ngrx/store';
import {selectSelectedExperiment} from '~/features/experiments/reducers';
import {selectRootProjects, selectSelectedProject} from '@common/core/reducers/projects.reducer';
import {formatStaticCrumb as commonFormatStaticCrumb, prepareLinkData} from '@common/layout/breadcrumbs/breadcrumbs-common.utils';
import {IBreadcrumbsLink} from '@common/layout/breadcrumbs/breadcrumbs.component';
export {formatStaticCrumb} from '@common/layout/breadcrumbs/breadcrumbs-common.utils';
import {IBreadcrumbs} from '@common/layout/breadcrumbs/breadcrumbs-common.utils';
export {prepareNames, IBreadcrumbs} from '@common/layout/breadcrumbs/breadcrumbs-common.utils';
export interface IBreadcrumbs {
project: Project;
projects: Project[];
experiment: IExperimentInfo;
model: TableModel;
task: Task;
}
export const formatStaticCrumb = (crumb: string): IBreadcrumbsLink => {
if (!crumb) {
return {url: null, name: null};
}
return commonFormatStaticCrumb(crumb);
};
export const selectBreadcrumbsStringsBase = createSelector(
selectSelectedProject, selectSelectedExperiment, selectSelectedTableModel, selectRootProjects,
(project, experiment, model, projects) =>
({project, experiment, model, projects}) as IBreadcrumbs);
export const prepareNames = (data: IBreadcrumbs, customProject?: boolean, fullScreen = false) => {
const project = prepareLinkData(data.project, true);
if (data.project) {
let subProjectsNames = [data.project?.name];
if (!customProject) {
subProjectsNames = data.project?.name?.split('/');
}
const allProjects = [
...data.projects,
{id: '*', name: 'All Experiments'},
data.project
];
let currentName = '';
const subProjects = subProjectsNames.map(name => {
currentName += currentName ? ('/' + name) : name;
return allProjects.find(proj => currentName === proj.name);
}) || [];
const subProjectsLinks = subProjects.map((subProject, index, arr) => ({
name: subProject?.name.substring(subProject?.name.lastIndexOf('/') + 1),
url: customProject ?
data.project?.system_tags?.includes('pipeline') ? `pipelines/${subProject?.id}/experiments` : '' :
fullScreen && index === (arr.length - 1) ? `projects/${subProject?.id}/experiments/${data?.experiment?.id}` :
subProject?.name === data.project?.name && data.project?.sub_projects?.length === 0 ?
`projects/${subProject?.id}` :
`projects/${subProject?.id}/projects`
})) as { name: string; url: string }[];
project.name = project?.name.substring(project.name.lastIndexOf('/') + 1);
project.subCrumbs = subProjectsLinks;
}
const task = prepareLinkData(data.task);
const experiment = (data.experiment) ? prepareLinkData(data.experiment, true) : {};
const output = formatStaticCrumb('');
const accountAdministration = formatStaticCrumb('account-administration');
const experiments = formatStaticCrumb('experiments');
const models = formatStaticCrumb('models');
const compare = customProject ?
data.project?.system_tags?.includes('pipeline') ?
{url: 'compare-experiments', name: 'Compare Runs'} :
{url: 'compare-experiments', name: 'Compare Versions'}
: formatStaticCrumb('compare-experiments');
return {
...(project.url !== '*' && {':projectId': project}),
':taskId': task,
':controllerId': experiment,
'compare-experiments': compare,
output,
experiments,
models,
accountAdministration,
profile: {url: 'profile', name: 'Profile'},
'webapp-configuration': {url: 'webapp-configuration', name: 'Configuration'},
'workspace-configuration': {url: 'workspace-configuration', name: 'Workspace'},
};
};

View File

@@ -32,17 +32,6 @@
</div>
<div class="caption">projects</div>
</a>
<a class="item d-block"
routerLink="/datasets"
routerLinkActive="active"
smTooltip="DATASETS"
[matTooltipShowDelay]="0"
matTooltipPosition="right">
<div class="item-icon">
<i class="al-icon al-ico-datasets al-color blue-300"></i>
</div>
<div class="caption">datasets</div>
</a>
<a class="item d-block"
routerLink="/pipelines"
routerLinkActive="active"
@@ -54,6 +43,17 @@
</div>
<div class="caption">pipelines</div>
</a>
<a class="item d-block"
routerLink="/datasets"
routerLinkActive="active"
smTooltip="DATASETS"
[matTooltipShowDelay]="0"
matTooltipPosition="right">
<div class="item-icon">
<i class="al-icon al-ico-datasets al-color blue-300"></i>
</div>
<div class="caption">datasets</div>
</a>
<a class="item d-block"
routerLink="/workers-and-queues"
routerLinkActive="active"

View File

@@ -5,8 +5,10 @@ export enum EntityTypeEnum {
experiment = 'experiment',
model = 'model',
project = 'project',
pipeline = 'pipeline',
controller = 'pipeline run',
dataset = 'version'
dataset = 'version',
simpleDataset = 'dataset'
}
export enum CircleTypeEnum {

View File

@@ -2,7 +2,7 @@
@font-face {
font-family: '#{$icomoon-font-family}';
src: url('./#{$icomoon-font-family}.ttf?8714dr') format('truetype');
src: url('./#{$icomoon-font-family}.ttf?ttf?vsfnj4') format('truetype');
font-weight: normal;
font-style: normal;
font-display: block;
@@ -23,6 +23,81 @@
-moz-osx-font-smoothing: grayscale;
}
.al-ico-sort-asc {
&:before {
content: $al-ico-sort-asc;
}
}
.al-ico-sort-desc {
&:before {
content: $al-ico-sort-desc;
}
}
.al-ico-grid-view {
&:before {
content: $al-ico-grid-view;
}
}
.al-ico-connect {
&:before {
content: $al-ico-connect;
}
}
.al-ico-disconnect {
&:before {
content: $al-ico-disconnect;
}
}
.al-ico-trash-all {
&:before {
content: $al-ico-trash-all;
}
}
.al-ico-drag {
&:before {
content: $al-ico-drag;
}
}
.al-ico-py {
&:before {
content: $al-ico-py;
}
}
.al-ico-file {
&:before {
content: $al-ico-file;
}
}
.al-ico-txt {
&:before {
content: $al-ico-txt;
}
}
.al-ico-pkl {
&:before {
content: $al-ico-pkl;
}
}
.al-ico-image {
&:before {
content: $al-ico-image;
}
}
.al-ico-zip {
&:before {
content: $al-ico-zip;
}
}
.al-ico-code-file {
&:before {
content: $al-ico-code-file;
}
}
.al-ico-audio {
&:before {
content: $al-ico-audio;
}
}
.al-ico-upload {
&:before {
content: $al-ico-upload;
@@ -759,11 +834,6 @@
content: $al-ico-link;
}
}
.al-ico-image {
&:before {
content: $al-ico-image;
}
}
.al-ico-code {
&:before {
content: $al-ico-code;
@@ -1156,11 +1226,6 @@
content: $al-ico-experiment-view;
}
}
.al-ico-code-file {
&:before {
content: $al-ico-code-file;
}
}
.al-ico-code-square {
&:before {
content: $al-ico-code-square;

View File

@@ -1,6 +1,21 @@
$icomoon-font-family: "trains" !default;
$icomoon-font-path: "fonts" !default;
$al-ico-sort-asc: "\e9e3";
$al-ico-sort-desc: "\e9e4";
$al-ico-grid-view: "\e9e0";
$al-ico-connect: "\e9de";
$al-ico-disconnect: "\e9da";
$al-ico-trash-all: "\e9d9";
$al-ico-drag: "\e9d8";
$al-ico-py: "\e9d7";
$al-ico-file: "\e9d3";
$al-ico-txt: "\e9d6";
$al-ico-pkl: "\e9cd";
$al-ico-image: "\e958";
$al-ico-zip: "\e9ce";
$al-ico-code-file: "\e9a4";
$al-ico-audio: "\e9d0";
$al-ico-upload: "\e9cc";
$al-ico-min-panel: "\e9ca";
$al-ico-max-panel: "\e9cb";
@@ -146,7 +161,6 @@ $al-ico-italic: "\e954";
$al-ico-heading: "\e955";
$al-ico-quote: "\e956";
$al-ico-link: "\e957";
$al-ico-image: "\e958";
$al-ico-code: "\e959";
$al-ico-list-bulleted: "\e95a";
$al-ico-list-numbered: "\e95b";
@@ -223,7 +237,6 @@ $al-ico-broken-file: "\e9c0";
$al-ico-run: "\e9c1";
$al-ico-table-view: "\e9c2";
$al-ico-experiment-view: "\e9c3";
$al-ico-code-file: "\e9a4";
$al-ico-code-square: "\e9c4";
$al-ico-video: "\e9c5";
$al-ico-less-than: "\e9c6";

View File

@@ -48,9 +48,9 @@
}
</style>
<polygon points="45 37.22 50 32.22 45 27.22 45 37.22" fill="#39405f"/>
<polygon points="20 27.22 20 37.22 25 32.22 20 27.22" fill="#39405f"/>
<polygon points="12 37.22 17 32.22 12 27.22 12 37.22" fill="#39405f"/>
<polygon points="45 37.22 50 32.22 45 27.22 45 37.22" fill="#5a658e"/>
<polygon points="20 27.22 20 37.22 25 32.22 20 27.22" fill="#5a658e"/>
<polygon points="12 37.22 17 32.22 12 27.22 12 37.22" fill="#5a658e"/>
<g class="hourglass">
<path d="M32,33.41l8,8V52H24V41.41ZM24,12V22.59l8,8,8-8V12Z" fill="#1a1e2c"/>
@@ -60,7 +60,7 @@
<rect x="22.05" y="19.95" width="19.9" height="11"/>
</clipPath>
<path fill="#39405f" clip-path="url(#t-clipper-path)" d="M41,19v3.18s-5,8.41-9,8.41-9-8.41-9-8.41V19Z"></path>
<path fill="#5a658e" clip-path="url(#t-clipper-path)" d="M41,19v3.18s-5,8.41-9,8.41-9-8.41-9-8.41V19Z"></path>
</g>
@@ -70,12 +70,12 @@
</clipPath>
<g clip-path="url(#bottom-clip-path)">
<path fill="#39405f" d="M24,52H40V48.49S36,40,32,40s-8,8.51-8,8.51Z"></path>
<path fill="#5a658e" d="M24,52H40V48.49S36,40,32,40s-8,8.51-8,8.51Z"></path>
</g>
</g>
<path d="M24,12V22.59l8,8,8-8V12Zm14,9.76-6,6-6-6V14H38ZM24,41.41V52H40V41.41l-8-8ZM38,50H26V42.24l6-6,6,6Z" fill="#1a1e2c"/>
<path d="M44,52H42V40.59L33.41,32,42,23.41V12h2a1,1,0,0,0,0-2H20a1,1,0,0,0,0,2h2V23.41L30.59,32,22,40.59V52H20a1,1,0,0,0,0,2H44a1,1,0,0,0,0-2ZM24,22.59V12H40V22.59l-8,8ZM40,52H24V41.41l8-8,8,8Z" fill="#39405f"/>
<path d="M44,52H42V40.59L33.41,32,42,23.41V12h2a1,1,0,0,0,0-2H20a1,1,0,0,0,0,2h2V23.41L30.59,32,22,40.59V52H20a1,1,0,0,0,0,2H44a1,1,0,0,0,0-2ZM24,22.59V12H40V22.59l-8,8ZM40,52H24V41.41l8-8,8,8Z" fill="#5a658e"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,10 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="64px" height="64px" viewBox="0 0 64 64">
<path d="M55,32A23,23,0,1,1,11.93,20.76l-2.5.4a1,1,0,0,1-.31-2L14,18.41a1,1,0,0,1,1.14.81l.93,5a1,1,0,0,1-.8,1.17h-.18a1,1,0,0,1-1-.81l-.5-2.7A21,21,0,1,0,32,11a1,1,0,0,1,0-2A23,23,0,0,1,55,32ZM32,50a1,1,0,0,0,1-1V47.21a1,1,0,0,0-2,0V49A1,1,0,0,0,32,50Zm0-32.21a1,1,0,0,0,1-1V15a1,1,0,0,0-2,0v1.79A1,1,0,0,0,32,17.79ZM20.54,22A1,1,0,0,0,22,22a1,1,0,0,0,0-1.41l-1.26-1.27a1,1,0,0,0-1.42,1.42ZM20,45a1,1,0,0,0,.71-.29L22,43.46a1,1,0,1,0-1.41-1.41l-1.27,1.26a1,1,0,0,0,0,1.42A1,1,0,0,0,20,45ZM42.76,22.24a1,1,0,0,0,.7-.29l1.27-1.26a1,1,0,0,0-1.42-1.42l-1.26,1.27a1,1,0,0,0,0,1.41A1,1,0,0,0,42.76,22.24ZM14,32a1,1,0,0,0,1,1h1.79a1,1,0,0,0,0-2H15A1,1,0,0,0,14,32Zm35,1a1,1,0,0,0,0-2H47.21a1,1,0,0,0,0,2Zm-7,10.46,1.26,1.27a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42l-1.27-1.26a1,1,0,1,0-1.41,1.41Z" fill="#39405f"/>
<path d="M55,32A23,23,0,1,1,11.93,20.76l-2.5.4a1,1,0,0,1-.31-2L14,18.41a1,1,0,0,1,1.14.81l.93,5a1,1,0,0,1-.8,1.17h-.18a1,1,0,0,1-1-.81l-.5-2.7A21,21,0,1,0,32,11a1,1,0,0,1,0-2A23,23,0,0,1,55,32ZM32,50a1,1,0,0,0,1-1V47.21a1,1,0,0,0-2,0V49A1,1,0,0,0,32,50Zm0-32.21a1,1,0,0,0,1-1V15a1,1,0,0,0-2,0v1.79A1,1,0,0,0,32,17.79ZM20.54,22A1,1,0,0,0,22,22a1,1,0,0,0,0-1.41l-1.26-1.27a1,1,0,0,0-1.42,1.42ZM20,45a1,1,0,0,0,.71-.29L22,43.46a1,1,0,1,0-1.41-1.41l-1.27,1.26a1,1,0,0,0,0,1.42A1,1,0,0,0,20,45ZM42.76,22.24a1,1,0,0,0,.7-.29l1.27-1.26a1,1,0,0,0-1.42-1.42l-1.26,1.27a1,1,0,0,0,0,1.41A1,1,0,0,0,42.76,22.24ZM14,32a1,1,0,0,0,1,1h1.79a1,1,0,0,0,0-2H15A1,1,0,0,0,14,32Zm35,1a1,1,0,0,0,0-2H47.21a1,1,0,0,0,0,2Zm-7,10.46,1.26,1.27a1,1,0,0,0,1.42,0,1,1,0,0,0,0-1.42l-1.27-1.26a1,1,0,1,0-1.41,1.41Z" fill="#5a658e"/>
<g id="seconds">
<line fill="none" stroke="#39405f" stroke-width="2" stroke-miterlimit="10" x1="32" y1="32" x2="32" y2="20" stroke-linecap="round"/>
<line fill="none" stroke="#5a658e" stroke-width="2" stroke-miterlimit="10" x1="32" y1="32" x2="32" y2="20" stroke-linecap="round"/>
</g>
<circle cx="32" cy="32" r="2" fill="#39405f"/>
<circle cx="32" cy="32" r="2" fill="#5a658e"/>
<circle cx="32" cy="32" r="1" fill="#1a1e2c"/>
<defs>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,5 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 242.15">
<title>no-code dark</title>
<path fill="#39405f"
<path fill="#5a658e"
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>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,5 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 242.15">
<title>no-log 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.11,9.8ZM20.82,11H279.18a10.2,10.2,0,0,1,10.11,10.1V58.18H10.71V20.82A9.93,9.93,0,0,1,20.82,11Zm9.79,27.24a5.69,5.69,0,0,1-1.53-3.68,5.64,5.64,0,0,1,1.53-3.67,6,6,0,0,1,7.66,0,5.64,5.64,0,0,1,1.53,3.67,5.22,5.22,0,0,1-5.21,5.21A6.43,6.43,0,0,1,30.61,38.27Zm28.77,0a5.69,5.69,0,0,1-1.53-3.68,5.64,5.64,0,0,1,1.53-3.67,6,6,0,0,1,7.66,0,5.64,5.64,0,0,1,1.53,3.67,5.22,5.22,0,0,1-5.2,5.21A7.25,7.25,0,0,1,59.38,38.27Zm29.08,0a5.69,5.69,0,0,1-1.53-3.68,5.64,5.64,0,0,1,1.53-3.67c1.85-1.84,5.52-1.84,7.66,0a5.64,5.64,0,0,1,1.53,3.67,5.22,5.22,0,0,1-5.2,5.21A6.5,6.5,0,0,1,88.46,38.27ZM263.58,98.58a5.49,5.49,0,0,1-5.52,5.51H41.64a5.51,5.51,0,0,1,0-11H258.06C261.13,93.37,263.58,95.52,263.58,98.58ZM36.42,133.16a5.5,5.5,0,0,1,5.52-5.51H201.43a5.52,5.52,0,1,1,0,11H41.64a5.44,5.44,0,0,1-5.21-5.52Zm227.16,34.91a5.49,5.49,0,0,1-5.52,5.51H41.64a5.51,5.51,0,1,1,0-11H258.06A5.49,5.49,0,0,1,263.58,168.07ZM155.51,202.66a5.5,5.5,0,0,1-5.51,5.52l-108.36,0a5.51,5.51,0,1,1,0-11H150A5.49,5.49,0,0,1,155.51,202.66Z"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="244" viewBox="0 0 300 244">
<path d="M20.82,243.07H279.18c11.49-.01,20.81-9.33,20.82-20.82V21.74c-.01-11.49-9.33-20.81-20.82-20.82H20.82C9.33,.94,.01,10.25,0,21.74V222.25c.01,11.49,9.33,20.81,20.82,20.82Zm258.36-10.72H20.82c-5.56-.05-10.06-4.54-10.11-10.1V69.8H289.29V222.55c-.07,5.48-4.57,9.87-10.06,9.8h-.05ZM20.82,11.92H279.18c5.56,.05,10.06,4.54,10.11,10.1V59.1H10.71V21.74c.06-5.48,4.55-9.88,10.04-9.82h.07Zm9.79,27.24c-.94-1-1.48-2.31-1.53-3.68,.05-1.37,.59-2.67,1.53-3.67,2.22-1.84,5.44-1.84,7.66,0,.94,1,1.48,2.3,1.53,3.67,0,2.88-2.33,5.2-5.21,5.21-1.46-.03-2.86-.56-3.98-1.5v-.03Zm28.77,0c-.94-1-1.48-2.31-1.53-3.68,.05-1.37,.59-2.67,1.53-3.67,2.22-1.84,5.44-1.84,7.66,0,.94,1,1.48,2.3,1.53,3.67,0,2.87-2.33,5.2-5.2,5.21-1.45-.09-2.84-.61-3.99-1.5v-.03Zm29.08,0c-.94-1-1.48-2.31-1.53-3.68,.05-1.37,.59-2.67,1.53-3.67,1.85-1.84,5.52-1.84,7.66,0,.94,1,1.48,2.3,1.53,3.67,0,2.87-2.33,5.2-5.2,5.21-1.46-.04-2.87-.57-3.99-1.5v-.03Zm175.12,60.34c.01,3.03-2.44,5.5-5.47,5.51-.02,0-.03,0-.05,0H41.64c-3.04-.18-5.35-2.79-5.17-5.83,.17-2.78,2.39-5,5.17-5.17h216.42c3.07,.28,5.52,2.43,5.52,5.49ZM36.42,134.08c0-3.04,2.45-5.5,5.49-5.51,.01,0,.02,0,.03,0H201.43c3.04-.26,5.71,1.99,5.97,5.03,.26,3.04-1.99,5.71-5.03,5.97-.31,.03-.63,.03-.94,0H41.64c-2.95-.12-5.26-2.57-5.21-5.52v.03Zm227.15,34.91c.01,3.03-2.44,5.5-5.47,5.51-.02,0-.03,0-.05,0H41.64c-3.04,.18-5.65-2.13-5.83-5.17-.18-3.04,2.13-5.65,5.17-5.83,.22-.01,.44-.01,.66,0h216.42c3.03-.02,5.5,2.43,5.52,5.46v.03h0Zm-108.07,34.59c.01,3.04-2.44,5.51-5.48,5.52-.01,0-.02,0-.03,0H41.64c-3.04,.18-5.65-2.13-5.83-5.17-.18-3.04,2.13-5.65,5.17-5.83,.22-.01,.44-.01,.66,0h108.36c3.03-.01,5.5,2.44,5.51,5.47h0Z" fill="#5a658e"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,26 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 278.07">
<defs>
<style>.cls-1 path{fill: #39405f}</style>
</defs>
<title>no-plots</title>
<g id="Layer_2" data-name="Layer 2">
<g id="Layer_1-2" data-name="Layer 1">
<g class="cls-1">
<path d="M219.71,11.73h72.46V260.42H219.71Z"/>
<path d="M124.93,103.84h72.46V260.42H124.93Z"/>
<path d="M29.28,177.52h72.45v82.89H29.28Z"/>
<path d="M0,269.63H300v8.44H0Z"/>
<path d="M0,251H10.72v9.46H0Z"/>
<path d="M0,223.07H10.72v9.46H0Z"/>
<path d="M0,195.19H10.72v9.46H0Z"/>
<path d="M0,167.31H10.72v9.46H0Z"/>
<path d="M0,139.42H10.72v9.46H0Z"/>
<path d="M0,111.53H10.72V121H0Z"/>
<path d="M0,83.65H10.72v9.47H0Z"/>
<path d="M0,55.77H10.72v9.46H0Z"/>
<path d="M0,27.89H10.72v9.46H0Z"/>
<path d="M0,0H10.72V9.46H0Z"/>
</g>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="280" viewBox="0 0 300 280">
<path d="M292.17,261.38h-72.46V12.69h72.46v248.69ZM197.39,104.8H124.93v156.58h72.46V104.8Zm-95.66,73.68H29.28v82.89H101.73v-82.89ZM0,270.6v8.44H300v-8.44H0Zm10.72-18.63H0v9.46H10.72v-9.46Zm0-27.93H0v9.46H10.72v-9.46Zm0-27.88H0v9.46H10.72v-9.46Zm0-27.88H0v9.46H10.72v-9.46Zm0-27.89H0v9.46H10.72v-9.46Zm0-27.89H0v9.47H10.72v-9.47Zm0-27.88H0v9.47H10.72v-9.47Zm0-27.88H0v9.46H10.72v-9.46Zm0-27.88H0v9.46H10.72v-9.46ZM10.72,.96H0V10.42H10.72V.96Z" fill="#5a658e"/>
</svg>

Before

Width:  |  Height:  |  Size: 931 B

After

Width:  |  Height:  |  Size: 556 B

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" id="Layer_1" x="0px" y="0px" width="148mm" height="80mm" viewBox="0 0 277.31937 149.55879" enable-background="new 0 0 792 612" xml:space="preserve" inkscape:version="0.92.3 (2405546, 2018-03-11)" sodipodi:docname="scikit learn logo small.svg"><metadata id="metadata35"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><defs id="defs33"/><sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="777" inkscape:window-height="626" id="namedview31" showgrid="false" inkscape:zoom="1.0907007" inkscape:cx="121.6884" inkscape:cy="79.49229" inkscape:window-x="2951" inkscape:window-y="679" inkscape:window-maximized="0" inkscape:current-layer="Layer_1" units="mm" showborder="true" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0"/>
<g id="g3" transform="translate(-120.60861,-220.26017)">
<path d="m 333.32,347.348 c 33.869,-33.867 39.498,-83.146 12.572,-110.07 -26.922,-26.921 -76.199,-21.293 -110.066,12.572 -33.867,33.866 -24.07,98.568 -12.57,110.07 9.293,9.293 76.199,21.293 110.064,-12.572 z" id="path5" inkscape:connector-curvature="0" style="fill:#f89939"/>
<path d="m 194.35,298.411 c -19.648,-19.648 -48.242,-22.919 -63.867,-7.295 -15.621,15.622 -12.355,44.22 7.297,63.865 19.652,19.654 57.195,13.969 63.863,7.295 5.396,-5.387 12.361,-44.215 -7.293,-63.865 z" id="path7" inkscape:connector-curvature="0" style="fill:#3499cd"/>
</g>
<g id="g9" transform="translate(-120.60861,-220.26017)">
<g id="g11">
<path d="m 262.143,339.047 c -3.471,3.195 -6.516,5.553 -9.133,7.068 -2.617,1.52 -5.113,2.279 -7.488,2.279 -2.732,0 -4.936,-1.059 -6.607,-3.178 -1.674,-2.121 -2.508,-4.965 -2.508,-8.543 0,-5.361 1.162,-11.797 3.486,-19.301 2.32,-7.51 5.145,-14.43 8.463,-20.761 l 9.729,-3.602 c 0.305,-0.102 0.537,-0.154 0.691,-0.154 0.738,0 1.348,0.544 1.816,1.627 0.473,1.088 0.711,2.55 0.711,4.388 0,5.209 -1.199,10.252 -3.602,15.129 -2.402,4.879 -6.154,10.086 -11.26,15.627 -0.205,2.656 -0.307,4.48 -0.307,5.477 0,2.223 0.408,3.982 1.225,5.285 0.818,1.305 1.902,1.953 3.256,1.953 1.381,0 2.848,-0.494 4.406,-1.49 1.555,-0.998 3.93,-3.064 7.121,-6.207 v 4.403 z m -14.668,-14.973 c 3.242,-3.605 5.875,-7.648 7.891,-12.121 2.016,-4.475 3.023,-8.324 3.023,-11.549 0,-0.94 -0.139,-1.704 -0.418,-2.278 -0.281,-0.575 -0.641,-0.864 -1.074,-0.864 -0.941,0 -2.316,2.352 -4.117,7.057 -1.801,4.704 -3.569,11.29 -5.305,19.755 z" id="path13" inkscape:connector-curvature="0" style="fill:#010101"/>
<path d="m 290.795,339.047 c -3.242,3.195 -6.152,5.553 -8.732,7.068 -2.58,1.52 -5.424,2.279 -8.541,2.279 -3.473,0 -6.275,-1.111 -8.41,-3.33 -2.131,-2.225 -3.195,-5.146 -3.195,-8.773 0,-5.412 1.875,-10.309 5.633,-14.688 3.75,-4.381 7.914,-6.57 12.484,-6.57 2.375,0 4.275,0.615 5.707,1.84 1.43,1.227 2.145,2.834 2.145,4.826 0,5.287 -5.617,9.574 -16.852,12.869 1.02,4.977 3.688,7.469 8.004,7.469 1.686,0 3.293,-0.453 4.824,-1.357 1.535,-0.908 3.844,-2.922 6.934,-6.035 v 4.402 z m -20.07,-7.084 c 6.535,-1.84 9.805,-5.234 9.805,-10.188 0,-2.451 -0.895,-3.676 -2.68,-3.676 -1.686,0 -3.293,1.281 -4.824,3.85 -1.536,2.565 -2.301,5.901 -2.301,10.014 z" id="path15" inkscape:connector-curvature="0" style="fill:#010101"/>
<path d="m 331.701,339.047 c -4.086,3.881 -7.01,6.412 -8.77,7.588 -1.762,1.174 -3.447,1.76 -5.057,1.76 -4.035,0 -5.936,-3.561 -5.707,-10.686 -2.553,3.65 -4.91,6.344 -7.068,8.084 -2.156,1.736 -4.383,2.602 -6.684,2.602 -2.244,0 -4.152,-1.051 -5.725,-3.158 -1.573,-2.107 -2.354,-4.691 -2.354,-7.758 0,-3.828 1.051,-7.48 3.156,-10.955 2.109,-3.473 4.809,-6.279 8.102,-8.424 3.293,-2.145 6.207,-3.219 8.732,-3.219 3.193,0 5.428,1.469 6.705,4.404 l 7.828,-4.326 h 2.148 l -3.381,11.221 c -1.736,5.645 -2.607,9.514 -2.607,11.607 0,2.195 0.777,3.293 2.336,3.293 0.992,0 2.09,-0.529 3.291,-1.59 1.201,-1.061 2.883,-2.676 5.053,-4.846 v 4.403 z m -28.037,2.109 c 2.553,0 4.959,-2.176 7.223,-6.529 2.26,-4.355 3.389,-8.373 3.389,-12.049 0,-1.428 -0.322,-2.547 -0.957,-3.35 -0.641,-0.807 -1.496,-1.207 -2.566,-1.207 -2.555,0 -4.977,2.17 -7.258,6.512 -2.285,4.342 -3.43,8.338 -3.43,11.986 0,1.381 0.34,2.498 1.016,3.354 0.676,0.856 1.534,1.283 2.583,1.283 z" id="path17" inkscape:connector-curvature="0" style="fill:#010101"/>
<path d="m 360.314,339.047 c -6.41,6.281 -11.352,9.424 -14.824,9.424 -1.559,0 -2.875,-0.658 -3.945,-1.969 -1.07,-1.316 -1.609,-2.945 -1.609,-4.887 0,-3.6 1.93,-8.424 5.785,-14.477 -1.891,0.971 -3.957,1.645 -6.205,2.029 -1.66,3.064 -4.266,6.359 -7.814,9.879 h -0.879 v -3.443 c 1.99,-2.068 3.791,-4.291 5.4,-6.666 -2.199,-0.971 -3.295,-2.414 -3.295,-4.326 0,-1.969 0.668,-4.068 2.012,-6.305 1.34,-2.232 3.184,-3.348 5.535,-3.348 1.992,0 2.986,1.018 2.986,3.062 0,1.609 -0.574,3.906 -1.725,6.895 4.238,-0.461 7.941,-3.701 11.109,-9.729 l 3.484,-0.154 -3.562,9.805 c -1.48,4.137 -2.438,6.955 -2.871,8.447 -0.433,1.492 -0.652,2.816 -0.652,3.963 0,1.074 0.25,1.932 0.746,2.566 0.498,0.643 1.17,0.959 2.012,0.959 0.918,0 1.801,-0.314 2.643,-0.936 0.842,-0.631 2.732,-2.359 5.67,-5.193 v 4.404 z" id="path19" inkscape:connector-curvature="0" style="fill:#010101"/>
<path d="m 397.928,339.047 c -5.898,6.234 -10.957,9.348 -15.168,9.348 -1.711,0 -3.09,-0.6 -4.137,-1.801 -1.049,-1.199 -1.572,-2.807 -1.572,-4.824 0,-2.732 1.125,-6.908 3.373,-12.523 1.199,-3.014 1.801,-4.932 1.801,-5.746 0,-0.818 -0.322,-1.227 -0.957,-1.227 -0.357,0 -0.832,0.18 -1.418,0.535 -0.539,0.357 -1.164,0.859 -1.879,1.496 -0.637,0.586 -1.354,1.301 -2.145,2.141 -0.691,0.721 -1.432,1.537 -2.219,2.453 l -2.148,2.492 c -0.943,1.148 -1.531,2.359 -1.76,3.637 -0.385,2.17 -0.639,4.164 -0.768,5.979 -0.078,1.35 -0.115,3.174 -0.115,5.477 l -8.465,1.988 c -0.279,-3.447 -0.422,-6.014 -0.422,-7.697 0,-4.111 0.479,-8.006 1.438,-11.682 0.957,-3.68 2.494,-7.814 4.615,-12.412 l 9.344,-1.799 c -1.965,5.287 -3.254,9.447 -3.867,12.484 4.188,-4.672 7.508,-7.906 9.969,-9.709 2.457,-1.801 4.645,-2.697 6.557,-2.697 1.299,0 2.385,0.49 3.25,1.471 0.869,0.982 1.301,2.215 1.301,3.689 0,2.449 -1.098,6.484 -3.291,12.104 -1.508,3.854 -2.262,6.355 -2.262,7.51 0,1.537 0.627,2.305 1.881,2.305 1.867,0 4.891,-2.465 9.064,-7.393 z" id="path21" inkscape:connector-curvature="0" style="fill:#010101"/>
</g>
</g>
<text font-size="23.0795" id="text25" style="font-size:23.0795002px;line-height:0%;font-family:Helvetica;fill:#ffffff" x="153.33279" y="81.945938">scikit</text>
</svg>

After

Width:  |  Height:  |  Size: 6.9 KiB

File diff suppressed because one or more lines are too long

View File

@@ -120,7 +120,7 @@ $sm-theme: mat.define-light-theme($sm-theme-primary, $sm-theme-accent, $sm-theme
background-color: transparent !important;
}
.mat-drawer-side {
.mat-drawer {
border-right: solid 1px $blue-100;
}
@@ -176,6 +176,9 @@ span.highlight-text {
hr {
border: none;
border-top: 1px solid rgba(0, 0, 0, .1);
&.dark{
border-top: 1px solid $blue-600;
}
}
.pointer {
@@ -511,13 +514,13 @@ html {
padding: 15px 15px;
background: $blue-25;
color: $blue-400;
font-weight: 500;
}
.mat-menu-content .mat-menu-item {
height: 40px;
font-size: 14px;
font-weight: 500;
padding: 0 32px 0 16px;
border-radius: 4px;
}
// hide arrows for number inputs
@@ -651,8 +654,7 @@ $type-colors: (
//material menu
body .mat-menu-content:not(:empty) {
padding-top: 0;
padding-bottom: 0;
padding: 4px;
.search-results {
overflow: auto;

View File

@@ -4,6 +4,12 @@ import {GetCurrentUserResponseUserObjectCompany} from '~/business-logic/model/us
export const AUTH_PREFIX = 'AUTH_';
export const refreshS3Credential = createAction(AUTH_PREFIX + ' [Refresh S3Credential]');
export const setS3Credentials = createAction(
AUTH_PREFIX + ' [Set S3]',
props<{ bucketCredentials: Credentials[] }>()
);
export const updateS3Credential = createAction(
AUTH_PREFIX + 'SET_BUCKETS_CREDENTIALS',
props<{s3BucketCredentials: {bucketCredentials: Credentials[]}}>()

View File

@@ -33,7 +33,7 @@ export const resetLoader = createAction(VIEW_PREFIX + '[reset loader]');
export const setBackdrop = createAction(
VIEW_PREFIX + '[set backdrop]',
props<{payload: boolean}>()
props<{active: boolean}>()
);
export const activeLoader = createAction(
@@ -84,7 +84,8 @@ export const firstLogin = createAction(
);
export const neverShowPopupAgain = createAction(VIEW_PREFIX + 'NEVER_SHOW_POPUP_AGAIN', props<{ popupId: string; reset?: boolean }>());
export const setRedactedArguments = createAction(VIEW_PREFIX + 'SET_REDACTED_ARGUMENTS', props<{ redactedArguments: { key: string} [] }>());
export const setHideRedactedArguments = createAction(VIEW_PREFIX + 'SET_SHOW_REDACTED_ARGUMENTS', props<{hide: boolean }>());
export const plotlyReady = createAction(VIEW_PREFIX + '[plotly ready]');
export const aceReady = createAction(VIEW_PREFIX + '[ace ready]');
export const openAppsAwarenessDialog = createAction(VIEW_PREFIX + '[apps awareness dialog]',

View File

@@ -161,3 +161,7 @@ export const getFilteredUsers = createAction(
PROJECTS_PREFIX + 'GET_FILTERED_USERS',
props<{filteredUsers: string[]}>()
);
export const setShowHidden = createAction(
PROJECTS_PREFIX + ' [set show hidden]',
props<{ show: boolean }>()
);

View File

@@ -41,5 +41,6 @@ export const setURLParams = createAction(
isArchived?: boolean;
isDeep?: boolean;
update?: boolean;
version?: string;
}>()
);

View File

@@ -77,6 +77,7 @@ export class CommonAuthEffects {
updateCredentialLabel = createEffect(() => this.actions.pipe(
ofType(authActions.updateCredentialLabel),
// eslint-disable-next-line @typescript-eslint/naming-convention
mergeMap(action => this.credentialsApi.authEditCredentials({access_key: action.credential.access_key, label: action.label}).pipe(
mergeMap(() => [
setCredentialLabel({credential: action.credential, label: action.label}),
@@ -89,6 +90,14 @@ export class CommonAuthEffects {
))
));
refresh = createEffect(() => this.actions.pipe(
ofType(authActions.refreshS3Credential, authActions.getSignedUrl),
map(() => {
const state = JSON.parse(window.localStorage.getItem('_saved_state_'));
return authActions.setS3Credentials({bucketCredentials: state?.auth?.s3BucketCredentials?.bucketCredentials});
})
));
signUrl = createEffect(() => this.actions.pipe(
ofType(authActions.getSignedUrl),
filter(action => !!action.url),

View File

@@ -19,7 +19,7 @@ import {
selectAllProjectsUsers,
selectLastUpdate, selectRootProjects,
selectSelectedMetricVariantForCurrProject,
selectSelectedProjectId
selectSelectedProjectId, selectShowHidden
} from '../reducers/projects.reducer';
import {OperationErrorDialogComponent} from '@common/shared/ui-components/overlay/operation-error-dialog/operation-error-dialog.component';
import {ApiTasksService} from '~/business-logic/api-services/tasks.service';
@@ -32,9 +32,8 @@ import {ProjectsGetAllExResponse} from '~/business-logic/model/projects/projects
import {Project} from '~/business-logic/model/projects/project';
import {ApiUsersService} from '~/business-logic/api-services/users.service';
import {get, last} from 'lodash/fp';
import {selectProjects, selectShowHidden} from '@common/projects/common-projects.reducer';
import {setShowHidden} from '@common/projects/common-projects.actions';
import {ProjectsGetAllExRequest} from '~/business-logic/model/projects/projectsGetAllExRequest';
import {setShowHidden} from '../actions/projects.actions';
export const ALL_PROJECTS_OBJECT = {id: '*', name: 'All Experiments'};
@@ -88,7 +87,7 @@ export class ProjectsEffects {
mergeMap(([projects, rootProjects]) => [
actions.setAllProjects({
projects: projects as Project[],
updating: rootProjects.length > 0
updating: rootProjects?.length > 0
}),
actions.setLastUpdate({lastUpdate: last(projects)?.last_update})
])

View File

@@ -46,7 +46,8 @@ export class RouterEffects {
...(action.orders && {order: encodeOrder(action.orders)}),
...(action.filters && {filter: encodeFilters(action.filters)}),
...(action.isArchived !== undefined && {archive: action.isArchived ? 'true' : null}),
...(action.isDeep && {deep: true})
...(action.isDeep && {deep: true}),
...(action.version && {version: action.version})
}
} as NavigationExtras;
this.router.navigate([], extra);

View File

@@ -3,26 +3,26 @@ import {merge, pick} from 'lodash/fp';
import {setPreferences} from '../actions/users.actions';
import {UserPreferences} from '@common/user-preferences';
interface extAction extends Action {
interface ExtAction extends Action {
noPreferences?: boolean;
}
const firstRun = {};
export function createUserPrefReducer(
export const createUserPrefReducer = (
key: string,
syncedKeys: string[],
actionsPrefix: string[],
userPreferences: UserPreferences,
reducer: ActionReducer<any>
): ActionReducer<any, extAction> {
): ActionReducer<any, ExtAction> => {
if (firstRun[key] === undefined) {
firstRun[key] = true;
}
let timeout: number;
return function (state, action): any {
return (state, action): any => {
let nextState = reducer(state, action);
if (firstRun[key] && userPreferences.isReady() && nextState[key]) {
@@ -50,4 +50,4 @@ export function createUserPrefReducer(
timeout = window.setTimeout(() => userPreferences.setPreferences(key, val), 2000);
return nextState;
};
}
};

View File

@@ -4,7 +4,7 @@ import {
cancelS3Credentials,
removeCredential, removeSignedUrl, resetCredential,
resetDontShowAgainForBucketEndpoint,
saveS3Credentials, setCredentialLabel, setSignedUrl,
saveS3Credentials, setCredentialLabel, setS3Credentials, setSignedUrl,
showLocalFilePopUp,
updateAllCredentials,
updateS3Credential
@@ -12,6 +12,7 @@ import {
import {CredentialKey} from '~/business-logic/model/auth/credentialKey';
import {inBucket} from '@common/settings/admin/base-admin.service';
import {filter, map, takeWhile, timeout} from 'rxjs/operators';
import {isEqual} from 'lodash/fp';
export interface Credentials {
Bucket?: string;
@@ -108,6 +109,13 @@ export const commonAuthReducer = [
return {...state, s3BucketCredentials: {bucketCredentials: [...state.s3BucketCredentials.bucketCredentials, action.newCredential]}};
}
}),
on(setS3Credentials, (state, action) => {
if (isEqual(state.s3BucketCredentials?.bucketCredentials, action.bucketCredentials)) {
return state;
} else {
return {...state, s3BucketCredentials: {bucketCredentials: action.bucketCredentials}};
}
}),
on(resetCredential, state => ({...state, newCredential: initAuth.newCredential})),
on(addCredential, (state, action) => ({
...state,

View File

@@ -1,4 +1,4 @@
import {on, createReducer, createSelector} from '@ngrx/store';
import {createReducer, createSelector, on} from '@ngrx/store';
import * as projectsActions from '../actions/projects.actions';
import {TagColor} from '../actions/projects.actions';
import {Project} from '~/business-logic/model/projects/project';
@@ -36,10 +36,11 @@ export interface RootProjects {
users: User[];
allUsers: User[];
extraUsers: User[];
showHidden: boolean;
}
const initRootProjects: RootProjects = {
projects: [],
projects: null,
selectedProject: null,
archive: false,
deep: false,
@@ -54,6 +55,7 @@ const initRootProjects: RootProjects = {
users: [],
allUsers: [],
extraUsers: [],
showHidden: false
};
export const projects = state => state.rootProjects as RootProjects;
@@ -100,7 +102,7 @@ export const projectsReducer = createReducer(
}
});
} else {
newProjects = [...newProjects, ...action.projects];
newProjects = [...(newProjects || []), ...action.projects];
}
return {...state, projects: sortByField(newProjects, 'name')};
@@ -145,4 +147,7 @@ export const projectsReducer = createReducer(
on(projectsActions.setProjectUsers, (state, action) => ({...state, users: action.users, extraUsers: []})),
on(projectsActions.setAllProjectUsers, (state, action) => ({...state, allUsers: action.users})),
on(projectsActions.setProjectExtraUsers, (state, action) => ({...state, extraUsers: action.users})),
on(projectsActions.setShowHidden, (state, action) => ({...state, showHidden: action.show}))
);
export const selectShowHidden = createSelector(projects, selectSelectedProject,
(state, selectedProject) => (state?.showHidden || selectedProject?.system_tags?.includes('hidden')));

View File

@@ -21,6 +21,8 @@ export interface ViewState {
aceCaretPosition: { [key: string]: Ace.Point };
preferencesReady: boolean;
showUserFocus: boolean;
redactedArguments: { key: string }[];
hideRedactedArguments: boolean;
}
export const initViewState: ViewState = {
@@ -41,11 +43,18 @@ export const initViewState: ViewState = {
aceCaretPosition: {},
preferencesReady: false,
showUserFocus: false,
redactedArguments: [{key: 'CLEARML_API_SECRET_KEY'},
{key: 'CLEARML_AGENT_GIT_PASS'},
{key: 'AWS_SECRET_ACCESS_KEY'},
{key: 'AZURE_STORAGE_KEY'}],
hideRedactedArguments: false,
};
export const views = state => state.views as ViewState;
export const selectReady = createSelector(views, state => state.preferencesReady);
export const selectLoading = createSelector(views, state => state.loading);
export const selectIsLoading = createSelector(views, (state) => Object.values(state.loading).some((value) => value));
export const selectBackdropActive = createSelector(views, state => state.backdropActive);
export const selectNotification = createSelector(views, state => state.notification);
@@ -61,6 +70,8 @@ export const selectPlotlyReady = createSelector(views, state => state.plotlyRead
export const selectAceReady = createSelector(views, state => state.aceReady);
export const selectAceCaretPosition = createSelector(views, state => state.aceCaretPosition);
export const selectNeverShowPopups = createSelector(views, (state): string[] => state.neverShowPopupAgain);
export const selectRedactedArguments = createSelector(views, (state): { key: string }[] => state.redactedArguments);
export const selectHideRedactedArguments = createSelector(views, (state): { key: string }[] => state.hideRedactedArguments ? state.redactedArguments : null);
export const selectShowUserFocus = createSelector(views, state => state.showUserFocus);
@@ -91,14 +102,16 @@ export const viewReducers = [
...state,
aceCaretPosition: {...state.aceCaretPosition, [action.id]: action.position}
})),
on(layoutActions.resetAceCaretsPositions, (state, action) => ({...state, aceCaretPosition: {}})),
on(layoutActions.resetAceCaretsPositions, state => ({...state, aceCaretPosition: {}})),
on(layoutActions.resetLoader, (state) => ({...state, loading: {}})),
on(layoutActions.setRedactedArguments, (state, action) => ({...state, redactedArguments: action.redactedArguments})),
on(layoutActions.setHideRedactedArguments, (state, action) => ({...state, hideRedactedArguments: action.hide})),
on(apiRequest, (state, action) => ({
...state,
loading: {...state.loading, [action?.endpoint || 'default']: true}
})),
on(layoutActions.setNotificationDialog, (state, action) => ({...state, notification: action.notification})),
on(layoutActions.setBackdrop, (state, action) => ({...state, backdropActive: action.payload})),
on(layoutActions.setBackdrop, (state, action) => ({...state, backdropActive: action.active})),
on(layoutActions.setAutoRefresh, (state, action) => ({...state, autoRefresh: action.autoRefresh})),
on(layoutActions.setCompareAutoRefresh, (state, action) => ({...state, compareAutoRefresh: action.autoRefresh})),
on(layoutActions.neverShowPopupAgain, (state, action) => ({

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import {FormControl, FormGroup, FormArray} from '@angular/forms';
import {UntypedFormControl, UntypedFormGroup, UntypedFormArray} from '@angular/forms';
import {forEach} from 'lodash/fp';
@@ -9,24 +9,24 @@ export class SmFormBuilderService {
create(formData: any, updateOn?: any) {
if (Array.isArray(formData)) {
const arr = formData.map( data => this.create(data));
return new FormArray(arr, {updateOn});
return new UntypedFormArray(arr, {updateOn});
} else if (typeof formData === 'function') {
return formData();
} else if (formData instanceof Object) {
if (formData.value) {
return new FormControl(formData.value);
return new UntypedFormControl(formData.value);
} else {
const obj = {};
Object.entries(formData).forEach(([key, value]) => obj[key] = this.create(value));
return new FormGroup(obj, {updateOn});
return new UntypedFormGroup(obj, {updateOn});
}
} else {
return new FormControl(formData);
return new UntypedFormControl(formData);
}
}
// @ts-ignore
getFormErrors(form: FormGroup | FormArray, errors?: any): any {
getFormErrors(form: UntypedFormGroup | UntypedFormArray, errors?: any): any {
// @ts-ignore
forEach((control: any) => {
// @ts-ignore
@@ -40,14 +40,14 @@ export class SmFormBuilderService {
this.create(formData, updateOn);
}
array(formData: Array<Object>, updateOn: any = 'change') {
array(formData: Array<any>, updateOn: any = 'change') {
const arr = formData.map( data => this.group(data, updateOn));
return new FormArray(arr, {updateOn: 'blur'});
return new UntypedFormArray(arr, {updateOn: 'blur'});
}
group(formData: Object, updateOn: any = 'change') {
const formGroup = new FormGroup({}, {updateOn});
Object.entries(formData).forEach(([key, value]) => formGroup.addControl(key, new FormControl(value)));
group(formData: any, updateOn: any = 'change') {
const formGroup = new UntypedFormGroup({}, {updateOn});
Object.entries(formData).forEach(([key, value]) => formGroup.addControl(key, new UntypedFormControl(value)));
return formGroup;
}

View File

@@ -187,6 +187,8 @@ export class DashboardSearchEffects {
stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active,
scroll_id: scrollIds?.[activeSearchLink.openDatasets] || null,
size: SEARCH_PAGE_SIZE,
include_dataset_stats: true,
stats_with_children: false,
include_stats: true,
only_fields: ['name', 'company', 'user', 'created', 'default_output_destination', 'tags', 'system_tags', 'basename']
/* eslint-enable @typescript-eslint/naming-convention */

View File

@@ -1,10 +0,0 @@
<cdk-virtual-scroll-viewport class="card-container" [itemSize]="cardHeight + 32">
<div class="card-row" [style.width.px]="rowWidth" *cdkVirtualFor="let row of resultRows$ | async">
<ng-container *ngFor="let result of row; trackBy: trackById">
<ng-container *ngTemplateOutlet="cardTemplate; context: {result}"></ng-container>
</ng-container>
</div>
<div class="load-more" *ngIf="showLoadMoreButton && (resultRows$ | async).length">
<button (click)="loadMoreClicked.emit()" class="btn btn-cml-primary load-more-btn">LOAD MORE</button>
</div>
</cdk-virtual-scroll-viewport>

View File

@@ -1,26 +0,0 @@
:host {
.card-container {
height: 100%;
padding: 0 24px 24px;
.card-row {
display: grid;
grid-template-columns: repeat(auto-fit, 352px);
grid-gap: 32px 24px;
margin: 0 auto;
padding: 16px 0;
}
}
}
.load-more {
display: flex;
justify-content: center;
width: 100%;
padding: 15px;
.load-more-btn {
padding: 8px 40px;
}
}

View File

@@ -1,65 +0,0 @@
import {Component, EventEmitter, Input, Output, TemplateRef, ViewChild} from '@angular/core';
import {BehaviorSubject, combineLatest, Observable} from 'rxjs';
import {BreakpointObserver, BreakpointState} from '@angular/cdk/layout';
import {map, take} from 'rxjs/operators';
import {chunk} from 'lodash/fp';
import {trackById} from '@common/shared/utils/forms-track-by';
import {CdkVirtualScrollViewport} from '@angular/cdk/scrolling';
import {Store} from '@ngrx/store';
import {selectScaleFactor} from '@common/core/reducers/view.reducer';
const SIDE_NAV_PLUS_PAD = 64 + 24 + 24;
const CARD_WIDTH = 352;
@Component({
selector: 'sm-search-results',
templateUrl: './search-results.component.html',
styleUrls: ['./search-results.component.scss']
})
export class SearchResultsComponent {
private cardLayoutChange$: Observable<BreakpointState>;
private results$ = new BehaviorSubject<any[]>(null);
public resultRows$: Observable<any[][]>;
public trackById = trackById;
public rowWidth = 300;
private _cardTemplate: TemplateRef<any>;
@Input() set cardTemplate(cardTemplate: TemplateRef<any>) {
this.viewPort?.scrollToIndex(0);
this._cardTemplate = cardTemplate;
}
get cardTemplate() {
return this._cardTemplate;
}
@Input() set results(results: any[]) {
this.results$.next(results);
}
@Input() cardHeight = 246;
@Input() showLoadMoreButton = false;
@Output() resultClicked = new EventEmitter<any>();
@Output() loadMoreClicked = new EventEmitter();
@ViewChild(CdkVirtualScrollViewport) viewPort: CdkVirtualScrollViewport;
constructor(private store: Store, private breakpointObserver: BreakpointObserver) {
this.store.select(selectScaleFactor)
.pipe(take(1), map(factor => 100 / factor))
.subscribe(factor => {
const points = {} as { [point: string]: number };
[2, 3, 4, 5, 6].forEach(num =>
points[`(min-width: ${num === 2 ? 0 : ((num - 2) * 24 + (num - 1) * CARD_WIDTH + SIDE_NAV_PLUS_PAD) * factor}px) and ` +
`(max-width: ${num === 6 ? 20000 : ((num - 1) * 24 + num * CARD_WIDTH + SIDE_NAV_PLUS_PAD) * factor}px)`] = num);
this.cardLayoutChange$ = breakpointObserver.observe(Object.keys(points));
this.resultRows$ = combineLatest([this.cardLayoutChange$, this.results$])
.pipe(map(([match, results]) => {
const point = Object.entries(match.breakpoints).find(([, val]) => val);
const cards = point ? points[point[0]] - 1 : 3;
this.rowWidth = cards * CARD_WIDTH + (cards - 1) * 24;
return chunk(cards, results);
}));
});
}
}

View File

@@ -17,6 +17,7 @@ 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';
import {selectShowHidden} from '@common/core/reducers/projects.reducer';
@Injectable()
export class CommonDashboardEffects {
@@ -33,16 +34,22 @@ export class CommonDashboardEffects {
getRecentProjects = createEffect(() => this.actions.pipe(
ofType(getRecentProjects),
withLatestFrom(this.store.select(selectCurrentUser), this.store.select(selectShowOnlyUserWork)),
mergeMap(([action, user, showOnlyUserWork]) =>
withLatestFrom(
this.store.select(selectCurrentUser),
this.store.select(selectShowOnlyUserWork),
this.store.select(selectShowHidden),
),
mergeMap(([action, user, showOnlyUserWork, showHidden]) =>
this.projectsApi.projectsGetAllEx({
stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active,
include_stats: true,
include_stats_filter: {system_tags: ['-pipeline']},
check_own_contents: true,
order_by: ['featured', '-last_update'],
page: 0,
page_size: CARDS_IN_ROW,
active_users: (showOnlyUserWork ? [user.id] : null),
...(showOnlyUserWork && {active_users: [user.id]}),
...(showHidden && {search_hidden: true}),
...(!showHidden && {include_stats_filter: {system_tags: ['-pipeline']}}),
only_fields: ['name', 'company', 'user', 'created', 'default_output_destination']
}).pipe(
mergeMap(({projects}) => [setRecentProjects({projects}), deactivateLoader(action.type)]),

View File

@@ -1,19 +1,20 @@
@import "../../../shared/ui-components/styles/mixins/common";
.recent-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 24px;
padding-bottom: 12px;
}
:host {
.recent-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 12px;
}
.table-container {
height: calc(100% - 38px);
min-height: 180px;
overflow-y: auto;
}
.table-container {
height: calc(100% - 38px);
min-height: 180px;
overflow-y: auto;
}
.recent-title {
@include recent-title();
.recent-title {
@include recent-title();
}
}

View File

@@ -1,10 +1,10 @@
<div class="sm-card-list-layout">
<div class="sm-card-list-layout" (smOverflows)="overflow = $event">
<div #header class="sm-card-list-header">
<div class="recent-title">RECENT PROJECTS
<button class="btn btn-link view-all" (click)="router.navigateByUrl('/projects')">VIEW ALL</button>
</div>
<div>
<button *ngIf="(recentProjectsList$ | async).length >= cardsInRow"
<button *ngIf="(recentProjectsList$ | async).length >= cardsInRow || overflow"
class="btn btn-cml-primary d-flex align-items-center"
(click)="openCreateProjectDialog()">
<i class="al-icon al-color sm blue-400 al-ico-add mr-2"></i>NEW PROJECT
@@ -12,7 +12,7 @@
</div>
</div>
<sm-project-card
*ngFor="let project of recentProjectsList$ | async"
*ngFor="let project of recentProjectsList$ | async; trackBy: trackById"
[project]="project" (projectCardClicked)="projectCardClicked($event)"
[hideMenu]="true"
></sm-project-card>

View File

@@ -7,10 +7,11 @@
}
.sm-card-list-layout {
height: 324px;
height: 320px;
overflow: hidden;
grid-gap: 16px 24px;
padding-top: 24px;
padding-bottom: 0;
}
.sm-card-list-header {

View File

@@ -3,15 +3,16 @@ import {Router} from '@angular/router';
import {MatDialog, MatDialogRef} from '@angular/material/dialog';
import {fromEvent, Observable, Subscription} from 'rxjs';
import {Store} from '@ngrx/store';
import {Project} from '../../../../business-logic/model/projects/project';
import {Project} from '~/business-logic/model/projects/project';
import {selectRecentProjects} from '../../common-dashboard.reducer';
import {getRecentProjects} from '../../common-dashboard.actions';
import {ProjectDialogComponent} from '../../../shared/project-dialog/project-dialog.component';
import {resetSelectedProject, setSelectedProjectId} from '../../../core/actions/projects.actions';
import {selectCurrentUser} from '../../../core/reducers/users-reducer';
import {ProjectDialogComponent} from '@common/shared/project-dialog/project-dialog.component';
import {resetSelectedProject, setSelectedProjectId} from '@common/core/actions/projects.actions';
import {selectCurrentUser} from '@common/core/reducers/users-reducer';
import {filter, take, throttleTime} from 'rxjs/operators';
import {isExample} from '../../../shared/utils/shared-utils';
import {isExample} from '@common/shared/utils/shared-utils';
import { CARDS_IN_ROW } from '../../common-dashboard.const';
import {trackById} from '@common/shared/utils/forms-track-by';
@Component({
selector : 'sm-dashboard-projects',
@@ -23,6 +24,8 @@ export class DashboardProjectsComponent implements OnInit, AfterViewInit, OnDest
private dialog: MatDialogRef<ProjectDialogComponent>;
private sub: Subscription;
readonly cardsInRow = CARDS_IN_ROW;
overflow: boolean;
trackById = trackById;
@Output() width = new EventEmitter<number>();
@@ -50,7 +53,7 @@ export class DashboardProjectsComponent implements OnInit, AfterViewInit, OnDest
.subscribe(() => this.width.emit(this.header.nativeElement.getBoundingClientRect().width));
}
public projectCardClicked(project: Project) {
this.router.navigateByUrl(`projects/${project.id}`);
(project.own_tasks===0 && project.sub_projects.length>0) ? this.router.navigateByUrl(`projects/${project.id}/projects`): this.router.navigateByUrl(`projects/${project.id}`);
this.store.dispatch(setSelectedProjectId({projectId: project.id, example: isExample(project)}));
}

View File

@@ -1,10 +1,25 @@
@import "variables";
:host {
flex: 0 0 220px;
.step-footer {
font-size: 12px;
}
.title {
max-width: 162px; // use for ellipsis
}
}
.step-title {
&.in_progress {
background-color: mix($running-green, $blue-950, 20%);
}
}
.step-footer {
font-size: 12px;
&.in_progress {
background-color: $running-green;
}
}

View File

@@ -17,10 +17,7 @@
(inlineActiveStateChanged)="projectNameEditActiveChanged($event)"
>
<span class="project-name"
matTooltipPosition="above"
[smTooltip]="project.name"
>{{project.name | shortProjectName}}</span>
<span class="project-name" [smTooltip]="project.name">{{project.name | shortProjectName}}</span>
</sm-inline-edit>
<sm-pipeline-card-menu
class="menu-wrapper"

View File

@@ -33,5 +33,19 @@
[columns]="columns"
[tableData]="tableData"
[selectionMode]="null"
[scrollable]="true"
></sm-table>
[virtualScroll]="true"
[scrollable]="true">
<ng-template
let-col
let-i="rowIndex"
let-row="rowData"
pTemplate="body">
<div [ngSwitch]="col.id" class="w-100">
<ng-container *ngSwitchCase="'0'">
<span class="ellipsis" [attr.fileType]="row[0].match('\\.([^ .]+)$')?.[1] || 'none'" smShowTooltipIfEllipsis [smTooltip]="row[0]">{{row[0]}}</span>
</ng-container>
<div *ngSwitchDefault class="ellipsis" smShowTooltipIfEllipsis [smTooltip]="row[col.id]">{{row[col.id]}}</div>
</div>
</ng-template>
</sm-table>

View File

@@ -13,8 +13,87 @@
}
::ng-deep sm-table {
tr.header, tr.header th:hover {background-color: $blue-900 !important;}
th:nth-child(1) {padding-left: 24px !important;}
td:nth-child(1) {padding-left: 24px !important;}
.p-datatable-wrapper > .p-datatable-table {
width: 100%;
}
[filetype]::before {
content: "\e9d3"; // fallback icon (file)
color: #596c71;
font-family: 'trains';
font-size: 24px;
margin-right: 12px;
vertical-align: middle;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// FILE TYPE ICONS
// ---------------
// Image
[filetype="png"]::before,
[filetype="jpg"]::before,
[filetype="jpeg"]::before,
[filetype="gif"]::before {
content: "\e958";
color: #3a7777;
}
// Video
[filetype="mp4"]::before,
[filetype="mov"]::before,
[filetype="wmv"]::before,
[filetype="avi"]::before {
content: "\e9c5";
color: #846300;
}
// Audio
[filetype="mp3"]::before,
[filetype="aac"]::before,
[filetype="wav"]::before {
content: "\e9d0";
color: #833e65;
}
[filetype="csv"]::before {
content: "\e9c9";
color: #145f82;
}
[filetype="txt"]::before {
content: "\e9d6";
color: #803d3d;
}
[filetype="zip"]::before,
[filetype="gz"]::before {
content: "\e9ce";
color: #615555;
}
[filetype="pkl"]::before {
content: "\e9cd";
color: #48507f;
}
[filetype="py"]::before {
content: "\e9d7";
color: #d1902e;
}
[filetype="html"]::before,
[filetype="yaml"]::before,
[filetype="json"]::before {
content: "\e9a4"; // code-icon
color: #a35151;
}
}
}

View File

@@ -6,7 +6,8 @@ import {fileSizeConfigStorage, FileSizePipe} from '@common/shared/pipes/filesize
@Component({
selector: 'sm-simple-dataset-version-content',
templateUrl: './simple-dataset-version-content.component.html',
styleUrls: ['./simple-dataset-version-content.component.scss']
styleUrls: ['./simple-dataset-version-content.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SimpleDatasetVersionContentComponent {
public columns: ISmCol[];

View File

@@ -3,7 +3,7 @@
<div class="expand-header">VERSION INFO</div>
</mat-expansion-panel-header>
<div class="panel-body" *ngIf="entity">
<div class="header">
<div class="header mt-2">
<div class="name ellipsis">{{entity.name}}<ng-container *ngIf="entity?.runtime?.version"> v{{entity.runtime.version}}</ng-container></div>
<span class="status" [class]="entity.status">{{entity.status | replaceViaMapPipe:convertStatusMap | replaceViaMapPipe:convertStatusMapBase}}</span>
</div>
@@ -11,7 +11,7 @@
<div class="param">
<div class="key">ID</div>
<div class="value d-flex align-item-center justify-content-between" [smTooltip]="entity.id" smShowTooltipIfEllipsis>
<span>{{entity.id?.slice(0, 8)}}</span>
<span>{{entity.id?.slice(0, 8)}}...</span>
<i
class="pointer al-icon al-ico-copy-to-clipboard sm"
ngxClipboard
@@ -60,6 +60,12 @@
>{{$any(entity?.runtime?.ds_change_size) | filesize: fileSizeConfigStorage}}</div>
</div>
</div>
<div class="section">
<div class="header"><span>DESCRIPTION</span><i class="al-icon al-ico-edit sm" (click)="editDescription.emit(entity)"></i></div>
<div class="param continue h-auto">
<div class="multi-line-value">{{entity?.comment}}</div>
</div>
</div>
</div>
<footer *ngIf="entity?.id">
<a

View File

@@ -3,15 +3,17 @@
:host {
.header {
width: 100%;
margin-top: 12px;
padding-bottom: 18px;
margin-bottom: 6px;
color: $blue-100;
border-bottom: solid 1px $dark-border;
}
.al-ico-copy-to-clipboard {
color: $blue-300;
opacity: 0;
transition: opacity 0.3s;
&:hover {
color: $blue-100;
}
}
.value:hover {
@@ -30,6 +32,31 @@
color: $blue-300;
margin-left: 4px;
}
.multi-line-value {
flex: 1 1 0;
color: $blue-100;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
white-space: pre-line;
}
}
.al-ico-edit {
color: $blue-300;
opacity: 0;
transition: opacity 0.3s;
cursor: pointer;
&:hover {
color: $blue-100;
}
}
&:hover {
.al-ico-edit {
opacity: 1;
}
}
}
}

View File

@@ -1,7 +1,8 @@
import {Component} from '@angular/core';
import {Component, EventEmitter, Output} from '@angular/core';
import {PipelineInfoComponent} from '@common/pipelines-controller/pipeline-details/pipeline-info.component';
import { fileSizeConfigStorage } from '@common/shared/pipes/filesize.pipe';
import {DATASETS_STATUS_LABEL, EXPERIMENTS_STATUS_LABELS} from '~/features/experiments/shared/experiments.const';
import {Task} from '~/business-logic/model/tasks/task';
@Component({
selector: 'sm-simple-dataset-version-details',
@@ -14,4 +15,5 @@ export class SimpleDatasetVersionDetailsComponent extends PipelineInfoComponent
public convertStatusMap = DATASETS_STATUS_LABEL;
public convertStatusMapBase = EXPERIMENTS_STATUS_LABELS;
@Output() editDescription = new EventEmitter<Task>();
}

View File

@@ -1,4 +1,9 @@
<sm-simple-dataset-version-details [entity]="selected$ | async" [project]="projectId$ | async" [step]="selectedEntity"></sm-simple-dataset-version-details>
<sm-simple-dataset-version-details
[entity]="selected$ | async"
[project]="projectId$ | async"
[step]="selectedEntity"
(editDescription)="editDescription($event)"
></sm-simple-dataset-version-details>
<div class="console-button">
<button class="btn btn-cml-primary d-flex align-items-center" (click)="toggleDetails()">
<i class="al-icon al-ico-console sm mr-3"></i>DETAILS

View File

@@ -1,13 +1,14 @@
import {Component} from '@angular/core';
import {
PipelineControllerInfoComponent, PipelineItem, StatusOption
} from '@common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component';
import {ChangeDetectorRef, Component, NgZone} from '@angular/core';
import {PipelineControllerInfoComponent, PipelineItem, StatusOption} from '@common/pipelines-controller/pipeline-controller-info/pipeline-controller-info.component';
import {DagManagerUnsortedService} from '@common/shared/services/dag-manager-unsorted.service';
import {
getSelectedPipelineStep,
setSelectedPipelineStep
} from '@common/experiments/actions/common-experiments-info.actions';
import {experimentDetailsUpdated, getSelectedPipelineStep, setSelectedPipelineStep} from '@common/experiments/actions/common-experiments-info.actions';
import {last} from 'lodash/fp';
import {Store} from '@ngrx/store';
import {MatDialog} from '@angular/material/dialog';
import {EditJsonComponent} from '@common/shared/ui-components/overlay/edit-json/edit-json.component';
import {Task} from '~/business-logic/model/tasks/task';
import {CommonExperimentsInfoEffects} from '@common/experiments/effects/common-experiments-info.effects';
import {tap} from 'rxjs/operators';
@Component({
selector: 'sm-simple-dataset-version-info',
@@ -23,6 +24,16 @@ export class SimpleDatasetVersionInfoComponent extends PipelineControllerInfoCom
defaultDetailsMode = StatusOption.content;
public maximizeResults: boolean;
constructor(
protected _dagManager: DagManagerUnsortedService<PipelineItem>,
protected store: Store<any>,
protected cdr: ChangeDetectorRef,
protected zone: NgZone,
private dialog: MatDialog,
private commonExperimentsInfoEffects: CommonExperimentsInfoEffects
) {
super(_dagManager, store, cdr, zone);
}
convertPipelineToDagModel(pipeline): PipelineItem[] {
const res = super.convertPipelineToDagModel(pipeline);
if (res?.length > 0) {
@@ -41,6 +52,13 @@ export class SimpleDatasetVersionInfoComponent extends PipelineControllerInfoCom
toggleResultSize() {
this.maximizeResults = ! this.maximizeResults;
if (this.detailsPanelMode === StatusOption.content) {
this.detailsPanelMode = null;
window.setTimeout(() => {
this.detailsPanelMode = StatusOption.content;
this.cdr.detectChanges();
}, 450);
}
}
selectStep(step?: PipelineItem) {
@@ -66,4 +84,21 @@ export class SimpleDatasetVersionInfoComponent extends PipelineControllerInfoCom
}
protected resetUninitializedRunningFields() {}
editDescription(dataset: Task) {
const editJsonComponent = this.dialog.open(EditJsonComponent, {
data: {
textData: dataset.comment,
title: 'EDIT DESCRIPTION',
typeJson: false,
}
});
editJsonComponent.afterClosed().subscribe(res => {
if (res !== undefined) {
this.store.dispatch(experimentDetailsUpdated({id: dataset.id, changes: {comment: res}}));
this.commonExperimentsInfoEffects.getExperimentInfo$
.pipe(tap(() => this.store.dispatch(getSelectedPipelineStep({id: dataset.id}))));
}
});
}
}

View File

@@ -1,7 +1,7 @@
<div class="preview-container" *ngIf="selected?.id">
<sm-experiment-output-plots #plots
class="dataset-version-preview"
[class.hidden]="plots.plotsList.length < 1"
[class.hidden]="plots.plotsList?.length < 1"
[isDatasetVersionPreview]="true"
[selected]="selected">
</sm-experiment-output-plots>
@@ -12,6 +12,6 @@
[isDatasetVersionPreview]="true"
[selected]="selected" >
</sm-debug-images>
<div *ngIf="plots.plotsList.length < 1 && !debugImages.debugImages?.[selected.id]?.data" class="no-data flex-middle">No preview to show</div>
<div *ngIf="plots.plotsList !== undefined && plots.plotsList.length < 1 && debugImages.debugImages !== null && (debugImages.debugImages[selected.id] && !debugImages.debugImages[selected.id].data)" class="no-data flex-middle">No preview to show</div>
</div>

View File

@@ -7,11 +7,11 @@ import * as experimentsActions from '@common/experiments/actions/common-experime
import {INITIAL_CONTROLLER_TABLE_COLS} from '@common/pipelines-controller/controllers.consts';
import {EXPERIMENTS_TABLE_COL_FIELDS} from '~/features/experiments/shared/experiments.const';
import {Store} from '@ngrx/store';
import {IExperimentsViewState} from '~/features/experiments/reducers/experiments-view.reducer';
import {SmSyncStateSelectorService} from '@common/core/services/sync-state-selector.service';
import {ActivatedRoute, Router} from '@angular/router';
import {MatDialog} from '@angular/material/dialog';
import {RefreshService} from '@common/core/services/refresh.service';
import { ExperimentsViewState } from '~/features/experiments/reducers/experiments-view.reducer';
import {take} from 'rxjs/operators';
@Component({
@@ -28,7 +28,7 @@ export class SimpleDatasetVersionsComponent extends ControllersComponent impleme
return params?.versionId;
}
constructor(protected store: Store<IExperimentsViewState>,
constructor(protected store: Store<ExperimentsViewState>,
protected syncSelector: SmSyncStateSelectorService,
protected route: ActivatedRoute,
protected router: Router,
@@ -46,7 +46,7 @@ export class SimpleDatasetVersionsComponent extends ControllersComponent impleme
.pipe(take(1))
.subscribe(experiments => {
this.firstExperiment = experiments?.[0];
if (this.firstExperiment ) {
if (this.firstExperiment) {
if (!this.route.snapshot.firstChild?.params.versionId) {
this.store.dispatch(experimentsActions.experimentSelectionChanged({
experiment: this.firstExperiment,

View File

@@ -48,7 +48,7 @@
<div class="d-flex justify-content-between">
<div>
Use ClearML Data from CLI or in your Python code.<br>
Run these code snippets for a quick example (Requires ClearML 1.6 or above).<br>
Run these code snippets for a quick example (Requires ClearML 1.7 or above).<br>
For more details see the <a [class.dark]="showButton" href="https://clear.ml/docs/latest/docs/clearml_data/clearml_data" target="_blank">documentation</a>
</div>
</div>

View File

@@ -5,6 +5,7 @@ import {setSelectedProjectId} from '@common/core/actions/projects.actions';
import {ConfirmDialogComponent} from '../../shared/ui-components/overlay/confirm-dialog/confirm-dialog.component';
import {showExampleDatasets} from '../../projects/common-projects.actions';
import {selectShowDatasetExamples} from '../../projects/common-projects.reducer';
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
@Component({
selector: 'sm-simple-datasets',
@@ -51,11 +52,11 @@ dataset.finalize()`;
}
protected getName() {
return 'dataset';
return EntityTypeEnum.simpleDataset;
}
protected getDeletePopupEntitiesList() {
return 'datasets';
return 'version';
}
createDataset() {

View File

@@ -25,31 +25,29 @@
<iframe (load)="iframeLoaded($event)" class="html-viewer" width="400" height="400" referrerpolicy="origin-when-cross-origin" [src]="source | safe:'url'"></iframe>
</div>
<div class="toolbar">
<div class="clickable-icon d-flex align-items-center justify-content-center pointer mr-2"
<div class="clickable-icon d-flex align-items-center justify-content-center pointer"
ngxClipboard
smTooltip="Copy URL"
matTooltipPosition="above"
[cbContent]="source"
(cbOnSuccess)="copyToClipboardSuccess(true)">
<i class="fas fa-copy"></i>
<i class="al-icon sm-md al-ico-copy-to-clipboard"></i>
</div>
<div class="clickable-icon d-flex align-items-center justify-content-center pointer"
smTooltip="Open URL in a new Tab"
matTooltipPosition="above"
(click)="openInNewTab(source)"
>
<i class="fas fa-external-link-alt"></i>
<i class="al-icon sm-md al-ico-export"></i>
</div>
</div>
</div>
</ng-container>
<div *ngIf="!isLoading" class="image-var ellipsis" [smTooltip]="frame?.variant" matTooltipPosition="above" smShowTooltipIfEllipsis
<div *ngIf="!isLoading" class="image-var ellipsis" [smTooltip]="frame?.variant" smShowTooltipIfEllipsis
>{{frame?.variantAndMetric || frame?.variant}}</div>
</div>
</ng-container>
<ng-container *ngIf="(source$ | async) as source">
<div *ngIf="isFailed" class="item">
<div *ngIf="isFailed" class="item-snippet">
<sm-snippet-error
[theme]="theme"
[copyContent]="source?.split('?X-Amz-Date')[0]"

View File

@@ -6,19 +6,10 @@
border-radius: 4px;
position: relative;
text-align: center;
background: #efefef;
&.dark{
background: #1f2434;
&.loading {
background: #1f2434;
}
background: $blue-50;
.image-var {
color: #a4b2db;
}
.html-viewer {
background-color: #1f2434;
}
&:hover {
box-shadow: 0 0 0 2px $blue-200;
}
&.loading {
@@ -30,7 +21,8 @@
top: 50%;
transform: translateY(-50%);
max-width: 100%;
max-height: 130px;
max-height: 100%;
border-radius: 4px;
}
img.loading, .html-wrap.loading {
@@ -39,16 +31,46 @@
background-position: center center;
background-size: 24px;
}
// LIGHT THEME
// --------------------------
&.light {
.image-var {
color: $blue-500;
background-color: rgba($blue-50, 0.9);
}
}
// DARK THEME
// --------------------------
&.dark {
background: $blue-700;
&.loading {
background: $blue-700;
}
.image-var {
color: $blue-300;
}
&:hover {
box-shadow: 0 0 0 2px $blue-500;
}
}
}
.image-var {
position: absolute;
color: $blue-500;
bottom: 2px;
left: 50%;
height: 20px;
transform: translateX(-50%);
width: calc(100% - 18px);
height: 20px;
position: absolute;
bottom: 8px;
left: 50%;
transform: translateX(-50%);
font-size: 12px;
border-radius: 4px;
padding: 0 12px;
color: $blue-100;
background-color: rgba($blue-900, 0.6);
}
.html-wrap {
@@ -78,10 +100,11 @@
.toolbar {
display: flex;
gap: 6px;
position: absolute;
bottom: 32px;
left: 50%;
transform: translateX(-50%);
left: 10px;
right: 10px;
opacity: 0;
visibility: hidden;
transition: opacity 0.5s, visibility 0.5s;
@@ -89,9 +112,13 @@
}
.clickable-icon {
width: 100%;
background-color: $blue-400;
color: $blue-50;
padding: 6px 18px;
border-radius: 4px;
&:hover {
background-color: $blue-500;
}
}

View File

@@ -18,6 +18,7 @@ import {
import {EventsDebugImagesResponse} from '~/business-logic/model/events/eventsDebugImagesResponse';
import {EventsGetTaskMetricsResponse} from '~/business-logic/model/events/eventsGetTaskMetricsResponse';
import {COMPARE_DEBUG_IMAGES_ONLY_FIELDS} from '../experiments-compare/experiments-compare.constants';
import {selectActiveWorkspaceReady} from '~/core/reducers/view.reducer';
export const ALL_IMAGES = '-- All --';
@@ -62,7 +63,7 @@ export class DebugImagesEffects {
/* eslint-disable @typescript-eslint/naming-convention */
metrics: [removeAllImagesFromPayload(action.payload)],
iters: 3,
scroll_id: debugImages[action.payload.task] ? debugImages[action.payload.task].scroll_id : null,
scroll_id: debugImages?.[action.payload.task] ? debugImages[action.payload.task].scroll_id : null,
navigate_earlier: action.type !== debugActions.getPreviousBatch.type,
refresh: [debugActions.setSelectedMetric.type, debugActions.refreshMetric.type].includes(action.type)
/* eslint-enable @typescript-eslint/naming-convention */
@@ -70,8 +71,8 @@ export class DebugImagesEffects {
.pipe(
mergeMap((res: EventsDebugImagesResponse ) => {
const actionsToShoot = [deactivateLoader(action.type)] as Action[];
actionsToShoot.push(debugActions.setDebugImages({res, task: action.payload.task}));
if (res.metrics[0].iterations && res.metrics[0].iterations.length > 0) {
actionsToShoot.push(debugActions.setDebugImages({res, task: action.payload.task}));
switch (action.type) {
case debugActions.getNextBatch.type:
actionsToShoot.push(debugActions.setTimeIsNow({task: action.payload.task, timeIsNow: false}));
@@ -112,6 +113,9 @@ export class DebugImagesEffects {
fetchExperiments$ = createEffect(() => this.actions$.pipe(
ofType(debugActions.fetchExperiments),
switchMap((action) => this.store.select(selectActiveWorkspaceReady).pipe(
filter(ready => ready),
map(() => action))),
// eslint-disable-next-line @typescript-eslint/naming-convention
switchMap((action) => this.apiTasks.tasksGetAllEx({id: action.tasks, only_fields: COMPARE_DEBUG_IMAGES_ONLY_FIELDS})
.pipe(
@@ -124,6 +128,9 @@ export class DebugImagesEffects {
fetchMetrics$ = createEffect(() => this.actions$.pipe(
ofType(debugActions.getDebugImagesMetrics, debugActions.refreshDebugImagesMetrics),
switchMap((action) => this.store.select(selectActiveWorkspaceReady).pipe(
filter(ready => ready),
map(() => action))),
switchMap((action) => this.eventsApi.eventsGetTaskMetrics({
/* eslint-disable @typescript-eslint/naming-convention */
tasks: action.tasks,

View File

@@ -11,11 +11,11 @@ import {
setViewerBeginningOfTime,
setViewerEndOfTime, setExperimentsNames, setMetrics, setSelectedMetric, setTimeIsNow
} from './debug-images-actions';
import {Task} from '../../business-logic/model/tasks/task';
import {Task} from '~/business-logic/model/tasks/task';
import {createFeatureSelector, createReducer, createSelector, on} from '@ngrx/store';
import {omit} from 'lodash/fp';
import {EventsGetDebugImageIterationsResponse} from '../../business-logic/model/events/eventsGetDebugImageIterationsResponse';
import {EventsDebugImagesResponse} from '../../business-logic/model/events/eventsDebugImagesResponse';
import {EventsGetDebugImageIterationsResponse} from '~/business-logic/model/events/eventsGetDebugImageIterationsResponse';
import {EventsDebugImagesResponse} from '~/business-logic/model/events/eventsDebugImagesResponse';
export interface IDebugImagesState {
@@ -47,7 +47,7 @@ export interface ITaskOptionalMetrics {
}
export const initialState: IDebugImagesState = {
debugImages: {},
debugImages: null,
settingsList: [],
searchTerm: '',
tasks: [],
@@ -92,7 +92,7 @@ export const debugSamplesReducer = createReducer(
on(getDebugImagesMetrics, state => ({...state, optionalMetrics: initialState.optionalMetrics, debugImages: initialState.debugImages})),
on(setSelectedMetric, (state, action) => ({
...state,
debugImages: omit(action.payload.task, state.debugImages),
...(state.debugImages && {debugImages: omit(action.payload.task, state.debugImages)}),
timeIsNow: {...state.timeIsNow, [action.payload.task]: true},
beginningOfTime: {...state.beginningOfTime, [action.payload.task]: false}
})),

View File

@@ -53,7 +53,7 @@
::ng-deep .mat-expansion-panel-content {
.mat-expansion-panel-body {
padding: 0 0 12px 28px;
padding: 12px 0 12px 28px;
}
}

View File

@@ -1,5 +1,6 @@
<div class="p-3 images-container">
<div class="single-debug-images-container" *ngFor="let experimentId of experimentIds; trackBy: trackExperiment" [class.separator]="experimentIds?.length > 1">
<div class="single-debug-images-container"
*ngFor="let experimentId of experimentIds; trackBy: trackExperiment; let first = first; let last = last" [class.separator]="experimentIds?.length > 1">
<header *ngIf="experimentIds?.length > 1">
<sm-experiment-compare-general-data
*ngIf="(experiments | itemById: experimentId).name"
@@ -9,7 +10,9 @@
>
</sm-experiment-compare-general-data>
</header>
<div class="d-flex" >
<div class="d-flex navigator-container" [class.active]="bindNavigationMode" [class.first]="first" [class.last]="last" >
<div class="connector-icon-container pointer" smTooltip="Sync browsing" [matTooltipShowDelay]="500" [class.active]="bindNavigationMode" [class.hidden]="last" (click)="toggleConnectNavigation()">
<i class="al-icon" [class.al-ico-connect]="bindNavigationMode" [class.al-ico-disconnect]="!bindNavigationMode"></i></div>
<div class="metric-bar" [class.minimized]="minimized" *ngIf="!thereAreNoMetrics(experimentId) && !isDatasetVersionPreview">
<label>Metric:</label>
<mat-form-field appearance="outline" [ngClass]="{'dark thin': isDarkTheme}">

View File

@@ -4,6 +4,44 @@
display: block;
height: 100%;
overflow-y: auto;
.connector-icon-container{
width: 32px;
height: 32px;
background: $blue-50;
&.active{
background: #fff;
}
border-radius: 32px;
position: absolute;
right: -16px;
top: 152px;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
color: $blue-300;
&.hidden{
display: none;
}
}
.navigator-container{
&.active{
background: $blue-50;
}
border-radius: 0;
margin: 0 0 24px -24px;
padding: 8px 0 4px 48px;
&.first{
border-radius: 6px 0 0 6px;
margin: 0 0 24px 0;
padding-left: 24px;
}
&.last{
border-radius: 0 6px 6px 0;
margin: 0 24px 24px -24px;
}
}
header {
margin-bottom: 24px;
@@ -60,7 +98,6 @@ sm-debug-images-view {
}
.metric-bar {
margin: 0 auto 24px;
grid-gap: 12px;
display: inline-grid;
grid-template-columns: auto 200px auto auto auto auto auto auto auto;
@@ -73,7 +110,6 @@ sm-debug-images-view {
.single-debug-images-container {
display: block;
overflow: hidden;
position: relative;
flex: 1;
min-width: 640px;
@@ -81,7 +117,7 @@ sm-debug-images-view {
color: $blue-500;
margin: 0 12px;
&.separator:not(:last-child){
border-right: 1px solid #f2f4fc;
border-right: 1px solid $blue-100;
}
}
@@ -99,3 +135,4 @@ sm-debug-images-view {
height: 250px;
}

View File

@@ -12,7 +12,7 @@ import {
} 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 {ExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer';
import {AdminService} from '~/shared/services/admin.service';
import {selectS3BucketCredentials} from '../core/reducers/common-auth-reducer';
import {MatDialog} from '@angular/material/dialog';
@@ -93,7 +93,7 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
public beginningOfTime$: Observable<any>;
public mergeIterations: boolean;
public debugImages: { [experimentId: string]: DebugSamples };
public debugImages: { [experimentId: string]: DebugSamples } = null;
public experimentNames: { [id: string]: string } = {};
public experimentIds: string[];
public allowAutorefresh: boolean = false;
@@ -111,9 +111,10 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
private selectedMetric: string;
public modifiedExperimentsNames: { [id: string]: string } = {};
public experiments: Partial<Task>[];
public bindNavigationMode: boolean = false;
constructor(
private store: Store<IExperimentInfoState>,
private store: Store<ExperimentInfoState>,
private adminService: AdminService,
private dialog: MatDialog,
private changeDetection: ChangeDetectorRef,
@@ -130,9 +131,12 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
this.debugImagesSubscription = combineLatest([
store.pipe(select(selectS3BucketCredentials)),
store.pipe(select(selectDebugImages))]).pipe(
map(([, debugImages]) => Object.entries(debugImages).reduce(((acc, val: any) => {
map(([, debugImages]) => !debugImages ? null : Object.entries(debugImages).reduce(((acc, val: any) => {
const id = val[0];
const iterations = val[1].metrics.find(m => m.task === id).iterations;
if (iterations?.length === 0) {
return {[id]:{}};
}
acc[id] = {
data: iterations.map(iteration => ({
iter: iteration.iter,
@@ -152,7 +156,11 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
return acc;
}), {}))
).subscribe(debugImages => {
console.log(debugImages);
this.debugImages = debugImages;
if (debugImages === null) {
return;
}
Object.keys(debugImages).forEach(key => {
if (!this.selectedMetrics[key]) {
this.selectedMetrics[key] = get('metric', debugImages[key]);
@@ -169,7 +177,7 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.selected && [changes.selected.currentValue.id] !== this.experimentIds) {
if (changes.selected && !isEqual([changes.selected.currentValue.id], this.experimentIds)) {
this.experimentNames = {[changes.selected.currentValue.id]: changes.selected.currentValue.name};
this.experimentIds = [changes.selected.currentValue.id];
this.selectMetric({value: this.allImages}, changes.selected.currentValue.id);
@@ -252,7 +260,7 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
task: experimentId,
metric: this.debugImages[experimentId]?.metric,
},
autoRefresh: (auto!==false)
autoRefresh: (auto !== false)
}));
}
});
@@ -318,22 +326,65 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
selectMetric(change: any, task) {
this.selectedMetric = change.value;
this.selectedMetrics[task] = change.value;
this.store.dispatch(debugActions.setSelectedMetric({payload: {task, metric: change.value}}));
if (this.bindNavigationMode) {
this.experimentIds.forEach(experimentId => {
this.selectedMetrics[experimentId] = change.value;
this.store.dispatch(debugActions.setSelectedMetric({payload: {task: experimentId, metric: change.value}}));
});
} else {
this.selectedMetrics[task] = change.value;
this.store.dispatch(debugActions.setSelectedMetric({payload: {task, metric: change.value}}));
}
}
nextBatch(taskMetric: TaskMetric) {
if (!this.beginningOfTime[taskMetric.task]) {
this.store.dispatch(debugActions.getNextBatch({payload: taskMetric}));
if (this.bindNavigationMode) {
this.experimentIds.forEach(experimentId => {
if (!this.beginningOfTime[experimentId]) {
this.store.dispatch(debugActions.getNextBatch({
payload: {
task: experimentId,
metric: this.selectedMetrics[experimentId]
}
}));
}
});
} else {
if (!this.beginningOfTime[taskMetric.task]) {
this.store.dispatch(debugActions.getNextBatch({payload: taskMetric}));
}
}
}
previousBatch(taskMetric: TaskMetric) {
this.store.dispatch(debugActions.getPreviousBatch({payload: taskMetric}));
if (this.bindNavigationMode) {
this.experimentIds.forEach(experimentId => {
this.store.dispatch(debugActions.getPreviousBatch({
payload: {
task: experimentId,
metric: this.selectedMetrics[experimentId]
}
}));
});
} else {
this.store.dispatch(debugActions.getPreviousBatch({payload: taskMetric}));
}
}
backToNow(taskMetric: TaskMetric) {
this.store.dispatch(debugActions.setSelectedMetric({payload: taskMetric}));
if (this.bindNavigationMode) {
this.experimentIds.forEach(experimentId => {
this.store.dispatch(debugActions.setSelectedMetric({
payload: {
task: experimentId,
metric: this.selectedMetrics[experimentId]
}
}));
});
} else {
this.store.dispatch(debugActions.setSelectedMetric({payload: taskMetric}));
}
}
thereAreNoMetrics(experiment) {
@@ -341,7 +392,7 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
}
thereAreNoDebugImages(experiment) {
return !(this.debugImages && this.debugImages[experiment] && this.debugImages[experiment].data.length > 0);
return !(this.debugImages && this.debugImages[experiment] && this.debugImages[experiment].data?.length > 0);
}
shouldShowNoImagesForExperiment(experiment: string) {
@@ -352,4 +403,7 @@ export class DebugImagesComponent implements OnInit, OnDestroy, OnChanges {
this.store.dispatch(addMessage('success', 'Copied to clipboard'));
}
toggleConnectNavigation() {
this.bindNavigationMode = !this.bindNavigationMode;
}
}

View File

@@ -1,87 +1,55 @@
import {Action, createAction, props} from '@ngrx/store';
import {ISmAction} from '../../core/models/actions';
import {ExperimentSettings} from '../../experiments/reducers/common-experiment-output.reducer';
import {createAction, props} from '@ngrx/store';
import {ScalarKeyEnum} from '~/business-logic/model/events/scalarKeyEnum';
import {EventsGetMultiTaskPlotsResponse} from '~/business-logic/model/events/eventsGetMultiTaskPlotsResponse';
import {ExperimentCompareSettings} from '@common/experiments-compare/reducers/experiments-compare-charts.reducer';
export const EXPERIMENTS_COMPARE_METRICS_CHARTS_ = 'EXPERIMENTS_COMPARE_METRICS_CHARTS_';
// COMMANDS:
export const SET_SELECTED_EXPERIMENTS = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_SELECTED_EXPERIMENTS';
export const SET_EXPERIMENT_METRICS_SEARCH_TERM = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_EXPERIMENT_METRICS_SEARCH_TERM';
export const SET_EXPERIMENT_HISTOGRAM = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_EXPERIMENT_HISTOGRAM';
export const SET_EXPERIMENT_PLOTS = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_EXPERIMENT_PLOTS';
export const SET_MULTI_SCALAR_CHARTS = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_MULTI_SCALAR_CHARTS';
export const SET_MULTI_PLOT_CHARTS = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_MULTI_PLOT_CHARTS';
// EVENTS:
export const GET_MULTI_SCALAR_CHARTS = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'GET_MULTI_SCALAR_CHARTS';
export const GET_MULTI_PLOT_CHARTS = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'GET_MULTI_PLOT_CHARTS';
export const getMultiScalarCharts = createAction(
EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'GET_MULTI_SCALAR_CHARTS',
props<{ taskIds: string[]; autoRefresh?: boolean; cached?: boolean }>()
);
export const getMultiPlotCharts = createAction(
EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'GET_MULTI_PLOT_CHARTS',
props<{ taskIds: Array<string>; autoRefresh?: boolean }>()
);
export const UPDATE_EXPERIMENT_SETTINGS = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'UPDATE_EXPERIMENT_SETTINGS';
export const RESET_EXPERIMENT_METRICS = EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'RESET_EXPERIMENT_METRICS';
export const setSelectedExperiments = createAction(
EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_SELECTED_EXPERIMENTS',
props<{selectedExperiments: string[]}>()
);
export class GetMultiScalarCharts implements ISmAction {
public type = GET_MULTI_SCALAR_CHARTS;
constructor(public payload: { taskIds: string[]; autoRefresh?: boolean; cached?: boolean }) {}
}
export class GetMultiPlotCharts implements ISmAction {
readonly type = GET_MULTI_PLOT_CHARTS;
constructor(public payload: { taskIds: Array<string>; autoRefresh?: boolean }) {}
}
export class SetSelectedExperiments implements Action {
readonly type = SET_SELECTED_EXPERIMENTS;
constructor(public payload: {selectedExperiments: Array<string>}) {
}
}
export class SetExperimentHistogram implements Action {
readonly type = SET_EXPERIMENT_HISTOGRAM;
constructor(public payload: any, public axisType: ScalarKeyEnum) {
}
}
export const setExperimentHistogram = createAction(
EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_EXPERIMENT_HISTOGRAM',
props<{payload; axisType: ScalarKeyEnum}>()
);
export const setAxisCache = createAction(
EXPERIMENTS_COMPARE_METRICS_CHARTS_ + '[set scalar axis type cache]',
props<{axis: ScalarKeyEnum}>()
);
export class SetExperimentPlots implements Action {
readonly type = SET_EXPERIMENT_PLOTS;
constructor(public payload: any) {
}
}
export class SetExperimentSettings implements Action {
readonly type = UPDATE_EXPERIMENT_SETTINGS;
constructor(public payload: { id: Array<string>; changes: Partial<ExperimentSettings>}) {
}
}
export class SetExperimentMetricsSearchTerm implements Action {
readonly type = SET_EXPERIMENT_METRICS_SEARCH_TERM;
constructor(public payload: { searchTerm: string}) {
}
}
export class ResetExperimentMetrics implements Action {
readonly type = RESET_EXPERIMENT_METRICS;
}
export const setExperimentPlots = createAction(
EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_EXPERIMENT_PLOTS',
props<{plots: EventsGetMultiTaskPlotsResponse['plots']}>()
);
export const setExperimentSettings = createAction(
EXPERIMENTS_COMPARE_METRICS_CHARTS_+ 'UPDATE_EXPERIMENT_SETTINGS',
props<{ id: string[]; changes: Partial<ExperimentCompareSettings> }>()
);
export const setExperimentMetricsSearchTerm = createAction(
EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'SET_EXPERIMENT_METRICS_SEARCH_TERM',
props<{ searchTerm: string }>()
);
export const resetExperimentMetrics = createAction(EXPERIMENTS_COMPARE_METRICS_CHARTS_ + 'RESET_EXPERIMENT_METRICS');

View File

@@ -1,10 +0,0 @@
import {Action} from '@ngrx/store';
export const EXPERIMENTS_COMPARE_DEBUG_IMAGES_ = 'EXPERIMENTS_COMPARE_DEBUG_IMAGES_';
export const SET_SOMETHING = EXPERIMENTS_COMPARE_DEBUG_IMAGES_ + 'SET_SOMETHING';
export class SetSomething implements Action {
readonly type = SET_SOMETHING;
}

View File

@@ -1,5 +1,5 @@
import {createAction, props} from '@ngrx/store';
import {IExperimentDetail} from '../../../features/experiments-compare/experiments-compare-models';
import {IExperimentDetail} from '~/features/experiments-compare/experiments-compare-models';
export const resetState = createAction('[experiment compare details] RESET_STATE');
export const setExperiments = createAction('[experiment compare details] SET_EXPERIMENTS', props<{experiments: IExperimentDetail[]}>());

View File

@@ -1,43 +1,20 @@
import {Action} from '@ngrx/store';
import {Task} from '../../../business-logic/model/tasks/task';
import {createAction, props} from '@ngrx/store';
import {Task} from '~/business-logic/model/tasks/task';
export const EXPERIMENTS_COMPARE_METRICS_VALUES_ = 'EXPERIMENTS_COMPARE_METRICS_VALUES_';
export const GET_COMPARED_EXPERIMENTS_METRICS_VALUES = EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'GET_COMPARED_EXPERIMENTS_METRICS_VALUES';
export const SET_COMPARED_EXPERIMENTS = EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'SET_COMPARED_EXPERIMENTS';
export const SET_METRIC_VALUES_SORT_BY = EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'SET_METRIC_VALUES_SORT_BY';
export const RESET_STATE = EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'RESET_STATE';
export class GetComparedExperimentsMetricsValues implements Action {
readonly type = GET_COMPARED_EXPERIMENTS_METRICS_VALUES;
constructor(public payload: { taskIds: string[]; autoRefresh?: boolean }) {}
}
export class SetComparedExperiments implements Action {
readonly type = SET_COMPARED_EXPERIMENTS;
public payload: { experiments: Array<Task> };
constructor(experiments: Array<Task>) {
this.payload = {experiments};
}
}
export class SetMetricValuesSortBy implements Action {
readonly type = SET_METRIC_VALUES_SORT_BY;
public payload: { metric: string, keyOrValue: string, order: string, keyOrder: Array<string> };
constructor(metric: string, keyOrValue: string, order: string, keyOrder: Array<string>) {
this.payload = {metric, keyOrValue, order, keyOrder};
}
}
export class ResetState implements Action {
readonly type = RESET_STATE;
constructor() {
}
}
export const getComparedExperimentsMetricsValues = createAction(
EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'GET_COMPARED_EXPERIMENTS_METRICS_VALUES',
props<{ taskIds: string[]; autoRefresh?: boolean }>()
);
export const setComparedExperiments = createAction(
EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'SET_COMPARED_EXPERIMENTS',
props<{ experiments: Task[] }>()
);
export const setMetricValuesSortBy = createAction(
EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'SET_METRIC_VALUES_SORT_BY',
props<{ metric: string; keyOrValue: string; order: string; keyOrder: string[] }>()
);
export const resetState = createAction(EXPERIMENTS_COMPARE_METRICS_VALUES_ + 'RESET_STATE');

View File

@@ -1,18 +1,29 @@
import {createAction, props} from '@ngrx/store';
import {GroupedHyperParams, HyperParams, MetricOption, MetricValueType} from '../reducers/experiments-compare-charts.reducer';
import {GroupedHyperParams, MetricOption, MetricValueType} from '../reducers/experiments-compare-charts.reducer';
export const EXPERIMENTS_COMPARE_SCALARS_GRAPH = 'EXPERIMENTS_COMPARE_SCALARS_GRAPH_';
export const GET_EXPERIMENTS_PARAMS = EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'GET_EXPERIMENTS_PARAMS';
export const SET_METRICS_LIST = EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_METRICS_LIST';
export const SET_PARAMS_LIST = EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_PARAMS_LIST';
export const SET_TASKS = EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_TASKS';
export const SET_HIDE_IDENTICAL_HYPER_PARAMS = EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_HIDE_IDENTICAL_HYPER_PARAMS';
export const SET_VALUE_TYPE = EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_VALUE_TYPE';
export const getExperimentsHyperParams = createAction(GET_EXPERIMENTS_PARAMS, props<{ experimentsIds: string[]; autoRefresh?: boolean }>());
export const setMetricsList = createAction(SET_METRICS_LIST, props<{ metricsList: MetricOption[] }>());
export const setTasks = createAction(SET_TASKS, props<{ tasks: any }>());
export const setvalueType = createAction(SET_VALUE_TYPE, props<{ valueType: MetricValueType }>());
export const setHyperParamsList = createAction(SET_PARAMS_LIST, props<{ hyperParams: GroupedHyperParams }>());
export const setShowIdenticalHyperParams = createAction(SET_HIDE_IDENTICAL_HYPER_PARAMS);
export const getExperimentsHyperParams = createAction(
EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'GET_EXPERIMENTS_PARAMS',
props<{ experimentsIds: string[]; autoRefresh?: boolean }>()
);
export const setMetricsList = createAction(
EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_METRICS_LIST',
props<{ metricsList: MetricOption[] }>()
);
export const setTasks = createAction(
EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_TASKS',
props<{ tasks: any }>()
);
export const setvalueType = createAction(
EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_VALUE_TYPE',
props<{ valueType: MetricValueType }>()
);
export const setHyperParamsList = createAction(
EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_PARAMS_LIST',
props<{ hyperParams: GroupedHyperParams }>()
);
export const setShowIdenticalHyperParams = createAction(EXPERIMENTS_COMPARE_SCALARS_GRAPH + 'SET_HIDE_IDENTICAL_HYPER_PARAMS');

View File

@@ -11,7 +11,7 @@ import {ChangeDetectorRef, OnDestroy, QueryList, ViewChildren, Directive} from '
import {ExperimentCompareDetailsBase} from '~/features/experiments-compare/experiments-compare-details.base';
import {ActivatedRoute, Router} from '@angular/router';
import {select, Store} from '@ngrx/store';
import {IExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer';
import {ExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer';
import {Observable, Subscription} from 'rxjs';
import {FlatTreeControl} from '@angular/cdk/tree';
import {CdkVirtualScrollViewport} from '@angular/cdk/scrolling';
@@ -82,7 +82,7 @@ export abstract class ExperimentCompareBase extends ExperimentCompareDetailsBase
constructor (
public router: Router,
public store: Store<IExperimentInfoState>,
public store: Store<ExperimentInfoState>,
public changeDetection: ChangeDetectorRef,
public activeRoute: ActivatedRoute,
public refresh: RefreshService

View File

@@ -35,7 +35,7 @@
class="title-key"
[smTooltip]="(renameMap[node.data.key] || node.data.key) | hideHashTitle"
[matTooltipShowDelay]="500"
matTooltipPosition="above"
smShowTooltipIfEllipsis
[class.ellipsis]="showEllipsis"
[style.width.px]="showEllipsis ? nativeWidth - 65 - node.level * 20 : null"

View File

@@ -20,7 +20,7 @@ import {
} from '../../jsonToDiffConvertor';
import {ExperimentCompareBase} from '../experiment-compare-base';
import {ActivatedRoute, Router} from '@angular/router';
import {IExperimentInfoState} from '../../../../features/experiments/reducers/experiment-info.reducer';
import {ExperimentInfoState} from '../../../../features/experiments/reducers/experiment-info.reducer';
import {ConfigurationItem} from '../../../../business-logic/model/tasks/configurationItem';
import {RefreshService} from '@common/core/services/refresh.service';
@@ -47,7 +47,7 @@ export class ExperimentCompareDetailsComponent extends ExperimentCompareBase imp
constructor(
public router: Router,
public store: Store<IExperimentInfoState>,
public store: Store<ExperimentInfoState>,
public changeDetection: ChangeDetectorRef,
public activeRoute: ActivatedRoute,
private cdr: ChangeDetectorRef,

View File

@@ -1,11 +1,11 @@
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 {ExperimentInfoState} from '~/features/experiments/reducers/experiment-info.reducer';
import {distinctUntilChanged, filter, map} from 'rxjs/operators';
import {selectRouterParams} from '@common/core/reducers/router-reducer';
import {get, has} from 'lodash/fp';
import {SetExperimentSettings, SetSelectedExperiments} from '../../actions/experiments-compare-charts.actions';
import {setExperimentSettings, setSelectedExperiments} from '../../actions/experiments-compare-charts.actions';
import {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';
@@ -55,7 +55,7 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
public metricValueType$: Observable<MetricValueType>;
public selectedItemsListMapper(data) {
return data
return data;
}
@ViewChild('searchMetric') searchMetricRef: ElementRef;
@@ -66,7 +66,7 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
}
}
constructor(private store: Store<IExperimentInfoState>, private refresh: RefreshService) {
constructor(private store: Store<ExperimentInfoState>, private refresh: RefreshService) {
this.metrics$ = this.store.pipe(select(selectScalarsGraphMetrics));
this.hyperParams$ = this.store.pipe(select(selectScalarsGraphHyperParams));
this.selectedHyperParams$ = this.store.pipe(select(selectSelectedSettingsHyperParams));
@@ -123,7 +123,7 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
)
.subscribe(ids => {
this.taskIds = ids.split(',');
this.store.dispatch(new SetSelectedExperiments({selectedExperiments: ['hyper-param-graph']}));
this.store.dispatch(setSelectedExperiments({selectedExperiments: ['hyper-param-graph']}));
this.store.dispatch(getExperimentsHyperParams({experimentsIds: this.taskIds}));
});
@@ -178,7 +178,7 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
}
updateServer(selectedMetric, selectedParams) {
this.store.dispatch(new SetExperimentSettings({id: ['hyper-param-graph'], changes: {selectedMetric: selectedMetric, selectedHyperParams: selectedParams}}));
this.store.dispatch(setExperimentSettings({id: ['hyper-param-graph'], changes: {selectedMetric, selectedHyperParams: selectedParams}}));
}

View File

@@ -31,9 +31,11 @@
[hiddenList]="listOfHidden | async"
[isGroupGraphs]="false"
[isCompare]="true"
[hoverMode]="hoverMode$ | async"
[smoothWeight]="(smoothWeight$ | async)"
[xAxisType]="xAxisType$ | async"
(resetGraphs)="resetMetrics()"
(hoverModeChanged)="hoverModeChanged($event)"
>
</sm-experiment-graphs>
</mat-drawer-content>

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