sync
This commit is contained in:
parent
25e57c1a56
commit
3b8d9e4298
41 changed files with 1571 additions and 543 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -4,9 +4,9 @@
|
|||
"Ведите",
|
||||
"дерево",
|
||||
"Количество",
|
||||
"модели",
|
||||
"может",
|
||||
"навык",
|
||||
"модели",
|
||||
"Новое",
|
||||
"отрицательное",
|
||||
"принимать",
|
||||
|
@ -18,6 +18,7 @@
|
|||
"Collada",
|
||||
"Contolls",
|
||||
"GLTF",
|
||||
"grau",
|
||||
"raycaster",
|
||||
"skils",
|
||||
"typedataset",
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,133 +1,183 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/logo.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="Web site created using create-react-app" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.png" />
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<title>Robossembler</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/logo.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="description" content="Web site created using create-react-app" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.png" />
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<title>Robossembler </title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div style="width: 100%; height: 100%" id="root"></div>
|
||||
</body>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div style="width: 100%; height: 100%" id="root"></div>
|
||||
<style>
|
||||
@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");
|
||||
</style>
|
||||
<style>
|
||||
[contenteditable]:focus {
|
||||
outline: 0px solid transparent;
|
||||
}
|
||||
/* Absolute Center Spinner */
|
||||
.loading {
|
||||
}
|
||||
|
||||
</body>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap')
|
||||
</style>
|
||||
<style>
|
||||
[contenteditable]:focus {
|
||||
outline: 0px solid transparent;
|
||||
}
|
||||
/* Absolute Center Spinner */
|
||||
.loading {
|
||||
|
||||
}
|
||||
/* Transparent Overlay */
|
||||
.loading:before {
|
||||
content: "";
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Transparent Overlay */
|
||||
.loading:before {
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
/* :not(:required) hides these rules from IE9 and below */
|
||||
.loading:not(:required) {
|
||||
/* hide "loading..." text */
|
||||
font: 0/0 a;
|
||||
color: transparent;
|
||||
text-shadow: none;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* :not(:required) hides these rules from IE9 and below */
|
||||
.loading:not(:required) {
|
||||
/* hide "loading..." text */
|
||||
font: 0/0 a;
|
||||
color: transparent;
|
||||
text-shadow: none;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
.loading:not(:required):after {
|
||||
margin-top: 14px;
|
||||
content: "";
|
||||
display: block;
|
||||
font-size: 8px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
-webkit-animation: spinner 1500ms infinite linear;
|
||||
-moz-animation: spinner 1500ms infinite linear;
|
||||
-ms-animation: spinner 1500ms infinite linear;
|
||||
-o-animation: spinner 1500ms infinite linear;
|
||||
animation: spinner 1500ms infinite linear;
|
||||
border-radius: 0.5em;
|
||||
-webkit-box-shadow: white 1.5em 0 0 0, white 1.1em 1.1em 0 0, white 0 1.5em 0 0, white -1.1em 1.1em 0 0,
|
||||
rgba(0, 0, 0, 0.5) -1.5em 0 0 0, rgba(0, 0, 0, 0.5) -1.1em -1.1em 0 0, white 0 -1.5em 0 0,
|
||||
white 1.1em -1.1em 0 0;
|
||||
box-shadow: white 1.5em 0 0 0, white 1.1em 1.1em 0 0, white 0 1.5em 0 0, white -1.1em 1.1em 0 0,
|
||||
white -1.5em 0 0 0, white -1.1em -1.1em 0 0, white 0 -1.5em 0 0, white 1.1em -1.1em 0 0;
|
||||
}
|
||||
|
||||
.loading:not(:required):after {
|
||||
margin-top: 14px;
|
||||
content: '';
|
||||
display: block;
|
||||
font-size: 8px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
-webkit-animation: spinner 1500ms infinite linear;
|
||||
-moz-animation: spinner 1500ms infinite linear;
|
||||
-ms-animation: spinner 1500ms infinite linear;
|
||||
-o-animation: spinner 1500ms infinite linear;
|
||||
animation: spinner 1500ms infinite linear;
|
||||
border-radius: 0.5em;
|
||||
-webkit-box-shadow: white 1.5em 0 0 0, white 1.1em 1.1em 0 0, white 0 1.5em 0 0, white -1.1em 1.1em 0 0, rgba(0, 0, 0, 0.5) -1.5em 0 0 0, rgba(0, 0, 0, 0.5) -1.1em -1.1em 0 0, white 0 -1.5em 0 0, white 1.1em -1.1em 0 0;
|
||||
box-shadow: white 1.5em 0 0 0, white 1.1em 1.1em 0 0, white 0 1.5em 0 0, white -1.1em 1.1em 0 0, white -1.5em 0 0 0, white -1.1em -1.1em 0 0, white 0 -1.5em 0 0, white 1.1em -1.1em 0 0;
|
||||
}
|
||||
/* Animation */
|
||||
|
||||
/* Animation */
|
||||
@-webkit-keyframes spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-moz-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-moz-keyframes spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-moz-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-o-keyframes spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-moz-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-moz-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-moz-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-moz-keyframes spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-moz-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@-o-keyframes spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-moz-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes spinner {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-moz-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
-o-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
.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;
|
||||
|
||||
</html>
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</html>
|
||||
|
|
|
@ -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()}`;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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<string[], void> => {
|
||||
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<React.CSSProperties>((acc, el) => {
|
||||
el.BTAction.rFind<BtActionViewModel>((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<SkillModel>((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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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: <SceneManger />,
|
||||
},
|
||||
{
|
||||
path: BehaviorTreeBuilderPath,
|
||||
path: BehaviorTreeBuilderPath(idURL),
|
||||
element: <BehaviorTreeBuilderScreen />,
|
||||
},
|
||||
{
|
||||
path: BehaviorTreeBuilderPath(),
|
||||
element: <BehaviorTreeBuilderScreen />,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
61
ui/src/core/store/theme_store.ts
Normal file
61
ui/src/core/store/theme_store.ts
Normal file
|
@ -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);
|
||||
}
|
54
ui/src/core/ui/button/button_v2.tsx
Normal file
54
ui/src/core/ui/button/button_v2.tsx
Normal file
|
@ -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 (
|
||||
<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,
|
||||
}}
|
||||
onClick={() => onClick()}
|
||||
>
|
||||
{icon}
|
||||
<CoreText
|
||||
color={textColor ?? themeStore.theme.black}
|
||||
text={text}
|
||||
type={match(type)
|
||||
.with(ButtonV2Type.default, () => CoreTextType.smallv3)
|
||||
.otherwise(() => CoreTextType.largeV2)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
88
ui/src/core/ui/card/card.tsx
Normal file
88
ui/src/core/ui/card/card.tsx
Normal file
|
@ -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<HTMLDivElement>(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 (
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
backgroundColor: bgColor,
|
||||
borderRadius: 12,
|
||||
border: `1.5px solid ${themeStore.theme.outlineVariantDark}`,
|
||||
padding: 10,
|
||||
marginTop: 10,
|
||||
marginRight: 10,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{ display: "flex", paddingTop: 10, paddingLeft: 20, paddingRight: 20, justifyContent: "space-between" }}
|
||||
>
|
||||
<div>
|
||||
<CoreText type={CoreTextType.mediumV2} text={descriptionTop} color={themeStore.theme.white} />
|
||||
<div style={{ height: 5 }} />
|
||||
<CoreText
|
||||
type={CoreTextType.mediumV2}
|
||||
text={new Date().fromUnixDate(date).formatDate()}
|
||||
color={themeStore.theme.outlineVariantLight}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex" }}>
|
||||
<ButtonV2 onClick={() => clickGoToIcon()} text="Перейти" />
|
||||
<div style={{ width: 10 }} />
|
||||
<Icon
|
||||
width={10}
|
||||
height={10}
|
||||
type={"Bucket"}
|
||||
onClick={() => clickDeleteIcon()}
|
||||
style={{
|
||||
border: `1px solid ${themeStore.theme.greenWhite}`,
|
||||
height: 30,
|
||||
width: 30,
|
||||
textAlign: "center",
|
||||
alignContent: "center",
|
||||
borderRadius: 5,
|
||||
cursor: "pointer",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: "calc(100% - 30px)",
|
||||
height: 1,
|
||||
backgroundColor: themeStore.theme.outlineVariantDark,
|
||||
marginLeft: 15,
|
||||
marginRight: 15,
|
||||
}}
|
||||
/>
|
||||
<div style={{ paddingRight: 30, paddingLeft: 30 }}>
|
||||
<div style={{ height: 20 }} />
|
||||
|
||||
<CoreText type={CoreTextType.largeV2} text={descriptionMiddle} color={themeStore.theme.white} />
|
||||
<CoreText type={CoreTextType.mediumV2} text={descriptionBottom} color={themeStore.theme.white} />
|
||||
<div style={{ height: 20 }} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -12,8 +12,6 @@ export const SelectDetail = observer((props: IFormBuilderComponentsProps<SelectD
|
|||
React.useEffect(() => {
|
||||
store.viewModel = new SelectDetailViewModel(props.dependency.details);
|
||||
store.isLoading = false;
|
||||
console.log(store.viewModel);
|
||||
|
||||
store.init();
|
||||
}, []);
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ import { FormState } from "../../../../../store/base_store";
|
|||
import { SelectDetailViewModel } from "../model/select_details_model";
|
||||
|
||||
export class SelectDetailStore extends FormState<SelectDetailViewModel, any> {
|
||||
|
||||
|
||||
viewModel = SelectDetailViewModel.empty();
|
||||
parts?: Parts[];
|
||||
isLoading: boolean = true;
|
||||
|
@ -16,7 +14,6 @@ export class SelectDetailStore extends FormState<SelectDetailViewModel, any> {
|
|||
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)) {
|
||||
|
|
|
@ -54,12 +54,52 @@ const getIconSvg = (
|
|||
switch (type) {
|
||||
case "":
|
||||
return Result.ok();
|
||||
case "LeftIcon":
|
||||
return Result.ok(
|
||||
<svg width="10" height="12" viewBox="0 0 10 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M9.5 6L0.5 11.25L0.5 0.75L9.5 6Z" fill="#E6E0E9" />
|
||||
</svg>
|
||||
);
|
||||
case "SettingGear":
|
||||
return Result.ok(
|
||||
<svg
|
||||
width={width ? width : "14"}
|
||||
height={height ? height : "14"}
|
||||
viewBox="0 0 14 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M8.93089 12.2675C8.87255 12.6642 8.51089 12.9792 8.07922 12.9792H5.92089C5.48922 12.9792 5.12756 12.6642 5.07506 12.2383L4.91756 11.1358C4.76006 11.0542 4.60839 10.9667 4.45672 10.8675L3.40672 11.2875C2.99839 11.4392 2.54922 11.27 2.35089 10.9083L1.28339 9.05917C1.07922 8.67417 1.16672 8.21917 1.49339 7.96251L2.38589 7.26834C2.38006 7.18084 2.37422 7.09334 2.37422 7.00001C2.37422 6.91251 2.38006 6.81917 2.38589 6.73167L1.49922 6.03751C1.15506 5.77501 1.06756 5.30251 1.28339 4.94084L2.36256 3.08001C2.56089 2.71834 3.01006 2.55501 3.40672 2.71251L4.46256 3.13834C4.61422 3.03917 4.76589 2.95167 4.91756 2.87001L5.07506 1.75584C5.12756 1.34751 5.48922 1.02667 5.91505 1.02667H8.07339C8.50505 1.02667 8.86672 1.34167 8.91922 1.76751L9.07672 2.87001C9.23422 2.95167 9.38589 3.03917 9.53755 3.13834L10.5876 2.71834C11.0017 2.56667 11.4509 2.73584 11.6492 3.09751L12.7226 4.95251C12.9326 5.33751 12.8392 5.79251 12.5126 6.04917L11.6259 6.74334C11.6317 6.83084 11.6376 6.91834 11.6376 7.01167C11.6376 7.10501 11.6317 7.19251 11.6259 7.28001L12.5126 7.97417C12.8392 8.23667 12.9326 8.69167 12.7284 9.05917L11.6434 10.9375C11.4451 11.2992 10.9959 11.4625 10.5934 11.305L9.54339 10.885C9.39172 10.9842 9.24006 11.0717 9.08839 11.1533L8.93089 12.2675ZM6.19506 11.8125H7.80506L8.02089 10.325L8.33006 10.1967C8.58672 10.0917 8.84339 9.94001 9.11172 9.74167L9.37422 9.54334L10.7626 10.1033L11.5676 8.70334L10.3834 7.78167L10.4242 7.45501L10.426 7.4393C10.4429 7.29325 10.4592 7.15206 10.4592 7.00001C10.4592 6.84251 10.4417 6.69084 10.4242 6.54501L10.3834 6.21834L11.5676 5.29667L10.7567 3.89667L9.36256 4.45667L9.10005 4.25251C8.85505 4.06584 8.59256 3.91417 8.32422 3.80334L8.02089 3.67501L7.80506 2.18751H6.19506L5.97922 3.67501L5.67005 3.79751C5.41339 3.90834 5.15672 4.05417 4.88839 4.25834L4.62589 4.45084L3.23756 3.89667L2.42672 5.29084L3.61089 6.21251L3.57006 6.53917C3.55256 6.69084 3.53506 6.84834 3.53506 7.00001C3.53506 7.15167 3.54672 7.30917 3.57006 7.45501L3.61089 7.78167L2.42672 8.70334L3.23172 10.1033L4.62589 9.54334L4.88839 9.74751C5.13922 9.94001 5.39006 10.0858 5.66422 10.1967L5.97339 10.325L6.19506 11.8125ZM9.04172 7.00001C9.04172 8.12759 8.12764 9.04167 7.00006 9.04167C5.87247 9.04167 4.95839 8.12759 4.95839 7.00001C4.95839 5.87242 5.87247 4.95834 7.00006 4.95834C8.12764 4.95834 9.04172 5.87242 9.04172 7.00001Z"
|
||||
fill="#CAC4D0"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "Bucket":
|
||||
return Result.ok(
|
||||
<svg
|
||||
width={width ?? "12"}
|
||||
height={height ??"14"}
|
||||
viewBox="0 0 12 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M4.66699 6.33333V10.3333M7.33366 6.33333V10.3333M0.666992 3.66667H11.3337M10.667 3.66667L10.089 11.7613C10.065 12.0977 9.91452 12.4125 9.66773 12.6424C9.42095 12.8722 9.09623 13 8.75899 13H3.24166C2.90442 13 2.5797 12.8722 2.33292 12.6424C2.08613 12.4125 1.9356 12.0977 1.91166 11.7613L1.33366 3.66667H10.667ZM8.00033 3.66667V1.66667C8.00033 1.48986 7.93009 1.32029 7.80506 1.19526C7.68004 1.07024 7.51047 1 7.33366 1H4.66699C4.49018 1 4.32061 1.07024 4.19559 1.19526C4.07056 1.32029 4.00033 1.48986 4.00033 1.66667V3.66667H8.00033Z"
|
||||
stroke={color ?? "#E9EDC9"}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "Error":
|
||||
return Result.ok(
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={width ? width : "20"}
|
||||
height={height ? height : "20"}
|
||||
width={width ?? "20"}
|
||||
height={height ?? "20"}
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
>
|
||||
|
@ -71,6 +111,173 @@ const getIconSvg = (
|
|||
/>
|
||||
</svg>
|
||||
);
|
||||
case "BottomSquare":
|
||||
return Result.ok(
|
||||
<svg width="21" height="28" viewBox="0 0 21 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M19.0909 8.61539H11.4545V2.15385C11.4545 1.58261 11.2534 1.03477 10.8954 0.630847C10.5374 0.226922 10.0518 0 9.54545 0H1.90909C1.40277 0 0.917184 0.226922 0.55916 0.630847C0.201136 1.03477 0 1.58261 0 2.15385V8.61539C0 9.18662 0.201136 9.73446 0.55916 10.1384C0.917184 10.5423 1.40277 10.7692 1.90909 10.7692H9.54545V17.2308H1.90909C1.40277 17.2308 0.917184 17.4577 0.55916 17.8616C0.201136 18.2655 0 18.8134 0 19.3846V25.8462C0 26.4174 0.201136 26.9652 0.55916 27.3692C0.917184 27.7731 1.40277 28 1.90909 28H9.54545C10.0518 28 10.5374 27.7731 10.8954 27.3692C11.2534 26.9652 11.4545 26.4174 11.4545 25.8462V19.3846H19.0909C19.5972 19.3846 20.0828 19.1577 20.4408 18.7538C20.7989 18.3498 21 17.802 21 17.2308V10.7692C21 10.198 20.7989 9.65016 20.4408 9.24623C20.0828 8.84231 19.5972 8.61539 19.0909 8.61539ZM9.54545 25.8462H1.90909V19.3846H9.54545V25.8462ZM9.54545 2.15385V8.61539H1.90909V2.15385H9.54545ZM19.0909 17.2308H11.4545V10.7692H19.0909V17.2308Z"
|
||||
fill="black"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "DashBoard":
|
||||
return Result.ok(
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M7.25547 8.65138C7.25547 8.42934 7.16727 8.21639 7.01026 8.05938C6.85325 7.90238 6.64031 7.81417 6.41826 7.81417C6.19622 7.81417 5.98327 7.90238 5.82627 8.05938C5.66926 8.21639 5.58105 8.42934 5.58105 8.65138V18.6979C5.58105 18.9199 5.66926 19.1329 5.82627 19.2899C5.98327 19.4469 6.19622 19.5351 6.41826 19.5351C6.64031 19.5351 6.85325 19.4469 7.01026 19.2899C7.16727 19.1329 7.25547 18.9199 7.25547 18.6979V8.65138ZM11.9997 4.46533C12.2217 4.46533 12.4346 4.55354 12.5917 4.71054C12.7487 4.86755 12.8369 5.0805 12.8369 5.30254V18.6979C12.8369 18.9199 12.7487 19.1329 12.5917 19.2899C12.4346 19.4469 12.2217 19.5351 11.9997 19.5351C11.7776 19.5351 11.5647 19.4469 11.4077 19.2899C11.2507 19.1329 11.1625 18.9199 11.1625 18.6979V5.30254C11.1625 5.0805 11.2507 4.86755 11.4077 4.71054C11.5647 4.55354 11.7776 4.46533 11.9997 4.46533ZM18.4183 13.1165C18.4183 12.8945 18.3301 12.6815 18.1731 12.5245C18.016 12.3675 17.8031 12.2793 17.5811 12.2793C17.359 12.2793 17.1461 12.3675 16.9891 12.5245C16.8321 12.6815 16.7438 12.8945 16.7438 13.1165V18.6979C16.7438 18.9199 16.8321 19.1329 16.9891 19.2899C17.1461 19.4469 17.359 19.5351 17.5811 19.5351C17.8031 19.5351 18.016 19.4469 18.1731 19.2899C18.3301 19.1329 18.4183 18.9199 18.4183 18.6979V13.1165Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M11.9364 0C9.35888 0 7.33953 6.65354e-08 5.76335 0.212093C4.15144 0.428651 2.87888 0.881861 1.87981 1.87981C0.880744 2.87888 0.428651 4.15144 0.212093 5.76446C6.65354e-08 7.33953 0 9.35888 0 11.9364V12.0636C0 14.6411 6.65354e-08 16.6605 0.212093 18.2367C0.428651 19.8486 0.881861 21.1211 1.87981 22.1202C2.87888 23.1193 4.15144 23.5713 5.76446 23.7879C7.33953 24 9.35888 24 11.9364 24H12.0636C14.6411 24 16.6605 24 18.2367 23.7879C19.8486 23.5713 21.1211 23.1181 22.1202 22.1202C23.1193 21.1211 23.5713 19.8486 23.7879 18.2355C24 16.6605 24 14.6411 24 12.0636V11.9364C24 9.35888 24 7.33953 23.7879 5.76335C23.5713 4.15144 23.1181 2.87888 22.1202 1.87981C21.1211 0.880744 19.8486 0.428651 18.2355 0.212093C16.6605 6.65354e-08 14.6411 0 12.0636 0H11.9364ZM3.06419 3.06419C3.70046 2.42791 4.56 2.06288 5.98772 1.87088C7.43888 1.67665 9.34549 1.67442 12 1.67442C14.6545 1.67442 16.5611 1.67665 18.0123 1.87088C19.44 2.06288 20.3007 2.42902 20.9369 3.06419C21.5721 3.70046 21.9371 4.56 22.1291 5.98772C22.3233 7.43888 22.3256 9.34549 22.3256 12C22.3256 14.6545 22.3233 16.5611 22.1291 18.0123C21.9371 19.44 21.571 20.3007 20.9358 20.9369C20.2995 21.5721 19.44 21.9371 18.0123 22.1291C16.5611 22.3233 14.6545 22.3256 12 22.3256C9.34549 22.3256 7.43888 22.3233 5.98772 22.1291C4.56 21.9371 3.69935 21.571 3.06307 20.9358C2.42791 20.2995 2.06288 19.44 1.87088 18.0123C1.67665 16.5611 1.67442 14.6545 1.67442 12C1.67442 9.34549 1.67665 7.43888 1.87088 5.98772C2.06288 4.56 2.42902 3.70046 3.06419 3.06419Z"
|
||||
fill="black"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "PlayComputer":
|
||||
return Result.ok(
|
||||
<svg width="26" height="24" viewBox="0 0 26 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M0.84375 0H22.7812L23.625 0.84375V10.1301C23.1025 9.7379 22.5362 9.40775 21.9375 9.14625V1.6875H1.6875V16.875H10.125C10.125 18.7006 10.7171 20.477 11.8125 21.9375H5.0625V20.25H10.125V18.5625H0.84375L0 17.7188V0.84375L0.84375 0Z"
|
||||
fill="black"
|
||||
/>
|
||||
<path
|
||||
d="M18.5624 10.125C19.1812 10.125 19.7791 10.2038 20.3563 10.3613C20.93 10.5199 21.4661 10.7488 21.9644 11.0481C22.4594 11.3462 22.9139 11.6977 23.3279 12.1027C23.7408 12.5077 24.0952 12.9622 24.3911 13.4662C24.8436 14.2447 25.1371 15.1053 25.2544 15.9981C25.3717 16.8909 25.3106 17.7981 25.0745 18.6671C24.917 19.2443 24.6886 19.7809 24.3894 20.277C24.0919 20.7709 23.738 21.2285 23.3347 21.6405C22.9297 22.0534 22.4752 22.4078 21.9712 22.7036C21.1927 23.1562 20.3321 23.4497 19.4393 23.567C18.5465 23.6843 17.6393 23.6231 16.7703 23.3871C16.2049 23.2333 15.6632 23.0028 15.1604 22.7019C14.6665 22.4045 14.209 22.0506 13.7969 21.6473C13.3826 21.2428 13.025 20.7842 12.7338 20.2838C12.2812 19.5053 11.9878 18.6447 11.8705 17.7519C11.7531 16.8591 11.8143 15.9519 12.0504 15.0829C12.2079 14.5057 12.4363 13.9691 12.7355 13.473C13.0336 12.978 13.3852 12.5235 13.7902 12.1095C14.1952 11.6966 14.6497 11.3422 15.1537 11.0464C16.189 10.4445 17.3649 10.1266 18.5624 10.125ZM21.9374 16.8547L16.8749 13.5V20.25L21.9374 16.8547Z"
|
||||
fill="black"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "Graph":
|
||||
return Result.ok(
|
||||
<svg width="26" height="24" viewBox="0 0 26 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M25 9.0799V2.1199C25 1.72226 24.6776 1.3999 24.28 1.3999L19.72 1.3999C19.3224 1.3999 19 1.72226 19 2.1199V9.0799C19 9.47755 19.3224 9.7999 19.72 9.7999L24.28 9.7999C24.6776 9.7999 25 9.47755 25 9.0799Z"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
/>
|
||||
<path
|
||||
d="M7 15.68L7 8.72C7 8.32236 6.67764 8 6.28 8L1.72 8C1.32236 8 1 8.32236 1 8.72L1 15.68C1 16.0776 1.32236 16.4 1.72 16.4H6.28C6.67764 16.4 7 16.0776 7 15.68Z"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
/>
|
||||
<path
|
||||
d="M25 22.2801V15.3201C25 14.9225 24.6776 14.6001 24.28 14.6001L19.72 14.6001C19.3224 14.6001 19 14.9225 19 15.3201V22.2801C19 22.6777 19.3224 23.0001 19.72 23.0001H24.28C24.6776 23.0001 25 22.6777 25 22.2801Z"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
/>
|
||||
<path
|
||||
d="M19 5.5998H14.8C14.1635 5.5998 13.553 5.85266 13.1029 6.30275C12.6529 6.75284 12.4 7.36328 12.4 7.9998V16.3998C12.4 17.0363 12.6529 17.6468 13.1029 18.0969C13.553 18.5469 14.1635 18.7998 14.8 18.7998H19M12.4 12.1998L7 12.1998"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "Storage":
|
||||
return Result.ok(
|
||||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M25 5.28571C25 5.84852 24.6896 6.40582 24.0866 6.92579C23.4835 7.44575 22.5996 7.91821 21.4853 8.31617C20.371 8.71414 19.0481 9.02982 17.5922 9.2452C16.1363 9.46057 14.5759 9.57143 13 9.57143C9.8174 9.57143 6.76516 9.1199 4.51472 8.31617C2.26428 7.51244 1 6.42236 1 5.28571C1 4.72291 1.31039 4.16561 1.91345 3.64564C2.5165 3.12568 3.40042 2.65322 4.51472 2.25526C5.62902 1.85729 6.95189 1.54161 8.4078 1.32623C9.86371 1.11085 11.4241 1 13 1C14.5759 1 16.1363 1.11085 17.5922 1.32623C19.0481 1.54161 20.371 1.85729 21.4853 2.25526C22.5996 2.65322 23.4835 3.12568 24.0866 3.64564C24.6896 4.16561 25 4.72291 25 5.28571Z"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M25 20.7144C25 21.4667 24.4455 22.2057 23.3923 22.8572C22.3391 23.5087 20.8242 24.0497 19 24.4259C17.1758 24.802 15.1064 25.0001 13 25.0001C10.8936 25.0001 8.82423 24.802 7 24.4259C5.17577 24.0497 3.66091 23.5087 2.60769 22.8572C1.55447 22.2057 1 21.4667 1 20.7144"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M25 15.5713C25 16.3236 24.4455 17.0626 23.3923 17.7141C22.3391 18.3657 20.8242 18.9067 19 19.2828C17.1758 19.659 15.1064 19.857 13 19.857C10.8936 19.857 8.82423 19.659 7 19.2828C5.17577 18.9067 3.66092 18.3657 2.6077 17.7141C1.55448 17.0626 1 16.3236 1 15.5713"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M25 10.4287C25 11.181 24.4455 11.9201 23.3923 12.5716C22.3391 13.2231 20.8242 13.7641 19 14.1402C17.1758 14.5164 15.1064 14.7144 13 14.7144C10.8936 14.7144 8.82423 14.5164 7 14.1402C5.17577 13.7641 3.66091 13.2231 2.60769 12.5716C1.55447 11.9201 1 11.181 1 10.4287"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path d="M1 5.28564V20.7142" stroke="black" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" />
|
||||
<path
|
||||
d="M25 5.28564V20.7142"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "RobotARM":
|
||||
return Result.ok(
|
||||
<svg width="27" height="25" viewBox="0 0 27 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M24.75 8.5H19.75L16 4.75L19.75 1H24.75M1.625 19.125C1.625 18.7935 1.7567 18.4755 1.99112 18.2411C2.22554 18.0067 2.54348 17.875 2.875 17.875H24.125C24.4565 17.875 24.7745 18.0067 25.0089 18.2411C25.2433 18.4755 25.375 18.7935 25.375 19.125V23.5H1.625V19.125Z"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M3.5 7.25C4.88071 7.25 6 6.13071 6 4.75C6 3.36929 4.88071 2.25 3.5 2.25C2.11929 2.25 1 3.36929 1 4.75C1 6.13071 2.11929 7.25 3.5 7.25Z"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
/>
|
||||
<path
|
||||
d="M6 4.75H16M4.75 7.25L9.75 17.875"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "Home":
|
||||
return Result.ok(
|
||||
<svg width="28" height="25" viewBox="0 0 28 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M1 13.8571L13.8571 1L26.7143 13.8571"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M3.85742 11V22.4286C3.85742 22.8075 4.00793 23.1708 4.27584 23.4387C4.54375 23.7066 4.90711 23.8571 5.28599 23.8571H9.57171C9.95059 23.8571 10.314 23.7066 10.5819 23.4387C10.8498 23.1708 11.0003 22.8075 11.0003 22.4286V16.7143C11.0003 16.3354 11.1508 15.972 11.4187 15.7041C11.6866 15.4362 12.05 15.2857 12.4289 15.2857H15.286C15.6649 15.2857 16.0282 15.4362 16.2961 15.7041C16.5641 15.972 16.7146 16.3354 16.7146 16.7143V22.4286C16.7146 22.8075 16.8651 23.1708 17.133 23.4387C17.4009 23.7066 17.7643 23.8571 18.1431 23.8571H22.4289C22.8077 23.8571 23.1711 23.7066 23.439 23.4387C23.7069 23.1708 23.8574 22.8075 23.8574 22.4286V11"
|
||||
stroke="black"
|
||||
strokeWidth="1.75"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "ComposeSquares":
|
||||
return Result.ok(
|
||||
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3.5 11C2.125 11 1 9.875 1 8.5V3.5C1 2.125 2.125 1 3.5 1H8.5C9.875 1 11 2.125 11 3.5M11 18.5C9.625 18.5 8.5 17.375 8.5 16V11C8.5 9.625 9.625 8.5 11 8.5H16C17.375 8.5 18.5 9.625 18.5 11"
|
||||
stroke="black"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M23.5 16H18.5C17.1193 16 16 17.1193 16 18.5V23.5C16 24.8807 17.1193 26 18.5 26H23.5C24.8807 26 26 24.8807 26 23.5V18.5C26 17.1193 24.8807 16 23.5 16Z"
|
||||
stroke="black"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
case "Log":
|
||||
return Result.ok(
|
||||
<svg
|
||||
|
@ -466,6 +673,12 @@ const getIconSvg = (
|
|||
<path d="M4 9.4L0 5.4L1.4 4L4 6.6L10.6 0L12 1.4L4 9.4Z" fill="white" />
|
||||
</svg>
|
||||
);
|
||||
case "Plus":
|
||||
return Result.ok(
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 6.75H6.75V12H5.25V6.75H0V5.25H5.25V0H6.75V5.25H12V6.75Z" fill="black" />
|
||||
</svg>
|
||||
);
|
||||
case "PlusCircle":
|
||||
return Result.ok(
|
||||
<svg width="33" height="33" viewBox="0 0 33 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
|
@ -482,7 +695,7 @@ const getIconSvg = (
|
|||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M16.06 0.589883L17.41 1.93988C18.2 2.71988 18.2 3.98988 17.41 4.76988L4.18 17.9999H0V13.8199L10.4 3.40988L13.23 0.589883C14.01 -0.190117 15.28 -0.190117 16.06 0.589883ZM2 15.9999L3.41 16.0599L13.23 6.22988L11.82 4.81988L2 14.6399V15.9999Z"
|
||||
fill="#31111D"
|
||||
fill={color ?? "#49454F"}
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
|
54
ui/src/core/ui/input/input_v2.tsx
Normal file
54
ui/src/core/ui/input/input_v2.tsx
Normal file
|
@ -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<InputV2Props> = ({ label, height, value, onChange }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
height: "max-content",
|
||||
minHeight: 56,
|
||||
justifyContent: "space-between",
|
||||
backgroundColor: themeStore.theme.surfaceContainerHighest,
|
||||
}}
|
||||
>
|
||||
<div style={{ paddingLeft: 10 }}>
|
||||
<CoreText
|
||||
style={{ paddingTop: 5 }}
|
||||
type={CoreTextType.smallV2}
|
||||
color={themeStore.theme.greenWhite}
|
||||
fontType={FontType.ubuntu}
|
||||
text={label}
|
||||
/>
|
||||
<CoreText
|
||||
onChange={(text) => {
|
||||
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}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Icon
|
||||
style={{ alignContent: "center", paddingRight: 10, position: "relative", display: "flex", paddingTop: 17 }}
|
||||
type="Pencil"
|
||||
color={themeStore.theme.greenWhite}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
49
ui/src/core/ui/modal/modal.tsx
Normal file
49
ui/src/core/ui/modal/modal.tsx
Normal file
|
@ -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<ModalProps> = ({ isOpen, onClose, children, style }) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: themeStore.theme.fon,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
onClick={() => onClose()}
|
||||
>
|
||||
<div
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
style={{
|
||||
backgroundColor: themeStore.theme.black,
|
||||
border: `1px solid ${themeStore.theme.greenWhite}`,
|
||||
padding: 20,
|
||||
borderRadius: 5,
|
||||
width: 400,
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
>
|
||||
<Icon type={props.icon ?? ""} />
|
||||
|
@ -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" },
|
||||
];
|
||||
|
|
213
ui/src/core/ui/pages/main_page_v2.tsx
Normal file
213
ui/src/core/ui/pages/main_page_v2.tsx
Normal file
|
@ -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 (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
backgroundColor: bgColor,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
overflow: "auto",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
alignSelf: "center",
|
||||
width: 645,
|
||||
height: 60,
|
||||
backgroundColor: themeStore.theme.navBlue,
|
||||
paddingBottom: 60,
|
||||
borderRadius: 20,
|
||||
zIndex: 20,
|
||||
}}
|
||||
>
|
||||
<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,
|
||||
|
||||
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: -5,
|
||||
left: 5,
|
||||
backgroundColor: themeStore.theme.greenWhite,
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 200,
|
||||
}}
|
||||
></div>
|
||||
</RefDiv>
|
||||
</div>
|
||||
</div>
|
||||
<div style={Object.assign({ width: "100%" }, style)}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
});
|
|
@ -21,7 +21,6 @@ export const PreviewPage = (props: IPreviewPageProps) => {
|
|||
<CoreText text={props.largeText ?? ""} type={CoreTextType.big} />
|
||||
<CoreText
|
||||
onClick={() => {
|
||||
console.log(200);
|
||||
if (props.click) props.click();
|
||||
}}
|
||||
text={props.minText ?? ""}
|
||||
|
|
21
ui/src/core/ui/ref/ref_div.tsx
Normal file
21
ui/src/core/ui/ref/ref_div.tsx
Normal file
|
@ -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<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
if (ref.current && onChange) {
|
||||
// @ts-ignore
|
||||
onChange(String(ref.current[property]));
|
||||
}
|
||||
} );
|
||||
return (
|
||||
<div ref={ref} style={style}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
96
ui/src/core/ui/select/select_v2.tsx
Normal file
96
ui/src/core/ui/select/select_v2.tsx
Normal file
|
@ -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<ISelectV2Props> = ({ items, initialValue, label, onChange, style }) => {
|
||||
const ref = React.useRef<HTMLDivElement>(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 (
|
||||
<div ref={ref} style={style}>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: themeStore.theme.darkSurface,
|
||||
height: 58,
|
||||
borderRadius: "4px 4px 4px 4px",
|
||||
border: `3px solid ${themeStore.theme.greenWhite}`,
|
||||
padding: "10px 10px 10px 10px",
|
||||
}}
|
||||
>
|
||||
<CoreText
|
||||
type={CoreTextType.small}
|
||||
color={themeStore.theme.greenWhite}
|
||||
text={label}
|
||||
style={{
|
||||
position: "relative",
|
||||
bottom: 20,
|
||||
backgroundColor: themeStore.theme.darkSurface,
|
||||
width: "min-content",
|
||||
paddingLeft: 5,
|
||||
paddingRight: 5,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 16,
|
||||
fontFamily: "Roboto",
|
||||
color: themeStore.theme.white,
|
||||
height: 24,
|
||||
position: "relative",
|
||||
top: -13,
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: themeStore.theme.surfaceContainer,
|
||||
boxShadow: "0px 1px 2px rgba(0, 0, 0, 0.3), 0px 2px 6px 2px rgba(0, 0, 0, 0.15)",
|
||||
borderRadius: 4,
|
||||
}}
|
||||
>
|
||||
<div style={{ position: "absolute", width: width, backgroundColor: themeStore.theme.surfaceContainer }}>
|
||||
{cursorIsCorses
|
||||
? items.map((el, i) => (
|
||||
<CoreText
|
||||
text={el.name}
|
||||
key={i}
|
||||
type={CoreTextType.smallV2}
|
||||
color={themeStore.theme.white}
|
||||
onClick={() => {
|
||||
setValue(el.name);
|
||||
onChange(el.value);
|
||||
}}
|
||||
style={{
|
||||
padding: 10,
|
||||
alignContent: "center",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -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 (
|
||||
<div
|
||||
contentEditable={props.contentEditable}
|
||||
onClick={() => {
|
||||
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}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -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}
|
||||
>
|
||||
<CoreText text="Новый проект" type={CoreTextType.big} />
|
||||
<CoreInput label={"название проекта"} onChange={(text) => store.setDescriptionToNewProject(text)} />
|
||||
|
@ -102,7 +102,7 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
style={{ marginRight: 10 }}
|
||||
filled={true}
|
||||
/>
|
||||
<CoreButton text="Отменить" onClick={() => store.handleCancel()} style={{ marginRight: 10 }} />
|
||||
<CoreButton text="Отменить" onClick={() => store.modalCancel()} style={{ marginRight: 10 }} />
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
|
|
|
@ -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<BehaviorTreeModel[]>(HttpMethod.GET, this.featureApi);
|
||||
getBtSkills = async (): Promise<Result<HttpError, Skills>> => {
|
||||
return (await this._jsonToClassInstanceRequest<Skills>(
|
||||
getBtSkills = async (): Promise<Result<HttpError, SkillModel[]>> => {
|
||||
return (await this._arrayJsonToClassInstanceRequest<SkillModel>(
|
||||
HttpMethod.GET,
|
||||
`${this.featureApi}/templates`,
|
||||
Skills
|
||||
)) as unknown as Promise<Result<HttpError, Skills>>;
|
||||
`/skills`,
|
||||
SkillModel
|
||||
)) as unknown as Promise<Result<HttpError, SkillModel[]>>;
|
||||
};
|
||||
saveNewBt = async (model: BehaviorTreeViewModel) => this._jsonRequest(HttpMethod.POST, this.featureApi, model);
|
||||
getBtById = async (id: string): Promise<Result<HttpError, BehaviorTreeModel>> =>
|
||||
|
@ -22,7 +22,7 @@ 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);
|
||||
editBt = async (model: BehaviorTreeModel) => {
|
||||
await this._jsonRequest(HttpMethod.POST, `${this.featureApi}/fill/tree`, model);
|
||||
return await this._jsonRequest(HttpMethod.PUT, this.featureApi, model);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -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<string, BehaviorTreeViewModel> {
|
||||
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("", "", "", "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<ISkillView[]>((acc, primitive) => {
|
||||
acc.rFind<ISkillView>((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;
|
||||
}, [])
|
||||
|
||||
}
|
||||
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<ISkillView[]>((acc, primitive) => {
|
||||
acc
|
||||
.rFind<ISkillView>((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;
|
||||
}, []);
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
<MainPage
|
||||
page={"Поведение"}
|
||||
panelStyle={{ padding: 20 }}
|
||||
maskLoader={store.isLoading}
|
||||
panelChildren={
|
||||
<MainPageV2
|
||||
style={{ position: "absolute", height: "100%" }}
|
||||
bgColor={themeStore.theme.black}
|
||||
children={
|
||||
<>
|
||||
{match(store.type)
|
||||
.with(StoreUIType.SelectBehaviorTree, () => (
|
||||
.with(StoreUIType.ViewBehaviorTree, () => (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundColor: "rgb(255, 217, 228)",
|
||||
padding: 10,
|
||||
textAlign: "center",
|
||||
width: 300,
|
||||
zIndex: 10,
|
||||
position: "absolute",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "space-between",
|
||||
backgroundColor: themeStore.theme.surfaceContainerLow,
|
||||
}}
|
||||
>
|
||||
{store.btTreeModels?.map((el, index) => (
|
||||
<div
|
||||
style={{ display: "flex", justifyContent: "center", height: 30, alignItems: "center" }}
|
||||
key={index}
|
||||
>
|
||||
<CoreText text={el.name} type={CoreTextType.medium} />
|
||||
<div style={{ width: 10 }} />
|
||||
<Icon
|
||||
type={"code"}
|
||||
style={{ height: "100%", placeContent: "center" }}
|
||||
onClick={() => BehaviorTreeBuilderPath + navigate(el._id)}
|
||||
<div style={{ margin: 20 }}>
|
||||
<div style={{ height: 58, alignContent: "center" }}>
|
||||
<CoreText
|
||||
text="Поведение"
|
||||
type={CoreTextType.mediumV2}
|
||||
color={themeStore.theme.onSurfaceVariant}
|
||||
style={{ marginLeft: 20 }}
|
||||
/>
|
||||
<div style={{ width: "100%", height: 1, backgroundColor: themeStore.theme.outlineVariant }} />
|
||||
</div>
|
||||
))}
|
||||
<Icon type="PlusCircle" onClick={() => store.editDrawer(DrawerState.newBehaviorTree, true)} />
|
||||
{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}
|
||||
className="dotted"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
backgroundSize: "20px 20px",
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
))
|
||||
.with(StoreUIType.ViewBehaviorTree, () => (
|
||||
<div
|
||||
style={{ height: "100%", display: "flex", flexDirection: "column", justifyContent: "space-between" }}
|
||||
>
|
||||
<div>
|
||||
<div style={{ height: 58, alignContent: "center" }}>
|
||||
<CoreText text="модели" type={CoreTextType.medium} />
|
||||
</div>
|
||||
{store.skillTemplates ? <SkillTree skills={store.skillTree} dragEnd={store.dragEnd} /> : null}
|
||||
.with(StoreUIType.SelectBehaviorTree, () => (
|
||||
<>
|
||||
<div style={{ height: 20 }} />
|
||||
<ButtonV2
|
||||
icon={<Icon type={"Plus"} style={{ alignSelf: "center", marginLeft: 10, marginRight: 10 }} />}
|
||||
text="СОЗДАТЬ ДЕРЕВО ПОВЕДЕНИЯ"
|
||||
onClick={() => store.modalShow()}
|
||||
/>
|
||||
<div style={{ height: 50 }} />
|
||||
|
||||
<div style={{ display: "inline-grid", gridTemplateColumns: "1fr 1fr 1fr", width: "100%" }}>
|
||||
{store.btTreeModels?.repeat(100).map((el, index) => (
|
||||
<CoreCard
|
||||
key={index}
|
||||
clickDeleteIcon={() => store.deleteBt(el._id)}
|
||||
clickGoToIcon={() => store.goToBt(el._id)}
|
||||
descriptionMiddle={el.description}
|
||||
descriptionTop={el.name}
|
||||
date={el.unixTime}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div style={{ width: 100, height: 40 }}>
|
||||
<CoreButton onClick={() => store.onClickSaveBehaviorTree()} text="Сохранить" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
))
|
||||
.otherwise(() => (
|
||||
<></>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
bodyChildren={
|
||||
<>
|
||||
<div style={{ display: "flex", width: "100%" }}>
|
||||
<div
|
||||
ref={ref}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: window.innerHeight,
|
||||
background: "white",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Drawer
|
||||
title={store.titleDrawer}
|
||||
destroyOnClose={true}
|
||||
onClose={() => store.editDrawer(DrawerState.newBehaviorTree, false)}
|
||||
open={store.drawers.find((el) => el.name === DrawerState.newBehaviorTree)?.status}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
|
||||
<div>
|
||||
<CoreInput label="Имя дерева" onChange={(text) => store.updateForm({ name: text })} />
|
||||
<CoreSelect
|
||||
items={store.scenes?.map((el) => el.name) ?? []}
|
||||
value={""}
|
||||
label={"Сцена"}
|
||||
onChange={(text) =>
|
||||
store.updateForm({ sceneId: store.scenes?.filter((el) => el.name.isEqual(text)).at(0)?._id })
|
||||
}
|
||||
<CoreModal
|
||||
isOpen={store.isModalOpen}
|
||||
onClose={() => store.modalCancel()}
|
||||
children={
|
||||
<>
|
||||
<div style={{ height: 30 }} />
|
||||
<CoreText
|
||||
text="Создание дерева поведения"
|
||||
type={CoreTextType.header}
|
||||
color={themeStore.theme.white}
|
||||
style={{ textAlignLast: "center" }}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex" }}>
|
||||
<CoreButton text="Сохранить" filled={true} onClick={() => store.createNewBehaviorTree()} />
|
||||
<div style={{ width: 10 }} />
|
||||
<CoreButton text="Отмена" onClick={() => store.editDrawer(DrawerState.newBehaviorTree, false)} />
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
<div style={{ height: 30 }} />
|
||||
<div
|
||||
style={{
|
||||
height: 1,
|
||||
width: "calc(100% - 30px)",
|
||||
backgroundColor: themeStore.theme.outlineVariant,
|
||||
}}
|
||||
/>
|
||||
<div style={{ height: 20 }} />
|
||||
<InputV2 label={"Название"} onChange={(text) => store.updateForm({ name: text })} />
|
||||
<div style={{ height: 20 }} />
|
||||
<InputV2 label={"Описание"} onChange={(text) => store.updateForm({ description: text })} />
|
||||
<div style={{ height: 20 }} />
|
||||
<SelectV2
|
||||
items={store.scenes?.map((el) => ({ name: el.name, value: el._id })) ?? []}
|
||||
initialValue={""}
|
||||
label={"Сцена"}
|
||||
onChange={(value: string) => store.updateForm({ sceneId: value })}
|
||||
/>
|
||||
<div style={{ height: 30 }} />
|
||||
<div
|
||||
style={{
|
||||
height: 1,
|
||||
width: "calc(100% - 30px)",
|
||||
backgroundColor: themeStore.theme.outlineVariant,
|
||||
}}
|
||||
/>
|
||||
<div style={{ display: "flex", paddingTop: 20, justifyContent: "center" }}>
|
||||
<ButtonV2 text="Сохранить" onClick={() => store.saveNewBt()} type={ButtonV2Type.default} />
|
||||
<div style={{ width: 20 }} />
|
||||
<ButtonV2 text="Отменить" onClick={() => store.modalCancel()} type={ButtonV2Type.default} />
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Drawer
|
||||
title={store.titleDrawer}
|
||||
destroyOnClose={true}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import React from "react";
|
||||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { CoreError, UiDrawerFormState } from "../../../core/store/base_store";
|
||||
import {
|
||||
|
@ -18,14 +19,14 @@ 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 React from "react";
|
||||
import { v4 } from "uuid";
|
||||
import { behaviorTreeBuilderStore } from "./behavior_tree_builder_screen";
|
||||
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";
|
||||
import { SceneAsset } from "../../../core/model/scene_asset";
|
||||
import { themeStore } from "../../..";
|
||||
|
||||
interface I2DArea {
|
||||
x: number;
|
||||
|
@ -59,15 +60,14 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
activeProject: string = "";
|
||||
behaviorTreeBuilderHttpRepository = new BehaviorTreeBuilderHttpRepository();
|
||||
canRun = true;
|
||||
shiftIsPressed = false;
|
||||
selected: string = "";
|
||||
selectedSid: string = "";
|
||||
deleteIsPressed = false;
|
||||
nodeBehaviorTree: NodeBehaviorTree[] = [];
|
||||
navigate?: NavigateFunction;
|
||||
editor?: NodeEditor<Schemes>;
|
||||
areaPlugin?: AreaPlugin<Schemes, AreaExtra>;
|
||||
nodeUpdateObserver?: NodeRerenderObserver;
|
||||
isModalOpen: boolean = false;
|
||||
primitiveViewModel: PrimitiveViewModel;
|
||||
skillTree: ISkillView = {
|
||||
name: "",
|
||||
|
@ -75,6 +75,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
{
|
||||
name: "Действия",
|
||||
children: [],
|
||||
isSystem: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -82,10 +83,13 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
constructor() {
|
||||
super(DrawerState);
|
||||
makeAutoObservable(this);
|
||||
this.type = StoreUIType.SelectBehaviorTree;
|
||||
|
||||
this.primitiveViewModel = new PrimitiveViewModel();
|
||||
this.skillTree.children?.push({ name: "Примитивы BT", children: this.primitiveViewModel.toSkillView() });
|
||||
this.skillTree.children?.push({
|
||||
name: "Примитивы BT",
|
||||
children: this.primitiveViewModel.toSkillView(),
|
||||
isSystem: true,
|
||||
});
|
||||
}
|
||||
|
||||
syncScene = async (editor: NodeEditor<Schemes>, area: AreaPlugin<Schemes, AreaExtra>) => {
|
||||
|
@ -140,14 +144,14 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
// eslint-disable-next-line array-callback-return
|
||||
.map((el) => {
|
||||
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<BehaviorTreeView
|
|||
);
|
||||
await this.mapOk("btTreeModels", this.behaviorTreeBuilderHttpRepository.getAllBtInstances());
|
||||
this.navigate = navigate;
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
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<BehaviorTreeView
|
|||
);
|
||||
} else {
|
||||
await this.mapOk("scenes", this.behaviorTreeBuilderHttpRepository.getAllScenes());
|
||||
this.type = StoreUIType.SelectBehaviorTree;
|
||||
// this.type = StoreUIType.SelectBehaviorTree;
|
||||
}
|
||||
};
|
||||
dragZoneSetOffset(offsetTop: number, offsetWidth: number, width: number, height: number) {
|
||||
|
@ -243,32 +228,30 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
validateBt() {}
|
||||
createNewBehaviorTree = async () => {
|
||||
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<BehaviorTreeView
|
|||
<div style={{ width: "100%", display: "flex", flexDirection: "column", alignItems: "flex-start" }}>
|
||||
{this.skillTemplates?.getSkillParams(label).map((el, index) => (
|
||||
<div style={{ display: "flex", flexDirection: "row", width: "100%", marginBottom: 5 }} key={index}>
|
||||
<div style={{ marginRight: 8, padding: 5 }}>IN</div>
|
||||
<div style={{ display: "flex", width: "100%", backgroundColor: "rgba(255, 255, 255, 0.33)", padding: 5 }}>
|
||||
<div
|
||||
style={{
|
||||
width: this.skillTemplates?.getSkillWidthAtLabel(label) * 10,
|
||||
marginRight: 8,
|
||||
padding: 5,
|
||||
color: behaviorTreeBuilderStore.isFilledInput(el.type, sid)
|
||||
? themeStore.theme.onSurface
|
||||
: themeStore.theme.error50,
|
||||
}}
|
||||
>
|
||||
{el.type}
|
||||
{behaviorTreeBuilderStore.isFilledInput(el.type, sid) ? "" : <span style={{ color: "red" }}>*</span>}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
width: 124,
|
||||
backgroundColor: themeStore.theme.outlineVariantDark,
|
||||
padding: 5,
|
||||
borderRadius: "4px 4px 0px 0px",
|
||||
borderBottom: `1px solid ${
|
||||
behaviorTreeBuilderStore.isFilledInput(el.type, sid)
|
||||
? themeStore.theme.onSurface
|
||||
: themeStore.theme.error50
|
||||
}`,
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
))}
|
||||
{this.skillTemplates?.getSkilsOut(label).map((el, index) => (
|
||||
|
||||
{/* {this.skillTemplates?.getSkilsOut(label).map((el, index) => (
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "row", width: "100%", marginBottom: 5, padding: 5 }}
|
||||
key={index}
|
||||
|
@ -321,7 +326,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
{el}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -342,10 +347,6 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
};
|
||||
}
|
||||
getStylesByLabelNode(label: string): React.CSSProperties | undefined {
|
||||
const result = this.primitiveViewModel.getPrimitiveAtLabel(label);
|
||||
if (result) {
|
||||
return clone(result.css as Object);
|
||||
}
|
||||
if (label.isEqual(SystemPrimitive.Fallback)) {
|
||||
return {
|
||||
border: "1px solid #003E61",
|
||||
|
@ -359,10 +360,29 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
background: "rgba(189, 232, 174, 1)",
|
||||
};
|
||||
}
|
||||
return {
|
||||
border: "1px solid rgba(0, 62, 97, 1)",
|
||||
background: "rgba(153, 195, 234, 1)",
|
||||
};
|
||||
return this.filledOutTemplates.getCssAtLabel(label);
|
||||
}
|
||||
changeSceneViewModel = (text: string) => {};
|
||||
modalShow = () => {
|
||||
this.isModalOpen = true;
|
||||
};
|
||||
|
||||
modalCancel = () => {
|
||||
this.isModalOpen = false;
|
||||
};
|
||||
deleteBt = (id: string) => this.behaviorTreeBuilderHttpRepository.deleteBt(id);
|
||||
saveNewBt = async () =>
|
||||
(await this.viewModel.valid<BehaviorTreeViewModel>()).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));
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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; */
|
||||
}
|
||||
|
|
|
@ -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)}
|
||||
`;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<ClassicPreset.Node, ClassicPreset.Connection<ClassicPreset.Node, ClassicPreset.Node>>;
|
||||
export type AreaExtra = ReactArea2D<Schemes>;
|
||||
|
@ -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);
|
||||
|
|
|
@ -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<NodeExtraData & { selected: boolean; styles
|
|||
box-sizing: border-box;
|
||||
width: ${(props) => (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<Scheme extends ClassicScheme>(props: Props<Scheme>)
|
|||
sortByIndex(inputs);
|
||||
sortByIndex(outputs);
|
||||
sortByIndex(controls);
|
||||
behaviorTreeBuilderStore.setSelected(label, selected, id);
|
||||
const refSelect = React.useRef<HTMLDivElement>(null);
|
||||
const refDelete = React.useRef<HTMLDivElement>(null);
|
||||
React.useEffect(() => {
|
||||
refSelect.current?.addEventListener("mouseup", () => behaviorTreeBuilderStore.setSelected(label, selected, id));
|
||||
refDelete.current?.addEventListener("mouseup", () => behaviorTreeBuilderStore.deleteBtAction(id));
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<div style={{ width: "100%" }}>
|
||||
<NodeStyles
|
||||
selected={selected}
|
||||
width={width}
|
||||
|
||||
style={behaviorTreeBuilderStore.getStylesByLabelNode(label)}
|
||||
style={Object.assign({ width: "100%" }, behaviorTreeBuilderStore.getStylesByLabelNode(label))}
|
||||
data-testid="node"
|
||||
className="node"
|
||||
|
||||
id="node"
|
||||
>
|
||||
<div style={{ display: "inline-flex", width: "100%", justifyContent: "space-between" }}>
|
||||
|
@ -147,14 +148,25 @@ export function SequenceNode<Scheme extends ClassicScheme>(props: Props<Scheme>)
|
|||
)
|
||||
)}
|
||||
|
||||
<div
|
||||
style={{ marginTop: 20, marginBottom: 20 }}
|
||||
onPointerDown={(e) => {}}
|
||||
className="title"
|
||||
data-testid="title"
|
||||
>
|
||||
<div>{label}</div>
|
||||
<div>{behaviorTreeBuilderStore.getBodyNode(label,id)}</div>
|
||||
<div style={{ marginTop: 20, marginBottom: 20 }} onPointerDown={(e) => {}} data-testid="title">
|
||||
<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 }} />
|
||||
|
||||
<div ref={refDelete}>
|
||||
<Icon
|
||||
type="Bucket"
|
||||
color={themeStore.theme.onSurfaceVariant}
|
||||
onClick={() => behaviorTreeBuilderStore.deleteBtAction(id)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>{behaviorTreeBuilderStore.getBodyNode(label, id)}</div>
|
||||
</div>
|
||||
{outputs.map(
|
||||
([key, output]) =>
|
||||
|
@ -179,6 +191,6 @@ export function SequenceNode<Scheme extends ClassicScheme>(props: Props<Scheme>)
|
|||
{outputs.isEmpty() ? <div style={{ width: 10 }} /> : null}
|
||||
</div>
|
||||
</NodeStyles>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -15,13 +15,12 @@ export const TopicsForm = observer((props: IPropsForm<Partial<TopicDependencyVie
|
|||
React.useEffect(() => {
|
||||
store.init();
|
||||
store.loadClassInstance(TopicDependencyViewModel, props.dependency as TopicDependencyViewModel);
|
||||
console.log(store.viewModel);
|
||||
}, [props]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<CoreText text={"Topics"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
{match(store.viewModel.mode)
|
||||
{match(store.viewModel?.mode ?? "")
|
||||
.with(StoreTopicType.btExecute, () => (
|
||||
<>
|
||||
<CoreText text={"Выберите точку размещения"} type={CoreTextType.header} />
|
||||
|
|
|
@ -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 ? (
|
||||
<svg
|
||||
style={{ marginRight: 5, width: 8 }}
|
||||
width="12"
|
||||
height="12"
|
||||
viewBox="0 0 12 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M6 12C9.31371 12 12 9.31371 12 6C12 2.68629 9.31371 0 6 0C2.68629 0 0 2.68629 0 6C0 9.31371 2.68629 12 6 12Z"
|
||||
fill="#49454F"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<CoreText text={props.element.name} type={CoreTextType.large} />
|
||||
{props.isBranch ? undefined : ""}
|
||||
<CoreText text={props.element.name} type={CoreTextType.large} color={themeStore.theme.darkOnSurfaceVariant} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -152,7 +152,7 @@ export const SkillsScreen = observer(() => {
|
|||
onClick={() => store.addNewParam(index)}
|
||||
/>
|
||||
{el.param.map((param) => (
|
||||
<div style={{ border: "1px solid", padding: 10, margin: 1 }} onClick={() => store.showModal()}>
|
||||
<div style={{ border: "1px solid", padding: 10, margin: 1 }} onClick={() => store.modalShow()}>
|
||||
<div>{param.type}</div>
|
||||
<div> {JSON.stringify(param.dependency)}</div>
|
||||
</div>
|
||||
|
|
|
@ -27,7 +27,7 @@ export class SkillsStore extends UiDrawerFormState<SkillModel, HttpError> {
|
|||
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<SkillModel, HttpError> {
|
|||
};
|
||||
addNewParam = (index: number) => {
|
||||
this.activeIndex = index;
|
||||
this.showModal();
|
||||
this.modalShow();
|
||||
};
|
||||
onChangeBtDependency = (dependency: Object) =>
|
||||
this.viewModel.BTAction.at(this.activeIndex ?? 0)
|
||||
|
|
|
@ -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(
|
||||
<>
|
||||
<SocketListener>
|
||||
|
@ -22,4 +23,3 @@ root.render(
|
|||
</SocketListener>
|
||||
</>
|
||||
);
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue