deleted unnecessary files
added new features
This commit is contained in:
parent
dffc73c30f
commit
6840402b1f
119 changed files with 1835 additions and 1522 deletions
|
@ -26,6 +26,9 @@ declare global {
|
|||
interface String {
|
||||
isEmpty(): boolean;
|
||||
isNotEmpty(): boolean;
|
||||
replaceMany(searchValues: string[], replaceValue: string): string;
|
||||
isEqual(str: string): boolean;
|
||||
isEqualMany(str: string[]): boolean;
|
||||
}
|
||||
interface Map<K, V> {
|
||||
addValueOrMakeCallback(key: K, value: V, callBack: CallBackVoidFunction): void;
|
||||
|
@ -37,8 +40,8 @@ declare global {
|
|||
}
|
||||
}
|
||||
export const extensions = () => {
|
||||
ArrayExtensions();
|
||||
StringExtensions();
|
||||
ArrayExtensions();
|
||||
NumberExtensions();
|
||||
MapExtensions();
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-extend-native */
|
||||
export const StringExtensions = () => {
|
||||
if ("".isEmpty === undefined) {
|
||||
// eslint-disable-next-line no-extend-native
|
||||
|
@ -11,4 +12,28 @@ export const StringExtensions = () => {
|
|||
return this.length !== 0;
|
||||
};
|
||||
}
|
||||
if ("".replaceMany === undefined) {
|
||||
String.prototype.replaceMany = function (searchValues: string[], replaceValue: string) {
|
||||
let result = this as string;
|
||||
searchValues.forEach((el) => {
|
||||
result = result.replaceAll(el, replaceValue);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
}
|
||||
if ("".isEqual === undefined) {
|
||||
String.prototype.isEqual = function (str: string) {
|
||||
return this === str;
|
||||
};
|
||||
}
|
||||
if ("".isEqualMany === undefined) {
|
||||
String.prototype.isEqualMany = function (str: string[]) {
|
||||
for (const el of str) {
|
||||
if (el === this) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
172
ui/src/core/model/robossembler_assets.ts
Normal file
172
ui/src/core/model/robossembler_assets.ts
Normal file
|
@ -0,0 +1,172 @@
|
|||
import { IsArray, IsEnum, IsNumber, IsOptional, IsString, ValidateNested } from "class-validator";
|
||||
import { Type } from "class-transformer";
|
||||
|
||||
export class Gravity {
|
||||
@IsNumber()
|
||||
x: number;
|
||||
@IsNumber()
|
||||
y: number;
|
||||
@IsNumber()
|
||||
z: number;
|
||||
}
|
||||
|
||||
export class Pose {
|
||||
@IsNumber()
|
||||
x: number;
|
||||
@IsNumber()
|
||||
y: number;
|
||||
@IsNumber()
|
||||
z: number;
|
||||
@IsNumber()
|
||||
roll: number;
|
||||
@IsNumber()
|
||||
pitch: number;
|
||||
@IsNumber()
|
||||
yaw: number;
|
||||
}
|
||||
|
||||
export class Position {
|
||||
@IsNumber()
|
||||
x: number;
|
||||
@IsNumber()
|
||||
y: number;
|
||||
@IsNumber()
|
||||
z: number;
|
||||
}
|
||||
|
||||
export enum InstanceType {
|
||||
RGB_CAMERA = "rgb_camera",
|
||||
SCENE_SIMPLE_OBJECT = "scene_simple_object",
|
||||
}
|
||||
|
||||
abstract class CoreInstances {}
|
||||
|
||||
export class Instance extends CoreInstances {
|
||||
@IsEnum(InstanceType)
|
||||
instanceType: InstanceType;
|
||||
@Type(() => Position)
|
||||
position: Position;
|
||||
@IsArray()
|
||||
quaternion: number[];
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
instanceAt: null | string = null;
|
||||
}
|
||||
|
||||
export class SceneSimpleObject extends Instance {}
|
||||
|
||||
export class InstanceRgbCamera extends Instance {
|
||||
@IsString()
|
||||
cameraLink: string;
|
||||
@IsString()
|
||||
topicCameraInfo: string;
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
topicDepth: string | null;
|
||||
@IsString()
|
||||
topicImage: string;
|
||||
}
|
||||
export class Asset {
|
||||
@IsString()
|
||||
name: string;
|
||||
@IsString()
|
||||
ixx: string;
|
||||
@IsString()
|
||||
ixy: string;
|
||||
@IsString()
|
||||
ixz: string;
|
||||
@IsString()
|
||||
iyy: string;
|
||||
@IsString()
|
||||
izz: string;
|
||||
@IsString()
|
||||
mass: string;
|
||||
@IsString()
|
||||
posX: string;
|
||||
@IsString()
|
||||
posY: string;
|
||||
@IsString()
|
||||
posZ: string;
|
||||
@IsString()
|
||||
eulerX: string;
|
||||
@IsString()
|
||||
eulerY: string;
|
||||
@IsString()
|
||||
eulerZ: string;
|
||||
@IsString()
|
||||
iyz: string;
|
||||
@IsString()
|
||||
meshPath: string;
|
||||
@IsString()
|
||||
friction: string;
|
||||
@IsString()
|
||||
centerMassX: string;
|
||||
@IsString()
|
||||
centerMassY: string;
|
||||
@IsString()
|
||||
centerMassZ: string;
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
actions: string[];
|
||||
}
|
||||
|
||||
export class Physics {
|
||||
@IsString()
|
||||
engine_name: string;
|
||||
@Type(() => Gravity)
|
||||
gravity: Gravity;
|
||||
}
|
||||
|
||||
export class RobossemblerAssets {
|
||||
@ValidateNested()
|
||||
@Type(() => Asset, {
|
||||
discriminator: {
|
||||
property: "type",
|
||||
subTypes: [
|
||||
{ value: InstanceRgbCamera, name: InstanceType.RGB_CAMERA },
|
||||
{ value: SceneSimpleObject, name: InstanceType.SCENE_SIMPLE_OBJECT },
|
||||
],
|
||||
},
|
||||
keepDiscriminatorProperty: true,
|
||||
})
|
||||
assets: Asset[];
|
||||
|
||||
@IsArray()
|
||||
@Type(() => Instance, {
|
||||
discriminator: {
|
||||
property: "type",
|
||||
subTypes: [
|
||||
{ value: InstanceRgbCamera, name: InstanceType.RGB_CAMERA },
|
||||
{ value: SceneSimpleObject, name: InstanceType.SCENE_SIMPLE_OBJECT },
|
||||
],
|
||||
},
|
||||
keepDiscriminatorProperty: true,
|
||||
})
|
||||
instances: Instance[];
|
||||
|
||||
@IsOptional()
|
||||
@ValidateNested()
|
||||
@Type(() => Physics)
|
||||
physics: Physics;
|
||||
|
||||
convertLocalPathsToServerPaths(server_address: string): RobossemblerAssets {
|
||||
this.assets = this.assets.map((el) => {
|
||||
el.meshPath = server_address + el.meshPath;
|
||||
return el;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
getAssetPath(assetName: string): string {
|
||||
const findElement = this.assets.find((el) => el.name === assetName);
|
||||
|
||||
if (findElement === undefined) {
|
||||
throw new Error("RobossemblerAssets.getAssetPath not found asset by name:" + assetName);
|
||||
}
|
||||
return findElement.meshPath;
|
||||
}
|
||||
|
||||
getAssetAtInstance(instanceAt: string): Asset {
|
||||
return this.assets.filter((el) => el.name === instanceAt)[0];
|
||||
}
|
||||
}
|
|
@ -35,11 +35,7 @@ import {
|
|||
} from "../../features/scene_manager/model/scene_assets";
|
||||
import { SceneMode } from "../../features/scene_manager/model/scene_view";
|
||||
import { throttle } from "../helper/throttle";
|
||||
import {
|
||||
InstanceRgbCamera,
|
||||
RobossemblerAssets,
|
||||
SceneSimpleObject,
|
||||
} from "../../features/scene_manager/model/robossembler_assets";
|
||||
import { Asset, InstanceRgbCamera, RobossemblerAssets, SceneSimpleObject } from "../model/robossembler_assets";
|
||||
import { CoreVector3 } from "../model/core_vector3";
|
||||
|
||||
export enum UserData {
|
||||
|
@ -157,6 +153,15 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
|
|||
}
|
||||
});
|
||||
}
|
||||
loadInstance(asset: Asset, loadCallback?: Function) {
|
||||
this.loader(
|
||||
asset.meshPath,
|
||||
loadCallback ? loadCallback : () => {},
|
||||
asset.name,
|
||||
new Vector3(Number(asset.posX), Number(asset.posY), Number(asset.posZ)),
|
||||
new Quaternion(0, 0, 0, 0)
|
||||
);
|
||||
}
|
||||
|
||||
setTransformMode(mode?: SceneMode) {
|
||||
switch (mode) {
|
||||
|
@ -283,18 +288,6 @@ export class CoreThreeRepository extends TypedEvent<BaseSceneItemModel> {
|
|||
floor.userData = {};
|
||||
floor.userData[UserData.cameraInitialization] = true;
|
||||
this.scene.add(floor);
|
||||
|
||||
const planeMesh = new Mesh(
|
||||
new PlaneGeometry(10, 10, 10, 10),
|
||||
new MeshBasicMaterial({ color: 0x808080, wireframe: true })
|
||||
);
|
||||
planeMesh.userData[UserData.selectedObject] = true;
|
||||
planeMesh.userData[UserData.objectForMagnetism] = true;
|
||||
planeMesh.rotation.x = -Math.PI / 2;
|
||||
this.makeCube(1);
|
||||
this.makeCube(2, new Vector3(20, 0, 10), "yellow");
|
||||
|
||||
this.scene.add(planeMesh);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -4,28 +4,19 @@ import {
|
|||
PipelineInstanceScreen,
|
||||
PipelineInstanceScreenPath,
|
||||
} from "../../features/pipeline_instance_main_screen/pipeline_instance_screen";
|
||||
import {
|
||||
SelectProjectScreen,
|
||||
SelectProjectScreenPath,
|
||||
} from "../../features/select_project/presentation/select_project";
|
||||
import {
|
||||
CreatePipelineScreen,
|
||||
CreatePipelineScreenPath,
|
||||
} from "../../features/create_pipeline/presentation/create_pipeline_screen";
|
||||
|
||||
import { CreateProjectScreen, CreateProjectScreenPath } from "../../features/create_project/create_project_screen";
|
||||
import {
|
||||
CreateTriggerScreenPath,
|
||||
TriggerScreen,
|
||||
} from "../../features/create_trigger/presentation/create_trigger_screen";
|
||||
import {
|
||||
CreateProcessScreen,
|
||||
CreateProcessScreenPath,
|
||||
} from "../../features/create_process/presentation/create_process_screen";
|
||||
import {
|
||||
CreateProjectInstancePath,
|
||||
CreateProjectInstanceScreen,
|
||||
} from "../../features/create_project_instance/create_project_instance";
|
||||
|
||||
import { SceneManger, SceneManagerPath } from "../../features/scene_manager/presentation/scene_manager";
|
||||
import {
|
||||
BehaviorTreeBuilderPath,
|
||||
BehaviorTreeBuilderScreen,
|
||||
} from "../../features/behavior_tree_builder/presentation/behavior_tree_builder_screen";
|
||||
import {
|
||||
StickObjectsMarkingScreen,
|
||||
StickObjectsMarkingScreenPath,
|
||||
} from "../../features/stick_objects_marking/stick_objects_marking_screen";
|
||||
import { DataSetScreen, DatasetsScreenPath } from "../../features/dataset/dataset_screen";
|
||||
|
||||
const idURL = ":id";
|
||||
|
||||
|
@ -38,32 +29,26 @@ export const router = createBrowserRouter([
|
|||
path: PipelineInstanceScreenPath + idURL,
|
||||
element: <PipelineInstanceScreen />,
|
||||
},
|
||||
{
|
||||
path: SelectProjectScreenPath,
|
||||
element: <SelectProjectScreen />,
|
||||
},
|
||||
{
|
||||
path: CreatePipelineScreenPath,
|
||||
element: <CreatePipelineScreen />,
|
||||
},
|
||||
|
||||
{
|
||||
path: CreateProjectScreenPath,
|
||||
element: <CreateProjectScreen />,
|
||||
},
|
||||
|
||||
{
|
||||
path: CreateTriggerScreenPath,
|
||||
element: <TriggerScreen />,
|
||||
},
|
||||
{
|
||||
path: CreateProcessScreenPath,
|
||||
element: <CreateProcessScreen />,
|
||||
},
|
||||
{
|
||||
path: CreateProjectInstancePath + idURL,
|
||||
element: <CreateProjectInstanceScreen />,
|
||||
},
|
||||
{
|
||||
path: SceneManagerPath + idURL,
|
||||
path: SceneManagerPath,
|
||||
element: <SceneManger />,
|
||||
},
|
||||
{
|
||||
path: BehaviorTreeBuilderPath,
|
||||
element: <BehaviorTreeBuilderScreen />,
|
||||
},
|
||||
{
|
||||
path: StickObjectsMarkingScreenPath,
|
||||
element: <StickObjectsMarkingScreen />,
|
||||
},
|
||||
{
|
||||
path: DatasetsScreenPath,
|
||||
element: <DataSetScreen />,
|
||||
},
|
||||
]);
|
||||
|
|
138
ui/src/core/ui/form_builder/form_builder.tsx
Normal file
138
ui/src/core/ui/form_builder/form_builder.tsx
Normal file
|
@ -0,0 +1,138 @@
|
|||
import * as React from "react";
|
||||
import { Input, Select, Button } from "antd";
|
||||
import { InputBuilderViewModel, InputType } from "./form_view_model";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { FormBuilderStore } from "./form_builder_store";
|
||||
import { extensions } from "../../extensions/extensions";
|
||||
import { FormBuilderValidationModel } from "../../../features/dataset/dataset_store";
|
||||
extensions();
|
||||
|
||||
export interface IFormBuilder {
|
||||
context: string;
|
||||
result: string;
|
||||
onChange: (change: FormBuilderValidationModel | undefined) => void;
|
||||
}
|
||||
|
||||
export const FormBuilder = observer((props: IFormBuilder) => {
|
||||
const [store] = React.useState(() => new FormBuilderStore());
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init(props.context, props.result);
|
||||
store.changerForm.on((event) => props.onChange(event));
|
||||
}, [store, props]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{store.isError ? (
|
||||
<>Error</>
|
||||
) : (
|
||||
<div>
|
||||
{store.formViewModel?.inputs.map((element) => {
|
||||
if (element.type.isEqual(InputType.ENUM)) {
|
||||
const values = element.values as string[];
|
||||
return (
|
||||
<>
|
||||
<div>{element.name}</div>
|
||||
|
||||
<Select
|
||||
defaultValue={element.defaultValue}
|
||||
style={{ width: 120 }}
|
||||
onChange={(e) => {
|
||||
store.changeTotalValue(element.id, e);
|
||||
}}
|
||||
options={values?.map((el) => {
|
||||
return { value: el };
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (element.type.isEqual(InputType.ARRAY)) {
|
||||
return (
|
||||
<div>
|
||||
<div style={{ fontSize: "large" }}>{element.name}</div>
|
||||
|
||||
{element.isOpen ? (
|
||||
<div>
|
||||
{element.totalValue instanceof Array
|
||||
? element.totalValue?.map((subArray, index) => {
|
||||
return (
|
||||
<>
|
||||
<div style={{ paddingLeft: "10px" }}>
|
||||
index: {index}
|
||||
<Button onClick={() => store.deleteTotalValueSubItem(element.id, index)}>
|
||||
Delete item
|
||||
</Button>
|
||||
</div>
|
||||
{subArray.map((subSubArrayItem: InputBuilderViewModel, subIndex: number) => {
|
||||
if (subSubArrayItem.type.isEqual(InputType.ENUM)) {
|
||||
return (
|
||||
<>
|
||||
<div>{subSubArrayItem.name}</div>
|
||||
|
||||
<Select
|
||||
defaultValue={subSubArrayItem.defaultValue}
|
||||
style={{ width: 120 }}
|
||||
onChange={(e) => {
|
||||
store.changeTotalSubValue(element.id, subIndex, e);
|
||||
}}
|
||||
options={subSubArrayItem.values?.map((el) => {
|
||||
return { value: el };
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (subSubArrayItem.type.isEqualMany([InputType.NUMBER, InputType.STRING]))
|
||||
return (
|
||||
<div style={{ width: "200px" }}>
|
||||
<div>{subSubArrayItem.name}</div>
|
||||
<Input
|
||||
onChange={(e) => {
|
||||
store.changeTotalSubValue(element.id, subIndex, e.target.value);
|
||||
}}
|
||||
defaultValue={subSubArrayItem.defaultValue}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return <>Error</>;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
onClick={() => {
|
||||
store.open(element.id);
|
||||
}}
|
||||
>
|
||||
+
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (element.type.isEqualMany([InputType.NUMBER, InputType.STRING]))
|
||||
return (
|
||||
<div style={{ width: "200px" }}>
|
||||
<div>{element.name}</div>
|
||||
<Input
|
||||
onChange={(e) => {
|
||||
store.changeTotalValue(element.id, e.target.value);
|
||||
}}
|
||||
defaultValue={element.defaultValue}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return <>Error</>;
|
||||
})}
|
||||
<Button onClick={() => store.saveForm()}>SAVE FORM</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
103
ui/src/core/ui/form_builder/form_builder_store.ts
Normal file
103
ui/src/core/ui/form_builder/form_builder_store.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
import { makeAutoObservable } from "mobx";
|
||||
import { FormViewModel } from "./form_view_model";
|
||||
import { TypedEvent } from "../../helper/typed_event";
|
||||
import { FormBuilderValidationModel } from "../../../features/dataset/dataset_store";
|
||||
|
||||
export class ChangerForm extends TypedEvent<FormBuilderValidationModel | undefined> {}
|
||||
|
||||
export class FormBuilderStore {
|
||||
isError = false;
|
||||
formViewModel?: FormViewModel;
|
||||
changerForm: ChangerForm;
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
this.changerForm = new ChangerForm();
|
||||
}
|
||||
|
||||
changeTotalSubValue(id: string, subIndex: number, value: string) {
|
||||
if (this.formViewModel?.inputs)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
} else {
|
||||
if (el.totalValue instanceof Array) {
|
||||
el.totalValue = el.totalValue.map((subElement) => {
|
||||
if (subElement instanceof Array) {
|
||||
subElement.map((subSubElement, i) => {
|
||||
if (subIndex !== i) {
|
||||
return subSubElement;
|
||||
}
|
||||
|
||||
subSubElement.totalValue = value;
|
||||
|
||||
return subSubElement;
|
||||
});
|
||||
}
|
||||
return subElement;
|
||||
});
|
||||
return el;
|
||||
}
|
||||
return el;
|
||||
}
|
||||
});
|
||||
this.changerForm.emit(this.formViewModel?.fromFormBuilderValidationModel());
|
||||
}
|
||||
|
||||
changeTotalValue(id: string, value: string) {
|
||||
if (this.formViewModel?.inputs)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
}
|
||||
el.totalValue = value;
|
||||
return el;
|
||||
});
|
||||
this.changerForm.emit(this.formViewModel?.fromFormBuilderValidationModel());
|
||||
}
|
||||
|
||||
deleteTotalValueSubItem(id: string, index: number): void {
|
||||
if (this.formViewModel?.inputs)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
} else {
|
||||
if (el.totalValue instanceof Array) {
|
||||
el.totalValue = el.totalValue.filter((_, i) => index !== i);
|
||||
return el;
|
||||
}
|
||||
return el;
|
||||
}
|
||||
});
|
||||
this.changerForm.emit(this.formViewModel?.fromFormBuilderValidationModel());
|
||||
}
|
||||
|
||||
saveForm(): void {
|
||||
console.log(this.formViewModel?.toResult());
|
||||
}
|
||||
|
||||
open = (id: string) => {
|
||||
if (this.formViewModel)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
}
|
||||
|
||||
el.isOpen = true;
|
||||
|
||||
if (!(el.totalValue instanceof Array)) {
|
||||
el.totalValue = [];
|
||||
}
|
||||
el.totalValue.push(el.values);
|
||||
return el;
|
||||
});
|
||||
};
|
||||
|
||||
init(context: string, result: string) {
|
||||
FormViewModel.fromString(result, context).fold(
|
||||
(model) => {
|
||||
this.formViewModel = model;
|
||||
},
|
||||
() => (this.isError = true)
|
||||
);
|
||||
}
|
||||
}
|
171
ui/src/core/ui/form_builder/form_view_model.ts
Normal file
171
ui/src/core/ui/form_builder/form_view_model.ts
Normal file
|
@ -0,0 +1,171 @@
|
|||
import { makeAutoObservable, observable } from "mobx";
|
||||
import { Result } from "../../helper/result";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { FormBuilderValidationModel } from "../../../features/dataset/dataset_store";
|
||||
|
||||
export enum InputType {
|
||||
NUMBER = "number",
|
||||
STRING = "string",
|
||||
ARRAY = "Array",
|
||||
ENUM = "Enum",
|
||||
}
|
||||
|
||||
export class InputBuilderViewModel {
|
||||
id: string;
|
||||
constructor(
|
||||
public name: string,
|
||||
public type: InputType,
|
||||
public defaultValue: string,
|
||||
public values: string[] | undefined | InputBuilderViewModel[] = undefined,
|
||||
public totalValue: any | undefined = undefined,
|
||||
public isOpen: boolean = false,
|
||||
public subType: string | undefined = undefined
|
||||
) {
|
||||
this.id = uuidv4();
|
||||
}
|
||||
static fromJSON(json: any) {
|
||||
return new InputBuilderViewModel(json.name, json.type, json.defaultValue, json.values, json.isOpen, json.id);
|
||||
}
|
||||
public toJson(): string {
|
||||
return JSON.stringify(this);
|
||||
}
|
||||
}
|
||||
|
||||
export const tagParse = new RegExp(/\${.*?}/gm);
|
||||
export const bracketParser = new RegExp(/<.*?>/gm);
|
||||
export const enumParser = new RegExp(/ENUM.*=..*?;/gm);
|
||||
export const enumBodyParse = new RegExp(/".*?;/gm);
|
||||
export const enumNameParse = new RegExp(/^(.*?)=/gm);
|
||||
export const typeBodyParse = new RegExp(/{.*?};/gms);
|
||||
export const typeNameParse = new RegExp(/type .*?{/gms);
|
||||
export const typeParse = new RegExp(/type.*?};/gms);
|
||||
|
||||
export class FormViewModel {
|
||||
@observable
|
||||
inputs: InputBuilderViewModel[];
|
||||
|
||||
constructor(inputs: InputBuilderViewModel[], public result: string, public context: string) {
|
||||
this.inputs = inputs;
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
public fromFormBuilderValidationModel() {
|
||||
console.log(this.toResult());
|
||||
return new FormBuilderValidationModel(
|
||||
this.context,
|
||||
this.result,
|
||||
this.inputs.map((el) => el.toJson()),
|
||||
this.toResult()
|
||||
);
|
||||
}
|
||||
public toResult() {
|
||||
let result = this.result;
|
||||
|
||||
this.inputs.forEach((element) => {
|
||||
let inputResult = element.totalValue ?? element.defaultValue;
|
||||
if (element.type.isEqualMany([InputType.STRING, InputType.ENUM])) {
|
||||
inputResult = `"${String(inputResult)}"`;
|
||||
}
|
||||
if (element.type.isEqual(InputType.NUMBER)) {
|
||||
inputResult = Number(inputResult);
|
||||
}
|
||||
if (element.type.isEqual(InputType.ARRAY)) {
|
||||
if (element.totalValue === undefined) {
|
||||
inputResult = "[]";
|
||||
} else {
|
||||
inputResult = [];
|
||||
// @ts-ignore
|
||||
element.totalValue.forEach((el) => {
|
||||
const objectUnion = {};
|
||||
if (el instanceof Array)
|
||||
el.forEach((subElement) => {
|
||||
let subResult = subElement.totalValue ?? subElement.defaultValue;
|
||||
if (element.type.isEqualMany([InputType.STRING, InputType.ENUM])) {
|
||||
subResult = `"${String(subResult)}"`;
|
||||
}
|
||||
if (element.type.isEqual(InputType.NUMBER)) {
|
||||
subResult = Number(subResult);
|
||||
}
|
||||
// @ts-ignore
|
||||
objectUnion[subElement.name] = subResult;
|
||||
});
|
||||
if (Object.keys(objectUnion).length !== 0) {
|
||||
inputResult.push(objectUnion);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (inputResult instanceof Array) inputResult = JSON.stringify(inputResult);
|
||||
result = result.replace(new RegExp("\\${" + element.name + ".*?}"), inputResult);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
static fromString(result: string, context: string): Result<void, FormViewModel> {
|
||||
try {
|
||||
const enums = new Map<string, string[]>();
|
||||
const types = new Map<string, InputBuilderViewModel[]>();
|
||||
|
||||
context.match(enumParser)?.forEach((el) => {
|
||||
const enumMatch = el.match(enumBodyParse)?.at(0);
|
||||
if (enumMatch !== undefined) {
|
||||
const EnumValue = enumMatch.slice(0, enumMatch.length - 2).split(",");
|
||||
const enumBody = EnumValue.map((el) => el.replaceAll('"', ""));
|
||||
const enumName = el.match(enumNameParse)?.at(0)?.split(" ").at(1);
|
||||
if (enumBody.isNotEmpty() && enumName) enums.set(enumName, enumBody);
|
||||
}
|
||||
});
|
||||
|
||||
context.match(typeParse)?.forEach((type) => {
|
||||
const matchTypeName = type.match(typeNameParse)?.at(0)?.split(" ").at(1);
|
||||
const typeBody = type.match(typeBodyParse)?.at(0);
|
||||
|
||||
if (typeBody && matchTypeName) types.set(matchTypeName, this.typeParse(typeBody, enums));
|
||||
});
|
||||
|
||||
return Result.ok(new FormViewModel(this.typeParse(result, enums, types), result, context));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return Result.error(undefined);
|
||||
}
|
||||
}
|
||||
static typeParse(
|
||||
result: string,
|
||||
enums: Map<string, string[]>,
|
||||
types: Map<string, InputBuilderViewModel[]> | undefined = undefined
|
||||
) {
|
||||
return result
|
||||
.match(tagParse)
|
||||
?.map((el) => {
|
||||
const inputArray = el.replaceMany(["$", "{", "}"], "").split(":");
|
||||
if (el.includes(InputType.ENUM)) {
|
||||
const enumName = inputArray.at(1)?.replaceMany([InputType.ENUM, "<", ">"], "");
|
||||
|
||||
if (enumName && enums.get(enumName)) {
|
||||
return new InputBuilderViewModel(inputArray[0], InputType.ENUM, inputArray[2], enums.get(enumName));
|
||||
}
|
||||
}
|
||||
if (el.includes(InputType.ARRAY) && types) {
|
||||
const name = inputArray.at(1)?.replaceMany(["Array<", ">"], "");
|
||||
|
||||
if (name) {
|
||||
return new InputBuilderViewModel(
|
||||
inputArray[0],
|
||||
InputType.ARRAY,
|
||||
inputArray[2],
|
||||
types.get(name),
|
||||
undefined,
|
||||
false,
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
if (el.includes(InputType.NUMBER)) {
|
||||
return new InputBuilderViewModel(inputArray[0], InputType.NUMBER, inputArray[2]);
|
||||
}
|
||||
if (el.includes(InputType.STRING)) {
|
||||
return new InputBuilderViewModel(inputArray[0], InputType.STRING, inputArray[2]);
|
||||
}
|
||||
return el;
|
||||
})
|
||||
.filter((el) => el !== undefined) as InputBuilderViewModel[];
|
||||
}
|
||||
}
|
33
ui/src/core/ui/form_builder/readme.md
Normal file
33
ui/src/core/ui/form_builder/readme.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# RESULT
|
||||
|
||||
```
|
||||
{
|
||||
"scene":{
|
||||
"objects": \${OBJECTS_SCENE:Array<OBJECTS_SCENE>:[]},
|
||||
},
|
||||
"camera_position":{
|
||||
"center_shell": [\${CENTER_SHELL_1:string:0}, \${COLISION_SHAPE:Enum<L>:"BOX"}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# CONTEXT
|
||||
|
||||
### хранит в себе type и enum для result
|
||||
|
||||
```
|
||||
ENUM T = "ObjectDetection","PoseEstimation";
|
||||
ENUM L = "POINT","SUN";
|
||||
|
||||
type MODELS = {
|
||||
"id": \${IMAGE_FORMAT:Enum<L>:"jpg"},,
|
||||
"name": \${NAME:string:""},
|
||||
"model": \${MODEL:string:"models/1.fbx"}
|
||||
};
|
||||
|
||||
type OBJECTS_SCENE = {
|
||||
"name": \${NAME:string:""},
|
||||
"collision_shape": \${COLISION_SHAPE:Enum<L>:"BOX"},
|
||||
"loc_xyz": [\${TEST123:string:"test123"}, \${LOC_XYZ_2:number:0}, \${LOC_XYZ_3:number:0}],
|
||||
};
|
||||
```
|
Loading…
Add table
Add a link
Reference in a new issue