set active project
This commit is contained in:
parent
814eb485eb
commit
4e726be376
25 changed files with 58 additions and 151 deletions
|
@ -1,8 +1,6 @@
|
|||
import {
|
||||
IProjectInstanceModel,
|
||||
ProjectInstanceDbModel,
|
||||
} from "../../features/projects/models/project_instance_database_model";
|
||||
|
||||
import { pipelineRealTimeService } from "../../features/_realtime/realtime_presentation";
|
||||
import { IProjectModel, ProjectDBModel } from "../../features/projects/models/project_model_database_model";
|
||||
import { App } from "../controllers/app";
|
||||
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||
import { SearchOneDataBaseModelUseCase } from "../usecases/search_database_model_usecase";
|
||||
|
@ -10,19 +8,15 @@ import { SearchOneDataBaseModelUseCase } from "../usecases/search_database_model
|
|||
export class SetLastActivePipelineToRealTimeServiceScenario {
|
||||
call = async (): Promise<void> => {
|
||||
return (
|
||||
await new SearchOneDataBaseModelUseCase<IProjectInstanceModel>(ProjectInstanceDbModel).call({
|
||||
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({
|
||||
isActive: true,
|
||||
})
|
||||
).fold(
|
||||
async (projectModel) => {
|
||||
if (projectModel.project === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const projectPath = App.staticFilesStoreDir() + projectModel.rootDir + "/";
|
||||
await new CreateFolderUseCase().call(projectPath);
|
||||
pipelineRealTimeService.setPipelineDependency(
|
||||
projectModel.project.pipelines,
|
||||
projectPath,
|
||||
projectModel._id,
|
||||
projectModel.rootDir
|
||||
|
|
|
@ -58,9 +58,8 @@ export class PipelineRealTimeService extends TypedEvent<ActivePipeline> {
|
|||
this.status.pipelineIsRunning = false;
|
||||
}
|
||||
}
|
||||
setPipelineDependency(pipelineModels: IPipeline[], path: string, projectId: string, rootDir: string) {
|
||||
this.pipelineModels = pipelineModels;
|
||||
this.status["projectId"] = projectId;
|
||||
setPipelineDependency(path: string, projectId: string, rootDir: string) {
|
||||
this.status["projectId"] = projectId;
|
||||
this.status["path"] = path;
|
||||
this.status["rootDir"] = rootDir;
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
import { IsArray, IsString } from "class-validator";
|
||||
|
||||
export class ProjectValidationModel {
|
||||
@IsArray()
|
||||
public pipelines: [string];
|
||||
|
||||
@IsString()
|
||||
public description: string;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { ProjectDBModel } from "./models/project_database_model";
|
||||
import { ProjectValidationModel } from "./models/project_validation_model";
|
||||
|
||||
export class ProjectsPresentation extends CrudController<ProjectValidationModel, typeof ProjectDBModel> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "project",
|
||||
validationModel: ProjectValidationModel,
|
||||
databaseModel: ProjectDBModel,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,50 +1,28 @@
|
|||
import { App } from "../../../core/controllers/app";
|
||||
import { CallbackStrategyWithEmpty } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { IPipeline } from "../../../core/models/process_model";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { PipelineValidationModel } from "../../_pipelines/models/pipeline_validation_model";
|
||||
import { IProjectInstanceModel, ProjectInstanceDbModel } from "../../projects/models/project_instance_database_model";
|
||||
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||
import { pipelineRealTimeService } from "../realtime_presentation";
|
||||
import { PipelineStatusUseCase } from "./pipeline_status_usecase";
|
||||
|
||||
const mongoPipelineModelMapper = (el: PipelineValidationModel): IPipeline => {
|
||||
const mapObj: IPipeline = {
|
||||
process: {
|
||||
type: el.process.type,
|
||||
command: el.process.command,
|
||||
isGenerating: Boolean(el.process.isGenerating),
|
||||
isLocaleCode: Boolean(el.process.isLocaleCode),
|
||||
issueType: el.process.issueType,
|
||||
},
|
||||
trigger: {
|
||||
type: el.trigger.type,
|
||||
value: el.trigger.value.map((el) => String(el)),
|
||||
},
|
||||
env: null,
|
||||
stackGenerateType: el.stackGenerateType,
|
||||
};
|
||||
return mapObj;
|
||||
};
|
||||
|
||||
|
||||
export class RunInstancePipelineUseCase extends CallbackStrategyWithEmpty {
|
||||
async call(): Promise<Result<any, string>> {
|
||||
return (await new PipelineStatusUseCase().call()).map(async (activePipelineModel) => {
|
||||
if (activePipelineModel.pipelineIsRunning) {
|
||||
return Result.error("pipeline is running");
|
||||
}
|
||||
const readByIdDataBaseModelUseCase = await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(
|
||||
ProjectInstanceDbModel
|
||||
const readByIdDataBaseModelUseCase = await new ReadByIdDataBaseModelUseCase<IProjectModel>(
|
||||
ProjectDBModel
|
||||
).call(activePipelineModel.projectId);
|
||||
|
||||
if (readByIdDataBaseModelUseCase.isFailure()) {
|
||||
return readByIdDataBaseModelUseCase.forward();
|
||||
}
|
||||
const projectModel = readByIdDataBaseModelUseCase.value;
|
||||
const resultMapper = projectModel.project.pipelines.map((el) => mongoPipelineModelMapper(el));
|
||||
|
||||
|
||||
pipelineRealTimeService.setPipelineDependency(
|
||||
resultMapper,
|
||||
App.staticFilesStoreDir() + projectModel.rootDir + "/",
|
||||
projectModel._id,
|
||||
projectModel.rootDir
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||
import { BehaviorTreeDBModel } from "../models/behavior_tree_database_model";
|
||||
|
||||
export class GetBehaviorTreeActiveProjectScenario extends CallbackStrategyWithEmpty {
|
||||
|
|
|
@ -2,8 +2,8 @@ import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core
|
|||
import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase";
|
||||
import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase";
|
||||
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
import { FolderStructure } from "../../projects/domain/upload_file_to_to_project_scenario";
|
||||
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||
import { BehaviorTreeValidationModel } from "../models/behavior_tree_validation_model";
|
||||
|
||||
export class SaveBtScenario extends CallbackStrategyWithValidationModel<BehaviorTreeValidationModel> {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
import { IProjectModel, projectSchema } from "../../_projects/models/project_database_model";
|
||||
import { IProjectModel, projectSchema } from "../../projects/models/project_model_database_model";
|
||||
|
||||
export interface IBehaviorTreeModel {
|
||||
name: string;
|
||||
|
|
|
@ -5,9 +5,9 @@ import { TypedEvent } from "../../../core/helpers/typed_event";
|
|||
import { EXEC_EVENT, ExecError, SpawnError } from "../../../core/models/exec_error_model";
|
||||
import { ExecutorResult } from "../../../core/models/executor_result";
|
||||
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
import { DatasetDBModel } from "../models/dataset_database_model";
|
||||
import { DatasetValidationModel, ProcessStatus } from "../models/dataset_validation_model";
|
||||
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||
|
||||
export class ProcessWatcherAndDatabaseUpdateService<A> extends TypedEvent<
|
||||
Result<ExecError | SpawnError, ExecutorResult>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||
import { DatasetDBModel } from "../models/dataset_database_model";
|
||||
|
||||
export class GetDatasetActiveProjectScenario extends CallbackStrategyWithEmpty {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
import { IDatasetModel } from "./dataset_validation_model";
|
||||
import { projectSchema } from "../../_projects/models/project_database_model";
|
||||
|
||||
import { projectSchema } from "../../projects/models/project_model_database_model";
|
||||
|
||||
export const DatasetSchema = new Schema({
|
||||
name: {
|
||||
type: String,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Type } from "class-transformer";
|
||||
import { IsArray, IsOptional, IsString, ValidateNested } from "class-validator";
|
||||
import { IProjectModel } from "../../_projects/models/project_database_model";
|
||||
import { IProjectModel } from "../../projects/models/project_model_database_model";
|
||||
|
||||
export class FormBuilderValidationModel {
|
||||
@IsString()
|
||||
|
|
|
@ -2,9 +2,8 @@ import { App } from "../../../core/controllers/app";
|
|||
import { Result } from "../../../core/helpers/result";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { IsString } from "class-validator";
|
||||
import { ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
import { CreateDataBaseModelUseCase } from "../../../core/usecases/create_database_model_usecase";
|
||||
import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase";
|
||||
import { ProjectDBModel } from "../models/project_model_database_model";
|
||||
|
||||
export class ProjectValidationModel {
|
||||
@IsString()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { CallbackStrategyWithEmpty } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
import { IProjectModel, ProjectDBModel } from "../models/project_model_database_model";
|
||||
|
||||
export class GetActiveProjectScenario extends CallbackStrategyWithEmpty {
|
||||
async call(): Promise<Result<any, { id: string }>> {
|
||||
|
|
|
@ -4,7 +4,7 @@ import { RobossemblerAssets } from "../../../core/models/robossembler_assets";
|
|||
import { StaticFiles } from "../../../core/models/static_files";
|
||||
import { ReadingJsonFileAndConvertingToInstanceClassScenario } from "../../../core/scenarios/read_file_and_json_to_plain_instance_class_scenario";
|
||||
import { GetServerAddressUseCase } from "../../../core/usecases/get_server_address_usecase";
|
||||
import { ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
import { ProjectDBModel } from "../models/project_model_database_model";
|
||||
|
||||
export class RobossemblerAssetsNetworkMapperScenario extends CallbackStrategyWithEmpty {
|
||||
async call(): ResponseBase {
|
||||
|
|
|
@ -6,37 +6,23 @@ import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecas
|
|||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { UpdateDataBaseModelUseCase } from "../../../core/usecases/update_database_model_usecase";
|
||||
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||
import { IProjectInstanceModel, ProjectInstanceDbModel } from "../models/project_instance_database_model";
|
||||
|
||||
import { IProjectModel, ProjectDBModel } from "../models/project_model_database_model";
|
||||
|
||||
export class SetActiveProjectScenario extends CallbackStrategyWithIdQuery {
|
||||
idValidationExpression = new MongoIdValidation();
|
||||
|
||||
async call(id: string): ResponseBase {
|
||||
try {
|
||||
const result = await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(ProjectInstanceDbModel).call(id);
|
||||
// id
|
||||
|
||||
if (result.isFailure()) {
|
||||
return result.forward();
|
||||
}
|
||||
const model = result.value;
|
||||
|
||||
return await (
|
||||
await new CreateFolderUseCase().call(App.staticFilesStoreDir() + model.rootDir)
|
||||
).map(async () => {
|
||||
model.isActive = true;
|
||||
return (await new UpdateDataBaseModelUseCase(ProjectInstanceDbModel).call(model)).map(async (el) => {
|
||||
// TODO(IDONTSUDO): move it to a separate UseCase
|
||||
await ProjectInstanceDbModel.updateMany(
|
||||
{ _id: { $ne: el._id }, isActive: { $eq: true } },
|
||||
{ isActive: false }
|
||||
);
|
||||
await new SetLastActivePipelineToRealTimeServiceScenario().call();
|
||||
return Result.ok(`project ${id} is active`);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
return Result.error("SetActiveProjectScenario error:" + String(error));
|
||||
}
|
||||
}
|
||||
call = async (id: string): ResponseBase => (await (await new ReadByIdDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(id)).map(async (model) => await (
|
||||
await new CreateFolderUseCase().call(model.rootDir)
|
||||
).map(async () => {
|
||||
model.isActive = true;
|
||||
return (await new UpdateDataBaseModelUseCase(ProjectDBModel).call(model)).map(async (el) => {
|
||||
await ProjectDBModel.updateMany(
|
||||
{ _id: { $ne: el._id }, isActive: { $eq: true } },
|
||||
{ isActive: false }
|
||||
);
|
||||
await new SetLastActivePipelineToRealTimeServiceScenario().call();
|
||||
return Result.ok(`project ${id} is active`);
|
||||
});
|
||||
})))
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,11 @@ import { CallbackStrategyWithFileUpload, ResponseBase } from "../../../core/cont
|
|||
import { IFile } from "../../../core/interfaces/file";
|
||||
import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase";
|
||||
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||
import { IProjectInstanceModel } from "../models/project_instance_database_model";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
import { ExecProcessUseCase } from "../../../core/usecases/exec_process_usecase";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { CreateManyFolderScenario } from "../../../core/scenarios/create_many_folder_scenario";
|
||||
import { IProjectModel, ProjectDBModel } from "../models/project_model_database_model";
|
||||
|
||||
export enum FolderStructure {
|
||||
assets = "assets",
|
||||
|
@ -21,7 +20,7 @@ export class UploadCadFileToProjectScenario extends CallbackStrategyWithFileUplo
|
|||
idValidationExpression = new MongoIdValidation();
|
||||
|
||||
async call(file: IFile, id: string): ResponseBase {
|
||||
return (await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(ProjectDBModel).call(id)).map(
|
||||
return (await new ReadByIdDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(id)).map(
|
||||
async (databaseModel) =>
|
||||
(await new CreateFileUseCase().call(`${databaseModel.rootDir}/${file.name}`, file.data)).map(async () =>
|
||||
(
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
import { IProjectModel, projectSchema } from "../../_projects/models/project_database_model";
|
||||
|
||||
export interface IProjectInstanceModel {
|
||||
_id: string;
|
||||
project: IProjectModel;
|
||||
description: string;
|
||||
rootDir: string;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
export const ProjectInstanceSchema = new Schema({
|
||||
description: {
|
||||
type: String,
|
||||
},
|
||||
rootDir: {
|
||||
type: String,
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
}).plugin(require("mongoose-autopopulate"));
|
||||
|
||||
export const schemaProjectInstance = "instance_project";
|
||||
|
||||
export const ProjectInstanceDbModel = model<IProjectInstanceModel>(schemaProjectInstance, ProjectInstanceSchema);
|
|
@ -1,9 +1,7 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
import { PipelineValidationModel } from "../../_pipelines/models/pipeline_validation_model";
|
||||
|
||||
export interface IProjectModel {
|
||||
_id?: string;
|
||||
pipelines: [PipelineValidationModel];
|
||||
rootDir: string;
|
||||
description: string;
|
||||
isActive: boolean;
|
|
@ -1,4 +1,4 @@
|
|||
import { IsMongoId, IsOptional, IsString } from "class-validator";
|
||||
import { IsOptional, IsString } from "class-validator";
|
||||
|
||||
export class ProjectInstanceValidationModel {
|
||||
@IsString()
|
|
@ -1,16 +1,15 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { ProjectDBModel } from "../_projects/models/project_database_model";
|
||||
import { CreateNewProjectInstanceScenario } from "./domain/create_new_project_scenario";
|
||||
import { CreateNewProjectInstanceScenario, ProjectValidationModel } from "./domain/create_new_project_scenario";
|
||||
import { GetActiveProjectScenario } from "./domain/get_active_project_scenario";
|
||||
import { RobossemblerAssetsNetworkMapperScenario } from "./domain/robossembler_assets_network_mapper_scenario";
|
||||
import { SetActiveProjectScenario } from "./domain/set_active_project_use_scenario";
|
||||
import { UploadCadFileToProjectScenario } from "./domain/upload_file_to_to_project_scenario";
|
||||
import { ProjectInstanceValidationModel as ProjectsValidationModel } from "./models/project_instance_validation_model";
|
||||
|
||||
export class ProjectsPresentation extends CrudController<ProjectsValidationModel, typeof ProjectDBModel> {
|
||||
import { ProjectDBModel } from "./models/project_model_database_model";
|
||||
|
||||
export class ProjectsPresentation extends CrudController<ProjectValidationModel, typeof ProjectDBModel> {
|
||||
constructor() {
|
||||
super({
|
||||
validationModel: ProjectsValidationModel,
|
||||
validationModel: ProjectValidationModel,
|
||||
url: "projects",
|
||||
databaseModel: ProjectDBModel,
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
import { IProjectModel, projectSchema } from "../../_projects/models/project_database_model";
|
||||
import { datasetSchema } from "../../datasets/models/dataset_database_model";
|
||||
import { IDatasetModel } from "../../datasets/models/dataset_validation_model";
|
||||
import { IProjectModel, projectSchema } from "../../projects/models/project_model_database_model";
|
||||
|
||||
export interface IWeightModel {
|
||||
name: string;
|
||||
|
|
|
@ -13,6 +13,6 @@ export class ProjectRepository extends HttpRepository {
|
|||
return this._jsonRequest<UUID>(HttpMethod.GET, "/projects/get/active/project/id");
|
||||
}
|
||||
async setActivePipeline(id: string) {
|
||||
return this._jsonRequest(HttpMethod.POST, `/project_instance/set/active/project?id=${id}`);
|
||||
return this._jsonRequest(HttpMethod.POST, `/projects/set/active/project?id=${id}`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
<div>
|
||||
{store.projectsModels?.map((el) => {
|
||||
return (
|
||||
<div style={{ margin: "10px", backgroundColor: "Highlight" }}>
|
||||
<div style={{ margin: 10, backgroundColor: "chartreuse" }}>
|
||||
{el.isActive ? (
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
@ -39,7 +39,7 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
>
|
||||
instance screen
|
||||
</Button>
|
||||
) : null}
|
||||
) : <Button style={{ backgroundColor: 'red' }} onClick={() => store.setActiveProject(el._id as string)}>active project</Button>}
|
||||
<div style={{ margin: "10px", display: "contents" }}> {el.description}</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -19,6 +19,7 @@ export class ProjectView {
|
|||
}
|
||||
}
|
||||
export class AllProjectStore extends SimpleErrorState {
|
||||
|
||||
projectsModels?: IProjectModel[];
|
||||
activeProjectId?: UUID;
|
||||
repository: ProjectRepository;
|
||||
|
@ -33,12 +34,15 @@ export class AllProjectStore extends SimpleErrorState {
|
|||
async getActiveProjectId(): Promise<void> {
|
||||
await this.mapOk<UUID>("activeProjectId", this.repository.getActivePipeline());
|
||||
}
|
||||
setActiveProject = async (id: string) => {
|
||||
await this.messageHttp(this.repository.setActivePipeline(id), { successMessage: "проект активирован", errorMessage: 'ошибка активации' })
|
||||
await this.mapOk<UUID>("activeProjectId", this.repository.getActivePipeline());
|
||||
await this.mapOk<IProjectModel[]>("projectsModels", this.repository.getAllProject());
|
||||
}
|
||||
async init() {
|
||||
await Promise.all([this.getProjects(), this.getActiveProjectId()]);
|
||||
this.projectsModels?.map((el) => (el._id === this.activeProjectId ? ((el.isActive = true), el) : el));
|
||||
}
|
||||
|
||||
async setPipelineActive(id: string) {
|
||||
await this.httpHelper(this.repository.setActivePipeline(id));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue