deleted unnecessary files
added new features
This commit is contained in:
parent
dffc73c30f
commit
6840402b1f
119 changed files with 1835 additions and 1522 deletions
BIN
.DS_Store
vendored
BIN
.DS_Store
vendored
Binary file not shown.
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
p.py
|
|
@ -107,7 +107,7 @@ export class App extends TypedEvent<ServerStatus> {
|
|||
await result.fold(
|
||||
async (_s) => {
|
||||
await new CheckAndCreateStaticFilesFolderUseCase().call();
|
||||
await new SetLastActivePipelineToRealTimeServiceScenario().call();
|
||||
// await new SetLastActivePipelineToRealTimeServiceScenario().call();
|
||||
},
|
||||
async (_e) => {
|
||||
this.setServerStatus(ServerStatus.error);
|
||||
|
|
|
@ -26,7 +26,7 @@ export abstract class CallBackStrategyWithQueryPage {
|
|||
export abstract class CallbackStrategyWithFileUpload {
|
||||
abstract checkingFileExpression: RegExp;
|
||||
abstract idValidationExpression: CoreValidation;
|
||||
abstract call(file: File, id: string, description: string): ResponseBase;
|
||||
abstract call(file: File, id: string): ResponseBase;
|
||||
}
|
||||
|
||||
interface ISubSetFeatureRouter<T> {
|
||||
|
@ -122,12 +122,12 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
|||
res.status(400).json("need file to form data request");
|
||||
return;
|
||||
}
|
||||
if (req.query.description === undefined) {
|
||||
res
|
||||
.status(400)
|
||||
.json("request query description is null, need query description &description={description:String}");
|
||||
return;
|
||||
}
|
||||
// if (req.query.description === undefined) {
|
||||
// res
|
||||
// .status(400)
|
||||
// .json("request query description is null, need query description &description={description:String}");
|
||||
// return;
|
||||
// }
|
||||
if (req.query.id === undefined) {
|
||||
res.status(400).json("request query id is null, need query id ?id={id:String}");
|
||||
return;
|
||||
|
@ -142,7 +142,7 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
|||
return;
|
||||
}
|
||||
}
|
||||
await this.responseHelper(res, el.fn.call(req["files"]["file"], req.query.id, req.query.description));
|
||||
await this.responseHelper(res, el.fn.call(req["files"]["file"], req.query.id));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -197,12 +197,10 @@ export class CoreHttpController<V> implements ICoreHttpController {
|
|||
}
|
||||
(await useCase(payload)).fold(
|
||||
(ok) => {
|
||||
res.json(ok);
|
||||
return;
|
||||
return res.json(ok);
|
||||
},
|
||||
(err) => {
|
||||
res.status(400).json({ error: String(err) });
|
||||
return;
|
||||
return res.status(400).json({ error: String(err) });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,30 +1,9 @@
|
|||
import { NixStoreManagerPresentation } from "../../features/nix_store_manager/nix_store_manager";
|
||||
import { PipelinePresentation } from "../../features/pipelines/pipeline_presentation";
|
||||
import { ProcessPresentation } from "../../features/process/process_presentation";
|
||||
import {
|
||||
ProjectInstancePresentation,
|
||||
RobossemblerAssetsPresentation,
|
||||
} from "../../features/project_instance/project_instance_presentation";
|
||||
import { DatasetsPresentation } from "../../features/datasets/datasets_presentation";
|
||||
import { ProjectsPresentation } from "../../features/projects/projects_presentation";
|
||||
import { RealTimePresentation } from "../../features/realtime/realtime_presentation";
|
||||
import { TriggerPresentation } from "../../features/triggers/triggers_presentation";
|
||||
// import { ProjectsPresentation } from "../../features/_projects/projects_presentation";
|
||||
import { extensions } from "../extensions/extensions";
|
||||
import { Routes } from "../interfaces/router";
|
||||
|
||||
extensions();
|
||||
|
||||
export const routersImplementPureCrud = [
|
||||
new TriggerPresentation(),
|
||||
new ProjectsPresentation(),
|
||||
new ProcessPresentation(),
|
||||
new PipelinePresentation(),
|
||||
];
|
||||
|
||||
export const httpRoutes: Routes[] = [
|
||||
new RealTimePresentation(),
|
||||
new ProjectInstancePresentation(),
|
||||
new NixStoreManagerPresentation(),
|
||||
new RobossemblerAssetsPresentation(),
|
||||
]
|
||||
.concat(routersImplementPureCrud)
|
||||
.map((el) => el.call());
|
||||
export const httpRoutes: Routes[] = [new ProjectsPresentation(), new DatasetsPresentation()].map((el) => el.call());
|
||||
|
|
|
@ -17,8 +17,6 @@ export interface WorkerDataExec {
|
|||
process.on("message", async (message) => {
|
||||
const workerData = message as WorkerDataExec;
|
||||
if (workerData.type == WorkerType.SPAWN) {
|
||||
// Maybe error
|
||||
// const subprocess = cp.spawn(workerData.command, workerData.cliArgs, {
|
||||
const subprocess = cp.spawn(workerData.command, {
|
||||
cwd: workerData.execPath,
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Trigger } from "../../features/triggers/models/trigger_database_model";
|
||||
import { Trigger } from "../../features/_triggers/models/trigger_database_model";
|
||||
import { EXEC_TYPE } from "./exec_error_model";
|
||||
|
||||
export interface IPipeline {
|
||||
|
|
|
@ -1,160 +1,23 @@
|
|||
import { IsArray, IsEnum, IsNumber, IsOptional, IsString, ValidateNested } from "class-validator";
|
||||
import { IsArray, IsString } from "class-validator";
|
||||
import { Type } from "class-transformer";
|
||||
|
||||
export class Gravity {
|
||||
@IsNumber()
|
||||
x: number;
|
||||
@IsNumber()
|
||||
y: number;
|
||||
@IsNumber()
|
||||
z: number;
|
||||
class Asset {
|
||||
@IsString()
|
||||
public name: string;
|
||||
@IsString()
|
||||
public mesh: string;
|
||||
@IsString()
|
||||
public image: string;
|
||||
}
|
||||
|
||||
export class Pose {
|
||||
@IsNumber()
|
||||
x: number;
|
||||
@IsNumber()
|
||||
y: number;
|
||||
@IsNumber()
|
||||
z: number;
|
||||
@IsNumber()
|
||||
roll: number;
|
||||
@IsNumber()
|
||||
pitch: number;
|
||||
@IsNumber()
|
||||
yaw: number;
|
||||
}
|
||||
|
||||
export class Position {
|
||||
@IsNumber()
|
||||
x: number;
|
||||
@IsNumber()
|
||||
y: number;
|
||||
@IsNumber()
|
||||
z: number;
|
||||
}
|
||||
|
||||
export enum InstanceType {
|
||||
RGB_CAMERA = "rgb_camera",
|
||||
SCENE_SIMPLE_OBJECT = "scene_simple_object",
|
||||
}
|
||||
|
||||
abstract class CoreInstances {}
|
||||
|
||||
export class Instance extends CoreInstances {
|
||||
@IsEnum(InstanceType)
|
||||
instanceType: InstanceType;
|
||||
@Type(() => Position)
|
||||
position: Position;
|
||||
@IsArray()
|
||||
quaternion: number[];
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
instanceAt: null | string = null;
|
||||
}
|
||||
|
||||
export class SceneSimpleObject extends Instance {}
|
||||
|
||||
export class InstanceRgbCamera extends Instance {
|
||||
@IsString()
|
||||
cameraLink: string;
|
||||
@IsString()
|
||||
topicCameraInfo: string;
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
topicDepth: string | null;
|
||||
@IsString()
|
||||
topicImage: string;
|
||||
}
|
||||
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()
|
||||
@IsArray()
|
||||
@Type(() => Asset)
|
||||
assets: Asset[];
|
||||
|
||||
@IsArray()
|
||||
@Type(() => Instance, {
|
||||
discriminator: {
|
||||
property: "type",
|
||||
subTypes: [
|
||||
{ value: InstanceRgbCamera, name: InstanceType.RGB_CAMERA },
|
||||
{ value: SceneSimpleObject, name: InstanceType.SCENE_SIMPLE_OBJECT },
|
||||
],
|
||||
},
|
||||
keepDiscriminatorProperty: true,
|
||||
})
|
||||
instances: Instance[];
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => Physics)
|
||||
physics: Physics;
|
||||
|
||||
convertLocalPathsToServerPaths(server_address: string): RobossemblerAssets {
|
||||
convertLocalPathsToServerPaths(serverAddress: string): RobossemblerAssets {
|
||||
this.assets = this.assets.map((el) => {
|
||||
el.meshPath = server_address + el.meshPath;
|
||||
el.mesh = `${serverAddress}/${el.mesh.slice(2, el.mesh.length)}`;
|
||||
el.image = `${serverAddress}/${el.image.slice(2, el.image.length)}`;
|
||||
return el;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
getAssetPath(assetName: string): string {
|
||||
const findElement = this.assets.find((el) => el.name === assetName);
|
||||
|
||||
if (findElement === undefined) {
|
||||
throw new Error("RobossemblerAssets.getAssetPath not found asset by name:" + assetName);
|
||||
}
|
||||
return findElement.meshPath;
|
||||
}
|
||||
|
||||
getAssetAtInstance(instanceAt: string): Asset {
|
||||
return this.assets.filter((el) => el.name === instanceAt)[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export enum StaticFiles {
|
||||
robossembler_assets = "robossembler_assets.json",
|
||||
assets = "/assets/assets.json",
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ export class ReadingJsonFileAndConvertingToInstanceClassScenario<T> {
|
|||
}
|
||||
call = async (path: string): Promise<Result<string, T>> => {
|
||||
try {
|
||||
console.log(path);
|
||||
const result = await new ReadFileAndParseJsonUseCase().call(path);
|
||||
if (result.isFailure()) {
|
||||
return result.forward();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import {
|
||||
IProjectInstanceModel,
|
||||
ProjectInstanceDbModel,
|
||||
} from "../../features/project_instance/models/project_instance_database_model";
|
||||
import { pipelineRealTimeService } from "../../features/realtime/realtime_presentation";
|
||||
} from "../../features/projects/models/project_instance_database_model";
|
||||
import { pipelineRealTimeService } from "../../features/_realtime/realtime_presentation";
|
||||
import { App } from "../controllers/app";
|
||||
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||
import { SearchDataBaseModelUseCase } from "../usecases/search_database_model_usecase";
|
||||
|
@ -15,6 +15,10 @@ export class SetLastActivePipelineToRealTimeServiceScenario {
|
|||
})
|
||||
).fold(
|
||||
async (projectModel) => {
|
||||
if (projectModel.project === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const projectPath = App.staticFilesStoreDir() + projectModel.rootDir + "/";
|
||||
await new CreateFolderUseCase().call(projectPath);
|
||||
pipelineRealTimeService.setPipelineDependency(
|
||||
|
|
|
@ -7,7 +7,7 @@ import { Result } from "../helpers/result";
|
|||
import { ExecutorResult } from "../models/executor_result";
|
||||
import { delay } from "../helpers/delay";
|
||||
import { TriggerService } from "./trigger_service";
|
||||
import { Trigger } from "../../features/triggers/models/trigger_database_model";
|
||||
import { Trigger } from "../../features/_triggers/models/trigger_database_model";
|
||||
|
||||
export interface Iteration {
|
||||
hashes: IHashesCache | null;
|
||||
|
|
|
@ -3,7 +3,7 @@ import { IHashesCache } from "./files_change_notifier_service";
|
|||
import { EventsFileChanger } from "../models/meta_data_file_manager_model";
|
||||
import { Result } from "../helpers/result";
|
||||
import { TypedEvent } from "../helpers/typed_event";
|
||||
import { Trigger, TriggerType } from "../../features/triggers/models/trigger_database_model";
|
||||
import { Trigger, TriggerType } from "../../features/_triggers/models/trigger_database_model";
|
||||
|
||||
export class TriggerCallResult {
|
||||
results: Array<TriggerSuccessResult | TriggerErrorReport>;
|
||||
|
|
|
@ -8,6 +8,7 @@ export class CreateFolderUseCase {
|
|||
}
|
||||
call = async (path: string): Promise<Result<Error, string>> => {
|
||||
try {
|
||||
console.log(path);
|
||||
if (await this.fileSystemRepository.dirIsExists(path)) {
|
||||
return Result.ok("ok");
|
||||
}
|
||||
|
|
26
server/src/core/usecases/exec_process_usecase.ts
Normal file
26
server/src/core/usecases/exec_process_usecase.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { Result } from "../helpers/result";
|
||||
import { TypedEvent } from "../helpers/typed_event";
|
||||
import { EXEC_TYPE, ExecError, SpawnError } from "../models/exec_error_model";
|
||||
import { ExecutorResult } from "../models/executor_result";
|
||||
import { ExecutorProgramService } from "../services/executor_program_service";
|
||||
|
||||
export class ExecProcessUseCase {
|
||||
call = async (
|
||||
path: string,
|
||||
command: string,
|
||||
watcher?: TypedEvent<Result<ExecError | SpawnError, ExecutorResult>>
|
||||
): Promise<Result<Error, string>> => {
|
||||
try {
|
||||
const executorProgramService = new ExecutorProgramService(path);
|
||||
if (watcher)
|
||||
executorProgramService.on((event) => {
|
||||
watcher.emit(event);
|
||||
});
|
||||
executorProgramService.call(EXEC_TYPE.EXEC, command);
|
||||
|
||||
return Result.ok("ok");
|
||||
} catch (error) {
|
||||
return Result.error(error);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -9,7 +9,15 @@ export class ReadByIdDataBaseModelUseCase<D> {
|
|||
call = async (id: string): Promise<Result<Error, D>> => {
|
||||
try {
|
||||
const dbModel = this.databaseModel as any;
|
||||
return Result.ok(await dbModel.findById(id));
|
||||
const model = await dbModel.findById(id);
|
||||
if (model === null) {
|
||||
return Result.error(
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
Error(`the database table ${this.databaseModel.modelName} does not contain an object with this ID`)
|
||||
);
|
||||
}
|
||||
return Result.ok(model);
|
||||
} catch (error) {
|
||||
return Result.error(error);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@ export class SearchDataBaseModelUseCase<T> {
|
|||
this.model = model;
|
||||
}
|
||||
|
||||
call = async (findFilter: Partial<T>): Promise<Result<null, T>> => {
|
||||
call = async (findFilter: Partial<T>, error: string = "not found database"): Promise<Result<string, T>> => {
|
||||
const result = await this.model.findOne(findFilter);
|
||||
if (result === null) {
|
||||
return Result.error(null);
|
||||
return Result.error(error);
|
||||
} else {
|
||||
return Result.ok(result);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { EXEC_TYPE } from "../../core/models/exec_error_model";
|
|||
import { ExecutorResult } from "../../core/models/executor_result";
|
||||
import { IPipeline, IssueType, StackGenerateType } from "../../core/models/process_model";
|
||||
import { StackService } from "../../core/services/stack_service";
|
||||
import { TriggerType } from "../triggers/models/trigger_database_model";
|
||||
import { TriggerType } from "../_triggers/models/trigger_database_model";
|
||||
|
||||
class NixStoreModel {}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
import { IPipeline } from "../../../core/models/process_model";
|
||||
import { schemaProcess } from "../../process/models/process_database_model";
|
||||
import { triggerSchema } from "../../triggers/models/trigger_database_model";
|
||||
import { schemaProcess } from "../../_process/models/process_database_model";
|
||||
import { triggerSchema } from "../../_triggers/models/trigger_database_model";
|
||||
|
||||
export const PipelineSchema = new Schema({
|
||||
process: {
|
|
@ -1,8 +1,8 @@
|
|||
import { IsOptional, ValidateNested } from "class-validator";
|
||||
import { IPipeline, IProcess, StackGenerateType } from "../../../core/models/process_model";
|
||||
import { Type } from "class-transformer";
|
||||
import { ProcessModel } from "../../process/models/process_validation_model";
|
||||
import { TriggerModelValidationModel } from "../../triggers/models/trigger_validation_model";
|
||||
import { ProcessModel } from "../../_process/models/process_validation_model";
|
||||
import { TriggerModelValidationModel } from "../../_triggers/models/trigger_validation_model";
|
||||
|
||||
export class PipelineModel implements IPipeline {
|
||||
@ValidateNested()
|
|
@ -1,6 +1,6 @@
|
|||
import { IsMongoId, IsOptional } from "class-validator";
|
||||
import { IProcess, StackGenerateType } from "../../../core/models/process_model";
|
||||
import { TriggerModelValidationModel } from "../../triggers/models/trigger_validation_model";
|
||||
import { TriggerModelValidationModel } from "../../_triggers/models/trigger_validation_model";
|
||||
|
||||
export class PipelineValidationModel {
|
||||
@IsMongoId()
|
|
@ -1,6 +1,5 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
import { schemaPipeline } from "../../pipelines/models/pipeline_database_model";
|
||||
import { PipelineValidationModel } from "../../pipelines/models/pipeline_validation_model";
|
||||
import { PipelineValidationModel } from "../../_pipelines/models/pipeline_validation_model";
|
||||
|
||||
export interface IProjectModel {
|
||||
_id?: string;
|
||||
|
@ -11,15 +10,12 @@ export interface IProjectModel {
|
|||
}
|
||||
|
||||
export const ProjectSchema = new Schema({
|
||||
pipelines: {
|
||||
type: Array<Schema.Types.ObjectId>,
|
||||
ref: schemaPipeline,
|
||||
autopopulate: true,
|
||||
default: null,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
},
|
||||
rootDir: {
|
||||
type: String,
|
||||
},
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false,
|
13
server/src/features/_projects/projects_presentation.ts
Normal file
13
server/src/features/_projects/projects_presentation.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
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,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -3,11 +3,8 @@ import { CallbackStrategyWithEmpty } from "../../../core/controllers/http_contro
|
|||
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 "../../project_instance/models/project_instance_database_model";
|
||||
import { PipelineValidationModel } from "../../_pipelines/models/pipeline_validation_model";
|
||||
import { IProjectInstanceModel, ProjectInstanceDbModel } from "../../projects/models/project_instance_database_model";
|
||||
import { pipelineRealTimeService } from "../realtime_presentation";
|
||||
import { PipelineStatusUseCase } from "./pipeline_status_usecase";
|
||||
|
17
server/src/features/datasets/datasets_presentation.ts
Normal file
17
server/src/features/datasets/datasets_presentation.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { CreateDataSetScenario } from "./domain/create_dataset_scanario";
|
||||
import { GetDatasetActiveProjectScenario } from "./domain/get_dataset_active_project_scenario";
|
||||
import { DatasetDBModel } from "./models/dataset_database_model";
|
||||
import { DatasetValidationModel } from "./models/dataset_validation_model";
|
||||
|
||||
export class DatasetsPresentation extends CrudController<DatasetValidationModel, typeof DatasetDBModel> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "datasets",
|
||||
validationModel: DatasetValidationModel,
|
||||
databaseModel: DatasetDBModel,
|
||||
});
|
||||
super.post(new CreateDataSetScenario().call);
|
||||
super.get(new GetDatasetActiveProjectScenario().call);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
import { ObjectId } from "mongoose";
|
||||
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
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 { ExecProcessUseCase } from "../../../core/usecases/exec_process_usecase";
|
||||
import { SearchDataBaseModelUseCase } 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 } from "../models/dataset_validation_model";
|
||||
|
||||
export class ProcessWatcherAndDatabaseUpdateService extends TypedEvent<Result<ExecError | SpawnError, ExecutorResult>> {
|
||||
databaseId: ObjectId;
|
||||
constructor(databaseId: ObjectId) {
|
||||
super();
|
||||
this.databaseId = databaseId;
|
||||
this.on((event) => this.lister(event));
|
||||
}
|
||||
|
||||
lister(event: Result<ExecError | SpawnError, ExecutorResult>) {
|
||||
event.fold(
|
||||
async (success) => {
|
||||
if (success.event == EXEC_EVENT.END) {
|
||||
const dbModel = await DatasetDBModel.findById(this.databaseId);
|
||||
if (dbModel !== null) {
|
||||
dbModel.local_path;
|
||||
dbModel.processStatus = "end";
|
||||
dbModel.processLogs = success.data;
|
||||
await dbModel.save();
|
||||
}
|
||||
}
|
||||
},
|
||||
async (error) => {
|
||||
const dbModel = await DatasetDBModel.findById(this.databaseId);
|
||||
if (dbModel !== null) {
|
||||
dbModel.processStatus = "error";
|
||||
dbModel.processLogs = error.message;
|
||||
await dbModel.save();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
export class CreateDataSetScenario extends CallbackStrategyWithValidationModel<DatasetValidationModel> {
|
||||
validationModel: DatasetValidationModel;
|
||||
call = async (model: DatasetValidationModel): ResponseBase => {
|
||||
return (
|
||||
await new SearchDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
|
||||
).map(async (project) => {
|
||||
model.processStatus = "exec";
|
||||
model.local_path = project.rootDir;
|
||||
model.projectId = project._id;
|
||||
const d = new DatasetDBModel();
|
||||
Object.assign(d, model);
|
||||
await d.save();
|
||||
|
||||
await new ExecProcessUseCase().call(
|
||||
`${project.rootDir}/`,
|
||||
`python3 $PYTHON_BLENDER_PROC --path '${project.rootDir}/${model.name}' --cfg '${JSON.stringify(model)}'`,
|
||||
new ProcessWatcherAndDatabaseUpdateService(d._id as unknown as ObjectId)
|
||||
);
|
||||
return Result.ok("create dataset ok");
|
||||
});
|
||||
};
|
||||
}
|
||||
// сохрнать formbuilder result и передать его в python
|
||||
// {
|
||||
// "typedataset": ${typedataset:Enum<T>:"ObjectDetection"},
|
||||
// "dataset_path": ${DATASET_PATH:string:""},
|
||||
// "models":${models:Array<MODELS>:[]},
|
||||
// "models_randomization":{
|
||||
// "loc_range_low": [${LOC_RANGE_LOW_1:number:-1}, ${LOC_RANGE_LOW_2:number:-1},/${LOC_RANGE_LOW_3:number:0}],
|
||||
// "loc_range_high": [${LOC_RANGE_HIGH_1:number:1}, ${LOC_RANGE_HIGH_2:number:1},/${LOC_RANGE_HIGH_3:number:2}]
|
||||
// },
|
||||
// "scene":{
|
||||
// "objects": ${OBJECTS_SCENE:Array<OBJECTS_SCENE>:[]},
|
||||
// "lights": ${LIGHTS:Array<LIGHTS>:[]},
|
||||
// },
|
||||
// "camera_position":{
|
||||
// "center_shell": [${CENTER_SHELL_1:number:0}, ${CENTER_SHELL_2:number:0}, ${CENTER_SHELL_3:number:0}],
|
||||
// "radius_range": [${RADIUS_RANGE_1:number:0.4}, ${RADIUS_RANGE_2:number:1.4}],
|
||||
// "elevation_range": [${ELEVATION_RANGE_1:number:10}, ${ELEVATION_RANGE_2:number:90}]
|
||||
// },
|
||||
// "generation":{
|
||||
// "n_cam_pose": ${N_CAM_POSE:number:5},
|
||||
// "n_sample_on_pose": ${N_SAMPLE_ON_POSE:number:3},
|
||||
// "n_series": ${N_SERIES:number:100},
|
||||
// "image_format": ${image_format:Enum<F>:"jpg"},
|
||||
// "image_size_wh": [${IMAGE_SIZE_WH_1:number:640}, ${IMAGE_SIZE_WH_2:number:480}]
|
||||
// }
|
||||
// }
|
|
@ -0,0 +1,15 @@
|
|||
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { SearchDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
import { DatasetDBModel } from "../models/dataset_database_model";
|
||||
|
||||
export class GetDatasetActiveProjectScenario extends CallbackStrategyWithEmpty {
|
||||
call = async (): ResponseBase => {
|
||||
return (
|
||||
await new SearchDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
|
||||
).map(async (project) => {
|
||||
return Result.ok(await DatasetDBModel.find({ projectId: project._id }));
|
||||
});
|
||||
};
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import { Mongoose, Schema, model } from "mongoose";
|
||||
import { IDatasetModel } from "./dataset_validation_model";
|
||||
import { projectSchema } from "../../_projects/models/project_database_model";
|
||||
|
||||
export const DatasetSchema = new Schema({
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
local_path: {
|
||||
type: String,
|
||||
},
|
||||
dataSetObjects: {
|
||||
type: Array,
|
||||
of: String,
|
||||
},
|
||||
formBuilder: {
|
||||
type: Schema.Types.Mixed,
|
||||
of: String,
|
||||
},
|
||||
processStatus: {
|
||||
type: String,
|
||||
default: "none",
|
||||
},
|
||||
projectId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: projectSchema,
|
||||
autopopulate: false,
|
||||
default: null,
|
||||
},
|
||||
processLogs: {
|
||||
type: String,
|
||||
},
|
||||
}).plugin(require("mongoose-autopopulate"));
|
||||
|
||||
export const datasetSchema = "Dataset";
|
||||
|
||||
export const DatasetDBModel = model<IDatasetModel>(datasetSchema, DatasetSchema);
|
|
@ -0,0 +1,34 @@
|
|||
import { Type } from "class-transformer";
|
||||
import { IsArray, IsString, ValidateNested } from "class-validator";
|
||||
|
||||
export class FormBuilderValidationModel {
|
||||
@IsString()
|
||||
public result: string;
|
||||
@IsString()
|
||||
public context: string;
|
||||
@IsArray()
|
||||
public form: [];
|
||||
}
|
||||
|
||||
export interface IDatasetModel {
|
||||
name: string;
|
||||
local_path: string;
|
||||
dataSetObjects: string[];
|
||||
formBuilder: FormBuilderValidationModel;
|
||||
processLogs: string;
|
||||
processStatus: string;
|
||||
}
|
||||
|
||||
export class DatasetValidationModel implements IDatasetModel {
|
||||
@IsString()
|
||||
public name: string;
|
||||
@IsArray()
|
||||
public dataSetObjects: string[];
|
||||
@ValidateNested()
|
||||
@Type(() => FormBuilderValidationModel)
|
||||
public formBuilder: FormBuilderValidationModel;
|
||||
public local_path: string;
|
||||
public processStatus: string;
|
||||
public projectId: string;
|
||||
public processLogs: string;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
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/create_folder_usecase";
|
||||
import { pipelineRealTimeService } from "../../realtime/realtime_presentation";
|
||||
import { ProjectInstanceDbModel } from "../models/project_instance_database_model";
|
||||
import { ProjectInstanceValidationModel } from "../models/project_instance_validation_model";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { SetActiveProjectScenario } from "./set_active_project_use_scenario";
|
||||
|
||||
export class CreateNewProjectInstanceScenario {
|
||||
call = async (): Promise<Result<Error, any>> => {
|
||||
try {
|
||||
// (await new SetActiveProjectScenario().call(id)).map(() => {
|
||||
// return Result.ok({ status: "ok" });
|
||||
// });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return Result.error(error as Error);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
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 { ReadingJsonFileAndConvertingToInstanceClassScenario } 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 ReadingJsonFileAndConvertingToInstanceClassScenario(RobossemblerAssets).call(
|
||||
`${activeInstanceModel.path}${StaticFiles.robossembler_assets}`
|
||||
)
|
||||
).map((robossemblerAssets) => {
|
||||
return new GetServerAddressUseCase().call().map((address) => {
|
||||
return Result.ok(
|
||||
robossemblerAssets.convertLocalPathsToServerPaths(
|
||||
`${address}/${activeInstanceModel.rootDir.pathNormalize()}`
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
return Result.error(error);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { CoreHttpController } from "../../core/controllers/http_controller";
|
||||
import { RobossemblerAssets } from "../../core/models/robossembler_assets";
|
||||
|
||||
import { CreateNewProjectInstanceScenario } from "./domain/create_new_project_scenario";
|
||||
import { RobossemblerAssetsNetworkMapperScenario } from "./domain/robossembler_assets_network_mapper_scenario";
|
||||
import { SaveActiveSceneScenario } from "./domain/save_active_scene_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";
|
||||
|
||||
export class ProjectInstancePresentation extends CrudController<
|
||||
ProjectInstanceValidationModel,
|
||||
typeof ProjectInstanceDbModel
|
||||
> {
|
||||
constructor() {
|
||||
super({
|
||||
validationModel: ProjectInstanceValidationModel,
|
||||
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(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class RobossemblerAssetsPresentation extends CoreHttpController<RobossemblerAssets> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "robossembler_assets",
|
||||
validationModel: RobossemblerAssets,
|
||||
});
|
||||
super.get(new RobossemblerAssetsNetworkMapperScenario().call);
|
||||
super.post(new SaveActiveSceneScenario().call);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
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";
|
||||
|
||||
export class ProjectValidationModel {
|
||||
@IsString()
|
||||
description: string;
|
||||
}
|
||||
export class CreateNewProjectInstanceScenario {
|
||||
call = async (model: ProjectValidationModel): Promise<Result<any, any>> => {
|
||||
try {
|
||||
const projectFolder = uuidv4();
|
||||
return (await new CreateFolderUseCase().call(App.staticFilesStoreDir() + projectFolder)).map(async (_) => {
|
||||
for await (const el of await ProjectDBModel.find({ isActive: true })) {
|
||||
el.isActive = false;
|
||||
await el.save();
|
||||
}
|
||||
|
||||
const projectDbModel = await new ProjectDBModel({
|
||||
isActive: true,
|
||||
rootDir: App.staticFilesStoreDir() + projectFolder,
|
||||
description: model.description,
|
||||
}).save();
|
||||
return Result.ok({ id: projectDbModel._id });
|
||||
});
|
||||
} catch (error) {
|
||||
return Result.error(error as Error);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { SearchDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../_projects/models/project_database_model";
|
||||
|
||||
export class GetActiveProjectScenario extends CallbackStrategyWithEmpty {
|
||||
async call(): ResponseBase {
|
||||
return (
|
||||
await new SearchDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call({ isActive: true }, "no active projects")
|
||||
).map((model) => Result.ok({ id: model._id }));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
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 { 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";
|
||||
|
||||
export class RobossemblerAssetsNetworkMapperScenario extends CallbackStrategyWithEmpty {
|
||||
async call(): ResponseBase {
|
||||
const projectDbModel = await ProjectDBModel.findOne({ isActive: true });
|
||||
if (projectDbModel === null) {
|
||||
return Result.error("is dont active projects");
|
||||
}
|
||||
const { rootDir } = projectDbModel;
|
||||
|
||||
return new GetServerAddressUseCase().call().map(async (address) =>
|
||||
(
|
||||
await new ReadingJsonFileAndConvertingToInstanceClassScenario<RobossemblerAssets>(RobossemblerAssets).call(
|
||||
rootDir + StaticFiles.assets
|
||||
)
|
||||
).map((model) => {
|
||||
return Result.ok(
|
||||
model.convertLocalPathsToServerPaths(
|
||||
`${address}/${
|
||||
rootDir.match(new RegExp(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gm))[0]
|
||||
}/assets`
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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 { WriteFileSystemFileUseCase } from "../../../core/usecases/write_file_system_file_usecase";
|
||||
import { PipelineStatusUseCase } from "../../realtime/domain/pipeline_status_usecase";
|
||||
import { PipelineStatusUseCase } from "../../_realtime/domain/pipeline_status_usecase";
|
||||
|
||||
export class SaveActiveSceneScenario extends CallbackStrategyWithValidationModel<RobossemblerAssets> {
|
||||
validationModel: RobossemblerAssets = new RobossemblerAssets();
|
|
@ -12,24 +12,31 @@ export class SetActiveProjectScenario extends CallbackStrategyWithIdQuery {
|
|||
idValidationExpression = new MongoIdValidation();
|
||||
|
||||
async call(id: string): ResponseBase {
|
||||
const result = await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(ProjectInstanceDbModel).call(id);
|
||||
// id
|
||||
try {
|
||||
const result = await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(ProjectInstanceDbModel).call(id);
|
||||
// id
|
||||
|
||||
if (result.isFailure()) {
|
||||
return result.forward();
|
||||
}
|
||||
const model = result.value;
|
||||
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`);
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,32 +6,28 @@ import { CreateDataBaseModelUseCase } from "../../../core/usecases/create_databa
|
|||
import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase";
|
||||
import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase";
|
||||
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||
import { ProjectInstanceDbModel } from "../models/project_instance_database_model";
|
||||
import { IProjectInstanceModel, ProjectInstanceDbModel } from "../models/project_instance_database_model";
|
||||
import { ProjectInstanceValidationModel } from "../models/project_instance_validation_model";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { SetActiveProjectScenario } from "./set_active_project_use_scenario";
|
||||
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";
|
||||
|
||||
export class UploadCadFileToProjectScenario extends CallbackStrategyWithFileUpload {
|
||||
checkingFileExpression: RegExp = RegExp(".FCStd");
|
||||
checkingFileExpression: RegExp = new RegExp(".FCStd");
|
||||
idValidationExpression = new MongoIdValidation();
|
||||
|
||||
async call(file: IFile, id: string, description: string): ResponseBase {
|
||||
const folderName = uuidv4() + "/";
|
||||
const model = new ProjectInstanceValidationModel();
|
||||
model["project"] = id;
|
||||
model["description"] = description;
|
||||
model["rootDir"] = folderName;
|
||||
model["isActive"] = true;
|
||||
return (await new CreateFolderUseCase().call(App.staticFilesStoreDir() + folderName)).map(async () =>
|
||||
(await new CreateDataBaseModelUseCase(ProjectInstanceDbModel).call(model)).map(async (databaseModel) =>
|
||||
(await new SetActiveProjectScenario().call(databaseModel.id)).map(async () =>
|
||||
(await new CreateFileUseCase().call(App.staticFilesStoreDir() + folderName + file.name, file.data)).map(
|
||||
() => {
|
||||
return Result.ok("ok");
|
||||
}
|
||||
)
|
||||
async call(file: IFile, id: string): ResponseBase {
|
||||
return (await new ReadByIdDataBaseModelUseCase<IProjectInstanceModel>(ProjectDBModel).call(id)).map(
|
||||
async (databaseModel) =>
|
||||
(await new CreateFileUseCase().call(`${databaseModel.rootDir}/${file.name}`, file.data)).map(
|
||||
async () =>
|
||||
await new ExecProcessUseCase().call(
|
||||
`${databaseModel.rootDir}/`,
|
||||
`python3 $PYTHON_BLENDER --path '${databaseModel.rootDir}/assets/'`
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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_database_model";
|
||||
|
||||
export interface IProjectInstanceModel {
|
||||
_id: string;
|
||||
|
@ -10,12 +10,6 @@ export interface IProjectInstanceModel {
|
|||
}
|
||||
|
||||
export const ProjectInstanceSchema = new Schema({
|
||||
project: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: projectSchema,
|
||||
autopopulate: true,
|
||||
default: null,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
},
|
|
@ -1,9 +1,6 @@
|
|||
import { IsMongoId, IsOptional, IsString } from "class-validator";
|
||||
|
||||
export class ProjectInstanceValidationModel {
|
||||
@IsMongoId()
|
||||
public project: string;
|
||||
|
||||
@IsString()
|
||||
public description: string;
|
||||
|
|
@ -1,13 +1,41 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { ProjectDBModel } from "./models/project_database_model";
|
||||
import { ProjectValidationModel } from "./models/project_validation_model";
|
||||
import { ProjectDBModel } from "../_projects/models/project_database_model";
|
||||
import { CreateNewProjectInstanceScenario } 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<ProjectValidationModel, typeof ProjectDBModel> {
|
||||
export class ProjectsPresentation extends CrudController<ProjectsValidationModel, typeof ProjectDBModel> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "project",
|
||||
validationModel: ProjectValidationModel,
|
||||
validationModel: ProjectsValidationModel,
|
||||
url: "projects",
|
||||
databaseModel: ProjectDBModel,
|
||||
});
|
||||
|
||||
super.post(new CreateNewProjectInstanceScenario().call);
|
||||
|
||||
this.subRoutes.push({
|
||||
method: "POST",
|
||||
subUrl: "set/active/project",
|
||||
fn: new SetActiveProjectScenario(),
|
||||
});
|
||||
this.subRoutes.push({
|
||||
method: "GET",
|
||||
subUrl: "get/active/project/id",
|
||||
fn: new GetActiveProjectScenario(),
|
||||
});
|
||||
this.subRoutes.push({
|
||||
method: "POST",
|
||||
subUrl: "upload",
|
||||
fn: new UploadCadFileToProjectScenario(),
|
||||
});
|
||||
this.subRoutes.push({
|
||||
method: "GET",
|
||||
subUrl: "assets",
|
||||
fn: new RobossemblerAssetsNetworkMapperScenario(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,10 @@ import { App } from "./core/controllers/app";
|
|||
import { SocketSubscriber } from "./core/controllers/socket_controller";
|
||||
import { extensions } from "./core/extensions/extensions";
|
||||
import { httpRoutes } from "./core/controllers/routes";
|
||||
import { pipelineRealTimeService } from "./features/realtime/realtime_presentation";
|
||||
import { main } from "./p";
|
||||
import { pipelineRealTimeService } from "./features/_realtime/realtime_presentation";
|
||||
|
||||
extensions();
|
||||
|
||||
const socketSubscribers = [new SocketSubscriber(pipelineRealTimeService, "realtime")];
|
||||
|
||||
new App(httpRoutes, socketSubscribers).listen();
|
||||
main();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { EXEC_TYPE } from "../../src/core/models/exec_error_model";
|
||||
import { IPipeline, IssueType, StackGenerateType } from "../../src/core/models/process_model";
|
||||
import { TriggerType } from "../../src/features/triggers/models/trigger_database_model";
|
||||
import { TriggerType } from "../../src/features/_triggers/models/trigger_database_model";
|
||||
|
||||
export const mockSimplePipeline: IPipeline[] = [
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { EventsFileChanger, MetaDataFileManagerModel } from "../../src/core/models/meta_data_file_manager_model";
|
||||
|
||||
import { TriggerService } from "../../src/core/services/trigger_service";
|
||||
import { TriggerType } from "../../src/features/triggers/models/trigger_database_model";
|
||||
import { TriggerType } from "../../src/features/_triggers/models/trigger_database_model";
|
||||
import { assert } from "../test";
|
||||
abstract class TriggerTest {
|
||||
abstract test(): Promise<boolean>;
|
||||
|
|
|
@ -14,7 +14,7 @@ import { UpdateDataBaseModelUseCaseTest } from "./usecases/update_database_model
|
|||
import { PaginationDataBaseModelUseCaseTest } from "./usecases/pagination_database_model_usecase_test";
|
||||
import { extensions } from "../src/core/extensions/extensions";
|
||||
import { CrudControllerTest } from "./controllers/crud_controller_test";
|
||||
import { TriggerPresentation } from "../src/features/triggers/triggers_presentation";
|
||||
import { TriggerPresentation } from "../src/features/_triggers/triggers_presentation";
|
||||
import { App, Environment, ServerStatus } from "../src/core/controllers/app";
|
||||
import { httpRoutes } from "../src/core/controllers/routes";
|
||||
import { DataBaseConnectUseCase } from "../src/core/usecases/database_connect_usecase";
|
||||
|
|
309
ui/package-lock.json
generated
309
ui/package-lock.json
generated
|
@ -26,15 +26,22 @@
|
|||
"mobx-react-lite": "^4.0.4",
|
||||
"mobx-store-inheritance": "^1.0.6",
|
||||
"react": "^18.2.0",
|
||||
"react-accessible-treeview": "^2.8.3",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-i18next": "^13.3.1",
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-router-dom": "^6.18.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rete-connection-plugin": "^2.0.0",
|
||||
"rete-react-plugin": "^2.0.4",
|
||||
"rete-render-utils": "^2.0.1",
|
||||
"sass": "^1.66.1",
|
||||
"serve": "^14.2.1",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"styled-components": "^6.1.8",
|
||||
"three": "^0.159.0",
|
||||
"three-stdlib": "^2.28.9",
|
||||
"three-transform-controls": "^1.0.4",
|
||||
|
@ -42,7 +49,8 @@
|
|||
"typescript": "^4.9.5",
|
||||
"urdf-loader": "^0.12.1",
|
||||
"uuid": "^9.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
"web-vitals": "^2.1.4",
|
||||
"xml-formatter": "^3.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/three": "^0.158.3"
|
||||
|
@ -2503,6 +2511,24 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/is-prop-valid": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
|
||||
"integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==",
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "^0.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/memoize": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA=="
|
||||
},
|
||||
"node_modules/@emotion/unitless": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz",
|
||||
"integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw=="
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
|
||||
|
@ -3232,6 +3258,21 @@
|
|||
"react-dom": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-dnd/asap": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
|
||||
"integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A=="
|
||||
},
|
||||
"node_modules/@react-dnd/invariant": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz",
|
||||
"integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw=="
|
||||
},
|
||||
"node_modules/@react-dnd/shallowequal": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
|
||||
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.0.tgz",
|
||||
|
@ -4048,6 +4089,11 @@
|
|||
"integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/stylis": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz",
|
||||
"integrity": "sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw=="
|
||||
},
|
||||
"node_modules/@types/testing-library__jest-dom": {
|
||||
"version": "5.14.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz",
|
||||
|
@ -5635,6 +5681,14 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/camelize": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
|
||||
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-api": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
|
||||
|
@ -6244,6 +6298,14 @@
|
|||
"postcss": "^8.4"
|
||||
}
|
||||
},
|
||||
"node_modules/css-color-keywords": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
|
||||
"integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/css-declaration-sorter": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz",
|
||||
|
@ -6434,6 +6496,16 @@
|
|||
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
|
||||
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
|
||||
},
|
||||
"node_modules/css-to-react-native": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
|
||||
"integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
|
||||
"dependencies": {
|
||||
"camelize": "^1.0.0",
|
||||
"css-color-keywords": "^1.0.0",
|
||||
"postcss-value-parser": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/css-tree": {
|
||||
"version": "1.0.0-alpha.37",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
|
||||
|
@ -6906,6 +6978,16 @@
|
|||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
||||
},
|
||||
"node_modules/dnd-core": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz",
|
||||
"integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==",
|
||||
"dependencies": {
|
||||
"@react-dnd/asap": "^5.0.1",
|
||||
"@react-dnd/invariant": "^4.0.1",
|
||||
"redux": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dns-packet": {
|
||||
"version": "5.6.1",
|
||||
"resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz",
|
||||
|
@ -8980,7 +9062,6 @@
|
|||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
|
@ -14375,6 +14456,17 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-accessible-treeview": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/react-accessible-treeview/-/react-accessible-treeview-2.8.3.tgz",
|
||||
"integrity": "sha512-taDTIYZ6p96/zIhJBUKvyGTXcInudatP/9fwKG0BW+VRf1PmU5hOT2FkDovDKzSwj2VSOj1PRx+E6ojhOA+2xA==",
|
||||
"peerDependencies": {
|
||||
"classnames": "^2.2.6",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-app-polyfill": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz",
|
||||
|
@ -14438,6 +14530,43 @@
|
|||
"node": ">= 12.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dnd": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz",
|
||||
"integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==",
|
||||
"dependencies": {
|
||||
"@react-dnd/invariant": "^4.0.1",
|
||||
"@react-dnd/shallowequal": "^4.0.1",
|
||||
"dnd-core": "^16.0.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"hoist-non-react-statics": "^3.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/hoist-non-react-statics": ">= 3.3.1",
|
||||
"@types/node": ">= 12",
|
||||
"@types/react": ">= 16",
|
||||
"react": ">= 16.14"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/hoist-non-react-statics": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-dnd-html5-backend": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz",
|
||||
"integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==",
|
||||
"dependencies": {
|
||||
"dnd-core": "^16.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||
|
@ -14671,6 +14800,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
|
||||
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.9.2"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect-metadata": {
|
||||
"version": "0.1.14",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz",
|
||||
|
@ -14953,6 +15090,69 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/rete": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/rete/-/rete-2.0.3.tgz",
|
||||
"integrity": "sha512-/xzcyEBhVXhMZVZHElnYaLKOmTEuwlnul9Wfjvxw5sdl/+6Nqn2nyqIaW4koefrFpIWZy9aitnjnP3zeCMVDuw==",
|
||||
"hasInstallScript": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rete-area-plugin": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rete-area-plugin/-/rete-area-plugin-2.0.2.tgz",
|
||||
"integrity": "sha512-pMRNRl5jNFwsEcaIWvaHgB9QV4CrqfGipEPpxPrbS1oQXezDJ18sbELU68WceJ534OMAcu/9XiN2VLpGbRWoog==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rete": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rete-connection-plugin": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rete-connection-plugin/-/rete-connection-plugin-2.0.1.tgz",
|
||||
"integrity": "sha512-KE1IcjeOQtHgkByODtWS5hgRJDGhR3Z9sZyJAEd7YMgI6o+KUIflcNjbkvhJvPeIAv6WlEAh7ZkwdLhF9bkr4w==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rete": "^2.0.1",
|
||||
"rete-area-plugin": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rete-react-plugin": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/rete-react-plugin/-/rete-react-plugin-2.0.5.tgz",
|
||||
"integrity": "sha512-xoui2+Mv6iqpRTxccAu3MZv3+l5LYk4AmtqGWEqlCIwZjplrsAoVeOLYq235spwf+vd3ujzapnycEzYF9aj3cA==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"usehooks-ts": "^2.9.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.6 || ^17 || ^18",
|
||||
"react-dom": "^16.8.6 || ^17 || ^18",
|
||||
"rete": "^2.0.1",
|
||||
"rete-area-plugin": "^2.0.0",
|
||||
"rete-render-utils": "^2.0.0",
|
||||
"styled-components": "^5.3.6 || ^6"
|
||||
}
|
||||
},
|
||||
"node_modules/rete-render-utils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rete-render-utils/-/rete-render-utils-2.0.2.tgz",
|
||||
"integrity": "sha512-f4kj+dFL5QrebOkjCdwi8htHteDFbKyqrVdFDToEUvGuGod1sdLeKxOPBOhwyYDB4Zxd3Cq84I93vD2etrTL9g==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rete": "^2.0.0",
|
||||
"rete-area-plugin": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
|
||||
|
@ -15535,8 +15735,7 @@
|
|||
"node_modules/shallowequal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
|
||||
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
|
||||
"peer": true
|
||||
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
|
@ -16137,6 +16336,70 @@
|
|||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-components": {
|
||||
"version": "6.1.8",
|
||||
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.8.tgz",
|
||||
"integrity": "sha512-PQ6Dn+QxlWyEGCKDS71NGsXoVLKfE1c3vApkvDYS5KAK+V8fNWGhbSUEo9Gg2iaID2tjLXegEW3bZDUGpofRWw==",
|
||||
"dependencies": {
|
||||
"@emotion/is-prop-valid": "1.2.1",
|
||||
"@emotion/unitless": "0.8.0",
|
||||
"@types/stylis": "4.2.0",
|
||||
"css-to-react-native": "3.2.0",
|
||||
"csstype": "3.1.2",
|
||||
"postcss": "8.4.31",
|
||||
"shallowequal": "1.1.0",
|
||||
"stylis": "4.3.1",
|
||||
"tslib": "2.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/styled-components"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">= 16.8.0",
|
||||
"react-dom": ">= 16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-components/node_modules/csstype": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
|
||||
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
|
||||
},
|
||||
"node_modules/styled-components/node_modules/postcss": {
|
||||
"version": "8.4.31",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.6",
|
||||
"picocolors": "^1.0.0",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/styled-components/node_modules/tslib": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||
},
|
||||
"node_modules/stylehacks": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
|
||||
|
@ -16152,6 +16415,11 @@
|
|||
"postcss": "^8.2.15"
|
||||
}
|
||||
},
|
||||
"node_modules/stylis": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz",
|
||||
"integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ=="
|
||||
},
|
||||
"node_modules/sucrase": {
|
||||
"version": "3.35.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||
|
@ -17104,6 +17372,20 @@
|
|||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/usehooks-ts": {
|
||||
"version": "2.16.0",
|
||||
"resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.16.0.tgz",
|
||||
"integrity": "sha512-bez95WqYujxp6hFdM/CpRDiVPirZPxlMzOH2QB8yopoKQMXpscyZoxOjpEdaxvV+CAWUDSM62cWnqHE0E/MZ7w==",
|
||||
"dependencies": {
|
||||
"lodash.debounce": "^4.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.15.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
|
@ -18164,11 +18446,30 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xml-formatter": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/xml-formatter/-/xml-formatter-3.6.2.tgz",
|
||||
"integrity": "sha512-enWhevZNOwffZFUhzl1WMcha8lFLZUgJ7NzFs5Ug4ZOFCoNheGYXz1J9Iz/e+cTn9rCkuT1GwTacz+YlmFHOGw==",
|
||||
"dependencies": {
|
||||
"xml-parser-xo": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/xml-name-validator": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
|
||||
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
|
||||
},
|
||||
"node_modules/xml-parser-xo": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/xml-parser-xo/-/xml-parser-xo-4.1.1.tgz",
|
||||
"integrity": "sha512-Ggf2y90+Y6e9IK5hoPuembVHJ03PhDSdhldEmgzbihzu9k0XBo0sfcFxaSi4W1PlUSSI1ok+MJ0JCXUn+U4Ilw==",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/xmlchars": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
|
||||
|
|
|
@ -44,7 +44,8 @@
|
|||
"typescript": "^4.9.5",
|
||||
"urdf-loader": "^0.12.1",
|
||||
"uuid": "^9.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
"web-vitals": "^2.1.4",
|
||||
"xml-formatter": "^3.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "react-scripts start",
|
||||
|
|
|
@ -26,6 +26,9 @@ declare global {
|
|||
interface String {
|
||||
isEmpty(): boolean;
|
||||
isNotEmpty(): boolean;
|
||||
replaceMany(searchValues: string[], replaceValue: string): string;
|
||||
isEqual(str: string): boolean;
|
||||
isEqualMany(str: string[]): boolean;
|
||||
}
|
||||
interface Map<K, V> {
|
||||
addValueOrMakeCallback(key: K, value: V, callBack: CallBackVoidFunction): void;
|
||||
|
@ -37,8 +40,8 @@ declare global {
|
|||
}
|
||||
}
|
||||
export const extensions = () => {
|
||||
ArrayExtensions();
|
||||
StringExtensions();
|
||||
ArrayExtensions();
|
||||
NumberExtensions();
|
||||
MapExtensions();
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-extend-native */
|
||||
export const StringExtensions = () => {
|
||||
if ("".isEmpty === undefined) {
|
||||
// eslint-disable-next-line no-extend-native
|
||||
|
@ -11,4 +12,28 @@ export const StringExtensions = () => {
|
|||
return this.length !== 0;
|
||||
};
|
||||
}
|
||||
if ("".replaceMany === undefined) {
|
||||
String.prototype.replaceMany = function (searchValues: string[], replaceValue: string) {
|
||||
let result = this as string;
|
||||
searchValues.forEach((el) => {
|
||||
result = result.replaceAll(el, replaceValue);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
}
|
||||
if ("".isEqual === undefined) {
|
||||
String.prototype.isEqual = function (str: string) {
|
||||
return this === str;
|
||||
};
|
||||
}
|
||||
if ("".isEqualMany === undefined) {
|
||||
String.prototype.isEqualMany = function (str: string[]) {
|
||||
for (const el of str) {
|
||||
if (el === this) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -105,6 +105,9 @@ export class Asset {
|
|||
centerMassY: string;
|
||||
@IsString()
|
||||
centerMassZ: string;
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
actions: string[];
|
||||
}
|
||||
|
||||
export class Physics {
|
||||
|
@ -116,13 +119,22 @@ export class Physics {
|
|||
|
||||
export class RobossemblerAssets {
|
||||
@ValidateNested()
|
||||
@Type(() => Asset)
|
||||
@Type(() => Asset, {
|
||||
discriminator: {
|
||||
property: "type",
|
||||
subTypes: [
|
||||
{ value: InstanceRgbCamera, name: InstanceType.RGB_CAMERA },
|
||||
{ value: SceneSimpleObject, name: InstanceType.SCENE_SIMPLE_OBJECT },
|
||||
],
|
||||
},
|
||||
keepDiscriminatorProperty: true,
|
||||
})
|
||||
assets: Asset[];
|
||||
|
||||
@IsArray()
|
||||
@Type(() => Instance, {
|
||||
discriminator: {
|
||||
property: "instanceType",
|
||||
property: "type",
|
||||
subTypes: [
|
||||
{ value: InstanceRgbCamera, name: InstanceType.RGB_CAMERA },
|
||||
{ value: SceneSimpleObject, name: InstanceType.SCENE_SIMPLE_OBJECT },
|
|
@ -35,11 +35,7 @@ import {
|
|||
} from "../../features/scene_manager/model/scene_assets";
|
||||
import { SceneMode } from "../../features/scene_manager/model/scene_view";
|
||||
import { throttle } from "../helper/throttle";
|
||||
import {
|
||||
InstanceRgbCamera,
|
||||
RobossemblerAssets,
|
||||
SceneSimpleObject,
|
||||
} from "../../features/scene_manager/model/robossembler_assets";
|
||||
import { Asset, InstanceRgbCamera, RobossemblerAssets, SceneSimpleObject } from "../model/robossembler_assets";
|
||||
import { CoreVector3 } from "../model/core_vector3";
|
||||
|
||||
export enum UserData {
|
||||
|
@ -157,6 +153,15 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
|
|||
}
|
||||
});
|
||||
}
|
||||
loadInstance(asset: Asset, loadCallback?: Function) {
|
||||
this.loader(
|
||||
asset.meshPath,
|
||||
loadCallback ? loadCallback : () => {},
|
||||
asset.name,
|
||||
new Vector3(Number(asset.posX), Number(asset.posY), Number(asset.posZ)),
|
||||
new Quaternion(0, 0, 0, 0)
|
||||
);
|
||||
}
|
||||
|
||||
setTransformMode(mode?: SceneMode) {
|
||||
switch (mode) {
|
||||
|
@ -283,18 +288,6 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
|
|||
floor.userData = {};
|
||||
floor.userData[UserData.cameraInitialization] = true;
|
||||
this.scene.add(floor);
|
||||
|
||||
const planeMesh = new Mesh(
|
||||
new PlaneGeometry(10, 10, 10, 10),
|
||||
new MeshBasicMaterial({ color: 0x808080, wireframe: true })
|
||||
);
|
||||
planeMesh.userData[UserData.selectedObject] = true;
|
||||
planeMesh.userData[UserData.objectForMagnetism] = true;
|
||||
planeMesh.rotation.x = -Math.PI / 2;
|
||||
this.makeCube(1);
|
||||
this.makeCube(2, new Vector3(20, 0, 10), "yellow");
|
||||
|
||||
this.scene.add(planeMesh);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -4,28 +4,19 @@ import {
|
|||
PipelineInstanceScreen,
|
||||
PipelineInstanceScreenPath,
|
||||
} from "../../features/pipeline_instance_main_screen/pipeline_instance_screen";
|
||||
import {
|
||||
SelectProjectScreen,
|
||||
SelectProjectScreenPath,
|
||||
} from "../../features/select_project/presentation/select_project";
|
||||
import {
|
||||
CreatePipelineScreen,
|
||||
CreatePipelineScreenPath,
|
||||
} from "../../features/create_pipeline/presentation/create_pipeline_screen";
|
||||
|
||||
import { CreateProjectScreen, CreateProjectScreenPath } from "../../features/create_project/create_project_screen";
|
||||
import {
|
||||
CreateTriggerScreenPath,
|
||||
TriggerScreen,
|
||||
} from "../../features/create_trigger/presentation/create_trigger_screen";
|
||||
import {
|
||||
CreateProcessScreen,
|
||||
CreateProcessScreenPath,
|
||||
} from "../../features/create_process/presentation/create_process_screen";
|
||||
import {
|
||||
CreateProjectInstancePath,
|
||||
CreateProjectInstanceScreen,
|
||||
} from "../../features/create_project_instance/create_project_instance";
|
||||
|
||||
import { SceneManger, SceneManagerPath } from "../../features/scene_manager/presentation/scene_manager";
|
||||
import {
|
||||
BehaviorTreeBuilderPath,
|
||||
BehaviorTreeBuilderScreen,
|
||||
} from "../../features/behavior_tree_builder/presentation/behavior_tree_builder_screen";
|
||||
import {
|
||||
StickObjectsMarkingScreen,
|
||||
StickObjectsMarkingScreenPath,
|
||||
} from "../../features/stick_objects_marking/stick_objects_marking_screen";
|
||||
import { DataSetScreen, DatasetsScreenPath } from "../../features/dataset/dataset_screen";
|
||||
|
||||
const idURL = ":id";
|
||||
|
||||
|
@ -38,32 +29,26 @@ export const router = createBrowserRouter([
|
|||
path: PipelineInstanceScreenPath + idURL,
|
||||
element: <PipelineInstanceScreen />,
|
||||
},
|
||||
{
|
||||
path: SelectProjectScreenPath,
|
||||
element: <SelectProjectScreen />,
|
||||
},
|
||||
{
|
||||
path: CreatePipelineScreenPath,
|
||||
element: <CreatePipelineScreen />,
|
||||
},
|
||||
|
||||
{
|
||||
path: CreateProjectScreenPath,
|
||||
element: <CreateProjectScreen />,
|
||||
},
|
||||
|
||||
{
|
||||
path: CreateTriggerScreenPath,
|
||||
element: <TriggerScreen />,
|
||||
},
|
||||
{
|
||||
path: CreateProcessScreenPath,
|
||||
element: <CreateProcessScreen />,
|
||||
},
|
||||
{
|
||||
path: CreateProjectInstancePath + idURL,
|
||||
element: <CreateProjectInstanceScreen />,
|
||||
},
|
||||
{
|
||||
path: SceneManagerPath + idURL,
|
||||
path: SceneManagerPath,
|
||||
element: <SceneManger />,
|
||||
},
|
||||
{
|
||||
path: BehaviorTreeBuilderPath,
|
||||
element: <BehaviorTreeBuilderScreen />,
|
||||
},
|
||||
{
|
||||
path: StickObjectsMarkingScreenPath,
|
||||
element: <StickObjectsMarkingScreen />,
|
||||
},
|
||||
{
|
||||
path: DatasetsScreenPath,
|
||||
element: <DataSetScreen />,
|
||||
},
|
||||
]);
|
||||
|
|
138
ui/src/core/ui/form_builder/form_builder.tsx
Normal file
138
ui/src/core/ui/form_builder/form_builder.tsx
Normal file
|
@ -0,0 +1,138 @@
|
|||
import * as React from "react";
|
||||
import { Input, Select, Button } from "antd";
|
||||
import { InputBuilderViewModel, InputType } from "./form_view_model";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { FormBuilderStore } from "./form_builder_store";
|
||||
import { extensions } from "../../extensions/extensions";
|
||||
import { FormBuilderValidationModel } from "../../../features/dataset/dataset_store";
|
||||
extensions();
|
||||
|
||||
export interface IFormBuilder {
|
||||
context: string;
|
||||
result: string;
|
||||
onChange: (change: FormBuilderValidationModel | undefined) => void;
|
||||
}
|
||||
|
||||
export const FormBuilder = observer((props: IFormBuilder) => {
|
||||
const [store] = React.useState(() => new FormBuilderStore());
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init(props.context, props.result);
|
||||
store.changerForm.on((event) => props.onChange(event));
|
||||
}, [store, props]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{store.isError ? (
|
||||
<>Error</>
|
||||
) : (
|
||||
<div>
|
||||
{store.formViewModel?.inputs.map((element) => {
|
||||
if (element.type.isEqual(InputType.ENUM)) {
|
||||
const values = element.values as string[];
|
||||
return (
|
||||
<>
|
||||
<div>{element.name}</div>
|
||||
|
||||
<Select
|
||||
defaultValue={element.defaultValue}
|
||||
style={{ width: 120 }}
|
||||
onChange={(e) => {
|
||||
store.changeTotalValue(element.id, e);
|
||||
}}
|
||||
options={values?.map((el) => {
|
||||
return { value: el };
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (element.type.isEqual(InputType.ARRAY)) {
|
||||
return (
|
||||
<div>
|
||||
<div style={{ fontSize: "large" }}>{element.name}</div>
|
||||
|
||||
{element.isOpen ? (
|
||||
<div>
|
||||
{element.totalValue instanceof Array
|
||||
? element.totalValue?.map((subArray, index) => {
|
||||
return (
|
||||
<>
|
||||
<div style={{ paddingLeft: "10px" }}>
|
||||
index: {index}
|
||||
<Button onClick={() => store.deleteTotalValueSubItem(element.id, index)}>
|
||||
Delete item
|
||||
</Button>
|
||||
</div>
|
||||
{subArray.map((subSubArrayItem: InputBuilderViewModel, subIndex: number) => {
|
||||
if (subSubArrayItem.type.isEqual(InputType.ENUM)) {
|
||||
return (
|
||||
<>
|
||||
<div>{subSubArrayItem.name}</div>
|
||||
|
||||
<Select
|
||||
defaultValue={subSubArrayItem.defaultValue}
|
||||
style={{ width: 120 }}
|
||||
onChange={(e) => {
|
||||
store.changeTotalSubValue(element.id, subIndex, e);
|
||||
}}
|
||||
options={subSubArrayItem.values?.map((el) => {
|
||||
return { value: el };
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (subSubArrayItem.type.isEqualMany([InputType.NUMBER, InputType.STRING]))
|
||||
return (
|
||||
<div style={{ width: "200px" }}>
|
||||
<div>{subSubArrayItem.name}</div>
|
||||
<Input
|
||||
onChange={(e) => {
|
||||
store.changeTotalSubValue(element.id, subIndex, e.target.value);
|
||||
}}
|
||||
defaultValue={subSubArrayItem.defaultValue}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return <>Error</>;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
onClick={() => {
|
||||
store.open(element.id);
|
||||
}}
|
||||
>
|
||||
+
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (element.type.isEqualMany([InputType.NUMBER, InputType.STRING]))
|
||||
return (
|
||||
<div style={{ width: "200px" }}>
|
||||
<div>{element.name}</div>
|
||||
<Input
|
||||
onChange={(e) => {
|
||||
store.changeTotalValue(element.id, e.target.value);
|
||||
}}
|
||||
defaultValue={element.defaultValue}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return <>Error</>;
|
||||
})}
|
||||
<Button onClick={() => store.saveForm()}>SAVE FORM</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
103
ui/src/core/ui/form_builder/form_builder_store.ts
Normal file
103
ui/src/core/ui/form_builder/form_builder_store.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
import { makeAutoObservable } from "mobx";
|
||||
import { FormViewModel } from "./form_view_model";
|
||||
import { TypedEvent } from "../../helper/typed_event";
|
||||
import { FormBuilderValidationModel } from "../../../features/dataset/dataset_store";
|
||||
|
||||
export class ChangerForm extends TypedEvent<FormBuilderValidationModel | undefined> {}
|
||||
|
||||
export class FormBuilderStore {
|
||||
isError = false;
|
||||
formViewModel?: FormViewModel;
|
||||
changerForm: ChangerForm;
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
this.changerForm = new ChangerForm();
|
||||
}
|
||||
|
||||
changeTotalSubValue(id: string, subIndex: number, value: string) {
|
||||
if (this.formViewModel?.inputs)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
} else {
|
||||
if (el.totalValue instanceof Array) {
|
||||
el.totalValue = el.totalValue.map((subElement) => {
|
||||
if (subElement instanceof Array) {
|
||||
subElement.map((subSubElement, i) => {
|
||||
if (subIndex !== i) {
|
||||
return subSubElement;
|
||||
}
|
||||
|
||||
subSubElement.totalValue = value;
|
||||
|
||||
return subSubElement;
|
||||
});
|
||||
}
|
||||
return subElement;
|
||||
});
|
||||
return el;
|
||||
}
|
||||
return el;
|
||||
}
|
||||
});
|
||||
this.changerForm.emit(this.formViewModel?.fromFormBuilderValidationModel());
|
||||
}
|
||||
|
||||
changeTotalValue(id: string, value: string) {
|
||||
if (this.formViewModel?.inputs)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
}
|
||||
el.totalValue = value;
|
||||
return el;
|
||||
});
|
||||
this.changerForm.emit(this.formViewModel?.fromFormBuilderValidationModel());
|
||||
}
|
||||
|
||||
deleteTotalValueSubItem(id: string, index: number): void {
|
||||
if (this.formViewModel?.inputs)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
} else {
|
||||
if (el.totalValue instanceof Array) {
|
||||
el.totalValue = el.totalValue.filter((_, i) => index !== i);
|
||||
return el;
|
||||
}
|
||||
return el;
|
||||
}
|
||||
});
|
||||
this.changerForm.emit(this.formViewModel?.fromFormBuilderValidationModel());
|
||||
}
|
||||
|
||||
saveForm(): void {
|
||||
console.log(this.formViewModel?.toResult());
|
||||
}
|
||||
|
||||
open = (id: string) => {
|
||||
if (this.formViewModel)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
}
|
||||
|
||||
el.isOpen = true;
|
||||
|
||||
if (!(el.totalValue instanceof Array)) {
|
||||
el.totalValue = [];
|
||||
}
|
||||
el.totalValue.push(el.values);
|
||||
return el;
|
||||
});
|
||||
};
|
||||
|
||||
init(context: string, result: string) {
|
||||
FormViewModel.fromString(result, context).fold(
|
||||
(model) => {
|
||||
this.formViewModel = model;
|
||||
},
|
||||
() => (this.isError = true)
|
||||
);
|
||||
}
|
||||
}
|
171
ui/src/core/ui/form_builder/form_view_model.ts
Normal file
171
ui/src/core/ui/form_builder/form_view_model.ts
Normal file
|
@ -0,0 +1,171 @@
|
|||
import { makeAutoObservable, observable } from "mobx";
|
||||
import { Result } from "../../helper/result";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { FormBuilderValidationModel } from "../../../features/dataset/dataset_store";
|
||||
|
||||
export enum InputType {
|
||||
NUMBER = "number",
|
||||
STRING = "string",
|
||||
ARRAY = "Array",
|
||||
ENUM = "Enum",
|
||||
}
|
||||
|
||||
export class InputBuilderViewModel {
|
||||
id: string;
|
||||
constructor(
|
||||
public name: string,
|
||||
public type: InputType,
|
||||
public defaultValue: string,
|
||||
public values: string[] | undefined | InputBuilderViewModel[] = undefined,
|
||||
public totalValue: any | undefined = undefined,
|
||||
public isOpen: boolean = false,
|
||||
public subType: string | undefined = undefined
|
||||
) {
|
||||
this.id = uuidv4();
|
||||
}
|
||||
static fromJSON(json: any) {
|
||||
return new InputBuilderViewModel(json.name, json.type, json.defaultValue, json.values, json.isOpen, json.id);
|
||||
}
|
||||
public toJson(): string {
|
||||
return JSON.stringify(this);
|
||||
}
|
||||
}
|
||||
|
||||
export const tagParse = new RegExp(/\${.*?}/gm);
|
||||
export const bracketParser = new RegExp(/<.*?>/gm);
|
||||
export const enumParser = new RegExp(/ENUM.*=..*?;/gm);
|
||||
export const enumBodyParse = new RegExp(/".*?;/gm);
|
||||
export const enumNameParse = new RegExp(/^(.*?)=/gm);
|
||||
export const typeBodyParse = new RegExp(/{.*?};/gms);
|
||||
export const typeNameParse = new RegExp(/type .*?{/gms);
|
||||
export const typeParse = new RegExp(/type.*?};/gms);
|
||||
|
||||
export class FormViewModel {
|
||||
@observable
|
||||
inputs: InputBuilderViewModel[];
|
||||
|
||||
constructor(inputs: InputBuilderViewModel[], public result: string, public context: string) {
|
||||
this.inputs = inputs;
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
public fromFormBuilderValidationModel() {
|
||||
console.log(this.toResult());
|
||||
return new FormBuilderValidationModel(
|
||||
this.context,
|
||||
this.result,
|
||||
this.inputs.map((el) => el.toJson()),
|
||||
this.toResult()
|
||||
);
|
||||
}
|
||||
public toResult() {
|
||||
let result = this.result;
|
||||
|
||||
this.inputs.forEach((element) => {
|
||||
let inputResult = element.totalValue ?? element.defaultValue;
|
||||
if (element.type.isEqualMany([InputType.STRING, InputType.ENUM])) {
|
||||
inputResult = `"${String(inputResult)}"`;
|
||||
}
|
||||
if (element.type.isEqual(InputType.NUMBER)) {
|
||||
inputResult = Number(inputResult);
|
||||
}
|
||||
if (element.type.isEqual(InputType.ARRAY)) {
|
||||
if (element.totalValue === undefined) {
|
||||
inputResult = "[]";
|
||||
} else {
|
||||
inputResult = [];
|
||||
// @ts-ignore
|
||||
element.totalValue.forEach((el) => {
|
||||
const objectUnion = {};
|
||||
if (el instanceof Array)
|
||||
el.forEach((subElement) => {
|
||||
let subResult = subElement.totalValue ?? subElement.defaultValue;
|
||||
if (element.type.isEqualMany([InputType.STRING, InputType.ENUM])) {
|
||||
subResult = `"${String(subResult)}"`;
|
||||
}
|
||||
if (element.type.isEqual(InputType.NUMBER)) {
|
||||
subResult = Number(subResult);
|
||||
}
|
||||
// @ts-ignore
|
||||
objectUnion[subElement.name] = subResult;
|
||||
});
|
||||
if (Object.keys(objectUnion).length !== 0) {
|
||||
inputResult.push(objectUnion);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (inputResult instanceof Array) inputResult = JSON.stringify(inputResult);
|
||||
result = result.replace(new RegExp("\\${" + element.name + ".*?}"), inputResult);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
static fromString(result: string, context: string): Result<void, FormViewModel> {
|
||||
try {
|
||||
const enums = new Map<string, string[]>();
|
||||
const types = new Map<string, InputBuilderViewModel[]>();
|
||||
|
||||
context.match(enumParser)?.forEach((el) => {
|
||||
const enumMatch = el.match(enumBodyParse)?.at(0);
|
||||
if (enumMatch !== undefined) {
|
||||
const EnumValue = enumMatch.slice(0, enumMatch.length - 2).split(",");
|
||||
const enumBody = EnumValue.map((el) => el.replaceAll('"', ""));
|
||||
const enumName = el.match(enumNameParse)?.at(0)?.split(" ").at(1);
|
||||
if (enumBody.isNotEmpty() && enumName) enums.set(enumName, enumBody);
|
||||
}
|
||||
});
|
||||
|
||||
context.match(typeParse)?.forEach((type) => {
|
||||
const matchTypeName = type.match(typeNameParse)?.at(0)?.split(" ").at(1);
|
||||
const typeBody = type.match(typeBodyParse)?.at(0);
|
||||
|
||||
if (typeBody && matchTypeName) types.set(matchTypeName, this.typeParse(typeBody, enums));
|
||||
});
|
||||
|
||||
return Result.ok(new FormViewModel(this.typeParse(result, enums, types), result, context));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return Result.error(undefined);
|
||||
}
|
||||
}
|
||||
static typeParse(
|
||||
result: string,
|
||||
enums: Map<string, string[]>,
|
||||
types: Map<string, InputBuilderViewModel[]> | undefined = undefined
|
||||
) {
|
||||
return result
|
||||
.match(tagParse)
|
||||
?.map((el) => {
|
||||
const inputArray = el.replaceMany(["$", "{", "}"], "").split(":");
|
||||
if (el.includes(InputType.ENUM)) {
|
||||
const enumName = inputArray.at(1)?.replaceMany([InputType.ENUM, "<", ">"], "");
|
||||
|
||||
if (enumName && enums.get(enumName)) {
|
||||
return new InputBuilderViewModel(inputArray[0], InputType.ENUM, inputArray[2], enums.get(enumName));
|
||||
}
|
||||
}
|
||||
if (el.includes(InputType.ARRAY) && types) {
|
||||
const name = inputArray.at(1)?.replaceMany(["Array<", ">"], "");
|
||||
|
||||
if (name) {
|
||||
return new InputBuilderViewModel(
|
||||
inputArray[0],
|
||||
InputType.ARRAY,
|
||||
inputArray[2],
|
||||
types.get(name),
|
||||
undefined,
|
||||
false,
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
if (el.includes(InputType.NUMBER)) {
|
||||
return new InputBuilderViewModel(inputArray[0], InputType.NUMBER, inputArray[2]);
|
||||
}
|
||||
if (el.includes(InputType.STRING)) {
|
||||
return new InputBuilderViewModel(inputArray[0], InputType.STRING, inputArray[2]);
|
||||
}
|
||||
return el;
|
||||
})
|
||||
.filter((el) => el !== undefined) as InputBuilderViewModel[];
|
||||
}
|
||||
}
|
33
ui/src/core/ui/form_builder/readme.md
Normal file
33
ui/src/core/ui/form_builder/readme.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# RESULT
|
||||
|
||||
```
|
||||
{
|
||||
"scene":{
|
||||
"objects": \${OBJECTS_SCENE:Array<OBJECTS_SCENE>:[]},
|
||||
},
|
||||
"camera_position":{
|
||||
"center_shell": [\${CENTER_SHELL_1:string:0}, \${COLISION_SHAPE:Enum<L>:"BOX"}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# CONTEXT
|
||||
|
||||
### хранит в себе type и enum для result
|
||||
|
||||
```
|
||||
ENUM T = "ObjectDetection","PoseEstimation";
|
||||
ENUM L = "POINT","SUN";
|
||||
|
||||
type MODELS = {
|
||||
"id": \${IMAGE_FORMAT:Enum<L>:"jpg"},,
|
||||
"name": \${NAME:string:""},
|
||||
"model": \${MODEL:string:"models/1.fbx"}
|
||||
};
|
||||
|
||||
type OBJECTS_SCENE = {
|
||||
"name": \${NAME:string:""},
|
||||
"collision_shape": \${COLISION_SHAPE:Enum<L>:"BOX"},
|
||||
"loc_xyz": [\${TEST123:string:"test123"}, \${LOC_XYZ_2:number:0}, \${LOC_XYZ_3:number:0}],
|
||||
};
|
||||
```
|
|
@ -2,13 +2,16 @@ import { ActivePipeline } from "../../../core/model/active_pipeline";
|
|||
import { HttpMethod, HttpRepository } from "../../../core/repository/http_repository";
|
||||
import { IProjectModel } from "../model/project_model";
|
||||
|
||||
export interface UUID {
|
||||
id: string;
|
||||
}
|
||||
export class ProjectRepository extends HttpRepository {
|
||||
async getAllProject() {
|
||||
return this._jsonRequest<IProjectModel[]>(HttpMethod.GET, "/project_instance");
|
||||
return this._jsonRequest<IProjectModel[]>(HttpMethod.GET, "/projects");
|
||||
}
|
||||
|
||||
async getActivePipeline() {
|
||||
return this._jsonRequest<ActivePipeline>(HttpMethod.GET, "/realtime");
|
||||
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}`);
|
||||
|
|
|
@ -2,7 +2,7 @@ import { PipelineModel } from "../../create_project/create_project_repository";
|
|||
|
||||
export interface IProjectModel {
|
||||
_id?: string;
|
||||
pipelines: [PipelineModel];
|
||||
rootDir: string;
|
||||
description: string;
|
||||
isActive?: boolean;
|
||||
}
|
||||
|
|
|
@ -3,19 +3,19 @@ import { AllProjectStore } from "./all_projects_store";
|
|||
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";
|
||||
import { CreateProjectScreenPath } from "../../create_project/create_project_screen";
|
||||
|
||||
export const AllProjectScreenPath = "/";
|
||||
export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
||||
const [allProjectStore] = React.useState(() => new AllProjectStore(new ProjectRepository()));
|
||||
const [store] = React.useState(() => new AllProjectStore(new ProjectRepository()));
|
||||
const navigate = useNavigate();
|
||||
|
||||
React.useEffect(() => {
|
||||
allProjectStore.init();
|
||||
}, [allProjectStore]);
|
||||
store.init();
|
||||
}, [store]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -23,35 +23,23 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
largeText={"Projects"}
|
||||
needBackButton={false}
|
||||
minText="create project?"
|
||||
path={SelectProjectScreenPath}
|
||||
isError={allProjectStore.isError}
|
||||
isLoading={allProjectStore.isLoading}
|
||||
path={CreateProjectScreenPath}
|
||||
isError={store.isError}
|
||||
isLoading={store.isLoading}
|
||||
children={
|
||||
<div>
|
||||
<h1>Projects</h1>
|
||||
<h5 style={{ backgroundColor: "ButtonShadow" }}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
navigate(PipelineInstanceScreenPath + allProjectStore.activePipeline?.projectId ?? "");
|
||||
}}
|
||||
>
|
||||
Project main panel
|
||||
</Button>
|
||||
{allProjectStore.activePipeline?.projectId ?? "loading"}
|
||||
</h5>
|
||||
{allProjectStore.projectsModels?.map((el) => {
|
||||
{store.projectsModels?.map((el) => {
|
||||
return (
|
||||
<div style={{ margin: "10px", backgroundColor: "Highlight" }}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
allProjectStore.setPipelineActive(el._id ?? "").then(() => {
|
||||
allProjectStore.init();
|
||||
navigate(PipelineInstanceScreenPath + el._id ?? "");
|
||||
});
|
||||
}}
|
||||
>
|
||||
set active project
|
||||
</Button>
|
||||
{el.isActive ? (
|
||||
<Button
|
||||
onClick={() => {
|
||||
navigate(`${PipelineInstanceScreenPath}${el._id}`);
|
||||
}}
|
||||
>
|
||||
instance screen
|
||||
</Button>
|
||||
) : null}
|
||||
<div style={{ margin: "10px", display: "contents" }}> {el.description}</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { ProjectRepository } from "../data/project_repository";
|
||||
import { ProjectRepository, UUID } from "../data/project_repository";
|
||||
import { IProjectModel } from "../model/project_model";
|
||||
import { SimpleErrorState } from "../../../core/store/base_store";
|
||||
import { ActivePipeline } from "../../../core/model/active_pipeline";
|
||||
|
@ -21,8 +21,8 @@ export class ProjectView {
|
|||
}
|
||||
export class AllProjectStore extends SimpleErrorState {
|
||||
projectsModels?: IProjectModel[];
|
||||
activeProjectId?: UUID;
|
||||
repository: ProjectRepository;
|
||||
activePipeline?: ActivePipeline;
|
||||
constructor(repository: ProjectRepository) {
|
||||
super();
|
||||
this.repository = repository;
|
||||
|
@ -31,18 +31,14 @@ export class AllProjectStore extends SimpleErrorState {
|
|||
async getProjects(): Promise<void> {
|
||||
await this.mapOk<IProjectModel[]>("projectsModels", this.repository.getAllProject());
|
||||
}
|
||||
|
||||
async getActiveProject(): Promise<void> {
|
||||
await this.mapOk<ActivePipeline>("activePipeline", this.repository.getActivePipeline());
|
||||
async getActiveProjectId(): Promise<void> {
|
||||
await this.mapOk<UUID>("activeProjectId", this.repository.getActivePipeline());
|
||||
}
|
||||
|
||||
async init() {
|
||||
await Promise.all([this.getProjects(), this.getActiveProject()]);
|
||||
await this.projectViewGenerate();
|
||||
}
|
||||
projectViewGenerate() {
|
||||
this.projectsModels = this.projectsModels?.filter((el) => el._id !== this.activePipeline?.projectId);
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -15,14 +15,19 @@ export class BtNodeView extends TypedEvent<BtDrawDragAndDropView> {}
|
|||
export class ReteObserver extends TypedEvent<any> {}
|
||||
export class BtBuilderModel {
|
||||
public static result = "";
|
||||
static fromReteScene(editor: NodeEditor<Schemes>, area: AreaPlugin<Schemes, AreaExtra>) {
|
||||
this.getFirstSequence(editor).map((sortedSequence) => {
|
||||
const firstNodeId = sortedSequence.getKeyFromValueIsExists(1) as string;
|
||||
this.findSequence(firstNodeId, editor, sortedSequence, 2);
|
||||
this.result += `<${this.getNodeLabelAtId(editor, firstNodeId)} id="${firstNodeId}">`;
|
||||
this.toXML(sortedSequence as Map<string, number>, editor, area, firstNodeId);
|
||||
this.result += `</${this.getNodeLabelAtId(editor, firstNodeId)}>`;
|
||||
});
|
||||
static fromReteScene(editor: NodeEditor<Schemes>, area: AreaPlugin<Schemes, AreaExtra>): Result<string, string> {
|
||||
try {
|
||||
this.getFirstSequence(editor).map((sortedSequence) => {
|
||||
const firstNodeId = sortedSequence.getKeyFromValueIsExists(1) as string;
|
||||
this.findSequence(firstNodeId, editor, sortedSequence, 2);
|
||||
this.result += `<${this.getNodeLabelAtId(editor, firstNodeId)} id="${firstNodeId}">`;
|
||||
this.toXML(sortedSequence as Map<string, number>, editor, area, firstNodeId);
|
||||
this.result += `</${this.getNodeLabelAtId(editor, firstNodeId)}>`;
|
||||
});
|
||||
return Result.ok(this.result);
|
||||
} catch (error) {
|
||||
return Result.error("BtBuilderModel fromReteScene error");
|
||||
}
|
||||
}
|
||||
public static getNodeLabelAtId(editor: NodeEditor<Schemes>, id: string) {
|
||||
return editor.getNode(id).label;
|
||||
|
|
|
@ -26,13 +26,15 @@ const skills = {
|
|||
],
|
||||
};
|
||||
export const behaviorTreeBuilderStore = new BehaviorTreeBuilderStore();
|
||||
|
||||
export const BehaviorTreeBuilderPath = "/behavior/tree/";
|
||||
export function BehaviorTreeBuilderScreen() {
|
||||
const store = behaviorTreeBuilderStore;
|
||||
const [ref] = useRete(createEditor);
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
// @ts-expect-error
|
||||
console.log(ref.current.clientHeight);
|
||||
|
||||
store.dragZoneSetOffset(
|
||||
// @ts-expect-error
|
||||
|
@ -40,9 +42,9 @@ export function BehaviorTreeBuilderScreen() {
|
|||
// @ts-expect-error
|
||||
ref.current.offsetLeft,
|
||||
// @ts-expect-error
|
||||
Number(String(ref.current.style.width).replaceAll("px", "")),
|
||||
ref.current.clientWidth,
|
||||
// @ts-expect-error
|
||||
Number(String(ref.current.style.height).replaceAll("px", ""))
|
||||
ref.current.clientHeight
|
||||
);
|
||||
|
||||
return () => {
|
||||
|
@ -60,28 +62,6 @@ export function BehaviorTreeBuilderScreen() {
|
|||
}}
|
||||
>
|
||||
<CoreText text="Robossembler studio" type={CoreTextType.header} />
|
||||
<Button
|
||||
onClick={() => {
|
||||
store.copyBt();
|
||||
}}
|
||||
>
|
||||
copy
|
||||
</Button>
|
||||
<Input onChange={(e) => store.setBt(e.target.value)} placeholder="bt JSON" />
|
||||
<Button
|
||||
onClick={() => {
|
||||
store.copyBt();
|
||||
}}
|
||||
>
|
||||
update value
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
store.validateBt();
|
||||
}}
|
||||
>
|
||||
validate
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ display: "flex" }}>
|
||||
<div
|
||||
|
@ -95,9 +75,11 @@ export function BehaviorTreeBuilderScreen() {
|
|||
style={{
|
||||
width: "1782px",
|
||||
height: "70px",
|
||||
background: "#244366",
|
||||
background: "rgb(27 45 66)",
|
||||
}}
|
||||
></div>
|
||||
>
|
||||
<Button onClick={() => store.saveBt()}>SAVE</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: "flex" }}>
|
||||
<div
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import xmlFormat from "xml-formatter";
|
||||
|
||||
import { HttpError } from "../../../core/repository/http_repository";
|
||||
import { UiErrorState } from "../../../core/store/base_store";
|
||||
|
@ -16,6 +17,9 @@ interface I2DArea {
|
|||
}
|
||||
|
||||
export class BehaviorTreeBuilderStore extends UiErrorState<HttpError> {
|
||||
saveBt(): void {
|
||||
this.reteNode?.emit("200");
|
||||
}
|
||||
validateBt() {}
|
||||
area?: I2DArea;
|
||||
btNodeView: BtNodeView = new BtNodeView();
|
||||
|
@ -95,9 +99,31 @@ export class BehaviorTreeBuilderStore extends UiErrorState<HttpError> {
|
|||
setBt(value: string): void {
|
||||
JSON.parse(value) as BtNodeView[];
|
||||
}
|
||||
bt(editor: NodeEditor<Schemes>, area: AreaPlugin<Schemes, AreaExtra>) {
|
||||
console.log(BtBuilderModel.fromReteScene(editor, area));
|
||||
}
|
||||
bt = async (editor: NodeEditor<Schemes>, area: AreaPlugin<Schemes, AreaExtra>) => {
|
||||
(await BtBuilderModel.fromReteScene(editor, area)).fold(
|
||||
(s) => {
|
||||
console.log(
|
||||
xmlFormat(`<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root main_tree_to_execute="Main">
|
||||
<BehaviorTree ID="Main">
|
||||
${s}
|
||||
</BehaviorTree>
|
||||
|
||||
<TreeNodesModel>
|
||||
<Action ID="RbsBtAction">
|
||||
<input_port name="do" />
|
||||
<input_port name="command" />
|
||||
<input_port name="server_name" />
|
||||
<input_port name="server_timeout" />
|
||||
</Action>
|
||||
</TreeNodesModel>
|
||||
|
||||
</root>`)
|
||||
);
|
||||
},
|
||||
(_) => _
|
||||
);
|
||||
};
|
||||
copyBt = () => {
|
||||
this.reteNode?.emit("200");
|
||||
};
|
||||
|
@ -110,7 +136,7 @@ export class BehaviorTreeBuilderStore extends UiErrorState<HttpError> {
|
|||
this.canRun = false;
|
||||
setTimeout(() => {
|
||||
this.canRun = true;
|
||||
}, 1000);
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
drawSkillCheck(x: number, y: number, name: string) {
|
||||
|
|
|
@ -29,7 +29,7 @@ export async function createEditor(container: HTMLElement) {
|
|||
node.addInput("a", new ClassicPreset.Input(socket));
|
||||
await editor.addNode(node);
|
||||
await areaContainer.translate(node.id, { x, y });
|
||||
}, 50);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
observer.on(() => {
|
||||
|
|
|
@ -104,13 +104,7 @@ export function SequenceNode<Scheme extends ClassicScheme>(props: Props<Scheme>)
|
|||
|
||||
return (
|
||||
<NodeStyles selected={selected} width={width} height={height} styles={props.styles} data-testid="node">
|
||||
<div
|
||||
onPointerDown={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
className="title"
|
||||
data-testid="title"
|
||||
>
|
||||
<div onPointerDown={(e) => {}} className="title" data-testid="title">
|
||||
{label}
|
||||
<div>{id}</div>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
import { HttpMethod, HttpRepository } from "../../../core/repository/http_repository";
|
||||
import { ITriggerModel } from "../../../core/model/trigger_model";
|
||||
import { Result } from "../../../core/helper/result";
|
||||
import { IProcess } from "../../create_process/model/process_model";
|
||||
import { PipelineModelDataBase } from "../model/pipeline_model";
|
||||
|
||||
export class CreatePipelineRepository extends HttpRepository {
|
||||
async savePipeline(model: PipelineModelDataBase): Promise<Result<Error, any>> {
|
||||
return await this._jsonRequest(HttpMethod.POST, `/pipeline`, model);
|
||||
}
|
||||
async getTriggers(page = 1): Promise<Result<Error, ITriggerModel[]>> {
|
||||
return await this._jsonRequest(HttpMethod.GET, `/trigger?${page}`);
|
||||
}
|
||||
|
||||
async getProcessed(page = 1): Promise<Result<Error, IProcess[]>> {
|
||||
return await this._jsonRequest<IProcess[]>(HttpMethod.GET, `/process?${page}`);
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
export interface IColor {
|
||||
color: string;
|
||||
}
|
||||
|
||||
export interface PipelineModelDataBase {
|
||||
process: string;
|
||||
trigger: string;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
import * as React from "react";
|
||||
import { Row, Button } from "antd";
|
||||
import { LoadPage } from "../../../core/ui/pages/load_page";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Icon, List } from "../../../core/ui/list/list";
|
||||
import { CreateTriggerScreenPath } from "../../create_trigger/presentation/create_trigger_screen";
|
||||
import { CreateProcessScreenPath } from "../../create_process/presentation/create_process_screen";
|
||||
import { CreatePipelineStore } from "./create_pipeline_store";
|
||||
import { CreatePipelineRepository } from "../data/create_pipeline_repository";
|
||||
|
||||
export const CreatePipelineScreenPath = "/create_pipeline";
|
||||
|
||||
export const CreatePipelineScreen: React.FunctionComponent = observer(() => {
|
||||
const [createPipelineStore] = React.useState(() => new CreatePipelineStore(new CreatePipelineRepository()));
|
||||
|
||||
React.useEffect(() => {}, [createPipelineStore]);
|
||||
return (
|
||||
<>
|
||||
<LoadPage
|
||||
largeText={"Create pipeline"}
|
||||
isError={createPipelineStore.isError}
|
||||
isLoading={createPipelineStore.isLoading}
|
||||
children={
|
||||
<>
|
||||
<Row>
|
||||
<List
|
||||
headers={"process"}
|
||||
link={{ path: CreateProcessScreenPath, text: "create process" }}
|
||||
values={createPipelineStore.processModels.map((el) => {
|
||||
return { text: el.description, id: el._id };
|
||||
})}
|
||||
onClick={(e) => createPipelineStore.addProcess(e.text, e.id!)}
|
||||
icon={Icon.add}
|
||||
/>
|
||||
<div style={{ flexGrow: "1" }}>
|
||||
<Button onClick={() => createPipelineStore.createPipeline()}>Save result</Button>
|
||||
<List
|
||||
headers="new pipeline"
|
||||
values={createPipelineStore.pipelineViewModels}
|
||||
icon={Icon.delete}
|
||||
onClick={(_e, index) => {
|
||||
createPipelineStore.filterPipelineViewModel(index);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<List
|
||||
headers="triggers"
|
||||
link={{ path: CreateTriggerScreenPath, text: "create trigger" }}
|
||||
values={createPipelineStore.triggersModels.map((el) => {
|
||||
return { text: el.description, id: el._id };
|
||||
})}
|
||||
onClick={(e) => createPipelineStore.addTrigger(e.text, e.id!)}
|
||||
icon={Icon.add}
|
||||
/>
|
||||
</Row>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
|
@ -1,99 +0,0 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { CreatePipelineRepository } from "../data/create_pipeline_repository";
|
||||
import { ITriggerModel } from "../../../core/model/trigger_model";
|
||||
import { IProcess } from "../../create_process/model/process_model";
|
||||
import { message } from "antd";
|
||||
import { SimpleErrorState } from "../../../core/store/base_store";
|
||||
|
||||
enum Type {
|
||||
PROCESS,
|
||||
TRIGGER,
|
||||
}
|
||||
export interface UnionView {
|
||||
text: string;
|
||||
color: string;
|
||||
type: Type;
|
||||
uuid?: string;
|
||||
}
|
||||
|
||||
export class CreatePipelineStore extends SimpleErrorState {
|
||||
repository: CreatePipelineRepository;
|
||||
triggersModels: ITriggerModel[] = [];
|
||||
processModels: IProcess[] = [];
|
||||
pipelineViewModels: UnionView[] = [];
|
||||
|
||||
constructor(repository: CreatePipelineRepository) {
|
||||
super();
|
||||
this.repository = repository;
|
||||
makeAutoObservable(this);
|
||||
this.init();
|
||||
}
|
||||
private init() {
|
||||
this.loadTriggers();
|
||||
this.loadProcess();
|
||||
}
|
||||
|
||||
filterPipelineViewModel(index: number): void {
|
||||
this.pipelineViewModels = this.pipelineViewModels.filter((_el, i) => i !== index);
|
||||
}
|
||||
addTrigger(e: string, id: string): void {
|
||||
const lastElement = this.pipelineViewModels.lastElement();
|
||||
if (this.pipelineViewModels.length === 2) {
|
||||
return;
|
||||
}
|
||||
if (lastElement !== undefined) {
|
||||
if (lastElement.type !== Type.PROCESS) {
|
||||
message.error("Need process");
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.pipelineViewModels.push({
|
||||
uuid: id,
|
||||
text: e,
|
||||
color: "blanchedalmond",
|
||||
type: Type.TRIGGER,
|
||||
});
|
||||
}
|
||||
addProcess(e: string, id: string): void {
|
||||
const lastElement = this.pipelineViewModels.lastElement();
|
||||
if (this.pipelineViewModels.length === 2) {
|
||||
return;
|
||||
}
|
||||
if (lastElement !== undefined) {
|
||||
if (lastElement.type !== Type.TRIGGER) {
|
||||
message.error("Need trigger");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.pipelineViewModels.push({
|
||||
uuid: id,
|
||||
text: e,
|
||||
color: "activeborder",
|
||||
type: Type.PROCESS,
|
||||
});
|
||||
}
|
||||
|
||||
async createPipeline(): Promise<void> {
|
||||
if (this.pipelineViewModels.isEmpty()) {
|
||||
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;
|
||||
|
||||
this.repository.savePipeline({
|
||||
process: processId,
|
||||
trigger: triggerId,
|
||||
});
|
||||
}
|
||||
|
||||
async loadProcess() {
|
||||
this.mapOk("processModels", this.repository.getProcessed());
|
||||
}
|
||||
|
||||
async loadTriggers() {
|
||||
this.mapOk("triggersModels", this.repository.getTriggers());
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
import { HttpMethod, HttpRepository } from "../../../core/repository/http_repository";
|
||||
import { IProcess } from "../model/process_model";
|
||||
|
||||
export class ProcessRepository extends HttpRepository {
|
||||
async save(model: IProcess): Promise<void> {
|
||||
await this._jsonRequest(HttpMethod.POST, "/process", model);
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
import { DatabaseModel } from "../../../core/model/database_model";
|
||||
|
||||
export interface IProcess extends DatabaseModel {
|
||||
description: string;
|
||||
type: EXEC_TYPE | string;
|
||||
command: string;
|
||||
isGenerating: boolean;
|
||||
isLocaleCode: boolean;
|
||||
issueType: IssueType | string;
|
||||
timeout?: number;
|
||||
commit?: string | undefined;
|
||||
}
|
||||
|
||||
export enum EXEC_TYPE {
|
||||
SPAWN = "SPAWN",
|
||||
EXEC = "EXEC",
|
||||
}
|
||||
export enum IssueType {
|
||||
WARNING = "WARNING",
|
||||
ERROR = "ERROR",
|
||||
}
|
||||
export const processModelMock: IProcess = {
|
||||
description: "",
|
||||
type: EXEC_TYPE.SPAWN,
|
||||
command: "",
|
||||
isGenerating: true,
|
||||
isLocaleCode: true,
|
||||
issueType: IssueType.WARNING,
|
||||
};
|
|
@ -1,65 +0,0 @@
|
|||
import * as React from "react";
|
||||
import { processStore } from "./logic/process_store";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { SubmitButton, Input, ResetButton, Form, Radio, Switch } from "formik-antd";
|
||||
import { Formik } from "formik";
|
||||
import { Row, Col } from "antd";
|
||||
import { EXEC_TYPE, IssueType, processModelMock } from "../model/process_model";
|
||||
export const CreateProcessScreenPath = "/create/process";
|
||||
export const CreateProcessScreen = observer(() => {
|
||||
return (
|
||||
<div>
|
||||
<div style={{ marginTop: 80 }}>
|
||||
<Formik
|
||||
initialValues={processModelMock}
|
||||
onSubmit={async (values, actions) => {
|
||||
await processStore.saveResult(values);
|
||||
actions.setSubmitting(false);
|
||||
actions.resetForm();
|
||||
}}
|
||||
validate={(values) => {
|
||||
if (!values.command) {
|
||||
return { command: "required" };
|
||||
}
|
||||
if (!values.description) {
|
||||
return { description: "required" };
|
||||
}
|
||||
return {};
|
||||
}}
|
||||
render={() => (
|
||||
<Form>
|
||||
<div
|
||||
style={{
|
||||
background: "white",
|
||||
flex: 1,
|
||||
padding: 40,
|
||||
width: "400px",
|
||||
}}
|
||||
>
|
||||
<Input name="description" placeholder="Description" />
|
||||
|
||||
<Input name="command" placeholder="Command process" />
|
||||
|
||||
<Radio.Group name="type" options={Object.values(EXEC_TYPE)} />
|
||||
|
||||
<Radio.Group name="issueType" options={Object.values(IssueType)} />
|
||||
|
||||
<Col style={{ marginTop: 20, justifyContent: "center" }}>
|
||||
<Switch name="isGenerating" checkedChildren="is generating" unCheckedChildren="is generating" />
|
||||
<Switch name="isLocalCode" checkedChildren="is local code" unCheckedChildren="is local code" />
|
||||
</Col>
|
||||
|
||||
<Row style={{ marginTop: 20, justifyContent: "center" }}>
|
||||
<Col>
|
||||
<ResetButton>Reset</ResetButton>
|
||||
<SubmitButton>Submit</SubmitButton>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -1,16 +0,0 @@
|
|||
import { makeAutoObservable } from "mobx";
|
||||
import { ProcessRepository } from "../../data/process_repostiory";
|
||||
import { IProcess } from "../../model/process_model";
|
||||
|
||||
class ProcessStore {
|
||||
repository: ProcessRepository;
|
||||
constructor(repository: ProcessRepository) {
|
||||
this.repository = repository;
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
async saveResult(model: IProcess) {
|
||||
await this.repository.save(model);
|
||||
}
|
||||
}
|
||||
|
||||
export const processStore = new ProcessStore(new ProcessRepository());
|
|
@ -2,19 +2,19 @@ import { Result } from "../../core/helper/result";
|
|||
import { DatabaseModel } from "../../core/model/database_model";
|
||||
import { ITriggerModel } from "../../core/model/trigger_model";
|
||||
import { HttpMethod, HttpRepository } from "../../core/repository/http_repository";
|
||||
import { IProcess } from "../create_process/model/process_model";
|
||||
import { UUID } from "../all_projects/data/project_repository";
|
||||
import { ICreateProjectViewModel } from "./project_model";
|
||||
|
||||
export interface PipelineModel extends DatabaseModel {
|
||||
process: IProcess;
|
||||
process: any;
|
||||
trigger: ITriggerModel;
|
||||
}
|
||||
|
||||
export class CreateProjectRepository extends HttpRepository {
|
||||
async getAllPipelines(page = 1): Promise<Result<Error, PipelineModel[]>> {
|
||||
return await this._jsonRequest<PipelineModel[]>(HttpMethod.GET, "/pipeline");
|
||||
async saveProject(model: ICreateProjectViewModel): Promise<Result<Error, UUID>> {
|
||||
return await this._jsonRequest<UUID>(HttpMethod.POST, "/projects", model);
|
||||
}
|
||||
async saveProject(model: ICreateProjectViewModel): Promise<Result<Error, void>> {
|
||||
return await this._jsonRequest<void>(HttpMethod.POST, "/project", model);
|
||||
async setProjectRootFile(file: File, projectId: string) {
|
||||
return await this._formDataRequest(HttpMethod.POST, `/projects/upload?id=${projectId}`, file);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,85 +1,46 @@
|
|||
import * as React from "react";
|
||||
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 { Col, Row, Input, Button, Upload } from "antd";
|
||||
import type { UploadProps } from "antd";
|
||||
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()));
|
||||
const [store] = React.useState(() => new CreateProjectStore(new CreateProjectRepository()));
|
||||
|
||||
React.useEffect(() => {
|
||||
createProjectStore.init();
|
||||
}, [createProjectStore]);
|
||||
store.init();
|
||||
}, [store]);
|
||||
return (
|
||||
<>
|
||||
<MainPage
|
||||
path={CreatePipelineScreenPath}
|
||||
path={""}
|
||||
largeText={"Create project"}
|
||||
minText={"add new pipelines?"}
|
||||
isLoading={createProjectStore.isLoading}
|
||||
isError={createProjectStore.isError}
|
||||
isLoading={store.isLoading}
|
||||
isError={store.isError}
|
||||
children={
|
||||
<Row>
|
||||
<Col>
|
||||
<>Pipelines</>
|
||||
{createProjectStore.pipelineModels?.map((el) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: "ActiveBorder",
|
||||
margin: "10px",
|
||||
width: "400px",
|
||||
<Row>
|
||||
<Col>
|
||||
<Row>
|
||||
<Input
|
||||
style={{ width: "250px" }}
|
||||
onChange={(e) => store.setDescriptionToNewProject(e.target.value)}
|
||||
placeholder="project description"
|
||||
/>
|
||||
<Upload
|
||||
onChange={(e) => {
|
||||
store.file = e.file.originFileObj;
|
||||
}}
|
||||
>
|
||||
<div>{el.process.description}</div>
|
||||
<div>{el.trigger.description}</div>
|
||||
<AddIcon
|
||||
style={{
|
||||
width: "50px",
|
||||
cursor: "pointer",
|
||||
height: "50px",
|
||||
marginRight: "40px",
|
||||
}}
|
||||
onClick={() => {
|
||||
createProjectStore.addPipeline(el);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Col>
|
||||
<Col>
|
||||
<Row>
|
||||
<Input
|
||||
style={{ width: "250px" }}
|
||||
onChange={(e) => createProjectStore.setDescriptionToNewProject(e.target.value)}
|
||||
placeholder="project description"
|
||||
/>
|
||||
|
||||
<Button onClick={() => createProjectStore.saveProject()}>save</Button>
|
||||
</Row>
|
||||
|
||||
{createProjectStore.newProjectViews.map((el, index) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: "ActiveBorder",
|
||||
margin: "10px",
|
||||
width: "400px",
|
||||
}}
|
||||
>
|
||||
<div>{el.process.description}</div>
|
||||
<div>{el.trigger.description}</div>
|
||||
<div>{index + 1}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Col>
|
||||
<Button>Click to Upload</Button>
|
||||
</Upload>
|
||||
<Button onClick={() => store.saveProject()}>save</Button>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Row>
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -1,30 +1,20 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { CreateProjectRepository, PipelineModel } from "./create_project_repository";
|
||||
import { CreateProjectRepository } from "./create_project_repository";
|
||||
import { message } from "antd";
|
||||
import { SimpleErrorState } from "../../core/store/base_store";
|
||||
|
||||
export class CreateProjectStore extends SimpleErrorState {
|
||||
repository: CreateProjectRepository;
|
||||
|
||||
pipelineModels?: PipelineModel[];
|
||||
newProjectDescription: string = "";
|
||||
newProjectViews: PipelineModel[] = [];
|
||||
file?: File;
|
||||
|
||||
constructor(repository: CreateProjectRepository) {
|
||||
super();
|
||||
this.repository = repository;
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
async init() {
|
||||
await this.loadPipelines();
|
||||
}
|
||||
async addPipeline(model: PipelineModel) {
|
||||
this.newProjectViews.push(model);
|
||||
}
|
||||
|
||||
async loadPipelines() {
|
||||
this.mapOk("pipelineModels", this.repository.getAllPipelines());
|
||||
}
|
||||
async init() {}
|
||||
|
||||
setDescriptionToNewProject(value: string): void {
|
||||
this.newProjectDescription = value;
|
||||
|
@ -35,27 +25,27 @@ export class CreateProjectStore extends SimpleErrorState {
|
|||
message.error("project description is not empty");
|
||||
return;
|
||||
}
|
||||
if (this.newProjectViews.isEmpty()) {
|
||||
message.error("project view is not empty");
|
||||
if (this.file === undefined) {
|
||||
message.error("upload file");
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
const result = await this.repository.saveProject({
|
||||
description: this.newProjectDescription,
|
||||
pipelines: this.newProjectViews.map((el) => el._id ?? ""),
|
||||
});
|
||||
|
||||
this.newProjectDescription = "";
|
||||
this.newProjectViews = [];
|
||||
this.isLoading = false;
|
||||
|
||||
result.fold(
|
||||
(_s) => {
|
||||
message.success("save");
|
||||
(
|
||||
await this.repository.saveProject({
|
||||
description: this.newProjectDescription,
|
||||
})
|
||||
).fold(
|
||||
(uuid) => {
|
||||
this.newProjectDescription = "";
|
||||
this.isLoading = false;
|
||||
this.repository.setProjectRootFile(this.file as File, uuid.id);
|
||||
},
|
||||
(_e) => {
|
||||
(_) => {
|
||||
this.isError = true;
|
||||
}
|
||||
);
|
||||
|
||||
//
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
export interface ICreateProjectViewModel {
|
||||
pipelines: string[];
|
||||
|
||||
description: string;
|
||||
}
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
import * as React from "react";
|
||||
import { CreateProjectInstanceStore } from "./create_project_instance_store";
|
||||
import { CreateProjectInstanceRepository } from "./create_project_instance_repository";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Upload, Button } from "antd";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { Input } from "antd";
|
||||
|
||||
export const CreateProjectInstancePath = "/create/project/instance/";
|
||||
|
||||
export const CreateProjectInstanceScreen = observer(() => {
|
||||
const [createProjectInstanceStore] = React.useState(
|
||||
() => new CreateProjectInstanceStore(new CreateProjectInstanceRepository())
|
||||
);
|
||||
const id = useParams().id;
|
||||
const navigate = useNavigate();
|
||||
|
||||
React.useEffect(() => {
|
||||
createProjectInstanceStore.init(navigate, id as string);
|
||||
}, [id, createProjectInstanceStore, navigate]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>project description</h1>
|
||||
<Input onChange={(e) => createProjectInstanceStore.setProjectDescription(e.target.value)}></Input>
|
||||
<h1>root entity</h1>
|
||||
<Upload
|
||||
onChange={(e) => {
|
||||
createProjectInstanceStore.file = e.file.originFileObj;
|
||||
}}
|
||||
>
|
||||
<Button>Upload root entity</Button>
|
||||
</Upload>
|
||||
<Button onClick={() => createProjectInstanceStore.saveInstance()}>Save</Button>
|
||||
</>
|
||||
);
|
||||
});
|
|
@ -1,16 +0,0 @@
|
|||
import { HttpMethod, HttpRepository } from "../../core/repository/http_repository";
|
||||
import { NewProjectModel } from "./new_project_model";
|
||||
|
||||
export class CreateProjectInstanceRepository extends HttpRepository {
|
||||
async setProjectRootFile(file: File) {
|
||||
return await this._formDataRequest(HttpMethod.POST, "/project_instance/upload", file);
|
||||
}
|
||||
|
||||
async createNewProject(project: NewProjectModel) {
|
||||
return await this._jsonRequest(HttpMethod.POST, "/project_instance", project);
|
||||
}
|
||||
|
||||
async setActiveProject(id: string) {
|
||||
return await this._jsonRequest(HttpMethod.POST, `/project_instance/set/active/project?id=${id}`);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
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";
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import { NewProjectModel } from "./new_project_model";
|
||||
|
||||
export class CreateProjectInstanceStore extends SimpleErrorState {
|
||||
newProjectModel: NewProjectModel;
|
||||
repository: CreateProjectInstanceRepository;
|
||||
file?: File;
|
||||
navigate?: NavigateFunction;
|
||||
constructor(repository: CreateProjectInstanceRepository) {
|
||||
super();
|
||||
this.repository = repository;
|
||||
makeAutoObservable(this);
|
||||
this.newProjectModel = NewProjectModel.empty();
|
||||
}
|
||||
|
||||
setProjectDescription(value: string): void {
|
||||
this.newProjectModel.description = value;
|
||||
}
|
||||
init(navigate: NavigateFunction, projectId: string) {
|
||||
this.navigate = navigate;
|
||||
this.newProjectModel.project = projectId;
|
||||
}
|
||||
async saveInstance(): Promise<void> {
|
||||
if (this.file === undefined) {
|
||||
message.error("Need upload file");
|
||||
} else {
|
||||
if (this.newProjectModel.isValid()) {
|
||||
await this.repository.createNewProject(this.newProjectModel);
|
||||
await this.repository.setProjectRootFile(this.file);
|
||||
if (this.navigate !== undefined) this.navigate("/");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
export class NewProjectModel {
|
||||
project: string;
|
||||
description: string;
|
||||
constructor(project: string, description: string) {
|
||||
this.project = project;
|
||||
this.description = description;
|
||||
}
|
||||
static empty() {
|
||||
return new NewProjectModel("", "");
|
||||
}
|
||||
isValid(): boolean {
|
||||
return this.project.isNotEmpty() && this.description.isNotEmpty();
|
||||
}
|
||||
messages() {
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
import { HttpMethod, HttpRepository } from "../../../core/repository/http_repository";
|
||||
import { ITriggerModel } from "../../../core/model/trigger_model";
|
||||
|
||||
export class TriggerRepository extends HttpRepository {
|
||||
public async save(model: ITriggerModel) {
|
||||
return await this._jsonRequest(HttpMethod.POST, "/trigger", model);
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
import { TriggerType } from "../../../core/model/trigger_model";
|
||||
|
||||
export interface ITriggerViewValueModel {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface TriggerViewModel extends ITriggerViewValueModel {
|
||||
id: string;
|
||||
type: TriggerType;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
import * as React from "react";
|
||||
import Editor from "@monaco-editor/react";
|
||||
import { Button } from "antd";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { CallBackStringVoidFunction } from "../../../../core/extensions/extensions";
|
||||
|
||||
interface ICodeTriggerFormProps {
|
||||
codeTriggerValue: string;
|
||||
clearTriggerCode: VoidFunction;
|
||||
saveCode: VoidFunction;
|
||||
writeNewTrigger: CallBackStringVoidFunction;
|
||||
}
|
||||
|
||||
export const CodeTriggerForm: React.FunctionComponent<ICodeTriggerFormProps> = observer(
|
||||
(props: ICodeTriggerFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<div style={{ width: "100%", backgroundColor: "black", height: "1px" }} />
|
||||
|
||||
<Editor
|
||||
height="40vh"
|
||||
defaultLanguage="javascript"
|
||||
value={props.codeTriggerValue}
|
||||
onChange={(v) => {
|
||||
props.writeNewTrigger(v ?? "");
|
||||
}}
|
||||
onValidate={(_m) => {}}
|
||||
/>
|
||||
|
||||
<div style={{ width: "100%", backgroundColor: "black", height: "1px" }} />
|
||||
<div style={{ height: "10px" }} />
|
||||
|
||||
<Button onClick={() => props.saveCode()} style={{ marginLeft: "10px", marginRight: "10px" }}>
|
||||
Save code
|
||||
</Button>
|
||||
|
||||
<Button onClick={() => props.clearTriggerCode()}>Reset code</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -1,51 +0,0 @@
|
|||
import * as React from "react";
|
||||
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 { TriggerType } from "../../../../core/model/trigger_model";
|
||||
import { validateRequired } from "../../../../core/helper/validate";
|
||||
export interface IFileTriggerFormProps {
|
||||
pushTrigger: (value: string, type: TriggerType) => void;
|
||||
}
|
||||
export const FileTriggerForm: React.FunctionComponent<IFileTriggerFormProps> = observer(
|
||||
(props: IFileTriggerFormProps) => {
|
||||
return (
|
||||
<>
|
||||
<div style={{ marginTop: 80 }}>
|
||||
<Formik
|
||||
initialValues={{
|
||||
value: "",
|
||||
}}
|
||||
onSubmit={(values, actions) => {
|
||||
props.pushTrigger(values.value, TriggerType.FILE);
|
||||
actions.setSubmitting(false);
|
||||
actions.resetForm();
|
||||
}}
|
||||
validate={(values) => {
|
||||
if (values.value.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return {};
|
||||
}}
|
||||
render={() => (
|
||||
<Form>
|
||||
<div style={{ background: "white", flex: 1, padding: 40 }}>
|
||||
<FormItem name="value" required={true} validate={validateRequired}>
|
||||
<Input name="value" placeholder="regExp file" />
|
||||
</FormItem>
|
||||
<Row style={{ marginTop: 60 }}>
|
||||
<Col offset={8}>
|
||||
<ResetButton>Reset</ResetButton>
|
||||
<SubmitButton>Submit</SubmitButton>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -1,75 +0,0 @@
|
|||
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 { 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 Bottom = observer((props: { triggers: TriggerViewModel[]; callBack: CallBackStringVoidFunction }) => {
|
||||
return (
|
||||
<Col>
|
||||
{props.triggers.map((el) => {
|
||||
return (
|
||||
<Row
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{el.value}
|
||||
<DeleteIcon onClick={() => props.callBack(el.id)} />
|
||||
</Row>
|
||||
);
|
||||
})}
|
||||
</Col>
|
||||
);
|
||||
});
|
||||
export const CreateTriggerScreenPath = "/create/trigger";
|
||||
|
||||
export const TriggerScreen: React.FunctionComponent = observer(() => {
|
||||
const [triggerStore] = React.useState(() => new TriggerStore(new TriggerRepository()));
|
||||
return (
|
||||
<>
|
||||
<main>
|
||||
{!triggerStore.isLoading ? (
|
||||
<>
|
||||
<Row style={{ justifyItems: "center", alignItems: "center" }}>
|
||||
<div style={{ height: "37px" }}>
|
||||
<Switch checked={triggerStore.getTriggerType()} onChange={() => triggerStore.setTriggerType()} />
|
||||
</div>
|
||||
<Title level={2}>Trigger editor: {triggerStore.getTriggerDescription()}</Title>
|
||||
<div style={{ width: "10px" }}></div>
|
||||
<Button onClick={() => triggerStore.saveResult()}>Save result</Button>
|
||||
</Row>
|
||||
<Input placeholder="trigger description" onChange={() => triggerStore.changeTriggerDescription} />
|
||||
{triggerStore.getTriggerType() ? (
|
||||
<>
|
||||
<FileTriggerForm pushTrigger={triggerStore.pushTrigger} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<CodeTriggerForm
|
||||
codeTriggerValue={triggerStore.codeTriggerValue}
|
||||
clearTriggerCode={triggerStore.clearTriggerCode}
|
||||
saveCode={triggerStore.saveCode}
|
||||
writeNewTrigger={triggerStore.writeNewTrigger}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Bottom triggers={triggerStore.triggers} callBack={triggerStore.deleteItem} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Loader />
|
||||
</>
|
||||
)}
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
});
|
|
@ -1,84 +0,0 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
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 { SimpleErrorState } from "../../../core/store/base_store";
|
||||
|
||||
export class TriggerStore extends SimpleErrorState {
|
||||
constructor(repository: TriggerRepository) {
|
||||
super();
|
||||
this.triggerType = TriggerType.FILE;
|
||||
this.repository = repository;
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
triggerDescription: string = "";
|
||||
triggerType: TriggerType;
|
||||
codeTriggerValue = "";
|
||||
triggers: TriggerViewModel[] = [];
|
||||
repository: TriggerRepository;
|
||||
|
||||
changeTriggerDescription(value: string): void {
|
||||
this.triggerDescription = value;
|
||||
}
|
||||
|
||||
deleteItem(id: string): void {
|
||||
this.triggers = this.triggers.filter((el) => el.id !== id);
|
||||
}
|
||||
|
||||
getTriggerType = (): boolean => {
|
||||
return this.triggerType === TriggerType.FILE;
|
||||
};
|
||||
setTriggerType = (): void => {
|
||||
this.triggers = [];
|
||||
if (this.triggerType === TriggerType.FILE) {
|
||||
this.triggerType = TriggerType.PROCESS;
|
||||
return;
|
||||
}
|
||||
this.triggerType = TriggerType.FILE;
|
||||
};
|
||||
getTriggerDescription = (): string => {
|
||||
return this.triggerType === TriggerType.FILE ? TriggerType.FILE : TriggerType.PROCESS;
|
||||
};
|
||||
pushTrigger = (value: string, type: TriggerType): void => {
|
||||
this.triggers.push({
|
||||
value: value,
|
||||
id: uuidv4(),
|
||||
type: type,
|
||||
});
|
||||
};
|
||||
|
||||
writeNewTrigger(v: string | undefined): void {
|
||||
if (v === undefined) {
|
||||
throw new Error("Editor Value is undefined");
|
||||
}
|
||||
this.codeTriggerValue = v;
|
||||
}
|
||||
clearTriggerCode(): void {
|
||||
this.codeTriggerValue = "";
|
||||
}
|
||||
saveCode(): void {
|
||||
if (this.codeTriggerValue !== "") {
|
||||
this.triggers.push({
|
||||
id: uuidv4(),
|
||||
value: this.codeTriggerValue,
|
||||
type: TriggerType.PROCESS,
|
||||
});
|
||||
|
||||
this.codeTriggerValue = "";
|
||||
}
|
||||
}
|
||||
async saveResult(): Promise<void> {
|
||||
await this.httpHelper(
|
||||
this.repository.save({
|
||||
type: this.getTriggerDescription(),
|
||||
description: this.triggerDescription,
|
||||
value: this.triggers.map((el) => {
|
||||
return el.value;
|
||||
}),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
export const triggerStore = new TriggerStore(new TriggerRepository());
|
75
ui/src/features/dataset/dataset_form_mock.ts
Normal file
75
ui/src/features/dataset/dataset_form_mock.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
export const datasetTypes = ["Object Detection - YOLOv8", "Pose Estimation - DOPE"];
|
||||
|
||||
export const datasetFormMockResult = `{
|
||||
"typedataset": \${typedataset:Enum<T>:"ObjectDetection"},
|
||||
"dataset_path": \${ПУТЬ ДАТАСЕТА:string:""},
|
||||
"models":\${models:Array<MODELS>:[]},
|
||||
"models_randomization":{
|
||||
"loc_range_low": [\${LOC_RANGE_LOW_1:number:-1}, \${LOC_RANGE_LOW_2:number:-1},/\${LOC_RANGE_LOW_3:number:0}],
|
||||
"loc_range_high": [\${LOC_RANGE_HIGH_1:number:1}, \${LOC_RANGE_HIGH_2:number:1},/\${LOC_RANGE_HIGH_3:number:2}]
|
||||
},
|
||||
"scene":{
|
||||
"objects": \${OBJECTS_SCENE:Array<OBJECTS_SCENE>:[]},
|
||||
"lights": \${LIGHTS:Array<LIGHTS>:[]},
|
||||
},
|
||||
"camera_position":{
|
||||
"center_shell": [\${CENTER_SHELL_1:number:0}, \${CENTER_SHELL_2:number:0}, \${CENTER_SHELL_3:number:0}],
|
||||
"radius_range": [\${RADIUS_RANGE_1:number:0.4}, \${RADIUS_RANGE_2:number:1.4}],
|
||||
"elevation_range": [\${ELEVATION_RANGE_1:number:10}, \${ELEVATION_RANGE_2:number:90}]
|
||||
},
|
||||
"generation":{
|
||||
"n_cam_pose": \${N_CAM_POSE:number:5},
|
||||
"n_sample_on_pose": \${N_SAMPLE_ON_POSE:number:3},
|
||||
"n_series": \${N_SERIES:number:100},
|
||||
"image_format": \${image_format:Enum<F>:"jpg"},
|
||||
"image_size_wh": [\${IMAGE_SIZE_WH_1:number:640}, \${IMAGE_SIZE_WH_2:number:480}]
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const datasetFormMockContext = `
|
||||
ENUM T = "ObjectDetection","PoseEstimation";
|
||||
ENUM L = "POINT","SUN";
|
||||
ENUM F = "JPEG","PNG";
|
||||
ENUM COLLISION_SHAPE = "SHAPE","COLLISION";
|
||||
|
||||
type MODELS = {
|
||||
"id": \${ID:number:1},
|
||||
"name": \${NAME:string:""},
|
||||
"model": \${MODEL:string:"models/1.fbx"}
|
||||
};
|
||||
type OBJECTS_SCENE = {
|
||||
"name": \${NAME:string:""},
|
||||
"collision_shape": \${collision_shape:Enum<COLLISION_SHAPE>:"BOX"},
|
||||
"loc_xyz": [\${LOC_XYZ_1:number:0}, \${LOC_XYZ_2:number:0}, \${LOC_XYZ_3:number:0}],
|
||||
"rot_euler": [\${ROT_EULER_1:number:0},\${ROT_EULER_2:number:0}, \${ROT_EULER_3:number:0}],
|
||||
"material_randomization": {
|
||||
"specular": [\${SPECULAR_1:number:0}, \${SPECULAR_2:number:1}],
|
||||
"roughness": [\${ROUGHNESS_1:number:0}, \${ROUGHNESS_2:number:1}],
|
||||
"metallic": [\${METALLIC_1:number:0}, \${METALLIC_2:number:1}],
|
||||
"base_color": [
|
||||
[
|
||||
\${BASE_COLOR_1:number:0},
|
||||
\${BASE_COLOR_2:number:0},
|
||||
\${BASE_COLOR_3:number:0},
|
||||
\${BASE_COLOR_4:number:1}
|
||||
],
|
||||
[
|
||||
\${BASE_COLOR_5:number:1},
|
||||
\${BASE_COLOR_6:number:1},
|
||||
\${BASE_COLOR_7:number:1},
|
||||
\${BASE_COLOR_8:number:1}
|
||||
]
|
||||
]
|
||||
}
|
||||
};
|
||||
type LIGHTS = {
|
||||
"id": \${ID:number:1},
|
||||
"type": \${type:Enum<L>:"POINT"},
|
||||
"loc_xyz": [\${LOC_XYZ_1:number:5}, \${LOC_XYZ_2:number:5}, \${LOC_XYZ_3:number:5}],
|
||||
"rot_euler": [\${ROT_EULER_1:number:-0.06}, \${ROT_EULER_2:number:0.61}, \${ROT_EULER_3:number:-0.19}],
|
||||
"color_range_low": [\${COLOR_RANGE_LOW_1:number:0.5}, \${COLOR_RANGE_LOW_2:number:0.5}, \${COLOR_RANGE_LOW_3:number:0.5}],
|
||||
"color_range_high":[\${COLOR_RANGE_HIGH_1:number:1}, \${COLOR_RANGE_HIGH_2:number:1}, $\{COLOR_RANGE_HIGH_3:number:1}],
|
||||
"energy_range":[\${ENERGY_RANGE_1:number:400},\${ENERGY_RANGE_2:number:900}]
|
||||
};
|
||||
`;
|
25
ui/src/features/dataset/dataset_model.ts
Normal file
25
ui/src/features/dataset/dataset_model.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { InputBuilderViewModel } from "../../core/ui/form_builder/form_view_model";
|
||||
|
||||
export interface Dataset {
|
||||
name: string;
|
||||
local_path: string;
|
||||
dataSetObjects: string[];
|
||||
unixDate: number;
|
||||
formBuilder: FormBuilder;
|
||||
}
|
||||
|
||||
export interface FormBuilder {
|
||||
result: string;
|
||||
context: string;
|
||||
form: InputBuilderViewModel[];
|
||||
}
|
||||
|
||||
export interface Assets {
|
||||
assets: Asset[];
|
||||
}
|
||||
|
||||
export interface Asset {
|
||||
name: string;
|
||||
mesh: string;
|
||||
image: string;
|
||||
}
|
16
ui/src/features/dataset/dataset_repository.ts
Normal file
16
ui/src/features/dataset/dataset_repository.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { Result } from "../../core/helper/result";
|
||||
import { HttpError, HttpMethod, HttpRepository } from "../../core/repository/http_repository";
|
||||
import { Assets, Dataset } from "./dataset_model";
|
||||
import { DataSetModel, IDatasetModel } from "./dataset_store";
|
||||
|
||||
export class DataSetRepository extends HttpRepository {
|
||||
getAssetsActiveProject = async (): Promise<Result<HttpError, Assets>> => {
|
||||
return this._jsonRequest<Assets>(HttpMethod.GET, "/projects/assets");
|
||||
};
|
||||
saveDataSet = async (model: DataSetModel) => {
|
||||
return this._jsonRequest<Dataset>(HttpMethod.POST, "/datasets", model);
|
||||
};
|
||||
getDatasetsActiveProject = async (): Promise<Result<HttpError, IDatasetModel[]>> => {
|
||||
return this._jsonRequest(HttpMethod.GET, "/datasets");
|
||||
};
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue