diff --git a/.vscode/settings.json b/.vscode/settings.json
index bb0a83f..1a82dcc 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,9 +4,9 @@
"Ведите",
"дерево",
"Количество",
+ "модели",
"может",
"навык",
- "модели",
"Новое",
"отрицательное",
"принимать",
@@ -18,6 +18,7 @@
"Collada",
"Contolls",
"GLTF",
+ "grau",
"raycaster",
"skils",
"typedataset",
diff --git a/server/src/features/behavior_trees/models/behavior_tree_database_model.ts b/server/src/features/behavior_trees/models/behavior_tree_database_model.ts
index 8297b58..33a0acf 100644
--- a/server/src/features/behavior_trees/models/behavior_tree_database_model.ts
+++ b/server/src/features/behavior_trees/models/behavior_tree_database_model.ts
@@ -12,6 +12,7 @@ export const BehaviorTreeSchema = new Schema({
name: {
type: String,
},
+ description: { type: String },
scene: {
type: Schema.Types.Mixed,
default: [],
@@ -21,7 +22,6 @@ export const BehaviorTreeSchema = new Schema({
},
unixTime: {
type: Number,
- default: Date.now(),
},
isFinished: {
type: Boolean,
diff --git a/server/src/features/behavior_trees/models/behavior_tree_validation_model.ts b/server/src/features/behavior_trees/models/behavior_tree_validation_model.ts
index 9dfac34..e729b67 100644
--- a/server/src/features/behavior_trees/models/behavior_tree_validation_model.ts
+++ b/server/src/features/behavior_trees/models/behavior_tree_validation_model.ts
@@ -1,4 +1,4 @@
-import { IsMongoId, IsString } from "class-validator";
+import { IsMongoId, IsNumber, IsString } from "class-validator";
import { IBehaviorTreeModel } from "./behavior_tree_database_model";
export class BehaviorTreeValidationModel implements IBehaviorTreeModel {
@@ -8,4 +8,6 @@ export class BehaviorTreeValidationModel implements IBehaviorTreeModel {
public project:string;
public skills:any;
public xml:string;
+ @IsNumber()
+ public unixTime: number
}
diff --git a/ui/public/index.html b/ui/public/index.html
index 583a521..c7814ac 100644
--- a/ui/public/index.html
+++ b/ui/public/index.html
@@ -1,133 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Robossembler
+
-
-
-
-
-
-
-
-
- Robossembler
-
+
+
+
+
-
-
-
+
+
-
+ .dotted {
+ background-image: -webkit-repeating-radial-gradient(
+ center center,
+ rgba(147, 147, 147, 30%),
+ rgba(147, 147, 147, 30%) 2px,
+ transparent 2px,
+ transparent 100%
+ );
+
+ background-image: -moz-repeating-radial-gradient(
+ center center,
+ rgba(147, 147, 147, 30%),
+ rgba(147, 147, 147, 30%) 2px,
+ transparent 2px,
+ transparent 100%
+ );
+ background-image: -ms-repeating-radial-gradient(
+ center center,
+ rgba(147, 147, 147, 30%),
+ rgba(147, 147, 147, 30%) 2px,
+ transparent 2px,
+ transparent 100%
+ );
+ background-image: repeating-radial-gradient(
+ center center,
+ rgba(147, 147, 147, 30%),
+ rgba(147, 147, 147, 30%) 2px,
+ transparent 2px,
+ transparent 100%
+ );
+ -webkit-background-size: 20px 20px;
+ -moz-background-size: 20px 20px;
+ background-size: 20px 20px;
-
\ No newline at end of file
+ width: 100%;
+ height: 100%;
+ }
+
+
diff --git a/ui/src/core/extensions/date.ts b/ui/src/core/extensions/date.ts
index 09ab47d..1f5337b 100644
--- a/ui/src/core/extensions/date.ts
+++ b/ui/src/core/extensions/date.ts
@@ -6,35 +6,7 @@ export const DateExtensions = () => {
}
if (Date.prototype.formatDate === undefined) {
Date.prototype.formatDate = function () {
- const days = ["Воскресенье", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"];
- const monthNames = [
- "Января",
- "Февраля",
- "Марта",
- "Апреля",
- "Майя",
- "Июня",
- "Июля",
- "Августа",
- "Сентября",
- "Октября",
- "Ноября",
- "Декабря",
- ];
-
- return (
- days[this.getDay()] +
- ", " +
- this.getDate() +
- ", " +
- monthNames[this.getMonth()] +
- ", " +
- this.getFullYear() +
- "г.," +
- this.getHours() +
- ":" +
- this.getMinutes()
- );
+ return `${this.getFullYear()}.${this.getMonth()}.${this.getDay()} ${this.getHours()}:${this.getMinutes()}`;
};
}
};
diff --git a/ui/src/core/model/skill_model.ts b/ui/src/core/model/skill_model.ts
index 83c2219..5ed4485 100644
--- a/ui/src/core/model/skill_model.ts
+++ b/ui/src/core/model/skill_model.ts
@@ -37,7 +37,7 @@ export interface IDeviceDependency {
export interface IParam {
type: string;
- dependency: Object;
+ dependency?: Object;
}
export class ParamViewModel implements IParam {
type: string;
@@ -190,6 +190,9 @@ export class SkillModel extends ValidationModel implements ISkill {
super();
makeAutoObservable(this);
}
+
+ bgColor: string = `rgba(5, 26, 39, 1)`;
+ borderColor: string = "rgba(25, 130, 196, 1)";
@IsOptional()
@IsString()
sid?: string;
@@ -239,13 +242,18 @@ export class Skills {
@IsArray()
@Type(() => SkillModel)
skills: SkillModel[];
+ static fromSkills = (skilsModel: SkillModel[]) => {
+ const skills = this.empty();
+ skills.skills = skilsModel;
+ return skills;
+ };
validation = (): Result => {
const errors: string[] = [];
this.skills.forEach((skill) => {
skill.BTAction.forEach((action) => {
if (action.param.isNotEmpty()) {
action.param.forEach((param) => {
- if (Object.keys(param.dependency).isEmpty()) {
+ if (Object.keys(param?.dependency ?? {}).isEmpty()) {
errors.push(param.type);
}
});
@@ -257,6 +265,16 @@ export class Skills {
}
return Result.ok(undefined);
};
+ getCssAtLabel = (label: string): React.CSSProperties =>
+ this.skills.reduce((acc, el) => {
+ el.BTAction.rFind((el) => el.name.isEqual(label)).map(() => {
+ acc = {
+ backgroundColor: el.bgColor,
+ border: `1px solid ${el.borderColor}`,
+ };
+ });
+ return acc;
+ }, {});
skillBySid = (sid: string) =>
SkillModel.isEmpty(
this.skills.reduce((acc, el) => {
@@ -270,7 +288,7 @@ export class Skills {
toSkillView = (): ISkillView[] =>
this.skills.map((el) => {
return {
- name: el.Module.name,
+ name: el.SkillPackage.name,
children: el.BTAction.map((act) => {
return { name: act.name, uuid: v4() };
}),
@@ -346,7 +364,7 @@ export class Skills {
skill.BTAction.map((action) => {
action.param.map((param) => {
if (param.type.isEqualR(skillType)) {
- acc.push(param.dependency);
+ acc.push(param?.dependency ?? {});
}
return param;
});
@@ -375,7 +393,7 @@ export class Skills {
skill.BTAction.forEach((action) => {
action.param.forEach((param) => {
if (param.type.isEqual(skillType)) {
- acc = Object.keys(param.dependency).isNotEmpty();
+ acc = Object.keys(param?.dependency ?? {}).isNotEmpty();
}
});
});
@@ -399,7 +417,6 @@ export class Skills {
return this.skills.filter((skill) => !skill.sid?.isEqual(sid));
}
updateSkill = (skill: SkillModel) => {
- console.log(skill);
this.skills = this.skills.map((el) => {
if (el.sid?.isEqual(skill.sid ?? "")) {
el = skill;
@@ -408,7 +425,13 @@ export class Skills {
});
};
skillHasForm = (label: string): boolean => {
- // TODO:NEED IMPLEMENTS
return true;
};
+ getSkillWidthAtLabel = (label: string): number =>
+ this.getSkillParams(label).reduce((acc, element) => {
+ if (element.type.length > acc) {
+ acc = element.type.length;
+ }
+ return acc;
+ }, 0);
}
diff --git a/ui/src/core/model/validation_model.ts b/ui/src/core/model/validation_model.ts
index 81a94ba..7603fa6 100644
--- a/ui/src/core/model/validation_model.ts
+++ b/ui/src/core/model/validation_model.ts
@@ -14,9 +14,8 @@ export class ValidationModel {
if (error.constraints) return Object.values(error.constraints).join(", ");
return "";
});
- console.log(errors)
- console.log(this)
- return Result.error(message.join(","));
+
+ return Result.error(message.join(", \n"));
} else {
return Result.ok(this as unknown as T);
}
diff --git a/ui/src/core/routers/routers.tsx b/ui/src/core/routers/routers.tsx
index f86090f..8887fc1 100644
--- a/ui/src/core/routers/routers.tsx
+++ b/ui/src/core/routers/routers.tsx
@@ -9,7 +9,10 @@ import { DataSetScreen, DatasetsScreenPath } from "../../features/dataset/datase
import { AssemblesScreen, AssemblesScreenPath } from "../../features/assembles/assembles_screen";
import { SimulationScreen, SimulationScreenPath } from "../../features/simulations/simulations_screen";
import { EstimateScreen, EstimateScreenPath } from "../../features/estimate/estimate_screen";
-import { CalculationInstanceScreenPath, CalculationInstanceScreen } from "../../features/calculation_instance/presentation/calculation_instance_screen";
+import {
+ CalculationInstanceScreenPath,
+ CalculationInstanceScreen,
+} from "../../features/calculation_instance/presentation/calculation_instance_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";
@@ -17,7 +20,6 @@ import { SkillsScreen, SkillsScreenPath } from "../../features/skills/skills_scr
import { CalculationsTemplateScreenPath } from "../../features/calculations_template/calculations_template_screen";
const idURL = ":id";
-
export const router = createBrowserRouter([
{
path: AllProjectScreenPath,
@@ -32,7 +34,11 @@ export const router = createBrowserRouter([
element: ,
},
{
- path: BehaviorTreeBuilderPath,
+ path: BehaviorTreeBuilderPath(idURL),
+ element: ,
+ },
+ {
+ path: BehaviorTreeBuilderPath(),
element: ,
},
{
diff --git a/ui/src/core/store/base_store.ts b/ui/src/core/store/base_store.ts
index 43ce8d1..ebd7e65 100644
--- a/ui/src/core/store/base_store.ts
+++ b/ui/src/core/store/base_store.ts
@@ -58,15 +58,15 @@ export class SimpleErrorState extends UiLoader {
}
export class ModalStore extends SimpleErrorState {
isModalOpen: boolean = false;
- showModal = () => {
+ modalShow = () => {
this.isModalOpen = true;
};
- handleOk = () => {
+ modalClickOk = () => {
this.isModalOpen = false;
};
- handleCancel = () => {
+ modalCancel = () => {
this.isModalOpen = false;
};
}
diff --git a/ui/src/core/store/theme_store.ts b/ui/src/core/store/theme_store.ts
new file mode 100644
index 0000000..b0e0da8
--- /dev/null
+++ b/ui/src/core/store/theme_store.ts
@@ -0,0 +1,61 @@
+import { makeAutoObservable } from "mobx";
+
+export abstract class Theme {
+ abstract greenWhite: string;
+ abstract white: string;
+ abstract black: string;
+ abstract green: string;
+ abstract grau: string;
+ abstract grauLeft: string;
+ abstract redAccent: string;
+ abstract grau2: string;
+ abstract outlineVariantDark: string;
+ abstract outlineVariantLight: string;
+ abstract surfaceContainerLow: string;
+ abstract surfaceContainer: string;
+ abstract darkSurfaceVariant: string;
+ abstract outlineVariant: string;
+ abstract navBlue: string;
+ abstract grayLeft: string;
+ abstract onSurface: string;
+ abstract surfaceContainerHighest: string;
+ abstract darkSurface: string;
+ abstract fon: string;
+ abstract onSurfaceVariant: string;
+ abstract darkOnSurfaceVariant: string;
+ abstract error50: string;
+}
+
+export class BlackTheme implements Theme {
+ error50: string = "rgba(220, 54, 46, 1)";
+ darkOnSurfaceVariant: string = "rgba(202, 196, 208, 1)";
+ darkSurfaceVariant: string = "rgba(73, 69, 79, 1)";
+ navBlue: string = "rgba(202, 211, 216, 1)";
+ fon: string = "rgba(147, 147, 147, 0.4)";
+ darkSurface: string = "rgba(20, 18, 24, 1)";
+ surfaceContainerHighest: string = "rgba(54, 52, 59, 1)";
+ onSurface: string = "rgba(230, 224, 233, 1)";
+ grayLeft: string = "rgba(213, 220, 224, 1)";
+ surfaceContainer: string = "rgba(33, 31, 38, 1)";
+ surfaceContainerLow: string = "rgba(29, 27, 32, 1)";
+ outlineVariantLight: string = "rgba(202, 196, 208, 1)";
+ grau2: string = "rgba(147, 147, 147, 1)";
+ greenWhite: string = "rgba(233, 237, 201, 1)";
+ white: string = "rgba(255, 255, 255, 1)";
+ black: string = "rgba(0, 0, 0, 1)";
+ green: string = "rgba(56, 87, 72, 1)";
+ grau: string = "rgba(147, 147, 147, 1)";
+ grauLeft: string = "";
+ redAccent: string = "rgba(72, 23, 39, 1)";
+ outlineVariantDark: string = "rgba(73, 69, 79, 1)";
+ outlineVariant: string = "rgba(202, 196, 208, 1)";
+ onSurfaceVariant: string = "rgba(202, 196, 208, 1)";
+}
+
+export class ThemeStore {
+ theme: Theme = new BlackTheme();
+ constructor() {
+ makeAutoObservable(this);
+ }
+ changeTheme = (theme: Theme) => (this.theme = theme);
+}
diff --git a/ui/src/core/ui/button/button_v2.tsx b/ui/src/core/ui/button/button_v2.tsx
new file mode 100644
index 0000000..80b72d9
--- /dev/null
+++ b/ui/src/core/ui/button/button_v2.tsx
@@ -0,0 +1,54 @@
+import { match } from "ts-pattern";
+import { themeStore } from "../../..";
+import { CoreText, CoreTextType } from "../text/text";
+export enum ButtonV2Type {
+ default = "default",
+}
+export const ButtonV2 = ({
+ text,
+ textColor,
+ onClick,
+ style,
+ icon,
+ isFilled,
+ type,
+}: {
+ text?: string;
+ textColor?: string;
+ onClick: () => void;
+ style?: React.CSSProperties;
+ icon?: React.ReactNode;
+ isFilled?: boolean;
+ type?: ButtonV2Type;
+}) => {
+ return (
+ 15)
+ .otherwise(() => 5),
+ borderRadius: match(type)
+ .with(ButtonV2Type.default, () => 5)
+ .otherwise(() => 100),
+ display: "flex",
+ paddingRight: 10,
+ paddingLeft: 10,
+ }}
+ onClick={() => onClick()}
+ >
+ {icon}
+ CoreTextType.smallv3)
+ .otherwise(() => CoreTextType.largeV2)}
+ />
+
+ );
+};
diff --git a/ui/src/core/ui/card/card.tsx b/ui/src/core/ui/card/card.tsx
new file mode 100644
index 0000000..08284ca
--- /dev/null
+++ b/ui/src/core/ui/card/card.tsx
@@ -0,0 +1,88 @@
+import { useRef, useEffect, useState } from "react";
+import { themeStore } from "../../..";
+import { ButtonV2 } from "../button/button_v2";
+import { Icon } from "../icons/icons";
+import { CoreText, CoreTextType } from "../text/text";
+
+export const CoreCard: React.FC<{
+ clickDeleteIcon: Function;
+ clickGoToIcon: Function;
+ date: number;
+ descriptionBottom?: string;
+ descriptionTop: string;
+ descriptionMiddle?: string;
+}> = ({ clickDeleteIcon, clickGoToIcon, descriptionBottom, descriptionTop, date, descriptionMiddle }) => {
+ const ref = useRef(null);
+ const [bgColor, setBgColor] = useState(themeStore.theme.surfaceContainerLow);
+ useEffect(() => {
+ ref.current?.addEventListener("mousemove", () => {
+ setBgColor(themeStore.theme.surfaceContainerHighest);
+ });
+ ref.current?.addEventListener("mouseleave", () => {
+ setBgColor(themeStore.theme.surfaceContainerLow);
+ });
+ }, []);
+ return (
+
+
+
+
+
+
clickGoToIcon()} text="Перейти" />
+
+ clickDeleteIcon()}
+ style={{
+ border: `1px solid ${themeStore.theme.greenWhite}`,
+ height: 30,
+ width: 30,
+ textAlign: "center",
+ alignContent: "center",
+ borderRadius: 5,
+ cursor: "pointer",
+ }}
+ />
+
+
+
+
+
+ );
+};
diff --git a/ui/src/core/ui/form_builder/forms/select_detail/presentation/select_detail_screen.tsx b/ui/src/core/ui/form_builder/forms/select_detail/presentation/select_detail_screen.tsx
index a5188f9..e5e5c9f 100644
--- a/ui/src/core/ui/form_builder/forms/select_detail/presentation/select_detail_screen.tsx
+++ b/ui/src/core/ui/form_builder/forms/select_detail/presentation/select_detail_screen.tsx
@@ -12,8 +12,6 @@ export const SelectDetail = observer((props: IFormBuilderComponentsProps {
store.viewModel = new SelectDetailViewModel(props.dependency.details);
store.isLoading = false;
- console.log(store.viewModel);
-
store.init();
}, []);
diff --git a/ui/src/core/ui/form_builder/forms/select_detail/presentation/select_detail_store.tsx b/ui/src/core/ui/form_builder/forms/select_detail/presentation/select_detail_store.tsx
index 3bcb116..1ad6afc 100644
--- a/ui/src/core/ui/form_builder/forms/select_detail/presentation/select_detail_store.tsx
+++ b/ui/src/core/ui/form_builder/forms/select_detail/presentation/select_detail_store.tsx
@@ -5,8 +5,6 @@ import { FormState } from "../../../../../store/base_store";
import { SelectDetailViewModel } from "../model/select_details_model";
export class SelectDetailStore extends FormState {
-
-
viewModel = SelectDetailViewModel.empty();
parts?: Parts[];
isLoading: boolean = true;
@@ -16,7 +14,6 @@ export class SelectDetailStore extends FormState {
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)) {
diff --git a/ui/src/core/ui/icons/icons.tsx b/ui/src/core/ui/icons/icons.tsx
index 6fc4d97..dcca5b6 100644
--- a/ui/src/core/ui/icons/icons.tsx
+++ b/ui/src/core/ui/icons/icons.tsx
@@ -54,12 +54,52 @@ const getIconSvg = (
switch (type) {
case "":
return Result.ok();
+ case "LeftIcon":
+ return Result.ok(
+
+ );
+ case "SettingGear":
+ return Result.ok(
+
+ );
+ case "Bucket":
+ return Result.ok(
+
+ );
case "Error":
return Result.ok(
);
+ case "BottomSquare":
+ return Result.ok(
+
+ );
+ case "DashBoard":
+ return Result.ok(
+
+ );
+ case "PlayComputer":
+ return Result.ok(
+
+ );
+ case "Graph":
+ return Result.ok(
+
+ );
+ case "Storage":
+ return Result.ok(
+
+ );
+ case "RobotARM":
+ return Result.ok(
+
+ );
+ case "Home":
+ return Result.ok(
+
+ );
+ case "ComposeSquares":
+ return Result.ok(
+
+ );
case "Log":
return Result.ok(
);
+ case "Plus":
+ return Result.ok(
+
+ );
case "PlusCircle":
return Result.ok(
);
diff --git a/ui/src/core/ui/input/input_v2.tsx b/ui/src/core/ui/input/input_v2.tsx
new file mode 100644
index 0000000..488e86f
--- /dev/null
+++ b/ui/src/core/ui/input/input_v2.tsx
@@ -0,0 +1,54 @@
+import { themeStore } from "../../..";
+import { Icon } from "../icons/icons";
+import { CoreText, CoreTextType, FontType } from "../text/text";
+
+interface InputV2Props {
+ label: string;
+ value?: string;
+ height?: number;
+ onChange?: (text: string) => void;
+}
+export const InputV2: React.FC = ({ label, height, value, onChange }) => {
+ return (
+
+
+
+ {
+ if (onChange) onChange(text);
+ }}
+ style={{
+ backgroundColor: themeStore.theme.surfaceContainerHighest,
+ paddingTop: 5,
+ borderRadius: 5,
+ }}
+ contentEditable={true}
+ type={CoreTextType.largeV2}
+ color={themeStore.theme.white}
+ fontType={FontType.ubuntu}
+ text={value}
+ />
+
+
+
+
+ );
+};
diff --git a/ui/src/core/ui/modal/modal.tsx b/ui/src/core/ui/modal/modal.tsx
new file mode 100644
index 0000000..7b6c8a5
--- /dev/null
+++ b/ui/src/core/ui/modal/modal.tsx
@@ -0,0 +1,49 @@
+import React from "react";
+import { themeStore } from "../../..";
+import { CoreText, CoreTextType } from "../text/text";
+import { InputV2 } from "../input/input_v2";
+import { CoreButton } from "../button/button";
+import { ButtonV2, ButtonV2Type } from "../button/button_v2";
+
+interface ModalProps {
+ isOpen: boolean;
+ onClose: () => void;
+ children: React.ReactNode;
+ style?: React.CSSProperties;
+}
+
+export const CoreModal: React.FC = ({ isOpen, onClose, children, style }) => {
+ if (!isOpen) return null;
+
+ return (
+ onClose()}
+ >
+
event.stopPropagation()}
+ style={{
+ backgroundColor: themeStore.theme.black,
+ border: `1px solid ${themeStore.theme.greenWhite}`,
+ padding: 20,
+ borderRadius: 5,
+ width: 400,
+ position: "relative",
+ }}
+ >
+ {children}
+
+
+ );
+};
+
\ No newline at end of file
diff --git a/ui/src/core/ui/pages/main_page.tsx b/ui/src/core/ui/pages/main_page.tsx
index 296fe1f..fe60d70 100644
--- a/ui/src/core/ui/pages/main_page.tsx
+++ b/ui/src/core/ui/pages/main_page.tsx
@@ -27,17 +27,19 @@ const Block = (props: IBlockProps) => {
style={
props.isActive
? {
- textAlignLast: "center",
- height: 32,
- backgroundColor: "rgba(232, 222, 248, 1)",
- marginLeft: 5,
- marginRight: 5,
- alignContent: "center",
- borderRadius: 12,
- }
+ textAlignLast: "center",
+ height: 32,
+ backgroundColor: "rgba(232, 222, 248, 1)",
+ marginLeft: 5,
+ marginRight: 5,
+ alignContent: "center",
+ borderRadius: 12,
+ }
: {
- textAlignLast: "center", alignContent: "center", height: 32,
- }
+ textAlignLast: "center",
+ alignContent: "center",
+ height: 32,
+ }
}
>
@@ -57,7 +59,6 @@ export interface IMainPageProps {
error?: UiBaseError[];
}
-
export const MainPage = (props: IMainPageProps) => {
const blocksNames = [
{ name: "Детали", path: DetailsScreenPath, icon: "Setting" },
@@ -65,7 +66,7 @@ export const MainPage = (props: IMainPageProps) => {
{ name: "Датасеты", path: DatasetsScreenPath, icon: "Datasets" },
{ name: "Сцена", path: SceneManagerPath, icon: "Scene" },
{ name: "Вычисления", path: SkillScreenPath, icon: "Layers" },
- { name: "Поведение", path: BehaviorTreeBuilderPath, icon: "Rocket" },
+ { name: "Поведение", path: BehaviorTreeBuilderPath(), icon: "Rocket" },
{ name: "Симуляция", path: SimulationScreenPath, icon: "Simulation" },
{ name: "Оценка", path: EstimateScreenPath, icon: "Grade" },
];
diff --git a/ui/src/core/ui/pages/main_page_v2.tsx b/ui/src/core/ui/pages/main_page_v2.tsx
new file mode 100644
index 0000000..b096e1e
--- /dev/null
+++ b/ui/src/core/ui/pages/main_page_v2.tsx
@@ -0,0 +1,213 @@
+import React, { useEffect } from "react";
+import { themeStore } from "../../..";
+import { Icon } from "../icons/icons";
+import { observer } from "mobx-react-lite";
+import { makeAutoObservable } from "mobx";
+import { RefDiv } from "../ref/ref_div";
+export enum CycleState {
+ isMoving = "isMoving",
+ stop = "stop",
+}
+function delay(ms: number) {
+ return new Promise((resolve) => setTimeout(resolve, ms));
+}
+
+class MainPageStore {
+ cycleState = CycleState.stop;
+ isFirstClick: boolean = true;
+ stepMs = { 1: 15, 2: 20, 3: 25, 4: 30, 5: 35, 6: 40, 7: 45, 8: 50 };
+ icons: {
+ icon: string;
+ isActive: boolean;
+ style: React.CSSProperties;
+ left: number;
+ top: number;
+ }[] = [
+ { icon: "Home", isActive: true, style: {}, left: 0, top: 0 },
+ { icon: "ComposeSquares", isActive: false, style: {}, left: 0, top: 0 },
+ { icon: "BottomSquare", isActive: false, style: {}, left: 0, top: 0 },
+ { icon: "RobotARM", isActive: false, style: {}, left: 0, top: 0 },
+ { icon: "Storage", isActive: false, style: {}, left: 0, top: 0 },
+ { icon: "Graph", isActive: false, style: {}, left: 0, top: 0 },
+ { icon: "PlayComputer", isActive: false, style: {}, left: 0, top: 0 },
+ { icon: "DashBoard", isActive: false, style: {}, left: 0, top: 0 },
+ ];
+ paddingLeft: number = 0;
+ offsetLeftCircle: number = 0;
+ leftCircle = 0;
+ constructor() {
+ makeAutoObservable(this);
+ }
+ init = (paddingLeft: number) => {
+ this.leftCircle = Math.abs(this.offsetLeftCircle - this.getActive()!.left) - paddingLeft;
+
+ this.paddingLeft = paddingLeft;
+ };
+ getActive = () => this.icons.filter((el) => el.isActive).at(0);
+ getActiveIndex = () => this.icons.findIndex((el) => el.isActive);
+ selectIndex = async (i: number) => {
+ const prevActive = this.getActive();
+ const prevActiveIndex = this.getActiveIndex();
+ this.icons
+ .map((element) => {
+ element.isActive = false;
+ return element;
+ })
+ .map((element, index) =>
+ i.isEqualR(index).fold(
+ () => {
+ element.isActive = true;
+ },
+ () => element
+ )
+ );
+ const nextActive = this.getActive();
+ const nextActiveIndex = this.getActiveIndex();
+
+ this.cycleState = CycleState.isMoving;
+ let distance = 0;
+
+ distance = nextActive!.left - this.offsetLeftCircle;
+
+ const step = distance / 10;
+
+ for await (const num of Array.from({ length: 10 }, (_, i) => i + 1)) {
+ // @ts-ignore
+ await delay(this.stepMs[Math.abs(nextActiveIndex - prevActiveIndex)]);
+ nextActive!.top = nextActive!.top + 3;
+ if (!this.isFirstClick) prevActive!.top = prevActive!.top - 3;
+ let offset = 0;
+ if (num === 10) {
+ offset = 6;
+ }
+ this.leftCircle = this.leftCircle + step - offset;
+ }
+ this.isFirstClick = false;
+ };
+ updateLeftStyle = (left: number, index: number) => this.icons.replacePropIndex({ left: left }, index);
+}
+export const MainPageV2: React.FC<{ children: React.ReactNode; bgColor: string; style?: React.CSSProperties | void }> =
+ observer(({ children, bgColor, style }) => {
+ const [store] = React.useState(() => new MainPageStore());
+ useEffect(() => {
+ store.init(4);
+ }, []);
+ return (
+
+
+
+ {store.icons.map((el, i) => (
+
+ {el.isActive === true ? (
+ <>
+ store.updateLeftStyle(Number(text), i)}
+ >
+ {
+ store.icons
+ .map((element) => {
+ element.isActive = false;
+ return element;
+ })
+ .map((element, index) =>
+ i.isEqualR(index).fold(
+ () => {
+ element.isActive = true;
+ },
+ () => element
+ )
+ );
+ }}
+ />
+
+ >
+ ) : (
+ <>
+ store.updateLeftStyle(Number(text), i)}
+ >
+ store.selectIndex(i)} />
+
+ >
+ )}
+
+ ))}
+ >
+ }
+ />
+
+
{
+ store.offsetLeftCircle = Number(text);
+ }}
+ style={{
+ position: "relative",
+ top: -30,
+ left: store.leftCircle,
+ backgroundColor: bgColor,
+ width: 60,
+ height: 60,
+ borderRadius: "50%",
+ paddingTop: 10,
+ zIndex: 21,
+ }}
+ >
+
+
+
+
+
{children}
+
+ );
+ });
diff --git a/ui/src/core/ui/pages/preview_page.tsx b/ui/src/core/ui/pages/preview_page.tsx
index d3f765e..58fe9a1 100644
--- a/ui/src/core/ui/pages/preview_page.tsx
+++ b/ui/src/core/ui/pages/preview_page.tsx
@@ -21,7 +21,6 @@ export const PreviewPage = (props: IPreviewPageProps) => {
{
- console.log(200);
if (props.click) props.click();
}}
text={props.minText ?? ""}
diff --git a/ui/src/core/ui/ref/ref_div.tsx b/ui/src/core/ui/ref/ref_div.tsx
new file mode 100644
index 0000000..3ee29b0
--- /dev/null
+++ b/ui/src/core/ui/ref/ref_div.tsx
@@ -0,0 +1,21 @@
+import { useEffect, useRef } from "react";
+
+export const RefDiv: React.FC<{
+ property?: string;
+ onChange?: (property: string) => void;
+ style?: React.CSSProperties;
+ children?: React.ReactNode;
+}> = ({ property, onChange, style, children }) => {
+ const ref = useRef(null);
+ useEffect(() => {
+ if (ref.current && onChange) {
+ // @ts-ignore
+ onChange(String(ref.current[property]));
+ }
+ } );
+ return (
+
+ {children}
+
+ );
+};
diff --git a/ui/src/core/ui/select/select_v2.tsx b/ui/src/core/ui/select/select_v2.tsx
new file mode 100644
index 0000000..f42e65e
--- /dev/null
+++ b/ui/src/core/ui/select/select_v2.tsx
@@ -0,0 +1,96 @@
+import React from "react";
+import { CoreText, CoreTextType } from "../text/text";
+import { IStyle } from "../../model/style";
+import { themeStore } from "../../..";
+
+interface ISelectV2Props extends IStyle {
+ items: { name: string; value: string }[];
+ initialValue: string;
+ label: string;
+ onChange: (value: string) => void;
+}
+export const SelectV2: React.FC = ({ items, initialValue, label, onChange, style }) => {
+ const ref = React.useRef(null);
+ const [cursorIsCorses, setCursorIsCorses] = React.useState(false);
+ const [width, setWidth] = React.useState(0);
+ const [value, setValue] = React.useState(initialValue);
+ React.useEffect(() => {
+ ref.current?.addEventListener("mousemove", () => {
+ setCursorIsCorses(true);
+ });
+ ref.current?.addEventListener("mouseleave", () => {
+ setCursorIsCorses(false);
+ });
+
+ setWidth(Number(ref.current?.clientWidth));
+ }, [ref, setCursorIsCorses]);
+
+ return (
+
+
+
+
+ {cursorIsCorses
+ ? items.map((el, i) => (
+ {
+ setValue(el.name);
+ onChange(el.value);
+ }}
+ style={{
+ padding: 10,
+ alignContent: "center",
+ cursor: "pointer",
+ }}
+ />
+ ))
+ : null}
+
+
+
+ );
+};
diff --git a/ui/src/core/ui/text/text.tsx b/ui/src/core/ui/text/text.tsx
index 6503f3f..85aef71 100644
--- a/ui/src/core/ui/text/text.tsx
+++ b/ui/src/core/ui/text/text.tsx
@@ -2,63 +2,106 @@ import * as React from "react";
import { IStyle } from "../../model/style";
export enum CoreTextType {
- header = 'header',
- medium = 'medium',
- large = 'large',
- small = 'small',
- big = 'big'
+ header = "header",
+ medium = "medium",
+ mediumV2 = "mediumV2",
+ largeV2 = "largeV2",
+ large = "large",
+ small = "small",
+ smallV2 = "smallV2",
+ smallv3 = "smallv3",
+ big = "big",
}
+export enum FontType {
+ ubuntu = "'Ubuntu'",
+ roboto = "'Roboto'",
+}
export interface ITextProps extends IStyle {
- text: string;
+ text?: string;
type: CoreTextType;
+ fontType?: FontType;
color?: string;
onClick?: Function;
+ onChange?: (text: string) => void;
+ contentEditable?: boolean;
}
const getStyle = (type: CoreTextType, color: string | undefined) => {
- if (type.isEqual(CoreTextType.small)) return {
- color: color ?? "rgba(73, 69, 79, 1)",
- fontSize: 12,
- fontFamily: "Roboto",
- fontWeight: 400,
- fontSizeAdjust: 14,
- textOverflow: "ellipsis",
- }
+ if (type.isEqual(CoreTextType.smallv3))
+ return {
+ fontWeight: "400",
+ fontSize: "16px;",
+ lineHeight: "19px",
+ fontStyle: "normal",
+ };
+ if (type.isEqual(CoreTextType.smallV2))
+ return {
+ fontStyle: "normal",
+ fontWeight: "400",
+ fontSize: 14,
+ color: color ?? "#1D1B20",
+ };
+ if (type.isEqual(CoreTextType.mediumV2))
+ return {
+ color: color ?? "rgba(73, 69, 79, 1)",
+ fontStyle: "normal",
+ fontWeight: "500",
+ fontSize: "16px",
+ lineHeight: "24px",
+ letterSpacing: "0.15px",
+ };
+ if (type.isEqual(CoreTextType.largeV2))
+ return {
+ color: color ?? "rgba(73, 69, 79, 1)",
- if (type.isEqual(CoreTextType.large)) return {
- color: color ?? "#1D1B20",
- fontSize: 16,
- fontFamily: "Roboto",
- fontWeight: 400,
- fontSizeAdjust: 14,
- textOverflow: "ellipsis",
- }
- if (type.isEqual(CoreTextType.medium)) return {
- color: color ?? "#1D1B20",
- fontSize: 14,
- fontFamily: "Roboto",
- fontWeight: 400,
- textOverflow: "ellipsis",
- fontSizeAdjust: 14,
- }
- if (type.isEqual(CoreTextType.header)) return {
- color: color ?? "#1D1B20",
- fontSize: 20,
- fontFamily: "Roboto",
- fontWeight: 500,
- textOverflow: "ellipsis",
- fontSizeAdjust: 16,
- }
- if (type.isEqual(CoreTextType.big)) return {
- color: color ?? "#1D1B20",
- fontSize: 40,
- fontFamily: "Roboto",
- fontWeight: 500,
- textOverflow: "ellipsis",
+ alignContent: "center",
+ fontWeight: 500,
+ fontSize: 14,
+ lineHeight: "20px",
+ };
+ if (type.isEqual(CoreTextType.small))
+ return {
+ color: color ?? "rgba(73, 69, 79, 1)",
+ fontSize: 12,
+ fontWeight: 400,
+ fontSizeAdjust: 14,
+ textOverflow: "ellipsis",
+ };
- fontSizeAdjust: 16,
- }
+ if (type.isEqual(CoreTextType.large))
+ return {
+ color: color ?? "#1D1B20",
+ fontSize: 16,
+ fontWeight: 400,
+ fontSizeAdjust: 14,
+ textOverflow: "ellipsis",
+ };
+ if (type.isEqual(CoreTextType.medium))
+ return {
+ color: color ?? "#1D1B20",
+ fontSize: 14,
+ fontWeight: 400,
+ textOverflow: "ellipsis",
+ fontSizeAdjust: 14,
+ };
+ if (type.isEqual(CoreTextType.header))
+ return {
+ color: color ?? "#1D1B20",
+ fontSize: 20,
+ fontWeight: 500,
+ textOverflow: "ellipsis",
+ fontSizeAdjust: 16,
+ };
+ if (type.isEqual(CoreTextType.big))
+ return {
+ color: color ?? "#1D1B20",
+ fontSize: 40,
+ fontWeight: 500,
+ textOverflow: "ellipsis",
+
+ fontSizeAdjust: 16,
+ };
return {
color: color ?? "rgba(73, 69, 79, 1)",
fontSize: 12,
@@ -66,21 +109,37 @@ const getStyle = (type: CoreTextType, color: string | undefined) => {
fontWeight: 400,
fontSizeAdjust: 14,
textOverflow: "ellipsis",
+ };
+};
+
+const appendStyle = (
+ type: CoreTextType,
+ color: string | undefined,
+ style: React.CSSProperties | undefined,
+ fontType: FontType | undefined
+) => {
+ let font = "Roboto";
+ if (fontType !== undefined) {
+ font = fontType;
}
-}
-const appendStyle = (type: CoreTextType, color: string | undefined, style: React.CSSProperties | undefined) => {
- return Object.assign(getStyle(type, color), style)
-}
+ return Object.assign(Object.assign(getStyle(type, color), style), { fontFamily: font });
+};
export function CoreText(props: ITextProps) {
return (
{
- if (props.onClick) props.onClick()
+ if (props.onClick) props.onClick();
+ }}
+ style={appendStyle(props.type, props.color, props.style, props.fontType)}
+ onInput={(event) => {
+ if (props.onChange) {
+ // @ts-expect-error
+ props.onChange(event.target.innerText);
+ }
}}
- style={appendStyle(props.type, props.color, props.style)}
>
{props.text}
);
}
-
\ No newline at end of file
diff --git a/ui/src/features/all_projects/presentation/all_projects_screen.tsx b/ui/src/features/all_projects/presentation/all_projects_screen.tsx
index 0a045a7..cadc55a 100644
--- a/ui/src/features/all_projects/presentation/all_projects_screen.tsx
+++ b/ui/src/features/all_projects/presentation/all_projects_screen.tsx
@@ -27,7 +27,7 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
largeText={"Проекты"}
needBackButton={false}
minText="Создать новый проект?"
- click={() => store.showModal()}
+ click={() => store.modalShow()}
isError={false}
isLoading={store.isLoading}
children={
@@ -82,7 +82,7 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
footer={null}
closable={false}
closeIcon={null}
- onCancel={store.handleCancel}
+ onCancel={store.modalCancel}
>
store.setDescriptionToNewProject(text)} />
@@ -102,7 +102,7 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
style={{ marginRight: 10 }}
filled={true}
/>
- store.handleCancel()} style={{ marginRight: 10 }} />
+ store.modalCancel()} style={{ marginRight: 10 }} />
>
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 3c26629..4ca160a 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
@@ -1,5 +1,5 @@
import { Result } from "../../../core/helper/result";
-import { Skills } from "../../../core/model/skill_model";
+import { SkillModel, Skills } from "../../../core/model/skill_model";
import { HttpError, HttpMethod, CoreHttpRepository } from "../../../core/repository/core_http_repository";
import { BehaviorTreeModel } from "../model/behavior_tree_model";
import { BehaviorTreeViewModel } from "../model/behavior_tree_view_model";
@@ -8,12 +8,12 @@ export class BehaviorTreeBuilderHttpRepository extends CoreHttpRepository {
featureApi = `/behavior/trees`;
getAllBtInstances = async () => this._jsonRequest(HttpMethod.GET, this.featureApi);
- getBtSkills = async (): Promise> => {
- return (await this._jsonToClassInstanceRequest(
+ getBtSkills = async (): Promise> => {
+ return (await this._arrayJsonToClassInstanceRequest(
HttpMethod.GET,
- `${this.featureApi}/templates`,
- Skills
- )) as unknown as Promise>;
+ `/skills`,
+ SkillModel
+ )) as unknown as Promise>;
};
saveNewBt = async (model: BehaviorTreeViewModel) => this._jsonRequest(HttpMethod.POST, this.featureApi, model);
getBtById = async (id: string): Promise> =>
@@ -22,7 +22,7 @@ export class BehaviorTreeBuilderHttpRepository extends CoreHttpRepository {
`${this.featureApi}/by_id?id=${id}`,
BehaviorTreeModel
) as unknown as Promise>;
-
+ deleteBt = (id: string) => this._jsonRequest(HttpMethod.DELETE, this.featureApi);
editBt = async (model: BehaviorTreeModel) => {
await this._jsonRequest(HttpMethod.POST, `${this.featureApi}/fill/tree`, model);
return await this._jsonRequest(HttpMethod.PUT, this.featureApi, model);
diff --git a/ui/src/features/behavior_tree_builder/model/behavior_tree_model.ts b/ui/src/features/behavior_tree_builder/model/behavior_tree_model.ts
index 74acb25..c564362 100644
--- a/ui/src/features/behavior_tree_builder/model/behavior_tree_model.ts
+++ b/ui/src/features/behavior_tree_builder/model/behavior_tree_model.ts
@@ -2,11 +2,14 @@ import { Type } from "class-transformer";
import { Result } from "../../../core/helper/result";
import { Skills } from "../../../core/model/skill_model";
import { NodeBehaviorTree } from "./node_behavior_tree";
-import { IsOptional, IsString } from "class-validator";
+import { IsNotEmpty, IsNumber, IsOptional, IsString } from "class-validator";
import { BehaviorTreeBuilderHttpRepository } from "../data/behavior_tree_builder_http_repository";
import { message } from "antd";
+import { ValidationModel } from "../../../core/model/validation_model";
-export class BehaviorTreeModel {
+export class BehaviorTreeModel extends ValidationModel {
+ @IsNumber()
+ unixTime: number = Date.now();
@IsString()
public sceneId: string;
@IsOptional()
@@ -14,10 +17,16 @@ export class BehaviorTreeModel {
public skills?: Skills;
public scene: NodeBehaviorTree[] = [];
public xml: string;
+ @IsString()
+ @IsNotEmpty()
+ public description: string;
+ @IsString()
+ @IsNotEmpty()
public name: string;
public project: string;
public _id: string;
constructor(skills: Skills, scene: NodeBehaviorTree[], xml: string, name: string, project: string, _id: string) {
+ super();
this.skills = skills;
this.scene = scene;
this.xml = xml;
@@ -32,11 +41,9 @@ export class BehaviorTreeModel {
}
getSceneDependency = async (behaviorTreeBuilderHttpRepository: BehaviorTreeBuilderHttpRepository) =>
(await behaviorTreeBuilderHttpRepository.getSceneAsset(this.sceneId)).fold(
- (s) => {
-
- },
+ (s) => {},
(e) => {
- message.error('Get Scene Dependency error')
+ message.error("Get Scene Dependency error");
}
);
diff --git a/ui/src/features/behavior_tree_builder/model/behavior_tree_view_model.ts b/ui/src/features/behavior_tree_builder/model/behavior_tree_view_model.ts
index 0960242..5504970 100644
--- a/ui/src/features/behavior_tree_builder/model/behavior_tree_view_model.ts
+++ b/ui/src/features/behavior_tree_builder/model/behavior_tree_view_model.ts
@@ -1,18 +1,30 @@
+import { IsNotEmpty, IsNumber, IsString } from "class-validator";
import { Result } from "../../../core/helper/result";
+import { ValidationModel } from "../../../core/model/validation_model";
-export class BehaviorTreeViewModel {
- constructor(public name: string, public project: string, public sceneId: string) {}
- static empty() {
- return new BehaviorTreeViewModel("", "", "");
+export class BehaviorTreeViewModel extends ValidationModel {
+ @IsNumber()
+ unixTime: number = Date.now();
+ @IsNotEmpty()
+ @IsString()
+ public name: string;
+ @IsNotEmpty()
+ @IsString()
+ public description: string;
+ @IsNotEmpty()
+ @IsString()
+ public project: string;
+ @IsNotEmpty()
+ @IsString()
+ public sceneId: string;
+ constructor(name: string, description: string, project: string, sceneId: string) {
+ super();
+ this.name = name;
+ this.description = description;
+ this.project = project;
+ this.sceneId = sceneId;
}
-
- valid(): Result {
- if (this.project.isEmpty()) {
- return Result.error("project is empty");
- }
- if (this.name.isEmpty()) {
- return Result.error("name is empty");
- }
- return Result.ok(this);
+ static empty() {
+ return new BehaviorTreeViewModel("", "", "", "");
}
}
diff --git a/ui/src/features/behavior_tree_builder/model/primitive_view_model.ts b/ui/src/features/behavior_tree_builder/model/primitive_view_model.ts
index cf97fc4..29fceab 100644
--- a/ui/src/features/behavior_tree_builder/model/primitive_view_model.ts
+++ b/ui/src/features/behavior_tree_builder/model/primitive_view_model.ts
@@ -4,76 +4,81 @@ import { ISkillView } from "../presentation/ui/skill_tree/skill_tree";
extensions();
export enum SystemPrimitive {
- Sequence = 'Sequence',
- Fallback = "Fallback",
- ReactiveSequence = "ReactiveSequence",
- SequenceWithMemory = 'SequenceWithMemory',
- ReactiveFallback = "ReactiveFallback",
- Decorator = "Decorator",
- Inverter = "Inverter",
- ForceSuccess = "ForceSuccess",
- ForceFailure = "ForceFailure",
- Repeat = "Repeat",
- RetryUntilSuccessful = "RetryUntilSuccessful",
- KeepRunningUntilFailure = "KeepRunningUntilFailure",
- Delay = "Delay",
- RunOnce = "RunOnce",
+ Sequence = "Sequence",
+ Fallback = "Fallback",
+ ReactiveSequence = "ReactiveSequence",
+ SequenceWithMemory = "SequenceWithMemory",
+ ReactiveFallback = "ReactiveFallback",
+ Decorator = "Decorator",
+ Inverter = "Inverter",
+ ForceSuccess = "ForceSuccess",
+ ForceFailure = "ForceFailure",
+ Repeat = "Repeat",
+ RetryUntilSuccessful = "RetryUntilSuccessful",
+ KeepRunningUntilFailure = "KeepRunningUntilFailure",
+ Delay = "Delay",
+ RunOnce = "RunOnce",
}
interface ISystemPrimitive {
- label: string;
- group: string;
- css?: React.CSSProperties;
- input: boolean;
- output: boolean;
-
+ label: string;
+ group: string;
+ css?: React.CSSProperties;
+ input: boolean;
+ output: boolean;
}
-
export class PrimitiveViewModel {
- primitives: ISystemPrimitive[] = [
- {
- label: SystemPrimitive.Inverter,
- group: SystemPrimitive.Decorator,
- input: true,
- output: true,
- css: {
- border: "1px solid #003E61",
- borderRadius: 33,
- background: "#BDE8AE",
- },
- },
- {
- label: SystemPrimitive.ForceSuccess,
- group: SystemPrimitive.Decorator,
- input: true,
- output: true,
- css: {
- border: "1px solid #003E61",
- borderRadius: 33,
- background: "#BDE8AE",
- },
- },
- { label: SystemPrimitive.ForceFailure, group: SystemPrimitive.Decorator, input: true, output: true },
- { label: SystemPrimitive.Repeat, group: SystemPrimitive.Decorator, input: true, output: true },
- { label: SystemPrimitive.RetryUntilSuccessful, group: SystemPrimitive.Decorator, input: true, output: true },
- { label: SystemPrimitive.KeepRunningUntilFailure, group: SystemPrimitive.Decorator, input: true, output: true },
- { label: SystemPrimitive.Delay, group: SystemPrimitive.Decorator, input: true, output: true },
- { label: SystemPrimitive.RunOnce, group: SystemPrimitive.Decorator, input: true, output: true },
- { label: SystemPrimitive.ReactiveSequence, group: SystemPrimitive.Sequence, input: true, output: true },
- { label: SystemPrimitive.Sequence, group: SystemPrimitive.Sequence, input: true, output: true },
- { label: SystemPrimitive.SequenceWithMemory, group: SystemPrimitive.Sequence, input: true, output: true },
- { label: SystemPrimitive.ReactiveFallback, group: SystemPrimitive.Fallback, input: true, output: true },
- { label: SystemPrimitive.Fallback, group: SystemPrimitive.Fallback, input: true, output: true },
-
- ];
- getPrimitiveAtLabel = (name: string) => {
- return this.primitives.find((el) => el.label.isEqual(name));
- }
- toSkillView = () => this.primitives.reduce((acc, primitive) => {
- acc.rFind((el) => el.name.isEqual(primitive.group)).fold(() => {
- acc.at(acc.findIndex((eeee) => eeee.name === primitive.group))?.children?.push({ name: primitive.label })
- }, () => { acc.push({ name: primitive.group, children: [{ name: primitive.label }] }) })
- return acc;
- }, [])
-
-}
\ No newline at end of file
+ primitives: ISystemPrimitive[] = [
+ {
+ label: SystemPrimitive.Inverter,
+ group: SystemPrimitive.Decorator,
+ input: true,
+ output: true,
+ css: {
+ border: "1px solid #003E61",
+ borderRadius: 33,
+ background: "#BDE8AE",
+ },
+ },
+ {
+ label: SystemPrimitive.ForceSuccess,
+ group: SystemPrimitive.Decorator,
+ input: true,
+ output: true,
+ css: {
+ border: `1px solid white`,
+ borderRadius: 5,
+ color: "white",
+ background: "rgba(106, 76, 147, 1)",
+ },
+ },
+ { label: SystemPrimitive.ForceFailure, group: SystemPrimitive.Decorator, input: true, output: true },
+ { label: SystemPrimitive.Repeat, group: SystemPrimitive.Decorator, input: true, output: true },
+ { label: SystemPrimitive.RetryUntilSuccessful, group: SystemPrimitive.Decorator, input: true, output: true },
+ { label: SystemPrimitive.KeepRunningUntilFailure, group: SystemPrimitive.Decorator, input: true, output: true },
+ { label: SystemPrimitive.Delay, group: SystemPrimitive.Decorator, input: true, output: true },
+ { label: SystemPrimitive.RunOnce, group: SystemPrimitive.Decorator, input: true, output: true },
+ { label: SystemPrimitive.ReactiveSequence, group: SystemPrimitive.Sequence, input: true, output: true },
+ { label: SystemPrimitive.Sequence, group: SystemPrimitive.Sequence, input: true, output: true },
+ { label: SystemPrimitive.SequenceWithMemory, group: SystemPrimitive.Sequence, input: true, output: true },
+ { label: SystemPrimitive.ReactiveFallback, group: SystemPrimitive.Fallback, input: true, output: true },
+ { label: SystemPrimitive.Fallback, group: SystemPrimitive.Fallback, input: true, output: true },
+ ];
+ getPrimitiveAtLabel = (name: string) => {
+ return this.primitives.find((el) => el.label.isEqual(name));
+ };
+ toSkillView = () =>
+ this.primitives.reduce((acc, primitive) => {
+ acc
+ .rFind((el) => el.name.isEqual(primitive.group))
+ .fold(
+ () => {
+ acc.at(acc.findIndex((element) => element.name === primitive.group))?.children?.push({ name: primitive.label });
+ },
+ () => {
+ acc.push({ name: primitive.group, children: [{ name: primitive.label }] });
+ }
+ );
+ return acc;
+ }, []);
+}
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 a187043..14a41c1 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
@@ -8,12 +8,20 @@ import { CoreButton } from "../../../core/ui/button/button";
import { observer } from "mobx-react-lite";
import { match } from "ts-pattern";
import { Icon } from "../../../core/ui/icons/icons";
-import { Drawer } from "antd";
+import { Drawer, theme } from "antd";
import { CoreInput } from "../../../core/ui/input/input";
import { CoreText, CoreTextType } from "../../../core/ui/text/text";
import { useNavigate, useParams } from "react-router-dom";
import { IForms, forms } from "./ui/forms/forms";
import { CoreSelect } from "../../../core/ui/select/select";
+import { ButtonV2, ButtonV2Type } from "../../../core/ui/button/button_v2";
+import { CoreCard } from "../../../core/ui/card/card";
+import { themeStore } from "../../..";
+import { CoreModal } from "../../../core/ui/modal/modal";
+import { InputV2 } from "../../../core/ui/input/input_v2";
+import { SelectV2 } from "../../../core/ui/select/select_v2";
+import { BehaviorTreeModel } from "../model/behavior_tree_model";
+import { MainPageV2 } from "../../../core/ui/pages/main_page_v2";
export const behaviorTreeBuilderScreenPath = "behavior/tree/screen/path";
export interface DOMReact {
@@ -28,8 +36,12 @@ export interface DOMReact {
}
export const behaviorTreeBuilderStore = new BehaviorTreeBuilderStore();
-
-export const BehaviorTreeBuilderPath = "/behavior/tree/";
+export const BehaviorTreeBuilderPath = (id?: string) => {
+ if (id) {
+ return `/behavior/tree/${id}`;
+ }
+ return `/behavior/tree/`;
+};
export const BehaviorTreeBuilderScreen = observer(() => {
const navigate = useNavigate();
@@ -53,101 +65,128 @@ export const BehaviorTreeBuilderScreen = observer(() => {
store.dispose();
};
}, [id, navigate, ref, store]);
-
return (
-
{match(store.type)
- .with(StoreUIType.SelectBehaviorTree, () => (
+ .with(StoreUIType.ViewBehaviorTree, () => (
<>
- {store.btTreeModels?.map((el, index) => (
-
-
-
-
BehaviorTreeBuilderPath + navigate(el._id)}
+
+
- ))}
-
store.editDrawer(DrawerState.newBehaviorTree, true)} />
+ {store.skillTemplates ? : null}
+
+
+ store.onClickSaveBehaviorTree()} text="Сохранить" />
+
+
>
))
- .with(StoreUIType.ViewBehaviorTree, () => (
-
-
-
-
-
- {store.skillTemplates ?
: null}
+ .with(StoreUIType.SelectBehaviorTree, () => (
+ <>
+
+
}
+ text="СОЗДАТЬ ДЕРЕВО ПОВЕДЕНИЯ"
+ onClick={() => store.modalShow()}
+ />
+
+
+
+ {store.btTreeModels?.repeat(100).map((el, index) => (
+ store.deleteBt(el._id)}
+ clickGoToIcon={() => store.goToBt(el._id)}
+ descriptionMiddle={el.description}
+ descriptionTop={el.name}
+ date={el.unixTime}
+ />
+ ))}
-
- store.onClickSaveBehaviorTree()} text="Сохранить" />
-
-
+ >
))
.otherwise(() => (
<>>
))}
- >
- }
- bodyChildren={
- <>
-
-
store.editDrawer(DrawerState.newBehaviorTree, false)}
- open={store.drawers.find((el) => el.name === DrawerState.newBehaviorTree)?.status}
- >
-
-
-
store.updateForm({ name: text })} />
- el.name) ?? []}
- value={""}
- label={"Сцена"}
- onChange={(text) =>
- store.updateForm({ sceneId: store.scenes?.filter((el) => el.name.isEqual(text)).at(0)?._id })
- }
+ store.modalCancel()}
+ children={
+ <>
+
+
-
-
-
store.createNewBehaviorTree()} />
-
- store.editDrawer(DrawerState.newBehaviorTree, false)} />
-
-
-
+
+
+
+
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} />
+
+ >
+ }
+ />
;
areaPlugin?: AreaPlugin;
nodeUpdateObserver?: NodeRerenderObserver;
+ isModalOpen: boolean = false;
primitiveViewModel: PrimitiveViewModel;
skillTree: ISkillView = {
name: "",
@@ -75,6 +75,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState, area: AreaPlugin) => {
@@ -140,14 +144,14 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState {
this.activeProject = el.id;
+ this.viewModel.project = this.activeProject;
});
(await this.behaviorTreeBuilderHttpRepository.getBtSkills()).fold(
(model) => {
-
- this.skillTemplates = model;
+ this.skillTemplates = Skills.fromSkills(model);
this.skillTree.children = this.skillTree.children?.map((el) => {
if (el.name === "Действия") {
- el.children = model.toSkillView();
+ el.children = this.skillTemplates.toSkillView();
}
return el;
});
@@ -157,29 +161,10 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState {
- const keyCode = event.keyCode || event.which;
- if (keyCode === 16) {
- this.shiftIsPressed = true;
- }
- if (keyCode === 8) {
- this.deleteIsPressed = true;
- }
- });
- document.addEventListener("keyup", (event) => {
- const keyCode = event.keyCode || event.which;
- if (keyCode === 16) {
- this.shiftIsPressed = false;
- }
- if (keyCode === 8 || keyCode === 46) {
- this.deleteIsPressed = false;
- }
- });
}
initParam = async (id?: string) => {
this.isLoading = true;
- this.type = StoreUIType.ViewBehaviorTree;
+
if (id) {
(await this.behaviorTreeBuilderHttpRepository.getBtById(id)).fold(
async (model) => {
@@ -197,7 +182,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState {
this.viewModel.project = this.activeProject;
- this.viewModel.valid().fold(
- async (model) => {
- await this.messageHttp(this.behaviorTreeBuilderHttpRepository.saveNewBt(model), {
- successMessage: "Новое дерево создано",
- });
- this.mapOk("btTreeModels", this.behaviorTreeBuilderHttpRepository.getAllBtInstances());
- },
- async (error) => message.error(error)
- );
+ // this.viewModel.valid().fold(
+ // async (model) => {
+ // await this.messageHttp(this.behaviorTreeBuilderHttpRepository.saveNewBt(model), {
+ // successMessage: "Новое дерево создано",
+ // });
+ // this.mapOk("btTreeModels", this.behaviorTreeBuilderHttpRepository.getAllBtInstances());
+ // },
+ // async (error) => message.error(error)
+ // );
};
setSelected = (label: string, selected: boolean, sid: string) => {
- this.selectedSid = sid;
+ // this.selectedSid = sid;
+ // this.selected = label;
+
+ // if (!Object.keys(SystemPrimitive).includes(label) && this.skillTemplates.skillHasForm(label)) {
+ this.editDrawer(DrawerState.editThreadBehaviorTree, true);
this.selected = label;
- if (
- this.shiftIsPressed &&
- !Object.keys(SystemPrimitive).includes(label) &&
- this.skillTemplates.skillHasForm(label)
- ) {
- this.editDrawer(DrawerState.editThreadBehaviorTree, selected);
- this.selected = label;
- }
- if (this.deleteIsPressed) {
- this.nodeBehaviorTree = this.nodeBehaviorTree.filter((el) => !el.id.isEqual(sid));
- this.filledOutTemplates.skills = this.filledOutTemplates.deleteSid(sid);
- this.nodeUpdateObserver?.emit({ type: UpdateEvent.DELETE, id: sid });
- }
+ // }
+ };
+ deleteBtAction = (sid: string) => {
+
+ this.nodeBehaviorTree = this.nodeBehaviorTree.filter((el) => !el.id.isEqual(sid));
+ this.filledOutTemplates.skills = this.filledOutTemplates.deleteSid(sid);
+ this.nodeUpdateObserver?.emit({ type: UpdateEvent.DELETE, id: sid });
};
formUpdateDependency = (dependency: Object, formType: string) => {
this.filledOutTemplates?.skillBySid(this.selectedSid ?? "").fold(
@@ -304,14 +287,36 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState
{this.skillTemplates?.getSkillParams(label).map((el, index) => (
-
IN
-
+
{el.type}
- {behaviorTreeBuilderStore.isFilledInput(el.type, sid) ? "" : *}
+
))}
- {this.skillTemplates?.getSkilsOut(label).map((el, index) => (
+
+ {/* {this.skillTemplates?.getSkilsOut(label).map((el, index) => (
- ))}
+ ))} */}
);
}
@@ -342,10 +347,6 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState {};
+ modalShow = () => {
+ this.isModalOpen = true;
+ };
+
+ modalCancel = () => {
+ this.isModalOpen = false;
+ };
+ deleteBt = (id: string) => this.behaviorTreeBuilderHttpRepository.deleteBt(id);
+ 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/editor/background.css b/ui/src/features/behavior_tree_builder/presentation/ui/editor/background.css
index 374597d..5722416 100644
--- a/ui/src/features/behavior_tree_builder/presentation/ui/editor/background.css
+++ b/ui/src/features/behavior_tree_builder/presentation/ui/editor/background.css
@@ -10,9 +10,4 @@
.background {
background: white;
- /* background: url(https://sport.mail.ru/img/_main/subnav.png);
- opacity: 1;
- background-image:linear-gradient(black 3.2px, transparent 3.2px), linear-gradient(90deg, black 3.2px, transparent 3.2px), linear-gradient(black 1.6px, transparent 1.6px), linear-gradient(90deg, black 1.6px, #101010ed 1.6px);
- background-size: 80px 80px, 80px 80px, 16px 16px, 16px 16px;
- background-position: -3.2px -3.2px, -3.2px -3.2px, -1.6px -1.6px, -1.6px -1.6px; */
}
diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/editor/custom_connection.tsx b/ui/src/features/behavior_tree_builder/presentation/ui/editor/custom_connection.tsx
index 7c5b642..f4770f2 100644
--- a/ui/src/features/behavior_tree_builder/presentation/ui/editor/custom_connection.tsx
+++ b/ui/src/features/behavior_tree_builder/presentation/ui/editor/custom_connection.tsx
@@ -15,7 +15,7 @@ const Svg = styled.svg`
const Path = styled.path<{ styles?: (props: any) => any }>`
fill: none;
strokeWidth: 3px;
- stroke: black;
+ stroke: white;
pointer-events: auto;
${(props) => props.styles && props.styles(props)}
`;
diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/editor/custom_socket.tsx b/ui/src/features/behavior_tree_builder/presentation/ui/editor/custom_socket.tsx
index 4f6e8ce..22fe480 100644
--- a/ui/src/features/behavior_tree_builder/presentation/ui/editor/custom_socket.tsx
+++ b/ui/src/features/behavior_tree_builder/presentation/ui/editor/custom_socket.tsx
@@ -5,11 +5,11 @@ import styled from "styled-components";
const Styles = styled.div`
display: inline-block;
cursor: pointer;
- border: 1px solid rgba(50, 50, 50, 1);
+ border: 1px solid rgb(255 255 255);
width: 10px;
height: 10px;
vertical-align: middle;
- background: rgba(50, 50, 50, 1);
+ background: white;
z-index: 2;
box-sizing: border-box;
&:hover {
diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/editor/editor.tsx b/ui/src/features/behavior_tree_builder/presentation/ui/editor/editor.tsx
index e25f459..72e0d2a 100644
--- a/ui/src/features/behavior_tree_builder/presentation/ui/editor/editor.tsx
+++ b/ui/src/features/behavior_tree_builder/presentation/ui/editor/editor.tsx
@@ -14,7 +14,6 @@ import {
UpdateEvent,
} from "../../../model/editor_view";
import { v4 } from "uuid";
-import constructWithOptions from "styled-components/dist/constructors/constructWithOptions";
export type Schemes = GetSchemes>;
export type AreaExtra = ReactArea2D;
@@ -126,7 +125,7 @@ export async function createEditor(container: HTMLElement) {
target: el.id,
});
}
-
+
nodeUpdateObserver.on(async (event) => {
if (event.type.isEqual(UpdateEvent.UPDATE)) {
areaContainer.update("node", event.id);
diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/editor/nodes/controls_node.tsx b/ui/src/features/behavior_tree_builder/presentation/ui/editor/nodes/controls_node.tsx
index 1a89dca..d6a054c 100644
--- a/ui/src/features/behavior_tree_builder/presentation/ui/editor/nodes/controls_node.tsx
+++ b/ui/src/features/behavior_tree_builder/presentation/ui/editor/nodes/controls_node.tsx
@@ -3,6 +3,8 @@ import { ClassicScheme, RenderEmit, Presets } from "rete-react-plugin";
import styled, { css } from "styled-components";
import { $nodewidth, $socketmargin, $socketsize } from "./vars";
import { behaviorTreeBuilderStore } from "../../../behavior_tree_builder_screen";
+import { themeStore } from "../../../../../..";
+import { Icon } from "../../../../../../core/ui/icons/icons";
const { RefSocket, RefControl } = Presets.classic;
type NodeExtraData = { width?: number; height?: number };
@@ -15,16 +17,12 @@ export const NodeStyles = styled.div (Number.isFinite(props.width) ? `${props.width}px` : `${$nodewidth}px`)};
height: ${(props) => (Number.isFinite(props.height) ? `${props.height}px` : "auto")};
-
+ color: white;
user-select: none;
&:hover {
background: #333;
}
- ${(props) =>
- props.selected &&
- css`
- border-color: red;
- `}
+
.title {
color: black;
font-family: sans-serif;
@@ -102,17 +100,20 @@ export function SequenceNode(props: Props)
sortByIndex(inputs);
sortByIndex(outputs);
sortByIndex(controls);
- behaviorTreeBuilderStore.setSelected(label, selected, id);
+ const refSelect = React.useRef(null);
+ const refDelete = React.useRef(null);
+ React.useEffect(() => {
+ refSelect.current?.addEventListener("mouseup", () => behaviorTreeBuilderStore.setSelected(label, selected, id));
+ refDelete.current?.addEventListener("mouseup", () => behaviorTreeBuilderStore.deleteBtAction(id));
+ }, []);
return (
- <>
+
@@ -147,14 +148,25 @@ export function SequenceNode
(props: Props)
)
)}
- {}}
- className="title"
- data-testid="title"
- >
-
{label}
-
{behaviorTreeBuilderStore.getBodyNode(label,id)}
+
{}} data-testid="title">
+
+
{label}
+
+
+
+
+
+
+
+ behaviorTreeBuilderStore.deleteBtAction(id)}
+ />
+
+
+
+
{behaviorTreeBuilderStore.getBodyNode(label, id)}
{outputs.map(
([key, output]) =>
@@ -179,6 +191,6 @@ export function SequenceNode
(props: Props)
{outputs.isEmpty() ? : null}
- >
+
);
}
diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topic_dependency_view_model.ts b/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topic_dependency_view_model.ts
index 9afc488..f33753b 100644
--- a/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topic_dependency_view_model.ts
+++ b/ui/src/features/behavior_tree_builder/presentation/ui/forms/topics_form/topic_dependency_view_model.ts
@@ -7,7 +7,7 @@ export class TopicDependencyViewModel extends ValidationModel {
@IsNotEmpty()
@IsString()
type: string;
- mode: StoreTopicType;
+ mode?: StoreTopicType;
constructor(type: string, mode: StoreTopicType) {
super();
makeAutoObservable(this);
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 08fb325..e9d5c6b 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
@@ -15,13 +15,12 @@ export const TopicsForm = observer((props: IPropsForm {
store.init();
store.loadClassInstance(TopicDependencyViewModel, props.dependency as TopicDependencyViewModel);
- console.log(store.viewModel);
}, [props]);
return (
- {match(store.viewModel.mode)
+ {match(store.viewModel?.mode ?? "")
.with(StoreTopicType.btExecute, () => (
<>
diff --git a/ui/src/features/behavior_tree_builder/presentation/ui/skill_tree/skill_tree.tsx b/ui/src/features/behavior_tree_builder/presentation/ui/skill_tree/skill_tree.tsx
index 6d5fdfd..3018063 100644
--- a/ui/src/features/behavior_tree_builder/presentation/ui/skill_tree/skill_tree.tsx
+++ b/ui/src/features/behavior_tree_builder/presentation/ui/skill_tree/skill_tree.tsx
@@ -4,10 +4,12 @@ import { IFlatMetadata } from "react-accessible-treeview/dist/TreeView/utils";
import { CallBackEventTarget } from "../../../../../core/extensions/extensions";
import "./styles.css";
import { CoreText, CoreTextType } from "../../../../../core/ui/text/text";
+import { themeStore } from "../../../../..";
export interface ISkillView {
name: string;
children?: ISkillView[];
+ isSystem?: boolean;
id?: string;
interface?: string;
out?: string;
@@ -54,26 +56,8 @@ export const RefListener = (props: IRefListerProps) => {
style={{ color: "black", alignItems: "center", height: "max-content", display: "flex" }}
draggable={props.isBranch ? undefined : "true"}
>
- {props.isBranch ? (
-
- ) : (
- ""
- )}
-
+ {props.isBranch ? undefined : ""}
+
);
diff --git a/ui/src/features/skills/skills_screen.tsx b/ui/src/features/skills/skills_screen.tsx
index 33362d8..f9fbd9e 100644
--- a/ui/src/features/skills/skills_screen.tsx
+++ b/ui/src/features/skills/skills_screen.tsx
@@ -152,7 +152,7 @@ export const SkillsScreen = observer(() => {
onClick={() => store.addNewParam(index)}
/>
{el.param.map((param) => (
- store.showModal()}>
+
store.modalShow()}>
{param.type}
{JSON.stringify(param.dependency)}
diff --git a/ui/src/features/skills/skills_store.ts b/ui/src/features/skills/skills_store.ts
index 8b7f64c..2035c2b 100644
--- a/ui/src/features/skills/skills_store.ts
+++ b/ui/src/features/skills/skills_store.ts
@@ -27,7 +27,7 @@ export class SkillsStore extends UiDrawerFormState
{
init = async (navigate?: NavigateFunction | undefined) => {
this.mapOk("skills", this.skillsHttpRepository.getAllSkills());
};
- showModal = () => {
+ modalShow = () => {
this.isModalOpen = true;
};
@@ -40,7 +40,7 @@ export class SkillsStore extends UiDrawerFormState {
};
addNewParam = (index: number) => {
this.activeIndex = index;
- this.showModal();
+ this.modalShow();
};
onChangeBtDependency = (dependency: Object) =>
this.viewModel.BTAction.at(this.activeIndex ?? 0)
diff --git a/ui/src/index.tsx b/ui/src/index.tsx
index db91325..0a5d52b 100644
--- a/ui/src/index.tsx
+++ b/ui/src/index.tsx
@@ -6,6 +6,7 @@ import { SocketListener } from "./features/socket_listener/socket_listener";
import { RouterProvider } from "react-router-dom";
import { router } from "./core/routers/routers";
import { configure } from "mobx";
+import { ThemeStore } from "./core/store/theme_store";
configure({
enforceActions: "never",
@@ -14,7 +15,7 @@ configure({
extensions();
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
-
+export const themeStore = new ThemeStore();
root.render(
<>
@@ -22,4 +23,3 @@ root.render(
>
);
-
\ No newline at end of file