UI: tagList, tagConfirm

This commit is contained in:
Patrick Haßel 2024-11-29 09:43:36 +01:00
parent dc6d19a633
commit a9394efc11
12 changed files with 50 additions and 21 deletions

View File

@ -1,7 +1,8 @@
import {Property} from "../Property/Property"; import {Property} from "../Property/Property";
import {orNull, validateString} from "../api/validators"; import {orNull, validateList, validateString} from "../api/validators";
import {Area} from '../Area/Area'; import {Area} from '../Area/Area';
import {Thing} from '../Thing/Thing'; import {Thing} from '../Thing/Thing';
import {Tag} from '../Tag/Tag';
export class Device extends Thing { export class Device extends Thing {
@ -10,10 +11,11 @@ export class Device extends Thing {
uuid: string, uuid: string,
name: string, name: string,
slug: string, slug: string,
tagList: Tag[],
readonly statePropertyId: string, readonly statePropertyId: string,
readonly stateProperty: Property | null, readonly stateProperty: Property | null,
) { ) {
super(area, uuid, name, slug); super(area, uuid, name, slug, tagList);
} }
static fromJson(json: any): Device { static fromJson(json: any): Device {
@ -22,6 +24,7 @@ export class Device extends Thing {
validateString(json.uuid), validateString(json.uuid),
validateString(json.name), validateString(json.name),
validateString(json.slug), validateString(json.slug),
validateList(json.tagList, Tag.fromJson),
validateString(json.statePropertyId), validateString(json.statePropertyId),
orNull(json.stateProperty, Property.fromJson), orNull(json.stateProperty, Property.fromJson),
); );

View File

@ -1,14 +1,14 @@
<div class="tile"> <div class="tile">
<div class="tileInner device" [ngClass]="ngClass(device)"> <div class="tileInner device" [ngClass]="ngClass()">
<div class="name"> <div class="name">
{{ device.nameWithArea }} {{ device.nameWithArea }}
</div> </div>
<div class="actions"> <div class="actions">
<div class="action switchOn" (click)="deviceService.setState(device, true)"></div> <div class="action switchOn" (click)="setState(true)"></div>
<div class="action switchOff" (click)="deviceService.setState(device, false)"></div> <div class="action switchOff" (click)="setState(false)"></div>
</div> </div>
<div class="timestamp details"> <div class="timestamp details">

View File

@ -28,11 +28,17 @@ export class DeviceTileComponent {
// //
} }
ngClass(device: Device) { ngClass() {
return { return {
"stateOn": device.stateProperty?.state?.value === true, "stateOn": this.device.stateProperty?.state?.value === true,
"stateOff": device.stateProperty?.state?.value === false, "stateOff": this.device.stateProperty?.state?.value === false,
}; };
} }
setState(newState: boolean) {
if (!this.device.hasTagBySlug('confirm') || confirm("Sicher?")) {
this.deviceService.setState(this.device, newState);
}
}
} }

View File

@ -1,8 +1,9 @@
import {Property} from "../Property/Property"; import {Property} from "../Property/Property";
import {orNull, validateString} from "../api/validators"; import {orNull, validateList, validateString} from "../api/validators";
import {Area} from '../Area/Area'; import {Area} from '../Area/Area';
import {Thing} from '../Thing/Thing'; import {Thing} from '../Thing/Thing';
import {Tag} from '../Tag/Tag';
export class Shutter extends Thing { export class Shutter extends Thing {
@ -11,10 +12,11 @@ export class Shutter extends Thing {
uuid: string, uuid: string,
name: string, name: string,
slug: string, slug: string,
tagList: Tag[],
readonly positionPropertyId: string, readonly positionPropertyId: string,
readonly positionProperty: Property | null, readonly positionProperty: Property | null,
) { ) {
super(area, uuid, name, slug); super(area, uuid, name, slug, tagList);
} }
static fromJson(json: any): Shutter { static fromJson(json: any): Shutter {
@ -23,6 +25,7 @@ export class Shutter extends Thing {
validateString(json.uuid), validateString(json.uuid),
validateString(json.name), validateString(json.name),
validateString(json.slug), validateString(json.slug),
validateList(json.tagList, Tag.fromJson),
validateString(json.positionPropertyId), validateString(json.positionPropertyId),
orNull(json.positionProperty, Property.fromJson), orNull(json.positionProperty, Property.fromJson),
); );

View File

@ -4,6 +4,7 @@ export class Tag {
constructor( constructor(
readonly uuid: string, readonly uuid: string,
readonly slug: string,
readonly name: string, readonly name: string,
) { ) {
// //
@ -12,6 +13,7 @@ export class Tag {
static fromJson(json: any): Tag { static fromJson(json: any): Tag {
return new Tag( return new Tag(
validateString(json.uuid), validateString(json.uuid),
validateString(json.slug),
validateString(json.name), validateString(json.name),
); );
} }

View File

@ -1,4 +1,5 @@
import {Area} from '../Area/Area'; import {Area} from '../Area/Area';
import {Tag} from '../Tag/Tag';
export abstract class Thing { export abstract class Thing {
@ -7,6 +8,7 @@ export abstract class Thing {
readonly uuid: string, readonly uuid: string,
readonly name: string, readonly name: string,
readonly slug: string, readonly slug: string,
readonly tagList: Tag[],
) { ) {
// //
} }
@ -25,6 +27,11 @@ export abstract class Thing {
return this.area.name + ' ' + this.name; return this.area.name + ' ' + this.name;
} }
hasTagBySlug(slug: string): boolean {
const slugLower = slug.toLowerCase();
return this.tagList.some(t => t.slug.toLocaleLowerCase() === slugLower);
}
static trackBy(index: number, thing: Thing) { static trackBy(index: number, thing: Thing) {
return thing.uuid; return thing.uuid;
} }

View File

@ -1,7 +1,8 @@
import {Property} from "../Property/Property"; import {Property} from "../Property/Property";
import {orNull, validateString} from "../api/validators"; import {orNull, validateList, validateString} from "../api/validators";
import {Area} from '../Area/Area'; import {Area} from '../Area/Area';
import {Thing} from '../Thing/Thing'; import {Thing} from '../Thing/Thing';
import {Tag} from '../Tag/Tag';
export class Tunable extends Thing { export class Tunable extends Thing {
@ -10,6 +11,7 @@ export class Tunable extends Thing {
uuid: string, uuid: string,
name: string, name: string,
slug: string, slug: string,
tagList: Tag[],
readonly statePropertyId: string, readonly statePropertyId: string,
readonly stateProperty: Property | null, readonly stateProperty: Property | null,
readonly brightnessPropertyId: string, readonly brightnessPropertyId: string,
@ -17,7 +19,7 @@ export class Tunable extends Thing {
readonly coldnessPropertyId: string, readonly coldnessPropertyId: string,
readonly coldnessProperty: Property | null, readonly coldnessProperty: Property | null,
) { ) {
super(area, uuid, name, slug); super(area, uuid, name, slug, tagList);
} }
static fromJson(json: any): Tunable { static fromJson(json: any): Tunable {
@ -26,6 +28,7 @@ export class Tunable extends Thing {
validateString(json.uuid), validateString(json.uuid),
validateString(json.name), validateString(json.name),
validateString(json.slug), validateString(json.slug),
validateList(json.tagList, Tag.fromJson),
validateString(json.statePropertyId), validateString(json.statePropertyId),
orNull(json.stateProperty, Property.fromJson), orNull(json.stateProperty, Property.fromJson),
validateString(json.brightnessPropertyId), validateString(json.brightnessPropertyId),

View File

@ -3,6 +3,7 @@
<div class="item itemLeft" routerLink="Dashboard" routerLinkActive="active">Dash</div> <div class="item itemLeft" routerLink="Dashboard" routerLinkActive="active">Dash</div>
<div class="item itemLeft" routerLink="ThingList/device" routerLinkActive="active">Geräte</div> <div class="item itemLeft" routerLink="ThingList/device" routerLinkActive="active">Geräte</div>
<div class="item itemLeft" routerLink="ThingList/light" routerLinkActive="active">Licht</div> <div class="item itemLeft" routerLink="ThingList/light" routerLinkActive="active">Licht</div>
<div class="item itemLeft" routerLink="ThingList/decoration" routerLinkActive="active">Deko</div>
<div class="item itemLeft" routerLink="ThingList/shutter" routerLinkActive="active">Rollladen</div> <div class="item itemLeft" routerLink="ThingList/shutter" routerLinkActive="active">Rollladen</div>
<div class="item itemRight" routerLink="GroupList" routerLinkActive="active">KNX</div> <div class="item itemRight" routerLink="GroupList" routerLinkActive="active">KNX</div>
</div> </div>

View File

@ -3,7 +3,7 @@ package de.ph87.home.device;
import de.ph87.home.area.AreaDto; import de.ph87.home.area.AreaDto;
import de.ph87.home.property.PropertyDto; import de.ph87.home.property.PropertyDto;
import de.ph87.home.property.PropertyTypeMismatch; import de.ph87.home.property.PropertyTypeMismatch;
import de.ph87.home.tag.Tag; import de.ph87.home.tag.TagDto;
import de.ph87.home.web.IWebSocketMessage; import de.ph87.home.web.IWebSocketMessage;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import lombok.Getter; import lombok.Getter;
@ -39,7 +39,7 @@ public class DeviceDto implements IWebSocketMessage {
private final PropertyDto<Boolean> stateProperty; private final PropertyDto<Boolean> stateProperty;
@NonNull @NonNull
private final List<String> tagList; private final List<TagDto> tagList;
public DeviceDto(@NonNull final Device device, @Nullable final PropertyDto<Boolean> stateProperty) { public DeviceDto(@NonNull final Device device, @Nullable final PropertyDto<Boolean> stateProperty) {
this.area = new AreaDto(device.getArea()); this.area = new AreaDto(device.getArea());
@ -48,7 +48,7 @@ public class DeviceDto implements IWebSocketMessage {
this.slug = device.getSlug(); this.slug = device.getSlug();
this.statePropertyId = device.getStatePropertyId(); this.statePropertyId = device.getStatePropertyId();
this.stateProperty = stateProperty; this.stateProperty = stateProperty;
this.tagList = device.getTagList().stream().map(Tag::getName).toList(); this.tagList = device.getTagList().stream().map(TagDto::new).toList();
} }
@Nullable @Nullable

View File

@ -3,7 +3,7 @@ package de.ph87.home.shutter;
import de.ph87.home.area.AreaDto; import de.ph87.home.area.AreaDto;
import de.ph87.home.property.PropertyDto; import de.ph87.home.property.PropertyDto;
import de.ph87.home.property.PropertyTypeMismatch; import de.ph87.home.property.PropertyTypeMismatch;
import de.ph87.home.tag.Tag; import de.ph87.home.tag.TagDto;
import de.ph87.home.web.IWebSocketMessage; import de.ph87.home.web.IWebSocketMessage;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import lombok.Getter; import lombok.Getter;
@ -39,7 +39,7 @@ public class ShutterDto implements IWebSocketMessage {
private final PropertyDto<Double> positionProperty; private final PropertyDto<Double> positionProperty;
@NonNull @NonNull
private final List<String> tagList; private final List<TagDto> tagList;
public ShutterDto(@NonNull final Shutter shutter, @Nullable final PropertyDto<Double> positionProperty) { public ShutterDto(@NonNull final Shutter shutter, @Nullable final PropertyDto<Double> positionProperty) {
this.area = new AreaDto(shutter.getArea()); this.area = new AreaDto(shutter.getArea());
@ -48,7 +48,7 @@ public class ShutterDto implements IWebSocketMessage {
this.slug = shutter.getSlug(); this.slug = shutter.getSlug();
this.positionPropertyId = shutter.getPositionPropertyId(); this.positionPropertyId = shutter.getPositionPropertyId();
this.positionProperty = positionProperty; this.positionProperty = positionProperty;
this.tagList = shutter.getTagList().stream().map(Tag::getName).toList(); this.tagList = shutter.getTagList().stream().map(TagDto::new).toList();
} }
@Nullable @Nullable

View File

@ -9,11 +9,15 @@ public class TagDto {
@NonNull @NonNull
private final String uuid; private final String uuid;
@NonNull
private final String slug;
@NonNull @NonNull
private final String name; private final String name;
public TagDto(@NonNull final Tag tag) { public TagDto(@NonNull final Tag tag) {
this.uuid = tag.getUuid(); this.uuid = tag.getUuid();
this.slug = tag.getSlug();
this.name = tag.getName(); this.name = tag.getName();
} }

View File

@ -3,7 +3,7 @@ package de.ph87.home.tunable;
import de.ph87.home.area.AreaDto; import de.ph87.home.area.AreaDto;
import de.ph87.home.property.PropertyDto; import de.ph87.home.property.PropertyDto;
import de.ph87.home.property.PropertyTypeMismatch; import de.ph87.home.property.PropertyTypeMismatch;
import de.ph87.home.tag.Tag; import de.ph87.home.tag.TagDto;
import de.ph87.home.web.IWebSocketMessage; import de.ph87.home.web.IWebSocketMessage;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import lombok.Getter; import lombok.Getter;
@ -53,7 +53,7 @@ public class TunableDto implements IWebSocketMessage {
private final PropertyDto<Double> coldnessProperty; private final PropertyDto<Double> coldnessProperty;
@NonNull @NonNull
private final List<String> tagList; private final List<TagDto> tagList;
public TunableDto(@NonNull final Tunable tunable, @Nullable final PropertyDto<Boolean> stateProperty, @Nullable final PropertyDto<Double> brightnessProperty, @Nullable final PropertyDto<Double> coldnessProperty) { public TunableDto(@NonNull final Tunable tunable, @Nullable final PropertyDto<Boolean> stateProperty, @Nullable final PropertyDto<Double> brightnessProperty, @Nullable final PropertyDto<Double> coldnessProperty) {
this.area = new AreaDto(tunable.getArea()); this.area = new AreaDto(tunable.getArea());
@ -66,7 +66,7 @@ public class TunableDto implements IWebSocketMessage {
this.stateProperty = stateProperty; this.stateProperty = stateProperty;
this.brightnessProperty = brightnessProperty; this.brightnessProperty = brightnessProperty;
this.coldnessProperty = coldnessProperty; this.coldnessProperty = coldnessProperty;
this.tagList = tunable.getTagList().stream().map(Tag::getName).toList(); this.tagList = tunable.getTagList().stream().map(TagDto::new).toList();
} }
@Nullable @Nullable