From 4e6132a872eef038ac9f8e00fb7a615eb81ab1dc Mon Sep 17 00:00:00 2001 From: IDONTSUDO Date: Tue, 24 Sep 2024 17:18:56 +0300 Subject: [PATCH] alex find bugs --- ui/src/core/helper/use_store.tsx | 6 +- .../model/form_builder_validation_model.tsx | 58 +++++ ui/src/core/model/skill_model.ts | 14 +- ui/src/core/routers/routers.tsx | 5 + ui/src/core/ui/form_builder/form_builder.tsx | 4 +- .../ui/form_builder/form_builder_store.ts | 4 +- .../core/ui/form_builder/form_view_model.ts | 4 +- ui/src/core/ui/input/input.tsx | 8 +- ui/src/core/ui/input/input_v2.tsx | 7 +- .../behavior_tree_builder_http_repository.ts | 1 - .../behavior_tree_builder_screen.tsx | 230 ++++++------------ .../behavior_tree_builder_store.tsx | 55 ++--- .../forms/form_builder/form_builder_form.tsx | 56 +++++ .../forms/form_builder/form_builder_store.ts | 23 ++ .../presentation/ui/forms/forms.tsx | 20 +- .../topic_dependency_view_model.tsx | 2 +- .../ui/forms/topics_form/topics_form.tsx | 2 +- .../behavior_tree_manager_repository.ts | 10 + .../behavior_tree_manager_screen.tsx | 100 ++++++++ .../behavior_tree_manager_store.ts | 60 +++++ .../behavior_tree_manager/number_trivia.ts | 11 + .../data/calculation_socket_repository.ts | 2 +- .../model/calculation_model.ts | 4 +- .../calculation_instance_screen.tsx | 4 +- .../{dataset_model.ts => dataset_model.tsx} | 50 +--- .../digital_twins/digital_twins_model.ts | 4 +- ui/src/features/skills/skills_screen.tsx | 37 ++- 27 files changed, 485 insertions(+), 296 deletions(-) create mode 100644 ui/src/core/model/form_builder_validation_model.tsx create mode 100644 ui/src/features/behavior_tree_builder/presentation/ui/forms/form_builder/form_builder_form.tsx create mode 100644 ui/src/features/behavior_tree_builder/presentation/ui/forms/form_builder/form_builder_store.ts create mode 100644 ui/src/features/behavior_tree_manager/behavior_tree_manager_repository.ts create mode 100644 ui/src/features/behavior_tree_manager/behavior_tree_manager_screen.tsx create mode 100644 ui/src/features/behavior_tree_manager/behavior_tree_manager_store.ts create mode 100644 ui/src/features/behavior_tree_manager/number_trivia.ts rename ui/src/features/dataset/{dataset_model.ts => dataset_model.tsx} (77%) diff --git a/ui/src/core/helper/use_store.tsx b/ui/src/core/helper/use_store.tsx index 5afe24d..db52450 100644 --- a/ui/src/core/helper/use_store.tsx +++ b/ui/src/core/helper/use_store.tsx @@ -1,15 +1,17 @@ import { ClassConstructor } from "class-transformer"; import React from "react"; +import { NavigateFunction, useNavigate } from "react-router-dom"; interface LifeCycleStore { - init?: () => void; + init?: (navigate?: NavigateFunction | undefined) => void; dispose?: () => void; } export const useStore = (storeConstructor: ClassConstructor) => { const [store] = React.useState(new storeConstructor()); + const navigate = useNavigate(); React.useEffect(() => { - store?.init?.(); + store?.init?.(navigate); return () => { store?.dispose?.(); }; diff --git a/ui/src/core/model/form_builder_validation_model.tsx b/ui/src/core/model/form_builder_validation_model.tsx new file mode 100644 index 0000000..f888f4e --- /dev/null +++ b/ui/src/core/model/form_builder_validation_model.tsx @@ -0,0 +1,58 @@ +import { IsNotEmpty, IsString } from "class-validator"; +import { BehaviorTreeBuilderStore } from "../../features/behavior_tree_builder/presentation/behavior_tree_builder_store"; +import { datasetFormMockContext, datasetFormMockResult, defaultFormValue } from "../../features/dataset/dataset_model"; +import { DependencyViewModel } from "./skill_model"; +import { ValidationModel } from "./validation_model"; + +export class FormBuilderValidationModel extends ValidationModel implements DependencyViewModel { + @IsNotEmpty() + @IsString() + public result: string; + @IsNotEmpty() + @IsString() + public context: string; + public form: string[]; + public output: any; + constructor(context: string, result: string, form: string[], output: string) { + super(); + this.context = context; + this.result = result; + this.form = form; + this.output = output; + } + toView = (store: BehaviorTreeBuilderStore | undefined) => <>IsFilled; + static isEmpty = (formBuilderValidationModel: FormBuilderValidationModel) => + formBuilderValidationModel.context.isEmpty() && + formBuilderValidationModel.result.isEmpty() && + formBuilderValidationModel.form.isEmpty(); + + static datasetEmpty() { + return new FormBuilderValidationModel(datasetFormMockContext, datasetFormMockResult, [], defaultFormValue); + } + static empty() { + return new FormBuilderValidationModel("", "", [], ""); + } + static emptyTest() { + return new FormBuilderValidationModel(``, ``, [], defaultFormValue); + } + static creteDataSetTest() { + return new FormBuilderValidationModel(``, scene, [], ""); + } + static vision(): FormBuilderValidationModel { + return new FormBuilderValidationModel( + `ENUM PRETRAIN = "true","false";`, + `{ + "numberOfEpochs": \${numberOfEpochs:number:10}, + "selectDataset": \${:OBJECT:{"dataset": {}}, + "pretrain": \${pretrain:Enum:true} + }`, + [], + "" + ); + } + } + export const scene = `{ + "center_shell": [\${CENTER_SHELL_1:number:0}, \${CENTER_SHELL_2:number:0}, \${CENTER_SHELL_3:number:0}], + "scene":\${:OBJECT:{"details": []} + }`; + \ No newline at end of file diff --git a/ui/src/core/model/skill_model.ts b/ui/src/core/model/skill_model.ts index eb64500..352881b 100644 --- a/ui/src/core/model/skill_model.ts +++ b/ui/src/core/model/skill_model.ts @@ -70,9 +70,7 @@ export class BtActionViewModel extends ValidationModel implements IBTAction { @IsNotEmpty() @IsString() name: string; - @IsNotEmpty() - @IsString() - format: string; + @IsNotEmpty() @IsString() type: string; @@ -84,16 +82,15 @@ export class BtActionViewModel extends ValidationModel implements IBTAction { @IsNotEmpty() @IsEnum(BtAction) typeAction: BtAction; - constructor(name: string, format: string, type: string, param: IParam[], result: string[], typeAction: BtAction) { + constructor(name: string, type: string, param: IParam[], result: string[], typeAction: BtAction) { super(); this.name = name; - this.format = format; this.type = type; this.param = param; this.result = result; this.typeAction = typeAction; } - static empty = () => new BtActionViewModel("", "", "", [], [], BtAction.ACTION); + static empty = () => new BtActionViewModel("", "", [], [], BtAction.ACTION); public validParam = (type: string) => this.param.someR((param) => param.type === type); } export interface IInterface { @@ -228,6 +225,8 @@ export class SkillModel extends ValidationModel implements ISkill { @ValidateNested() @Type(() => Module) Module: IModule; + @IsNotEmpty() + @IsArray() @Type(() => BtActionViewModel) BTAction: BtActionViewModel[]; topicsOut: TopicViewModel[] = []; @@ -337,7 +336,7 @@ export class Skills { toSkillView = (): ISkillView[] => this.skills.map((el) => { return { - name: el.SkillPackage.name, + name: el.Module.name, children: el.BTAction.map((act) => { return { name: act.name, uuid: v4() }; }), @@ -487,4 +486,3 @@ export class Skills { () => Result.error(false) ); } - diff --git a/ui/src/core/routers/routers.tsx b/ui/src/core/routers/routers.tsx index 8887fc1..c3e3a4e 100644 --- a/ui/src/core/routers/routers.tsx +++ b/ui/src/core/routers/routers.tsx @@ -18,6 +18,7 @@ import { DigitalTwinsScreen, DigitalTwinsScreenPath } from "../../features/digit import { TopicsScreen, TopicsScreenPath } from "../../features/topics/topics_screen"; import { SkillsScreen, SkillsScreenPath } from "../../features/skills/skills_screen"; import { CalculationsTemplateScreenPath } from "../../features/calculations_template/calculations_template_screen"; +import { BehaviorTreeManagerScreen, BehaviorTreeManagerScreenPath } from "../../features/behavior_tree_manager/behavior_tree_manager_screen"; const idURL = ":id"; export const router = createBrowserRouter([ @@ -85,4 +86,8 @@ export const router = createBrowserRouter([ path: CalculationsTemplateScreenPath, element: , }, + { + path: BehaviorTreeManagerScreenPath, + element: , + }, ]); diff --git a/ui/src/core/ui/form_builder/form_builder.tsx b/ui/src/core/ui/form_builder/form_builder.tsx index c11a082..e8a6ad0 100644 --- a/ui/src/core/ui/form_builder/form_builder.tsx +++ b/ui/src/core/ui/form_builder/form_builder.tsx @@ -2,12 +2,12 @@ import * as React from "react"; import { FormViewModel, InputBuilderViewModel, InputType } from "./form_view_model"; import { observer } from "mobx-react-lite"; import { FormBuilderStore } from "./form_builder_store"; -import { FormBuilderValidationModel } from "../../../features/dataset/dataset_model"; -import { CoreSelect } from "../select/select"; + import { CoreSelect } from "../select/select"; import { CoreInput } from "../input/input"; import { Icon } from "../icons/icons"; import { CoreText, CoreTextType } from "../text/text"; import { getFormBuilderComponents } from "./forms/form_builder_components"; +import { FormBuilderValidationModel } from "../../model/form_builder_validation_model"; export interface IFormBuilder { formBuilder: FormBuilderValidationModel; diff --git a/ui/src/core/ui/form_builder/form_builder_store.ts b/ui/src/core/ui/form_builder/form_builder_store.ts index 53e1992..ebffcb2 100644 --- a/ui/src/core/ui/form_builder/form_builder_store.ts +++ b/ui/src/core/ui/form_builder/form_builder_store.ts @@ -1,8 +1,8 @@ import { makeAutoObservable } from "mobx"; import { FormViewModel } from "./form_view_model"; import { TypedEvent } from "../../helper/typed_event"; -import { FormBuilderValidationModel } from "../../../features/dataset/dataset_model"; - +import { FormBuilderValidationModel } from "../../model/form_builder_validation_model"; + export class ChangerForm extends TypedEvent {} export class FormBuilderStore { diff --git a/ui/src/core/ui/form_builder/form_view_model.ts b/ui/src/core/ui/form_builder/form_view_model.ts index a7a5864..1c6e6f2 100644 --- a/ui/src/core/ui/form_builder/form_view_model.ts +++ b/ui/src/core/ui/form_builder/form_view_model.ts @@ -1,8 +1,8 @@ import { makeAutoObservable, observable } from "mobx"; import { Result } from "../../helper/result"; import { v4 as uuidv4 } from "uuid"; -import { FormBuilderValidationModel } from "../../../features/dataset/dataset_model"; - +import { FormBuilderValidationModel } from "../../model/form_builder_validation_model"; + export enum InputType { NUMBER = "number", STRING = "string", diff --git a/ui/src/core/ui/input/input.tsx b/ui/src/core/ui/input/input.tsx index c22b1d7..7dccf93 100644 --- a/ui/src/core/ui/input/input.tsx +++ b/ui/src/core/ui/input/input.tsx @@ -14,6 +14,7 @@ interface IInputProps extends IStyle { validation?: (value: string) => boolean; error?: string; type?: CoreInputType; + trim?: boolean; } export const CoreInput = (props: IInputProps) => { @@ -49,7 +50,7 @@ export const CoreInput = (props: IInputProps) => {
{ top: isSmall ? -8 : undefined, }} onInput={(e) => { - const val = e.currentTarget.innerText; + let val = e.currentTarget.innerText; setValue(val); if (val) { + if (props.trim) { + val = val.trim().replaceAll("\n", ""); + } if (props.validation !== undefined && props.validation(val) && props.onChange) { props.onChange(val); return; diff --git a/ui/src/core/ui/input/input_v2.tsx b/ui/src/core/ui/input/input_v2.tsx index 488e86f..16ab3f5 100644 --- a/ui/src/core/ui/input/input_v2.tsx +++ b/ui/src/core/ui/input/input_v2.tsx @@ -5,10 +5,11 @@ import { CoreText, CoreTextType, FontType } from "../text/text"; interface InputV2Props { label: string; value?: string; + trim?: boolean; height?: number; onChange?: (text: string) => void; } -export const InputV2: React.FC = ({ label, height, value, onChange }) => { +export const InputV2: React.FC = ({ label, height, value, onChange, trim }) => { return (
= ({ label, height, value, onChange /> { - if (onChange) onChange(text); + let result = text; + if (trim) result = result.trim().replaceAll("\n", ""); + if (onChange) onChange(result); }} style={{ backgroundColor: themeStore.theme.surfaceContainerHighest, diff --git a/ui/src/features/behavior_tree_builder/data/behavior_tree_builder_http_repository.ts b/ui/src/features/behavior_tree_builder/data/behavior_tree_builder_http_repository.ts index 4c3dd97..0da5653 100644 --- a/ui/src/features/behavior_tree_builder/data/behavior_tree_builder_http_repository.ts +++ b/ui/src/features/behavior_tree_builder/data/behavior_tree_builder_http_repository.ts @@ -15,7 +15,6 @@ export class BehaviorTreeBuilderHttpRepository extends CoreHttpRepository { SkillModel )) as unknown as Promise>; }; - saveNewBt = async (model: BehaviorTreeViewModel) => this._jsonRequest(HttpMethod.POST, this.featureApi, model); getBtById = async (id: string): Promise> => this._jsonToClassInstanceRequest( HttpMethod.GET, diff --git a/ui/src/features/behavior_tree_builder/presentation/behavior_tree_builder_screen.tsx b/ui/src/features/behavior_tree_builder/presentation/behavior_tree_builder_screen.tsx index 82aa1e8..3e0e557 100644 --- a/ui/src/features/behavior_tree_builder/presentation/behavior_tree_builder_screen.tsx +++ b/ui/src/features/behavior_tree_builder/presentation/behavior_tree_builder_screen.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import { useRete } from "rete-react-plugin"; import { createEditor } from "./ui/editor/editor"; import { SkillTree } from "./ui/skill_tree/skill_tree"; -import { BehaviorTreeBuilderStore, DrawerState, StoreUIType } from "./behavior_tree_builder_store"; +import { BehaviorTreeBuilderStore, DrawerState } from "./behavior_tree_builder_store"; import { observer } from "mobx-react-lite"; import { match } from "ts-pattern"; import { Icon } from "../../../core/ui/icons/icons"; @@ -51,179 +51,97 @@ export const BehaviorTreeBuilderScreen = observer(() => { const domReact: DOMReact = ref.current.getBoundingClientRect(); store.dragZoneSetOffset(0, domReact.y, domReact.width, domReact.height); } - }, [store.type]); + }, [ref.current]); + React.useEffect(() => { store.init(navigate).then(() => { - store.initParam(id).then(() => {}); + store.initParam(id); }); return () => { store.dispose(); }; - }, [id, navigate, ref, store]); + }, []); return ( - {match(store.type) - .with(StoreUIType.ViewBehaviorTree, () => ( -
- {}} text="Запуск" textColor={themeStore.theme.black} /> -
- {}} - text="Стоп" - type={ButtonV2Type.empty} - textColor={themeStore.theme.greenWhite} - /> -
-
- {store.isNeedSaveBtn ? ( - store.onClickSaveBehaviorTree()} type="Floppy" /> - ) : undefined} -
-
- )) - .with(StoreUIType.SelectBehaviorTree, () => <>) - .otherwise(() => ( - <> - ))} +
+ {}} text="Запуск" textColor={themeStore.theme.black} /> +
+ {}} + text="Стоп" + type={ButtonV2Type.empty} + textColor={themeStore.theme.greenWhite} + /> +
+
+ {store.isNeedSaveBtn ? ( + store.onClickSaveBehaviorTree()} type="Floppy" /> + ) : undefined} +
+
} style={{ position: "absolute", height: "100%", overflow: "hidden" }} bgColor={themeStore.theme.black} children={ <> - {match(store.type) - .with(StoreUIType.ViewBehaviorTree, () => ( - <> -
-
-
- -
-
- {store.skillTemplates ? : null} -
-
-
- - )) - .with(StoreUIType.SelectBehaviorTree, () => ( -
-
- } - text="СОЗДАТЬ ДЕРЕВО ПОВЕДЕНИЯ" - onClick={() => store.modalShow()} - /> -
- -
- {store.btTreeModels?.map((el, index) => ( - store.deleteBt(el._id)} - clickGoToIcon={() => store.goToBt(el._id)} - descriptionMiddle={el.description} - descriptionTop={el.name} - date={el.unixTime} - /> - ))} + <> +
+
+
+ +
+ {store.skillTemplates ? : null}
- )) - .otherwise(() => ( - <> - ))} - store.modalCancel()} - children={ - <> -
- -
-
-
- store.updateForm({ name: text })} /> -
- store.updateForm({ description: text })} /> -
- ({ name: el.name, value: el._id })) ?? []} - initialValue={""} - label={"Сцена"} - onChange={(value: string) => store.updateForm({ sceneId: value })} - /> -
-
-
- store.saveNewBt()} type={ButtonV2Type.default} /> -
- store.modalCancel()} type={ButtonV2Type.default} /> -
- - } - /> +
+
+ + store.editDrawer(DrawerState.editThreadBehaviorTree, false)} diff --git a/ui/src/features/behavior_tree_builder/presentation/behavior_tree_builder_store.tsx b/ui/src/features/behavior_tree_builder/presentation/behavior_tree_builder_store.tsx index 199cf19..97e8486 100644 --- a/ui/src/features/behavior_tree_builder/presentation/behavior_tree_builder_store.tsx +++ b/ui/src/features/behavior_tree_builder/presentation/behavior_tree_builder_store.tsx @@ -24,7 +24,6 @@ import { UiBaseError } from "../../../core/model/ui_base_error"; import { BehaviorTreeBuilderPath, behaviorTreeBuilderStore } from "./behavior_tree_builder_screen"; import { BehaviorTreeModel } from "../model/behavior_tree_model"; import { PrimitiveViewModel, SystemPrimitive } from "../model/primitive_view_model"; -import { SceneModel } from "../../scene_manager/model/scene_model"; import { SceneAsset } from "../../../core/model/scene_asset"; import { themeStore } from "../../.."; @@ -36,20 +35,12 @@ interface I2DArea { } export enum DrawerState { - newBehaviorTree = "Новое дерево поведения", editThreadBehaviorTree = "Редактирование", } -export enum StoreUIType { - SelectBehaviorTree, - ViewBehaviorTree, -} - export class BehaviorTreeBuilderStore extends UiDrawerFormState { - type: StoreUIType = StoreUIType.ViewBehaviorTree; sceneAsset?: SceneAsset; viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty(); - scenes?: SceneModel[]; behaviorTreeModel: BehaviorTreeModel = BehaviorTreeModel.empty(); skillTemplates: Skills = Skills.empty(); filledOutTemplates: Skills = Skills.empty(); @@ -68,7 +59,6 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState; areaPlugin?: AreaPlugin; nodeUpdateObserver?: NodeRerenderObserver; - isModalOpen: boolean = false; primitiveViewModel: PrimitiveViewModel; skillTree: ISkillView = { name: "", @@ -144,7 +134,20 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState { (await this.behaviorTreeBuilderHttpRepository.getActiveProjectId()) // eslint-disable-next-line array-callback-return @@ -180,16 +183,13 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState { this.errors.push(new UiBaseError(`не найдено дерево с id:${id}`)); } ); - } else { - this.type = StoreUIType.SelectBehaviorTree; - await this.mapOk("scenes", this.behaviorTreeBuilderHttpRepository.getAllScenes()); } }; dragZoneSetOffset(offsetTop: number, offsetWidth: number, width: number, height: number) { @@ -211,7 +211,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState { - console.log(xml) + console.log(xml); this.behaviorTreeModel.skills = this.filledOutTemplates; this.behaviorTreeModel.scene = NodeBehaviorTree.fromReteScene( this.editor as NodeEditor, @@ -356,29 +356,4 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState {}; - modalShow = () => { - this.isModalOpen = true; - }; - - modalCancel = () => { - this.isModalOpen = false; - }; - deleteBt = async (id: string) => ( - await this.behaviorTreeBuilderHttpRepository.deleteBt(id), - await this.mapOk("btTreeModels", this.behaviorTreeBuilderHttpRepository.getAllBtInstances()) - ); - saveNewBt = async () => - (await this.viewModel.valid()).fold( - async (model) => { - await this.messageHttp(this.behaviorTreeBuilderHttpRepository.saveNewBt(model), { - successMessage: "Новое дерево создано", - }); - await this.mapOk("btTreeModels", this.behaviorTreeBuilderHttpRepository.getAllBtInstances()); - this.modalCancel(); - }, - async (error) => message.error(error) - ); - goToBt = (id: string) => { - if (this.navigate) this.navigate(BehaviorTreeBuilderPath(id)); - }; } diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/forms/form_builder/form_builder_form.tsx b/ui/src/features/behavior_tree_builder/presentation/ui/forms/form_builder/form_builder_form.tsx new file mode 100644 index 0000000..3ef3075 --- /dev/null +++ b/ui/src/features/behavior_tree_builder/presentation/ui/forms/form_builder/form_builder_form.tsx @@ -0,0 +1,56 @@ +import React, { useEffect } from "react"; +import { observer } from "mobx-react-lite"; +import { FormBuilderStore } from "./form_builder_store"; +import { IPropsForm } from "../forms"; +import { useStore } from "../../../../../../core/helper/use_store"; +import { isBtScreen } from "../../../behavior_tree_builder_screen"; +import { CoreInput } from "../../../../../../core/ui/input/input"; +import { CoreButton } from "../../../../../../core/ui/button/button"; +import { Modal, message } from "antd"; +import { FormBuilder } from "../../../../../../core/ui/form_builder/form_builder"; +import { FormBuilderValidationModel } from "../../../../../../core/model/form_builder_validation_model"; + +export const FormBuilderForm = observer((props: IPropsForm>) => { + const store = useStore(FormBuilderStore); + useEffect(() => { + store.initParam(isBtScreen(), props.store); + }, []); + + return ( +
+
FormBuilder
+ {store.isBtScreen ? ( + <> + store.updateForm({ context: text })} /> + store.updateForm({ result: text })} /> +
+ store.openModal()} /> + + (await store.viewModel.valid()).fold( + (model) => props.onChange(model), + (error) => message.error(error) + ) + } + /> +
+ { + store.isModalOpen = false; + }} + > + {}} /> + + + ) : ( + <> + )} +
+ ); +}); diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/forms/form_builder/form_builder_store.ts b/ui/src/features/behavior_tree_builder/presentation/ui/forms/form_builder/form_builder_store.ts new file mode 100644 index 0000000..d40863e --- /dev/null +++ b/ui/src/features/behavior_tree_builder/presentation/ui/forms/form_builder/form_builder_store.ts @@ -0,0 +1,23 @@ +import makeAutoObservable from "mobx-store-inheritance"; +import { NavigateFunction } from "react-router-dom"; +import { FormState, CoreError } from "../../../../../../core/store/base_store"; +import { BehaviorTreeBuilderStore } from "../../../behavior_tree_builder_store"; +import { FormBuilderValidationModel } from "../../../../../../core/model/form_builder_validation_model"; + +export class FormBuilderStore extends FormState { + openModal() { + this.isModalOpen = true; + } + isBtScreen = false; + isModalOpen = false; + viewModel: FormBuilderValidationModel = FormBuilderValidationModel.empty(); + constructor() { + super(); + makeAutoObservable(this); + } + errorHandingStrategy = (error: CoreError) => {}; + init = async (navigate?: NavigateFunction | undefined) => {}; + initParam = (isSkillScreen: boolean, store: BehaviorTreeBuilderStore | undefined) => { + this.isBtScreen = true; + }; +} diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/forms/forms.tsx b/ui/src/features/behavior_tree_builder/presentation/ui/forms/forms.tsx index be6f8ad..bbcf06f 100644 --- a/ui/src/features/behavior_tree_builder/presentation/ui/forms/forms.tsx +++ b/ui/src/features/behavior_tree_builder/presentation/ui/forms/forms.tsx @@ -1,11 +1,9 @@ +import { FormBuilderValidationModel } from "../../../../../core/model/form_builder_validation_model"; import { DependencyViewModel } from "../../../../../core/model/skill_model"; -import { BehaviorTreeBuilderStore } from "../../behavior_tree_builder_store"; -import { CameraDeviceForm } from "./camera_device_form/camera_device_form_form"; -import { MoveToPose } from "./move_to_pose/move_to_pose_form"; -import { RobotDeviceForm } from "./robot_device_form/robot_device_form_form"; + import { BehaviorTreeBuilderStore } from "../../behavior_tree_builder_store"; +import { FormBuilderForm } from "./form_builder/form_builder_form"; import { TopicDependencyViewModel } from "./topics_form/topic_dependency_view_model"; import { TopicsForm } from "./topics_form/topics_form"; -import { WeightsForm } from "./weights_form/weights_form"; export interface IPropsForm { dependency: T; @@ -22,6 +20,7 @@ export enum Form { robotName = "robot_name", cameraDeviceForm = "camera", topic = "topic", + formBuilder = "formBuilder", moveToPose = "move_to_pose", } export interface BtDependencyFormBuilder { @@ -35,15 +34,18 @@ export const btDependencyFormBuilder = (onChange: (dependency: DependencyViewMod form: Form.topic, component: , }, + { + form: Form.formBuilder, + component: ( + + ), + }, ]; export const forms = ( props: any, onChange: (dependency: DependencyViewModel) => void, store: BehaviorTreeBuilderStore ): IForms[] => [ - // { name: Form.weights, component: }, - // { name: Form.robotName, component: }, - // { name: Form.cameraDeviceForm, component: }, { name: Form.topic, component: }, - // { name: Form.moveToPose, component: }, + { name: Form.formBuilder, component: }, ]; diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topic_dependency_view_model.tsx b/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topic_dependency_view_model.tsx index b2cef23..d7c4dc9 100644 --- a/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topic_dependency_view_model.tsx +++ b/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topic_dependency_view_model.tsx @@ -22,7 +22,7 @@ export class TopicDependencyViewModel extends ValidationModel implements Depende toView = (store: BehaviorTreeBuilderStore | undefined): React.ReactNode => { if (store && this.sid) { if (store.filledOutTemplates.topicsStack.some((el) => el.sid?.isEqual(this.sid ?? ""))) { - return ; + return
{this.topicOut}
; } else { return ; } diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topics_form.tsx b/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topics_form.tsx index cabfad7..b4339c1 100644 --- a/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topics_form.tsx +++ b/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topics_form.tsx @@ -33,7 +33,7 @@ export const TopicsForm = observer((props: IPropsForm ( <> this._jsonRequest(HttpMethod.DELETE, `${this.featureApi}?id=${id}`); + saveNewBt = async (model: BehaviorTreeViewModel) => this._jsonRequest(HttpMethod.POST, this.featureApi, model); + getAllBtInstances = async () => this._jsonRequest(HttpMethod.GET, this.featureApi); +} diff --git a/ui/src/features/behavior_tree_manager/behavior_tree_manager_screen.tsx b/ui/src/features/behavior_tree_manager/behavior_tree_manager_screen.tsx new file mode 100644 index 0000000..fe8d179 --- /dev/null +++ b/ui/src/features/behavior_tree_manager/behavior_tree_manager_screen.tsx @@ -0,0 +1,100 @@ +import { observer } from "mobx-react-lite"; +import { BehaviorTreeManagerStore } from "./behavior_tree_manager_store"; +import React from "react"; +import { useStore } from "../../core/helper/use_store"; +import { ButtonV2, ButtonV2Type } from "../../core/ui/button/button_v2"; +import { CoreCard } from "../../core/ui/card/card"; +import { Icon } from "../../core/ui/icons/icons"; +import { themeStore } from "../.."; +import { InputV2 } from "../../core/ui/input/input_v2"; +import { CoreModal } from "../../core/ui/modal/modal"; +import { SelectV2 } from "../../core/ui/select/select_v2"; +import { CoreText, CoreTextType } from "../../core/ui/text/text"; +import { MainPageV2 } from "../../core/ui/pages/main_page_v2"; + +export const BehaviorTreeManagerScreenPath = "/behavior/tree/manager"; + +export const BehaviorTreeManagerScreen = observer(() => { + const store = useStore(BehaviorTreeManagerStore); + + return ( + <> + +
+
+ } + text="СОЗДАТЬ ДЕРЕВО ПОВЕДЕНИЯ" + onClick={() => store.modalShow()} + /> +
+ +
+ {store.btTreeModels?.map((el, index) => ( + store.deleteBt(el._id)} + clickGoToIcon={() => store.goToBt(el._id)} + descriptionMiddle={el.description} + descriptionTop={el.name} + date={el.unixTime} + /> + ))} +
+
+ store.modalCancel()} + children={ + <> +
+ +
+
+
+ store.updateForm({ name: text })} /> +
+ store.updateForm({ description: text })} /> +
+ ({ name: el.name, value: el._id })) ?? []} + initialValue={""} + label={"Сцена"} + onChange={(value: string) => store.updateForm({ sceneId: value })} + /> +
+
+
+ store.saveNewBt()} type={ButtonV2Type.default} /> +
+ store.modalCancel()} type={ButtonV2Type.default} /> +
+ + } + /> + + } + bgColor={themeStore.theme.black} + /> + + ); +}); diff --git a/ui/src/features/behavior_tree_manager/behavior_tree_manager_store.ts b/ui/src/features/behavior_tree_manager/behavior_tree_manager_store.ts new file mode 100644 index 0000000..36b3bab --- /dev/null +++ b/ui/src/features/behavior_tree_manager/behavior_tree_manager_store.ts @@ -0,0 +1,60 @@ +import makeAutoObservable from "mobx-store-inheritance"; +import { UiDrawerFormState, CoreError } from "../../core/store/base_store"; +import { BehaviorTreeViewModel } from "../behavior_tree_builder/model/behavior_tree_view_model"; +import { NavigateFunction } from "react-router-dom"; +import { BehaviorTreeBuilderPath } from "../behavior_tree_builder/presentation/behavior_tree_builder_screen"; +import { BehaviorTreeModel } from "../behavior_tree_builder/model/behavior_tree_model"; +import { SceneModel } from "../scene_manager/model/scene_model"; +import { BehaviorTreeManagerHttpRepository } from "./behavior_tree_manager_repository"; +import { message } from "antd"; +export enum DrawerState { + newBehaviorTree = "Новое дерево поведения", +} +export class BehaviorTreeManagerStore extends UiDrawerFormState { + viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty(); + navigate?: NavigateFunction; + btTreeModels: BehaviorTreeModel[] = []; + scenes?: SceneModel[]; + behaviorTreeManagerHttpRepository = new BehaviorTreeManagerHttpRepository(); + isModalOpen: boolean = false; + activeProject?: string; + constructor() { + super(DrawerState); + makeAutoObservable(this); + } + init = async (navigate?: NavigateFunction | undefined): Promise => { + this.navigate = navigate; + (await this.behaviorTreeManagerHttpRepository.getActiveProjectId()).map((el) => { + this.activeProject = el.id; + this.viewModel.project = this.activeProject; + }); + + await this.mapOk("btTreeModels", this.behaviorTreeManagerHttpRepository.getAllBtInstances()); + await this.mapOk("scenes", this.behaviorTreeManagerHttpRepository.getAllScenes()); + }; + deleteBt = async (id: string) => ( + await this.behaviorTreeManagerHttpRepository.deleteBt(id), + await this.mapOk("btTreeModels", this.behaviorTreeManagerHttpRepository.getAllBtInstances()) + ); + saveNewBt = async () => + (await this.viewModel.valid()).fold( + async (model) => { + await this.messageHttp(this.behaviorTreeManagerHttpRepository.saveNewBt(model), { + successMessage: "Новое дерево создано", + }); + await this.mapOk("btTreeModels", this.behaviorTreeManagerHttpRepository.getAllBtInstances()); + }, + async (error) => message.error(error) + ); + goToBt = (id: string) => { + console.log(this.navigate); + if (this.navigate) this.navigate(BehaviorTreeBuilderPath(id)); + }; + modalShow = () => { + this.isModalOpen = true; + }; + + modalCancel = () => { + this.isModalOpen = false; + }; +} diff --git a/ui/src/features/behavior_tree_manager/number_trivia.ts b/ui/src/features/behavior_tree_manager/number_trivia.ts new file mode 100644 index 0000000..d017d38 --- /dev/null +++ b/ui/src/features/behavior_tree_manager/number_trivia.ts @@ -0,0 +1,11 @@ +import { Result } from "../../core/helper/result"; + +export class NumberTriviaModel { + constructor() {} + isValid(): Result { + return Result.ok(); + } + static empty() { + return new NumberTriviaModel(); + } +} diff --git a/ui/src/features/calculation_instance/data/calculation_socket_repository.ts b/ui/src/features/calculation_instance/data/calculation_socket_repository.ts index 30eda15..fd30d60 100644 --- a/ui/src/features/calculation_instance/data/calculation_socket_repository.ts +++ b/ui/src/features/calculation_instance/data/calculation_socket_repository.ts @@ -2,7 +2,7 @@ import { TypedEvent } from "../../../core/helper/typed_event"; import { SocketRepository, socketRepository } from "../../../core/repository/core_socket_repository"; import { ProcessStatus } from "../../dataset/dataset_model"; -export interface ProcessUpdate { +export interface ProcessUpdate { id: string; status: ProcessStatus; } diff --git a/ui/src/features/calculation_instance/model/calculation_model.ts b/ui/src/features/calculation_instance/model/calculation_model.ts index 0f74d13..4e4f953 100644 --- a/ui/src/features/calculation_instance/model/calculation_model.ts +++ b/ui/src/features/calculation_instance/model/calculation_model.ts @@ -1,6 +1,6 @@ -import { FormBuilderValidationModel } from "../../dataset/dataset_model"; -import { IsNotEmpty, IsString } from "class-validator"; + import { IsNotEmpty, IsString } from "class-validator"; import { ValidationModel } from "../../../core/model/validation_model"; +import { FormBuilderValidationModel } from "../../../core/model/form_builder_validation_model"; export enum ModelMachineLearningTypes { OBJECT_DETECTION = "OBJECT_DETECTION", diff --git a/ui/src/features/calculation_instance/presentation/calculation_instance_screen.tsx b/ui/src/features/calculation_instance/presentation/calculation_instance_screen.tsx index 18717a3..b6422c6 100644 --- a/ui/src/features/calculation_instance/presentation/calculation_instance_screen.tsx +++ b/ui/src/features/calculation_instance/presentation/calculation_instance_screen.tsx @@ -13,8 +13,8 @@ import { FormBuilder } from "../../../core/ui/form_builder/form_builder"; import { match } from "ts-pattern"; import { TemplateModelCard } from "./ui/template_model_card"; import { Icon } from "../../../core/ui/icons/icons"; -import { FormBuilderValidationModel } from "../../dataset/dataset_model"; -import { useStore } from "../../../core/helper/use_store"; + import { useStore } from "../../../core/helper/use_store"; +import { FormBuilderValidationModel } from "../../../core/model/form_builder_validation_model"; interface IItem { name: string; diff --git a/ui/src/features/dataset/dataset_model.ts b/ui/src/features/dataset/dataset_model.tsx similarity index 77% rename from ui/src/features/dataset/dataset_model.ts rename to ui/src/features/dataset/dataset_model.tsx index b57b33d..f3544f4 100644 --- a/ui/src/features/dataset/dataset_model.ts +++ b/ui/src/features/dataset/dataset_model.tsx @@ -1,5 +1,6 @@ import { Result } from "../../core/helper/result"; import makeAutoObservable from "mobx-store-inheritance"; +import { FormBuilderValidationModel } from "../../core/model/form_builder_validation_model"; export enum ProcessStatus { END = "END", @@ -37,52 +38,7 @@ export interface Asset { image: string; } -export class FormBuilderValidationModel { - public result: string; - public context: string; - public form: string[]; - public output: any; - constructor(context: string, result: string, form: string[], output: string) { - this.context = context; - this.result = result; - 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); - } - static empty() { - return new FormBuilderValidationModel("", "", [], ""); - } - static emptyTest() { - return new FormBuilderValidationModel(``, ``, [], defaultFormValue); - } - static creteDataSetTest() { - return new FormBuilderValidationModel(``, scene, [], ""); - } - static vision(): FormBuilderValidationModel { - return new FormBuilderValidationModel( - `ENUM PRETRAIN = "true","false";`, - `{ - "numberOfEpochs": \${numberOfEpochs:number:10}, - "selectDataset": \${:OBJECT:{"dataset": {}}, - "pretrain": \${pretrain:Enum:true} - }`, - [], - "" - ); - } -} -export const scene = `{ - "center_shell": [\${CENTER_SHELL_1:number:0}, \${CENTER_SHELL_2:number:0}, \${CENTER_SHELL_3:number:0}], - "scene":\${:OBJECT:{"details": []} -}`; - + export class DataSetModel { dataSetObjects: string[]; datasetType: string; @@ -209,5 +165,3 @@ 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] }, }; - - diff --git a/ui/src/features/digital_twins/digital_twins_model.ts b/ui/src/features/digital_twins/digital_twins_model.ts index c3418ed..7dd6c8c 100644 --- a/ui/src/features/digital_twins/digital_twins_model.ts +++ b/ui/src/features/digital_twins/digital_twins_model.ts @@ -1,8 +1,8 @@ import { ValidationModel } from "../../core/model/validation_model"; import { Type } from "class-transformer"; import { IsEnum, IsNotEmpty, IsString } from "class-validator"; -import { FormBuilderValidationModel } from "../dataset/dataset_model"; - +import { FormBuilderValidationModel } from "../../core/model/form_builder_validation_model"; + export enum DigitalTwinsTypes { CAMERA = "CAMERA", ROBOT = "ROBOT", diff --git a/ui/src/features/skills/skills_screen.tsx b/ui/src/features/skills/skills_screen.tsx index ec7465e..232c28f 100644 --- a/ui/src/features/skills/skills_screen.tsx +++ b/ui/src/features/skills/skills_screen.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { observer } from "mobx-react-lite"; import { DrawersSkills, SkillsStore } from "./skills_store"; import { Drawer, Modal } from "antd"; @@ -73,44 +72,58 @@ export const SkillsScreen = observer(() => {
store.updateForm({ SkillPackage: Object.assign(store.viewModel.SkillPackage, { name: text }) }) } /> store.updateForm({ SkillPackage: Object.assign(store.viewModel.SkillPackage, { format: text }) }) } /> store.updateForm({ SkillPackage: Object.assign(store.viewModel.SkillPackage, { version: text }) }) } /> store.updateForm({ Module: Object.assign(store.viewModel.Module, { description: text }) }) } /> store.updateForm({ Module: Object.assign(store.viewModel.Module, { name: text }) })} /> - store.updateForm({ Module: Object.assign(store.viewModel.Module, { node_name: text }) })} + onChange={(text) => + store.updateForm({ Module: Object.assign(store.viewModel.Module, { node_name: text }) }) + } /> store.updateForm({ Launch: Object.assign(store.viewModel.Launch, { package: text }) })} + onChange={(text) => + store.updateForm({ Launch: Object.assign(store.viewModel.Launch, { package: text }) }) + } /> store.updateForm({ Launch: Object.assign(store.viewModel.Launch, { executable: text }) })} + onChange={(text) => + store.updateForm({ Launch: Object.assign(store.viewModel.Launch, { executable: text }) }) + } /> { {store.viewModel.topicsOut.map((el, index) => (
@@ -129,6 +143,7 @@ export const SkillsScreen = observer(() => { } /> @@ -146,6 +161,7 @@ export const SkillsScreen = observer(() => { {store.viewModel.BTAction.map((el, index) => (
@@ -153,20 +169,14 @@ export const SkillsScreen = observer(() => { } /> store.updateForm({ BTAction: store.viewModel.BTAction.replacePropIndex({ type: text }, index) }) } /> - - store.updateForm({ BTAction: store.viewModel.BTAction.replacePropIndex({ format: text }, index) }) - } - /> - + { ); }); + \ No newline at end of file