((resolve) => {
+ let indexToSplit: number = 0;
+
+ const interval = setInterval(() => {
+ if (this.subnavigationbuttons && this.container) {
+
+ const colLeftPadding = 16;
+ const paddingLeftRight = 24;
+ const ionItemWidth = this.container?.nativeElement.offsetWidth - colLeftPadding;
+ if (ionItemWidth) {
+
+ let sum: number = colLeftPadding;
+ this.subnavigationbuttons.forEach((b, index, el) => {
+ sum += b.nativeElement.offsetWidth + paddingLeftRight;
+ if ((ionItemWidth) > sum) {
+ indexToSplit = index;
+ }
+ });
+
+ // Workaround
+ if (ionItemWidth > sum) {
+ ++indexToSplit;
+ }
+
+ clearInterval(interval);
+ resolve(indexToSplit);
+ }
+ }
+ }, FooterNavigationComponent.INTERVAL);
+ });
+ }
+}
diff --git a/ui/src/app/shared/genericComponents/genericComponents.ts b/ui/src/app/shared/genericComponents/genericComponents.ts
index 417ac36b721..7136735eded 100644
--- a/ui/src/app/shared/genericComponents/genericComponents.ts
+++ b/ui/src/app/shared/genericComponents/genericComponents.ts
@@ -13,6 +13,7 @@ import { FlatWidgetHorizontalLineComponent } from './flat/flat-widget-horizontal
import { FlatWidgetLineComponent } from './flat/flat-widget-line/flat-widget-line';
import { FlatWidgetLineItemComponent } from './flat/flat-widget-line/flat-widget-line-item/flat-widget-line-item';
import { FlatWidgetPercentagebarComponent } from './flat/flat-widget-percentagebar/flat-widget-percentagebar';
+import { FooterNavigationComponent } from './footer-navigation/footerNavigation';
import { HelpButtonComponent } from './modal/help-button/help-button';
import { ModalComponent } from './modal/modal';
import { ModalButtonsComponent } from './modal/modal-button/modal-button';
@@ -59,6 +60,7 @@ import { NotificationComponent } from './shared/notification/notification';
PickDateComponent,
HelpButtonComponent,
NotificationComponent,
+ FooterNavigationComponent,
],
exports: [
// Flat
@@ -85,6 +87,7 @@ import { NotificationComponent } from './shared/notification/notification';
PickDateComponent,
HelpButtonComponent,
NotificationComponent,
+ FooterNavigationComponent,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
diff --git a/ui/src/app/shared/genericComponents/shared/converter.ts b/ui/src/app/shared/genericComponents/shared/converter.ts
index 12458d38a0e..4054c9f9ec0 100644
--- a/ui/src/app/shared/genericComponents/shared/converter.ts
+++ b/ui/src/app/shared/genericComponents/shared/converter.ts
@@ -1,6 +1,7 @@
// @ts-strict-ignore
import { TranslateService } from "@ngx-translate/core";
+
import { CurrentData, EdgeConfig, Utils } from "../../shared";
import { TimeUtils } from "../../utils/time/timeutils";
import { Formatter } from "./formatter";
diff --git a/ui/src/app/shared/genericComponents/shared/dataservice.ts b/ui/src/app/shared/genericComponents/shared/dataservice.ts
index 7af1ff7bb55..c43aad16467 100644
--- a/ui/src/app/shared/genericComponents/shared/dataservice.ts
+++ b/ui/src/app/shared/genericComponents/shared/dataservice.ts
@@ -3,6 +3,7 @@ import { Injectable } from "@angular/core";
import { BehaviorSubject, Subject } from "rxjs";
import { ChannelAddress, Edge } from "../../shared";
+import { RefresherCustomEvent } from "@ionic/angular";
@Injectable()
export abstract class DataService {
@@ -29,4 +30,6 @@ export abstract class DataService {
* @param channels the channels
*/
public abstract unsubscribeFromChannels(channels: ChannelAddress[]);
+
+ public abstract refresh(ev: RefresherCustomEvent);
}
diff --git a/ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts b/ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts
new file mode 100644
index 00000000000..b5ed8cf783e
--- /dev/null
+++ b/ui/src/app/shared/jsonrpc/request/getPropertiesOfFactoryRequest.ts
@@ -0,0 +1,33 @@
+
+import { JsonrpcRequest } from "../base";
+
+/**
+ * Represents a JSON-RPC Request to get properties and the factory of a factoryId.
+ *
+ *
+ * This is used by UI to get the properties for component update and installation.
+ *
+ *
+ * {
+ * "jsonrpc": "2.0",
+ * "id": "UUID",
+ * "method": "getPropertiesOfFactory",
+ * "params": {
+ * "factoryId": string
+ * }
+ * }
+ *
+ */
+export class GetPropertiesOfFactoryRequest extends JsonrpcRequest {
+
+ private static METHOD: string = "getPropertiesOfFactory";
+
+ public constructor(
+ params: {
+ factoryId: string,
+ },
+ ) {
+ super(GetPropertiesOfFactoryRequest.METHOD, params);
+ }
+
+}
diff --git a/ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts b/ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts
new file mode 100644
index 00000000000..7ca2647c505
--- /dev/null
+++ b/ui/src/app/shared/jsonrpc/response/getPropertiesOfFactoryResponse.ts
@@ -0,0 +1,31 @@
+import { EdgeConfig } from "../../edge/edgeconfig";
+import { JsonrpcResponseSuccess } from "../base";
+
+/**
+ * Represents a JSON-RPC Response for a {@link GetPropertiesOfFactoryResponse}.
+ *
+ *
+ * {
+ * "jsonrpc": "2.0",
+ * "id": UUID,
+ * "result": {
+ * "factory": EdgeConfig.Factory,
+ * "properties": EdgeConfig.FactoryProperty[]
+ * }
+ * }
+ *
+ */
+export class GetPropertiesOfFactoryResponse extends JsonrpcResponseSuccess {
+
+ public constructor(
+ public override readonly id: string,
+ public override readonly result: {
+ factory: EdgeConfig.Factory,
+ properties: EdgeConfig.FactoryProperty[],
+ },
+ ) {
+ super(id, result);
+ }
+
+}
+
diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts
index 64997f0428c..fb192b6ae74 100644
--- a/ui/src/app/shared/service/service.ts
+++ b/ui/src/app/shared/service/service.ts
@@ -169,14 +169,10 @@ export class Service extends AbstractService {
public getConfig(): Promise {
return new Promise((resolve, reject) => {
this.getCurrentEdge().then(edge => {
- edge.getConfig(this.websocket).pipe(
- filter(config => config != null && config.isValid()),
- first(),
- ).toPromise()
- .then(config => resolve(config))
- .catch(reason => reject(reason));
- })
- .catch(reason => reject(reason));
+ edge.getFirstValidConfig(this.websocket)
+ .then(resolve)
+ .catch(reject);
+ }).catch(reason => reject(reason));
});
}
diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts
index c751bfd0527..8f3b5d125fd 100644
--- a/ui/src/app/shared/service/utils.ts
+++ b/ui/src/app/shared/service/utils.ts
@@ -659,7 +659,7 @@ export namespace HistoryUtils {
export type DisplayValues = {
name: string,
/** suffix to the name */
- nameSuffix?: (energyValues: QueryHistoricTimeseriesEnergyResponse) => number | string,
+ nameSuffix?: (energyValues: QueryHistoricTimeseriesEnergyResponse) => number | string | null,
/** Convert the values to be displayed in Chart */
converter: () => any,
/** If dataset should be hidden on Init */
diff --git a/ui/src/app/shared/service/websocket.ts b/ui/src/app/shared/service/websocket.ts
index a6295c1dbb9..2cfa39ac454 100644
--- a/ui/src/app/shared/service/websocket.ts
+++ b/ui/src/app/shared/service/websocket.ts
@@ -82,6 +82,7 @@ export class Websocket implements WebsocketInterface {
}
const token = this.cookieService.get('token');
if (token) {
+
// Login with Session Token
this.login(new AuthenticateWithTokenRequest({ token: token }));
this.status = 'authenticating';
@@ -89,7 +90,6 @@ export class Websocket implements WebsocketInterface {
} else {
// No Token -> directly ask for Login credentials
this.status = 'waiting for credentials';
- this.router.navigate(['/login']);
}
},
},
diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts
index 12eb25994cb..86e15a76d18 100644
--- a/ui/src/app/shared/shared.ts
+++ b/ui/src/app/shared/shared.ts
@@ -70,6 +70,19 @@ export class EdgePermission {
return !edge.isVersionAtLeast('2024.6.1');
}
+ /**
+ * Determines if the edge has only the factories which are used by the
+ * active components in the edgeconfig or if all factories are inlcuded.
+ *
+ * The reason this was introduced is to reduce the size of the EdgeConfig
+ * and therefore improve performance in network, backend, ui, edge.
+ *
+ * @returns true if only the factories of the used components are in the edgeconfig
+ */
+ public static hasReducedFactories(edge: Edge): boolean {
+ return edge.isVersionAtLeast('2024.6.1');
+ }
+
}
export class UserPermission {
diff --git a/ui/src/app/shared/status/single/status.component.spec.ts b/ui/src/app/shared/status/single/status.component.spec.ts
index 7499acb1944..4f92151f8fb 100644
--- a/ui/src/app/shared/status/single/status.component.spec.ts
+++ b/ui/src/app/shared/status/single/status.component.spec.ts
@@ -12,7 +12,7 @@ describe('StatusComponent', () => {
const testComponent = new EdgeConfig.Component("test", {}, {
"testChannel": {
accessMode: "RO",
- category: "ENUM",
+ category: "STATE",
type: "BOOLEAN",
unit: "W",
level: "OK",
diff --git a/ui/src/app/shared/status/single/status.component.ts b/ui/src/app/shared/status/single/status.component.ts
index c1d8c019409..c203e873a27 100644
--- a/ui/src/app/shared/status/single/status.component.ts
+++ b/ui/src/app/shared/status/single/status.component.ts
@@ -82,6 +82,12 @@ export class StatusSingleComponent implements OnInit, OnDestroy {
if (EdgePermission.hasChannelsInEdgeConfig(this.edge)) {
const channels: typeof this.channels['componentId'] = {};
for (const [key, value] of Object.entries(this.config.components[componentId].channels)) {
+
+ // show only state channels
+ if (value.category !== "STATE") {
+ continue;
+ }
+
channels[key] = { text: value.text, level: value.level };
}
resolve(channels);
diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json
index fbd56096e39..b582b58c8b2 100644
--- a/ui/src/assets/i18n/de.json
+++ b/ui/src/assets/i18n/de.json
@@ -954,5 +954,8 @@
"SET_VALUE": "Eingestellter Wert",
"MORE_CHANNELS": "Weitere Kanäle hinzufügen",
"CHANNEL": "Kanal"
+ },
+ "APP": {
+ "FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE": "Diese Funktion ist vorübergehend in der App nicht verfügbar, verwenden Sie bitte dafür die Web-App."
}
-}
+}
\ No newline at end of file
diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json
index 3b4def7a994..70acb7994e9 100644
--- a/ui/src/assets/i18n/en.json
+++ b/ui/src/assets/i18n/en.json
@@ -957,5 +957,8 @@
"SET_VALUE": "Set value",
"MORE_CHANNELS": "Add More Channels",
"CHANNEL": "Channel"
+ },
+ "APP": {
+ "FUNCTIONALITY_TEMPORARILY_NOT_AVAILABLE": "This function is temporarily not available in the app, please use the web app instead."
}
-}
+}
\ No newline at end of file