From ae9842d5e1dbe0c44a526abf960fe9606773a0c2 Mon Sep 17 00:00:00 2001 From: IDONTSUDO Date: Thu, 28 Dec 2023 17:18:12 +0300 Subject: [PATCH] process --- server/package.json | 2 +- server/src/core/controllers/app.ts | 3 +- .../src/core/controllers/http_controller.ts | 23 ++- server/src/core/extensions/extensions.ts | 1 + server/src/core/extensions/string.ts | 8 ++ server/src/core/helpers/worker_computed.ts | 4 +- .../src/core/middlewares/validation_auth.ts | 8 +- server/src/core/models/exec_error_model.ts | 22 ++- server/src/core/models/executor_result.ts | 11 +- server/src/core/models/robossembler_assets.ts | 131 ++++++++++++++++++ server/src/core/models/static_files.ts | 3 + ...d_json_to_plain_instance_class_scenario.ts | 29 ++++ ...e_pipeline_to_realtime_service_scenario.ts | 11 +- .../core/services/executor_program_service.ts | 86 ++++++------ .../services/pipeline_real_time_service.ts | 11 +- server/src/core/services/stack_service.ts | 13 +- ..._and_create_static_files_folder_usecase.ts | 2 +- ...er_usecase.ts => create_folder_usecase.ts} | 2 +- .../find_and_update_database_model_usecase.ts | 11 ++ .../usecases/get_server_address_usecase.ts | 7 + .../core/usecases/read_file_and_parse_json.ts | 21 +++ .../src/core/validations/core_validation.ts | 4 + .../core/validations/mongo_id_validation.ts | 6 + .../domain/create_new_project_scenario.ts | 2 +- ...ssembler_assets_network_mapper_scenario.ts | 31 +++++ .../domain/set_active_project_use_scenario.ts | 30 ++++ .../project_instance_presentation.ts | 16 +++ .../domain/pipeline_status_usecase.ts | 1 + .../domain/run_instance_pipeline_usecase.ts | 46 ++++-- server/test/services/stack_service_test.ts | 2 +- server/test/test.ts | 22 +-- ui/src/core/extensions/extensions.ts | 5 +- ...{active_pipiline.ts => active_pipeline.ts} | 0 ui/src/core/model/ui_base_error.ts | 6 + ui/src/core/repository/http_repository.ts | 37 +++-- ui/src/core/routers/routers.tsx | 7 +- ui/src/core/store/base_store.ts | 35 ++++- .../all_projects/data/project_repository.ts | 25 +--- .../presentation/all_projects_screen.tsx | 40 +++++- .../presentation/all_projects_store.ts | 58 ++++++-- .../presentation/create_pipeline_screen.tsx | 4 +- .../presentation/create_pipeline_store.ts | 44 ++---- .../presentation/logic/process_store.ts | 4 +- .../create_project/create_project_screen.tsx | 24 ++-- .../create_project/create_project_store.ts | 30 +--- .../create_project_instance.tsx | 5 +- .../create_project_instance_repository.ts | 15 +- .../create_project_instance_store.ts | 21 +-- .../components/code_trigger_form.tsx | 60 ++++---- .../components/file_trigger_form.tsx | 89 ++++++------ .../presentation/create_trigger_screen.tsx | 61 ++++---- .../presentation/trigger_store.ts | 27 ++-- ui/src/features/p.tsx | 68 +++++++++ .../pipeline_instance_screen.tsx | 9 +- .../pipeline_instance_store.ts | 4 +- .../features/scene_manager/scene_manager.tsx | 11 +- .../scene_manager/scene_manager_store.ts | 30 +++- .../data/select_project_repository.ts | 8 +- .../presentation/select_project.tsx | 16 +-- .../presentation/select_project_store.ts | 38 +++-- ui/src/index.tsx | 12 +- 61 files changed, 929 insertions(+), 433 deletions(-) create mode 100644 server/src/core/models/robossembler_assets.ts create mode 100644 server/src/core/models/static_files.ts create mode 100644 server/src/core/scenarios/read_file_and_json_to_plain_instance_class_scenario.ts rename server/src/core/usecases/{crete_folder_usecase.ts => create_folder_usecase.ts} (88%) create mode 100644 server/src/core/usecases/find_and_update_database_model_usecase.ts create mode 100644 server/src/core/usecases/get_server_address_usecase.ts create mode 100644 server/src/core/usecases/read_file_and_parse_json.ts create mode 100644 server/src/core/validations/core_validation.ts create mode 100644 server/src/core/validations/mongo_id_validation.ts create mode 100644 server/src/features/project_instance/domain/robossembler_assets_network_mapper_scenario.ts create mode 100644 server/src/features/project_instance/domain/set_active_project_use_scenario.ts rename ui/src/core/model/{active_pipiline.ts => active_pipeline.ts} (100%) create mode 100644 ui/src/core/model/ui_base_error.ts create mode 100644 ui/src/features/p.tsx diff --git a/server/package.json b/server/package.json index a0cd0d3..d062c30 100644 --- a/server/package.json +++ b/server/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "pretest": "tsc", + "test:dev": "NODE_ENV=test_dev tsc-watch --onSuccess 'ts-node ./build/test/test.js'", "test:unit": "NODE_ENV=unit tsc-watch --onSuccess 'ts-node ./build/test/test.js'", "test:e2e": "NODE_ENV=e2e tsc-watch --onSuccess 'ts-node ./build/test/test.js'", "dev": "NODE_ENV=dev tsc-watch --onSuccess 'ts-node ./build/src/main.js'" diff --git a/server/src/core/controllers/app.ts b/server/src/core/controllers/app.ts index a3889ea..00b8bc9 100644 --- a/server/src/core/controllers/app.ts +++ b/server/src/core/controllers/app.ts @@ -85,7 +85,7 @@ export class App extends TypedEvent { this.app.use(cors()); this.app.use(express.json()); this.app.use(express.urlencoded({ extended: true })); - this.app.use(express.static("public")); + this.app.use(express.static(App.staticFilesStoreDir())); this.app.use( fileUpload({ @@ -118,6 +118,7 @@ export class App extends TypedEvent { static staticFilesStoreDir = () => { const dir = dirname(__filename); const rootDir = dir.slice(0, dir.length - 20); + return rootDir + "public/"; }; } diff --git a/server/src/core/controllers/http_controller.ts b/server/src/core/controllers/http_controller.ts index ae3b30d..346e8ea 100644 --- a/server/src/core/controllers/http_controller.ts +++ b/server/src/core/controllers/http_controller.ts @@ -2,11 +2,11 @@ import { validationModelMiddleware } from "../middlewares/validation_model"; import { Result } from "../helpers/result"; import { Router, Request, Response } from "express"; import { IRouteModel, Routes } from "../interfaces/router"; +import { CoreValidation } from "../validations/core_validation"; export type HttpMethodType = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "PATCH" | "HEAD"; export type ResponseBase = Promise>; - export abstract class CallbackStrategyWithEmpty { abstract call(): ResponseBase; } @@ -15,7 +15,7 @@ export abstract class CallbackStrategyWithValidationModel { abstract call(a: V): ResponseBase; } export abstract class CallbackStrategyWithIdQuery { - abstract idValidationExpression: RegExp | null; + abstract idValidationExpression: CoreValidation; abstract call(id: string): ResponseBase; } export abstract class CallBackStrategyWithQueryPage { @@ -84,7 +84,24 @@ export class CoreHttpController implements ICoreHttpController { throw Error("needs to be implimed"); } if (el.fn instanceof CallbackStrategyWithIdQuery) { - throw Error("needs to be implimed"); + if (req.query.id === undefined) { + res.status(400).json("request query id is null, need query id ?id={id:String}"); + return; + } + if (el.fn.idValidationExpression !== undefined) { + if (!el.fn.idValidationExpression.regExp.test(req.query.id)) { + res + .status(400) + .json( + `request query id must fall under the pattern: ${el.fn.idValidationExpression.regExp} message: ${el.fn.idValidationExpression.message} ` + ); + return; + } else { + await this.responseHelper(res, el.fn.call(req.query.id)); + } + } else { + await this.responseHelper(res, el.fn.call(req["files"]["file"])); + } } if (el.fn instanceof CallBackStrategyWithQueryPage) { throw Error("needs to be implimed"); diff --git a/server/src/core/extensions/extensions.ts b/server/src/core/extensions/extensions.ts index 7fb1c66..b945e51 100644 --- a/server/src/core/extensions/extensions.ts +++ b/server/src/core/extensions/extensions.ts @@ -20,6 +20,7 @@ declare global { lastElement(): string; hasPattern(pattern: string): boolean; hasNoPattern(pattern: string): boolean; + pathNormalize(): string; } } export const extensions = () => { diff --git a/server/src/core/extensions/string.ts b/server/src/core/extensions/string.ts index bdd093d..055c615 100644 --- a/server/src/core/extensions/string.ts +++ b/server/src/core/extensions/string.ts @@ -5,6 +5,11 @@ export const StringExtensions = () => { return this.length === 0; }; } + if ("".pathNormalize === undefined) { + String.prototype.pathNormalize = function () { + return this.replace("//", "/"); + }; + } if ("".isNotEmpty === undefined) { // eslint-disable-next-line no-extend-native String.prototype.isNotEmpty = function () { @@ -27,3 +32,6 @@ export const StringExtensions = () => { }; } }; +// python3 /Users/idontsudo/framework/path.py --path /Users/idontsudo/webservice/server/build/public/0a3422cc-f2e3-4abc-87d8-ae13b8b6d26d/ --env /Users/idontsudo/framework/cad_generation/env.json +// python3 /Users/idontsudo/framework/path.py --path /Users/idontsudo/webservice/server/build/public/0a3422cc-f2e3-4abc-87d8-ae13b8b6d26d/ --env /Users/idontsudo/framework/cad_generation/env.json +// /Users/idontsudo/Desktop/FreeCAD.app/Contents/MacOS/FreeCAD /Users/idontsudo/framework/cad_generation/main.py diff --git a/server/src/core/helpers/worker_computed.ts b/server/src/core/helpers/worker_computed.ts index a5ab80a..bc88fad 100644 --- a/server/src/core/helpers/worker_computed.ts +++ b/server/src/core/helpers/worker_computed.ts @@ -17,7 +17,9 @@ export interface WorkerDataExec { process.on("message", async (message) => { const workerData = message as WorkerDataExec; if (workerData.type == WorkerType.SPAWN) { - const subprocess = cp.spawn(workerData.command, workerData.cliArgs, { + // Maybe error + // const subprocess = cp.spawn(workerData.command, workerData.cliArgs, { + const subprocess = cp.spawn(workerData.command, { cwd: workerData.execPath, }); diff --git a/server/src/core/middlewares/validation_auth.ts b/server/src/core/middlewares/validation_auth.ts index 40f88d5..bea5b04 100644 --- a/server/src/core/middlewares/validation_auth.ts +++ b/server/src/core/middlewares/validation_auth.ts @@ -1,12 +1,6 @@ import { RequestHandler } from "express"; -export const validationMiddleware = ( - type: any, - value = "body", - skipMissingProperties = false, - whitelist = true, - forbidNonWhitelisted = true -): RequestHandler => { +export const validationMiddleware = (): RequestHandler => { // TODO:(IDONTSUDO) need TOKEN // return nextTick return (req, res, next) => {}; diff --git a/server/src/core/models/exec_error_model.ts b/server/src/core/models/exec_error_model.ts index bbb9f38..12cb3ac 100644 --- a/server/src/core/models/exec_error_model.ts +++ b/server/src/core/models/exec_error_model.ts @@ -4,10 +4,15 @@ extensions(); export class ExecError extends Error { static isExecError(e: any): ExecError | void { - if ("type" in e && "script" in e && "unixTime" in e && "error" in e) { - return new ExecError(e.type, e.event, e.data); + try { + if (e) { + if ("type" in e && "script" in e && "unixTime" in e && "error" in e) { + return new ExecError(e.type, e.event, e.data); + } + } + } catch (error) { + console.log(error); } - return; } script: string; unixTime: number; @@ -34,10 +39,15 @@ export class SpawnError extends Error { this.unixTime = Date.now(); } static isError(errorType: any): SpawnError | void { - if ("command" in errorType && "error" in errorType && "execPath" in errorType) { - return new SpawnError(errorType.command, errorType.execPath, errorType.error); + try { + if (errorType) { + if ("command" in errorType && "error" in errorType && "execPath" in errorType) { + return new SpawnError(errorType.command, errorType.execPath, errorType.error); + } + } + } catch (error) { + console.log(error); } - return; } } diff --git a/server/src/core/models/executor_result.ts b/server/src/core/models/executor_result.ts index 8df94ab..fd4c32a 100644 --- a/server/src/core/models/executor_result.ts +++ b/server/src/core/models/executor_result.ts @@ -10,9 +10,14 @@ export class ExecutorResult { this.data = data; } static isExecutorResult(value: any): void | ExecutorResult { - if ("type" in value && "event" in value && "data" in value) { - return new ExecutorResult(value.type, value.event, value.data); + try { + if (value) { + if ("type" in value && "event" in value && "data" in value) { + return new ExecutorResult(value.type, value.event, value.data); + } + } + } catch (error) { + console.log(error); } - return; } } diff --git a/server/src/core/models/robossembler_assets.ts b/server/src/core/models/robossembler_assets.ts new file mode 100644 index 0000000..8fcf172 --- /dev/null +++ b/server/src/core/models/robossembler_assets.ts @@ -0,0 +1,131 @@ +import { IsEnum, IsNumber, IsOptional, IsString, ValidateNested } from "class-validator"; +import { Type } from "class-transformer"; + +export enum AssetsType { + Asset = "asset", + Light = "light", +} + +export class Gravity { + @IsNumber() + x: number; + @IsNumber() + y: number; + @IsNumber() + z: number; +} +export class Pose { + @IsNumber() + x: number; + @IsNumber() + y: number; + @IsNumber() + z: number; + @IsNumber() + roll: number; + @IsNumber() + pitch: number; + @IsNumber() + yaw: number; +} + +export class Instance { + @IsString() + model_name: string; + @IsString() + model_id: string; + @IsString() + id: string; + @ValidateNested() + @Type(() => Pose) + pose: Pose; + @IsNumber() + scale: number; + @IsEnum(AssetsType) + type: AssetsType; + @IsOptional() + @IsString() + parent?: string; + @IsOptional() + @IsString() + light_type?: string; + @IsOptional() + @IsString() + intencity?: number; + @IsOptional() + @IsString() + diffuse?: number[]; + @IsOptional() + @IsNumber() + spot_angle?: number; +} + +export class Asset { + @IsString() + name: string; + @IsString() + ixx: string; + @IsString() + ixy: string; + @IsString() + ixz: string; + @IsString() + iyy: string; + @IsString() + izz: string; + @IsString() + mass: string; + @IsString() + posX: string; + @IsString() + posY: string; + @IsString() + posZ: string; + @IsString() + eulerX: string; + @IsString() + eulerY: string; + @IsString() + eulerZ: string; + @IsString() + iyz: string; + @IsString() + meshPath: string; + @IsString() + friction: string; + @IsString() + centerMassX: string; + @IsString() + centerMassY: string; + @IsString() + centerMassZ: string; +} + +export class Physics { + @IsString() + engine_name: string; + @Type(() => Gravity) + gravity: Gravity; +} + +export class RobossemblerAssets { + @ValidateNested() + @Type(() => Asset) + assets: Asset[]; + + @ValidateNested() + @Type(() => Instance) + instances: Instance[]; + + @IsOptional() + @ValidateNested() + @Type(() => Physics) + physics: Physics; + convertLocalPathsToServerPaths(server_address: string): RobossemblerAssets { + this.assets = this.assets.map((el) => { + el.meshPath = server_address + el.meshPath; + return el; + }); + return this; + } +} diff --git a/server/src/core/models/static_files.ts b/server/src/core/models/static_files.ts new file mode 100644 index 0000000..dfe36c4 --- /dev/null +++ b/server/src/core/models/static_files.ts @@ -0,0 +1,3 @@ +export enum StaticFiles { + robossembler_assets = "robossembler_assets.json", +} diff --git a/server/src/core/scenarios/read_file_and_json_to_plain_instance_class_scenario.ts b/server/src/core/scenarios/read_file_and_json_to_plain_instance_class_scenario.ts new file mode 100644 index 0000000..8281896 --- /dev/null +++ b/server/src/core/scenarios/read_file_and_json_to_plain_instance_class_scenario.ts @@ -0,0 +1,29 @@ +import { ClassConstructor, plainToInstance } from "class-transformer"; +import { ReadFileAndParseJsonUseCase } from "../usecases/read_file_and_parse_json"; +import { Result } from "../helpers/result"; +import { validate, ValidationError } from "class-validator"; +const skipMissingProperties = false, + whitelist = true, + forbidNonWhitelisted = true; + +export class ReadingJsonFileAndConvertingToInstanceClass { + model: ClassConstructor; + constructor(cls: ClassConstructor) { + this.model = cls; + } + call = async (path: string): Promise> => { + const result = await new ReadFileAndParseJsonUseCase().call(path); + if (result.isFailure()) { + return result.forward(); + } + const json = result.value; + const model = plainToInstance(this.model, json); + const errors = await validate(model as object, { skipMissingProperties, whitelist, forbidNonWhitelisted }); + if (errors.length > 0) { + const message = errors.map((error: ValidationError) => Object.values(error.constraints)).join(", "); + return Result.error(message); + } else { + return Result.ok(model as T); + } + }; +} diff --git a/server/src/core/scenarios/set_active_pipeline_to_realtime_service_scenario.ts b/server/src/core/scenarios/set_active_pipeline_to_realtime_service_scenario.ts index 8fac80e..a52eb2a 100644 --- a/server/src/core/scenarios/set_active_pipeline_to_realtime_service_scenario.ts +++ b/server/src/core/scenarios/set_active_pipeline_to_realtime_service_scenario.ts @@ -4,7 +4,7 @@ import { } from "../../features/project_instance/models/project_instance_database_model"; import { pipelineRealTimeService } from "../../features/realtime/realtime_presentation"; import { App } from "../controllers/app"; -import { CreateFolderUseCase } from "../usecases/crete_folder_usecase"; +import { CreateFolderUseCase } from "../usecases/create_folder_usecase"; import { SearchDataBaseModelUseCase } from "../usecases/search_database_model_usecase"; export class SetLastActivePipelineToRealTimeServiceScenario { @@ -12,12 +12,11 @@ export class SetLastActivePipelineToRealTimeServiceScenario { const result = await new SearchDataBaseModelUseCase(ProjectInstanceDbModel).call({ isActive: true, }); - - if (result.isSuccess()) { - const projectModel = result.value; - const projectPath = App.staticFilesStoreDir() + result.value.rootDir + "/"; + await result.map(async (el) => { + const projectModel = el; + const projectPath = App.staticFilesStoreDir() + projectModel.rootDir + "/"; await new CreateFolderUseCase().call(projectPath); pipelineRealTimeService.setPipelineDependency(projectModel.project.pipelines, projectPath, projectModel._id); - } + }); }; } diff --git a/server/src/core/services/executor_program_service.ts b/server/src/core/services/executor_program_service.ts index ef69884..f6ed534 100644 --- a/server/src/core/services/executor_program_service.ts +++ b/server/src/core/services/executor_program_service.ts @@ -21,57 +21,61 @@ export class ExecutorProgramService constructor(execPath: string, maxTime: number | null = null) { super(); - this.execPath = execPath; + this.execPath = execPath.pathNormalize(); this.maxTime = maxTime; } private async workerExecuted(command: string, workerType: WorkerType, args: Array | undefined = undefined) { - cluster.setupPrimary({ - exec: __dirname + "/../helpers/worker_computed.js", - }); + try { + cluster.setupPrimary({ + exec: __dirname + "/../helpers/worker_computed.js", + }); - const worker = cluster.fork(); + const worker = cluster.fork(); - await delay(300); + await delay(300); - this.worker = worker; + this.worker = worker; - const workerDataExec: WorkerDataExec = { - command: command, - execPath: this.execPath, - type: workerType, - cliArgs: args, - }; - worker.send(workerDataExec); - worker.on("message", (e) => { - const spawnError = SpawnError.isError(e); + const workerDataExec: WorkerDataExec = { + command: command, + execPath: this.execPath, + type: workerType, + cliArgs: args, + }; + worker.send(workerDataExec); + worker.on("message", (e) => { + const spawnError = SpawnError.isError(e); - if (spawnError instanceof SpawnError) { - this.emit(Result.error(spawnError)); - return; + if (spawnError instanceof SpawnError) { + this.emit(Result.error(spawnError)); + return; + } + const execError = ExecError.isExecError(e); + + if (execError instanceof ExecError) { + this.emit(Result.error(execError)); + return; + } + + const executorResult = ExecutorResult.isExecutorResult(e); + if (executorResult instanceof ExecutorResult) { + this.emit(Result.ok(executorResult)); + return; + } + }); + if (this.maxTime != null) { + setTimeout(() => { + this.worker.kill(); + this.emit( + Result.error( + WorkerType.EXEC ? new ExecError(command, "timeout err") : new SpawnError(command, "timeout err") + ) + ); + }, this.maxTime!); } - - const executorResult = ExecutorResult.isExecutorResult(e); - - if (executorResult instanceof ExecutorResult) { - this.emit(Result.ok(executorResult)); - return; - } - - const execError = ExecError.isExecError(e); - - if (execError instanceof ExecError) { - this.emit(Result.error(execError)); - return; - } - }); - if (this.maxTime != null) { - setTimeout(() => { - this.worker.kill(); - this.emit( - Result.error(WorkerType.EXEC ? new ExecError(command, "timeout err") : new SpawnError(command, "timeout err")) - ); - }, this.maxTime!); + } catch (error) { + console.log(error); } } diff --git a/server/src/core/services/pipeline_real_time_service.ts b/server/src/core/services/pipeline_real_time_service.ts index 479b7b2..cea7af3 100644 --- a/server/src/core/services/pipeline_real_time_service.ts +++ b/server/src/core/services/pipeline_real_time_service.ts @@ -3,7 +3,7 @@ import { ExecError } from "../models/exec_error_model"; import { ExecutorResult } from "../models/executor_result"; import { ActivePipeline } from "../models/active_pipeline_model"; import { IPipeline } from "../models/process_model"; -import { Iteration } from "./stack_service"; +import { Iteration, StackService } from "./stack_service"; export class PipelineRealTimeService extends TypedEvent { status: ActivePipeline; @@ -65,9 +65,10 @@ export class PipelineRealTimeService extends TypedEvent { this.status["path"] = path; } runPipeline(): void { - // const stack = new StackService(this.pipelineModels, this.path); - // this.status["pipelineIsRunning"] = true; - // stack.on(this.pipelineSubscriber); - // stack.call(); + const stack = new StackService(this.pipelineModels, this.status.path); + + this.status["pipelineIsRunning"] = true; + stack.on(this.pipelineSubscriber); + stack.call(); } } diff --git a/server/src/core/services/stack_service.ts b/server/src/core/services/stack_service.ts index fd09310..336b758 100644 --- a/server/src/core/services/stack_service.ts +++ b/server/src/core/services/stack_service.ts @@ -11,7 +11,7 @@ import { Trigger } from "../../features/triggers/models/trigger_database_model"; export interface Iteration { hashes: IHashesCache | null; - process: IPipeline; + pipeline: IPipeline; result?: ExecError | SpawnError | ExecutorResult; } @@ -36,12 +36,12 @@ export class StackService extends TypedEvent implements IStackServi el = this.commandHandler(el); this.callStack.push({ hashes: null, - process: el, + pipeline: el, }); } } private commandHandler(processMetaData: IPipeline) { - processMetaData.process.command = processMetaData.process.command.replace("$PATH", this.path); + processMetaData.process.command = processMetaData.process.command.replace("$PATH", this.path).pathNormalize(); return processMetaData; } public async call() { @@ -52,10 +52,7 @@ export class StackService extends TypedEvent implements IStackServi } async execStack(stackNumber: number, stackLayer: Iteration): Promise { const executorService = new ExecutorProgramService(this.path); - executorService.call(stackLayer.process.process.type, stackLayer.process.process.command); - executorService.on((e) => { - console.log(e); - }); + executorService.call(stackLayer.pipeline.process.type, stackLayer.pipeline.process.command); const filesChangeNotifierService = new FilesChangeNotifierService(this.path); filesChangeNotifierService.call(); @@ -73,7 +70,7 @@ export class StackService extends TypedEvent implements IStackServi result.map(async (el) => { this.callStack.at(stackNumber).result = el; this.callStack.at(stackNumber).hashes = filesChangeNotifierService.hashes; - (await this.triggerExec(stackLayer.process.trigger, stackNumber)).map(() => { + (await this.triggerExec(stackLayer.pipeline.trigger, stackNumber)).map(() => { filesChangeNotifierService.cancel(); }); }); diff --git a/server/src/core/usecases/check_and_create_static_files_folder_usecase.ts b/server/src/core/usecases/check_and_create_static_files_folder_usecase.ts index cb5f2a9..17decc3 100644 --- a/server/src/core/usecases/check_and_create_static_files_folder_usecase.ts +++ b/server/src/core/usecases/check_and_create_static_files_folder_usecase.ts @@ -1,6 +1,6 @@ import { App } from "../controllers/app"; import { FileSystemRepository } from "../repository/file_system_repository"; -import { CreateFolderUseCase } from "./crete_folder_usecase"; +import { CreateFolderUseCase } from "./create_folder_usecase"; export class CheckAndCreateStaticFilesFolderUseCase { fileSystemRepository: FileSystemRepository; diff --git a/server/src/core/usecases/crete_folder_usecase.ts b/server/src/core/usecases/create_folder_usecase.ts similarity index 88% rename from server/src/core/usecases/crete_folder_usecase.ts rename to server/src/core/usecases/create_folder_usecase.ts index d74dba8..5a007fe 100644 --- a/server/src/core/usecases/crete_folder_usecase.ts +++ b/server/src/core/usecases/create_folder_usecase.ts @@ -9,7 +9,7 @@ export class CreateFolderUseCase { call = async (path: string): Promise> => { try { if (await this.fileSystemRepository.dirIsExists(path)) { - return Result.error(new Error("createFolderUseCase create dir ")); + return Result.ok("ok"); } await this.fileSystemRepository.createDir(path); diff --git a/server/src/core/usecases/find_and_update_database_model_usecase.ts b/server/src/core/usecases/find_and_update_database_model_usecase.ts new file mode 100644 index 0000000..7f1e7d1 --- /dev/null +++ b/server/src/core/usecases/find_and_update_database_model_usecase.ts @@ -0,0 +1,11 @@ +export class FindPredicateModelAndUpdateDatabaseModelUseCase { + databaseModel: D; + + constructor(model) { + this.databaseModel = model; + } + async call(conditions: Partial, update: Partial) { + const dbModel = this.databaseModel as any; + dbModel.findOneAndUpdate(conditions, update); + } +} diff --git a/server/src/core/usecases/get_server_address_usecase.ts b/server/src/core/usecases/get_server_address_usecase.ts new file mode 100644 index 0000000..6a00cc6 --- /dev/null +++ b/server/src/core/usecases/get_server_address_usecase.ts @@ -0,0 +1,7 @@ +import { Result } from "../helpers/result"; + +export class GetServerAddressUseCase { + call = (): Result => { + return Result.ok("http://localhost:4001"); + }; +} diff --git a/server/src/core/usecases/read_file_and_parse_json.ts b/server/src/core/usecases/read_file_and_parse_json.ts new file mode 100644 index 0000000..9e67ec0 --- /dev/null +++ b/server/src/core/usecases/read_file_and_parse_json.ts @@ -0,0 +1,21 @@ +import { Result } from "../helpers/result"; +import { FileSystemRepository } from "../repository/file_system_repository"; + +export class ReadFileAndParseJsonUseCase { + fileSystemRepository: FileSystemRepository; + + constructor() { + this.fileSystemRepository = new FileSystemRepository(); + } + async call(path: string): Promise> { + try { + if (RegExp(path).test("^(.+)/([^/]+)$")) { + return Result.error(`ReadFileAndParseJsonUseCase got the bad way: ${path}`); + } + const file = await this.fileSystemRepository.readFileAsync(path); + return Result.ok(JSON.parse(file.toString())); + } catch (error) { + return Result.error(`ReadFileAndParseJsonUseCase is not json type file parse path:${path}`); + } + } +} diff --git a/server/src/core/validations/core_validation.ts b/server/src/core/validations/core_validation.ts new file mode 100644 index 0000000..e9571a0 --- /dev/null +++ b/server/src/core/validations/core_validation.ts @@ -0,0 +1,4 @@ +export abstract class CoreValidation { + abstract regExp: RegExp; + abstract message: string; +} diff --git a/server/src/core/validations/mongo_id_validation.ts b/server/src/core/validations/mongo_id_validation.ts new file mode 100644 index 0000000..9cc8275 --- /dev/null +++ b/server/src/core/validations/mongo_id_validation.ts @@ -0,0 +1,6 @@ +import { CoreValidation } from "./core_validation"; + +export class MongoIdValidation extends CoreValidation { + regExp = RegExp("^[0-9a-fA-F]{24}$"); + message = "is do not mongo db object uuid"; +} diff --git a/server/src/features/project_instance/domain/create_new_project_scenario.ts b/server/src/features/project_instance/domain/create_new_project_scenario.ts index b5a162a..bc9bfab 100644 --- a/server/src/features/project_instance/domain/create_new_project_scenario.ts +++ b/server/src/features/project_instance/domain/create_new_project_scenario.ts @@ -1,7 +1,7 @@ import { App } from "../../../core/controllers/app"; import { Result } from "../../../core/helpers/result"; import { CreateDataBaseModelUseCase } from "../../../core/usecases/create_database_model_usecase"; -import { CreateFolderUseCase } from "../../../core/usecases/crete_folder_usecase"; +import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase"; import { ProjectInstanceDbModel } from "../models/project_instance_database_model"; import { ProjectInstanceValidationModel } from "../models/project_instance_validation_model"; import { v4 as uuidv4 } from "uuid"; diff --git a/server/src/features/project_instance/domain/robossembler_assets_network_mapper_scenario.ts b/server/src/features/project_instance/domain/robossembler_assets_network_mapper_scenario.ts new file mode 100644 index 0000000..d96a60f --- /dev/null +++ b/server/src/features/project_instance/domain/robossembler_assets_network_mapper_scenario.ts @@ -0,0 +1,31 @@ +import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller"; +import { Result } from "../../../core/helpers/result"; +import { RobossemblerAssets } from "../../../core/models/robossembler_assets"; +import { StaticFiles } from "../../../core/models/static_files"; +import { ReadingJsonFileAndConvertingToInstanceClass } from "../../../core/scenarios/read_file_and_json_to_plain_instance_class_scenario"; +import { GetServerAddressUseCase } from "../../../core/usecases/get_server_address_usecase"; +import { PipelineStatusUseCase } from "../../realtime/domain/pipeline_status_usecase"; + +export class RobossemblerAssetsNetworkMapperScenario extends CallbackStrategyWithEmpty { + async call(): ResponseBase { + try { + const result = await new PipelineStatusUseCase().call(); + + return await result.map(async (activeInstanceModel) => { + return ( + await new ReadingJsonFileAndConvertingToInstanceClass(RobossemblerAssets).call( + `${activeInstanceModel.path}${StaticFiles.robossembler_assets}` + ) + ).map((robossemblerAssets) => { + return new GetServerAddressUseCase().call().map((address) => { + return Result.ok( + robossemblerAssets.convertLocalPathsToServerPaths(`${address}/${activeInstanceModel.projectUUID}`) + ); + }); + }); + }); + } catch (error) { + return Result.error(error); + } + } +} diff --git a/server/src/features/project_instance/domain/set_active_project_use_scenario.ts b/server/src/features/project_instance/domain/set_active_project_use_scenario.ts new file mode 100644 index 0000000..698d4ed --- /dev/null +++ b/server/src/features/project_instance/domain/set_active_project_use_scenario.ts @@ -0,0 +1,30 @@ +import { App } from "../../../core/controllers/app"; +import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller"; +import { Result } from "../../../core/helpers/result"; +import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase"; +import { FindPredicateModelAndUpdateDatabaseModelUseCase } from "../../../core/usecases/find_and_update_database_model_usecase"; +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"; + +export class SetActiveProjectScenario extends CallbackStrategyWithIdQuery { + idValidationExpression = new MongoIdValidation(); + + async call(id: string): ResponseBase { + const result = await new ReadByIdDataBaseModelUseCase(ProjectInstanceDbModel).call(id); + + if (result.isFailure()) { + return result.forward(); + } + + const model = result.value; + return (await new CreateFolderUseCase().call(App.staticFilesStoreDir() + model.rootDir)).map(async () => { + model.isActive = true; + new FindPredicateModelAndUpdateDatabaseModelUseCase(ProjectInstanceDbModel).call({}, {}); + return (await new UpdateDataBaseModelUseCase(ProjectInstanceDbModel).call(model)).map(() => { + return Result.ok(`project ${id} is active`); + }); + }); + } +} diff --git a/server/src/features/project_instance/project_instance_presentation.ts b/server/src/features/project_instance/project_instance_presentation.ts index e0de67c..cd64ef1 100644 --- a/server/src/features/project_instance/project_instance_presentation.ts +++ b/server/src/features/project_instance/project_instance_presentation.ts @@ -1,5 +1,8 @@ import { CrudController } from "../../core/controllers/crud_controller"; + import { CreateNewProjectInstanceScenario } from "./domain/create_new_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 { ProjectInstanceDbModel } from "./models/project_instance_database_model"; import { ProjectInstanceValidationModel } from "./models/project_instance_validation_model"; @@ -14,12 +17,25 @@ export class ProjectInstancePresentation extends CrudController< url: "project_instance", databaseModel: ProjectInstanceDbModel, }); + super.post(new CreateNewProjectInstanceScenario().call); + this.subRoutes.push({ + method: "POST", + subUrl: "set/active/project", + fn: new SetActiveProjectScenario(), + }); + this.subRoutes.push({ method: "POST", subUrl: "upload", fn: new UploadCadFileToProjectScenario(), }); + + this.subRoutes.push({ + method: "GET", + subUrl: "assets", + fn: new RobossemblerAssetsNetworkMapperScenario(), + }); } } diff --git a/server/src/features/realtime/domain/pipeline_status_usecase.ts b/server/src/features/realtime/domain/pipeline_status_usecase.ts index 96422c2..4df9d34 100644 --- a/server/src/features/realtime/domain/pipeline_status_usecase.ts +++ b/server/src/features/realtime/domain/pipeline_status_usecase.ts @@ -9,6 +9,7 @@ export class PipelineStatusUseCase { if (status.projectUUID !== null) { return Result.ok(status); } + if (status.projectUUID === null) { return Result.error(new Error("pipelineRealTimeService does not have an active project instance")); } diff --git a/server/src/features/realtime/domain/run_instance_pipeline_usecase.ts b/server/src/features/realtime/domain/run_instance_pipeline_usecase.ts index 7fff00e..483ad34 100644 --- a/server/src/features/realtime/domain/run_instance_pipeline_usecase.ts +++ b/server/src/features/realtime/domain/run_instance_pipeline_usecase.ts @@ -1,39 +1,55 @@ import { App } from "../../../core/controllers/app"; 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 { UpdateDataBaseModelUseCase } from "../../../core/usecases/update_database_model_usecase"; +import { PipelineValidationModel } from "../../pipelines/models/pipeline_validation_model"; import { IProjectInstanceModel, ProjectInstanceDbModel, } from "../../project_instance/models/project_instance_database_model"; -import { RealTimeValidationModel, pipelineRealTimeService } from "../realtime_presentation"; +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 { - async call(model: RealTimeValidationModel): Promise> { - const { id } = model; + async call(): Promise> { + const r = await new PipelineStatusUseCase().call(); + if (r.isFailure()) { + return r; + } const readByIdDataBaseModelUseCase = await new ReadByIdDataBaseModelUseCase( ProjectInstanceDbModel - ).call(id); + ).call(r.value.projectUUID); if (readByIdDataBaseModelUseCase.isFailure()) { return readByIdDataBaseModelUseCase.forward(); } - const projectModel = readByIdDataBaseModelUseCase.value; - projectModel.isActive = true; + const resultMapper = projectModel.project.pipelines.map((el) => mongoPipelineModelMapper(el)); - const updateDataBaseModelUseCase = await new UpdateDataBaseModelUseCase( - ProjectInstanceDbModel - ).call(projectModel); - - if (updateDataBaseModelUseCase.isFailure()) { - return updateDataBaseModelUseCase.forward(); - } pipelineRealTimeService.setPipelineDependency( - projectModel.project.pipelines, + resultMapper, App.staticFilesStoreDir() + projectModel.rootDir + "/", projectModel._id ); + pipelineRealTimeService.runPipeline(); return Result.ok({ status: "ok" }); diff --git a/server/test/services/stack_service_test.ts b/server/test/services/stack_service_test.ts index 5b44e60..9a47f15 100644 --- a/server/test/services/stack_service_test.ts +++ b/server/test/services/stack_service_test.ts @@ -4,7 +4,7 @@ import { delay } from "../../src/core/helpers/delay"; import { assert, dirname__ } from "../test"; import { mockSimplePipeline } from "../model/mock_pipelines"; import { FileSystemRepository } from "../../src/core/repository/file_system_repository"; -import { CreateFolderUseCase } from "../../src/core/usecases/crete_folder_usecase"; +import { CreateFolderUseCase } from "../../src/core/usecases/create_folder_usecase"; abstract class IStackServiceTest { abstract test(): Promise; diff --git a/server/test/test.ts b/server/test/test.ts index ee7d4de..d0487c5 100644 --- a/server/test/test.ts +++ b/server/test/test.ts @@ -37,19 +37,19 @@ const init = async () => { const unitTest = async () => { await init(); - // await new ExecutorProgramServiceTest(dirname__).test(); - // await new FilesChangerTest(dirname__).test(); + await new ExecutorProgramServiceTest(dirname__).test(); + await new FilesChangerTest(dirname__).test(); await new StackServiceTest(dirname__).test(); - // await new TriggerServiceTest().test(); - // await new CreateDataBaseModelUseCaseTest().test(); - // await new CreateDataBaseModelUseCaseTest().test(); - // await new DeleteDataBaseModelUseCaseTest().test(); - // await new ReadDataBaseModelUseCaseTest().test(); - // await new UpdateDataBaseModelUseCaseTest().test(); + await new TriggerServiceTest().test(); + await new CreateDataBaseModelUseCaseTest().test(); + await new CreateDataBaseModelUseCaseTest().test(); + await new DeleteDataBaseModelUseCaseTest().test(); + await new ReadDataBaseModelUseCaseTest().test(); + await new UpdateDataBaseModelUseCaseTest().test(); - // for await (const usecase of tests) { - // testCore.assert(await new usecase().test(), usecase.name); - // } + for await (const usecase of tests) { + testCore.assert(await new usecase().test(), usecase.name); + } }; const presentationCrudControllers = [new TriggerPresentation()]; const e2eTest = async () => { diff --git a/ui/src/core/extensions/extensions.ts b/ui/src/core/extensions/extensions.ts index 5723394..3ce759c 100644 --- a/ui/src/core/extensions/extensions.ts +++ b/ui/src/core/extensions/extensions.ts @@ -2,7 +2,8 @@ import { ArrayExtensions } from "./array"; import { MapExtensions } from "./map"; import { StringExtensions } from "./string"; -export type CallBackFunction = (value: T) => void; +export type CallBackVoidFunction = (value: T) => void; +export type CallBackStringVoidFunction = (value: string) => void; declare global { interface Array { @@ -17,7 +18,7 @@ declare global { isEmpty(): boolean; } interface Map { - addValueOrMakeCallback(key: K, value: V, callBack: CallBackFunction): void; + addValueOrMakeCallback(key: K, value: V, callBack: CallBackVoidFunction): void; } } export const extensions = () => { diff --git a/ui/src/core/model/active_pipiline.ts b/ui/src/core/model/active_pipeline.ts similarity index 100% rename from ui/src/core/model/active_pipiline.ts rename to ui/src/core/model/active_pipeline.ts diff --git a/ui/src/core/model/ui_base_error.ts b/ui/src/core/model/ui_base_error.ts new file mode 100644 index 0000000..2811b4f --- /dev/null +++ b/ui/src/core/model/ui_base_error.ts @@ -0,0 +1,6 @@ +export class UiBaseError { + text: string; + constructor(text: string) { + this.text = text; + } +} diff --git a/ui/src/core/repository/http_repository.ts b/ui/src/core/repository/http_repository.ts index 0ebb2e7..e62eedc 100644 --- a/ui/src/core/repository/http_repository.ts +++ b/ui/src/core/repository/http_repository.ts @@ -16,18 +16,32 @@ export class HttpError extends Error { export class HttpRepository { private server = "http://localhost:4001"; + public async formDataRequest(method: HttpMethod, url: string, data?: any): Promise> { + let formData = new FormData(); + formData.append("file", data); - public async jsonRequest( - method: HttpMethod, - url: string, - data?: any - ): Promise> { + const reqInit = { + body: formData, + method: method, + }; + + if (data !== undefined) { + reqInit["body"] = data; + } + const response = await fetch(this.server + url, reqInit); + if (response.status !== 200) { + throw Result.error(new Error(await response.json())); + } + return Result.ok(response.text as T); + } + public async jsonRequest(method: HttpMethod, url: string, data?: any): Promise> { try { const reqInit = { body: data, method: method, headers: { "Content-Type": "application/json" }, }; + console.log(reqInit); if (data !== undefined) { reqInit["body"] = JSON.stringify(data); } @@ -37,28 +51,25 @@ export class HttpRepository { return Result.error(new HttpError(this.server + url, response.status)); } - return Result.ok(await response.json()); + return Result.ok(await response.json()); } catch (error) { return Result.error(new HttpError(error, 0)); } } - public async request( - method: HttpMethod, - url: string, - data?: any - ): Promise { + public async request(method: HttpMethod, url: string, data?: any): Promise> { const reqInit = { body: data, method: method, }; + if (data !== undefined) { reqInit["body"] = data; } const response = await fetch(this.server + url, reqInit); if (response.status !== 200) { - throw new Error(await response.json()); + throw Result.error(new Error(await response.json())); } - return response.json(); + return Result.ok(response.text as T); } } diff --git a/ui/src/core/routers/routers.tsx b/ui/src/core/routers/routers.tsx index e71ed7b..7d58fb5 100644 --- a/ui/src/core/routers/routers.tsx +++ b/ui/src/core/routers/routers.tsx @@ -21,18 +21,17 @@ import { CreateProcessScreen, CreateProcessScreenPath, } from "../../features/create_process/presentation/create_process_screen"; -import { ProjectRepository } from "../../features/all_projects/data/project_repository"; import { CreateProjectInstancePath, CreateProjectInstanceScreen, } from "../../features/create_project_instance/create_project_instance"; +import { SceneManger, SceneManagerPath } from "../../features/scene_manager/scene_manager"; const idURL = ":id"; export const router = createBrowserRouter([ { path: AllProjectScreenPath, - loader: new ProjectRepository().loader, element: , }, { @@ -63,4 +62,8 @@ export const router = createBrowserRouter([ path: CreateProjectInstancePath + idURL, element: , }, + { + path: SceneManagerPath + idURL, + element: , + }, ]); diff --git a/ui/src/core/store/base_store.ts b/ui/src/core/store/base_store.ts index 825a76e..3149052 100644 --- a/ui/src/core/store/base_store.ts +++ b/ui/src/core/store/base_store.ts @@ -1,22 +1,49 @@ // TODO(IDONTSUDO): нужно переписать все запросы под BaseStore import { Result } from "../helper/result"; +import { UiBaseError } from "../model/ui_base_error"; +import { HttpError } from "../repository/http_repository"; -export class BaseStore { +export type CoreError = HttpError | Error; + +export abstract class UiLoader { isLoading = false; - isError = false; - async loadingHelper(callBack: Promise>) { this.isLoading = true; const result = await callBack; if (result.isFailure()) { - this.isError = true; this.isLoading = false; + this.errorHandingStrategy(result.error); return result.forward(); } this.isLoading = false; return result; } + abstract errorHandingStrategy: (error?: any) => void; + + mapOk = async (property: string, callBack: Promise>) => { + return ( + (await this.loadingHelper(callBack)) + // eslint-disable-next-line array-callback-return + .map((el) => { + // @ts-ignore + this[property] = el; + }) + ); + }; +} +export class SimpleErrorState extends UiLoader { + errorHandingStrategy = () => { + this.isError = true; + }; + isError = false; +} + +export abstract class UiErrorState extends UiLoader { + abstract errorHandingStrategy: (error: T) => void; + abstract init(): Promise; + dispose() {} + errors: UiBaseError[] = []; } diff --git a/ui/src/features/all_projects/data/project_repository.ts b/ui/src/features/all_projects/data/project_repository.ts index 19641a9..00950ec 100644 --- a/ui/src/features/all_projects/data/project_repository.ts +++ b/ui/src/features/all_projects/data/project_repository.ts @@ -1,27 +1,16 @@ -import { redirect } from "react-router-dom"; -import { ActivePipeline } from "../../../core/model/active_pipiline"; -import { - HttpMethod, - HttpRepository, -} from "../../../core/repository/http_repository"; -import { PipelineInstanceScreenPath } from "../../pipeline_instance_main_screen/pipeline_instance_screen"; +import { ActivePipeline } from "../../../core/model/active_pipeline"; +import { HttpMethod, HttpRepository } from "../../../core/repository/http_repository"; import { IProjectModel } from "../model/project_model"; export class ProjectRepository extends HttpRepository { async getAllProject() { - return this.jsonRequest(HttpMethod.GET, "/project"); + return this.jsonRequest(HttpMethod.GET, "/project_instance"); } - + async getActivePipeline() { return this.jsonRequest(HttpMethod.GET, "/realtime"); } - loader = async () => { - const result = await this.getActivePipeline(); - - // if (result.isSuccess() && result.value.projectUUID !== null) { - // return redirect(PipelineInstanceScreenPath + result.value.projectUUID); - // } - - return null; - }; + async setActivePipeline(id: string) { + return this.jsonRequest(HttpMethod.POST, `/project_instance/set/active/project?id=${id}`); + } } diff --git a/ui/src/features/all_projects/presentation/all_projects_screen.tsx b/ui/src/features/all_projects/presentation/all_projects_screen.tsx index 6248f6b..b55ef8f 100644 --- a/ui/src/features/all_projects/presentation/all_projects_screen.tsx +++ b/ui/src/features/all_projects/presentation/all_projects_screen.tsx @@ -4,13 +4,18 @@ import { ProjectRepository } from "../data/project_repository"; import { LoadPage } from "../../../core/ui/pages/load_page"; import { observer } from "mobx-react-lite"; import { SelectProjectScreenPath } from "../../select_project/presentation/select_project"; +import { useNavigate } from "react-router-dom"; +import { Button } from "antd"; +import { PipelineInstanceScreenPath } from "../../pipeline_instance_main_screen/pipeline_instance_screen"; export const AllProjectScreenPath = "/"; - export const AllProjectScreen: React.FunctionComponent = observer(() => { - const [allProjectStore] = React.useState( - () => new AllProjectStore(new ProjectRepository()) - ); + const [allProjectStore] = React.useState(() => new AllProjectStore(new ProjectRepository())); + const navigate = useNavigate(); + + React.useEffect(() => { + allProjectStore.init(); + }, [allProjectStore]); return ( <> @@ -23,8 +28,33 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => { isLoading={allProjectStore.isLoading} children={
+

Projects

+
+ + {allProjectStore.activePipeline?.projectUUID ?? "loading"} +
{allProjectStore.projectsModels?.map((el) => { - return
{el.description}
; + return ( +
+ +
{el.description}
+
+ ); })}
} diff --git a/ui/src/features/all_projects/presentation/all_projects_store.ts b/ui/src/features/all_projects/presentation/all_projects_store.ts index 7851c79..ce98ff6 100644 --- a/ui/src/features/all_projects/presentation/all_projects_store.ts +++ b/ui/src/features/all_projects/presentation/all_projects_store.ts @@ -1,24 +1,62 @@ import makeAutoObservable from "mobx-store-inheritance"; import { ProjectRepository } from "../data/project_repository"; import { IProjectModel } from "../model/project_model"; -import { BaseStore } from "../../../core/store/base_store"; +import { SimpleErrorState } from "../../../core/store/base_store"; +import { ActivePipeline } from "../../../core/model/active_pipeline"; -export class AllProjectStore extends BaseStore { +interface IProjectView { + isActive: boolean; + description: string; + id: string; +} +export class ProjectView { + isActive: boolean; + description: string; + id: string; + constructor(view: IProjectView) { + this.isActive = view.isActive; + this.description = view.description; + this.id = view.id; + } +} +export class AllProjectStore extends SimpleErrorState { projectsModels?: IProjectModel[]; repository: ProjectRepository; - redirect = false; + activePipeline?: ActivePipeline; constructor(repository: ProjectRepository) { super(); this.repository = repository; makeAutoObservable(this); } - - async getProjects() { - const result = await this.loadingHelper(this.repository.getAllProject()); - if (result.isSuccess()) { - this.projectsModels = result.value; - } + async getProjects(): Promise { + await this.mapOk("projectsModels", this.repository.getAllProject()); } - + async getActiveProject(): Promise { + await this.mapOk("activePipeline", this.repository.getActivePipeline()); + } + async foo(): Promise { + this.isLoading = true; + const result = await this.repository.getActivePipeline(); + result.fold( + (success) => { + this.activePipeline = success; + this.isLoading = false; + }, + (_error) => { + this.isError = true; + } + ); + } + + async init() { + await Promise.all([this.getProjects(), this.getActiveProject()]); + await this.projectViewGenerate(); + } + projectViewGenerate() { + this.projectsModels = this.projectsModels?.filter((el) => el._id === this.activePipeline?.projectUUID); + } + async setPipelineActive(id: string) { + await this.loadingHelper(this.repository.setActivePipeline(id)); + } } diff --git a/ui/src/features/create_pipeline/presentation/create_pipeline_screen.tsx b/ui/src/features/create_pipeline/presentation/create_pipeline_screen.tsx index 2d95a95..c5f170c 100644 --- a/ui/src/features/create_pipeline/presentation/create_pipeline_screen.tsx +++ b/ui/src/features/create_pipeline/presentation/create_pipeline_screen.tsx @@ -29,9 +29,7 @@ export const CreatePipelineScreen: React.FunctionComponent = observer(() => { icon={Icon.add} />
- + i !== index - ); + this.pipelineViewModels = this.pipelineViewModels.filter((_el, i) => i !== index); } addTrigger(e: string, id: string): void { const lastElement = this.pipelineViewModels.lastElement(); @@ -82,12 +80,8 @@ export class CreatePipelineStore extends BaseStore { message.error("not found pipelines process"); return; } - const triggerId = this.pipelineViewModels.find( - (el) => el.type === Type.TRIGGER - )!.uuid as string; - const processId = this.pipelineViewModels.find( - (el) => el.type === Type.PROCESS - )!.uuid as string; + const triggerId = this.pipelineViewModels.find((el) => el.type === Type.TRIGGER)!.uuid as string; + const processId = this.pipelineViewModels.find((el) => el.type === Type.PROCESS)!.uuid as string; this.repository.savePipeline({ process: processId, @@ -96,33 +90,11 @@ export class CreatePipelineStore extends BaseStore { } async loadProcess() { - this.isLoading = true; - const result = await this.repository.getProcessed(); - result.fold( - (s) => { - this.processModels = s; - }, - (_e) => { - this.isError = true; - } - ); - this.isLoading = false; + this.mapOk("processModels", this.repository.getProcessed()); } async loadTriggers() { - this.isLoading = true; - const result = await this.repository.getTriggers(1); - result.fold( - (s) => { - this.triggersModels = s; - }, - (_e) => { - this.isError = true; - } - ); - this.isLoading = false; + this.mapOk("triggersModels", this.repository.getTriggers()); } } -export const createPipelineStore = new CreatePipelineStore( - new CreatePipelineRepository() -); +export const createPipelineStore = new CreatePipelineStore(new CreatePipelineRepository()); diff --git a/ui/src/features/create_process/presentation/logic/process_store.ts b/ui/src/features/create_process/presentation/logic/process_store.ts index 127cb56..d9e5afc 100644 --- a/ui/src/features/create_process/presentation/logic/process_store.ts +++ b/ui/src/features/create_process/presentation/logic/process_store.ts @@ -8,8 +8,8 @@ class ProcessStore { this.repository = repository; makeAutoObservable(this); } - async saveResult(model:IProcess) { - await this.repository.save(model) + async saveResult(model: IProcess) { + await this.repository.save(model); } } diff --git a/ui/src/features/create_project/create_project_screen.tsx b/ui/src/features/create_project/create_project_screen.tsx index f12cc10..273193e 100644 --- a/ui/src/features/create_project/create_project_screen.tsx +++ b/ui/src/features/create_project/create_project_screen.tsx @@ -1,17 +1,23 @@ import * as React from "react"; -import { LoadPage } from "../../core/ui/pages/load_page"; -import { createProjectStore } from "./create_project_store"; +import { LoadPage as MainPage } from "../../core/ui/pages/load_page"; import { observer } from "mobx-react-lite"; import { Col, Row, Input, Button } from "antd"; import { ReactComponent as AddIcon } from "../../core/assets/icons/add.svg"; import { CreatePipelineScreenPath } from "../create_pipeline/presentation/create_pipeline_screen"; +import { CreateProjectStore } from "./create_project_store"; +import { CreateProjectRepository } from "./create_project_repository"; export const CreateProjectScreenPath = "/create_project"; export const CreateProjectScreen: React.FunctionComponent = observer(() => { + const [createProjectStore] = React.useState(() => new CreateProjectStore(new CreateProjectRepository())); + + React.useEffect(() => { + createProjectStore.init(); + }, [createProjectStore]); return ( <> - { })} - - createProjectStore.setDescriptionToNewProject( - e.target.value - ) - } + onChange={(e) => createProjectStore.setDescriptionToNewProject(e.target.value)} placeholder="project description" /> - + {createProjectStore.newProjectViews.map((el, index) => { @@ -87,4 +86,3 @@ export const CreateProjectScreen: React.FunctionComponent = observer(() => { ); }); - \ No newline at end of file diff --git a/ui/src/features/create_project/create_project_store.ts b/ui/src/features/create_project/create_project_store.ts index 73f634a..c330d02 100644 --- a/ui/src/features/create_project/create_project_store.ts +++ b/ui/src/features/create_project/create_project_store.ts @@ -1,12 +1,9 @@ import makeAutoObservable from "mobx-store-inheritance"; -import { - CreateProjectRepository, - PipelineModel, -} from "./create_project_repository"; +import { CreateProjectRepository, PipelineModel } from "./create_project_repository"; import { message } from "antd"; -import { BaseStore } from "../../core/store/base_store"; +import { SimpleErrorState } from "../../core/store/base_store"; -class CreateProjectStore extends BaseStore { +export class CreateProjectStore extends SimpleErrorState { repository: CreateProjectRepository; pipelineModels?: PipelineModel[]; @@ -17,25 +14,16 @@ class CreateProjectStore extends BaseStore { super(); this.repository = repository; makeAutoObservable(this); - this.loadPipelines(); } - + async init() { + await this.loadPipelines(); + } async addPipeline(model: PipelineModel) { this.newProjectViews.push(model); } async loadPipelines() { - this.isLoading = true; - const result = await this.repository.getAllPipelines(); - result.fold( - (s) => { - this.pipelineModels = s; - }, - (_e) => { - this.isError = true; - } - ); - this.isLoading = false; + this.mapOk("pipelineModels", this.repository.getAllPipelines()); } setDescriptionToNewProject(value: string): void { @@ -71,7 +59,3 @@ class CreateProjectStore extends BaseStore { ); } } - -export const createProjectStore = new CreateProjectStore( - new CreateProjectRepository() -); diff --git a/ui/src/features/create_project_instance/create_project_instance.tsx b/ui/src/features/create_project_instance/create_project_instance.tsx index cc0463b..b762f4a 100644 --- a/ui/src/features/create_project_instance/create_project_instance.tsx +++ b/ui/src/features/create_project_instance/create_project_instance.tsx @@ -12,16 +12,17 @@ export const CreateProjectInstanceScreen = observer(() => { () => new CreateProjectInstanceStore(new CreateProjectInstanceRepository()) ); const id = useParams().id; - createProjectInstanceStore.getProjectById(id as string) + React.useEffect(() => {}, [id, createProjectInstanceStore]); return ( <> { - console.log(e); + createProjectInstanceStore.file = e.file.originFileObj; }} > + ); }); diff --git a/ui/src/features/create_project_instance/create_project_instance_repository.ts b/ui/src/features/create_project_instance/create_project_instance_repository.ts index 6b6d1b9..a1c0db6 100644 --- a/ui/src/features/create_project_instance/create_project_instance_repository.ts +++ b/ui/src/features/create_project_instance/create_project_instance_repository.ts @@ -1,10 +1,13 @@ -import { - HttpMethod, - HttpRepository, -} from "../../core/repository/http_repository"; +import { HttpMethod, HttpRepository } from "../../core/repository/http_repository"; +// this.subRoutes.push({ +// method: "POST", +// subUrl: "upload export class CreateProjectInstanceRepository extends HttpRepository { - async getProjectInstance(id: string) { - return await this.jsonRequest(HttpMethod.GET, ""); + async setProjectRootFile() { + return await this.formDataRequest(HttpMethod.POST, "/project_instance/upload/"); } + // async getProjectInstance(id: string) { + // return await this.jsonRequest(HttpMethod.GET, ""); + // } } diff --git a/ui/src/features/create_project_instance/create_project_instance_store.ts b/ui/src/features/create_project_instance/create_project_instance_store.ts index be7a346..6f86c05 100644 --- a/ui/src/features/create_project_instance/create_project_instance_store.ts +++ b/ui/src/features/create_project_instance/create_project_instance_store.ts @@ -1,18 +1,23 @@ import makeAutoObservable from "mobx-store-inheritance"; -import { BaseStore } from "../../core/store/base_store"; +import { SimpleErrorState } from "../../core/store/base_store"; import { CreateProjectInstanceRepository } from "./create_project_instance_repository"; +import { message } from "antd"; +import { HttpMethod } from "../../core/repository/http_repository"; -export class CreateProjectInstanceStore extends BaseStore { +export class CreateProjectInstanceStore extends SimpleErrorState { + file?: File; + + saveInstance(): void { + if (this.file === undefined) { + message.error("Need upload file"); + } else { + // this.repository.formDataRequest(HttpMethod.POST, "", this.file); + } + } constructor(repository: CreateProjectInstanceRepository) { super(); this.repository = repository; makeAutoObservable(this); } repository: CreateProjectInstanceRepository; - async getProjectById(id: string) { - const result = await this.loadingHelper(this.repository.getProjectInstance(id)) - if(result.isSuccess()){ - - } - } } diff --git a/ui/src/features/create_trigger/presentation/components/code_trigger_form.tsx b/ui/src/features/create_trigger/presentation/components/code_trigger_form.tsx index 14e7946..d399667 100644 --- a/ui/src/features/create_trigger/presentation/components/code_trigger_form.tsx +++ b/ui/src/features/create_trigger/presentation/components/code_trigger_form.tsx @@ -2,36 +2,40 @@ import * as React from "react"; import Editor from "@monaco-editor/react"; import { Button } from "antd"; import { observer } from "mobx-react-lite"; -import { triggerStore } from "../trigger_store"; +import { CallBackStringVoidFunction } from "../../../../core/extensions/extensions"; -export const CodeTriggerForm: React.FunctionComponent = observer(() => { - return ( - <> -
+interface ICodeTriggerFormProps { + codeTriggerValue: string; + clearTriggerCode: VoidFunction; + saveCode: VoidFunction; + writeNewTrigger: CallBackStringVoidFunction; +} - { - triggerStore.writeNewTrigger(v); - }} - onValidate={(_m) => {}} - /> +export const CodeTriggerForm: React.FunctionComponent = observer( + (props: ICodeTriggerFormProps) => { + return ( + <> +
-
-
+ { + props.writeNewTrigger(v ?? ""); + }} + onValidate={(_m) => {}} + /> - +
+
- - - ); -}); + + + + + ); + } +); diff --git a/ui/src/features/create_trigger/presentation/components/file_trigger_form.tsx b/ui/src/features/create_trigger/presentation/components/file_trigger_form.tsx index a09b70f..2f6936d 100644 --- a/ui/src/features/create_trigger/presentation/components/file_trigger_form.tsx +++ b/ui/src/features/create_trigger/presentation/components/file_trigger_form.tsx @@ -3,50 +3,49 @@ import { Formik } from "formik"; import { SubmitButton, Input, ResetButton, Form, FormItem } from "formik-antd"; import { Row, Col } from "antd"; import { observer } from "mobx-react-lite"; -import { triggerStore } from "../trigger_store"; import { TriggerType } from "../../../../core/model/trigger_model"; import { validateRequired } from "../../../../core/helper/validate"; - -export const FileTriggerForm: React.FunctionComponent = observer(() => { - return ( - <> -
- { - triggerStore.pushTrigger(values.value, TriggerType.FILE); - actions.setSubmitting(false); - actions.resetForm(); - }} - validate={(values) => { - if (values.value.length === 0) { - return false; - } - return {}; - }} - render={() => ( -
-
- - - - - - Reset - Submit - - -
-
- )} - /> -
- - ); -}); +export interface IFileTriggerFormProps { + pushTrigger: (value: string, type: TriggerType) => void; +} +export const FileTriggerForm: React.FunctionComponent = observer( + (props: IFileTriggerFormProps) => { + return ( + <> +
+ { + props.pushTrigger(values.value, TriggerType.FILE); + actions.setSubmitting(false); + actions.resetForm(); + }} + validate={(values) => { + if (values.value.length === 0) { + return false; + } + return {}; + }} + render={() => ( +
+
+ + + + + + Reset + Submit + + +
+
+ )} + /> +
+ + ); + } +); diff --git a/ui/src/features/create_trigger/presentation/create_trigger_screen.tsx b/ui/src/features/create_trigger/presentation/create_trigger_screen.tsx index 73524e2..243f62e 100644 --- a/ui/src/features/create_trigger/presentation/create_trigger_screen.tsx +++ b/ui/src/features/create_trigger/presentation/create_trigger_screen.tsx @@ -2,35 +2,20 @@ import * as React from "react"; import { Button, Col, Row, Switch, Typography, Input } from "antd"; import { CodeTriggerForm } from "./components/code_trigger_form"; import { observer } from "mobx-react-lite"; -import { triggerStore } from "./trigger_store"; import { FileTriggerForm } from "./components/file_trigger_form"; import { ReactComponent as DeleteIcon } from "../../../core/assets/icons/delete.svg"; import { Loader } from "../../../core/ui/loader/loader"; +import { TriggerRepository } from "../data/trigger_repository"; +import { TriggerStore } from "./trigger_store"; +import { TriggerViewModel } from "../model/trigger_form_view_model"; +import { CallBackStringVoidFunction } from "../../../core/extensions/extensions"; const { Title } = Typography; -const Header = observer(() => { - return ( - -
- triggerStore.setTriggerType()} - /> -
- - Trigger editor: {triggerStore.getTriggerDescription()} - -
- -
- ); -}); - -const Bottom = observer(() => { +const Bottom = observer((props: { triggers: TriggerViewModel[]; callBack: CallBackStringVoidFunction }) => { return ( - {triggerStore.triggers.map((el) => { + {props.triggers.map((el) => { return ( { }} > {el.value} - triggerStore.deleteItem(el.id)} /> + props.callBack(el.id)} /> ); })} ); }); -export const CreateTriggerScreenPath = '/create/trigger' +export const CreateTriggerScreenPath = "/create/trigger"; + export const TriggerScreen: React.FunctionComponent = observer(() => { + const [triggerStore] = React.useState(() => new TriggerStore(new TriggerRepository())); return ( <>
{!triggerStore.isLoading ? ( <> -
, - triggerStore.changeTriggerDescription} - /> + +
+ triggerStore.setTriggerType()} /> +
+ Trigger editor: {triggerStore.getTriggerDescription()} +
+ +
+ triggerStore.changeTriggerDescription} /> {triggerStore.getTriggerType() ? ( <> - + ) : ( <> - + )} - + ) : ( <> - - + )}
diff --git a/ui/src/features/create_trigger/presentation/trigger_store.ts b/ui/src/features/create_trigger/presentation/trigger_store.ts index efbfde7..d570ade 100644 --- a/ui/src/features/create_trigger/presentation/trigger_store.ts +++ b/ui/src/features/create_trigger/presentation/trigger_store.ts @@ -3,9 +3,9 @@ import { v4 as uuidv4 } from "uuid"; import { TriggerType } from "../../../core/model/trigger_model"; import { TriggerRepository } from "../data/trigger_repository"; import { TriggerViewModel } from "../model/trigger_form_view_model"; -import { BaseStore } from "../../../core/store/base_store"; +import { SimpleErrorState } from "../../../core/store/base_store"; -class TriggerStore extends BaseStore { +export class TriggerStore extends SimpleErrorState { constructor(repository: TriggerRepository) { super(); this.triggerType = TriggerType.FILE; @@ -39,9 +39,7 @@ class TriggerStore extends BaseStore { this.triggerType = TriggerType.FILE; }; getTriggerDescription = (): string => { - return this.triggerType === TriggerType.FILE - ? TriggerType.FILE - : TriggerType.PROCESS; + return this.triggerType === TriggerType.FILE ? TriggerType.FILE : TriggerType.PROCESS; }; pushTrigger = (value: string, type: TriggerType): void => { this.triggers.push({ @@ -72,16 +70,15 @@ class TriggerStore extends BaseStore { } } async saveResult(): Promise { - this.isLoading = true; - await this.repository.save({ - type: this.getTriggerDescription(), - description: this.triggerDescription, - value: this.triggers.map((el) => { - return el.value; - }), - }); - this.isLoading = false; + await this.loadingHelper( + this.repository.save({ + type: this.getTriggerDescription(), + description: this.triggerDescription, + value: this.triggers.map((el) => { + return el.value; + }), + }) + ); } } - export const triggerStore = new TriggerStore(new TriggerRepository()); diff --git a/ui/src/features/p.tsx b/ui/src/features/p.tsx new file mode 100644 index 0000000..81853f1 --- /dev/null +++ b/ui/src/features/p.tsx @@ -0,0 +1,68 @@ +export {}; +// import React from "react"; +// import { CoreError, UiErrorState } from "../core/store/base_store"; +// import { SelectProjectStore } from "./select_project/presentation/select_project_store"; + +// export declare type ClassConstructor = { +// new (...args: any[]): T; +// }; +// interface MobxReactComponentProps, ClassConstructor> { +// store: ClassConstructor; +// children: (element: T) => React.ReactElement; +// } + +// class UiStateErrorComponent, K> extends React.Component< +// MobxReactComponentProps, +// { store: T | undefined } +// > { +// async componentDidMount(): Promise { +// const store = this.props.store as ClassConstructor; +// console.log(store); +// const s = new store(); +// this.setState({ store: s }); +// if (this.state !== null) { +// await this.state.store?.init(); +// } +// } +// componentWillUnmount(): void { +// if (this.state.store !== undefined) { +// this.state.store.dispose(); +// } +// } + +// render() { +// if (this.state !== null) { +// if (this.state.store?.isLoading) { +// return <>Loading; +// } +// if (this.state.store !== undefined) { +// return this.props.children(this.state.store); +// } +// } + +// return ( +//
+// <>{this.props.children} +//
+// ); +// } +// } + +// export const ExampleScreen: React.FC = () => { +// return ( +//
+// store={SelectProjectStore}> +// {(store) => { +// console.log(store); +// return ( +//
+// {store.projects.map((el) => { +// return <>{el}; +// })} +//
+// ); +// }} +// +//
+// ); +// }; diff --git a/ui/src/features/pipeline_instance_main_screen/pipeline_instance_screen.tsx b/ui/src/features/pipeline_instance_main_screen/pipeline_instance_screen.tsx index 6efdf6d..5476534 100644 --- a/ui/src/features/pipeline_instance_main_screen/pipeline_instance_screen.tsx +++ b/ui/src/features/pipeline_instance_main_screen/pipeline_instance_screen.tsx @@ -4,13 +4,12 @@ import { PipelineInstanceStore } from "./pipeline_instance_store"; export const PipelineInstanceScreenPath = "/pipeline_instance/"; export const PipelineInstanceScreen: React.FunctionComponent = () => { - const [pipelineInstanceStore] = React.useState( - () => new PipelineInstanceStore() - ); - + const [pipelineInstanceStore] = React.useState(() => new PipelineInstanceStore()); + React.useEffect(() => {}, [pipelineInstanceStore]); return (
} diff --git a/ui/src/features/pipeline_instance_main_screen/pipeline_instance_store.ts b/ui/src/features/pipeline_instance_main_screen/pipeline_instance_store.ts index e51c874..7c9bb7f 100644 --- a/ui/src/features/pipeline_instance_main_screen/pipeline_instance_store.ts +++ b/ui/src/features/pipeline_instance_main_screen/pipeline_instance_store.ts @@ -1,7 +1,7 @@ import makeAutoObservable from "mobx-store-inheritance"; -import { BaseStore } from "../../core/store/base_store"; +import { SimpleErrorState } from "../../core/store/base_store"; -export class PipelineInstanceStore extends BaseStore { +export class PipelineInstanceStore extends SimpleErrorState { constructor() { super(); makeAutoObservable(this); diff --git a/ui/src/features/scene_manager/scene_manager.tsx b/ui/src/features/scene_manager/scene_manager.tsx index d3e03b7..cdec5ae 100644 --- a/ui/src/features/scene_manager/scene_manager.tsx +++ b/ui/src/features/scene_manager/scene_manager.tsx @@ -2,6 +2,7 @@ import * as React from "react"; import { SceneMangerStore, StaticAssetItemModel } from "./scene_manager_store"; import { observer } from "mobx-react-lite"; import { StaticAssetModelView } from "./components/static_asset_item_view"; +import { useParams } from "react-router-dom"; // const useKeyLister = (fn: Function) => { // const pressed = new Map(); @@ -26,21 +27,25 @@ import { StaticAssetModelView } from "./components/static_asset_item_view"; // return []; // }; - +export const SceneManagerPath = "/scene/manager/"; export const SceneManger = observer(() => { const canvasRef = React.useRef(null); const [sceneMangerStore] = React.useState(() => new SceneMangerStore()); + const id = useParams().id as string; React.useEffect(() => { - sceneMangerStore.loadGl(canvasRef.current!); + if (id) { + sceneMangerStore.loadScene(id, canvasRef.current!); + } return () => { sceneMangerStore.dispose(); }; - }); + }, [id, sceneMangerStore]); return (
+
{sceneMangerStore.errors.isNotEmpty() ? <>{sceneMangerStore.errors[0].text} : <>}
{sceneMangerStore.sceneItems.map((el) => { if (el instanceof StaticAssetItemModel) { diff --git a/ui/src/features/scene_manager/scene_manager_store.ts b/ui/src/features/scene_manager/scene_manager_store.ts index 96ae25e..5162597 100644 --- a/ui/src/features/scene_manager/scene_manager_store.ts +++ b/ui/src/features/scene_manager/scene_manager_store.ts @@ -1,8 +1,11 @@ /* eslint-disable array-callback-return */ -import { makeAutoObservable } from "mobx"; +import makeAutoObservable from "mobx-store-inheritance"; import { CoreThereRepository } from "../../core/repository/core_there_repository"; import { v4 as uuidv4 } from "uuid"; import { Vector2 } from "three"; +import { HttpError, HttpMethod, HttpRepository } from "../../core/repository/http_repository"; +import { UiErrorState } from "../../core/store/base_store"; +import { UiBaseError } from "../../core/model/ui_base_error"; export class BaseSceneItemModel { id: string; @@ -24,12 +27,35 @@ export class StaticAssetItemModel extends BaseSceneItemModel { } } -export class SceneMangerStore { +export enum RobossemblerFiles { + robossemblerAssets = "robossembler_assets.json", +} + +export class SceneMangerStore extends UiErrorState { + async init(): Promise {} + errorHandingStrategy = (error: HttpError) => { + if (error.status === 404) { + this.errors.push(new UiBaseError(`${RobossemblerFiles.robossemblerAssets} not found to project`)); + } + }; + + async loadScene(sceneId: string, canvasRef: HTMLCanvasElement) { + ( + await this.loadingHelper( + this.httpRepository.jsonRequest(HttpMethod.GET, "/" + sceneId + "/" + RobossemblerFiles.robossemblerAssets) + ) + ).map((el) => { + this.loadGl(canvasRef); + }); + } coreThereRepository: null | CoreThereRepository = null; + httpRepository: HttpRepository; sceneItems: BaseSceneItemModel[] = []; constructor() { + super(); makeAutoObservable(this); + this.httpRepository = new HttpRepository(); } loadGl(canvasRef: HTMLCanvasElement): void { diff --git a/ui/src/features/select_project/data/select_project_repository.ts b/ui/src/features/select_project/data/select_project_repository.ts index 67ee41f..482f509 100644 --- a/ui/src/features/select_project/data/select_project_repository.ts +++ b/ui/src/features/select_project/data/select_project_repository.ts @@ -1,11 +1,11 @@ import { Result } from "../../../core/helper/result"; -import { - HttpMethod, - HttpRepository, -} from "../../../core/repository/http_repository"; +import { HttpMethod, HttpRepository } from "../../../core/repository/http_repository"; import { IProjectModel } from "../model/project_model"; export class SelectProjectRepository extends HttpRepository { + async setActiveProject(id: string) { + return await this.jsonRequest(HttpMethod.POST, `/project?${id}`); + } async getAllProjects(page = 1): Promise> { return await this.jsonRequest(HttpMethod.GET, `/project?${page}`); } diff --git a/ui/src/features/select_project/presentation/select_project.tsx b/ui/src/features/select_project/presentation/select_project.tsx index 543820d..f8e6d36 100644 --- a/ui/src/features/select_project/presentation/select_project.tsx +++ b/ui/src/features/select_project/presentation/select_project.tsx @@ -3,16 +3,16 @@ import { observer } from "mobx-react-lite"; import { LoadPage } from "../../../core/ui/pages/load_page"; import { CreateProjectScreenPath } from "../../create_project/create_project_screen"; import { SelectProjectStore } from "./select_project_store"; -import { SelectProjectRepository } from "../data/select_project_repository"; import { useNavigate } from "react-router-dom"; import { CreateProjectInstancePath } from "../../create_project_instance/create_project_instance"; import { Button } from "antd"; export const SelectProjectScreenPath = "/select_project"; export const SelectProjectScreen: React.FunctionComponent = observer(() => { - const [selectProjectStore] = React.useState( - () => new SelectProjectStore(new SelectProjectRepository()) - ); + const [selectProjectStore] = React.useState(() => new SelectProjectStore()); + React.useEffect(() => { + selectProjectStore.init(); + }, [selectProjectStore]); const navigate = useNavigate(); return ( @@ -22,17 +22,13 @@ export const SelectProjectScreen: React.FunctionComponent = observer(() => { largeText={"Select project"} minText={"add new project?"} isLoading={selectProjectStore.isLoading} - isError={selectProjectStore.isError} + isError={selectProjectStore.errors.isNotEmpty()} children={selectProjectStore.projects.map((el) => { return ( <>
{el.description}
- +
); diff --git a/ui/src/features/select_project/presentation/select_project_store.ts b/ui/src/features/select_project/presentation/select_project_store.ts index e950a7f..35f82ea 100644 --- a/ui/src/features/select_project/presentation/select_project_store.ts +++ b/ui/src/features/select_project/presentation/select_project_store.ts @@ -1,33 +1,31 @@ import makeAutoObservable from "mobx-store-inheritance"; import { SelectProjectRepository } from "../data/select_project_repository"; import { IProjectModel } from "../model/project_model"; -import { BaseStore } from "../../../core/store/base_store"; +import { CoreError, UiErrorState } from "../../../core/store/base_store"; + +export class SelectProjectStore extends UiErrorState { + errorHandingStrategy = (error: CoreError) => { + console.log(error); + }; -export class SelectProjectStore extends BaseStore { repository: SelectProjectRepository; - + errors = []; page = 1; projects: IProjectModel[] = []; - constructor(repository: SelectProjectRepository) { - super() - this.repository = repository; + constructor() { + super(); + + this.repository = new SelectProjectRepository(); makeAutoObservable(this); - this.getPipelines(); } - + async setActiveProject(id: string): Promise { + this.loadingHelper(this.repository.setActiveProject(id)); + } async getPipelines(): Promise { - this.isLoading = true; - const result = await this.repository.getAllProjects(this.page); - result.fold( - (s) => { - this.projects = s; - }, - (_e) => { - this.isError = true; - } - ); - this.isLoading = false; + await this.mapOk("projects", this.repository.getAllProjects(this.page)); + } + async init() { + await this.getPipelines(); } } - \ No newline at end of file diff --git a/ui/src/index.tsx b/ui/src/index.tsx index 571cfd8..dd0f8c8 100644 --- a/ui/src/index.tsx +++ b/ui/src/index.tsx @@ -2,21 +2,19 @@ import React from "react"; import ReactDOM from "react-dom/client"; import "antd/dist/antd.min.css"; -import { RouterProvider } from "react-router-dom"; -import { router } from "./core/routers/routers"; -import { SocketLister } from "./features/socket_lister/socket_lister"; import { extensions } from "./core/extensions/extensions"; -import { SceneManger } from "./features/scene_manager/scene_manager"; +import { SocketLister } from "./features/socket_lister/socket_lister"; +import { RouterProvider } from "react-router-dom"; +import { router } from "./core/routers/routers"; extensions(); const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement); root.render( <> - {/* + - */} - + );