This commit is contained in:
IDONTSUDO 2025-01-19 21:37:27 +03:00
parent c2da1d8f4c
commit c2b91ee4d7
23 changed files with 432 additions and 137 deletions

View file

@ -20,6 +20,7 @@
"GLTF",
"grau",
"idontsudo",
"Pids",
"raycaster",
"skils",
"typedataset",

View file

@ -15,12 +15,12 @@
"checkCommand": null,
"filter": null
},
"btBuilderProcess": {
"execCommand": "nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${dir_path}",
"btRuntimeProcess": {
"execCommand": "sleep 4",
"date": null,
"status": null,
"delay": 0,
"checkCommand": null,
"filter": null
}
}
}

View file

@ -2,17 +2,23 @@ import { Disposable, Listener, TypedEvent } from "../helpers/typed_event";
import { GetRootDirUseCase } from "../usecases/get_root_dir_usecase"
import { exec } from 'child_process';
enum ProcessStatus {
export const activeProcessPids: { [name: string]: { pid: number, status: ProcessStatus } } = {}
export enum ProcessStatus {
run = 'run',
endError = 'endError',
endOk = 'endOk',
userDelete = 'userDelete',
}
class ExecutorProgramServiceV2 extends TypedEvent<{ [name: string]: { pid: number, status: ProcessStatus } }> {}
export const executorProgramServiceV2 = new ExecutorProgramServiceV2();
class ProcessData {
log: string | undefined;
status: ProcessStatus;
constructor(log: string | undefined, status: ProcessStatus) {
// console.log(log)
if (log !== undefined) {
this.log = log;
}
@ -29,7 +35,6 @@ export abstract class ExecProcessWatcher extends TypedEvent<ProcessData> impleme
super();
this.on((event) => {
if (event.log !== undefined) {
console.log(event.log)
this.logs.push(event.log);
}
this.status = event.status;
@ -42,17 +47,26 @@ export abstract class ExecProcessWatcher extends TypedEvent<ProcessData> impleme
}
export class ExecProcessScenarioV2 {
call = (command: string, watcher: ExecProcessWatcher): void => {
call = (command: string, watcher: ExecProcessWatcher, name?: string): void => {
const process = exec(command, { cwd: new GetRootDirUseCase().call() });
if (process.pid) {
activeProcessPids[name ?? command] = { pid: process.pid, status: ProcessStatus.run };
executorProgramServiceV2.emit(activeProcessPids);
}
process.stdout.on('data', (data) => watcher.emit(new ProcessData(data, ProcessStatus.run)))
process.stderr.on('data', (data) => watcher.emit(new ProcessData(data, ProcessStatus.run)));
process.on('close', (code) =>{
if(code === 0){
process.on('close', (code) => {
if (code === 0) {
watcher.emit(new ProcessData(undefined, ProcessStatus.endOk))
}else{
activeProcessPids[name ?? command] = { pid: process.pid ?? 0, status: ProcessStatus.endOk }
executorProgramServiceV2.emit(activeProcessPids);
} else {
watcher.emit(new ProcessData(undefined, ProcessStatus.endError))
activeProcessPids[name ?? command] = { pid: process.pid ?? 0, status: ProcessStatus.endError };
executorProgramServiceV2.emit(activeProcessPids);
}
});
process.on('error', (err) => watcher.emit(new ProcessData(err.message, ProcessStatus.endError)));
}
}

View file

@ -7,6 +7,7 @@ import { ExecutorResult } from "../models/executor_result";
import { ExecutorProgramService } from "../services/executor_program_service";
export const executorProgramService = new ExecutorProgramService("");
export class KillLastProcessUseCase extends CallbackStrategyWithEmpty {
call = async (): Promise<Result<undefined, string>> => {
executorProgramService.deleteWorker();

View file

@ -2,12 +2,13 @@ import { IsMongoId, IsNumber, IsString } from "class-validator";
import { IBehaviorTreeModel } from "./behavior_tree_database_model";
export class BehaviorTreeValidationModel implements IBehaviorTreeModel {
_id: string;
@IsString()
public name: string;
@IsMongoId()
public project:string;
public skills:any;
public xml:string;
public project: string;
public skills: any;
public xml: string;
@IsNumber()
public unixTime: number
}

View file

@ -15,6 +15,7 @@ export enum ProcessStatus {
END = "END",
ERROR = "ERROR",
NEW = "NEW",
}
export interface IDatasetModel {
_id?: string;

View file

@ -1,7 +1,53 @@
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
import {
CallbackStrategyWithIdQuery,
CallbackStrategyWithValidationModel,
ResponseBase,
} from "../../../core/controllers/http_controller";
import { StaticFilesProject } from "../../../core/models/static_files";
import {
ExecProcessScenarioV2,
ExecProcessWatcher,
activeProcessPids,
} from "../../../core/scenarios/exec_process_scenario_v2";
import { ReadByIdDataBaseModelScenario } from "../../../core/scenarios/read_by_id_database_model_scenario";
import { SearchOneDataBaseModelUseCase } from "../../../core/usecases/search_database_model_usecase";
import { CoreValidation } from "../../../core/validations/core_validation";
import { MongoIdValidation } from "../../../core/validations/mongo_id_validation";
import { BehaviorTreeDBModel } from "../../behavior_trees/models/behavior_tree_database_model";
import { BehaviorTreeValidationModel } from "../../behavior_trees/models/behavior_tree_validation_model";
import { IProjectModel, ProjectDBModel } from "../../projects/models/project_model_database_model";
import { GetCommandScenario } from "./get_command_scenario";
export class ExecBtBuilderUseCase extends CallbackStrategyWithEmpty {
call(): ResponseBase {
throw new Error("Method not implemented.");
class ProcessWatcher extends ExecProcessWatcher {
async result(): Promise<any> {
console.log(this);
}
}
export enum Proceed {
EXEC_BT = "EXEC_BT",
}
export class ExecBtScenario extends CallbackStrategyWithIdQuery {
idValidationExpression: CoreValidation = new MongoIdValidation();
call = async (id: string): ResponseBase =>
(await new ReadByIdDataBaseModelScenario<BehaviorTreeValidationModel>(BehaviorTreeDBModel).call(id)).map(
async (behaviorTreeValidationModel) =>
(
await new SearchOneDataBaseModelUseCase<IProjectModel>(ProjectDBModel).call(
{ isActive: true },
"no active projects"
)
).map(async (model) =>
(await new GetCommandScenario().call("btRuntimeProcess")).map((execProcessData) =>
new ExecProcessScenarioV2().call(
execProcessData.execCommand.replace(
"${bt_path}",
`${model.rootDir}/${StaticFilesProject.behaviorTrees}/${behaviorTreeValidationModel.name}/bt.xml`
),
new ProcessWatcher(),
Proceed.EXEC_BT
)
)
)
);
}

View file

@ -0,0 +1,7 @@
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
import { Result } from "../../../core/helpers/result";
import { activeProcessPids } from "../../../core/scenarios/exec_process_scenario_v2";
export class GetRunTimeStatuses extends CallbackStrategyWithEmpty {
call = async (): ResponseBase => Result.ok(activeProcessPids);
}

View file

@ -1,10 +0,0 @@
import { CallbackStrategyWithEmpty, ResponseBase } from "../../../core/controllers/http_controller";
import { Result } from "../../../core/helpers/result";
import { SpawnProcessUseCase } from "../../../core/usecases/exec_process_usecase";
import { GetCommandScenario } from "./get_command_scenario";
import { ProcessWatcher } from "../service/process_watcher";
import { App } from "../../../core/controllers/app";
export class GetSimulationStateScenario extends CallbackStrategyWithEmpty {
call = async (): ResponseBase => Result.ok("");
}

View file

@ -0,0 +1,51 @@
import { IsString } from "class-validator";
import { CallbackStrategyWithValidationModel, ResponseBase } from "../../../core/controllers/http_controller";
import { ProcessStatus, activeProcessPids } from "../../../core/scenarios/exec_process_scenario_v2";
import { Result } from "../../../core/helpers/result";
import { GetRootDirUseCase } from "../../../core/usecases/get_root_dir_usecase";
import { exec } from 'child_process';
export class StopProcessModel {
@IsString()
pid: string
}
export class StopProcessUseCase extends CallbackStrategyWithValidationModel<StopProcessModel> {
validationModel: StopProcessModel = new StopProcessModel();
call = async (model: StopProcessModel): ResponseBase => {
try {
if (activeProcessPids[model.pid] === undefined) {
return Result.error('missing pid');
}
const processKillStatus = await new Promise<string>((resolve, reject) => {
try {
exec(`kill ${activeProcessPids[model.pid].pid}`, { cwd: new GetRootDirUseCase().call() }, (error, stdout, stderr) => {
if (error) {
reject(`Ошибка: ${stderr}`); return;
}
if (stderr) {
reject(`Ошибка: ${stderr}`);
return;
}
resolve('Process kill')
});
} catch (e) {
resolve('Process kill')
}
})
if (processKillStatus == 'Process kill') {
activeProcessPids[model.pid].status = ProcessStatus.userDelete;
}
return Result.ok(processKillStatus);
} catch (error) {
return Result.ok(error)
}
}
}

View file

@ -11,4 +11,4 @@ export interface ExecProcess {
delay: number;
checkCommand: null;
filter: null;
}
}

View file

@ -1,42 +1,19 @@
import { CrudController } from "../../core/controllers/crud_controller";
import { ExecRunTimeCommandValidationModel } from "./model/run_time_validation_model";
import { ExecRuntimeDatabaseModel } from "./model/run_time_database_model";
import { CoreHttpController, SubRouter, HttpMethodType, CallbackStrategyWithIdQuery, ResponseBase } from "../../core/controllers/http_controller";
import { ExecBtBuilderUseCase } from "./domain/exec_bt_builder_usecase";
import { ExecSimulationUseCase } from "./domain/exec_simulation_usecase";
import { GetBtBuilderStateUseCase } from "./domain/get_bt_builder_status_usecase";
import { GetSimulationStateScenario } from "./domain/get_simulation_state_usecase";
import { MongoIdValidation } from "../../core/validations/mongo_id_validation";
import { CoreValidation } from "../../core/validations/core_validation";
import { ReadByIdDataBaseModelUseCase } from "../../core/usecases/read_by_id_database_model_usecase";
import { ICalculationInstance, CalculationInstanceDBModel } from "../calculations_instance/models/calculations_instance_database_model";
import { Result } from "../../core/helpers/result";
import { SpawnProcessUseCase } from "../../core/usecases/exec_process_usecase";
import { ProcessWatcher } from "./service/process_watcher";
import { CoreHttpController, SubRouter, CallbackStrategyWithIdQuery } from "../../core/controllers/http_controller";
import { ExecBtScenario } from "./domain/exec_bt_builder_usecase";
import { GetRunTimeStatuses } from "./domain/get_run_time_statuses_usecase";
import { StopProcessUseCase } from "./domain/stop_process_usecase";
class ExecAnalyzeScenario extends CallbackStrategyWithIdQuery {
idValidationExpression: CoreValidation = new MongoIdValidation()
call = async (id: string) =>
(await new ReadByIdDataBaseModelUseCase<ICalculationInstance>(CalculationInstanceDBModel).call(id)).map(async (model) =>
(await new SpawnProcessUseCase().call('/Users/idontsudo/webservice', `nix run github:nixos/nixpkgs#python312Packages.tensorboard -- --logdir ${model.instancePath}`, "", new ProcessWatcher())).map(() => Result.ok('ok'),),
)
}
export class RunTimePresentation extends CrudController<ExecRunTimeCommandValidationModel, any> {
export class RunTimePresentation extends CoreHttpController<ExecRunTimeCommandValidationModel> {
constructor() {
super({
url: "run_time",
});
this.subRoutes.push(new SubRouter("POST", "/exec/bt/builder", new ExecBtBuilderUseCase()));
this.subRoutes.push(new SubRouter("POST", "/get/bt/builder/state", new GetBtBuilderStateUseCase()));
this.subRoutes.push(new SubRouter("POST", "/get/simulator/state", new GetSimulationStateScenario()));
this.subRoutes.push(new SubRouter('POST', "exec/analyze", new ExecAnalyzeScenario()))
this.subRoutes.push({
method: "POST",
subUrl: "/exec/simulation/",
fn: new ExecSimulationUseCase(),
});
this.subRoutes.push(new SubRouter<any>("POST", "exec/bt", new ExecBtScenario()));
this.subRoutes.push(new SubRouter("GET", "status", new GetRunTimeStatuses()));
this.subRoutes.push(new SubRouter<any>("POST", "kill", new StopProcessUseCase()))
}
}

View file

@ -5,10 +5,11 @@ import { extensions } from "./core/extensions/extensions";
import { httpRoutes } from "./core/controllers/routes";
import { executorProgramService } from "./core/usecases/exec_process_usecase";
import { main } from "./p";
import { executorProgramServiceV2 } from "./core/scenarios/exec_process_scenario_v2";
extensions();
const socketSubscribers = [new SocketSubscriber(executorProgramService, "realtime")];
const socketSubscribers = [new SocketSubscriber(executorProgramService, "realtime"), new SocketSubscriber(executorProgramServiceV2, 'realtimeV2',)];
new App(httpRoutes, socketSubscribers).listen();
// main()

View file

@ -1,23 +1,27 @@
import { Socket, io } from "socket.io-client";
import { Result } from "../helper/result";
import { TypedEvent } from "../helper/typed_event";
import { RuntimeModel } from "../../features/behavior_tree_builder/presentation/ui/actions/runtime_actions";
export class SocketRepository extends TypedEvent<any> {
serverURL = "ws://localhost:4001";
socket: Socket | undefined;
async connect():Promise<Result<boolean, boolean>> {
async connect(): Promise<Result<boolean, boolean>> {
const socket = io(this.serverURL);
this.socket = socket;
socket.connect();
socket.on('realtime', (d) =>{
socketCoreInstances.forEach((el) => {
socket.on(el.event, (event) => el.emit(event))
})
socket.on('realtime', (d) => {
this.emit({
event:"realtime",
payload:d
event: "realtime",
payload: d
})
})
if(socket.connected){
if (socket.connected) {
return Result.ok(true)
}
return Result.error(false)
@ -25,4 +29,15 @@ export class SocketRepository extends TypedEvent<any> {
}
export const socketRepository = new SocketRepository()
export const socketRepository = new SocketRepository()
export abstract class SocketCore<T> extends TypedEvent<T> {
abstract event: string
}
export class RunTimeSocketRepository extends SocketCore<RuntimeModel> {
event = 'realtimeV2';
}
export const runTimeSocketRepository = new RunTimeSocketRepository();
const socketCoreInstances: SocketCore<any>[] = [runTimeSocketRepository]

View file

@ -17,6 +17,7 @@ interface IMessage {
errorMessage?: string;
}
export abstract class UiLoader {
navigate?: NavigateFunction;
isLoading = false;
async httpHelper<T>(callBack: Promise<Result<any, T>>) {
this.isLoading = true;
@ -75,7 +76,7 @@ export abstract class UiErrorState<T> extends UiLoader {
console.log(error);
};
abstract init(navigate?: NavigateFunction): Promise<any>;
dispose() {}
dispose() { }
errors: UiBaseError[] = [];
}

View file

@ -931,6 +931,18 @@ const getIconSvg = (
/>
</svg>
);
case "3points":
return Result.ok(
<svg
xmlns="http://www.w3.org/2000/svg"
width={width ? width : "20"}
height={height ? height : "20"}
viewBox="0 0 128 512"
>
<path d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z" />
</svg>
);
case "Move":
return Result.ok(
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" xmlSpace="preserve">

View file

@ -107,7 +107,7 @@ export const MainPageV2: React.FC<{
overflow: "auto",
}}
>
<div
{/* <div
style={{
alignSelf: "center",
width: 645,
@ -222,7 +222,7 @@ export const MainPageV2: React.FC<{
>
{rightChild}
</div>
</div>
</div> */}
<div style={Object.assign({ width: "100%" }, style)}>{children}</div>
</div>

View file

@ -0,0 +1,46 @@
import React, { useEffect, useRef, useState } from "react";
import styled from "styled-components";
interface PopoverProps {
content: React.ReactNode;
children: React.ReactNode;
}
const PopoverV2: React.FC<PopoverProps> = ({ content, children }) => {
const [visible, setVisible] = useState(false);
const ref = useRef<HTMLDivElement>(null);
const togglePopover = () => {
setVisible((prev) => !prev);
};
return (
<div
style={{
position: "relative",
display: "inline-block",
}}
onClick={() => togglePopover()}
>
{children}
<div
style={{
position: "absolute",
backgroundColor: "white",
border: "1px solid #ccc;",
borderRadius: "4px",
padding: "10px;",
zIndex: "1000",
transition: "opacity 0.2s ease, visibility 0.2s ease",
opacity: visible ? 1 : 0,
visibility: visible ? "visible" : "hidden",
}}
>
{content}
</div>
</div>
);
};
// visibility: ${({ visible }) => (visible ? 'visible' : 'hidden')};
// opacity: ${({ visible }) => (visible ? 1 : 0)};
// transition: opacity 0.2s ease, visibility 0.2s ease;
export default PopoverV2;

View file

@ -4,20 +4,15 @@ import { createEditor } from "./ui/editor/editor";
import { SkillTree } from "./ui/skill_tree/skill_tree";
import { BehaviorTreeBuilderStore, DrawerState } from "./behavior_tree_builder_store";
import { observer } from "mobx-react-lite";
import { match } from "ts-pattern";
import { Icon } from "../../../core/ui/icons/icons";
import { CoreText, CoreTextType } from "../../../core/ui/text/text";
import { useNavigate, useParams } from "react-router-dom";
import { IForms, forms } from "./ui/forms/forms";
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 { MainPageV2 } from "../../../core/ui/pages/main_page_v2";
import { DrawerV2 } from "../../../core/ui/drawer/drawer";
import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
import PopoverV2 from "../../../core/ui/popover/popover";
export const behaviorTreeBuilderScreenPath = "behavior/tree/screen/path";
@ -66,54 +61,36 @@ export const BehaviorTreeBuilderScreen = observer(() => {
}, []);
return (
<MainPageV2
rightChild={
<>
<div
style={{
width: "100%",
display: "flex",
flexDirection: "row",
justifyContent: "end",
paddingRight: 30,
alignItems: "center",
}}
>
{/* <ButtonV2 style={{ height: 40 }} onClick={() => {}} text="Запуск" textColor={themeStore.theme.black} />
<div style={{ width: 10 }} />
<ButtonV2
style={{ height: 40 }}
onClick={() => {}}
text="Стоп"
type={ButtonV2Type.empty}
textColor={themeStore.theme.greenWhite}
/>
<div style={{ width: 10 }} /> */}
{store.isNeedSaveBtn ? (
<div
style={{
backgroundColor: store.isNeedSaveBtn ? themeStore.theme.greenWhite : undefined,
height: 40,
textAlign: "center",
alignContent: "center",
width: 40,
borderRadius: 100,
}}
>
{store.isNeedSaveBtn ? (
<Icon style={{ height: 21 }} onClick={() => store.onClickSaveBehaviorTree()} type="Floppy" />
) : undefined}
</div>
) : (
<></>
)}
</div>
</>
}
style={{ position: "absolute", height: "100%", overflow: "hidden" }}
bgColor={themeStore.theme.black}
children={
<>
<>
<div style={{ position: "absolute", zIndex: 100 }}>
<div
style={{
width: "100%",
display: "flex",
flexDirection: "row",
justifyContent: "end",
paddingRight: 30,
alignItems: "center",
}}
>
<div
style={{
backgroundColor: themeStore.theme.greenWhite,
height: 40,
textAlign: "center",
alignContent: "center",
width: 40,
borderRadius: 100,
}}
>
<Icon style={{ height: 21 }} onClick={() => store.onClickSaveBehaviorTree()} type="Floppy" />
</div>
</div>
</div>
<div
style={{
height: "100%",
@ -148,7 +125,7 @@ export const BehaviorTreeBuilderScreen = observer(() => {
width: "calc(100% - 300px)",
}}
>
{/* <PanelGroup direction="horizontal" style={{ width: "100%" }}>
<PanelGroup direction="horizontal" style={{ width: "100%" }}>
<Panel>
<div
ref={ref}
@ -160,18 +137,46 @@ export const BehaviorTreeBuilderScreen = observer(() => {
}}
/>
</Panel>
{store.panels.map((el) => (
{store.panels.map((el, index) => (
<>
<PanelResizeHandle>
<div style={{ width: "100%", color: "white" }}>BANE</div>
<PanelResizeHandle
children={
<>
<div style={{ width: 10, height: "100%", backgroundColor: "beige" }}></div>
</>
}
></PanelResizeHandle>
<Panel
style={{ backgroundColor: "rgb(29, 27, 32)" }}
defaultSize={el.size}
onResize={(size) => store.panelResize(size, index)}
>
<div
style={{ width: 10, height: "100%", backgroundColor: "beige", border: "1px solid black" }}
></div>
</PanelResizeHandle>
<Panel defaultSize={0}> </Panel>
style={{
display: "flex",
width: "100%",
justifyContent: "space-between",
backgroundColor: "beige",
}}
>
<PopoverV2
children={<Icon type={"3points"} height={26} />}
content={
<div style={{ width: "max-content", padding: 10 }}>
{store.panelActions.map((el, i) => (
<CoreText type={CoreTextType.medium} text={el.name} onClick={() => el.action(index)} />
))}
</div>
}
/>
<div style={{ color: "black", alignContent: "center", paddingRight: 10 }}>{el.name}</div>
</div>
{el.body}
</Panel>
</>
))}
</PanelGroup> */}
</PanelGroup>
</div>
</>

View file

@ -26,6 +26,7 @@ import { BehaviorTreeModel } from "../model/behavior_tree_model";
import { PrimitiveViewModel, SystemPrimitive } from "../model/primitive_view_model";
import { SceneAsset } from "../../../core/model/scene_asset";
import { themeStore } from "../../..";
import { RunTimeActions } from "./ui/actions/runtime_actions";
interface I2DArea {
x: number;
@ -37,8 +38,31 @@ interface I2DArea {
export enum DrawerState {
editThreadBehaviorTree = "Редактирование",
}
interface IActionPanel {
name: string;
selectIsClosePopover?: boolean;
action: (index: number) => void;
}
export class PanelBody {
body?: React.ReactNode;
size: number = 0;
name: string = "выберите тип панели";
constructor(body: React.ReactNode | undefined, name: string | undefined, size: number | undefined) {
makeAutoObservable(this);
if (name) this.name = name;
if (body) this.body = body;
if (size) this.size = size;
}
}
export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeViewModel, CoreError> {
panelActions: IActionPanel[] = [
{ name: "Добавить панель", action: () => this.addNewPanel() },
{ name: "Убрать панель", action: (index) => this.removePanel(index) },
{ name: "Runtime", action: (index) => this.changePanel(index, "Runtime", <RunTimeActions />) },
];
sceneAsset?: SceneAsset;
viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty();
behaviorTreeModel: BehaviorTreeModel = BehaviorTreeModel.empty();
@ -51,11 +75,10 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
activeProject: string = "";
behaviorTreeBuilderHttpRepository = new BehaviorTreeBuilderHttpRepository();
canRun = true;
isNeedSaveBtn = false;
isNeedSaveBtn = true;
selected: string = "";
selectedSid: string = "";
nodeBehaviorTree: NodeBehaviorTree[] = [];
navigate?: NavigateFunction;
editor?: NodeEditor<Schemes>;
areaPlugin?: AreaPlugin<Schemes, AreaExtra>;
nodeUpdateObserver?: NodeRerenderObserver;
@ -70,8 +93,12 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
},
],
};
panels = [1, 1, 1, 1];
panels: PanelBody[] = [new PanelBody(<RunTimeActions />, "Runtime", 200)];
addNewPanel = () => this.panels.push(new PanelBody(undefined, undefined, undefined));
removePanel = (index: number) =>
this.panels.length !== 1
? (this.panels = this.panels.filter((_, i) => i !== index))
: message.error("должна быть хоть одна панель");
constructor() {
super(DrawerState);
makeAutoObservable(this);
@ -116,7 +143,7 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
name: name,
id: sid,
});
this.isNeedSaveBtn = true;
// this.isNeedSaveBtn = true;
if (!name.isEqualMany(Object.keys(SystemPrimitive))) {
this.skillTemplates?.getSkill(name).fold(
(skill) => {
@ -346,4 +373,11 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
);
}
changeSceneViewModel = (text: string) => {};
changePanel = (index: number, name: string, body?: React.ReactNode) => {
this.panels = this.panels.replacePropIndex({ name: name, body: body }, index);
};
panelResize = (size: number, index: number) => {
this.panels.replacePropIndex({ size: size }, index);
};
}

View file

@ -0,0 +1,94 @@
import { NavigateFunction, useParams } from "react-router-dom";
import { CoreHttpRepository, HttpMethod } from "../../../../../core/repository/core_http_repository";
import { CoreError, UiErrorState } from "../../../../../core/store/base_store";
import { ProcessStatus } from "../../../../dataset/dataset_model";
import makeAutoObservable from "mobx-store-inheritance";
import { useStore } from "../../../../../core/helper/use_store";
import { Loader } from "../../../../../core/ui/loader/loader";
import { useEffect } from "react";
import {
RunTimeSocketRepository,
runTimeSocketRepository,
} from "../../../../../core/repository/core_socket_repository";
import { observer } from "mobx-react-lite";
interface IPid {
pid: string;
}
export interface RuntimeModel {
[name: string]: { pid: number; status: String };
}
export class RunTimeHttpRepository extends CoreHttpRepository {
feature = "/run_time";
stop = (model: IPid) => this._jsonRequest(HttpMethod.POST, this.feature + "/kill", model);
getStatuses = () => this._jsonRequest<RuntimeModel>(HttpMethod.GET, this.feature + "/status");
execBt = (id: string) => this._jsonRequest(HttpMethod.POST, this.feature + `/exec/bt?id=${id}`);
}
// export class RunTimeSocketRepository extends SockeCore {}
export class RunTimeStore extends UiErrorState<CoreError> {
runTimeHttpRepository: RunTimeHttpRepository = new RunTimeHttpRepository();
runTimeSocketRepository: RunTimeSocketRepository = runTimeSocketRepository;
pageId: string;
runTime?: RuntimeModel = {};
constructor() {
super();
makeAutoObservable(this);
runTimeSocketRepository.on((event) => (console.log(event), (this.runTime = event)));
}
async init(navigate?: NavigateFunction | undefined): Promise<any> {
this.mapOk("runTime", this.runTimeHttpRepository.getStatuses());
this.navigate = navigate;
}
executeBt = () => this.runTimeHttpRepository.execBt(this.pageId);
initParam = (id: string) => (this.pageId = id);
isExecuteBt = (): boolean => {
if (this.runTime === undefined) {
return false;
}
if (
this.runTime["EXEC_BT"] !== undefined &&
this.runTime["EXEC_BT"]["status"] !== undefined &&
this.runTime["EXEC_BT"]["status"] === "endOk"
) {
return false;
}
return true;
};
}
export const RunTimeActions = observer(() => {
const store = useStore(RunTimeStore);
const params = useParams();
useEffect(() => {
store.initParam(params.id as string);
}, []);
return (
<div style={{ width: "100%" }}>
{store.isLoading ? (
<Loader />
) : (
<>
{store.isExecuteBt() ? (
<>
<div
style={{ justifyContent: "center", color: "white", justifySelf: "center" }}
onClick={() => store.executeBt()}
>
Дерево запущено
</div>
</>
) : (
<>
<div
style={{ justifyContent: "center", color: "white", justifySelf: "center" }}
onClick={() => store.executeBt()}
>
Запустить дерево
</div>
</>
)}
</>
)}
</div>
);
});

View file

@ -12,7 +12,6 @@ export enum DrawerState {
}
export class BehaviorTreeManagerStore extends UiDrawerFormState<BehaviorTreeViewModel, CoreError> {
viewModel: BehaviorTreeViewModel = BehaviorTreeViewModel.empty();
navigate?: NavigateFunction;
btTreeModels: BehaviorTreeModel[] = [];
scenes?: SceneModel[];
behaviorTreeManagerHttpRepository = new BehaviorTreeManagerHttpRepository();

View file

@ -26,7 +26,6 @@ export class PoseEstimateRepository extends HttpRepository {
execAnalyze = (id: string) => this._jsonRequest(HttpMethod.POST, `/run_time/exec/analyze?id=${id}`);
}
export class PoseEstimateStore extends UiErrorState<any> {
navigate?: NavigateFunction;
poseEstimateRepository = new PoseEstimateRepository();
constructor() {
super();