mirror of
https://github.com/clearml/clearml-web
synced 2025-05-08 22:09:54 +00:00
Merge branch 'development' of https://github.com/Nuva-Org/clearml-web into development
This commit is contained in:
commit
4183bc7b7a
@ -35,7 +35,16 @@ import { BASE_PATH, COLLECTION_FORMATS } from "../variables";
|
|||||||
import { Configuration } from "../configuration";
|
import { Configuration } from "../configuration";
|
||||||
import { PipelinesDeleteRunsRequest } from "~/business-logic/model/pipelines/pipelinesDeleteRunsRequest";
|
import { PipelinesDeleteRunsRequest } from "~/business-logic/model/pipelines/pipelinesDeleteRunsRequest";
|
||||||
import { PipelinesDeleteRunsResponse } from "~/business-logic/model/pipelines/pipelinesDeleteRunsResponse";
|
import { PipelinesDeleteRunsResponse } from "~/business-logic/model/pipelines/pipelinesDeleteRunsResponse";
|
||||||
import { PipelinesCreateRequest, PipelinesCreateResponse, PipelinesCreateStepsRequest, PipelinesCreateStepsResponse, pipelinesSettingsModel } from "../model/pipelines/models";
|
import {
|
||||||
|
PipelinesCreateRequest,
|
||||||
|
PipelinesCreateResponse,
|
||||||
|
PipelinesCreateStepsRequest,
|
||||||
|
PipelinesCreateStepsResponse, pipelinesSettingsModel,
|
||||||
|
PipelinesGetByIdRequest,
|
||||||
|
PipelinesGetByIdResponse,
|
||||||
|
PipelinesUpdateRequest,
|
||||||
|
PipelinesUpdateResponse,
|
||||||
|
} from "../model/pipelines/models";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApiPipelinesService {
|
export class ApiPipelinesService {
|
||||||
@ -216,7 +225,7 @@ export class ApiPipelinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.apiRequest.post<PipelinesCreateResponse>(
|
return this.apiRequest.post<PipelinesCreateResponse>(
|
||||||
`${this.basePath}/pipelines.create`,
|
`${this.basePath}/pipelines.create_pipeline`,
|
||||||
request,
|
request,
|
||||||
{
|
{
|
||||||
withCredentials: this.configuration.withCredentials,
|
withCredentials: this.configuration.withCredentials,
|
||||||
@ -227,7 +236,6 @@ export class ApiPipelinesService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Create a new pipeline step
|
* Create a new pipeline step
|
||||||
@ -270,7 +278,7 @@ export class ApiPipelinesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.apiRequest.post<PipelinesCreateStepsResponse>(
|
return this.apiRequest.post<PipelinesCreateStepsResponse>(
|
||||||
`${this.basePath}/pipelines.create.step`,
|
`${this.basePath}/pipelines.create_step`,
|
||||||
request,
|
request,
|
||||||
{
|
{
|
||||||
withCredentials: this.configuration.withCredentials,
|
withCredentials: this.configuration.withCredentials,
|
||||||
@ -333,5 +341,107 @@ export class ApiPipelinesService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update pipeline information
|
||||||
|
* @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 pipelinesUpdate(
|
||||||
|
request: PipelinesUpdateRequest,
|
||||||
|
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 projectsUpdate."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<PipelinesUpdateResponse>(
|
||||||
|
`${this.basePath}/pipelines.update_pipeline`,
|
||||||
|
{...request, pipeline_id: request.id},
|
||||||
|
{
|
||||||
|
withCredentials: this.configuration.withCredentials,
|
||||||
|
headers: headers,
|
||||||
|
observe: observe,
|
||||||
|
reportProgress: reportProgress,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @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 pipelinesGetById(
|
||||||
|
request: PipelinesGetByIdRequest,
|
||||||
|
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 pipelinesGetById."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<PipelinesGetByIdResponse>(
|
||||||
|
`${this.basePath}/pipelines.get_by_id`,
|
||||||
|
request,
|
||||||
|
{
|
||||||
|
withCredentials: this.configuration.withCredentials,
|
||||||
|
headers: headers,
|
||||||
|
observe: observe,
|
||||||
|
reportProgress: reportProgress,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,9 @@ export * from '././pipelinesCreateResponse';
|
|||||||
export * from '././pipelinesCreateStepsRequest';
|
export * from '././pipelinesCreateStepsRequest';
|
||||||
export * from '././pipelinesCreateStepsResponse';
|
export * from '././pipelinesCreateStepsResponse';
|
||||||
export * from './pipelinesSettingsModel';
|
export * from './pipelinesSettingsModel';
|
||||||
|
export * from '././pipelinesGetByIdRequest';
|
||||||
|
export * from '././pipelinesGetByIdResponse';
|
||||||
|
export * from '././pipelinesUpdateRequest';
|
||||||
|
export * from '././pipelinesUpdateResponse';
|
||||||
|
|
||||||
export * from "././pipeline";
|
export * from "././pipeline";
|
@ -15,7 +15,11 @@ import { PipelinesParameter } from './pipelinesParameter';
|
|||||||
* Do not edit the class manually.
|
* Do not edit the class manually.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
interface FlowDisplay {
|
||||||
|
|
||||||
|
nodes?: Array<unknown>;
|
||||||
|
edges?: Array<unknown>
|
||||||
|
}
|
||||||
|
|
||||||
export interface Pipeline {
|
export interface Pipeline {
|
||||||
/**
|
/**
|
||||||
@ -70,5 +74,7 @@ export interface Pipeline {
|
|||||||
own_models?: number;
|
own_models?: number;
|
||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
|
|
||||||
parameters?: Array<PipelinesParameter>
|
parameters?: Array<PipelinesParameter>;
|
||||||
|
|
||||||
|
flow_display?: FlowDisplay;
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,5 @@ export interface PipelinesCreateResponse {
|
|||||||
* Pipeline id
|
* Pipeline id
|
||||||
*/
|
*/
|
||||||
id?: string;
|
id?: string;
|
||||||
|
project_id?: string;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export interface PipelinesCreateStepsRequest {
|
export interface PipelinesCreateStepsRequest {
|
||||||
/**
|
/**
|
||||||
* Pipeline name. Unique within the company.
|
* Pipeline step name. Unique within the company.
|
||||||
*/
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
/**
|
/**
|
||||||
@ -10,5 +10,7 @@ export interface PipelinesCreateStepsRequest {
|
|||||||
|
|
||||||
experiment?: string;
|
experiment?: string;
|
||||||
|
|
||||||
parameters?: Array<object>
|
parameters?: Array<object>,
|
||||||
|
|
||||||
|
pipeline_id?: string;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
export interface PipelinesGetByIdRequest {
|
||||||
|
/**
|
||||||
|
* Project id
|
||||||
|
*/
|
||||||
|
pipeline?: string;
|
||||||
|
pipeline_name?: string;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
import { Pipeline } from './pipeline';
|
||||||
|
|
||||||
|
|
||||||
|
export interface PipelinesGetByIdResponse {
|
||||||
|
pipeline?: Pipeline;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
import { Pipeline } from "./pipeline";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export interface PipelinesUpdateRequest extends Pipeline {
|
||||||
|
flow_display?: unknown;
|
||||||
|
pipeline_id?: string;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* projects
|
||||||
|
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||||
|
*
|
||||||
|
* OpenAPI spec version: 2.14
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by the swagger code generator program.
|
||||||
|
* https://github.com/swagger-api/swagger-codegen.git
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Pipeline } from "./pipeline";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export interface PipelinesUpdateResponse extends Pipeline {
|
||||||
|
/**
|
||||||
|
* Number of projects updated (0 or 1)
|
||||||
|
*/
|
||||||
|
updated?: number;
|
||||||
|
/**
|
||||||
|
* Updated fields names and values
|
||||||
|
*/
|
||||||
|
fields?: object;
|
||||||
|
|
||||||
|
id?: string;
|
||||||
|
}
|
@ -58,4 +58,5 @@ export interface ProjectsGetAllResponseSingle {
|
|||||||
sub_projects?: Array<ProjectsGetAllResponseSingleSubProjects>;
|
sub_projects?: Array<ProjectsGetAllResponseSingleSubProjects>;
|
||||||
isRoot?: boolean;
|
isRoot?: boolean;
|
||||||
last_update?: string; //MANUALLY
|
last_update?: string; //MANUALLY
|
||||||
|
//basename?: string;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
<div class="d-flex justify-content-end align-items-center header-container">
|
<div class="d-flex justify-content-end align-items-center header-container">
|
||||||
|
<div class="pipeline-name">
|
||||||
|
Editing {{pipelineData?.name}}
|
||||||
|
</div>
|
||||||
<!-- <sm-clear-filters-button
|
<!-- <sm-clear-filters-button
|
||||||
*ngIf="!minimizedView"
|
*ngIf="!minimizedView"
|
||||||
[tableFilters]="tableFilters"
|
[tableFilters]="tableFilters"
|
||||||
@ -31,7 +34,7 @@
|
|||||||
(setAutoRefresh)="setAutoRefresh.emit($event)"
|
(setAutoRefresh)="setAutoRefresh.emit($event)"
|
||||||
>
|
>
|
||||||
</sm-refresh-button> -->
|
</sm-refresh-button> -->
|
||||||
<button class="btn btn-icon g-btn" smTooltip="Save pipeline">
|
<button class="btn btn-icon g-btn" smTooltip="Save pipeline" (click)="savePipelineClicked()">
|
||||||
<i class="icon i-pipeline-save lm"></i>
|
<i class="icon i-pipeline-save lm"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-icon g-btn" smTooltip="Compile pipeline">
|
<button class="btn btn-icon g-btn" smTooltip="Compile pipeline">
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pipeline-name {
|
||||||
|
color: white;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
&.archive-mode {
|
&.archive-mode {
|
||||||
transition: background-color 0.5s;
|
transition: background-color 0.5s;
|
||||||
background-color: #333746;
|
background-color: #333746;
|
||||||
|
@ -8,6 +8,7 @@ import {Option} from '@common/shared/ui-components/inputs/button-toggle/button-t
|
|||||||
import {trackByValue} from '@common/shared/utils/forms-track-by';
|
import {trackByValue} from '@common/shared/utils/forms-track-by';
|
||||||
import {resourceToIconMap} from '~/features/experiments/experiments.consts';
|
import {resourceToIconMap} from '~/features/experiments/experiments.consts';
|
||||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||||
|
import { Pipeline } from '~/business-logic/model/pipelines/pipeline';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -25,9 +26,10 @@ export class EditPipelineHeaderComponent extends BaseEntityHeaderComponent imple
|
|||||||
get tableCols() {
|
get tableCols() {
|
||||||
return this._tableCols;
|
return this._tableCols;
|
||||||
}
|
}
|
||||||
|
@Input() pipelineData: Pipeline;
|
||||||
@Output() createPipelineStep = new EventEmitter();
|
@Output() createPipelineStep = new EventEmitter();
|
||||||
@Output() settingsPipelineAction = new EventEmitter();
|
@Output() settingsPipelineAction = new EventEmitter();
|
||||||
|
@Output() savePipeline = new EventEmitter();
|
||||||
// @Output() selectedTableColsChanged = new EventEmitter<ISmCol>();
|
// @Output() selectedTableColsChanged = new EventEmitter<ISmCol>();
|
||||||
// @Output() removeColFromList = new EventEmitter<ISmCol['id']>();
|
// @Output() removeColFromList = new EventEmitter<ISmCol['id']>();
|
||||||
// @Output() getMetricsToDisplay = new EventEmitter();
|
// @Output() getMetricsToDisplay = new EventEmitter();
|
||||||
@ -56,4 +58,7 @@ export class EditPipelineHeaderComponent extends BaseEntityHeaderComponent imple
|
|||||||
settings() {
|
settings() {
|
||||||
this.settingsPipelineAction.emit();
|
this.settingsPipelineAction.emit();
|
||||||
}
|
}
|
||||||
|
savePipelineClicked() {
|
||||||
|
this.savePipeline.emit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
<sm-edit-pipeline-header
|
<sm-edit-pipeline-header
|
||||||
(createPipelineStep)="createPipeline()"
|
|
||||||
(settingsPipelineAction)="settings()"
|
(settingsPipelineAction)="settings()"
|
||||||
|
(createPipelineStep)="createPipelineStep()"
|
||||||
|
(savePipeline)="savePipeline()"
|
||||||
|
[pipelineData]="selectedPipeline"
|
||||||
>
|
>
|
||||||
</sm-edit-pipeline-header>
|
</sm-edit-pipeline-header>
|
||||||
<div class="edit-pipeline-body">
|
<div class="edit-pipeline-body">
|
||||||
<!-- <div class="details"><i class="icon no-output-icon i-no-code-dark"></i> DETAILS</div> -->
|
<!-- <div class="details"><i class="icon no-output-icon i-no-code-dark"></i> DETAILS</div> -->
|
||||||
<sm-flow-editor/>
|
<sm-flow-editor *ngIf="selectedPipeline?.flow_display?.nodes?.length" [pipelineData]="selectedPipeline" (nodesChangedInReactFlow)="nodesChangedInReactFlow($event)" (edgesChangedInReactFlow)="edgesChangedInReactFlow($event)" />
|
||||||
<div class="pipeline-empty">
|
<div class="pipeline-empty">
|
||||||
<i class="icon i-fingers-white mx-auto xxl"></i>
|
<i class="icon i-fingers-white mx-auto xxl"></i>
|
||||||
<br/>
|
<br/>
|
||||||
|
@ -1,20 +1,73 @@
|
|||||||
import { Component, inject } from '@angular/core';
|
import { Component, OnDestroy, OnInit, inject } from '@angular/core';
|
||||||
import { PipelineAddStepDialogComponent } from '../pipeline-add-step-dialog/pipeline-add-step-dialog.component';
|
import { PipelineAddStepDialogComponent } from '../pipeline-add-step-dialog/pipeline-add-step-dialog.component';
|
||||||
import { PipelineSettingComponent } from '../pipeline-setting/pipeline-setting.component';
|
import { PipelineSettingComponent } from '../pipeline-setting/pipeline-setting.component';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { createPipelineStep,settingsPipelineAction} from '../pipelines.actions';
|
import { createPipelineStep, settingsPipelineAction, getPipelineById, resetPipelines, resetPipelinesSearchQuery, updatePipeline } from '../pipelines.actions';
|
||||||
|
import { selectRouterParams } from '@common/core/reducers/router-reducer';
|
||||||
|
import { Observable, Subscription, map } from 'rxjs';
|
||||||
|
import { Params } from '@angular/router';
|
||||||
|
import { selectSelectedPipeline } from '../pipelines.reducer';
|
||||||
|
import { Pipeline } from '~/business-logic/model/pipelines/models';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'sm-edit-pipeline-page',
|
selector: 'sm-edit-pipeline-page',
|
||||||
templateUrl: './edit-pipeline-page.component.html',
|
templateUrl: './edit-pipeline-page.component.html',
|
||||||
styleUrls: ['./edit-pipeline-page.component.scss']
|
styleUrls: ['./edit-pipeline-page.component.scss']
|
||||||
})
|
})
|
||||||
export class EditPipelinePageComponent {
|
export class EditPipelinePageComponent implements OnInit, OnDestroy {
|
||||||
protected dialog = inject(MatDialog);
|
protected dialog = inject(MatDialog);
|
||||||
protected store = inject(Store);
|
protected store = inject(Store);
|
||||||
|
public subs = new Subscription();
|
||||||
|
public selectedPipelineId$: Observable<string>;
|
||||||
|
private selectedPipeline$: Observable<Pipeline>;
|
||||||
|
public selectedPipeline: Pipeline;
|
||||||
|
pipelineId: string;
|
||||||
|
private reactFlowState = {nodes: [], edges: []};
|
||||||
|
|
||||||
createPipeline() {
|
constructor() {
|
||||||
|
|
||||||
|
this.selectedPipelineId$ = this.store.select(selectRouterParams).pipe(map((params: Params) => {
|
||||||
|
// eslint-disable-next-line @ngrx/avoid-mapping-selectors
|
||||||
|
//console.log(params);
|
||||||
|
return params?.id
|
||||||
|
}));
|
||||||
|
this.selectedPipeline$ = this.store.select(selectSelectedPipeline)
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.subs.add(this.selectedPipelineId$.pipe(
|
||||||
|
).subscribe((pipelineId) => {
|
||||||
|
this.pipelineId = pipelineId;
|
||||||
|
setTimeout(()=> {
|
||||||
|
this.store.dispatch(getPipelineById({id: pipelineId, name: ''}))
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
this.subs.add(this.selectedPipeline$.pipe(
|
||||||
|
).subscribe((pipelineData) => {
|
||||||
|
this.selectedPipeline = pipelineData;
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(pipelineData);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.subs.unsubscribe();
|
||||||
|
this.store.dispatch(resetPipelines());
|
||||||
|
this.store.dispatch(resetPipelinesSearchQuery());
|
||||||
|
}
|
||||||
|
|
||||||
|
savePipeline () {
|
||||||
|
const pipelineState = cloneDeep(this.selectedPipeline);
|
||||||
|
pipelineState.flow_display.nodes = this.reactFlowState.nodes;
|
||||||
|
pipelineState.flow_display.edges = this.reactFlowState.edges;
|
||||||
|
this.store.dispatch(updatePipeline({changes: {...pipelineState}}));
|
||||||
|
}
|
||||||
|
createPipelineStep() {
|
||||||
|
|
||||||
this.dialog.open(PipelineAddStepDialogComponent, {
|
this.dialog.open(PipelineAddStepDialogComponent, {
|
||||||
data: {defaultExperimentId: ''},
|
data: {defaultExperimentId: ''},
|
||||||
@ -24,7 +77,7 @@ export class EditPipelinePageComponent {
|
|||||||
.afterClosed()
|
.afterClosed()
|
||||||
.subscribe(pipeline => {
|
.subscribe(pipeline => {
|
||||||
if (pipeline) {
|
if (pipeline) {
|
||||||
this.store.dispatch(createPipelineStep({pipelinesCreateStepRequest: pipeline}));
|
this.store.dispatch(createPipelineStep({pipelinesCreateStepRequest: {...pipeline, pipeline_id: this.pipelineId}}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,4 +103,19 @@ export class EditPipelinePageComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
public nodesChangedInReactFlow(data) {
|
||||||
|
this.reactFlowState.nodes = data;
|
||||||
|
//console.log("nodes changed", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
public edgesChangedInReactFlow(data) {
|
||||||
|
this.reactFlowState.edges = data;
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log("edges changed", data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { createRoot } from 'react-dom/client';
|
|||||||
|
|
||||||
|
|
||||||
import { PipelineFlowComponent } from './react/pipeline-flow.component';
|
import { PipelineFlowComponent } from './react/pipeline-flow.component';
|
||||||
|
import { Pipeline } from '~/business-logic/model/pipelines/pipeline';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -20,26 +21,29 @@ const containerElementName = 'myReactComponentContainer';
|
|||||||
export class FlowEditorComponent implements OnChanges, OnDestroy, AfterViewInit {
|
export class FlowEditorComponent implements OnChanges, OnDestroy, AfterViewInit {
|
||||||
@ViewChild(containerElementName, {static: false}) containerRef: ElementRef;
|
@ViewChild(containerElementName, {static: false}) containerRef: ElementRef;
|
||||||
|
|
||||||
@Input() public counter = 10;
|
@Input() public pipelineData: Pipeline;
|
||||||
@Output() public componentClick = new EventEmitter<void>();
|
@Output() nodesChangedInReactFlow = new EventEmitter<Array<unknown>>();
|
||||||
|
@Output() edgesChangedInReactFlow = new EventEmitter<Array<unknown>>();
|
||||||
|
|
||||||
initialNodes = [
|
/* initialNodes = [
|
||||||
{ id: '1', position: { x: 0, y: 0 }, data: { label: '1' }, type: "normal" },
|
{ id: '1', position: { x: 0, y: 0 }, data: { label: '1' }, type: "normal" },
|
||||||
{ id: '2', position: { x: 0, y: 100 }, data: { label: '2' }, type: "normal" },
|
{ id: '2', position: { x: 0, y: 100 }, data: { label: '2' }, type: "normal" },
|
||||||
];
|
];
|
||||||
initialEdges = [{ id: 'e1-2', source: '1', target: '2' }];
|
initialEdges = [{ id: 'e1-2', source: '1', target: '2' }]; */
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.handleDivClicked = this.handleDivClicked.bind(this);
|
//this.handleDivClicked = this.handleDivClicked.bind(this);
|
||||||
|
this.nodesDataChanged = this.nodesDataChanged.bind(this);
|
||||||
|
this.edgesDataChanged = this.edgesDataChanged.bind(this);
|
||||||
window.React = React;
|
window.React = React;
|
||||||
}
|
}
|
||||||
|
|
||||||
public handleDivClicked() {
|
// public handleDivClicked() {
|
||||||
if (this.componentClick) {
|
// if (this.componentClick) {
|
||||||
this.componentClick.emit();
|
// this.componentClick.emit();
|
||||||
this.render();
|
// this.render();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
ngOnChanges(_changes: SimpleChanges): void {
|
ngOnChanges(_changes: SimpleChanges): void {
|
||||||
@ -51,8 +55,21 @@ export class FlowEditorComponent implements OnChanges, OnDestroy, AfterViewInit
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
if(this.containerRef?.nativeElement)
|
||||||
ReactDOM.unmountComponentAtNode(this.containerRef.nativeElement);
|
ReactDOM.unmountComponentAtNode(this.containerRef.nativeElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public nodesDataChanged(nodes: Array<unknown>) {
|
||||||
|
this.nodesChangedInReactFlow?.emit(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
public edgesDataChanged(edges: Array<unknown>) {
|
||||||
|
this.edgesChangedInReactFlow?.emit(edges)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private render() {
|
private render() {
|
||||||
const root = createRoot(this.containerRef.nativeElement);
|
const root = createRoot(this.containerRef.nativeElement);
|
||||||
|
|
||||||
@ -60,8 +77,10 @@ export class FlowEditorComponent implements OnChanges, OnDestroy, AfterViewInit
|
|||||||
root.render(React.createElement("div", {
|
root.render(React.createElement("div", {
|
||||||
className: 'i-am-classy',
|
className: 'i-am-classy',
|
||||||
children: React.createElement(PipelineFlowComponent, {
|
children: React.createElement(PipelineFlowComponent, {
|
||||||
initialNodes: this.initialNodes,
|
initialNodes: this.pipelineData?.flow_display?.nodes,
|
||||||
initialEdges: this.initialEdges
|
initialEdges: this.pipelineData?.flow_display?.edges,
|
||||||
|
onNodesDataChanged: this.nodesDataChanged,
|
||||||
|
onEdgesDataChanged: this.edgesDataChanged
|
||||||
})
|
})
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,65 @@
|
|||||||
import * as React from 'react';
|
import * as React from "react";
|
||||||
import { FunctionComponent, useCallback, useEffect, useRef, useState } from 'react';
|
import {
|
||||||
import ReactFlow, { Background, Controls, MarkerType, MiniMap, addEdge, useEdgesState, useNodesState, updateEdge, BackgroundVariant } from 'reactflow';
|
FunctionComponent,
|
||||||
import PipelineStepComponent from './pipeline-step.component';
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import ReactFlow, {
|
||||||
|
Background,
|
||||||
|
Controls,
|
||||||
|
MarkerType,
|
||||||
|
MiniMap,
|
||||||
|
addEdge,
|
||||||
|
useEdgesState,
|
||||||
|
useNodesState,
|
||||||
|
updateEdge,
|
||||||
|
BackgroundVariant,
|
||||||
|
} from "reactflow";
|
||||||
|
import PipelineStepComponent from "./pipeline-step.component";
|
||||||
|
|
||||||
export interface IMyComponentProps {
|
export interface IMyComponentProps {
|
||||||
initialNodes: any;
|
initialNodes: any;
|
||||||
initialEdges: any;
|
initialEdges: any;
|
||||||
|
onNodesDataChanged: Function,
|
||||||
|
onEdgesDataChanged: Function
|
||||||
}
|
}
|
||||||
|
|
||||||
const edgeOptions = {
|
const edgeOptions = {
|
||||||
animated: true,
|
animated: true,
|
||||||
style: {
|
style: {
|
||||||
stroke: '#B0B0B0',
|
stroke: "#B0B0B0",
|
||||||
|
|
||||||
},
|
},
|
||||||
markerEnd: {
|
markerEnd: {
|
||||||
type: MarkerType.ArrowClosed,
|
type: MarkerType.ArrowClosed,
|
||||||
color: '#B0B0B0',
|
color: "#B0B0B0",
|
||||||
strokeWidth: 2
|
strokeWidth: 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const connectionLineStyle = { stroke: '#B0B0B0' };
|
const connectionLineStyle = { stroke: "#B0B0B0" };
|
||||||
|
|
||||||
export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (props: IMyComponentProps) => {
|
|
||||||
|
|
||||||
|
export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (
|
||||||
|
props: IMyComponentProps
|
||||||
|
) => {
|
||||||
// const timerHandle = useRef<number | null>(null);
|
// const timerHandle = useRef<number | null>(null);
|
||||||
// const [stateCounter, setStateCounter] = useState(42);
|
// const [stateCounter, setStateCounter] = useState(42);
|
||||||
|
|
||||||
const [nodes, setNodes, onNodesChange] = useNodesState(props.initialNodes);
|
const [nodes, setNodes, onNodesChange] = useNodesState(props.initialNodes?.length ? props.initialNodes : []);
|
||||||
const [edges, setEdges, onEdgesChange] = useEdgesState(props.initialEdges);
|
const [edges, setEdges, onEdgesChange] = useEdgesState(props.initialEdges?.length? props.initialEdges: []);
|
||||||
const edgeUpdateSuccessful = useRef(true);
|
const edgeUpdateSuccessful = useRef(true);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
props.onNodesDataChanged(nodes);
|
||||||
|
}, [nodes]);
|
||||||
|
React.useEffect(() => {
|
||||||
|
props.onEdgesDataChanged(edges)
|
||||||
|
}, [edges])
|
||||||
|
|
||||||
|
|
||||||
const onConnect = useCallback(
|
const onConnect = useCallback(
|
||||||
(params) => setEdges((eds) => addEdge(params, eds)),
|
(params) => setEdges((eds) => addEdge(params, eds)),
|
||||||
[setEdges],
|
[setEdges]
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,7 +99,6 @@ export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (prop
|
|||||||
// setNodeData(clone(node));
|
// setNodeData(clone(node));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const onPaneClick = () => {
|
const onPaneClick = () => {
|
||||||
// setIsShowNodeEditModal(false);
|
// setIsShowNodeEditModal(false);
|
||||||
};
|
};
|
||||||
@ -89,8 +110,15 @@ export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (prop
|
|||||||
["NormalOperationPipelineNode"]
|
["NormalOperationPipelineNode"]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
return <div style={{ width: '100%', height: 'calc(100vh - 130px)', position: "relative", overflow: "hidden" }}>
|
<div
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
height: "calc(100vh - 130px)",
|
||||||
|
position: "relative",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodes={nodes}
|
nodes={nodes}
|
||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
@ -124,5 +152,6 @@ export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (prop
|
|||||||
<MiniMap />
|
<MiniMap />
|
||||||
<Background gap={12} size={1} />
|
<Background gap={12} size={1} />
|
||||||
</ReactFlow> */}
|
</ReactFlow> */}
|
||||||
</div>;
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
@ -2,7 +2,8 @@ import React from "react";
|
|||||||
import { Handle, Position } from 'reactflow';
|
import { Handle, Position } from 'reactflow';
|
||||||
/* import "./pipeline-step.css" */
|
/* import "./pipeline-step.css" */
|
||||||
|
|
||||||
export default function PipelineStepComponent({ data }) {
|
export default function PipelineStepComponent({ data, ...others }) {
|
||||||
|
//console.log("from reactstep", others)
|
||||||
return (
|
return (
|
||||||
<div className="" style={{
|
<div className="" style={{
|
||||||
padding: "2px",
|
padding: "2px",
|
||||||
@ -32,7 +33,7 @@ export default function PipelineStepComponent({ data }) {
|
|||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
whiteSpace: "nowrap"
|
whiteSpace: "nowrap"
|
||||||
}
|
}
|
||||||
}>{data.name} test name</div>
|
}>{data.name}</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="step-part step-footer queued" style={{
|
<div className="step-part step-footer queued" style={{
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
smUniqueNameValidator >
|
smUniqueNameValidator >
|
||||||
<i matSuffix class="al-icon sm-md search-icon me-2"
|
<i matSuffix class="al-icon sm-md search-icon me-2"
|
||||||
[ngClass]="experimentInput.value? 'al-ico-dialog-x pointer':'al-ico-search'"
|
[ngClass]="experimentInput.value? 'al-ico-dialog-x pointer':'al-ico-search'"
|
||||||
(mousedown)="!isFocused(experimentInputRef) && experimentInput.value && clear(); experimentInput.reset(); experimentInputRef.focus()"
|
(mousedown)="!isFocused(experimentInputRef) && experimentInput.value && clear(); experimentInput.reset(); experimentInputRef.focus(); step.parameters = [];"
|
||||||
smClickStopPropagation></i>
|
smClickStopPropagation></i>
|
||||||
<mat-error *ngIf="experimentInput?.errors?.existName">Please provide a experiment</mat-error>
|
<mat-error *ngIf="experimentInput?.errors?.existName">Please provide a experiment</mat-error>
|
||||||
<mat-error *ngIf="experimentInput?.errors?.uniqueName && !readOnlyExperimentsNames.includes(step.experiment?.label)">Please
|
<mat-error *ngIf="experimentInput?.errors?.uniqueName && !readOnlyExperimentsNames.includes(step.experiment?.label)">Please
|
||||||
@ -52,7 +52,7 @@
|
|||||||
<textarea class="step-description" name="description" matInput [(ngModel)]="step.description"
|
<textarea class="step-description" name="description" matInput [(ngModel)]="step.description"
|
||||||
#description="ngModel"></textarea>
|
#description="ngModel"></textarea>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<div class="parameters">
|
<div class="parameters" *ngIf="step?.parameters?.length">
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<mat-label>Parameters</mat-label>
|
<mat-label>Parameters</mat-label>
|
||||||
<sm-search search-button
|
<sm-search search-button
|
||||||
|
@ -18,8 +18,9 @@ import {
|
|||||||
} from '@common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component';
|
} from '@common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component';
|
||||||
import { Task } from '~/business-logic/model/tasks/task';
|
import { Task } from '~/business-logic/model/tasks/task';
|
||||||
import { PipelineParametersComponent } from '@common/pipelines/pipeline-parameters/pipeline-parameters.component';
|
import { PipelineParametersComponent } from '@common/pipelines/pipeline-parameters/pipeline-parameters.component';
|
||||||
import { PipelinesParameter } from '~/business-logic/model/pipelines/pipelinesParameter';
|
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
import { ParamsItem } from '~/business-logic/model/tasks/paramsItem';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -36,22 +37,16 @@ export class PipelineAddStepFormComponent implements OnChanges, OnDestroy {
|
|||||||
public panelHeight: number;
|
public panelHeight: number;
|
||||||
private subs = new Subscription();
|
private subs = new Subscription();
|
||||||
private rootFiltered: boolean;
|
private rootFiltered: boolean;
|
||||||
public readonly experimentsRoot = {label: 'My experiment', value: null};
|
public readonly experimentsRoot = {label: 'My experiment', value: null, parameters: []};
|
||||||
@ViewChild('experimentInput') experimentInput: NgModel;
|
@ViewChild('experimentInput') experimentInput: NgModel;
|
||||||
|
|
||||||
public pipelinesNames: Array<string>;
|
public pipelinesNames: Array<string>;
|
||||||
public experimentsNames: Array<string>;
|
public experimentsNames: Array<string>;
|
||||||
public step: { name: string; description: string; experiment: { label: string; value: string }, parameters: Array<PipelinesParameter> } = {
|
public step: { name: string; description: string; experiment: { label: string; value: string }, parameters: Array<ParamsItem> } = {
|
||||||
name: null,
|
name: null,
|
||||||
description: '',
|
description: '',
|
||||||
experiment: null,
|
experiment: null,
|
||||||
parameters: [{
|
parameters: [],
|
||||||
name: "Paramter1",
|
|
||||||
value: ""
|
|
||||||
}, {
|
|
||||||
name: "Parameter2",
|
|
||||||
value: ""
|
|
||||||
}],
|
|
||||||
};
|
};
|
||||||
filterText: string = '';
|
filterText: string = '';
|
||||||
isAutoCompleteOpen: boolean;
|
isAutoCompleteOpen: boolean;
|
||||||
@ -95,7 +90,7 @@ export class PipelineAddStepFormComponent implements OnChanges, OnDestroy {
|
|||||||
this._experiments = experiments;
|
this._experiments = experiments;
|
||||||
this.experimentsOptions = [
|
this.experimentsOptions = [
|
||||||
...((this.rootFiltered || experiments === null) ? [] : [this.experimentsRoot]),
|
...((this.rootFiltered || experiments === null) ? [] : [this.experimentsRoot]),
|
||||||
...(experiments ? experiments.map(experiment => ({label: experiment.name, value: experiment.id})) : [])
|
...(experiments ? experiments.map(experiment => ({label: experiment.name, value: experiment.id, parameters: experiment.hyperparams})) : [])
|
||||||
];
|
];
|
||||||
this.experimentsNames = this.experimentsOptions.map(experiment => experiment.label);
|
this.experimentsNames = this.experimentsOptions.map(experiment => experiment.label);
|
||||||
}
|
}
|
||||||
@ -136,6 +131,25 @@ export class PipelineAddStepFormComponent implements OnChanges, OnDestroy {
|
|||||||
|
|
||||||
experimentSelected($event: MatOptionSelectionChange) {
|
experimentSelected($event: MatOptionSelectionChange) {
|
||||||
this.step.experiment = {label: $event.source.value.label, value: $event.source.value.value};
|
this.step.experiment = {label: $event.source.value.label, value: $event.source.value.value};
|
||||||
|
this.step.parameters = [];
|
||||||
|
for (const section in $event.source?.value?.parameters) {
|
||||||
|
for (const param in $event.source?.value?.parameters[section]) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log($event.source?.value?.parameters[section][param]);
|
||||||
|
this.step.parameters.push({
|
||||||
|
name: $event.source?.value?.parameters[section][param].name,
|
||||||
|
value: $event.source?.value?.parameters[section][param].value,
|
||||||
|
section: $event.source?.value?.parameters[section][param].section
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//.map((paramSectionKey, paramSectionValue) => {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
|
||||||
|
// paramSec.forEach((paraKey, paramVal) => {
|
||||||
|
//
|
||||||
|
// })
|
||||||
|
//});
|
||||||
}
|
}
|
||||||
setIsAutoCompleteOpen(focus: boolean) {
|
setIsAutoCompleteOpen(focus: boolean) {
|
||||||
this.isAutoCompleteOpen = focus;
|
this.isAutoCompleteOpen = focus;
|
||||||
|
@ -1,46 +1,50 @@
|
|||||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
import {pageSize} from '@common/projects/common-projects.consts';
|
import { pageSize } from "@common/projects/common-projects.consts";
|
||||||
import {CommonProjectsPageComponent} from '@common/projects/containers/projects-page/common-projects-page.component';
|
import { CommonProjectsPageComponent } from "@common/projects/containers/projects-page/common-projects-page.component";
|
||||||
import {isExample} from '@common/shared/utils/shared-utils';
|
import { isExample } from "@common/shared/utils/shared-utils";
|
||||||
import {trackById} from '@common/shared/utils/forms-track-by';
|
import { trackById } from "@common/shared/utils/forms-track-by";
|
||||||
import {
|
import {
|
||||||
addProjectTags,
|
addProjectTags,
|
||||||
getProjectsTags, setBreadcrumbsOptions,
|
getProjectsTags,
|
||||||
|
setBreadcrumbsOptions,
|
||||||
setDefaultNestedModeForFeature,
|
setDefaultNestedModeForFeature,
|
||||||
setSelectedProjectId,
|
setSelectedProjectId,
|
||||||
setTags
|
setTags,
|
||||||
} from '@common/core/actions/projects.actions';
|
} from "@common/core/actions/projects.actions";
|
||||||
import {
|
import {
|
||||||
selectDefaultNestedModeForFeature,
|
selectDefaultNestedModeForFeature,
|
||||||
selectMainPageTagsFilter,
|
selectMainPageTagsFilter,
|
||||||
selectMainPageTagsFilterMatchMode,
|
selectMainPageTagsFilterMatchMode,
|
||||||
selectProjectTags
|
selectProjectTags,
|
||||||
} from '@common/core/reducers/projects.reducer';
|
} from "@common/core/reducers/projects.reducer";
|
||||||
import {combineLatest, Observable, Subscription} from 'rxjs';
|
import { combineLatest, Observable, Subscription } from "rxjs";
|
||||||
import {Project} from '~/business-logic/model/projects/project';
|
import { Project } from "~/business-logic/model/projects/project";
|
||||||
import {
|
import {
|
||||||
getAllProjectsPageProjects,
|
getAllProjectsPageProjects,
|
||||||
resetProjects,
|
resetProjects,
|
||||||
showExamplePipelines,
|
showExamplePipelines,
|
||||||
updateProject
|
updateProject,
|
||||||
} from '@common/projects/common-projects.actions';
|
} from "@common/projects/common-projects.actions";
|
||||||
import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle';
|
import { ProjectsGetAllResponseSingle } from "~/business-logic/model/projects/projectsGetAllResponseSingle";
|
||||||
import {selectShowPipelineExamples} from '@common/projects/common-projects.reducer';
|
import { selectShowPipelineExamples } from "@common/projects/common-projects.reducer";
|
||||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
import { EntityTypeEnum } from "~/shared/constants/non-common-consts";
|
||||||
// import {
|
// import {
|
||||||
// PipelinesEmptyStateComponent
|
// PipelinesEmptyStateComponent
|
||||||
// } from '@common/pipelines/pipelines-page/pipelines-empty-state/pipelines-empty-state.component';
|
// } from '@common/pipelines/pipelines-page/pipelines-empty-state/pipelines-empty-state.component';
|
||||||
import {debounceTime, skip, withLatestFrom} from 'rxjs/operators';
|
import { debounceTime, skip, withLatestFrom } from "rxjs/operators";
|
||||||
import {ProjectTypeEnum} from '@common/nested-project-view/nested-project-view-page/nested-project-view-page.component';
|
import { ProjectTypeEnum } from "@common/nested-project-view/nested-project-view-page/nested-project-view-page.component";
|
||||||
import { PipelineDialogComponent } from '../pipeline-dialog/pipeline-dialog.component';
|
import { PipelineDialogComponent } from "../pipeline-dialog/pipeline-dialog.component";
|
||||||
import { createPipeline } from '../pipelines.actions';
|
import { createPipeline } from "../pipelines.actions";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'sm-pipelines-page',
|
selector: "sm-pipelines-page",
|
||||||
templateUrl: './pipelines-page.component.html',
|
templateUrl: "./pipelines-page.component.html",
|
||||||
styleUrls: ['./pipelines-page.component.scss']
|
styleUrls: ["./pipelines-page.component.scss"],
|
||||||
})
|
})
|
||||||
export class PipelinesPageComponent extends CommonProjectsPageComponent implements OnInit, OnDestroy {
|
export class PipelinesPageComponent
|
||||||
|
extends CommonProjectsPageComponent
|
||||||
|
implements OnInit, OnDestroy
|
||||||
|
{
|
||||||
initPipelineCode = `from clearml import PipelineDecorator
|
initPipelineCode = `from clearml import PipelineDecorator
|
||||||
|
|
||||||
@PipelineDecorator.component(cache=True, execution_queue="default")
|
@PipelineDecorator.component(cache=True, execution_queue="default")
|
||||||
@ -76,38 +80,42 @@ if __name__ == '__main__':
|
|||||||
private mainPageFilterSub: Subscription;
|
private mainPageFilterSub: Subscription;
|
||||||
public isNested$: Observable<boolean>;
|
public isNested$: Observable<boolean>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
override ngOnInit() {
|
override ngOnInit() {
|
||||||
super.ngOnInit();
|
super.ngOnInit();
|
||||||
this.store.dispatch(getProjectsTags({entity: this.getName()}));
|
this.store.dispatch(getProjectsTags({ entity: this.getName() }));
|
||||||
this.showExamples$ = this.store.select(selectShowPipelineExamples);
|
this.showExamples$ = this.store.select(selectShowPipelineExamples);
|
||||||
this.projectsTags$ = this.store.select(selectProjectTags);
|
this.projectsTags$ = this.store.select(selectProjectTags);
|
||||||
this.mainPageFilterSub = combineLatest([
|
this.mainPageFilterSub = combineLatest([
|
||||||
this.store.select(selectMainPageTagsFilter),
|
this.store.select(selectMainPageTagsFilter),
|
||||||
this.store.select(selectMainPageTagsFilterMatchMode)
|
this.store.select(selectMainPageTagsFilterMatchMode),
|
||||||
]).pipe(debounceTime(0), skip(1))
|
])
|
||||||
|
.pipe(debounceTime(0), skip(1))
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.store.dispatch(resetProjects());
|
this.store.dispatch(resetProjects());
|
||||||
this.store.dispatch(getAllProjectsPageProjects());
|
this.store.dispatch(getAllProjectsPageProjects());
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override ngOnDestroy() {
|
override ngOnDestroy() {
|
||||||
super.ngOnDestroy();
|
super.ngOnDestroy();
|
||||||
this.headerUserFocusSub?.unsubscribe();
|
this.headerUserFocusSub?.unsubscribe();
|
||||||
this.mainPageFilterSub.unsubscribe();
|
this.mainPageFilterSub.unsubscribe();
|
||||||
this.store.dispatch(setTags({tags: []}));
|
this.store.dispatch(setTags({ tags: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
addTag(project: Project, newTag: string) {
|
addTag(project: Project, newTag: string) {
|
||||||
const tags = [...project.tags, newTag];
|
const tags = [...project.tags, newTag];
|
||||||
this.store.dispatch(updateProject({id: project.id, changes: {tags}}));
|
this.store.dispatch(updateProject({ id: project.id, changes: { tags } }));
|
||||||
this.store.dispatch(addProjectTags({tags: [newTag], systemTags: []}));
|
this.store.dispatch(addProjectTags({ tags: [newTag], systemTags: [] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTag(project: Project, deleteTag: string) {
|
removeTag(project: Project, deleteTag: string) {
|
||||||
const tags = project.tags?.filter(tag => tag != deleteTag);
|
const tags = project.tags?.filter((tag) => tag != deleteTag);
|
||||||
this.store.dispatch(updateProject({id: project.id, changes: {tags}}));
|
this.store.dispatch(updateProject({ id: project.id, changes: { tags } }));
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
@ -116,13 +124,27 @@ if __name__ == '__main__':
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override projectCardClicked(project: ProjectsGetAllResponseSingle) {
|
public override projectCardClicked(project: ProjectsGetAllResponseSingle) {
|
||||||
this.router.navigate([project.id, 'experiments'], {relativeTo: this.projectId ? this.route.parent.parent.parent : this.route});
|
this.router.navigate([project.id, "experiments"], {
|
||||||
this.store.dispatch(setSelectedProjectId({projectId: project.id, example: isExample(project)}));
|
relativeTo: this.projectId ? this.route.parent.parent.parent : this.route,
|
||||||
|
});
|
||||||
|
this.store.dispatch(
|
||||||
|
setSelectedProjectId({
|
||||||
|
projectId: project.id,
|
||||||
|
example: isExample(project),
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public pipelineEditClicked(pipeline: ProjectsGetAllResponseSingle) {
|
public pipelineEditClicked(pipeline: ProjectsGetAllResponseSingle) {
|
||||||
this.router.navigate([pipeline.id, 'edit'], {relativeTo: this.projectId ? this.route.parent.parent.parent : this.route});
|
this.router.navigate([pipeline.id, /* pipeline.basename, */ "edit"], {
|
||||||
this.store.dispatch(setSelectedProjectId({projectId: pipeline.id, example: isExample(pipeline)}));
|
relativeTo: this.projectId ? this.route.parent.parent.parent : this.route,
|
||||||
|
});
|
||||||
|
this.store.dispatch(
|
||||||
|
setSelectedProjectId({
|
||||||
|
projectId: pipeline.id,
|
||||||
|
example: isExample(pipeline),
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override getName() {
|
protected override getName() {
|
||||||
@ -130,20 +152,22 @@ if __name__ == '__main__':
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override getDeletePopupEntitiesList() {
|
protected override getDeletePopupEntitiesList() {
|
||||||
return 'run';
|
return "run";
|
||||||
}
|
}
|
||||||
|
|
||||||
createPipeline() {
|
createPipeline() {
|
||||||
|
this.dialog
|
||||||
this.dialog.open(PipelineDialogComponent, {
|
.open(PipelineDialogComponent, {
|
||||||
data: {defaultProjectId: this.projectId},
|
data: { defaultProjectId: this.projectId },
|
||||||
panelClass: 'light-theme',
|
panelClass: "light-theme",
|
||||||
width: '690px'
|
width: "690px",
|
||||||
})
|
})
|
||||||
.afterClosed()
|
.afterClosed()
|
||||||
.subscribe(pipeline => {
|
.subscribe((pipeline) => {
|
||||||
if (pipeline) {
|
if (pipeline) {
|
||||||
this.store.dispatch(createPipeline({pipelinesCreateRequest: pipeline}));
|
this.store.dispatch(
|
||||||
|
createPipeline({ pipelinesCreateRequest: pipeline })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -153,7 +177,6 @@ if __name__ == '__main__':
|
|||||||
// },
|
// },
|
||||||
// width: '640px'
|
// width: '640px'
|
||||||
// });
|
// });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createExamples() {
|
createExamples() {
|
||||||
@ -161,44 +184,69 @@ if __name__ == '__main__':
|
|||||||
}
|
}
|
||||||
|
|
||||||
override shouldReRoute(selectedProject, config) {
|
override shouldReRoute(selectedProject, config) {
|
||||||
const relevantSubProjects = selectedProject?.sub_projects?.filter(proj => proj.name.includes('.pipelines'));
|
const relevantSubProjects = selectedProject?.sub_projects?.filter((proj) =>
|
||||||
return config[2] === 'projects' && selectedProject.id !== '*' && (relevantSubProjects?.every(subProject => subProject.name.startsWith(selectedProject.name + '/.')));
|
proj.name.includes(".pipelines")
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
config[2] === "projects" &&
|
||||||
|
selectedProject.id !== "*" &&
|
||||||
|
relevantSubProjects?.every((subProject) =>
|
||||||
|
subProject.name.startsWith(selectedProject.name + "/.")
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
override noProjectsReRoute() {
|
override noProjectsReRoute() {
|
||||||
return this.router.navigate(['..', 'pipelines'], {relativeTo: this.route});
|
return this.router.navigate(["..", "pipelines"], {
|
||||||
|
relativeTo: this.route,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleNestedView(nested: boolean) {
|
toggleNestedView(nested: boolean) {
|
||||||
this.store.dispatch(setDefaultNestedModeForFeature({feature: 'pipelines', isNested: nested}));
|
this.store.dispatch(
|
||||||
|
setDefaultNestedModeForFeature({ feature: "pipelines", isNested: nested })
|
||||||
|
);
|
||||||
|
|
||||||
if (nested) {
|
if (nested) {
|
||||||
this.router.navigate(['*', 'projects'], {relativeTo: this.route});
|
this.router.navigate(["*", "projects"], { relativeTo: this.route });
|
||||||
} else {
|
} else {
|
||||||
this.router.navigateByUrl('pipelines');
|
this.router.navigateByUrl("pipelines");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override setupBreadcrumbsOptions() {
|
override setupBreadcrumbsOptions() {
|
||||||
this.subs.add(this.selectedProject$.pipe(
|
this.subs.add(
|
||||||
|
this.selectedProject$
|
||||||
|
.pipe(
|
||||||
withLatestFrom(this.store.select(selectDefaultNestedModeForFeature))
|
withLatestFrom(this.store.select(selectDefaultNestedModeForFeature))
|
||||||
).subscribe(([selectedProject, defaultNestedModeForFeature]) => {
|
)
|
||||||
this.store.dispatch(setBreadcrumbsOptions({
|
.subscribe(([selectedProject, defaultNestedModeForFeature]) => {
|
||||||
|
this.store.dispatch(
|
||||||
|
setBreadcrumbsOptions({
|
||||||
breadcrumbOptions: {
|
breadcrumbOptions: {
|
||||||
showProjects: !!selectedProject,
|
showProjects: !!selectedProject,
|
||||||
featureBreadcrumb: {
|
featureBreadcrumb: {
|
||||||
name: 'PIPELINES',
|
name: "PIPELINES",
|
||||||
url: defaultNestedModeForFeature['pipelines'] ? 'pipelines/*/projects' : 'pipelines'
|
url: defaultNestedModeForFeature["pipelines"]
|
||||||
|
? "pipelines/*/projects"
|
||||||
|
: "pipelines",
|
||||||
},
|
},
|
||||||
projectsOptions: {
|
projectsOptions: {
|
||||||
basePath: 'pipelines',
|
basePath: "pipelines",
|
||||||
filterBaseNameWith: ['.pipelines'],
|
filterBaseNameWith: [".pipelines"],
|
||||||
compareModule: null,
|
compareModule: null,
|
||||||
showSelectedProject: selectedProject?.id !== '*',
|
showSelectedProject: selectedProject?.id !== "*",
|
||||||
...(selectedProject && selectedProject?.id !== '*' && {selectedProjectBreadcrumb: {name: selectedProject?.basename}})
|
...(selectedProject &&
|
||||||
}
|
selectedProject?.id !== "*" && {
|
||||||
}
|
selectedProjectBreadcrumb: {
|
||||||
}));
|
name: selectedProject?.basename,
|
||||||
}));
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import {createAction, props} from '@ngrx/store';
|
import {createAction, props} from '@ngrx/store';
|
||||||
// import {ReportsGetAllExResponse} from '~/business-logic/model/reports/reportsGetAllExResponse';
|
// import {ReportsGetAllExResponse} from '~/business-logic/model/reports/reportsGetAllExResponse';
|
||||||
// import {IReport} from './reports.consts';
|
// import {IReport} from './reports.consts';
|
||||||
import { Pipeline, PipelinesCreateRequest } from '~/business-logic/model/pipelines/models';
|
import { Pipeline, PipelinesCreateRequest, PipelinesUpdateRequest, PipelinesUpdateResponse, pipelinesSettingsModel } from '~/business-logic/model/pipelines/models';
|
||||||
import { PipelinesCreateStepsRequest } from '~/business-logic/model/pipelines/pipelinesCreateStepsRequest';
|
import { PipelinesCreateStepsRequest } from '~/business-logic/model/pipelines/pipelinesCreateStepsRequest';
|
||||||
import { pipelinesSettingsModel } from '~/business-logic/model/pipelines/models';
|
import { TasksGetByIdRequest } from '~/business-logic/model/tasks/models';
|
||||||
import { Task } from '~/business-logic/model/tasks/task';
|
import { Task } from '~/business-logic/model/tasks/task';
|
||||||
|
|
||||||
export const PIPELINES_PREFIX = 'PIPELINES_';
|
export const PIPELINES_PREFIX = 'PIPELINES_';
|
||||||
@ -22,6 +22,31 @@ export const settingsPipelineAction= createAction(
|
|||||||
props<{ pipelinesSettingsRequest: pipelinesSettingsModel }>()
|
props<{ pipelinesSettingsRequest: pipelinesSettingsModel }>()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getPipelineById = createAction(
|
||||||
|
PIPELINES_PREFIX + '[GET_PIPELINE_BY_ID]',
|
||||||
|
props<{ id: string, name: string }>()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const setSelectedPipeline = createAction(
|
||||||
|
PIPELINES_PREFIX + '[SET_SELECTED_PIPELINE]',
|
||||||
|
props<{ data: PipelinesUpdateResponse }>()
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
export const updatePipeline = createAction(
|
||||||
|
PIPELINES_PREFIX + '[update pipeline]',
|
||||||
|
props<{changes: Partial<PipelinesUpdateRequest>}>()
|
||||||
|
);
|
||||||
|
export const updatePipelineSuccess = createAction(
|
||||||
|
PIPELINES_PREFIX + '[update pipeline success]',
|
||||||
|
props<{changes: Partial<PipelinesUpdateResponse>}>()
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getExperimentById = createAction(
|
||||||
|
PIPELINES_PREFIX + 'GET_EXPERIMENTS_BY_ID',
|
||||||
|
props<{ getExperimentByIdRequest: TasksGetByIdRequest }>()
|
||||||
|
);
|
||||||
|
|
||||||
export const getAllExperiments = createAction(
|
export const getAllExperiments = createAction(
|
||||||
PIPELINES_PREFIX + 'GET_EXPERIMENTS',
|
PIPELINES_PREFIX + 'GET_EXPERIMENTS',
|
||||||
props<{ query: string; regExp?: boolean }>()
|
props<{ query: string; regExp?: boolean }>()
|
||||||
@ -33,14 +58,7 @@ export const setExperimentsResults = createAction(
|
|||||||
props<{ experiments: Task[]}>()
|
props<{ experiments: Task[]}>()
|
||||||
);
|
);
|
||||||
|
|
||||||
export const updateProject = createAction(
|
|
||||||
PIPELINES_PREFIX + '[update pipeline]',
|
|
||||||
props<{id: string; changes: Partial<Pipeline>}>()
|
|
||||||
);
|
|
||||||
export const updatePipelineSuccess = createAction(
|
|
||||||
PIPELINES_PREFIX + '[update pipeline success]',
|
|
||||||
props<{id: string; changes: Partial<Pipeline>}>()
|
|
||||||
);
|
|
||||||
export const getAllPipelinesPagePipelines = createAction(
|
export const getAllPipelinesPagePipelines = createAction(
|
||||||
PIPELINES_PREFIX + 'GET_PIPELINES'
|
PIPELINES_PREFIX + 'GET_PIPELINES'
|
||||||
);
|
);
|
||||||
@ -113,10 +131,7 @@ export const showExampleDatasets = createAction(PIPELINES_PREFIX + '[show datase
|
|||||||
// props<{ reports: IReport[]; scroll: ReportsGetAllExResponse['scroll_id']; noMoreReports: boolean }>()
|
// props<{ reports: IReport[]; scroll: ReportsGetAllExResponse['scroll_id']; noMoreReports: boolean }>()
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// export const getReport = createAction(
|
|
||||||
// PIPELINES_PREFIX + '[get report]',
|
|
||||||
// props<{ id: string }>()
|
|
||||||
// );
|
|
||||||
|
|
||||||
// export const setReport = createAction(
|
// export const setReport = createAction(
|
||||||
// PIPELINES_PREFIX + '[set report]',
|
// PIPELINES_PREFIX + '[set report]',
|
||||||
@ -135,6 +150,9 @@ export const showExampleDatasets = createAction(PIPELINES_PREFIX + '[show datase
|
|||||||
// );
|
// );
|
||||||
|
|
||||||
// export const moveReport = createAction(
|
// export const moveReport = createAction(
|
||||||
|
// The `setExperimentsResults` action is updating the state with a new array of experiments. It
|
||||||
|
// takes in an action containing the new array of experiments and updates the `experiments` field
|
||||||
|
// in the state with this new array.
|
||||||
// PIPELINES_PREFIX + '[move report]',
|
// PIPELINES_PREFIX + '[move report]',
|
||||||
// props<{ report: IReport }>()
|
// props<{ report: IReport }>()
|
||||||
// );
|
// );
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {Actions, /* concatLatestFrom, */ createEffect, ofType} from '@ngrx/effects';
|
import {Actions, concatLatestFrom, /* concatLatestFrom, */ createEffect, ofType} from '@ngrx/effects';
|
||||||
import {/* Action, */ Store} from '@ngrx/store';
|
import {/* Action, */ Store} from '@ngrx/store';
|
||||||
import {ActivatedRoute, Router} from '@angular/router';
|
import {ActivatedRoute, Router} from '@angular/router';
|
||||||
import {catchError, filter, map, mergeMap, switchMap, /* tap */} from 'rxjs/operators';
|
import {catchError, filter, map, mergeMap, switchMap, /* tap */} from 'rxjs/operators';
|
||||||
import {activeLoader, /* addMessage, */ deactivateLoader, setServerError} from '../core/actions/layout.actions';
|
import {activeLoader, addMessage, /* addMessage, */ deactivateLoader, setServerError} from '../core/actions/layout.actions';
|
||||||
import {requestFailed} from '../core/actions/http.actions';
|
import {requestFailed} from '../core/actions/http.actions';
|
||||||
import {
|
import {
|
||||||
createPipeline, createPipelineStep, getAllExperiments, setExperimentsResults, settingsPipelineAction
|
createPipeline, createPipelineStep, getAllExperiments, setExperimentsResults, settingsPipelineAction,
|
||||||
|
createPipeline, createPipelineStep, getAllExperiments, getExperimentById, getPipelineById, setExperimentsResults, setSelectedPipeline, updatePipeline, updatePipelineSuccess
|
||||||
} from './pipelines.actions';
|
} from './pipelines.actions';
|
||||||
// import {ApiReportsService} from '~/business-logic/api-services/reports.service';
|
// import {ApiReportsService} from '~/business-logic/api-services/reports.service';
|
||||||
/* import {IReport, PAGE_SIZE} from './reports.consts';
|
/* import {IReport, PAGE_SIZE} from './reports.consts';
|
||||||
@ -49,11 +50,59 @@ import { pipelinesSettingsModel } from '~/business-logic/model/pipelines/pipelin
|
|||||||
import { ApiPipelinesService } from '~/business-logic/api-services/pipelines.service';
|
import { ApiPipelinesService } from '~/business-logic/api-services/pipelines.service';
|
||||||
import { PipelinesCreateStepsResponse } from '~/business-logic/model/pipelines/pipelinesCreateStepsResponse';
|
import { PipelinesCreateStepsResponse } from '~/business-logic/model/pipelines/pipelinesCreateStepsResponse';
|
||||||
import { ApiTasksService } from '~/business-logic/api-services/tasks.service';
|
import { ApiTasksService } from '~/business-logic/api-services/tasks.service';
|
||||||
|
import { PipelinesUpdateResponse } from '~/business-logic/model/pipelines/pipelinesUpdateResponse';
|
||||||
|
import { selectSelectedPipeline } from './pipelines.reducer';
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
import { MESSAGES_SEVERITY } from '@common/constants';
|
||||||
/* import {selectRouterParams} from '@common/core/reducers/router-reducer';
|
/* import {selectRouterParams} from '@common/core/reducers/router-reducer';
|
||||||
import {setMainPageTagsFilter} from '@common/core/actions/projects.actions';
|
import {setMainPageTagsFilter} from '@common/core/actions/projects.actions';
|
||||||
import {cleanTag} from '@common/shared/utils/helpers.util';
|
import {cleanTag} from '@common/shared/utils/helpers.util';
|
||||||
import {excludedKey, getTagsFilters} from '@common/shared/utils/tableParamEncode'; */
|
import {excludedKey, getTagsFilters} from '@common/shared/utils/tableParamEncode'; */
|
||||||
|
|
||||||
|
const checkIsBetween = (preNodePos: number, curNodePos: number, buffer1: number) => {
|
||||||
|
if (
|
||||||
|
preNodePos > curNodePos - buffer1 &&
|
||||||
|
preNodePos < curNodePos + buffer1
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkOverlappingNodes = (allNodes, x, y, buffer) => {
|
||||||
|
const overlap = (nodes, x1, y1, buffer) => {
|
||||||
|
|
||||||
|
|
||||||
|
const isOverlap = nodes.filter((node) => {
|
||||||
|
const isCheckX = checkIsBetween(node?.position?.x, x1, buffer);
|
||||||
|
const isCheckY = checkIsBetween(node?.position?.y, y1, buffer);
|
||||||
|
return isCheckX && isCheckY;
|
||||||
|
});
|
||||||
|
if (isOverlap.length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const overlapChecks = (nodes1, x, y, buffer) => {
|
||||||
|
let X1 = x;
|
||||||
|
let Y1 = y;
|
||||||
|
let resp = false;
|
||||||
|
if (nodes1) {
|
||||||
|
resp = overlap(nodes1, x, y, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp === true) {
|
||||||
|
X1 += buffer;
|
||||||
|
Y1 += buffer;
|
||||||
|
return overlapChecks(nodes1, X1, Y1, buffer);
|
||||||
|
}
|
||||||
|
return { x: X1, y: Y1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
return overlapChecks(allNodes, x, y, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PipelinesEffects {
|
export class PipelinesEffects {
|
||||||
|
|
||||||
@ -70,6 +119,8 @@ export class PipelinesEffects {
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
activeLoader = createEffect(() => this.actions.pipe(
|
activeLoader = createEffect(() => this.actions.pipe(
|
||||||
ofType(/* getReports, getReport, */ createPipeline, createPipelineStep, getAllExperiments, settingsPipelineAction/* updateReport, restoreReport, archiveReport */),
|
ofType(/* getReports, getReport, */ createPipeline, createPipelineStep, getAllExperiments, settingsPipelineAction/* updateReport, restoreReport, archiveReport */),
|
||||||
filter(action => !action['refresh']),
|
filter(action => !action['refresh']),
|
||||||
@ -80,11 +131,10 @@ export class PipelinesEffects {
|
|||||||
ofType(createPipeline),
|
ofType(createPipeline),
|
||||||
switchMap((action) => this.pipelinesApiService.pipelinesCreate(action.pipelinesCreateRequest)
|
switchMap((action) => this.pipelinesApiService.pipelinesCreate(action.pipelinesCreateRequest)
|
||||||
.pipe(mergeMap((res: PipelinesCreateResponse) => {
|
.pipe(mergeMap((res: PipelinesCreateResponse) => {
|
||||||
this.router.navigate(['pipelines', res.id, 'edit']);
|
this.router.navigate(['pipelines', res.project_id, 'edit']);
|
||||||
return [deactivateLoader(createPipeline.type)];
|
return [deactivateLoader(createPipeline.type), addMessage(MESSAGES_SEVERITY.SUCCESS, 'New pipeline created successfully. You can now start adding steps to it.')];
|
||||||
}),
|
}),
|
||||||
catchError(err => {
|
catchError(err => {
|
||||||
// this.router.navigate(['pipelines', 'b2c6686fb12e4649a954991ca7c24518', 'edit']);
|
|
||||||
return [
|
return [
|
||||||
requestFailed(err),
|
requestFailed(err),
|
||||||
setServerError(err, null, 'failed to create a new pipeline'),
|
setServerError(err, null, 'failed to create a new pipeline'),
|
||||||
@ -96,12 +146,54 @@ export class PipelinesEffects {
|
|||||||
|
|
||||||
createPipelineStep$ = createEffect(() => this.actions.pipe(
|
createPipelineStep$ = createEffect(() => this.actions.pipe(
|
||||||
ofType(createPipelineStep),
|
ofType(createPipelineStep),
|
||||||
switchMap((action) => this.pipelinesApiService.pipelinesCreateStep(action.pipelinesCreateStepRequest)
|
concatLatestFrom(() => [
|
||||||
|
this.store.select(selectSelectedPipeline)
|
||||||
|
]),
|
||||||
|
switchMap(([action, selectedPipelineData]) => this.pipelinesApiService.pipelinesCreateStep(action.pipelinesCreateStepRequest)
|
||||||
.pipe(mergeMap((res: PipelinesCreateStepsResponse) => {
|
.pipe(mergeMap((res: PipelinesCreateStepsResponse) => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(res)
|
console.log(res)
|
||||||
// this.router.navigate(['pipelines', res.id, 'edit']);
|
// this.router.navigate(['pipelines', res.id, 'edit']);
|
||||||
return [deactivateLoader(createPipeline.type)];
|
//this.pipelinesApiService.pipelinesGetById({pipeline: action.pipelinesCreateStepRequest.pipeline_id}).pipe()
|
||||||
|
//const selectedPipeline =
|
||||||
|
if(res.id) {
|
||||||
|
const position = checkOverlappingNodes(selectedPipelineData?.flow_display?.nodes, 0, 0, 50);
|
||||||
|
const pipelineData = cloneDeep(selectedPipelineData);
|
||||||
|
|
||||||
|
const newNodeData = cloneDeep(action.pipelinesCreateStepRequest);
|
||||||
|
if (newNodeData) {
|
||||||
|
const newNode = {
|
||||||
|
id: String(res.id),
|
||||||
|
// type: 'consoleJobNode',
|
||||||
|
position,
|
||||||
|
data: {
|
||||||
|
...newNodeData
|
||||||
|
},
|
||||||
|
sourcePosition: 'right',
|
||||||
|
targetPosition: 'left',
|
||||||
|
type: 'normal'
|
||||||
|
};
|
||||||
|
if (pipelineData?.flow_display?.nodes?.length) {
|
||||||
|
pipelineData.flow_display.nodes.push(newNode);
|
||||||
|
//setNodes([...nodes, newNode]);
|
||||||
|
//updatePipelineData([...nodes, newNode]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
pipelineData.flow_display.nodes = [newNode];
|
||||||
|
} catch(e) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
//updatePipelineData([...nodes, newNode]);
|
||||||
|
}
|
||||||
|
this.store.dispatch(setSelectedPipeline({data: cloneDeep(pipelineData)}));
|
||||||
|
this.store.dispatch(updatePipeline({changes: pipelineData}))
|
||||||
|
// reactFlowInstance.addNodes(newNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [deactivateLoader(createPipelineStep.type), addMessage(MESSAGES_SEVERITY.SUCCESS, 'Added new step to pipeline')];
|
||||||
}),
|
}),
|
||||||
catchError(err => {
|
catchError(err => {
|
||||||
return [
|
return [
|
||||||
@ -130,8 +222,26 @@ export class PipelinesEffects {
|
|||||||
})))
|
})))
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// not using
|
||||||
|
getExperimentById$ = createEffect(() => this.actions.pipe(
|
||||||
|
ofType(getExperimentById),
|
||||||
|
switchMap((action) => this.experimentsApiService.tasksGetByIdEx({
|
||||||
|
...action.getExperimentByIdRequest,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
only_fields: ['name', 'comment', 'parent.name', 'parent.project.id', 'runtime', 'configuration', 'status']
|
||||||
|
}).pipe(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
mergeMap((res) => {
|
||||||
|
return [/* setSelectedPipelineStep({step: res?.tasks[0]}), */ deactivateLoader(getExperimentById.type)]
|
||||||
|
}
|
||||||
|
|
||||||
|
),
|
||||||
|
catchError(error => [
|
||||||
|
requestFailed(error),
|
||||||
|
deactivateLoader(action.type),
|
||||||
|
])
|
||||||
|
))
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
getAllExperiments$ = createEffect(() => this.actions.pipe(
|
getAllExperiments$ = createEffect(() => this.actions.pipe(
|
||||||
@ -143,7 +253,7 @@ export class PipelinesEffects {
|
|||||||
},
|
},
|
||||||
size: 20,
|
size: 20,
|
||||||
// user: this.store.select(selectCurrentUser)?.id,
|
// user: this.store.select(selectCurrentUser)?.id,
|
||||||
only_fields: ['name', 'created', 'status', 'type', 'user.name', 'id', 'company'],
|
only_fields: ['name', 'status', 'type', 'user.name', 'id', 'hyperparams'],
|
||||||
// order_by: orderBy,
|
// order_by: orderBy,
|
||||||
// type: [excludedKey, 'annotation_manual', excludedKey, 'annotation', excludedKey, 'dataset_import'],
|
// type: [excludedKey, 'annotation_manual', excludedKey, 'annotation', excludedKey, 'dataset_import'],
|
||||||
// system_tags: ['-archived', '-pipeline', '-dataset'],
|
// system_tags: ['-archived', '-pipeline', '-dataset'],
|
||||||
@ -161,22 +271,46 @@ export class PipelinesEffects {
|
|||||||
// map(action => activeLoader(action.type))
|
// map(action => activeLoader(action.type))
|
||||||
// ));
|
// ));
|
||||||
|
|
||||||
// updateProject = createEffect(() => this.actions.pipe(
|
updatePipeline = createEffect(() => this.actions.pipe(
|
||||||
// ofType(updateProject),
|
ofType(updatePipeline),
|
||||||
// mergeMap(action => this.projectsApi.projectsUpdate({project: action.id, ...action.changes})
|
mergeMap(action => this.pipelinesApiService.pipelinesUpdate({...action.changes})
|
||||||
// .pipe(
|
.pipe(
|
||||||
// mergeMap((res: ProjectsUpdateResponse) => [
|
mergeMap((res: PipelinesUpdateResponse) => [
|
||||||
// deactivateLoader(action.type),
|
deactivateLoader(action.type),
|
||||||
// updateProjectSuccess({id: action.id, changes: res.fields})
|
updatePipelineSuccess({changes: res}),
|
||||||
// ]),
|
addMessage(MESSAGES_SEVERITY.SUCCESS, 'Pipeline saved successfully')
|
||||||
// catchError(error => [deactivateLoader(action.type), requestFailed(error),
|
]),
|
||||||
// setServerError(error, undefined, error?.error?.meta?.result_subcode === 800 ?
|
catchError(error => [deactivateLoader(action.type), requestFailed(error),
|
||||||
// 'Name should be 3 characters long' : error?.error?.meta?.result_subcode === 801 ? 'Name' +
|
setServerError(error, undefined, error?.error?.meta?.result_subcode === 800 ?
|
||||||
// ' already' +
|
'Name should be 3 characters long' : error?.error?.meta?.result_subcode === 801 ? 'Name' +
|
||||||
// ' exists in this project' : undefined)])
|
' already' +
|
||||||
// )
|
' exists in this pipeline' : undefined)])
|
||||||
// )
|
)
|
||||||
// ));
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
getPipelineById$ = createEffect(() => this.actions.pipe(
|
||||||
|
ofType(getPipelineById),
|
||||||
|
switchMap((action) => this.pipelinesApiService.pipelinesGetById({
|
||||||
|
pipeline: action.id,
|
||||||
|
pipeline_name: action.name,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
// only_fields: ['name', 'status', 'company.id', 'user.id', 'comment', 'report', 'tags', 'system_tags', 'report_assets', 'project.name']
|
||||||
|
}).pipe(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
mergeMap((res) => {
|
||||||
|
return [setSelectedPipeline({data: res?.pipeline}), deactivateLoader(getPipelineById.type)]
|
||||||
|
}
|
||||||
|
|
||||||
|
),
|
||||||
|
catchError(error => [
|
||||||
|
requestFailed(error),
|
||||||
|
deactivateLoader(action.type),
|
||||||
|
])
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// getAllProjects = createEffect(() => this.actions.pipe(
|
// getAllProjects = createEffect(() => this.actions.pipe(
|
||||||
// ofType(getAllProjectsPageProjects),
|
// ofType(getAllProjectsPageProjects),
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
setNoMorePipelines,
|
setNoMorePipelines,
|
||||||
setPipelinesOrderBy,
|
setPipelinesOrderBy,
|
||||||
setPipelinesSearchQuery,
|
setPipelinesSearchQuery,
|
||||||
|
setSelectedPipeline,
|
||||||
setTableModeAwareness,
|
setTableModeAwareness,
|
||||||
showExampleDatasets,
|
showExampleDatasets,
|
||||||
showExamplePipelines,
|
showExamplePipelines,
|
||||||
@ -43,7 +44,7 @@ export interface PipelineState {
|
|||||||
pipelines: Pipeline[];
|
pipelines: Pipeline[];
|
||||||
pipelinesNonFilteredList: Pipeline[];
|
pipelinesNonFilteredList: Pipeline[];
|
||||||
selectedProjectId: string;
|
selectedProjectId: string;
|
||||||
selectedProject: Pipeline;
|
selectedPipeline: Pipeline;
|
||||||
projectReadyForDeletion: CommonReadyForDeletion;
|
projectReadyForDeletion: CommonReadyForDeletion;
|
||||||
validatedProject: Pipeline;
|
validatedProject: Pipeline;
|
||||||
noMorePipelines: boolean;
|
noMorePipelines: boolean;
|
||||||
@ -57,7 +58,7 @@ export interface PipelineState {
|
|||||||
export const pipelinesInitState: PipelineState = {
|
export const pipelinesInitState: PipelineState = {
|
||||||
pipelines: null,
|
pipelines: null,
|
||||||
selectedProjectId: '',
|
selectedProjectId: '',
|
||||||
selectedProject: {},
|
selectedPipeline: {},
|
||||||
orderBy: 'last_update',
|
orderBy: 'last_update',
|
||||||
sortOrder: TABLE_SORT_ORDER.DESC,
|
sortOrder: TABLE_SORT_ORDER.DESC,
|
||||||
searchQuery: null,
|
searchQuery: null,
|
||||||
@ -88,12 +89,13 @@ export const pipelinesReducers = [
|
|||||||
on(setCurrentScrollId, (state, action) => ({...state, scrollId: action.scrollId})),
|
on(setCurrentScrollId, (state, action) => ({...state, scrollId: action.scrollId})),
|
||||||
on(setNoMorePipelines, (state, action) => ({...state, noMorePipelines: action.payload})),
|
on(setNoMorePipelines, (state, action) => ({...state, noMorePipelines: action.payload})),
|
||||||
on(updatePipelineSuccess, (state, action) => ({
|
on(updatePipelineSuccess, (state, action) => ({
|
||||||
...state, pipelines: state.pipelines?.map(pr => pr.id === action.id ? {
|
...state, pipelines: state.pipelines?.map(pr => pr.id === action.changes.id ? {
|
||||||
...pr,
|
...pr,
|
||||||
...action.changes,
|
...action.changes,
|
||||||
...(!!action.changes?.name && {basename: action.changes?.name.split('/').at(-1)})
|
...(!!action.changes?.name && {basename: action.changes?.name.split('/').at(-1)})
|
||||||
} : pr)
|
} : pr)
|
||||||
})),
|
})),
|
||||||
|
on(setSelectedPipeline, (state, action) => ({...state, selectedPipeline: {...action.data}})),
|
||||||
on(resetPipelines, state => ({
|
on(resetPipelines, state => ({
|
||||||
...state,
|
...state,
|
||||||
scrollId: null,
|
scrollId: null,
|
||||||
@ -140,6 +142,7 @@ export const pipelinesReducers = [
|
|||||||
...state,
|
...state,
|
||||||
experiments: [...action.experiments],
|
experiments: [...action.experiments],
|
||||||
})),
|
})),
|
||||||
|
|
||||||
] as ReducerTypes<PipelineState, ActionCreator[]>[];
|
] as ReducerTypes<PipelineState, ActionCreator[]>[];
|
||||||
export const pipelinesReducer = createReducer(pipelinesInitState, ...pipelinesReducers);
|
export const pipelinesReducer = createReducer(pipelinesInitState, ...pipelinesReducers);
|
||||||
|
|
||||||
@ -148,7 +151,7 @@ export const pipelines = state => state.pipelines as PipelineState;
|
|||||||
|
|
||||||
export const selectPipelines = createSelector(pipelines, state => state[PIPELINES_KEY]);
|
export const selectPipelines = createSelector(pipelines, state => state[PIPELINES_KEY]);
|
||||||
export const selectNonFilteredPipelinesList = createSelector(pipelines, state => state?.pipelinesNonFilteredList || []);
|
export const selectNonFilteredPipelinesList = createSelector(pipelines, state => state?.pipelinesNonFilteredList || []);
|
||||||
// export const selectSelectedProjectId = createSelector(selectRouterParams, (params: any) => params ? params.projectId : '');
|
export const selectSelectedPipeline = createSelector(pipelines, state => state?.selectedPipeline);
|
||||||
export const selectPipelinesOrderBy = createSelector(pipelines, state => state?.orderBy || '');
|
export const selectPipelinesOrderBy = createSelector(pipelines, state => state?.orderBy || '');
|
||||||
export const selectPipelinesSortOrder = createSelector(pipelines, state => state?.sortOrder || TABLE_SORT_ORDER.DESC);
|
export const selectPipelinesSortOrder = createSelector(pipelines, state => state?.sortOrder || TABLE_SORT_ORDER.DESC);
|
||||||
export const selectPipelinesSearchQuery = createSelector(pipelines, state => state?.searchQuery);
|
export const selectPipelinesSearchQuery = createSelector(pipelines, state => state?.searchQuery);
|
||||||
|
Loading…
Reference in New Issue
Block a user