mirror of
https://github.com/clearml/clearml-web
synced 2025-03-13 07:08:17 +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 { PipelinesDeleteRunsRequest } from "~/business-logic/model/pipelines/pipelinesDeleteRunsRequest";
|
||||
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()
|
||||
export class ApiPipelinesService {
|
||||
@ -216,7 +225,7 @@ export class ApiPipelinesService {
|
||||
}
|
||||
|
||||
return this.apiRequest.post<PipelinesCreateResponse>(
|
||||
`${this.basePath}/pipelines.create`,
|
||||
`${this.basePath}/pipelines.create_pipeline`,
|
||||
request,
|
||||
{
|
||||
withCredentials: this.configuration.withCredentials,
|
||||
@ -227,7 +236,6 @@ export class ApiPipelinesService {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Create a new pipeline step
|
||||
@ -270,7 +278,7 @@ export class ApiPipelinesService {
|
||||
}
|
||||
|
||||
return this.apiRequest.post<PipelinesCreateStepsResponse>(
|
||||
`${this.basePath}/pipelines.create.step`,
|
||||
`${this.basePath}/pipelines.create_step`,
|
||||
request,
|
||||
{
|
||||
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 '././pipelinesCreateStepsResponse';
|
||||
export * from './pipelinesSettingsModel';
|
||||
export * from '././pipelinesGetByIdRequest';
|
||||
export * from '././pipelinesGetByIdResponse';
|
||||
export * from '././pipelinesUpdateRequest';
|
||||
export * from '././pipelinesUpdateResponse';
|
||||
|
||||
export * from "././pipeline";
|
@ -15,7 +15,11 @@ import { PipelinesParameter } from './pipelinesParameter';
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
interface FlowDisplay {
|
||||
|
||||
nodes?: Array<unknown>;
|
||||
edges?: Array<unknown>
|
||||
}
|
||||
|
||||
export interface Pipeline {
|
||||
/**
|
||||
@ -70,5 +74,7 @@ export interface Pipeline {
|
||||
own_models?: number;
|
||||
hidden?: boolean;
|
||||
|
||||
parameters?: Array<PipelinesParameter>
|
||||
parameters?: Array<PipelinesParameter>;
|
||||
|
||||
flow_display?: FlowDisplay;
|
||||
}
|
||||
|
@ -4,4 +4,5 @@ export interface PipelinesCreateResponse {
|
||||
* Pipeline id
|
||||
*/
|
||||
id?: string;
|
||||
project_id?: string;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
export interface PipelinesCreateStepsRequest {
|
||||
/**
|
||||
* Pipeline name. Unique within the company.
|
||||
* Pipeline step name. Unique within the company.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
@ -10,5 +10,7 @@ export interface PipelinesCreateStepsRequest {
|
||||
|
||||
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>;
|
||||
isRoot?: boolean;
|
||||
last_update?: string; //MANUALLY
|
||||
//basename?: string;
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
<div class="d-flex justify-content-end align-items-center header-container">
|
||||
<div class="pipeline-name">
|
||||
Editing {{pipelineData?.name}}
|
||||
</div>
|
||||
<!-- <sm-clear-filters-button
|
||||
*ngIf="!minimizedView"
|
||||
[tableFilters]="tableFilters"
|
||||
@ -31,7 +34,7 @@
|
||||
(setAutoRefresh)="setAutoRefresh.emit($event)"
|
||||
>
|
||||
</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>
|
||||
</button>
|
||||
<button class="btn btn-icon g-btn" smTooltip="Compile pipeline">
|
||||
|
@ -29,6 +29,10 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.pipeline-name {
|
||||
color: white;
|
||||
flex-grow: 1;
|
||||
}
|
||||
&.archive-mode {
|
||||
transition: background-color 0.5s;
|
||||
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 {resourceToIconMap} from '~/features/experiments/experiments.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() {
|
||||
return this._tableCols;
|
||||
}
|
||||
|
||||
@Input() pipelineData: Pipeline;
|
||||
@Output() createPipelineStep = new EventEmitter();
|
||||
@Output() settingsPipelineAction = new EventEmitter();
|
||||
@Output() savePipeline = new EventEmitter();
|
||||
// @Output() selectedTableColsChanged = new EventEmitter<ISmCol>();
|
||||
// @Output() removeColFromList = new EventEmitter<ISmCol['id']>();
|
||||
// @Output() getMetricsToDisplay = new EventEmitter();
|
||||
@ -56,4 +58,7 @@ export class EditPipelineHeaderComponent extends BaseEntityHeaderComponent imple
|
||||
settings() {
|
||||
this.settingsPipelineAction.emit();
|
||||
}
|
||||
savePipelineClicked() {
|
||||
this.savePipeline.emit();
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
<sm-edit-pipeline-header
|
||||
(createPipelineStep)="createPipeline()"
|
||||
(settingsPipelineAction)="settings()"
|
||||
(createPipelineStep)="createPipelineStep()"
|
||||
(savePipeline)="savePipeline()"
|
||||
[pipelineData]="selectedPipeline"
|
||||
>
|
||||
</sm-edit-pipeline-header>
|
||||
<div class="edit-pipeline-body">
|
||||
<!-- <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">
|
||||
<i class="icon i-fingers-white mx-auto xxl"></i>
|
||||
<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 { PipelineSettingComponent } from '../pipeline-setting/pipeline-setting.component';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
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({
|
||||
selector: 'sm-edit-pipeline-page',
|
||||
templateUrl: './edit-pipeline-page.component.html',
|
||||
styleUrls: ['./edit-pipeline-page.component.scss']
|
||||
})
|
||||
export class EditPipelinePageComponent {
|
||||
export class EditPipelinePageComponent implements OnInit, OnDestroy {
|
||||
protected dialog = inject(MatDialog);
|
||||
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, {
|
||||
data: {defaultExperimentId: ''},
|
||||
@ -24,7 +77,7 @@ export class EditPipelinePageComponent {
|
||||
.afterClosed()
|
||||
.subscribe(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 { Pipeline } from '~/business-logic/model/pipelines/pipeline';
|
||||
|
||||
|
||||
|
||||
@ -20,26 +21,29 @@ const containerElementName = 'myReactComponentContainer';
|
||||
export class FlowEditorComponent implements OnChanges, OnDestroy, AfterViewInit {
|
||||
@ViewChild(containerElementName, {static: false}) containerRef: ElementRef;
|
||||
|
||||
@Input() public counter = 10;
|
||||
@Output() public componentClick = new EventEmitter<void>();
|
||||
@Input() public pipelineData: Pipeline;
|
||||
@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: '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() {
|
||||
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;
|
||||
}
|
||||
|
||||
public handleDivClicked() {
|
||||
if (this.componentClick) {
|
||||
this.componentClick.emit();
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
// public handleDivClicked() {
|
||||
// if (this.componentClick) {
|
||||
// this.componentClick.emit();
|
||||
// this.render();
|
||||
// }
|
||||
// }
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
ngOnChanges(_changes: SimpleChanges): void {
|
||||
@ -51,8 +55,21 @@ export class FlowEditorComponent implements OnChanges, OnDestroy, AfterViewInit
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if(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() {
|
||||
const root = createRoot(this.containerRef.nativeElement);
|
||||
|
||||
@ -60,8 +77,10 @@ export class FlowEditorComponent implements OnChanges, OnDestroy, AfterViewInit
|
||||
root.render(React.createElement("div", {
|
||||
className: 'i-am-classy',
|
||||
children: React.createElement(PipelineFlowComponent, {
|
||||
initialNodes: this.initialNodes,
|
||||
initialEdges: this.initialEdges
|
||||
initialNodes: this.pipelineData?.flow_display?.nodes,
|
||||
initialEdges: this.pipelineData?.flow_display?.edges,
|
||||
onNodesDataChanged: this.nodesDataChanged,
|
||||
onEdgesDataChanged: this.edgesDataChanged
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
@ -1,43 +1,65 @@
|
||||
import * as React from 'react';
|
||||
import { FunctionComponent, 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';
|
||||
|
||||
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
FunctionComponent,
|
||||
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 {
|
||||
initialNodes: any;
|
||||
initialEdges: any;
|
||||
onNodesDataChanged: Function,
|
||||
onEdgesDataChanged: Function
|
||||
}
|
||||
|
||||
const edgeOptions = {
|
||||
animated: true,
|
||||
style: {
|
||||
stroke: '#B0B0B0',
|
||||
|
||||
stroke: "#B0B0B0",
|
||||
},
|
||||
markerEnd: {
|
||||
type: MarkerType.ArrowClosed,
|
||||
color: '#B0B0B0',
|
||||
strokeWidth: 2
|
||||
color: "#B0B0B0",
|
||||
strokeWidth: 2,
|
||||
},
|
||||
};
|
||||
const connectionLineStyle = { stroke: '#B0B0B0' };
|
||||
|
||||
export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (props: IMyComponentProps) => {
|
||||
const connectionLineStyle = { stroke: "#B0B0B0" };
|
||||
|
||||
export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (
|
||||
props: IMyComponentProps
|
||||
) => {
|
||||
// const timerHandle = useRef<number | null>(null);
|
||||
// const [stateCounter, setStateCounter] = useState(42);
|
||||
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState(props.initialNodes);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState(props.initialEdges);
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState(props.initialNodes?.length ? props.initialNodes : []);
|
||||
const [edges, setEdges, onEdgesChange] = useEdgesState(props.initialEdges?.length? props.initialEdges: []);
|
||||
const edgeUpdateSuccessful = useRef(true);
|
||||
|
||||
React.useEffect(() => {
|
||||
props.onNodesDataChanged(nodes);
|
||||
}, [nodes]);
|
||||
React.useEffect(() => {
|
||||
props.onEdgesDataChanged(edges)
|
||||
}, [edges])
|
||||
|
||||
|
||||
const onConnect = useCallback(
|
||||
(params) => setEdges((eds) => addEdge(params, eds)),
|
||||
[setEdges],
|
||||
[setEdges]
|
||||
);
|
||||
|
||||
/**
|
||||
@ -77,7 +99,6 @@ export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (prop
|
||||
// setNodeData(clone(node));
|
||||
};
|
||||
|
||||
|
||||
const onPaneClick = () => {
|
||||
// setIsShowNodeEditModal(false);
|
||||
};
|
||||
@ -89,8 +110,15 @@ export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (prop
|
||||
["NormalOperationPipelineNode"]
|
||||
);
|
||||
|
||||
|
||||
return <div style={{ width: '100%', height: 'calc(100vh - 130px)', position: "relative", overflow: "hidden" }}>
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "calc(100vh - 130px)",
|
||||
position: "relative",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
onNodesChange={onNodesChange}
|
||||
@ -124,5 +152,6 @@ export const PipelineFlowComponent: FunctionComponent<IMyComponentProps> = (prop
|
||||
<MiniMap />
|
||||
<Background gap={12} size={1} />
|
||||
</ReactFlow> */}
|
||||
</div>;
|
||||
</div>
|
||||
);
|
||||
};
|
@ -2,7 +2,8 @@ import React from "react";
|
||||
import { Handle, Position } from 'reactflow';
|
||||
/* import "./pipeline-step.css" */
|
||||
|
||||
export default function PipelineStepComponent({ data }) {
|
||||
export default function PipelineStepComponent({ data, ...others }) {
|
||||
//console.log("from reactstep", others)
|
||||
return (
|
||||
<div className="" style={{
|
||||
padding: "2px",
|
||||
@ -32,7 +33,7 @@ export default function PipelineStepComponent({ data }) {
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap"
|
||||
}
|
||||
}>{data.name} test name</div>
|
||||
}>{data.name}</div>
|
||||
|
||||
</div>
|
||||
<div className="step-part step-footer queued" style={{
|
||||
|
@ -17,7 +17,7 @@
|
||||
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()"
|
||||
(mousedown)="!isFocused(experimentInputRef) && experimentInput.value && clear(); experimentInput.reset(); experimentInputRef.focus(); step.parameters = [];"
|
||||
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
|
||||
@ -52,7 +52,7 @@
|
||||
<textarea class="step-description" name="description" matInput [(ngModel)]="step.description"
|
||||
#description="ngModel"></textarea>
|
||||
</mat-form-field>
|
||||
<div class="parameters">
|
||||
<div class="parameters" *ngIf="step?.parameters?.length">
|
||||
<div class="search">
|
||||
<mat-label>Parameters</mat-label>
|
||||
<sm-search search-button
|
||||
|
@ -18,8 +18,9 @@ import {
|
||||
} from '@common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component';
|
||||
import { Task } from '~/business-logic/model/tasks/task';
|
||||
import { PipelineParametersComponent } from '@common/pipelines/pipeline-parameters/pipeline-parameters.component';
|
||||
import { PipelinesParameter } from '~/business-logic/model/pipelines/pipelinesParameter';
|
||||
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { ParamsItem } from '~/business-logic/model/tasks/paramsItem';
|
||||
|
||||
|
||||
@Component({
|
||||
@ -36,22 +37,16 @@ export class PipelineAddStepFormComponent implements OnChanges, OnDestroy {
|
||||
public panelHeight: number;
|
||||
private subs = new Subscription();
|
||||
private rootFiltered: boolean;
|
||||
public readonly experimentsRoot = {label: 'My experiment', value: null};
|
||||
public readonly experimentsRoot = {label: 'My experiment', value: null, parameters: []};
|
||||
@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<PipelinesParameter> } = {
|
||||
public step: { name: string; description: string; experiment: { label: string; value: string }, parameters: Array<ParamsItem> } = {
|
||||
name: null,
|
||||
description: '',
|
||||
experiment: null,
|
||||
parameters: [{
|
||||
name: "Paramter1",
|
||||
value: ""
|
||||
}, {
|
||||
name: "Parameter2",
|
||||
value: ""
|
||||
}],
|
||||
parameters: [],
|
||||
};
|
||||
filterText: string = '';
|
||||
isAutoCompleteOpen: boolean;
|
||||
@ -95,7 +90,7 @@ export class PipelineAddStepFormComponent implements OnChanges, OnDestroy {
|
||||
this._experiments = experiments;
|
||||
this.experimentsOptions = [
|
||||
...((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);
|
||||
}
|
||||
@ -136,6 +131,25 @@ export class PipelineAddStepFormComponent implements OnChanges, OnDestroy {
|
||||
|
||||
experimentSelected($event: MatOptionSelectionChange) {
|
||||
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) {
|
||||
this.isAutoCompleteOpen = focus;
|
||||
|
@ -1,46 +1,50 @@
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {pageSize} from '@common/projects/common-projects.consts';
|
||||
import {CommonProjectsPageComponent} from '@common/projects/containers/projects-page/common-projects-page.component';
|
||||
import {isExample} from '@common/shared/utils/shared-utils';
|
||||
import {trackById} from '@common/shared/utils/forms-track-by';
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { pageSize } from "@common/projects/common-projects.consts";
|
||||
import { CommonProjectsPageComponent } from "@common/projects/containers/projects-page/common-projects-page.component";
|
||||
import { isExample } from "@common/shared/utils/shared-utils";
|
||||
import { trackById } from "@common/shared/utils/forms-track-by";
|
||||
import {
|
||||
addProjectTags,
|
||||
getProjectsTags, setBreadcrumbsOptions,
|
||||
getProjectsTags,
|
||||
setBreadcrumbsOptions,
|
||||
setDefaultNestedModeForFeature,
|
||||
setSelectedProjectId,
|
||||
setTags
|
||||
} from '@common/core/actions/projects.actions';
|
||||
setTags,
|
||||
} from "@common/core/actions/projects.actions";
|
||||
import {
|
||||
selectDefaultNestedModeForFeature,
|
||||
selectMainPageTagsFilter,
|
||||
selectMainPageTagsFilterMatchMode,
|
||||
selectProjectTags
|
||||
} from '@common/core/reducers/projects.reducer';
|
||||
import {combineLatest, Observable, Subscription} from 'rxjs';
|
||||
import {Project} from '~/business-logic/model/projects/project';
|
||||
selectProjectTags,
|
||||
} from "@common/core/reducers/projects.reducer";
|
||||
import { combineLatest, Observable, Subscription } from "rxjs";
|
||||
import { Project } from "~/business-logic/model/projects/project";
|
||||
import {
|
||||
getAllProjectsPageProjects,
|
||||
resetProjects,
|
||||
showExamplePipelines,
|
||||
updateProject
|
||||
} from '@common/projects/common-projects.actions';
|
||||
import {ProjectsGetAllResponseSingle} from '~/business-logic/model/projects/projectsGetAllResponseSingle';
|
||||
import {selectShowPipelineExamples} from '@common/projects/common-projects.reducer';
|
||||
import {EntityTypeEnum} from '~/shared/constants/non-common-consts';
|
||||
updateProject,
|
||||
} from "@common/projects/common-projects.actions";
|
||||
import { ProjectsGetAllResponseSingle } from "~/business-logic/model/projects/projectsGetAllResponseSingle";
|
||||
import { selectShowPipelineExamples } from "@common/projects/common-projects.reducer";
|
||||
import { EntityTypeEnum } from "~/shared/constants/non-common-consts";
|
||||
// import {
|
||||
// PipelinesEmptyStateComponent
|
||||
// } from '@common/pipelines/pipelines-page/pipelines-empty-state/pipelines-empty-state.component';
|
||||
import {debounceTime, skip, withLatestFrom} from 'rxjs/operators';
|
||||
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 { createPipeline } from '../pipelines.actions';
|
||||
import { debounceTime, skip, withLatestFrom } from "rxjs/operators";
|
||||
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 { createPipeline } from "../pipelines.actions";
|
||||
|
||||
@Component({
|
||||
selector: 'sm-pipelines-page',
|
||||
templateUrl: './pipelines-page.component.html',
|
||||
styleUrls: ['./pipelines-page.component.scss']
|
||||
selector: "sm-pipelines-page",
|
||||
templateUrl: "./pipelines-page.component.html",
|
||||
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
|
||||
|
||||
@PipelineDecorator.component(cache=True, execution_queue="default")
|
||||
@ -76,6 +80,10 @@ if __name__ == '__main__':
|
||||
private mainPageFilterSub: Subscription;
|
||||
public isNested$: Observable<boolean>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
override ngOnInit() {
|
||||
super.ngOnInit();
|
||||
this.store.dispatch(getProjectsTags({ entity: this.getName() }));
|
||||
@ -83,13 +91,13 @@ if __name__ == '__main__':
|
||||
this.projectsTags$ = this.store.select(selectProjectTags);
|
||||
this.mainPageFilterSub = combineLatest([
|
||||
this.store.select(selectMainPageTagsFilter),
|
||||
this.store.select(selectMainPageTagsFilterMatchMode)
|
||||
]).pipe(debounceTime(0), skip(1))
|
||||
this.store.select(selectMainPageTagsFilterMatchMode),
|
||||
])
|
||||
.pipe(debounceTime(0), skip(1))
|
||||
.subscribe(() => {
|
||||
this.store.dispatch(resetProjects());
|
||||
this.store.dispatch(getAllProjectsPageProjects());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
override ngOnDestroy() {
|
||||
@ -106,7 +114,7 @@ if __name__ == '__main__':
|
||||
}
|
||||
|
||||
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 } }));
|
||||
}
|
||||
|
||||
@ -116,13 +124,27 @@ if __name__ == '__main__':
|
||||
}
|
||||
|
||||
public override projectCardClicked(project: ProjectsGetAllResponseSingle) {
|
||||
this.router.navigate([project.id, 'experiments'], {relativeTo: this.projectId ? this.route.parent.parent.parent : this.route});
|
||||
this.store.dispatch(setSelectedProjectId({projectId: project.id, example: isExample(project)}));
|
||||
this.router.navigate([project.id, "experiments"], {
|
||||
relativeTo: this.projectId ? this.route.parent.parent.parent : this.route,
|
||||
});
|
||||
this.store.dispatch(
|
||||
setSelectedProjectId({
|
||||
projectId: project.id,
|
||||
example: isExample(project),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public pipelineEditClicked(pipeline: ProjectsGetAllResponseSingle) {
|
||||
this.router.navigate([pipeline.id, 'edit'], {relativeTo: this.projectId ? this.route.parent.parent.parent : this.route});
|
||||
this.store.dispatch(setSelectedProjectId({projectId: pipeline.id, example: isExample(pipeline)}));
|
||||
this.router.navigate([pipeline.id, /* pipeline.basename, */ "edit"], {
|
||||
relativeTo: this.projectId ? this.route.parent.parent.parent : this.route,
|
||||
});
|
||||
this.store.dispatch(
|
||||
setSelectedProjectId({
|
||||
projectId: pipeline.id,
|
||||
example: isExample(pipeline),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
protected override getName() {
|
||||
@ -130,20 +152,22 @@ if __name__ == '__main__':
|
||||
}
|
||||
|
||||
protected override getDeletePopupEntitiesList() {
|
||||
return 'run';
|
||||
return "run";
|
||||
}
|
||||
|
||||
createPipeline() {
|
||||
|
||||
this.dialog.open(PipelineDialogComponent, {
|
||||
this.dialog
|
||||
.open(PipelineDialogComponent, {
|
||||
data: { defaultProjectId: this.projectId },
|
||||
panelClass: 'light-theme',
|
||||
width: '690px'
|
||||
panelClass: "light-theme",
|
||||
width: "690px",
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe(pipeline => {
|
||||
.subscribe((pipeline) => {
|
||||
if (pipeline) {
|
||||
this.store.dispatch(createPipeline({pipelinesCreateRequest: pipeline}));
|
||||
this.store.dispatch(
|
||||
createPipeline({ pipelinesCreateRequest: pipeline })
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@ -153,7 +177,6 @@ if __name__ == '__main__':
|
||||
// },
|
||||
// width: '640px'
|
||||
// });
|
||||
|
||||
}
|
||||
|
||||
createExamples() {
|
||||
@ -161,44 +184,69 @@ if __name__ == '__main__':
|
||||
}
|
||||
|
||||
override shouldReRoute(selectedProject, config) {
|
||||
const relevantSubProjects = selectedProject?.sub_projects?.filter(proj => proj.name.includes('.pipelines'));
|
||||
return config[2] === 'projects' && selectedProject.id !== '*' && (relevantSubProjects?.every(subProject => subProject.name.startsWith(selectedProject.name + '/.')));
|
||||
const relevantSubProjects = selectedProject?.sub_projects?.filter((proj) =>
|
||||
proj.name.includes(".pipelines")
|
||||
);
|
||||
return (
|
||||
config[2] === "projects" &&
|
||||
selectedProject.id !== "*" &&
|
||||
relevantSubProjects?.every((subProject) =>
|
||||
subProject.name.startsWith(selectedProject.name + "/.")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
override noProjectsReRoute() {
|
||||
return this.router.navigate(['..', 'pipelines'], {relativeTo: this.route});
|
||||
return this.router.navigate(["..", "pipelines"], {
|
||||
relativeTo: this.route,
|
||||
});
|
||||
}
|
||||
|
||||
toggleNestedView(nested: boolean) {
|
||||
this.store.dispatch(setDefaultNestedModeForFeature({feature: 'pipelines', isNested: nested}));
|
||||
this.store.dispatch(
|
||||
setDefaultNestedModeForFeature({ feature: "pipelines", isNested: nested })
|
||||
);
|
||||
|
||||
if (nested) {
|
||||
this.router.navigate(['*', 'projects'], {relativeTo: this.route});
|
||||
this.router.navigate(["*", "projects"], { relativeTo: this.route });
|
||||
} else {
|
||||
this.router.navigateByUrl('pipelines');
|
||||
this.router.navigateByUrl("pipelines");
|
||||
}
|
||||
}
|
||||
|
||||
override setupBreadcrumbsOptions() {
|
||||
this.subs.add(this.selectedProject$.pipe(
|
||||
this.subs.add(
|
||||
this.selectedProject$
|
||||
.pipe(
|
||||
withLatestFrom(this.store.select(selectDefaultNestedModeForFeature))
|
||||
).subscribe(([selectedProject, defaultNestedModeForFeature]) => {
|
||||
this.store.dispatch(setBreadcrumbsOptions({
|
||||
)
|
||||
.subscribe(([selectedProject, defaultNestedModeForFeature]) => {
|
||||
this.store.dispatch(
|
||||
setBreadcrumbsOptions({
|
||||
breadcrumbOptions: {
|
||||
showProjects: !!selectedProject,
|
||||
featureBreadcrumb: {
|
||||
name: 'PIPELINES',
|
||||
url: defaultNestedModeForFeature['pipelines'] ? 'pipelines/*/projects' : 'pipelines'
|
||||
name: "PIPELINES",
|
||||
url: defaultNestedModeForFeature["pipelines"]
|
||||
? "pipelines/*/projects"
|
||||
: "pipelines",
|
||||
},
|
||||
projectsOptions: {
|
||||
basePath: 'pipelines',
|
||||
filterBaseNameWith: ['.pipelines'],
|
||||
basePath: "pipelines",
|
||||
filterBaseNameWith: [".pipelines"],
|
||||
compareModule: null,
|
||||
showSelectedProject: selectedProject?.id !== '*',
|
||||
...(selectedProject && selectedProject?.id !== '*' && {selectedProjectBreadcrumb: {name: selectedProject?.basename}})
|
||||
}
|
||||
}
|
||||
}));
|
||||
}));
|
||||
showSelectedProject: selectedProject?.id !== "*",
|
||||
...(selectedProject &&
|
||||
selectedProject?.id !== "*" && {
|
||||
selectedProjectBreadcrumb: {
|
||||
name: selectedProject?.basename,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
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 { Pipeline, PipelinesCreateRequest, PipelinesUpdateRequest, PipelinesUpdateResponse, pipelinesSettingsModel } from '~/business-logic/model/pipelines/models';
|
||||
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';
|
||||
|
||||
export const PIPELINES_PREFIX = 'PIPELINES_';
|
||||
@ -22,6 +22,31 @@ export const settingsPipelineAction= createAction(
|
||||
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(
|
||||
PIPELINES_PREFIX + 'GET_EXPERIMENTS',
|
||||
props<{ query: string; regExp?: boolean }>()
|
||||
@ -33,14 +58,7 @@ export const setExperimentsResults = createAction(
|
||||
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(
|
||||
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 }>()
|
||||
// );
|
||||
|
||||
// export const getReport = createAction(
|
||||
// PIPELINES_PREFIX + '[get report]',
|
||||
// props<{ id: string }>()
|
||||
// );
|
||||
|
||||
|
||||
// export const setReport = createAction(
|
||||
// PIPELINES_PREFIX + '[set report]',
|
||||
@ -135,6 +150,9 @@ export const showExampleDatasets = createAction(PIPELINES_PREFIX + '[show datase
|
||||
// );
|
||||
|
||||
// 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]',
|
||||
// props<{ report: IReport }>()
|
||||
// );
|
||||
|
@ -1,12 +1,13 @@
|
||||
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 {ActivatedRoute, Router} from '@angular/router';
|
||||
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 {
|
||||
createPipeline, createPipelineStep, getAllExperiments, setExperimentsResults, settingsPipelineAction
|
||||
createPipeline, createPipelineStep, getAllExperiments, setExperimentsResults, settingsPipelineAction,
|
||||
createPipeline, createPipelineStep, getAllExperiments, getExperimentById, getPipelineById, setExperimentsResults, setSelectedPipeline, updatePipeline, updatePipelineSuccess
|
||||
} from './pipelines.actions';
|
||||
// import {ApiReportsService} from '~/business-logic/api-services/reports.service';
|
||||
/* 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 { PipelinesCreateStepsResponse } from '~/business-logic/model/pipelines/pipelinesCreateStepsResponse';
|
||||
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 {setMainPageTagsFilter} from '@common/core/actions/projects.actions';
|
||||
import {cleanTag} from '@common/shared/utils/helpers.util';
|
||||
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()
|
||||
export class PipelinesEffects {
|
||||
|
||||
@ -70,6 +119,8 @@ export class PipelinesEffects {
|
||||
) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
activeLoader = createEffect(() => this.actions.pipe(
|
||||
ofType(/* getReports, getReport, */ createPipeline, createPipelineStep, getAllExperiments, settingsPipelineAction/* updateReport, restoreReport, archiveReport */),
|
||||
filter(action => !action['refresh']),
|
||||
@ -80,11 +131,10 @@ export class PipelinesEffects {
|
||||
ofType(createPipeline),
|
||||
switchMap((action) => this.pipelinesApiService.pipelinesCreate(action.pipelinesCreateRequest)
|
||||
.pipe(mergeMap((res: PipelinesCreateResponse) => {
|
||||
this.router.navigate(['pipelines', res.id, 'edit']);
|
||||
return [deactivateLoader(createPipeline.type)];
|
||||
this.router.navigate(['pipelines', res.project_id, 'edit']);
|
||||
return [deactivateLoader(createPipeline.type), addMessage(MESSAGES_SEVERITY.SUCCESS, 'New pipeline created successfully. You can now start adding steps to it.')];
|
||||
}),
|
||||
catchError(err => {
|
||||
// this.router.navigate(['pipelines', 'b2c6686fb12e4649a954991ca7c24518', 'edit']);
|
||||
return [
|
||||
requestFailed(err),
|
||||
setServerError(err, null, 'failed to create a new pipeline'),
|
||||
@ -96,12 +146,54 @@ export class PipelinesEffects {
|
||||
|
||||
createPipelineStep$ = createEffect(() => this.actions.pipe(
|
||||
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) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(res)
|
||||
// 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 => {
|
||||
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(
|
||||
@ -143,7 +253,7 @@ export class PipelinesEffects {
|
||||
},
|
||||
size: 20,
|
||||
// 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,
|
||||
// type: [excludedKey, 'annotation_manual', excludedKey, 'annotation', excludedKey, 'dataset_import'],
|
||||
// system_tags: ['-archived', '-pipeline', '-dataset'],
|
||||
@ -161,22 +271,46 @@ export class PipelinesEffects {
|
||||
// map(action => activeLoader(action.type))
|
||||
// ));
|
||||
|
||||
// updateProject = createEffect(() => this.actions.pipe(
|
||||
// ofType(updateProject),
|
||||
// mergeMap(action => this.projectsApi.projectsUpdate({project: action.id, ...action.changes})
|
||||
// .pipe(
|
||||
// mergeMap((res: ProjectsUpdateResponse) => [
|
||||
// deactivateLoader(action.type),
|
||||
// updateProjectSuccess({id: action.id, changes: res.fields})
|
||||
// ]),
|
||||
// catchError(error => [deactivateLoader(action.type), requestFailed(error),
|
||||
// setServerError(error, undefined, error?.error?.meta?.result_subcode === 800 ?
|
||||
// 'Name should be 3 characters long' : error?.error?.meta?.result_subcode === 801 ? 'Name' +
|
||||
// ' already' +
|
||||
// ' exists in this project' : undefined)])
|
||||
// )
|
||||
// )
|
||||
// ));
|
||||
updatePipeline = createEffect(() => this.actions.pipe(
|
||||
ofType(updatePipeline),
|
||||
mergeMap(action => this.pipelinesApiService.pipelinesUpdate({...action.changes})
|
||||
.pipe(
|
||||
mergeMap((res: PipelinesUpdateResponse) => [
|
||||
deactivateLoader(action.type),
|
||||
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 ?
|
||||
'Name should be 3 characters long' : error?.error?.meta?.result_subcode === 801 ? 'Name' +
|
||||
' 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(
|
||||
// ofType(getAllProjectsPageProjects),
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
setNoMorePipelines,
|
||||
setPipelinesOrderBy,
|
||||
setPipelinesSearchQuery,
|
||||
setSelectedPipeline,
|
||||
setTableModeAwareness,
|
||||
showExampleDatasets,
|
||||
showExamplePipelines,
|
||||
@ -43,7 +44,7 @@ export interface PipelineState {
|
||||
pipelines: Pipeline[];
|
||||
pipelinesNonFilteredList: Pipeline[];
|
||||
selectedProjectId: string;
|
||||
selectedProject: Pipeline;
|
||||
selectedPipeline: Pipeline;
|
||||
projectReadyForDeletion: CommonReadyForDeletion;
|
||||
validatedProject: Pipeline;
|
||||
noMorePipelines: boolean;
|
||||
@ -57,7 +58,7 @@ export interface PipelineState {
|
||||
export const pipelinesInitState: PipelineState = {
|
||||
pipelines: null,
|
||||
selectedProjectId: '',
|
||||
selectedProject: {},
|
||||
selectedPipeline: {},
|
||||
orderBy: 'last_update',
|
||||
sortOrder: TABLE_SORT_ORDER.DESC,
|
||||
searchQuery: null,
|
||||
@ -88,12 +89,13 @@ export const pipelinesReducers = [
|
||||
on(setCurrentScrollId, (state, action) => ({...state, scrollId: action.scrollId})),
|
||||
on(setNoMorePipelines, (state, action) => ({...state, noMorePipelines: action.payload})),
|
||||
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,
|
||||
...action.changes,
|
||||
...(!!action.changes?.name && {basename: action.changes?.name.split('/').at(-1)})
|
||||
} : pr)
|
||||
})),
|
||||
on(setSelectedPipeline, (state, action) => ({...state, selectedPipeline: {...action.data}})),
|
||||
on(resetPipelines, state => ({
|
||||
...state,
|
||||
scrollId: null,
|
||||
@ -140,6 +142,7 @@ export const pipelinesReducers = [
|
||||
...state,
|
||||
experiments: [...action.experiments],
|
||||
})),
|
||||
|
||||
] as ReducerTypes<PipelineState, ActionCreator[]>[];
|
||||
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 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 selectPipelinesSortOrder = createSelector(pipelines, state => state?.sortOrder || TABLE_SORT_ORDER.DESC);
|
||||
export const selectPipelinesSearchQuery = createSelector(pipelines, state => state?.searchQuery);
|
||||
|
Loading…
Reference in New Issue
Block a user