alexander test
This commit is contained in:
parent
3b8d9e4298
commit
401080d78e
41 changed files with 811 additions and 363 deletions
|
@ -18,6 +18,12 @@ export const SkillsSchema = new Schema({
|
|||
param: {
|
||||
type: Schema.Types.Mixed,
|
||||
},
|
||||
bgColor: {
|
||||
type:Schema.Types.String,
|
||||
},
|
||||
borderColor:{
|
||||
type:Schema.Types.String
|
||||
}
|
||||
}).plugin(require("mongoose-autopopulate"));
|
||||
|
||||
export const skillsSchema = "skills";
|
||||
|
|
|
@ -143,14 +143,14 @@
|
|||
}
|
||||
|
||||
.dotted {
|
||||
background-image: -webkit-repeating-radial-gradient(
|
||||
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%),
|
||||
|
@ -179,5 +179,9 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #d6dee1;
|
||||
border-radius: 20px;
|
||||
}
|
||||
</style>
|
||||
</html>
|
||||
|
|
|
@ -104,4 +104,9 @@ export const ArrayExtensions = () => {
|
|||
return this;
|
||||
};
|
||||
}
|
||||
if ([].updateAll === undefined) {
|
||||
Array.prototype.updateAll = function (element) {
|
||||
return this.map((el) => Object.assign(el, element));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -28,6 +28,7 @@ declare global {
|
|||
indexOfR(element: T): Result<void, Array<T>>;
|
||||
replacePropIndex(property: Partial<T>, index: number): T[];
|
||||
someR(predicate: (value: T) => boolean): Result<void, Array<T>>;
|
||||
updateAll(value: Partial<T>): Array<T>;
|
||||
}
|
||||
interface Date {
|
||||
formatDate(): string;
|
||||
|
|
18
ui/src/core/helper/use_store.tsx
Normal file
18
ui/src/core/helper/use_store.tsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { ClassConstructor } from "class-transformer";
|
||||
import React from "react";
|
||||
|
||||
interface LifeCycleStore {
|
||||
init?: () => void;
|
||||
dispose?: () => void;
|
||||
}
|
||||
|
||||
export const useStore = <S extends LifeCycleStore>(storeConstructor: ClassConstructor<S>) => {
|
||||
const [store] = React.useState(new storeConstructor());
|
||||
React.useEffect(() => {
|
||||
store?.init?.();
|
||||
return () => {
|
||||
store?.dispose?.();
|
||||
};
|
||||
}, []);
|
||||
return store;
|
||||
};
|
|
@ -1,12 +1,22 @@
|
|||
import { IsArray, IsEnum, IsNotEmpty, IsOptional, IsString, ValidateNested } from "class-validator";
|
||||
import {
|
||||
IsArray,
|
||||
IsEnum,
|
||||
IsNotEmpty,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
isMongoId,
|
||||
} from "class-validator";
|
||||
import { Type } from "class-transformer";
|
||||
import { ISkillView } from "../../features/behavior_tree_builder/presentation/ui/skill_tree/skill_tree";
|
||||
import { v4 } from "uuid";
|
||||
import { Result } from "../helper/result";
|
||||
import { ValidationModel } from "./validation_model";
|
||||
import { TopicViewModel } from "../../features/topics/topic_view_model";
|
||||
import { ITopicModel, TopicViewModel } from "../../features/topics/topic_view_model";
|
||||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import clone from "just-clone";
|
||||
import { BehaviorTreeBuilderStore } from "../../features/behavior_tree_builder/presentation/behavior_tree_builder_store";
|
||||
|
||||
export interface IDependency {
|
||||
skills: ISkillDependency[];
|
||||
|
@ -34,19 +44,27 @@ export interface IWeightsDependency {
|
|||
export interface IDeviceDependency {
|
||||
sid: string;
|
||||
}
|
||||
|
||||
export interface IDependency {}
|
||||
export interface IParam {
|
||||
isFilled: boolean;
|
||||
type: string;
|
||||
dependency?: Object;
|
||||
dependency?: DependencyViewModel;
|
||||
}
|
||||
export class DependencyViewModel {
|
||||
static empty = () => new DependencyViewModel();
|
||||
toView = (store: BehaviorTreeBuilderStore | undefined): React.ReactNode => "string";
|
||||
}
|
||||
export class ParamViewModel implements IParam {
|
||||
type: string;
|
||||
dependency: Object;
|
||||
constructor(type: string, dependency: Object) {
|
||||
|
||||
@Type(() => DependencyViewModel)
|
||||
dependency: DependencyViewModel;
|
||||
isFilled: boolean = false;
|
||||
constructor(type: string, dependency: DependencyViewModel) {
|
||||
this.type = type;
|
||||
this.dependency = dependency;
|
||||
}
|
||||
static empty = () => new ParamViewModel("", {});
|
||||
static empty = () => new ParamViewModel("", DependencyViewModel.empty());
|
||||
}
|
||||
export interface IBTAction {
|
||||
name: string;
|
||||
|
@ -69,6 +87,7 @@ export class BtActionViewModel extends ValidationModel implements IBTAction {
|
|||
@IsNotEmpty()
|
||||
@IsString()
|
||||
type: string;
|
||||
@Type(() => ParamViewModel)
|
||||
param: IParam[];
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
|
@ -144,6 +163,11 @@ export class Module implements IModule {
|
|||
name: string;
|
||||
@IsString()
|
||||
description: string;
|
||||
constructor(name: string, description: string) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
static empty = () => new Module("", "");
|
||||
}
|
||||
export class BTAction implements IBTAction {
|
||||
@IsString()
|
||||
|
@ -186,6 +210,9 @@ export class Setting implements ISetting {
|
|||
}
|
||||
|
||||
export class SkillModel extends ValidationModel implements ISkill {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
_id?: string;
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
|
@ -202,12 +229,14 @@ export class SkillModel extends ValidationModel implements ISkill {
|
|||
@ValidateNested()
|
||||
@Type(() => Module)
|
||||
Module: IModule;
|
||||
@Type(() => BtActionViewModel)
|
||||
BTAction: BtActionViewModel[];
|
||||
topicsOut: TopicViewModel[] = [];
|
||||
static empty() {
|
||||
const skillModel = new SkillModel();
|
||||
skillModel.BTAction = [];
|
||||
skillModel.SkillPackage = SkillPackage.empty();
|
||||
skillModel.Module = Module.empty();
|
||||
return skillModel;
|
||||
}
|
||||
public static isEmpty(skill: SkillModel): Result<void, SkillModel> {
|
||||
|
@ -223,6 +252,7 @@ export class SkillModel extends ValidationModel implements ISkill {
|
|||
result.sid = sid;
|
||||
return result;
|
||||
};
|
||||
emptyParam = () => this.BTAction.at(0)?.param.at(0)?.dependency === undefined;
|
||||
}
|
||||
|
||||
export class SkillDependency implements IDependency {
|
||||
|
@ -239,6 +269,13 @@ export class SkillDependency implements IDependency {
|
|||
}
|
||||
|
||||
export class Skills {
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@Type(() => TopicViewModel)
|
||||
topicsStack: ITopicModel[] = [];
|
||||
@IsArray()
|
||||
@Type(() => SkillModel)
|
||||
skills: SkillModel[];
|
||||
|
@ -247,6 +284,16 @@ export class Skills {
|
|||
skills.skills = skilsModel;
|
||||
return skills;
|
||||
};
|
||||
deleteTopic = (sid: string) => (this.topicsStack = this.topicsStack.filter((el) => !el.sid?.isEqual(sid)));
|
||||
|
||||
getSkillAtSid = (sid: string): Result<void, SkillModel> => {
|
||||
const result = this.skills.filter((skill) => skill.sid?.isEqual(sid)).at(0);
|
||||
if (result === undefined) {
|
||||
return Result.error(undefined);
|
||||
}
|
||||
return Result.ok(result);
|
||||
};
|
||||
|
||||
validation = (): Result<string[], void> => {
|
||||
const errors: string[] = [];
|
||||
this.skills.forEach((skill) => {
|
||||
|
@ -330,8 +377,9 @@ export class Skills {
|
|||
getSkillDo = (name: string) =>
|
||||
this.skills.reduce((acc, el) => {
|
||||
if (el.BTAction.find((el) => el.name.isEqual(name))) {
|
||||
|
||||
acc = el.Module.name;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, "error");
|
||||
|
||||
|
@ -357,14 +405,14 @@ export class Skills {
|
|||
.flat(1)
|
||||
.filter((el) => el !== "");
|
||||
|
||||
getDependencyBySkillLabelAndType = <T>(skillType: string, sid: string) =>
|
||||
getDependencyBySkillLabelAndType = (skillType: string, sid: string): DependencyViewModel =>
|
||||
this.skills
|
||||
.reduce<Object[]>((acc, skill) => {
|
||||
.reduce<DependencyViewModel[]>((acc, skill) => {
|
||||
if (skill.sid?.isEqual(sid)) {
|
||||
skill.BTAction.map((action) => {
|
||||
action.param.map((param) => {
|
||||
if (param.type.isEqualR(skillType)) {
|
||||
acc.push(param?.dependency ?? {});
|
||||
acc.push(param?.dependency ?? DependencyViewModel.empty());
|
||||
}
|
||||
return param;
|
||||
});
|
||||
|
@ -374,7 +422,7 @@ export class Skills {
|
|||
|
||||
return acc;
|
||||
}, [])
|
||||
.at(0) as T;
|
||||
.at(0) ?? DependencyViewModel.empty();
|
||||
static isEmpty(model: Skills): Result<void, void> {
|
||||
if (model.skills.isEmpty()) {
|
||||
return Result.error(undefined);
|
||||
|
@ -392,13 +440,10 @@ export class Skills {
|
|||
if (skill.sid?.isEqual(sid)) {
|
||||
skill.BTAction.forEach((action) => {
|
||||
action.param.forEach((param) => {
|
||||
if (param.type.isEqual(skillType)) {
|
||||
acc = Object.keys(param?.dependency ?? {}).isNotEmpty();
|
||||
}
|
||||
acc = param.isFilled;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, false);
|
||||
|
||||
|
@ -406,7 +451,6 @@ export class Skills {
|
|||
this.skills.reduce((acc, skill) => {
|
||||
skill.BTAction.forEach((action) =>
|
||||
action.param.forEach((param) => {
|
||||
// acc.incrementValue(param.sid ?? "empty");
|
||||
return param;
|
||||
})
|
||||
);
|
||||
|
@ -434,4 +478,11 @@ export class Skills {
|
|||
}
|
||||
return acc;
|
||||
}, 0);
|
||||
skillIsDependencyFilled = (label: string): Result<boolean, boolean> =>
|
||||
this.getSkill(label).fold(
|
||||
(skill) => {
|
||||
return Result.ok(skill.BTAction.find((el) => el.name.isEqual(label))?.param.isEmpty());
|
||||
},
|
||||
() => Result.error(false)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { themeStore } from "../../..";
|
|||
import { CoreText, CoreTextType } from "../text/text";
|
||||
export enum ButtonV2Type {
|
||||
default = "default",
|
||||
empty = "empty",
|
||||
}
|
||||
export const ButtonV2 = ({
|
||||
text,
|
||||
|
@ -10,7 +11,7 @@ export const ButtonV2 = ({
|
|||
onClick,
|
||||
style,
|
||||
icon,
|
||||
isFilled,
|
||||
|
||||
type,
|
||||
}: {
|
||||
text?: string;
|
||||
|
@ -18,27 +19,36 @@ export const ButtonV2 = ({
|
|||
onClick: () => void;
|
||||
style?: React.CSSProperties;
|
||||
icon?: React.ReactNode;
|
||||
isFilled?: boolean;
|
||||
type?: ButtonV2Type;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
backgroundColor: themeStore.theme.greenWhite,
|
||||
color: textColor ?? themeStore.theme.black,
|
||||
width: "max-content",
|
||||
height: "max-content",
|
||||
padding: match(type)
|
||||
.with(ButtonV2Type.default, () => 15)
|
||||
.otherwise(() => 5),
|
||||
borderRadius: match(type)
|
||||
.with(ButtonV2Type.default, () => 5)
|
||||
.otherwise(() => 100),
|
||||
display: "flex",
|
||||
paddingRight: 10,
|
||||
paddingLeft: 10,
|
||||
}}
|
||||
style={Object.assign(
|
||||
{
|
||||
cursor: "pointer",
|
||||
backgroundColor: match(type)
|
||||
.with(ButtonV2Type.empty, () => undefined)
|
||||
.with(ButtonV2Type.default, () => themeStore.theme.greenWhite)
|
||||
.otherwise(() => themeStore.theme.greenWhite),
|
||||
color: textColor ?? themeStore.theme.black,
|
||||
width: "max-content",
|
||||
height: "max-content",
|
||||
padding: match(type)
|
||||
.with(ButtonV2Type.default, () => 15)
|
||||
.otherwise(() => 5),
|
||||
border: match(type)
|
||||
.with(ButtonV2Type.empty, () => `1px solid ${themeStore.theme.greenWhite}`)
|
||||
.with(ButtonV2Type.default, () => undefined)
|
||||
.otherwise(() => undefined),
|
||||
borderRadius: match(type)
|
||||
.with(ButtonV2Type.default, () => 5)
|
||||
.otherwise(() => 100),
|
||||
display: "flex",
|
||||
paddingRight: 10,
|
||||
paddingLeft: 10,
|
||||
},
|
||||
style
|
||||
)}
|
||||
onClick={() => onClick()}
|
||||
>
|
||||
{icon}
|
||||
|
|
56
ui/src/core/ui/drawer/drawer.tsx
Normal file
56
ui/src/core/ui/drawer/drawer.tsx
Normal file
|
@ -0,0 +1,56 @@
|
|||
import React from "react";
|
||||
import { themeStore } from "../../..";
|
||||
import { CoreText, CoreTextType } from "../text/text";
|
||||
|
||||
export const DrawerV2: React.FC<{
|
||||
isOpen?: boolean;
|
||||
title?: string;
|
||||
onClose: () => void;
|
||||
children: React.ReactNode;
|
||||
}> = ({ isOpen, onClose, children, title }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
right: isOpen ? 0 : -300,
|
||||
width: 300,
|
||||
height: "100%",
|
||||
backgroundColor: themeStore.theme.darkSurface,
|
||||
boxShadow: "-2px 0 5px rgba(0, 0, 0, 0.5)",
|
||||
transition: "right 0.3s ease",
|
||||
zIndex: 1000,
|
||||
|
||||
}}
|
||||
>
|
||||
<div style={{ height: "100%", width: "100%" }}>
|
||||
<div style={{ padding: 20 }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<CoreText type={CoreTextType.header} text={title} color={themeStore.theme.darkOnSurfaceVariant} />
|
||||
<button
|
||||
style={{
|
||||
background: "none",
|
||||
border: "none",
|
||||
fontSize: 24,
|
||||
cursor: "pointer",
|
||||
color: themeStore.theme.darkOnSurfaceVariant,
|
||||
}}
|
||||
onClick={onClose}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div style={{ width: "100%", height: 1, backgroundColor: themeStore.theme.outlineVariant }}></div>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -4,7 +4,6 @@ import { Parts } from "../../../../../../features/details/details_http_repositor
|
|||
export class SelectDetailViewModel {
|
||||
details: Parts[];
|
||||
constructor(parts: Parts[]) {
|
||||
console.log(parts)
|
||||
this.details = parts;
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
|
|
@ -8,11 +8,12 @@ export interface IIconsProps extends IStyle {
|
|||
height?: number;
|
||||
width?: number;
|
||||
color?: string;
|
||||
iconStyle?: React.CSSProperties;
|
||||
isNeedStopPropagation?: boolean;
|
||||
}
|
||||
|
||||
export function Icon(props: IIconsProps) {
|
||||
return getIconSvg(props.type, props.height, props.width, props.color).fold(
|
||||
return getIconSvg(props.type, props.height, props.width, props.color, props.iconStyle).fold(
|
||||
(node) => {
|
||||
return (
|
||||
<div
|
||||
|
@ -49,11 +50,21 @@ const getIconSvg = (
|
|||
type: string,
|
||||
height: number | undefined,
|
||||
width: number | undefined,
|
||||
color: string | undefined
|
||||
color: string | undefined,
|
||||
iconStyle: React.CSSProperties | undefined
|
||||
): Result<undefined, React.JSX.Element> => {
|
||||
switch (type) {
|
||||
case "":
|
||||
return Result.ok();
|
||||
case "Floppy":
|
||||
return Result.ok(
|
||||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3.70455 1.36364C3.28261 1.36364 2.87796 1.53125 2.5796 1.8296C2.28125 2.12796 2.11364 2.53261 2.11364 2.95455V17.0455C2.11365 17.428 2.2515 17.7977 2.50195 18.0869C2.75239 18.3761 3.09865 18.5654 3.47727 18.62V12.0455C3.47727 11.503 3.69278 10.9827 4.07637 10.5991C4.45997 10.2155 4.98024 10 5.52273 10H15.9773C16.5198 10 17.04 10.2155 17.4236 10.5991C17.8072 10.9827 18.0227 11.503 18.0227 12.0455V18.62C18.4014 18.5654 18.7476 18.3761 18.9981 18.0869C19.2485 17.7977 19.3864 17.428 19.3864 17.0455V5.26C19.3864 4.83727 19.2191 4.43273 18.92 4.13455L16.6155 1.83C16.4677 1.68214 16.2922 1.56484 16.0991 1.48482C15.906 1.4048 15.699 1.36362 15.49 1.36364H15.2955V5.22727C15.2955 5.49589 15.2425 5.76187 15.1398 6.01003C15.037 6.2582 14.8863 6.48369 14.6964 6.67363C14.5064 6.86357 14.2809 7.01423 14.0328 7.11703C13.7846 7.21982 13.5186 7.27273 13.25 7.27273H7.34091C6.79842 7.27273 6.27815 7.05722 5.89455 6.67363C5.51096 6.29003 5.29545 5.76976 5.29545 5.22727V1.36364H3.70455ZM6.65909 1.36364V5.22727C6.65909 5.60364 6.96455 5.90909 7.34091 5.90909H13.25C13.4308 5.90909 13.6043 5.83726 13.7321 5.70939C13.86 5.58153 13.9318 5.4081 13.9318 5.22727V1.36364H6.65909ZM16.6591 18.6364V12.0455C16.6591 11.8646 16.5873 11.6912 16.4594 11.5633C16.3315 11.4355 16.1581 11.3636 15.9773 11.3636H5.52273C5.3419 11.3636 5.16847 11.4355 5.04061 11.5633C4.91274 11.6912 4.84091 11.8646 4.84091 12.0455V18.6364H16.6591ZM0.75 2.95455C0.75 2.17095 1.06128 1.41945 1.61537 0.865366C2.16945 0.311281 2.92095 0 3.70455 0H15.4909C16.2745 4.67926e-05 17.026 0.311359 17.58 0.865454L19.8845 3.17C20.4391 3.72455 20.75 4.47636 20.75 5.26V17.0455C20.75 17.8291 20.4387 18.5805 19.8846 19.1346C19.3305 19.6887 18.5791 20 17.7955 20H3.70455C2.92095 20 2.16945 19.6887 1.61537 19.1346C1.06128 18.5805 0.75 17.8291 0.75 17.0455V2.95455Z"
|
||||
fill="black"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "LeftIcon":
|
||||
return Result.ok(
|
||||
<svg width="10" height="12" viewBox="0 0 10 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
|
@ -80,8 +91,9 @@ const getIconSvg = (
|
|||
case "Bucket":
|
||||
return Result.ok(
|
||||
<svg
|
||||
style={iconStyle}
|
||||
width={width ?? "12"}
|
||||
height={height ??"14"}
|
||||
height={height ?? "14"}
|
||||
viewBox="0 0 12 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
|
@ -86,128 +86,145 @@ class MainPageStore {
|
|||
};
|
||||
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 (
|
||||
export const MainPageV2: React.FC<{
|
||||
children: React.ReactNode;
|
||||
bgColor: string;
|
||||
style?: React.CSSProperties | void;
|
||||
rightChild?: React.ReactNode;
|
||||
}> = observer(({ children, bgColor, style, rightChild }) => {
|
||||
const [store] = React.useState(() => new MainPageStore());
|
||||
useEffect(() => {
|
||||
store.init(4);
|
||||
}, []);
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
backgroundColor: bgColor,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
backgroundColor: bgColor,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
alignSelf: "center",
|
||||
width: 645,
|
||||
height: 60,
|
||||
backgroundColor: themeStore.theme.navBlue,
|
||||
paddingBottom: 60,
|
||||
borderRadius: 20,
|
||||
zIndex: 20,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
<RefDiv
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
width: 645,
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
height: 60,
|
||||
backgroundColor: themeStore.theme.navBlue,
|
||||
paddingBottom: 60,
|
||||
borderRadius: 20,
|
||||
zIndex: 20,
|
||||
justifyContent: "space-evenly",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<RefDiv
|
||||
style={{
|
||||
display: "flex",
|
||||
width: "100%",
|
||||
height: 60,
|
||||
justifyContent: "space-evenly",
|
||||
alignItems: "center",
|
||||
}}
|
||||
children={
|
||||
<>
|
||||
{store.icons.map((el, i) => (
|
||||
<div key={i} style={{ zIndex: 25 }}>
|
||||
{el.isActive === true ? (
|
||||
<>
|
||||
<RefDiv
|
||||
style={{ position: "relative", top: 30 }}
|
||||
property="offsetLeft"
|
||||
onChange={(text) => store.updateLeftStyle(Number(text), i)}
|
||||
>
|
||||
<Icon
|
||||
type={el.icon}
|
||||
style={{
|
||||
margin: 10,
|
||||
zIndex: 25,
|
||||
children={
|
||||
<>
|
||||
{store.icons.map((el, i) => (
|
||||
<div key={i} style={{ zIndex: 25 }}>
|
||||
{el.isActive === true ? (
|
||||
<>
|
||||
<RefDiv
|
||||
style={{ position: "relative", top: 30 }}
|
||||
property="offsetLeft"
|
||||
onChange={(text) => store.updateLeftStyle(Number(text), i)}
|
||||
>
|
||||
<Icon
|
||||
type={el.icon}
|
||||
style={{
|
||||
margin: 10,
|
||||
zIndex: 25,
|
||||
|
||||
position: "relative",
|
||||
}}
|
||||
onClick={() => {
|
||||
store.icons
|
||||
.map((element) => {
|
||||
element.isActive = false;
|
||||
return element;
|
||||
})
|
||||
.map((element, index) =>
|
||||
i.isEqualR(index).fold(
|
||||
() => {
|
||||
element.isActive = true;
|
||||
},
|
||||
() => element
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</RefDiv>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RefDiv
|
||||
style={{ position: "relative", top: el.top, zIndex: 23 }}
|
||||
property="offsetLeft"
|
||||
onChange={(text) => store.updateLeftStyle(Number(text), i)}
|
||||
>
|
||||
<Icon type={el.icon} style={{ margin: 10 }} onClick={() => store.selectIndex(i)} />
|
||||
</RefDiv>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<div style={{ width: 0, height: 0 }}>
|
||||
<RefDiv
|
||||
property="offsetLeft"
|
||||
onChange={(text) => {
|
||||
store.offsetLeftCircle = Number(text);
|
||||
}}
|
||||
position: "relative",
|
||||
}}
|
||||
onClick={() => {
|
||||
store.icons
|
||||
.map((element) => {
|
||||
element.isActive = false;
|
||||
return element;
|
||||
})
|
||||
.map((element, index) =>
|
||||
i.isEqualR(index).fold(
|
||||
() => {
|
||||
element.isActive = true;
|
||||
},
|
||||
() => element
|
||||
)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</RefDiv>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<RefDiv
|
||||
style={{ position: "relative", top: el.top, zIndex: 23 }}
|
||||
property="offsetLeft"
|
||||
onChange={(text) => store.updateLeftStyle(Number(text), i)}
|
||||
>
|
||||
<Icon type={el.icon} style={{ margin: 10 }} onClick={() => store.selectIndex(i)} />
|
||||
</RefDiv>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<div style={{ width: 0, height: 0 }}>
|
||||
<RefDiv
|
||||
property="offsetLeft"
|
||||
onChange={(text) => {
|
||||
store.offsetLeftCircle = Number(text);
|
||||
}}
|
||||
style={{
|
||||
position: "relative",
|
||||
top: -30,
|
||||
left: store.leftCircle,
|
||||
backgroundColor: bgColor,
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: "50%",
|
||||
paddingTop: 10,
|
||||
zIndex: 21,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
top: -30,
|
||||
left: store.leftCircle,
|
||||
backgroundColor: bgColor,
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: "50%",
|
||||
paddingTop: 10,
|
||||
zIndex: 21,
|
||||
top: -5,
|
||||
left: 5,
|
||||
backgroundColor: themeStore.theme.greenWhite,
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 200,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
top: -5,
|
||||
left: 5,
|
||||
backgroundColor: themeStore.theme.greenWhite,
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 200,
|
||||
}}
|
||||
></div>
|
||||
</RefDiv>
|
||||
</div>
|
||||
></div>
|
||||
</RefDiv>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
top: 13,
|
||||
width: 300,
|
||||
height: 50,
|
||||
|
||||
}}
|
||||
>
|
||||
{rightChild}
|
||||
</div>
|
||||
<div style={Object.assign({ width: "100%" }, style)}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
<div style={Object.assign({ width: "100%" }, style)}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -12,16 +12,13 @@ import { DigitalTwinsScreenPath } from "../../digital_twins/digital_twins_screen
|
|||
import { TopicsScreenPath } from "../../topics/topics_screen";
|
||||
import { SkillsScreenPath } from "../../skills/skills_screen";
|
||||
import { CalculationsTemplateScreenPath } from "../../calculations_template/calculations_template_screen";
|
||||
import { useStore } from "../../../core/helper/use_store";
|
||||
|
||||
export const AllProjectScreenPath = "/";
|
||||
export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
||||
const [store] = React.useState(() => new AllProjectStore());
|
||||
const store = useStore(AllProjectStore);
|
||||
const navigate = useNavigate();
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PreviewPage
|
||||
largeText={"Проекты"}
|
||||
|
|
|
@ -22,9 +22,10 @@ export class BehaviorTreeBuilderHttpRepository extends CoreHttpRepository {
|
|||
`${this.featureApi}/by_id?id=${id}`,
|
||||
BehaviorTreeModel
|
||||
) as unknown as Promise<Result<HttpError, BehaviorTreeModel>>;
|
||||
deleteBt = (id: string) => this._jsonRequest(HttpMethod.DELETE, this.featureApi);
|
||||
deleteBt = (id: string) => this._jsonRequest(HttpMethod.DELETE, `${this.featureApi}?id=${id}`);
|
||||
editBt = async (model: BehaviorTreeModel) => {
|
||||
await this._jsonRequest(HttpMethod.POST, `${this.featureApi}/fill/tree`, model);
|
||||
model.__v = undefined
|
||||
return await this._jsonRequest(HttpMethod.PUT, this.featureApi, model);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import { message } from "antd";
|
|||
import { ValidationModel } from "../../../core/model/validation_model";
|
||||
|
||||
export class BehaviorTreeModel extends ValidationModel {
|
||||
__v?: string;
|
||||
@IsNumber()
|
||||
unixTime: number = Date.now();
|
||||
@IsString()
|
||||
|
|
|
@ -37,6 +37,7 @@ export class BehaviorTreeBuilderModel {
|
|||
this.result = "";
|
||||
this.getFirstSequence(editor).map((sortedSequence) => {
|
||||
const firstNodeId = sortedSequence.getKeyFromValueIsExists(1) as string;
|
||||
|
||||
this.findSequence(firstNodeId, editor, sortedSequence, 2);
|
||||
this.result += `<${this.getNodeLabelAtId(editor, firstNodeId, skills)}>`;
|
||||
this.toXML(sortedSequence as Map<string, number>, editor, area, firstNodeId, skills);
|
||||
|
@ -49,12 +50,16 @@ export class BehaviorTreeBuilderModel {
|
|||
}
|
||||
|
||||
public static getNodeLabelAtId(editor: NodeEditor<Schemes>, id: string, skills?: Skills) {
|
||||
if (skills?.getSkillsNames().find((el) => el.name.isEqual(editor.getNode(id).label))) {
|
||||
return `Action ID="RbsAction" do="${skills.getSkillDo(editor.getNode(id).label)}" command="${
|
||||
editor.getNode(id).label
|
||||
}" sid=${id}"`;
|
||||
try {
|
||||
if (skills?.getSkillsNames().find((el) => el.name.isEqual(editor.getNode(id).label))) {
|
||||
return `Action ID="RbsAction" do="${skills.getSkillDo(editor.getNode(id).label)}" command="${
|
||||
editor.getNode(id).label
|
||||
}" sid=${id}"`;
|
||||
}
|
||||
return editor.getNode(id).label;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
return editor.getNode(id).label;
|
||||
}
|
||||
|
||||
static toXML(
|
||||
|
|
|
@ -35,9 +35,9 @@ export class PrimitiveViewModel {
|
|||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
border: "1px solid #003E61",
|
||||
borderRadius: 33,
|
||||
background: "#BDE8AE",
|
||||
border: "1px solid 6A4C93",
|
||||
borderRadius: 5,
|
||||
background: "rgba(21, 15, 29, 1)",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -46,23 +46,132 @@ export class PrimitiveViewModel {
|
|||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
border: `1px solid white`,
|
||||
border: "1px solid 6A4C93",
|
||||
borderRadius: 5,
|
||||
background: "rgba(21, 15, 29, 1)",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.ForceFailure,
|
||||
group: SystemPrimitive.Decorator,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
border: "1px solid 6A4C93",
|
||||
borderRadius: 5,
|
||||
background: "rgba(21, 15, 29, 1)",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.Repeat,
|
||||
group: SystemPrimitive.Decorator,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
border: "1px solid 6A4C93",
|
||||
borderRadius: 5,
|
||||
background: "rgba(21, 15, 29, 1)",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.RetryUntilSuccessful,
|
||||
group: SystemPrimitive.Decorator,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
border: "1px solid 6A4C93",
|
||||
borderRadius: 5,
|
||||
background: "rgba(21, 15, 29, 1)",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.KeepRunningUntilFailure,
|
||||
group: SystemPrimitive.Decorator,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
border: "1px solid 6A4C93",
|
||||
borderRadius: 5,
|
||||
background: "rgba(21, 15, 29, 1)",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.Delay,
|
||||
group: SystemPrimitive.Decorator,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
border: "1px solid 6A4C93",
|
||||
borderRadius: 5,
|
||||
background: "rgba(21, 15, 29, 1)",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.RunOnce,
|
||||
group: SystemPrimitive.Decorator,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
border: "1px solid 6A4C93",
|
||||
borderRadius: 5,
|
||||
background: "rgba(21, 15, 29, 1)",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.ReactiveSequence,
|
||||
group: SystemPrimitive.Sequence,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
background: "rgba(28, 40, 8, 1)",
|
||||
border: "1px solid rgba(138, 201, 38, 1)",
|
||||
borderRadius: 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.Sequence,
|
||||
group: SystemPrimitive.Sequence,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
background: "rgba(28, 40, 8, 1)",
|
||||
border: "1px solid rgba(138, 201, 38, 1)",
|
||||
borderRadius: 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.SequenceWithMemory,
|
||||
group: SystemPrimitive.Sequence,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
background: "rgba(28, 40, 8, 1)",
|
||||
border: "1px solid rgba(138, 201, 38, 1)",
|
||||
borderRadius: 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.ReactiveFallback,
|
||||
group: SystemPrimitive.Fallback,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
background: "rgba(40, 8, 8, 1)",
|
||||
border: "1px solid rgba(201, 38, 38, 1)",
|
||||
borderRadius: 5,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: SystemPrimitive.Fallback,
|
||||
group: SystemPrimitive.Fallback,
|
||||
input: true,
|
||||
output: true,
|
||||
css: {
|
||||
background: "rgba(40, 8, 8, 1)",
|
||||
border: "1px solid rgba(201, 38, 38, 1)",
|
||||
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));
|
||||
|
@ -73,7 +182,9 @@ export class PrimitiveViewModel {
|
|||
.rFind<ISkillView>((el) => el.name.isEqual(primitive.group))
|
||||
.fold(
|
||||
() => {
|
||||
acc.at(acc.findIndex((element) => element.name === primitive.group))?.children?.push({ name: primitive.label });
|
||||
acc
|
||||
.at(acc.findIndex((element) => element.name === primitive.group))
|
||||
?.children?.push({ name: primitive.label });
|
||||
},
|
||||
() => {
|
||||
acc.push({ name: primitive.group, children: [{ name: primitive.label }] });
|
||||
|
|
|
@ -3,25 +3,20 @@ 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 { MainPage } from "../../../core/ui/pages/main_page";
|
||||
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, 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";
|
||||
import { DrawerV2 } from "../../../core/ui/drawer/drawer";
|
||||
|
||||
export const behaviorTreeBuilderScreenPath = "behavior/tree/screen/path";
|
||||
export interface DOMReact {
|
||||
|
@ -42,24 +37,24 @@ export const BehaviorTreeBuilderPath = (id?: string) => {
|
|||
}
|
||||
return `/behavior/tree/`;
|
||||
};
|
||||
|
||||
export const isBtScreen = () =>
|
||||
Boolean(window.location.href.match(new RegExp(BehaviorTreeBuilderPath()))?.at(0)) ?? false;
|
||||
export const BehaviorTreeBuilderScreen = observer(() => {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
// @ts-expect-error
|
||||
const [ref] = useRete<HTMLDivElement>(createEditor);
|
||||
const store = behaviorTreeBuilderStore;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (ref.current) {
|
||||
// @ts-expect-error
|
||||
const domReact: DOMReact = ref.current.getBoundingClientRect();
|
||||
store.dragZoneSetOffset(0, domReact.y, domReact.width, domReact.height);
|
||||
}
|
||||
}, [store.type]);
|
||||
React.useEffect(() => {
|
||||
store.init(navigate).then(() => {
|
||||
store.initParam(id).then(() => {
|
||||
if (ref.current) {
|
||||
// @ts-expect-error
|
||||
const domReact: DOMReact = ref.current.getBoundingClientRect();
|
||||
|
||||
store.dragZoneSetOffset(0, domReact.y, domReact.width, domReact.height);
|
||||
}
|
||||
});
|
||||
store.initParam(id).then(() => {});
|
||||
});
|
||||
return () => {
|
||||
store.dispose();
|
||||
|
@ -67,7 +62,52 @@ export const BehaviorTreeBuilderScreen = observer(() => {
|
|||
}, [id, navigate, ref, store]);
|
||||
return (
|
||||
<MainPageV2
|
||||
style={{ position: "absolute", height: "100%" }}
|
||||
rightChild={
|
||||
<>
|
||||
{match(store.type)
|
||||
.with(StoreUIType.ViewBehaviorTree, () => (
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "end",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<ButtonV2 style={{ height: 40 }} onClick={() => {}} text="Запуск" textColor={themeStore.theme.black} />
|
||||
<div style={{ width: 10 }} />
|
||||
<ButtonV2
|
||||
style={{ height: 40 }}
|
||||
onClick={() => {}}
|
||||
text="Стоп"
|
||||
type={ButtonV2Type.empty}
|
||||
textColor={themeStore.theme.greenWhite}
|
||||
/>
|
||||
<div style={{ width: 10 }} />
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: store.isNeedSaveBtn ? themeStore.theme.greenWhite : undefined,
|
||||
height: 40,
|
||||
textAlign: "center",
|
||||
alignContent: "center",
|
||||
width: 40,
|
||||
borderRadius: 100,
|
||||
}}
|
||||
>
|
||||
{store.isNeedSaveBtn ? (
|
||||
<Icon style={{ height: 21 }} onClick={() => store.onClickSaveBehaviorTree()} type="Floppy" />
|
||||
) : undefined}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
.with(StoreUIType.SelectBehaviorTree, () => <></>)
|
||||
.otherwise(() => (
|
||||
<></>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
style={{ position: "absolute", height: "100%", overflow: "hidden" }}
|
||||
bgColor={themeStore.theme.black}
|
||||
children={
|
||||
<>
|
||||
|
@ -98,9 +138,6 @@ export const BehaviorTreeBuilderScreen = observer(() => {
|
|||
</div>
|
||||
{store.skillTemplates ? <SkillTree skills={store.skillTree} dragEnd={store.dragEnd} /> : null}
|
||||
</div>
|
||||
<div style={{ width: 100, height: 40 }}>
|
||||
<CoreButton onClick={() => store.onClickSaveBehaviorTree()} text="Сохранить" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
ref={ref}
|
||||
|
@ -114,7 +151,7 @@ export const BehaviorTreeBuilderScreen = observer(() => {
|
|||
</>
|
||||
))
|
||||
.with(StoreUIType.SelectBehaviorTree, () => (
|
||||
<>
|
||||
<div style={{ height: "100%", overflowY: "auto", overflowX: "hidden" }}>
|
||||
<div style={{ height: 20 }} />
|
||||
<ButtonV2
|
||||
icon={<Icon type={"Plus"} style={{ alignSelf: "center", marginLeft: 10, marginRight: 10 }} />}
|
||||
|
@ -124,7 +161,7 @@ export const BehaviorTreeBuilderScreen = observer(() => {
|
|||
<div style={{ height: 50 }} />
|
||||
|
||||
<div style={{ display: "inline-grid", gridTemplateColumns: "1fr 1fr 1fr", width: "100%" }}>
|
||||
{store.btTreeModels?.repeat(100).map((el, index) => (
|
||||
{store.btTreeModels?.map((el, index) => (
|
||||
<CoreCard
|
||||
key={index}
|
||||
clickDeleteIcon={() => store.deleteBt(el._id)}
|
||||
|
@ -135,7 +172,7 @@ export const BehaviorTreeBuilderScreen = observer(() => {
|
|||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
))
|
||||
.otherwise(() => (
|
||||
<></>
|
||||
|
@ -187,14 +224,13 @@ export const BehaviorTreeBuilderScreen = observer(() => {
|
|||
</>
|
||||
}
|
||||
/>
|
||||
<Drawer
|
||||
<DrawerV2
|
||||
title={store.titleDrawer}
|
||||
destroyOnClose={true}
|
||||
onClose={() => store.editDrawer(DrawerState.editThreadBehaviorTree, false)}
|
||||
open={store.drawers.find((el) => el.name === DrawerState.editThreadBehaviorTree)?.status}
|
||||
isOpen={store.drawers.find((el) => el.name === DrawerState.editThreadBehaviorTree)?.status}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
|
||||
<div>
|
||||
<div style={{ height: "100%" }}>
|
||||
{store.skillTemplates?.getForms(store.selected ?? "").map((formType, index) =>
|
||||
forms(
|
||||
store.filledOutTemplates?.getDependencyBySkillLabelAndType(
|
||||
|
@ -206,13 +242,21 @@ export const BehaviorTreeBuilderScreen = observer(() => {
|
|||
)
|
||||
.rFind<IForms>((form) => form.name.isEqual(formType))
|
||||
.fold(
|
||||
(s) => <div key={index}>{s.component}</div>,
|
||||
() => <div key={index + "error"}>Error: Unknown form type {formType}</div>
|
||||
(s) => (
|
||||
<div key={index} style={{ height: "100%" }}>
|
||||
{s.component}
|
||||
</div>
|
||||
),
|
||||
() => (
|
||||
<div key={index + "error"} style={{ height: "100%" }}>
|
||||
Error: Unknown form type {formType}
|
||||
</div>
|
||||
)
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
</DrawerV2>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import React from "react";
|
||||
import { message } from "antd";
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { v4 } from "uuid";
|
||||
import clone from "just-clone";
|
||||
import { CoreError, UiDrawerFormState } from "../../../core/store/base_store";
|
||||
import {
|
||||
BehaviorTreeBuilderModel,
|
||||
|
@ -13,15 +17,11 @@ import { AreaExtra, Schemes } from "./ui/editor/editor";
|
|||
import { AreaPlugin } from "rete-area-plugin";
|
||||
import { NodeBehaviorTree } from "../model/node_behavior_tree";
|
||||
import { BehaviorTreeBuilderHttpRepository } from "../data/behavior_tree_builder_http_repository";
|
||||
import { IParam, Skills } from "../../../core/model/skill_model";
|
||||
import { DependencyViewModel, IParam, Skills } from "../../../core/model/skill_model";
|
||||
import { ISkillView } from "./ui/skill_tree/skill_tree";
|
||||
import { message } from "antd";
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import { BehaviorTreeViewModel } from "../model/behavior_tree_view_model";
|
||||
import { UiBaseError } from "../../../core/model/ui_base_error";
|
||||
import { v4 } from "uuid";
|
||||
import { BehaviorTreeBuilderPath, behaviorTreeBuilderStore } from "./behavior_tree_builder_screen";
|
||||
import clone from "just-clone";
|
||||
import { BehaviorTreeModel } from "../model/behavior_tree_model";
|
||||
import { PrimitiveViewModel, SystemPrimitive } from "../model/primitive_view_model";
|
||||
import { SceneModel } from "../../scene_manager/model/scene_model";
|
||||
|
@ -60,6 +60,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
activeProject: string = "";
|
||||
behaviorTreeBuilderHttpRepository = new BehaviorTreeBuilderHttpRepository();
|
||||
canRun = true;
|
||||
isNeedSaveBtn = true;
|
||||
selected: string = "";
|
||||
selectedSid: string = "";
|
||||
nodeBehaviorTree: NodeBehaviorTree[] = [];
|
||||
|
@ -83,7 +84,6 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
constructor() {
|
||||
super(DrawerState);
|
||||
makeAutoObservable(this);
|
||||
|
||||
this.primitiveViewModel = new PrimitiveViewModel();
|
||||
this.skillTree.children?.push({
|
||||
name: "Примитивы BT",
|
||||
|
@ -96,7 +96,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
this.editor = editor;
|
||||
this.areaPlugin = area;
|
||||
};
|
||||
|
||||
getAllTopics = () => this.filledOutTemplates.topicsStack;
|
||||
errorHandingStrategy = (_: CoreError) => {};
|
||||
|
||||
dragEnd = (e: EventTarget) => {
|
||||
|
@ -125,13 +125,19 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
name: name,
|
||||
id: sid,
|
||||
});
|
||||
this.isNeedSaveBtn = true;
|
||||
if (!name.isEqualMany(Object.keys(SystemPrimitive))) {
|
||||
this.skillTemplates?.getSkill(name).fold(
|
||||
(m) => {
|
||||
const modelSetId = clone(m).setSid(sid);
|
||||
modelSetId.BTAction = m.BTAction.filter((el) => el.name.isEqual(name));
|
||||
(skill) => {
|
||||
const skillModel = clone(skill).setSid(sid);
|
||||
skillModel.BTAction = skill.BTAction.filter((el) => el.name.isEqual(name));
|
||||
|
||||
this.filledOutTemplates?.skills.push(modelSetId);
|
||||
this.filledOutTemplates?.skills.push(skillModel);
|
||||
if (skill.emptyParam()) {
|
||||
this.filledOutTemplates.topicsStack.push(
|
||||
...skillModel.topicsOut.updateAll({ sid: skillModel.sid ?? "" })
|
||||
);
|
||||
}
|
||||
},
|
||||
() => console.log("error")
|
||||
);
|
||||
|
@ -139,7 +145,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
}
|
||||
};
|
||||
|
||||
async init(navigate: NavigateFunction): Promise<any> {
|
||||
async init(navigate: NavigateFunction): Promise<void> {
|
||||
(await this.behaviorTreeBuilderHttpRepository.getActiveProjectId())
|
||||
// eslint-disable-next-line array-callback-return
|
||||
.map((el) => {
|
||||
|
@ -175,14 +181,15 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
await this.mapOk("sceneAsset", this.behaviorTreeBuilderHttpRepository.getSceneAsset(model.sceneId));
|
||||
this.isLoading = false;
|
||||
this.reteForceUpdateObserver?.emit("");
|
||||
this.type = StoreUIType.ViewBehaviorTree;
|
||||
},
|
||||
async () => {
|
||||
this.errors.push(new UiBaseError(`не найдено дерево с id:${id}`));
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.type = StoreUIType.SelectBehaviorTree;
|
||||
await this.mapOk("scenes", this.behaviorTreeBuilderHttpRepository.getAllScenes());
|
||||
// this.type = StoreUIType.SelectBehaviorTree;
|
||||
}
|
||||
};
|
||||
dragZoneSetOffset(offsetTop: number, offsetWidth: number, width: number, height: number) {
|
||||
|
@ -193,11 +200,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
h: height,
|
||||
};
|
||||
}
|
||||
dispose(): void {
|
||||
document.removeEventListener("keyup", () => {});
|
||||
document.removeEventListener("keydown", () => {});
|
||||
}
|
||||
onClickSaveBehaviorTree = async (): Promise<void> => {
|
||||
onClickSaveBehaviorTree = async () =>
|
||||
this.filledOutTemplates.validation().fold(
|
||||
async () => {
|
||||
(
|
||||
|
@ -224,7 +227,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
},
|
||||
async () => message.error(`Дерево поведения не заполнено`)
|
||||
);
|
||||
};
|
||||
|
||||
validateBt() {}
|
||||
createNewBehaviorTree = async () => {
|
||||
this.viewModel.project = this.activeProject;
|
||||
|
@ -239,21 +242,24 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
// );
|
||||
};
|
||||
setSelected = (label: string, selected: boolean, sid: string) => {
|
||||
// this.selectedSid = sid;
|
||||
// this.selected = label;
|
||||
this.selectedSid = sid;
|
||||
this.selected = label;
|
||||
|
||||
// if (!Object.keys(SystemPrimitive).includes(label) && this.skillTemplates.skillHasForm(label)) {
|
||||
this.editDrawer(DrawerState.editThreadBehaviorTree, true);
|
||||
this.selected = label;
|
||||
// }
|
||||
};
|
||||
deleteBtAction = (sid: string) => {
|
||||
|
||||
this.nodeBehaviorTree = this.nodeBehaviorTree.filter((el) => !el.id.isEqual(sid));
|
||||
this.filledOutTemplates.skills = this.filledOutTemplates.deleteSid(sid);
|
||||
this.filledOutTemplates.deleteTopic(sid);
|
||||
this.nodeUpdateObserver?.emit({ type: UpdateEvent.DELETE, id: sid });
|
||||
|
||||
Array.from(this.areaPlugin!.nodeViews.keys()).forEach((id) => {
|
||||
this.areaPlugin?.update("node", id);
|
||||
});
|
||||
};
|
||||
formUpdateDependency = (dependency: Object, formType: string) => {
|
||||
formUpdateDependency = (dependency: DependencyViewModel, formType: string) => {
|
||||
this.filledOutTemplates?.skillBySid(this.selectedSid ?? "").fold(
|
||||
(m) => {
|
||||
const model = clone(m);
|
||||
|
@ -263,15 +269,15 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
const paramClone = clone(param);
|
||||
if (param.type.isEqual(formType)) {
|
||||
paramClone.dependency = dependency;
|
||||
paramClone.isFilled = true;
|
||||
}
|
||||
result.push(paramClone);
|
||||
});
|
||||
|
||||
action.param = result;
|
||||
return action;
|
||||
});
|
||||
|
||||
this.filledOutTemplates.updateSkill(model);
|
||||
this.editDrawer(DrawerState.editThreadBehaviorTree, false);
|
||||
},
|
||||
() => console.log("UNKNOWN SID: " + this.selectedSid)
|
||||
);
|
||||
|
@ -312,27 +318,19 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
: themeStore.theme.error50
|
||||
}`,
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* {this.skillTemplates?.getSkilsOut(label).map((el, index) => (
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "row", width: "100%", marginBottom: 5, padding: 5 }}
|
||||
key={index}
|
||||
>
|
||||
<div style={{ marginRight: 8, padding: 5 }}>OUT</div>
|
||||
<div style={{ display: "flex", width: "100%", backgroundColor: "rgba(255, 255, 255, 0.33)", padding: 5 }}>
|
||||
{el}
|
||||
>
|
||||
{behaviorTreeBuilderStore.isFilledInput(el.type, sid)
|
||||
? this.filledOutTemplates.getDependencyBySkillLabelAndType(label, sid).toView(behaviorTreeBuilderStore)
|
||||
: undefined}
|
||||
</div>
|
||||
</div>
|
||||
))} */}
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
isFilledInput = (type: string, sid: string): boolean => {
|
||||
return this.filledOutTemplates?.dependencyIsFilled(type, sid) ?? false;
|
||||
};
|
||||
isFilledInput = (type: string, sid: string): boolean =>
|
||||
this.filledOutTemplates?.dependencyIsFilled(type, sid) ?? false;
|
||||
|
||||
getInputs(name: string) {
|
||||
const result = this.primitiveViewModel.getPrimitiveAtLabel(name);
|
||||
if (result) {
|
||||
|
@ -347,19 +345,10 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
};
|
||||
}
|
||||
getStylesByLabelNode(label: string): React.CSSProperties | undefined {
|
||||
if (label.isEqual(SystemPrimitive.Fallback)) {
|
||||
return {
|
||||
border: "1px solid #003E61",
|
||||
borderRadius: 33,
|
||||
background: "#BDE8AE",
|
||||
};
|
||||
}
|
||||
if (label.isEqual(SystemPrimitive.Sequence)) {
|
||||
return {
|
||||
border: "1px solid #003E61",
|
||||
background: "rgba(189, 232, 174, 1)",
|
||||
};
|
||||
for (const el of this.primitiveViewModel.primitives) {
|
||||
if (el.label.isEqual(label)) return el.css;
|
||||
}
|
||||
|
||||
return this.filledOutTemplates.getCssAtLabel(label);
|
||||
}
|
||||
changeSceneViewModel = (text: string) => {};
|
||||
|
@ -370,7 +359,10 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
modalCancel = () => {
|
||||
this.isModalOpen = false;
|
||||
};
|
||||
deleteBt = (id: string) => this.behaviorTreeBuilderHttpRepository.deleteBt(id);
|
||||
deleteBt = async (id: string) => (
|
||||
await this.behaviorTreeBuilderHttpRepository.deleteBt(id),
|
||||
await this.mapOk("btTreeModels", this.behaviorTreeBuilderHttpRepository.getAllBtInstances())
|
||||
);
|
||||
saveNewBt = async () =>
|
||||
(await this.viewModel.valid<BehaviorTreeViewModel>()).fold(
|
||||
async (model) => {
|
||||
|
|
|
@ -5,6 +5,7 @@ import { $nodewidth, $socketmargin, $socketsize } from "./vars";
|
|||
import { behaviorTreeBuilderStore } from "../../../behavior_tree_builder_screen";
|
||||
import { themeStore } from "../../../../../..";
|
||||
import { Icon } from "../../../../../../core/ui/icons/icons";
|
||||
import { SystemPrimitive } from "../../../../model/primitive_view_model";
|
||||
const { RefSocket, RefControl } = Presets.classic;
|
||||
|
||||
type NodeExtraData = { width?: number; height?: number };
|
||||
|
@ -152,18 +153,51 @@ export function SequenceNode<Scheme extends ClassicScheme>(props: Props<Scheme>)
|
|||
<div style={{ display: "flex", width: "100%", justifyContent: "space-between" }}>
|
||||
<div style={{ paddingLeft: 5 }}>{label}</div>
|
||||
<div style={{ display: "flex" }}>
|
||||
<div ref={refSelect}>
|
||||
<Icon type="SettingGear" />
|
||||
</div>
|
||||
<div style={{ width: 2 }} />
|
||||
{Object.keys(SystemPrimitive)
|
||||
.rFind<string>((el) => el.isEqual(label))
|
||||
.fold(
|
||||
() => (
|
||||
<>
|
||||
<div ref={refDelete}>
|
||||
<Icon
|
||||
style={{ height: "100%", marginRight: 10 }}
|
||||
iconStyle={{ height: "100%" }}
|
||||
type="Bucket"
|
||||
color={themeStore.theme.onSurfaceVariant}
|
||||
onClick={() => behaviorTreeBuilderStore.deleteBtAction(id)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
() => (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: behaviorTreeBuilderStore.skillTemplates!.skillIsDependencyFilled(label).fold(
|
||||
(result) => {
|
||||
if (result) {
|
||||
return "none";
|
||||
}
|
||||
},
|
||||
() => undefined
|
||||
),
|
||||
}}
|
||||
ref={refSelect}
|
||||
>
|
||||
<Icon type="SettingGear" />
|
||||
</div>
|
||||
<div style={{ width: 2 }} />
|
||||
|
||||
<div ref={refDelete}>
|
||||
<Icon
|
||||
type="Bucket"
|
||||
color={themeStore.theme.onSurfaceVariant}
|
||||
onClick={() => behaviorTreeBuilderStore.deleteBtAction(id)}
|
||||
/>
|
||||
</div>
|
||||
<div ref={refDelete}>
|
||||
<Icon
|
||||
type="Bucket"
|
||||
color={themeStore.theme.onSurfaceVariant}
|
||||
onClick={() => behaviorTreeBuilderStore.deleteBtAction(id)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div>{behaviorTreeBuilderStore.getBodyNode(label, id)}</div>
|
||||
|
|
|
@ -29,7 +29,7 @@ export const CameraDeviceForm = observer((props: IPropsForm<Partial<IDeviceDepen
|
|||
onClick={async () => {
|
||||
(await store.viewModel.valid<SidViewModel>()).fold(
|
||||
(s) => {
|
||||
props.onChange(s);
|
||||
// props.onChange(s);
|
||||
},
|
||||
(e) => message.error(e)
|
||||
);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
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";
|
||||
|
@ -9,7 +10,7 @@ import { WeightsForm } from "./weights_form/weights_form";
|
|||
export interface IPropsForm<T> {
|
||||
dependency: T;
|
||||
store?: BehaviorTreeBuilderStore;
|
||||
onChange: (dependency: Object) => void;
|
||||
onChange: (dependency: DependencyViewModel) => void;
|
||||
}
|
||||
|
||||
export interface IForms {
|
||||
|
@ -28,7 +29,7 @@ export interface BtDependencyFormBuilder {
|
|||
component?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const btDependencyFormBuilder = (onChange: (dependency: Object) => void) => [
|
||||
export const btDependencyFormBuilder = (onChange: (dependency: DependencyViewModel) => void) => [
|
||||
{ form: Form.weights, component: null },
|
||||
{
|
||||
form: Form.topic,
|
||||
|
@ -37,12 +38,12 @@ export const btDependencyFormBuilder = (onChange: (dependency: Object) => void)
|
|||
];
|
||||
export const forms = (
|
||||
props: any,
|
||||
onChange: (dependency: Object) => void,
|
||||
onChange: (dependency: DependencyViewModel) => void,
|
||||
store: BehaviorTreeBuilderStore
|
||||
): IForms[] => [
|
||||
{ name: Form.weights, component: <WeightsForm dependency={props} onChange={onChange} /> },
|
||||
{ name: Form.robotName, component: <RobotDeviceForm store={store} dependency={props} onChange={onChange} /> },
|
||||
{ name: Form.cameraDeviceForm, component: <CameraDeviceForm store={store} dependency={props} onChange={onChange} /> },
|
||||
// { name: Form.weights, component: <WeightsForm dependency={props} onChange={onChange} /> },
|
||||
// { name: Form.robotName, component: <RobotDeviceForm store={store} dependency={props} onChange={onChange} /> },
|
||||
// { name: Form.cameraDeviceForm, component: <CameraDeviceForm store={store} dependency={props} onChange={onChange} /> },
|
||||
{ name: Form.topic, component: <TopicsForm store={store} dependency={props} onChange={onChange} /> },
|
||||
{ name: Form.moveToPose, component: <MoveToPose store={store} dependency={props} onChange={onChange} /> },
|
||||
// { name: Form.moveToPose, component: <MoveToPose store={store} dependency={props} onChange={onChange} /> },
|
||||
];
|
||||
|
|
|
@ -39,7 +39,7 @@ export const MoveToPose = observer((props: IPropsForm<MoveToPoseRobotModel | und
|
|||
onClick={() => {
|
||||
store.viewModel.valid().fold(
|
||||
(s) => {
|
||||
props.onChange(s);
|
||||
// props.onChange(s);
|
||||
},
|
||||
(e) => message.error(e)
|
||||
);
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { ValidationModel } from "../../../../../../core/model/validation_model";
|
||||
import { IsNotEmpty, IsString } from "class-validator";
|
||||
import { StoreTopicType } from "./topics_form_store";
|
||||
|
||||
export class TopicDependencyViewModel extends ValidationModel {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
type: string;
|
||||
mode?: StoreTopicType;
|
||||
constructor(type: string, mode: StoreTopicType) {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
this.type = type;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
static empty() {
|
||||
return new TopicDependencyViewModel("", StoreTopicType.specifiesDependencies);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { ValidationModel } from "../../../../../../core/model/validation_model";
|
||||
import { IsNotEmpty, IsString } from "class-validator";
|
||||
import { StoreTopicType } from "./topics_form_store";
|
||||
import { DependencyViewModel } from "../../../../../../core/model/skill_model";
|
||||
import { BehaviorTreeBuilderStore } from "../../../behavior_tree_builder_store";
|
||||
import { CoreText, CoreTextType } from "../../../../../../core/ui/text/text";
|
||||
|
||||
export class TopicDependencyViewModel extends ValidationModel implements DependencyViewModel {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
type: string;
|
||||
mode?: StoreTopicType;
|
||||
sid?: string;
|
||||
topicOut?: string;
|
||||
constructor(type: string, mode: StoreTopicType) {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
this.type = type;
|
||||
this.mode = mode;
|
||||
}
|
||||
toView = (store: BehaviorTreeBuilderStore | undefined): React.ReactNode => {
|
||||
if (store && this.sid) {
|
||||
if (store.filledOutTemplates.topicsStack.some((el) => el.sid?.isEqual(this.sid ?? ""))) {
|
||||
return <CoreText type={CoreTextType.header} text={this.topicOut} color="red" />;
|
||||
} else {
|
||||
return <CoreText type={CoreTextType.header} text="Error" color="red" />;
|
||||
}
|
||||
}
|
||||
return <CoreText type={CoreTextType.header} text="Error" color="red" />;
|
||||
};
|
||||
|
||||
static empty() {
|
||||
return new TopicDependencyViewModel("", StoreTopicType.specifiesDependencies);
|
||||
}
|
||||
}
|
|
@ -8,22 +8,71 @@ import { match } from "ts-pattern";
|
|||
import { CoreInput } from "../../../../../../core/ui/input/input";
|
||||
import { CoreButton } from "../../../../../../core/ui/button/button";
|
||||
import { message } from "antd";
|
||||
import { themeStore } from "../../../../../..";
|
||||
import { isBtScreen } from "../../../behavior_tree_builder_screen";
|
||||
|
||||
export const TopicsForm = observer((props: IPropsForm<Partial<TopicDependencyViewModel>>) => {
|
||||
const [store] = React.useState(() => new TopicsFormStore());
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
store.initParam(isBtScreen(), props.store);
|
||||
|
||||
store.loadClassInstance(TopicDependencyViewModel, props.dependency as TopicDependencyViewModel);
|
||||
}, [props]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CoreText text={"Topics"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
{match(store.viewModel?.mode ?? "")
|
||||
<div style={{ height: "100%", overflow: "scroll" }}>
|
||||
<CoreText
|
||||
text={"Topics"}
|
||||
type={CoreTextType.header}
|
||||
style={{ padding: 10 }}
|
||||
color={themeStore.theme.darkOnSurfaceVariant}
|
||||
/>
|
||||
{match(store.type)
|
||||
.with(StoreTopicType.btExecute, () => (
|
||||
<>
|
||||
<CoreText text={"Выберите точку размещения"} type={CoreTextType.header} />
|
||||
<CoreText
|
||||
text={"Выберите тип топика"}
|
||||
type={CoreTextType.header}
|
||||
style={{ padding: 10 }}
|
||||
color={themeStore.theme.darkOnSurfaceVariant}
|
||||
/>
|
||||
{store
|
||||
.getAllTopicsMatched()
|
||||
|
||||
?.map((el) => (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
border: el.name.isEqual(store.viewModel.topicOut ?? "") ? "1px solid beige" : undefined,
|
||||
}}
|
||||
onClick={() => (store.updateForm({ topicOut: el.name }), store.updateForm({ sid: el.sid }))}
|
||||
>
|
||||
<CoreText
|
||||
text={`name:${el.name}`}
|
||||
type={CoreTextType.header}
|
||||
style={{ padding: 10 }}
|
||||
color={themeStore.theme.darkOnSurfaceVariant}
|
||||
/>
|
||||
<CoreText
|
||||
text={`type:${el.type}`}
|
||||
type={CoreTextType.header}
|
||||
style={{ padding: 10 }}
|
||||
color={themeStore.theme.darkOnSurfaceVariant}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<CoreButton
|
||||
text="OK"
|
||||
style={{ width: 100 }}
|
||||
onClick={async () => {
|
||||
(await store.viewModel.valid<TopicDependencyViewModel>()).fold(
|
||||
(model) => props.onChange(model),
|
||||
(e) => message.error(e)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
))
|
||||
.with(StoreTopicType.specifiesDependencies, () => (
|
||||
|
|
|
@ -4,20 +4,30 @@ import { TopicDependencyViewModel } from "./topic_dependency_view_model";
|
|||
import { FormState, CoreError } from "../../../../../../core/store/base_store";
|
||||
import { TopicsFormHttpRepository } from "./topics_form_http_repository";
|
||||
import { Topics } from "../../../../../../core/model/topics";
|
||||
import { BehaviorTreeBuilderStore } from "../../../behavior_tree_builder_store";
|
||||
import { ITopicModel } from "../../../../../topics/topic_view_model";
|
||||
export enum StoreTopicType {
|
||||
specifiesDependencies = "specifiesDependencies",
|
||||
btExecute = "btExecute",
|
||||
}
|
||||
export class TopicsFormStore extends FormState<TopicDependencyViewModel, CoreError> {
|
||||
type: StoreTopicType = StoreTopicType.btExecute;
|
||||
topics?: ITopicModel[];
|
||||
behaviorTreeBuilderStore?: BehaviorTreeBuilderStore;
|
||||
viewModel: TopicDependencyViewModel = TopicDependencyViewModel.empty();
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
topics?: Topics;
|
||||
viewModel: TopicDependencyViewModel = TopicDependencyViewModel.empty();
|
||||
cameraDeviceHttpRepository: TopicsFormHttpRepository = new TopicsFormHttpRepository();
|
||||
topicsFormHttpRepository: TopicsFormHttpRepository = new TopicsFormHttpRepository();
|
||||
errorHandingStrategy = (error: CoreError) => {};
|
||||
init = async (navigate?: NavigateFunction | undefined) => {
|
||||
// await this.mapOk('topics', this.cameraDeviceHttpRepository.getAllTopics())
|
||||
};
|
||||
getAllTopicsMatched = () => this.topics?.filter((el) => el.type.isEqual(this.viewModel.type));
|
||||
initParam = (isBtScreen: boolean, behaviorTreeBuilderStore: BehaviorTreeBuilderStore | undefined) => {
|
||||
isBtScreen ? (this.type = StoreTopicType.btExecute) : (this.type = StoreTopicType.specifiesDependencies);
|
||||
this.behaviorTreeBuilderStore = behaviorTreeBuilderStore;
|
||||
this.topics = behaviorTreeBuilderStore?.getAllTopics();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ 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";
|
||||
|
||||
interface IItem {
|
||||
name: string;
|
||||
|
@ -25,11 +26,8 @@ const skills: IItem[] = [{ name: "ML", isActive: true }];
|
|||
export const CalculationInstanceScreenPath = "/calculation";
|
||||
|
||||
export const CalculationInstanceScreen = observer(() => {
|
||||
const [store] = React.useState(() => new CalculationInstanceStore());
|
||||
const store = useStore(CalculationInstanceStore);
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<MainPage
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { observer } from "mobx-react-lite";
|
||||
import { CalculationsTemplateStore } from "./calculations_template_store";
|
||||
import React from "react";
|
||||
import { useStore } from "../../core/helper/use_store";
|
||||
|
||||
export const CalculationsTemplateScreenPath = "/calculations/template";
|
||||
|
||||
export const CalculationsTemplateScreen = observer(() => {
|
||||
const [store] = React.useState(() => new CalculationsTemplateStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
const store = useStore(CalculationsTemplateStore);
|
||||
|
||||
return <></>;
|
||||
});
|
||||
|
|
|
@ -7,15 +7,13 @@ import { MainPage } from "../../core/ui/pages/main_page";
|
|||
import { CardDataSet, CardDataSetType } from "./card_dataset";
|
||||
import { CoreInput } from "../../core/ui/input/input";
|
||||
import { CoreButton } from "../../core/ui/button/button";
|
||||
import { useStore } from "../../core/helper/use_store";
|
||||
|
||||
export const DatasetsScreenPath = "/dataset";
|
||||
|
||||
export const DataSetScreen: React.FunctionComponent = observer(() => {
|
||||
const [store] = React.useState(() => new DataSetStore());
|
||||
const store = useStore(DataSetStore);
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<MainPage
|
||||
|
@ -100,7 +98,6 @@ export const DataSetScreen: React.FunctionComponent = observer(() => {
|
|||
filled={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex" }}>
|
||||
|
|
|
@ -6,11 +6,12 @@ import { CoreText, CoreTextType } from "../../core/ui/text/text";
|
|||
import { CoreButton } from "../../core/ui/button/button";
|
||||
import { Drawer, Upload } from "antd";
|
||||
import { CoreInput } from "../../core/ui/input/input";
|
||||
import { useStore } from "../../core/helper/use_store";
|
||||
|
||||
export const DetailsScreenPath = "/details";
|
||||
|
||||
export const DetailsScreen = observer(() => {
|
||||
const [store] = React.useState(() => new DetailsStore());
|
||||
const store = useStore(DetailsStore);
|
||||
React.useEffect(() => {
|
||||
store.loadScene(canvasRef.current!);
|
||||
}, []);
|
||||
|
|
|
@ -8,14 +8,13 @@ import { CoreInput } from "../../core/ui/input/input";
|
|||
import { CoreSelect } from "../../core/ui/select/select";
|
||||
import { DigitalTwinsModel, DigitalTwinsTypes } from "./digital_twins_model";
|
||||
import { match } from "ts-pattern";
|
||||
import { useStore } from "../../core/helper/use_store";
|
||||
|
||||
export const DigitalTwinsScreenPath = "/digital_twins";
|
||||
|
||||
export const DigitalTwinsScreen = observer(() => {
|
||||
const [store] = React.useState(() => new DigitalTwinsStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
const store = useStore(DigitalTwinsStore);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: "flex" }}>
|
||||
|
|
|
@ -43,8 +43,7 @@ export class DigitalTwinsStore extends UiDrawerFormState<DigitalTwinsModel, Http
|
|||
this.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false);
|
||||
})
|
||||
.with(DigitalTwinStoreType.selectTwinTemplate, () => {
|
||||
console.log(200);
|
||||
|
||||
|
||||
// this.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false),
|
||||
// await (
|
||||
// await this.digitalTwinsHttpRepository.createNewDigitalTwinsInstance(this.viewModel)
|
||||
|
|
|
@ -11,18 +11,18 @@ import { DrawersDataset } from "../../dataset/dataset_store";
|
|||
import { Icon } from "../../../core/ui/icons/icons";
|
||||
import { sceneManagerForms } from "./forms/scene_manager_forms";
|
||||
import { SceneMode } from "../model/scene_view";
|
||||
import { useStore } from "../../../core/helper/use_store";
|
||||
|
||||
export const SceneManagerPath = "/scene/manager/";
|
||||
|
||||
export const SceneManger = observer(() => {
|
||||
const canvasRef = React.useRef<HTMLCanvasElement>(null);
|
||||
const [store] = React.useState(() => new SceneMangerStore());
|
||||
const store = useStore(SceneMangerStore);
|
||||
const id = useParams().id as string;
|
||||
const navigate = useNavigate();
|
||||
store.initParam(id);
|
||||
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
React.useEffect(() => {
|
||||
store.loadScene(canvasRef.current!);
|
||||
document.body.style.overflow = "hidden";
|
||||
return () => {
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import * as React from "react";
|
||||
import { MainPage } from "../../core/ui/pages/main_page";
|
||||
import { SimulationStore } from "./simulations_store";
|
||||
interface ISimulationScreenProps { }
|
||||
import { useStore } from "../../core/helper/use_store";
|
||||
interface ISimulationScreenProps {}
|
||||
export const SimulationScreenPath = "/simulation";
|
||||
|
||||
export const SimulationScreen = (props: ISimulationScreenProps) => {
|
||||
const [store] = React.useState(() => new SimulationStore());
|
||||
const store = useStore(SimulationStore);
|
||||
const canvasRef = React.useRef<HTMLCanvasElement>(null);
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
store.loadScene(canvasRef.current!);
|
||||
}, []);
|
||||
return <MainPage page={"Симуляция"} bodyChildren={<canvas ref={canvasRef} style={{ overflow: "hidden" }} />} />;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,5 +4,6 @@ import { HttpMethod, HttpRepository } from "../../core/repository/core_http_repo
|
|||
export class SkillsHttpRepository extends HttpRepository {
|
||||
featureApi = "/skills";
|
||||
createNewSkill = (model: SkillModel) => this._jsonRequest(HttpMethod.POST, this.featureApi, model);
|
||||
deleteSkill = (id: string) => this._jsonRequest(HttpMethod.DELETE, `${this.featureApi}?id=${id}`);
|
||||
getAllSkills = () => this._arrayJsonToClassInstanceRequest(HttpMethod.GET, this.featureApi, SkillModel);
|
||||
}
|
||||
|
|
|
@ -9,14 +9,12 @@ import { BtAction, BtActionViewModel } from "../../core/model/skill_model";
|
|||
import { btDependencyFormBuilder } from "../behavior_tree_builder/presentation/ui/forms/forms";
|
||||
import { CoreButton } from "../../core/ui/button/button";
|
||||
import { CoreSelect } from "../../core/ui/select/select";
|
||||
import { useStore } from "../../core/helper/use_store";
|
||||
|
||||
export const SkillsScreenPath = "/skills";
|
||||
|
||||
export const SkillsScreen = observer(() => {
|
||||
const [store] = React.useState(() => new SkillsStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
const store = useStore(SkillsStore);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -36,10 +34,17 @@ export const SkillsScreen = observer(() => {
|
|||
borderRadius: 20,
|
||||
}}
|
||||
>
|
||||
<CoreText text="Delete" type={CoreTextType.header} onClick={() => store.deleteSkill(el._id as string)} />
|
||||
<CoreText text={`skill server name:${el.SkillPackage.name}`} type={CoreTextType.header} />
|
||||
<div>
|
||||
<CoreText text={"Topics"} type={CoreTextType.header} />
|
||||
{el.topicsOut.map((el) => (
|
||||
<div>
|
||||
<div>{el.name}</div>
|
||||
<div>{el.type}</div>
|
||||
</div>
|
||||
))}
|
||||
<CoreText text={"actions"} type={CoreTextType.header} />
|
||||
|
||||
{el.BTAction.map((el) => (
|
||||
<div>
|
||||
<CoreText text={el.name} type={CoreTextType.medium} />
|
||||
|
@ -83,6 +88,16 @@ export const SkillsScreen = observer(() => {
|
|||
store.updateForm({ SkillPackage: Object.assign(store.viewModel.SkillPackage, { version: text }) })
|
||||
}
|
||||
/>
|
||||
<CoreInput
|
||||
label={"Module description"}
|
||||
onChange={(text) =>
|
||||
store.updateForm({ Module: Object.assign(store.viewModel.Module, { description: text }) })
|
||||
}
|
||||
/>
|
||||
<CoreInput
|
||||
label={"Module name"}
|
||||
onChange={(text) => store.updateForm({ Module: Object.assign(store.viewModel.Module, { name: text }) })}
|
||||
/>
|
||||
<CoreText
|
||||
text={`Topics ${store.viewModel.topicsOut.length}`}
|
||||
type={CoreTextType.large}
|
||||
|
|
|
@ -2,7 +2,7 @@ import makeAutoObservable from "mobx-store-inheritance";
|
|||
import { UiDrawerFormState } from "../../core/store/base_store";
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import { HttpError } from "../../core/repository/core_http_repository";
|
||||
import { ParamViewModel, SkillModel } from "../../core/model/skill_model";
|
||||
import { DependencyViewModel, ParamViewModel, SkillModel } from "../../core/model/skill_model";
|
||||
import { Form } from "../behavior_tree_builder/presentation/ui/forms/forms";
|
||||
import { message } from "antd";
|
||||
import { SkillsHttpRepository } from "./skills_http_repository";
|
||||
|
@ -26,7 +26,9 @@ export class SkillsStore extends UiDrawerFormState<SkillModel, HttpError> {
|
|||
}
|
||||
init = async (navigate?: NavigateFunction | undefined) => {
|
||||
this.mapOk("skills", this.skillsHttpRepository.getAllSkills());
|
||||
|
||||
};
|
||||
deleteSkill = async (id: string) => (await this.skillsHttpRepository.deleteSkill(id), this.init());
|
||||
modalShow = () => {
|
||||
this.isModalOpen = true;
|
||||
};
|
||||
|
@ -42,7 +44,7 @@ export class SkillsStore extends UiDrawerFormState<SkillModel, HttpError> {
|
|||
this.activeIndex = index;
|
||||
this.modalShow();
|
||||
};
|
||||
onChangeBtDependency = (dependency: Object) =>
|
||||
onChangeBtDependency = (dependency: DependencyViewModel) =>
|
||||
this.viewModel.BTAction.at(this.activeIndex ?? 0)
|
||||
?.validParam(this.selectParam?.form ?? "")
|
||||
.fold(
|
||||
|
@ -67,11 +69,11 @@ export class SkillsStore extends UiDrawerFormState<SkillModel, HttpError> {
|
|||
|
||||
clickParam(el: { form: Form; component: null } | { form: Form; component: React.JSX.Element }): void {
|
||||
this.selectParam = el;
|
||||
if (el.component === null) this.onChangeBtDependency({});
|
||||
if (el.component === null) this.onChangeBtDependency(DependencyViewModel.empty());
|
||||
}
|
||||
saveNewSkill = async () => {
|
||||
(await this.viewModel.valid<SkillModel>()).fold(
|
||||
async (model) => this.skillsHttpRepository.createNewSkill(model),
|
||||
async (model) => (this.skillsHttpRepository.createNewSkill(model), this.handleCancel(), this.init()),
|
||||
async (e) => message.error(e)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -3,11 +3,7 @@ import { socketListenerStore } from "./socket_listener_store";
|
|||
import { observer } from "mobx-react-lite";
|
||||
import { CoreText, CoreTextType } from "../../core/ui/text/text";
|
||||
|
||||
export interface ISocketListenerProps {
|
||||
children?: JSX.Element;
|
||||
}
|
||||
|
||||
export const SocketListener = observer((props: ISocketListenerProps) => {
|
||||
export const SocketListener: React.FC<{ children?: JSX.Element }> = observer(({ children }) => {
|
||||
React.useEffect(() => {
|
||||
socketListenerStore.init();
|
||||
}, []);
|
||||
|
@ -18,7 +14,7 @@ export const SocketListener = observer((props: ISocketListenerProps) => {
|
|||
<CoreText
|
||||
text="Server error reconnect..."
|
||||
type={CoreTextType.header}
|
||||
style={{ color: "white", textAlign: "center",marginTop:1 }}
|
||||
style={{ color: "white", textAlign: "center", marginTop: 1 }}
|
||||
/>
|
||||
<div style={{ width: 20 }} />
|
||||
<div className="loading">Loading…</div>
|
||||
|
@ -27,7 +23,7 @@ export const SocketListener = observer((props: ISocketListenerProps) => {
|
|||
<></>
|
||||
)}
|
||||
|
||||
{props.children}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@ export class TopicViewModel extends ValidationModel {
|
|||
@IsNotEmpty()
|
||||
@IsString()
|
||||
type: string;
|
||||
sid?: string;
|
||||
constructor(name: string, type: string) {
|
||||
super();
|
||||
this.name = name;
|
||||
|
@ -19,6 +20,7 @@ export class TopicViewModel extends ValidationModel {
|
|||
}
|
||||
export interface ITopicModel {
|
||||
digitalTwinId?: string;
|
||||
sid?: string;
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import React from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { TopicsStore } from "./topics_store";
|
||||
import React from "react";
|
||||
import { useStore } from "../../core/helper/use_store";
|
||||
|
||||
export const TopicsScreenPath = "/topics";
|
||||
|
||||
export const TopicsScreen = observer(() => {
|
||||
const [store] = React.useState(() => new TopicsStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
const store = useStore(TopicsStore);
|
||||
|
||||
return (
|
||||
<>
|
||||
{store.topics?.map((el) => (
|
||||
|
|
|
@ -16,6 +16,7 @@ extensions();
|
|||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
|
||||
export const themeStore = new ThemeStore();
|
||||
|
||||
root.render(
|
||||
<>
|
||||
<SocketListener>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue