Added new store and updated pipeline service. Added create pipeline dialog.

This commit is contained in:
Shubham Takode
2024-02-12 20:56:36 +05:30
parent 6d005d709a
commit 01951cd2cd
16 changed files with 1747 additions and 200 deletions

View File

@@ -12,145 +12,217 @@
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/member-ordering */
import {HTTP} from '../../app.constants';
import {SmApiRequestsService} from "./api-requests.service";
import { HTTP } from "../../app.constants";
import { SmApiRequestsService } from "./api-requests.service";
import { Inject, Injectable, Optional } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
HttpResponse, HttpEvent } from '@angular/common/http';
import { CustomHttpUrlEncodingCodec } from '../encoder';
import { Inject, Injectable, Optional } from "@angular/core";
import {
HttpClient,
HttpHeaders,
HttpParams,
HttpResponse,
HttpEvent,
} from "@angular/common/http";
import { CustomHttpUrlEncodingCodec } from "../encoder";
import { Observable } from 'rxjs';
import { Observable } from "rxjs";
import { PipelinesStartPipelineRequest } from '../model/pipelines/pipelinesStartPipelineRequest';
import { PipelinesStartPipelineResponse } from '../model/pipelines/pipelinesStartPipelineResponse';
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 { PipelinesStartPipelineRequest } from "../model/pipelines/pipelinesStartPipelineRequest";
import { PipelinesStartPipelineResponse } from "../model/pipelines/pipelinesStartPipelineResponse";
import { BASE_PATH, COLLECTION_FORMATS } from "../variables";
import { Configuration } from "../configuration";
import { PipelinesDeleteRunsRequest } from "~/business-logic/model/pipelines/pipelinesDeleteRunsRequest";
import { PipelinesDeleteRunsResponse } from "~/business-logic/model/pipelines/pipelinesDeleteRunsResponse";
import { PipelinesCreateRequest, PipelinesCreateResponse } from "../model/pipelines/models";
@Injectable()
export class ApiPipelinesService {
protected basePath = HTTP.API_BASE_URL;
public defaultHeaders = new HttpHeaders();
public configuration = new Configuration();
protected basePath = HTTP.API_BASE_URL;
public defaultHeaders = new HttpHeaders();
public configuration = new Configuration();
constructor(
protected apiRequest: SmApiRequestsService,
@Optional() @Inject(BASE_PATH) basePath: string,
@Optional() configuration: Configuration
) {
if (basePath) {
this.basePath = basePath;
}
if (configuration) {
this.configuration = configuration;
this.basePath = basePath || configuration.basePath || this.basePath;
}
}
constructor(protected apiRequest: SmApiRequestsService, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
if (basePath) {
this.basePath = basePath;
}
if (configuration) {
this.configuration = configuration;
this.basePath = basePath || configuration.basePath || this.basePath;
}
/**
* @param consumes string[] mime-types
* @return true: consumes contains 'multipart/form-data', false: otherwise
*/
private canConsumeForm(consumes: string[]): boolean {
const form = "multipart/form-data";
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
}
/**
*
* Delete pipeline runs
* @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 pipelinesDeleteRuns(
request: PipelinesDeleteRunsRequest,
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 pipelinesDeleteRuns."
);
}
/**
* @param consumes string[] mime-types
* @return true: consumes contains 'multipart/form-data', false: otherwise
*/
private canConsumeForm(consumes: string[]): boolean {
const form = 'multipart/form-data';
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
let headers = this.defaultHeaders;
if (options && options.async_enable) {
headers = headers.set(this.configuration.asyncHeader, "1");
}
/**
*
* Delete pipeline runs
* @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 pipelinesDeleteRuns(request: PipelinesDeleteRunsRequest, 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 pipelinesDeleteRuns.');
}
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<PipelinesDeleteRunsResponse>(`${this.basePath}/pipelines.delete_runs`,
request,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
// 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);
}
/**
*
* Start a pipeline
* @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 pipelinesStartPipeline(request: PipelinesStartPipelineRequest, 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 pipelinesStartPipeline.');
}
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<PipelinesStartPipelineResponse>(`${this.basePath}/pipelines.start_pipeline`,
request,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
// 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<PipelinesDeleteRunsResponse>(
`${this.basePath}/pipelines.delete_runs`,
request,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress,
}
);
}
/**
*
* Start a pipeline
* @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 pipelinesStartPipeline(
request: PipelinesStartPipelineRequest,
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 pipelinesStartPipeline."
);
}
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<PipelinesStartPipelineResponse>(
`${this.basePath}/pipelines.start_pipeline`,
request,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress,
}
);
}
/**
*
* Create a new pipeline
* @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 pipelinesCreate(
request: PipelinesCreateRequest,
options?: any,
observe: any = "body",
reportProgress: boolean = false
): Observable<any> {
if (request === null || request === undefined) {
throw new Error(
"Required parameter request was null or undefined when calling pipelinesCreate."
);
}
let headers = this.defaultHeaders;
if (options && options.async_enable) {
headers = headers.set(this.configuration.asyncHeader, "1");
}
// to determine the Accept header
const httpHeaderAccepts: string[] = ["application/json"];
const httpHeaderAcceptSelected: string | undefined =
this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected != undefined) {
headers = headers.set("Accept", httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = [];
const httpContentTypeSelected: string | undefined =
this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected != undefined) {
headers = headers.set("Content-Type", httpContentTypeSelected);
}
return this.apiRequest.post<PipelinesCreateResponse>(
`${this.basePath}/pipelines.create`,
request,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress,
}
);
}
}

View File

@@ -1,2 +1,5 @@
export * from '././pipelinesStartPipelineRequest';
export * from '././pipelinesStartPipelineResponse';
export * from '././pipelinesCreateRequest';
export * from '././pipelinesCreateResponse';
export * from "././pipeline";

View File

@@ -0,0 +1,73 @@
import {ProjectsGetAllResponseSingleSubProjects} from '~/business-logic/model/projects/projectsGetAllResponseSingleSubProjects';
import {Stats} from '~/business-logic/model/projects/stats';
import {ProjectsGetAllResponseSingleDatasetStats} from '~/business-logic/model/projects/projectsGetAllResponseSingleDatasetStats';
/**
* pipelines
* 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.
*/
export interface Pipeline {
/**
* Pipeline id
*/
id?: string;
/**
* Pipeline name
*/
name?: string;
/**
* Pipeline base name
*/
basename?: string;
/**
* Pipeline description
*/
description?: string;
/**
* Associated user id
*/
user?: string;
/**
* Company id
*/
company?: {id: string; name?: string};
/**
* Creation time
*/
created?: string;
/**
* User-defined tags
*/
tags?: Array<string>;
/**
* System tags. This field is reserved for system use, please don\'t use it.
*/
system_tags?: Array<string>;
/**
* The default output destination URL for new tasks under this project
*/
default_output_destination?: string;
stats?: Stats;
dataset_stats?: ProjectsGetAllResponseSingleDatasetStats;
/**
* Last project update time. Reflects the last time the project metadata was changed or a task in this project has changed status
*/
last_update?: string;
sub_projects?: ProjectsGetAllResponseSingleSubProjects[];
own_tasks?: number;
own_models?: number;
hidden?: boolean;
parameters?: Array<object>
}

View File

@@ -0,0 +1,20 @@
export interface PipelinesCreateRequest {
/**
* Pipeline name. Unique within the company.
*/
name: string;
/**
* User-defined tags list
*/
tags?: Array<string>;
/**
* Free text comment
*/
description?: string;
/**
* Project ID of the project to which this report is assigned Must exist[ab]
*/
project?: string;
parameters?: Array<object>
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,138 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
OnChanges, OnDestroy, OnInit,
Output,
ViewChild
} from '@angular/core';
import {NgModel} from '@angular/forms';
import {Observable, Subscription} from 'rxjs';
import {Project} from '~/business-logic/model/projects/project';
import {trackByValue} from '@common/shared/utils/forms-track-by';
import {MatOptionSelectionChange} from '@angular/material/core';
import {rootProjectsPageSize} from '@common/constants';
import {
IOption
} from '@common/shared/ui-components/inputs/select-autocomplete-with-chips/select-autocomplete-with-chips.component';
@Component({
selector: 'sm-create-new-pipeline-form',
templateUrl: './create-new-pipeline-form.component.html',
styleUrls: ['./create-new-pipeline-form.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CreateNewPipelineFormComponent implements OnChanges, OnDestroy {
public filteredProjects$: Observable<{ label: string; value: string }[]>;
private _projects: Project[];
public projectsOptions: { label: string; value: string }[];
public trackByValue = trackByValue;
public panelHeight: number;
private subs = new Subscription();
private rootFiltered: boolean;
public readonly projectsRoot = {label: 'Projects root', value: null};
@ViewChild('projectInput') projectInput: NgModel;
public pipelinesNames: Array<string>;
public projectsNames: Array<string>;
public pipeline: { name: string; description: string; project: { label: string; value: string }, parameters: Array<object>, tags: Array<string> } = {
name: null,
description: '',
project: null,
parameters: [],
tags: [],
};
filterText: string = '';
isAutoCompleteOpen: boolean;
@Input() readOnlyProjectsNames: string[];
@Input() defaultProjectId: string;
public loading: boolean;
public noMoreOptions: boolean;
private previousLength: number | undefined;
@Input() set projects(projects: Project[]) {
this.loading = false;
this.noMoreOptions = projects?.length === this.previousLength || projects?.length < rootProjectsPageSize;
this.previousLength = projects?.length;
this._projects = projects;
this.projectsOptions = [
...((this.rootFiltered || projects === null) ? [] : [this.projectsRoot]),
...(projects ? projects.map(project => ({label: project.name, value: project.id})) : [])
];
this.projectsNames = this.projectsOptions.map(project => project.label);
}
get projects() {
return this._projects;
}
@Output() pipelineCreated = new EventEmitter();
@Output() filterSearchChanged = new EventEmitter<{value: string; loadMore?: boolean}>();
ngOnInit(): void {
this.searchChanged(['*', null].includes(this.defaultProjectId) ? '' : this.defaultProjectId);
setTimeout(() => {
this.subs.add(this.projectInput.valueChanges.subscribe(searchString => {
if (searchString !== this.pipeline.project) {
this.searchChanged(searchString?.label || searchString || '');
}
})
);
});
}
ngOnDestroy(): void {
this.subs.unsubscribe();
}
ngOnChanges(): void {
if (this.projects?.length > 0 && this.pipeline.project === null) {
this.pipeline.project = this.projectsOptions.find(p => p.value === this.defaultProjectId) || {label: this.projectsRoot.label, value: null};
this.projectInput.control.updateValueAndValidity();
}
}
createNewSelected($event: MatOptionSelectionChange) {
this.pipeline.project = {label: $event.source.value, value: null};
}
projectSelected($event: MatOptionSelectionChange) {
this.pipeline.project = {label: $event.source.value.label, value: $event.source.value.value};
}
setIsAutoCompleteOpen(focus: boolean) {
this.isAutoCompleteOpen = focus;
}
displayFn(project: IOption | string) {
return typeof project === 'string' ? project : project?.label;
}
clear() {
this.projectInput.control.setValue('');
}
send() {
this.pipelineCreated.emit(this.pipeline);
}
searchChanged(searchString: string) {
this.projectsOptions = null;
this.projectsNames = null;
this.rootFiltered = searchString && !this.projectsRoot.label.toLowerCase().includes(searchString.toLowerCase());
searchString !== null && this.filterSearchChanged.emit({value: searchString, loadMore: false});
}
loadMore(searchString) {
this.loading = true;
this.filterSearchChanged.emit({value: searchString || '', loadMore: true});
}
isFocused(locationRef: HTMLInputElement) {
return document.activeElement === locationRef;
}
}

View File

@@ -0,0 +1,9 @@
<sm-dialog-template iconClass="al-ico-pipelines" header="CREATE NEW PIPELINE">
<sm-create-new-pipeline-form
[projects]="projects$| async"
[readOnlyProjectsNames]="readOnlyProjectsNames$ | async"
[defaultProjectId]="data?.defaultProjectId"
(pipelineCreated)="createPipeline($event)"
(filterSearchChanged)="filterSearchChanged($event)"
></sm-create-new-pipeline-form>
</sm-dialog-template>

View File

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

View File

@@ -0,0 +1,53 @@
import {Component, Inject} from '@angular/core';
import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog';
import {Store} from '@ngrx/store';
import {Observable} from 'rxjs';
import {selectTablesFilterProjectsOptions} from '@common/core/reducers/projects.reducer';
import {getTablesFilterProjectsOptions, resetTablesFilterProjectsOptions} from '@common/core/actions/projects.actions';
import {map} from 'rxjs/operators';
import { Project } from '~/business-logic/model/projects/project';
import {isReadOnly} from '@common/shared/utils/is-read-only';
import { PipelinesCreateRequest } from '~/business-logic/model/pipelines/models';
@Component({
selector: 'sm-pipeline-dialog',
templateUrl: './pipeline-dialog.component.html',
styleUrls: ['./pipeline-dialog.component.scss']
})
export class PipelineDialogComponent {
public projects$: Observable<Project[]>;
public readOnlyProjectsNames$: Observable<string[]>;
constructor(
private store: Store,
private matDialogRef: MatDialogRef<PipelineDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: { defaultProjectId: string}
) {
this.projects$ = this.store.select(selectTablesFilterProjectsOptions);
this.readOnlyProjectsNames$ = this.store.select(selectTablesFilterProjectsOptions)
.pipe(map(projects => projects?.filter(project => isReadOnly(project)).map(project=> project.name)));
this.store.dispatch(resetTablesFilterProjectsOptions());
}
public createPipeline(pipelineForm) {
const pipeline = this.convertFormToPipeline(pipelineForm);
this.matDialogRef.close(pipeline);
}
private convertFormToPipeline(pipelineForm: any): PipelinesCreateRequest {
return {
name: pipelineForm.name,
description: pipelineForm.description,
project:pipelineForm.project.value,
tags: pipelineForm.tags,
parameters: pipelineForm.parameters
};
}
filterSearchChanged($event: {value: string; loadMore?: boolean}) {
!$event.loadMore && this.store.dispatch(resetTablesFilterProjectsOptions());
this.store.dispatch(getTablesFilterProjectsOptions({searchString: $event.value || '', loadMore: $event.loadMore, allowPublic: false}));
}
}

View File

@@ -27,11 +27,13 @@ import {
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 {
// 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';
@Component({
selector: 'sm-pipelines-page',
@@ -132,12 +134,25 @@ if __name__ == '__main__':
}
createPipeline() {
this.dialog.open(PipelinesEmptyStateComponent, {
data: {
pipelineCode: this.initPipelineCode
},
width: '1248px'
});
this.dialog.open(PipelineDialogComponent, {
data: {defaultProjectId: this.projectId},
panelClass: 'light-theme',
width: '640px'
})
.afterClosed()
.subscribe(pipeline => {
if (pipeline) {
this.store.dispatch(createPipeline({pipelinesCreateRequest: pipeline}));
}
});
// this.dialog.open(PipelineDialogComponent, {
// data: {
// panelClass: 'light-theme',
// },
// width: '640px'
// });
}

View File

@@ -0,0 +1,179 @@
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';
export const PIPELINES_PREFIX = 'PIPELINES_';
export const createPipeline = createAction(
PIPELINES_PREFIX + 'CREATE_PIPELINE',
props<{ pipelinesCreateRequest: PipelinesCreateRequest }>()
);
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'
);
export const setPipelinesOrderBy = createAction(
PIPELINES_PREFIX + 'SET_ORDER_BY',
props<{orderBy: string}>()
);
export const setPipelinesSearchQuery = createAction(
PIPELINES_PREFIX + 'SET_SEARCH_QUERY',
props<{query: string; regExp?: boolean, skipGetAll?: boolean}>()
);
export const resetPipelinesSearchQuery = createAction(PIPELINES_PREFIX + 'RESET_SEARCH_QUERY');
export const addToPipelinesList = createAction(
PIPELINES_PREFIX + 'ADD_TO_PIPELINES_LIST',
props<{pipelines: Pipeline[]; reset?: boolean}>()
);
export const resetPipelines = createAction(PIPELINES_PREFIX + 'RESET_PIPELINES');
export const checkPipelineForDeletion = createAction(
PIPELINES_PREFIX + 'CHECK_PIPELINE_FOR_DELETION',
props<{pipeline: Pipeline}>()
);
export const resetReadyToDelete = createAction(PIPELINES_PREFIX + 'RESET_READY_TO_DELETE');
export const setNoMorePipelines = createAction(
PIPELINES_PREFIX + 'SET_NO_MORE_PIPELINES',
props<{payload: boolean}>()
);
export const setCurrentScrollId = createAction(
PIPELINES_PREFIX + ' [set current scrollId]',
props<{scrollId: string}>()
);
export const setTableModeAwareness = createAction(
PIPELINES_PREFIX + '[set table mode awareness]',
props<{awareness: boolean}>()
);
export const showExamplePipelines = createAction(PIPELINES_PREFIX + '[show pipelines examples]');
export const showExampleDatasets = createAction(PIPELINES_PREFIX + '[show datasets examples]');
// export const resetReports = createAction(PIPELINES_PREFIX + '[reset reports]');
// export const getReports = createAction(
// PIPELINES_PREFIX + '[get reports]',
// (loadMore = false) => ({loadMore})
// );
// export const getReportsTags = createAction(
// PIPELINES_PREFIX + '[get reports tags]'
// );
// export const setReportsTags = createAction(
// PIPELINES_PREFIX + '[set reports tags]',
// props<{ tags: string[] }>()
// );
// export const addReportsTags = createAction(
// PIPELINES_PREFIX + '[add reports tags]',
// props<{ tags: string[] }>()
// );
// export const setReports = createAction(
// PIPELINES_PREFIX + '[set reports]',
// props<{ reports: IReport[]; scroll: ReportsGetAllExResponse['scroll_id']; noMoreReports: boolean }>()
// );
// export const addReports = createAction(
// PIPELINES_PREFIX + '[add reports]',
// 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]',
// props<{ report: IReport }>()
// );
// export const deleteReport = createAction(
// PIPELINES_PREFIX + '[delete report]',
// props<{ report: IReport }>()
// );
// export const updateReport = createAction(
// PIPELINES_PREFIX + '[update report]',
// props<{ id: string; changes: Partial<IReport>; refresh?: boolean }>()
// );
// export const moveReport = createAction(
// PIPELINES_PREFIX + '[move report]',
// props<{ report: IReport }>()
// );
// export const navigateToProjectAfterMove = createAction(
// PIPELINES_PREFIX + '[navigateToProjectAfterMove]',
// props<{ projectId: string }>()
// );
// export const publishReport = createAction(
// PIPELINES_PREFIX + '[publish report]',
// props<{ id: string }>()
// );
// export const removeReport = createAction(
// PIPELINES_PREFIX + '[remove report]',
// props<{ id: string }>()
// );
// export const setReportChanges = createAction(
// PIPELINES_PREFIX + '[set report changes]',
// props<{ id: string; changes: Partial<IReport>; filterOut?: boolean}>()
// );
// export const setArchive = createAction(
// PIPELINES_PREFIX + '[set archive view]',
// props<{ archive: boolean }>()
// );
// export const archiveReport = createAction(
// PIPELINES_PREFIX + '[archive report]',
// props<{ report: IReport; skipUndo?: boolean }>()
// );
// export const restoreReport = createAction(
// PIPELINES_PREFIX + '[restore report]',
// props<{ report: IReport; skipUndo?: boolean }>()
// );
// export const setReportsOrderBy = createAction(
// PIPELINES_PREFIX + 'SET_ORDER_BY',
// props<{ orderBy: string }>()
// );
// export const setReportsSearchQuery = createAction(
// PIPELINES_PREFIX + 'SET_SEARCH_QUERY',
// props<{ query: string; regExp?: boolean }>()
// );
// export const deleteResource = createAction(
// PIPELINES_PREFIX + 'DELETE_RESOURCE',
// props<{resource: string}>()
// );
// export const setEditMode = createAction(
// PIPELINES_PREFIX + 'Set Edit Mode',
// props<{editing: boolean}>()
// );
// export const setDirty = createAction(
// PIPELINES_PREFIX + 'Set Dirty',
// props<{dirty: boolean}>()
// );

View File

@@ -0,0 +1,667 @@
import {Injectable} from '@angular/core';
import {Actions, /* 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 {requestFailed} from '../core/actions/http.actions';
import {
createPipeline
} from './pipelines.actions';
// import {ApiReportsService} from '~/business-logic/api-services/reports.service';
/* import {IReport, PAGE_SIZE} from './reports.consts';
import {
selectArchiveView,
selectNestedReports,
selectReport,
selectReportsOrderBy,
selectReportsQueryString,
selectReportsScrollId,
selectReportsSortOrder
} from '@common/reports/reports.reducer';
import {ReportsGetAllExResponse} from '~/business-logic/model/reports/reportsGetAllExResponse';
import {Report} from '~/business-logic/model/reports/report';
import {ReportsUpdateResponse} from '~/business-logic/model/reports/reportsUpdateResponse';
import {ReportsMoveResponse} from '~/business-logic/model/reports/reportsMoveResponse';
import {
selectHideExamples,
selectMainPageTagsFilter,
selectMainPageTagsFilterMatchMode,
selectSelectedProjectId
} from '../core/reducers/projects.reducer';
import {TABLE_SORT_ORDER} from '../shared/ui-components/data/table/table.consts';
import {selectCurrentUser, selectShowOnlyUserWork} from '../core/reducers/users-reducer';
import {escapeRegex} from '../shared/utils/escape-regex';
import {MESSAGES_SEVERITY} from '../constants'; */
import {MatDialog} from '@angular/material/dialog';
/* import {
ChangeProjectDialogComponent
} from '@common/experiments/shared/components/change-project-dialog/change-project-dialog.component';
import {ReportsMoveRequest} from '~/business-logic/model/reports/reportsMoveRequest';
import {selectActiveWorkspaceReady} from '~/core/reducers/view.reducer';
*/
// import {ReportsCreateResponse} from '~/business-logic/model/reports/reportsCreateResponse';
// import {ConfirmDialogComponent} from '@common/shared/ui-components/overlay/confirm-dialog/confirm-dialog.component';
import {HttpClient} from '@angular/common/http';
import { PipelinesCreateResponse } from '~/business-logic/model/pipelines/pipelinesCreateResponse';
import { ApiPipelinesService } from '~/business-logic/api-services/pipelines.service';
/* import {selectRouterParams} from '@common/core/reducers/router-reducer';
import {setMainPageTagsFilter} from '@common/core/actions/projects.actions';
import {cleanTag} from '@common/shared/utils/helpers.util';
import {excludedKey, getTagsFilters} from '@common/shared/utils/tableParamEncode'; */
@Injectable()
export class PipelinesEffects {
constructor(
private actions: Actions,
private store: Store,
private route: ActivatedRoute,
private router: Router,
private pipelinesApiService: ApiPipelinesService,
private http: HttpClient,
private matDialog: MatDialog,
// public projectsApi: ApiProjectsService,
) {
}
activeLoader = createEffect(() => this.actions.pipe(
ofType(/* getReports, getReport, */ createPipeline,/* updateReport, restoreReport, archiveReport */),
filter(action => !action['refresh']),
map(action => activeLoader(action.type))
));
createPipeline$ = createEffect(() => this.actions.pipe(
ofType(createPipeline),
switchMap((action) => this.pipelinesApiService.pipelinesCreate(action.pipelinesCreateRequest)
.pipe(mergeMap((res: PipelinesCreateResponse) => {
this.router.navigate(['pipelines', res.id, 'edit']);
return [deactivateLoader(createPipeline.type)];
}),
catchError(err => {
// this.router.navigate(['pipelines', 'b2c6686fb12e4649a954991ca7c24518', 'edit']);
return [
requestFailed(err),
setServerError(err, null, 'failed to create a new pipeline'),
deactivateLoader(createPipeline.type),
]
})))
));
// activeLoader = createEffect(() => this.actions.pipe(
// ofType(updateProject, getAllProjectsPageProjects),
// 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)])
// )
// )
// ));
// getAllProjects = createEffect(() => this.actions.pipe(
// ofType(getAllProjectsPageProjects),
// concatLatestFrom(() => [
// this.store.select(selectRouterParams).pipe(map(params => params?.projectId)),
// this.store.select(selectSelectedProjectId),
// this.store.select(selectSelectedProject),
// ]),
// switchMap(([action, routerProjectId, projectId, selectedProject]) =>
// (selectedProject || !projectId && !routerProjectId ? of(selectedProject) : this.projectsApi.projectsGetAllEx({
// id: routerProjectId || projectId,
// // eslint-disable-next-line @typescript-eslint/naming-convention
// only_fields: ['name']
// }).pipe(map(res => res.projects[0])))
// .pipe(
// concatLatestFrom(() => [
// this.store.select(selectProjectsOrderBy),
// this.store.select(selectProjectsSortOrder),
// this.store.select(selectProjectsSearchQuery),
// this.store.select(selectProjectsScrollId),
// this.store.select(selectCurrentUser),
// this.store.select(selectShowOnlyUserWork),
// this.store.select(selectShowHidden),
// this.store.select(selectHideExamples),
// this.store.select(selectMainPageTagsFilter),
// this.store.select(selectMainPageTagsFilterMatchMode),
// ]),
// switchMap(([currentProject,
// orderBy, sortOrder, searchQuery, scrollId, user, showOnlyUserWork, showHidden, hideExamples,
// mainPageTagsFilter, mainPageTagsFilterMatchMode]
// ) => {
// const selectedProjectId = routerProjectId || projectId; // In rare cases where router not updated yet with
// const selectedProjectName = selectSelectedProjectId && selectedProjectId !== '*' ? currentProject?.name : null;
// const selectedProjectBasename = selectedProjectName?.split('/').at(-1);
// // current project id
// const projectsView = this.route.snapshot.firstChild.routeConfig.path === 'projects';
// const nested = this.route.snapshot.firstChild?.firstChild?.firstChild?.routeConfig?.path === 'projects';
// const datasets = isDatasets(this.route.snapshot);
// const pipelines = isPipelines(this.route.snapshot);
// const reports = isReports(this.route.snapshot);
// let statsFilter;
// /* eslint-disable @typescript-eslint/naming-convention */
// if (!nested) {
// if (pipelines) {
// statsFilter = {system_tags: ['pipeline'], type: [TaskTypeEnum.Controller]};
// } else if (datasets) {
// statsFilter = {system_tags: ['dataset'], type: [TaskTypeEnum.DataProcessing]};
// }
// }
// if (projectsView && !showHidden) {
// statsFilter = {system_tags: ['-pipeline', '-dataset', '-Annotation', '-report']};
// }
// return forkJoin([
// // projects list
// this.projectsApi.projectsGetAllEx({
// ...(!nested && mainPageTagsFilter?.length > 0 && {
// filters: {
// tags: getTagsFilters(mainPageTagsFilterMatchMode === 'AND', mainPageTagsFilter),
// }
// }),
// ...(nested && mainPageTagsFilter?.length > 0 && {
// children_tags_filter: getTagsFilters(mainPageTagsFilterMatchMode === 'AND', mainPageTagsFilter)
// }),
// stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active,
// include_stats: true,
// shallow_search: !searchQuery?.query,
// ...(((projectsView || nested) && !searchQuery?.query) && {permission_roots_only: true}),
// ...((projectsView && selectedProjectId && selectedProjectId !== '*') && {parent: [selectedProjectId]}),
// scroll_id: scrollId || null, // null to create new scroll (undefined doesn't generate scroll)
// size: pageSize,
// ...(showOnlyUserWork && {active_users: [user?.id]}),
// ...((showHidden) && {search_hidden: true}),
// ...(hideExamples && {allow_public: false}),
// order_by: ['featured', sortOrder === TABLE_SORT_ORDER.DESC ? '-' + orderBy : orderBy],
// only_fields: ['name', 'company', 'user', 'created', 'default_output_destination', 'basename', 'system_tags']
// .concat(pipelines || datasets ? ['tags', 'last_update'] : []),
// ...(searchQuery?.query && {
// _any_: {
// pattern: searchQuery.regExp ? searchQuery.query : escapeRegex(searchQuery.query),
// fields: ['id', 'basename', 'description']
// }
// }),
// ...(!projectsView && getFeatureProjectRequest(this.route.snapshot, nested, searchQuery, selectedProjectName, selectedProjectId)),
// }),
// // Getting [current project] stats from server
// ((nested || projectsView) && selectedProjectId && selectedProjectId !== '*' && !scrollId && !searchQuery?.query) ?
// this.projectsApi.projectsGetAllEx({
// ...(!datasets && !pipelines && !reports && {id: selectedProjectId}),
// ...(datasets && {
// name: `^${escapeRegex(selectedProjectName)}/\\.datasets$`,
// search_hidden: true,
// children_type: 'dataset'
// }),
// ...(pipelines && {
// name: `^${escapeRegex(selectedProjectName)}/\\.pipelines$`,
// search_hidden: true,
// children_type: 'pipeline'
// }),
// ...(reports && {
// name: `^${escapeRegex(selectedProjectName)}/\\.reports$`,
// search_hidden: true,
// children_type: 'report'
// }),
// ...((!showHidden && projectsView) && {include_stats_filter: statsFilter}),
// ...((pipelines && !nested) && {
// include_stats_filter: {
// system_tags: ['pipeline'],
// type: ['controller']
// }
// }),
// ...(datasets && !nested ? {include_dataset_stats: true} : {include_stats: true}),
// stats_with_children: reports || pipelines || datasets,
// stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active,
// ...(showHidden && {search_hidden: true}),
// check_own_contents: true, // in order to check if project is empty
// ...(showOnlyUserWork && {active_users: [user.id]}),
// only_fields: ['name', 'company', 'user', 'created', 'default_output_destination'],
// ...(!projectsView && getSelfFeatureProjectRequest(this.route.snapshot)),
// }) : nested && reports && selectedProjectId === '*' && !scrollId && !searchQuery?.query ?
// // nested reports virtual card
// this.projectsApi.projectsGetAllEx({
// name: '^\\.reports$',
// search_hidden: true,
// children_type: 'report',
// stats_with_children: false,
// stats_for_state: ProjectsGetAllExRequest.StatsForStateEnum.Active,
// include_stats: true,
// check_own_contents: true, // in order to check if project is empty
// ...(showOnlyUserWork && {active_users: [user.id]}),
// only_fields: ['id', 'company'],
// ...(mainPageTagsFilter?.length > 0 && {
// children_tags_filter: getTagsFilters(mainPageTagsFilterMatchMode === 'AND', mainPageTagsFilter)
// }),
// /* eslint-enable @typescript-eslint/naming-convention */
// }) :
// of(null),
// ]).pipe(
// debounceTime(0),
// map(([projectsRes, currentProjectRes]: [ProjectsGetAllExResponse, ProjectsGetAllExResponse]) => ({
// newScrollId: projectsRes.scroll_id,
// projects: currentProjectRes !== null && currentProjectRes.projects.length !== 0 &&
// this.isNotEmptyExampleProject(currentProjectRes.projects[0]) ?
// /* eslint-disable @typescript-eslint/naming-convention */
// [(currentProjectRes?.projects?.length === 0 ?
// {
// isRoot: true,
// sub_projects: null,
// name: `[${selectedProjectName}]`,
// basename: `[${selectedProjectBasename}]`
// } :
// {
// ...currentProjectRes.projects[0],
// id: selectedProjectId,
// isRoot: true,
// // eslint-disable-next-line @typescript-eslint/naming-convention
// sub_projects: null,
// name: !selectedProjectName && currentProjectRes.projects[0].stats ? '[Root]' : `[${selectedProjectName}]`,
// basename: !selectedProjectName && currentProjectRes.projects[0].stats ? '[Root]' : `[${selectedProjectBasename}]`
// }),
// ...projectsRes.projects
// /* eslint-enable @typescript-eslint/naming-convention */
// ] :
// projectsRes.projects
// }
// )),
// mergeMap(({newScrollId, projects}) => [
// addToProjectsList({
// projects, reset: !scrollId
// }),
// deactivateLoader(action.type),
// setCurrentScrollId({scrollId: newScrollId}),
// setNoMoreProjects({payload: projects.length < pageSize})]),
// catchError(error => [deactivateLoader(action.type), requestFailed(error)])
// );
// }
// )
// )
// ),
// ));
// updateProjectStats = createEffect(() => this.actions.pipe(
// ofType(setFilterByUser),
// concatLatestFrom(() => [
// this.store.select(selectSelectedProject),
// this.store.select(selectCurrentUser),
// this.store.select(selectShowHidden)
// ]),
// filter(([, project]) => !!project),
// switchMap(([action, project, user, showHidden]) => this.projectsApi.projectsGetAllEx({
// /* eslint-disable @typescript-eslint/naming-convention */
// id: [project.id],
// include_stats: true,
// ...(showHidden && {search_hidden: true}),
// ...(!showHidden && {include_stats_filter: {system_tags: ['-pipeline', '-dataset']}}),
// ...(action.showOnlyUserWork && {active_users: [user.id]}),
// /* eslint-enable @typescript-eslint/naming-convention */
// })),
// switchMap(({projects}) => [setSelectedProjectStats({project: projects[0]})]),
// catchError(error => [requestFailed(error)])
// ));
// setProjectsOrderBy = createEffect(() => this.actions.pipe(
// ofType(setProjectsOrderBy),
// mergeMap(() => [getAllProjectsPageProjects()])
// ));
// showExamplePipeline = createEffect(() => this.actions.pipe(
// ofType(showExamplePipelines),
// map(() => localStorage.setItem('_saved_pipeline_state_', JSON.stringify(
// {...JSON.parse(localStorage.getItem('_saved_pipeline_state_')), showPipelineExamples: true}
// )))
// ), {dispatch: false});
// showExampleDataset = createEffect(() => this.actions.pipe(
// ofType(showExampleDatasets),
// map(() => localStorage.setItem('_saved_pipeline_state_', JSON.stringify(
// {...JSON.parse(localStorage.getItem('_saved_pipeline_state_')), showDatasetExamples: true})))
// ), {dispatch: false});
// setProjectsSearchQuery = createEffect(() => this.actions.pipe(
// ofType(setProjectsSearchQuery),
// filter(action => !action.skipGetAll),
// mergeMap(() => [getAllProjectsPageProjects()])
// ));
// private isNotEmptyExampleProject(project: Project) {
// return !(isExample(project) && project.own_models === 0 && project.own_tasks === 0);
// }
// getReports = createEffect(() => this.actions.pipe(
// ofType(getReports, setReportsOrderBy),
// concatLatestFrom(() => [
// this.store.select(selectReportsScrollId),
// this.store.select(selectArchiveView),
// this.store.select(selectReportsOrderBy),
// this.store.select(selectReportsSortOrder),
// this.store.select(selectShowOnlyUserWork),
// this.store.select(selectMainPageTagsFilter),
// this.store.select(selectMainPageTagsFilterMatchMode),
// this.store.select(selectCurrentUser),
// this.store.select(selectReportsQueryString),
// this.store.select(selectHideExamples),
// this.store.select(selectRouterParams).pipe(map(params => params?.projectId)),
// ]),
// switchMap(([action, scroll, archive, orderBy, sortOrder, showOnlyUserWork, mainPageTagsFilter, mainPageTagsFilterMatchMode, user, searchQuery, hideExamples, projectId]) =>
// this.pipelinesApiService.reportsGetAllEx({
// /* eslint-disable @typescript-eslint/naming-convention */
// only_fields: ['name', 'comment', 'company', 'tags', 'report', 'project.name', 'user.name', 'status', 'last_update', 'system_tags'] as (keyof Report)[],
// size: PAGE_SIZE,
// project: projectId === '*' ? null : projectId,
// scroll_id: action['loadMore'] ? scroll : null,
// ...(hideExamples && {allow_public: false}),
// system_tags: [archive ? '__$and' : excludedKey, 'archived'],
// ...(showOnlyUserWork && {user: [user.id]}),
// order_by: [sortOrder === TABLE_SORT_ORDER.DESC ? '-' + orderBy : orderBy],
// ...(mainPageTagsFilter?.length > 0 && {
// filters: {
// tags: getTagsFilters(!!mainPageTagsFilterMatchMode, mainPageTagsFilter),
// }
// }),
// ...(searchQuery?.query && {
// _any_: {
// pattern: searchQuery.regExp ? searchQuery.query : escapeRegex(searchQuery.query),
// fields: ['id', 'name', 'tags', 'project', 'comment', 'report']
// }
// })
// /* eslint-enable @typescript-eslint/naming-convention */
// })
// .pipe(
// mergeMap((res: ReportsGetAllExResponse) => [
// deactivateLoader(action.type),
// action['loadMore'] ?
// addReports({
// reports: res.tasks as IReport[],
// scroll: res.scroll_id,
// noMoreReports: res.tasks.length < PAGE_SIZE
// }) :
// setReports({
// reports: res.tasks as IReport[],
// scroll: res.scroll_id,
// noMoreReports: res.tasks.length < PAGE_SIZE
// })
// ]),
// catchError(err => [
// requestFailed(err),
// setServerError(err, null, 'failed to fetch reports'),
// deactivateLoader(action.type),
// ])
// )
// )
// ));
// getReportsTags = createEffect(() => this.actions.pipe(
// ofType(getReportsTags),
// switchMap(() => this.pipelinesApiService.reportsGetTags({})),
// concatLatestFrom(() => this.store.select(selectMainPageTagsFilter)),
// mergeMap(([res, fTags]) => [
// setReportsTags({tags: res.tags}),
// ...(fTags?.some(fTag => !res.tags.includes(cleanTag(fTag))) ?
// [
// setMainPageTagsFilter({
// tags: fTags.filter(fTag => res.tags.includes(cleanTag(fTag))),
// feature: 'reports'
// })
// ] : []),
// ]),
// catchError(err => [
// requestFailed(err),
// setServerError(err, null, 'failed to fetch reports'),
// ])
// ));
// getReport = createEffect(() => this.actions.pipe(
// ofType(getReport),
// switchMap((action) => this.store.select(selectActiveWorkspaceReady).pipe(
// filter(ready => ready),
// map(() => action))),
// switchMap(action => this.pipelinesApiService.reportsGetAllEx({
// id: [action.id],
// // 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']
// })),
// tap(res => {
// if (res.tasks.length === 0) {
// this.router.navigateByUrl('/404');
// }
// }),
// mergeMap((res: ReportsGetAllExResponse) => [
// setReport({report: res.tasks[0] as IReport}),
// deactivateLoader(getReport.type),
// ]),
// catchError(err => [
// deactivateLoader(getReport.type),
// requestFailed(err),
// setServerError(err, null, 'failed to fetch report'),
// ])
// ));
// updateReport = createEffect(() => this.actions.pipe(
// ofType(updateReport),
// switchMap(action => this.pipelinesApiService.reportsUpdate({
// task: action.id,
// ...action.changes
// }).pipe(
// mergeMap((res: ReportsUpdateResponse) => [
// setReportChanges({id: action.id, changes: {...res.fields, ...action.changes}}),
// deactivateLoader(action.type),
// ]),
// catchError(err => [
// deactivateLoader(action.type),
// requestFailed(err),
// setServerError(err, null, 'failed to update report'),
// ])
// )
// )
// ));
// moveReport = createEffect(() => this.actions.pipe(
// ofType(moveReport),
// switchMap(action =>
// this.matDialog.open(ChangeProjectDialogComponent, {
// data: {
// currentProjects: action.report.project?.id ?? action.report.project,
// defaultProject: action.report.project,
// reference: action.report.name,
// type: 'report'
// }
// }).afterClosed()
// // eslint-disable-next-line @typescript-eslint/naming-convention
// .pipe(
// filter(project => !!project),
// // eslint-disable-next-line @typescript-eslint/naming-convention
// map(project => ({task: action.report.id, project: project.id, project_name: project.name}))
// )
// ),
// switchMap((moveRequest: ReportsMoveRequest) => this.pipelinesApiService.reportsMove(moveRequest)
// .pipe(
// concatLatestFrom(() => [
// this.store.select(selectSelectedProjectId),
// this.store.select(selectNestedReports)
// ]),
// mergeMap(([res, projectId, nested]: [ReportsMoveResponse, string, boolean]) => [
// setReportChanges({
// id: moveRequest.task,
// filterOut: projectId && (projectId !== '*' || nested) && projectId !== moveRequest.project,
// changes: {
// project: (moveRequest.project ?
// {id: res.project_id, name: moveRequest.project_name} :
// {id: res.project_id, name: moveRequest.project_name ?? 'Root project'})
// }
// }),
// deactivateLoader(moveReport.type),
// addMessage(MESSAGES_SEVERITY.SUCCESS, `Report moved successfully to ${moveRequest.project_name ?? 'Projects root'}`),
// navigateToProjectAfterMove({projectId: res.project_id})
// ]),
// catchError(err => [
// deactivateLoader(moveReport.type),
// requestFailed(err),
// setServerError(err, null, 'failed to move report'),
// ])
// )
// )
// ));
// navigateToProjectAfterMove = createEffect(() => this.actions.pipe(
// ofType(navigateToProjectAfterMove),
// concatLatestFrom(() => this.store.select(selectReport)),
// filter(([, report]) => !!report?.id),
// tap(([action, report]) => {
// this.router.navigateByUrl(`reports/${action.projectId}/${report.id}`);
// }),
// ), {dispatch: false});
// publishReport = createEffect(() => this.actions.pipe(
// ofType(publishReport),
// switchMap(action => this.pipelinesApiService.reportsPublish({task: action.id})
// .pipe(
// mergeMap((res: ReportsUpdateResponse) => [
// setReportChanges({id: action.id, changes: res.fields}),
// deactivateLoader(action.type),
// ]),
// catchError(err => [
// deactivateLoader(action.type),
// requestFailed(err),
// setServerError(err, null, 'failed to publish report'),
// ])
// )
// )
// ));
// archiveReport = createEffect(() => this.actions.pipe(
// ofType(archiveReport),
// switchMap((action) => this.pipelinesApiService.reportsArchive({task: action.report.id})
// .pipe(
// mergeMap(() => {
// const undoActions = [
// {
// name: 'Undo', actions: [
// restoreReport({report: action.report, skipUndo: true})
// ]
// }
// ];
// return [
// deactivateLoader(action.type),
// getReports(),
// ...(!action.skipUndo ?
// [addMessage(MESSAGES_SEVERITY.SUCCESS, 'Report archived successfully', [null, ...undoActions
// ].filter(a => a))] : []),
// // eslint-disable-next-line @typescript-eslint/naming-convention
// setReportChanges({
// id: action.report.id,
// // eslint-disable-next-line @typescript-eslint/naming-convention
// changes: {system_tags: (action.report.system_tags || []).concat('archived')}
// })
// ];
// }),
// catchError(error => [
// requestFailed(error),
// deactivateLoader(action.type),
// setServerError(error, null, 'Failed To Archive reports')
// ])
// )
// )
// ));
// restoreReport = createEffect(() => this.actions.pipe(
// ofType(restoreReport),
// switchMap((action) => this.pipelinesApiService.reportsUnarchive({task: action.report.id})
// .pipe(
// mergeMap(() => {
// const undoActions = [
// {
// name: 'Undo', actions: [
// archiveReport({report: action.report, skipUndo: true}),
// ]
// }
// ];
// const actions: Action[] = [
// deactivateLoader(action.type),
// getReports(),
// ...(!action.skipUndo ?
// [(addMessage(MESSAGES_SEVERITY.SUCCESS, 'Report restored successfully', [null, ...undoActions].filter(a => a)))] : []),
// setReportChanges({
// id: action.report.id,
// // eslint-disable-next-line @typescript-eslint/naming-convention
// changes: {system_tags: (action.report.system_tags || []).filter(tag => tag !== 'archived')}
// })
// ];
// return actions;
// }),
// catchError(error => [
// requestFailed(error),
// deactivateLoader(action.type),
// setServerError(error, null, 'Failed To restore reports')
// ])
// )
// )
// ));
// deleteReport = createEffect(() => this.actions.pipe(
// ofType(deleteReport),
// switchMap(action => this.matDialog.open(
// ConfirmDialogComponent,
// {
// data: {
// title: 'DELETE',
// body: '<p class="text-center">Permanently Delete Report</p>',
// yes: 'Delete',
// no: 'Cancel',
// iconClass: 'al-ico-trash',
// width: 430
// }
// }).afterClosed().pipe(
// filter(confirm => !!confirm),
// switchMap(() => this.pipelinesApiService.reportsDelete({task: action.report.id})),
// mergeMap(() => {
// this.router.navigate(['reports'], {queryParamsHandling: 'merge'});
// return [
// removeReport({id: action.report.id}),
// getReports(),
// deactivateLoader(action.type),
// addMessage(MESSAGES_SEVERITY.SUCCESS, 'Report deleted successfully')
// ];
// }),
// catchError(error => [
// requestFailed(error),
// deactivateLoader(action.type),
// setServerError(error, null, 'Failed To delete reports')
// ])
// )),
// ));
// deleteResource = createEffect(() => this.actions.pipe(
// ofType(deleteResource),
// switchMap(action => this.http.delete(action.resource)
// .pipe(
// catchError(() => [addMessage(MESSAGES_SEVERITY.ERROR, 'failed to delete resource')]),
// concatLatestFrom(() => this.store.select(selectReport)),
// mergeMap(([, report]) => [updateReport({
// id: report.id,
// changes: {
// // eslint-disable-next-line @typescript-eslint/naming-convention
// report_assets: report.report_assets?.filter(r => r !== action.resource),
// }
// })])
// )
// )
// ));
}

View File

@@ -1,78 +1,155 @@
import {InjectionToken, NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {PipelinesPageComponent} from './pipelines-page/pipelines-page.component';
import {CommonProjectsModule} from '@common/projects/common-projects.module';
import {StoreConfig, StoreModule} from '@ngrx/store';
import {projectsReducer, ProjectsState} from '~/features/projects/projects.reducer';
import {ProjectsSharedModule} from '~/features/projects/shared/projects-shared.module';
import {merge} from 'lodash-es';
import {PipelinesRouterModule} from '@common/pipelines/pipelines.route';
import {PipelineCardComponent} from '@common/pipelines/pipeline-card/pipeline-card.component';
import {ButtonToggleComponent} from '@common/shared/ui-components/inputs/button-toggle/button-toggle.component';
import { EditPipelineComponent } from './edit-pipeline/edit-pipeline.component';
import { EditPipelineHeaderComponent } from './edit-pipeline-header/edit-pipeline-header.component';
import {ClearFiltersButtonComponent} from '@common/shared/components/clear-filters-button/clear-filters-button.component';
import {MenuComponent} from '@common/shared/ui-components/panel/menu/menu.component';
import {MenuItemComponent} from '@common/shared/ui-components/panel/menu-item/menu-item.component';
import {MAT_FORM_FIELD_DEFAULT_OPTIONS} from '@angular/material/form-field';
// import { ExperimentCustomColsMenuComponent } from '@common/experiments/dumb/experiment-custom-cols-menu/experiment-custom-cols-menu.component';
import { RefreshButtonComponent } from '@common/shared/components/refresh-button/refresh-button.component';
import { ExperimentSharedModule } from '~/features/experiments/shared/experiment-shared.module';
import { LabeledFormFieldDirective } from "../shared/directive/labeled-form-field.directive";
import { InjectionToken, NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { PipelinesPageComponent } from "./pipelines-page/pipelines-page.component";
import { CommonProjectsModule } from "@common/projects/common-projects.module";
import { ActionReducer, StoreConfig, StoreModule } from "@ngrx/store";
import {
projectsReducer,
ProjectsState,
} from "~/features/projects/projects.reducer";
import { ProjectsSharedModule } from "~/features/projects/shared/projects-shared.module";
import { merge } from "lodash-es";
import { PipelinesRouterModule } from "@common/pipelines/pipelines.route";
import { PipelineCardComponent } from "@common/pipelines/pipeline-card/pipeline-card.component";
import { ButtonToggleComponent } from "@common/shared/ui-components/inputs/button-toggle/button-toggle.component";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { MatMenuModule } from "@angular/material/menu";
import { MatSidenavModule } from "@angular/material/sidenav";
import { MatInputModule } from "@angular/material/input";
import { PipelineDialogComponent } from "./pipeline-dialog/pipeline-dialog.component";
import { CreateNewPipelineFormComponent } from "./pipeline-dialog/create-new-pipeline-form/create-new-pipeline-form.component";
import { MatAutocompleteModule } from "@angular/material/autocomplete";
import { ScrollEndDirective } from "@common/shared/ui-components/directives/scroll-end.directive";
import { ClickStopPropagationDirective } from "@common/shared/ui-components/directives/click-stop-propagation.directive";
import { ShowTooltipIfEllipsisDirective } from "@common/shared/ui-components/indicators/tooltip/show-tooltip-if-ellipsis.directive";
import { MatProgressSpinnerModule } from "@angular/material/progress-spinner";
import { TooltipDirective } from "@common/shared/ui-components/indicators/tooltip/tooltip.directive";
import { SearchTextDirective } from "@common/shared/ui-components/directives/searchText.directive";
import { SharedModule } from "~/shared/shared.module";
import { CommonLayoutModule } from "@common/layout/layout.module";
import { ScrollingModule } from "@angular/cdk/scrolling";
import { ExistNameValidatorDirective } from "@common/shared/ui-components/template-forms-ui/exist-name-validator.directive";
import { UniqueNameValidatorDirective } from "@common/shared/ui-components/template-forms-ui/unique-name-validator.directive";
import { MarkdownEditorComponent } from "@common/shared/components/markdown-editor/markdown-editor.component";
import { SearchComponent } from "@common/shared/ui-components/inputs/search/search.component";
import { TagListComponent } from "@common/shared/ui-components/tags/tag-list/tag-list.component";
import { DialogTemplateComponent } from "@common/shared/ui-components/overlay/dialog-template/dialog-template.component";
import { ToggleArchiveComponent } from "@common/shared/ui-components/buttons/toggle-archive/toggle-archive.component";
import { LabeledFormFieldDirective } from "@common/shared/directive/labeled-form-field.directive";
import { EditPipelineComponent } from "./edit-pipeline/edit-pipeline.component";
import { EditPipelineHeaderComponent } from "./edit-pipeline-header/edit-pipeline-header.component";
import { ClearFiltersButtonComponent } from "@common/shared/components/clear-filters-button/clear-filters-button.component";
import { MenuComponent } from "@common/shared/ui-components/panel/menu/menu.component";
import { MenuItemComponent } from "@common/shared/ui-components/panel/menu-item/menu-item.component";
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from "@angular/material/form-field";
import { RefreshButtonComponent } from "@common/shared/components/refresh-button/refresh-button.component";
import { ExperimentSharedModule } from "~/features/experiments/shared/experiment-shared.module";
import { EffectsModule } from "@ngrx/effects";
import { PipelinesEffects } from "./pipelines.effects";
import { PipelineState, pipelinesReducer, PIPELINES_KEY } from "./pipelines.reducer";
import { UserPreferences } from "@common/user-preferences";
import { createUserPrefFeatureReducer } from "@common/core/meta-reducers/user-pref-reducer";
import { PIPELINES_PREFIX } from "./pipelines.actions";
export const pipelinesSyncedKeys = ["projects.showPipelineExamples"];
const pipelinesSyncedKeys2 = ['orderBy', 'sortOrder'];
// export const REPORTS_STORE_CONFIG_TOKEN =
// new InjectionToken<StoreConfig<ReportsState, any>>('DatasetsConfigToken');
export const PIPELINES_CONFIG_TOKEN = new InjectionToken<
StoreConfig<ProjectsState, any>
>("PipelineConfigToken");
export const pipelinesSyncedKeys = [
'projects.showPipelineExamples',
];
export const PIPELINES_CONFIG_TOKEN_FOR_PIPELINE_SERVICE =
new InjectionToken<StoreConfig<PipelineState, any>>('PipelineConfigToken');
export const PIPELINES_CONFIG_TOKEN =
new InjectionToken<StoreConfig<ProjectsState , any>>('PipelineConfigToken');
const localStorageKey = '_saved_pipeline_state_';
const localStorageKey = "_saved_pipeline_state_";
const getPipelineConfig = () => ({
metaReducers: [reducer => {
let onInit = true;
return (state, action) => {
const nextState = reducer(state, action);
if (onInit) {
onInit = false;
const savedState = JSON.parse(localStorage.getItem(localStorageKey));
return merge({}, nextState, savedState);
}
return nextState;
};
}]
metaReducers: [
(reducer) => {
let onInit = true;
return (state, action) => {
const nextState = reducer(state, action);
if (onInit) {
onInit = false;
const savedState = JSON.parse(localStorage.getItem(localStorageKey));
return merge({}, nextState, savedState);
}
return nextState;
};
},
],
});
const getInitState = (userPreferences: UserPreferences) => ({
metaReducers: [
(reducer: ActionReducer<any>) =>
createUserPrefFeatureReducer(PIPELINES_KEY, pipelinesSyncedKeys2, [PIPELINES_PREFIX], userPreferences, reducer),
]
});
@NgModule({
declarations: [
PipelinesPageComponent,
EditPipelineComponent,
EditPipelineHeaderComponent,
],
exports: [PipelinesPageComponent, EditPipelineComponent],
providers: [
{ provide: PIPELINES_CONFIG_TOKEN, useFactory: getPipelineConfig },
{ provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { floatLabel: 'always' } },
],
imports: [
CommonModule,
CommonProjectsModule,
ProjectsSharedModule,
PipelinesRouterModule,
StoreModule.forFeature('projects', projectsReducer, PIPELINES_CONFIG_TOKEN),
PipelineCardComponent,
ButtonToggleComponent,
ClearFiltersButtonComponent,
MenuComponent,
MenuItemComponent,
ExperimentSharedModule,
RefreshButtonComponent,
LabeledFormFieldDirective
]
declarations: [
PipelinesPageComponent,
PipelineDialogComponent,
CreateNewPipelineFormComponent,
EditPipelineComponent,
EditPipelineHeaderComponent,
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
CommonProjectsModule,
ProjectsSharedModule,
PipelinesRouterModule,
StoreModule.forFeature("projects", projectsReducer, PIPELINES_CONFIG_TOKEN),
EffectsModule.forFeature([PipelinesEffects]),
StoreModule.forFeature(PIPELINES_KEY, pipelinesReducer, PIPELINES_CONFIG_TOKEN_FOR_PIPELINE_SERVICE),
PipelineCardComponent,
ButtonToggleComponent,
SharedModule,
CommonLayoutModule,
ScrollingModule,
ExistNameValidatorDirective,
MatProgressSpinnerModule,
LabeledFormFieldDirective,
SearchTextDirective,
UniqueNameValidatorDirective,
MarkdownEditorComponent,
SearchComponent,
TagListComponent,
DialogTemplateComponent,
TooltipDirective,
ButtonToggleComponent,
ToggleArchiveComponent,
MatMenuModule,
MatSidenavModule,
MatInputModule,
MatAutocompleteModule,
ScrollEndDirective,
ClickStopPropagationDirective,
ShowTooltipIfEllipsisDirective,
ClearFiltersButtonComponent,
MenuComponent,
MenuItemComponent,
ExperimentSharedModule,
RefreshButtonComponent,
LabeledFormFieldDirective,
],
exports: [PipelinesPageComponent, EditPipelineComponent],
providers: [
{ provide: PIPELINES_CONFIG_TOKEN, useFactory: getPipelineConfig },
{provide: PIPELINES_CONFIG_TOKEN_FOR_PIPELINE_SERVICE, useFactory: getInitState, deps: [UserPreferences]},
{
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
useValue: { floatLabel: "always" },
},
],
})
export class PipelinesModule { }
export class PipelinesModule {}

View File

@@ -0,0 +1,158 @@
import {ActionCreator, createReducer, createSelector, on, ReducerTypes} from '@ngrx/store';
import {TABLE_SORT_ORDER, TableSortOrderEnum} from '../shared/ui-components/data/table/table.consts';
import {
addToPipelinesList,
checkPipelineForDeletion,
resetPipelines,
resetPipelinesSearchQuery,
resetReadyToDelete,
setCurrentScrollId,
setNoMorePipelines,
setPipelinesOrderBy,
setPipelinesSearchQuery,
setTableModeAwareness,
showExampleDatasets,
showExamplePipelines,
updatePipelineSuccess
} from './pipelines.actions';
import {SearchState} from '../common-search/common-search.reducer';
import { Pipeline } from '~/business-logic/model/pipelines/pipeline';
export const PIPELINES_KEY = 'pipelines';
export interface CommonReadyForDeletion {
experiments: { total: number; archived: number; unarchived: number };
models: { total: number; archived: number; unarchived: number };
reports: { total: number; archived: number; unarchived: number };
pipelines: { total: number; unarchived: number };
datasets: { total: number; unarchived: number };
}
export interface CommonProjectReadyForDeletion extends CommonReadyForDeletion {
project: Pipeline;
}
export interface PipelineState {
orderBy: string;
sortOrder: TableSortOrderEnum;
searchQuery: SearchState['searchQuery'];
pipelines: Pipeline[];
pipelinesNonFilteredList: Pipeline[];
selectedProjectId: string;
selectedProject: Pipeline;
projectReadyForDeletion: CommonReadyForDeletion;
validatedProject: Pipeline;
noMorePipelines: boolean;
scrollId: string;
tableModeAwareness: boolean;
showPipelineExamples: boolean;
showDatasetExamples: boolean;
}
export const pipelinesInitState: PipelineState = {
pipelines: null,
selectedProjectId: '',
selectedProject: {},
orderBy: 'last_update',
sortOrder: TABLE_SORT_ORDER.DESC,
searchQuery: null,
pipelinesNonFilteredList: [],
projectReadyForDeletion: null,
validatedProject: null,
noMorePipelines: true,
scrollId: null,
tableModeAwareness: true,
showPipelineExamples: false,
showDatasetExamples: false,
};
const getCorrectSortingOrder = (currentSortOrder: TableSortOrderEnum, currentOrderField: string, nextOrderField: string) => {
if (currentOrderField === nextOrderField) {
return currentSortOrder === TABLE_SORT_ORDER.DESC ? TABLE_SORT_ORDER.ASC : TABLE_SORT_ORDER.DESC;
} else {
return nextOrderField === 'last_update' ? TABLE_SORT_ORDER.DESC : TABLE_SORT_ORDER.ASC;
}
};
export const pipelinesReducers = [
on(addToPipelinesList, (state, action) => ({
...state,
pipelines: action.reset ? action.pipelines : [...(state.pipelines || []), ...action.pipelines]
})),
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 ? {
...pr,
...action.changes,
...(!!action.changes?.name && {basename: action.changes?.name.split('/').at(-1)})
} : pr)
})),
on(resetPipelines, state => ({
...state,
scrollId: null,
noMorePipelines: pipelinesInitState.noMorePipelines,
pipelines: pipelinesInitState.pipelines
})),
on(setPipelinesOrderBy, (state, action) => ({
...state,
orderBy: action.orderBy,
sortOrder: getCorrectSortingOrder(state.sortOrder, state.orderBy, action.orderBy),
scrollId: null,
noMorePipelines: pipelinesInitState.noMorePipelines,
pipelines: pipelinesInitState.pipelines
})),
on(setPipelinesSearchQuery, (state, action) => ({
...state,
searchQuery: (action as ReturnType<typeof setPipelinesSearchQuery>),
scrollId: null,
noMorePipelines: pipelinesInitState.noMorePipelines,
pipelines: pipelinesInitState.pipelines
})),
on(resetPipelinesSearchQuery, state => ({
...state,
// searchQuery: pipelinesInitState.searchQuery,
scrollId: null,
noMorePipelines: pipelinesInitState.noMorePipelines,
pipelines: pipelinesInitState.pipelines
})),
on(checkPipelineForDeletion, (state, action) => ({
...state,
validatedProject: action.pipeline,
projectReadyForDeletion: pipelinesInitState.projectReadyForDeletion
})),
on(resetReadyToDelete, state => ({
...state,
projectReadyForDeletion: pipelinesInitState.projectReadyForDeletion,
validatedProject: pipelinesInitState.validatedProject
})),
on(setTableModeAwareness, (state, action) =>
({...state, tableModeAwareness: (action as ReturnType<typeof setTableModeAwareness>).awareness})),
on(showExamplePipelines, state => ({...state, showPipelineExamples: true})),
on(showExampleDatasets, state => ({...state, showDatasetExamples: true}))
] as ReducerTypes<PipelineState, ActionCreator[]>[];
export const pipelinesReducer = createReducer(pipelinesInitState, ...pipelinesReducers);
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 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);
export const selectValidatedProject = createSelector(pipelines, state => state.validatedProject);
export const selectReadyForDeletion = createSelector(pipelines, state =>
state.projectReadyForDeletion);
export const selectProjectReadyForDeletion = createSelector(selectValidatedProject, selectReadyForDeletion,
(project, projectReadyForDeletion) => projectReadyForDeletion ? {...projectReadyForDeletion, project} : null);
export const selectProjectForDelete = createSelector(pipelines, state => [state?.validatedProject]);
export const selectNoMorePipelines = createSelector(pipelines, state => state.noMorePipelines);
export const selectPipelinesScrollId = createSelector(pipelines, (state): string => state?.scrollId || null);
export const selectTableModeAwareness = createSelector(pipelines, state => state?.tableModeAwareness);
export const selectShowPipelineExamples = createSelector(pipelines, state => state?.showPipelineExamples);
export const selectShowDatasetExamples = createSelector(pipelines, state => state?.showDatasetExamples);