-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/src/app/features/dashboard/dashboard.const.ts b/src/app/features/dashboard/dashboard.const.ts
index 2124a7e9..b6e67ee9 100644
--- a/src/app/features/dashboard/dashboard.const.ts
+++ b/src/app/features/dashboard/dashboard.const.ts
@@ -7,42 +7,38 @@ export const RECENT_EXPERIMENTS_TABLE_COLS: ISmCol[] = [
id : RECENT_TASKS_TABLE_COL_FIELDS.TYPE,
headerType : ColHeaderTypeEnum.title,
header : 'TYPE',
- bodyStyleClass: 'type-col'
+ bodyStyleClass: 'type-col',
+ disableDrag : true,
},
{
- id : RECENT_TASKS_TABLE_COL_FIELDS.NAME,
- headerType: ColHeaderTypeEnum.title,
- header : 'TITLE',
+ id : RECENT_TASKS_TABLE_COL_FIELDS.NAME,
+ headerType : ColHeaderTypeEnum.title,
+ header : 'TITLE',
+ disableDrag: true,
},
{
- id : RECENT_TASKS_TABLE_COL_FIELDS.PROJECT,
- headerType: ColHeaderTypeEnum.title,
- header : 'PROJECT',
+ id : RECENT_TASKS_TABLE_COL_FIELDS.PROJECT,
+ headerType : ColHeaderTypeEnum.title,
+ header : 'PROJECT',
+ disableDrag: true,
},
{
- id : RECENT_TASKS_TABLE_COL_FIELDS.STARTED,
- headerType: ColHeaderTypeEnum.title,
- header : 'STARTED',
+ id : RECENT_TASKS_TABLE_COL_FIELDS.STARTED,
+ headerType : ColHeaderTypeEnum.title,
+ header : 'STARTED',
+ disableDrag: true,
},
{
- id : RECENT_TASKS_TABLE_COL_FIELDS.LAST_UPDATE,
- headerType: ColHeaderTypeEnum.title,
- header : 'UPDATED'
+ id : RECENT_TASKS_TABLE_COL_FIELDS.LAST_UPDATE,
+ headerType : ColHeaderTypeEnum.title,
+ header : 'UPDATED',
+ disableDrag: true,
},
- // {
- // id : RECENT_TASKS_TABLE_COL_FIELDS.QUEUE,
- // headerType: ColHeaderTypeEnum.title,
- // header : 'QUEUE'
- // },
- // {
- // id : RECENT_TASKS_TABLE_COL_FIELDS.WORKER,
- // headerType: ColHeaderTypeEnum.title,
- // header : 'WORKER'
- // },
{
id : RECENT_TASKS_TABLE_COL_FIELDS.STATUS,
headerType : ColHeaderTypeEnum.title,
header : 'STATUS',
- bodyStyleClass: 'status-col'
+ bodyStyleClass: 'status-col',
+ disableDrag : true,
}
];
diff --git a/src/app/features/dashboard/dashboard.module.ts b/src/app/features/dashboard/dashboard.module.ts
index 458f383e..1c8ffc39 100644
--- a/src/app/features/dashboard/dashboard.module.ts
+++ b/src/app/features/dashboard/dashboard.module.ts
@@ -12,18 +12,20 @@ import {commonDashboardReducer} from '../../webapp-common/dashboard/common-dashb
import {CommonSearchResultsModule} from '../../webapp-common/search/common-search-results.module';
import {DashboardSearchComponent} from './containers/dashboard-search/dashboard-search.component';
import {SearchResultsPageComponent} from './dumb/search-results-page/search-results-page.component';
+import {SharedModule} from '../../shared/shared.module';
@NgModule({
- imports : [
- ProjectCreateDialogModule,
- CommonModule,
- SMSharedModule,
- ExperimentSharedModule,
- DashboardRoutingModule,
- CommonSearchResultsModule,
- StoreModule.forFeature('dashboard', commonDashboardReducer),
- CommonDashboardModule,
- ],
+ imports: [
+ ProjectCreateDialogModule,
+ CommonModule,
+ SMSharedModule,
+ ExperimentSharedModule,
+ DashboardRoutingModule,
+ CommonSearchResultsModule,
+ StoreModule.forFeature('dashboard', commonDashboardReducer),
+ CommonDashboardModule,
+ SharedModule,
+ ],
declarations : [DashboardComponent, GettingStartedCardComponent, DashboardSearchComponent, SearchResultsPageComponent]
})
export class DashboardModule {
diff --git a/src/app/features/experiments-compare/experiment-details-reverter-service.base.ts b/src/app/features/experiments-compare/experiment-details-reverter-service.base.ts
index 7c1ac21d..d77c2536 100644
--- a/src/app/features/experiments-compare/experiment-details-reverter-service.base.ts
+++ b/src/app/features/experiments-compare/experiment-details-reverter-service.base.ts
@@ -15,19 +15,17 @@ export abstract class ExperimentDetailsReverterServiceBase {
return experimentIds.map(id => {
const exp = experiments.find(ex => ex.id === id);
return {
- id : exp.id,
- name : exp.name,
- status : exp.status,
+ id: exp.id,
+ name: exp.name,
+ status: exp.status,
last_iteration: exp.last_iteration,
- last_update : exp.last_update,
- project : exp.project,
- completed : exp.completed,
- tags : exp.tags,
- execution : this.revertExecution(exp),
- artifacts : this.revertArtifacts(exp),
- parameters : get('execution.parameters', exp) ?
- this.revertExecutionParameters(exp.execution.parameters) :
- undefined,
+ last_update: exp.last_update,
+ project: exp.project,
+ completed: exp.completed,
+ tags: exp.tags,
+ execution: this.revertExecution(exp),
+ artifacts: this.revertArtifacts(exp),
+ configuration: exp.configuration
};
});
}
@@ -35,18 +33,13 @@ export abstract class ExperimentDetailsReverterServiceBase {
protected sortObjectByKey(obj) {
const orderedLabels = {};
Object.keys(obj).sort().forEach((key) => {
- orderedLabels[key] = obj[key];
+ orderedLabels[key] = typeof obj[key] === 'string' ? obj[key] : this.sortObjectByKey(obj[key]);
});
return orderedLabels;
}
- public revertExecutionParameters(parameters: Execution['parameters']) {
- return this.sortObjectByKey(parameters);
- }
-
abstract revertArtifacts(exp: ISelectedExperiment);
abstract revertExecution(exp: ISelectedExperiment);
-
}
diff --git a/src/app/features/experiments-compare/experiments-compare-consts.ts b/src/app/features/experiments-compare/experiments-compare-consts.ts
index ee163464..eaf3f9a6 100644
--- a/src/app/features/experiments-compare/experiments-compare-consts.ts
+++ b/src/app/features/experiments-compare/experiments-compare-consts.ts
@@ -1,14 +1,17 @@
-export const EXPERIMENT_INFO_ONLY_FIELDS = [
+export const COMPARE_DETAILS_ONLY_FIELDS = [
'id',
'name',
'type',
'status',
'last_update',
'project.name',
- 'execution',
+ 'execution.artifacts',
+ 'execution.docker_cmd',
+ 'execution.model_labels',
'execution.model.name',
'execution.model.uri',
'execution.model.framework',
+ 'execution.model.design',
'script',
'tags',
'published',
@@ -17,5 +20,18 @@ export const EXPERIMENT_INFO_ONLY_FIELDS = [
'output.model.uri',
'output.model.framework',
'output.model.design',
-
+ 'configuration'
+];
+
+export const COMPARE_PARAMS_ONLY_FIELDS = [
+ 'id',
+ 'name',
+ 'type',
+ 'status',
+ 'last_update',
+ 'project.name',
+ 'tags',
+ 'published',
+ 'last_iteration',
+ 'hyperparams'
];
diff --git a/src/app/features/experiments-compare/experiments-compare-details.base.ts b/src/app/features/experiments-compare/experiments-compare-details.base.ts
index ec077349..bc607bc5 100644
--- a/src/app/features/experiments-compare/experiments-compare-details.base.ts
+++ b/src/app/features/experiments-compare/experiments-compare-details.base.ts
@@ -3,6 +3,7 @@ export abstract class ExperimentCompareDetailsBase {
return {
artifacts: this.buildSectionTree(experiment, 'artifacts', mergedExperiment),
execution: this.buildSectionTree(experiment, 'execution', mergedExperiment),
+ configuration: this.buildSectionTree(experiment, 'configuration', mergedExperiment),
};
}
diff --git a/src/app/features/experiments/actions/experiments-info.actions.ts b/src/app/features/experiments/actions/experiments-info.actions.ts
index 3ac39157..2519d7a3 100644
--- a/src/app/features/experiments/actions/experiments-info.actions.ts
+++ b/src/app/features/experiments/actions/experiments-info.actions.ts
@@ -37,21 +37,6 @@ export class CustomOutputLabelAdded implements Action {
-export class ModelSelected implements Action {
- readonly type = MODEL_SELECTED;
- public payload: {
- model: Model;
- fieldsToPopulate: { labelEnum: boolean; networkDesign: boolean };
- };
-
- constructor(payload: {
- model: Model;
- fieldsToPopulate: { labelEnum: boolean; networkDesign: boolean };
- }) {
- this.payload = payload;
- }
-}
-
export class UpdateSectionKnowledge implements Action {
readonly type = UPDATE_SECTION_KNOWLEDGE;
@@ -61,7 +46,6 @@ export class UpdateSectionKnowledge implements Action {
export class ExperimentDataUpdated implements Action {
readonly type = EXPERIMENT_DATA_UPDATED;
-
constructor(public payload: { id: Task['id']; changes: Partial
}) {
}
}
diff --git a/src/app/features/experiments/containers/experiment-info-execution/experiment-info-execution.component.html b/src/app/features/experiments/containers/experiment-info-execution/experiment-info-execution.component.html
index 3261ce60..62e23e0d 100644
--- a/src/app/features/experiments/containers/experiment-info-execution/experiment-info-execution.component.html
+++ b/src/app/features/experiments/containers/experiment-info-execution/experiment-info-execution.component.html
@@ -6,6 +6,7 @@
[editable]="editable$ | async"
[isInDev]="isInDev$ | async"
[formData]="executionInfo$ | async"
+ [showExtraDataSpinner]="showExtraDataloader$ | async"
[saving]="saving$ |async"
(formDataChanged)="onFormValuesChanged($event)"
(saveFormData)="saveExecutionData()"
diff --git a/src/app/features/experiments/containers/experiment-info-execution/experiment-info-execution.component.ts b/src/app/features/experiments/containers/experiment-info-execution/experiment-info-execution.component.ts
index 4cae3934..d7394dfe 100644
--- a/src/app/features/experiments/containers/experiment-info-execution/experiment-info-execution.component.ts
+++ b/src/app/features/experiments/containers/experiment-info-execution/experiment-info-execution.component.ts
@@ -4,19 +4,20 @@ import {Observable, Subscription} from 'rxjs';
import {IExecutionForm} from '../../shared/experiment-execution.model';
import {ISelectedExperiment} from '../../shared/experiment-info.model';
import {IExperimentInfoState} from '../../reducers/experiment-info.reducer';
-import {selectIsExperimentEditable, selectSelectedExperiment} from '../../reducers';
+import {selectIsExperimentEditable, selectSelectedExperiment, selectShowExtraDataSpinner} from '../../reducers';
import * as infoActions from '../../actions/experiments-info.actions';
import {selectExperimentExecutionInfoData, selectIsExperimentSaving, selectIsSelectedExperimentInDev} from '../../../../webapp-common/experiments/reducers';
import {selectBackdropActive} from '../../../../webapp-common/core/reducers/view-reducer';
@Component({
- selector : 'sm-experiment-info-input-model',
+ selector : 'sm-experiment-info-execution',
templateUrl: './experiment-info-execution.component.html',
styleUrls : ['./experiment-info-execution.component.scss']
})
export class ExperimentInfoExecutionComponent implements OnInit, OnDestroy {
public executionInfo$: Observable;
+ public showExtraDataloader$: Observable;
public selectedExperimentSubscrition: Subscription;
private selectedExperiment: ISelectedExperiment;
public editable$: Observable;
@@ -26,6 +27,7 @@ export class ExperimentInfoExecutionComponent implements OnInit, OnDestroy {
constructor(private store: Store) {
this.executionInfo$ = this.store.select(selectExperimentExecutionInfoData);
+ this.showExtraDataloader$ = this.store.select(selectShowExtraDataSpinner);
this.editable$ = this.store.select(selectIsExperimentEditable);
this.isInDev$ = this.store.select(selectIsSelectedExperimentInDev);
this.saving$ = this.store.select(selectIsExperimentSaving);
diff --git a/src/app/features/experiments/containers/experiment-info/experiment-info.component.html b/src/app/features/experiments/containers/experiment-info/experiment-info.component.html
index 926b729b..181dc1bb 100644
--- a/src/app/features/experiments/containers/experiment-info/experiment-info.component.html
+++ b/src/app/features/experiments/containers/experiment-info/experiment-info.component.html
@@ -1,16 +1,16 @@
-
-
+
+
+
diff --git a/src/app/features/experiments/containers/experiment-info/experiment-info.component.ts b/src/app/features/experiments/containers/experiment-info/experiment-info.component.ts
index 6cf90cbf..19c424e8 100644
--- a/src/app/features/experiments/containers/experiment-info/experiment-info.component.ts
+++ b/src/app/features/experiments/containers/experiment-info/experiment-info.component.ts
@@ -14,12 +14,14 @@ import * as commonInfoActions from '../../../../webapp-common/experiments/action
import * as infoActions from '../../actions/experiments-info.actions';
import {AddMessage} from '../../../../webapp-common/core/actions/layout.actions';
import {IExperimentInfo, ISelectedExperiment} from '../../shared/experiment-info.model';
+import {selectSelectedTableExperiment} from '../../../../webapp-common/experiments/reducers';
+import {ITableExperiment} from '../../../../webapp-common/experiments/shared/common-experiment-model.model';
@Component({
- selector : 'sm-experiment-info',
+ selector: 'sm-experiment-info',
templateUrl: './experiment-info.component.html',
- styleUrls : ['./experiment-info.component.scss']
+ styleUrls: ['./experiment-info.component.scss']
})
export class ExperimentInfoComponent implements OnInit, OnDestroy {
@@ -32,20 +34,22 @@ export class ExperimentInfoComponent implements OnInit, OnDestroy {
public isExample: boolean;
private projectId: string;
private experimentId: string;
- public showMaximize: boolean;
+ public resultsTab: boolean;
public queryParams$: Observable;
public routerConfig: string[];
private routerConfigSubscription: Subscription;
+ public tableSelectedExperiment$: Observable;
constructor(
private router: Router,
private store: Store,
private route: ActivatedRoute
) {
- this.editable$ = this.store.select(selectIsExperimentEditable);
- this.infoData$ = this.store.select(selectExperimentInfoData);
+ this.editable$ = this.store.select(selectIsExperimentEditable);
+ this.infoData$ = this.store.select(selectExperimentInfoData);
this.backdropActive$ = this.store.select(selectBackdropActive);
- this.queryParams$ = this.store.select(selectRouterQueryParams);
+ this.queryParams$ = this.store.select(selectRouterQueryParams);
+ this.tableSelectedExperiment$ = this.store.select(selectSelectedTableExperiment)
}
@@ -53,16 +57,17 @@ export class ExperimentInfoComponent implements OnInit, OnDestroy {
this.selectedExperimentSubscription = this.store.select(selectSelectedExperiment)
.subscribe(experiment => {
this.selectedExperiment = experiment;
- this.isExample = isExample(experiment);
+ this.isExample = isExample(experiment);
});
- this.routerConfigSubscription = this.store.select(selectRouterConfig).subscribe(routerConfig => {
+ this.routerConfigSubscription = this.store.select(selectRouterConfig).subscribe(routerConfig => {
this.routerConfig = routerConfig;
});
- this.paramsSubscription = this.store.select(selectRouterParams)
+
+ this.paramsSubscription = this.store.select(selectRouterParams)
.pipe(
tap((params) => {
- this.projectId = get('projectId', params);
- this.showMaximize = 'info-output' === this.route.firstChild.routeConfig.path;
+ this.projectId = get('projectId', params);
+ this.resultsTab = 'info-output' === this.route.firstChild.routeConfig.path;
}),
debounceTime(150),
map(params => get('experimentId', params)),
@@ -71,8 +76,12 @@ export class ExperimentInfoComponent implements OnInit, OnDestroy {
)
.subscribe(experimentId => {
this.experimentId = experimentId;
- this.store.dispatch(new commonInfoActions.ResetExperimentInfo());
- this.store.dispatch(new commonInfoActions.GetExperimentInfo(experimentId));
+
+ // We already have GetExperimentInfo in output (results) component
+ if (!this.resultsTab) {
+ this.store.dispatch(new commonInfoActions.ResetExperimentInfo());
+ this.store.dispatch(new commonInfoActions.GetExperimentInfo(experimentId));
+ }
});
}
@@ -80,7 +89,7 @@ export class ExperimentInfoComponent implements OnInit, OnDestroy {
this.paramsSubscription.unsubscribe();
this.selectedExperimentSubscription.unsubscribe();
this.routerConfigSubscription.unsubscribe();
- this.store.dispatch(new commonInfoActions.SetExperiment(null));
+ // this.store.dispatch(new commonInfoActions.SetExperiment(null));
this.store.dispatch(new commonInfoActions.ResetExperimentInfo());
}
diff --git a/src/app/features/experiments/experiments-routing.module.ts b/src/app/features/experiments/experiments-routing.module.ts
index 40269604..8ac3bc3b 100644
--- a/src/app/features/experiments/experiments-routing.module.ts
+++ b/src/app/features/experiments/experiments-routing.module.ts
@@ -18,6 +18,8 @@ import {ExperimentInfoInputModelComponent} from '../../webapp-common/experiments
import {ExperimentInfoOutputModelComponent} from '../../webapp-common/experiments/containers/experiment-info-output-model/experiment-info-output-model.component';
import {ExperimentInfoArtifactItemComponent} from '../../webapp-common/experiments/containers/experiment-info-artifact-item/experiment-info-artifact-item.component';
import {LeavingBeforeSaveAlertGuard} from '../../webapp-common/shared/guards/leaving-before-save-alert.guard';
+import {ExperimentInfoTaskModelComponent} from '../../webapp-common/experiments/containers/experiment-info-task-model/experiment-info-task-model.component';
+import {ExperimentInfoHyperParametersFormContainerComponent} from '../../webapp-common/experiments/containers/experiment-info-hyper-parameters-form-container/experiment-info-hyper-parameters-form-container.component';
export const routes: Routes = [
{
@@ -35,11 +37,17 @@ export const routes: Routes = [
{path: '', redirectTo: 'input-model', pathMatch: 'full'},
{path: 'input-model', component: ExperimentInfoInputModelComponent},
{path: 'output-model', component: ExperimentInfoOutputModelComponent},
- {path: 'artifact/:artifactId', children:[{ path:':mode', component: ExperimentInfoArtifactItemComponent}]},
- {path: 'other/:artifactId', children:[{ path:':mode', component: ExperimentInfoArtifactItemComponent}]}
+ {path: 'artifact/:artifactId', children: [{path: ':mode', component: ExperimentInfoArtifactItemComponent}]},
+ {path: 'other/:artifactId', children: [{path: ':mode', component: ExperimentInfoArtifactItemComponent}]}
+ ]
+ },
+ {
+ path : 'hyper-params', component: ExperimentInfoHyperParametersComponent, canDeactivate: [LeavingBeforeSaveAlertGuard],
+ children: [
+ {path: 'configuration/:configObject', component: ExperimentInfoTaskModelComponent},
+ {path: 'hyper-param/:hyperParamId', component: ExperimentInfoHyperParametersFormContainerComponent}
]
},
- {path: 'hyper-params', component: ExperimentInfoHyperParametersComponent, canDeactivate: [LeavingBeforeSaveAlertGuard]},
{path: 'general', component: ExperimentInfoGeneralComponent},
{
path : 'info-output',
diff --git a/src/app/features/experiments/experiments.consts.ts b/src/app/features/experiments/experiments.consts.ts
index fa94330c..7bfaf446 100644
--- a/src/app/features/experiments/experiments.consts.ts
+++ b/src/app/features/experiments/experiments.consts.ts
@@ -24,6 +24,7 @@ export const EXPERIMENT_INFO_ONLY_FIELDS = [
'output.model.project',
'output.model.design',
'output.model.uri',
+ 'hyperparams',
'execution',
'execution.model.name',
'execution.model.uri',
@@ -32,11 +33,19 @@ export const EXPERIMENT_INFO_ONLY_FIELDS = [
'execution.model.task.project.id',
'execution.model.project.id',
'execution.model.labels',
- 'script',
+ 'execution.model.design',
+ 'script.binary',
+ 'script.repository',
+ 'script.tag',
+ 'script.branch',
+ 'script.version_num',
+ 'script.entry_point',
+ 'script.working_dir',
+ 'script.requirements',
'system_tags',
'published',
'last_iteration',
- 'tags'
+ 'tags',
];
export const INITIAL_EXPERIMENT_TABLE_COLS: ISmCol[] = [
@@ -98,6 +107,7 @@ export const INITIAL_EXPERIMENT_TABLE_COLS: ISmCol[] = [
},
{
id : EXPERIMENTS_TABLE_COL_FIELDS.USER,
+ getter : 'user.name',
headerType : ColHeaderTypeEnum.sortFilter,
searchableFilter: true,
filterable : true,
diff --git a/src/app/features/experiments/reducers/experiment-info.reducer.ts b/src/app/features/experiments/reducers/experiment-info.reducer.ts
index ca7e6d0f..29c6a473 100644
--- a/src/app/features/experiments/reducers/experiment-info.reducer.ts
+++ b/src/app/features/experiments/reducers/experiment-info.reducer.ts
@@ -4,7 +4,7 @@ import {experimentSections, experimentSectionsEnum} from '../shared/experiments.
import {get, set} from 'lodash/fp';
import {commonExperimentInfoReducer, ICommonExperimentInfoState, initialCommonExperimentInfoState} from '../../../webapp-common/experiments/reducers/common-experiment-info.reducer';
import * as actions from '../../../webapp-common/experiments/actions/common-experiments-info.actions';
-import {SET_EXPERIMENT} from '../../../webapp-common/experiments/actions/common-experiments-info.actions';
+import {deleteHyperParamsSection, hyperParamsSectionUpdated, saveExperimentConfigObj, saveHyperParamsSection, SET_EXPERIMENT, setExperimentSaving, updateExperimentAtPath} from '../../../webapp-common/experiments/actions/common-experiments-info.actions';
export interface IExperimentInfoState extends ICommonExperimentInfoState {
activeSectionEdit: string;
@@ -16,13 +16,13 @@ export interface IExperimentInfoState extends ICommonExperimentInfoState {
export const initialState: IExperimentInfoState = {
...initialCommonExperimentInfoState,
- activeSectionEdit : null,
- saving : false,
- infoDataFreeze : null,
- userKnowledge : {
+ activeSectionEdit: null,
+ saving : false,
+ infoDataFreeze : null,
+ userKnowledge : {
[experimentSections.MODEL_INPUT]: false
} as any,
- errors : {
+ errors : {
model : null,
execution: null,
},
@@ -40,8 +40,17 @@ export function experimentInfoReducer(state: IExperimentInfoState = initialState
return {...state, infoData: {...state.infoData, model: {...state.infoData.model, ...action.payload}}};
case EXPERIMENT_DATA_UPDATED:
return {...state, infoData: {...state.infoData, ...action.payload.changes}};
+ case hyperParamsSectionUpdated.type:
+ return {...state, infoData: {...state.infoData, hyperparams: {...state.infoData.hyperparams, [action.section]: action.hyperparams}}};
+
case EXPERIMENT_SAVE:
return {...state, saving: true};
+ case saveHyperParamsSection.type:
+ return {...state, saving: true};
+ case saveExperimentConfigObj.type:
+ return {...state, saving: true};
+ case deleteHyperParamsSection.type:
+ return {...state, saving: true};
case ACTIVATE_EDIT:
return {...state, activeSectionEdit: action.payload, infoDataFreeze: state.infoData};
case SET_FREEZE_INFO:
@@ -52,6 +61,11 @@ export function experimentInfoReducer(state: IExperimentInfoState = initialState
return {...state, infoData: state.infoDataFreeze ? state.infoDataFreeze : state.infoData};
case EXPERIMENT_DETAILS_UPDATED:
return {...state, infoData: {...state.infoData, ...action.payload.changes}};
+ case setExperimentSaving.type:
+ return {...state, saving: action.saving};
+ case updateExperimentAtPath.type:
+ const newInfoData = set(action.path, action.value, state.infoData);
+ return {...state, infoData: newInfoData as any};
case actions.EXPERIMENT_UPDATED_SUCCESSFULLY:
return {...state, saving: false};
case ADD_CUSTOM_OUTPUT_LABEL: {
diff --git a/src/app/features/experiments/reducers/experiments-view.reducer.ts b/src/app/features/experiments/reducers/experiments-view.reducer.ts
index a461f9cd..dc41055c 100644
--- a/src/app/features/experiments/reducers/experiments-view.reducer.ts
+++ b/src/app/features/experiments/reducers/experiments-view.reducer.ts
@@ -12,7 +12,7 @@ export function experimentsViewReducer(state: IExperimentsViewState = initialSta
switch (action.type) {
case commonActions.RESET_EXPERIMENTS:
- return {...state, experiments: [], selectedExperiment: null, metricVariants: []};
+ return {...state, experiments: [], selectedExperiment: null, metricVariants: [], showAllSelectedIsActive: false};
default:
return commonExperimentsViewReducer(state, action);
}
diff --git a/src/app/features/experiments/reducers/index.ts b/src/app/features/experiments/reducers/index.ts
index 5b198a3a..4e0b36b4 100644
--- a/src/app/features/experiments/reducers/index.ts
+++ b/src/app/features/experiments/reducers/index.ts
@@ -34,6 +34,8 @@ export const selectMetricsLoading = createSelector(experimentsView, (sta
export const experimentInfo = createSelector(experiments, (state): IExperimentInfoState => state ? state.info : {});
export const selectSelectedExperiment = createSelector(experimentInfo, (state): ISelectedExperiment => state.selectedExperiment);
export const selectExperimentInfoData = createSelector(experimentInfo, (state): IExperimentInfo => state.infoData);
+export const selectShowExtraDataSpinner = createSelector(experimentInfo, state => state.showExtraDataSpinner);
+
// output selectors
diff --git a/src/app/features/experiments/shared/components/experiment-menu/experiment-menu.component.html b/src/app/features/experiments/shared/components/experiment-menu/experiment-menu.component.html
index 55930756..061b62e5 100644
--- a/src/app/features/experiments/shared/components/experiment-menu/experiment-menu.component.html
+++ b/src/app/features/experiments/shared/components/experiment-menu/experiment-menu.component.html
@@ -1,4 +1,4 @@
-
+
Manage Queue
-
-
+
{{'Add Tag' + (numSelected > 1 ? ' (' + numSelected + ' items)' : '')}}
@@ -45,7 +49,7 @@
Clone
- Move To Project
+ Move to Project
diff --git a/src/app/features/experiments/shared/components/experiment-menu/experiment-menu.component.scss b/src/app/features/experiments/shared/components/experiment-menu/experiment-menu.component.scss
index 1d4a1648..49773ec6 100644
--- a/src/app/features/experiments/shared/components/experiment-menu/experiment-menu.component.scss
+++ b/src/app/features/experiments/shared/components/experiment-menu/experiment-menu.component.scss
@@ -20,3 +20,6 @@ button {
}
}
+.al-ico-bars-menu {
+ line-height: 20px;
+}
diff --git a/src/app/features/experiments/shared/experiment-info.model.ts b/src/app/features/experiments/shared/experiment-info.model.ts
index 85f8b18e..437fcead 100644
--- a/src/app/features/experiments/shared/experiment-info.model.ts
+++ b/src/app/features/experiments/shared/experiment-info.model.ts
@@ -6,10 +6,11 @@ import {TaskStatusEnum} from '../../../business-logic/model/tasks/taskStatusEnum
import {Project} from '../../../business-logic/model/projects/project';
import {Script} from '../../../business-logic/model/tasks/script';
import {IExecutionForm} from './experiment-execution.model';
-import {Execution} from '../../../business-logic/model/tasks/execution';
import {IHyperParamsForm} from '../../../webapp-common/experiments/shared/experiment-hyper-params.model';
import {Artifact} from '../../../business-logic/model/tasks/artifact';
import {IExperimentModelInfo} from '../../../webapp-common/experiments/shared/common-experiment-model.model';
+import {ParamsItem} from '../../../business-logic/model/tasks/paramsItem';
+import {ConfigurationItem} from '../../../business-logic/model/tasks/configurationItem';
/**
* an extended object of task that includes projection, will come from the server as an api response.
@@ -38,6 +39,8 @@ export interface ISelectedExperiment {
status_message?: string;
status_reason?: string;
last_iteration?: number;
+ hyperparams?: { [section: string]: { [key: string]: ParamsItem } };
+ configuration?: { [key: string]: ConfigurationItem };
}
/**
@@ -49,7 +52,8 @@ export interface IExperimentInfo {
comment?: string;
model?: IExperimentModelInfo;
execution?: IExecutionForm;
- hyperParams?: IHyperParamsForm;
+ hyperparams?: { [key: string]: { [key: string]: ParamsItem }; };
+ configuration?: any;
artifacts?: Artifact[];
}
@@ -70,6 +74,7 @@ export interface ISelectedExperimentExecution {
id: Model['id'],
name: Model['name'],
uri: Model['uri'],
+ design?: Model['design'];
created: Model['created'],
labels: Model['labels'],
task: {
@@ -85,8 +90,6 @@ export interface ISelectedExperimentExecution {
name: User['name'];
},
};
- parameters: Execution['parameters'];
- model_desc?: any;
framework?: any;
model_labels?: { [key: string]: number; };
artifacts?: Artifact[];
diff --git a/src/app/features/experiments/shared/experiments.const.ts b/src/app/features/experiments/shared/experiments.const.ts
index c9f1b572..f147c18a 100644
--- a/src/app/features/experiments/shared/experiments.const.ts
+++ b/src/app/features/experiments/shared/experiments.const.ts
@@ -21,7 +21,7 @@ export const EXPERIMENTS_TABLE_COL_FIELDS = {
TYPE : 'type' as ExperimentTableColFieldsEnum,
NAME : 'name' as ExperimentTableColFieldsEnum,
TAGS : 'tags' as ExperimentTableColFieldsEnum,
- USER : 'user.name' as ExperimentTableColFieldsEnum,
+ USER : 'users' as ExperimentTableColFieldsEnum,
STARTED : 'started' as ExperimentTableColFieldsEnum,
COMPLETED : 'completed' as ExperimentTableColFieldsEnum,
STATUS : 'status' as ExperimentTableColFieldsEnum,
diff --git a/src/app/features/experiments/shared/services/experiment-converter.service.ts b/src/app/features/experiments/shared/services/experiment-converter.service.ts
index f650c87a..7b764935 100644
--- a/src/app/features/experiments/shared/services/experiment-converter.service.ts
+++ b/src/app/features/experiments/shared/services/experiment-converter.service.ts
@@ -24,19 +24,18 @@ export class ExperimentConverterService {
if (!isEqual(executionInfoNoOutputDest, executionInfoNoOutputDestBeforeChange) ||
!isEqual(experimentInfo.model, experimentInfoBeforeChange.model) ||
- !isEqual(experimentInfo.hyperParams, experimentInfoBeforeChange.hyperParams) ||
+ !isEqual(experimentInfo.hyperparams, experimentInfoBeforeChange.hyperparams) ||
!isEqual(experimentInfo.model, experimentInfoBeforeChange.model)
) {
convertedExperiment.execution = this.convertExecution(experimentInfo.execution,
- experimentInfo.model, experimentInfo.hyperParams);
+ experimentInfo.model);
}
return convertedExperiment;
}
- convertExecution(execution: IExecutionForm, model: IExperimentModelInfo,
- hyperParams: IHyperParamsForm): Execution {
+ convertExecution(execution: IExecutionForm, model: IExperimentModelInfo): Execution {
return {
- ...this.commonExperimentConverterService.commonConvertExecution(execution, model, hyperParams),
+ ...this.commonExperimentConverterService.commonConvertExecution(execution, model),
};
}
diff --git a/src/app/features/models/containers/model-menu/model-menu.component.html b/src/app/features/models/containers/model-menu/model-menu.component.html
index a18820c3..bd22e2e7 100644
--- a/src/app/features/models/containers/model-menu/model-menu.component.html
+++ b/src/app/features/models/containers/model-menu/model-menu.component.html
@@ -1,4 +1,4 @@
-
+
Publish
-
+
{{model?.system_tags?.includes('archived') ? 'Restore from archive' : 'Archive'}}
-
@@ -26,7 +28,7 @@
Download
- Move To Project
+ Move to Project
diff --git a/src/app/features/models/containers/model-menu/model-menu.component.scss b/src/app/features/models/containers/model-menu/model-menu.component.scss
index 3ef56047..49773ec6 100644
--- a/src/app/features/models/containers/model-menu/model-menu.component.scss
+++ b/src/app/features/models/containers/model-menu/model-menu.component.scss
@@ -19,3 +19,7 @@ button {
}
}
}
+
+.al-ico-bars-menu {
+ line-height: 20px;
+}
diff --git a/src/app/features/models/dumb/model-header/model-header.component.scss b/src/app/features/models/dumb/model-header/model-header.component.scss
index 5f704723..20307753 100644
--- a/src/app/features/models/dumb/model-header/model-header.component.scss
+++ b/src/app/features/models/dumb/model-header/model-header.component.scss
@@ -4,7 +4,6 @@
.header-container {
padding-left: 24px;
- padding-right: 24px;
height: 66px;
transition: background-color 0.5s;
/deep/ button {
diff --git a/src/app/features/not-found/not-found/not-found.component.html b/src/app/features/not-found/not-found/not-found.component.html
index 3738275c..e80dd6d0 100644
--- a/src/app/features/not-found/not-found/not-found.component.html
+++ b/src/app/features/not-found/not-found/not-found.component.html
@@ -1,6 +1,6 @@
diff --git a/src/app/features/not-found/not-found/not-found.component.scss b/src/app/features/not-found/not-found/not-found.component.scss
index 5b448712..d2d3cef3 100644
--- a/src/app/features/not-found/not-found/not-found.component.scss
+++ b/src/app/features/not-found/not-found/not-found.component.scss
@@ -45,6 +45,7 @@
}
}
.cat{
+ font-size: 140px;
width:140px;
height:140px;
margin-top:44px;
diff --git a/src/app/features/projects/dumb/project-card/project-card.component.html b/src/app/features/projects/dumb/project-card/project-card.component.html
index e24a2461..ce01f388 100644
--- a/src/app/features/projects/dumb/project-card/project-card.component.html
+++ b/src/app/features/projects/dumb/project-card/project-card.component.html
@@ -1,5 +1,5 @@
+ [isExample]=" project.name !== 'All projects' && !project.company?.id">
Sample
diff --git a/src/app/layout/layout.module.ts b/src/app/layout/layout.module.ts
index cb27070a..47edd50d 100644
--- a/src/app/layout/layout.module.ts
+++ b/src/app/layout/layout.module.ts
@@ -5,16 +5,18 @@ import {SMSharedModule} from '../webapp-common/shared/shared.module';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {RouterModule} from '@angular/router';
import {SurveyComponent} from './survey/survey.component';
+import {SharedModule} from '../shared/shared.module';
@NgModule({
declarations: [SideNavComponent, SurveyComponent],
exports: [SideNavComponent, SurveyComponent],
- imports: [
- CommonModule,
- SMSharedModule,
- FormsModule,
- ReactiveFormsModule,
- RouterModule,
- ]
+ imports: [
+ CommonModule,
+ SMSharedModule,
+ FormsModule,
+ ReactiveFormsModule,
+ RouterModule,
+ SharedModule,
+ ]
})
export class LayoutModule { }
diff --git a/src/app/layout/side-nav/side-nav.component.html b/src/app/layout/side-nav/side-nav.component.html
index 1fe937c2..80b3621e 100644
--- a/src/app/layout/side-nav/side-nav.component.html
+++ b/src/app/layout/side-nav/side-nav.component.html
@@ -3,7 +3,7 @@
-

+
diff --git a/src/app/layout/side-nav/side-nav.component.scss b/src/app/layout/side-nav/side-nav.component.scss
index ac7ff3bb..3f8a7726 100644
--- a/src/app/layout/side-nav/side-nav.component.scss
+++ b/src/app/layout/side-nav/side-nav.component.scss
@@ -1,11 +1,5 @@
@import "../../webapp-common/shared/ui-components/styles/variables";
-:host {
- position: fixed;
- height: 100%;
- top: 0;
-}
-
$transition-delay: 0.1;
$transition-speed: 0.15;
@@ -19,19 +13,6 @@ $transition-speed: 0.15;
transition-delay: $transition-delay + s;
overflow: hidden;
- //&:hover {
- // width: $side-bar-open-width;
- // .item.logo {
- // .item-icon {
- // transition: opacity $transition-speed + $transition-delay + s;
- // opacity: 0;
- // }
- //.caption {
- // opacity: 1;
- //}
- //}
- //}
-
.item.logo {
background: $eggplant-purple;
cursor: default;
@@ -41,10 +22,6 @@ $transition-speed: 0.15;
opacity: 1;
height: 100%;
- .logo-a {
- max-height: $side-bar-close-width * 0.5;
- width: auto;
- }
}
&:hover {
@@ -55,7 +32,7 @@ $transition-speed: 0.15;
}
a:hover {
- color: $cloudy-blue;
+ color: $blue-250;
}
.item {
@@ -66,8 +43,12 @@ $transition-speed: 0.15;
text-align: center;
cursor: pointer;
+ .fa-24 {
+ font-size: 24px;
+ }
+
&:hover {
- background-color: $dark-grey-blue-two;
+ background-color: $blue-500;
box-shadow: inset 0 -1px 0 0 #252b3d;
.caption {
@@ -81,17 +62,11 @@ $transition-speed: 0.15;
position: absolute;
left: 0;
color: #a7b2d8;
-
- img {
- max-width: 48%;
- height: 100%;
- padding: 4px;
-
- &.resized-icon {
- max-width: 62%;
- }
+ i{
+ line-height: 64px;
+ height: 64px;
+ width: 64px;
}
-
.neon {
color: $neon-yellow-betterinchrome;
}
@@ -104,7 +79,7 @@ $transition-speed: 0.15;
text-transform: uppercase;
font-size: 15px;
opacity: 0.4;
- color: $cloudy-blue;
+ color: $blue-250;
}
}
diff --git a/src/app/layout/side-nav/side-nav.component.ts b/src/app/layout/side-nav/side-nav.component.ts
index a9a5112a..5bda6739 100644
--- a/src/app/layout/side-nav/side-nav.component.ts
+++ b/src/app/layout/side-nav/side-nav.component.ts
@@ -5,6 +5,7 @@ import {selectSelectedProjectId} from '../../webapp-common/core/reducers/project
import {Observable} from 'rxjs';
import {Router} from '@angular/router';
import {SearchDeactivate} from '../../webapp-common/search/common-search-results.actions';
+import {environment} from '../../../environments/environment';
@Component({
@@ -15,6 +16,8 @@ import {SearchDeactivate} from '../../webapp-common/search/common-search-results
export class SideNavComponent {
public selectedProjectId$: Observable
;
currentUser: any;
+ environment = environment;
+
constructor(public store: Store, private router: Router) {
this.selectedProjectId$ = this.store.select(selectSelectedProjectId);
@@ -25,4 +28,8 @@ export class SideNavComponent {
public resetSearch() {
this.store.dispatch(new SearchDeactivate());
}
+
+ get guestUser(): boolean {
+ return this.currentUser && this.currentUser?.role === 'guest';
+ }
}
diff --git a/src/app/shared/constants/non-common-consts.ts b/src/app/shared/constants/non-common-consts.ts
index cc0a0625..6c69d1f3 100644
--- a/src/app/shared/constants/non-common-consts.ts
+++ b/src/app/shared/constants/non-common-consts.ts
@@ -5,14 +5,23 @@ export const PROJECT_ROUTES = ['experiments', 'models'];
export type PROJECT_ROUTES_TYPE = 'models' | 'experiments';
export const EXPERIMENTS_STATUS_LABELS = {
- [TaskStatusEnum.Created] : 'Draft',
- [TaskStatusEnum.Queued] : 'Pending',
- [TaskStatusEnum.InProgress] : 'Running',
- [TaskStatusEnum.Completed] : 'Completed',
- [TaskStatusEnum.Published] : 'Published',
- [TaskStatusEnum.Failed] : 'Failed',
- [TaskStatusEnum.Stopped] : 'Completed',
- [TaskStatusEnum.Closed] : 'Closed',
- [TaskTypeEnum.Testing] : 'Testing',
- [TaskTypeEnum.Training] : 'Training'
+ [TaskStatusEnum.Created] : 'Draft',
+ [TaskStatusEnum.Queued] : 'Pending',
+ [TaskStatusEnum.InProgress] : 'Running',
+ [TaskStatusEnum.Completed] : 'Completed',
+ [TaskStatusEnum.Published] : 'Published',
+ [TaskStatusEnum.Failed] : 'Failed',
+ [TaskStatusEnum.Stopped] : 'Completed',
+ [TaskStatusEnum.Closed] : 'Closed',
+ [TaskTypeEnum.Testing] : 'Testing',
+ [TaskTypeEnum.Training] : 'Training',
+ [TaskTypeEnum.Inference] : 'Inference',
+ [TaskTypeEnum.DataProcessing]: 'Data Processing',
+ [TaskTypeEnum.Application] : 'Application',
+ [TaskTypeEnum.Monitor] : 'Monitor',
+ [TaskTypeEnum.Controller] : 'Controller',
+ [TaskTypeEnum.Optimizer] : 'Optimizer',
+ [TaskTypeEnum.Service] : 'Service',
+ [TaskTypeEnum.Qc] : 'Qc',
+ [TaskTypeEnum.Custom] : 'Custom'
};
diff --git a/src/app/shared/directives/check-permission.directive.ts b/src/app/shared/directives/check-permission.directive.ts
index 5e158f86..f177c57d 100644
--- a/src/app/shared/directives/check-permission.directive.ts
+++ b/src/app/shared/directives/check-permission.directive.ts
@@ -1,15 +1,51 @@
-import {Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core';
+import {Directive, Input, OnDestroy, TemplateRef, ViewContainerRef} from '@angular/core';
+import { Store } from '@ngrx/store';
+import {selectCurrentUser} from '../../webapp-common/core/reducers/users-reducer';
+import {Subscription} from 'rxjs';
+import {User} from '../../business-logic/model/users/user';
@Directive({
selector: '[smCheckPermission]'
})
-export class CheckPermissionDirective {
+export class CheckPermissionDirective implements OnDestroy{
+ private userDataSubscription: Subscription;
+ private elseTemplateRef: TemplateRef|null = null;
+ private user: User;
+ private blocked = true;
- @Input() set smCheckPermission(permission: string) {
- this.viewContainer.createEmbeddedView(this.templateRef);
+ @Input() set smCheckPermission(permission: boolean) {
+ this.blocked = !permission;
+ this.setUpView();
}
- constructor(private templateRef: TemplateRef,
- private viewContainer: ViewContainerRef
- ) {
+
+ @Input()
+ set smCheckPermissionElse(templateRef: TemplateRef|null) {
+ this.elseTemplateRef = templateRef;
+ this.setUpView();
+ }
+
+ constructor(
+ private templateRef: TemplateRef,
+ private viewContainer: ViewContainerRef,
+ private store: Store) {
+ this.userDataSubscription = this.store.select(selectCurrentUser)
+ .subscribe((user: User) => {
+ this.user = user;
+ this.setUpView();
+ });
+ }
+
+ setUpView() {
+ const allowed = !this.blocked && this.user && this.user.role !== 'guest';
+ this.viewContainer.clear();
+ if (allowed) {
+ this.viewContainer.createEmbeddedView(this.templateRef);
+ } else if (this.elseTemplateRef) {
+ this.viewContainer.createEmbeddedView(this.elseTemplateRef);
+ }
+ }
+
+ ngOnDestroy(): void {
+ this.userDataSubscription?.unsubscribe();
}
}
diff --git a/src/app/shared/guards/auth.guard.ts b/src/app/shared/guards/auth.guard.ts
deleted file mode 100644
index b6dde761..00000000
--- a/src/app/shared/guards/auth.guard.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-// src/app/auth/auth-guard.service.ts
-import {Injectable} from '@angular/core';
-import {Router, CanActivate} from '@angular/router';
-import {Store} from '@ngrx/store';
-import {selectCurrentUser} from '../../webapp-common/core/reducers/users-reducer';
-import {User} from '../../business-logic/model/users/user';
-
-@Injectable()
-export class AuthGuard implements CanActivate {
- private user: User;
-
- constructor(
- public router: Router,
- public store: Store) {
- this.store.select(selectCurrentUser).subscribe(user => {this.user = user; });
- }
-
- canActivate(): boolean {
- if (!this.user) {
- this.router.navigateByUrl('/login');
- }
- return !!this.user;
- }
-}
diff --git a/src/app/webapp-common/admin/admin.component.html b/src/app/webapp-common/admin/admin.component.html
index 528be3bb..d2d2cdb2 100644
--- a/src/app/webapp-common/admin/admin.component.html
+++ b/src/app/webapp-common/admin/admin.component.html
@@ -3,7 +3,13 @@
logout
+
+ Disable HiDPI browser scale override. Reload to apply
+
@@ -12,7 +18,7 @@
(credentialRevoked)="onCredentialRevoked($event)">
- Create new credentials
+ Create new credentials
diff --git a/src/app/webapp-common/admin/admin.component.scss b/src/app/webapp-common/admin/admin.component.scss
index 40f216fb..616ba81f 100644
--- a/src/app/webapp-common/admin/admin.component.scss
+++ b/src/app/webapp-common/admin/admin.component.scss
@@ -1,6 +1,11 @@
+@import "../../webapp-common/shared/ui-components/styles/variables.scss";
+@import "../../webapp-common/shared/ui-components/styles/mixins/lines.scss";
+
:host {
margin: 0 auto;
width: 97%;
+ overflow: auto;
+ padding-top: 20px;
/deep/ .empty-card .line {
display: none;
@@ -11,4 +16,24 @@
align-items: center;
margin-top: 20px;
}
+
+ .separator {
+ margin: $card-spacer-y / 2 $card-spacer-x;
+ @include line($line-height-sm + px)
+ }
+
+ mat-slide-toggle {
+ display: block;
+ }
+
+ .reload {
+ color: transparent;
+ text-decoration: underline;
+ transition: color 0.5s;
+
+ &.highlight {
+ color: $neon-yellow;
+ transition: color 0.5s;
+ }
+ }
}
diff --git a/src/app/webapp-common/admin/admin.component.ts b/src/app/webapp-common/admin/admin.component.ts
index 6171de28..3ae313c5 100644
--- a/src/app/webapp-common/admin/admin.component.ts
+++ b/src/app/webapp-common/admin/admin.component.ts
@@ -11,6 +11,8 @@ import {CreateCredentialDialogComponent} from './create-credential-dialog/create
import {filter, map} from 'rxjs/operators';
import {Logout} from '../core/actions/users.actions';
import * as versions from '../../../version.json';
+import {MatSlideToggleChange} from '@angular/material/slide-toggle';
+
@Component({
selector : 'sm-admin',
@@ -24,13 +26,17 @@ export class AdminComponent implements OnInit, OnDestroy {
public credentials: Observable;
public newCredential: Observable;
public S3BucketCredentials: Observable;
- public version = versions['webapp-treeish'];
+ public version = versions['version'];
+ public disableHidpi: boolean = false;
+ public disableHidpiChanged: boolean = false;
+ public isChrome: boolean;
constructor(
public adminService: AdminService,
private store: Store,
private dialog: MatDialog
) {
+ this.isChrome = window['chrome'];
this.currentUser = store.select(selectCurrentUser);
this.userTitle = this.currentUser.pipe(
map((user) => [
@@ -45,6 +51,9 @@ export class AdminComponent implements OnInit, OnDestroy {
ngOnInit() {
+
+ this.disableHidpi = window.localStorage.getItem('disableHidpi') === 'true';
+
this.store.dispatch(getAllCredentials());
this.newCredentialSub = this.newCredential.pipe(filter(credential => Object.keys(credential).length > 0)).subscribe(credential => {
const dialog = this.dialog.open(CreateCredentialDialogComponent, {data: {credential}});
@@ -74,4 +83,17 @@ export class AdminComponent implements OnInit, OnDestroy {
ngOnDestroy(): void {
this.newCredentialSub.unsubscribe();
}
+
+ HidpiChange(event: MatSlideToggleChange) {
+ window.localStorage.setItem('disableHidpi', JSON.stringify(event.checked));
+ this.disableHidpiChanged = !this.disableHidpiChanged;
+ }
+
+ reload(event) {
+ if (this.disableHidpiChanged) {
+ event.stopPropagation();
+ event.preventDefault();
+ window.location.reload();
+ }
+ }
}
diff --git a/src/app/webapp-common/admin/base-admin.service.ts b/src/app/webapp-common/admin/base-admin.service.ts
index f9406bc2..30804afb 100644
--- a/src/app/webapp-common/admin/base-admin.service.ts
+++ b/src/app/webapp-common/admin/base-admin.service.ts
@@ -49,7 +49,11 @@ export class BaseAdminService {
this.store.dispatch(showLocalFilePopUp({url}));
}
- signUrlIfNeeded(url, skipLocalFile = false) {
+ signUrlIfNeeded(url, skipLocalFile = true, skipFileServer = true) {
+ if (isFileserverUrl(url, window.location.hostname) && !skipFileServer) {
+ return converToReverseProxy(url);
+ }
+
if (this.isLocalFile(url) && !skipLocalFile) {
this.checkLocalServerRunning(url);
return this.redirectToLocalServer(url);
@@ -59,9 +63,6 @@ export class BaseAdminService {
return this.signGoogleCloudUrl(url);
}
- if (isFileserverUrl(url, window.location.hostname)) {
- return converToReverseProxy(url);
- }
const now = new Date();
if (this.previouslySignedUrls[url] && (new Date(this.previouslySignedUrls[url].expires).getTime() > now.getTime())) {
return this.previouslySignedUrls[url].signedURL;
@@ -180,11 +181,11 @@ export class BaseAdminService {
}
public isS3Url(src) {
- return src.startsWith('s3://');
+ return src?.startsWith('s3://');
}
public isGoogleCloudUrl(src) {
- return src.startsWith('gs://');
+ return src?.startsWith('gs://');
}
public getBucketAndKeyFromSrc = (src) => {
@@ -214,6 +215,7 @@ export class BaseAdminService {
};
} else {
try {
+ src = this.encodeSpecialCharacters(src);
const amazon = AmazonS3URI(src);
return {
Bucket: amazon.bucket,
@@ -229,7 +231,7 @@ export class BaseAdminService {
// Uses Allegro Chrome extension injecting patch_local_link function to window - hack to get local files.
redirectToLocalServer(url: string): string {
- return `http://localhost:${LOCAL_SERVER_PORT}${url.replace('file://','/')}`;
+ return `http://localhost:${LOCAL_SERVER_PORT}${url.replace('file://', '/')}`;
}
isLocalFile(url: string): boolean {
@@ -263,4 +265,19 @@ export class BaseAdminService {
return url.startsWith('azure://');
}
+ public replaceAll(baseString: string, toReplace: string, replaceWith: string, ignore= false): string{
+ return baseString.replace(new RegExp(toReplace.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(replaceWith)=="string")?replaceWith.replace(/\$/g,"$$$$"):replaceWith);
+
+ }
+
+
+ private encodeSpecialCharacters(src: string) {
+ src = this.replaceAll(src, '%','%25');
+ src = this.replaceAll(src, '#','%23');
+ src = this.replaceAll(src, '\\','%5C');
+ src = this.replaceAll(src, '^','%5E');
+ return src;
+ }
+
+
}
diff --git a/src/app/webapp-common/admin/s3-access/s3-access.component.html b/src/app/webapp-common/admin/s3-access/s3-access.component.html
index 77f2f9fc..e63c01ba 100644
--- a/src/app/webapp-common/admin/s3-access/s3-access.component.html
+++ b/src/app/webapp-common/admin/s3-access/s3-access.component.html
@@ -33,7 +33,7 @@
-
+
diff --git a/src/app/webapp-common/assets/icons/compare-icon.svg b/src/app/webapp-common/assets/icons/compare-icon.svg
index 2e0e320a..a27cadd1 100644
--- a/src/app/webapp-common/assets/icons/compare-icon.svg
+++ b/src/app/webapp-common/assets/icons/compare-icon.svg
@@ -2,7 +2,7 @@
diff --git a/src/app/webapp-common/common-styles.scss b/src/app/webapp-common/common-styles.scss
index f9529eaf..1ac1e0da 100644
--- a/src/app/webapp-common/common-styles.scss
+++ b/src/app/webapp-common/common-styles.scss
@@ -1,7 +1,7 @@
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
@import '~@angular/material/theming';
-@import "~angular-notifier/styles.scss";
-@import "~angular-notifier/styles/themes/theme-material.scss";
+@import "angular-notifier/styles.scss";
+@import "angular-notifier/styles/themes/theme-material.scss";
@import "shared/ui-components/styles/notifications";
@import "~britecharts/src/styles/charts/line";
@import "~britecharts/src/styles/charts/donut";
@@ -10,6 +10,7 @@
@import "~britecharts/src/styles/common/axes";
@import "~britecharts/src/styles/common/grid";
@import "shared/ui-components/styles/material-palette";
+@import "assets/fonts/trains-icons.scss";
@include mat-core();
//@import "../webapp-common/shared/ui-components/styles/material-theme.scss";
@@ -35,14 +36,16 @@ $sm-theme: mat-light-theme($sm-theme-primary, $sm-theme-accent, $sm-theme-warn);
@include mat-radio-theme($sm-theme);
.mat-checkbox-frame,
- .mat-radio-outer-circle{
+ .mat-radio-outer-circle {
border-color: $purple;
}
+
.light-theme .mat-radio-button.mat-radio-disabled .mat-radio-outer-circle,
- .light-theme .mat-radio-button.mat-radio-disabled .mat-radio-label-content{
+ .light-theme .mat-radio-button.mat-radio-disabled .mat-radio-label-content {
border-color: $blue-200 !important;
color: $blue-200 !important;
}
+
.light-theme .mat-radio-button.mat-radio-disabled .mat-radio-inner-circle {
background-color: transparent !important;
}
@@ -52,13 +55,13 @@ $sm-theme: mat-light-theme($sm-theme-primary, $sm-theme-accent, $sm-theme-warn);
outline: none !important;
}
-html,
-body {
+html, body {
height: 100%;
margin: 0;
padding: 0;
font-family: 'Heebo', sans-serif;
font-size: 13px;
+ overflow: hidden;
}
@@ -99,6 +102,22 @@ h5.al-header {
}
}
+mat-expansion-panel {
+ box-shadow: unset;
+
+ &:hover {
+ background: transparent !important;
+ }
+
+ .mat-expansion-panel-header {
+ margin-bottom: 0;
+
+ &:hover {
+ background: transparent !important;
+ }
+ }
+}
+
.mat-expansion-panel-header {
font-family: 'Heebo', sans-serif;
}
@@ -397,10 +416,10 @@ as-split {
}
$type-colors: (
- string: #ff8400,
- number: $neon-yellow-betterinchrome,
- boolean: #b938a4,
- date: #05668D,
+ string: #ff8400,
+ number: $neon-yellow-betterinchrome,
+ boolean: #b938a4,
+ date: #05668D,
);
.dark-theme {
@@ -418,7 +437,7 @@ $type-colors: (
}
.segment-key {
- color: $cloudy-blue !important;
+ color: $blue-250 !important;
}
}
}
@@ -529,3 +548,9 @@ body .mat-menu-panel .mat-form-field {
}
}
}
+
+.hyper-parameters-tooltip {
+ white-space: pre-line;
+ text-align: left !important;
+ font-size: 14px !important;
+}
diff --git a/src/app/webapp-common/core/actions/layout.actions.ts b/src/app/webapp-common/core/actions/layout.actions.ts
index 5fefbde5..a3f9ace8 100644
--- a/src/app/webapp-common/core/actions/layout.actions.ts
+++ b/src/app/webapp-common/core/actions/layout.actions.ts
@@ -1,7 +1,5 @@
-import { MatSnackBarConfig } from '@angular/material/snack-bar';
import {MessageSeverityEnum, VIEW_ACTIONS} from '../../../app.constants';
-import {Action} from '@ngrx/store';
-import {ISmAction} from '../models/actions';
+import {Action, createAction, props} from '@ngrx/store';
import {omit} from 'lodash/fp';
export class SetAutoRefresh {
@@ -87,16 +85,15 @@ export class AddMessage implements Action {
public payload: {
severity: string;
msg: string;
- action?: string;
- config?: MatSnackBarConfig;
+ userActions?: {actions: any[]; name: string}[];
};
- constructor(severity: MessageSeverityEnum, msg: string, action?: string, config?: MatSnackBarConfig) {
- this.payload = {severity, msg, action, config};
+ constructor(severity: MessageSeverityEnum, msg: string, userActions?: {actions: any[]; name: string}[]) {
+ this.payload = {severity, msg, userActions};
}
}
-export class SetServerUpdatesAvailable implements ISmAction {
+export class SetServerUpdatesAvailable implements Action {
public type = VIEW_ACTIONS.SET_SERVER_UPDATES_AVAILABLE;
public payload: { availableUpdates: any };
@@ -105,4 +102,9 @@ export class SetServerUpdatesAvailable implements ISmAction {
}
}
+export const setScaleFactor = createAction(
+ VIEW_ACTIONS + '[set scale]',
+ props<{scale: number}>()
+ );
+
diff --git a/src/app/webapp-common/core/actions/users.actions.ts b/src/app/webapp-common/core/actions/users.actions.ts
index 92da2516..49ae883c 100644
--- a/src/app/webapp-common/core/actions/users.actions.ts
+++ b/src/app/webapp-common/core/actions/users.actions.ts
@@ -1,4 +1,4 @@
-import {Action} from '@ngrx/store';
+import {Action, createAction, props} from '@ngrx/store';
import {USERS_ACTIONS} from '../../../app.constants';
import {User} from '../../../business-logic/model/users/user';
@@ -8,11 +8,10 @@ export class FetchCurrentUser implements Action {
}
-export class SetCurrentUser implements Action {
- type = USERS_ACTIONS.SET_CURRENT_USER;
-
- constructor(public payload: User) {}
-}
+export const setCurrentUser = createAction(
+ USERS_ACTIONS.SET_CURRENT_USER,
+ props<{user: User; terms_of_use?: any}>()
+);
export class Logout implements Action {
type = USERS_ACTIONS.LOGOUT;
diff --git a/src/app/webapp-common/core/effects/layout.effects.ts b/src/app/webapp-common/core/effects/layout.effects.ts
index 20549af2..1899b061 100644
--- a/src/app/webapp-common/core/effects/layout.effects.ts
+++ b/src/app/webapp-common/core/effects/layout.effects.ts
@@ -1,15 +1,15 @@
import {Injectable} from '@angular/core';
import {Actions, Effect, ofType} from '@ngrx/effects';
-import {VIEW_ACTIONS} from '../../../app.constants';
+import {EmptyAction, VIEW_ACTIONS} from '../../../app.constants';
import * as layoutActions from '../actions/layout.actions';
-import {filter, flatMap, map, switchMap, tap, take} from 'rxjs/operators';
+import {filter, map, switchMap, take, flatMap} from 'rxjs/operators';
import {get} from 'lodash/fp';
import {ApiTasksService} from '../../../business-logic/api-services/tasks.service';
import {Observable, of} from 'rxjs';
import {ApiModelsService} from '../../../business-logic/api-services/models.service';
-import {NotifierService} from 'angular-notifier';
import { MatDialogRef, MatDialog } from '@angular/material/dialog';
import {AlertDialogComponent} from '../../shared/ui-components/overlay/alert-dialog/alert-dialog.component';
+import {NotifierService} from '../../angular-notifier';
const ERROR_AGGREGATION = 600000;
@@ -46,6 +46,7 @@ export class LayoutEffects {
@Effect({dispatch: false})
popupError = this.actions.pipe(
ofType
(VIEW_ACTIONS.SET_SERVER_ERROR),
+ filter(action => action.payload.serverError?.status !== 401),
map((action) => {
const customMessage: string = action.payload.customMessage;
if (action.payload.aggregateSimilar) {
@@ -70,13 +71,12 @@ export class LayoutEffects {
})
);
- @Effect({dispatch: false})
+ @Effect()
addMessage: Observable = this.actions.pipe(
ofType(VIEW_ACTIONS.ADD_MESSAGE),
map((action: layoutActions.AddMessage) => action.payload),
- tap(payload => {
- this.notifierService.show({type: payload.severity, message: payload.msg});
- })
+ flatMap(payload => this.notifierService.show({type: payload.severity, message: payload.msg, actions: payload.userActions})),
+ flatMap(actions => actions.length > 0? actions : [new EmptyAction()])
);
private parseError(errorMessage) {
diff --git a/src/app/webapp-common/core/effects/projects.effects.ts b/src/app/webapp-common/core/effects/projects.effects.ts
index bba095ea..ad7ddf13 100644
--- a/src/app/webapp-common/core/effects/projects.effects.ts
+++ b/src/app/webapp-common/core/effects/projects.effects.ts
@@ -24,6 +24,8 @@ import {MatDialog} from '@angular/material/dialog';
import {ApiOrganizationService} from '../../../business-logic/api-services/organization.service';
import {OrganizationGetTagsResponse} from '../../../business-logic/model/organization/organizationGetTagsResponse';
+const ALL_PROJECTS_OBJECT = {id: '*', name: 'All Projects'};
+
@Injectable()
export class ProjectsEffects {
@@ -36,7 +38,7 @@ export class ProjectsEffects {
getProjects$ = this.actions$.pipe(
ofType(actions.GET_PROJECTS),
switchMap(() =>
- this.projectsApi.projectsGetAllEx({})
+ this.projectsApi.projectsGetAllEx({only_fields:['name', 'company']})
.pipe(map(res => new actions.SetAllProjects(res.projects)))
)
);
@@ -77,7 +79,7 @@ export class ProjectsEffects {
filter(([action, projects]) => !!action.payload.projectId),
switchMap(([action, projects]) => {
if (action.payload.projectId === '*') {
- return [new actions.SetSelectedProject({id: '*', name: 'All Projects'})];
+ return [new actions.SetSelectedProject(ALL_PROJECTS_OBJECT)];
} else {
const proj = projects.find(proj => proj.id === action.payload.projectId);
if (proj) {
diff --git a/src/app/webapp-common/core/effects/users.effects.ts b/src/app/webapp-common/core/effects/users.effects.ts
index a08737e4..3ef95229 100644
--- a/src/app/webapp-common/core/effects/users.effects.ts
+++ b/src/app/webapp-common/core/effects/users.effects.ts
@@ -3,7 +3,7 @@ import {Router} from '@angular/router';
import {Actions, Effect, ofType} from '@ngrx/effects';
import {USERS_ACTIONS} from '../../../app.constants';
import {ApiUsersService} from '../../../business-logic/api-services/users.service';
-import {FetchCurrentUser, SetCurrentUser} from '../actions/users.actions';
+import {FetchCurrentUser, setCurrentUser} from '../actions/users.actions';
import {catchError, flatMap, switchMap} from 'rxjs/operators';
import {RequestFailed} from '../actions/http.actions';
import {logoutFn} from '../../../shared/utils/logout-utils';
@@ -13,15 +13,17 @@ import {ApiAuthService} from '../../../business-logic/api-services/auth.service'
@Injectable()
export class CommonUserEffects {
- constructor(private actions: Actions, private userService: ApiUsersService,
- private router: Router, private authService: ApiAuthService) {}
+ constructor(
+ private actions: Actions, private userService: ApiUsersService,
+ private router: Router, private authService: ApiAuthService
+ ) {}
@Effect()
fetchUser$ = this.actions.pipe(
ofType(USERS_ACTIONS.FETCH_CURRENT_USER),
flatMap(() => this.userService.usersGetCurrentUser({})
.pipe(
- switchMap((res) => [new SetCurrentUser(res)]),
+ switchMap((res) => [setCurrentUser(res)]),
catchError(error => [new RequestFailed(error)])
)
)
diff --git a/src/app/webapp-common/core/interceptors/webapp-interceptor.ts b/src/app/webapp-common/core/interceptors/webapp-interceptor.ts
index dce8966a..b9c70801 100644
--- a/src/app/webapp-common/core/interceptors/webapp-interceptor.ts
+++ b/src/app/webapp-common/core/interceptors/webapp-interceptor.ts
@@ -2,13 +2,20 @@ import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { environment } from '../../../../environments/environment';
-import {catchError, take} from 'rxjs/operators';
+import {catchError} from 'rxjs/operators';
import { Router } from '@angular/router';
+import {selectCurrentUser} from '../reducers/users-reducer';
+import {Store} from '@ngrx/store';
+import { setCurrentUser } from '../actions/users.actions';
+import {User} from '../../../business-logic/model/users/user';
@Injectable()
export class WebappIntercptor implements HttpInterceptor {
+ private user: User;
- constructor(private router: Router) {}
+ constructor(private router: Router, private store: Store) {
+ this.store.select(selectCurrentUser).subscribe(user => this.user = user);
+ }
intercept(request: HttpRequest, next: HttpHandler): Observable> {
request = request.clone({
@@ -19,12 +26,17 @@ export class WebappIntercptor implements HttpInterceptor {
return next.handle(request).pipe(
catchError((err: HttpErrorResponse) => {
const redirectUrl: string = window.location.pathname + window.location.search;
- if(request.url.endsWith('system.company_info')){
+ if (request.url.endsWith('system.company_info')) {
return throwError(err);
}
// For automatic login don't go to login page (login in APP_INITIALIZER)
- if (err.status === 401 && (['/dashboard'].includes(redirectUrl) || !environment.autoLogin)) {
+ if (err.status === 401 && (
+ ['/dashboard'].includes(redirectUrl) ||
+ !environment.autoLogin ||
+ (environment.autoLogin && this.user)
+ )) {
if (redirectUrl.indexOf('/login') === -1) {
+ this.store.dispatch(setCurrentUser({user: null, terms_of_use: null }));
this.router.navigate(['login'], {queryParams: {redirect: redirectUrl}});
}
return throwError(err);
diff --git a/src/app/webapp-common/core/reducers/projects.reducer.ts b/src/app/webapp-common/core/reducers/projects.reducer.ts
index a281eab8..8b754d66 100644
--- a/src/app/webapp-common/core/reducers/projects.reducer.ts
+++ b/src/app/webapp-common/core/reducers/projects.reducer.ts
@@ -1,9 +1,9 @@
import {createSelector} from '@ngrx/store';
import * as projectsActions from '../actions/projects.actions';
-import {Project} from '../../../business-logic/model/projects/project';
-import {sortBy} from 'lodash/fp';
import {setTagColors, setTags, TagColor} from '../actions/projects.actions';
+import {Project} from '../../../business-logic/model/projects/project';
import {getSystemTags} from '../../../features/experiments/shared/experiments.utils';
+
export const SYSTEM_TAGS_BLACK_LIST = ['archived'];
interface RootProjects {
@@ -25,7 +25,7 @@ const initRootProjects: RootProjects = {
};
export const projects = state => state.rootProjects as RootProjects;
-export const selectProjects = createSelector(projects, (state): Project[] => sortBy('name', state.projects));
+export const selectProjects = createSelector(projects, (state): Project[] => state.projects);
export const selectSelectedProject = createSelector(projects, state => state.selectedProject);
export const selectSelectedProjectId = createSelector(selectSelectedProject, (selectedProject): string => selectedProject ? selectedProject.id : '');
export const selectIsArchivedMode = createSelector(projects, state => state.archive);
diff --git a/src/app/webapp-common/core/reducers/users-reducer.ts b/src/app/webapp-common/core/reducers/users-reducer.ts
index c8ea06d5..6d69c960 100644
--- a/src/app/webapp-common/core/reducers/users-reducer.ts
+++ b/src/app/webapp-common/core/reducers/users-reducer.ts
@@ -1,5 +1,6 @@
import {USERS_ACTIONS} from '../../../app.constants';
import {createSelector} from '@ngrx/store';
+import {setCurrentUser} from '../actions/users.actions';
export interface IUsersState {
currentUser: string;
@@ -21,11 +22,11 @@ export function usersReducer(state = initUsers, action) {
switch (action.type) {
case USERS_ACTIONS.FETCH_CURRENT_USER:
return {...state};
- case USERS_ACTIONS.SET_CURRENT_USER:
+ case setCurrentUser.type:
return {
...state,
- currentUser: action.payload.user,
- termsOfUse: action.payload.terms_of_use
+ currentUser: action.user,
+ termsOfUse: action.terms_of_use
};
case USERS_ACTIONS.LOGOUT:
return {
diff --git a/src/app/webapp-common/core/reducers/view-reducer.ts b/src/app/webapp-common/core/reducers/view-reducer.ts
index 93f22218..1391a845 100644
--- a/src/app/webapp-common/core/reducers/view-reducer.ts
+++ b/src/app/webapp-common/core/reducers/view-reducer.ts
@@ -1,6 +1,7 @@
import {HTTP, HTTP_ACTIONS, VIEW_ACTIONS} from '../../../app.constants';
import {createSelector} from '@ngrx/store';
import {get} from 'lodash/fp';
+import {setScaleFactor} from '../actions/layout.actions';
export interface ViewState {
loading: {[endpoint: string]: boolean};
@@ -12,6 +13,7 @@ export interface ViewState {
autoRefresh: boolean;
compareAutoRefresh: boolean;
applicationVisible: boolean;
+ scaleFactor: number;
}
export const initViewState: ViewState = {
@@ -25,6 +27,7 @@ export const initViewState: ViewState = {
autoRefresh: true,
compareAutoRefresh: false,
applicationVisible: true,
+ scaleFactor: 100
};
export const views = state => state.views as ViewState;
@@ -38,6 +41,7 @@ export const selectResultMessage = createSelector(views, state => state.resultMe
export const selectAutoRefresh = createSelector(views, state => state && state.autoRefresh);
export const selectCompareAutoRefresh = createSelector(views, state => state.compareAutoRefresh);
export const selectAppVisible = createSelector(views, state => state.applicationVisible);
+export const selectScaleFactor = createSelector(views, state => state.scaleFactor);
export function viewReducer(viewState: ViewState = initViewState, action) {
@@ -58,6 +62,8 @@ export function viewReducer(viewState: ViewState = initViewState, action) {
};
case VIEW_ACTIONS.VISIBILITY_CHANGED:
return {...viewState, applicationVisible: action.visible};
+ case setScaleFactor.type:
+ return {...viewState, scaleFactor: action.scale};
case VIEW_ACTIONS.RESET_LOADER:
return {...viewState, loading: {}};
case HTTP.API_REQUEST_SUCCESS:
diff --git a/src/app/webapp-common/dashboard/common-dashboard.actions.ts b/src/app/webapp-common/dashboard/common-dashboard.actions.ts
index 7109e102..c5c13024 100644
--- a/src/app/webapp-common/dashboard/common-dashboard.actions.ts
+++ b/src/app/webapp-common/dashboard/common-dashboard.actions.ts
@@ -11,7 +11,7 @@ export class GetRecentProjects implements ISmAction {
public type = DASHBOARD_ACTIONS.GET_RECENT_PROJECTS;
public payload: { getAllFilter: ProjectsGetAllRequest };
- constructor(getAllFilter: any = {stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active, include_stats: true, order_by: ['-last_update'], page: 0, page_size: CARDS_IN_ROW}) {
+ constructor(getAllFilter: any = {stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active, include_stats: true, order_by: ['featured', '-last_update'], page: 0, page_size: CARDS_IN_ROW}) {
this.payload = {getAllFilter};
}
}
diff --git a/src/app/webapp-common/dashboard/common-dashboard.effects.ts b/src/app/webapp-common/dashboard/common-dashboard.effects.ts
index 13e99e0d..143b98e9 100644
--- a/src/app/webapp-common/dashboard/common-dashboard.effects.ts
+++ b/src/app/webapp-common/dashboard/common-dashboard.effects.ts
@@ -28,7 +28,7 @@ export class CommonDashboardEffects {
flatMap((action) => this.projectsApi.projectsGetAllEx(action.payload.getAllFilter)
.pipe(
flatMap(res => [new SetRecentProjects(res.projects), new DeactiveLoader(action.type)]),
- catchError(error => [new DeactiveLoader(action.type), new AddMessage(MESSAGES_SEVERITY.ERROR, 'Fetching projects failed'), new RequestFailed(error)])
+ catchError(error => [new DeactiveLoader(action.type), new RequestFailed(error)])
)
)
);
@@ -47,7 +47,7 @@ export class CommonDashboardEffects {
})
.pipe(
flatMap(res => [new SetRecentTasks(res.tasks as Array), new DeactiveLoader(action.type)]),
- catchError(err => [new RequestFailed(err), new AddMessage(MESSAGES_SEVERITY.ERROR, 'Fetching recent experiments failed'), new DeactiveLoader(action.type)])
+ catchError(err => [new RequestFailed(err), new DeactiveLoader(action.type)])
)
)
);
diff --git a/src/app/webapp-common/dashboard/common-dashboard.module.ts b/src/app/webapp-common/dashboard/common-dashboard.module.ts
index 0a5defa1..24460cf7 100644
--- a/src/app/webapp-common/dashboard/common-dashboard.module.ts
+++ b/src/app/webapp-common/dashboard/common-dashboard.module.ts
@@ -13,22 +13,25 @@ import {EffectsModule} from '@ngrx/effects';
import {ProjectsSharedModule} from '../../features/projects/shared/projects-shared.module';
import {CommonSearchResultsModule} from '../search/common-search-results.module';
import {CommonExperimentSharedModule} from '../experiments/shared/common-experiment-shared.module';
+import {SharedModule} from '../../shared/shared.module';
@NgModule({
declarations: [DashboardProjectsComponent, DashboardExperimentsComponent, RecentExperimentTableComponent],
exports : [DashboardProjectsComponent, DashboardExperimentsComponent],
- imports : [
- SMSharedModule,
- ExperimentsCommonModule,
- CommonModule,
- ExperimentSharedModule,
- CommonSearchModule,
- CommonSearchResultsModule,
- ProjectsSharedModule,
- CommonExperimentSharedModule,
- EffectsModule.forFeature([CommonDashboardEffects]),
- CommonLayoutModule,
- ExperimentSharedModule]
+ imports: [
+ SMSharedModule,
+ ExperimentsCommonModule,
+ CommonModule,
+ ExperimentSharedModule,
+ CommonSearchModule,
+ CommonSearchResultsModule,
+ ProjectsSharedModule,
+ CommonExperimentSharedModule,
+ EffectsModule.forFeature([CommonDashboardEffects]),
+ CommonLayoutModule,
+ ExperimentSharedModule,
+ SharedModule
+ ]
})
export class CommonDashboardModule {
}
diff --git a/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.html b/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.html
index fd84b951..6154812d 100644
--- a/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.html
+++ b/src/app/webapp-common/dashboard/containers/dashboard-projects/dashboard-projects.component.html
@@ -3,12 +3,11 @@
RECENT PROJECTS
VIEW ALL
-
+
= CARDS_IN_ROW"
class="btn btn-primary d-flex align-items-center"
(click)="openCreateProjectDialog()">
- NEW PROJECT
-
+ NEW PROJECT
@@ -19,6 +18,6 @@
-
+
diff --git a/src/app/webapp-common/dashboard/dashboard-search.component.base.ts b/src/app/webapp-common/dashboard/dashboard-search.component.base.ts
index dc3d3e58..0291ca22 100644
--- a/src/app/webapp-common/dashboard/dashboard-search.component.base.ts
+++ b/src/app/webapp-common/dashboard/dashboard-search.component.base.ts
@@ -60,7 +60,7 @@ export abstract class DashboardSearchComponentBase {
public searchTermChanged(term: string) {
if (term && term.length > 0) {
- this.store.dispatch(new SearchStart(term));
+ this.store.dispatch(new SearchStart(term, term.length < 3));
} else {
this.activeLink = 'projects';
this.store.dispatch(new SearchDeactivate());
diff --git a/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.html b/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.html
index 73f581ec..f7925f92 100644
--- a/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.html
+++ b/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.html
@@ -19,12 +19,12 @@
(loadedmetadata)="loadedMedia()"
(click)="imageClicked.emit()"
>
-
+
diff --git a/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.scss b/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.scss
index a7457dcb..8a8466a1 100644
--- a/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.scss
+++ b/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.scss
@@ -58,11 +58,28 @@
transform: scale(0.44);
transform-origin: 0 0;
}
+.html-snippet {
+ &:hover {
+ .toolbar {
+ opacity: 1;
+ visibility: visible;
+ }
+ }
+
+ .toolbar {
+ display: flex;
+ position: absolute;
+ bottom: 8px;
+ left: 16px;
+ opacity: 0;
+ visibility: hidden;
+ transition: opacity 0.5s, visibility 0.5s;
+ }
+}
.clickable-icon {
background-color: #efefef;
padding: 4px 24px;
- margin: 0 auto;
border-radius: 4px;
}
diff --git a/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.ts b/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.ts
index 8202faaa..d6e9531e 100644
--- a/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.ts
+++ b/src/app/webapp-common/debug-images/debug-image-snippet/debug-image-snippet.component.ts
@@ -1,5 +1,5 @@
import {Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild} from '@angular/core';
-import {isHtmlPage} from '../../shared/utils/shared-utils';
+import {isHtmlPage, isTextFileURL} from '../../shared/utils/shared-utils';
import {IsAudioPipe} from '../../shared/pipes/is-audio.pipe';
import {IsVideoPipe} from '../../shared/pipes/is-video.pipe';
import {AddMessage} from '../../core/actions/layout.actions';
@@ -21,7 +21,7 @@ export class DebugImageSnippetComponent implements OnInit {
if (frame.url) {
this.isVideo = (new IsVideoPipe().transform(frame.url));
this.isAudio = (new IsAudioPipe()).transform(frame.url);
- this.isHtml = isHtmlPage(frame.url);
+ this.isHtml = isHtmlPage(frame.url) || isTextFileURL(frame.url);
}
this._frame = frame;
}
@@ -35,7 +35,7 @@ export class DebugImageSnippetComponent implements OnInit {
isFailed = false;
isLoading = true;
- constructor(private store: Store) {
+ constructor(private store: Store) {
}
ngOnInit() {
diff --git a/src/app/webapp-common/debug-images/debug-images-view/debug-images-view.component.scss b/src/app/webapp-common/debug-images/debug-images-view/debug-images-view.component.scss
index cd04f676..0ff37a4d 100644
--- a/src/app/webapp-common/debug-images/debug-images-view/debug-images-view.component.scss
+++ b/src/app/webapp-common/debug-images/debug-images-view/debug-images-view.component.scss
@@ -58,9 +58,6 @@
.mat-expansion-panel-header {
margin-bottom: 0;
- &:hover{
- background:transparent;
- }
}
.mat-expansion-panel-header-title {
diff --git a/src/app/webapp-common/debug-images/debug-images.component.html b/src/app/webapp-common/debug-images/debug-images.component.html
index 3df7deed..a4993048 100644
--- a/src/app/webapp-common/debug-images/debug-images.component.html
+++ b/src/app/webapp-common/debug-images/debug-images.component.html
@@ -15,20 +15,20 @@
{{debugImages && debugImages[experimentId] && debugImages[experimentId][debugImages[experimentId].length - 1].iter}}
-
+
{{debugImages && debugImages[experimentId] && debugImages[experimentId][0].iter}}
-
diff --git a/src/app/webapp-common/debug-images/debug-images.component.scss b/src/app/webapp-common/debug-images/debug-images.component.scss
index cb528d56..f3cc224b 100644
--- a/src/app/webapp-common/debug-images/debug-images.component.scss
+++ b/src/app/webapp-common/debug-images/debug-images.component.scss
@@ -30,7 +30,7 @@ sm-debug-images-view {
align-items: center;
margin-bottom: 24px;
- .i-next-batch, .i-prev-batch, .i-back-to-top {
+ .al-ico-next-batch, .al-ico-prev-batch, .al-ico-back-to-top {
cursor: pointer;
}
diff --git a/src/app/webapp-common/debug-images/debug-images.component.ts b/src/app/webapp-common/debug-images/debug-images.component.ts
index 722f0d72..ed0738e3 100644
--- a/src/app/webapp-common/debug-images/debug-images.component.ts
+++ b/src/app/webapp-common/debug-images/debug-images.component.ts
@@ -79,13 +79,14 @@ export class DebugImagesComponent implements OnInit, OnDestroy {
map(([bucketCredentials, debugImages]) => {
const debugImagesP = Object.entries(debugImages).reduce(((previousValue, currentValue: any) => {
previousValue[currentValue[0]] = currentValue[1].metrics[0].iterations.map(iteration => {
- const events = iteration.events.map(event => {
- const signedUrl = this.adminService.signUrlIfNeeded(event.url);
- return {...event, oldSrc: event.url, url: signedUrl};
- });
- return {...iteration, events};
- }
- );
+ const events = iteration.events.map(event => {
+ const signedUrl = this.adminService.signUrlIfNeeded(event.url);
+ const parsed = new URL(signedUrl);
+ parsed.searchParams.append('X-Amz-Date', event.timestamp);
+ return {...event, oldSrc: event.url, url: parsed.toString()};
+ });
+ return {...iteration, events};
+ });
previousValue[currentValue[0]].metric = currentValue[1].metrics[0].metric;
previousValue[currentValue[0]].scrollId = currentValue[1].scroll_id;
return previousValue;
diff --git a/src/app/webapp-common/experiments-compare/actions/experiments-compare-charts.actions.ts b/src/app/webapp-common/experiments-compare/actions/experiments-compare-charts.actions.ts
index c55cb0e7..bcba569b 100644
--- a/src/app/webapp-common/experiments-compare/actions/experiments-compare-charts.actions.ts
+++ b/src/app/webapp-common/experiments-compare/actions/experiments-compare-charts.actions.ts
@@ -1,6 +1,7 @@
import {Action} from '@ngrx/store';
import {ISmAction} from '../../core/models/actions';
import {IExperimentSettings} from '../../experiments/reducers/common-experiment-output.reducer';
+import {ScalarKeyEnum} from '../../../business-logic/model/events/scalarKeyEnum';
export const EXPERIMENTS_COMPARE_METRICS_CHARTS_ = 'EXPERIMENTS_COMPARE_METRICS_CHARTS_';
@@ -29,7 +30,7 @@ export const RESET_EXPERIMENT_METRICS = EXPERIMENTS_COMPARE_METRICS_CHA
export class GetMultiScalarCharts implements ISmAction {
public type = GET_MULTI_SCALAR_CHARTS;
- constructor(public payload: { taskIds: string[]; autoRefresh?: boolean }) {}
+ constructor(public payload: { taskIds: string[]; autoRefresh?: boolean; cached?: boolean }) {}
}
export class GetMultiPlotCharts implements ISmAction {
@@ -47,7 +48,7 @@ export class SetSelectedExperiments implements Action {
export class SetExperimentHistogram implements Action {
readonly type = SET_EXPERIMENT_HISTOGRAM;
- constructor(public payload: any) {
+ constructor(public payload: any, public axisType: ScalarKeyEnum) {
}
}
diff --git a/src/app/webapp-common/experiments-compare/actions/experiments-compare-details.actions.ts b/src/app/webapp-common/experiments-compare/actions/experiments-compare-details.actions.ts
index 5e6c6e46..461a6fe9 100644
--- a/src/app/webapp-common/experiments-compare/actions/experiments-compare-details.actions.ts
+++ b/src/app/webapp-common/experiments-compare/actions/experiments-compare-details.actions.ts
@@ -1,51 +1,6 @@
-import {Action} from '@ngrx/store';
-import {Task} from '../../../business-logic/model/tasks/task';
+import {createAction, props} from '@ngrx/store';
import {IExperimentDetail} from '../../../features/experiments-compare/experiments-compare-models';
-export const EXPERIMENTS_COMPARE_DETAILS_PREFIX = 'EXPERIMENTS_COMPARE_DETAILS_';
-
-// commands.
-export const SET_EXPERIMENTS = EXPERIMENTS_COMPARE_DETAILS_PREFIX + 'SET_EXPERIMENTS';
-export const EXPAND_NODE = EXPERIMENTS_COMPARE_DETAILS_PREFIX + 'EXPAND_NODE';
-export const EXPAND_NODES = EXPERIMENTS_COMPARE_DETAILS_PREFIX + 'EXPAND_NODES';
-export const COLLAPSE_NODE = EXPERIMENTS_COMPARE_DETAILS_PREFIX + 'COLLAPSE_NODE';
-export const RESET_STATE = EXPERIMENTS_COMPARE_DETAILS_PREFIX + 'RESET_STATE';
-
-// events.
-export const EXPERIMENT_LIST_UPDATED = EXPERIMENTS_COMPARE_DETAILS_PREFIX + 'EXPERIMENT_LIST_UPDATED';
-export const REFETCH_EXPERIMENT_REQUESTED = EXPERIMENTS_COMPARE_DETAILS_PREFIX + 'REFETCH_EXPERIMENT_REQUESTED';
-
-
-export class ExperimentListUpdated implements Action {
- readonly type = EXPERIMENT_LIST_UPDATED;
-
- constructor(public payload: Array) {
- }
-}
-
-export class SetExperiments implements Action {
- readonly type = SET_EXPERIMENTS;
-
- constructor(public payload: Array) {
- }
-}
-
-export class ExpandNode implements Action {
- readonly type = EXPAND_NODE;
-
- // the node path.
- constructor(public payload: string | Array) {
- }
-}
-
-export class CollapseNode implements Action {
- readonly type = COLLAPSE_NODE;
-
- // the node path.
- constructor(public payload: string) {
- }
-}
-
-export class ResetState implements Action {
- readonly type = RESET_STATE;
-}
+export const resetState = createAction('[experiment compare details] RESET_STATE');
+export const setExperiments = createAction('[experiment compare details] SET_EXPERIMENTS', props<{experiments: IExperimentDetail[]}>());
+export const experimentListUpdated = createAction('[experiment compare details] EXPERIMENT_LIST_UPDATED', props<{ids: string[]}>());
diff --git a/src/app/webapp-common/experiments-compare/actions/experiments-compare-scalars-graph.actions.ts b/src/app/webapp-common/experiments-compare/actions/experiments-compare-scalars-graph.actions.ts
index eb41dd41..2e78242a 100644
--- a/src/app/webapp-common/experiments-compare/actions/experiments-compare-scalars-graph.actions.ts
+++ b/src/app/webapp-common/experiments-compare/actions/experiments-compare-scalars-graph.actions.ts
@@ -1,5 +1,5 @@
import {createAction, props} from '@ngrx/store';
-import {HyperParams, MetricOption, MetricValueType} from '../reducers/experiments-compare-charts.reducer';
+import {GroupedHyperParams, HyperParams, MetricOption, MetricValueType} from '../reducers/experiments-compare-charts.reducer';
export const EXPERIMENTS_COMPARE_SCALARS_GRAPH = 'EXPERIMENTS_COMPARE_SCALARS_GRAPH_';
@@ -14,5 +14,5 @@ export const getExperimentsHyperParams = createAction(GET_EXPERIMENTS_PARAMS, pr
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: HyperParams }>());
+export const setHyperParamsList = createAction(SET_PARAMS_LIST, props<{ hyperParams: GroupedHyperParams }>());
export const setShowIdenticalHyperParams = createAction(SET_HIDE_IDENTICAL_HYPER_PARAMS);
diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.html b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.html
index 997df8e3..b2ace1b5 100644
--- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.html
+++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.html
@@ -1,5 +1,4 @@
- {{node.data.key | prettifyTitleKeyPipe}}
+ {{(RENAME_MAP[node.data.key] || node.data.key) | hideHashTitle}}
+
@@ -45,8 +45,12 @@
'hide-identical-mode': hideIdenticalFields
}">
-
-
{{node.data.key | hideHash}}{{node.data.value}}
+
{{node.data.key | hideHash}}{{node.data.value}}
+
diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.scss b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.scss
index 77e65f0a..88762594 100644
--- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.scss
+++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.scss
@@ -1,290 +1,41 @@
-@import "../../../shared/ui-components/styles/variables";
+@import "../experiment-compare-base.component";
-sm-compare-card-list {
- display: block;
- height: 100%;
-
- pre {
- line-height: 28px;
- vertical-align: middle;
- }
-
- .node {
- height: 28px;
- line-height: 28px;
- vertical-align: middle;
- margin-bottom: 1px;
- margin-top: 1px;
-
- &.parent {
- .fas {
- margin-left: 6px;
- font-size: 11px;
- width: 16px;
- height: 28px;
- display: inline-flex;
- line-height: 28px;
- align-items: center;
- justify-content: center;
- }
- }
- }
-
- &.pending {
- opacity: 0.2;
- }
-}
-
-.al-header {
- margin-bottom: 0px;
-
- &.main-header {
- text-transform: uppercase;
- }
-
- &.sub-header {
- color: #5a658e;
- text-transform: capitalize;
- }
-}
-
-$extra-header-min-height: 50px;
:host {
-
- .tree-card-body {
- height: 100%;
- padding: 20px 15px 0 0;
- }
-
.section {
- display: inline-block;
- font-family: monospace;
- font-size: 13px;
- //margin-right: 20px;
- padding-left: 8px;
- min-width: 100%;
- overflow: hidden;
- text-align: left;
- color: #1a1e2c;
-
- .virtual-scroll-container {
- height: 100% !important;
-
- .content {
- &.al-empty-collapse {
- color: #384161c7;
- pointer-events: none;
- cursor: default;
-
- .fas {
- width: 3px;
- visibility: hidden;
- }
-
- &.hide-field {
- background-color: #f8f9fa !important;
-
- &.al-danger {
- border-left: 1px #ff9898 solid;
- }
-
- > * {
- visibility: hidden;
- }
- }
- }
- }
- }
-
pre {
- margin-bottom: 0;
- margin-top: 0;
+ display: inline-block;
+ position: relative;
overflow: visible;
- padding-right: 16px;
- padding-left: 6px;
- }
- .node-item-container {
- margin-bottom: 1px;
- height: 28px;
-
- .full-width {
- width: 100%;
+ &.with-ellipsis {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ width: 370px;
}
- .height {
- min-height: 28px;
- vertical-align: middle;
- line-height: 28px;
- white-space: nowrap;
- position: relative;
- width: 99%;
- }
-
- .inline-block {
- display: inline-block;
- }
-
- &.not-existing-on-compared {
- background-color: #f8f9fa !important;
- }
-
- &.not-existing-on-origin.not-existing-on-compared.equal-row {
- background-color: #f8f9fa;
- }
-
- &.selected-diff {
- background-color: #f4f7ff;
- position: relative;
-
- &:before {
- content: ' ';
- background: #4d66ff;
- display: block;
- width: 8px;
- position: absolute;
- transform: translate(-100%);
- height: 100%;
- border-left: 0px solid;
- border-top-left-radius: 5px;
- border-bottom-left-radius: 5px;
- left: 0;
- }
- }
- }
-
- }
-
-
- .parent {
- //height: 36px;
- .depth-0 {
- .content {
- text-transform: uppercase;
- }
- }
-
- .content {
- font-family: "Heebo", sans-serif;
- font-weight: 500;
- color: #384161;
- white-space: nowrap;
- cursor: pointer;
-
- &.al-empty-collapse {
- cursor: default;
- }
-
- &.selected-diff {
- background-color: #f4f7ff;
- position: relative;
-
- &:before {
- content: ' ';
- background: #4d66ff;
- display: block;
- width: 8px;
- position: absolute;
- transform: translate(-100%);
- height: 100%;
- border-left: 0px solid;
- border-top-left-radius: 5px;
- border-bottom-left-radius: 5px;
- left: 0;
- }
- }
- }
- }
-
- .is-not-origin {
- .content.selected-diff {
- &:before {
- background: #ff9898;
- }
- }
- .node-item-container {
- &.not-existing-on-origin.diff-row {
- background-color: transparent;
- }
-
- &.diff-row {
- background-color: #FFDCDC;
-
- &:hover {
- background-color: #ffb4b4;
+ &:hover {
+ .extend-toggle {
+ visibility: visible;
}
}
- .equal-row {
- background-color: transparent;
- }
+ &.no-ellipsis {
- &.not-existing-on-compared.not-existing-on-origin {
- border: none;
-
- pre {
+ .extend-toggle {
visibility: hidden !important;
}
}
-
- &.not-existing-on-compared {
- position: relative;
- width: 100%;
- background-color: #f8f9fa !important;
- border-left: 1px #ff9898 solid;
-
- .tab-forward {
- padding-left: 0;
- }
-
- .border-placeholder {
- background-color: #f8f9fa;
- position: relative;
- width: 100%;
- height: 100%;
- border-left: 1px #ff9898 solid;
- padding-left: 0;
- }
-
- &.selected-diff {
- border-left: none;
- }
- }
-
- &.selected-diff {
- &:before {
- background: #ff9898;
- }
- }
-
}
- .hide-identical-mode.equal-row {
- pre {
- color: #ced1db;
+ .title-key {
+ width: 100%;
+
+ &.ellipsis {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 339px;
}
}
}
-
-}
-
-.card-extra-header {
- display: flex;
- min-height: $extra-header-min-height;
- align-items: center;
- width: 100%;
- justify-content: flex-end;
-}
-
-.action-container {
- margin-right: 60px;
-}
-
-.action-title {
- padding-left: 10px;
-}
-
-.compare-header-container {
- display: block;
- height: 64px;
}
diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.ts b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.ts
index 1626570e..97cf4b36 100644
--- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.ts
+++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-details/experiment-compare-details.component.ts
@@ -1,36 +1,14 @@
-import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren} from '@angular/core';
-import {ActivatedRoute, Router} from '@angular/router';
+import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core';
import {select, Store} from '@ngrx/store';
+import {experimentListUpdated, setExperiments} from '../../actions/experiments-compare-details.actions';
+import {selectExperimentsDetails} from '../../reducers';
+import {filter, tap} from 'rxjs/operators';
+import {ExperimentCompareTree, IExperimentDetail} from '../../../../features/experiments-compare/experiments-compare-models';
+import {convertExperimentsArrays, getAllKeysEmptyObject, isDetailsConverted} from '../../jsonToDiffConvertor';
+import {ExperimentCompareBase} from '../experiment-compare-base';
+import {ActivatedRoute, Router} from '@angular/router';
import {IExperimentInfoState} from '../../../../features/experiments/reducers/experiment-info.reducer';
-import {selectRouterParams} from '../../../core/reducers/router-reducer';
-import {get, has, isEqual, isEmpty} from 'lodash/fp';
-import * as detailsActions from '../../actions/experiments-compare-details.actions';
-import {Subscription} from 'rxjs';
-import {selectExperimentsDetails, selectHideIdenticalFields, selectRefreshing} from '../../reducers';
-import {filter, map, tap} from 'rxjs/operators';
-import {ActiveLoader, AddMessage, DeactiveLoader} from '../../../core/actions/layout.actions';
-import {CompareCardListComponent} from '../../dumbs/compare-card-list/compare-card-list.component';
-import {
- ExperimentCompareTree, ExperimentCompareTreeSection, IExperimentDetail
-} from '../../../../features/experiments-compare/experiments-compare-models';
-import {ExperimentCompareDetailsBase} from '../../../../features/experiments-compare/experiments-compare-details.base';
-import {FlatTreeControl} from '@angular/cdk/tree';
-import {MatTreeFlatDataSource, MatTreeFlattener} from '@angular/material/tree';
-import {refetchExperimentRequested} from '../../actions/compare-header.actions';
-import {CdkVirtualScrollViewport} from '@angular/cdk/scrolling';
-import {TreeNode, TreeNodeMetadata} from '../../shared/experiments-compare-details.model';
-import {treeBuilderService} from '../../services/tree-builder.service';
-import {convertExperimentsArrays, createDiffObjectDetails, getAllKeysEmptyObject} from '../../jsonToDiffConvertor';
-
-export type nextDiffDirectionEnum = 'down' | 'up';
-
-export interface FlatNode {
- data: any;
- metaData: TreeNodeMetadata;
- level: number;
- parent: TreeNode
;
- hasChildren: boolean;
-}
+import {ConfigurationItem} from '../../../../business-logic/model/tasks/configurationItem';
@Component({
selector: 'sm-experiment-compare-details',
@@ -38,332 +16,41 @@ export interface FlatNode {
styleUrls: ['./experiment-compare-details.component.scss', '../../cdk-drag.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
-export class ExperimentCompareDetailsComponent extends ExperimentCompareDetailsBase implements OnInit, OnDestroy {
+export class ExperimentCompareDetailsComponent extends ExperimentCompareBase implements OnInit {
+ public showEllipsis: boolean = true;
-
- private paramsSubscription: Subscription;
- private experimentsSubscription: Subscription;
- private hideIdenticalFieldsSub: Subscription;
- private refreshingSubscription: Subscription;
- // private searchStringSub: Subscription;
-
- public tree: ExperimentCompareTree = {};
- public experiments: Array;
- private allPathsDiffs: any = {};
- public selectedPath: string = null;
- private selectedPathIndex: number = -1;
- private onlyDiffsPaths: string[];
- private taskIds: string;
- public allPaths: any = {};
- public calculatingTree: boolean;
- public hideIdenticalFields = false;
- public experimentsDataControl: { [key: string]: [MatTreeFlatDataSource, FlatNode>, FlatTreeControl] } = {};
- public compareTabPage: string;
- public foundPaths: string[] = [];
- public foundIndex: number = 0;
- public searchText = '';
- private experimentsDataSources: { [id: string]: { all: any; onlyDiffs: any } } = {};
- private previousOpenPaths: string[] = [];
- private scrollSubscription: Subscription[];
- private timeoutIndex: NodeJS.Timeout;
- private originalScrolledElement: EventTarget;
- public experimentTags: {[experimentId: string]: string[]} = {};
-
- get baseExperiment(): IExperimentDetail {
- return get('[0]', this.experiments);
+ constructor(public router: Router,
+ public store: Store,
+ public changeDetection: ChangeDetectorRef,
+ public activeRoute: ActivatedRoute) {
+ super(router, store, changeDetection, activeRoute);
}
- @ViewChild('cardList', {static: true}) cardList: CompareCardListComponent;
- @ViewChildren('virtualScrollRef') virtualScrollRef: QueryList;
-
- constructor(private router: Router,
- private store: Store,
- private changeDetection: ChangeDetectorRef,
- private activeRoute: ActivatedRoute) {
- super();
- }
+ experiments$ = this.store.pipe(select(selectExperimentsDetails));
ngOnInit() {
- this.hideIdenticalFieldsSub = this.store.select(selectHideIdenticalFields).subscribe(hide => {
- this.hideIdenticalFields = hide;
+ this.onInit();
- Object.keys(this.experimentsDataControl).forEach(id => {
- const [dataSource, treeControl] = this.experimentsDataControl[id];
- const expandedPaths = treeControl.expansionModel.selected.map(node => node.data.path);
- dataSource.data = this.experimentsDataSources[id][this.hideIdenticalFields ? 'onlyDiffs' : 'all'];
- const expandedDataNodes = treeControl.dataNodes.filter(node => node.hasChildren).filter(node => expandedPaths.includes(node.data.path));
- treeControl.expansionModel.select(...expandedDataNodes);
- });
- this.find(this.searchText);
- });
+ this.routerParamsSubscription = this.taskIds$.subscribe((experimentIds: string) => this.store.dispatch(experimentListUpdated({ids: experimentIds.split(',')})));
- this.compareTabPage = get('snapshot.routeConfig.data.mode', this.activeRoute);
-
- this.paramsSubscription = this.store.pipe(
- select(selectRouterParams),
- map(params => get('ids', params)),
- tap(taskIds => this.taskIds = taskIds),
- filter(taskIds => !!taskIds && taskIds !== this.getExperimentIdsParams(this.experiments))
- )
- .subscribe((experimentIds: string) => {
- this.store.dispatch(new detailsActions.ExperimentListUpdated(experimentIds.split(',')));
- });
-
- this.experimentsSubscription = this.store.pipe(select(selectExperimentsDetails))
- .pipe(
- filter(experiments => !!experiments && experiments.length > 0),
- tap(experiments => this.syncUrl(experiments, this.taskIds))
- )
- .subscribe(experiments => {
- experiments = experiments.map(({tags, ...experiment}) => {
- if (tags?.length || !this.experimentTags[experiment.id]?.length) {
- this.experimentTags[experiment.id] = tags;
- }
- return experiment;
- });
- experiments = experiments.map(experiment => convertExperimentsArrays(experiment, experiments[0], experiments));
- this.allPathsDiffs = {};
- this.onlyDiffsPaths = [];
- this.experiments = experiments;
- this.allPaths = [];
- this.previousOpenPaths = [];
- this.calculateTree(experiments);
- // this.refreshDisabled = false;
- });
-
- this.refreshingSubscription = this.store.pipe(select(selectRefreshing)).pipe(filter(({refreshing}) => refreshing)).subscribe(({autoRefresh}) =>
- this.store.dispatch(refetchExperimentRequested({autoRefresh})));
- }
-
- ngOnDestroy(): void {
- this.store.dispatch(new detailsActions.ResetState());
- this.paramsSubscription.unsubscribe();
- this.experimentsSubscription.unsubscribe();
- this.hideIdenticalFieldsSub.unsubscribe();
- this.refreshingSubscription.unsubscribe();
- }
-
- toggleNode(node) {
- Object.keys(this.experimentsDataControl).forEach(id => {
- const [dataSource, treeControl] = this.experimentsDataControl[id];
- const n = treeControl.dataNodes.filter(n => n.hasChildren).find(n => n.data.path === node.data.path);
- treeControl.toggle(n);
+ this.experimentsSubscription = this.experiments$.pipe(
+ filter(experiments => !!experiments && experiments.length > 0),
+ tap(experiments => {
+ this.syncUrl(experiments);
+ this.extractTags(experiments);
+ }),
+ ).subscribe(experiments => {
+ this.originalExperiments = experiments.reduce((acc, exp) => {
+ acc[exp.id] = isDetailsConverted(exp) ? this.originalExperiments[exp.id] : exp;
+ return acc;
+ }, {} as { [id: string]: ConfigurationItem });
+ experiments = Object.values(this.originalExperiments).map(experiment => convertExperimentsArrays(experiment, this.originalExperiments[experiments[0].id], experiments));
+ this.resetComponentState(experiments);
+ this.calculateTree(experiments);
});
}
- calculateTree(experiments) {
- this.calculatingTree = true;
- this.store.dispatch(new ActiveLoader('CALCULATING_DIFF_TREE'));
- this.changeDetection.detectChanges();
-
- setTimeout(() => {
- const experimentTrees = this.compareTabPage === 'details' ? this.buildDetailsTree(experiments) : this.buildHyperParamsTree(experiments);
- this.tree = experimentTrees;
- this.ClearRemovedExperiment(experiments);
-
- const treeFlattener = new MatTreeFlattener, FlatNode>(
- this.nodeTransformer,
- this.getNodeLevel,
- this.getIsNodeExpandable,
- this.getNodeChildren
- );
- const expandedsPaths = this.getExpandedPath(experimentTrees);
-
- Object.keys(experimentTrees).forEach(experimentID => {
- const sectionTree = experimentTrees[experimentID];
- let root = Object.keys(sectionTree).map((section: string) => sectionTree[section].children[0]);
- if (this.compareTabPage === 'hyper-params') {
- root = root[0].children;
- }
- const rootOnlyDiffs = this.filterTreeDiffs(root);
- const treeControl: FlatTreeControl = new FlatTreeControl(this.getNodeLevel, this.getIsNodeExpandable);
- const dataSource: MatTreeFlatDataSource, FlatNode> = new MatTreeFlatDataSource(treeControl, treeFlattener);
-
- this.experimentsDataControl[experimentID] = [dataSource, treeControl];
- this.experimentsDataSources[experimentID] = {all: root, onlyDiffs: rootOnlyDiffs};
- dataSource.data = this.experimentsDataSources[experimentID][this.hideIdenticalFields ? 'onlyDiffs' : 'all'];
- this.setExpandedPaths(expandedsPaths, treeControl);
- this.selectedPath && window.setTimeout(() => this.exapndAndScrollToPath());
- });
- this.calculatingTree = false;
- this.store.dispatch(new DeactiveLoader('CALCULATING_DIFF_TREE'));
- if (!this.changeDetection['destroyed']) {
- this.changeDetection.detectChanges();
- }
- this.onlyDiffsPaths = Object.keys(this.allPathsDiffs).filter(key => !!this.allPathsDiffs[key]);
- this.syncScrollSubscription();
- if (this.searchText) {
- this.findAllOccurrences(this.searchText);
- if (this.foundIndex >= this.foundPaths.length) {
- this.foundIndex = this.foundPaths.length;
- this.findPrev();
- }
- if (this.foundPaths.length > 0 && this.foundIndex === -1) {
- this.findNext();
- }
- this.changeDetection.detectChanges();
- }
- }, 0);
- }
-
- private ClearRemovedExperiment(experiments) {
- const expIds = experiments.map(exp => exp.id);
- Object.keys(this.experimentsDataControl).forEach(expId => {
- if (!expIds.includes(expId)) {
- delete this.experimentsDataControl[expId];
- delete this.experimentsDataSources[expId];
- }
- });
- }
-
- private getExpandedPath(experimentTrees: ExperimentCompareTree) {
- let expandedsPaths = [];
- Object.keys(experimentTrees).some(experimentID => {
- if (this.experimentsDataControl[experimentID]) {
- expandedsPaths = this.experimentsDataControl[experimentID][1].expansionModel.selected.map(node => node.data.path);
- return expandedsPaths.length > 0;
- }
- });
- return expandedsPaths;
- }
-
- private setExpandedPaths(expandedsPaths: any[], treeControl: FlatTreeControl) {
- if (expandedsPaths.length > 0) {
- const expandedDatanodes = treeControl.dataNodes.filter(node => node.hasChildren).filter(node => expandedsPaths.includes(node.data.path));
- treeControl.expansionModel.select(...expandedDatanodes);
- }
- if (this.compareTabPage !== 'details') {
- treeControl.expand(treeControl.dataNodes[0]);
- }
- }
-
- private syncScrollSubscription() {
- this.scrollSubscription && this.scrollSubscription.forEach(sub => sub.unsubscribe());
- this.scrollSubscription = this.virtualScrollRef.map(kk => kk.elementScrolled().subscribe((event: Event) => {
- const target = event.target as HTMLElement;
- if (!this.originalScrolledElement) {
- this.originalScrolledElement = target;
- }
- if (this.originalScrolledElement !== target) {
- return;
- }
-
- clearTimeout(this.timeoutIndex);
- this.timeoutIndex = setTimeout(() => this.originalScrolledElement = null, 500);
- this.virtualScrollRef.forEach(k => {
- if (k.elementRef.nativeElement !== kk.elementRef.nativeElement) {
- k.elementRef.nativeElement.scrollTo({top: target.scrollTop, left: target.scrollLeft});
- }
- });
- })
- );
- }
-
- goToNextDiff(direction: nextDiffDirectionEnum) {
- if (direction === 'down') {
- this.selectedPathIndex = this.onlyDiffsPaths.length - 1 > this.selectedPathIndex ? this.selectedPathIndex + 1 : 0;
- } else if (this.selectedPathIndex > 0) {
- this.selectedPathIndex -= 1;
- } else {
- this.selectedPathIndex = this.onlyDiffsPaths.length - 1;
- }
- this.selectedPath = this.onlyDiffsPaths[this.selectedPathIndex];
- this.exapndAndScrollToPath();
- }
-
- private exapndAndScrollToPath() {
- const openPaths = [];
- let pathPartial = '';
- const selectedPath = this.selectedPath ? this.selectedPath.split(',') : [];
- selectedPath.forEach((pathPart, index) => {
- if (index === 0) {
- pathPartial = pathPart;
- } else {
- pathPartial = pathPartial + ',' + pathPart;
- }
- openPaths.push(pathPartial);
- });
- let nodeGotExpanded = false;
- if (!isEqual(openPaths.slice(0, openPaths.length - 1), this.previousOpenPaths)) {
- Object.keys(this.experimentsDataControl).forEach(id => {
- const [dataSource, treeControl] = this.experimentsDataControl[id];
- const nodesToOpen = treeControl.dataNodes.filter(node => node.hasChildren).filter(n => {
- const currentPath = n.data.path;
- return !treeControl.isExpanded(n) && openPaths.includes(currentPath);
- });
- if (nodesToOpen.length > 0) {
- treeControl.expansionModel.select(...nodesToOpen);
- nodeGotExpanded = true;
- }
- });
- }
- this.previousOpenPaths = openPaths.slice(0, openPaths.length - 1);
- const [dataSource, treeControl] = Object.values(this.experimentsDataControl)[0];
- const selectedNodeIndex = this.findRealIndex(dataSource);
- const scrollToInPixels = (selectedNodeIndex + 1) * 28 - this.virtualScrollRef.first.getViewportSize() / 2;
- if (nodeGotExpanded) {
- // Hack to make multiple scroll work with cdk. Don't change
- window.setTimeout(() => this.virtualScrollRef.forEach(vs => vs.elementRef.nativeElement.scrollTo({top: scrollToInPixels})), 200);
- window.setTimeout(() => this.virtualScrollRef.forEach(vs => vs.elementRef.nativeElement.scrollTo({top: scrollToInPixels})), 300);
- } else {
- this.virtualScrollRef.forEach(vs => vs.elementRef.nativeElement.scrollTo({top: scrollToInPixels}));
- window.setTimeout(() => this.virtualScrollRef.forEach(vs => vs.elementRef.nativeElement.scrollTo({top: scrollToInPixels})), 0);
- // window.setTimeout(() => this.virtualScrollRef.forEach(vs => vs.elementRef.nativeElement.scrollTo({top: scrollToInPixels})), 100);
- }
- }
-
- public find(text: string) {
- if (text) {
- this.findAllOccurrences(text);
- this.foundIndex = -1;
- this.findNext();
- } else if (this.searchText !== text) {
- this.foundPaths = [];
- this.selectedPath = null;
- }
- this.searchText = text;
- }
-
- private findAllOccurrences(text) {
- text = text.toLowerCase();
- const foundPathsPerExpTemp = Object.values(this.experimentsDataControl).map(exp => exp[1].dataNodes
- .map((node, index) => {
- if (node.hasChildren) {
- if (node.data.key.includes(text)) {
- return {path: node.data.path, index};
- }
- } else if (node.data.key.replace(/(a_){0,1}hash_/, '').includes(text) || (node.data.value !== undefined && JSON.stringify(node.data.value).toLowerCase().includes(text))) {
- return {path: node.data.path, index};
- }
- })
- .filter(i => i)
- );
-
- const foundPathsPerExp = (foundPathsPerExpTemp as any).flat()
- .sort((a, b) => (a.index > b.index) ? 1 : -1)
- .map(found => found.path);
- this.foundPaths = Array.from(new Set((foundPathsPerExp)));
- }
-
- public findNext() {
- if (this.foundPaths.length === 0) {
- return;
- }
- this.foundIndex = this.foundIndex === (this.foundPaths.length - 1) ? 0 : this.foundIndex + 1;
- this.selectedPath = this.foundPaths[this.foundIndex];
- this.exapndAndScrollToPath();
- }
-
- public findPrev() {
- if (this.foundPaths.length === 0) {
- return;
- }
- this.foundIndex = this.foundIndex === 0 ? this.foundPaths.length - 1 : this.foundIndex - 1;
- this.selectedPath = this.foundPaths[this.foundIndex];
- this.exapndAndScrollToPath();
- }
-
- buildDetailsTree(experiments: Array): ExperimentCompareTree {
+ buildCompareTree(experiments: Array): ExperimentCompareTree {
const mergedExperiment = getAllKeysEmptyObject(experiments);
return experiments
.reduce((acc, cur) => {
@@ -373,158 +60,11 @@ export class ExperimentCompareDetailsComponent extends ExperimentCompareDetailsB
}, {} as ExperimentCompareTree);
}
- buildHyperParamsTree(experiments: Array): ExperimentCompareTree {
- const mergedExperiment = getAllKeysEmptyObject(experiments);
- return experiments
- .reduce((acc, cur) => {
- acc[cur.id] = {
- 'hyper-params': this.buildSectionTree(cur, 'parameters', mergedExperiment)
- };
-
- return acc;
- }, {} as ExperimentCompareTree);
- }
-
- buildSectionTree(experiment, section, mergedExperiment): ExperimentCompareTreeSection {
- return treeBuilderService.buildTreeFromJson(
- {[section]: mergedExperiment[section]},
- this.dataTransformer,
- this.metaDataTransformer,
- {experiment: experiment}
- );
- }
-
- dataTransformer = (data, key, path, extraParams: { experiment; section: string }) => {
- // TODO: get the origin experiment from the state (selectedExperiment).
- const originExperiment: any = this.baseExperiment;
- const fullPath = path.concat([key]);
- const diffObject = createDiffObjectDetails(originExperiment, extraParams.experiment, fullPath, key);
- return {...diffObject, key, path: fullPath.join(',')};
- };
-
- metaDataTransformer = (data, key, path, extraParams): TreeNodeMetadata => {
- // TODO: get the origin experiment from the state (selectedExperiment).
- const fullPath = path.concat([key]);
- const originExperiment: any = this.baseExperiment;
- const originObject = get(fullPath, originExperiment);
- const comparedObject = get(fullPath, extraParams.experiment);
- const keyExists = has(fullPath, extraParams.experiment);
- const isEquals = (originObject === comparedObject) || isEqual(originObject, comparedObject);
- const isPrimitive = this.isPrimitive(originObject) || originObject === undefined || originObject === null;
- const isEmptyObject = isEmpty(comparedObject) || Object.values(comparedObject).every(val => val === undefined);
-
- this.allPaths[fullPath] = this.allPaths[fullPath] || !isEquals;
- if (isPrimitive) {
- this.setPathDif(fullPath, isEquals, (originObject === undefined && comparedObject === undefined));
- }
- if (originObject === undefined && comparedObject && !this.isPrimitive(comparedObject)) {
- delete this.allPathsDiffs[fullPath];
- }
- return {
- classStyle: (isEquals ? '' : 'al-danger ') + (isEmptyObject ? 'al-empty-collapse ' : '') + (keyExists ? '' : 'hide-field'),
- };
- };
-
- isPrimitive(obj) {
- return (typeof obj === 'string' || typeof obj === 'boolean' || typeof obj === 'number');
- }
-
- private setPathDif(fullPath, isEquals, undefinedOriginFirstRun) {
- if (!this.allPathsDiffs[fullPath]) {
- this.allPathsDiffs[fullPath] = !isEquals;
- }
- if (undefinedOriginFirstRun && this.allPathsDiffs[fullPath] === undefined) {
- this.allPathsDiffs[fullPath] = false;
- }
- }
-
experimentListChanged(experiments: Array) {
- this.store.dispatch(new detailsActions.SetExperiments(experiments));
+ this.store.dispatch(setExperiments({experiments}));
}
- private syncUrl(experiments: Array, urlParams: string) {
- const newParams = this.getExperimentIdsParams(experiments);
- if (newParams !== urlParams) {
- this.router.navigateByUrl(this.router.url.replace(urlParams, newParams));
- }
- }
-
- private getExperimentIdsParams(experiments: Array): string {
- return experiments ? experiments.map(e => e.id).toString() : '';
- }
-
- selectedPathClicked(path) {
- if (this.onlyDiffsPaths.includes(path)) {
- this.selectedPath = path;
- this.selectedPathIndex = this.onlyDiffsPaths.indexOf(this.selectedPath);
- }
- }
-
- keyClicked(data, event: MouseEvent) {
- const path = data.path;
- this.selectedPathClicked(path);
- }
-
- checkIfSelectedPath = (data: any) => this.selectedPath === (data.path);
-
- // checkIfFoundPathPath = (data: any) => this.foundPath === (data.path);
-
- checkIfIdenticalRow(data: any) {
- if (this.hideIdenticalFields && this.allPaths) {
- const currentPath = data.path;
- return !this.allPaths[currentPath];
- } else {
- return false;
- }
- }
-
- private filterTreeDiffs(node: any) {
- if (node.data && this.allPaths[node.data.path] === false) {
- return false;
- }
- if (Array.isArray(node)) {
- return node.map(item => this.filterTreeDiffs(item)).filter(item => !!item);
- }
- if (node.children) {
- return {...node, children: this.filterTreeDiffs(node.children)};
- }
- if (node.data) {
- return {...node, data: this.filterTreeDiffs(node.data)};
- }
- return node;
- }
-
- private findRealIndex(ds: MatTreeFlatDataSource, FlatNode>) {
- return ds._expandedData.value.findIndex(node => node.data?.path === this.selectedPath);
- }
-
- copyIdToClipboard() {
- this.store.dispatch(new AddMessage('success', 'Copied to clipboard'));
- }
-
- // Function that maps a nested node to a flat node
- private nodeTransformer(node: TreeNode, level: number) {
- return {
- data: node.data,
- metaData: node.metaData,
- level,
- parent: node.parent,
- hasChildren: !!node.children,
- };
- }
-
-// Function that gets a flat node's level
- private getNodeLevel({level}: FlatNode) {
- return level;
- }
-
-// Function that determines whether a flat node is expandable or not
- private getIsNodeExpandable({hasChildren}: FlatNode) {
- return hasChildren;
- }
-
-// Function that returns a nested node's list of children
- private getNodeChildren(node: TreeNode) {
- return node.children;
+ toggleEllipsis() {
+ this.showEllipsis = !this.showEllipsis;
}
}
diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.html b/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.html
index 8fb91f53..b58b6041 100644
--- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.html
+++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.html
@@ -50,7 +50,7 @@
- Hide identical fields
-
+
diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.scss b/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.scss
index 8c6745db..b9ffba33 100644
--- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.scss
+++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.scss
@@ -16,19 +16,6 @@
}
}
- /deep/ sm-checked-filter-list {
-
- .title {
- font-size: 16px;
- font-weight: 500;
- }
-
- .purple-v {
- width: 20px !important;
- height: 20px !important;
- }
- }
-
/deep/ .mat-expansion-panel-body {
padding: 0;
}
@@ -91,12 +78,6 @@
}
}
-sm-checked-filter-list {
- flex: 1;
- overflow: auto;
- margin: 0 12px 0 32px;
-}
-
.separate-margins {
margin: 24px 0 20px 0;
}
@@ -121,9 +102,6 @@ sm-checked-filter-list {
&__header {
padding: 0 2px 0 0;
- &:hover {
- background: rgba(0, 0, 0, 0) !important;
- }
}
&__title {
@@ -155,7 +133,7 @@ sm-checked-filter-list {
}
&:hover {
- background: $very-light-blue;
+ background: $blue-50;
}
}
@@ -191,3 +169,7 @@ sm-checked-filter-list {
width: 300px;
height: 300px;
}
+
+sm-grouped-checked-filter-list {
+ margin: 0 12px 0 32px;
+}
diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.ts b/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.ts
index 6fdedcdf..203c2847 100644
--- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.ts
+++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component.ts
@@ -5,11 +5,11 @@ import {select, Store} from '@ngrx/store';
import {IExperimentInfoState} from '../../../../features/experiments/reducers/experiment-info.reducer';
import {distinctUntilChanged, distinctUntilKeyChanged, filter, map} from 'rxjs/operators';
import {selectRouterParams} from '../../../core/reducers/router-reducer';
-import {get} from 'lodash/fp';
+import {get, has} from 'lodash/fp';
import {SetExperimentSettings, SetSelectedExperiments} from '../../actions/experiments-compare-charts.actions';
import {selectRefreshing, selectScalarsGraphHyperParams, selectScalarsGraphMetrics, selectScalarsGraphShowIdenticalHyperParams, selectScalarsGraphTasks, selectMetricValueType, selectSelectedSettigsHyperParams, selectSelectedSettigsMetric} from '../../reducers';
import {getExperimentsHyperParams, setShowIdenticalHyperParams, setvalueType} from '../../actions/experiments-compare-scalars-graph.actions';
-import {HyperParams, MetricOption, MetricValueType, SelectedMetric, VariantOption} from '../../reducers/experiments-compare-charts.reducer';
+import {GroupedHyperParams, HyperParams, MetricOption, MetricValueType, SelectedMetric, VariantOption} from '../../reducers/experiments-compare-charts.reducer';
import {MatRadioChange} from '@angular/material/radio';
@@ -32,7 +32,7 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
private refreshingSubscription: Subscription;
public selectShowIdenticalHyperParams$: Observable
;
- public hyperParams$: Observable;
+ public hyperParams$: Observable;
public metrics$: Observable;
public selectedHyperParams$: Observable;
private selectedMetric$: Observable;
@@ -42,7 +42,7 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
public graphs: { [key: string]: ExperimentGraph };
public selectedHyperParams: string[];
public selectedMetric: SelectedMetric;
- public hyperParams: string[];
+ public hyperParams: { [section: string]: string[] };
public showIdenticalParamsActive: boolean;
public metrics: MetricOption[];
@@ -76,7 +76,7 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
ngOnInit() {
this.selectMetricSubscription = this.selectedMetric$.pipe(
distinctUntilChanged((x, y) => x?.path === y?.path)
- ).subscribe((selectedMetric: SelectedMetric) => this.selectedMetric = {...selectedMetric});
+ ).subscribe((selectedMetric: SelectedMetric) => this.selectedMetric = selectedMetric?.name? {...selectedMetric} : null);
this.metricSubscription = this.metrics$.pipe(filter(metrics => !!metrics)).subscribe(metrics => {
this.metrics = metrics;
@@ -93,8 +93,19 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
)
.subscribe(([selectedParams, allParams, showIdentical]) => {
this.showIdenticalParamsActive = showIdentical;
- this.hyperParams = Object.entries(allParams).filter(([param, hasDiff]) => showIdentical || hasDiff).map(([param, hasDiff]) => param).sort((a, b) => a.toLowerCase() > b.toLowerCase() ? 1 : -1);
- this.selectedHyperParams = selectedParams.filter(selectedParam => this.hyperParams.includes(selectedParam));
+ this.hyperParams = Object.entries(allParams).reduce((acc, [sectionKey, params]) => {
+ const section = Object.keys(params).sort((a, b) => a.toLowerCase() > b.toLowerCase() ? 1 : -1).reduce((acc2, paramKey) => {
+ if (showIdentical || params[paramKey]) {
+ acc2[paramKey] = true;
+ }
+ return acc2;
+ }, {});
+ if (Object.keys(section).length > 0) {
+ acc[sectionKey] = section;
+ }
+ return acc;
+ }, {});
+ this.selectedHyperParams = selectedParams.filter(selectedParam => has(selectedParam, this.hyperParams));
});
this.routerParamsSubscription = this.store.pipe(
@@ -179,11 +190,11 @@ export class ExperimentCompareHyperParamsGraphComponent implements OnInit, OnDes
this.listOpen = true;
}
- trackMetricByFn(item: MetricOption): string {
+ trackMetricByFn(index: number, item: MetricOption): string {
return item.metricName;
}
- trackVariantByFn(item: VariantOption['value']): string {
+ trackVariantByFn(index: number, item: VariantOption['value']): string {
return item.path;
}
diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-charts/experiment-compare-scalar-charts.component.ts b/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-charts/experiment-compare-scalar-charts.component.ts
index bef2f5f3..f0f9e65e 100644
--- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-charts/experiment-compare-scalar-charts.component.ts
+++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-charts/experiment-compare-scalar-charts.component.ts
@@ -69,7 +69,9 @@ export class ExperimentCompareScalarChartsComponent implements OnInit, OnDestroy
distinctUntilChanged(),
tap(() => this.refreshDisabled = true)
);
- this.xAxisSub = this.xAxisType$.pipe(filter((axis) => !!axis)).subscribe((axis) => this.store.dispatch(new GetMultiScalarCharts({taskIds: this.taskIds})));
+ this.xAxisSub = this.xAxisType$
+ .pipe(filter((axis) => !!axis))
+ .subscribe((axis) => this.store.dispatch(new GetMultiScalarCharts({taskIds: this.taskIds, cached: true})));
}
ngOnInit() {
diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-values/experiment-compare-metric-values.component.scss b/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-values/experiment-compare-metric-values.component.scss
index 620d911d..a5d0fc49 100644
--- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-values/experiment-compare-metric-values.component.scss
+++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-metric-values/experiment-compare-metric-values.component.scss
@@ -1,3 +1,5 @@
+@import "../../../shared/ui-components/styles/variables";
+
.no-metric {
background-color: #f2f3f6;
}
@@ -14,6 +16,10 @@
.content {
cursor: pointer;
+ font-size: 13px;
+ font-weight: 500;
+ color: $blue-500;
+
.fas {
margin-left: 6px;
font-size: 11px;
diff --git a/src/app/webapp-common/experiments-compare/containers/experiment-compare-plots/experiment-compare-plots.component.scss b/src/app/webapp-common/experiments-compare/containers/experiment-compare-plots/experiment-compare-plots.component.scss
index da74936d..94941214 100644
--- a/src/app/webapp-common/experiments-compare/containers/experiment-compare-plots/experiment-compare-plots.component.scss
+++ b/src/app/webapp-common/experiments-compare/containers/experiment-compare-plots/experiment-compare-plots.component.scss
@@ -17,7 +17,7 @@
.graphs-container {
padding: 0 !important;
- width: calc(100vw - 420px);
+ width: calc(100% - 420px);
}
}
diff --git a/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.scss b/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.scss
index 1bb19dd9..dcbb7452 100644
--- a/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.scss
+++ b/src/app/webapp-common/experiments-compare/containers/select-experiments-for-compare/select-experiments-for-compare.component.scss
@@ -23,7 +23,7 @@
&.show-table {
height: auto;
overflow: initial;
- max-height: 500px;
+ max-height: 400px;
}
}
@@ -38,7 +38,7 @@
:host {
sm-select-experiments-for-compare-table {
overflow: auto;
- height: 500px;
+ max-height: 500px;
}
/deep/ .form-control.table-container footer.d-flex.justify-content-center {
diff --git a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.html b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.html
index 31557cbb..3721d9dc 100644
--- a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.html
+++ b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-general-data/experiment-compare-general-data.component.html
@@ -1,5 +1,5 @@
-
+
-
+
diff --git a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.scss b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.scss
index 03c7a760..2deb53bf 100644
--- a/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.scss
+++ b/src/app/webapp-common/experiments-compare/dumbs/experiment-compare-header/experiment-compare-header.component.scss
@@ -23,7 +23,7 @@
}
.btn-group sm-search {
- width: 243px;
+ width: 200px;
.search-input-container {
@@ -60,7 +60,7 @@
.mat-select-trigger {
width: 142px;
- border: 1px solid $cloudy-blue;
+ border: 1px solid $blue-250;
border-radius: 4px;
height: 32px;
padding: 7px 14px;
@@ -95,6 +95,18 @@
}
}
+ .settings {
+ display: flex;
+ align-items: center;
+
+ .btn {
+ color: $blue-300;
+ width: 40px;
+ height: 40px;
+ font-size: 15px;
+ }
+ }
+
button {
font-weight: 500;
font-size: 13px;
@@ -102,7 +114,7 @@
.btn-add-experiment {
width: 146px;
- background-color: $very-light-blue;
+ background-color: $blue-50;
}
diff --git a/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.html b/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.html
index f5862a45..b2b8a2ad 100644
--- a/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.html
+++ b/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.html
@@ -4,19 +4,22 @@
-
-
+
+
+
-
- filteredExperiments.length + 1) || experiment.hidden) && toggleHideExperiment(experiment.id)"
- [ngClass]="{'hide':filteredExperiments.includes(experiment.id),
- 'pointer': (experiments.length> filteredExperiments.length + 1) || experiment.hidden}">
+
{{experiment.name + (experiment.duplicateName ? ('.' + (experiment.id|slice:0:5)) : '')}}
-
+
diff --git a/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.ts b/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.ts
index 67030496..40f05d18 100644
--- a/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.ts
+++ b/src/app/webapp-common/experiments-compare/dumbs/parallel-coordinates-graph/parallel-coordinates-graph.component.ts
@@ -2,10 +2,12 @@ import {ChangeDetectorRef, Component, ElementRef, HostListener, Input, OnInit, R
import {PlotlyGraphBase} from '../../../shared/experiment-graphs/single-graph/plotly-graph-base';
import {debounceTime, filter} from 'rxjs/operators';
import {ColorHashService} from '../../../shared/services/color-hash/color-hash.service';
-import {get, isEqual, max, min, uniq, cloneDeep} from 'lodash/fp';
+import {get, getOr, isEqual, max, min, uniq, cloneDeep} from 'lodash/fp';
import {MetricValueType, SelectedMetric} from '../../reducers/experiments-compare-charts.reducer';
import {Task} from '../../../../business-logic/model/tasks/task';
import {select} from 'd3-selection';
+import {sortCol} from '../../../shared/utils/tableParamEncode';
+import {Store} from '@ngrx/store';
declare let Plotly;
@@ -14,6 +16,15 @@ interface ExtraTask extends Task {
hidden: boolean;
}
+interface ParaPlotData {
+ type: string;
+ dimensions: any[];
+ line: {
+ color: Plotly.Color;
+ colorscale?: Plotly.ColorScale;
+ };
+}
+
@Component({
selector: 'sm-parallel-coordinates-graph',
templateUrl: './parallel-coordinates-graph.component.html',
@@ -21,7 +32,7 @@ interface ExtraTask extends Task {
})
export class ParallelCoordinatesGraphComponent extends PlotlyGraphBase implements OnInit {
- private data: { line: { color: Task[]; colorscale: (number | string)[][] }; type: string; dimensions: unknown[] }[];
+ private data: ParaPlotData[];
private _experiments: ExtraTask[];
private _metric: SelectedMetric;
public experimentsColors = {};
@@ -32,6 +43,8 @@ export class ParallelCoordinatesGraphComponent extends PlotlyGraphBase implement
@ViewChild('parallelGraph', {static: true}) parallelGraph: ElementRef;
private graphWidth: any;
private _metricValueType: MetricValueType;
+ private highlighted: ExtraTask;
+ private dimensionsOrder: string[];
@HostListener('window:resize')
redrawChart() {
@@ -122,10 +135,12 @@ export class ParallelCoordinatesGraphComponent extends PlotlyGraphBase implement
}
constructor(
- public renderer: Renderer2,
- public colorHash: ColorHashService,
- public changeDetector: ChangeDetectorRef) {
- super();
+ protected store: Store,
+ protected renderer: Renderer2,
+ protected elementRef: ElementRef,
+ private colorHash: ColorHashService,
+ private changeDetector: ChangeDetectorRef) {
+ super(store, renderer, elementRef);
}
ngOnInit(): void {
@@ -142,46 +157,50 @@ export class ParallelCoordinatesGraphComponent extends PlotlyGraphBase implement
this.prepareGraph();
}
- getStringColor(name): string {
- const colorArr = this.colorHash.initColor(name);
+ getStringColor(experiment: ExtraTask): string {
+ const colorArr = this.colorHash.initColor(experiment.id);
return `rgb(${colorArr[0]},${colorArr[1]},${colorArr[2]})`;
}
- getColorsArray(experiments): Task[] {
- return experiments.map((experiment, index) => (index === (experiments.length - 1)) ? 1.0 : index / 10);
+ getColorsArray(experiments): number[] {
+ return experiments.map((experiment, index) => index / (experiments.length - 1));
}
private prepareGraph(): void {
- this.experiments.forEach(experiment => this.experimentsColors[experiment.id] = this.getStringColor(experiment.id));
- const filteredExperiments = this.experiments.filter(experiment => !this.filteredExperiments.includes(experiment.id));
+ this.experiments.forEach(experiment => this.experimentsColors[experiment.id] = this.getStringColor(experiment));
+ const filteredExperiments = this.experiments.filter(experiment => !experiment.hidden);
if (this.parameters && filteredExperiments.length > 0) {
- const trace: any = {
+ const trace = {
type: 'parcoords',
dimensions: this.parameters.map((parameter) => {
- const dimension: any = {};
- const allValuesIncludingNull = filteredExperiments.map(experiment => experiment.execution.parameters[parameter]);
+ parameter = `${parameter}.value`;
+ const allValuesIncludingNull = this.experiments.map(experiment => get(parameter, experiment.hyperparams));
const allValues = allValuesIncludingNull.filter(value => (value !== undefined)).filter(value => (value !== ''));
- dimension.label = parameter;
const textVal: any = {};
- dimension.ticktext = this.naturalCompare(uniq(allValues).filter(text => text !== ''));
- (allValuesIncludingNull.length > allValues.length) && (dimension.ticktext = ['N/A'].concat(dimension.ticktext));
- dimension.tickvals = dimension.ticktext.map((text, index) => {
+ let ticktext = this.naturalCompare(uniq(allValues).filter(text => text !== ''));
+ (allValuesIncludingNull.length > allValues.length) && (ticktext = ['N/A'].concat(ticktext));
+ const tickvals = ticktext.map((text, index) => {
textVal[text] = index;
return index;
});
- dimension.values = filteredExperiments.map((experiment) => (textVal[['', undefined].includes(experiment.execution.parameters[parameter]) ? 'N/A' : experiment.execution.parameters[parameter]]));
- dimension.range = [0, max(dimension.tickvals)];
- return dimension;
+ return {
+ label: parameter,
+ ticktext,
+ tickvals,
+ values: filteredExperiments.map((experiment) => (textVal[['', undefined].includes(get(parameter, experiment.hyperparams)) ? 'N/A' : get(parameter, experiment.hyperparams)])),
+ range: [0, max(tickvals)]
+ };
})
- };
+ } as ParaPlotData ;
if (filteredExperiments.length > 1) {
trace.line = {
color: this.getColorsArray(filteredExperiments),
- colorscale: filteredExperiments.map((experiment, index) => [index === filteredExperiments.length - 1 ? 1.0 : index / 10, this.getStringColor(experiment.id)])
+ colorscale: filteredExperiments.map((experiment, index) =>
+ [index / (filteredExperiments.length - 1), this.getStringColor(experiment)] as [number, string]),
};
} else {
trace.line = {
- color: this.getStringColor(filteredExperiments[0].id)
+ color: this.getStringColor(filteredExperiments[0])
};
}
@@ -190,18 +209,25 @@ export class ParallelCoordinatesGraphComponent extends PlotlyGraphBase implement
// this.drawChart();
if (this.metric) {
- const metricDimension: any = {};
- const allValuesIncludingNull = filteredExperiments.map(experiment => get(`${this.metric.path}.${this.metricValueType}`, experiment.last_metrics));
+ const allValuesIncludingNull = this.experiments.map(experiment => get(`${this.metric.path}.${this.metricValueType}`, experiment.last_metrics));
const allValues = allValuesIncludingNull.filter(value => value !== undefined);
const NAVal = this.getNAValue(allValues);
- metricDimension.label = this.metric.name;
- metricDimension.ticktext = uniq(allValuesIncludingNull.map(value => value !== undefined ? value : 'N/A'));
- metricDimension.tickvals = metricDimension.ticktext.map(text => text === 'N/A' ? NAVal : text);
- metricDimension.values = filteredExperiments.map((experiment) => get(`${this.metric.path}.${this.metricValueType}`, experiment.last_metrics) === undefined ? NAVal :
- parseFloat(get(`${this.metric.path}.${this.metricValueType}`, experiment.last_metrics)));
- trace.dimensions.push(metricDimension);
+ const ticktext = uniq(allValuesIncludingNull.map(value => value !== undefined ? value : 'N/A'));
+ const tickvals = ticktext.map(text => text === 'N/A' ? NAVal : text);
+ trace.dimensions.push({
+ label: this.metric.name,
+ ticktext,
+ tickvals,
+ values: filteredExperiments.map((experiment) =>
+ parseFloat(getOr(NAVal, `${this.metric.path}.${this.metricValueType}`, experiment.last_metrics))
+ ),
+ range: [min(tickvals), max(tickvals)]
+ });
}
this.data = [trace];
+ if (this.dimensionsOrder) {
+ this.data[0].dimensions.sort((a, b) => sortCol(a.label, b.label, this.dimensionsOrder));
+ }
this.drawChart();
}
}
@@ -212,7 +238,7 @@ export class ParallelCoordinatesGraphComponent extends PlotlyGraphBase implement
}
const valuesMax = max(values);
const valuesMin = min(values);
- return valuesMax === valuesMin ? (valuesMin - 1) : valuesMin - ((valuesMax - valuesMin) / 10);
+ return valuesMax === valuesMin ? (valuesMin - 1) : valuesMin - ((valuesMax - valuesMin) / values.length);
}
private drawChart() {
@@ -261,4 +287,20 @@ export class ParallelCoordinatesGraphComponent extends PlotlyGraphBase implement
const collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
return (myArray.sort(collator.compare));
}
+
+ highlightExperiment(experiment: ExtraTask) {
+ if (this.highlighted?.id != experiment?.id) {
+ this.highlighted = experiment;
+ this.dimensionsOrder = this.parallelGraph.nativeElement.data?.[0].dimensions.map(d => d.label);
+ this._experiments = this.experiments.map(exp => ({...exp, hidden: exp.id !== experiment.id}));
+ this.prepareGraph();
+ }
+ }
+
+ removeHighlightExperiment() {
+ this.highlighted = null;
+ this._experiments = this.experiments.map(experiment => ({...experiment, hidden: this.filteredExperiments.includes(experiment.id)}));
+ this.prepareGraph();
+ this.dimensionsOrder = null;
+ }
}
diff --git a/src/app/webapp-common/experiments-compare/dumbs/select-experiments-for-compare-table/select-experiments-for-compare-table.component.ts b/src/app/webapp-common/experiments-compare/dumbs/select-experiments-for-compare-table/select-experiments-for-compare-table.component.ts
index 03223175..cdae10f4 100644
--- a/src/app/webapp-common/experiments-compare/dumbs/select-experiments-for-compare-table/select-experiments-for-compare-table.component.ts
+++ b/src/app/webapp-common/experiments-compare/dumbs/select-experiments-for-compare-table/select-experiments-for-compare-table.component.ts
@@ -10,7 +10,7 @@ export const EXPERIMENTS_TABLE_COL_FIELDS = {
USER : 'user.name' as ExperimentTableColFieldsEnum,
TAGS : 'tags' as ExperimentTableColFieldsEnum,
STATUS : 'status' as ExperimentTableColFieldsEnum,
- PROJECT : 'project.name' as ExperimentTableColFieldsEnum,
+ PROJECT : 'project.name' as ExperimentTableColFieldsEnum,
};
export const INITIAL_EXPERIMENT_TABLE_COLS = [
@@ -23,64 +23,72 @@ export const INITIAL_EXPERIMENT_TABLE_COLS = [
static : true,
headerStyleClass: 'selected-col-header',
style : {width: '20px'},
+ disableDrag : true,
},
{
- id : EXPERIMENTS_TABLE_COL_FIELDS.TYPE,
- sortable : false,
- filterable : false,
- static : true,
- header : 'TYPE',
- style : {width: '40px'},
+ id : EXPERIMENTS_TABLE_COL_FIELDS.TYPE,
+ sortable : false,
+ filterable : false,
+ static : true,
+ header : 'TYPE',
+ style : {width: '40px'},
+ disableDrag: true,
},
{
- id : EXPERIMENTS_TABLE_COL_FIELDS.ID,
- sortable : false,
- filterable : false,
- header : 'ID',
- hidden : true,
- static : true,
- style : {width: '150px'},
+ id : EXPERIMENTS_TABLE_COL_FIELDS.ID,
+ sortable : false,
+ filterable : false,
+ header : 'ID',
+ hidden : true,
+ static : true,
+ style : {width: '150px'},
+ disableDrag: true,
},
{
- id : EXPERIMENTS_TABLE_COL_FIELDS.NAME,
- sortable : false,
- static : true,
- header : 'NAME',
- style : {width: '170px'},
+ id : EXPERIMENTS_TABLE_COL_FIELDS.NAME,
+ sortable : false,
+ static : true,
+ header : 'NAME',
+ style : {width: '170px'},
+ disableDrag: true,
},
{
- id : EXPERIMENTS_TABLE_COL_FIELDS.USER,
- sortable: false,
- static : true,
- header : 'USER',
- style : {width: '115px'}
+ id : EXPERIMENTS_TABLE_COL_FIELDS.USER,
+ sortable : false,
+ static : true,
+ header : 'USER',
+ style : {width: '115px'},
+ disableDrag: true,
},
{
- id : EXPERIMENTS_TABLE_COL_FIELDS.TAGS,
- sortable: false,
- static : true,
- header : 'TAGS',
- style : {width: '110px'}
+ id : EXPERIMENTS_TABLE_COL_FIELDS.TAGS,
+ sortable : false,
+ static : true,
+ header : 'TAGS',
+ style : {width: '110px'},
+ disableDrag: true,
},
{
- id : EXPERIMENTS_TABLE_COL_FIELDS.STATUS,
- filterable : false,
- static : true,
- header : 'STATUS',
- style : {width: '80px'},
+ id : EXPERIMENTS_TABLE_COL_FIELDS.STATUS,
+ filterable : false,
+ static : true,
+ header : 'STATUS',
+ style : {width: '80px'},
+ disableDrag: true,
},
{
- id : EXPERIMENTS_TABLE_COL_FIELDS.PROJECT,
- filterable : false,
- static : true,
- header : 'PROJECT',
- style : {width: '80px'},
+ id : EXPERIMENTS_TABLE_COL_FIELDS.PROJECT,
+ filterable : false,
+ static : true,
+ header : 'PROJECT',
+ style : {width: '80px'},
+ disableDrag: true,
}
];
export enum ExperimentTagsEnum {
Development = 'development',
- Hidden = 'archived'
+ Hidden = 'archived'
}
export interface AddExperimentEvent {
@@ -106,11 +114,11 @@ export class SelectExperimentsForCompareTableComponent implements OnInit {
public typeFiltersValue: any;
public menuPosition: { x: number; y: number };
public menuData;
- public menuOpen: boolean = false;
+ public menuOpen: boolean = false;
@Input() searchTerm;
@Input() tableCols;
@Input() experiments: Array
= [];
- @Input() selectedExperiments: Array = [];
+ @Input() selectedExperiments: Array = [];
@Output() experimentsSelectionChanged = new EventEmitter();
diff --git a/src/app/webapp-common/experiments-compare/effects/experiments-compare-charts.effects.ts b/src/app/webapp-common/experiments-compare/effects/experiments-compare-charts.effects.ts
index 55fb97aa..e3cf6b1a 100644
--- a/src/app/webapp-common/experiments-compare/effects/experiments-compare-charts.effects.ts
+++ b/src/app/webapp-common/experiments-compare/effects/experiments-compare-charts.effects.ts
@@ -11,7 +11,7 @@ import {ApiAuthService} from '../../../business-logic/api-services/auth.service'
import {BlTasksService} from '../../../business-logic/services/tasks.service';
import {ApiEventsService} from '../../../business-logic/api-services/events.service';
import {RequestFailed} from '../../core/actions/http.actions';
-import {selectCompareSelectedSettingsxAxisType} from '../reducers';
+import {selectCompareHistogramCacheAxisType, selectCompareSelectedSettingsxAxisType} from '../reducers';
import {setRefreshing} from '../actions/compare-header.actions';
import {ScalarKeyEnum} from '../../../business-logic/model/events/scalarKeyEnum';
@@ -33,39 +33,28 @@ export class ExperimentsCompareChartsEffects {
getMultiScalarCharts = this.actions$.pipe(
ofType(chartActions.GET_MULTI_SCALAR_CHARTS),
debounceTime(200),
- withLatestFrom(this.store.select(selectCompareSelectedSettingsxAxisType)),
- flatMap(([action, axisType]) => this.eventsApi.eventsMultiTaskScalarMetricsIterHistogram({
- tasks: action.payload.taskIds,
- key: !axisType || axisType === ScalarKeyEnum.IsoTime ? ScalarKeyEnum.Timestamp : axisType
- }).pipe(
- flatMap(res => {
- if (!axisType || axisType === ScalarKeyEnum.IsoTime) {
- res = {metrics: Object.keys(res.metrics).reduce((metricAcc, metricName) => {
- const metric = res.metrics[metricName];
- metricAcc[metricName] = Object.keys(metric).reduce((groupAcc, groupName) => {
- const group = metric[groupName];
- groupAcc[groupName] = Object.keys(group).reduce((graphAcc, graphName) => {
- const graph = group[graphName];
- graphAcc[graphName] = {...graph, x: graph.x.map(ts => new Date(ts))};
- return graphAcc;
- }, {});
- return groupAcc;
- }, {});
- return metricAcc;
- }, {})};
- }
- return [
+ withLatestFrom(this.store.select(selectCompareSelectedSettingsxAxisType), this.store.select(selectCompareHistogramCacheAxisType)),
+ flatMap(([action, axisType, prevAxisType]) => {
+ if ([ScalarKeyEnum.IsoTime, ScalarKeyEnum.Timestamp].includes(prevAxisType) &&
+ [ScalarKeyEnum.IsoTime, ScalarKeyEnum.Timestamp].includes(axisType)) {
+ return [setRefreshing({payload: false}), new DeactiveLoader(action.type)];
+ }
+ return this.eventsApi.eventsMultiTaskScalarMetricsIterHistogram({
+ tasks: action.payload.taskIds,
+ key: !axisType || axisType === ScalarKeyEnum.IsoTime ? ScalarKeyEnum.Timestamp : axisType
+ }).pipe(
+ flatMap(res => [
// also here
- new chartActions.SetExperimentHistogram(res),
+ new chartActions.SetExperimentHistogram(res, axisType),
setRefreshing({payload: false}),
- new DeactiveLoader(action.type)];
- }),
- catchError(error => [
- new RequestFailed(error), new DeactiveLoader(action.type), setRefreshing({payload: false}),
- new SetServerError(error, null, 'Failed to get Scalar Charts', action.payload.autoRefresh)
- ])
- )
- )
+ new DeactiveLoader(action.type)]
+ ),
+ catchError(error => [
+ new RequestFailed(error), new DeactiveLoader(action.type), setRefreshing({payload: false}),
+ new SetServerError(error, null, 'Failed to get Scalar Charts', action.payload.autoRefresh)
+ ])
+ );
+ })
);
@Effect()
diff --git a/src/app/webapp-common/experiments-compare/effects/experiments-compare-details.effects.ts b/src/app/webapp-common/experiments-compare/effects/experiments-compare-details.effects.ts
index d00982d1..62061db2 100644
--- a/src/app/webapp-common/experiments-compare/effects/experiments-compare-details.effects.ts
+++ b/src/app/webapp-common/experiments-compare/effects/experiments-compare-details.effects.ts
@@ -1,90 +1,88 @@
import {Injectable} from '@angular/core';
import {Actions, Effect, ofType} from '@ngrx/effects';
import {select, Store} from '@ngrx/store';
-import {IExperimentCompareDetailsState} from '../reducers/experiments-compare-details.reducer';
-import * as detailsActions from '../actions/experiments-compare-details.actions';
import {ActiveLoader, DeactiveLoader, SetServerError} from '../../core/actions/layout.actions';
import {catchError, flatMap, map, switchMap, withLatestFrom} from 'rxjs/operators';
import {ApiTasksService} from '../../../business-logic/api-services/tasks.service';
import {ExperimentDetailsReverterService} from '../services/experiment-details-reverter.service';
import {RequestFailed} from '../../core/actions/http.actions';
-import {selectExperimentIds, selectExperimentsDetails} from '../reducers';
+import {selectExperimentIdsDetails, selectExperimentsDetails} from '../reducers';
import {Observable, of} from 'rxjs';
-import {EXPERIMENT_INFO_ONLY_FIELDS} from '../../../features/experiments-compare/experiments-compare-consts';
+import {COMPARE_DETAILS_ONLY_FIELDS} from '../../../features/experiments-compare/experiments-compare-consts';
import {IExperimentDetail} from '../../../features/experiments-compare/experiments-compare-models';
-import {refetchExperimentRequested, setRefreshing} from '../actions/compare-header.actions';
+import {REFETCH_EXPERIMENT_REQUESTED, refetchExperimentRequested, setRefreshing} from '../actions/compare-header.actions';
+import {ExperimentCompareDetailsState} from '../reducers/experiments-compare-details.reducer';
+import {experimentListUpdated, setExperiments} from '../actions/experiments-compare-details.actions';
@Injectable()
export class ExperimentsCompareDetailsEffects {
- constructor(private actions$: Actions, private tasksApi: ApiTasksService, private store: Store,
+ constructor(private actions$: Actions, private tasksApi: ApiTasksService, private store: Store,
private experimentDetailsReverter: ExperimentDetailsReverterService
) {
}
@Effect()
activeLoader$ = this.actions$.pipe(
- ofType(detailsActions.EXPERIMENT_LIST_UPDATED, detailsActions.REFETCH_EXPERIMENT_REQUESTED),
+ ofType(experimentListUpdated, REFETCH_EXPERIMENT_REQUESTED),
map(action => new ActiveLoader(action.type))
);
@Effect()
UpdateExperimentsDetail$ = this.actions$.pipe(
- ofType(detailsActions.EXPERIMENT_LIST_UPDATED),
- withLatestFrom(this.store.pipe(select(selectExperimentIds))),
- map(([action, oldExperimentIds]) => [action, action.payload.filter(id => !oldExperimentIds.includes(id))]),
- switchMap(([action, newExperimentIds]: [detailsActions.ExperimentListUpdated, Array]) =>
- this.fetchExperimentDetails$(newExperimentIds)
- .pipe(
- withLatestFrom(this.store.pipe(select(selectExperimentsDetails))),
- // get only the relevant experiments
- map(([experiments, oldExperiments]) => oldExperiments.filter(exp => action.payload.includes(exp.id)).concat(experiments)),
- flatMap(experiments => [
- new DeactiveLoader(action.type),
- new detailsActions.SetExperiments(experiments)
- ]),
- catchError(error => {
- return [
- new RequestFailed(error),
+ ofType(experimentListUpdated),
+ withLatestFrom(this.store.pipe(select(selectExperimentIdsDetails))),
+ switchMap(([action, oldExperimentIds]) => {
+ const newExperimentIds = action.ids.filter(id => !oldExperimentIds.includes(id));
+ return this.fetchExperimentDetails$(newExperimentIds)
+ .pipe(
+ withLatestFrom(this.store.pipe(select(selectExperimentsDetails))),
+ // get only the relevant experiments
+ map(([experiments, oldExperiments]) => oldExperiments.filter(exp => action.ids.includes(exp.id)).concat(experiments)),
+ flatMap(experiments => [
new DeactiveLoader(action.type),
- new SetServerError(error, null, 'The attempt to retrieve your experiment data failed. Refresh your browser and try again.')
- ];
- })
- )
+ setExperiments({experiments})
+ ]),
+ catchError(error => [
+ new RequestFailed(error),
+ new DeactiveLoader(action.type),
+ new SetServerError(error, null, 'The attempt to retrieve your experiment data failed. Refresh your browser and try again.')
+ ]
+ )
+ );
+ }
)
);
@Effect()
RefetchExperiment$ = this.actions$.pipe(
ofType(refetchExperimentRequested),
- withLatestFrom(this.store.select(selectExperimentIds)),
+ withLatestFrom(this.store.select(selectExperimentIdsDetails)),
switchMap(([action, newExperimentIds]) =>
this.fetchExperimentDetails$(newExperimentIds).pipe(
flatMap(experiments => [
new DeactiveLoader(action.type),
setRefreshing({payload: false}),
- new detailsActions.SetExperiments(experiments)
+ setExperiments({experiments})
]),
- catchError(error => {
- return [
- new RequestFailed(error),
- new DeactiveLoader(action.type),
- setRefreshing({payload: false}),
- new SetServerError(
- error, null,
- 'The attempt to retrieve your experiment data failed. Refresh your browser and try again.',
- action.autoRefresh
- )
- ];
- })
+ catchError(error => [
+ new RequestFailed(error),
+ new DeactiveLoader(action.type),
+ setRefreshing({payload: false}),
+ new SetServerError(
+ error, null,
+ 'The attempt to retrieve your experiment data failed. Refresh your browser and try again.',
+ action.autoRefresh
+ )
+ ])
)),
);
fetchExperimentDetails$(ids): Observable> {
return ids.length > 0 ?
this.tasksApi.tasksGetAllEx({
- id : ids,
- only_fields: EXPERIMENT_INFO_ONLY_FIELDS
+ id: ids,
+ only_fields: COMPARE_DETAILS_ONLY_FIELDS
}).pipe(
map(res => this.experimentDetailsReverter.revertExperiments(ids, res.tasks))
)
diff --git a/src/app/webapp-common/experiments-compare/effects/experiments-compare-scalars-graph.effects.ts b/src/app/webapp-common/experiments-compare/effects/experiments-compare-scalars-graph.effects.ts
index 01b688d4..c1098bd3 100644
--- a/src/app/webapp-common/experiments-compare/effects/experiments-compare-scalars-graph.effects.ts
+++ b/src/app/webapp-common/experiments-compare/effects/experiments-compare-scalars-graph.effects.ts
@@ -8,7 +8,7 @@ import {RequestFailed} from '../../core/actions/http.actions';
import {ApiTasksService} from '../../../business-logic/api-services/tasks.service';
import {getExperimentsHyperParams, setHyperParamsList, setMetricsList, setTasks} from '../actions/experiments-compare-scalars-graph.actions';
import {setRefreshing} from '../actions/compare-header.actions';
-import {HyperParams} from '../reducers/experiments-compare-charts.reducer';
+import {GroupedHyperParams, HyperParams} from '../reducers/experiments-compare-charts.reducer';
@Injectable()
export class ExperimentsCompareScalarsGraphEffects {
@@ -20,32 +20,32 @@ export class ExperimentsCompareScalarsGraphEffects {
activeLoader = createEffect(() => this.actions$.pipe(
ofType(getExperimentsHyperParams),
map(action => new ActiveLoader(action.type))
- )
+ )
);
loadMovies$ = createEffect(() => this.actions$.pipe(
ofType(getExperimentsHyperParams),
flatMap((action) => this.tasksApiService.tasksGetAllEx({
- id: action.experimentsIds,
- only_fields: ['last_metrics', 'name', 'last_iteration', 'execution.parameters']
- })
- .pipe(
- // map(res => res.tasks)),
- flatMap(res => {
- const metricsList = this.getMetricOptions(res.tasks);
- const paramsHasDiffs = this.getParametersHasDiffs(res.tasks);
- return [
- setTasks({tasks: res.tasks}),
- setMetricsList({metricsList: metricsList}),
- setHyperParamsList({hyperParams: paramsHasDiffs}),
- setRefreshing({payload: false}),
- new DeactiveLoader(action.type)];
- }),
- catchError(error => [
- new RequestFailed(error), new DeactiveLoader(action.type), setRefreshing({payload: false}),
- new SetServerError(error, null, 'Failed to get Compared Experiments')
- ])
- )
+ id: action.experimentsIds,
+ only_fields: ['last_metrics', 'name', 'last_iteration', 'hyperparams']
+ })
+ .pipe(
+ // map(res => res.tasks)),
+ flatMap(res => {
+ const metricsList = this.getMetricOptions(res.tasks);
+ const paramsHasDiffs = this.getParametersHasDiffs(res.tasks);
+ return [
+ setTasks({tasks: res.tasks}),
+ setMetricsList({metricsList: metricsList}),
+ setHyperParamsList({hyperParams: paramsHasDiffs}),
+ setRefreshing({payload: false}),
+ new DeactiveLoader(action.type)];
+ }),
+ catchError(error => [
+ new RequestFailed(error), new DeactiveLoader(action.type), setRefreshing({payload: false}),
+ new SetServerError(error, null, 'Failed to get Compared Experiments')
+ ])
+ )
))
);
@@ -65,7 +65,7 @@ export class ExperimentsCompareScalarsGraphEffects {
}
}
}
- const metricsList = Object.keys(metrics).sort((a, b) => a.toLowerCase() > b.toLowerCase() ? 1 : -1).map(metricName => ({
+ const metricsList = Object.keys(metrics).sort((a, b) => a.toLowerCase() > b.toLowerCase() ? 1 : -1).map(metricName => ({
metricName,
variants: Object.keys(metrics[metricName]).sort().map(variant => ({
name: variant,
@@ -75,18 +75,27 @@ export class ExperimentsCompareScalarsGraphEffects {
return metricsList;
}
- private getParametersHasDiffs(tasks): HyperParams {
+ private getParametersHasDiffs(tasks): GroupedHyperParams {
const numberOfTasks = tasks.length;
- const paramsValues: {string?: any[]} = {};
+ let paramsValues: { [section: string]: { [param: string]: any[] } } = {};
tasks.forEach(task => {
- Object.entries(task.execution.parameters).forEach( ([param, value]) =>
- paramsValues.hasOwnProperty(param) ? paramsValues[param].push(value) : (paramsValues[param] = [value])
- );
+ paramsValues = task.hyperparams ? Object.values(task.hyperparams).reduce((acc, paramsObj) => {
+ Object.values(paramsObj).forEach((paramObj) => {
+ acc[paramObj.section] = acc[paramObj.section] || {};
+ acc[paramObj.section][paramObj.name] = acc[paramObj.section][paramObj.name] || [];
+ acc[paramObj.section][paramObj.name].push(paramObj.value);
+ });
+ return acc;
+ }, paramsValues) as { [section: string]: { [param: string]: any[] } } : paramsValues;
});
- return Object.entries(paramsValues).reduce((acc, [paramKey, values]) => {
- acc[paramKey] = values.every(value => value !== '') && (numberOfTasks != values.length || values.some(val => val !== values[0]));
- return acc;
- }, {});
+ const paramsValuesHasDiff: { [section: string]: HyperParams } = {};
+ Object.entries(paramsValues).forEach(([section, params]) => {
+ paramsValuesHasDiff[section] = Object.entries(params).reduce((acc, [paramKey, values]) => {
+ acc[paramKey] = values.every(value => value !== '') && (numberOfTasks != values.length || values.some(val => val !== values[0]));
+ return acc;
+ }, {});
+ });
+ return paramsValuesHasDiff;
}
}
diff --git a/src/app/webapp-common/experiments-compare/effects/select-experiment-for-compare-effects.service.ts b/src/app/webapp-common/experiments-compare/effects/select-experiment-for-compare-effects.service.ts
index d506f16a..6f75ce04 100644
--- a/src/app/webapp-common/experiments-compare/effects/select-experiment-for-compare-effects.service.ts
+++ b/src/app/webapp-common/experiments-compare/effects/select-experiment-for-compare-effects.service.ts
@@ -13,7 +13,7 @@ import {select, Store} from '@ngrx/store';
import {get, isEmpty} from 'lodash/fp';
import {escapeRegex} from '../../shared/utils/shared-utils';
import {NONE_USER_TASK_TYPES} from '../../experiments/shared/common-experiments.const';
-import {selectExperimentIds, selectExperimentsUpdateTime} from '../reducers';
+import {selectExperimentsUpdateTime} from '../reducers';
import {EmptyAction} from '../../../app.constants';
import {selectRouterParams} from '../../core/reducers/router-reducer';
import {selectAppVisible} from '../../core/reducers/view-reducer';
diff --git a/src/app/webapp-common/experiments-compare/experiments-compare-routing.module.ts b/src/app/webapp-common/experiments-compare/experiments-compare-routing.module.ts
index 46154aee..db2b7d1c 100644
--- a/src/app/webapp-common/experiments-compare/experiments-compare-routing.module.ts
+++ b/src/app/webapp-common/experiments-compare/experiments-compare-routing.module.ts
@@ -9,6 +9,7 @@ import {ExperimentComparePlotsComponent} from './containers/experiment-compare-p
import {DebugImagesComponent} from '../debug-images/debug-images.component';
import {ExperimentCompareHyperParamsGraphComponent} from './containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component';
import {RouterHelperGuard} from './experiment-compare-router-helper.guard';
+import {ExperimentCompareParamsComponent} from './containers/experiment-compare-params/experiment-compare-params.component';
export const routes: Routes = [
@@ -22,7 +23,7 @@ export const routes: Routes = [
{path: 'metrics-charts', redirectTo: 'scalars/graph', pathMatch: 'full'},
{path: 'details', component: ExperimentCompareDetailsComponent, data: {mode: 'details'}},
- {path: 'hyper-params/values', component: ExperimentCompareDetailsComponent, canActivate: [RouterHelperGuard], data: {mode: 'hyper-params'}},
+ {path: 'hyper-params/values', component: ExperimentCompareParamsComponent, canActivate: [RouterHelperGuard], data: {mode: 'hyper-params'}},
{path: 'hyper-params/graph', component: ExperimentCompareHyperParamsGraphComponent},
{path: 'scalars/values', component: ExperimentCompareMetricValuesComponent, canActivate: [RouterHelperGuard]},
{path: 'scalars/graph', component: ExperimentCompareScalarChartsComponent},
diff --git a/src/app/webapp-common/experiments-compare/experiments-compare.component.scss b/src/app/webapp-common/experiments-compare/experiments-compare.component.scss
index 1755e34f..2c290696 100644
--- a/src/app/webapp-common/experiments-compare/experiments-compare.component.scss
+++ b/src/app/webapp-common/experiments-compare/experiments-compare.component.scss
@@ -87,19 +87,4 @@ $header-height: 60px;
/deep/ al-drawer button.drawer-toggle {
border-radius: 0 6px 6px 0;
}
-
- /deep/ .labeled-row {
- .label-container {
-
- width: 100px !important;
- flex: 0 0 100px;
- }
-
- .content {
- display: block;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- }
}
diff --git a/src/app/webapp-common/experiments-compare/experiments-compare.module.ts b/src/app/webapp-common/experiments-compare/experiments-compare.module.ts
index 1c78065d..33c445b1 100644
--- a/src/app/webapp-common/experiments-compare/experiments-compare.module.ts
+++ b/src/app/webapp-common/experiments-compare/experiments-compare.module.ts
@@ -40,8 +40,9 @@ import {ParallelCoordinatesGraphComponent} from './dumbs/parallel-coordinates-gr
import {ExperimentCompareHyperParamsGraphComponent} from './containers/experiment-compare-hyper-params-graph/experiment-compare-hyper-params-graph.component';
import {ExperimentsCompareScalarsGraphEffects} from './effects/experiments-compare-scalars-graph.effects';
import {ScrollingModule} from '@angular/cdk/scrolling';
-import {PrettifyTitleKeyPipe} from './prettify-title-key.pipe';
import {MatRadioModule} from '@angular/material/radio';
+import {ExperimentCompareParamsComponent} from './containers/experiment-compare-params/experiment-compare-params.component';
+import {ExperimentsCompareParamsEffects} from './effects/experiments-compare-params.effects';
const syncedKeys = [
'charts.settingsList',
@@ -57,13 +58,13 @@ export function localStorageReducer(reducer: ActionReducer): ActionReducer<
declarations: [
ExperimentsCompareComponent,
ExperimentCompareDetailsComponent,
+ ExperimentCompareParamsComponent,
ExperimentCompareMetricValuesComponent,
ExperimentCompareScalarChartsComponent,
ExperimentComparePlotsComponent,
ExperimentCompareHeaderComponent,
ExperimentCompareGeneralDataComponent,
GetKeyValueArrayPipePipe,
- PrettifyTitleKeyPipe,
SelectExperimentsForCompareComponent,
SelectExperimentsForCompareTableComponent,
CompareCardListComponent,
@@ -93,6 +94,7 @@ export function localStorageReducer(reducer: ActionReducer): ActionReducer<
StoreModule.forFeature('experimentsCompare', experimentsCompareReducers, {metaReducers: [localStorageReducer]}),
EffectsModule.forFeature([
ExperimentsCompareDetailsEffects,
+ ExperimentsCompareParamsEffects,
ExperimentsCompareDebugImagesEffects,
ExperimentsCompareChartsEffects,
ExperimentsCompareMetricsValuesEffects,
diff --git a/src/app/webapp-common/experiments-compare/jsonToDiffConvertor.ts b/src/app/webapp-common/experiments-compare/jsonToDiffConvertor.ts
index 642e60df..45568f3b 100644
--- a/src/app/webapp-common/experiments-compare/jsonToDiffConvertor.ts
+++ b/src/app/webapp-common/experiments-compare/jsonToDiffConvertor.ts
@@ -1,9 +1,9 @@
import {get, has, isArray, isEqual, mergeWith} from 'lodash/fp';
-import hoconParser from 'hocon-parser';
-import hash from 'object-hash';
import {IExperimentDetail} from '../../features/experiments-compare/experiments-compare-models';
import {treeBuilderService} from './services/tree-builder.service';
import {TreeNode} from './shared/experiments-compare-details.model';
+import {getAlternativeConvertedExperiment, getDisplayTextForTitles} from '../../features/experiments-compare/experiment-compare-utils';
+import {ConfigurationItem} from '../../business-logic/model/tasks/configurationItem';
export interface TreeNodeJsonData {
key: string;
@@ -35,14 +35,10 @@ function isObject(val) {
return val && typeof val === 'object';
}
-function isArrayOrderNotImportant2(val, key, allExperiments = []) {
- const allIsOne = allExperiments.every(experiment => experiment && experiment[key] && experiment[key].length === 1);
- return Array.isArray(val) && !allIsOne && (arrayOrderIsNotImportant(key));
-}
-function convertToHashItem(item, originItem) {
- const itemHash = hash(item);
- const convertedItemHash = (originItem && isArray(originItem) && originItem.map(element => hash(element)).includes(itemHash) ? 'a_hash_' : 'hash_') + itemHash;
+function convertToHashItem(item, originItem, path) {
+ const itemHash = getDisplayTextForTitles(item, path);
+ const convertedItemHash = (originItem && isArray(originItem) && originItem.map(element => getDisplayTextForTitles(element, path)).includes(itemHash) ? 'a_hash_' : 'hash_') + itemHash;
return convertedItemHash;
}
@@ -62,7 +58,7 @@ function convertnetworkDesign(networkDesign: string): any {
if (!networkDesign) {
return [];
}
- if (typeof networkDesign !== 'string'){
+ if (typeof networkDesign !== 'string') {
return networkDesign;
}
return networkDesign;
@@ -86,7 +82,11 @@ function convertUncommittedChanges(diff: string[]): { [files: string]: string[]
acc[curr] = [];
} else {
if (currKey === null) {
- acc[`hash_${curr}`] = curr;
+ if (curr.startsWith('** Content is too large to display.')) {
+ acc['a_hash_'] = curr;
+ } else {
+ acc[`hash_${curr}`] = curr;
+ }
} else {
acc[currKey].push(curr);
}
@@ -95,9 +95,42 @@ function convertUncommittedChanges(diff: string[]): { [files: string]: string[]
}, {}) : diff;
}
-export function convertExperimentsArrays(experiment, origin, experiments): IExperimentDetail {
+function convertHyperParams(hyperParams: { [section: string]: { [name: string]: any } }, originHyperParams): { [section: string]: { [name: string]: any } } {
+ if (!hyperParams) {
+ return {};
+ }
+
+ if (isParamsConverted(hyperParams)) {
+ return hyperParams;
+ }
+
+ return Object.entries(hyperParams).reduce((result, [sectionName, section]) => {
+ result[sectionName] = Object.entries(section).reduce((acc, [paramName, param]) => {
+ const hasInOrigin = has(`${sectionName}.${paramName}`, originHyperParams);
+ acc[(hasInOrigin ? ' ' : '') + paramName] = param.value;
+ return acc;
+ }, {});
+ return result;
+ }, {});
+}
+
+function convertConfiguration(confParams: { [name: string]: ConfigurationItem }, originConfParams): { [name: string]: string | string[] } {
+ if (!confParams) {
+ return {};
+ }
+
+ return Object.entries(confParams).reduce((acc, [paramName, {value}]) => {
+ const hasInOrigin = has(paramName, originConfParams.configuration);
+ acc[(hasInOrigin ? ' ' : '') + paramName] = value? value.split('\n'): undefined;
+ return acc;
+ }, {});
+}
+
+export function convertExperimentsArrays(experiment, origin, experiments, path = ''): IExperimentDetail {
const convertedExperiment: IExperimentDetail = {};
+ let counter = 1;
Object.keys(experiment).forEach(key => {
+ const newPath = `${path}.${key}`;
switch (key) {
case 'installed_packages':
convertedExperiment[key] = convertInstalledPackages(experiment[key]);
@@ -108,16 +141,35 @@ export function convertExperimentsArrays(experiment, origin, experiments): IExpe
case 'uncommitted_changes':
convertedExperiment[key] = convertUncommittedChanges(experiment[key]);
break;
+ case 'tags':
+ convertedExperiment[key] = experiment[key];
+ break;
+ case 'configuration':
+ convertedExperiment[key] = convertConfiguration(experiment[key], origin);
+ break;
default:
- if (isObject(experiment[key]) && (!isArrayOrderNotImportant(experiment[key], key, experiments))) {
- convertedExperiment[key] = convertExperimentsArrays(experiment[key], origin ? origin[key] : null, experiments.map(exp => exp ? exp[key] : null));
+ const alternativeConvertedExperiment = getAlternativeConvertedExperiment(newPath, experiment[key]);
+ if (alternativeConvertedExperiment) {
+ convertedExperiment[key] = alternativeConvertedExperiment;
+ } else if (isObject(experiment[key]) && (!isArrayOrderNotImportant(experiment[key], key, experiments))) {
+ let newKey = getDisplayTextForTitles(experiment[key], newPath) || key;
+
+ // Makes base/origin rows first
+ if (origin && Array.isArray(origin) && origin.map(item => getDisplayTextForTitles(item, newPath)).includes(newKey)) {
+ newKey = `0${newKey}`;
+ }
+ convertedExperiment[newKey] = convertExperimentsArrays(experiment[key], origin ? origin[key] : null, experiments.map(exp => exp ? exp[key] : null), newPath);
} else if (isArrayOrderNotImportant(experiment[key], key, experiments)) {
const hashedObj = {};
experiment[key].forEach(item => {
- const convertedItemHash = convertToHashItem(item, origin && origin[key]);
+ let convertedItemHash = convertToHashItem(item, origin && (Array.isArray(origin) ? (origin.map(item => item[key]) as any).flat() : origin[key]), newPath);
+ if (hashedObj[convertedItemHash]) {
+ convertedItemHash = `${counter}${convertedItemHash}`;
+ counter++;
+ }
if (isObject(item)) {
hashedObj[convertedItemHash] =
- convertExperimentsArrays(item, origin ? origin[key] : null, experiments.map(exp => exp ? exp[key] : null));
+ convertExperimentsArrays(item, origin ? origin[key] : null, experiments.map(exp => exp ? exp[key] : null), newPath);
} else {
hashedObj[convertedItemHash] = item;
}
@@ -132,6 +184,13 @@ export function convertExperimentsArrays(experiment, origin, experiments): IExpe
return convertedExperiment;
}
+export function convertExperimentsArraysParams(experiment, origin): IExperimentDetail {
+ return Object.keys(experiment).reduce((acc, key) => {
+ acc[key] = key === 'hyperparams' ? convertHyperParams(experiment[key], origin.hyperparams) : experiment[key];
+ return acc;
+ }, {} as IExperimentDetail);
+}
+
function abSort(obj) {
return Object.keys(obj).sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
@@ -151,6 +210,16 @@ function sortObject(obj, origin, parentKey: string) {
return orderedObj;
}
+export function isDetailsConverted(exp) {
+ return exp.execution?.installed_packages && !Array.isArray(exp.execution?.installed_packages)
+}
+
+export function isParamsConverted(hyperparams) {
+ const firstKey = hyperparams && Object.keys(hyperparams)[0];
+ const firstParam = firstKey && Object.values(hyperparams[firstKey])[0];
+ return typeof firstParam === 'string';
+}
+
export function getAllKeysEmptyObject(jsons) {
let obj = {};
jsons.forEach(json => obj = mergeWith(customMergeStrategyForArrays, obj, json));
diff --git a/src/app/webapp-common/experiments-compare/prettify-title-key.pipe.ts b/src/app/webapp-common/experiments-compare/prettify-title-key.pipe.ts
deleted file mode 100644
index 45204721..00000000
--- a/src/app/webapp-common/experiments-compare/prettify-title-key.pipe.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import {Pipe, PipeTransform} from '@angular/core';
-
-@Pipe({
- name: 'prettifyTitleKeyPipe',
- pure: true
-})
-export class PrettifyTitleKeyPipe implements PipeTransform {
-
- transform(value: string): string {
- switch (value) {
- case 'network_design': return 'Network Design';
- case 'uncommitted_changes': return 'Uncommitted Changes';
- case 'installed_packages': return 'Installed Packages';
- case 'base_docker_image': return 'Base Docker Image';
- case ' input model': return 'Input Model';
- case ' output model': return 'Output Model';
- case ' output model': return 'Output Model';
- case 'model': return 'Model';
- case 'source': return 'Source';
- default:
- return value;
- }
-
- }
-
-}
diff --git a/src/app/webapp-common/experiments-compare/reducers/experiments-compare-charts.reducer.ts b/src/app/webapp-common/experiments-compare/reducers/experiments-compare-charts.reducer.ts
index bb21a839..77b4da83 100644
--- a/src/app/webapp-common/experiments-compare/reducers/experiments-compare-charts.reducer.ts
+++ b/src/app/webapp-common/experiments-compare/reducers/experiments-compare-charts.reducer.ts
@@ -9,6 +9,10 @@ export interface SelectedMetric {
path: string;
}
+export interface GroupedHyperParams {
+ [section: string]: HyperParams;
+}
+
export interface HyperParams {
[name: string]: boolean;
}
@@ -26,6 +30,7 @@ export interface MetricOption {
export interface IExperimentCompareChartsState {
metricsMultiScalarsCharts: any;
metricsHistogramCharts: any;
+ cachedAxisType: ScalarKeyEnum;
metricsPlotsCharts: any;
settingsList: Array;
searchTerm: string;
@@ -48,6 +53,7 @@ export interface IExperimentCompareSettings {
export const initialState: IExperimentCompareChartsState = {
metricsMultiScalarsCharts: null,
metricsHistogramCharts: null,
+ cachedAxisType: null,
metricsPlotsCharts: null,
settingsList: [], // TODO, Make this an object with ID's as key YK
searchTerm: '',
@@ -62,7 +68,7 @@ export function experimentsCompareChartsReducer(state: IExperimentCompareChartsS
case SET_EXPERIMENT_METRICS_SEARCH_TERM:
return {...state, searchTerm: action.payload.searchTerm};
case SET_EXPERIMENT_HISTOGRAM:
- return {...state, metricsHistogramCharts: action.payload};
+ return {...state, metricsHistogramCharts: action.payload, cachedAxisType: action.axisType};
case SET_EXPERIMENT_PLOTS:
return {...state, metricsPlotsCharts: action.payload};
case UPDATE_EXPERIMENT_SETTINGS: {
@@ -77,7 +83,13 @@ export function experimentsCompareChartsReducer(state: IExperimentCompareChartsS
return {...state, settingsList: newSettings};
}
case RESET_EXPERIMENT_METRICS:
- return {...state, metricsMultiScalarsCharts: null, metricsHistogramCharts: null, metricsPlotsCharts: null};
+ return {
+ ...state,
+ metricsMultiScalarsCharts: initialState.metricsMultiScalarsCharts,
+ metricsHistogramCharts: initialState.metricsHistogramCharts,
+ metricsPlotsCharts: initialState.metricsPlotsCharts,
+ cachedAxisType: initialState.cachedAxisType
+ };
default:
return state;
}
diff --git a/src/app/webapp-common/experiments-compare/reducers/experiments-compare-details.reducer.ts b/src/app/webapp-common/experiments-compare/reducers/experiments-compare-details.reducer.ts
index c1d5d0d9..6ea16da1 100644
--- a/src/app/webapp-common/experiments-compare/reducers/experiments-compare-details.reducer.ts
+++ b/src/app/webapp-common/experiments-compare/reducers/experiments-compare-details.reducer.ts
@@ -1,28 +1,22 @@
-import * as actions from '../actions/experiments-compare-details.actions';
+import {resetState, setExperiments} from '../actions/experiments-compare-details.actions';
import {IExperimentDetail} from '../../../features/experiments-compare/experiments-compare-models';
+import {createReducer, on} from '@ngrx/store';
-export interface IExperimentCompareDetailsState {
+export interface ExperimentCompareDetailsState {
experiments: Array;
- expandedPaths: Array;
}
-export const initialState: IExperimentCompareDetailsState = {
- expandedPaths: [],
+export const initialState: ExperimentCompareDetailsState = {
experiments : []
};
+const _experimentsCompareDetailsReducer = createReducer(initialState,
+ on(setExperiments, (state: ExperimentCompareDetailsState, {experiments}) => ({...state, experiments: experiments})),
+ on(resetState, (state: ExperimentCompareDetailsState) => ({...initialState}))
+);
-export function experimentsCompareDetailsReducer(state: IExperimentCompareDetailsState = initialState, action): IExperimentCompareDetailsState {
- switch (action.type) {
- case actions.SET_EXPERIMENTS:
- return {...state, experiments: action.payload};
- case actions.EXPAND_NODE:
- return {...state, expandedPaths: state.expandedPaths.concat(action.payload)};
- case actions.COLLAPSE_NODE:
- return {...state, expandedPaths: state.expandedPaths.filter(path => path !== action.payload)};
- case actions.RESET_STATE:
- return {...initialState};
- default:
- return state;
- }
+export function experimentsCompareDetailsReducer(state, action) {
+ return _experimentsCompareDetailsReducer(state, action);
}
+
+
diff --git a/src/app/webapp-common/experiments-compare/reducers/experiments-compare-scalars-graph.reducer.ts b/src/app/webapp-common/experiments-compare/reducers/experiments-compare-scalars-graph.reducer.ts
index 2a583b23..f7bf8f1e 100644
--- a/src/app/webapp-common/experiments-compare/reducers/experiments-compare-scalars-graph.reducer.ts
+++ b/src/app/webapp-common/experiments-compare/reducers/experiments-compare-scalars-graph.reducer.ts
@@ -1,11 +1,11 @@
import {createReducer, on} from '@ngrx/store';
import {setHyperParamsList, setMetricsList, setShowIdenticalHyperParams, setTasks, setvalueType} from '../actions/experiments-compare-scalars-graph.actions';
-import {HyperParams, MetricOption, MetricValueType} from './experiments-compare-charts.reducer';
+import {GroupedHyperParams, HyperParams, MetricOption, MetricValueType} from './experiments-compare-charts.reducer';
export interface ScalarsGraphState {
showIdenticalHyperParams: boolean;
metrics: MetricOption[];
- hyperParams: HyperParams;
+ hyperParams: GroupedHyperParams;
tasks: any;
valueType: MetricValueType;
}
diff --git a/src/app/webapp-common/experiments-compare/reducers/index.ts b/src/app/webapp-common/experiments-compare/reducers/index.ts
index 495aa4ce..f041b504 100644
--- a/src/app/webapp-common/experiments-compare/reducers/index.ts
+++ b/src/app/webapp-common/experiments-compare/reducers/index.ts
@@ -1,6 +1,6 @@
import {ActionReducerMap, createFeatureSelector, createSelector} from '@ngrx/store';
-import {experimentsCompareDetailsReducer, IExperimentCompareDetailsState} from './experiments-compare-details.reducer';
-import {experimentsCompareChartsReducer, HyperParams, IExperimentCompareChartsState, IExperimentCompareSettings, MetricOption, MetricValueType} from './experiments-compare-charts.reducer';
+import {ExperimentCompareDetailsState, experimentsCompareDetailsReducer} from './experiments-compare-details.reducer';
+import {experimentsCompareChartsReducer, GroupedHyperParams, HyperParams, IExperimentCompareChartsState, IExperimentCompareSettings, MetricOption, MetricValueType} from './experiments-compare-charts.reducer';
import {experimentsCompareMetricsValuesReducer, IExperimentCompareMetricsValuesState, MetricSortBy} from './experiments-compare-metrics-values.reducer';
import {experimentsCompareDebugImagesReducer} from './experiments-compare-debug-images.reducer';
import {get} from 'lodash/fp';
@@ -9,9 +9,13 @@ import {compareHeader, CompareHeaderState} from './compare-header.reducer';
import {IExperimentDetail} from '../../../features/experiments-compare/experiments-compare-models';
import {ScalarKeyEnum} from '../../../business-logic/model/events/scalarKeyEnum';
import {scalarsGraphReducer, ScalarsGraphState} from './experiments-compare-scalars-graph.reducer';
+import {experimentOutput} from '../../../features/experiments/reducers';
+import {ExperimentParams} from '../shared/experiments-compare-details.model';
+import {ExperimentCompareParamsState, experimentsCompareParamsReducer} from './experiments-compare-params.reducer';
export const experimentsCompareReducers: ActionReducerMap = {
details : experimentsCompareDetailsReducer,
+ params : experimentsCompareParamsReducer,
metricsValues: experimentsCompareMetricsValuesReducer,
charts : experimentsCompareChartsReducer,
debugImages : experimentsCompareDebugImagesReducer,
@@ -22,12 +26,18 @@ export const experimentsCompareReducers: ActionReducerMap = {
export const experimentsCompare = createFeatureSelector('experimentsCompare');
// Details
-export const experimentsDetails = createSelector(experimentsCompare, (state): IExperimentCompareDetailsState => state ? state.details : {});
+export const experimentsDetails = createSelector(experimentsCompare, (state): ExperimentCompareDetailsState => state ? state.details : {});
export const selectExperimentsDetails = createSelector(experimentsDetails, (state): Array => state.experiments);
-export const selectExpandedPaths = createSelector(experimentsDetails, (state): Array => state.expandedPaths);
-export const selectExperimentIds = createSelector(selectExperimentsDetails,
+export const selectExperimentIdsDetails = createSelector(selectExperimentsDetails,
(experiments): Array => experiments.map(exp => exp.id));
+// Params
+export const experimentsParams = createSelector(experimentsCompare, (state): ExperimentCompareParamsState => state ? state.params : {});
+export const selectExperimentsParams = createSelector(experimentsParams, (state): Array => state.experiments);
+export const selectExperimentIdsParams = createSelector(selectExperimentsParams,
+ (experiments): Array => experiments.map(exp => exp.id));
+
+
// select experiments for compare and header
export const selectCompareHeader = createSelector(experimentsCompare, (state): CompareHeaderState => state ? state.compareHeader : {});
export const selectExperimentsForCompareSearchResults = createSelector(selectCompareHeader, (state): Array => state ? state.searchResultsExperiments : []);
@@ -47,7 +57,7 @@ export const selectCompareMetricsValuesSortConfig = createSelector(compareMetric
// Charts
export const compareCharts = createSelector(experimentsCompare, (state): IExperimentCompareChartsState => state ? state.charts : {});
export const selectSelectedExperiments = createSelector(compareCharts, (state): Array => state ? state.selectedExperiments : []);
-export const selectCompareTasksScalarCharts = createSelector(compareCharts, state => state.metricsHistogramCharts);
+export const selectCompareHistogramCacheAxisType = createSelector(compareCharts, (state) => state.cachedAxisType);
export const selectCompareTasksPlotCharts = createSelector(compareCharts, state => state.metricsPlotsCharts);
export const selectSelectedExperimentSettings = createSelector(compareCharts, selectSelectedExperiments,
@@ -75,7 +85,30 @@ export const selectCompareSelectedSettingsxAxisType = createSelector(selectSelec
export const selectScalarsGraph = createSelector(experimentsCompare, (state): ScalarsGraphState => state ? state.scalarsGraph : {});
export const selectScalarsGraphShowIdenticalHyperParams = createSelector(selectScalarsGraph, (state): boolean => state ? state.showIdenticalHyperParams : true);
export const selectScalarsGraphMetrics = createSelector(selectScalarsGraph, (state): MetricOption[] => state.metrics);
-export const selectScalarsGraphHyperParams = createSelector(selectScalarsGraph, (state): HyperParams => state ? state.hyperParams : {});
+export const selectScalarsGraphHyperParams = createSelector(selectScalarsGraph, (state): GroupedHyperParams => state ? state.hyperParams : {});
export const selectScalarsGraphTasks = createSelector(selectScalarsGraph, (state): any[] => state ? state.tasks : []);
export const selectMetricValueType = createSelector(selectScalarsGraph, (state): MetricValueType => state ? state.valueType : 'value');
+export const selectCompareTasksScalarCharts = createSelector(
+ selectCompareSelectedSettingsxAxisType,
+ compareCharts,
+ (axisType, state) => {
+ if (!axisType || axisType === ScalarKeyEnum.IsoTime) {
+ return {
+ metrics: Object.keys(state.metricsHistogramCharts.metrics).reduce((metricAcc, metricName) => {
+ const metric = state.metricsHistogramCharts.metrics[metricName];
+ metricAcc[metricName] = Object.keys(metric).reduce((groupAcc, groupName) => {
+ const group = metric[groupName];
+ groupAcc[groupName] = Object.keys(group).reduce((graphAcc, graphName) => {
+ const graph = group[graphName];
+ graphAcc[graphName] = {...graph, x: graph.x.map(ts => new Date(ts))};
+ return graphAcc;
+ }, {});
+ return groupAcc;
+ }, {});
+ return metricAcc;
+ }, {})
+ };
+ }
+ return state.metricsHistogramCharts;
+ });
diff --git a/src/app/webapp-common/experiments-compare/services/experiment-details-reverter.service.ts b/src/app/webapp-common/experiments-compare/services/experiment-details-reverter.service.ts
index 57851dcf..22de6dbb 100644
--- a/src/app/webapp-common/experiments-compare/services/experiment-details-reverter.service.ts
+++ b/src/app/webapp-common/experiments-compare/services/experiment-details-reverter.service.ts
@@ -9,6 +9,7 @@ import {Task} from '../../../business-logic/model/tasks/task';
import {ExperimentDetailsReverterServiceBase} from '../../../features/experiments-compare/experiment-details-reverter-service.base';
import {ARTIFACTS_TYPES} from '../../tasks/tasks.constants';
import {Artifact} from '../../../business-logic/model/tasks/artifact';
+import {crc32} from '../../shared/utils/shared-utils';
@Injectable({
providedIn: 'root'
@@ -38,18 +39,17 @@ export class ExperimentDetailsReverterService extends ExperimentDetailsReverterS
}
revertAuditLog(artifact: Artifact): any {
- const {uri, content_size, hash, timestamp, display_data, type_data, ...restArtifact} = artifact;
+ const {uri, content_size, hash, timestamp, display_data, mode, key, type_data, ...restArtifact} = artifact;
const result = {
...restArtifact,
- 'file path': uri,
'file size': content_size,
'file hash': hash,
- 'timestamp': timestamp
};
if (type_data) {
+ const preview = type_data.preview && type_data.preview.trim().split('\n') || [];
result['content type'] = type_data['content_type'] || '';
- result['preview'] = type_data.preview && type_data.preview.trim().split('\n') || [];
+ result['preview'] = (preview.length < 3000 && preview[0]?.length < 3000) ? preview : [`** Content is too large to display. Hash: ${crc32(type_data.preview)}`];
result['data hash'] = type_data.data_hash || '';
}
display_data.forEach(pair => result[pair[0]] = pair[1]);
@@ -67,26 +67,27 @@ export class ExperimentDetailsReverterService extends ExperimentDetailsReverterS
revertModel(experiment: ISelectedExperiment): ModelDetails {
return {
model: this.revertModelInput(experiment.execution),
- network_design: this.revertNetworkDesign(experiment.execution),
+ network_design: this.revertNetworkDesign(experiment.execution.model),
};
}
- revertNetworkDesign(execution) {
- let networkDesign = get('design.design', execution) || get('model_desc.design', execution) || get('model_desc.prototxt', execution);
+ revertNetworkDesign(model): string {
+ let networkDesign = get('design.design', model) || get('design', model);
networkDesign = typeof networkDesign === 'string' ? networkDesign.split('\n') : {};
return networkDesign;
}
revertExecution(experiment: ISelectedExperiment): ExecutionDetails {
let pip = get('script.requirements.pip', experiment);
- let diff = get('script.diff', experiment);
pip = (pip === undefined || Array.isArray(pip)) ? pip : pip.split('\n');
pip = pip?.filter(row => !row.startsWith('#') && row.length > 0); // Should we remove comments????
- diff = (!diff || Array.isArray(diff)) ? diff : diff.split('\n');
-
- let base_docker_image = get('execution.docker_cmd', experiment) || '';
- // base_docker_image = base_docker_image ? {'': base_docker_image} : undefined;
+ let diff = get('script.diff', experiment);
+ if (diff) {
+ diff = (Array.isArray(diff)) ? diff : diff.split('\n');
+ diff = (diff.length < 3000 && diff[0]?.length < 3000) ? diff : [`** Content is too large to display. Hash: ${crc32(get('script.diff', experiment))}`];
+ }
+ const base_docker_image = get('execution.docker_cmd', experiment) || '';
return {
source: experiment.script ? this.revertExecutionSource(experiment.script) : undefined,
@@ -114,7 +115,7 @@ export class ExperimentDetailsReverterService extends ExperimentDetailsReverterS
script_path: script.entry_point,
branch: script.branch,
commit_id: script.version_num,
- tag_name: script.tag
+ tag_name: script.tag || '' // In tag_name we want undefined == null == ""
};
}
diff --git a/src/app/webapp-common/experiments-compare/shared/experiments-compare-details.model.ts b/src/app/webapp-common/experiments-compare/shared/experiments-compare-details.model.ts
index 483c2af5..dc92247c 100644
--- a/src/app/webapp-common/experiments-compare/shared/experiments-compare-details.model.ts
+++ b/src/app/webapp-common/experiments-compare/shared/experiments-compare-details.model.ts
@@ -20,7 +20,16 @@ export interface ExperimentDetailBase {
tags?: string[];
}
-
+export interface ExperimentParams {
+ id?: Task['id'];
+ name?: string;
+ status?: Task['status'];
+ last_iteration?: Task['last_iteration'];
+ last_update?: Task['last_update'];
+ project?: Project;
+ hyperparams?: any[];
+ tags?: string[];
+}
export interface ModelDetails {
model?: ModelDetailsInput;
@@ -53,7 +62,6 @@ export interface ExecutionDetails {
script_path?: string; // Script.entry_point;
branch?: string; // Script.branch;
};
- parameters?: { [key: string]: any };
uncommitted_changes?: { [key: string]: any };
installed_packages?: { [key: string]: any };
base_docker_image?: { [key: string]: any };
diff --git a/src/app/webapp-common/experiments/actions/common-experiment-output.actions.ts b/src/app/webapp-common/experiments/actions/common-experiment-output.actions.ts
index a620f6f4..cc21661b 100644
--- a/src/app/webapp-common/experiments/actions/common-experiment-output.actions.ts
+++ b/src/app/webapp-common/experiments/actions/common-experiment-output.actions.ts
@@ -1,6 +1,7 @@
import {Action, createAction, props} from '@ngrx/store';
import {ISelectedExperiment} from '../../../features/experiments/shared/experiment-info.model';
import {IExperimentSettings} from '../reducers/common-experiment-output.reducer';
+import {ScalarKeyEnum} from '../../../business-logic/model/events/scalarKeyEnum';
export const EXPERIMENTS_OUTPUT_PREFIX = 'EXPERIMENTS_OUTPUT_';
@@ -56,7 +57,7 @@ export class ExperimentScalarRequested implements Action {
export class SetExperimentHistogram implements Action {
readonly type = SET_EXPERIMENT_HISTOGRAM;
- constructor(public payload: any) {
+ constructor(public payload: any, public axisType: ScalarKeyEnum) {
}
}
@@ -67,19 +68,15 @@ export class SetExperimentPlots implements Action {
}
}
-export class GetExperimentLog implements Action {
- readonly type = GET_EXPERIMENT_LOG;
+export const getExperimentLog = createAction(
+ GET_EXPERIMENT_LOG,
+ props<{id: string; direction?: string; refresh?: boolean; from?: number}>()
+);
- constructor(public payload: ISelectedExperiment['id']) {
- }
-}
-
-export class SetExperimentLog implements Action {
- readonly type = SET_EXPERIMENT_LOG;
-
- constructor(public events: Array, public scrollID: string) {
- }
-}
+export const setExperimentLog = createAction(
+ SET_EXPERIMENT_LOG,
+ props<{events: any[]; direction?: string; total: number; refresh?: boolean}>()
+);
export class SetExperimentSettings implements Action {
readonly type = UPDATE_EXPERIMENT_SETTINGS;
diff --git a/src/app/webapp-common/experiments/actions/common-experiments-info.actions.ts b/src/app/webapp-common/experiments/actions/common-experiments-info.actions.ts
index 4ef73ce0..b65fb107 100644
--- a/src/app/webapp-common/experiments/actions/common-experiments-info.actions.ts
+++ b/src/app/webapp-common/experiments/actions/common-experiments-info.actions.ts
@@ -1,8 +1,11 @@
-import {Action} from '@ngrx/store';
+import {Action, createAction, props} from '@ngrx/store';
import {Task} from '../../../business-logic/model/tasks/task';
import {IExperimentInfo, ISelectedExperiment} from '../../../features/experiments/shared/experiment-info.model';
import {Model} from '../../../business-logic/model/models/model';
import {ITableExperiment} from '../shared/common-experiment-model.model';
+import {ParamsItem} from '../../../business-logic/model/tasks/paramsItem';
+import {ConfigurationItem} from '../../../business-logic/model/tasks/configurationItem';
+
export const EXPERIMENTS_INFO_PREFIX = 'EXPERIMENTS_INFO_';
export const GET_EXPERIMENT_INFO = EXPERIMENTS_INFO_PREFIX + 'GET_EXPERIMENT_INFO';
export const AUTO_REFRESH_EXPERIMENT_INFO = EXPERIMENTS_INFO_PREFIX + 'AUTO_REFRESH_EXPERIMENT_INFO';
@@ -40,6 +43,8 @@ export class SetExperiment implements Action {
export class ExperimentUpdatedSuccessfully implements Action {
readonly type = EXPERIMENT_UPDATED_SUCCESSFULLY;
+ constructor(public payload: string) {
+ }
}
export class SetExperimentInfoData implements Action {
@@ -49,6 +54,21 @@ export class SetExperimentInfoData implements Action {
}
}
+export const getExperiment= createAction(
+ EXPERIMENTS_INFO_PREFIX + '[set experiment]',
+ props<{experimentId: string}>()
+);
+
+export const getExperimentUncommittedChanges = createAction(
+ EXPERIMENTS_INFO_PREFIX + '[get uncommitted change]',
+ props<{experimentId: string}>()
+);
+
+export const setExperimentUncommittedChanges = createAction(
+ EXPERIMENTS_INFO_PREFIX + '[set uncommitted change]',
+ props<{diff: string}>()
+);
+
export class ModelSelected implements Action {
readonly type = MODEL_SELECTED;
public payload: {
@@ -67,6 +87,29 @@ export class ModelSelected implements Action {
export class UpdateExperimentInfoData implements Action {
readonly type = UPDATE_EXPERIMENT_INFO_DATA;
- constructor(public payload: { id: ITableExperiment['id'], changes: Partial }) {
+ constructor(public payload: { id: ITableExperiment['id'], changes: Partial }) {
}
}
+export const saveHyperParamsSection = createAction(
+ EXPERIMENTS_INFO_PREFIX + 'SAVE_HYPERPARAMS', props<{ hyperparams: ParamsItem[] }>());
+
+export const saveExperimentConfigObj = createAction(
+ EXPERIMENTS_INFO_PREFIX + 'SAVE_CONFIG_OBJ', props<{ configuration: Array; }>());
+
+export const deleteHyperParamsSection = createAction(
+ EXPERIMENTS_INFO_PREFIX + 'DELETE_HYPERPARAMS_SECTION', props<{ section: string }>());
+
+export const hyperParamsSectionUpdated = createAction(
+ EXPERIMENTS_INFO_PREFIX + 'UPDATE_HYPERPARAMS', props<{ section: string, hyperparams: ParamsItem[] }>());
+
+export const getExperimentConfigurationNames = createAction(
+ EXPERIMENTS_INFO_PREFIX + 'GET_CONFIGURATION',props<{ experimentId: string }>());
+
+export const setExperimentSaving = createAction(
+ EXPERIMENTS_INFO_PREFIX + 'SET_SAVING',props<{ saving: boolean }>());
+
+export const getExperimentConfigurationObj = createAction(
+ EXPERIMENTS_INFO_PREFIX + 'GET_CONFIGURATION_OBJ');
+
+export const updateExperimentAtPath = createAction(
+ EXPERIMENTS_INFO_PREFIX + 'UPDATE_EXPERIMENT_AT_PATH',props<{ path: string, value:any}>());
diff --git a/src/app/webapp-common/experiments/actions/common-experiments-menu.actions.ts b/src/app/webapp-common/experiments/actions/common-experiments-menu.actions.ts
index 3ef46666..874bdf70 100644
--- a/src/app/webapp-common/experiments/actions/common-experiments-menu.actions.ts
+++ b/src/app/webapp-common/experiments/actions/common-experiments-menu.actions.ts
@@ -39,20 +39,6 @@ export class StopClicked implements Action {
}
}
-export class ArchiveClicked implements Action {
- readonly type = ARCHIVE_CLICKED;
-
- constructor(public payload: { experiment: ISelectedExperiment; selectedExperiment: any; projectId: string }) {
- }
-}
-
-export class RestoreClicked implements Action {
- readonly type = RESTORE_CLICKED;
-
- constructor(public payload: { experiment: ISelectedExperiment; selectedExperiment: any; projectId: string }) {
- }
-}
-
export class ChangeProjectRequested implements Action {
readonly type = CHANGE_PROJECT_REQUESTED;
diff --git a/src/app/webapp-common/experiments/actions/common-experiments-view.actions.ts b/src/app/webapp-common/experiments/actions/common-experiments-view.actions.ts
index 58df9265..837ac2d2 100644
--- a/src/app/webapp-common/experiments/actions/common-experiments-view.actions.ts
+++ b/src/app/webapp-common/experiments/actions/common-experiments-view.actions.ts
@@ -6,40 +6,41 @@ import {MetricVariantResult} from '../../../business-logic/model/projects/metric
import {TableFilter} from '../../shared/utils/tableParamEncode';
import {PROJECTS_PREFIX} from '../../core/actions/projects.actions';
import {User} from '../../../business-logic/model/users/user';
+import {ParamsItem} from '../../../business-logic/model/tasks/paramsItem';
export const EXPERIMENTS_PREFIX = 'EXPERIMENTS_';
// COMMANDS:
export const ARCHIVE_SELECTED_EXPERIMENTS = EXPERIMENTS_PREFIX + 'ARCHIVE_SELECTED_EXPERIMENTS';
export const RESTORE_SELECTED_EXPERIMENTS = EXPERIMENTS_PREFIX + 'RESTORE_SELECTED_EXPERIMENTS';
-export const ADD_MANY_EXPERIMENTS = EXPERIMENTS_PREFIX + 'ADD_MANY_EXPERIMENTS';
-export const GET_EXPERIMENTS = EXPERIMENTS_PREFIX + 'GET_EXPERIMENTS';
-export const REFRESH_EXPERIMENTS = EXPERIMENTS_PREFIX + 'REFRESH_EXPERIMENTS';
-export const GET_NEXT_EXPERIMENTS = EXPERIMENTS_PREFIX + 'GET_NEXT_EXPERIMENTS';
-export const SET_EXPERIMENTS = EXPERIMENTS_PREFIX + 'SET_EXPERIMENTS';
-export const SET_NEXT_PAGE = EXPERIMENTS_PREFIX + 'SET_NEXT_PAGE';
-export const SET_SELECTED_EXPERIMENTS = EXPERIMENTS_PREFIX + 'SET_SELECTED_EXPERIMENTS';
-export const SET_SELECTED_EXPERIMENT = EXPERIMENTS_PREFIX + 'SET_SELECTED_EXPERIMENT';
-export const SET_VIEW_MODE = EXPERIMENTS_PREFIX + 'SET_VIEW_MODE';
-export const SET_NO_MORE_EXPERIMENTS = EXPERIMENTS_PREFIX + 'SET_NO_MORE_EXPERIMENTS';
-export const REMOVE_MANY_EXPERIMENTS = EXPERIMENTS_PREFIX + 'REMOVE_MANY_EXPERIMENTS';
-export const UPDATE_ONE_EXPERIMENTS = EXPERIMENTS_PREFIX + 'UPDATE_ONE_EXPERIMENTS';
-export const RESET_EXPERIMENTS = EXPERIMENTS_PREFIX + 'RESET_EXPERIMENTS';
+export const ADD_MANY_EXPERIMENTS = EXPERIMENTS_PREFIX + 'ADD_MANY_EXPERIMENTS';
+export const GET_EXPERIMENTS = EXPERIMENTS_PREFIX + 'GET_EXPERIMENTS';
+export const REFRESH_EXPERIMENTS = EXPERIMENTS_PREFIX + 'REFRESH_EXPERIMENTS';
+export const GET_NEXT_EXPERIMENTS = EXPERIMENTS_PREFIX + 'GET_NEXT_EXPERIMENTS';
+export const SET_EXPERIMENTS = EXPERIMENTS_PREFIX + 'SET_EXPERIMENTS';
+export const SET_NEXT_PAGE = EXPERIMENTS_PREFIX + 'SET_NEXT_PAGE';
+export const SET_SELECTED_EXPERIMENTS = EXPERIMENTS_PREFIX + 'SET_SELECTED_EXPERIMENTS';
+export const SET_SELECTED_EXPERIMENT = EXPERIMENTS_PREFIX + 'SET_SELECTED_EXPERIMENT';
+export const SET_VIEW_MODE = EXPERIMENTS_PREFIX + 'SET_VIEW_MODE';
+export const SET_NO_MORE_EXPERIMENTS = EXPERIMENTS_PREFIX + 'SET_NO_MORE_EXPERIMENTS';
+export const REMOVE_MANY_EXPERIMENTS = EXPERIMENTS_PREFIX + 'REMOVE_MANY_EXPERIMENTS';
+export const UPDATE_ONE_EXPERIMENTS = EXPERIMENTS_PREFIX + 'UPDATE_ONE_EXPERIMENTS';
+export const RESET_EXPERIMENTS = EXPERIMENTS_PREFIX + 'RESET_EXPERIMENTS';
-export const SHOW_ALL_SELECTED = EXPERIMENTS_PREFIX + 'SHOW_ALL_SELECTED';
+export const SHOW_ALL_SELECTED = EXPERIMENTS_PREFIX + 'SHOW_ALL_SELECTED';
export const SET_SHOW_ALL_SELECTED_IS_ACTIVE = EXPERIMENTS_PREFIX + 'SET_SHOW_ALL_SELECTED_IS_ACTIVE';
// EVENTS:
-export const ARCHIVE_MODE_CHANGED = EXPERIMENTS_PREFIX + 'ARCHIVE_MODE_CHANGED';
+export const ARCHIVE_MODE_CHANGED = EXPERIMENTS_PREFIX + 'ARCHIVE_MODE_CHANGED';
-export const GLOBAL_FILTER_CHANGED = EXPERIMENTS_PREFIX + 'GLOBAL_FILTER_CHANGED';
-export const TABLE_SORT_CHANGED = EXPERIMENTS_PREFIX + 'TABLE_SORT_CHANGED';
-export const TABLE_FILTER_CHANGED = EXPERIMENTS_PREFIX + 'TABLE_FILTER_CHANGED';
+export const GLOBAL_FILTER_CHANGED = EXPERIMENTS_PREFIX + 'GLOBAL_FILTER_CHANGED';
+export const TABLE_SORT_CHANGED = EXPERIMENTS_PREFIX + 'TABLE_SORT_CHANGED';
+export const TABLE_FILTER_CHANGED = EXPERIMENTS_PREFIX + 'TABLE_FILTER_CHANGED';
export const SET_TABLE_FILTERS = EXPERIMENTS_PREFIX + 'SET_TABLE_FILTERS';
export const GET_PROJECT_TYPES = EXPERIMENTS_PREFIX + 'GET_PROJECT_TYPES';
export const SET_PROJECT_TYPES = EXPERIMENTS_PREFIX + 'SET_PROJECT_TYPES';
export const EXPERIMENT_SELECTION_CHANGED = EXPERIMENTS_PREFIX + 'EXPERIMENT_SELECTION_CHANGED';
// export const EXPERIMENTS_SELECTION_CHANGED = EXPERIMENTS_PREFIX + 'EXPERIMENTS_SELECTION_CHANGED';
-export const TOGGLE_COL_HIDDEN = EXPERIMENTS_PREFIX + 'TOGGLE_COL_HIDDEN';
+export const TOGGLE_COL_HIDDEN = EXPERIMENTS_PREFIX + 'TOGGLE_COL_HIDDEN';
export class GetExperiments implements Action {
readonly type = GET_EXPERIMENTS;
@@ -73,7 +74,7 @@ export class SetExperiments implements Action {
export const setExperimentInPlace = createAction(
EXPERIMENTS_PREFIX + '[set experiment in place]',
- props<{experiments: ITableExperiment[]}>()
+ props<{ experiments: ITableExperiment[] }>()
);
export class SetNoMoreExperiments implements Action {
@@ -136,17 +137,30 @@ export class ToggleColHidden implements Action {
export const setHiddenColumns = createAction(
EXPERIMENTS_PREFIX + 'SET_HIDDEN_COLS',
- props<{visibleColumns: string[]}>()
+ props<{ visibleColumns: string[] }>()
);
export const setUsers = createAction(
EXPERIMENTS_PREFIX + 'SET_USERS',
- props<{users: User[]}>()
+ props<{ users: User[] }>()
);
+
+
export const getUsers = createAction(
EXPERIMENTS_PREFIX + 'GET_USERS');
+export const getFilteredUsers = createAction(
+ EXPERIMENTS_PREFIX + 'GET_FILTERED_USERS');
+
+export const getTags = createAction(
+ EXPERIMENTS_PREFIX + 'GET_TAGS');
+
+export const setTags = createAction(
+ EXPERIMENTS_PREFIX + 'SET_TAGS',
+ props<{ tags: string[] }>()
+);
+
export class TableSortChanged implements Action {
public type = TABLE_SORT_CHANGED;
public payload: { colId: string; sortOrder: (TableSortOrderEnum) };
@@ -159,17 +173,18 @@ export class TableSortChanged implements Action {
export class TableFilterChanged implements Action {
public type = TABLE_FILTER_CHANGED;
- constructor(public payload: TableFilter) {}
+ constructor(public payload: TableFilter) {
+ }
}
export const setTableFilters = createAction(
SET_TABLE_FILTERS,
- props<{filters: TableFilter[]}>()
+ props<{ filters: TableFilter[] }>()
);
export const setProjectsTypes = createAction(
SET_PROJECT_TYPES,
- props<{ types?: Array}>()
+ props<{ types?: Array }>()
);
export const getProjectTypes = createAction(
@@ -210,14 +225,14 @@ export class ArchivedModeChanged implements Action {
export class ArchivedSelectedExperiments implements Action {
public type = ARCHIVE_SELECTED_EXPERIMENTS;
- constructor(public payload: { projectId: string }) {
+ constructor(public payload: { skipUndo?: boolean }) {
}
}
export class RestoreSelectedExperiments implements Action {
public type = RESTORE_SELECTED_EXPERIMENTS;
- constructor(public payload: { projectId: string }) {
+ constructor(public payload: { skipUndo?: boolean }) {
}
}
@@ -237,16 +252,16 @@ export class ResetExperiments implements Action {
}
}
-export const GET_CUSTOM_METRICS = EXPERIMENTS_PREFIX + 'GET_CUSTOM_METRICS';
+export const GET_CUSTOM_METRICS = EXPERIMENTS_PREFIX + 'GET_CUSTOM_METRICS';
export const GET_CUSTOM_HYPER_PARAMS = EXPERIMENTS_PREFIX + 'GET_CUSTOM_HYPER_PARAMS';
-export const SET_CUSTOM_METRICS = EXPERIMENTS_PREFIX + 'SET_CUSTOM_METRICS';
+export const SET_CUSTOM_METRICS = EXPERIMENTS_PREFIX + 'SET_CUSTOM_METRICS';
export const SET_CUSTOM_HYPER_PARAMS = EXPERIMENTS_PREFIX + 'SET_CUSTOM_HYPER_PARAMS';
-export const ADD_COL = EXPERIMENTS_PREFIX + 'ADD_COL';
-export const REMOVE_COL = EXPERIMENTS_PREFIX + 'REMOVE_COL';
+export const ADD_COL = EXPERIMENTS_PREFIX + 'ADD_COL';
+export const REMOVE_COL = EXPERIMENTS_PREFIX + 'REMOVE_COL';
export const SET_COLS_ORDER = EXPERIMENTS_PREFIX + 'SET_COLS_ORDER';
export const CHANGE_COLS_ORDER = EXPERIMENTS_PREFIX + 'CHANGE_COLS_ORDER';
export const CLEAR_HYPER_PARAMS_COLS = EXPERIMENTS_PREFIX + 'CLEAR_COLS';
-export const RESET_SORT_ORDER = EXPERIMENTS_PREFIX + 'RESET_SORT_ORDER';
+export const RESET_SORT_ORDER = EXPERIMENTS_PREFIX + 'RESET_SORT_ORDER';
export class GetCustomMetrics implements Action {
readonly type = GET_CUSTOM_METRICS;
@@ -276,7 +291,7 @@ export class SetCustomHyperParams implements Action {
export const setExtraColumns = createAction(
EXPERIMENTS_PREFIX + 'SET_EXTRA_COLUMNS',
- props<{columns: any[]}>()
+ props<{ columns: any[] }>()
);
export class AddCol implements Action {
@@ -290,22 +305,24 @@ export class AddCol implements Action {
export class RemoveCol implements Action {
public type = REMOVE_COL;
- public payload: { col: {id: string; projectId: string} };
+ public payload: { col: { id: string; projectId: string } };
- constructor(col: {id: string; projectId: string}) {
+ constructor(col: { id: string; projectId: string }) {
this.payload = {col};
}
}
+
export const changeColsOrder = createAction(
EXPERIMENTS_PREFIX + 'CHANGE_COLS_ORDER',
- props<{cols: string[]}>()
+ props<{ cols: string[] }>()
);
export const setColsOrderForProject = createAction(
EXPERIMENTS_PREFIX + 'SET_COLS_ORDER',
- props<{cols: string[]; project: string}>()
+ props<{ cols: string[]; project: string }>()
);
+
export class ClearHyperParamsCols implements Action {
public type = CLEAR_HYPER_PARAMS_COLS;
public payload: { projectId };
@@ -321,10 +338,10 @@ export class ResetSortOrder implements Action {
export const setArchive = createAction(
EXPERIMENTS_PREFIX + 'SET_ARCHIVE',
- props<{archive: boolean}>()
+ props<{ archive: boolean }>()
);
export const afterSetArchive = createAction(EXPERIMENTS_PREFIX + 'AFTER_SET_ARCHIVE');
-export const setSplitSize = createAction( EXPERIMENTS_PREFIX + 'SET_SPLIT_SIZE', props<{splitSize: number}>()
+export const setSplitSize = createAction(EXPERIMENTS_PREFIX + 'SET_SPLIT_SIZE', props<{ splitSize: number }>()
);
diff --git a/src/app/webapp-common/experiments/common-experiments.component.html b/src/app/webapp-common/experiments/common-experiments.component.html
index 6b5ed575..84c0afa1 100644
--- a/src/app/webapp-common/experiments/common-experiments.component.html
+++ b/src/app/webapp-common/experiments/common-experiments.component.html
@@ -17,8 +17,8 @@
(setAutoRefresh)="setAutoRefresh($event)"
(clearSelection)="clearSelection()"
>
- 1) || (showAllSelectedIsActive$ |async)">
-
+ 1) || (showAllSelectedIsActive$ |async)">
+
- 1) || (showAllSelectedIsActive$ |async)"
- [numberOfSelectedExperiments]="(selectedExperiments$ | async)?.length"
- [disableArchive]="(selectedExperiments$ | async) | hasExampleItem"
- [archiveToolTipMessage]="((selectedExperiments$ | async) | hasExampleItem)?'Archiving is disabled as one or more of the experiments you chose are example experiments':null"
+ 1 || (showAllSelectedIsActive$ |async)"
+ [numberOfSelectedEntities]="(selectedExperiments$ | async)?.length"
[showAllSelectedIsActive]="showAllSelectedIsActive$ |async"
[isArchivedMode]="isArchived$ | async"
- (restoreExperimentsClicked)="restoreExperiments()"
- (compareExperimentsClicked)="compareExperiments()"
- (archiveExperimentsClicked)="archiveExperiments()"
+ (compareEntitiesClicked)="compareExperiments()"
(showAllSelectedClicked)="showAllSelected($event)"
->
+ (archiveEntitiesClicked)="archiveExperiments()"
+ (restoreEntitiesClicked)="restoreExperiments()"
+>
diff --git a/src/app/webapp-common/experiments/common-experiments.component.scss b/src/app/webapp-common/experiments/common-experiments.component.scss
index 38e30cbb..82d9b8d7 100644
--- a/src/app/webapp-common/experiments/common-experiments.component.scss
+++ b/src/app/webapp-common/experiments/common-experiments.component.scss
@@ -1,11 +1,11 @@
-@import "./../../webapp-common/shared/ui-components/styles/variables";
-@import "./../../webapp-common/layout/layout.scss";
+@import "./../shared/ui-components/styles/variables";
+@import "./../layout/layout.scss";
:host {
.experiment-body {
width: 100%;
height: calc(100% - #{$project-header-height});
- &.compare {
+ &.footer-visible {
height: calc(100% - #{$project-header-height + $project-footer-height});
}
}
diff --git a/src/app/webapp-common/experiments/common-experiments.component.ts b/src/app/webapp-common/experiments/common-experiments.component.ts
index a034ddfb..b4cc75c1 100644
--- a/src/app/webapp-common/experiments/common-experiments.component.ts
+++ b/src/app/webapp-common/experiments/common-experiments.component.ts
@@ -1,12 +1,12 @@
import {ChangeDetectionStrategy, Component, OnDestroy, OnInit} from '@angular/core';
-import {selectExperimentsHiddenTableCols, selectExperimentsList, selectExperimentsMetricsCols, selectExperimentsTableCols, selectExperimentsTableColsOrder, selectGlobalFilter, selectHyperParamsVariants, selectIsExperimentInEditMode, selectNoMoreExperiments, selectSelectedExperiments, selectSelectedTableExperiment, selectShowAllSelectedIsActive, selectTableFilters, selectTableSortField, selectTableSortOrder, selectExperimentsUsers, selectExperimentsTypes} from './reducers/index';
+import {selectExperimentsHiddenTableCols, selectExperimentsList, selectExperimentsMetricsCols, selectExperimentsTableCols, selectExperimentsTableColsOrder, selectGlobalFilter, selectHyperParamsVariants, selectIsExperimentInEditMode, selectNoMoreExperiments, selectSelectedExperiments, selectSelectedTableExperiment, selectShowAllSelectedIsActive, selectTableFilters, selectTableSortField, selectTableSortOrder, selectExperimentsUsers, selectExperimentsTypes, selectExperimentsTags} from './reducers/index';
import {selectIsArchivedMode, selectProjectSystemTags, selectProjectTags} from '../core/reducers/projects.reducer';
import {select, Store} from '@ngrx/store';
import {ColHeaderTypeEnum, ISmCol, TableSortOrderEnum} from '../shared/ui-components/data/table/table.consts';
import {ActivatedRoute, Params, Router} from '@angular/router';
import {get, isEqual} from 'lodash/fp';
import {selectRouterParams} from '../core/reducers/router-reducer';
-import {filter, map, skip, tap, withLatestFrom} from 'rxjs/operators';
+import {filter, map, skip, tap, withLatestFrom, distinctUntilChanged} from 'rxjs/operators';
import {MatDialog, MatDialogRef} from '@angular/material/dialog';
import {combineLatest, Observable, Subscription} from 'rxjs';
import {ConfirmDialogComponent} from '../shared/ui-components/overlay/confirm-dialog/confirm-dialog.component';
@@ -29,6 +29,7 @@ import {getTags, ResetProjectSelection} from '../core/actions/projects.actions';
import {decodeColumns, decodeFilter, decodeOrder, MetricColumn} from '../shared/utils/tableParamEncode';
import {BaseEntityPage} from '../shared/entity-page/base-entity-page';
import {User} from '../../business-logic/model/users/user';
+import {groupHyperParams} from '../shared/utils/shared-utils';
@Component({
selector : 'sm-common-experiments',
@@ -53,7 +54,7 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
public filteredTableCols$: Observable;
public tableCols$: Observable;
public metricVariants$: Observable;
- public hyperParams$: Observable;
+ public hyperParams$: Observable;
private hiddenTableCols$: Observable;
private metricTableCols$: Observable;
private searchSubs: Subscription;
@@ -81,7 +82,7 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
constructor(
protected store: Store, private route: ActivatedRoute,
- private router: Router, private dialog: MatDialog, private syncSelector: SmSyncStateSelectorService
+ private router: Router, private dialog: MatDialog
) {
super(store);
this.tableSortField$ = this.store.select(selectTableSortField).pipe(tap(field => this.sortField = field));
@@ -100,7 +101,7 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
this.isExperimentInEditMode$ = this.store.select(selectIsExperimentInEditMode);
this.users$ = this.store.select(selectExperimentsUsers);
this.types$ = this.store.select(selectExperimentsTypes);
- this.tags$ = this.store.select(selectProjectTags);
+ this.tags$ = this.store.select(selectExperimentsTags);
this.systemTags$ = this.store.select(selectProjectSystemTags);
@@ -112,12 +113,14 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
this.columns$ = this.store.select(selectExperimentsTableCols);
this.metricVariants$ = this.store.select(selectMetricVariants);
this.metricLoading$ = this.store.select(selectMetricsLoading);
- this.hyperParams$ = this.store.select(selectHyperParamsVariants);
+ this.hyperParams$ = this.store.select(selectHyperParamsVariants).pipe(
+ map(hyperParams => groupHyperParams(hyperParams))
+ );
this.experiments$ = this.store.select(selectExperimentsList).pipe(
withLatestFrom(this.isArchived$),
// lil hack for hiding archived task after they been archived from task info or footer...
map(([experiments, showArchived]) => this.filterArchivedExperiments(experiments, showArchived)),
- tap(_ => this.refreshing = false)
+ tap(() => this.refreshing = false)
);
this.showInfo$ = this.store.pipe(
select(selectRouterParams),
@@ -137,14 +140,14 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
.pipe(
map(([tableCols, hiddenCols, metricCols]) =>
tableCols.concat(metricCols.map(col => ({...col, metric: true})))
- .map(col => ({...col, hidden: hiddenCols[col.id] || null}))),
- filter(col => col.id !== EXPERIMENTS_TABLE_COL_FIELDS.PROJECT || this.selectedProject == '*')
+ .map(col => ({...col, hidden: hiddenCols[col.id] || null}))
+ .filter(col => col.id !== EXPERIMENTS_TABLE_COL_FIELDS.PROJECT || this.selectedProject == '*'))
); // Only show project col on "all projects"
this.tableCols$ = this.filteredTableCols$.pipe(map(cols => cols.filter(col => !col.hidden)));
let prevQueryParams: Params;
- this.selectedProjectSubs = combineLatest( [
+ this.selectedProjectSubs = combineLatest([
this.store.select(selectRouterParams),
this.route.queryParams
]).pipe(
@@ -188,6 +191,7 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
}
this.dispatchAndLock(new experimentsActions.GetExperiments());
this.store.dispatch(experimentsActions.getUsers());
+ this.store.dispatch(experimentsActions.getTags());
this.store.dispatch(getTags());
this.store.dispatch(getProjectTypes());
});
@@ -220,12 +224,13 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
}
selectExperimentFromUrl() {
- this.ExperimentFromUrlSub = combineLatest(
+ this.ExperimentFromUrlSub = combineLatest([
this.store.select(selectRouterParams)
.pipe(map(params => get('experimentId', params))),
this.experiments$
- ).pipe(
- map(([experimentId, experiments]) => experiments.find(experiment => experiment.id === experimentId))
+ ]).pipe(
+ map(([experimentId, experiments]) => experiments.find(experiment => experiment.id === experimentId)),
+ distinctUntilChanged()
).subscribe((selectedExperiment) => {
this.store.dispatch(new experimentsActions.SetSelectedExperiment(selectedExperiment));
});
@@ -237,9 +242,9 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
filterArchivedExperiments(experiments, showArchived) {
if (showArchived) {
- return experiments.filter(ex => ex.system_tags && ex.system_tags.includes('archived'));
+ return experiments.filter(ex => ex?.system_tags?.includes('archived'));
} else {
- return experiments.filter(ex => !ex.system_tags || !(ex.system_tags.includes('archived')));
+ return experiments.filter(ex => !(ex?.system_tags?.includes('archived')));
}
}
@@ -269,11 +274,11 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
}
archiveExperiments() {
- this.store.dispatch(new experimentsActions.ArchivedSelectedExperiments({projectId: this.projectId}));
+ this.store.dispatch(new experimentsActions.ArchivedSelectedExperiments({}));
}
restoreExperiments() {
- this.store.dispatch(new experimentsActions.RestoreSelectedExperiments({projectId: this.projectId}));
+ this.store.dispatch(new experimentsActions.RestoreSelectedExperiments({}));
}
onSearchValueChanged(value: string) {
@@ -363,7 +368,7 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
createParamColumn(param: string) {
return {
- id : `execution.parameters.${param}`,
+ id : `hyperparams.${param}`,
headerType : ColHeaderTypeEnum.sort,
sortable : true,
filterable: false,
@@ -406,8 +411,12 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
}
closeExperimentPanel() {
- const params = this.syncSelector.selectSync(selectRouterParams);
- this.router.navigate([`projects/${params.projectId}/experiments`], {queryParamsHandling: 'merge'});
+ this.router.navigate([`projects/${this.projectId}/experiments`], {queryParamsHandling: 'merge'});
+ window.setTimeout(() => this.infoDisabled = false);
+ }
+
+ clickOnSplit() {
+ this.infoDisabled = false;
}
setAutoRefresh($event: boolean) {
@@ -423,7 +432,7 @@ export class CommonExperimentsComponent extends BaseEntityPage implements OnInit
}
refreshTagsList() {
- this.store.dispatch(getTags());
+ this.store.dispatch(experimentsActions.getTags());
}
refreshTypesList() {
diff --git a/src/app/webapp-common/experiments/common-experiments.module.ts b/src/app/webapp-common/experiments/common-experiments.module.ts
index 8fedea79..b643fa9e 100644
--- a/src/app/webapp-common/experiments/common-experiments.module.ts
+++ b/src/app/webapp-common/experiments/common-experiments.module.ts
@@ -10,13 +10,12 @@ import {CommonExperimentsMenuEffects} from './effects/common-experiments-menu.ef
import {ExperimentHeaderComponent} from './dumb/experiment-header/experiment-header.component';
import {ExperimentInfoHeaderComponent} from './dumb/experiment-info-header/experiment-info-header.component';
import {ExperimentsTableComponent} from './dumb/experiments-table/experiments-table.component';
-import {ExperimentFooterComponent} from './dumb/experiment-footer/experiment-footer.component';
import {ExperimentOutputComponent} from './containers/experiment-ouptut/experiment-output.component';
import {ExperimentOutputLogComponent} from './containers/experiment-output-log/experiment-output-log.component';
import {ExperimentLogInfoComponent} from './dumb/experiment-log-info/experiment-log-info.component';
import {ExperimentInfoGeneralComponent} from './containers/experiment-info-general/experiment-info-general.component';
import {ExperimentGeneralInfoComponent} from './dumb/experiment-general-info/experiment-general-info.component';
-import {ExperimentModelsFormComponent} from './dumb/experiment-models-form/experiment-models-form.component';
+import {ExperimentInputModelFormComponent} from './dumb/experiment-input-model-form/experiment-input-model-form.component';
import {ExperimentNetworkDesignFormComponent} from './dumb/experiment-network-design-form/experiment-network-design-form.component';
import {ExperimentModelsFormViewComponent} from './dumb/experiment-models-form-view/experiment-models-form-view.component';
import {ExperimentExecutionFormComponent} from './dumb/experiment-execution-form/experiment-execution-form.component';
@@ -41,11 +40,10 @@ import {ExperimentCompareSharedModule} from '../experiments-compare/shared/exper
import {ExperimentCustomColsMenuComponent} from './dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component';
import {SelectMetricForCustomColComponent} from './dumb/select-metric-for-custom-col/select-metric-for-custom-col.component';
import {ExperimentInfoHyperParametersComponent} from './containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component';
-import {ExperimentHyperParamsFormComponent} from './dumb/experiment-hyper-params-form/experiment-hyper-params-form.component';
import {ExperimentExecutionDiffComponent} from './dumb/experiment-execution-diff/experiment-execution-diff.component';
import {ExperimentExecutionRequirementsComponent} from './dumb/experiment-execution-requirements/experiment-execution-requirements.component';
import {SelectHyperParamsForCustomColComponent} from './dumb/select-hyper-params-for-custom-col/select-hyper-params-for-custom-col.component';
-import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
+import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
import {ExperimentArtifactsNavbarComponent} from './dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component';
import {ExperimentOutputModelViewComponent} from './dumb/experiment-output-model-view/experiment-output-model-view.component';
import {ExperimentInfoArtifactsComponent} from './containers/experiment-info-aritfacts/experiment-info-artifacts.component';
@@ -54,11 +52,16 @@ import {ExperimentInfoOutputModelComponent} from './containers/experiment-info-o
import {ExperimentInfoArtifactItemComponent} from './containers/experiment-info-artifact-item/experiment-info-artifact-item.component';
import {ExperimentArtifactItemViewComponent} from './dumb/experiment-artifact-item-view/experiment-artifact-item-view.component';
import {ExperimentInfoInputModelComponent} from './containers/experiment-info-input-model/experiment-info-input-model.component';
-import { ExperimentOrchestrationFormComponent } from './dumb/experiment-orchestration-form/experiment-orchestration-form.component';
+import {ExperimentOrchestrationFormComponent} from './dumb/experiment-orchestration-form/experiment-orchestration-form.component';
import {ScrollingModule} from '@angular/cdk/scrolling';
import {BaseClickableArtifact} from './dumb/base-clickable-artifact';
import {BaseExperimentMenuComponent} from './shared/components/base-experiment-menu';
import {NoUnderscorePipe} from '../shared/pipes/no-underscore.pipe';
+import {ExperimentHyperParamsNavbarComponent} from './dumb/experiment-hyper-params-navbar/experiment-hyper-params-navbar.component';
+import {ExperimentInfoTaskModelComponent} from './containers/experiment-info-task-model/experiment-info-task-model.component';
+import {ExperimentInfoHyperParametersFormContainerComponent} from './containers/experiment-info-hyper-parameters-form-container/experiment-info-hyper-parameters-form-container.component';
+import {ExperimentTaskModelFormComponent} from './dumb/experiment-task-model-form/experiment-task-model-form.component';
+import {SharedModule} from '../../shared/shared.module';
@NgModule({
declarations : [
@@ -71,13 +74,14 @@ import {NoUnderscorePipe} from '../shared/pipes/no-underscore.pipe';
ExperimentInfoHeaderComponent,
ExperimentsTableComponent,
ExperimentInfoInputModelComponent,
- ExperimentFooterComponent,
+ ExperimentInfoTaskModelComponent,
ExperimentOutputComponent,
ExperimentOutputLogComponent,
ExperimentLogInfoComponent,
ExperimentInfoGeneralComponent,
ExperimentGeneralInfoComponent,
- ExperimentModelsFormComponent,
+ ExperimentInputModelFormComponent,
+ ExperimentTaskModelFormComponent,
ExperimentNetworkDesignFormComponent,
ExperimentModelsFormViewComponent,
ExperimentOutputModelViewComponent,
@@ -91,11 +95,12 @@ import {NoUnderscorePipe} from '../shared/pipes/no-underscore.pipe';
ExperimentCustomColsMenuComponent,
ExperimentTableCardComponent,
ExperimentInfoHyperParametersComponent,
- ExperimentHyperParamsFormComponent,
+ ExperimentInfoHyperParametersFormContainerComponent,
ExperimentExecutionDiffComponent,
ExperimentExecutionRequirementsComponent,
ExperimentArtifactsNavbarComponent,
ExperimentInfoArtifactsComponent,
+ ExperimentHyperParamsNavbarComponent,
ExperimentOutputModelFormComponent,
ExperimentInfoOutputModelComponent,
ExperimentInfoArtifactItemComponent,
@@ -104,24 +109,25 @@ import {NoUnderscorePipe} from '../shared/pipes/no-underscore.pipe';
BaseExperimentMenuComponent
],
exports : [ExperimentTypeIconLabelComponent, CommonExperimentsComponent, ExperimentInfoHeaderComponent, ExperimentExecutionFormComponent],
- imports : [
- AngularSplitModule.forRoot(),
- ScrollingModule,
- ExperimentGraphsModule,
- SMMaterialModule,
- FormsModule,
- ReactiveFormsModule,
- ExperimentCompareSharedModule,
- CommonExperimentSharedModule,
- CommonLayoutModule,
- ExperimentSharedModule,
- SMSharedModule,
- SharedPipesModule,
- RouterModule,
- CommonModule,
- EffectsModule.forFeature([CommonExperimentsViewEffects, CommonExperimentsInfoEffects, CommonExperimentOutputEffects, CommonExperimentsMenuEffects]),
- MatProgressSpinnerModule,
- ],
+ imports: [
+ AngularSplitModule.forRoot(),
+ ScrollingModule,
+ ExperimentGraphsModule,
+ SMMaterialModule,
+ FormsModule,
+ ReactiveFormsModule,
+ ExperimentCompareSharedModule,
+ CommonExperimentSharedModule,
+ CommonLayoutModule,
+ ExperimentSharedModule,
+ SMSharedModule,
+ SharedPipesModule,
+ RouterModule,
+ CommonModule,
+ EffectsModule.forFeature([CommonExperimentsViewEffects, CommonExperimentsInfoEffects, CommonExperimentOutputEffects, CommonExperimentsMenuEffects]),
+ MatProgressSpinnerModule,
+ SharedModule,
+ ],
providers : [ExperimentTableCardComponent, NoUnderscorePipe, TitleCasePipe]
})
export class ExperimentsCommonModule {
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-aritfacts.component.scss b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-aritfacts.component.scss
index 09bb546d..783d3b78 100644
--- a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-aritfacts.component.scss
+++ b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-aritfacts.component.scss
@@ -1,8 +1,30 @@
+@import "../../../shared/ui-components/styles/variables";
+@import "../../../../webapp-common/layout/layout.scss";
+
:host {
display: block;
position: relative;
height: 100%;
+ .no-data{
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ width: 100%;
+ .i-no-data-artifacts{
+ width: 200px;
+ height: 160px;
+ }
+ span{
+ font-size: 20px;
+ font-weight: bold;
+ line-height: 1.45;
+ color: $cloudy-blue-two;
+ }
+ }
+
.col-6 {
padding: 0;
}
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.html b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.html
index 45bf0546..72b23ba1 100644
--- a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.html
+++ b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.html
@@ -1,14 +1,37 @@
-
-
-
-
-
+
+
+ 0) ||
+ editable; else noData">
+
+
+
+
-
+
+
+
+
+ NO ARTIFACTS RECORDED
+
+
+
+
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.ts b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.ts
index 2f265f60..cbdfccaa 100644
--- a/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.ts
+++ b/src/app/webapp-common/experiments/containers/experiment-info-aritfacts/experiment-info-artifacts.component.ts
@@ -4,7 +4,7 @@ import {selectBackdropActive} from '../../../core/reducers/view-reducer';
import {combineLatest, Observable, Subscription} from 'rxjs';
import {IExperimentInfoState} from '../../../../features/experiments/reducers/experiment-info.reducer';
import {selectExperimentModelInfoData} from '../../reducers';
-import {selectExperimentInfoData} from '../../../../features/experiments/reducers';
+import {selectExperimentInfoData, selectIsExperimentEditable} from '../../../../features/experiments/reducers';
import {IExperimentInfo} from '../../../../features/experiments/shared/experiment-info.model';
import {selectRouterConfig, selectRouterParams} from '../../../core/reducers/router-reducer';
import {map} from 'rxjs/operators';
@@ -29,10 +29,12 @@ export class ExperimentInfoArtifactsComponent implements OnDestroy {
private onOutputModel$: Observable
;
private experimentKey$: Observable;
public routerConfig$: Observable;
+ public editable$: Observable;
constructor(private store: Store, public router: Router, private route: ActivatedRoute
) {
this.backdropActive$ = this.store.select(selectBackdropActive);
+ this.editable$ = this.store.select(selectIsExperimentEditable);
this.modelInfo$ = this.store.select(selectExperimentModelInfoData);
this.ExperimentInfo$ = this.store.select(selectExperimentInfoData);
this.routerConfig$ = this.store.select(selectRouterConfig);
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.html b/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.html
index 2180256e..a824bf12 100644
--- a/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.html
+++ b/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.html
@@ -1,13 +1,14 @@
-
+
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.scss b/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.scss
index 62e20bc7..122d870b 100644
--- a/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.scss
+++ b/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.scss
@@ -1,4 +1,32 @@
:host {
display: block;
position: relative;
+ height: 100%;
+
+ .col-6 {
+ padding: 0;
+ }
+
+ .hyper-col {
+ overflow: auto;
+ height: 100%;
+ padding: 0;
+ }
+
+ /deep/ sm-labeled-row {
+ border-bottom: none !important;
+ }
+
+ /deep/ hr {
+ margin: 0 26px;
+ }
+
+ /deep/ sm-textarea-control textarea{
+ font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ }
+
+ sm-experiment-hyper-params-navbar {
+ border-right: 1px solid #dee1e9;
+ }
+
}
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.ts b/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.ts
index 58be1821..99a25a06 100644
--- a/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.ts
+++ b/src/app/webapp-common/experiments/containers/experiment-info-hyper-parameters/experiment-info-hyper-parameters.component.ts
@@ -1,73 +1,84 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Store} from '@ngrx/store';
-import {selectExperimentHyperParamsInfoData, selectIsExperimentSaving, selectIsSelectedExperimentInDev} from '../../reducers';
+import {selectExperimentConfiguration, selectExperimentHyperParamsInfoData, selectExperimentHyperParamsSelectedSectionFromRoute, selectExperimentSelectedConfigObjectFromRoute, selectIsExperimentSaving, selectIsSelectedExperimentInDev} from '../../reducers';
import {ICommonExperimentInfoState} from '../../reducers/common-experiment-info.reducer';
import * as infoActions from '../../../../features/experiments/actions/experiments-info.actions';
import {ExperimentDataUpdated, SetExperimentFormErrors} from '../../../../features/experiments/actions/experiments-info.actions';
import {ISelectedExperiment} from '../../../../features/experiments/shared/experiment-info.model';
import {selectBackdropActive} from '../../../core/reducers/view-reducer';
-import {Observable, Subscription} from 'rxjs';
+import {combineLatest, merge, Observable, Subscription} from 'rxjs';
import {IHyperParamsForm} from '../../shared/experiment-hyper-params.model';
import {selectIsExperimentEditable, selectSelectedExperiment} from '../../../../features/experiments/reducers';
import {cloneDeep} from 'lodash/fp';
+import {selectRouterConfig, selectRouterParams} from '../../../core/reducers/router-reducer';
+import {Params, Router} from '@angular/router';
+import {ParamsItem} from '../../../../business-logic/model/tasks/paramsItem';
+import {filter, tap, withLatestFrom} from 'rxjs/operators';
+import {getExperimentConfigurationNames, getExperimentConfigurationObj} from '../../actions/common-experiments-info.actions';
@Component({
- selector : 'sm-experiment-info-hyper-parameters',
+ selector: 'sm-experiment-info-hyper-parameters',
templateUrl: './experiment-info-hyper-parameters.component.html',
- styleUrls : ['./experiment-info-hyper-parameters.component.scss']
+ styleUrls: ['./experiment-info-hyper-parameters.component.scss']
})
export class ExperimentInfoHyperParametersComponent implements OnInit, OnDestroy {
- public hyperParamsInfo$: Observable;
- // public errors$: Observable;
- public selectedExperimentSbscrition: Subscription;
- private selectedExperiment: ISelectedExperiment;
+ public selectedExperiment: ISelectedExperiment;
public editable$: Observable;
public isInDev$: Observable;
public saving$: Observable;
public backdropActive$: Observable;
- private selectedExperimentSubscrition: Subscription;
+ private selectedExperimentSubscription: Subscription;
+ public routerConfig$: Observable;
+ public routerParams$: Observable;
+ public hyperParamsInfo$: Observable<{ [p: string]: { [p: string]: ParamsItem } }>;
+ public configuration$: Observable;
+ private hyperParamsConfigSubscription: Subscription;
- constructor(private store: Store) {
+ constructor(private store: Store, protected router: Router) {
this.hyperParamsInfo$ = this.store.select(selectExperimentHyperParamsInfoData);
- this.editable$ = this.store.select(selectIsExperimentEditable);
- this.isInDev$ = this.store.select(selectIsSelectedExperimentInDev);
- this.saving$ = this.store.select(selectIsExperimentSaving);
- this.backdropActive$ = this.store.select(selectBackdropActive);
+ this.configuration$ = this.store.select(selectExperimentConfiguration);
+ this.editable$ = this.store.select(selectIsExperimentEditable);
+ this.isInDev$ = this.store.select(selectIsSelectedExperimentInDev);
+ this.saving$ = this.store.select(selectIsExperimentSaving);
+ this.backdropActive$ = this.store.select(selectBackdropActive);
+ this.routerConfig$ = this.store.select(selectRouterConfig);
+ this.routerParams$ = this.store.select(selectRouterParams);
}
ngOnInit() {
- this.selectedExperimentSubscrition = this.store.select(selectSelectedExperiment)
+ this.selectedExperimentSubscription = this.store.select(selectSelectedExperiment)
+ .pipe(
+ tap((selectedExperiment) => this.selectedExperiment = selectedExperiment),
+ filter((selectedExperiment) => selectedExperiment && !selectedExperiment.configuration)
+ )
.subscribe(selectedExperiment => {
- this.selectedExperiment = selectedExperiment;
+ this.store.dispatch(getExperimentConfigurationNames({experimentId: selectedExperiment.id}));
+ this.store.dispatch(getExperimentConfigurationObj());
});
+ this.hyperParamsConfigSubscription = combineLatest([this.hyperParamsInfo$, this.configuration$]).pipe(
+ withLatestFrom(
+ this.store.select(selectExperimentHyperParamsSelectedSectionFromRoute),
+ this.store.select(selectExperimentSelectedConfigObjectFromRoute)
+ )).subscribe(([[hyperparams, configuration], selectedHyperParam, selectedConfig]) => {
+ if ((hyperparams && configuration && !(selectedHyperParam in hyperparams) && !(selectedConfig in configuration))) {
+ if (selectedHyperParam) {
+ this.router.navigateByUrl(this.router.url.replace(selectedHyperParam, Object.keys(hyperparams)[0]));
+ } else if (selectedConfig) {
+ this.router.navigateByUrl(this.router.url.replace(`configuration/${selectedConfig}`, `hyper-param/${Object.keys(hyperparams)[0]}`));
+ }
+ }
+ });
this.store.dispatch(new SetExperimentFormErrors(null));
}
ngOnDestroy(): void {
- this.selectedExperimentSubscrition.unsubscribe();
- }
-
- onFormValuesChanged(event) {
- this.store.dispatch(new ExperimentDataUpdated({id: this.selectedExperiment.id, changes: {[event.field]: cloneDeep(event.value)}}));
- }
-
- saveHyperParametersData() {
- this.store.dispatch(new infoActions.SaveExperiment());
- this.store.dispatch(new infoActions.DeactivateEdit());
- }
-
- cancelHyperParametersChange() {
- this.store.dispatch(new infoActions.DeactivateEdit());
- this.store.dispatch(new infoActions.CancelExperimentEdit());
+ this.selectedExperimentSubscription.unsubscribe();
+ this.hyperParamsConfigSubscription.unsubscribe();
}
activateEditChanged(e) {
this.store.dispatch(new infoActions.ActivateEdit(e.sectionName));
}
- // onFormErrorsChanged($event) {
- //
- // }
-
}
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-input-model/experiment-info-input-model.component.html b/src/app/webapp-common/experiments/containers/experiment-info-input-model/experiment-info-input-model.component.html
index 1fef896d..895daa6b 100644
--- a/src/app/webapp-common/experiments/containers/experiment-info-input-model/experiment-info-input-model.component.html
+++ b/src/app/webapp-common/experiments/containers/experiment-info-input-model/experiment-info-input-model.component.html
@@ -1,4 +1,4 @@
-
-
+
diff --git a/src/app/webapp-common/experiments/containers/experiment-info-input-model/experiment-info-input-model.component.ts b/src/app/webapp-common/experiments/containers/experiment-info-input-model/experiment-info-input-model.component.ts
index 0f6dd0d5..40c90311 100644
--- a/src/app/webapp-common/experiments/containers/experiment-info-input-model/experiment-info-input-model.component.ts
+++ b/src/app/webapp-common/experiments/containers/experiment-info-input-model/experiment-info-input-model.component.ts
@@ -9,6 +9,8 @@ import {IExperimentInfoState} from '../../../../features/experiments/reducers/ex
import {experimentSectionsEnum} from '../../../../features/experiments/shared/experiments.const';
import {selectIsExperimentEditable, selectSelectedExperiment} from '../../../../features/experiments/reducers';
import * as infoActions from '../../../../features/experiments/actions/experiments-info.actions';
+import { ModelSelected } from '../../actions/common-experiments-info.actions';
+
@Component({
selector : 'sm-experiment-info-input-model',
@@ -18,12 +20,13 @@ import * as infoActions from '../../../../features/experiments/actions/experimen
export class ExperimentInfoInputModelComponent implements OnInit, OnDestroy {
public modelInfo$: Observable;
public selectedExperimentSubscription: Subscription;
- private selectedExperiment: ISelectedExperiment;
+ public selectedExperiment: ISelectedExperiment;
public editable$: Observable;
public errors$: Observable;
public userKnowledge$: Observable
diff --git a/src/app/webapp-common/experiments/containers/experiment-output-log/experiment-output-log.component.ts b/src/app/webapp-common/experiments/containers/experiment-output-log/experiment-output-log.component.ts
index ef865e33..7447445a 100644
--- a/src/app/webapp-common/experiments/containers/experiment-output-log/experiment-output-log.component.ts
+++ b/src/app/webapp-common/experiments/containers/experiment-output-log/experiment-output-log.component.ts
@@ -1,13 +1,16 @@
-import {Component, OnDestroy, OnInit, ChangeDetectorRef} from '@angular/core';
-import {select, Store} from '@ngrx/store';
-import {selectExperimentLog, selectIsExperimentInProgress, selectLogFilter} from '../../reducers';
+import {Component, OnDestroy, OnInit, ChangeDetectorRef, ViewChild} from '@angular/core';
+import {Store} from '@ngrx/store';
+import {selectExperimentBeginningOfLog, selectExperimentLog, selectLogFilter} from '../../reducers';
import {Observable, Subscription} from 'rxjs';
-import {distinctUntilChanged, filter, tap} from 'rxjs/operators';
+import {distinctUntilChanged, filter} from 'rxjs/operators';
+import {last} from 'lodash/fp';
import {HTTP} from '../../../../app.constants';
import {ISelectedExperiment} from '../../../../features/experiments/shared/experiment-info.model';
import {IExperimentInfoState} from '../../../../features/experiments/reducers/experiment-info.reducer';
import {selectSelectedExperiment} from '../../../../features/experiments/reducers';
-import {GetExperimentLog, ResetLogFilter, ResetOutput, SetLogFilter} from '../../actions/common-experiment-output.actions';
+import {ResetLogFilter, ResetOutput, SetLogFilter, getExperimentLog} from '../../actions/common-experiment-output.actions';
+import {ExperimentLogInfoComponent} from '../../dumb/experiment-log-info/experiment-log-info.component';
+import {selectRefreshing} from '../../../experiments-compare/reducers';
@Component({
selector: 'sm-experiment-output-log',
@@ -20,19 +23,21 @@ export class ExperimentOutputLogComponent implements OnInit, OnDestroy {
private experiment: ISelectedExperiment;
public API_BASE_URL = HTTP.API_BASE_URL;
- public log$: Observable>;
- public experiment$: Observable;
+ public log$: Observable;
+ public experiment$: Observable;
public filter$: Observable;
+ public logBeginning$: Observable;
public creator: string | Worker;
public disabled: boolean;
public hasLog: boolean;
- public selectIsExperimentPendingRunning: Observable;
public logSubscription: Subscription;
+ private refreshingSubscription: Subscription;
+ @ViewChild('log', {static: false}) private logRef: ExperimentLogInfoComponent;
- constructor(private store: Store,
- private cdr: ChangeDetectorRef) {
+ constructor(private store: Store, private cdr: ChangeDetectorRef) {
this.log$ = this.store.select(selectExperimentLog);
+ this.logBeginning$ = this.store.select(selectExperimentBeginningOfLog);
this.filter$ = this.store.select(selectLogFilter);
this.experiment$ = this.store.select(selectSelectedExperiment);
}
@@ -52,15 +57,30 @@ export class ExperimentOutputLogComponent implements OnInit, OnDestroy {
distinctUntilChanged()
)
.subscribe(experiment => {
- if (this.experiment && this.experiment.id !== experiment.id) {
+ if (this.experiment?.id !== experiment.id || this.experiment?.started !== experiment.started) {
this.store.dispatch(new ResetOutput());
+ this.logRef?.reset();
+ this.experiment = experiment;
+ this.store.dispatch(getExperimentLog({
+ id: this.experiment.id,
+ direction: null
+ }));
+ } else if (!this.logRef?.lines?.length || this.logRef?.canRefresh) {
+ this.store.dispatch(getExperimentLog({
+ id: this.experiment.id,
+ direction: !this.logRef?.orgLogs ? 'prev' : 'next',
+ from: last(this.logRef?.orgLogs)?.timestamp
+ }));
}
- this.experiment = experiment;
- this.store.dispatch(new GetExperimentLog(experiment.id));
});
- this.selectIsExperimentPendingRunning = this.store.pipe(
- select(selectIsExperimentInProgress)
- );
+
+ this.refreshingSubscription = this.store.select(selectRefreshing)
+ .pipe(filter(({refreshing}) => refreshing))
+ .subscribe(({autoRefresh}) => this.store.dispatch(getExperimentLog({
+ id: this.experiment.id,
+ direction: autoRefresh ? 'prev' : 'next',
+ from: last(this.logRef?.orgLogs)?.timestamp
+ })));
}
ngOnDestroy(): void {
@@ -70,11 +90,11 @@ export class ExperimentOutputLogComponent implements OnInit, OnDestroy {
this.store.dispatch(new ResetOutput());
}
- refreshExperimentLog() {
- this.store.dispatch(new GetExperimentLog(this.experiment.id));
+ public filterLog(event: KeyboardEvent) {
+ this.store.dispatch(new SetLogFilter((event.target as HTMLInputElement).value));
}
- public filterLog(event: KeyboardEvent) {
- this.store.dispatch(new SetLogFilter((event.target).value));
+ getLogs({direction, from}: {direction: string; from?: number}) {
+ this.store.dispatch(getExperimentLog({id: this.experiment.id, direction, from, refresh: !from}));
}
}
diff --git a/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.html b/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.html
index 62c10626..21bed719 100644
--- a/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.html
+++ b/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.html
@@ -24,6 +24,7 @@
[xAxisType]="(xAxisType$ | async)"
[showSettings]="showSettingsBar"
[splitSize]="splitSize$ | async"
+ [breakPoint]="900"
(changeWeight)="changeSmoothness($event)"
(resetGraphs)="resetMetrics()"
(toggleSettings)="toggleSettingsBar()"
diff --git a/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.scss b/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.scss
index c4ac807f..5115acca 100644
--- a/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.scss
+++ b/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.scss
@@ -6,7 +6,7 @@
.list-container {
display: block;
- height: calc(100vh - 209px);
+ height: 100%;
overflow-y: auto;
overflow-x: hidden;
diff --git a/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.ts b/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.ts
index 4550c07e..4622b8cf 100644
--- a/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.ts
+++ b/src/app/webapp-common/experiments/containers/experiment-output-scalars/experiment-output-scalars.component.ts
@@ -9,7 +9,7 @@ import {scrollToElement} from '../../../shared/utils/shared-utils';
import {ActivatedRoute, Router} from '@angular/router';
import {of} from 'rxjs';
import {IExperimentInfoState} from '../../../../features/experiments/reducers/experiment-info.reducer';
-import {ExperimentScalarRequested, GetExperimentLog, ResetExperimentMetrics, SetExperimentMetricsSearchTerm, SetExperimentSettings} from '../../actions/common-experiment-output.actions';
+import {ExperimentScalarRequested, ResetExperimentMetrics, SetExperimentMetricsSearchTerm, SetExperimentSettings} from '../../actions/common-experiment-output.actions';
import {ExperimentGraph} from '../../../tasks/tasks.model';
import {convertScalars, sortMetricsList} from '../../../tasks/tasks.utils';
import {ScalarKeyEnum} from '../../../../business-logic/model/events/scalarKeyEnum';
diff --git a/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.html b/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.html
index 41b19b87..c134198e 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.html
+++ b/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.html
@@ -1,29 +1,34 @@
-
-
- {{artifact?.uri}}
- {{artifact?.uri}}
-
-
-
-
{{artifact?.content_size ? (artifact?.content_size | filesize) : ''}}
-
{{artifact?.hash}}
-
{{data[1]}}
-
-
-
-
-
-
+
+
+
+ {{artifact?.uri}}
+ {{artifact?.uri}}
+
+
+
+
{{artifact?.content_size ? (artifact?.content_size | filesize) : ''}}
+
{{artifact?.hash}}
+
{{data[1]}}
+
+
+
+
+
+
+
+
diff --git a/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.scss b/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.scss
index 6f02dbc5..78c8b983 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.scss
+++ b/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.scss
@@ -1,17 +1,9 @@
:host {
- display: block;
- padding: 24px;
- .model-info-container {
- display: flex;
- flex-direction: column;
- height: calc(100% - 20px);
-
- sm-section-header {
- margin-top: 48px;
- }
-
- .preview {
- flex: 1;
- }
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ .editable-design {
+ flex: 1;
+ min-height: 300px;
}
}
diff --git a/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.ts b/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.ts
index eed04165..3aad37a5 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.ts
+++ b/src/app/webapp-common/experiments/dumb/experiment-artifact-item-view/experiment-artifact-item-view.component.ts
@@ -33,4 +33,13 @@ export class ExperimentArtifactItemViewComponent extends BaseClickableArtifact{
constructor(protected adminService: AdminService, protected store: Store) {
super(adminService, store);
}
+
+ linkClicked(event: Event) {
+ const signed = this.adminService.signUrlIfNeeded(this.artifact.uri, true);
+ const a = document.createElement('a');
+ a.href = signed || this.artifact.uri;
+ a.target = '_blank';
+ a.click();
+ event.preventDefault();
+ }
}
diff --git a/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.html b/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.html
index f7b8f736..986104ce 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.html
+++ b/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.html
@@ -1,10 +1,10 @@
-
+
MODELS
@@ -21,7 +21,7 @@
0">
-
+
DATA AUDIT
- {{artifact.key}}
+ {{artifact.key}}
0">
-
+
OTHER
- {{artifact.key}}
+ {{artifact.key}}
diff --git a/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.scss b/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.scss
index 803f7d96..f6ef0f59 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.scss
+++ b/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.scss
@@ -92,7 +92,7 @@
display: flex;
align-items: center;
- .icon {
+ .icon, .al-icon {
margin-right: 10px;
}
}
diff --git a/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.ts b/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.ts
index 3cf24ea8..6e22237e 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.ts
+++ b/src/app/webapp-common/experiments/dumb/experiment-artifacts-navbar/experiment-artifacts-navbar.component.ts
@@ -28,6 +28,8 @@ export class ExperimentArtifactsNavbarComponent {
@Input() selectedArtifactKey;
@Input() outputModel;
+ @Input() inputModel;
+ @Input() editable;
@Input() activeSection;
@Input() routerConfig: string[];
@Output() artifactSelected = new EventEmitter();
diff --git a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.html b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.html
index 620ae104..f4c54627 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.html
+++ b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.html
@@ -1,5 +1,5 @@
HYPER PARAMETERS
diff --git a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.ts b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.ts
index 329cdd7d..ce08dde7 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.ts
+++ b/src/app/webapp-common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component.ts
@@ -2,28 +2,38 @@ import {Component, EventEmitter, Input, Output} from '@angular/core';
import {CustomColumnMode} from '../../shared/common-experiments.const';
@Component({
- selector : 'sm-experiment-custom-cols-menu',
+ selector: 'sm-experiment-custom-cols-menu',
templateUrl: './experiment-custom-cols-menu.component.html',
- styleUrls : ['./experiment-custom-cols-menu.component.scss']
+ styleUrls: ['./experiment-custom-cols-menu.component.scss']
})
export class ExperimentCustomColsMenuComponent {
+ public hasHyperParams: boolean;
+ private _hyperParams: { [section: string]: any[] };
+
+ @Input() metricVariants;
@Input() customColumnMode: CustomColumnMode;
@Input() tableCols;
- @Input() metricVariants;
- @Input() hyperParams;
+
+ @Input() set hyperParams(hyperParams: { [section: string]: any[] }) {
+ this._hyperParams = hyperParams;
+ this.hasHyperParams = Object.values(hyperParams).some(section => Object.keys(section).length > 0);
+ }
+ get hyperParams() {
+ return this._hyperParams;
+ }
+
@Input() isLoading: boolean;
@Output() selectMetricActiveChanged = new EventEmitter();
- @Output() getMetricsToDisplay = new EventEmitter();
- @Output() removeColFromList = new EventEmitter();
- @Output() selectedTableColsChanged = new EventEmitter();
- @Output() selectedMetricToShow = new EventEmitter();
- @Output() selectedHyperParamToShow = new EventEmitter();
- @Output() addCustomColClicked = new EventEmitter();
- @Output() clearSelection = new EventEmitter();
+ @Output() getMetricsToDisplay = new EventEmitter();
+ @Output() removeColFromList = new EventEmitter();
+ @Output() selectedTableColsChanged = new EventEmitter();
+ @Output() selectedMetricToShow = new EventEmitter();
+ @Output() selectedHyperParamToShow = new EventEmitter();
+ @Output() addCustomColClicked = new EventEmitter();
+ @Output() clearSelection = new EventEmitter();
- public menuFooterHover;
public CustomColumnMode = CustomColumnMode;
}
diff --git a/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.html b/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.html
index 48b81746..f4ca33fd 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.html
+++ b/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.html
@@ -1,10 +1,9 @@
-
-
-No changes logged
+
+No changes logged
+
diff --git a/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.scss b/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.scss
index f1dbf577..75c1953d 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.scss
+++ b/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.scss
@@ -1,7 +1,20 @@
-sm-textarea-control {
- display: block;
- height: 180px;
- &.hidden {
- display: none;
+@import "../../../shared/ui-components/styles/variables";
+
+:host {
+ .diff-container {
+ background-color: $blue-600;
+ padding: 12px 0 12px 12px;
+ border-radius: 4px;
+
+ .viewport {
+ height: 250px;
+ color: $white;
+ overflow-x: scroll;
+
+ .line {
+ height: 19px;
+ white-space: pre;
+ }
+ }
}
}
diff --git a/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.ts b/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.ts
index 939b1f3b..1f6a1044 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.ts
+++ b/src/app/webapp-common/experiments/dumb/experiment-execution-diff/experiment-execution-diff.component.ts
@@ -10,34 +10,24 @@ import {TextareaControlComponent} from '../../../shared/ui-components/forms/text
templateUrl: './experiment-execution-diff.component.html',
styleUrls : ['./experiment-execution-diff.component.scss'],
})
-export class ExperimentExecutionDiffComponent implements IExperimentInfoFormComponent, OnInit, OnDestroy {
+export class ExperimentExecutionDiffComponent implements IExperimentInfoFormComponent {
+
+ lines: string[];
+ @Input() set formData(data: IExecutionForm['diff']) {
+ this.lines = data ? data.split('\n') : [];
+ }
- @Input() formData: IExecutionForm['diff'];
@Input() isInDev: boolean = false;
private _editable: boolean;
@Input() set editable(editable: boolean) {
this._editable = editable;
- window.setTimeout(() => this.diff.onResize());
}
get editable() {
return this._editable;
}
+ @Input() showSpinner: boolean;
@Output() freezeForm = new EventEmitter();
@Output() formDataChanged = new EventEmitter<{ field: string; value: any }>();
HELP_TEXTS = HELP_TEXTS;
- @ViewChild('diff', {static: true}) diff: TextareaControlComponent;
- private formChangesSubscription: Subscription;
-
- ngOnInit(): void {
- this.formChangesSubscription = this.diff.formDataChanged.subscribe(formValue => {
- if (this.editable) {
- this.formDataChanged.emit({field: 'diff', value: formValue.value});
- }
- });
- }
-
- ngOnDestroy(): void {
- this.formChangesSubscription.unsubscribe();
- }
}
diff --git a/src/app/webapp-common/experiments/dumb/experiment-execution-form/experiment-execution-form.component.html b/src/app/webapp-common/experiments/dumb/experiment-execution-form/experiment-execution-form.component.html
index ab6e9eef..fa71bae1 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-execution-form/experiment-execution-form.component.html
+++ b/src/app/webapp-common/experiments/dumb/experiment-execution-form/experiment-execution-form.component.html
@@ -18,7 +18,8 @@
@@ -29,6 +30,7 @@
[editable]="editable && diffSection.inEditMode"
[isInDev]="isInDev"
[formData]="formData.diff"
+ [showSpinner]="showExtraDataSpinner"
(formDataChanged)="fieldValueChanged($event)"
(freezeForm)="freezeForm.emit($event)">
-
+
+
+ CLEAR
+
{
if (confirmed) {
- this.freezeForm.emit();
+ this.activateEdit.emit({editMode: true, sectionName: 'diff'});
this.fieldValueChanged({field: 'diff', value: ''});
this.saveFormData.emit();
}
@@ -98,4 +99,24 @@ export class ExperimentExecutionFormComponent extends ImmutableFormContainer imp
}
});
}
+
+ clearInstalledPackages() {
+ const confirmDialogRef: MatDialogRef = this.dialog.open(ConfirmDialogComponent, {
+ data: {
+ title: 'Clear installed packages',
+ body: 'Are you sure you want to clear the entire contents of Installed packages?',
+ yes: 'Clear',
+ no: 'Keep',
+ iconClass: 'al-icon al-ico-trash al-color blue-300',
+ }
+ });
+
+ confirmDialogRef.afterClosed().pipe(take(1)).subscribe((confirmed) => {
+ if (confirmed) {
+ this.activateEdit.emit({editMode: true, sectionName: 'requirements'});
+ this.fieldValueChanged({field: 'requirements', value: ''});
+ this.saveFormData.emit();
+ }
+ });
+ }
}
diff --git a/src/app/webapp-common/experiments/dumb/experiment-execution-output/experiment-execution-output.component.html b/src/app/webapp-common/experiments/dumb/experiment-execution-output/experiment-execution-output.component.html
index c8f741f7..bd010ba0 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-execution-output/experiment-execution-output.component.html
+++ b/src/app/webapp-common/experiments/dumb/experiment-execution-output/experiment-execution-output.component.html
@@ -2,7 +2,7 @@
@@ -10,7 +10,7 @@
diff --git a/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.html b/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.html
index e98090f6..39a0cf59 100644
--- a/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.html
+++ b/src/app/webapp-common/experiments/dumb/experiment-execution-parameters/experiment-execution-parameters.component.html
@@ -1,56 +1,70 @@
-