2024-05-29 15:38:36 +03:00
|
|
|
|
import { IsArray, IsOptional, IsString, ValidateNested } from "class-validator";
|
2024-04-23 15:56:52 +03:00
|
|
|
|
import { Type } from "class-transformer";
|
|
|
|
|
import { ISkillView } from "../../features/behavior_tree_builder/presentation/ui/skill_tree/skill_tree";
|
|
|
|
|
import { v4 } from "uuid";
|
2024-05-29 15:38:36 +03:00
|
|
|
|
import { Result } from "../helper/result";
|
|
|
|
|
import clone from "just-clone";
|
2024-04-23 15:56:52 +03:00
|
|
|
|
|
2024-05-29 15:38:36 +03:00
|
|
|
|
export interface IDependency {
|
|
|
|
|
skills: ISkillDependency[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ISkillDependency {
|
|
|
|
|
sid: string;
|
|
|
|
|
dependency: Object;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ISkill {
|
|
|
|
|
sid?: string;
|
2024-04-23 15:56:52 +03:00
|
|
|
|
SkillPackage: ISkillPackage;
|
|
|
|
|
Module: IModule;
|
|
|
|
|
Launch: ILaunch;
|
|
|
|
|
ROS2: IRos2;
|
|
|
|
|
BTAction: IBTAction[];
|
|
|
|
|
Interface: IInterface;
|
|
|
|
|
Settings: ISetting[];
|
|
|
|
|
xxx: IXxx;
|
|
|
|
|
}
|
2024-05-13 20:43:11 +03:00
|
|
|
|
export interface IWeightsDependency {
|
2024-06-10 15:16:30 +03:00
|
|
|
|
weights_name: string;
|
2024-05-29 15:38:36 +03:00
|
|
|
|
object_name: string;
|
|
|
|
|
weights_file: string;
|
|
|
|
|
dimensions: number[];
|
2024-05-13 20:43:11 +03:00
|
|
|
|
}
|
2024-06-10 15:16:30 +03:00
|
|
|
|
export interface IDeviceDependency {
|
|
|
|
|
sid: string;
|
|
|
|
|
}
|
2024-04-23 15:56:52 +03:00
|
|
|
|
|
2024-05-13 20:43:11 +03:00
|
|
|
|
export interface IParam {
|
|
|
|
|
type: string;
|
2024-05-29 15:38:36 +03:00
|
|
|
|
dependency: Object;
|
2024-05-13 20:43:11 +03:00
|
|
|
|
}
|
2024-04-23 15:56:52 +03:00
|
|
|
|
export interface IBTAction {
|
|
|
|
|
name: string;
|
|
|
|
|
format: string;
|
2024-05-29 15:38:36 +03:00
|
|
|
|
// TODO: Нужно выпилить его отсюда
|
|
|
|
|
// sid?: string;
|
2024-04-23 15:56:52 +03:00
|
|
|
|
type: string;
|
2024-05-13 20:43:11 +03:00
|
|
|
|
param: IParam[];
|
2024-04-23 15:56:52 +03:00
|
|
|
|
result: string[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface IInterface {
|
|
|
|
|
Input: IPut[];
|
|
|
|
|
Output: IPut[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface IPut {
|
|
|
|
|
name: string;
|
|
|
|
|
type: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ILaunch {
|
|
|
|
|
executable: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface IModule {
|
|
|
|
|
name: string;
|
|
|
|
|
description: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface IRos2 {
|
|
|
|
|
node_name: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ISetting {
|
|
|
|
|
name: string;
|
|
|
|
|
value: number | string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ISkillPackage {
|
|
|
|
|
name: string;
|
|
|
|
|
version: string;
|
|
|
|
|
format: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface IXxx {
|
|
|
|
|
cameraLink: string;
|
|
|
|
|
topicImage: string;
|
|
|
|
|
topicCameraInfo: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class SkillPackage implements ISkillPackage {
|
|
|
|
|
@IsString()
|
|
|
|
|
name: string;
|
|
|
|
|
@IsString()
|
|
|
|
|
version: string;
|
|
|
|
|
@IsString()
|
|
|
|
|
format: string;
|
|
|
|
|
}
|
|
|
|
|
export class Module implements IModule {
|
|
|
|
|
@IsString()
|
|
|
|
|
name: string;
|
|
|
|
|
@IsString()
|
|
|
|
|
description: string;
|
|
|
|
|
}
|
|
|
|
|
export class BTAction implements IBTAction {
|
|
|
|
|
@IsString()
|
|
|
|
|
name: string;
|
|
|
|
|
@IsString()
|
|
|
|
|
format: string;
|
|
|
|
|
@IsString()
|
|
|
|
|
type: string;
|
2024-05-29 15:38:36 +03:00
|
|
|
|
sid?: string;
|
2024-04-23 15:56:52 +03:00
|
|
|
|
@IsArray()
|
2024-05-13 20:43:11 +03:00
|
|
|
|
param: IParam[];
|
2024-04-23 15:56:52 +03:00
|
|
|
|
@IsArray()
|
|
|
|
|
result: string[];
|
|
|
|
|
}
|
|
|
|
|
export class Launch implements ILaunch {
|
|
|
|
|
@IsString()
|
|
|
|
|
executable: string;
|
|
|
|
|
}
|
|
|
|
|
export class Ros2 implements IRos2 {
|
|
|
|
|
@IsString()
|
|
|
|
|
node_name: string;
|
|
|
|
|
}
|
|
|
|
|
export class Put implements IPut {
|
|
|
|
|
@IsString()
|
|
|
|
|
name: string;
|
|
|
|
|
@IsString()
|
|
|
|
|
type: string;
|
|
|
|
|
}
|
|
|
|
|
export class Interface implements IInterface {
|
|
|
|
|
@ValidateNested()
|
|
|
|
|
@Type(() => Put)
|
|
|
|
|
Input: IPut[];
|
|
|
|
|
@ValidateNested()
|
|
|
|
|
@Type(() => Put)
|
|
|
|
|
Output: IPut[];
|
|
|
|
|
}
|
|
|
|
|
export class Setting implements ISetting {
|
|
|
|
|
name: string;
|
|
|
|
|
value: string | number;
|
|
|
|
|
}
|
|
|
|
|
export class Xxx implements IXxx {
|
|
|
|
|
cameraLink: string;
|
|
|
|
|
topicImage: string;
|
|
|
|
|
topicCameraInfo: string;
|
|
|
|
|
}
|
2024-05-29 15:38:36 +03:00
|
|
|
|
export class SkillModel implements ISkill {
|
|
|
|
|
@IsOptional()
|
|
|
|
|
@IsString()
|
|
|
|
|
sid?: string;
|
2024-04-23 15:56:52 +03:00
|
|
|
|
@ValidateNested()
|
|
|
|
|
@Type(() => SkillPackage)
|
|
|
|
|
SkillPackage: ISkillPackage;
|
|
|
|
|
@ValidateNested()
|
|
|
|
|
@Type(() => Module)
|
|
|
|
|
Module: IModule;
|
|
|
|
|
@ValidateNested()
|
|
|
|
|
@Type(() => Launch)
|
|
|
|
|
Launch: ILaunch;
|
|
|
|
|
@ValidateNested()
|
|
|
|
|
@Type(() => Ros2)
|
|
|
|
|
ROS2: IRos2;
|
|
|
|
|
@ValidateNested()
|
|
|
|
|
@IsArray()
|
|
|
|
|
@Type(() => BTAction)
|
|
|
|
|
BTAction: IBTAction[];
|
|
|
|
|
@ValidateNested()
|
|
|
|
|
@Type(() => Interface)
|
|
|
|
|
Interface: IInterface;
|
|
|
|
|
@ValidateNested()
|
|
|
|
|
@IsArray()
|
|
|
|
|
@Type(() => Setting)
|
|
|
|
|
Settings: ISetting[];
|
|
|
|
|
@ValidateNested()
|
|
|
|
|
@Type(() => Xxx)
|
|
|
|
|
xxx: IXxx;
|
2024-05-29 15:38:36 +03:00
|
|
|
|
static empty() {
|
|
|
|
|
const skillModel = new SkillModel();
|
|
|
|
|
skillModel.BTAction = [];
|
|
|
|
|
return skillModel;
|
|
|
|
|
}
|
|
|
|
|
public static isEmpty(skill: SkillModel): Result<void, SkillModel> {
|
|
|
|
|
if (skill.BTAction.isEmpty()) {
|
|
|
|
|
return Result.error(undefined);
|
|
|
|
|
}
|
|
|
|
|
return Result.ok(Object.assign(skill, {}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getSid = () => this.sid;
|
|
|
|
|
public setSid = (sid: string) => {
|
|
|
|
|
const result = clone(this);
|
|
|
|
|
result.sid = sid;
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class SkillDependency implements IDependency {
|
2024-06-10 15:16:30 +03:00
|
|
|
|
constructor(public skills: ISkillDependency[]) { }
|
2024-05-29 15:38:36 +03:00
|
|
|
|
static empty() {
|
|
|
|
|
return new SkillDependency([]);
|
|
|
|
|
}
|
|
|
|
|
static isEmpty = (skill: SkillDependency) => {
|
|
|
|
|
if (skill.skills.isEmpty()) {
|
|
|
|
|
return Result.error(undefined);
|
|
|
|
|
}
|
|
|
|
|
return Result.ok(skill);
|
|
|
|
|
};
|
2024-04-23 15:56:52 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class Skills {
|
|
|
|
|
@IsArray()
|
2024-05-29 15:38:36 +03:00
|
|
|
|
@Type(() => SkillModel)
|
|
|
|
|
skills: SkillModel[];
|
|
|
|
|
validation = (): Result<string[], void> => {
|
|
|
|
|
const errors: string[] = [];
|
|
|
|
|
this.skills.forEach((skill) => {
|
|
|
|
|
skill.BTAction.forEach((action) => {
|
|
|
|
|
if (action.param.isNotEmpty()) {
|
|
|
|
|
action.param.forEach((param) => {
|
|
|
|
|
if (Object.keys(param.dependency).isEmpty()) {
|
|
|
|
|
errors.push(param.type);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
if (errors.isNotEmpty()) {
|
|
|
|
|
return Result.error(errors);
|
|
|
|
|
}
|
|
|
|
|
return Result.ok(undefined);
|
|
|
|
|
};
|
|
|
|
|
skillBySid = (sid: string) =>
|
|
|
|
|
SkillModel.isEmpty(
|
|
|
|
|
this.skills.reduce<SkillModel>((acc, el) => {
|
|
|
|
|
if (el.sid?.isEqual(sid)) {
|
|
|
|
|
acc = el;
|
|
|
|
|
}
|
|
|
|
|
return acc;
|
|
|
|
|
}, SkillModel.empty())
|
|
|
|
|
);
|
|
|
|
|
|
2024-05-13 20:43:11 +03:00
|
|
|
|
toSkillView = (): ISkillView[] =>
|
|
|
|
|
this.skills.map((el) => {
|
2024-04-23 15:56:52 +03:00
|
|
|
|
return {
|
|
|
|
|
name: el.Module.name,
|
|
|
|
|
children: el.BTAction.map((act) => {
|
|
|
|
|
return { name: act.name, uuid: v4() };
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
});
|
2024-05-29 15:38:36 +03:00
|
|
|
|
getSkill = (name: string) =>
|
|
|
|
|
SkillModel.isEmpty(
|
|
|
|
|
this.skills.reduce<SkillModel>((acc, el) => {
|
|
|
|
|
if (el.BTAction.find((el) => el.name.isEqual(name))) {
|
|
|
|
|
el.BTAction.map((action) => {
|
|
|
|
|
action.param.map((param) => {
|
|
|
|
|
return param;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
acc = el;
|
|
|
|
|
}
|
|
|
|
|
return acc;
|
|
|
|
|
}, SkillModel.empty())
|
|
|
|
|
);
|
2024-05-13 20:43:11 +03:00
|
|
|
|
|
|
|
|
|
getSkilsOut = (name: string) =>
|
|
|
|
|
this.skills
|
|
|
|
|
.reduce<string[][]>((acc, el) => {
|
|
|
|
|
if (el.BTAction.find((el) => el.name.isEqual(name))) {
|
|
|
|
|
acc = el.BTAction.filter((f) => f.name.isEqual(name)).map((z) => z.result);
|
|
|
|
|
}
|
|
|
|
|
return acc;
|
|
|
|
|
}, [])
|
|
|
|
|
.flat(1);
|
|
|
|
|
getSkillParams = (name: string) =>
|
|
|
|
|
this.skills
|
|
|
|
|
.reduce<IParam[][]>((acc, el) => {
|
|
|
|
|
if (el.BTAction.find((el) => el.name.isEqual(name))) {
|
|
|
|
|
acc = el.BTAction.filter((f) => f.name.isEqual(name)).map((z) => z.param);
|
|
|
|
|
}
|
|
|
|
|
return acc;
|
|
|
|
|
}, [])
|
|
|
|
|
.flat(1);
|
|
|
|
|
getSkillDo = (name: string) =>
|
|
|
|
|
this.skills.reduce((acc, el) => {
|
2024-04-23 15:56:52 +03:00
|
|
|
|
if (el.BTAction.find((el) => el.name.isEqual(name))) {
|
|
|
|
|
acc = el.Module.name;
|
|
|
|
|
}
|
|
|
|
|
return acc;
|
|
|
|
|
}, "error");
|
2024-05-13 20:43:11 +03:00
|
|
|
|
|
|
|
|
|
getSkillsNames = () =>
|
|
|
|
|
this.skills
|
2024-04-23 15:56:52 +03:00
|
|
|
|
.map((el) => {
|
|
|
|
|
return el.BTAction.map((act) => {
|
|
|
|
|
return { name: act.name };
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.flat(1);
|
2024-05-13 20:43:11 +03:00
|
|
|
|
|
|
|
|
|
getForms = (skillLabel: string) =>
|
|
|
|
|
this.skills
|
2024-05-29 15:38:36 +03:00
|
|
|
|
.reduce<SkillModel[]>((acc, el) => {
|
2024-05-13 20:43:11 +03:00
|
|
|
|
if (el.BTAction.find((el) => el.name.isEqual(skillLabel))) {
|
|
|
|
|
acc.push(el);
|
|
|
|
|
}
|
|
|
|
|
return acc;
|
|
|
|
|
}, [])
|
|
|
|
|
.map((el) => el.BTAction.map((act) => act.param.map((el) => el.type).flat(1)))
|
|
|
|
|
.flat(1)
|
|
|
|
|
.flat(1)
|
|
|
|
|
.filter((el) => el !== "");
|
2024-05-29 15:38:36 +03:00
|
|
|
|
|
|
|
|
|
getDependencyBySkillLabelAndType = <T>(skillType: string, sid: string) =>
|
2024-05-13 20:43:11 +03:00
|
|
|
|
this.skills
|
2024-05-29 15:38:36 +03:00
|
|
|
|
.reduce<Object[]>((acc, skill) => {
|
|
|
|
|
if (skill.sid?.isEqual(sid)) {
|
|
|
|
|
skill.BTAction.map((action) => {
|
|
|
|
|
action.param.map((param) => {
|
|
|
|
|
if (param.type.isEqual(skillType)) {
|
|
|
|
|
acc.push(param.dependency);
|
|
|
|
|
}
|
|
|
|
|
return param;
|
|
|
|
|
});
|
|
|
|
|
return action;
|
|
|
|
|
});
|
2024-05-13 20:43:11 +03:00
|
|
|
|
}
|
2024-05-29 15:38:36 +03:00
|
|
|
|
|
2024-05-13 20:43:11 +03:00
|
|
|
|
return acc;
|
|
|
|
|
}, [])
|
|
|
|
|
.at(0) as T;
|
2024-05-29 15:38:36 +03:00
|
|
|
|
static isEmpty(model: Skills): Result<void, void> {
|
|
|
|
|
if (model.skills.isEmpty()) {
|
|
|
|
|
return Result.error(undefined);
|
|
|
|
|
}
|
|
|
|
|
return Result.ok(undefined);
|
|
|
|
|
}
|
|
|
|
|
static empty() {
|
|
|
|
|
const skills = new Skills();
|
|
|
|
|
skills.skills = [];
|
|
|
|
|
return skills;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public dependencyIsFilled = (skillType: string, sid: string) =>
|
|
|
|
|
this.skills.reduce((acc, skill) => {
|
|
|
|
|
if (skill.sid?.isEqual(sid)) {
|
|
|
|
|
skill.BTAction.forEach((action) => {
|
|
|
|
|
action.param.forEach((param) => {
|
|
|
|
|
if (param.type.isEqual(skillType)) {
|
|
|
|
|
// console.log('SKILL TYPE')
|
|
|
|
|
// console.log(skillType);
|
|
|
|
|
// console.log("SID")
|
|
|
|
|
// console.log(sid)
|
|
|
|
|
// console.log("DEPENDENCY")
|
|
|
|
|
// console.log(param.dependency)
|
|
|
|
|
acc = Object.keys(param.dependency).isNotEmpty();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
|
}, false);
|
|
|
|
|
|
|
|
|
|
getAllSids = () =>
|
|
|
|
|
this.skills.reduce((acc, skill) => {
|
|
|
|
|
skill.BTAction.forEach((action) =>
|
|
|
|
|
action.param.forEach((param) => {
|
|
|
|
|
// acc.incrementValue(param.sid ?? "empty");
|
|
|
|
|
return param;
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
return acc;
|
|
|
|
|
}, new Map<string, number>());
|
|
|
|
|
|
|
|
|
|
deleteSid(sid: string): SkillModel[] {
|
|
|
|
|
return this.skills.filter((skill) => !skill.sid?.isEqual(sid));
|
|
|
|
|
}
|
|
|
|
|
updateSkill = (skill: SkillModel) => {
|
|
|
|
|
console.log(skill);
|
|
|
|
|
this.skills = this.skills.map((el) => {
|
|
|
|
|
if (el.sid?.isEqual(skill.sid ?? "")) {
|
|
|
|
|
el = skill;
|
|
|
|
|
}
|
|
|
|
|
return el;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
skillHasForm = (label: string): boolean => {
|
|
|
|
|
// TODO:NEED IMPLEMENTS
|
|
|
|
|
return true;
|
|
|
|
|
};
|
2024-04-23 15:56:52 +03:00
|
|
|
|
}
|