alexander
This commit is contained in:
parent
cf75b4220a
commit
7063e93c75
94 changed files with 1201 additions and 24490 deletions
|
@ -1,18 +1,17 @@
|
|||
import { IsNotEmpty } from "class-validator";
|
||||
import { Result } from "../helper/result";
|
||||
import { IDeviceDependency } from "./skill_model";
|
||||
import { ValidationModel } from "./validation_model";
|
||||
|
||||
export class SidViewModel implements IDeviceDependency {
|
||||
sid: string;
|
||||
constructor(sid: string) {
|
||||
this.sid = sid;
|
||||
}
|
||||
valid = (): Result<string, SidViewModel> => {
|
||||
if (this.sid.isEmpty()) {
|
||||
return Result.error('sid is empty')
|
||||
}
|
||||
return Result.ok(this)
|
||||
}
|
||||
static empty() {
|
||||
return new SidViewModel('')
|
||||
}
|
||||
}
|
||||
export class SidViewModel extends ValidationModel implements IDeviceDependency {
|
||||
@IsNotEmpty()
|
||||
sid: string;
|
||||
constructor(sid: string) {
|
||||
super();
|
||||
this.sid = sid;
|
||||
}
|
||||
|
||||
static empty() {
|
||||
return new SidViewModel("");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,8 +186,6 @@ export class CoreThreeRepository extends TypedEvent<any> {
|
|||
);
|
||||
loadUrdfRobot = (robotModel: RobotModel) =>
|
||||
this.urdfLoader.load(robotModel.httpUrl, (robot) => {
|
||||
console.log(robot);
|
||||
// Object3D.DEFAULT_UP = new Vector3(0, 0, 1);
|
||||
robot.userData[UserData.selectedObject] = true;
|
||||
robot.name = robotModel.name;
|
||||
if (robotModel.position) robot.position.copy(robotModel.position);
|
||||
|
|
|
@ -11,6 +11,8 @@ import { SimulationScreen, SimulationScreenPath } from "../../features/simulatio
|
|||
import { EstimateScreen, EstimateScreenPath } from "../../features/estimate/estimate_screen";
|
||||
import { CalculationScreenPath, CalculationScreen } from "../../features/calculation/presentation/calculation_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";
|
||||
|
||||
const idURL = ":id";
|
||||
|
||||
|
@ -59,4 +61,12 @@ export const router = createBrowserRouter([
|
|||
path: CalculationScreenPath,
|
||||
element: <CalculationScreen />,
|
||||
},
|
||||
{
|
||||
path: DigitalTwinsScreenPath,
|
||||
element: <DigitalTwinsScreen />,
|
||||
},
|
||||
{
|
||||
path: TopicsScreenPath,
|
||||
element: <TopicsScreen />,
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -34,14 +34,10 @@ export abstract class UiLoader {
|
|||
abstract errorHandingStrategy: (error?: any) => void;
|
||||
|
||||
mapOk = async <T>(property: string, callBack: Promise<Result<CoreError, T>>) => {
|
||||
return (
|
||||
(await this.httpHelper(callBack))
|
||||
// eslint-disable-next-line array-callback-return
|
||||
.map((el) => {
|
||||
// @ts-ignore
|
||||
this[property] = el;
|
||||
})
|
||||
);
|
||||
return (await this.httpHelper(callBack)).map((el) => {
|
||||
// @ts-ignore
|
||||
this[property] = el;
|
||||
});
|
||||
};
|
||||
messageHttp = async <T>(callBack: Promise<Result<CoreError, T>>, report?: IMessage) => {
|
||||
return (await this.httpHelper(callBack)).fold(
|
||||
|
@ -76,7 +72,6 @@ export class ModalStore extends SimpleErrorState {
|
|||
}
|
||||
export abstract class UiErrorState<T> extends UiLoader {
|
||||
errorHandingStrategy = (error: T) => {
|
||||
// message.error(error as any);
|
||||
console.log(error);
|
||||
};
|
||||
abstract init(navigate?: NavigateFunction): Promise<any>;
|
||||
|
@ -109,10 +104,8 @@ export abstract class DrawerState<E> extends UiErrorState<E> {
|
|||
export abstract class UiDrawerFormState<V, E> extends DrawerState<E> {
|
||||
abstract viewModel: V;
|
||||
updateForm(value: Partial<V>) {
|
||||
// {"id":"123","userId":"132"}
|
||||
//@ts-ignore
|
||||
this.viewModel = Object.assign(this.viewModel, value);
|
||||
console.log(this.viewModel)
|
||||
}
|
||||
loadDependency = (viewModel: V) => {
|
||||
this.viewModel = viewModel;
|
||||
|
@ -120,7 +113,6 @@ export abstract class UiDrawerFormState<V, E> extends DrawerState<E> {
|
|||
loadClassInstance = (instance: ClassConstructor<V>, viewModel: V) => {
|
||||
this.viewModel = plainToInstance(instance, viewModel);
|
||||
};
|
||||
|
||||
}
|
||||
export abstract class FormState<V, E> extends UiErrorState<E> {
|
||||
abstract viewModel: V;
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
{
|
||||
"center_shell": [
|
||||
0,
|
||||
0,
|
||||
0
|
||||
],
|
||||
"scene": {
|
||||
"details": [
|
||||
{
|
||||
"name": "body_down",
|
||||
"part_path": "parts/objects/body_down.stl",
|
||||
"material_path": "",
|
||||
"mass": 100,
|
||||
"inertia": {
|
||||
"ixx": 0.1,
|
||||
"ixy": 0,
|
||||
"ixz": 0,
|
||||
"iyy": 0.1,
|
||||
"iyz": 0,
|
||||
"izz": 0.1
|
||||
},
|
||||
"visual": ".dae",
|
||||
"collision": ".stl",
|
||||
"stlUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/parts/objects/body_down.stl",
|
||||
"glUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.glb",
|
||||
"daeUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.dae",
|
||||
"objUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.obj",
|
||||
"image": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_down.png",
|
||||
"solidType": "active",
|
||||
"isSelect": true
|
||||
},
|
||||
{
|
||||
"name": "sol_gear",
|
||||
"part_path": "parts/objects/sol_gear.stl",
|
||||
"material_path": "",
|
||||
"mass": 100,
|
||||
"inertia": {
|
||||
"ixx": 0.1,
|
||||
"ixy": 0,
|
||||
"ixz": 0,
|
||||
"iyy": 0.1,
|
||||
"iyz": 0,
|
||||
"izz": 0.1
|
||||
},
|
||||
"visual": ".dae",
|
||||
"collision": ".stl",
|
||||
"stlUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/parts/objects/sol_gear.stl",
|
||||
"glUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/sol_gear.glb",
|
||||
"daeUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/sol_gear.dae",
|
||||
"objUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/sol_gear.obj",
|
||||
"image": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/sol_gear.png",
|
||||
"solidType": "active",
|
||||
"isSelect": true
|
||||
},
|
||||
{
|
||||
"name": "output_shaft",
|
||||
"part_path": "parts/objects/output_shaft.stl",
|
||||
"material_path": "",
|
||||
"mass": 100,
|
||||
"inertia": {
|
||||
"ixx": 0.1,
|
||||
"ixy": 0,
|
||||
"ixz": 0,
|
||||
"iyy": 0.1,
|
||||
"iyz": 0,
|
||||
"izz": 0.1
|
||||
},
|
||||
"visual": ".dae",
|
||||
"collision": ".stl",
|
||||
"stlUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/parts/objects/output_shaft.stl",
|
||||
"glUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/output_shaft.glb",
|
||||
"daeUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/output_shaft.dae",
|
||||
"objUrl": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/output_shaft.obj",
|
||||
"image": "http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/output_shaft.png",
|
||||
"solidType": "active",
|
||||
"isSelect": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -38,11 +38,12 @@ export const FormBuilder = observer((props: IFormBuilder) => {
|
|||
<>Error</>
|
||||
) : (
|
||||
<div>
|
||||
{store.formViewModel?.inputs?.map((element) => {
|
||||
{store.formViewModel?.inputs?.map((element,index) => {
|
||||
if (element.type?.isEqual(InputType.ENUM)) {
|
||||
const values = element.values as string[];
|
||||
return (
|
||||
<CoreSelect
|
||||
key={index}
|
||||
items={values}
|
||||
value={element.totalValue ?? element.defaultValue}
|
||||
onChange={(value) => store.changeTotalValue(element.id, value)}
|
||||
|
@ -53,7 +54,7 @@ export const FormBuilder = observer((props: IFormBuilder) => {
|
|||
}
|
||||
if (element.type?.isEqual(InputType.ARRAY)) {
|
||||
return (
|
||||
<div style={{ border: "1px black solid", margin: 20 }}>
|
||||
<div key={index} style={{ border: "1px black solid", margin: 20 }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
|
|
|
@ -47,15 +47,13 @@ export class FormBuilderStore {
|
|||
changeTotalValue(id: string, value: any) {
|
||||
if (this.formViewModel?.inputs)
|
||||
this.formViewModel.inputs = this.formViewModel?.inputs.map((el) => {
|
||||
|
||||
if (!el.id.isEqual(id)) {
|
||||
return el;
|
||||
}
|
||||
|
||||
if (value instanceof String) {
|
||||
if (typeof value === "string") {
|
||||
el.totalValue = value;
|
||||
}else{
|
||||
el.totalValue = JSON.stringify(value)
|
||||
} else {
|
||||
el.totalValue = JSON.stringify(value);
|
||||
}
|
||||
return el;
|
||||
});
|
||||
|
|
|
@ -85,7 +85,6 @@ export class FormViewModel {
|
|||
}
|
||||
public json() {
|
||||
const result = this.toResult();
|
||||
console.log(result)
|
||||
if (result.isEmpty()) {
|
||||
console.log("result is Empty error");
|
||||
return;
|
||||
|
@ -109,6 +108,7 @@ export class FormViewModel {
|
|||
|
||||
this.inputs.forEach((element) => {
|
||||
let inputResult = element.totalValue ?? element.defaultValue;
|
||||
|
||||
if (element.type.isEqualMany([InputType.STRING, InputType.ENUM])) {
|
||||
inputResult = `"${String(inputResult)}"`;
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ export class FormViewModel {
|
|||
inputResult = Number(inputResult);
|
||||
}
|
||||
if (element.type.isEqual(InputType.OBJECT)) {
|
||||
inputResult = element.totalValue ?? element.defaultValue
|
||||
inputResult = element.totalValue ?? JSON.stringify(element.defaultValue);
|
||||
}
|
||||
if (element.type.isEqual(InputType.ARRAY)) {
|
||||
if (element.totalValue === undefined) {
|
||||
|
@ -130,7 +130,6 @@ export class FormViewModel {
|
|||
if (el instanceof Array)
|
||||
el.forEach((subElement) => {
|
||||
let subResult = subElement.totalValue ?? subElement.defaultValue;
|
||||
console.log(subResult);
|
||||
if (subElement.type.isEqualMany([InputType.STRING, InputType.ENUM])) {
|
||||
subResult = `"${String(subResult)}"`;
|
||||
}
|
||||
|
@ -183,8 +182,8 @@ export class FormViewModel {
|
|||
}
|
||||
static fromString(result: string, context: string): Result<void, FormViewModel> {
|
||||
try {
|
||||
if(result.isEmpty() && context.isEmpty()){
|
||||
return Result.error(undefined)
|
||||
if (result.isEmpty() && context.isEmpty()) {
|
||||
return Result.error(undefined);
|
||||
}
|
||||
const enums = new Map<string, string[]>();
|
||||
const types = new Map<string, InputBuilderViewModel[]>();
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Parts } from "../../../../../../features/details/details_http_repositor
|
|||
export class SelectDetailViewModel {
|
||||
details: Parts[];
|
||||
constructor(parts: Parts[]) {
|
||||
console.log(parts)
|
||||
this.details = parts;
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
|
|
@ -1,30 +1,40 @@
|
|||
// @ts-nocheck
|
||||
import React from "react";
|
||||
import { IFormBuilderComponentsProps } from "../../form_builder_components";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { ListItem } from "./ui/list_item";
|
||||
import { SelectDetailStore } from "./select_detail_store";
|
||||
import { SelectDetailViewModel } from "../model/select_details_model";
|
||||
import { plainToInstance } from "class-transformer";
|
||||
|
||||
export const SelectDetail = observer((props: IFormBuilderComponentsProps<SelectDetailViewModel>) => {
|
||||
const [store] = React.useState(() => new SelectDetailStore());
|
||||
|
||||
React.useEffect(() => {
|
||||
store.loadClassInstance(SelectDetailViewModel, props.dependency);
|
||||
store.viewModel = new SelectDetailViewModel(props.dependency.details);
|
||||
store.isLoading = false;
|
||||
console.log(store.viewModel);
|
||||
|
||||
store.init();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{store.parts?.map((el) => {
|
||||
return (
|
||||
<ListItem
|
||||
status={store.viewModel.isSelected(el.name)}
|
||||
name={el.name}
|
||||
imgURL={el.image}
|
||||
onChange={() => (store.viewModel.select(el), props.onChange(store.viewModel.toDependency()))}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{store.isLoading ? (
|
||||
<></>
|
||||
) : (
|
||||
<>
|
||||
{store.parts?.map((el) => {
|
||||
return (
|
||||
<ListItem
|
||||
status={store.viewModel.isSelected(el.name)}
|
||||
name={el.name}
|
||||
imgURL={el.image}
|
||||
onChange={() => (store.viewModel.select(el), props.onChange(store.viewModel.toDependency()))}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -5,13 +5,26 @@ 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;
|
||||
dataSetRepository: DataSetHttpRepository = new DataSetHttpRepository();
|
||||
constructor() {
|
||||
super();
|
||||
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)) {
|
||||
return el.isSelect as boolean;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
init = async () => {
|
||||
await this.mapOk("parts", this.dataSetRepository.getAssetsActiveProject());
|
||||
};
|
||||
|
|
|
@ -47,9 +47,9 @@ export const CoreInput = (props: IInputProps) => {
|
|||
/>
|
||||
|
||||
<div
|
||||
ref={ref}
|
||||
contentEditable={true}
|
||||
defaultValue={props.value}
|
||||
style={{
|
||||
style={{
|
||||
backgroundColor: "#00008000",
|
||||
border: 1,
|
||||
fontSize: isSmall ? 12 : 16,
|
||||
|
|
|
@ -29,7 +29,7 @@ export const CoreSlider = ({
|
|||
<div
|
||||
ref={refSlider}
|
||||
onClick={(event) => {
|
||||
console.log(event)
|
||||
|
||||
}}
|
||||
style={{ width: "100%", height: 11, backgroundColor: "rgba(104, 80, 164, 1)" }}
|
||||
>
|
||||
|
|
|
@ -8,6 +8,7 @@ import { CoreText, CoreTextType } from "../../../core/ui/text/text";
|
|||
import { CoreButton } from "../../../core/ui/button/button";
|
||||
import { CoreInput } from "../../../core/ui/input/input";
|
||||
import { DetailsScreenPath } from "../../details/details_screen";
|
||||
import { DigitalTwinsScreenPath } from "../../digital_twins/digital_twins_screen";
|
||||
|
||||
export const AllProjectScreenPath = "/";
|
||||
export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
||||
|
@ -18,7 +19,6 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
store.init();
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<PreviewPage
|
||||
largeText={"Проекты"}
|
||||
|
@ -29,6 +29,7 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
isLoading={store.isLoading}
|
||||
children={
|
||||
<>
|
||||
<div onClick={() => navigate(DigitalTwinsScreenPath)}>Digital twins</div>
|
||||
{store.projectsModels?.map((el) => {
|
||||
return (
|
||||
<div
|
||||
|
@ -101,4 +102,4 @@ export const AllProjectScreen: React.FunctionComponent = observer(() => {
|
|||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ import { IProjectModel, IProjectView } from "../model/project_model";
|
|||
import { ModalStore } from "../../../core/store/base_store";
|
||||
import { message } from "antd";
|
||||
|
||||
|
||||
|
||||
export class ProjectView {
|
||||
isActive: boolean;
|
||||
description: string;
|
||||
|
|
|
@ -187,7 +187,6 @@ export class BehaviorTreeBuilderStore extends UiDrawerFormState<BehaviorTreeView
|
|||
if (model.skills) this.filledOutTemplates = model.skills;
|
||||
|
||||
await this.mapOk("sceneAsset", this.behaviorTreeBuilderHttpRepository.getSceneAsset(model.sceneId));
|
||||
|
||||
this.isLoading = false;
|
||||
this.reteForceUpdateObserver?.emit("");
|
||||
},
|
||||
|
|
|
@ -1,38 +1,40 @@
|
|||
import React from "react"
|
||||
import { observer } from "mobx-react-lite"
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { message } from "antd";
|
||||
import { CameraDeviceStore } from "./camera_device_store"
|
||||
import { CameraDeviceStore } from "./camera_device_store";
|
||||
import { IPropsForm } from "../forms";
|
||||
import { IDeviceDependency } from "../../../../../../core/model/skill_model";
|
||||
import { CoreButton } from "../../../../../../core/ui/button/button";
|
||||
import { CoreSelect } from "../../../../../../core/ui/select/select";
|
||||
import { CoreText, CoreTextType } from "../../../../../../core/ui/text/text";
|
||||
|
||||
|
||||
|
||||
|
||||
import { SidViewModel } from "../../../../../../core/model/device_dependency_view_model";
|
||||
|
||||
export const CameraDeviceForm = observer((props: IPropsForm<Partial<IDeviceDependency>>) => {
|
||||
const [store] = React.useState(() => new CameraDeviceStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, [store]);
|
||||
return (
|
||||
<div style={{ border: '1px solid', margin: 10, padding: 10 }}>
|
||||
<CoreText text={"Cameras"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
<CoreSelect
|
||||
items={store.cameras?.camera.map((el) => el.sid) ?? []}
|
||||
value={props.dependency?.sid ?? ""}
|
||||
label={'Выберите камеру'}
|
||||
onChange={(value: string) =>
|
||||
store.updateForm({ sid: value })
|
||||
|
||||
} />
|
||||
<CoreButton style={{ margin: 10, width: 100 }} text="OK" onClick={() => {
|
||||
store.viewModel.valid().fold((s) => {
|
||||
props.onChange(s);
|
||||
}, (e) => message.error(e))
|
||||
}} />
|
||||
</div>
|
||||
)
|
||||
})
|
||||
const [store] = React.useState(() => new CameraDeviceStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, [store]);
|
||||
return (
|
||||
<div style={{ border: "1px solid", margin: 10, padding: 10 }}>
|
||||
<CoreText text={"Cameras"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
<CoreSelect
|
||||
items={store.cameras?.camera.map((el) => el.sid) ?? []}
|
||||
value={props.dependency?.sid ?? ""}
|
||||
label={"Выберите камеру"}
|
||||
onChange={(value: string) => store.updateForm({ sid: value })}
|
||||
/>
|
||||
<CoreButton
|
||||
style={{ margin: 10, width: 100 }}
|
||||
text="OK"
|
||||
onClick={async () => {
|
||||
(await store.viewModel.valid<SidViewModel>()).fold(
|
||||
(s) => {
|
||||
props.onChange(s);
|
||||
},
|
||||
(e) => message.error(e)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -16,25 +16,38 @@ export const TopicsForm = observer((props: IPropsForm<Partial<TopicDependencyVie
|
|||
store.init();
|
||||
}, [store, props]);
|
||||
|
||||
return <div style={{ border: '1px solid', margin: 10, padding: 10 }}>
|
||||
<CoreText text={"Topics"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
<CoreSelect
|
||||
items={store.topics?.topics?.map((el) => el.name) ?? []}
|
||||
value={props.dependency?.sid ?? ""}
|
||||
label={'Выберите топик'}
|
||||
onChange={(value: string) =>
|
||||
store.updateForm({ sid: value })
|
||||
} />
|
||||
return (
|
||||
<div style={{ border: "1px solid", margin: 10, padding: 10 }}>
|
||||
<CoreText text={"Topics"} type={CoreTextType.header} style={{ padding: 10 }} />
|
||||
<CoreSelect
|
||||
items={store.topics?.topics?.map((el) => el.name) ?? []}
|
||||
value={props.dependency?.sid ?? ""}
|
||||
label={"Выберите топик"}
|
||||
onChange={(value: string) => store.updateForm({ sid: value })}
|
||||
/>
|
||||
|
||||
<div>is input: <CoreSwitch isSelected={store.viewModel.axis} id={""} onChange={(status: boolean, id: string) => {
|
||||
console.log(200)
|
||||
store.updateForm({ axis: !status })
|
||||
|
||||
}} /></div>
|
||||
<CoreButton style={{ margin: 10, width: 100 }} text="OK" onClick={() => {
|
||||
store.viewModel.valid().fold((s) => {
|
||||
props.onChange(s);
|
||||
}, (e) => message.error(e))
|
||||
}} />
|
||||
</div>;
|
||||
<div>
|
||||
is input:{" "}
|
||||
<CoreSwitch
|
||||
isSelected={store.viewModel.axis}
|
||||
id={""}
|
||||
onChange={(status: boolean, id: string) => {
|
||||
store.updateForm({ axis: !status });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<CoreButton
|
||||
style={{ margin: 10, width: 100 }}
|
||||
text="OK"
|
||||
onClick={async () => {
|
||||
(await store.viewModel.valid<TopicDependencyViewModel>()).fold(
|
||||
(s) => {
|
||||
props.onChange(s);
|
||||
},
|
||||
(e) => message.error(e)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -6,16 +6,22 @@ import { TopicsFormHttpRepository } from "./topics_form_http_repository";
|
|||
import { Topics } from "../../../../../../core/model/topics";
|
||||
|
||||
export class TopicsFormStore extends FormState<TopicDependencyViewModel, CoreError> {
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
topics?: Topics;
|
||||
viewModel: TopicDependencyViewModel = TopicDependencyViewModel.empty();
|
||||
cameraDeviceHttpRepository: TopicsFormHttpRepository = new TopicsFormHttpRepository();
|
||||
errorHandingStrategy = (error: CoreError) => { }
|
||||
init = async (navigate?: NavigateFunction | undefined) => {
|
||||
await this.mapOk('topics', this.cameraDeviceHttpRepository.getAllTopics())
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
topics?: Topics;
|
||||
viewModel: TopicDependencyViewModel = TopicDependencyViewModel.empty();
|
||||
cameraDeviceHttpRepository: TopicsFormHttpRepository = new TopicsFormHttpRepository();
|
||||
errorHandingStrategy = (error: CoreError) => {};
|
||||
init = async (navigate?: NavigateFunction | undefined) => {
|
||||
try {
|
||||
throw new Error('213')
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// await this.mapOk('topics', this.cameraDeviceHttpRepository.getAllTopics())
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { observer } from "mobx-react-lite";
|
||||
import React from "react";
|
||||
|
||||
import { Select, message } from "antd";
|
||||
import { WeightsFormStore } from "./weights_store";
|
||||
import { IWeightsDependency } from "../../../../../../core/model/skill_model";
|
||||
|
@ -47,9 +46,9 @@ export const WeightsForm = observer((props: IWeightsFormProps) => {
|
|||
placeholder="Выберите деталь"
|
||||
optionFilterProp="children"
|
||||
defaultValue={props.dependency?.weights_name}
|
||||
onChange={(e) => {
|
||||
store.updateForm({ weights_name: e });
|
||||
store.updateWeights(e);
|
||||
onChange={(text) => {
|
||||
store.updateForm({ weights_name: text });
|
||||
store.updateWeights(text);
|
||||
}}
|
||||
filterOption={(input: string, option?: { label: string; value: string }) =>
|
||||
(option?.label ?? "").toLowerCase().includes(input.toLowerCase())
|
||||
|
|
|
@ -135,6 +135,7 @@ export class CalculationStore extends UiDrawerFormState<CalculationModel, HttpEr
|
|||
};
|
||||
makeEditProcess = (el: CalculationModel) => {
|
||||
this.editProcess = el;
|
||||
this.loadClassInstance(CalculationModel, el);
|
||||
this.editDrawer(DrawersSkill.EDIT_SKILL, true);
|
||||
};
|
||||
deleteTemplate = async (el: CalculationModel) => {
|
||||
|
|
|
@ -36,19 +36,8 @@ export interface Asset {
|
|||
mesh: string;
|
||||
image: string;
|
||||
}
|
||||
|
||||
export class FormBuilderValidationModel {
|
||||
static vision(): FormBuilderValidationModel {
|
||||
return new FormBuilderValidationModel(
|
||||
`ENUM PRETRAIN = "true","false";`,
|
||||
`{
|
||||
"numberOfEpochs": \${numberOfEpochs:number:10},
|
||||
"selectDataset": \${<SelectDataset/>:OBJECT:{"dataset": {}},
|
||||
"pretrain": \${pretrain:Enum<PRETRAIN>:true}
|
||||
}`,
|
||||
[],
|
||||
''
|
||||
);
|
||||
}
|
||||
public result: string;
|
||||
public context: string;
|
||||
public form: string[];
|
||||
|
@ -59,6 +48,11 @@ export class FormBuilderValidationModel {
|
|||
this.form = form;
|
||||
this.output = output;
|
||||
}
|
||||
static isEmpty = (formBuilderValidationModel: FormBuilderValidationModel) =>
|
||||
formBuilderValidationModel.context.isEmpty() &&
|
||||
formBuilderValidationModel.result.isEmpty() &&
|
||||
formBuilderValidationModel.form.isEmpty();
|
||||
|
||||
static datasetEmpty() {
|
||||
return new FormBuilderValidationModel(datasetFormMockContext, datasetFormMockResult, [], defaultFormValue);
|
||||
}
|
||||
|
@ -71,13 +65,24 @@ export class FormBuilderValidationModel {
|
|||
static creteDataSetTest() {
|
||||
return new FormBuilderValidationModel(``, scene, [], "");
|
||||
}
|
||||
static vision(): FormBuilderValidationModel {
|
||||
return new FormBuilderValidationModel(
|
||||
`ENUM PRETRAIN = "true","false";`,
|
||||
`{
|
||||
"numberOfEpochs": \${numberOfEpochs:number:10},
|
||||
"selectDataset": \${<SelectDataset/>:OBJECT:{"dataset": {}},
|
||||
"pretrain": \${pretrain:Enum<PRETRAIN>:true}
|
||||
}`,
|
||||
[],
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
||||
export const scene = `{
|
||||
"center_shell": [\${CENTER_SHELL_1:number:0}, \${CENTER_SHELL_2:number:0}, \${CENTER_SHELL_3:number:0}],
|
||||
"scene":\${<SelectScene/>:OBJECT:{"details": []}
|
||||
}`;
|
||||
|
||||
// {"name":"body_up","isSelect":true,"part_path":"parts/objects/body_up.stl","material_path":"","inertia":{"ixx":0.1,"ixy":0,"ixz":0,"iyy":0.1,"iyz":0,"izz":0.1},"visual":".dae","collision":".stl","stlUrl":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/parts/objects/body_up.stl","glUrl":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_up.glb","daeUrl":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_up.dae","objUrl":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_up.obj","image":"http://localhost:4001/d370204b-205b-44bb-9698-3bf083b4b7a7/assets/libs/objects/body_up.png","solidType":"active"}
|
||||
export class DataSetModel {
|
||||
dataSetObjects: string[];
|
||||
datasetType: string;
|
||||
|
@ -128,11 +133,12 @@ export class DataSetModel {
|
|||
|
||||
export const datasetTypes = ["Object Detection - YOLOv8", "Pose Estimation - DOPE"];
|
||||
|
||||
export const datasetFormMockResult = `{
|
||||
export const datasetFormMockResult = `
|
||||
{
|
||||
"typedataset": \${typedataset:Enum<T>:ObjectDetection},
|
||||
"models_randomization":{
|
||||
"loc_range_low": [\${LOC_RANGE_LOW_1:number:-1}, \${LOC_RANGE_LOW_2:number:-1},/\${LOC_RANGE_LOW_3:number:0}],
|
||||
"loc_range_high": [\${LOC_RANGE_HIGH_1:number:1}, \${LOC_RANGE_HIGH_2:number:1},/\${LOC_RANGE_HIGH_3:number:2}]
|
||||
"loc_range_low": [\${LOC_RANGE_LOW_1:number:-1}, \${LOC_RANGE_LOW_2:number:-1},\${LOC_RANGE_LOW_3:number:0}],
|
||||
"loc_range_high": [\${LOC_RANGE_HIGH_1:number:1}, \${LOC_RANGE_HIGH_2:number:1},\${LOC_RANGE_HIGH_3:number:2}]
|
||||
},
|
||||
"selectParts":\${<SelectScene/>:OBJECT:{"details": []},
|
||||
"scene":{
|
||||
|
@ -203,3 +209,11 @@ export const defaultFormValue: any = {
|
|||
camera_position: { center_shell: [0, 0, 0], radius_range: [1, 1.4], elevation_range: [10, 90] },
|
||||
generation: { n_cam_pose: 5, n_sample_on_pose: 3, n_series: 100, image_format: "JPEG", image_size_wh: [640, 480] },
|
||||
};
|
||||
|
||||
// `{
|
||||
// "camera_name": \${CAMERA_NAME:string: },
|
||||
// "camera_namespace": \${CAMERA_NAMESPACE:string: },
|
||||
// "staticProp":{
|
||||
// "e23e":""
|
||||
// }
|
||||
// }`;
|
||||
|
|
|
@ -3,6 +3,7 @@ import { EnvelopmentViewModel } from "./envelopment_view_model";
|
|||
export interface Parts {
|
||||
isSelect?: boolean;
|
||||
name: string;
|
||||
mass?:number;
|
||||
part_path: string;
|
||||
material_path: string;
|
||||
stlUrl: string;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { HttpMethod, HttpRepository } from "../../core/repository/core_http_repository";
|
||||
import { UUID } from "../all_projects/data/project_http_repository";
|
||||
import { DigitalTwinsModel } from "./digital_twins_model";
|
||||
|
||||
export class DigitalTwinsHttpRepository extends HttpRepository {
|
||||
featureApi = `/digital/twins/template`;
|
||||
subFeatureApi = `/digital/twins/instance`;
|
||||
getAllDigitalTwinsTemplate = () => this._jsonRequest(HttpMethod.GET, this.featureApi);
|
||||
getAllDigitalTwinsInstance = () => this._jsonRequest(HttpMethod.GET, this.subFeatureApi);
|
||||
createNewDigitalTwinsTemplate = (model: DigitalTwinsModel) =>
|
||||
this._jsonRequest(HttpMethod.POST, this.featureApi, model);
|
||||
createNewDigitalTwinsInstance = (model: DigitalTwinsModel) =>
|
||||
this._jsonRequest<UUID>(HttpMethod.POST, this.subFeatureApi, model);
|
||||
deleteDigitalTwinsTemplate = (id: string) => this._jsonRequest(HttpMethod.DELETE, `${this.featureApi}?id=${id}`);
|
||||
deleteDigitalTwinsInstance = (id: string) => this._jsonRequest(HttpMethod.DELETE, `${this.subFeatureApi}?id=${id}`);
|
||||
execDigitalTwinsInstance = (id: UUID) =>
|
||||
this._jsonRequest(HttpMethod.POST, `${this.subFeatureApi}/exec/instance?id=${id.id}`);
|
||||
}
|
43
ui/src/features/digital_twins/digital_twins_model.ts
Normal file
43
ui/src/features/digital_twins/digital_twins_model.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { ValidationModel } from "../../core/model/validation_model";
|
||||
import { Type } from "class-transformer";
|
||||
import { IsEnum, IsString } from "class-validator";
|
||||
import { FormBuilderValidationModel } from "../dataset/dataset_model";
|
||||
|
||||
export enum DigitalTwinsTypes {
|
||||
CAMERA = "CAMERA",
|
||||
ROBOT = "ROBOT",
|
||||
}
|
||||
export class Interfaces {
|
||||
@IsString()
|
||||
cmd: string;
|
||||
}
|
||||
|
||||
export class DigitalTwinsModel extends ValidationModel {
|
||||
_id?: string;
|
||||
path: string = "";
|
||||
name: string = "";
|
||||
instanceName: string = "";
|
||||
@IsEnum(DigitalTwinsTypes)
|
||||
entity: DigitalTwinsTypes;
|
||||
@IsString()
|
||||
description: string;
|
||||
@IsString()
|
||||
command: string;
|
||||
@Type(() => Interfaces)
|
||||
interfaces: Interfaces;
|
||||
formBuilder = FormBuilderValidationModel.empty();
|
||||
static empty() {
|
||||
return new DigitalTwinsModel();
|
||||
}
|
||||
}
|
||||
export interface DigitalTwinsTemplate {
|
||||
interfaces: Interfaces;
|
||||
_id?: string;
|
||||
path: string;
|
||||
name: string;
|
||||
entity: string;
|
||||
description: string;
|
||||
command: string;
|
||||
__v: string;
|
||||
formBuilder?: FormBuilderValidationModel;
|
||||
}
|
149
ui/src/features/digital_twins/digital_twins_screen.tsx
Normal file
149
ui/src/features/digital_twins/digital_twins_screen.tsx
Normal file
|
@ -0,0 +1,149 @@
|
|||
import React from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { DigitalTwinStoreType, DigitalTwinsStore, DrawersDigitalTwin } from "./digital_twins_store";
|
||||
import { Drawer, Modal } from "antd";
|
||||
import { CoreButton } from "../../core/ui/button/button";
|
||||
import { FormBuilder } from "../../core/ui/form_builder/form_builder";
|
||||
import { CoreInput } from "../../core/ui/input/input";
|
||||
import { CoreSelect } from "../../core/ui/select/select";
|
||||
import { DigitalTwinsModel, DigitalTwinsTypes } from "./digital_twins_model";
|
||||
import { match } from "ts-pattern";
|
||||
|
||||
export const DigitalTwinsScreenPath = "/digital_twins";
|
||||
|
||||
export const DigitalTwinsScreen = observer(() => {
|
||||
const [store] = React.useState(() => new DigitalTwinsStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: "flex" }}>
|
||||
<CoreButton
|
||||
text="Новый шаблон двойника"
|
||||
filled={true}
|
||||
onClick={() => store.editDrawer(DrawersDigitalTwin.newTwinTemplate, true)}
|
||||
/>
|
||||
<CoreButton
|
||||
text="Новый двойник"
|
||||
filled={true}
|
||||
onClick={() => store.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, true)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Drawer
|
||||
width={(window.innerWidth / 100) * 50}
|
||||
title={store.titleDrawer}
|
||||
destroyOnClose={true}
|
||||
onClose={() => {
|
||||
store.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false);
|
||||
store.type = DigitalTwinStoreType.selectTwinTemplate;
|
||||
store.viewModel = DigitalTwinsModel.empty();
|
||||
}}
|
||||
open={store.drawers.find((el) => el.name === DrawersDigitalTwin.newInstanceTwinTemplate)?.status}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
|
||||
{match(store.type)
|
||||
.with(DigitalTwinStoreType.editInstanceTemplate, () => (
|
||||
<>
|
||||
<CoreInput onChange={(text) => store.updateForm({ instanceName: text })} label={"Instance name"} />
|
||||
<FormBuilder
|
||||
formBuilder={store.viewModel.formBuilder}
|
||||
onChange={(change) => store.updateForm({ formBuilder: change })}
|
||||
/>
|
||||
</>
|
||||
))
|
||||
.with(DigitalTwinStoreType.selectTwinTemplate, () => (
|
||||
<>
|
||||
{store.digitalTwinsTemplates?.map((el, i) => (
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
backgroundColor: "rgba(104, 80, 164, 1)",
|
||||
width: 180,
|
||||
height: 180,
|
||||
borderRadius: 10,
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
}}
|
||||
>
|
||||
<div onClick={() => store.deleteDigitalTwinsTemplate(el._id!)}>DELETE</div>
|
||||
<div onClick={() => store.createInstanceTwins(el)}>CREATE</div>
|
||||
{el.name}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
))
|
||||
.otherwise(() => (
|
||||
<></>
|
||||
))}
|
||||
<div style={{ display: "flex" }}>
|
||||
<CoreButton text="Сохранить" filled={true} onClick={() => store.saveInstanceDigitalTwin()} />
|
||||
<div style={{ width: 10 }} />
|
||||
<CoreButton
|
||||
text="Отмена"
|
||||
onClick={() => store.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
|
||||
<Drawer
|
||||
width={(window.innerWidth / 100) * 50}
|
||||
title={store.titleDrawer}
|
||||
destroyOnClose={true}
|
||||
onClose={() => store.editDrawer(DrawersDigitalTwin.newTwinTemplate, false)}
|
||||
open={store.drawers.find((el) => el.name === DrawersDigitalTwin.newTwinTemplate)?.status}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "column", justifyContent: "space-between", height: "100%" }}>
|
||||
<CoreInput onChange={(text) => store.updateForm({ name: text })} label={"Имя"} />
|
||||
<CoreSelect
|
||||
items={Object.keys(DigitalTwinsTypes)}
|
||||
value={Object.keys(DigitalTwinsTypes)[0]}
|
||||
label={"entity"}
|
||||
onChange={(value: string) => store.updateForm({ entity: value as any })}
|
||||
/>
|
||||
<CoreInput onChange={(text) => store.updateForm({ description: text })} label={"Описание"} />
|
||||
<CoreInput onChange={(text) => store.updateForm({ command: text })} label={"Команда"} />
|
||||
<CoreInput onChange={(text) => store.updateForm({ interfaces: { cmd: text } })} label={"Cmd"} />
|
||||
<CoreInput
|
||||
label="FormBuilder Result"
|
||||
onChange={(text) => (store.viewModel.formBuilder.result = text)}
|
||||
style={{ height: 200, overflow: "overlay" }}
|
||||
/>
|
||||
<CoreInput
|
||||
label="FormBuilder Context"
|
||||
onChange={(text) => (store.viewModel.formBuilder.context = text)}
|
||||
style={{ height: 200, overflow: "overlay" }}
|
||||
/>
|
||||
<div style={{ height: 10 }} />
|
||||
<CoreButton
|
||||
style={{ width: 206 }}
|
||||
text={"Посмотреть FormBuilder "}
|
||||
onClick={() => (store.isModalOpen = true)}
|
||||
/>
|
||||
<div style={{ height: 100 }} />
|
||||
|
||||
<div style={{ display: "flex" }}>
|
||||
<CoreButton text="Сохранить" filled={true} onClick={() => store.saveTemplateDigitalTwin()} />
|
||||
<div style={{ width: 10 }} />
|
||||
<CoreButton text="Отмена" onClick={() => store.editDrawer(DrawersDigitalTwin.newTwinTemplate, false)} />
|
||||
</div>
|
||||
</div>
|
||||
</Drawer>
|
||||
|
||||
<Modal
|
||||
destroyOnClose={true}
|
||||
open={store.isModalOpen}
|
||||
footer={null}
|
||||
closable={false}
|
||||
closeIcon={null}
|
||||
onCancel={() => {
|
||||
store.isModalOpen = false;
|
||||
}}
|
||||
>
|
||||
<FormBuilder formBuilder={store.viewModel.formBuilder} onChange={() => {}} />
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
});
|
68
ui/src/features/digital_twins/digital_twins_store.ts
Normal file
68
ui/src/features/digital_twins/digital_twins_store.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { UiDrawerFormState } from "../../core/store/base_store";
|
||||
import { DigitalTwinsModel, DigitalTwinsTemplate as DigitalTwins } from "./digital_twins_model";
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import { message } from "antd";
|
||||
import { DigitalTwinsHttpRepository } from "./digital_twins_http_repository";
|
||||
import { HttpError } from "../../core/repository/core_http_repository";
|
||||
import { match } from "ts-pattern";
|
||||
|
||||
export enum DrawersDigitalTwin {
|
||||
newTwinTemplate = "Новый шаблон двойника",
|
||||
newInstanceTwinTemplate = "Новый инстанц шаблона двойника",
|
||||
}
|
||||
export enum DigitalTwinStoreType {
|
||||
selectTwinTemplate = "selectTwinTemplate",
|
||||
editInstanceTemplate = "editInstanceTemplate",
|
||||
}
|
||||
export class DigitalTwinsStore extends UiDrawerFormState<DigitalTwinsModel, HttpError> {
|
||||
type: DigitalTwinStoreType = DigitalTwinStoreType.selectTwinTemplate;
|
||||
digitalTwinsTemplates?: DigitalTwins[];
|
||||
digitalTwinsInstances?: DigitalTwins[];
|
||||
digitalTwinsHttpRepository: DigitalTwinsHttpRepository = new DigitalTwinsHttpRepository();
|
||||
viewModel: DigitalTwinsModel = DigitalTwinsModel.empty();
|
||||
isModalOpen: boolean = false;
|
||||
init = async (_navigate?: NavigateFunction | undefined): Promise<any> => this.refresh();
|
||||
constructor() {
|
||||
super(DrawersDigitalTwin);
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
refresh = async () => {
|
||||
this.mapOk("digitalTwinsTemplates", this.digitalTwinsHttpRepository.getAllDigitalTwinsTemplate());
|
||||
this.mapOk("digitalTwinsInstances", this.digitalTwinsHttpRepository.getAllDigitalTwinsInstance());
|
||||
};
|
||||
saveInstanceDigitalTwin = async () =>
|
||||
match(this.type)
|
||||
.with(DigitalTwinStoreType.editInstanceTemplate, async () => {
|
||||
|
||||
this.viewModel._id = undefined;
|
||||
(await this.digitalTwinsHttpRepository.createNewDigitalTwinsInstance(this.viewModel)).map(async (id) => {
|
||||
await this.digitalTwinsHttpRepository.execDigitalTwinsInstance(id);
|
||||
await this.refresh();
|
||||
});
|
||||
this.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false);
|
||||
})
|
||||
.with(DigitalTwinStoreType.selectTwinTemplate, () => {
|
||||
console.log(200);
|
||||
|
||||
// this.editDrawer(DrawersDigitalTwin.newInstanceTwinTemplate, false),
|
||||
// await (
|
||||
// await this.digitalTwinsHttpRepository.createNewDigitalTwinsInstance(this.viewModel)
|
||||
// ).map(() => this.refresh())
|
||||
});
|
||||
createInstanceTwins = (el: DigitalTwins): void => {
|
||||
this.loadDependency(el as any);
|
||||
this.type = DigitalTwinStoreType.editInstanceTemplate;
|
||||
};
|
||||
saveTemplateDigitalTwin = async () =>
|
||||
(await this.viewModel.valid<DigitalTwinsModel>()).fold(
|
||||
async (model) => {
|
||||
(await this.digitalTwinsHttpRepository.createNewDigitalTwinsTemplate(model)).map(() => {
|
||||
this.refresh();
|
||||
});
|
||||
},
|
||||
async (e) => message.error(e)
|
||||
);
|
||||
deleteDigitalTwinsTemplate = async (id: string) =>
|
||||
(await this.digitalTwinsHttpRepository.deleteDigitalTwinsTemplate(id)).map(() => this.refresh());
|
||||
}
|
|
@ -88,3 +88,4 @@ export class RobotFormStore extends FormState<RobotModel, CoreError> {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
12
ui/src/features/topics/topic_view_model.ts
Normal file
12
ui/src/features/topics/topic_view_model.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { ValidationModel } from "../../core/model/validation_model";
|
||||
|
||||
export class TopicViewModel extends ValidationModel {
|
||||
static empty() {
|
||||
return new TopicViewModel();
|
||||
}
|
||||
}
|
||||
export interface ITopicModel {
|
||||
digitalTwinId?: string;
|
||||
name: string;
|
||||
type: string;
|
||||
}
|
5
ui/src/features/topics/topics_repository.ts
Normal file
5
ui/src/features/topics/topics_repository.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { HttpMethod, HttpRepository } from "../../core/repository/core_http_repository";
|
||||
|
||||
export class TopicsHttpRepository extends HttpRepository {
|
||||
getAllTopics = () => this._jsonRequest(HttpMethod.GET, "/topics");
|
||||
}
|
22
ui/src/features/topics/topics_screen.tsx
Normal file
22
ui/src/features/topics/topics_screen.tsx
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { observer } from "mobx-react-lite";
|
||||
import { TopicsStore } from "./topics_store";
|
||||
import React from "react";
|
||||
|
||||
export const TopicsScreenPath = "/topics";
|
||||
|
||||
export const TopicsScreen = observer(() => {
|
||||
const [store] = React.useState(() => new TopicsStore());
|
||||
React.useEffect(() => {
|
||||
store.init();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
{store.topics?.map((el) => (
|
||||
<div>
|
||||
<div>{el.name}</div>
|
||||
<div>{el.type}</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
});
|
19
ui/src/features/topics/topics_store.ts
Normal file
19
ui/src/features/topics/topics_store.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import makeAutoObservable from "mobx-store-inheritance";
|
||||
import { FormState } from "../../core/store/base_store";
|
||||
import { HttpError } from "../../core/repository/core_http_repository";
|
||||
import { ITopicModel, TopicViewModel as TopicModel } from "./topic_view_model";
|
||||
import { NavigateFunction } from "react-router-dom";
|
||||
import { TopicsHttpRepository } from "./topics_repository";
|
||||
|
||||
export class TopicsStore extends FormState<TopicModel, HttpError> {
|
||||
viewModel: TopicModel = TopicModel.empty();
|
||||
topics?: ITopicModel[];
|
||||
topicsHttpRepository: TopicsHttpRepository = new TopicsHttpRepository();
|
||||
constructor() {
|
||||
super();
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
init = async (navigate?: NavigateFunction | undefined) => {
|
||||
await this.mapOk("topics", this.topicsHttpRepository.getAllTopics());
|
||||
};
|
||||
}
|
|
@ -22,4 +22,3 @@ root.render(
|
|||
</SocketLister>
|
||||
</>
|
||||
);
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue