Added create pipeline step modal

This commit is contained in:
Shubham Takode 2024-02-15 01:27:39 +05:30
parent 4db6069900
commit c482eacf9a
18 changed files with 490 additions and 36 deletions

View File

@ -34,7 +34,7 @@ import { BASE_PATH, COLLECTION_FORMATS } from "../variables";
import { Configuration } from "../configuration";
import { PipelinesDeleteRunsRequest } from "~/business-logic/model/pipelines/pipelinesDeleteRunsRequest";
import { PipelinesDeleteRunsResponse } from "~/business-logic/model/pipelines/pipelinesDeleteRunsResponse";
import { PipelinesCreateRequest, PipelinesCreateResponse } from "../model/pipelines/models";
import { PipelinesCreateRequest, PipelinesCreateResponse, PipelinesCreateStepsRequest, PipelinesCreateStepsResponse } from "../model/pipelines/models";
@Injectable()
export class ApiPipelinesService {
@ -225,4 +225,60 @@ export class ApiPipelinesService {
}
);
}
/**
*
* Create a new pipeline step
* @param request request body
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public pipelinesCreateStep(
request: PipelinesCreateStepsRequest,
options?: any,
observe: any = "body",
reportProgress: boolean = false
): Observable<any> {
if (request === null || request === undefined) {
throw new Error(
"Required parameter request was null or undefined when calling pipelinesCreate."
);
}
let headers = this.defaultHeaders;
if (options && options.async_enable) {
headers = headers.set(this.configuration.asyncHeader, "1");
}
// to determine the Accept header
const httpHeaderAccepts: string[] = ["application/json"];
const httpHeaderAcceptSelected: string | undefined =
this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected != undefined) {
headers = headers.set("Accept", httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = [];
const httpContentTypeSelected: string | undefined =
this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected != undefined) {
headers = headers.set("Content-Type", httpContentTypeSelected);
}
return this.apiRequest.post<PipelinesCreateStepsResponse>(
`${this.basePath}/pipelines.create.step`,
request,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress,
}
);
}
}

View File

@ -2,4 +2,7 @@ export * from '././pipelinesStartPipelineRequest';
export * from '././pipelinesStartPipelineResponse';
export * from '././pipelinesCreateRequest';
export * from '././pipelinesCreateResponse';
export * from '././pipelinesCreateStepsRequest';
export * from '././pipelinesCreateStepsResponse';
export * from "././pipeline";

View File

@ -0,0 +1,14 @@
export interface PipelinesCreateStepsRequest {
/**
* Pipeline name. Unique within the company.
*/
name: string;
/**
* Free text comment
*/
description?: string;
experiment?: string;
parameters?: Array<object>
}

View File

@ -0,0 +1,7 @@
export interface PipelinesCreateStepsResponse {
/**
* Pipeline id
*/
id?: string;
}

View File

@ -39,7 +39,7 @@
<button class="btn btn-icon g-btn" smTooltip="Compile pipeline">
<i class="icon i-pipeline-compile lm"></i>
</button>
<button class="btn btn-icon g-btn" smTooltip="Add new step to pipeline">
<button class="btn btn-icon g-btn" smTooltip="Add new step to pipeline" (click)="addNewStep()">
<i class="icon i-pipeline-add-new-step lm"></i>
</button>
<button class="btn btn-icon g-btn" smTooltip="Run pipeline">

View File

@ -19,40 +19,25 @@ import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
export class EditPipelineHeaderComponent extends BaseEntityHeaderComponent implements OnInit{
private _tableCols: any;
toggleButtons: Option[];
@Input() isArchived: boolean;
@Input() metricVariants: Array<MetricVariantResult>;
@Input() hyperParams: any[];
@Input() minimizedView: boolean;
@Input() isMetricsLoading: boolean;
@Input() tableFilters: { [s: string]: FilterMetadata };
@Input() sharedView: boolean;
@Input() showNavbarLinks: boolean;
@Input() tableMode: 'table' | 'info' | 'compare';
@Input() compareView: 'scalars' | 'plots';
@Input() showCompareScalarSettings: boolean;
@Input() rippleEffect: boolean;
@Input() addButtonTemplate: TemplateRef<any>;
@Input() set tableCols(tableCols) {
this._tableCols = tableCols?.filter(col => col.header !== '');
}
get tableCols() {
return this._tableCols;
}
@Output() isArchivedChanged = new EventEmitter<boolean>();
@Output() selectedTableColsChanged = new EventEmitter<ISmCol>();
@Output() removeColFromList = new EventEmitter<ISmCol['id']>();
@Output() getMetricsToDisplay = new EventEmitter();
@Output() selectedMetricToShow = new EventEmitter<SelectionEvent>();
@Output() selectedHyperParamToShow = new EventEmitter<{param: string; addCol: boolean}>();
@Output() setAutoRefresh = new EventEmitter<boolean>();
@Output() toggleShowCompareSettings = new EventEmitter<boolean>();
@Output() compareViewChanged = new EventEmitter<'scalars' | 'plots'>();
@Output() clearSelection = new EventEmitter();
@Output() clearTableFilters = new EventEmitter<{ [s: string]: FilterMetadata }>();
@Output() tableModeChanged = new EventEmitter<'table' | 'info' | 'compare'>();
@Output() createPipelineStep = new EventEmitter();
// @Output() selectedTableColsChanged = new EventEmitter<ISmCol>();
// @Output() removeColFromList = new EventEmitter<ISmCol['id']>();
// @Output() getMetricsToDisplay = new EventEmitter();
// @Output() selectedMetricToShow = new EventEmitter<SelectionEvent>();
// @Output() selectedHyperParamToShow = new EventEmitter<{param: string; addCol: boolean}>();
// @Output() setAutoRefresh = new EventEmitter<boolean>();
// @Output() toggleShowCompareSettings = new EventEmitter<boolean>();
// @Output() compareViewChanged = new EventEmitter<'scalars' | 'plots'>();
// @Output() clearSelection = new EventEmitter();
// @Output() clearTableFilters = new EventEmitter<{ [s: string]: FilterMetadata }>();
// @Output() tableModeChanged = new EventEmitter<'table' | 'info' | 'compare'>();
protected readonly resourceToIconMap = resourceToIconMap;
protected readonly trackByValue = trackByValue;
@ -63,4 +48,8 @@ export class EditPipelineHeaderComponent extends BaseEntityHeaderComponent imple
...(this.entityType === EntityTypeEnum.experiment ? [{label: 'Compare view', value: 'compare', icon: 'al-ico-charts-view'}] : [])
];
}
addNewStep() {
this.createPipelineStep.emit();
}
}

View File

@ -1,4 +1,5 @@
<sm-edit-pipeline-header
(createPipelineStep)="createPipeline()"
>
</sm-edit-pipeline-header>
<div class="edit-pipeline-body">

View File

@ -1,4 +1,8 @@
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { PipelineAddStepDialogComponent } from '../pipeline-add-step-dialog/pipeline-add-step-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { Store } from '@ngrx/store';
import { createPipelineStep } from '../pipelines.actions';
@Component({
selector: 'sm-edit-pipeline-page',
@ -6,5 +10,30 @@ import { Component } from '@angular/core';
styleUrls: ['./edit-pipeline-page.component.scss']
})
export class EditPipelinePageComponent {
protected dialog = inject(MatDialog);
protected store = inject(Store);
createPipeline() {
this.dialog.open(PipelineAddStepDialogComponent, {
data: {defaultExperimentId: ''},
panelClass: 'light-theme',
width: '640px'
})
.afterClosed()
.subscribe(pipeline => {
if (pipeline) {
this.store.dispatch(createPipelineStep({pipelinesCreateStepRequest: pipeline}));
}
});
// this.dialog.open(PipelineDialogComponent, {
// data: {
// panelClass: 'light-theme',
// },
// width: '640px'
// });
}
}

View File

@ -0,0 +1,9 @@
<sm-dialog-template iconClass="al-ico-pipelines" header="CREATE NEW PIPELINE">
<sm-pipeline-add-step-form
[experiments]="experiments$| async"
[readOnlyExperimentsNames]="readOnlyExperimentsNames$ | async"
[defaultExperimentId]="data?.defaultExperimentId"
(stepCreated)="createStep($event)"
(filterSearchChanged)="filterSearchChanged($event)"
></sm-pipeline-add-step-form>
</sm-dialog-template>

View File

@ -0,0 +1,4 @@
:host{
width: 640px;
display: block;
}

View File

@ -0,0 +1,56 @@
import {Component, Inject} from '@angular/core';
import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import {Store} from '@ngrx/store';
import {Observable} from 'rxjs';
import {/* getTablesFilterProjectsOptions, */ resetTablesFilterProjectsOptions} from '@common/core/actions/projects.actions';
import {map} from 'rxjs/operators';
import {isReadOnly} from '@common/shared/utils/is-read-only';
import { Task } from '~/business-logic/model/tasks/task';
//import { selectExperimentsList } from '@common/experiments/reducers';
import { globalFilterChanged } from '@common/experiments/actions/common-experiments-view.actions';
import { PipelinesCreateStepsRequest } from '~/business-logic/model/pipelines/pipelinesCreateStepsRequest';
import { selectExperiments } from '../pipelines.reducer';
import { getAllExperiments } from '../pipelines.actions';
@Component({
selector: 'sm-pipeline-add-step-dialog',
templateUrl: './pipeline-add-step-dialog.component.html',
styleUrls: ['./pipeline-add-step-dialog.component.scss']
})
export class PipelineAddStepDialogComponent {
public experiments$: Observable<Task[]>;
public readOnlyExperimentsNames$: Observable<string[]>;
constructor(
private store: Store,
private matDialogRef: MatDialogRef<PipelineAddStepDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: { defaultExperimentId: string}
) {
this.experiments$ = this.store.select(selectExperiments);
this.readOnlyExperimentsNames$ = this.store.select(selectExperiments)
.pipe(map(experiments => experiments?.filter(experiment => isReadOnly(experiment)).map(experiment=> experiment.name)));
this.store.dispatch(resetTablesFilterProjectsOptions());
}
public createStep(pipelineForm) {
const pipeline = this.convertFormToPipeline(pipelineForm);
this.matDialogRef.close(pipeline);
}
private convertFormToPipeline(stepForm: any): PipelinesCreateStepsRequest {
return {
name: stepForm.name,
description: stepForm.description,
experiment:stepForm.experiment.value,
parameters: stepForm.parameters
};
}
filterSearchChanged($event: {value: string; loadMore?: boolean}) {
!$event.loadMore && this.store.dispatch(getAllExperiments({query: $event.value}));
this.store.dispatch(getAllExperiments({query: $event.value || '', /* loadMore: $event.loadMore, allowPublic: false */}));
}
}

View File

@ -0,0 +1,60 @@
<form (submit)="pipelineForm.invalid && send()" #pipelineForm='ngForm' class="d-flex flex-column">
<mat-form-field appearance="outline" hideRequiredMarker class="mat-light">
<mat-label>Step name</mat-label>
<mat-error *ngIf="name.touched && name.errors?.required">*Please add name.</mat-error>
<mat-error *ngIf="name.touched && name.errors?.uniqueName">*Step name already exists.</mat-error>
<mat-error *ngIf="name.touched && name.errors?.minlength">*Step name should contain more than 3
characters.</mat-error>
<input name="stepName" [(ngModel)]="step.name" #name="ngModel" matInput autocomplete="off"
smUniqueNameValidator [existingNames]="experimentsNames" required minlength="3">
</mat-form-field>
<mat-form-field class="w-100" appearance="outline"
(mousedown)="!isFocused(experimentInputRef) && experimentInput.value && experimentInput.reset(); experimentInputRef.blur(); experimentInputRef.focus()">
<mat-label>Experiment</mat-label>
<input matInput type="text" [matAutocomplete]="auto" [ngModel]="step.experiment" name="experimentName"
placeholder="Search for existing experiments" #experimentInputRef #experimentInput="ngModel" required
(keydown.enter)="experimentInput.control.markAsTouched()" [smExistNameValidator]="experimentsNames"
smUniqueNameValidator >
<i matSuffix class="al-icon sm-md search-icon me-2"
[ngClass]="experimentInput.value? 'al-ico-dialog-x pointer':'al-ico-search'"
(mousedown)="!isFocused(experimentInputRef) && experimentInput.value && clear(); experimentInput.reset(); experimentInputRef.focus()"
smClickStopPropagation></i>
<mat-error *ngIf="experimentInput?.errors?.existName">Please provide a experiment</mat-error>
<mat-error *ngIf="experimentInput?.errors?.uniqueName && !readOnlyExperimentsNames.includes(step.experiment?.label)">Please
provide a different name as this experiment name is taken as an Example project
</mat-error>
<mat-autocomplete #auto="matAutocomplete" class="light-theme" [displayWith]="displayFn"
(opened)="setIsAutoCompleteOpen(true)" (closed)="setIsAutoCompleteOpen(false)" autoActiveFirstOption>
<!-- Currently we don't have create new project in create report-->
<!-- <mat-option-->
<!-- class="item"-->
<!-- *ngIf="projects !== null && experimentInput.value && !(experimentInput.value | stringIncludedInArray:projectsNames)"-->
<!-- [value]="experimentInput.value"-->
<!-- (onSelectionChange)="createNewSelected($event)"-->
<!-- >"{{experimentInput.value}}" <span class="new">(Create New)</span></mat-option>-->
<mat-option *ngFor="let experiment of experimentsOptions; trackBy: trackByValue" [value]="experiment"
[smTooltip]="experiment.label" smShowTooltipIfEllipsis (onSelectionChange)="experimentSelected($event)">
<div [smSearchText]="experimentInput.value">{{experiment.label}}</div>
</mat-option>
<div *ngIf="experiments === null" class="p-4 pe-none">
<mat-spinner class="m-auto" [diameter]="32" [strokeWidth]="4" color="accent"></mat-spinner>
</div>
<div *ngIf="experiments && !noMoreOptions" (smScrollEnd)="!loading && loadMore(experimentInput.value)"
class="text-center">Loading more...</div>
<mat-option disabled style="height: 0; min-height: 0;"></mat-option>
<!-- Empty mat-option, so the autocomplete menu will always pop -->
</mat-autocomplete>
</mat-form-field>
<mat-form-field appearance="outline" hideRequiredMarker>
<mat-error *ngIf="description?.touched && description?.invalid">*Please add description.
</mat-error>
<mat-label>Description</mat-label>
<textarea class="step-description" name="description" matInput [(ngModel)]="step.description"
#description="ngModel"></textarea>
</mat-form-field>
<div class="w-100 create-step-button">
<button class="btn btn-dark-fill center" data-id="Create Step" [disabled]="pipelineForm.invalid"
(click)="send()">ADD STEP
</button>
</div>
</form>

View File

@ -0,0 +1,12 @@
:host {
.create-report-button {
padding: 32px 12px 0;
}
mat-form-field {
width: 100%;
.report-description {
min-height: 68px;
}
}
}

View File

@ -0,0 +1,137 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
OnChanges, OnDestroy,
Output,
ViewChild
} from '@angular/core';
import {NgModel} from '@angular/forms';
import {Observable, Subscription} from 'rxjs';
import {trackByValue} from '@common/shared/utils/forms-track-by';
import {MatOptionSelectionChange} from '@angular/material/core';
import {rootProjectsPageSize} from '@common/constants';
import {
IOption
} from '@common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component';
import { Task } from '~/business-logic/model/tasks/task';
@Component({
selector: 'sm-pipeline-add-step-form',
templateUrl: './pipeline-add-step-form.component.html',
styleUrls: ['./pipeline-add-step-form.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PipelineAddStepFormComponent implements OnChanges, OnDestroy {
public filteredExperiments$: Observable<{ label: string; value: string }[]>;
private _experiments: Task[];
public experimentsOptions: { label: string; value: string }[];
public trackByValue = trackByValue;
public panelHeight: number;
private subs = new Subscription();
private rootFiltered: boolean;
public readonly experimentsRoot = {label: 'My experiment', value: null};
@ViewChild('experimentInput') experimentInput: NgModel;
public pipelinesNames: Array<string>;
public experimentsNames: Array<string>;
public step: { name: string; description: string; experiment: { label: string; value: string }, parameters: Array<object> } = {
name: null,
description: '',
experiment: null,
parameters: [],
};
filterText: string = '';
isAutoCompleteOpen: boolean;
@Input() readOnlyExperimentsNames: string[];
@Input() defaultExperimentId: string;
public loading: boolean;
public noMoreOptions: boolean;
private previousLength: number | undefined;
@Input() set experiments(experiments: Task[]) {
this.loading = false;
this.noMoreOptions = experiments?.length === this.previousLength || experiments?.length < rootProjectsPageSize;
this.previousLength = experiments?.length;
this._experiments = experiments;
this.experimentsOptions = [
...((this.rootFiltered || experiments === null) ? [] : [this.experimentsRoot]),
...(experiments ? experiments.map(experiment => ({label: experiment.name, value: experiment.id})) : [])
];
this.experimentsNames = this.experimentsOptions.map(experiment => experiment.label);
}
get experiments() {
return this._experiments;
}
@Output() stepCreated = new EventEmitter();
@Output() filterSearchChanged = new EventEmitter<{value: string; loadMore?: boolean}>();
ngOnInit(): void {
this.searchChanged(['*', null].includes(this.defaultExperimentId) ? '' : this.defaultExperimentId);
setTimeout(() => {
this.subs.add(this.experimentInput.valueChanges.subscribe(searchString => {
if (searchString !== this.step.experiment) {
this.searchChanged(searchString?.label || searchString || '');
}
})
);
});
}
ngOnDestroy(): void {
this.subs.unsubscribe();
}
ngOnChanges(): void {
if (this.experiments?.length > 0 && this.step.experiment === null) {
this.step.experiment = this.experimentsOptions.find(p => p.value === this.defaultExperimentId) || {label: this.experimentsRoot.label, value: null};
this.experimentInput.control.updateValueAndValidity();
}
}
createNewSelected($event: MatOptionSelectionChange) {
this.step.experiment = {label: $event.source.value, value: null};
}
experimentSelected($event: MatOptionSelectionChange) {
this.step.experiment = {label: $event.source.value.label, value: $event.source.value.value};
}
setIsAutoCompleteOpen(focus: boolean) {
this.isAutoCompleteOpen = focus;
}
displayFn(experiment: IOption | string) {
return typeof experiment === 'string' ? experiment : experiment?.label;
}
clear() {
this.experimentInput.control.setValue('');
}
send() {
this.stepCreated.emit(this.step);
}
searchChanged(searchString: string) {
this.experimentsOptions = null;
this.experimentsNames = null;
this.rootFiltered = searchString && !this.experimentsRoot.label.toLowerCase().includes(searchString.toLowerCase());
searchString !== null && this.filterSearchChanged.emit({value: searchString, loadMore: false});
}
loadMore(searchString) {
this.loading = true;
this.filterSearchChanged.emit({value: searchString || '', loadMore: true});
}
isFocused(locationRef: HTMLInputElement) {
return document.activeElement === locationRef;
}
}

View File

@ -2,6 +2,8 @@ import {createAction, props} from '@ngrx/store';
// import {ReportsGetAllExResponse} from '~/business-logic/model/reports/reportsGetAllExResponse';
// import {IReport} from './reports.consts';
import { Pipeline, PipelinesCreateRequest } from '~/business-logic/model/pipelines/models';
import { PipelinesCreateStepsRequest } from '~/business-logic/model/pipelines/pipelinesCreateStepsRequest';
import { Task } from '~/business-logic/model/tasks/task';
export const PIPELINES_PREFIX = 'PIPELINES_';
@ -10,7 +12,21 @@ export const createPipeline = createAction(
props<{ pipelinesCreateRequest: PipelinesCreateRequest }>()
);
export const createPipelineStep = createAction(
PIPELINES_PREFIX + 'CREATE_PIPELINE_STEP',
props<{ pipelinesCreateStepRequest: PipelinesCreateStepsRequest }>()
);
export const getAllExperiments = createAction(
PIPELINES_PREFIX + 'GET_EXPERIMENTS',
props<{ query: string; regExp?: boolean }>()
);
export const setExperimentsResults = createAction(
PIPELINES_PREFIX + 'SET_EXPERIMENTS',
props<{ experiments: Task[]}>()
);
export const updateProject = createAction(
PIPELINES_PREFIX + '[update pipeline]',

View File

@ -6,7 +6,7 @@ import {catchError, filter, map, mergeMap, switchMap, /* tap */} from 'rxjs/oper
import {activeLoader, /* addMessage, */ deactivateLoader, setServerError} from '../core/actions/layout.actions';
import {requestFailed} from '../core/actions/http.actions';
import {
createPipeline
createPipeline, createPipelineStep, getAllExperiments, setExperimentsResults
} from './pipelines.actions';
// import {ApiReportsService} from '~/business-logic/api-services/reports.service';
/* import {IReport, PAGE_SIZE} from './reports.consts';
@ -30,10 +30,11 @@ import {
selectSelectedProjectId
} from '../core/reducers/projects.reducer';
import {TABLE_SORT_ORDER} from '../shared/ui-components/data/table/table.consts';
import {selectCurrentUser, selectShowOnlyUserWork} from '../core/reducers/users-reducer';
import {escapeRegex} from '../shared/utils/escape-regex';
import {MESSAGES_SEVERITY} from '../constants'; */
import {MatDialog} from '@angular/material/dialog';
import {selectCurrentUser} from '../core/reducers/users-reducer';
/* import {
ChangeProjectDialogComponent
} from '@common/experiments/shared/components/change-project-dialog/change-project-dialog.component';
@ -45,6 +46,8 @@ import {selectActiveWorkspaceReady} from '~/core/reducers/view.reducer';
import {HttpClient} from '@angular/common/http';
import { PipelinesCreateResponse } from '~/business-logic/model/pipelines/pipelinesCreateResponse';
import { ApiPipelinesService } from '~/business-logic/api-services/pipelines.service';
import { PipelinesCreateStepsResponse } from '~/business-logic/model/pipelines/pipelinesCreateStepsResponse';
import { ApiTasksService } from '~/business-logic/api-services/tasks.service';
/* import {selectRouterParams} from '@common/core/reducers/router-reducer';
import {setMainPageTagsFilter} from '@common/core/actions/projects.actions';
import {cleanTag} from '@common/shared/utils/helpers.util';
@ -59,6 +62,7 @@ export class PipelinesEffects {
private route: ActivatedRoute,
private router: Router,
private pipelinesApiService: ApiPipelinesService,
private experimentsApiService: ApiTasksService,
private http: HttpClient,
private matDialog: MatDialog,
// public projectsApi: ApiProjectsService,
@ -66,7 +70,7 @@ export class PipelinesEffects {
}
activeLoader = createEffect(() => this.actions.pipe(
ofType(/* getReports, getReport, */ createPipeline,/* updateReport, restoreReport, archiveReport */),
ofType(/* getReports, getReport, */ createPipeline, createPipelineStep, getAllExperiments/* updateReport, restoreReport, archiveReport */),
filter(action => !action['refresh']),
map(action => activeLoader(action.type))
));
@ -88,6 +92,51 @@ export class PipelinesEffects {
})))
));
createPipelineStep$ = createEffect(() => this.actions.pipe(
ofType(createPipelineStep),
switchMap((action) => this.pipelinesApiService.pipelinesCreateStep(action.pipelinesCreateStepRequest)
.pipe(mergeMap((res: PipelinesCreateStepsResponse) => {
// eslint-disable-next-line no-console
console.log(res)
// this.router.navigate(['pipelines', res.id, 'edit']);
return [deactivateLoader(createPipeline.type)];
}),
catchError(err => {
return [
requestFailed(err),
setServerError(err, null, 'failed to create a new pipeline step'),
deactivateLoader(createPipelineStep.type),
]
})))
));
getAllExperiments$ = createEffect(() => this.actions.pipe(
ofType(getAllExperiments),
switchMap((action) => this.experimentsApiService.tasksGetAllEx({
_any_: {
pattern: action.query ? action.query : '',
fields: ['name', 'id']
},
size: 20,
// user: this.store.select(selectCurrentUser)?.id,
only_fields: ['name', 'created', 'status', 'type', 'user.name', 'id', 'company'],
// order_by: orderBy,
// type: [excludedKey, 'annotation_manual', excludedKey, 'annotation', excludedKey, 'dataset_import'],
// system_tags: ['-archived', '-pipeline', '-dataset'],
search_hidden: false,
/* eslint-enable @typescript-eslint/naming-convention */
}).pipe(
mergeMap(res => [setExperimentsResults({
experiments: res.tasks,
}), deactivateLoader(getAllExperiments.type)]),
catchError(error => [deactivateLoader(getAllExperiments.type), requestFailed(error)])))
));
// activeLoader = createEffect(() => this.actions.pipe(
// ofType(updateProject, getAllProjectsPageProjects),
// map(action => activeLoader(action.type))

View File

@ -51,6 +51,8 @@ import { PipelineState, pipelinesReducer, PIPELINES_KEY } from "./pipelines.redu
import { UserPreferences } from "@common/user-preferences";
import { createUserPrefFeatureReducer } from "@common/core/meta-reducers/user-pref-reducer";
import { PIPELINES_PREFIX } from "./pipelines.actions";
import { PipelineAddStepDialogComponent } from "./pipeline-add-step-dialog/pipeline-add-step-dialog.component";
import { PipelineAddStepFormComponent } from "./pipeline-add-step-dialog/pipeline-add-step-form/pipeline-add-step-form.component";
export const pipelinesSyncedKeys = ["projects.showPipelineExamples"];
const pipelinesSyncedKeys2 = ['orderBy', 'sortOrder'];
@ -96,7 +98,9 @@ const getInitState = (userPreferences: UserPreferences) => ({
declarations: [
PipelinesPageComponent,
PipelineDialogComponent,
PipelineAddStepDialogComponent,
CreateNewPipelineFormComponent,
PipelineAddStepFormComponent,
EditPipelinePageComponent,
EditPipelineHeaderComponent,
],

View File

@ -8,6 +8,7 @@ import {
resetPipelinesSearchQuery,
resetReadyToDelete,
setCurrentScrollId,
setExperimentsResults,
setNoMorePipelines,
setPipelinesOrderBy,
setPipelinesSearchQuery,
@ -18,7 +19,7 @@ import {
} from './pipelines.actions';
import {SearchState} from '../common-search/common-search.reducer';
import { Pipeline } from '~/business-logic/model/pipelines/pipeline';
import { Task } from '~/business-logic/model/tasks/task';
export const PIPELINES_KEY = 'pipelines';
@ -50,6 +51,7 @@ export interface PipelineState {
tableModeAwareness: boolean;
showPipelineExamples: boolean;
showDatasetExamples: boolean;
experiments: Task[];
}
export const pipelinesInitState: PipelineState = {
@ -67,6 +69,7 @@ export const pipelinesInitState: PipelineState = {
tableModeAwareness: true,
showPipelineExamples: false,
showDatasetExamples: false,
experiments: null
};
const getCorrectSortingOrder = (currentSortOrder: TableSortOrderEnum, currentOrderField: string, nextOrderField: string) => {
@ -132,7 +135,11 @@ export const pipelinesReducers = [
on(setTableModeAwareness, (state, action) =>
({...state, tableModeAwareness: (action as ReturnType<typeof setTableModeAwareness>).awareness})),
on(showExamplePipelines, state => ({...state, showPipelineExamples: true})),
on(showExampleDatasets, state => ({...state, showDatasetExamples: true}))
on(showExampleDatasets, state => ({...state, showDatasetExamples: true})),
on(setExperimentsResults, (state, action) => ({
...state,
experiments: [...action.experiments],
})),
] as ReducerTypes<PipelineState, ActionCreator[]>[];
export const pipelinesReducer = createReducer(pipelinesInitState, ...pipelinesReducers);
@ -156,3 +163,4 @@ export const selectPipelinesScrollId = createSelector(pipelines, (state): string
export const selectTableModeAwareness = createSelector(pipelines, state => state?.tableModeAwareness);
export const selectShowPipelineExamples = createSelector(pipelines, state => state?.showPipelineExamples);
export const selectShowDatasetExamples = createSelector(pipelines, state => state?.showDatasetExamples);
export const selectExperiments = createSelector(pipelines, state => state?.experiments);