From 2a0a54607819085edef2a4cec0c5229ff8495a36 Mon Sep 17 00:00:00 2001 From: Johannes Haller Date: Mon, 23 Feb 2026 17:16:10 +0100 Subject: [PATCH 1/5] Sort components alphabetically in flat widgets Import ArrayUtils and apply ArrayUtils.sortedAlphabetically to various component lists in production/consumption flat widgets (live and history). Chargers, meters, EVCSs and heat components are now sorted by alias for consistent ordering. No functional logic changes aside from deterministic ordering; changes affect ui/src/app/edge/*/flat/flat.ts files. --- .../history/common/production/flat/flat.ts | 11 +++--- .../edge/live/common/consumption/flat/flat.ts | 21 ++++++----- .../common/consumption/history/flat/flat.ts | 35 +++++++++++-------- .../edge/live/common/production/flat/flat.ts | 11 +++--- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/ui/src/app/edge/history/common/production/flat/flat.ts b/ui/src/app/edge/history/common/production/flat/flat.ts index 39fc49ffaed..a3db194fb1a 100644 --- a/ui/src/app/edge/history/common/production/flat/flat.ts +++ b/ui/src/app/edge/history/common/production/flat/flat.ts @@ -2,6 +2,7 @@ import { Component } from "@angular/core"; import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; import { ChannelAddress, EdgeConfig, Utils } from "../../../../../shared/shared"; +import { ArrayUtils } from "../../../../../shared/utils/array/array.utils"; @Component({ selector: "productionWidget", @@ -16,14 +17,16 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { // Get Chargers - this.chargerComponents = + this.chargerComponents = ArrayUtils.sortedAlphabetically( this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") - .filter(component => component.isEnabled); + .filter(component => component.isEnabled), + (c) => c.alias); // Get productionMeters - this.productionMeterComponents = + this.productionMeterComponents = ArrayUtils.sortedAlphabetically( this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isProducer(component)); + .filter(component => component.isEnabled && this.config.isProducer(component)), + (c) => c.alias); return []; } } diff --git a/ui/src/app/edge/live/common/consumption/flat/flat.ts b/ui/src/app/edge/live/common/consumption/flat/flat.ts index 24a10bbaec6..06f11cb2fa7 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/flat/flat.ts @@ -4,6 +4,7 @@ import { EvcsComponent } from "src/app/shared/components/edge/config-components/ import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; import { Modal } from "src/app/shared/components/flat/flat"; import { ChannelAddress, CurrentData, EdgeConfig, Utils } from "src/app/shared/shared"; +import { ArrayUtils } from "src/app/shared/utils/array/array.utils"; import { ModalComponent } from "../modal/modal"; @Component({ @@ -41,14 +42,16 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { ]; // Get consumptionMeterComponents - this.consumptionMeters = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => { - const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); - const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); + this.consumptionMeters = ArrayUtils.sortedAlphabetically( + this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => { + const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); + const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); - return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && - isEvcs === false; - }); + return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && + isEvcs === false; + }), + (c) => c.alias); for (const component of this.consumptionMeters) { channelAddresses.push( @@ -60,7 +63,9 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { } // Get EVCSs - this.evcss = EvcsComponent.getComponents(this.config, this.edge); + this.evcss = ArrayUtils.sortedAlphabetically( + EvcsComponent.getComponents(this.config, this.edge), + (c) => c.alias); for (const component of this.evcss) { channelAddresses.push( diff --git a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts index d5ee33fd30d..c7b8a3e08dd 100644 --- a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts @@ -3,6 +3,7 @@ import { Component } from "@angular/core"; import { EvcsComponent } from "src/app/shared/components/edge/config-components/evcs/evcsComponent"; import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; import { ChannelAddress, CurrentData, EdgeConfig } from "../../../../../../shared/shared"; +import { ArrayUtils } from "../../../../../../shared/utils/array/array.utils"; @Component({ selector: "consumptionWidget", @@ -19,27 +20,33 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { const channels: ChannelAddress[] = [new ChannelAddress("_sum", "ConsumptionActiveEnergy")]; - this.evcsComponents = EvcsComponent.getComponents(this.config, this.edge); + this.evcsComponents = ArrayUtils.sortedAlphabetically( + EvcsComponent.getComponents(this.config, this.edge), + (c) => c.alias); - this.heatComponents = this.config?.getComponentsImplementingNature("io.openems.edge.heat.api.Heat") - .filter(component => - !(component.factoryId === "Controller.Heat.Heatingelement") && - !component.isEnabled === false); + this.heatComponents = ArrayUtils.sortedAlphabetically( + this.config?.getComponentsImplementingNature("io.openems.edge.heat.api.Heat") + .filter(component => + !(component.factoryId === "Controller.Heat.Heatingelement") && + !component.isEnabled === false), + (c) => c.alias); channels.push( ...this.heatComponents.map( (component) => new ChannelAddress(component.id, "ActiveProductionEnergy") ) ); - this.consumptionMeterComponents = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => { - const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); - const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); - const isHeat = natureIds.includes("io.openems.edge.heat.api.Heat"); - - return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && - isEvcs === false && isHeat === false; - }); + this.consumptionMeterComponents = ArrayUtils.sortedAlphabetically( + this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => { + const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); + const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); + const isHeat = natureIds.includes("io.openems.edge.heat.api.Heat"); + + return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && + isEvcs === false && isHeat === false; + }), + (c) => c.alias); return channels; } diff --git a/ui/src/app/edge/live/common/production/flat/flat.ts b/ui/src/app/edge/live/common/production/flat/flat.ts index c73d2288b6e..66fdc3f6fe9 100644 --- a/ui/src/app/edge/live/common/production/flat/flat.ts +++ b/ui/src/app/edge/live/common/production/flat/flat.ts @@ -2,6 +2,7 @@ import { Component } from "@angular/core"; import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; import { Modal } from "src/app/shared/components/flat/flat"; import { EdgeConfig, Utils } from "src/app/shared/shared"; +import { ArrayUtils } from "src/app/shared/utils/array/array.utils"; import { ModalComponent } from "../modal/modal"; @Component({ @@ -26,14 +27,16 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses() { // Get Chargers - this.chargerComponents = + this.chargerComponents = ArrayUtils.sortedAlphabetically( this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") - .filter(component => component.isEnabled); + .filter(component => component.isEnabled), + (c) => c.alias); // Get productionMeters - this.productionMeterComponents = + this.productionMeterComponents = ArrayUtils.sortedAlphabetically( this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isProducer(component)); + .filter(component => component.isEnabled && this.config.isProducer(component)), + (c) => c.alias); return []; } From d6f46853412dcbc1e10401abaae69f913dc0c96d Mon Sep 17 00:00:00 2001 From: Sn0w3y Date: Tue, 24 Feb 2026 23:30:43 +0100 Subject: [PATCH 2/5] Add ArrayUtils.alphabetically and use in sorts and add Tests Add ArrayUtils.alphabetically(fn) and add Tests for it aswell --- .../history/common/production/flat/flat.ts | 14 +++---- .../edge/live/common/consumption/flat/flat.ts | 22 +++++------ .../common/consumption/history/flat/flat.ts | 39 +++++++++---------- .../edge/live/common/production/flat/flat.ts | 14 +++---- .../shared/utils/array/array.utils.spec.ts | 7 ++++ ui/src/app/shared/utils/array/array.utils.ts | 17 +++++++- 6 files changed, 62 insertions(+), 51 deletions(-) diff --git a/ui/src/app/edge/history/common/production/flat/flat.ts b/ui/src/app/edge/history/common/production/flat/flat.ts index a3db194fb1a..dfb1b2ef832 100644 --- a/ui/src/app/edge/history/common/production/flat/flat.ts +++ b/ui/src/app/edge/history/common/production/flat/flat.ts @@ -17,16 +17,14 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { // Get Chargers - this.chargerComponents = ArrayUtils.sortedAlphabetically( - this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") - .filter(component => component.isEnabled), - (c) => c.alias); + this.chargerComponents = this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") + .filter(component => component.isEnabled) + .sort(ArrayUtils.alphabetically(c => c.alias)); // Get productionMeters - this.productionMeterComponents = ArrayUtils.sortedAlphabetically( - this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isProducer(component)), - (c) => c.alias); + this.productionMeterComponents = this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => component.isEnabled && this.config.isProducer(component)) + .sort(ArrayUtils.alphabetically(c => c.alias)); return []; } } diff --git a/ui/src/app/edge/live/common/consumption/flat/flat.ts b/ui/src/app/edge/live/common/consumption/flat/flat.ts index 06f11cb2fa7..647195ccc79 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/flat/flat.ts @@ -42,16 +42,15 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { ]; // Get consumptionMeterComponents - this.consumptionMeters = ArrayUtils.sortedAlphabetically( - this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => { - const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); - const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); + this.consumptionMeters = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => { + const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); + const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); - return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && - isEvcs === false; - }), - (c) => c.alias); + return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && + isEvcs === false; + }) + .sort(ArrayUtils.alphabetically(c => c.alias)); for (const component of this.consumptionMeters) { channelAddresses.push( @@ -63,9 +62,8 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { } // Get EVCSs - this.evcss = ArrayUtils.sortedAlphabetically( - EvcsComponent.getComponents(this.config, this.edge), - (c) => c.alias); + this.evcss = EvcsComponent.getComponents(this.config, this.edge) + .sort(ArrayUtils.alphabetically(c => c.alias)); for (const component of this.evcss) { channelAddresses.push( diff --git a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts index c7b8a3e08dd..b58f6ca3c2c 100644 --- a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts @@ -20,33 +20,30 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { const channels: ChannelAddress[] = [new ChannelAddress("_sum", "ConsumptionActiveEnergy")]; - this.evcsComponents = ArrayUtils.sortedAlphabetically( - EvcsComponent.getComponents(this.config, this.edge), - (c) => c.alias); - - this.heatComponents = ArrayUtils.sortedAlphabetically( - this.config?.getComponentsImplementingNature("io.openems.edge.heat.api.Heat") - .filter(component => - !(component.factoryId === "Controller.Heat.Heatingelement") && - !component.isEnabled === false), - (c) => c.alias); + this.evcsComponents = EvcsComponent.getComponents(this.config, this.edge) + .sort(ArrayUtils.alphabetically(c => c.alias)); + + this.heatComponents = this.config?.getComponentsImplementingNature("io.openems.edge.heat.api.Heat") + .filter(component => + !(component.factoryId === "Controller.Heat.Heatingelement") && + !component.isEnabled === false) + .sort(ArrayUtils.alphabetically(c => c.alias)); channels.push( ...this.heatComponents.map( (component) => new ChannelAddress(component.id, "ActiveProductionEnergy") ) ); - this.consumptionMeterComponents = ArrayUtils.sortedAlphabetically( - this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => { - const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); - const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); - const isHeat = natureIds.includes("io.openems.edge.heat.api.Heat"); - - return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && - isEvcs === false && isHeat === false; - }), - (c) => c.alias); + this.consumptionMeterComponents = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => { + const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); + const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); + const isHeat = natureIds.includes("io.openems.edge.heat.api.Heat"); + + return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && + isEvcs === false && isHeat === false; + }) + .sort(ArrayUtils.alphabetically(c => c.alias)); return channels; } diff --git a/ui/src/app/edge/live/common/production/flat/flat.ts b/ui/src/app/edge/live/common/production/flat/flat.ts index 66fdc3f6fe9..89daf698976 100644 --- a/ui/src/app/edge/live/common/production/flat/flat.ts +++ b/ui/src/app/edge/live/common/production/flat/flat.ts @@ -27,16 +27,14 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses() { // Get Chargers - this.chargerComponents = ArrayUtils.sortedAlphabetically( - this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") - .filter(component => component.isEnabled), - (c) => c.alias); + this.chargerComponents = this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") + .filter(component => component.isEnabled) + .sort(ArrayUtils.alphabetically(c => c.alias)); // Get productionMeters - this.productionMeterComponents = ArrayUtils.sortedAlphabetically( - this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isProducer(component)), - (c) => c.alias); + this.productionMeterComponents = this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => component.isEnabled && this.config.isProducer(component)) + .sort(ArrayUtils.alphabetically(c => c.alias)); return []; } diff --git a/ui/src/app/shared/utils/array/array.utils.spec.ts b/ui/src/app/shared/utils/array/array.utils.spec.ts index 9e5f64f9a48..c673cb42aaf 100644 --- a/ui/src/app/shared/utils/array/array.utils.spec.ts +++ b/ui/src/app/shared/utils/array/array.utils.spec.ts @@ -25,6 +25,13 @@ describe("Array-Utils", () => { expect(() => ArrayUtils.sortedAlphabetically(inputArr, null)).toThrow(); }); + it("+alphabetically comparator", () => { + const inputArr = ["A", null, "C", undefined, "B", "a", "1"]; + const sortedArr = ["1", "A", "a", "B", "C", null, undefined]; + + expect([...inputArr].sort(ArrayUtils.alphabetically(a => a))).toEqual(sortedArr); + }); + describe("ReducerFunctions", () => { it("+sum", () => { diff --git a/ui/src/app/shared/utils/array/array.utils.ts b/ui/src/app/shared/utils/array/array.utils.ts index 9dede66ec7a..d7d357991c9 100644 --- a/ui/src/app/shared/utils/array/array.utils.ts +++ b/ui/src/app/shared/utils/array/array.utils.ts @@ -62,7 +62,20 @@ export namespace ArrayUtils { * @returns sorted array */ export function sortedAlphabetically(array: T[], fn: (arg: T) => string): T[] { - return array.sort((a: T, b: T) => { + return array.sort(alphabetically(fn)); + } + + /** + * Creates a comparator that sorts items alphabetically by a string key returned from `fn`. + * + * The comparator places falsy keys (null, undefined or empty string) after non-falsy keys; + * two falsy keys compare as equal. + * + * @param fn to get a string to sort by + * @returns A comparator `(a, b) => number` suitable for `Array.sort`. + */ + export function alphabetically(fn: (arg: T) => string): (a: T, b: T) => number { + return (a: T, b: T) => { const aVal = fn(a); const bVal = fn(b); if (!aVal) { @@ -71,7 +84,7 @@ export namespace ArrayUtils { return -1; } return aVal.localeCompare(bVal, undefined, { sensitivity: "accent" }); - }); + }; } /** From 528d3aa954038ba0d1e6a2021ea6894f4d2ef2b4 Mon Sep 17 00:00:00 2001 From: Sn0w3y Date: Tue, 24 Feb 2026 23:42:15 +0100 Subject: [PATCH 3/5] Fix Formattings --- .../history/common/production/flat/flat.ts | 14 ++++--- .../edge/live/common/consumption/flat/flat.ts | 22 ++++++----- .../common/consumption/history/flat/flat.ts | 39 ++++++++++--------- .../edge/live/common/production/flat/flat.ts | 14 ++++--- 4 files changed, 49 insertions(+), 40 deletions(-) diff --git a/ui/src/app/edge/history/common/production/flat/flat.ts b/ui/src/app/edge/history/common/production/flat/flat.ts index dfb1b2ef832..fcd730dfa9b 100644 --- a/ui/src/app/edge/history/common/production/flat/flat.ts +++ b/ui/src/app/edge/history/common/production/flat/flat.ts @@ -17,14 +17,16 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { // Get Chargers - this.chargerComponents = this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") - .filter(component => component.isEnabled) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.chargerComponents = + this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") + .filter(component => component.isEnabled) + .sort(ArrayUtils.alphabetically(c => c.alias)); // Get productionMeters - this.productionMeterComponents = this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isProducer(component)) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.productionMeterComponents = + this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => component.isEnabled && this.config.isProducer(component)) + .sort(ArrayUtils.alphabetically(c => c.alias)); return []; } } diff --git a/ui/src/app/edge/live/common/consumption/flat/flat.ts b/ui/src/app/edge/live/common/consumption/flat/flat.ts index 647195ccc79..a10c13b2274 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/flat/flat.ts @@ -42,15 +42,16 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { ]; // Get consumptionMeterComponents - this.consumptionMeters = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => { - const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); - const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); + this.consumptionMeters = + this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => { + const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); + const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); - return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && - isEvcs === false; - }) - .sort(ArrayUtils.alphabetically(c => c.alias)); + return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && + isEvcs === false; + }) + .sort(ArrayUtils.alphabetically(c => c.alias)); for (const component of this.consumptionMeters) { channelAddresses.push( @@ -62,8 +63,9 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { } // Get EVCSs - this.evcss = EvcsComponent.getComponents(this.config, this.edge) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.evcss = + EvcsComponent.getComponents(this.config, this.edge) + .sort(ArrayUtils.alphabetically(c => c.alias)); for (const component of this.evcss) { channelAddresses.push( diff --git a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts index b58f6ca3c2c..f935db3ecf6 100644 --- a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts @@ -20,30 +20,33 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { const channels: ChannelAddress[] = [new ChannelAddress("_sum", "ConsumptionActiveEnergy")]; - this.evcsComponents = EvcsComponent.getComponents(this.config, this.edge) - .sort(ArrayUtils.alphabetically(c => c.alias)); - - this.heatComponents = this.config?.getComponentsImplementingNature("io.openems.edge.heat.api.Heat") - .filter(component => - !(component.factoryId === "Controller.Heat.Heatingelement") && - !component.isEnabled === false) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.evcsComponents = + EvcsComponent.getComponents(this.config, this.edge) + .sort(ArrayUtils.alphabetically(c => c.alias)); + + this.heatComponents = + this.config?.getComponentsImplementingNature("io.openems.edge.heat.api.Heat") + .filter(component => + !(component.factoryId === "Controller.Heat.Heatingelement") && + !component.isEnabled === false) + .sort(ArrayUtils.alphabetically(c => c.alias)); channels.push( ...this.heatComponents.map( (component) => new ChannelAddress(component.id, "ActiveProductionEnergy") ) ); - this.consumptionMeterComponents = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => { - const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); - const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); - const isHeat = natureIds.includes("io.openems.edge.heat.api.Heat"); - - return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && - isEvcs === false && isHeat === false; - }) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.consumptionMeterComponents = + this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => { + const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); + const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); + const isHeat = natureIds.includes("io.openems.edge.heat.api.Heat"); + + return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && + isEvcs === false && isHeat === false; + }) + .sort(ArrayUtils.alphabetically(c => c.alias)); return channels; } diff --git a/ui/src/app/edge/live/common/production/flat/flat.ts b/ui/src/app/edge/live/common/production/flat/flat.ts index 89daf698976..10960e79f74 100644 --- a/ui/src/app/edge/live/common/production/flat/flat.ts +++ b/ui/src/app/edge/live/common/production/flat/flat.ts @@ -27,14 +27,16 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses() { // Get Chargers - this.chargerComponents = this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") - .filter(component => component.isEnabled) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.chargerComponents = + this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") + .filter(component => component.isEnabled) + .sort(ArrayUtils.alphabetically(c => c.alias)); // Get productionMeters - this.productionMeterComponents = this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isProducer(component)) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.productionMeterComponents = + this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => component.isEnabled && this.config.isProducer(component)) + .sort(ArrayUtils.alphabetically(c => c.alias)); return []; } From 00845d11a8104c217f972717d049bcb973c6835b Mon Sep 17 00:00:00 2001 From: Sn0w3y Date: Tue, 24 Feb 2026 23:44:28 +0100 Subject: [PATCH 4/5] Fix Formatting again.. --- .../edge/live/common/consumption/flat/flat.ts | 22 +++++------ .../common/consumption/history/flat/flat.ts | 39 +++++++++---------- 2 files changed, 28 insertions(+), 33 deletions(-) diff --git a/ui/src/app/edge/live/common/consumption/flat/flat.ts b/ui/src/app/edge/live/common/consumption/flat/flat.ts index a10c13b2274..647195ccc79 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/flat/flat.ts @@ -42,16 +42,15 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { ]; // Get consumptionMeterComponents - this.consumptionMeters = - this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => { - const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); - const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); + this.consumptionMeters = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => { + const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); + const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); - return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && - isEvcs === false; - }) - .sort(ArrayUtils.alphabetically(c => c.alias)); + return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && + isEvcs === false; + }) + .sort(ArrayUtils.alphabetically(c => c.alias)); for (const component of this.consumptionMeters) { channelAddresses.push( @@ -63,9 +62,8 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { } // Get EVCSs - this.evcss = - EvcsComponent.getComponents(this.config, this.edge) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.evcss = EvcsComponent.getComponents(this.config, this.edge) + .sort(ArrayUtils.alphabetically(c => c.alias)); for (const component of this.evcss) { channelAddresses.push( diff --git a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts index f935db3ecf6..b58f6ca3c2c 100644 --- a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts @@ -20,33 +20,30 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { const channels: ChannelAddress[] = [new ChannelAddress("_sum", "ConsumptionActiveEnergy")]; - this.evcsComponents = - EvcsComponent.getComponents(this.config, this.edge) - .sort(ArrayUtils.alphabetically(c => c.alias)); - - this.heatComponents = - this.config?.getComponentsImplementingNature("io.openems.edge.heat.api.Heat") - .filter(component => - !(component.factoryId === "Controller.Heat.Heatingelement") && - !component.isEnabled === false) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.evcsComponents = EvcsComponent.getComponents(this.config, this.edge) + .sort(ArrayUtils.alphabetically(c => c.alias)); + + this.heatComponents = this.config?.getComponentsImplementingNature("io.openems.edge.heat.api.Heat") + .filter(component => + !(component.factoryId === "Controller.Heat.Heatingelement") && + !component.isEnabled === false) + .sort(ArrayUtils.alphabetically(c => c.alias)); channels.push( ...this.heatComponents.map( (component) => new ChannelAddress(component.id, "ActiveProductionEnergy") ) ); - this.consumptionMeterComponents = - this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => { - const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); - const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); - const isHeat = natureIds.includes("io.openems.edge.heat.api.Heat"); - - return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && - isEvcs === false && isHeat === false; - }) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.consumptionMeterComponents = this.config?.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") + .filter(component => { + const natureIds = this.config?.getNatureIdsByFactoryId(component.factoryId); + const isEvcs = natureIds.includes("io.openems.edge.evcs.api.Evcs"); + const isHeat = natureIds.includes("io.openems.edge.heat.api.Heat"); + + return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && + isEvcs === false && isHeat === false; + }) + .sort(ArrayUtils.alphabetically(c => c.alias)); return channels; } From 1cdb2c6042720659314aea5334debdd6a269dc04 Mon Sep 17 00:00:00 2001 From: Johannes Haller Date: Tue, 3 Mar 2026 10:36:32 +0100 Subject: [PATCH 5/5] Remove sorting from component lists This commit removes the sorting based on the component alias from various component lists across the application. Previously, components such as chargers, production meters, consumption meters, and EVCS components were sorted alphabetically by their alias before being processed or displayed. This sorting logic has been removed to streamline the data processing and potentially improve performance. The decision to remove sorting is based on the premise that the order of components does not impact the functionality or the user interface experience. Additionally, sorting is now centralized in the EdgeConfig class, ensuring a consistent approach across the application and reducing redundancy. --- ui/src/app/edge/history/common/production/flat/flat.ts | 7 ++----- ui/src/app/edge/live/common/consumption/flat/flat.ts | 7 ++----- .../edge/live/common/consumption/history/flat/flat.ts | 10 +++------- ui/src/app/edge/live/common/production/flat/flat.ts | 7 ++----- ui/src/app/shared/components/edge/edgeconfig.ts | 5 +++-- 5 files changed, 12 insertions(+), 24 deletions(-) diff --git a/ui/src/app/edge/history/common/production/flat/flat.ts b/ui/src/app/edge/history/common/production/flat/flat.ts index fcd730dfa9b..39fc49ffaed 100644 --- a/ui/src/app/edge/history/common/production/flat/flat.ts +++ b/ui/src/app/edge/history/common/production/flat/flat.ts @@ -2,7 +2,6 @@ import { Component } from "@angular/core"; import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; import { ChannelAddress, EdgeConfig, Utils } from "../../../../../shared/shared"; -import { ArrayUtils } from "../../../../../shared/utils/array/array.utils"; @Component({ selector: "productionWidget", @@ -19,14 +18,12 @@ export class FlatComponent extends AbstractFlatWidget { // Get Chargers this.chargerComponents = this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") - .filter(component => component.isEnabled) - .sort(ArrayUtils.alphabetically(c => c.alias)); + .filter(component => component.isEnabled); // Get productionMeters this.productionMeterComponents = this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isProducer(component)) - .sort(ArrayUtils.alphabetically(c => c.alias)); + .filter(component => component.isEnabled && this.config.isProducer(component)); return []; } } diff --git a/ui/src/app/edge/live/common/consumption/flat/flat.ts b/ui/src/app/edge/live/common/consumption/flat/flat.ts index 647195ccc79..24a10bbaec6 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/flat/flat.ts @@ -4,7 +4,6 @@ import { EvcsComponent } from "src/app/shared/components/edge/config-components/ import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; import { Modal } from "src/app/shared/components/flat/flat"; import { ChannelAddress, CurrentData, EdgeConfig, Utils } from "src/app/shared/shared"; -import { ArrayUtils } from "src/app/shared/utils/array/array.utils"; import { ModalComponent } from "../modal/modal"; @Component({ @@ -49,8 +48,7 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && isEvcs === false; - }) - .sort(ArrayUtils.alphabetically(c => c.alias)); + }); for (const component of this.consumptionMeters) { channelAddresses.push( @@ -62,8 +60,7 @@ export class CommonConsumptionGeneralComponent extends AbstractFlatWidget { } // Get EVCSs - this.evcss = EvcsComponent.getComponents(this.config, this.edge) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.evcss = EvcsComponent.getComponents(this.config, this.edge); for (const component of this.evcss) { channelAddresses.push( diff --git a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts index b58f6ca3c2c..d5ee33fd30d 100644 --- a/ui/src/app/edge/live/common/consumption/history/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/history/flat/flat.ts @@ -3,7 +3,6 @@ import { Component } from "@angular/core"; import { EvcsComponent } from "src/app/shared/components/edge/config-components/evcs/evcsComponent"; import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; import { ChannelAddress, CurrentData, EdgeConfig } from "../../../../../../shared/shared"; -import { ArrayUtils } from "../../../../../../shared/utils/array/array.utils"; @Component({ selector: "consumptionWidget", @@ -20,14 +19,12 @@ export class FlatComponent extends AbstractFlatWidget { protected override getChannelAddresses(): ChannelAddress[] { const channels: ChannelAddress[] = [new ChannelAddress("_sum", "ConsumptionActiveEnergy")]; - this.evcsComponents = EvcsComponent.getComponents(this.config, this.edge) - .sort(ArrayUtils.alphabetically(c => c.alias)); + this.evcsComponents = EvcsComponent.getComponents(this.config, this.edge); this.heatComponents = this.config?.getComponentsImplementingNature("io.openems.edge.heat.api.Heat") .filter(component => !(component.factoryId === "Controller.Heat.Heatingelement") && - !component.isEnabled === false) - .sort(ArrayUtils.alphabetically(c => c.alias)); + !component.isEnabled === false); channels.push( ...this.heatComponents.map( (component) => new ChannelAddress(component.id, "ActiveProductionEnergy") @@ -42,8 +39,7 @@ export class FlatComponent extends AbstractFlatWidget { return component.isEnabled && this.config?.isTypeConsumptionMetered(component) && isEvcs === false && isHeat === false; - }) - .sort(ArrayUtils.alphabetically(c => c.alias)); + }); return channels; } diff --git a/ui/src/app/edge/live/common/production/flat/flat.ts b/ui/src/app/edge/live/common/production/flat/flat.ts index 10960e79f74..c73d2288b6e 100644 --- a/ui/src/app/edge/live/common/production/flat/flat.ts +++ b/ui/src/app/edge/live/common/production/flat/flat.ts @@ -2,7 +2,6 @@ import { Component } from "@angular/core"; import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; import { Modal } from "src/app/shared/components/flat/flat"; import { EdgeConfig, Utils } from "src/app/shared/shared"; -import { ArrayUtils } from "src/app/shared/utils/array/array.utils"; import { ModalComponent } from "../modal/modal"; @Component({ @@ -29,14 +28,12 @@ export class FlatComponent extends AbstractFlatWidget { // Get Chargers this.chargerComponents = this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") - .filter(component => component.isEnabled) - .sort(ArrayUtils.alphabetically(c => c.alias)); + .filter(component => component.isEnabled); // Get productionMeters this.productionMeterComponents = this.config.getComponentsImplementingNature("io.openems.edge.meter.api.ElectricityMeter") - .filter(component => component.isEnabled && this.config.isProducer(component)) - .sort(ArrayUtils.alphabetically(c => c.alias)); + .filter(component => component.isEnabled && this.config.isProducer(component)); return []; } diff --git a/ui/src/app/shared/components/edge/edgeconfig.ts b/ui/src/app/shared/components/edge/edgeconfig.ts index cbdac8b8830..e1210f5f43f 100644 --- a/ui/src/app/shared/components/edge/edgeconfig.ts +++ b/ui/src/app/shared/components/edge/edgeconfig.ts @@ -1,6 +1,7 @@ import { TranslateService } from "@ngx-translate/core"; import { ChannelAddress } from "../../shared"; import { Widgets } from "../../type/widgets"; +import { ArrayUtils } from "../../utils/array/array.utils"; import { Edge } from "./edge"; export interface CategorizedComponents { @@ -410,7 +411,7 @@ export class EdgeConfig { for (const componentId of componentIds) { result.push(this.components[componentId]); } - return result; + return result.sort(ArrayUtils.alphabetically(c => c.alias)); } /** @@ -475,7 +476,7 @@ export class EdgeConfig { result.push(...this.getComponentsImplementingNature("io.openems.edge.meter.api.SymmetricMeter")); } - return result; + return result.sort(ArrayUtils.alphabetically(c => c.alias)); } /**