deleted unnecessary files

added new features
This commit is contained in:
IDONTSUDO 2024-04-09 16:31:25 +03:00
parent dffc73c30f
commit 6840402b1f
119 changed files with 1835 additions and 1522 deletions

BIN
.DS_Store vendored

Binary file not shown.

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
p.py

View file

@ -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);

View file

@ -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) });
}
);
}

View file

@ -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());

View file

@ -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,
});

View file

@ -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 {

View file

@ -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];
}
}

View file

@ -1,3 +1,4 @@
export enum StaticFiles {
robossembler_assets = "robossembler_assets.json",
assets = "/assets/assets.json",
}

View file

@ -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();

View file

@ -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(

View file

@ -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;

View file

@ -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>;

View file

@ -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");
}

View 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);
}
};
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 {}

View file

@ -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: {

View file

@ -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()

View file

@ -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()

View file

@ -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,

View 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,
});
}
}

View file

@ -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";

View 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);
}
}

View file

@ -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}]
// }
// }

View file

@ -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 }));
});
};
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}
};
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
};
}

View file

@ -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 }));
}
}

View file

@ -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`
)
);
})
);
}
}

View file

@ -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();

View file

@ -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));
}
}
}

View file

@ -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/'`
)
)
)
);
}
}

View file

@ -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,
},

View file

@ -1,9 +1,6 @@
import { IsMongoId, IsOptional, IsString } from "class-validator";
export class ProjectInstanceValidationModel {
@IsMongoId()
public project: string;
@IsString()
public description: string;

View file

@ -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(),
});
}
}

View file

@ -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();

View file

@ -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[] = [
{

View file

@ -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>;

View file

@ -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
View file

@ -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",

View file

@ -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",

View file

@ -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();
};

View file

@ -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;
};
}
};

View file

@ -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 },

View file

@ -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() {

View file

@ -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 />,
},
]);

View 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>
);
});

View 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)
);
}
}

View 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[];
}
}

View 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}],
};
```

View file

@ -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}`);

View file

@ -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;
}

View file

@ -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>
);

View file

@ -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));
}

View file

@ -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;

View file

@ -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

View file

@ -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) {

View file

@ -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(() => {

View file

@ -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>

View file

@ -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}`);
}
}

View file

@ -1,8 +0,0 @@
export interface IColor {
color: string;
}
export interface PipelineModelDataBase {
process: string;
trigger: string;
}

View file

@ -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>
</>
}
/>
</>
);
});

View file

@ -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());
}
}

View file

@ -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);
}
}

View file

@ -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,
};

View file

@ -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>
);
});

View file

@ -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());

View file

@ -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);
}
}

View 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>
}
/>

View file

@ -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;
}
);
//
}
}

View file

@ -1,5 +1,3 @@
export interface ICreateProjectViewModel {
pipelines: string[];
description: string;
}

View file

@ -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>
</>
);
});

View file

@ -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}`);
}
}

View file

@ -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("/");
}
}
}
}

View file

@ -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 "";
}
}

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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>
</>
);
}
);

View file

@ -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>
</>
);
}
);

View file

@ -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>
</>
);
});

View file

@ -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());

View 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}]
};
`;

View 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;
}

View 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