progress
This commit is contained in:
parent
c2da1d8f4c
commit
c2b91ee4d7
23 changed files with 432 additions and 137 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -20,6 +20,7 @@
|
|||
"GLTF",
|
||||
"grau",
|
||||
"idontsudo",
|
||||
"Pids",
|
||||
"raycaster",
|
||||
"skils",
|
||||
"typedataset",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ export enum ProcessStatus {
|
|||
END = "END",
|
||||
ERROR = "ERROR",
|
||||
NEW = "NEW",
|
||||
|
||||
}
|
||||
export interface IDatasetModel {
|
||||
_id?: string;
|
||||
|
|
|
@ -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
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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("");
|
||||
}
|
51
server/src/features/runtime/domain/stop_process_usecase.ts
Normal file
51
server/src/features/runtime/domain/stop_process_usecase.ts
Normal 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)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -11,4 +11,4 @@ export interface ExecProcess {
|
|||
delay: number;
|
||||
checkCommand: null;
|
||||
filter: null;
|
||||
}
|
||||
}
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
|
@ -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]
|
|
@ -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[] = [];
|
||||
}
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
46
ui/src/core/ui/popover/popover.tsx
Normal file
46
ui/src/core/ui/popover/popover.tsx
Normal 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;
|
|
@ -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>
|
||||
</>
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
});
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue