alexander
This commit is contained in:
parent
cf75b4220a
commit
7063e93c75
94 changed files with 1201 additions and 24490 deletions
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
|
@ -23,5 +23,11 @@
|
|||
"typedataset",
|
||||
"URDF",
|
||||
"usecases"
|
||||
]
|
||||
],
|
||||
"files.exclude": {
|
||||
"**/.git": false,
|
||||
"**/.svn": false,
|
||||
"**/.hg": false,
|
||||
"**/CVS": false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ export PYTHON_BLENDER="/путь_к_директории_с_файлами_из/
|
|||
export PYTHON_BLENDER_PROC="/путь_к_генератору_датасетов_/renderBOPdataset.py"
|
||||
export PYTHON_EDUCATION="absolute_path/webp/education.py"
|
||||
export PYTHON_ROBOT_BUILDER="/путь_к_генератору_датасетов_/robot_builder.py"
|
||||
|
||||
export GET_INTERFACES="/путь_к_директории_WEB_P/get_interfaces.py"
|
||||
```
|
||||
## Запуск сервера
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ module.exports = {
|
|||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn", // or "error"
|
||||
"warn",
|
||||
{
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
|
|
3
server/.gitignore
vendored
3
server/.gitignore
vendored
|
@ -8,4 +8,5 @@ coverage
|
|||
build/
|
||||
model_create.ts
|
||||
public
|
||||
p.ts
|
||||
p.ts
|
||||
package-lock.json
|
6159
server/package-lock.json
generated
6159
server/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -106,6 +106,7 @@ export class App extends TypedEvent<ServerStatus> {
|
|||
await result.fold(
|
||||
async (_s) => {
|
||||
await new CheckAndCreateStaticFilesFolderUseCase().call();
|
||||
|
||||
// await new SetLastActivePipelineToRealTimeServiceScenario().call();
|
||||
},
|
||||
async (_e) => {
|
||||
|
|
|
@ -6,14 +6,20 @@ import { extensions } from "../extensions/extensions";
|
|||
import { Routes } from "../interfaces/router";
|
||||
import { ScenesPresentation } from "../../features/scenes/scenes_presentation";
|
||||
import { CalculationsInstancesPresentation } from "../../features/calculations_instance/calculations_instance_presentation";
|
||||
import { DigitalTwinsInstancePresentation } from "../../features/digital_twins_instance/digital_twins_instance_presentation";
|
||||
import { DigitalTwinsTemplatePresentation } from "../../features/digital_twins_template/digital_twins_template_presentation";
|
||||
import { TopicsPresentation } from "../../features/topics/topics_presentation";
|
||||
|
||||
extensions();
|
||||
|
||||
export const httpRoutes: Routes[] = [
|
||||
new ProjectsPresentation(),
|
||||
new DatasetsPresentation(),
|
||||
new ScenesPresentation(),
|
||||
new BehaviorTreesPresentation(),
|
||||
new CalculationsTemplatePresentation(),
|
||||
new ScenesPresentation(),
|
||||
new CalculationsInstancesPresentation(),
|
||||
new DigitalTwinsTemplatePresentation(),
|
||||
new DigitalTwinsInstancePresentation(),
|
||||
new TopicsPresentation(),
|
||||
].map((el) => el.call());
|
||||
|
|
5
server/src/core/models/instance.ts
Normal file
5
server/src/core/models/instance.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export interface Instance {
|
||||
instanceName: string;
|
||||
path: string;
|
||||
instancePath: string;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { Trigger } from "../../features/_triggers/models/trigger_database_model";
|
||||
import { EXEC_TYPE } from "./exec_error_model";
|
||||
|
||||
export interface Trigger {}
|
||||
export interface IPipeline {
|
||||
process: IProcess;
|
||||
trigger?: Trigger;
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
export enum StaticFiles {
|
||||
export enum StaticFilesProject {
|
||||
robossembler_assets = "robossembler_assets.json",
|
||||
assets = "/assets/assets.json",
|
||||
parts = "/assets/parts.json",
|
||||
robots = "/robots/",
|
||||
scenes = "/scenes/",
|
||||
behaviorTrees = "behavior_trees",
|
||||
process = "/process/",
|
||||
}
|
||||
|
||||
export enum StaticFilesServer {
|
||||
process = "/process/",
|
||||
digitalTwins = "/digital_twins/",
|
||||
}
|
||||
|
|
15
server/src/core/scenarios/create_intance_scenario.ts
Normal file
15
server/src/core/scenarios/create_intance_scenario.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { CallbackStrategyWithValidationModel, ResponseBase } from "../controllers/http_controller";
|
||||
import { Instance } from "../models/instance";
|
||||
import { CreateDataBaseModelUseCase } from "../usecases/create_database_model_usecase";
|
||||
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||
|
||||
export abstract class CreateInstanceScenario<V extends Instance> extends CallbackStrategyWithValidationModel<V> {
|
||||
abstract validationModel: V;
|
||||
abstract databaseModel: any;
|
||||
call = async (model: V): ResponseBase => {
|
||||
model.instancePath = `${model.path}/${model.instanceName}`;
|
||||
return (await new CreateFolderUseCase().call(model.instancePath)).map(
|
||||
async () => await new CreateDataBaseModelUseCase(this.databaseModel).call(model)
|
||||
);
|
||||
};
|
||||
}
|
22
server/src/core/scenarios/create_template_scenario.ts
Normal file
22
server/src/core/scenarios/create_template_scenario.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { App } from "../controllers/app";
|
||||
import { CallbackStrategyWithValidationModel, ResponseBase } from "../controllers/http_controller";
|
||||
import { StaticFilesServer } from "../models/static_files";
|
||||
import { CreateDataBaseModelUseCase } from "../usecases/create_database_model_usecase";
|
||||
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||
|
||||
interface IModel {
|
||||
path: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export abstract class CreateTemplateScenario<V extends IModel> extends CallbackStrategyWithValidationModel<V> {
|
||||
validationModel: V;
|
||||
abstract databaseModel: any;
|
||||
abstract path: string;
|
||||
call = async (model: V): ResponseBase => {
|
||||
model.path = App.staticFilesStoreDir() + StaticFilesServer.process + model.name;
|
||||
return (await new CreateFolderUseCase().call(model.path)).map(() => {
|
||||
return new CreateDataBaseModelUseCase(this.databaseModel).call(model);
|
||||
});
|
||||
};
|
||||
}
|
20
server/src/core/scenarios/delete_instance_scenario.ts
Normal file
20
server/src/core/scenarios/delete_instance_scenario.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { CallbackStrategyWithIdQuery, ResponseBase } from "../controllers/http_controller";
|
||||
import { Instance } from "../models/instance";
|
||||
import { DeleteDataBaseModelUseCase } from "../usecases/delete_database_model_usecase";
|
||||
import { DeleteRecursiveFolderUseCase } from "../usecases/delete_recursive_folder_usecase";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../usecases/read_by_id_database_model_usecase";
|
||||
import { CoreValidation } from "../validations/core_validation";
|
||||
import { MongoIdValidation } from "../validations/mongo_id_validation";
|
||||
|
||||
|
||||
|
||||
export abstract class DeleteInstanceScenario<D extends Instance> extends CallbackStrategyWithIdQuery {
|
||||
abstract databaseModel: any;
|
||||
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||
call = async (id: string): ResponseBase =>
|
||||
(await new ReadByIdDataBaseModelUseCase<D>(this.databaseModel).call(id)).map(async (model) => {
|
||||
return (await new DeleteRecursiveFolderUseCase().call(model.instancePath)).map(
|
||||
async () => await new DeleteDataBaseModelUseCase(this.databaseModel).call(id)
|
||||
);
|
||||
});
|
||||
}
|
20
server/src/core/scenarios/delete_template_scenario.ts
Normal file
20
server/src/core/scenarios/delete_template_scenario.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { CalculationsTemplateValidationModel } from "../../features/calculations_templates/models/calculations_template_validation_model";
|
||||
import { CallbackStrategyWithIdQuery, ResponseBase } from "../controllers/http_controller";
|
||||
import { DeleteDataBaseModelUseCase } from "../usecases/delete_database_model_usecase";
|
||||
import { DeleteRecursiveFolderUseCase } from "../usecases/delete_recursive_folder_usecase";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../usecases/read_by_id_database_model_usecase";
|
||||
import { CoreValidation } from "../validations/core_validation";
|
||||
import { MongoIdValidation } from "../validations/mongo_id_validation";
|
||||
|
||||
export abstract class DeleteTemplateScenario extends CallbackStrategyWithIdQuery {
|
||||
abstract databaseModel: any;
|
||||
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||
call = async (id: string): ResponseBase =>
|
||||
(await new ReadByIdDataBaseModelUseCase<CalculationsTemplateValidationModel>(this.databaseModel).call(id)).map(
|
||||
async (model) => {
|
||||
return (await new DeleteRecursiveFolderUseCase().call(model.path)).map(
|
||||
async () => await new DeleteDataBaseModelUseCase(this.databaseModel).call(id)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
|
||||
import { pipelineRealTimeService } from "../../features/_realtime/realtime_presentation";
|
||||
|
||||
import { IProjectModel, ProjectDBModel } from "../../features/projects/models/project_model_database_model";
|
||||
import { App } from "../controllers/app";
|
||||
import { PipelineRealTimeService } from "../services/pipeline_real_time_service";
|
||||
import { CreateFolderUseCase } from "../usecases/create_folder_usecase";
|
||||
import { SearchOneDataBaseModelUseCase } from "../usecases/search_database_model_usecase";
|
||||
|
||||
export const pipelineRealTimeService = new PipelineRealTimeService();
|
||||
|
||||
|
||||
export class SetLastActivePipelineToRealTimeServiceScenario {
|
||||
call = async (): Promise<void> => {
|
||||
return (
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { FilesChangeNotifierService, IHashesCache } from "./files_change_notifier_service";
|
||||
import { IPipeline } from "../models/process_model";
|
||||
import { IPipeline, Trigger } from "../models/process_model";
|
||||
import { ExecutorProgramService } from "./executor_program_service";
|
||||
import { EXEC_EVENT, ExecError, SpawnError } from "../models/exec_error_model";
|
||||
import { TypedEvent } from "../helpers/typed_event";
|
||||
|
@ -7,8 +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";
|
||||
|
||||
|
||||
export interface Iteration {
|
||||
hashes: IHashesCache | null;
|
||||
pipeline: IPipeline;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// @ts-nocheck
|
||||
import * as vm from "node:vm";
|
||||
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 } from "../models/process_model";
|
||||
|
||||
export class TriggerCallResult {
|
||||
results: Array<TriggerSuccessResult | TriggerErrorReport>;
|
||||
|
||||
|
|
|
@ -1,24 +1,19 @@
|
|||
import { App } from "../controllers/app";
|
||||
import { StaticFilesServer } from "../models/static_files";
|
||||
import { FileSystemRepository } from "../repository/file_system_repository";
|
||||
import { CreateFolderUseCase } from "./create_folder_usecase";
|
||||
|
||||
export class CheckAndCreateStaticFilesFolderUseCase {
|
||||
fileSystemRepository: FileSystemRepository;
|
||||
|
||||
constructor() {
|
||||
this.fileSystemRepository = new FileSystemRepository();
|
||||
}
|
||||
fileSystemRepository: FileSystemRepository = new FileSystemRepository();
|
||||
call = async (): Promise<void> => {
|
||||
Object.keys(StaticFilesServer).forEach(async (key) => {
|
||||
if (!(await this.fileSystemRepository.dirIsExists(App.staticFilesStoreDir() + key))) {
|
||||
await new CreateFolderUseCase().call(App.staticFilesStoreDir() + key);
|
||||
}
|
||||
});
|
||||
if (await this.fileSystemRepository.dirIsExists(App.staticFilesStoreDir())) {
|
||||
return;
|
||||
}
|
||||
const createFolderUseCase = await new CreateFolderUseCase().call(App.staticFilesStoreDir());
|
||||
|
||||
createFolderUseCase.fold(
|
||||
(_s) => {},
|
||||
(e) => {
|
||||
console.log(e);
|
||||
}
|
||||
);
|
||||
await new CreateFolderUseCase().call(App.staticFilesStoreDir());
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,15 +1,8 @@
|
|||
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { CreateDataBaseModelUseCase } from "../../../core/usecases/create_database_model_usecase";
|
||||
import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase";
|
||||
import { CreateInstanceScenario } from "../../../core/scenarios/create_intance_scenario";
|
||||
import { CalculationInstanceDBModel } from "../models/calculations_instance_database_model";
|
||||
import { CalculationInstanceValidationModel } from "../models/calculations_instance_validation_model";
|
||||
|
||||
export class CreateCalculationInstanceScenario extends CallbackStrategyWithValidationModel<CalculationInstanceValidationModel> {
|
||||
export class CreateCalculationInstanceScenario extends CreateInstanceScenario<CalculationInstanceValidationModel> {
|
||||
databaseModel = CalculationInstanceDBModel;
|
||||
validationModel: CalculationInstanceValidationModel = new CalculationInstanceValidationModel();
|
||||
call = async (model: CalculationInstanceValidationModel): ResponseBase => {
|
||||
model.instancePath = `${model.path}/${model.instanceName}`;
|
||||
return (await new CreateFolderUseCase().call(model.instancePath)).map(
|
||||
async () => await new CreateDataBaseModelUseCase(CalculationInstanceDBModel).call(model)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,21 +1,7 @@
|
|||
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { DeleteDataBaseModelUseCase } from "../../../core/usecases/delete_database_model_usecase";
|
||||
import { DeleteRecursiveFolderUseCase } from "../../../core/usecases/delete_recursive_folder_usecase";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { CoreValidation } from "../../../core/validations/core_validation";
|
||||
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||
import { CalculationsTemplateDBModel } from "../../calculations_templates/models/calculations_template_database_model";
|
||||
import { DeleteInstanceScenario } from "../../../core/scenarios/delete_instance_scenario";
|
||||
import { CalculationInstanceDBModel } from "../models/calculations_instance_database_model";
|
||||
import { CalculationInstanceValidationModel } from "../models/calculations_instance_validation_model";
|
||||
|
||||
export class DeleteCalculationsInstanceScenario extends CallbackStrategyWithIdQuery {
|
||||
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||
call = async (id: string): ResponseBase =>
|
||||
(
|
||||
await new ReadByIdDataBaseModelUseCase<CalculationInstanceValidationModel>(CalculationInstanceDBModel).call(id)
|
||||
).map(async (model) => {
|
||||
return (await new DeleteRecursiveFolderUseCase().call(model.instancePath)).map(
|
||||
async () => await new DeleteDataBaseModelUseCase(CalculationInstanceDBModel).call(id)
|
||||
);
|
||||
});
|
||||
export class DeleteCalculationsInstanceScenario extends DeleteInstanceScenario<CalculationInstanceValidationModel> {
|
||||
databaseModel = CalculationInstanceDBModel;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { CreateCalculationsTemplateScenario } from "./domain/create_calculations_template_scenario";
|
||||
import { DeleteCalculationsTemplateScenario } from "./domain/delete_calculations_template_scenario";
|
||||
import { CalculationsTemplateValidationModel as CalculationsTemplateValidationModel } from "./models/calculations_template_validation_model";
|
||||
import { CalculationsTemplateDBModel } from "./models/calculations_template_database_model";
|
||||
import { CreateCalculationsTemplateScenario } from "./domain/create_calculations_template_scenario";
|
||||
|
||||
export class CalculationsTemplatePresentation extends CrudController<
|
||||
CalculationsTemplateValidationModel,
|
||||
|
|
|
@ -1,27 +1,10 @@
|
|||
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { StaticFiles } from "../../../core/models/static_files";
|
||||
import { CreateDataBaseModelUseCase } from "../../../core/usecases/create_database_model_usecase";
|
||||
import { CreateFolderUseCase } from "../../../core/usecases/create_folder_usecase";
|
||||
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||
import { CalculationsTemplateValidationModel } from "../models/calculations_template_validation_model";
|
||||
import { StaticFilesServer } from "../../../core/models/static_files";
|
||||
import { CreateTemplateScenario } from "../../../core/scenarios/create_template_scenario";
|
||||
import { CalculationsTemplateDBModel } from "../models/calculations_template_database_model";
|
||||
import { CalculationsTemplateValidationModel } from "../models/calculations_template_validation_model";
|
||||
|
||||
export class CreateCalculationsTemplateScenario extends CallbackStrategyWithValidationModel<CalculationsTemplateValidationModel> {
|
||||
export class CreateCalculationsTemplateScenario extends CreateTemplateScenario<CalculationsTemplateValidationModel> {
|
||||
validationModel: CalculationsTemplateValidationModel = new CalculationsTemplateValidationModel();
|
||||
call = async (model: CalculationsTemplateValidationModel): ResponseBase => {
|
||||
return (
|
||||
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(
|
||||
{ isActive: true },
|
||||
"no active projects"
|
||||
)
|
||||
).map(async (project) => {
|
||||
model.path = project.rootDir + StaticFiles.process + model.name;
|
||||
return (await new CreateFolderUseCase().call(model.path)).map(() => {
|
||||
return new CreateDataBaseModelUseCase(CalculationsTemplateDBModel).call(model);
|
||||
});
|
||||
});
|
||||
};
|
||||
databaseModel = CalculationsTemplateDBModel;
|
||||
path: string = StaticFilesServer.process;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,6 @@
|
|||
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { DeleteDataBaseModelUseCase } from "../../../core/usecases/delete_database_model_usecase";
|
||||
import { DeleteRecursiveFolderUseCase } from "../../../core/usecases/delete_recursive_folder_usecase";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { CoreValidation } from "../../../core/validations/core_validation";
|
||||
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||
import { DeleteTemplateScenario } from "../../../core/scenarios/delete_template_scenario";
|
||||
import { CalculationsTemplateDBModel } from "../models/calculations_template_database_model";
|
||||
import { CalculationsTemplateValidationModel } from "../models/calculations_template_validation_model";
|
||||
|
||||
export class DeleteCalculationsTemplateScenario extends CallbackStrategyWithIdQuery {
|
||||
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||
call = async (id: string): ResponseBase =>
|
||||
(
|
||||
await new ReadByIdDataBaseModelUseCase<CalculationsTemplateValidationModel>(CalculationsTemplateDBModel).call(id)
|
||||
).map(async (model) => {
|
||||
return (await new DeleteRecursiveFolderUseCase().call(model.path)).map(
|
||||
async () => await new DeleteDataBaseModelUseCase(CalculationsTemplateDBModel).call(id)
|
||||
);
|
||||
});
|
||||
export class DeleteCalculationsTemplateScenario extends DeleteTemplateScenario {
|
||||
databaseModel = CalculationsTemplateDBModel;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { CreateDigitalTwinsInstanceScenario } from "./domain/create_digital_twins_instance";
|
||||
import { DeleteDigitalTwinsInstanceScenario } from "./domain/delete_digital_twins_instance";
|
||||
import { ExecInstanceScenario } from "./domain/exec_instance_scenario";
|
||||
import { DigitalTwinsInstanceDatabaseModel } from "./model/digital_twins_instance_database_model";
|
||||
import { DigitalTwinsInstanceValidationModel } from "./model/digital_twins_instance_validation_model";
|
||||
|
||||
export class DigitalTwinsInstancePresentation extends CrudController<
|
||||
DigitalTwinsInstanceValidationModel,
|
||||
typeof DigitalTwinsInstanceDatabaseModel
|
||||
> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "digital/twins/instance",
|
||||
validationModel: DigitalTwinsInstanceValidationModel,
|
||||
databaseModel: DigitalTwinsInstanceDatabaseModel,
|
||||
});
|
||||
super.post(new CreateDigitalTwinsInstanceScenario().call);
|
||||
super.delete(new DeleteDigitalTwinsInstanceScenario().call);
|
||||
this.subRoutes.push({
|
||||
method: "POST",
|
||||
fn: new ExecInstanceScenario(),
|
||||
subUrl: "exec/instance",
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { CreateInstanceScenario } from "../../../core/scenarios/create_intance_scenario";
|
||||
import { DigitalTwinsInstanceDatabaseModel } from "../model/digital_twins_instance_database_model";
|
||||
import { DigitalTwinsInstanceValidationModel } from "../model/digital_twins_instance_validation_model";
|
||||
|
||||
|
||||
|
||||
export class CreateDigitalTwinsInstanceScenario extends CreateInstanceScenario<DigitalTwinsInstanceValidationModel> {
|
||||
databaseModel = DigitalTwinsInstanceDatabaseModel;
|
||||
validationModel: DigitalTwinsInstanceValidationModel = new DigitalTwinsInstanceValidationModel();
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { DeleteInstanceScenario } from "../../../core/scenarios/delete_instance_scenario";
|
||||
import { DigitalTwinsInstanceDatabaseModel } from "../model/digital_twins_instance_database_model";
|
||||
import { DigitalTwinsInstanceValidationModel } from "../model/digital_twins_instance_validation_model";
|
||||
|
||||
export class DeleteDigitalTwinsInstanceScenario extends DeleteInstanceScenario<DigitalTwinsInstanceValidationModel> {
|
||||
databaseModel = DigitalTwinsInstanceDatabaseModel;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { ExecProcessUseCase } from "../../../core/usecases/exec_process_usecase";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { CoreValidation } from "../../../core/validations/core_validation";
|
||||
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
|
||||
import {
|
||||
DigitalTwinsInstanceDatabaseModel,
|
||||
IDigitalTwinsInstanceModel,
|
||||
} from "../model/digital_twins_instance_database_model";
|
||||
import { ITopicModel } from "../../topics/topic_database_model";
|
||||
import { ExecInstanceTwinsProcessService } from "../services/exec_instance_twins_process_service";
|
||||
|
||||
export interface Topics {
|
||||
topics: ITopicModel[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
export class ExecInstanceScenario extends CallbackStrategyWithIdQuery {
|
||||
idValidationExpression: CoreValidation = new MongoIdValidation();
|
||||
call = async (id: string): ResponseBase =>
|
||||
(
|
||||
await new ReadByIdDataBaseModelUseCase<IDigitalTwinsInstanceModel>(DigitalTwinsInstanceDatabaseModel).call(id)
|
||||
).map((document) =>
|
||||
new ExecProcessUseCase().call(
|
||||
document.instancePath,
|
||||
`python3 $GET_INTERFACES --path ${document.instancePath}`,
|
||||
"",
|
||||
new ExecInstanceTwinsProcessService(document.instancePath, document)
|
||||
)
|
||||
);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
|
||||
export interface IDigitalTwinsInstanceModel {
|
||||
instancePath: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export const DigitalTwinsInstanceSchema = new Schema({
|
||||
path: String,
|
||||
name: String,
|
||||
entity: String,
|
||||
description: String,
|
||||
command: String,
|
||||
status: {
|
||||
type: String,
|
||||
},
|
||||
interfaces: {
|
||||
cmd: String,
|
||||
},
|
||||
instancePath: {
|
||||
type: String,
|
||||
},
|
||||
formBuilder: {
|
||||
type: Schema.Types.Mixed,
|
||||
},
|
||||
}).plugin(require("mongoose-autopopulate"));
|
||||
|
||||
export const digitalTwinsInstanceSchema = "digital_twins_instance";
|
||||
|
||||
export const DigitalTwinsInstanceDatabaseModel = model<IDigitalTwinsInstanceModel>(
|
||||
digitalTwinsInstanceSchema,
|
||||
DigitalTwinsInstanceSchema
|
||||
);
|
|
@ -0,0 +1,26 @@
|
|||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsString } from "class-validator";
|
||||
import { Instance } from "../../../core/models/instance";
|
||||
|
||||
enum DigitalTwinsTypes {
|
||||
CAMERA = "CAMERA",
|
||||
ROBOT = "ROBOT",
|
||||
}
|
||||
export class Interfaces {
|
||||
@IsString()
|
||||
cmd: string;
|
||||
}
|
||||
export class DigitalTwinsInstanceValidationModel implements Instance {
|
||||
instanceName: string;
|
||||
instancePath: string;
|
||||
path: string;
|
||||
name: string;
|
||||
@IsEnum(DigitalTwinsTypes)
|
||||
entity: DigitalTwinsTypes;
|
||||
@IsString()
|
||||
description: string;
|
||||
@IsString()
|
||||
command: string;
|
||||
@Type(() => Interfaces)
|
||||
interfaces: Interfaces;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
import { Result } from "../../../core/helpers/result";
|
||||
import { TypedEvent } from "../../../core/helpers/typed_event";
|
||||
import { ExecError, SpawnError, EXEC_EVENT } from "../../../core/models/exec_error_model";
|
||||
import { ExecutorResult } from "../../../core/models/executor_result";
|
||||
import { CreateDataBaseModelUseCase } from "../../../core/usecases/create_database_model_usecase";
|
||||
import { ReadFileAndParseJsonUseCase } from "../../../core/usecases/read_file_and_parse_json";
|
||||
import { ITopicModel, TopicDatabaseModel } from "../../topics/topic_database_model";
|
||||
import { Topics } from "../domain/exec_instance_scenario";
|
||||
|
||||
export class ExecInstanceTwinsProcessService extends TypedEvent<
|
||||
Result<ExecError | SpawnError, ExecutorResult>
|
||||
> {
|
||||
path: string;
|
||||
databaseModel: any;
|
||||
constructor(path: string, databaseModel: any) {
|
||||
super();
|
||||
this.path = path;
|
||||
this.databaseModel = databaseModel;
|
||||
this.on((event) => this.lister(event));
|
||||
}
|
||||
|
||||
lister = (event: Result<ExecError | SpawnError, ExecutorResult>) =>
|
||||
event.fold(
|
||||
async (success) => {
|
||||
if (success.event == EXEC_EVENT.END) {
|
||||
(await new ReadFileAndParseJsonUseCase().call<Topics>(this.path + "/topics.json")).fold(
|
||||
async (model) => {
|
||||
await model.topics.forEach(async (el) => {
|
||||
el.digitalTwinId = this.databaseModel._id;
|
||||
await new CreateDataBaseModelUseCase<ITopicModel>(TopicDatabaseModel).call(el);
|
||||
});
|
||||
|
||||
this.databaseModel.status = "END";
|
||||
await this.databaseModel.save();
|
||||
},
|
||||
|
||||
async (e) => {
|
||||
this.databaseModel.status = "ERROR";
|
||||
await this.databaseModel.save();
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
async (error) => {
|
||||
this.databaseModel.status = "ERROR";
|
||||
await this.databaseModel.save();
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { CreateDigitalTwinsTemplateScenario } from "./domain/create_digital_twins_template";
|
||||
import { DeleteDigitalTwinsTemplateScenario } from "./domain/delete_digital_twins_template";
|
||||
import { DigitalTwinsTemplateDBModel } from "./models/digital_twins_template_database_model";
|
||||
import { DigitalTwinsTemplateValidationModel } from "./models/digital_twins_template_validation_model";
|
||||
|
||||
export class DigitalTwinsTemplatePresentation extends CrudController<
|
||||
DigitalTwinsTemplateValidationModel,
|
||||
typeof DigitalTwinsTemplateDBModel
|
||||
> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "digital/twins/template",
|
||||
validationModel: DigitalTwinsTemplateValidationModel,
|
||||
databaseModel: DigitalTwinsTemplateDBModel,
|
||||
});
|
||||
super.post(new CreateDigitalTwinsTemplateScenario().call);
|
||||
super.delete(new DeleteDigitalTwinsTemplateScenario().call);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { StaticFilesServer } from "../../../core/models/static_files";
|
||||
import { CreateTemplateScenario } from "../../../core/scenarios/create_template_scenario";
|
||||
import { DigitalTwinsTemplateDBModel } from "../models/digital_twins_template_database_model";
|
||||
import { DigitalTwinsTemplateValidationModel } from "../models/digital_twins_template_validation_model";
|
||||
|
||||
export class CreateDigitalTwinsTemplateScenario extends CreateTemplateScenario<DigitalTwinsTemplateValidationModel> {
|
||||
validationModel: DigitalTwinsTemplateValidationModel = new DigitalTwinsTemplateValidationModel();
|
||||
databaseModel = DigitalTwinsTemplateDBModel;
|
||||
path: string = StaticFilesServer.digitalTwins;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import { DeleteTemplateScenario } from "../../../core/scenarios/delete_template_scenario";
|
||||
import { DigitalTwinsTemplateDBModel } from "../models/digital_twins_template_database_model";
|
||||
|
||||
export class DeleteDigitalTwinsTemplateScenario extends DeleteTemplateScenario {
|
||||
databaseModel = DigitalTwinsTemplateDBModel;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
|
||||
export interface IDigitalTwinsTemplateTemplateModel {}
|
||||
|
||||
export const DigitalTwinsTemplateSchema = new Schema({
|
||||
path: String,
|
||||
name: String,
|
||||
entity: String,
|
||||
description: String,
|
||||
command: String,
|
||||
interfaces: {
|
||||
cmd: String,
|
||||
},
|
||||
formBuilder:{
|
||||
type: Schema.Types.Mixed,
|
||||
}
|
||||
}).plugin(require("mongoose-autopopulate"));
|
||||
|
||||
export const digitalTwinsTemplateSchema = "digital_twins_templates";
|
||||
|
||||
export const DigitalTwinsTemplateDBModel = model<IDigitalTwinsTemplateTemplateModel>(
|
||||
digitalTwinsTemplateSchema,
|
||||
DigitalTwinsTemplateSchema
|
||||
);
|
|
@ -0,0 +1,23 @@
|
|||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsString } from "class-validator";
|
||||
|
||||
enum DigitalTwinsTypes {
|
||||
CAMERA = "CAMERA",
|
||||
ROBOT = "ROBOT",
|
||||
}
|
||||
export class Interfaces {
|
||||
@IsString()
|
||||
cmd: string;
|
||||
}
|
||||
export class DigitalTwinsTemplateValidationModel {
|
||||
path: string;
|
||||
name: string;
|
||||
@IsEnum(DigitalTwinsTypes)
|
||||
entity: DigitalTwinsTypes;
|
||||
@IsString()
|
||||
description: string;
|
||||
@IsString()
|
||||
command: string;
|
||||
@Type(() => Interfaces)
|
||||
interfaces: Interfaces;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import { Result } from "../../../core/helpers/result";
|
||||
import { ActivePipeline } from "../../../core/models/active_pipeline_model";
|
||||
import { pipelineRealTimeService } from "../../../core/scenarios/set_active_pipeline_to_realtime_service_scenario";
|
||||
|
||||
export class PipelineStatusUseCase {
|
||||
async call(): Promise<Result<Error, ActivePipeline>> {
|
||||
try {
|
||||
const status = pipelineRealTimeService.status;
|
||||
if (status.projectId !== null) {
|
||||
return Result.ok(status);
|
||||
}
|
||||
|
||||
if (status.projectId === null) {
|
||||
return Result.error(new Error("pipelineRealTimeService does not have an active project instance"));
|
||||
}
|
||||
} catch (error) {
|
||||
return Result.error(error as Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { StaticFiles } from "../../../core/models/static_files";
|
||||
import { StaticFilesProject } from "../../../core/models/static_files";
|
||||
import { GetServerAddressUseCase } from "../../../core/usecases/get_server_address_usecase";
|
||||
import { ReadFileAndParseJsonUseCase } from "../../../core/usecases/read_file_and_parse_json";
|
||||
import { SearchManyDataBaseModelUseCase } from "../../../core/usecases/search_many_database_model_usecase";
|
||||
|
@ -27,7 +27,7 @@ export class RobossemblerAssetsNetworkMapperScenario extends CallbackStrategyWit
|
|||
).map((projectModel) => {
|
||||
const { rootDir } = projectModel[0];
|
||||
return new GetServerAddressUseCase().call().map(async (serverAddress) =>
|
||||
(await new ReadFileAndParseJsonUseCase().call<Parts[]>(rootDir + StaticFiles.parts)).map((model) => {
|
||||
(await new ReadFileAndParseJsonUseCase().call<Parts[]>(rootDir + StaticFilesProject.parts)).map((model) => {
|
||||
const assetAddress =
|
||||
serverAddress +
|
||||
"/" +
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
import { CallbackStrategyWithValidationModel, 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 { StaticFilesProject } 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 "./pipeline_status_usecase";
|
||||
|
||||
export class SaveActiveSceneScenario extends CallbackStrategyWithValidationModel<RobossemblerAssets> {
|
||||
validationModel: RobossemblerAssets = new RobossemblerAssets();
|
||||
async call(model: RobossemblerAssets): ResponseBase {
|
||||
return (await new PipelineStatusUseCase().call()).map(async (activeInstanceModel) =>
|
||||
(
|
||||
await new ReadingJsonFileAndConvertingToInstanceClassScenario(RobossemblerAssets).call(
|
||||
`${activeInstanceModel.path}${StaticFiles.robossembler_assets}`.pathNormalize()
|
||||
`${activeInstanceModel.path}${StaticFilesProject.robossembler_assets}`.pathNormalize()
|
||||
)
|
||||
).map(async (prevModel) => {
|
||||
model.assets = prevModel.assets;
|
||||
return (
|
||||
await new WriteFileSystemFileUseCase().call(
|
||||
`${activeInstanceModel.path}${StaticFiles.robossembler_assets}`.pathNormalize(),
|
||||
`${activeInstanceModel.path}${StaticFilesProject.robossembler_assets}`.pathNormalize(),
|
||||
JSON.stringify(model)
|
||||
)
|
||||
).map(() => Result.ok("assets is rewrite"));
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Result } from "../../../core/helpers/result";
|
|||
import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase";
|
||||
import { SearchManyDataBaseModelUseCase } from "../../../core/usecases/search_many_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||
import { StaticFiles } from "../../../core/models/static_files";
|
||||
import { StaticFilesProject } from "../../../core/models/static_files";
|
||||
import { CreateDataBaseModelUseCase } from "../../../core/usecases/create_database_model_usecase";
|
||||
import { SceneDBModel } from "../model/scene_database_model";
|
||||
export class SceneModel {
|
||||
|
@ -33,7 +33,7 @@ export class CreateNewSceneScenario extends CallbackStrategyWithValidationModel<
|
|||
|
||||
return (
|
||||
await new CreateFileUseCase().call(
|
||||
`${rootDir}${StaticFiles.scenes}${model.name}.json`,
|
||||
`${rootDir}${StaticFilesProject.scenes}${model.name}.json`,
|
||||
Buffer.from(JSON.stringify(new SceneAssets(model.name)))
|
||||
)
|
||||
).map(async () =>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { RobotModel } from "../model/robot_model";
|
||||
import { StaticFiles } from "../../../core/models/static_files";
|
||||
import { StaticFilesProject } from "../../../core/models/static_files";
|
||||
import { GetServerAddressUseCase } from "../../../core/usecases/get_server_address_usecase";
|
||||
import { SearchManyDataBaseModelUseCase } from "../../../core/usecases/search_many_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||
|
@ -9,31 +9,7 @@ import { ExecProcessUseCase } from "../../../core/usecases/exec_process_usecase"
|
|||
|
||||
export class CreateRobotScenario extends CallbackStrategyWithValidationModel<RobotModel> {
|
||||
validationModel: RobotModel = new RobotModel();
|
||||
call = async (model: RobotModel): ResponseBase =>
|
||||
(
|
||||
await new SearchManyDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(
|
||||
{ isActive: true },
|
||||
"is dont active projects"
|
||||
)
|
||||
).map((projectModel) => {
|
||||
const { rootDir } = projectModel[0];
|
||||
|
||||
return new GetServerAddressUseCase().call().map(async (serverAddress) =>
|
||||
(
|
||||
await new ExecProcessUseCase().call(
|
||||
rootDir,
|
||||
`python3 $PYTHON_ROBOT_BUILDER --path ${projectModel[0].rootDir + StaticFiles.robots} --name ${
|
||||
model.name
|
||||
} --nDOF ${model.nDof} --toolType ${model.toolType}`,
|
||||
""
|
||||
)
|
||||
).map(() =>
|
||||
Result.ok({
|
||||
robotUrl: `${serverAddress}/${
|
||||
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]
|
||||
}${StaticFiles.robots}${model.name}/robot.xml`,
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
call = async (model: RobotModel): ResponseBase => {
|
||||
return Result.ok([]);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { StaticFiles } from "../../../core/models/static_files";
|
||||
import { StaticFilesProject } from "../../../core/models/static_files";
|
||||
import { DeleteDataBaseModelUseCase } from "../../../core/usecases/delete_database_model_usecase";
|
||||
import { DeleteFileUseCase } from "../../../core/usecases/delete_file_usecase";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
|
@ -23,7 +23,7 @@ export class DeleteSceneScenario extends CallbackStrategyWithIdQuery {
|
|||
).map(async (projectModel) => {
|
||||
const { rootDir } = projectModel[0];
|
||||
|
||||
(await new DeleteFileUseCase()).call(`${rootDir}${StaticFiles.scenes}${sceneModel.name}.json`);
|
||||
(await new DeleteFileUseCase()).call(`${rootDir}${StaticFilesProject.scenes}${sceneModel.name}.json`);
|
||||
return Result.ok("Delete scene");
|
||||
})
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { StaticFiles } from "../../../core/models/static_files";
|
||||
import { StaticFilesProject } from "../../../core/models/static_files";
|
||||
import { CreateFileUseCase } from "../../../core/usecases/create_file_usecase";
|
||||
import { SearchManyDataBaseModelUseCase } from "../../../core/usecases/search_many_database_model_usecase";
|
||||
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
|
||||
|
@ -19,7 +19,7 @@ export class EditSceneScenario extends CallbackStrategyWithValidationModel<Scene
|
|||
|
||||
return (
|
||||
await new CreateFileUseCase().call(
|
||||
`${rootDir}${StaticFiles.scenes}${model.name}.json`,
|
||||
`${rootDir}${StaticFilesProject.scenes}${model.name}.json`,
|
||||
Buffer.from(JSON.stringify(model))
|
||||
)
|
||||
).map(async () => Result.ok("Edit"));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { CallbackStrategyWithIdQuery, ResponseBase } from "../../../core/controllers/http_controller";
|
||||
import { Result } from "../../../core/helpers/result";
|
||||
import { StaticFiles } from "../../../core/models/static_files";
|
||||
import { StaticFilesProject } from "../../../core/models/static_files";
|
||||
import { ReadByIdDataBaseModelUseCase } from "../../../core/usecases/read_by_id_database_model_usecase";
|
||||
import { ReadFileAndParseJsonUseCase } from "../../../core/usecases/read_file_and_parse_json";
|
||||
import { SearchManyDataBaseModelUseCase } from "../../../core/usecases/search_many_database_model_usecase";
|
||||
|
@ -22,7 +22,7 @@ export class ReadSceneScenario extends CallbackStrategyWithIdQuery {
|
|||
).map(async (projectModel) => {
|
||||
const { rootDir } = projectModel[0];
|
||||
|
||||
return (await new ReadFileAndParseJsonUseCase().call(`${rootDir}${StaticFiles.scenes}${model.name}.json`)).map(
|
||||
return (await new ReadFileAndParseJsonUseCase().call(`${rootDir}${StaticFilesProject.scenes}${model.name}.json`)).map(
|
||||
async (sceneAsset) => Result.ok(sceneAsset)
|
||||
);
|
||||
})
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
|
||||
export interface ISkillsInstanceModel {}
|
||||
|
||||
export const SkillsInstanceSchema = new Schema({}).plugin(require("mongoose-autopopulate"));
|
||||
|
||||
export const skillsInstanceSchema = "skills_instances";
|
||||
|
||||
export const SkillsInstanceDBModel = model<ISkillsInstanceModel>(skillsInstanceSchema, SkillsInstanceSchema);
|
|
@ -0,0 +1 @@
|
|||
export class SkillInstanceValidationModel {}
|
|
@ -0,0 +1 @@
|
|||
export class SkillsInstancePresentation {}
|
|
@ -0,0 +1,9 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
|
||||
export interface ISkillsTemplateModel {}
|
||||
|
||||
export const SkillsTemplateSchema = new Schema({}).plugin(require("mongoose-autopopulate"));
|
||||
|
||||
export const skillsTemplateSchema = "skills_templates";
|
||||
|
||||
export const SkillsTemplateDBModel = model<ISkillsTemplateModel>(skillsTemplateSchema, SkillsTemplateSchema);
|
|
@ -0,0 +1 @@
|
|||
export class SkillTemplateValidationModel {}
|
|
@ -0,0 +1 @@
|
|||
export class SkillsTemplatePresentation {}
|
26
server/src/features/topics/topic_database_model.ts
Normal file
26
server/src/features/topics/topic_database_model.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { Schema, model } from "mongoose";
|
||||
import { digitalTwinsInstanceSchema } from "../digital_twins_instance/model/digital_twins_instance_database_model";
|
||||
|
||||
export interface ITopicModel {
|
||||
digitalTwinId?: string;
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export const TopicSchema = new Schema({
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
},
|
||||
digitalTwinId: {
|
||||
type: Schema.Types.ObjectId,
|
||||
ref: digitalTwinsInstanceSchema,
|
||||
autopopulate: true,
|
||||
},
|
||||
}).plugin(require("mongoose-autopopulate"));
|
||||
|
||||
export const topicSchema = "topics";
|
||||
|
||||
export const TopicDatabaseModel = model<ITopicModel>(topicSchema, TopicSchema);
|
10
server/src/features/topics/topic_validation_model.ts
Normal file
10
server/src/features/topics/topic_validation_model.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsString } from "class-validator";
|
||||
import { ITopicModel } from "./topic_database_model";
|
||||
|
||||
export class TopicValidationModel implements ITopicModel {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
type: string;
|
||||
}
|
13
server/src/features/topics/topics_presentation.ts
Normal file
13
server/src/features/topics/topics_presentation.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { CrudController } from "../../core/controllers/crud_controller";
|
||||
import { TopicDatabaseModel } from "./topic_database_model";
|
||||
import { TopicValidationModel } from "./topic_validation_model";
|
||||
|
||||
export class TopicsPresentation extends CrudController<TopicValidationModel, typeof TopicDatabaseModel> {
|
||||
constructor() {
|
||||
super({
|
||||
url: "topics",
|
||||
validationModel: TopicValidationModel,
|
||||
databaseModel: TopicDatabaseModel,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
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";
|
||||
|
||||
export const mockSimplePipeline: IPipeline[] = [
|
||||
{
|
||||
process: {
|
||||
type: EXEC_TYPE.EXEC,
|
||||
command: `nix run gitlab:robossembler/nix-robossembler-overlay#test-script '{
|
||||
"filesMeta":[
|
||||
{"type":"folder","name":"example", "path": null,"rewrite":true}
|
||||
],
|
||||
"path":"$PATH"
|
||||
}'`,
|
||||
isGenerating: true,
|
||||
isLocaleCode: false,
|
||||
issueType: IssueType.WARNING,
|
||||
},
|
||||
trigger: {
|
||||
type: TriggerType.PROCESS,
|
||||
value: [""],
|
||||
},
|
||||
env: null,
|
||||
stackGenerateType: StackGenerateType.SINGLETON,
|
||||
},
|
||||
{
|
||||
process: {
|
||||
type: EXEC_TYPE.EXEC,
|
||||
command: `nix run gitlab:robossembler/nix-robossembler-overlay#test-script '{
|
||||
"filesMeta":[
|
||||
{"type":"file","name":"1.txt", "path":"example","rewrite":true}
|
||||
],
|
||||
"path":"$PATH"
|
||||
}'`,
|
||||
isGenerating: true,
|
||||
isLocaleCode: false,
|
||||
issueType: IssueType.WARNING,
|
||||
},
|
||||
trigger: null,
|
||||
env: null,
|
||||
stackGenerateType: StackGenerateType.SINGLETON,
|
||||
},
|
||||
];
|
|
@ -1,5 +1,4 @@
|
|||
import { PipelineRealTimeService } from "../../src/core/services/pipeline_real_time_service";
|
||||
import { mockSimplePipeline } from "../model/mock_pipelines";
|
||||
import { dirname__ } from "../test";
|
||||
|
||||
export class PipelineRealTimeServiceTest extends PipelineRealTimeService {
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
import { rmSync } from "fs";
|
||||
import { StackService } from "../../src/core/services/stack_service";
|
||||
import { delay } from "../../src/core/helpers/delay";
|
||||
import { assert, dirname__ } from "../test";
|
||||
import { mockSimplePipeline } from "../model/mock_pipelines";
|
||||
import { FileSystemRepository } from "../../src/core/repository/file_system_repository";
|
||||
import { CreateFolderUseCase } from "../../src/core/usecases/create_folder_usecase";
|
||||
|
||||
abstract class IStackServiceTest {
|
||||
abstract test(): Promise<boolean>;
|
||||
}
|
||||
|
||||
class SimpleTestStackServiceTest extends StackService implements IStackServiceTest {
|
||||
fileSystemRepository: FileSystemRepository;
|
||||
constructor() {
|
||||
super(mockSimplePipeline, dirname__ + "/context/");
|
||||
this.fileSystemRepository = new FileSystemRepository();
|
||||
}
|
||||
async test(): Promise<boolean> {
|
||||
await this.call();
|
||||
console.log(this.path);
|
||||
const testResult = this.fileSystemRepository.readDirRecursive(this.path).equals(["1.txt", "test.txt"], true);
|
||||
await delay(100);
|
||||
rmSync(this.path + "example/", { recursive: true });
|
||||
return testResult;
|
||||
}
|
||||
}
|
||||
|
||||
export class StackServiceTest {
|
||||
dirName: string;
|
||||
fileSystemRepository: FileSystemRepository;
|
||||
constructor(dirName: string) {
|
||||
this.dirName = dirName;
|
||||
this.fileSystemRepository = new FileSystemRepository();
|
||||
}
|
||||
public async test() {
|
||||
const tests = [new SimpleTestStackServiceTest()];
|
||||
await new CreateFolderUseCase().call(this.dirName + "/context/");
|
||||
|
||||
for await (const el of tests) {
|
||||
assert((await el.test()) === true, el.constructor.name);
|
||||
await delay(3000);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
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 { assert } from "../test";
|
||||
abstract class TriggerTest {
|
||||
abstract test(): Promise<boolean>;
|
||||
}
|
||||
class TriggerServiceFileOkTest extends TriggerService implements TriggerTest {
|
||||
constructor() {
|
||||
super(
|
||||
{
|
||||
type: TriggerType.FILE,
|
||||
value: ["context"],
|
||||
},
|
||||
{
|
||||
"/context/": new MetaDataFileManagerModel("", "", EventsFileChanger.create),
|
||||
},
|
||||
""
|
||||
);
|
||||
}
|
||||
async test(): Promise<boolean> {
|
||||
const r = await this.call();
|
||||
|
||||
return r.isSuccess();
|
||||
}
|
||||
}
|
||||
class TriggerServiceFileErrorTest extends TriggerService implements TriggerTest {
|
||||
constructor() {
|
||||
super(
|
||||
{
|
||||
type: TriggerType.FILE,
|
||||
value: ["123"],
|
||||
},
|
||||
{
|
||||
"/ctx/": new MetaDataFileManagerModel("", "", EventsFileChanger.create),
|
||||
"/context/": new MetaDataFileManagerModel("", "", EventsFileChanger.create),
|
||||
},
|
||||
|
||||
""
|
||||
);
|
||||
}
|
||||
async test(): Promise<boolean> {
|
||||
const r = await this.call();
|
||||
|
||||
return r.isFailure();
|
||||
}
|
||||
}
|
||||
class TriggerServiceProcessOkTest extends TriggerService implements TriggerTest {
|
||||
constructor() {
|
||||
super(
|
||||
{
|
||||
type: TriggerType.PROCESS,
|
||||
value: [
|
||||
`function main(){
|
||||
return true
|
||||
}
|
||||
|
||||
main()`,
|
||||
],
|
||||
},
|
||||
{
|
||||
"/context/": new MetaDataFileManagerModel("", "", EventsFileChanger.create),
|
||||
},
|
||||
""
|
||||
);
|
||||
}
|
||||
async test(): Promise<boolean> {
|
||||
const r = await this.call();
|
||||
return r.isSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
class TriggerServiceProcessErrorTest extends TriggerService implements TriggerTest {
|
||||
constructor() {
|
||||
super(
|
||||
{
|
||||
type: TriggerType.PROCESS,
|
||||
value: [
|
||||
`function main(){
|
||||
return true
|
||||
}
|
||||
|
||||
`,
|
||||
],
|
||||
},
|
||||
{
|
||||
"/context/": new MetaDataFileManagerModel("", "", EventsFileChanger.create),
|
||||
},
|
||||
""
|
||||
);
|
||||
}
|
||||
async test(): Promise<boolean> {
|
||||
const r = await this.call();
|
||||
return r.isFailure();
|
||||
}
|
||||
}
|
||||
export class TriggerServiceTest {
|
||||
public async test() {
|
||||
const tests: TriggerTest[] = [
|
||||
new TriggerServiceFileOkTest(),
|
||||
new TriggerServiceFileErrorTest(),
|
||||
new TriggerServiceProcessOkTest(),
|
||||
new TriggerServiceProcessErrorTest(),
|
||||
];
|
||||
for await (const el of tests) {
|
||||
assert((await el.test()) === true, el.constructor.name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,8 @@
|
|||
import "reflect-metadata";
|
||||
import { TestCore } from "./core/test_core";
|
||||
// import { UnitTestEnv } from "../src/core/di/env";
|
||||
import { dirname } from "path";
|
||||
// import locator from "../src/core/di/register_di";
|
||||
import { ExecutorProgramServiceTest } from "./services/executor_program_service_test";
|
||||
import { FilesChangerTest } from "./services/files_change_notifier_service_test";
|
||||
import { TriggerServiceTest } from "./services/trigger_service_test";
|
||||
import { StackServiceTest } from "./services/stack_service_test";
|
||||
import { CreateDataBaseModelUseCaseTest } from "./usecases/create_database_model_usecase_test";
|
||||
import { DeleteDataBaseModelUseCaseTest } from "./usecases/delete_database_model_usecase_test";
|
||||
import { ReadDataBaseModelUseCaseTest } from "./usecases/read_database_model_usecase_test";
|
||||
|
@ -39,8 +35,6 @@ const unitTest = async () => {
|
|||
await init();
|
||||
await new ExecutorProgramServiceTest(dirname__).test();
|
||||
await new FilesChangerTest(dirname__).test();
|
||||
await new StackServiceTest(dirname__).test();
|
||||
await new TriggerServiceTest().test();
|
||||
await new CreateDataBaseModelUseCaseTest().test();
|
||||
await new CreateDataBaseModelUseCaseTest().test();
|
||||
await new DeleteDataBaseModelUseCaseTest().test();
|
||||
|
|
3
ui/.gitignore
vendored
3
ui/.gitignore
vendored
|
@ -21,4 +21,5 @@
|
|||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
todo.md
|
||||
todo.md
|
||||
package-lock.json
|
17765
ui/package-lock.json
generated
17765
ui/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,18 +1,17 @@
|
|||
import { IsNotEmpty } from "class-validator";
|
||||
import { Result } from "../helper/result";
|
||||
import { IDeviceDependency } from "./skill_model";
|
||||
import { ValidationModel } from "./validation_model";
|
||||
|
||||
export class SidViewModel implements IDeviceDependency {
|
||||
sid: string;
|
||||
constructor(sid: string) {
|
||||
this.sid = sid;
|
||||
}
|
||||
valid = (): Result<string, SidViewModel> => {
|
||||
if (this.sid.isEmpty()) {
|
||||
return Result.error('sid is empty')
|
||||
}
|
||||
return Result.ok(this)
|
||||
}
|
||||
static empty() {
|
||||
return new SidViewModel('')
|
||||
}
|
||||
}
|
||||
export class SidViewModel extends ValidationModel implements IDeviceDependency {
|
||||
@IsNotEmpty()
|
||||
sid: string;
|
||||
constructor(sid: string) {
|
||||
super();
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
static empty() {
|
||||
return new SidViewModel("");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,8 +186,6 @@ export class CoreThreeRepository extends TypedEvent<any> {
|
|||
);
|
||||
loadUrdfRobot = (robotModel: RobotModel) =>
|
||||
this.urdfLoader.load(robotModel.httpUrl, (robot) => {
|
||||
console.log(robot);
|
||||
// Object3D.DEFAULT_UP = new Vector3(0, 0, 1);
|
||||
robot.userData[UserData.selectedObject] = true;
|
||||
robot.name = robotModel.name;
|
||||
if (robotModel.position) robot.position.copy(robotModel.position);
|
||||
|
|
|
@ -11,6 +11,8 @@ import { SimulationScreen, SimulationScreenPath } from "../../features/simulatio
|
|||
import { EstimateScreen, EstimateScreenPath } from "../../features/estimate/estimate_screen";
|
||||
import { CalculationScreenPath, CalculationScreen } from "../../features/calculation/presentation/calculation_screen";
|
||||
import { DetailsScreenPath, DetailsScreen } from "../../features/details/details_screen";
|
||||
import { DigitalTwinsScreen, DigitalTwinsScreenPath } from "../../features/digital_twins/digital_twins_screen";
|
||||
import { TopicsScreen, TopicsScreenPath } from "../../features/topics/topics_screen";
|
||||
|
||||
const idURL = ":id";
|
||||
|
||||
|
@ -59,4 +61,12 @@ export const router = createBrowserRouter([
|
|||
path: CalculationScreenPath,
|
||||
element: <CalculationScreen />,
|
||||
},
|
||||
{
|
||||
path: DigitalTwinsScreenPath,
|
||||
element: <DigitalTwinsScreen />,
|
||||
},
|
||||
{
|
||||
path: TopicsScreenPath,
|
||||
element: <TopicsScreen />,
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -34,14 +34,10 @@ export abstract class UiLoader {
|
|||
abstract errorHandingStrategy: (error?: any) => void;
|
||||
|
||||
mapOk = async <T>(property: string, callBack: Promise<Result<CoreError, T>>) => {
|
||||
return (
|
||||
(await this.httpHelper(callBack))
|
||||
// eslint-disable-next-line array-callback-return
|
||||
.map((el) => {
|
||||
// @ts-ignore
|
||||
this[property] = el;
|
||||
})
|
||||
);
|
||||
return (await this.httpHelper(callBack)).map((el) => {
|
||||
// @ts-ignore
|
||||
this[property] = el;
|
||||
});
|
||||
};
|
||||
messageHttp = async <T>(callBack: Promise<Result<CoreError, T>>, report?: IMessage) => {
|
||||
return (await this.httpHelper(callBack)).fold(
|
||||
|
@ -76,7 +72,6 @@ export class ModalStore extends SimpleErrorState {
|
|||
}
|
||||
export abstract class UiErrorState<T> extends UiLoader {
|
||||
errorHandingStrategy = (error: T) => {
|
||||
// message.error(error as any);
|
||||
console.log(error);
|
||||
};
|
||||
abstract init(navigate?: NavigateFunction): Promise<any>;
|
||||
|
@ -109,10 +104,8 @@ export abstract class DrawerState<E> extends UiErrorState<E> {
|
|||
export abstract class UiDrawerFormState<V, E> extends DrawerState<E> {
|
||||
abstract viewModel: V;
|
||||
updateForm(value: Partial<V>) {
|
||||
// {"id":"123","userId":"132"}
|
||||
//@ts-ignore
|
||||
this.viewModel = Object.assign(this.viewModel, value);
|
||||
console.log(this.viewModel)
|
||||
}
|
||||
loadDependency = (viewModel: V) => {
|
||||
this.viewModel = viewModel;
|
||||
|
@ -120,7 +113,6 @@ export abstract class UiDrawerFormState<V, E> extends DrawerState<E> {
|
|||
loadClassInstance = (instance: ClassConstructor<V>, viewModel: V) => {
|
||||
this.viewModel = plainToInstance(instance, viewModel);
|
||||
};
|
||||
|
||||
}
|
||||
export abstract class FormState<V, E> extends UiErrorState<E> {
|
||||
abstract viewModel: V;
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
{
|
||||
"center_shell": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"scene": {
|
||||
"details": [
|
||||
{
|
||||
"name": "body_down",
|
||||
"part_path": "parts/objects/body_down.stl",
|
||||
"material_path": "",
|
||||
"mass": 100,
|
||||
"inertia": {
|
||||
"ixx": 0.1,
|
||||
"ixy": 0,
|
||||
"ixz": 0,
|
||||
"iyy": 0.1,
|
||||
"iyz": 0,
|
||||
"izz": 0.1
|
||||
},
|
||||
"visual": ".dae",
|
||||
"collision": ".stl",
|
||||
"stlUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/parts/objects/body_down.stl",
|
||||
"glUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.glb",
|
||||
"daeUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.dae",
|
||||
"objUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.obj",
|
||||
"image": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.png",
|
||||
"solidType": "active",
|
||||
"isSelect": true
|
||||
},
|
||||
{
|
||||
"name": "sol_gear",
|
||||
"part_path": "parts/objects/sol_gear.stl",
|
||||
"material_path": "",
|
||||
"mass": 100,
|
||||
"inertia": {
|
||||
"ixx": 0.1,
|
||||
"ixy": 0,
|
||||
"ixz": 0,
|
||||
"iyy": 0.1,
|
||||
"iyz": 0,
|
||||
"izz": 0.1
|
||||
},
|
||||
"visual": ".dae",
|
||||
"collision": ".stl",
|
||||
"stlUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/parts/objects/sol_gear.stl",
|
||||
"glUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/sol_gear.glb",
|
||||
"daeUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/sol_gear.dae",
|
||||
"objUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/sol_gear.obj",
|
||||
"image": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/sol_gear.png",
|
||||
"solidType": "active",
|
||||
"isSelect": true
|
||||
},
|
||||
{
|
||||
"name": "output_shaft",
|
||||
"part_path": "parts/objects/output_shaft.stl",
|
||||
"material_path": "",
|
||||
"mass": 100,
|
||||
"inertia": {
|
||||
"ixx": 0.1,
|
||||
"ixy": 0,
|
||||
"ixz": 0,
|
||||
"iyy": 0.1,
|
||||
"iyz": 0,
|
||||
"izz": 0.1
|
||||
},
|
||||
"visual": ".dae",
|
||||
"collision": ".stl",
|
||||
"stlUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/parts/objects/output_shaft.stl",
|
||||
"glUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/output_shaft.glb",
|
||||
"daeUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/output_shaft.dae",
|
||||
"objUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/output_shaft.obj",
|
||||
"image": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/output_shaft.png",
|
||||
"solidType": "active",
|
||||
"isSelect": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -38,11 +38,12 @@ export const FormBuilder = observer((props: IFormBuilder) => {
|
|||
<>Error</>
|
||||
) : (
|
||||
<div>
|
||||
{store.formViewModel?.inputs?.map((element) => {
|
||||
{store.formViewModel?.inputs?.map((element,index) => {
|
||||
if (element.type?.isEqual(InputType.ENUM)) {
|
||||
const values = element.values as string[];
|
||||
return (
|
||||
<CoreSelect
|
||||
key={index}
|
||||
items={values}
|
||||
value={element.totalValue ?? element.defaultValue}
|
||||
onChange={(value) => store.changeTotalValue(element.id, value)}
|
||||
|
@ -53,7 +54,7 @@ export const FormBuilder = observer((props: IFormBuilder) => {
|
|||
}
|
||||
if (element.type?.isEqual(InputType.ARRAY)) {
|
||||
return (
|
||||
<div style={{ border: "1px black solid", margin: 20 }}>
|
||||
<div key={index} style={{ border: "1px black solid", margin: 20 }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
|
|
|
@ -47,15 +47,13 @@ export class FormBuilderStore {
|
|||
changeTotalValue(id: string, value: any) {
|
||||
if (this.formViewModel?.inputs)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
}
|
||||
|
||||
if (value instanceof String) {
|
||||
if (typeof value === "string") {
|
||||
el.totalValue = value;
|
||||
}else{
|
||||
el.totalValue = JSON.stringify(value)
|
||||
} else {
|
||||
el.totalValue = JSON.stringify(value);
|
||||
}
|
||||
return el;
|
||||
});
|
||||
|
|
|
@ -85,7 +85,6 @@ export class FormViewModel {
|
|||
}
|
||||
public json() {
|
||||
const result = this.toResult();
|
||||
console.log(result)
|
||||
if (result.isEmpty()) {
|
||||
console.log("result is Empty error");
|
||||
return;
|
||||
|
@ -109,6 +108,7 @@ export class FormViewModel {
|
|||
|
||||
this.inputs.forEach((element) => {
|
||||
let inputResult = element.totalValue ?? element.defaultValue;
|
||||
|
||||
if (element.type.isEqualMany([InputType.STRING, InputType.ENUM])) {
|
||||
inputResult = `"${String(inputResult)}"`;
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ export class FormViewModel {
|
|||
inputResult = Number(inputResult);
|
||||
}
|
||||
if (element.type.isEqual(InputType.OBJECT)) {
|
||||
inputResult = element.totalValue ?? element.defaultValue
|
||||
inputResult = element.totalValue ?? JSON.stringify(element.defaultValue);
|
||||
}
|
||||
if (element.type.isEqual(InputType.ARRAY)) {
|
||||
if (element.totalValue === undefined) {
|
||||
|
@ -130,7 +130,6 @@ export class FormViewModel {
|
|||
if (el instanceof Array)
|
||||
el.forEach((subElement) => {
|
||||
let subResult = subElement.totalValue ?? subElement.defaultValue;
|
||||
console.log(subResult);
|
||||
if (subElement.type.isEqualMany([InputType.STRING, InputType.ENUM])) {
|
||||
subResult = `"${String(subResult)}"`;
|
||||
}
|
||||
|
@ -183,8 +182,8 @@ export class FormViewModel {
|
|||
}
|
||||
static fromString(result: string, context: string): Result<void, FormViewModel> {
|
||||
try {
|
||||
if(result.isEmpty() && context.isEmpty()){
|
||||
return Result.error(undefined)
|
||||
if (result.isEmpty() && context.isEmpty()) {
|
||||
return Result.error(undefined);
|
||||
}
|
||||
const enums = new Map<string, string[]>();
|
||||
const types = new Map<string, InputBuilderViewModel[]>();
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Parts } from "../../../../../../features/details/details_http_repositor
|
|||
export class SelectDetailViewModel {
|
||||
details: Parts[];
|
||||
constructor(parts: Parts[]) {
|
||||
console.log(parts)
|
||||
this.details = parts;
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
|
|
@ -1,30 +1,40 @@
|
|||
// @ts-nocheck
|
||||
import React from "react";
|
||||
import { IFormBuilderComponentsProps } from "../../form_builder_components";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { ListItem } from "./ui/list_item";
|
||||
import { SelectDetailStore } from "./select_detail_store";
|
||||
import { SelectDetailViewModel } from "../model/select_details_model";
|
||||
import { plainToInstance } from "class-transformer";
|
||||
|
||||
export const SelectDetail = observer((props: IFormBuilderComponentsProps<SelectDetailViewModel>) => {
|
||||
const [store] = React.useState(() => new SelectDetailStore());
|
||||
|
||||
React.useEffect(() => {
|
||||
store.loadClassInstance(SelectDetailViewModel, props.dependency);
|
||||
store.viewModel = new SelectDetailViewModel(props.dependency.details);
|
||||
store.isLoading = false;
|
||||
console.log(store.viewModel);
|
||||
|
||||
store.init();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{store.parts?.map((el) => {
|
||||
return (
|
||||
<ListItem
|
||||
status={store.viewModel.isSelected(el.name)}
|
||||
name={el.name}
|
||||
imgURL={el.image}
|
||||
onChange={() => (store.viewModel.select(el), props.onChange(store.viewModel.toDependency()))}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{store.isLoading ? (
|
||||
<></>
|
||||
) : (
|
||||
<>
|
||||
{store.parts?.map((el) => {
|
||||
return (
|
||||
<ListItem
|
||||
status={store.viewModel.isSelected(el.name)}
|
||||
name={el.name}
|
||||
imgURL={el.image}
|
||||
onChange={() => (store.viewModel.select(el), props.onChange(store.viewModel.toDependency()))}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -5,13 +5,26 @@ import { FormState } from "../../../../../store/base_store";
|
|||
import { SelectDetailViewModel } from "../model/select_details_model";
|
||||
|
||||
export class SelectDetailStore extends FormState<SelectDetailViewModel, any> {
|
||||
|
||||
|
||||
viewModel = SelectDetailViewModel.empty();
|
||||
parts?: Parts[];
|
||||
isLoading: boolean = true;
|
||||
dataSetRepository: DataSetHttpRepository = new DataSetHttpRepository();
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
isSelected = (name: string) => {
|
||||
console.log(this.viewModel.details);
|
||||
if (this.viewModel.details)
|
||||
for (const el of this.viewModel.details) {
|
||||
if (el.name.isEqual(name)) {
|
||||
return el.isSelect as boolean;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
init = async () => {
|
||||
await this.mapOk("parts", this.dataSetRepository.getAssetsActiveProject());
|
||||
};
|
||||
|
|
|
@ -47,9 +47,9 @@ export const CoreInput = (props: IInputProps) => {
|
|||
/>
|
||||
|
||||
<div
|
||||
ref={ref}
|
||||
contentEditable={true}
|
||||
defaultValue={props.value}
|
||||
style={{
|
||||
style={{
|
||||
backgroundColor: "#00008000",
|
||||
border: 1,
|
||||
fontSize: isSmall ? 12 : 16,
|
||||
|
|
|
@ -29,7 +29,7 @@ export const CoreSlider = ({
|
|||
<div
|
||||
ref={refSlider}
|
||||
onClick={(event) => {
|
||||
console.log(event)
|
||||
|
||||
}}
|
||||
style={{ width: "100%", height: 11, backgroundColor: "rgba(104, 80, 164, 1)" }}
|
||||
>
|
||||
|
|
|
@ -8,6 +8,7 @@ import { CoreText, CoreTextType } from "../../../core/ui/text/text";
|
|||
import { CoreButton } from "../../../core/ui/button/button";
|
||||
import { CoreInput } from "../../../core/ui/input/input";
|
||||
import { DetailsScreenPath } from "../../details/details_screen";
|
||||
import { DigitalTwinsScreenPath } from "../../digital_twins/digital_twins_screen";
|
||||
|
||||
export const AllProjectScreenPath = "/";
|
||||
export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
||||
|
@ -18,7 +19,6 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
store.init();
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<PreviewPage
|
||||
largeText={"Проекты"}
|
||||
|
@ -29,6 +29,7 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
isLoading={store.isLoading}
|
||||
children={
|
||||
<>
|
||||
<div onClick={() => navigate(DigitalTwinsScreenPath)}>Digital twins</div>
|
||||
{store.projectsModels?.map((el) => {
|
||||
return (
|
||||
<div
|
||||
|
@ -101,4 +102,4 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ import { IProjectModel, IProjectView } from "../model/project_model";
|
|||
import { ModalStore } from "../../../core/store/base_store";
|
||||
import { message } from "antd";
|
||||
|
||||
|
||||
|
||||
export class ProjectView {
|
||||
isActive: boolean;
|
||||
description: string;
|
||||
|
|
|
@ -187,7 +187,6 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
if (model.skills) this.filledOutTemplates = model.skills;
|
||||
|
||||
await this.mapOk("sceneAsset", this.behaviorTreeBuilderHttpRepository.getSceneAsset(model.sceneId));
|
||||
|
||||
this.isLoading = false;
|
||||
this.reteForceUpdateObserver?.emit("");
|
||||
},
|
||||
|
|
|
@ -1,38 +1,40 @@
|
|||
import React from "react"
|
||||
import { observer } from "mobx-react-lite"
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { message } from "antd";
|
||||
import { CameraDeviceStore } from "./camera_device_store"
|
||||
import { CameraDeviceStore } from "./camera_device_store";
|
||||
import { IPropsForm } from "../forms";
|
||||
import { IDeviceDependency } from "../../../../../../core/model/skill_model";
|
||||
import { CoreButton } from "../../../../../../core/ui/button/button";
|
||||
import { CoreSelect } from "../../../../../../core/ui/select/select";
|
||||
import { CoreText, CoreTextType } from "../../../../../../core/ui/text/text";
|
||||
|
||||
|
||||
|
||||
|
||||
import { SidViewModel } from "../../../../../../core/model/device_dependency_view_model";
|
||||
|
||||
export const CameraDeviceForm = observer((props: IPropsForm<Partial<IDeviceDependency>>) => {
|
||||
const [store] = React.useState(() => new CameraDeviceStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, [store]);
|
||||
return (
|
||||
<div style={{ border: '1px solid', margin: 10, padding: 10 }}>
|
||||
<CoreText text={"Cameras"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
<CoreSelect
|
||||
items={store.cameras?.camera.map((el) => el.sid) ?? []}
|
||||
value={props.dependency?.sid ?? ""}
|
||||
label={'Выберите камеру'}
|
||||
onChange={(value: string) =>
|
||||
store.updateForm({ sid: value })
|
||||
|
||||
} />
|
||||
<CoreButton style={{ margin: 10, width: 100 }} text="OK" onClick={() => {
|
||||
store.viewModel.valid().fold((s) => {
|
||||
props.onChange(s);
|
||||
}, (e) => message.error(e))
|
||||
}} />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
const [store] = React.useState(() => new CameraDeviceStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, [store]);
|
||||
return (
|
||||
<div style={{ border: "1px solid", margin: 10, padding: 10 }}>
|
||||
<CoreText text={"Cameras"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
<CoreSelect
|
||||
items={store.cameras?.camera.map((el) => el.sid) ?? []}
|
||||
value={props.dependency?.sid ?? ""}
|
||||
label={"Выберите камеру"}
|
||||
onChange={(value: string) => store.updateForm({ sid: value })}
|
||||
/>
|
||||
<CoreButton
|
||||
style={{ margin: 10, width: 100 }}
|
||||
text="OK"
|
||||
onClick={async () => {
|
||||
(await store.viewModel.valid<SidViewModel>()).fold(
|
||||
(s) => {
|
||||
props.onChange(s);
|
||||
},
|
||||
(e) => message.error(e)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -16,25 +16,38 @@ export const TopicsForm = observer((props: IPropsForm<Partial<TopicDependencyVie
|
|||
store.init();
|
||||
}, [store, props]);
|
||||
|
||||
return <div style={{ border: '1px solid', margin: 10, padding: 10 }}>
|
||||
<CoreText text={"Topics"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
<CoreSelect
|
||||
items={store.topics?.topics?.map((el) => el.name) ?? []}
|
||||
value={props.dependency?.sid ?? ""}
|
||||
label={'Выберите топик'}
|
||||
onChange={(value: string) =>
|
||||
store.updateForm({ sid: value })
|
||||
} />
|
||||
return (
|
||||
<div style={{ border: "1px solid", margin: 10, padding: 10 }}>
|
||||
<CoreText text={"Topics"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
<CoreSelect
|
||||
items={store.topics?.topics?.map((el) => el.name) ?? []}
|
||||
value={props.dependency?.sid ?? ""}
|
||||
label={"Выберите топик"}
|
||||
onChange={(value: string) => store.updateForm({ sid: value })}
|
||||
/>
|
||||
|
||||
<div>is input: <CoreSwitch isSelected={store.viewModel.axis} id={""} onChange={(status: boolean, id: string) => {
|
||||
console.log(200)
|
||||
store.updateForm({ axis: !status })
|
||||
|
||||
}} /></div>
|
||||
<CoreButton style={{ margin: 10, width: 100 }} text="OK" onClick={() => {
|
||||
store.viewModel.valid().fold((s) => {
|
||||
props.onChange(s);
|
||||
}, (e) => message.error(e))
|
||||
}} />
|
||||
</div>;
|
||||
<div>
|
||||
is input:{" "}
|
||||
<CoreSwitch
|
||||
isSelected={store.viewModel.axis}
|
||||
id={""}
|
||||
onChange={(status: boolean, id: string) => {
|
||||
store.updateForm({ axis: !status });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<CoreButton
|
||||
style={{ margin: 10, width: 100 }}
|
||||
text="OK"
|
||||
onClick={async () => {
|
||||
(await store.viewModel.valid<TopicDependencyViewModel>()).fold(
|
||||
(s) => {
|
||||
props.onChange(s);
|
||||
},
|
||||
(e) => message.error(e)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -6,16 +6,22 @@ import { TopicsFormHttpRepository } from "./topics_form_http_repository";
|
|||
import { Topics } from "../../../../../../core/model/topics";
|
||||
|
||||
export class TopicsFormStore extends FormState<TopicDependencyViewModel, CoreError> {
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
topics?: Topics;
|
||||
viewModel: TopicDependencyViewModel = TopicDependencyViewModel.empty();
|
||||
cameraDeviceHttpRepository: TopicsFormHttpRepository = new TopicsFormHttpRepository();
|
||||
errorHandingStrategy = (error: CoreError) => { }
|
||||
init = async (navigate?: NavigateFunction | undefined) => {
|
||||
await this.mapOk('topics', this.cameraDeviceHttpRepository.getAllTopics())
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
topics?: Topics;
|
||||
viewModel: TopicDependencyViewModel = TopicDependencyViewModel.empty();
|
||||
cameraDeviceHttpRepository: TopicsFormHttpRepository = new TopicsFormHttpRepository();
|
||||
errorHandingStrategy = (error: CoreError) => {};
|
||||
init = async (navigate?: NavigateFunction | undefined) => {
|
||||
try {
|
||||
throw new Error('213')
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// await this.mapOk('topics', this.cameraDeviceHttpRepository.getAllTopics())
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { observer } from "mobx-react-lite";
|
||||
import React from "react";
|
||||
|
||||
import { Select, message } from "antd";
|
||||
import { WeightsFormStore } from "./weights_store";
|
||||
import { IWeightsDependency } from "../../../../../../core/model/skill_model";
|
||||
|
@ -47,9 +46,9 @@ export const WeightsForm = observer((props: IWeightsFormProps) => {
|
|||
placeholder="Выберите деталь"
|
||||
optionFilterProp="children"
|
||||
defaultValue={props.dependency?.weights_name}
|
||||
onChange={(e) => {
|
||||
store.updateForm({ weights_name: e });
|
||||
store.updateWeights(e);
|
||||
onChange={(text) => {
|
||||
store.updateForm({ weights_name: text });
|
||||
store.updateWeights(text);
|
||||
}}
|
||||
filterOption={(input: string, option?: { label: string; value: string }) =>
|
||||
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
|
||||
|
|
|
@ -135,6 +135,7 @@ export class CalculationStore extends UiDrawerFormState<CalculationModel, HttpEr
|
|||
};
|
||||
makeEditProcess = (el: CalculationModel) => {
|
||||
this.editProcess = el;
|
||||
this.loadClassInstance(CalculationModel, el);
|
||||
this.editDrawer(DrawersSkill.EDIT_SKILL, true);
|
||||
};
|
||||
deleteTemplate = async (el: CalculationModel) => {
|
||||
|
|
|
@ -36,19 +36,8 @@ export interface Asset {
|
|||
mesh: string;
|
||||
image: string;
|
||||
}
|
||||
|
||||
export class FormBuilderValidationModel {
|
||||
static vision(): FormBuilderValidationModel {
|
||||
return new FormBuilderValidationModel(
|
||||
`ENUM PRETRAIN = "true","false";`,
|
||||
`{
|
||||
"numberOfEpochs": \${numberOfEpochs:number:10},
|
||||
"selectDataset": \${<SelectDataset/>:OBJECT:{"dataset": {}},
|
||||
"pretrain": \${pretrain:Enum<PRETRAIN>:true}
|
||||
}`,
|
||||
[],
|
||||
''
|
||||
);
|
||||
}
|
||||
public result: string;
|
||||
public context: string;
|
||||
public form: string[];
|
||||
|
@ -59,6 +48,11 @@ export class FormBuilderValidationModel {
|
|||
this.form = form;
|
||||
this.output = output;
|
||||
}
|
||||
static isEmpty = (formBuilderValidationModel: FormBuilderValidationModel) =>
|
||||
formBuilderValidationModel.context.isEmpty() &&
|
||||
formBuilderValidationModel.result.isEmpty() &&
|
||||
formBuilderValidationModel.form.isEmpty();
|
||||
|
||||
static datasetEmpty() {
|
||||
return new FormBuilderValidationModel(datasetFormMockContext, datasetFormMockResult, [], defaultFormValue);
|
||||
}
|
||||
|
@ -71,13 +65,24 @@ export class FormBuilderValidationModel {
|
|||
static creteDataSetTest() {
|
||||
return new FormBuilderValidationModel(``, scene, [], "");
|
||||
}
|
||||
static vision(): FormBuilderValidationModel {
|
||||
return new FormBuilderValidationModel(
|
||||
`ENUM PRETRAIN = "true","false";`,
|
||||
`{
|
||||
"numberOfEpochs": \${numberOfEpochs:number:10},
|
||||
"selectDataset": \${<SelectDataset/>:OBJECT:{"dataset": {}},
|
||||
"pretrain": \${pretrain:Enum<PRETRAIN>:true}
|
||||
}`,
|
||||
[],
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
||||
export const scene = `{
|
||||
"center_shell": [\${CENTER_SHELL_1:number:0}, \${CENTER_SHELL_2:number:0}, \${CENTER_SHELL_3:number:0}],
|
||||
"scene":\${<SelectScene/>:OBJECT:{"details": []}
|
||||
}`;
|
||||
|
||||
// {"name":"body_up","isSelect":true,"part_path":"parts/objects/body_up.stl","material_path":"","inertia":{"ixx":0.1,"ixy":0,"ixz":0,"iyy":0.1,"iyz":0,"izz":0.1},"visual":".dae","collision":".stl","stlUrl":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/parts/objects/body_up.stl","glUrl":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_up.glb","daeUrl":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_up.dae","objUrl":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_up.obj","image":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_up.png","solidType":"active"}
|
||||
export class DataSetModel {
|
||||
dataSetObjects: string[];
|
||||
datasetType: string;
|
||||
|
@ -128,11 +133,12 @@ export class DataSetModel {
|
|||
|
||||
export const datasetTypes = ["Object Detection - YOLOv8", "Pose Estimation - DOPE"];
|
||||
|
||||
export const datasetFormMockResult = `{
|
||||
export const datasetFormMockResult = `
|
||||
{
|
||||
"typedataset": \${typedataset:Enum<T>:ObjectDetection},
|
||||
"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}]
|
||||
"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}]
|
||||
},
|
||||
"selectParts":\${<SelectScene/>:OBJECT:{"details": []},
|
||||
"scene":{
|
||||
|
@ -203,3 +209,11 @@ export const defaultFormValue: any = {
|
|||
camera_position: { center_shell: [0, 0, 0], radius_range: [1, 1.4], elevation_range: [10, 90] },
|
||||
generation: { n_cam_pose: 5, n_sample_on_pose: 3, n_series: 100, image_format: "JPEG", image_size_wh: [640, 480] },
|
||||
};
|
||||
|
||||
// `{
|
||||
// "camera_name": \${CAMERA_NAME:string: },
|
||||
// "camera_namespace": \${CAMERA_NAMESPACE:string: },
|
||||
// "staticProp":{
|
||||
// "e23e":""
|
||||
// }
|
||||
// }`;
|
||||
|
|
|
@ -3,6 +3,7 @@ import { EnvelopmentViewModel } from "./envelopment_view_model";
|
|||
export interface Parts {
|
||||
isSelect?: boolean;
|
||||
name: string;
|
||||
mass?:number;
|
||||
part_path: string;
|
||||
material_path: string;
|
||||
stlUrl: string;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { HttpMethod, HttpRepository } from "../../core/repository/core_http_repository";
|
||||
import { UUID } from "../all_projects/data/project_http_repository";
|
||||
import { DigitalTwinsModel } from "./digital_twins_model";
|
||||
|
||||
export class DigitalTwinsHttpRepository extends HttpRepository {
|
||||
featureApi = `/digital/twins/template`;
|
||||
subFeatureApi = `/digital/twins/instance`;
|
||||
getAllDigitalTwinsTemplate = () => this._jsonRequest(HttpMethod.GET, this.featureApi);
|
||||
getAllDigitalTwinsInstance = () => this._jsonRequest(HttpMethod.GET, this.subFeatureApi);
|
||||
createNewDigitalTwinsTemplate = (model: DigitalTwinsModel) =>
|
||||
this._jsonRequest(HttpMethod.POST, this.featureApi, model);
|
||||
createNewDigitalTwinsInstance = (model: DigitalTwinsModel) =>
|
||||
this._jsonRequest<UUID>(HttpMethod.POST, this.subFeatureApi, model);
|
||||
deleteDigitalTwinsTemplate = (id: string) => this._jsonRequest(HttpMethod.DELETE, `${this.featureApi}?id=${id}`);
|
||||
deleteDigitalTwinsInstance = (id: string) => this._jsonRequest(HttpMethod.DELETE, `${this.subFeatureApi}?id=${id}`);
|
||||
execDigitalTwinsInstance = (id: UUID) =>
|
||||
this._jsonRequest(HttpMethod.POST, `${this.subFeatureApi}/exec/instance?id=${id.id}`);
|
||||
}
|
43
ui/src/features/digital_twins/digital_twins_model.ts
Normal file
43
ui/src/features/digital_twins/digital_twins_model.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { ValidationModel } from "../../core/model/validation_model";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsString } from "class-validator";
|
||||
import { FormBuilderValidationModel } from "../dataset/dataset_model";
|
||||
|
||||
export enum DigitalTwinsTypes {
|
||||
CAMERA = "CAMERA",
|
||||
ROBOT = "ROBOT",
|
||||
}
|
||||
export class Interfaces {
|
||||
@IsString()
|
||||
cmd: string;
|
||||
}
|
||||
|
||||
export class DigitalTwinsModel extends ValidationModel {
|
||||
_id?: string;
|
||||
path: string = "";
|
||||
name: string = "";
|
||||
instanceName: string = "";
|
||||
@IsEnum(DigitalTwinsTypes)
|
||||
entity: DigitalTwinsTypes;
|
||||
@IsString()
|
||||
description: string;
|
||||
@IsString()
|
||||
command: string;
|
||||
@Type(() => Interfaces)
|
||||
interfaces: Interfaces;
|
||||
formBuilder = FormBuilderValidationModel.empty();
|
||||
static empty() {
|
||||
return new DigitalTwinsModel();
|
||||
}
|
||||
}
|
||||
export interface DigitalTwinsTemplate {
|
||||
interfaces: Interfaces;
|
||||
_id?: string;
|
||||
path: string;
|
||||
name: string;
|
||||
entity: string;
|
||||
description: string;
|
||||
command: string;
|
||||
__v: string;
|
||||
formBuilder?: FormBuilderValidationModel;
|
||||
}
|
149
ui/src/features/digital_twins/digital_twins_screen.tsx
Normal file
149
ui/src/features/digital_twins/digital_twins_screen.tsx
Normal file
|
@ -0,0 +1,149 @@
|
|||
import React from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { DigitalTwinStoreType, DigitalTwinsStore, DrawersDigitalTwin } from "./digital_twins_store";
|
||||
import { Drawer, Modal } from "antd";
|
||||
import { CoreButton } from "../../core/ui/button/button";
|
||||
import { FormBuilder } from "../../core/ui/form_builder/form_builder";
|
||||
import { CoreInput } from "../../core/ui/input/input";
|
||||
import { CoreSelect } from "../../core/ui/select/select";
|
||||
import { DigitalTwinsModel, DigitalTwinsTypes } from "./digital_twins_model";
|
||||
import { match } from "ts-pattern";
|
||||
|
||||
export const DigitalTwinsScreenPath = "/digital_twins";
|
||||
|
||||
export const DigitalTwinsScreen = observer(() => {
|
||||
const [store] = React.useState(() => new DigitalTwinsStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: "flex" }}>
|
||||
<CoreButton
|
||||
text="Новый шаблон двойника"
|
||||
filled={true}
|
||||
onClick={() => store.editDrawer(DrawersDigitalTwin.newTwinTemplate, true)}
|
||||
/>
|
||||
<CoreButton
|
||||
text="Новый двойник"
|
||||
filled={true}
|
||||
onClick={() => store.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, true)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Drawer
|
||||
width={(window.innerWidth / 100) * 50}
|
||||
title={store.titleDrawer}
|
||||
destroyOnClose={true}
|
||||
onClose={() => {
|
||||
store.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false);
|
||||
store.type = DigitalTwinStoreType.selectTwinTemplate;
|
||||
store.viewModel = DigitalTwinsModel.empty();
|
||||
}}
|
||||
open={store.drawers.find((el) => el.name === DrawersDigitalTwin.newInstanceTwinTemplate)?.status}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
|
||||
{match(store.type)
|
||||
.with(DigitalTwinStoreType.editInstanceTemplate, () => (
|
||||
<>
|
||||
<CoreInput onChange={(text) => store.updateForm({ instanceName: text })} label={"Instance name"} />
|
||||
<FormBuilder
|
||||
formBuilder={store.viewModel.formBuilder}
|
||||
onChange={(change) => store.updateForm({ formBuilder: change })}
|
||||
/>
|
||||
</>
|
||||
))
|
||||
.with(DigitalTwinStoreType.selectTwinTemplate, () => (
|
||||
<>
|
||||
{store.digitalTwinsTemplates?.map((el, i) => (
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
backgroundColor: "rgba(104, 80, 164, 1)",
|
||||
width: 180,
|
||||
height: 180,
|
||||
borderRadius: 10,
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
}}
|
||||
>
|
||||
<div onClick={() => store.deleteDigitalTwinsTemplate(el._id!)}>DELETE</div>
|
||||
<div onClick={() => store.createInstanceTwins(el)}>CREATE</div>
|
||||
{el.name}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
))
|
||||
.otherwise(() => (
|
||||
<></>
|
||||
))}
|
||||
<div style={{ display: "flex" }}>
|
||||
<CoreButton text="Сохранить" filled={true} onClick={() => store.saveInstanceDigitalTwin()} />
|
||||
<div style={{ width: 10 }} />
|
||||
<CoreButton
|
||||
text="Отмена"
|
||||
onClick={() => store.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
|
||||
<Drawer
|
||||
width={(window.innerWidth / 100) * 50}
|
||||
title={store.titleDrawer}
|
||||
destroyOnClose={true}
|
||||
onClose={() => store.editDrawer(DrawersDigitalTwin.newTwinTemplate, false)}
|
||||
open={store.drawers.find((el) => el.name === DrawersDigitalTwin.newTwinTemplate)?.status}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
|
||||
<CoreInput onChange={(text) => store.updateForm({ name: text })} label={"Имя"} />
|
||||
<CoreSelect
|
||||
items={Object.keys(DigitalTwinsTypes)}
|
||||
value={Object.keys(DigitalTwinsTypes)[0]}
|
||||
label={"entity"}
|
||||
onChange={(value: string) => store.updateForm({ entity: value as any })}
|
||||
/>
|
||||
<CoreInput onChange={(text) => store.updateForm({ description: text })} label={"Описание"} />
|
||||
<CoreInput onChange={(text) => store.updateForm({ command: text })} label={"Команда"} />
|
||||
<CoreInput onChange={(text) => store.updateForm({ interfaces: { cmd: text } })} label={"Cmd"} />
|
||||
<CoreInput
|
||||
label="FormBuilder Result"
|
||||
onChange={(text) => (store.viewModel.formBuilder.result = text)}
|
||||
style={{ height: 200, overflow: "overlay" }}
|
||||
/>
|
||||
<CoreInput
|
||||
label="FormBuilder Context"
|
||||
onChange={(text) => (store.viewModel.formBuilder.context = text)}
|
||||
style={{ height: 200, overflow: "overlay" }}
|
||||
/>
|
||||
<div style={{ height: 10 }} />
|
||||
<CoreButton
|
||||
style={{ width: 206 }}
|
||||
text={"Посмотреть FormBuilder "}
|
||||
onClick={() => (store.isModalOpen = true)}
|
||||
/>
|
||||
<div style={{ height: 100 }} />
|
||||
|
||||
<div style={{ display: "flex" }}>
|
||||
<CoreButton text="Сохранить" filled={true} onClick={() => store.saveTemplateDigitalTwin()} />
|
||||
<div style={{ width: 10 }} />
|
||||
<CoreButton text="Отмена" onClick={() => store.editDrawer(DrawersDigitalTwin.newTwinTemplate, false)} />
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
|
||||
<Modal
|
||||
destroyOnClose={true}
|
||||
open={store.isModalOpen}
|
||||
footer={null}
|
||||
closable={false}
|
||||
closeIcon={null}
|
||||
onCancel={() => {
|
||||
store.isModalOpen = false;
|
||||
}}
|
||||
>
|
||||
<FormBuilder formBuilder={store.viewModel.formBuilder} onChange={() => {}} />
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
});
|
68
ui/src/features/digital_twins/digital_twins_store.ts
Normal file
68
ui/src/features/digital_twins/digital_twins_store.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { UiDrawerFormState } from "../../core/store/base_store";
|
||||
import { DigitalTwinsModel, DigitalTwinsTemplate as DigitalTwins } from "./digital_twins_model";
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import { message } from "antd";
|
||||
import { DigitalTwinsHttpRepository } from "./digital_twins_http_repository";
|
||||
import { HttpError } from "../../core/repository/core_http_repository";
|
||||
import { match } from "ts-pattern";
|
||||
|
||||
export enum DrawersDigitalTwin {
|
||||
newTwinTemplate = "Новый шаблон двойника",
|
||||
newInstanceTwinTemplate = "Новый инстанц шаблона двойника",
|
||||
}
|
||||
export enum DigitalTwinStoreType {
|
||||
selectTwinTemplate = "selectTwinTemplate",
|
||||
editInstanceTemplate = "editInstanceTemplate",
|
||||
}
|
||||
export class DigitalTwinsStore extends UiDrawerFormState<DigitalTwinsModel, HttpError> {
|
||||
type: DigitalTwinStoreType = DigitalTwinStoreType.selectTwinTemplate;
|
||||
digitalTwinsTemplates?: DigitalTwins[];
|
||||
digitalTwinsInstances?: DigitalTwins[];
|
||||
digitalTwinsHttpRepository: DigitalTwinsHttpRepository = new DigitalTwinsHttpRepository();
|
||||
viewModel: DigitalTwinsModel = DigitalTwinsModel.empty();
|
||||
isModalOpen: boolean = false;
|
||||
init = async (_navigate?: NavigateFunction | undefined): Promise<any> => this.refresh();
|
||||
constructor() {
|
||||
super(DrawersDigitalTwin);
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
refresh = async () => {
|
||||
this.mapOk("digitalTwinsTemplates", this.digitalTwinsHttpRepository.getAllDigitalTwinsTemplate());
|
||||
this.mapOk("digitalTwinsInstances", this.digitalTwinsHttpRepository.getAllDigitalTwinsInstance());
|
||||
};
|
||||
saveInstanceDigitalTwin = async () =>
|
||||
match(this.type)
|
||||
.with(DigitalTwinStoreType.editInstanceTemplate, async () => {
|
||||
|
||||
this.viewModel._id = undefined;
|
||||
(await this.digitalTwinsHttpRepository.createNewDigitalTwinsInstance(this.viewModel)).map(async (id) => {
|
||||
await this.digitalTwinsHttpRepository.execDigitalTwinsInstance(id);
|
||||
await this.refresh();
|
||||
});
|
||||
this.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false);
|
||||
})
|
||||
.with(DigitalTwinStoreType.selectTwinTemplate, () => {
|
||||
console.log(200);
|
||||
|
||||
// this.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false),
|
||||
// await (
|
||||
// await this.digitalTwinsHttpRepository.createNewDigitalTwinsInstance(this.viewModel)
|
||||
// ).map(() => this.refresh())
|
||||
});
|
||||
createInstanceTwins = (el: DigitalTwins): void => {
|
||||
this.loadDependency(el as any);
|
||||
this.type = DigitalTwinStoreType.editInstanceTemplate;
|
||||
};
|
||||
saveTemplateDigitalTwin = async () =>
|
||||
(await this.viewModel.valid<DigitalTwinsModel>()).fold(
|
||||
async (model) => {
|
||||
(await this.digitalTwinsHttpRepository.createNewDigitalTwinsTemplate(model)).map(() => {
|
||||
this.refresh();
|
||||
});
|
||||
},
|
||||
async (e) => message.error(e)
|
||||
);
|
||||
deleteDigitalTwinsTemplate = async (id: string) =>
|
||||
(await this.digitalTwinsHttpRepository.deleteDigitalTwinsTemplate(id)).map(() => this.refresh());
|
||||
}
|
|
@ -88,3 +88,4 @@ export class RobotFormStore extends FormState<RobotModel, CoreError> {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
12
ui/src/features/topics/topic_view_model.ts
Normal file
12
ui/src/features/topics/topic_view_model.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { ValidationModel } from "../../core/model/validation_model";
|
||||
|
||||
export class TopicViewModel extends ValidationModel {
|
||||
static empty() {
|
||||
return new TopicViewModel();
|
||||
}
|
||||
}
|
||||
export interface ITopicModel {
|
||||
digitalTwinId?: string;
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
5
ui/src/features/topics/topics_repository.ts
Normal file
5
ui/src/features/topics/topics_repository.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { HttpMethod, HttpRepository } from "../../core/repository/core_http_repository";
|
||||
|
||||
export class TopicsHttpRepository extends HttpRepository {
|
||||
getAllTopics = () => this._jsonRequest(HttpMethod.GET, "/topics");
|
||||
}
|
22
ui/src/features/topics/topics_screen.tsx
Normal file
22
ui/src/features/topics/topics_screen.tsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { observer } from "mobx-react-lite";
|
||||
import { TopicsStore } from "./topics_store";
|
||||
import React from "react";
|
||||
|
||||
export const TopicsScreenPath = "/topics";
|
||||
|
||||
export const TopicsScreen = observer(() => {
|
||||
const [store] = React.useState(() => new TopicsStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
{store.topics?.map((el) => (
|
||||
<div>
|
||||
<div>{el.name}</div>
|
||||
<div>{el.type}</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
});
|
19
ui/src/features/topics/topics_store.ts
Normal file
19
ui/src/features/topics/topics_store.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { FormState } from "../../core/store/base_store";
|
||||
import { HttpError } from "../../core/repository/core_http_repository";
|
||||
import { ITopicModel, TopicViewModel as TopicModel } from "./topic_view_model";
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import { TopicsHttpRepository } from "./topics_repository";
|
||||
|
||||
export class TopicsStore extends FormState<TopicModel, HttpError> {
|
||||
viewModel: TopicModel = TopicModel.empty();
|
||||
topics?: ITopicModel[];
|
||||
topicsHttpRepository: TopicsHttpRepository = new TopicsHttpRepository();
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
init = async (navigate?: NavigateFunction | undefined) => {
|
||||
await this.mapOk("topics", this.topicsHttpRepository.getAllTopics());
|
||||
};
|
||||
}
|
|
@ -22,4 +22,3 @@ root.render(
|
|||
</SocketLister>
|
||||
</>
|
||||
);
|
||||
|
22
web_p/get_interfaces_mock.py
Normal file
22
web_p/get_interfaces_mock.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
import shutil
|
||||
import argparse
|
||||
import os.path
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--path")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def copy_and_move_folder(src, dst):
|
||||
try:
|
||||
if os.path.exists(dst):
|
||||
shutil.rmtree(dst)
|
||||
shutil.copytree(src, dst)
|
||||
print(f"Folder {src} successfully copied")
|
||||
except shutil.Error as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
|
||||
source_folder = os.path.dirname(os.path.abspath(__file__)) + "/interfaces/"
|
||||
|
||||
copy_and_move_folder(source_folder, args.path)
|
124
web_p/interfaces/topics.json
Normal file
124
web_p/interfaces/topics.json
Normal file
|
@ -0,0 +1,124 @@
|
|||
{
|
||||
"topics": [
|
||||
{
|
||||
"name": "/cartesian_force_controller/current_pose",
|
||||
"type": "geometry_msgs/msg/PoseStamped"
|
||||
},
|
||||
{
|
||||
"name": "/cartesian_force_controller/current_twist",
|
||||
"type": "geometry_msgs/msg/TwistStamped"
|
||||
},
|
||||
{
|
||||
"name": "/cartesian_force_controller/target_wrench",
|
||||
"type": "geometry_msgs/msg/WrenchStamped"
|
||||
},
|
||||
{
|
||||
"name": "/cartesian_force_controller/transition_event",
|
||||
"type": "lifecycle_msgs/msg/TransitionEvent"
|
||||
},
|
||||
{
|
||||
"name": "/cartesian_motion_controller/current_pose",
|
||||
"type": "geometry_msgs/msg/PoseStamped"
|
||||
},
|
||||
{
|
||||
"name": "/cartesian_motion_controller/current_twist",
|
||||
"type": "geometry_msgs/msg/TwistStamped"
|
||||
},
|
||||
{
|
||||
"name": "/cartesian_motion_controller/target_frame",
|
||||
"type": "geometry_msgs/msg/PoseStamped"
|
||||
},
|
||||
{
|
||||
"name": "/cartesian_motion_controller/transition_event",
|
||||
"type": "lifecycle_msgs/msg/TransitionEvent"
|
||||
},
|
||||
{
|
||||
"name": "/clock",
|
||||
"type": "rosgraph_msgs/msg/Clock"
|
||||
},
|
||||
{
|
||||
"name": "/dynamic_joint_states",
|
||||
"type": "control_msgs/msg/DynamicJointState"
|
||||
},
|
||||
{
|
||||
"name": "/force_torque_sensor_broadcaster/transition_event",
|
||||
"type": "lifecycle_msgs/msg/TransitionEvent"
|
||||
},
|
||||
{
|
||||
"name": "/force_torque_sensor_broadcaster/wrench",
|
||||
"type": "geometry_msgs/msg/WrenchStamped"
|
||||
},
|
||||
{
|
||||
"name": "/gripper_control_action_server/gripper_controller/commands",
|
||||
"type": "std_msgs/msg/Float64MultiArray"
|
||||
},
|
||||
{
|
||||
"name": "/gripper_controller/transition_event",
|
||||
"type": "lifecycle_msgs/msg/TransitionEvent"
|
||||
},
|
||||
{
|
||||
"name": "/gz_enviroment/transition_event",
|
||||
"type": "lifecycle_msgs/msg/TransitionEvent"
|
||||
},
|
||||
{
|
||||
"name": "/joint_effort_controller/commands",
|
||||
"type": "std_msgs/msg/Float64MultiArray"
|
||||
},
|
||||
{
|
||||
"name": "/joint_effort_controller/transition_event",
|
||||
"type": "lifecycle_msgs/msg/TransitionEvent"
|
||||
},
|
||||
{
|
||||
"name": "/joint_state_broadcaster/transition_event",
|
||||
"type": "lifecycle_msgs/msg/TransitionEvent"
|
||||
},
|
||||
{
|
||||
"name": "/joint_states",
|
||||
"type": "sensor_msgs/msg/JointState"
|
||||
},
|
||||
{
|
||||
"name": "/joint_trajectory_controller/controller_state",
|
||||
"type": "control_msgs/msg/JointTrajectoryControllerState"
|
||||
},
|
||||
{
|
||||
"name": "/joint_trajectory_controller/joint_trajectory",
|
||||
"type": "trajectory_msgs/msg/JointTrajectory"
|
||||
},
|
||||
{
|
||||
"name": "/joint_trajectory_controller/state",
|
||||
"type": "control_msgs/msg/JointTrajectoryControllerState"
|
||||
},
|
||||
{
|
||||
"name": "/joint_trajectory_controller/transition_event",
|
||||
"type": "lifecycle_msgs/msg/TransitionEvent"
|
||||
},
|
||||
{
|
||||
"name": "/rgbd_camera/camera_info",
|
||||
"type": "sensor_msgs/msg/CameraInfo"
|
||||
},
|
||||
{
|
||||
"name": "/rgbd_camera/depth_image",
|
||||
"type": "sensor_msgs/msg/Image"
|
||||
},
|
||||
{
|
||||
"name": "/rgbd_camera/image",
|
||||
"type": "sensor_msgs/msg/Image"
|
||||
},
|
||||
{
|
||||
"name": "/rgbd_camera/points",
|
||||
"type": "sensor_msgs/msg/PointCloud2"
|
||||
},
|
||||
{
|
||||
"name": "/robot_description",
|
||||
"type": "std_msgs/msg/String"
|
||||
},
|
||||
{
|
||||
"name": "/tf",
|
||||
"type": "tf2_msgs/msg/TFMessage"
|
||||
},
|
||||
{
|
||||
"name": "/tf_static",
|
||||
"type": "tf2_msgs/msg/TFMessage"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue