diff --git a/projects/aas-portal/src/app/aas/aas.component.html b/projects/aas-portal/src/app/aas/aas.component.html index cfebf37a..5c2dcc56 100644 --- a/projects/aas-portal/src/app/aas/aas.component.html +++ b/projects/aas-portal/src/app/aas/aas.component.html @@ -76,10 +76,10 @@
- -
diff --git a/projects/aas-portal/src/app/aas/aas.component.ts b/projects/aas-portal/src/app/aas/aas.component.ts index b9c2ac4a..b4109c58 100644 --- a/projects/aas-portal/src/app/aas/aas.component.ts +++ b/projects/aas-portal/src/app/aas/aas.component.ts @@ -90,13 +90,9 @@ export class AASComponent implements OnInit, OnDestroy, AfterViewInit { public readonly selectedElements = signal([]); - public get canUndo(): boolean { - return this.commandHandler.canUndo; - } + public readonly canUndo = this.commandHandler.canUndo; - public get canRedo(): boolean { - return this.commandHandler.canRedo; - } + public readonly canRedo = this.commandHandler.canRedo; public readonly canPlay = computed(() => { const state = this.store.state(); diff --git a/projects/aas-portal/src/app/aas/command-handler.service.ts b/projects/aas-portal/src/app/aas/command-handler.service.ts index 261df29b..25399bc7 100644 --- a/projects/aas-portal/src/app/aas/command-handler.service.ts +++ b/projects/aas-portal/src/app/aas/command-handler.service.ts @@ -6,7 +6,7 @@ * *****************************************************************************/ -import { Injectable } from '@angular/core'; +import { Injectable, computed, signal } from '@angular/core'; import { NotifyService } from 'aas-lib'; import { Command } from '../types/command'; @@ -14,8 +14,8 @@ import { Command } from '../types/command'; providedIn: 'root', }) export class CommandHandlerService { - private commands: Array = []; - private position = -1; + private readonly commands = signal([]); + private readonly position = signal(-1); public constructor(private notify: NotifyService) {} @@ -27,30 +27,26 @@ export class CommandHandlerService { try { command.execute(); - if (this.commands.length > 0 && this.position < this.commands.length - 1) { - this.commands.splice(this.position + 1); + if (this.commands().length > 0 && this.position() < this.commands().length - 1) { + this.commands.update(values => values.filter((_, i) => i <= this.position())); } - this.commands.push(command); - ++this.position; + this.commands.update(values => [...values, command]); + this.position.update(value => value + 1); } catch (error) { command.abort(); throw error; } } - public get canUndo(): boolean { - return this.position >= 0; - } + public readonly canUndo = computed(() => this.position() >= 0); - public get canRedo(): boolean { - return this.position + 1 < this.commands.length; - } + public readonly canRedo = computed(() => this.position() + 1 < this.commands().length); public undo(): void { try { - this.commands[this.position].undo(); - --this.position; + this.commands()[this.position()].undo(); + this.position.update(value => value - 1); } catch (error) { this.notify.error(error); } @@ -58,15 +54,15 @@ export class CommandHandlerService { public redo(): void { try { - ++this.position; - this.commands[this.position].redo(); + this.position.update(value => value + 1); + this.commands()[this.position()].redo(); } catch (error) { this.notify.error(error); } } public clear(): void { - this.commands = []; - this.position = -1; + this.commands.set([]); + this.position.set(-1); } } diff --git a/projects/aas-portal/src/app/dashboard/dashboard.component.ts b/projects/aas-portal/src/app/dashboard/dashboard.component.ts index 5f9abcf1..3ab47d39 100644 --- a/projects/aas-portal/src/app/dashboard/dashboard.component.ts +++ b/projects/aas-portal/src/app/dashboard/dashboard.component.ts @@ -175,6 +175,10 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit, Aft public readonly selectionMode = this.dashboard.selectionMode.asReadonly(); + public readonly canUndo = computed(() => this.editMode() && this.commandHandler.canUndo()); + + public readonly canRedo = computed(() => this.editMode() && this.commandHandler.canRedo()); + public ngOnInit(): void { this.commandHandler.clear(); @@ -455,20 +459,12 @@ export class DashboardComponent implements OnInit, OnDestroy, AfterViewInit, Aft } } - public canUndo(): boolean { - return this.editMode() && this.commandHandler.canUndo; - } - public undo(): void { if (this.canUndo()) { this.commandHandler.undo(); } } - public canRedo(): boolean { - return this.editMode() && this.commandHandler.canRedo; - } - public redo(): void { if (this.canRedo()) { this.commandHandler.redo(); diff --git a/projects/aas-portal/src/test/aas/aas.component.spec.ts b/projects/aas-portal/src/test/aas/aas.component.spec.ts index 1d48184c..2cfe41d5 100644 --- a/projects/aas-portal/src/test/aas/aas.component.spec.ts +++ b/projects/aas-portal/src/test/aas/aas.component.spec.ts @@ -24,7 +24,7 @@ import { provideHttpClientTesting } from '@angular/common/http/testing'; import { DashboardPage, DashboardService } from '../../app/dashboard/dashboard.service'; import { DashboardChartType } from '../../app/dashboard/dashboard.service'; import { Router, provideRouter } from '@angular/router'; -import { Component, Input, input, output, signal } from '@angular/core'; +import { Component, input, output, signal } from '@angular/core'; import { AASApiService } from '../../app/aas/aas-api.service'; import { ToolbarService } from '../../app/toolbar.service'; import { AASStore } from '../../app/aas/aas.store'; @@ -58,16 +58,11 @@ class TestAASTreeComponent { standalone: true, }) class TestSecureImageComponent { - @Input() - public src = ''; - @Input() - public alt?: string; - @Input() - public classname?: string; - @Input() - public width = -1; - @Input() - public height = -1; + public readonly src = input.required(); + public readonly alt = input(); + public readonly classname = input(); + public readonly width = input(); + public readonly height = input(); } describe('AASComponent', () => { diff --git a/projects/aas-portal/src/test/aas/command-handler.service.spec.ts b/projects/aas-portal/src/test/aas/command-handler.service.spec.ts index 3c022b55..b1634bf1 100644 --- a/projects/aas-portal/src/test/aas/command-handler.service.spec.ts +++ b/projects/aas-portal/src/test/aas/command-handler.service.spec.ts @@ -88,41 +88,41 @@ describe('CommandHandlerService', () => { expect(service).toBeTruthy(); }); - it('indicates that undo is not possible', function () { - expect(service.canUndo).toBeFalse(); + it('indicates that undo is not possible', () => { + expect(service.canUndo()).toBeFalse(); }); - it('indicates that redo is not possible', function () { - expect(service.canRedo).toBeFalse(); + it('indicates that redo is not possible', () => { + expect(service.canRedo()).toBeFalse(); }); - it('can execute a command', function () { + it('can execute a command', () => { const spy = jasmine.createSpy('execute'); service.execute(new TestCommand(spy)); expect(spy).toHaveBeenCalled(); }); - it('can undo/redo a command', function () { + it('can undo/redo a command', () => { const undoSpy = jasmine.createSpy('undo'); const redoSpy = jasmine.createSpy('redo'); service.execute(new TestCommand(undefined, undoSpy, redoSpy)); - expect(service.canUndo).toBeTrue(); + expect(service.canUndo()).toBeTrue(); service.undo(); expect(undoSpy).toHaveBeenCalled(); - expect(service.canRedo).toBeTrue(); + expect(service.canRedo()).toBeTrue(); service.redo(); expect(redoSpy).toHaveBeenCalled(); }); - it('clears the undo/redo stack', function () { + it('clears the undo/redo stack', () => { service.execute(new TestCommand()); service.execute(new TestCommand()); service.clear(); - expect(service.canUndo).toBeFalse(); - expect(service.canRedo).toBeFalse(); + expect(service.canUndo()).toBeFalse(); + expect(service.canRedo()).toBeFalse(); }); - it('aborts a failed command', function () { + it('aborts a failed command', () => { const abortSpy = jasmine.createSpy('abort'); expect(() => service.execute(new FailCommand(abortSpy))).toThrowError(); expect(abortSpy).toHaveBeenCalled();