From af9aaea28b6cac8f0ef5f670bd0c413b6cc281d7 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Sat, 31 Aug 2024 15:15:06 +0200 Subject: [PATCH 01/24] Start development of version 2024.10.0-SNAPSHOT --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 4 ++-- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/changelog/view/component/changelog.constants.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index 69b49e779e..cbfc12274f 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -22,7 +22,7 @@ public class OpenemsConstants { *

* This is the month of the release. */ - public static final short VERSION_MINOR = 9; + public static final short VERSION_MINOR = 10; /** * The patch version of OpenEMS. @@ -36,7 +36,7 @@ public class OpenemsConstants { /** * The additional version string. */ - public static final String VERSION_STRING = ""; + public static final String VERSION_STRING = "SNAPSHOT"; /** * The complete version as a SemanticVersion. diff --git a/ui/package-lock.json b/ui/package-lock.json index edc7956ab6..57e8255f84 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.9.0", + "version": "2024.10.0-SNAPSHOT", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.9.0", + "version": "2024.10.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "18.0.5", diff --git a/ui/package.json b/ui/package.json index 0e232477e3..8f0c436942 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.9.0", + "version": "2024.10.0-SNAPSHOT", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 99de881dd8..700da6a26c 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.9.0"; + public static readonly UI_VERSION = "2024.10.0-SNAPSHOT"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + ". "; From 6eb132474792e9df11bea45d192322b36050a140 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 2 Sep 2024 20:54:04 +0200 Subject: [PATCH 02/24] UI: modularize translation files & pageTitle fallback - Adding possibility to modularize translation files - add fallback for currentPageTitle Reviewed-by: Sagar Venu <32655208+venu-sagar@users.noreply.github.com> Reviewed-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-committed-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> --- ui/src/app/edge/edge.component.ts | 2 -- .../service/globalRouteChangeHandler.ts | 3 ++- ui/src/app/shared/type/language.ts | 23 ++++++++++++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ui/src/app/edge/edge.component.ts b/ui/src/app/edge/edge.component.ts index fdeeebc3a3..c0acc0aa95 100644 --- a/ui/src/app/edge/edge.component.ts +++ b/ui/src/app/edge/edge.component.ts @@ -10,8 +10,6 @@ import { ChannelAddress, Edge, Service, Websocket } from "src/app/shared/shared" template: ` - `, }) export class EdgeComponent implements OnInit, OnDestroy { diff --git a/ui/src/app/shared/service/globalRouteChangeHandler.ts b/ui/src/app/shared/service/globalRouteChangeHandler.ts index 17d628c4fa..8992c77e7a 100644 --- a/ui/src/app/shared/service/globalRouteChangeHandler.ts +++ b/ui/src/app/shared/service/globalRouteChangeHandler.ts @@ -4,6 +4,7 @@ import { Router, RoutesRecognized } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import { filter, map } from "rxjs/operators"; +import { environment } from "src/environments"; import { Service } from "./service"; @Injectable({ @@ -35,7 +36,7 @@ export class GlobalRouteChangeHandler { throw new Error("Either use navbarTitle or navbarTitleToBeTranslated"); } - this.service.currentPageTitle = e.navbarTitle ?? (e.navbarTitleToBeTranslated ? translate.instant(e.navbarTitleToBeTranslated) : null) ?? this.service.currentPageTitle; + this.service.currentPageTitle = e.navbarTitle ?? (e.navbarTitleToBeTranslated ? translate.instant(e.navbarTitleToBeTranslated) : null) ?? this.service.currentPageTitle ?? environment.uiTitle; }); } } diff --git a/ui/src/app/shared/type/language.ts b/ui/src/app/shared/type/language.ts index 79a88549ab..b76c3dd2d8 100644 --- a/ui/src/app/shared/type/language.ts +++ b/ui/src/app/shared/type/language.ts @@ -13,8 +13,9 @@ import es from "src/assets/i18n/es.json"; import fr from "src/assets/i18n/fr.json"; import ja from "src/assets/i18n/ja.json"; import nl from "src/assets/i18n/nl.json"; +import { environment } from "src/environments"; -interface Translation { +export interface Translation { [key: string]: string | Translation; } @@ -107,4 +108,24 @@ export class Language { return lang?.i18nLocaleKey ?? Language.DEFAULT.i18nLocaleKey; } + + /** + * Sets a additional translation file + * + * e.g. AdvertismentModule + * + * @param translationFile the translation file + * @returns translations params + */ + public static setAdditionalTranslationFile(translationFile: any): { lang: string, translations: {}, shouldMerge?: boolean } { + let key = localStorage.LANGUAGE ?? Language.DEFAULT.key; + if (!(key in translationFile)) { + + if (environment.debugMode) { + console.warn(`[Advert] No translation available for Language ${key}. Implemented languages are: ${Object.keys(translationFile)}`); + } + key = Language.DEFAULT.key; + } + return { lang: key, translations: translationFile[key], shouldMerge: true }; + } } From 07075d137296c9e7520aa9a01395b104649a68b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:43:47 +0200 Subject: [PATCH 03/24] Build(deps): Bump org.dhatim:fastexcel from 0.18.1 to 0.18.2 in /cnf (#2772) * Build(deps): Bump org.dhatim:fastexcel from 0.18.1 to 0.18.2 in /cnf Bumps [org.dhatim:fastexcel](https://github.com/dhatim/fastexcel) from 0.18.1 to 0.18.2. - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.1...0.18.2) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Build(deps): Bump org.dhatim:fastexcel-reader in /cnf Bumps [org.dhatim:fastexcel-reader](https://github.com/dhatim/fastexcel) from 0.18.1 to 0.18.2. - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.1...0.18.2) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel-reader dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun + dependabot.yml --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- .github/dependabot.yml | 4 ++++ cnf/pom.xml | 4 ++-- io.openems.backend.application/BackendApp.bndrun | 4 ++-- io.openems.edge.application/EdgeApp.bndrun | 4 ++-- io.openems.wrapper/bnd.bnd | 4 ++-- io.openems.wrapper/fastexcel.bnd | 6 +++--- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a7dddbfd65..37fcbfbbc5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,6 +10,10 @@ updates: influxdb: patterns: - "com.influxdb:*" + fastexcel: + patterns: + - "org.dhatim:fastexcel" + - "org.dhatim:fastexcel-reader" - package-ecosystem: npm directory: "/ui" diff --git a/cnf/pom.xml b/cnf/pom.xml index fe40c659af..56115404f1 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -260,12 +260,12 @@ org.dhatim fastexcel - 0.18.1 + 0.18.2 org.dhatim fastexcel-reader - 0.18.1 + 0.18.2 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 923ac4c24c..8edfd8287e 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -101,8 +101,8 @@ io.openems.wrapper.retrofit-converter-scalars;version=snapshot,\ io.openems.wrapper.retrofit2;version=snapshot,\ io.reactivex.rxjava3.rxjava;version='[3.1.9,3.1.10)',\ - org.apache.commons.commons-codec;version='[1.17.0,1.17.1)',\ - org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ + org.apache.commons.commons-codec;version='[1.17.1,1.17.2)',\ + org.apache.commons.commons-compress;version='[1.27.1,1.27.2)',\ org.apache.commons.commons-csv;version='[1.11.0,1.11.1)',\ org.apache.commons.commons-io;version='[2.16.1,2.16.2)',\ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index c621ec4d94..1e489ec354 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -396,8 +396,8 @@ io.reactivex.rxjava3.rxjava;version='[3.1.9,3.1.10)',\ javax.jmdns;version='[3.4.1,3.4.2)',\ javax.xml.soap-api;version='[1.4.0,1.4.1)',\ - org.apache.commons.commons-codec;version='[1.17.0,1.17.1)',\ - org.apache.commons.commons-compress;version='[1.26.2,1.26.3)',\ + org.apache.commons.commons-codec;version='[1.17.1,1.17.2)',\ + org.apache.commons.commons-compress;version='[1.27.1,1.27.2)',\ org.apache.commons.commons-csv;version='[1.11.0,1.11.1)',\ org.apache.commons.commons-io;version='[2.16.1,2.16.2)',\ org.apache.commons.math3;version='[3.6.1,3.6.2)',\ diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index 8bed7415c1..250390423e 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -24,7 +24,7 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea com.google.gson;version='2.10.1',\ de.bytefish:pgbulkinsert;version='8.1.4',\ fr.turri:aXMLRPC;version='1.13.0',\ - org.dhatim:fastexcel;version='0.18.1',\ - org.dhatim:fastexcel-reader;version='0.18.1',\ + org.dhatim:fastexcel;version='0.18.2',\ + org.dhatim:fastexcel-reader;version='0.18.2',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ diff --git a/io.openems.wrapper/fastexcel.bnd b/io.openems.wrapper/fastexcel.bnd index e3fa142345..5e05cab91a 100644 --- a/io.openems.wrapper/fastexcel.bnd +++ b/io.openems.wrapper/fastexcel.bnd @@ -1,11 +1,11 @@ Bundle-Name: fastexcel Bundle-DocURL: https://github.com/dhatim/fastexcel Bundle-License: https://opensource.org/licenses/Apache-2.0 -Bundle-Version: 0.18.1 +Bundle-Version: 0.18.2 Include-Resource: \ - @fastexcel-0.18.1.jar,\ - @fastexcel-reader-0.18.1.jar,\ + @fastexcel-0.18.2.jar,\ + @fastexcel-reader-0.18.2.jar,\ -dsannotations: * From aeb561e9829a9bd6b38be4a60b75b38e33685e08 Mon Sep 17 00:00:00 2001 From: "Kai J." Date: Tue, 3 Sep 2024 14:45:13 +0200 Subject: [PATCH 04/24] Contribution Guidelines & Code of Conduct (#2780) Add: - .github/CONTRIBUTING.md - .github/CODE_OF_CONDUCT.md Update: - .github/ISSUE_TEMPLATE --- .github/CODE_OF_CONDUCT.md | 133 +++++++++++++++++++++ .github/CONTRIBUTING.md | 52 ++++++++ .github/ISSUE_TEMPLATE.md | 14 --- .github/ISSUE_TEMPLATE/bug-report.yml | 38 ++++++ .github/ISSUE_TEMPLATE/config.yml | 8 ++ .github/ISSUE_TEMPLATE/feature-request.yml | 29 +++++ .github/ISSUE_TEMPLATE/hacktober.yml | 70 +++++++++++ README.md | 1 + 8 files changed, 331 insertions(+), 14 deletions(-) create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/CONTRIBUTING.md delete mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml create mode 100644 .github/ISSUE_TEMPLATE/hacktober.yml diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..c56eb39bb9 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,133 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official email address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at office@openems.io. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations + diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000000..16b23745db --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,52 @@ +# Contributing + +- [๐Ÿ“œ Contributor License Agreement](#-contributor-license-agreement) +- [๐Ÿค Contributor Code of Conduct](#-contributor-code-of-conduct) +- [๐Ÿชฒ Bug Reports, Issues and Questions](#-bug-reports-issues-and-questions) +- [๐Ÿ’ก Feature Requests](#-feature-requests) +- [๐Ÿ–Œ๏ธ Coding Style](#๏ธ-coding-style) +- [๐Ÿ“ Documentation](#-documentation) + +## ๐Ÿ“œ Contributor License Agreement + +By contributing, you agree to the Licenses of this repository: + +- OpenEMS Edge und Backend + + [Eclipse Public License version 2.0](../LICENSE-EPL-2.0) + +- OpenEMS UI + + [GNU Affero General Public License version 3](../LICENSE-AGPL-3.0) + +## ๐Ÿค Contributor Code of Conduct + +By contributing, you agree to respect the [Code of Conduct](CODE_OF_CONDUCT.md) of this repository. + +## ๐Ÿชฒ Bug Reports, Issues and Questions + +A great way to contribute to the project is to send a detailed report when you encounter an issue. We always appreciate a well-written, thorough bug report, and will thank you for it! + +To maintain clear and organized communication, all discussions should take place in the [OpenEMS Community forum](https://community.openems.io/). This helps keep everything together and ensures that conversations are streamlined and accessible to all contributors. + +โš ๏ธ *Please refrain from opening empty pull requests solely for the purpose of discussing ideas. Instead, utilize the forum to share and refine your concepts before submitting any code changes.* + +## ๐Ÿ’ก Feature Requests + +Similar to issue reports, feature requests should be submitted to the [OpenEMS Community forum](https://community.openems.io/) for discussion. This helps ensure that all ideas are properly reviewed and discussed by the community. + +When submitting a feature request, please be clear about the intended outcome and how it would relate to existing features. Providing detailed information helps in evaluating the request more effectively. + +โš ๏ธ *Additionally, avoid submitting duplicate feature requests. Before posting, search for existing requests, and if you find a similar or identical one, please join that discussion instead of creating a new thread.* + +## ๐Ÿ–Œ๏ธ Coding Style + +We welcome pull-requests! While we will consider all submissions, we cannot promise that every request will be accepted. + +To increase your changes of a merged pull-requests and help us review your code, please follow our [coding guidelines](https://openems.github.io/openems.io/openems/latest/contribute/coding-guidelines.html). + +## ๐Ÿ“ Documentation + +The documentation site for OpenEMS is hosted on [https://openems.github.io/openems.io/openems/latest](https://openems.github.io/openems.io/openems/latest). We greatly appreciate contributions that improve the quality and clarity of our documentation. + +If you would like to contribute by updating or adding a page, please refer to our [Contribute/Documentation](https://openems.github.io/openems.io/openems/latest/contribute/documentation.html) guide for detailed instructions on how to contribute effectively to the OpenEMS documentation. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index e81592e5d4..0000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,14 +0,0 @@ - -### Bug Report or Feature Request (mark with an `x`) -``` -- [ ] bug report -> please search issues before submitting -- [ ] feature request -``` - -### Bug description or desired functionality. - diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000000..27690e4ce3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,38 @@ +name: Bug Report +description: Found something you weren't expecting? Report it here! +labels: ["type/bug"] +body: + - type: markdown + attributes: + value: | + 1. Please speak English, this is the language all maintainers can speak and write. + 2. Please ask questions or configuration/deploy problems on our [Community forum](https://community.openems.io/). + 3. Make sure you are using the latest release and + take a moment to check that your issue hasn't been reported before. + 4. It's really important to provide pertinent details and logs. + - type: textarea + id: description + attributes: + label: Description + description: | + Please provide a description of your issue here. + validations: + required: true + - type: textarea + id: screenshots + attributes: + label: Screenshots + description: Please provide one or more screenshots, if feasible. + - type: input + id: os-ver + attributes: + label: Operating System + description: The operating system you are running on. + - type: textarea + id: reproduce-info + attributes: + label: How to reproduce the Error? + description: | + Please provide step-by-step instructions on how to reproduce the error. + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..fe2aaeb311 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: OpenEMS.io + url: https://openems.io/ + about: News and general information are posted here. + - name: OpenEMS Community + url: https://community.openems.io/ + about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000000..c27dc9306d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,29 @@ +name: Feature Request +description: Got an idea for a feature that OpenEMS is still missing? Submit your idea here! +labels: ["type/enhancement"] +body: + - type: markdown + attributes: + value: | + 1. Please speak English, this is the language all maintainers can speak and write. + 2. Please ask questions or configuration/deploy problems on our [Community forum](https://community.openems.io/). + 3. Please take a moment to check that your feature hasn't already been suggested. + - type: dropdown + id: component + attributes: + label: Component + description: Select the relevant component for this feature request. + options: + - "Edge" + - "UI" + - "Backend" + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + placeholder: | + What is the use case? + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/hacktober.yml b/.github/ISSUE_TEMPLATE/hacktober.yml new file mode 100644 index 0000000000..5a0bb4e6a4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/hacktober.yml @@ -0,0 +1,70 @@ +name: Hacktoberfest +description: Perfect contribution for Hacktoberfest +labels: ["hacktoberfest"] +body: + - type: markdown + attributes: + value: | + 1. Please speak English, this is the language all maintainers can speak and write. + - type: dropdown + id: type + attributes: + label: Contribution Type + description: Select the relevant Contribution type. + options: + - "Feature" + - "Bug Fix" + - "Documentation" + validations: + required: true + - type: dropdown + id: component + attributes: + label: Component + description: Select the relevant component for this feature request. + options: + - "Edge" + - "UI" + - "Backend" + validations: + required: true + - type: dropdown + id: contributor-level + attributes: + label: Contributor Level + description: What OpenEMS knowledge level is required for the task? + options: + - "Newbie" + - "Casual" + - "Expert" + validations: + required: true + - type: textarea + id: description + attributes: + label: Description + placeholder: | + What purpose does the task serve? + validations: + required: true + - type: textarea + id: definition-of-done + attributes: + label: Definition of Done + placeholder: | + What result is expected? + validations: + required: true + - type: textarea + id: difficulties + attributes: + label: Difficulties + placeholder: | + What difficulties may occur? + - type: markdown + attributes: + value: | + --- + - *For questions and suggestions please interact with the [community](https://community.openems.io/).* + - *Do you need help getting started? Then please read the documentation [documentation](https://openems.github.io/openems.io/openems/latest/introduction.html).* + - *Also read our [contribution guidelines](https://github.com/OpenEMS/openems/blob/develop/.github/CONTRIBUTING.md) before submitting code suggestions.* \ No newline at end of file diff --git a/README.md b/README.md index 09bf75eeaa..519047007e 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ OpenEMS is generally used in combination with external hardware and software com * Open up a [Live-Demo on Gitpod](https://gitpod.io/#https://github.com/OpenEMS/openems) * Follow the [Getting Started](https://openems.github.io/openems.io/openems/latest/gettingstarted.html) guide to setup OpenEMS on your own computer +* Please checkout our [contribution guidelines](CONTRIBUTING.md) before submitting code ## Documentation From b7b3847b2a3297be35aa5cec45f49df0ebe4f0bd Mon Sep 17 00:00:00 2001 From: luzpaz Date: Tue, 3 Sep 2024 09:46:25 -0400 Subject: [PATCH 05/24] Fix various typos (#2730) * Fix various typos Found via `codespell -q 3 -S "./.git,*.pdf,*.po,*.pot,*.ts" -L abl,addess,afe,als,atleast,ba,corrently,datas,ist,plattform,pres,repid,sie` --------- Co-authored-by: Stefan Feilmeier --- doc/modules/ROOT/pages/gettingstarted.adoc | 2 +- doc/modules/ROOT/pages/intellij.adoc | 2 +- io.openems.backend.timedata.aggregatedinflux/readme.adoc | 4 ++-- .../src/io/openems/common/websocket/MyDraft6455.java | 4 ++-- .../edge/battery/fenecon/home/BatteryFeneconHomeImpl.java | 2 +- .../com/dalsemi/onewire/adapter/MulticastListener.java | 2 +- .../src/com/dalsemi/onewire/adapter/RawSendPacket.java | 2 +- .../src/com/dalsemi/onewire/adapter/UAdapterState.java | 2 +- .../src/com/dalsemi/onewire/adapter/USerialAdapter.java | 2 +- .../src/com/dalsemi/onewire/application/file/OWFile.java | 2 +- .../onewire/application/file/OWFileInputStream.java | 2 +- .../onewire/application/file/OWFileOutputStream.java | 2 +- .../dalsemi/onewire/container/MemoryBankEEPROMstatus.java | 2 +- .../dalsemi/onewire/container/MemoryBankScratchSHAEE.java | 2 +- .../com/dalsemi/onewire/container/OneWireContainer33.java | 8 ++++---- .../com/dalsemi/onewire/container/OneWireContainer37.java | 2 +- .../com/dalsemi/onewire/container/OneWireContainer41.java | 2 +- .../ess/fixstateofcharge/ConfigFixStateOfCharge.java | 2 +- .../fixstateofcharge/ConfigPrepareBatteryExtension.java | 2 +- .../ess/fixstateofcharge/api/ConfigProperties.java | 2 +- .../io/openems/edge/controller/ess/limiter14a/Config.java | 2 +- .../src/io/openems/edge/core/appmanager/AppDef.java | 2 +- .../io/openems/edge/core/appmanager/AppManagerImpl.java | 4 ++-- .../edge/core/appmanager/translation_en.properties | 4 ++-- .../src/io/openems/edge/energy/optimizer/Params.java | 2 +- .../src/io/openems/edge/energy/optimizer/ParamsUtils.java | 2 +- .../ess/core/power/solver/nearequal/SolveNearEqual.java | 2 +- .../io/openems/edge/evcs/hypercharger/AvailableState.java | 2 +- io.openems.edge.evcs.cluster/readme.adoc | 2 +- .../edge/evcs/webasto/next/enums/EvseErrorCode.java | 2 +- .../src/io/openems/edge/io/gpio/linuxfs/Gpio.java | 2 +- .../src/com/ed/data/BatteryData.java | 2 +- io.openems.edge.katek.edcom/src/com/ed/data/History.java | 2 +- io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java | 4 ++-- .../io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java | 2 +- ui/src/app/edge/history/history.component.ts | 4 ++-- 36 files changed, 45 insertions(+), 45 deletions(-) diff --git a/doc/modules/ROOT/pages/gettingstarted.adoc b/doc/modules/ROOT/pages/gettingstarted.adoc index 345571185f..6ecd5effb4 100644 --- a/doc/modules/ROOT/pages/gettingstarted.adoc +++ b/doc/modules/ROOT/pages/gettingstarted.adoc @@ -236,7 +236,7 @@ image::openems-ui-login.png[OpenEMS UI Login screen] .OpenEMS UI Energymonitor screen image::openems-ui-edge-overview.png[OpenEMS UI Energymonitor screen] -_Unfortunately the hosted version of OpenEMS UI is currently slightly outdated and incompatble with latest OpenEMS Edge. Follow the xref:ui/setup-ide.adoc[OpenEMS UI guide] to produce the following visualization. The language can be changed in the "burger menu" on top left -> btn:[admin] -> btn:[Allgemeine Einstellungen]._ +_Unfortunately the hosted version of OpenEMS UI is currently slightly outdated and incompatible with latest OpenEMS Edge. Follow the xref:ui/setup-ide.adoc[OpenEMS UI guide] to produce the following visualization. The language can be changed in the "burger menu" on top left -> btn:[admin] -> btn:[Allgemeine Einstellungen]._ .OpenEMS UI Energymonitor screen image::openems-ui-edge-overview2.png[OpenEMS UI Energymonitor screen] diff --git a/doc/modules/ROOT/pages/intellij.adoc b/doc/modules/ROOT/pages/intellij.adoc index de14e90997..e1ff054626 100644 --- a/doc/modules/ROOT/pages/intellij.adoc +++ b/doc/modules/ROOT/pages/intellij.adoc @@ -36,7 +36,7 @@ image::intellij-import-bnd.png[] + .build.gradle image::intellij-build-gradle.png[] -.. or alternativly make an configuration "edit configuration" +.. or alternatively make an configuration "edit configuration" + .build gradle over configuration image::intellij-add-configuration.png[] diff --git a/io.openems.backend.timedata.aggregatedinflux/readme.adoc b/io.openems.backend.timedata.aggregatedinflux/readme.adoc index 077f29c83f..b1cd9297cf 100644 --- a/io.openems.backend.timedata.aggregatedinflux/readme.adoc +++ b/io.openems.backend.timedata.aggregatedinflux/readme.adoc @@ -45,7 +45,7 @@ This list must be adopted to a concrete usecase. It strongly depends on * your strategy to select component-IDs. * the components you are using within OpenEMS. -If you detect some widgets within your OpenEMS-UI which hava empty values, +If you detect some widgets within your OpenEMS-UI which have empty values, it may have to do with an incorrect hardcoded list. ==== @@ -57,7 +57,7 @@ the following configuration may provide a good start setup: *Create database and set retention policy:* -Before starting the OpenEMS backend and after intially setting up the influx servers, +Before starting the OpenEMS backend and after initially setting up the influx servers, you need to create the databases `influx0` and `aggregated0` and some retention policies: diff --git a/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java b/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java index a89e41b5d3..3f549c9cb4 100644 --- a/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java +++ b/io.openems.common/src/io/openems/common/websocket/MyDraft6455.java @@ -920,8 +920,8 @@ public void processFrame(WebSocketImpl webSocketImpl, Framedata frame) throws In } else if (curop == Opcode.BINARY) { this.processFrameBinary(webSocketImpl, frame); } else { - this.log.error("non control or continious frame expected"); - throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "non control or continious frame expected"); + this.log.error("non control or continuous frame expected"); + throw new InvalidDataException(CloseFrame.PROTOCOL_ERROR, "non control or continuous frame expected"); } } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImpl.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImpl.java index c941c32eab..efa68f7d43 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImpl.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImpl.java @@ -369,7 +369,7 @@ private void detectHardwareType() throws OpenemsException { /** * Get GoodWe hardware version from register value. * - * @param value Register value not formated with SCALE_FACTOR_MINUS_1 + * @param value Register value not formatted with SCALE_FACTOR_MINUS_1 * @return type as {@link GoodweHardwareType} or null */ public static BatteryFeneconHomeHardwareType parseHardwareTypeFromRegisterValue(int value) { diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/MulticastListener.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/MulticastListener.java index 73965b9d85..1b509c0c83 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/MulticastListener.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/MulticastListener.java @@ -34,7 +34,7 @@ import java.net.UnknownHostException; /** - * Generic Mulitcast broadcast listener. Listens for a specific message and, in + * Generic Multicast broadcast listener. Listens for a specific message and, in * response, gives the specified reply. Used by NetAdapterHost for automatic * discovery of host components for the network-based DSPortAdapter. * diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/RawSendPacket.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/RawSendPacket.java index 538990d113..3887723978 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/RawSendPacket.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/RawSendPacket.java @@ -57,7 +57,7 @@ class RawSendPacket { // -------- /** - * Construct and initiailize the raw send packet + * Construct and initialize the raw send packet */ public RawSendPacket() { this.buffer = new StringBuilder(); diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java index 4aa06613e0..ed93664f6c 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java @@ -148,7 +148,7 @@ class UAdapterState { /** * This is the current 'real' speed that the OneWire is operating at. This is - * used to represent the actual mode that the DS2480 is operting in. For example + * used to represent the actual mode that the DS2480 is operating in. For example * the logical speed might be USPEED_REGULAR but for RF emission reasons we may * put the actual DS2480 in SPEED_FLEX. *

diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/USerialAdapter.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/USerialAdapter.java index 86062ea2a5..fae5e1ee21 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/USerialAdapter.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/USerialAdapter.java @@ -2305,7 +2305,7 @@ private boolean uAdapterPresent() throws OneWireException { /** * Do a master reset on the DS2480. This reduces the baud rate to 9600 and - * peforms a break. A single timing byte is then sent. + * performs a break. A single timing byte is then sent. */ private void uMasterReset() { if (doDebugMessages) { diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFile.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFile.java index 2ecb30f573..577852c3d0 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFile.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFile.java @@ -145,7 +145,7 @@ *

  • File/directory names are not case sensitive and will be automatically * changed to all-CAPS *
  • Only files can have extensions - *
  • Extensions are numberical in the range 0 to 125 + *
  • Extensions are numerical in the range 0 to 125 *
  • Extensions 100 to 125 are special purpose and not yet implemented or * allowed *
  • Files can have the read-only attribute diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileInputStream.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileInputStream.java index cd5371b201..4299e90101 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileInputStream.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileInputStream.java @@ -51,7 +51,7 @@ *
  • File/directory names are not case sensitive and will be automatically * changed to all-CAPS *
  • Only files can have extensions - *
  • Extensions are numberical in the range 0 to 125 + *
  • Extensions are numerical in the range 0 to 125 *
  • Extensions 100 to 125 are special purpose and not yet implemented or * allowed *
  • Files can have the read-only attribute diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileOutputStream.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileOutputStream.java index 3f0335b23f..18ed1be8b8 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileOutputStream.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/application/file/OWFileOutputStream.java @@ -70,7 +70,7 @@ *
  • File/directory names are not case sensitive and will be automatically * changed to all-CAPS *
  • Only files can have extensions - *
  • Extensions are numberical in the range 0 to 125 + *
  • Extensions are numerical in the range 0 to 125 *
  • Extensions 100 to 125 are special purpose and not yet implemented or * allowed *
  • Files can have the read-only attribute diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankEEPROMstatus.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankEEPROMstatus.java index f015e79cd1..19d1cea33b 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankEEPROMstatus.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankEEPROMstatus.java @@ -704,7 +704,7 @@ public boolean writeScratchpad(int addr, byte[] out_buf, int offset, int len) } /** - * Copy all 8 bytes of the Sratch Pad to a certain address in memory. + * Copy all 8 bytes of the Scratch Pad to a certain address in memory. * * @param addr the address to copy the data to * @param auth byte[] containing write authorization diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankScratchSHAEE.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankScratchSHAEE.java index 512b7a2ba1..2b57f4167e 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankScratchSHAEE.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/MemoryBankScratchSHAEE.java @@ -467,7 +467,7 @@ public void copyScratchpad(int addr, byte[] scratchpad, int scratchpadOffset, by } /** - * Copy all 8 bytes of the Sratch Pad to a certain address in memory using the + * Copy all 8 bytes of the Scratch Pad to a certain address in memory using the * provided authorization MAC * * @param addr the address to copy the data to diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer33.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer33.java index e21c41885f..541303b50e 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer33.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer33.java @@ -822,7 +822,7 @@ private void initmem() { this.memoryPages[0].pageCRC = true; this.memoryPages[0].checked = false; - // Set memory bank varialbes + // Set memory bank variables this.memoryPages[1] = new MemoryBankSHAEE(this, this.mbScratchpad); this.memoryPages[1].bankDescription = "Page One with EPROM mode and write protection."; this.memoryPages[1].generalPurposeMemory = true; @@ -836,7 +836,7 @@ private void initmem() { this.memoryPages[1].pageCRC = true; this.memoryPages[1].checked = false; - // Set memory bank varialbes + // Set memory bank variables this.memoryPages[2] = new MemoryBankSHAEE(this, this.mbScratchpad); this.memoryPages[2].bankDescription = "Page Two and Three with write protection."; this.memoryPages[2].generalPurposeMemory = true; @@ -1110,7 +1110,7 @@ public void readScratchpad(byte[] scratchpad, int offset, byte[] extraInfo) } /** - * Copy all 8 bytes of the Sratch Pad to a certain page and offset in memory. + * Copy all 8 bytes of the Scratch Pad to a certain page and offset in memory. * * @param targetPage the page to copy the data to * @param targetPageOffset the offset into the page to copy to @@ -1129,7 +1129,7 @@ public boolean copyScratchpad(int targetPage, int targetPageOffset, byte[] copy_ } /** - * Copy all 8 bytes of the Sratch Pad to a certain page and offset in memory. + * Copy all 8 bytes of the Scratch Pad to a certain page and offset in memory. * * The container secret must be set so that the container can produce the * correct MAC. diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer37.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer37.java index 693c0b021a..26bbe4770a 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer37.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer37.java @@ -870,7 +870,7 @@ public boolean verifyPassword(byte[] password, int offset, int type) throws OneW // ***************************************************************************** // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Private initilizers +// Private initializers // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ***************************************************************************** diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer41.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer41.java index 9267ff60c9..4c92bd471c 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer41.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/container/OneWireContainer41.java @@ -4454,7 +4454,7 @@ private void setDate(int timeReg, int year, int month, int day, byte[] state) { // ***************************************************************************** // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Private initilizers +// Private initializers // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ***************************************************************************** diff --git a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigFixStateOfCharge.java b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigFixStateOfCharge.java index 18d1425863..386c51b0d9 100644 --- a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigFixStateOfCharge.java +++ b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigFixStateOfCharge.java @@ -43,7 +43,7 @@ @AttributeDefinition(name = "Terminate time buffer in min", description = "Terminate itself after this time buffer. If zero is given, it will terminate instantly.") int terminationBuffer() default 0; - @AttributeDefinition(name = "Terminates itself after separate conditon", description = "Terminate itself after separate end condition given by the property endCondition.") + @AttributeDefinition(name = "Terminates itself after separate condition", description = "Terminate itself after separate end condition given by the property endCondition.") boolean conditionalTermination() default false; @AttributeDefinition(name = "Condition for termination", description = "Terminates itself if the conditionalTermination is true and this end condition was fulfilled.") diff --git a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigPrepareBatteryExtension.java b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigPrepareBatteryExtension.java index 3df7ef6eb6..fe9358fea5 100644 --- a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigPrepareBatteryExtension.java +++ b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/ConfigPrepareBatteryExtension.java @@ -43,7 +43,7 @@ @AttributeDefinition(name = "Terminate time buffer in min", description = "Terminate itself after this time buffer. If zero is given, it will terminate instantly.") int terminationBuffer() default 120; - @AttributeDefinition(name = "Terminates itself after separate conditon", description = "Terminate itself after separate end condition given by the property endCondition.") + @AttributeDefinition(name = "Terminates itself after separate condition", description = "Terminate itself after separate end condition given by the property endCondition.") boolean conditionalTermination() default true; @AttributeDefinition(name = "Condition for termination", description = "Terminates itself if the conditionalTermination is true and this end condition was fulfilled.") diff --git a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/api/ConfigProperties.java b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/api/ConfigProperties.java index b3ce96e393..8b92801164 100644 --- a/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/api/ConfigProperties.java +++ b/io.openems.edge.controller.ess.fixstateofcharge/src/io/openems/edge/controller/ess/fixstateofcharge/api/ConfigProperties.java @@ -23,7 +23,7 @@ public class ConfigProperties { // Terminate time buffer in min private final int terminationBuffer; - // Terminates itself after separate conditon + // Terminates itself after separate condition private final boolean conditionalTermination; // Condition for termination diff --git a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java index 6a7c1da734..69f598db15 100644 --- a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java +++ b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java @@ -20,7 +20,7 @@ @AttributeDefinition(name = "Ess-ID", description = "ID of Ess.") String ess_id() default "ess0"; - @AttributeDefinition(name = "Input Channel", description = "When receiveing a signal, this channel triggers the execution of the limitation.") + @AttributeDefinition(name = "Input Channel", description = "When receiving a signal, this channel triggers the execution of the limitation.") String inputChannelAddress(); String webconsole_configurationFactory_nameHint() default "Controller Ess Limiter ยง14a [{id}]"; diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java index 806e0c79a6..777c07abda 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java @@ -32,7 +32,7 @@ * * @param the type of the app * @param the type of the property - * @param the type of the paramters + * @param the type of the parameters */ public class AppDef getInstantiatedApps() { /** * formats the given apps into a JSON array string. * - * @param apps that should be formated - * @return formated apps string + * @param apps that should be formatted + * @return formatted apps string */ private static String getJsonAppsString(List apps) { return JsonUtils diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 3e1bbf49ec..03cade10cf 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -405,7 +405,7 @@ App.TimeOfUseTariff.Tibber.accessToken.label = Token App.TimeOfUseTariff.Tibber.accessToken.description = To link to your Tibber account you need a personal access token. You can create this under "developer.tibber.com/settings/access-token". App.TimeOfUseTariff.Tibber.filterForHome.label = Filter for Home App.TimeOfUseTariff.Tibber.filterForHome.description = For multiple 'Homes', add either an ID (format UUID) or 'appNickname' for unambiguous identification -App.TimeOfUseTariff.Tibber.multipleHomesCheck.label = Do you have more than one contract connected to your Tibber account? +App.TimeOfUseTariff.Tibber.multipleHomesCheck.label = Do you have more than one contract connected to your Tibber account? # PvSelfConsumption App.PvSelfConsumption.GridOptimizedCharge.Name = Grid-optimized charge @@ -442,5 +442,5 @@ App.Ess.FixStateOfCharge.targetTime.label = Target time [YYYY-MM-DDTHH:mm:ssTZD App.Ess.FixStateOfCharge.targetTimeBuffer.label = Target time buffer App.Ess.FixStateOfCharge.selfTermination.label = Terminates itself at the end App.Ess.FixStateOfCharge.terminationBuffer.label = Terminate time buffer in min -App.Ess.FixStateOfCharge.conditionalTermination.label = Terminates itself after separate conditon +App.Ess.FixStateOfCharge.conditionalTermination.label = Terminates itself after separate condition App.Ess.FixStateOfCharge.isRunning.label = Controller active? diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java index b13de0b854..f49fe773eb 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Params.java @@ -23,7 +23,7 @@ public record Params(// int essTotalEnergy, // /** ESS Energy below a configured Minimum-SoC [Wh] */ int essMinSocEnergy, // - /** ESS Energy below a configured Maximium-SoC [Wh] */ + /** ESS Energy below a configured Maximum-SoC [Wh] */ int essMaxSocEnergy, // /** ESS Initially Available Energy (SoC in [Wh]) */ int essInitialEnergy, // diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java index f350cf2ab4..cd1e73e75e 100644 --- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java +++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/ParamsUtils.java @@ -32,7 +32,7 @@ private ParamsUtils() { * predicted consumption energy that cannot be supplied from production. * * @param essMinSocEnergy ESS energy below a configured minimum SoC [Wh] - * @param essMaxSocEnergy ESS energy below a configured maximium SoC [Wh] + * @param essMaxSocEnergy ESS energy below a configured maximum SoC [Wh] * @param productions Production predictions per period * @param consumptions Consumption predictions per period * @param prices Prices per period diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java index 093dc19fab..19e01b3e06 100644 --- a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/solver/nearequal/SolveNearEqual.java @@ -30,7 +30,7 @@ public class SolveNearEqual { */ public PointValuePair solve(int totalVariables) { - // If the SetPower is greater than Sum of inidividual upper bound, then return + // If the SetPower is greater than Sum of individual upper bound, then return // the upper bound if (this.powerSetValue > Arrays.stream(this.upperBound).sum()) { return new PointValuePair(this.upperBound, 0.0); diff --git a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/AvailableState.java b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/AvailableState.java index 47a5baf316..9ba99066d7 100644 --- a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/AvailableState.java +++ b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/AvailableState.java @@ -14,7 +14,7 @@ public enum AvailableState implements OptionsEnum { SUSPENDED_EV(4, "Suspended electric vehicle"), // SUSPENDED_EV_SE(5, "Suspended electric vehicle se"), // FINISHING(6, "Finishing"), // - RESERVED(7, "Reseved"), // + RESERVED(7, "Reserved"), // UNAVAILABLE(8, "Unavailable"), // UNAVAILABLE_FW_UPDATE(9, "Unavailable firmware update"), // FAULTED(10, "Faulted"), // diff --git a/io.openems.edge.evcs.cluster/readme.adoc b/io.openems.edge.evcs.cluster/readme.adoc index 81558b7e2e..fcd9b961ce 100644 --- a/io.openems.edge.evcs.cluster/readme.adoc +++ b/io.openems.edge.evcs.cluster/readme.adoc @@ -1,6 +1,6 @@ = EVCS Cluster -Distributes the charging power (Depending on the implementation) to the priorized charging stations. +Distributes the charging power (Depending on the implementation) to the prioritized charging stations. The implementations calculate the maximum power that can be used by all charging stations. Possible Cluster implementations: diff --git a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/enums/EvseErrorCode.java b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/enums/EvseErrorCode.java index b8656c5abd..7bf947b82f 100644 --- a/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/enums/EvseErrorCode.java +++ b/io.openems.edge.evcs.webasto.next/src/io/openems/edge/evcs/webasto/next/enums/EvseErrorCode.java @@ -10,7 +10,7 @@ public enum EvseErrorCode implements OptionsEnum { EV_COMMUNICATION_ERROR(3, "EV communication error"), // OVER_VOLTAGE(4, "Over Voltage"), // UNDER_VOLTAGE(5, "Under Voltage"), // - OVER_CURRENT_FALIURE(6, "Over current faliure"), // + OVER_CURRENT_FAILURE(6, "Over current failure"), // OTHER_ERROR(7, "Other error"), // GROUND_FAILURE(8, "Ground failure"), // RCD_MODULE_ERROR(9, "Error RCD modulel"), // diff --git a/io.openems.edge.io.gpio/src/io/openems/edge/io/gpio/linuxfs/Gpio.java b/io.openems.edge.io.gpio/src/io/openems/edge/io/gpio/linuxfs/Gpio.java index 7391d7c4a9..4f9f500d03 100644 --- a/io.openems.edge.io.gpio/src/io/openems/edge/io/gpio/linuxfs/Gpio.java +++ b/io.openems.edge.io.gpio/src/io/openems/edge/io/gpio/linuxfs/Gpio.java @@ -93,7 +93,7 @@ private synchronized void writeFile(String filename, String value) throws Openem } else if (msg.contains("busy")) { throw new OpenemsException("Skipping write to GPIO pin [" + this.pinNumber + "]: device is busy."); } else { - throw new OpenemsException("Unkown error writing GPIO file: " + msg); + throw new OpenemsException("Unknown error writing GPIO file: " + msg); } } } diff --git a/io.openems.edge.katek.edcom/src/com/ed/data/BatteryData.java b/io.openems.edge.katek.edcom/src/com/ed/data/BatteryData.java index 7760611ec6..c08f72d189 100644 --- a/io.openems.edge.katek.edcom/src/com/ed/data/BatteryData.java +++ b/io.openems.edge.katek.edcom/src/com/ed/data/BatteryData.java @@ -69,7 +69,7 @@ public final class BatteryData implements DataSet { public final DspVar bms_u_cell_max_total; /** - * Battery mininum cell temperature [ยฐC] + * Battery minimum cell temperature [ยฐC] */ public final DspVar bms_Tmin_total; diff --git a/io.openems.edge.katek.edcom/src/com/ed/data/History.java b/io.openems.edge.katek.edcom/src/com/ed/data/History.java index 47beb589be..596a56ecf3 100644 --- a/io.openems.edge.katek.edcom/src/com/ed/data/History.java +++ b/io.openems.edge.katek.edcom/src/com/ed/data/History.java @@ -408,7 +408,7 @@ public synchronized SortedMap> getHistoryDay() th *

    * All recorded performance values in per hour of the requested day * sorted by hour in ascending order. The values are stored in arrays of - * lenght 30 and 12. Arrays of length 30 represent 2 minute average + * length 30 and 12. Arrays of length 30 represent 2 minute average * values, arrays of 12 represent 5 minute average values. *

    *

    diff --git a/io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java b/io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java index 4b04490507..3e39681b18 100644 --- a/io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java +++ b/io.openems.edge.katek.edcom/src/com/ed/edcom/Client.java @@ -196,7 +196,7 @@ public byte getAccessFeedb() { /** * Check if ID is accepted by inverter * - * @return true - ID accepted, false - ID not accpeted. + * @return true - ID accepted, false - ID not accepted. */ public boolean isIdAccepted() { @@ -206,7 +206,7 @@ public boolean isIdAccepted() { /** * Check if user password is accepted by inverter * - * @return true - ID accepted, false - ID not accpeted. + * @return true - ID accepted, false - ID not accepted. */ public boolean isPasswordAccepted() { return this.accessBitTest(2); diff --git a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java index 7ee0066337..e12637892d 100644 --- a/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java +++ b/io.openems.edge.timedata.rrd4j/src/io/openems/edge/timedata/rrd4j/Rrd4jReadHandler.java @@ -150,7 +150,7 @@ private static Timeranges getTimerangesOfNotSendData(RrdDb db, long start) throw * @param rrdDbId the id of the rrdb * @param notSendChannel the channel with the timestamps where the data got * not send - * @param lastResendTimestamp the timstamp of the last resend + * @param lastResendTimestamp the timestamp of the last resend * @param debugMode if debugMode is active * @return the {@link Timeranges} * @throws OpenemsNamedException on error diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index 719a287a15..1e3672ca49 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -74,11 +74,11 @@ export class HistoryComponent implements OnInit { /* handle grid breakpoints */(window.innerWidth < 768 ? window.innerWidth - 150 : window.innerWidth - 400)); this.socChartHeight = /* minimum size */ Math.max(150, - /* maximium size */ Math.min(200, ref), + /* maximum size */ Math.min(200, ref), ) + "px"; this.energyChartHeight = /* minimum size */ Math.max(300, - /* maximium size */ Math.min(600, ref), + /* maximum size */ Math.min(600, ref), ) + "px"; } From e5160e40d03b01a591bb163cbd77e312f725ce5b Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 10 Sep 2024 14:12:31 +0200 Subject: [PATCH 06/24] FEMS Backports 2024-09 (#2788) - AppCenter: handle hardware specifics via hardware Apps - AppCenter: App for Phoenix Contact Meter EEM-MB370-24DC - AppCenter: App for PqPlus Meter UMD96 & UMD97 - Channels: allow translatable Channel descriptions - Controller.Api.ModbusTcp.ReadWrite: UI live and historic view - GoodWe: fix StateRegisters - Simulated Predictor - UI: track connection State & add backend not accessible info --------- Co-authored-by: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Co-authored-by: Fabian Brandtner <10850256+fabian94533@users.noreply.github.com> Co-authored-by: Johann Kaufmann <165755282+johannk24@users.noreply.github.com> Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Co-authored-by: Michael Grill <59126309+michaelgrill@users.noreply.github.com> Co-authored-by: Stefan Feilmeier <3515268+sfeilmeier@users.noreply.github.com> --- .../common/oem/DummyOpenemsEdgeOem.java | 12 + .../io/openems/edge/common/channel/Doc.java | 19 +- .../common/channel/internal/AbstractDoc.java | 56 +- .../common/test/DummyComponentContext.java | 12 +- .../common/test/DummyComponentInstance.java | 59 + .../channel/ChannelTranslationTest.java | 51 + .../common/channel/translation_de.properties | 1 + .../common/channel/translation_en.properties | 2 + .../edge/controller/api/common/ApiWorker.java | 29 +- .../edge/controller/api/common/Status.java | 37 + .../controller/api/common/WriteObject.java | 7 + .../edge/controller/api/common/WritePojo.java | 5 + .../api/modbus/AbstractModbusTcpApi.java | 145 ++- .../controller/api/modbus/ModbusTcpApi.java | 2 +- .../ControllerApiModbusTcpReadOnlyImpl.java | 24 +- .../api/modbus/readwrite/Config.java | 7 + .../ControllerApiModbusTcpReadWrite.java | 47 + .../ControllerApiModbusTcpReadWriteImpl.java | 159 ++- ...ntrollerApiModbusTcpReadWriteImplTest.java | 21 +- .../api/modbus/readwrite/MyConfig.java | 27 + .../edge/app/common/props/RelayProps.java | 21 +- .../io/openems/edge/app/ess/Limiter14a.java | 178 +++ .../io/openems/edge/app/hardware/IoGpio.java | 141 +++ .../edge/app/heat/CombinedHeatAndPower.java | 3 +- .../io/openems/edge/app/heat/HeatPump.java | 3 +- .../openems/edge/app/heat/HeatingElement.java | 3 +- .../app/integratedsystem/FeneconHome.java | 34 +- .../app/integratedsystem/FeneconHome20.java | 24 +- .../app/integratedsystem/FeneconHome30.java | 23 +- .../FeneconHomeComponents.java | 60 + .../IntegratedSystemProps.java | 30 + .../commercial/FeneconCommercial92.java | 175 +++ .../FeneconCommercialComponents.java | 130 ++ .../app/loadcontrol/ManualRelayControl.java | 3 +- .../app/loadcontrol/ThresholdControl.java | 3 +- .../openems/edge/app/meter/JanitzaMeter.java | 9 +- .../edge/app/meter/PhoenixContactMeter.java | 169 +++ .../openems/edge/app/meter/PqPlusMeter.java | 279 +++++ .../app/openemshardware/BeagleBoneBlack.java | 121 ++ .../edge/app/openemshardware/Compulab.java | 121 ++ .../edge/app/openemshardware/TechbaseCm3.java | 132 ++ .../edge/app/openemshardware/TechbaseCm4.java | 121 ++ .../app/openemshardware/TechbaseCm4Max.java | 121 ++ .../app/openemshardware/TechbaseCm4s.java | 132 ++ .../app/openemshardware/TechbaseCm4sGen2.java | 137 +++ .../app/timeofusetariff/AwattarHourly.java | 3 +- .../edge/app/timeofusetariff/EntsoE.java | 3 +- .../edge/app/timeofusetariff/GroupeE.java | 3 +- .../edge/app/timeofusetariff/RabotCharge.java | 3 +- .../timeofusetariff/StadtwerkHassfurt.java | 3 +- .../timeofusetariff/StromdaoCorrently.java | 3 +- .../edge/app/timeofusetariff/Tibber.java | 3 +- .../edge/core/appmanager/AppManager.java | 37 +- .../edge/core/appmanager/AppManagerUtil.java | 9 + .../core/appmanager/AppManagerUtilImpl.java | 17 + .../core/appmanager/OpenemsAppCategory.java | 5 + .../appmanager/ResolveOpenemsHardware.java | 189 +++ .../dependency/AppManagerAppHelperImpl.java | 23 + ...edulerByCentralOrderAggregateTaskImpl.java | 1 + .../core/appmanager/translation_de.properties | 60 +- .../core/appmanager/translation_en.properties | 60 +- .../validator/CheckCommercial92.java | 51 + .../core/appmanager/validator/CheckHome.java | 13 +- .../core/appmanager/validator/CheckOr.java | 102 ++ .../validator/CheckableFactory.java | 130 ++ .../core/appmanager/validator/Checkables.java | 26 + .../appmanager/validator/ValidatorConfig.java | 11 + .../appmanager/validator/ValidatorImpl.java | 63 +- .../validator/translation_de.properties | 5 + .../validator/translation_en.properties | 5 + .../ComponentManagerImpl.java | 25 +- .../app/integratedsystem/TestFeneconHome.java | 107 +- .../edge/app/timeofusetariff/TestTibber.java | 27 +- .../AppManagerImpSynchronizationTest.java | 199 --- .../AppManagerImplSynchronizationTest.java | 128 ++ .../core/appmanager/AppManagerImplTest.java | 7 +- .../core/appmanager/AppManagerTestBundle.java | 290 +++-- .../io/openems/edge/core/appmanager/Apps.java | 124 +- .../edge/core/appmanager/DummyValidator.java | 46 +- .../ResolveOpenemsHardwareTest.java | 165 +++ .../core/appmanager/TestTranslations.java | 38 +- .../appmanager/validator/CheckHomeTest.java | 7 +- .../edge/ess/api/ManagedSymmetricEss.java | 4 +- .../edge/goodwe/common/AbstractGoodWe.java | 73 +- .../io/openems/edge/goodwe/common/GoodWe.java | 164 +-- io.openems.edge.simulator/bnd.bnd | 1 + .../openems/edge/simulator/DataContainer.java | 45 +- .../edge/simulator/app/SimulatorAppImpl.java | 6 + .../datasource/api/AbstractCsvDatasource.java | 15 + .../datasource/api/SimulatorDatasource.java | 17 +- .../edge/simulator/predictor/Config.java | 38 + .../predictor/SimulatorPredictor.java | 23 + .../predictor/SimulatorPredictorImpl.java | 102 ++ .../SimulatorDatasourceCsvDirectImplTest.java | 28 +- .../edge/simulator/predictor/MyConfig.java | 80 ++ .../predictor/SimulatorPredictorImplTest.java | 55 + ui/src/app/app-routing.module.ts | 9 +- ui/src/app/app.component.ts | 2 + ui/src/app/app.module.ts | 2 + .../ModbusTcpApi/chart/channels.spec.ts | 1070 +++++++++++++++++ .../Controller/ModbusTcpApi/chart/chart.ts | 89 ++ .../Controller/ModbusTcpApi/flat/flat.html | 5 + .../Controller/ModbusTcpApi/flat/flat.ts | 21 + .../ModbusTcpApi/modbusTcpApi.module.ts | 24 + .../ModbusTcpApi/overview/overview.html | 23 + .../ModbusTcpApi/overview/overview.ts | 7 + .../history/Controller/controller.module.ts | 3 + .../app/edge/history/history.component.html | 11 + ui/src/app/edge/history/history.component.ts | 4 +- .../Controller/ModbusTcpApi/flat/flat.html | 3 + .../live/Controller/ModbusTcpApi/flat/flat.ts | 51 + .../Controller/ModbusTcpApi/modal/modal.html | 23 + .../Controller/ModbusTcpApi/modal/modal.ts | 102 ++ .../ModbusTcpApi/modbusTcpApi.module.ts | 20 + ui/src/app/edge/live/live.component.html | 7 + ui/src/app/edge/live/live.component.ts | 4 +- ui/src/app/edge/live/live.module.ts | 32 +- ui/src/app/index/login.component.ts | 2 + ui/src/app/index/shared/loading-screen.html | 64 +- ui/src/app/index/shared/loading-screen.ts | 39 +- .../chart/abstracthistorychart.html | 2 + .../components/chart/abstracthistorychart.ts | 10 +- .../shared/components/edge/edgeconfig.spec.ts | 27 + .../components/header/header.component.ts | 4 +- .../shared/components/modal/modal.module.ts | 2 + .../app/shared/components/shared/converter.ts | 28 + .../app/shared/components/shared/formatter.ts | 5 + ui/src/app/shared/ngrx-store/states.ts | 110 ++ ui/src/app/shared/pipe/converter/converter.ts | 22 + ui/src/app/shared/pipe/pipe.ts | 3 + ui/src/app/shared/service/pagination.ts | 2 + .../shared/service/previousRouteService.ts | 29 + ui/src/app/shared/service/service.ts | 2 + ui/src/app/shared/service/utils.ts | 1 + ui/src/app/shared/service/websocket.ts | 13 +- ui/src/app/shared/shared.module.ts | 6 +- ui/src/app/shared/shared.ts | 13 + ui/src/app/shared/type/general.ts | 5 + ui/src/app/shared/type/language.ts | 16 +- ui/src/app/shared/type/widget.ts | 4 + ui/src/assets/i18n/de.json | 25 + ui/src/assets/i18n/en.json | 25 + ui/src/themes/openems/scss/variables.scss | 9 +- 143 files changed, 6740 insertions(+), 777 deletions(-) create mode 100644 io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentInstance.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/channel/ChannelTranslationTest.java create mode 100644 io.openems.edge.common/test/io/openems/edge/common/channel/translation_de.properties create mode 100644 io.openems.edge.common/test/io/openems/edge/common/channel/translation_en.properties create mode 100644 io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/ess/Limiter14a.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/hardware/IoGpio.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercial92.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercialComponents.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/meter/PhoenixContactMeter.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/meter/PqPlusMeter.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/BeagleBoneBlack.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/Compulab.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm3.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4Max.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4s.java create mode 100644 io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4sGen2.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveOpenemsHardware.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckCommercial92.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckOr.java create mode 100644 io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckableFactory.java delete mode 100644 io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java create mode 100644 io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplSynchronizationTest.java create mode 100644 io.openems.edge.core/test/io/openems/edge/core/appmanager/ResolveOpenemsHardwareTest.java create mode 100644 io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/Config.java create mode 100644 io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictor.java create mode 100644 io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictorImpl.java create mode 100644 io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/MyConfig.java create mode 100644 io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/SimulatorPredictorImplTest.java create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/chart/channels.spec.ts create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/chart/chart.ts create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.html create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.ts create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.html create mode 100644 ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.ts create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.html create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.ts create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.html create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.ts create mode 100644 ui/src/app/edge/live/Controller/ModbusTcpApi/modbusTcpApi.module.ts create mode 100644 ui/src/app/shared/ngrx-store/states.ts create mode 100644 ui/src/app/shared/pipe/converter/converter.ts create mode 100644 ui/src/app/shared/service/previousRouteService.ts diff --git a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java index 4b0aabf35b..cd0a08830c 100644 --- a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java +++ b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java @@ -60,6 +60,8 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.FENECON.Home", "https://fenecon.de/fenecon-home-10/") // .put("App.FENECON.Home.20", "https://fenecon.de/fenecon-home-20-30/") // .put("App.FENECON.Home.30", "https://fenecon.de/fenecon-home-20-30/") // + .put("App.FENECON.Commercial.92", "https://fenecon.de/fenecon-commercial/") // + .put("App.FENECON.Industrial.L.ILK710", "https://fenecon.de/fenecon-industrial-l/") // .put("App.FENECON.Industrial.S.ISK010", "https://fenecon.de/fenecon-industrial-s/") // .put("App.FENECON.Industrial.S.ISK110", "https://fenecon.de/fenecon-industrial-s/") // .put("App.FENECON.Industrial.S.ISK011", "https://fenecon.de/fenecon-industrial-s/") // @@ -92,8 +94,17 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.LoadControl.ThresholdControl", "") // .put("App.Meter.Socomec", "") // .put("App.Meter.CarloGavazzi", "") // + .put("App.Meter.PqPlus", "") // .put("App.Meter.Janitza", "") // .put("App.Meter.Discovergy", "")// + .put("App.Meter.PhoenixContact", "")// + .put("App.OpenemsHardware.BeagleBoneBlack", "") // + .put("App.OpenemsHardware.Compulab", "") // + .put("App.OpenemsHardware.CM3", "") // + .put("App.OpenemsHardware.CM4", "") // + .put("App.OpenemsHardware.CM4Max", "") // + .put("App.OpenemsHardware.CM4S", "") // + .put("App.OpenemsHardware.CM4S.Gen2", "") // .put("App.PvInverter.Fronius", "") // .put("App.PvInverter.Kaco", "") // .put("App.PvInverter.Kostal", "") // @@ -105,6 +116,7 @@ public SystemUpdateParams getSystemUpdateParams() { .put("App.Ess.FixStateOfCharge", "") // .put("App.Ess.PowerPlantController", "") // .put("App.Ess.PrepareBatteryExtension", "") // + .put("App.Ess.Limiter14a", "") // .build(); // NOTE: this will certainly get refactored in future, but it's a good start to diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java b/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java index 29257d4927..8838ceff5f 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java @@ -5,6 +5,7 @@ import io.openems.common.channel.Level; import io.openems.common.channel.PersistencePriority; import io.openems.common.channel.Unit; +import io.openems.common.session.Language; import io.openems.common.types.OpenemsType; import io.openems.common.types.OptionsEnum; import io.openems.edge.common.channel.internal.AbstractDoc; @@ -135,6 +136,23 @@ public static StateChannelDoc of(Level level) { */ public String getText(); + /** + * Gets the translated text. Defaults to empty String. + * + * @param lang language to get translated text + * @return the text + */ + public String getText(Language lang); + + /** + * Sets the translation key. + * + * @param channelKey the translationKey of the channel + * @param clazz the class of the channel parent + * @return myself + */ + public Doc translationKey(Class clazz, String channelKey); + /** * Is the more verbose debug mode activated?. * @@ -153,5 +171,4 @@ public static StateChannelDoc of(Level level) { */ public > C createChannelInstance(OpenemsComponent component, io.openems.edge.common.channel.ChannelId channelId); - } diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java b/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java index 1fe4388ba8..22c752983d 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java @@ -1,9 +1,12 @@ package io.openems.edge.common.channel.internal; import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Function; import io.openems.common.channel.AccessMode; import io.openems.common.channel.PersistencePriority; @@ -11,6 +14,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.function.ThrowingBiConsumer; import io.openems.common.function.ThrowingConsumer; +import io.openems.common.session.Language; import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.ChannelId; @@ -26,6 +30,8 @@ public abstract class AbstractDoc implements Doc { private final OpenemsType type; + private Function getTextFunction; + protected AbstractDoc(OpenemsType type) { this.type = type; } @@ -118,20 +124,56 @@ public T getInitialValue() { return this.initialValue; } - /* - * Description - */ - private String text = ""; - @Override public AbstractDoc text(String text) { - this.text = text; + this.getTextFunction = lang -> { + return text; + }; return this.self(); } @Override public String getText() { - return this.text; + return this.getText(Language.DEFAULT); + } + + @Override + public String getText(Language lang) { + if (this.getTextFunction == null) { + return ""; + } + return this.getTextFunction.apply(lang); + } + + @Override + public AbstractDoc translationKey(Class clazz, String channelKey) { + this.getTextFunction = lang -> { + var bundle = AbstractDoc.getResourceBundle(lang, clazz); + if (bundle != null && bundle.containsKey(channelKey)) { + var textTranslated = bundle.getString(channelKey); + return textTranslated; + } + if (lang != Language.EN) { + // TODO: Use Language.DEFAULT for default language + bundle = AbstractDoc.getResourceBundle(Language.EN, clazz); + if (bundle != null && bundle.containsKey(channelKey)) { + var textTranslated = bundle.getString(channelKey); + return textTranslated; + } + } + + return channelKey; + }; + return this; + } + + private static ResourceBundle getResourceBundle(Language lang, Class clazz) { + try { + return ResourceBundle.getBundle(clazz.getPackageName() + ".translation", lang.getLocal(), + clazz.getModule()); + } catch (MissingResourceException e) { + return null; + } } @Override diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentContext.java b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentContext.java index 7779c03368..71007da35d 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentContext.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentContext.java @@ -33,9 +33,16 @@ public static DummyComponentContext from(AbstractComponentConfig configuration) } private final Dictionary properties; + private final ComponentInstance instance; - public DummyComponentContext(Dictionary properties) { + public DummyComponentContext(Dictionary properties, ComponentInstance instance) { + super(); this.properties = properties; + this.instance = instance; + } + + public DummyComponentContext(Dictionary properties) { + this(properties, null); } public DummyComponentContext() { @@ -85,8 +92,9 @@ public Bundle getUsingBundle() { } @Override + @SuppressWarnings("unchecked") public ComponentInstance getComponentInstance() { - return null; + return (ComponentInstance) this.instance; } @Override diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentInstance.java b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentInstance.java new file mode 100644 index 0000000000..16283c87c4 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentInstance.java @@ -0,0 +1,59 @@ +package io.openems.edge.common.test; + +import org.osgi.service.component.ComponentInstance; + +import io.openems.common.utils.FunctionUtils; + +public class DummyComponentInstance implements ComponentInstance { + + public static class DummyComponentInstanceBuilder { + + private Runnable dispose; + private S instance; + + public DummyComponentInstanceBuilder setDispose(Runnable dispose) { + this.dispose = dispose; + return this; + } + + public DummyComponentInstanceBuilder setInstance(S instance) { + this.instance = instance; + return this; + } + + public DummyComponentInstance build() { + return new DummyComponentInstance<>(this.dispose, this.instance); + } + + } + + /** + * Creates a builder for a {@link DummyComponentInstance}. + * + * @param the type of the service + * @return the builder + */ + public static DummyComponentInstanceBuilder create() { + return new DummyComponentInstanceBuilder<>(); + } + + private final Runnable dispose; + private final S instance; + + public DummyComponentInstance(Runnable dispose, S instance) { + super(); + this.dispose = dispose != null ? dispose : FunctionUtils::doNothing; + this.instance = instance; + } + + @Override + public void dispose() { + this.dispose.run(); + } + + @Override + public S getInstance() { + return this.instance; + } + +} \ No newline at end of file diff --git a/io.openems.edge.common/test/io/openems/edge/common/channel/ChannelTranslationTest.java b/io.openems.edge.common/test/io/openems/edge/common/channel/ChannelTranslationTest.java new file mode 100644 index 0000000000..b4bc56abff --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/channel/ChannelTranslationTest.java @@ -0,0 +1,51 @@ +package io.openems.edge.common.channel; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.openems.common.channel.Level; +import io.openems.common.session.Language; + +public class ChannelTranslationTest { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + TEST_CHANNEL(Doc.of(Level.WARNING) // + .translationKey(ChannelTranslationTest.class, "Test.TestChannel")), // + ONLY_ENGLISH(Doc.of(Level.INFO) // + .translationKey(ChannelTranslationTest.class, "Test.OnlyEnglish")), // + NO_TRANSLATION(Doc.of(Level.OK) // + .text("No Translation")),; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + @Test + public void testTranslatedGermanChannelText() { + assertEquals("German Test", ChannelTranslationTest.ChannelId.TEST_CHANNEL.doc().getText(Language.DE)); + } + + @Test + public void testTranslatedEnglishChannelText() { + assertEquals("English Test", ChannelTranslationTest.ChannelId.TEST_CHANNEL.doc().getText(Language.EN)); + } + + @Test + public void testOnlyEnglishTranslationTest() { + assertEquals("Only English", ChannelTranslationTest.ChannelId.ONLY_ENGLISH.doc().getText(Language.DE)); + } + + @Test + public void testNoTranslation() { + assertEquals("No Translation", ChannelTranslationTest.ChannelId.NO_TRANSLATION.doc().getText(Language.DE)); + } +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/channel/translation_de.properties b/io.openems.edge.common/test/io/openems/edge/common/channel/translation_de.properties new file mode 100644 index 0000000000..7762fa376a --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/channel/translation_de.properties @@ -0,0 +1 @@ +Test.TestChannel = German Test \ No newline at end of file diff --git a/io.openems.edge.common/test/io/openems/edge/common/channel/translation_en.properties b/io.openems.edge.common/test/io/openems/edge/common/channel/translation_en.properties new file mode 100644 index 0000000000..a0778bfbcd --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/channel/translation_en.properties @@ -0,0 +1,2 @@ +Test.TestChannel = English Test +Test.OnlyEnglish = Only English \ No newline at end of file diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java index 7ad767546d..4e15cd6d47 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/ApiWorker.java @@ -10,6 +10,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,10 +21,12 @@ import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; import io.openems.common.jsonrpc.request.SetChannelValueRequest; import io.openems.common.types.OpenemsType; +import io.openems.common.utils.FunctionUtils; import io.openems.common.utils.JsonUtils; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.StringReadChannel; import io.openems.edge.common.channel.WriteChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.user.User; @@ -40,7 +43,7 @@ public class ApiWorker { private final Logger log = LoggerFactory.getLogger(ApiWorker.class); - private final OpenemsComponent parent; + private final AbstractOpenemsComponent parent; /** * Debug information about writes to channels is sent to this channel. @@ -58,8 +61,24 @@ public class ApiWorker { private int timeoutSeconds = DEFAULT_TIMEOUT_SECONDS; - public ApiWorker(OpenemsComponent parent) { + /** + * Handles write-only channel overriding. + */ + public record WriteHandler(Consumer, WriteObject>> handleWrites, // + Consumer setOverrideStatus, // + Runnable handleTimeout) { + } + + private WriteHandler writeHandler; + + public ApiWorker(AbstractOpenemsComponent parent) { + this(parent, new WriteHandler(FunctionUtils::doNothing, // + FunctionUtils::doNothing, FunctionUtils::doNothing)); + } + + public ApiWorker(AbstractOpenemsComponent parent, WriteHandler writeHandler) { // this.parent = parent; + this.writeHandler = writeHandler; this.executor = Executors.newSingleThreadScheduledExecutor(); } @@ -150,6 +169,8 @@ private synchronized void resetTimeout() { + entry.getKey().address() + "] after [" + this.timeoutSeconds + "s]"); entry.getValue().notifyTimeout(); } + this.writeHandler.setOverrideStatus.accept(Status.INACTIVE); + this.writeHandler.handleTimeout.run(); this.values.clear(); } }, this.timeoutSeconds, TimeUnit.SECONDS); @@ -186,7 +207,11 @@ public void run() throws OpenemsNamedException { "Set Channel [" + channel.address() + "] to Value [" + writeObject.valueToString() + "]"); writeObject.setNextWriteValue(channel); writeObject.notifySuccess(); + logs.add(channel.address() + ":" + writeObject.valueToString()); + + this.writeHandler.handleWrites.accept(entry); + this.writeHandler.setOverrideStatus.accept(Status.ACTIVE); } catch (OpenemsException e) { OpenemsComponent.logError(this.parent, this.log, "Unable to set Channel [" + channel.address() + "] to Value [" + writeObject.valueToString() + "]: " + e.getMessage()); diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java new file mode 100644 index 0000000000..14c18bde3e --- /dev/null +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java @@ -0,0 +1,37 @@ +package io.openems.edge.controller.api.common; + +import io.openems.common.types.OptionsEnum; + +public enum Status implements OptionsEnum { + + ACTIVE(0, "Active"), // + + INACTIVE(1, "Inactive"), // + + ERROR(2, "Error"); // + + + private final int value; + private final String name; + + private Status(int value, String name) { + this.value = value; + this.name = name; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public OptionsEnum getUndefined() { + return INACTIVE; + } + +} diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java index 25d3b9f829..02c4533867 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java @@ -118,6 +118,13 @@ public void notifyTimeout() { * @return the value as String */ public abstract String valueToString(); + + /** + * Gets the value of the current object. + * + * @return the value as the corresponding type + */ + public abstract Object value(); /** * Is there a defined value?. diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WritePojo.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WritePojo.java index c6d390c5ee..5a71dc9a94 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WritePojo.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WritePojo.java @@ -29,4 +29,9 @@ public boolean isNull() { return this.value == null; } + @Override + public Object value() { + return this.value; + } + } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java index d862b6c717..52e5f67dea 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java @@ -1,8 +1,11 @@ package io.openems.edge.controller.api.modbus; +import java.util.Arrays; import java.util.List; +import java.util.Map.Entry; import java.util.TreeMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -35,6 +38,9 @@ import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.api.common.ApiWorker; +import io.openems.edge.controller.api.common.ApiWorker.WriteHandler; +import io.openems.edge.controller.api.common.Status; +import io.openems.edge.controller.api.common.WriteObject; import io.openems.edge.controller.api.common.WritePojo; import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolExportXlsxRequest; import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolExportXlsxResponse; @@ -48,16 +54,15 @@ public abstract class AbstractModbusTcpApi extends AbstractOpenemsComponent public static final int DEFAULT_PORT = 502; public static final int DEFAULT_MAX_CONCURRENT_CONNECTIONS = 5; - protected final ApiWorker apiWorker = new ApiWorker(this); - - private final Logger log = LoggerFactory.getLogger(AbstractModbusTcpApi.class); - private final MyProcessImage processImage; - private final String implementationName; - /** * Holds the link between Modbus address and ModbusRecord. */ protected final TreeMap records = new TreeMap<>(); + protected final ApiWorker apiWorker = new ApiWorker(this, + new WriteHandler(this.handleWrites(), this::setOverrideStatus, this.handleTimeouts())); + private final Logger log = LoggerFactory.getLogger(AbstractModbusTcpApi.class); + private final MyProcessImage processImage; + private final String implementationName; /** * Holds the link between Modbus start address of a Component and the @@ -66,10 +71,12 @@ public abstract class AbstractModbusTcpApi extends AbstractOpenemsComponent private final TreeMap components = new TreeMap<>(); private ConfigRecord config; + private List invalidComponents = new CopyOnWriteArrayList<>(); protected synchronized void addComponent(OpenemsComponent component) { if (!(component instanceof ModbusSlave)) { this.logError(this.log, "Component [" + component.id() + "] does not implement ModbusSlave"); + this.invalidComponents.add(component); this._setComponentNoModbusApiFault(true); return; } @@ -77,8 +84,20 @@ protected synchronized void addComponent(OpenemsComponent component) { this.updateComponents(); } + protected abstract Consumer, WriteObject>> handleWrites(); + + protected abstract void setOverrideStatus(Status status); + + protected abstract Runnable handleTimeouts(); + protected synchronized void removeComponent(OpenemsComponent component) { - this._components.remove(component); + if (this.invalidComponents.remove(component)) { + if (this.invalidComponents.isEmpty()) { + this._setComponentNoModbusApiFault(false); + } + this._components.remove(component); + return; + } this.updateComponents(); } @@ -92,19 +111,39 @@ public AbstractModbusTcpApi(String implementationName, this.processImage = new MyProcessImage(this); } - protected void activate(ComponentContext context, String id, String alias, boolean enabled, ConfigurationAdmin cm, - ConfigRecord config) throws OpenemsException { - super.activate(context, id, alias, enabled); + protected void activate(ComponentContext context, ConfigurationAdmin cm, ConfigRecord config) + throws OpenemsException { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.handleActivate(config, cm, config.id()); + } - // configuration settings - this.config = config; + protected void modified(ComponentContext context, ConfigurationAdmin cm, ConfigRecord config) + throws OpenemsException { + super.modified(context, config.id(), config.alias(), config.enabled()); // update filter for 'Components'; allow disable components final var filter = ConfigUtils.generateReferenceTargetFilter(this.servicePid(), false, config.componentIds); - if (OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter)) { + OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter); + + // Config (relevant for API) was not modified + if (this.config.equals(config)) { return; } + ModbusSlaveFactory.close(); + + // Activate with new config + this.handleModified(config, cm, config.id()); + } + + private void handleActivate(ConfigRecord config, ConfigurationAdmin cm, String id) { + // configuration settings + this.config = config; + + // update filter for 'Components'; allow disable components + final var filter = ConfigUtils.generateReferenceTargetFilter(this.servicePid(), false, config.componentIds); + OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter); + this.apiWorker.setTimeoutSeconds(config.apiTimeout); if (!this.isEnabled()) { @@ -118,6 +157,24 @@ protected void activate(ComponentContext context, String id, String alias, boole this.updateComponents(); } + private void handleModified(ConfigRecord config, ConfigurationAdmin cm, String id) { + // configuration settings + this.config = config; + + this.apiWorker.setTimeoutSeconds(config.apiTimeout); + + if (!this.isEnabled()) { + // abort if disabled + this.startApiWorker.deactivate(); + return; + } + + // Modify Modbus-Server + this.startApiWorker.modified(id); + + this.updateComponents(); + } + /** * Called by addComponent/removeComponent. Initializes the ModbusRecords, once * all Components are available. Fault-State otherwise. @@ -142,6 +199,7 @@ private synchronized void updateComponents() { @Override protected void deactivate() { + this.startApiWorker.deactivate(); ModbusSlaveFactory.close(); super.deactivate(); @@ -171,10 +229,11 @@ protected void forever() { this.slave = ModbusSlaveFactory.createTCPSlave(port, AbstractModbusTcpApi.this.config.maxConcurrentConnections); this.slave.addProcessImage(UNIT_ID, AbstractModbusTcpApi.this.processImage); - this.slave.open(); - AbstractModbusTcpApi.this.logInfo(this.log, AbstractModbusTcpApi.this.implementationName + if (isEnabled()) { + this.slave.open(); + AbstractModbusTcpApi.this.logInfo(this.log, AbstractModbusTcpApi.this.implementationName + " started on port [" + port + "] with UnitId [" + AbstractModbusTcpApi.UNIT_ID + "]."); - + } } catch (ModbusException e) { ModbusSlaveFactory.close(); AbstractModbusTcpApi.this.logError(this.log, @@ -431,21 +490,45 @@ protected ModbusSlave getPossiblyDisabledComponent(String componentId) { .orElse(null); } - protected static class ConfigRecord { - public final Meta metaComponent; - public final String[] componentIds; - public final int apiTimeout; - public final int port; - public final int maxConcurrentConnections; - - public ConfigRecord(Meta metaComponent, String[] componentIds, int apiTimeout, int port, - int maxConcurrentConnections) { - super(); - this.metaComponent = metaComponent; - this.componentIds = componentIds; - this.apiTimeout = apiTimeout; - this.port = port; - this.maxConcurrentConnections = maxConcurrentConnections; + public static record ConfigRecord(String id, String alias, boolean enabled, Meta metaComponent, + String[] componentIds, int apiTimeout, int port, int maxConcurrentConnections) { + + @Override + public boolean equals(Object other) { + + if (this == other) { + return true; + } + if (other == null) { + return false; + } + if (!(other instanceof ConfigRecord)) { + return false; + } + ConfigRecord config = (ConfigRecord) other; + + if (config.id.equals(this.id) && config.alias.equals(this.alias) // + && config.enabled == this.enabled && config.metaComponent.equals(this.metaComponent) // + && Arrays.equals(config.componentIds, this.componentIds) // + && config.apiTimeout == this.apiTimeout && config.port == this.port // + && config.maxConcurrentConnections == this.maxConcurrentConnections) { + return true; + } + + return false; + } } + + ; + + /** + * Format a given channelAddress to a ChannelId. + * + * @param channel WriteChannel + * @return component_channelId as String + */ + public static String formatChannelName(WriteChannel channel) { + return channel.getComponent().alias() + "_" + channel.channelId().name(); + } } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java index 21d232a791..da838a2d94 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java @@ -18,7 +18,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { .debounce(10, Debounce.TRUE_VALUES_IN_A_ROW_TO_SET_TRUE) // .text("A configured Component is not available")), // PROCESS_IMAGE_FAULT(Doc.of(Level.FAULT) // - .debounce(50, Debounce.FALSE_VALUES_IN_A_ROW_TO_SET_FALSE) // + .debounce(10, Debounce.FALSE_VALUES_IN_A_ROW_TO_SET_FALSE) // .text("Invalid Modbus Function call. Only FC3, FC4, FC6 and FC16 are supported")); private final Doc doc; diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java index b983cbd8df..01c6e47638 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java @@ -1,5 +1,8 @@ package io.openems.edge.controller.api.modbus.readonly; +import java.util.Map.Entry; +import java.util.function.Consumer; + import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -16,10 +19,13 @@ import io.openems.common.channel.AccessMode; import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.jsonapi.ComponentJsonApi; import io.openems.edge.common.meta.Meta; import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.api.common.Status; +import io.openems.edge.controller.api.common.WriteObject; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.api.modbus.ModbusTcpApi; @@ -59,8 +65,8 @@ public ControllerApiModbusTcpReadOnlyImpl() { @Activate private void activate(ComponentContext context, Config config) throws ModbusException, OpenemsException { - super.activate(context, config.id(), config.alias(), config.enabled(), this.cm, - new ConfigRecord(this.metaComponent, config.component_ids(), 0 /* no timeout */, config.port(), + super.activate(context, this.cm, + new ConfigRecord(config.id(), config.alias(), config.enabled(),this.metaComponent, config.component_ids(), 0 /* no timeout */, config.port(), config.maxConcurrentConnections())); } @@ -74,4 +80,18 @@ protected void deactivate() { protected AccessMode getAccessMode() { return AccessMode.READ_ONLY; } + + @Override + protected Consumer, WriteObject>> handleWrites() { + return entry -> { }; + } + + @Override + protected void setOverrideStatus(Status status) { + } + + @Override + protected Runnable handleTimeouts() { + return () -> { }; + } } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java index 744d65b22b..0614487de2 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java @@ -25,6 +25,13 @@ @AttributeDefinition(name = "Component-IDs", description = "Components that should be made available via Modbus.") String[] component_ids() default { "_sum" }; + // TODO: Currently unused + @AttributeDefinition(name = "Read Channel-IDs", description = "Contains the channelnames of all read channels.") + String[] readChannels() default { }; + + @AttributeDefinition(name = "Write Channel-IDs", description = "Contains the channelnames of all overridden channels.") + String[] writeChannels(); + @AttributeDefinition(name = "Api-Timeout", description = "Sets the timeout in seconds for updates on Channels set by this Api.") int apiTimeout() default 60; diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java index 78c23fcc52..8a18a1aada 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java @@ -1,13 +1,33 @@ package io.openems.edge.controller.api.modbus.readwrite; +import static io.openems.common.channel.PersistencePriority.HIGH; +import static io.openems.common.channel.Unit.CUMULATED_SECONDS; +import static io.openems.common.types.OpenemsType.LONG; + +import io.openems.common.channel.PersistencePriority; import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.StringReadChannel; +import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.controller.api.common.Status; public interface ControllerApiModbusTcpReadWrite extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + + OVERRIDE_STATUS(Doc.of(Status.values()) // + .persistencePriority(PersistencePriority.HIGH)), // + + CUMULATED_ACTIVE_TIME(Doc.of(LONG)// + .unit(CUMULATED_SECONDS) // + .persistencePriority(HIGH)), // + + CUMULATED_INACTIVE_TIME(Doc.of(LONG)// + .unit(CUMULATED_SECONDS) // + .persistencePriority(HIGH)), // + API_WORKER_LOG(Doc.of(OpenemsType.STRING) // .text("Logs Write-Commands via ApiWorker")); // @@ -32,4 +52,31 @@ public default StringReadChannel getApiWorkerLogChannel() { return this.channel(ChannelId.API_WORKER_LOG); } + /** + * Gets the Channel for {@link ChannelId#OVERRIDE_STATUS}. + * + * @return the Channel + */ + public default Channel getOverrideStatusChannel() { + return this.channel(ChannelId.OVERRIDE_STATUS); + } + + /** + * Gets the Status. See {@link ChannelId#OVERRIDE_STATUS}. + * + * @return the Channel {@link Value} + */ + public default Status getOverrideStatus() { + return this.getOverrideStatusChannel().value().asEnum(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#OVERRIDE_STATUS} Channel. + * + * @param value the next value + */ + public default void _setOverrideStatus(Status value) { + this.getOverrideStatusChannel().setNextValue(value); + } + } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java index af51ee0b09..74055d005b 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java @@ -1,27 +1,49 @@ package io.openems.edge.controller.api.modbus.readwrite; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map.Entry; +import java.util.function.Consumer; + +import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.ghgande.j2mod.modbus.ModbusException; import io.openems.common.channel.AccessMode; +import io.openems.common.channel.PersistencePriority; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.jsonapi.ComponentJsonApi; import io.openems.edge.common.meta.Meta; import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.api.common.Status; +import io.openems.edge.controller.api.common.WriteObject; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.api.modbus.ModbusTcpApi; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateActiveTime; @Designate(ocd = Config.class, factory = true) @Component(// @@ -30,7 +52,22 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerApiModbusTcpReadWriteImpl extends AbstractModbusTcpApi - implements ControllerApiModbusTcpReadWrite, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi { + implements ControllerApiModbusTcpReadWrite, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi, TimedataProvider { + + private final Logger log = LoggerFactory.getLogger(ControllerApiModbusTcpReadWriteImpl.class); + + private final CalculateActiveTime calculateCumulatedActiveTime = new CalculateActiveTime(this, + ControllerApiModbusTcpReadWrite.ChannelId.CUMULATED_ACTIVE_TIME); + + private final CalculateActiveTime calculateCumulatedInactiveTime = new CalculateActiveTime(this, + ControllerApiModbusTcpReadWrite.ChannelId.CUMULATED_INACTIVE_TIME); + + private List writeChannels; + + private boolean isActive = false; + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL) + private volatile Timedata timedata = null; @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) private Meta metaComponent = null; @@ -39,7 +76,11 @@ public class ControllerApiModbusTcpReadWriteImpl extends AbstractModbusTcpApi private ConfigurationAdmin cm; @Override - @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE) + @Reference(// + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY, // + cardinality = ReferenceCardinality.MULTIPLE // + ) protected void addComponent(OpenemsComponent component) { super.addComponent(component); } @@ -60,9 +101,24 @@ public ControllerApiModbusTcpReadWriteImpl() { @Activate private void activate(ComponentContext context, Config config) throws ModbusException, OpenemsException { - super.activate(context, config.id(), config.alias(), config.enabled(), this.cm, - new ConfigRecord(this.metaComponent, config.component_ids(), config.apiTimeout(), config.port(), - config.maxConcurrentConnections())); + super.activate(context, this.cm, + new ConfigRecord(config.id(), config.alias(), config.enabled(), this.metaComponent, + config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections())); + this.applyConfig(config); + this.handleTimeDataChannels(); + } + + @Modified + private void modified(ComponentContext context, Config config) throws OpenemsNamedException { + super.modified(context, this.cm, + new ConfigRecord(config.id(), config.alias(), config.enabled(), this.metaComponent, + config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections())); + this.applyConfig(config); + this.handleTimeDataChannels(); + } + + private void applyConfig(Config config) { + this.writeChannels = new ArrayList<>(Arrays.asList(config.writeChannels())); } @Override @@ -70,9 +126,102 @@ private void activate(ComponentContext context, Config config) throws ModbusExce protected void deactivate() { super.deactivate(); } + + @Override + public void run() throws OpenemsNamedException { + this.isActive = false; + super.run(); + + this.calculateCumulatedActiveTime.update(this.isActive); + this.calculateCumulatedInactiveTime.update(!this.isActive); + } @Override protected AccessMode getAccessMode() { return AccessMode.READ_WRITE; } + + /** + * Updating the configuration property to given value. + * + * @param targetProperty Property that should be changed + * @param requiredValue Value that should be set + */ + private void configUpdate(String targetProperty, String requiredValue) { + Configuration c; + try { + var pid = this.servicePid(); + if (pid.isEmpty()) { + this.logInfo(this.log, "PID of " + this.id() + " is Empty"); + return; + } + c = this.cm.getConfiguration(pid, "?"); + var properties = c.getProperties(); + if (!this.writeChannels.contains(requiredValue)) { + this.writeChannels.add(requiredValue); + properties.put(targetProperty, this.writeChannels.toArray(String[]::new)); + c.update(properties); + } + } catch (IOException | SecurityException e) { + this.logError(this.log, "ERROR: " + e.getMessage()); + } + } + + @Override + protected Consumer, WriteObject>> handleWrites() { + return entry -> { + this.isActive = true; + WriteChannel channel = entry.getKey(); + var writeObject = entry.getValue(); + + String channelName = formatChannelName(channel); + var currentChannel = new ChannelIdImpl(channelName, + Doc.of(channel.getType()).persistencePriority(PersistencePriority.HIGH)); + if (!channels().stream().anyMatch(p -> p.channelId().name().equals(currentChannel.name()))) { + addChannel(currentChannel).setNextValue(writeObject.value()); + } else { + channel(currentChannel).setNextValue(writeObject.value()); + } + this.configUpdate("writeChannels", channel(currentChannel).channelId().id()); + }; + } + + @Override + protected void setOverrideStatus(Status status) { + this._setOverrideStatus(status); + } + + @Override + protected Runnable handleTimeouts() { + return () -> { + this.writeChannels.forEach(c -> { + channels().stream().filter(channel -> channel.channelId().id().equals(c)).findFirst() + .ifPresent(channel -> channel.setNextValue(null)); + }); + }; + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + /** + * Checks, if timedata channels are already set. + * If not, they will be created and added to current channels. + */ + protected void handleTimeDataChannels() { + var activeTimeChannel = new ChannelIdImpl("CUMULATED_ACTIVE_TIME", // + Doc.of(OpenemsType.DOUBLE).persistencePriority(PersistencePriority.HIGH)); + var inactiveTimeChannel = new ChannelIdImpl("CUMULATED_INACTIVE_TIME", // + Doc.of(OpenemsType.DOUBLE).persistencePriority(PersistencePriority.HIGH)); + + List timeChannels = Arrays.asList(activeTimeChannel, inactiveTimeChannel); + timeChannels.forEach(channel -> { + if (channels().stream().noneMatch(ch -> ch.channelId().id().equals(channel.id()))) { + addChannel(channel); + } + }); + } + } diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java index 5da230c70a..58ea9ca90c 100644 --- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java +++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java @@ -1,9 +1,11 @@ package io.openems.edge.controller.api.modbus.readwrite; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Test; - import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.common.test.DummyCycle; import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi; import io.openems.edge.controller.test.ControllerTest; @@ -26,4 +28,21 @@ public void test() throws Exception { .next(new TestCase()) // ; } + + @Test + public void testTimedataChannels() throws Exception { + var controller = new ControllerApiModbusTcpReadWriteImpl(); // + boolean channelNotFound = controller.channels().stream().noneMatch(// + ch -> ch.channelId().id().equals("CumulatedActiveTime") // + || ch.channelId().id().equals("CumulatedInactiveTime")); // + assertFalse(channelNotFound); + } + + @Test + public void testAddFalseComponents() throws Exception { + var controller = new ControllerApiModbusTcpReadWriteImpl(); // + controller.addComponent(new DummyCycle(1000)); // + controller.getComponentNoModbusApiFaultChannel().nextProcessImage(); // + assertTrue(controller.getComponentNoModbusApiFault().get()); // + } } diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java index 54489b1473..5c06b07855 100644 --- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java +++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java @@ -1,7 +1,12 @@ package io.openems.edge.controller.api.modbus.readwrite; +import java.nio.channels.Channels; + import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.types.EdgeConfig.Component.Channel; import io.openems.common.utils.ConfigUtils; +import io.openems.edge.common.channel.ChannelId; +import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; @SuppressWarnings("all") public class MyConfig extends AbstractComponentConfig implements Config { @@ -13,9 +18,21 @@ protected static class Builder { private String[] componentIds; private int maxConcurrentConnections; private int apiTimeout; + private String[] writeChannels = {}; + private String[] readChannels = {}; private Builder() { } + + public Builder setWriteChannels(String... writeChannels) { + this.writeChannels = writeChannels; + return this; + } + + public Builder setReadChannels(String... readChannels) { + this.readChannels = readChannels; + return this; + } public Builder setId(String id) { this.id = id; @@ -98,4 +115,14 @@ public int apiTimeout() { return this.builder.apiTimeout; } + @Override + public String[] readChannels() { + return this.builder.readChannels; + } + + @Override + public String[] writeChannels() { + return this.builder.writeChannels; + } + } \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/app/common/props/RelayProps.java b/io.openems.edge.core/src/io/openems/edge/app/common/props/RelayProps.java index 479a34f8fc..f8275bd4fc 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/common/props/RelayProps.java +++ b/io.openems.edge.core/src/io/openems/edge/app/common/props/RelayProps.java @@ -21,6 +21,7 @@ import io.openems.common.session.Language; import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.hardware.IoGpio; import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.core.appmanager.AbstractOpenemsApp; import io.openems.edge.core.appmanager.AppDef; @@ -91,13 +92,19 @@ public static RelayContactInformation createPhaseInformation(// final List preferredRelays // ) { final var relayInfos = util.getAllRelayInfos(ComponentUtil.CORE_COMPONENT_IDS, // - component -> filter.stream().allMatch(t -> t.componentFilter().test(component)), // + component -> filter.stream() // + .map(RelayContactFilter::componentFilter) // + .filter(Objects::nonNull) // + .allMatch(t -> t.test(component)), // component -> filter.stream() // .map(RelayContactFilter::componentAliasMapper) // .filter(Objects::nonNull) // .map(t -> t.apply(component)) // .findAny().orElse(component.alias()), // - (component, channel) -> filter.stream().allMatch(t -> t.channelFilter().test(component, channel)), // + (component, channel) -> filter.stream() // + .map(RelayContactFilter::channelFilter) // + .filter(Objects::nonNull) // + .allMatch(t -> t.test(component, channel)), // (component, channel) -> filter.stream() // .map(RelayContactFilter::channelAliasMapper) // .filter(Objects::nonNull) // @@ -105,6 +112,7 @@ public static RelayContactInformation createPhaseInformation(// .findAny().orElse(channel.address().toString()), // (component, channel) -> filter.stream() // .map(RelayContactFilter::disabledReasons) // + .filter(Objects::nonNull) // .map(t -> t.apply(component, channel)) // .flatMap(Collection::stream) // .toList()); @@ -171,6 +179,15 @@ public static RelayContactFilter feneconHomeFilter(// ); } + /** + * Creates a {@link RelayContactFilter} for {@link IoGpio} components. + * + * @return the {@link RelayContactFilter} + */ + public static RelayContactFilter gpioFilter() { + return new RelayContactFilter(t -> !t.serviceFactoryPid().equals("IO.Gpio"), null, null, null, null); + } + /** * Creates the {@link PreferredRelay} if a Home 20/30 relay board is installed. * diff --git a/io.openems.edge.core/src/io/openems/edge/app/ess/Limiter14a.java b/io.openems.edge.core/src/io/openems/edge/app/ess/Limiter14a.java new file mode 100644 index 0000000000..8856960f7d --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/ess/Limiter14a.java @@ -0,0 +1,178 @@ +package io.openems.edge.app.ess; + +import static io.openems.edge.app.common.props.CommonProps.alias; +import static java.util.Collections.emptyList; + +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.ComponentProps; +import io.openems.edge.app.common.props.RelayProps; +import io.openems.edge.app.common.props.RelayProps.RelayContactInformation; +import io.openems.edge.app.common.props.RelayProps.RelayContactInformationProvider; +import io.openems.edge.app.ess.Limiter14a.Limiter14aBundle; +import io.openems.edge.app.ess.Limiter14a.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter.BundleProvider; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; +import io.openems.edge.core.appmanager.dependency.DependencyUtil; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; + +@Component(name = "App.Ess.Limiter14a") +public class Limiter14a extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public record Limiter14aBundle(// + ResourceBundle bundle, // + RelayContactInformation relayContactInformation // + ) implements BundleProvider, RelayContactInformationProvider { + + } + + public static enum Property implements Type { + CTRL_ESS_LIMITER_14A_ID(AppDef.componentId("ctrlEssLimiter14a0")), // + + ALIAS(alias()), // + ESS_ID(ComponentProps.pickManagedSymmetricEssId()), // + INPUT_CHANNEL_ADDRESS(RelayProps.relayContactDef(1)), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, Limiter14aBundle> getParamter() { + return t -> new Limiter14aBundle(// + createResourceBundle(t.language), // + RelayProps.createPhaseInformation(t.app.componentUtil, 1, emptyList(), emptyList()) // + ); + } + + } + + @Activate + public Limiter14a(// + @Reference ComponentManager componentManager, // + ComponentContext componentContext, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.ESS }; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE; + } + + @Override + protected Limiter14a getApp() { + return this; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + + final var id = this.getId(t, p, Property.CTRL_ESS_LIMITER_14A_ID); + + final var alias = this.getString(p, Property.ALIAS); + final var essId = this.getString(p, Property.ESS_ID); + final var inputAddress = this.getString(p, Property.INPUT_CHANNEL_ADDRESS); + + final var components = List.of(// + new EdgeConfig.Component(id, alias, "Controller.Ess.Limiter14a", // + JsonUtils.buildJsonObject() // + .addProperty("ess.id", essId) // + .addProperty("inputChannelAddress", inputAddress) // + .build())); + + final var componentIdOfRelay = inputAddress.substring(0, inputAddress.indexOf('/')); + final var appIdOfRelay = DependencyUtil.getInstanceIdOfAppWhichHasComponent(this.componentManager, + componentIdOfRelay); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .addTask(Tasks.schedulerByCentralOrder( + new SchedulerComponent(id, "Controller.Ess.Limiter14a", this.getAppId()))) // + .onlyIf(appIdOfRelay != null, c -> c.addDependency(new DependencyDeclaration("RELAY", // + DependencyDeclaration.CreatePolicy.NEVER, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.NEVER, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ALL, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setSpecificInstanceId(appIdOfRelay) // + .build())))// + .build(); + }; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanSee(Role.ADMIN) // + .setCanDelete(Role.ADMIN) // + .build(); + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/hardware/IoGpio.java b/io.openems.edge.core/src/io/openems/edge/app/hardware/IoGpio.java new file mode 100644 index 0000000000..19720a1e14 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/hardware/IoGpio.java @@ -0,0 +1,141 @@ +package io.openems.edge.app.hardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.hardware.IoGpio.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; + +@Component(name = "App.Hardware.IoGpio") +public class IoGpio extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public enum Property implements Type { + // TODO default value should start at 0 but for integrated systems and hardware + // apps to work properly this one starts at 1 + IO_ID(AppDef.componentId("io1")), // + + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + + } + + @Activate + public IoGpio(// + @Reference ComponentManager componentManager, // + ComponentContext componentContext, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.HARDWARE }; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE; + } + + @Override + protected IoGpio getApp() { + return this; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var id = this.getId(t, p, Property.IO_ID); + + final var alias = this.getString(p, Property.ALIAS); + + final var components = List.of(// + new EdgeConfig.Component(id, alias, "IO.Gpio", JsonUtils.buildJsonObject() // + .addProperty("enabled", true) // + .addProperty("gpioPath", "/sys/class") // + .addProperty("hardwareType", "MODBERRY_X500_M40804_WB") // + .build())); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanSee(Role.ADMIN) // + .setCanDelete(Role.ADMIN) // + .build(); + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/heat/CombinedHeatAndPower.java b/io.openems.edge.core/src/io/openems/edge/app/heat/CombinedHeatAndPower.java index cf84a43bc4..3f1ca372b1 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/heat/CombinedHeatAndPower.java +++ b/io.openems.edge.core/src/io/openems/edge/app/heat/CombinedHeatAndPower.java @@ -122,7 +122,8 @@ public Function, CombinedHeatAndPowerPa return new CombinedHeatAndPowerParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 1, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, false)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, false), + RelayProps.gpioFilter()), // List.of(RelayProps.feneconHome2030PreferredRelays(isHomeInstalled, new int[] { 5 }), // PreferredRelay.of(4, new int[] { 1 }), // PreferredRelay.of(8, new int[] { 1 }))) // diff --git a/io.openems.edge.core/src/io/openems/edge/app/heat/HeatPump.java b/io.openems.edge.core/src/io/openems/edge/app/heat/HeatPump.java index 3800b3065c..1a7c9bcb76 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/heat/HeatPump.java +++ b/io.openems.edge.core/src/io/openems/edge/app/heat/HeatPump.java @@ -121,7 +121,8 @@ public Function, HeatPumpParameter> getParamter() { return new HeatPumpParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 2, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, false)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, false), + RelayProps.gpioFilter()), // List.of(RelayProps.feneconHome2030PreferredRelays(isHomeInstalled, new int[] { 5, 6 }), // PreferredRelay.of(4, new int[] { 2, 3 }), // PreferredRelay.of(8, new int[] { 2, 3 }))) // diff --git a/io.openems.edge.core/src/io/openems/edge/app/heat/HeatingElement.java b/io.openems.edge.core/src/io/openems/edge/app/heat/HeatingElement.java index d816f514ce..d483ac7ef6 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/heat/HeatingElement.java +++ b/io.openems.edge.core/src/io/openems/edge/app/heat/HeatingElement.java @@ -156,7 +156,8 @@ public Function, HeatingElementParameter> get return new HeatingElementParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 3, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true), + RelayProps.gpioFilter()), // List.of(RelayProps.feneconHome2030PreferredRelays(isHomeInstalled, new int[] { 1, 2, 3 }), // PreferredRelay.of(4, new int[] { 1, 2, 3 }), // diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome.java index 833c1a2d55..790bcc230f 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome.java @@ -3,6 +3,7 @@ import static io.openems.edge.app.common.props.CommonProps.alias; import static io.openems.edge.app.common.props.CommonProps.defaultDef; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.batteryInverter; +import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.essLimiter14aToHardware; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridOptimizedCharge; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.predictor; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.prepareBatteryExtension; @@ -14,6 +15,7 @@ import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.feedInType; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasAcMeter; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEmergencyReserve; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEssLimiter14a; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.maxFeedInPower; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.safetyCountry; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.shadowManagementDisabled; @@ -54,6 +56,8 @@ import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.AppDef; import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; import io.openems.edge.core.appmanager.ComponentUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; import io.openems.edge.core.appmanager.OpenemsApp; @@ -118,7 +122,7 @@ */ @Component(name = "App.FENECON.Home") public class FeneconHome extends AbstractOpenemsAppWithProps - implements OpenemsApp { + implements OpenemsApp, AppManagerUtilSupplier { public record FeneconHomeParameter(// ResourceBundle bundle, // @@ -162,7 +166,7 @@ public static enum Property implements Type { return new JsonPrimitive(parameter.defaultValues().feedInSetting()); }))), // - + HAS_ESS_LIMITER_14A(hasEssLimiter14a()), // // External AC PV HAS_AC_METER(AppDef.copyOfGeneric(hasAcMeter(), def -> def // .setDefaultValue((app, property, l, parameter) -> { @@ -248,10 +252,18 @@ public Function, FeneconHomeParameter> getParamt } } + private final AppManagerUtil appManagerUtil; + @Activate - public FeneconHome(@Reference ComponentManager componentManager, ComponentContext context, - @Reference ConfigurationAdmin cm, @Reference ComponentUtil componentUtil) { + public FeneconHome(// + @Reference final ComponentManager componentManager, // + final ComponentContext context, // + @Reference final ConfigurationAdmin cm, // + @Reference final ComponentUtil componentUtil, // + @Reference final AppManagerUtil appManagerUtil // + ) { super(componentManager, context, cm, componentUtil); + this.appManagerUtil = appManagerUtil; } @Override @@ -280,6 +292,8 @@ AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { : 0; final var shadowManagmentDisabled = this.getBoolean(p, Property.SHADOW_MANAGEMENT_DISABLED); + + final var hasEssLimiter14a = this.getBoolean(p, Property.HAS_ESS_LIMITER_14A); final var hasAcMeter = this.getBoolean(p, Property.HAS_AC_METER); // for older versions this property is undefined final var acType = this.getEnum(p, AcMeterType.class, Property.AC_METER_TYPE); @@ -420,6 +434,13 @@ AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { dependencies.add(acType.getDependency(modbusIdExternal)); } + if (hasEssLimiter14a) { + final var dependency = essLimiter14aToHardware(this.appManagerUtil); + if (dependency != null) { + dependencies.add(dependency); + } + } + final var schedulerComponents = new ArrayList(); if (hasEmergencyReserve) { schedulerComponents.add(new SchedulerComponent("ctrlEmergencyCapacityReserve0", @@ -539,4 +560,9 @@ private static Optional getBatteryInverter(ComponentManage return batteryInverter; } + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java index 083bd11673..e557fd7ebb 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome20.java @@ -10,6 +10,7 @@ import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ctrlEssSurplusFeedToGrid; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.emergencyMeter; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ess; +import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.essLimiter14aToHardware; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridMeter; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridOptimizedCharge; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.io; @@ -29,6 +30,7 @@ import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.gridMeterType; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasAcMeter; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEmergencyReserve; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEssLimiter14a; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.maxFeedInPower; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.safetyCountry; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.shadowManagementDisabled; @@ -66,6 +68,8 @@ import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.AppDef; import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; import io.openems.edge.core.appmanager.ComponentUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; import io.openems.edge.core.appmanager.OpenemsApp; @@ -134,7 +138,7 @@ */ @Component(name = "App.FENECON.Home.20") public class FeneconHome20 extends AbstractOpenemsAppWithProps - implements OpenemsApp { + implements OpenemsApp, AppManagerUtilSupplier { public enum Property implements PropertyParent { ALIAS(alias()), // @@ -149,6 +153,8 @@ public enum Property implements PropertyParent { GRID_METER_CATEGORY(gridMeterType()), // CT_RATIO_FIRST(ctRatioFirst(GRID_METER_CATEGORY)), // + HAS_ESS_LIMITER_14A(hasEssLimiter14a()), // + HAS_AC_METER(hasAcMeter()), // AC_METER_TYPE(acMeterType(HAS_AC_METER)), // @@ -194,15 +200,18 @@ public Type self() { private static final IntFunction MPPT_ALIAS = value -> "ALIAS_MPPT_" + (value + 1); private final Map pvDefs = new TreeMap<>(); + private final AppManagerUtil appManagerUtil; @Activate public FeneconHome20(// @Reference final ComponentManager componentManager, // final ComponentContext componentContext, // @Reference final ConfigurationAdmin cm, // - @Reference final ComponentUtil componentUtil // + @Reference final ComponentUtil componentUtil, // + @Reference final AppManagerUtil appManagerUtil // ) { super(componentManager, componentContext, cm, componentUtil); + this.appManagerUtil = appManagerUtil; BooleanExpression anyOldPvSelected = null; for (int i = 0; i < MAX_NUMBER_OF_PV; i++) { @@ -287,6 +296,7 @@ protected ThrowingTriFunction(); if (hasEmergencyReserve) { schedulerComponents.add(new SchedulerComponent("ctrlEmergencyCapacityReserve0", @@ -421,6 +436,11 @@ protected PropertyParent[] propertyValues() { return builder.build().toArray(PropertyParent[]::new); } + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + public static interface PropertyParent extends Type { } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java index 34d2c67278..019e73af9c 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHome30.java @@ -10,6 +10,7 @@ import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ctrlEssSurplusFeedToGrid; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.emergencyMeter; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.ess; +import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.essLimiter14aToHardware; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridMeter; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.gridOptimizedCharge; import static io.openems.edge.app.integratedsystem.FeneconHomeComponents.io; @@ -29,6 +30,7 @@ import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.gridMeterType; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasAcMeter; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEmergencyReserve; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.hasEssLimiter14a; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.maxFeedInPower; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.safetyCountry; import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.shadowManagementDisabled; @@ -66,6 +68,8 @@ import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.AppDef; import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; import io.openems.edge.core.appmanager.ComponentUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; import io.openems.edge.core.appmanager.OpenemsApp; @@ -134,7 +138,7 @@ */ @Component(name = "App.FENECON.Home.30") public class FeneconHome30 extends AbstractOpenemsAppWithProps - implements OpenemsApp { + implements OpenemsApp, AppManagerUtilSupplier { public enum Property implements PropertyParent { ALIAS(alias()), // @@ -149,6 +153,8 @@ public enum Property implements PropertyParent { GRID_METER_CATEGORY(gridMeterType()), // CT_RATIO_FIRST(ctRatioFirst(GRID_METER_CATEGORY)), // + HAS_ESS_LIMITER_14A(hasEssLimiter14a()), // + HAS_AC_METER(hasAcMeter()), // AC_METER_TYPE(acMeterType(HAS_AC_METER)), // @@ -194,15 +200,18 @@ public Type self() { private static final IntFunction MPPT_ALIAS = value -> "ALIAS_MPPT_" + (value + 1); private final Map pvDefs = new TreeMap<>(); + private final AppManagerUtil appManagerUtil; @Activate public FeneconHome30(// @Reference final ComponentManager componentManager, // final ComponentContext componentContext, // @Reference final ConfigurationAdmin cm, // - @Reference final ComponentUtil componentUtil // + @Reference final ComponentUtil componentUtil, // + @Reference final AppManagerUtil appManagerUtil // ) { super(componentManager, componentContext, cm, componentUtil); + this.appManagerUtil = appManagerUtil; BooleanExpression anyOldPvSelected = null; for (int i = 0; i < MAX_NUMBER_OF_PV; i++) { @@ -288,6 +297,7 @@ protected ThrowingTriFunction(); if (hasEmergencyReserve) { schedulerComponents.add(new SchedulerComponent("ctrlEmergencyCapacityReserve0", @@ -423,6 +437,11 @@ protected PropertyParent[] propertyValues() { return builder.build().toArray(PropertyParent[]::new); } + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + public static interface PropertyParent extends Type { } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java index 3a0b44135d..72f62c234b 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/FeneconHomeComponents.java @@ -2,16 +2,22 @@ import java.util.ResourceBundle; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.EdgeConfig; import io.openems.common.types.EdgeConfig.Component; import io.openems.common.utils.JsonUtils; import io.openems.edge.app.enums.FeedInType; import io.openems.edge.app.enums.Parity; import io.openems.edge.app.enums.SafetyCountry; +import io.openems.edge.app.ess.Limiter14a; import io.openems.edge.app.ess.PrepareBatteryExtension; +import io.openems.edge.app.hardware.IoGpio; import io.openems.edge.app.pvselfconsumption.GridOptimizedCharge; import io.openems.edge.app.pvselfconsumption.SelfConsumptionOptimization; +import io.openems.edge.core.appmanager.AppManagerUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsAppCategory; import io.openems.edge.core.appmanager.TranslationUtil; import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; @@ -480,6 +486,60 @@ public static DependencyDeclaration prepareBatteryExtension() { .build()); } + /** + * Creates a default essLimiter14a dependency for a FENECON Home. + * + * @param ioId the id of the input component + * @return the {@link DependencyDeclaration} + */ + public static DependencyDeclaration essLimiter14a(// + final String ioId // + ) { + return new DependencyDeclaration("ESS_LIMITER_14A", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.IF_MINE, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Ess.Limiter14a") // + .setProperties(JsonUtils.buildJsonObject() // + .addProperty(Limiter14a.Property.ESS_ID.name(), "ess0") // + .addProperty(Limiter14a.Property.INPUT_CHANNEL_ADDRESS.name(), ioId + "/DigitalInput1") // + .build()) // + .build()); + } + + /** + * Creates a default essLimiter14a dependency for a FENECON Home which can be + * different depending on the hardware type. + * + * @param appManagerUtil the {@link AppManagerUtil} to get the hardware type + * @return the {@link DependencyDeclaration} of the specific hardware or null if + * not specified for the current hardware + * @throws OpenemsNamedException on error + */ + public static DependencyDeclaration essLimiter14aToHardware(AppManagerUtil appManagerUtil) + throws OpenemsNamedException { + final var deviceHardware = appManagerUtil + .getInstantiatedAppsByCategories(OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE); + final var app = deviceHardware.stream().findAny().orElse(null); + switch (app == null ? "" : app.appId) { + case "App.OpenemsHardware.CM3", "App.OpenemsHardware.CM4S" -> { + for (var dependency : app.dependencies) { + if (!"IO_GPIO".equals(dependency.key)) { + continue; + } + final var instance = appManagerUtil.findInstanceByIdOrError(dependency.instanceId); + final var ioId = instance.properties.get(IoGpio.Property.IO_ID.name()).getAsString(); + return essLimiter14a(ioId); + } + } + } + throw new OpenemsException( + "Hardware " + (app == null ? "UNDEFINED" : app.appId) + " not supported for ess limiter 14a."); + } + private FeneconHomeComponents() { } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/IntegratedSystemProps.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/IntegratedSystemProps.java index d5610be64f..4170c49226 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/IntegratedSystemProps.java +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/IntegratedSystemProps.java @@ -12,8 +12,10 @@ import io.openems.edge.app.enums.OptionsFactory; import io.openems.edge.app.enums.SafetyCountry; import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; import io.openems.edge.core.appmanager.Nameable; import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCategory; import io.openems.edge.core.appmanager.Type.Parameter.BundleProvider; import io.openems.edge.core.appmanager.formly.Exp; import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; @@ -271,6 +273,34 @@ public static final AppDef acMeterType(// })); } + /** + * Creates a {@link AppDef} for selecting if the system has a ess limiter for + * 14a. + * + * @param the type of the app + * @return the created {@link AppDef} + */ + public static final // + AppDef hasEssLimiter14a() { + return AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.IntegratedSystem.hasEssLimiter14a.label") // + .setDefaultValue(false) // + .setField(JsonFormlyUtil::buildCheckboxFromNameable, (app, property, l, parameter, field) -> { + final var hardwareTypes = app.getAppManagerUtil() + .getInstantiatedAppsByCategories(OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE); + + final var isSupported = hardwareTypes.stream()// + .anyMatch(t -> switch (t.appId) { + case "App.OpenemsHardware.CM3", "App.OpenemsHardware.CM4S" -> true; + default -> false; + }); + + if (!isSupported) { + field.disabled(true); + } + })); + } + private IntegratedSystemProps() { } diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercial92.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercial92.java new file mode 100644 index 0000000000..0bc05c28b0 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercial92.java @@ -0,0 +1,175 @@ +package io.openems.edge.app.integratedsystem.fenecon.commercial; + +import static io.openems.edge.app.common.props.CommonProps.alias; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.feedInType; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.maxFeedInPower; +import static io.openems.edge.app.integratedsystem.IntegratedSystemProps.safetyCountry; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.enums.FeedInType; +import io.openems.edge.app.integratedsystem.FeneconHomeComponents; +import io.openems.edge.app.integratedsystem.fenecon.commercial.FeneconCommercial92.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.InterfaceConfiguration; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; + +@Component(name = "App.FENECON.Commercial.92") +public class FeneconCommercial92 extends + AbstractOpenemsAppWithProps implements OpenemsApp { + + public enum Property implements Type { + ALIAS(alias()), // + + SAFETY_COUNTRY(AppDef.copyOfGeneric(safetyCountry(), def -> def // + .setRequired(true))), // + + FEED_IN_TYPE(feedInType(FeedInType.EXTERNAL_LIMITATION)), // + MAX_FEED_IN_POWER(maxFeedInPower(FEED_IN_TYPE)), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + + } + + @Activate + public FeneconCommercial92(// + @Reference final ComponentManager componentManager, // + final ComponentContext componentContext, // + @Reference final ConfigurationAdmin cm, // + @Reference final ComponentUtil componentUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.INTEGRATED_SYSTEM }; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + protected FeneconCommercial92 getApp() { + return this; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var bundle = AbstractOpenemsApp.getTranslationBundle(l); + + final var batteryId = "battery0"; + final var batteryInverterId = "batteryInverter0"; + final var modbusToBatteryId = "modbus0"; + final var modbusToBatteryInverterId = "modbus1"; + final var modbusToGridMeterId = "modbus2"; + final var modbusToExternalDevicesId = "modbus3"; + final var gridMeterId = "meter0"; + final var essId = "ess0"; + + final var feedInType = this.getEnum(p, FeedInType.class, Property.FEED_IN_TYPE); + final var maxFeedInPower = feedInType == FeedInType.DYNAMIC_LIMITATION + ? this.getInt(p, Property.MAX_FEED_IN_POWER) + : 0; + + final var components = Lists.newArrayList(// + FeneconHomeComponents.battery(bundle, batteryId, modbusToBatteryId), // + FeneconCommercialComponents.batteryInverter(bundle, batteryInverterId, modbusToBatteryInverterId), // + FeneconHomeComponents.ess(bundle, essId, batteryId, batteryInverterId), // + FeneconHomeComponents.io(bundle, modbusToBatteryId), // + FeneconHomeComponents.modbusInternal(bundle, t, modbusToBatteryId), // + FeneconHomeComponents.predictor(bundle, t), // + FeneconCommercialComponents.modbusToBatteryInverter(bundle, t, modbusToBatteryInverterId), // + FeneconCommercialComponents.modbusToGridMeter(bundle, t, modbusToGridMeterId), // + FeneconHomeComponents.modbusForExternalMeters(bundle, t, modbusToExternalDevicesId) // + ); + + final var dependencies = Lists.newArrayList(// + FeneconHomeComponents.selfConsumptionOptimization(t, essId, gridMeterId), // + FeneconHomeComponents.gridOptimizedCharge(t, feedInType, maxFeedInPower), // + FeneconHomeComponents.prepareBatteryExtension(), // + FeneconCommercialComponents.gridMeter(bundle, gridMeterId, modbusToGridMeterId) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .addTask(Tasks.staticIp(new InterfaceConfiguration("eth1") // + .addIp("BatteryInverter", "172.16.0.99/24"))) + .addDependencies(dependencies) // + .build(); + }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.INSTALLER) // + .setCanSee(Role.INSTALLER) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercialComponents.java b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercialComponents.java new file mode 100644 index 0000000000..f4857fd115 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/integratedsystem/fenecon/commercial/FeneconCommercialComponents.java @@ -0,0 +1,130 @@ +package io.openems.edge.app.integratedsystem.fenecon.commercial; + +import static io.openems.edge.core.appmanager.TranslationUtil.translate; + +import java.util.ResourceBundle; + +import io.openems.common.types.EdgeConfig; +import io.openems.common.types.EdgeConfig.Component; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.enums.MeterType; +import io.openems.edge.app.enums.Parity; +import io.openems.edge.app.meter.KdkMeter; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; + +public final class FeneconCommercialComponents { + + /** + * Creates a default battery inverter component for a FENECON Commercial 92. + * + * @param bundle the translation bundle + * @param batteryInverterId the id of the battery inverter + * @param modbusId the id of the modbus bridge + * @return the {@link Component} + */ + public static EdgeConfig.Component batteryInverter(// + final ResourceBundle bundle, // + final String batteryInverterId, // + final String modbusId // + ) { + return new EdgeConfig.Component(batteryInverterId, + translate(bundle, "App.IntegratedSystem.batteryInverter0.alias"), + "Battery-Inverter.Kaco.BlueplanetGridsave", // + JsonUtils.buildJsonObject() // + .addProperty("enabled", true) // + .addProperty("modbus.id", modbusId) // + .addProperty("startStop", "AUTO") // + .build()); + } + + /** + * Creates a default modbus bridge component to the battery inverter for a + * FENECON Commercial 92. + * + * @param bundle the translation bundle + * @param t the current {@link ConfigurationTarget} + * @param modbusId the id of the modbus bridge + * @return the {@link Component} + */ + public static EdgeConfig.Component modbusToBatteryInverter(// + final ResourceBundle bundle, // + final ConfigurationTarget t, // + final String modbusId // + ) { + return new EdgeConfig.Component(modbusId, translate(bundle, "App.IntegratedSystem.modbus1.alias"), + "Bridge.Modbus.Tcp", // + JsonUtils.buildJsonObject() // + .addProperty("enabled", true) // + .addProperty("ip", "172.16.0.100") // + .addProperty("port", 502) // + .onlyIf(t == ConfigurationTarget.ADD, b -> b// + .addProperty("invalidateElementsAfterReadErrors", 1) // + .addProperty("logVerbosity", "NONE")) + .build()); + } + + /** + * Creates a default modbus bridge component to the grid meter for a FENECON + * Commercial 92. + * + * @param bundle the translation bundle + * @param t the current {@link ConfigurationTarget} + * @param modbusId the id of the external modbus bridge + * @return the {@link Component} + */ + public static EdgeConfig.Component modbusToGridMeter(// + final ResourceBundle bundle, // + final ConfigurationTarget t, // + final String modbusId // + ) { + return new EdgeConfig.Component(modbusId, translate(bundle, "App.IntegratedSystem.modbusToGridMeter.alias"), + "Bridge.Modbus.Serial", // + JsonUtils.buildJsonObject() // + .addProperty("enabled", true) // + .addProperty("baudRate", 9600) // + .addProperty("databits", 8) // + .addProperty("parity", Parity.NONE) // + .addProperty("portName", "/dev/busUSB2") // + .addProperty("stopbits", "ONE") // + .onlyIf(t == ConfigurationTarget.ADD, b -> b// + .addProperty("invalidateElementsAfterReadErrors", 1) // + .addProperty("logVerbosity", "NONE")) + .build()); + } + + /** + * Creates a default gridMeter dependency for a FENECON Commercial 92. + * + * @param bundle the translation bundle + * @param gridMeterId the id of the grid meter + * @param modbusId the id of the modbus bridge + * @return the {@link DependencyDeclaration} + */ + public static DependencyDeclaration gridMeter(// + final ResourceBundle bundle, // + final String gridMeterId, // + final String modbusId // + ) { + return new DependencyDeclaration("GRID_METER", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.ALWAYS, // + DependencyDeclaration.DeletePolicy.IF_MINE, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Meter.Kdk") // + .setAlias(translate(bundle, "App.Meter.gridMeter")) // + .setProperties(JsonUtils.buildJsonObject() // + .addProperty(KdkMeter.Property.METER_ID.name(), gridMeterId) // + .addProperty(KdkMeter.Property.MODBUS_ID.name(), modbusId) // + .addProperty(KdkMeter.Property.MODBUS_UNIT_ID.name(), 5) // + .addProperty(KdkMeter.Property.TYPE.name(), MeterType.GRID) // + .build()) + .build()); + } + + private FeneconCommercialComponents() { + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ManualRelayControl.java b/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ManualRelayControl.java index b10ae500aa..eac82b5b98 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ManualRelayControl.java +++ b/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ManualRelayControl.java @@ -114,7 +114,8 @@ public Function, ManualRelayControlParame return new ManualRelayControlParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 2, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true), + RelayProps.gpioFilter()), // List.of(PreferredRelay.of(4, new int[] { 1 }), // PreferredRelay.of(8, new int[] { 1 }))) // ); diff --git a/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ThresholdControl.java b/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ThresholdControl.java index 00b93cd7ab..23e3d80be1 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ThresholdControl.java +++ b/io.openems.edge.core/src/io/openems/edge/app/loadcontrol/ThresholdControl.java @@ -115,7 +115,8 @@ public Function, ThresholdControlControlPar return new ThresholdControlControlParameter(// createResourceBundle(t.language), // createPhaseInformation(t.app.componentUtil, 2, // - List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true)), // + List.of(RelayProps.feneconHomeFilter(t.language, isHomeInstalled, true), + RelayProps.gpioFilter()), // List.of(PreferredRelay.of(4, new int[] { 1 }), // PreferredRelay.of(8, new int[] { 1 }))) // ); diff --git a/io.openems.edge.core/src/io/openems/edge/app/meter/JanitzaMeter.java b/io.openems.edge.core/src/io/openems/edge/app/meter/JanitzaMeter.java index ac824238ce..98b14f0e69 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/meter/JanitzaMeter.java +++ b/io.openems.edge.core/src/io/openems/edge/app/meter/JanitzaMeter.java @@ -43,6 +43,7 @@ import io.openems.edge.core.appmanager.OpenemsApp; import io.openems.edge.core.appmanager.OpenemsAppCardinality; import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.TranslationUtil; import io.openems.edge.core.appmanager.Type; import io.openems.edge.core.appmanager.Type.Parameter; import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; @@ -168,7 +169,7 @@ protected ThrowingTriFunction, L final var meterId = this.getId(t, p, Property.METER_ID, "meter1"); final var alias = this.getString(p, l, Property.ALIAS); - final var factorieId = this.getString(p, Property.MODEL); + final var factoryId = this.getString(p, Property.MODEL); final var type = this.getEnum(p, MeterType.class, Property.TYPE); final var modbusUnitId = this.getInt(p, Property.MODBUS_UNIT_ID); final var integrationType = this.getEnum(p, ModbusType.class, Property.INTEGRATION_TYPE); @@ -182,7 +183,9 @@ protected ThrowingTriFunction, L final var port = this.getInt(p, Property.PORT); final var tcpModbusId = this.getId(t, p, Property.MODBUS_ID); - components.add(new EdgeConfig.Component(tcpModbusId, "bridge", "Bridge.Modbus.Tcp", // + components.add(new EdgeConfig.Component(tcpModbusId, + TranslationUtil.translate(AbstractOpenemsApp.getTranslationBundle(l), "App.Meter.alias"), + "Bridge.Modbus.Tcp", // JsonUtils.buildJsonObject() // .addProperty("ip", ip) // .addProperty("port", port) // @@ -192,7 +195,7 @@ protected ThrowingTriFunction, L } }; - components.add(new EdgeConfig.Component(meterId, alias, factorieId, // + components.add(new EdgeConfig.Component(meterId, alias, factoryId, // JsonUtils.buildJsonObject() // .addProperty("modbus.id", modbusId) // .addProperty("modbusUnitId", modbusUnitId) // diff --git a/io.openems.edge.core/src/io/openems/edge/app/meter/PhoenixContactMeter.java b/io.openems.edge.core/src/io/openems/edge/app/meter/PhoenixContactMeter.java new file mode 100644 index 0000000000..82fd0866bd --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/meter/PhoenixContactMeter.java @@ -0,0 +1,169 @@ +package io.openems.edge.app.meter; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.app.enums.MeterType; +import io.openems.edge.app.meter.PhoenixContactMeter.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.TranslationUtil; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; + +/** + * Describes a App for a PhoenixContact meter. + */ +@Component(name = "App.Meter.PhoenixContact") +public class PhoenixContactMeter extends + AbstractOpenemsAppWithProps implements OpenemsApp { + + public enum Property implements Type { + // Component-IDs + METER_ID(AppDef.componentId("meter1")), // + MODBUS_ID(AppDef.componentId("modbus2")), // + // Properties + ALIAS(CommonProps.alias()), // + TYPE(AppDef.copyOfGeneric(MeterProps.type(MeterType.GRID), def -> def // + .setRequired(true))), // + IP(MeterProps.ip() // + .setRequired(true)), // + PORT(MeterProps.port() // + .setRequired(true)), // + MODBUS_UNIT_ID(AppDef.copyOfGeneric(MeterProps.modbusUnitId(), def -> def // + .setRequired(true) // + .setDefaultValue(1))), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public PhoenixContactMeter(// + @Reference final ComponentManager componentManager, // + final ComponentContext componentContext, // + @Reference final ConfigurationAdmin cm, // + @Reference final ComponentUtil componentUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var meterId = this.getId(t, p, Property.METER_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var type = this.getEnum(p, MeterType.class, Property.TYPE); + final var modbusUnitId = this.getInt(p, Property.MODBUS_UNIT_ID); + + final var ip = this.getString(p, Property.IP); + final var port = this.getInt(p, Property.PORT); + final var modbusId = this.getId(t, p, Property.MODBUS_ID); + + final var components = Lists.newArrayList(// + new EdgeConfig.Component(modbusId, + TranslationUtil.translate(AbstractOpenemsApp.getTranslationBundle(l), "App.Meter.alias"), + "Bridge.Modbus.Tcp", // + JsonUtils.buildJsonObject() // + .addProperty("ip", ip) // + .addProperty("port", port) // + .build()), // + new EdgeConfig.Component(meterId, alias, "Meter.PhoenixContact", // + JsonUtils.buildJsonObject() // + .addProperty("modbus.id", modbusId) // + .addProperty("modbusUnitId", modbusUnitId) // + .addProperty("type", type) // + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public final OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.METER }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.MULTIPLE; + } + + @Override + protected PhoenixContactMeter getApp() { + return this; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanSee(Role.ADMIN)// + .setCanDelete(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/meter/PqPlusMeter.java b/io.openems.edge.core/src/io/openems/edge/app/meter/PqPlusMeter.java new file mode 100644 index 0000000000..064eef6f63 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/meter/PqPlusMeter.java @@ -0,0 +1,279 @@ +package io.openems.edge.app.meter; + +import static io.openems.edge.app.common.props.CommonProps.defaultDef; +import static io.openems.edge.core.appmanager.TranslationUtil.translate; + +import java.util.ArrayList; +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommonProps; +import io.openems.edge.app.common.props.CommunicationProps; +import io.openems.edge.app.common.props.ComponentProps; +import io.openems.edge.app.common.props.PropsUtil; +import io.openems.edge.app.enums.MeterType; +import io.openems.edge.app.enums.ModbusType; +import io.openems.edge.app.enums.OptionsFactory; +import io.openems.edge.app.enums.TranslatableEnum; +import io.openems.edge.app.meter.PqPlusMeter.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.AppManagerUtil; +import io.openems.edge.core.appmanager.AppManagerUtilSupplier; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ComponentUtilSupplier; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.TranslationUtil; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.formly.Exp; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; + +/** + * Describes a App for a PQ-Plus meter. + * + *

    +  {
    +    "appId":"App.Meter.PqPlus",
    +    "alias":"PQ-Plus Meter",
    +    "instanceId": UUID,
    +    "image": base64,
    +    "properties":{
    +    	"METER_ID": "meter1",
    +    	"TYPE": "PRODUCTION",
    +    	"MODBUS_ID": "modbus1",
    +    	"MODBUS_UNIT_ID": 6
    +    },
    +    "appDescriptor": {
    +    	"websiteUrl": {@link AppDescriptor#getWebsiteUrl()}
    +    }
    +  }
    + * 
    + */ +@Component(name = "App.Meter.PqPlus") +public class PqPlusMeter extends AbstractOpenemsAppWithProps + implements OpenemsApp, ComponentUtilSupplier, AppManagerUtilSupplier { + + public enum Property implements Type { + // Component-IDs + METER_ID(AppDef.componentId("meter1")), // + MODBUS_ID(AppDef.componentId("modbus2")), // + // Properties + ALIAS(CommonProps.alias()), // + TYPE(AppDef.copyOfGeneric(MeterProps.type(MeterType.GRID), def -> def // + .setRequired(true))), // + INTEGRATION_TYPE(CommunicationProps.modbusType() // + .setRequired(true)), // + IP(MeterProps.ip() // + .setDefaultValue("10.4.0.12") // + .setRequired(true) // + .wrapField((app, property, l, parameter, field) -> { + field.onlyShowIf((Exp.currentModelValue(INTEGRATION_TYPE) // + .equal(Exp.staticValue(ModbusType.TCP)))); + })), // + PORT(MeterProps.port() // + .setRequired(true) // + .wrapField((app, property, l, parameter, field) -> { + field.onlyShowIf((Exp.currentModelValue(INTEGRATION_TYPE) // + .equal(Exp.staticValue(ModbusType.TCP)))); + })), // + SELECTED_MODBUS_ID(AppDef.copyOfGeneric(ComponentProps.pickSerialModbusId(), def -> def // + .setRequired(true) // + .wrapField((app, property, l, parameter, field) -> { + if (PropsUtil.isHomeInstalled(app.getAppManagerUtil())) { + field.readonly(true); + } + field.onlyShowIf(Exp.currentModelValue(INTEGRATION_TYPE) // + .equal(Exp.staticValue(ModbusType.RTU))); + })) // + .setAutoGenerateField(false)), // + MODEL(AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".productModel") // + .setDefaultValue(PqPlusModel.UMD_96.getValue()) // + .setRequired(true) // + .setField(JsonFormlyUtil::buildSelect, (app, property, l, parameter, field) -> { + field.setOptions(OptionsFactory.of(PqPlusModel.class), l); + }))), // + MODBUS_UNIT_ID(AppDef.copyOfGeneric(MeterProps.modbusUnitId(), def -> def // + .setRequired(true) // + .setAutoGenerateField(false) // + .setDefaultValue(6))), // + MODBUS_GROUP(CommunicationProps.modbusGroup(// + SELECTED_MODBUS_ID, SELECTED_MODBUS_ID.def(), // + MODBUS_UNIT_ID, MODBUS_UNIT_ID.def(), INTEGRATION_TYPE)), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + private final AppManagerUtil appManagerUtil; + + @Activate + public PqPlusMeter(// + @Reference final ComponentManager componentManager, // + final ComponentContext componentContext, // + @Reference final ConfigurationAdmin cm, // + @Reference final ComponentUtil componentUtil, // + @Reference final AppManagerUtil appManagerUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + this.appManagerUtil = appManagerUtil; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var meterId = this.getId(t, p, Property.METER_ID); + + final var alias = this.getString(p, l, Property.ALIAS); + final var factoryId = this.getString(p, Property.MODEL); + final var type = this.getEnum(p, MeterType.class, Property.TYPE); + final var modbusUnitId = this.getInt(p, Property.MODBUS_UNIT_ID); + final var integrationType = this.getEnum(p, ModbusType.class, Property.INTEGRATION_TYPE); + + final var components = new ArrayList(); + + final var modbusId = switch (integrationType) { + case RTU -> this.getString(p, Property.SELECTED_MODBUS_ID); + case TCP -> { + final var ip = this.getString(p, Property.IP); + final var port = this.getInt(p, Property.PORT); + final var tcpModbusId = this.getId(t, p, Property.MODBUS_ID); + + components.add(new EdgeConfig.Component(tcpModbusId, + TranslationUtil.translate(AbstractOpenemsApp.getTranslationBundle(l), "App.Meter.alias"), + "Bridge.Modbus.Tcp", // + JsonUtils.buildJsonObject() // + .addProperty("ip", ip) // + .addProperty("port", port) // + .build())); + + yield tcpModbusId; + } + }; + + components.add(// + new EdgeConfig.Component(meterId, alias, factoryId, // + JsonUtils.buildJsonObject() // + .addProperty("modbus.id", modbusId) // + .addProperty("modbusUnitId", modbusUnitId) // + .addProperty("type", type) // + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public final OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.METER }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public AppManagerUtil getAppManagerUtil() { + return this.appManagerUtil; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.MULTIPLE; + } + + @Override + protected PqPlusMeter getApp() { + return this; + } + + public enum PqPlusModel implements TranslatableEnum { + UMD_96("Meter.PqPlus.UMD96", "App.Meter.PqPlus.UMD96"), // + UMD_97("Meter.PqPlus.UMD97", "App.Meter.PqPlus.UMD97"), // + ; + + private final String value; + private final String translation; + + private PqPlusModel(String value, String translation) { + this.value = value; + this.translation = translation; + } + + @Override + public String getTranslation(Language language) { + return translate(getTranslationBundle(language), this.translation); + } + + @Override + public String getValue() { + return this.value; + } + + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanSee(Role.ADMIN)// + .setCanDelete(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/BeagleBoneBlack.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/BeagleBoneBlack.java new file mode 100644 index 0000000000..19c4f155ac --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/BeagleBoneBlack.java @@ -0,0 +1,121 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.BeagleBoneBlack.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; + +@Component(name = "App.OpenemsHardware.BeagleBoneBlack") +public class BeagleBoneBlack extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public BeagleBoneBlack(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.empty(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected BeagleBoneBlack getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/Compulab.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/Compulab.java new file mode 100644 index 0000000000..dde30d24c6 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/Compulab.java @@ -0,0 +1,121 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.Compulab.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; + +@Component(name = "App.OpenemsHardware.Compulab") +public class Compulab extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public Compulab(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.empty(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected Compulab getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm3.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm3.java new file mode 100644 index 0000000000..d89f0430bb --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm3.java @@ -0,0 +1,132 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.TechbaseCm3.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; + +@Component(name = "App.OpenemsHardware.CM3") +public class TechbaseCm3 extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm3(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.create() // + .addDependencies(new DependencyDeclaration("IO_GPIO", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.ALWAYS, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Hardware.IoGpio") // + .build())) + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm3 getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // TODO maybe only system + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4.java new file mode 100644 index 0000000000..f0a35bdc8f --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4.java @@ -0,0 +1,121 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.TechbaseCm4.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; + +@Component(name = "App.OpenemsHardware.CM4") +public class TechbaseCm4 extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm4(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.empty(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm4 getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4Max.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4Max.java new file mode 100644 index 0000000000..a67442790b --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4Max.java @@ -0,0 +1,121 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.TechbaseCm4Max.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; + +@Component(name = "App.OpenemsHardware.CM4Max") +public class TechbaseCm4Max extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm4Max(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.empty(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm4Max getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4s.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4s.java new file mode 100644 index 0000000000..8ce06dcb34 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4s.java @@ -0,0 +1,132 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.edge.app.openemshardware.TechbaseCm4s.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; + +@Component(name = "App.OpenemsHardware.CM4S") +public class TechbaseCm4s extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm4s(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.create() // + .addDependencies(new DependencyDeclaration("IO_GPIO", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.ALWAYS, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Hardware.IoGpio") // + .build())) + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm4s getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4sGen2.java b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4sGen2.java new file mode 100644 index 0000000000..dd6b6df3c0 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/openemshardware/TechbaseCm4sGen2.java @@ -0,0 +1,137 @@ +package io.openems.edge.app.openemshardware; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.hardware.IoGpio; +import io.openems.edge.app.openemshardware.TechbaseCm4sGen2.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; + +@Component(name = "App.OpenemsHardware.CM4S.Gen2") +public class TechbaseCm4sGen2 extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Properties + ALIAS(alias()), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public TechbaseCm4sGen2(// + @Reference ComponentManager componentManager, // + ComponentContext context, // + @Reference ConfigurationAdmin cm, // + @Reference ComponentUtil componentUtil // + ) { + super(componentManager, context, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + return AppConfiguration.create() // + .addDependencies(new DependencyDeclaration("IO_GPIO", // + DependencyDeclaration.CreatePolicy.IF_NOT_EXISTING, // + DependencyDeclaration.UpdatePolicy.NEVER, // + DependencyDeclaration.DeletePolicy.ALWAYS, // + DependencyDeclaration.DependencyUpdatePolicy.ALLOW_ONLY_UNCONFIGURED_PROPERTIES, // + DependencyDeclaration.DependencyDeletePolicy.NOT_ALLOWED, // + DependencyDeclaration.AppDependencyConfig.create() // + .setAppId("App.Hardware.IoGpio") // + .setInitialProperties(JsonUtils.buildJsonObject() // + .addProperty(IoGpio.Property.IO_ID.name(), "io1") // + .build()) + .build())) + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE }; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + protected TechbaseCm4sGen2 getApp() { + return this; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE_IN_CATEGORY; + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // + .setCanSee(Role.ADMIN) // + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java index 2a239b4579..31200d3988 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/AwattarHourly.java @@ -2,6 +2,7 @@ import static io.openems.edge.app.common.props.CommonProps.alias; import static io.openems.edge.app.common.props.CommonProps.defaultDef; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -168,7 +169,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java index 417b2e8a67..0c2f6d2f10 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java @@ -1,5 +1,6 @@ package io.openems.edge.app.timeofusetariff; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -167,7 +168,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java index 1415ce3636..b466c39ff1 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/GroupeE.java @@ -1,5 +1,6 @@ package io.openems.edge.app.timeofusetariff; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -150,7 +151,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java index c423c7bbcb..de9a446a21 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/RabotCharge.java @@ -1,6 +1,7 @@ package io.openems.edge.app.timeofusetariff; import static io.openems.edge.core.appmanager.formly.enums.InputType.PASSWORD; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -177,7 +178,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java index e013386d2d..8bf099ba33 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StadtwerkHassfurt.java @@ -1,6 +1,7 @@ package io.openems.edge.app.timeofusetariff; import static io.openems.edge.app.common.props.CommonProps.defaultDef; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -166,7 +167,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java index 603fb81f5b..fbbeb95133 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/StromdaoCorrently.java @@ -1,5 +1,6 @@ package io.openems.edge.app.timeofusetariff; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -163,7 +164,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java index 38b7b7b8b8..3eeeb094ba 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/Tibber.java @@ -1,6 +1,7 @@ package io.openems.edge.app.timeofusetariff; import static io.openems.edge.core.appmanager.formly.enums.InputType.PASSWORD; +import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import java.util.Map; @@ -196,7 +197,7 @@ public OpenemsAppCardinality getCardinality() { @Override protected ValidatorConfig.Builder getValidateBuilder() { return ValidatorConfig.create() // - .setCompatibleCheckableConfigs(checkHome()); + .setCompatibleCheckableConfigs(checkHome().or(checkCommercial92())); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java index 73749f40d6..4a999860bc 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManager.java @@ -13,12 +13,14 @@ public interface AppManager extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { WRONG_APP_CONFIGURATION(Doc.of(Level.WARNING) // - .text("App-Manager configuration is wrong")), // + .translationKey(AppManager.class, "AppManager.WrongAppConfiguration")), // DEFECTIVE_APP(Doc.of(Level.INFO) // // TODO should be a WARNING eventually - .text("Defective App detected")), // + .translationKey(AppManager.class, "AppManager.DefectiveApp")), // APPS_NOT_SYNCED_WITH_BACKEND(Doc.of(Level.INFO) // - .text("The currently installed apps are not the same as logged in the backend")), // + .translationKey(AppManager.class, "AppManager.AppsNotSynced")), // + HARDWARE_MISSMATCH(Doc.of(Level.INFO) // + .text("The current installed hardware app is not the same as defined in 'hardware.conf'")), // ; private final Doc doc; @@ -67,6 +69,16 @@ public default void _setAppsNotSyncedWithBackend(boolean value) { this.getAppsNotSyncedWithBackendChannel().setNextValue(value); } + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#HARDWARE_MISSMATCH} Channel. + * + * @param value the next value + */ + public default void _setHardwareMissmatch(boolean value) { + this.getHardwareMissmatchChannel().setNextValue(value); + } + /** * Gets the Defective-App Warning State. See {@link ChannelId#DEFECTIVE_APP}. * @@ -123,4 +135,23 @@ public default StateChannel getAppsNotSyncedWithBackendChannel() { return this.channel(ChannelId.APPS_NOT_SYNCED_WITH_BACKEND); } + /** + * Gets the Hardware-Missmatch info State. See + * {@link ChannelId#HARDWARE_MISSMATCH}. + * + * @return the Channel {@link Value} + */ + public default Value getHardwareMissmatch() { + return this.getAppsNotSyncedWithBackendChannel().value(); + } + + /** + * Gets the channel for {@link ChannelId#HARDWARE_MISSMATCH}. + * + * @return the Channel + */ + public default StateChannel getHardwareMissmatchChannel() { + return this.channel(ChannelId.HARDWARE_MISSMATCH); + } + } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtil.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtil.java index 22649215c2..e1e7d3f1fe 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtil.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtil.java @@ -51,6 +51,15 @@ public default List getInstantiatedAppsOf(String... appIds) .toList(); } + /** + * Gets the installed apps which match any of the provided + * {@link OpenemsAppCategory OpenemsAppCategories}. + * + * @param categories the {@link OpenemsAppCategory} to be contained by the app + * @return the found {@link OpenemsAppInstance OpenemsAppInstances} + */ + public List getInstantiatedAppsByCategories(OpenemsAppCategory... categories); + /** * Finds the {@link OpenemsApp} with the given id. * diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtilImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtilImpl.java index 188b47f064..3337a884e1 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtilImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerUtilImpl.java @@ -6,6 +6,7 @@ import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -46,6 +47,22 @@ public Optional findInstanceById(UUID id) { .flatMap(t -> t.findInstanceById(id)); } + @Override + public List getInstantiatedAppsByCategories(OpenemsAppCategory... categories) { + return this.getInstantiatedApps().stream() // + .filter(t -> { + final var app = this.findAppById(t.appId).orElse(null); + + if (app == null) { + return false; + } + + return Stream.of(app.getCategories()) // + .anyMatch(c1 -> Stream.of(categories) // + .anyMatch(c2 -> c1 == c2)); + }).toList(); + } + @Override public AppConfiguration getAppConfiguration(ConfigurationTarget target, OpenemsApp app, String alias, JsonObject properties, Language language) throws OpenemsNamedException { diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java index 3e287c25f9..9f11f6825c 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java @@ -44,6 +44,11 @@ public enum OpenemsAppCategory { */ HARDWARE("hardware"), + /** + * The hardware on which the OpenEMS software runs. + */ + OPENEMS_DEVICE_HARDWARE("openemsDeviceHardware"), + /** * Peak-Shaving. */ diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveOpenemsHardware.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveOpenemsHardware.java new file mode 100644 index 0000000000..be8d1cee00 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/ResolveOpenemsHardware.java @@ -0,0 +1,189 @@ +package io.openems.edge.core.appmanager; + +import static java.util.Collections.emptyMap; +import static java.util.stream.Collectors.toMap; + +import java.io.File; +import java.nio.file.Files; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.component.annotations.ServiceScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.utils.JsonUtils; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; + +@Component(immediate = true, scope = ServiceScope.SINGLETON) +public class ResolveOpenemsHardware implements Runnable { + + public static final String OPENEMS_HARDWARE_FILE_NAME = "hardware.conf"; + public static final String OPENEMS_HARDWARE_APP_KEY = "appId"; + + private final Logger log = LoggerFactory.getLogger(ResolveOpenemsHardware.class); + + private final ComponentContext context; + private final AppManagerImpl appManagerImpl; + private final AppManagerUtil appManagerUtil; + private final String requireApp; + private CompletableFuture task; + private final Executor delayedExecutor; + + /** + * Binds a {@link OpenemsApp}. + * + * @param app the {@link OpenemsApp} to bind + */ + @Reference(// + cardinality = ReferenceCardinality.MULTIPLE, // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY // + ) + public void bindApp(OpenemsApp app) { + this.trigger(); + } + + /** + * Unbinds a {@link OpenemsApp}. + * + * @param app the {@link OpenemsApp} to unbind + */ + public void unbindApp(OpenemsApp app) { + // empty + } + + public ResolveOpenemsHardware(// + ComponentContext context, // + AppManager appManagerImpl, // + AppManagerUtil appManagerUtil, // + Executor delayedExecutor // + ) { + super(); + this.context = context; + this.appManagerImpl = (AppManagerImpl) appManagerImpl; + this.appManagerUtil = appManagerUtil; + this.delayedExecutor = delayedExecutor; + + final var hardwareProperties = this.getHardwareProperties(); + this.requireApp = hardwareProperties.get(OPENEMS_HARDWARE_APP_KEY); + + this.trigger(); + } + + @Activate + public ResolveOpenemsHardware(// + ComponentContext context, // + @Reference AppManager appManagerImpl, // + @Reference AppManagerUtil appManagerUtil // + ) { + this(context, appManagerImpl, appManagerUtil, CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS)); + } + + @Deactivate + private void deactivate() { + final var task = this.task; + if (task != null) { + task.cancel(false); + } + } + + private synchronized void trigger() { + if (this.requireApp == null) { + this.task = CompletableFuture.runAsync(this.context.getComponentInstance()::dispose); + return; + } + + final var activeTask = this.task; + if (activeTask != null) { + activeTask.cancel(false); + } + + // waits 5 seconds until every app is activated + this.task = CompletableFuture.runAsync(() -> { + try { + this.run(); + } finally { + this.context.getComponentInstance().dispose(); + } + }, this.delayedExecutor); + } + + @Override + public void run() { + // currently its ignored if the app of an installed hardware app is not yet + // active or available after a 5 seconds delay from the last activated app and + // would therefore not be returned by the following method which could result in + // 2 hardware apps being installed + final var hardwareApps = this.appManagerUtil + .getInstantiatedAppsByCategories(OpenemsAppCategory.OPENEMS_DEVICE_HARDWARE); + + if (hardwareApps.size() >= 1) { + // validate + if (hardwareApps.size() > 1) { + // more than 1 installed => impossible + this.appManagerImpl._setHardwareMissmatch(true); + return; + } + + final var installedHardwareApp = hardwareApps.get(0); + if (installedHardwareApp.appId.equals(this.requireApp)) { + // installed hardware app matches the on in the properties file + this.appManagerImpl._setHardwareMissmatch(false); + return; + } + + this.appManagerImpl._setHardwareMissmatch(true); + return; + } + + this.log.trace("Try to install '" + this.requireApp + "'"); + try { + this.appManagerImpl.handleAddAppInstanceRequest(null, + new AddAppInstance.Request(this.requireApp, null, null, JsonUtils.buildJsonObject() // + .build()), + true); + + this.log.trace("Installed '" + this.requireApp + "' successfully"); + this.appManagerImpl._setHardwareMissmatch(false); + } catch (Exception e) { + this.log.error("Installation of '" + this.requireApp + "' failed", e); + this.appManagerImpl._setHardwareMissmatch(true); + } + + } + + private Map getHardwareProperties() { + final var configDir = System.getProperty("felix.cm.dir"); + if (configDir == null) { + return emptyMap(); + } + final var hardwareFile = new File(configDir, OPENEMS_HARDWARE_FILE_NAME); + + if (!hardwareFile.exists()) { + return emptyMap(); + } + + try { + return Files.lines(hardwareFile.toPath()) // + .map(t -> t.split("=", 2)) // + .filter(t -> t.length == 2) // + .collect(toMap(t -> t[0], t -> t[1])); + + } catch (Exception e) { + this.log.error("Unable to read hardware info file", e); + return emptyMap(); + } + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java index b6b13ef091..7ce7533c0f 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java @@ -30,6 +30,7 @@ import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.component.annotations.ServiceScope; +import org.osgi.service.condition.Condition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,6 +58,11 @@ import io.openems.edge.core.appmanager.TranslationUtil; import io.openems.edge.core.appmanager.dependency.DependencyDeclaration.AppDependencyConfig; import io.openems.edge.core.appmanager.dependency.aggregatetask.AggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.ComponentAggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.PersistencePredictorAggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerAggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderAggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.StaticIpAggregateTask; @Component(// immediate = true, // @@ -66,6 +72,23 @@ public class AppManagerAppHelperImpl implements AppManagerAppHelper { private final Logger log = LoggerFactory.getLogger(this.getClass()); + @Component(service = { StartTarget.class }) + public static class StartTarget implements Condition { + @Reference + private ComponentAggregateTask componentAggregateTask; + @Reference + private PersistencePredictorAggregateTask persistencePredictorAggregateTask; + @Reference + private SchedulerAggregateTask schedulerAggregateTask; + @Reference + private SchedulerByCentralOrderAggregateTask schedulerByCentralOrderAggregateTask; + @Reference + private StaticIpAggregateTask staticIpAggregateTask; + } + + @Reference + private StartTarget startCondition; + @Reference(// policy = ReferencePolicy.DYNAMIC, // policyOption = ReferencePolicyOption.GREEDY, // diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java index 639fad889a..c7b69815ce 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java @@ -62,6 +62,7 @@ public ProductionSchedulerOrderDefinition() { .thenByFactoryId("Controller.Ess.FixActivePower") // .thenByFactoryId("Controller.Ess.FixStateOfCharge")// .thenByFactoryId("Controller.Ess.EmergencyCapacityReserve") // + .thenByFactoryId("Controller.Ess.Limiter14a") // .thenBy(new SchedulerOrderDefinition() // .filterByFactoryId("Controller.Api.ModbusTcp.ReadWrite") // .thenByCreatedAppId("App.Ess.GeneratingPlantController") // diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index 78905f75ed..b0e860ca53 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -11,6 +11,7 @@ meter = Erzeugungs- und Verbrauchszรคhler peakShaving = Lastspitzenkappung und atypische Netznutzung api = Schnittstellen ess = Speichersystemsteuerung +openemsDeviceHardware = OpenEMS Gerรคte Hardware timedata = Timedata test = Test @@ -172,6 +173,30 @@ App.Hardware.KMtronic8Channel.Name = FEMS Relaisboard 8-Kanal TCP App.Hardware.KMtronic8Channel.Name.short = FEMS Relaisboard 8-Kanal TCP App.Hardware.KMtronic8Channel.ip.description = Die IP-Adresse des Relaisboards App.Hardware.KMtronic8Channel.installationHint = Hinweis: Stellen Sie vor der Installation sicher, dass das Relaisboard elektrisch als auch netzwerkseitig korrekt angeschlossen wurde. Andernfalls kรถnnen Fehlermeldungen im Online-Monitoring auftreten. +App.Hardware.IoGpio.Name = IO GPIO +App.Hardware.IoGpio.Name.short = IO GPIO + +# Openems device hardware +App.OpenemsHardware.BeagleBoneBlack.Name = BeagleBoneBlack +App.OpenemsHardware.BeagleBoneBlack.Name.short = BeagleBoneBlack + +App.OpenemsHardware.Compulab.Name = Compulab +App.OpenemsHardware.Compulab.Name.short = Compulab + +App.OpenemsHardware.CM3.Name = Techbase Compute Module 3 +App.OpenemsHardware.CM3.Name.short = Techbase CM3 + +App.OpenemsHardware.CM4.Name = Techbase Compute Module 4 +App.OpenemsHardware.CM4.Name.short = Techbase CM4 + +App.OpenemsHardware.CM4S.Name = Techbase Compute Module 4S +App.OpenemsHardware.CM4S.Name.short = Techbase CM4S + +App.OpenemsHardware.CM4S.Gen2.Name = Techbase Compute Module 4S Gen 2 +App.OpenemsHardware.CM4S.Gen2.Name.short = Techbase CM4S Gen 2 + +App.OpenemsHardware.CM4Max.Name = Techbase Compute Module 4 Max +App.OpenemsHardware.CM4Max.Name.short = Techbase CM4 Max # Heat App.Heat.CHP.Name = Blockheizkraftwerk (BHKW) @@ -219,12 +244,14 @@ App.IntegratedSystem.gridMeterType.option.commercialMeter = Home 3-Phasensensor App.IntegratedSystem.ctRatioFirst.label = Wandler-Primรคrstrom (200A - 5000A/5A) App.IntegratedSystem.shadowManagementDisabled.label = Schattenmanagement deaktivieren App.IntegratedSystem.shadowManagementDisabled.description = Nur wenn Optimierer verbaut sind, muss das Schattenmanagement deaktiviert werden +App.IntegratedSystem.hasEssLimiter14a.label = Hat Limitierer fรผr ยง14a App.IntegratedSystem.modbus0.alias = Kommunikation mit der Batterie App.IntegratedSystem.modbus0N.alias = Kommunikation mit den Batterien App.IntegratedSystem.modbus1.alias = Kommunikation mit dem Batterie-Wechselrichter App.IntegratedSystem.modbus1N.alias = Kommunikation mit dem Batterie-Wechselrichter {0} App.IntegratedSystem.modbus2.alias = externe RS485 Schnittstelle +App.IntegratedSystem.modbusToGridMeter.alias = Kommunikation mit dem Netzzรคhler App.IntegratedSystem.io0.alias = EMS Box Relais App.IntegratedSystem.battery0.alias = Batterie App.IntegratedSystem.batteryN.alias = Batterie {0} @@ -282,6 +309,19 @@ App.FENECON.Home.30.Name.short = FENECON Home 30 App.FENECON.Home.20.Name = FENECON Home 20 App.FENECON.Home.20.Name.short = FENECON Home 20 +App.FENECON.Commercial.92.Name = FENECON Commercial +App.FENECON.Commercial.92.Name.short = FENECON Commercial +App.FENECON.Industrial.L.io0 = Relais +App.FENECON.Industrial.L.Name = FENECON Industrial L +App.FENECON.Industrial.L.Name.short = FENECON Industrial L +App.FENECON.Industrial.L.modbus0.alias = Kommunikation mit dem Klimagerรคt +App.FENECON.Industrial.L.essN.alias = Batteriespeicher {0} + +App.FENECON.Industrial.L.ILK710.Name = FENECON Industrial L ILK710 +App.FENECON.Industrial.L.ILK710.Name.short = ILK710 +App.FENECON.Industrial.L.ILK710.batteryProtectionType.label = Battery Protection Typ +App.FENECON.Industrial.L.ILK710.batteryFirmwareVersion.label = Battery Firmware Version + App.FENECON.Industrial.S.io0 = Relais App.FENECON.Industrial.S.ess0.alias = Batteriespeicher App.FENECON.Industrial.S.essN.alias = Batteriespeicher {0} @@ -298,6 +338,7 @@ App.FENECON.Industrial.S.ISK011.Name = FENECON Industrial S ISK011 App.FENECON.Industrial.S.ISK011.Name.short = ISK011 # Meter +App.Meter.alias = Kommunikation mit dem Zรคhler App.Meter.mountType.label = Verwendungsart App.Meter.modbusUnitId.description = Modbus Unit-ID des Zรคhlers App.Meter.ip.description = IP-Adresse des Zรคhlers @@ -311,6 +352,11 @@ App.Meter.CarloGavazzi.Name.short = CARLO GAVAZZI App.Meter.Janitza.Name = Janitza Zรคhler App.Meter.Janitza.Name.short = Janitza App.Meter.Janitza.productModel = Gerรคtemodell +App.Meter.PqPlus.UMD96 = PQ-Plus Zรคhler UMD96 +App.Meter.PqPlus.UMD97 = PQ-Plus Zรคhler UMD97 +App.Meter.PqPlus.Name = PQ-Plus Zรคhler +App.Meter.PqPlus.Name.short = PQ-Plus +App.Meter.PqPlus.productModel = Gerรคtemodell App.Meter.Socomec.Name = SOCOMEC Zรคhler App.Meter.Socomec.Name.short = SOCOMEC App.Meter.Kdk.Name = KDK Zรคhler @@ -330,7 +376,8 @@ App.Meter.Discovergy.fullSerialNumber.label = Discovergy Komplette Seriennummer App.Meter.Discovergy.meterId.label = Discovergy MeterId App.Meter.Discovergy.meterId.description = Interne Zรคhler Id. Dieser is ein Hex String mit Lรคnge 32. App.Meter.Discovergy.serialType.label = Typ der Seriennummer - +App.Meter.PhoenixContact.Name = PhoenixContact Zรคhler +App.Meter.PhoenixContact.Name.short = PhoenixContact # PeakShaving App.PeakShaving.power.label = Maximale Netzbezugsleistung @@ -443,6 +490,13 @@ App.Ess.FixStateOfCharge.targetSoc.label = Ziel-SoC App.Ess.FixStateOfCharge.targetTime.label = Zielzeit App.Ess.FixStateOfCharge.targetTimeBuffer.label = Zielzeitpuffer App.Ess.FixStateOfCharge.selfTermination.label = Beendet sich selbst am Ende -App.Ess.FixStateOfCharge.terminationBuffer.label = Zeitpuffer zum Beenden +App.Ess.FixStateOfCharge.terminationBuffer.label = Zeitpuffer zum Beenden App.Ess.FixStateOfCharge.conditionalTermination.label = Beendet sich selbst nach separater Bedingung -App.Ess.FixStateOfCharge.isRunning.label = Kontroller aktiv? \ No newline at end of file +App.Ess.FixStateOfCharge.isRunning.label = Kontroller aktiv? + +App.Ess.Limiter14a.Name = ESS Limiter fรผr ยง14a +App.Ess.Limiter14a.Name.short = ESS Limiter ยง14a + +AppManager.DefectiveApp = Defekte App erkannt +AppManager.WrongAppConfiguration = App-Manager Konfiguration ist falsch +AppManager.AppsNotSynced = Die aktuell installierten Apps sind nicht dieselben wie im Backend hinterlegt diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 03cade10cf..460116c4f5 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -11,6 +11,7 @@ meter = Production and consumption meter peakShaving = Peak shaving and atypical grid usage api = Interfaces ess = Energy Storage controller +openemsDeviceHardware = OpenEMS Device Hardware timedata = Timedata test = Test @@ -172,6 +173,30 @@ App.Hardware.KMtronic8Channel.Name = FEMS Relay board 8-channel TCP App.Hardware.KMtronic8Channel.Name.short = FEMS Relay board 8-channel TCP App.Hardware.KMtronic8Channel.ip.description = The IP address of the relay board App.Hardware.KMtronic8Channel.installationHint = Note: Before installing the relay board please make sure that it is connected correctly both electrically and to the network. Otherwise error messages in the Online-Monitoring may occur. +App.Hardware.IoGpio.Name = IO GPIO +App.Hardware.IoGpio.Name.short = IO GPIO + +# Openems device hardware +App.OpenemsHardware.BeagleBoneBlack.Name = BeagleBoneBlack +App.OpenemsHardware.BeagleBoneBlack.Name.short = BeagleBoneBlack + +App.OpenemsHardware.Compulab.Name = Compulab +App.OpenemsHardware.Compulab.Name.short = Compulab + +App.OpenemsHardware.CM3.Name = Techbase Compute Module 3 +App.OpenemsHardware.CM3.Name.short = Techbase CM3 + +App.OpenemsHardware.CM4.Name = Techbase Compute Module 4 +App.OpenemsHardware.CM4.Name.short = Techbase CM4 + +App.OpenemsHardware.CM4S.Name = Techbase Compute Module 4S +App.OpenemsHardware.CM4S.Name.short = Techbase CM4S + +App.OpenemsHardware.CM4S.Gen2.Name = Techbase Compute Module 4S Gen 2 +App.OpenemsHardware.CM4S.Gen2.Name.short = Techbase CM4S Gen 2 + +App.OpenemsHardware.CM4Max.Name = Techbase Compute Module 4 Max +App.OpenemsHardware.CM4Max.Name.short = Techbase CM4 Max # Heat App.Heat.CHP.Name = Combined heat and power plant (CHP) @@ -219,12 +244,14 @@ App.IntegratedSystem.gridMeterType.option.commercialMeter = Home 3-phase sensor App.IntegratedSystem.ctRatioFirst.label = CT-Ratio (200A - 5000A/5A) App.IntegratedSystem.shadowManagementDisabled.label = Deactivate shadow management App.IntegratedSystem.shadowManagementDisabled.description = Only if optimisers are installed, shadow management must be deactivated +App.IntegratedSystem.hasEssLimiter14a.label = Has limiter for ยง14a App.IntegratedSystem.modbus0.alias = Communication with the battery App.IntegratedSystem.modbus0N.alias = Communication with the batteries App.IntegratedSystem.modbus1.alias = Communication with the battery inverter App.IntegratedSystem.modbus1N.alias = Communication with the battery inverter {0} App.IntegratedSystem.modbus2.alias = external RS485 interface +App.IntegratedSystem.modbusToGridMeter.alias = Communication with the Grid-Meter App.IntegratedSystem.io0.alias = EMS Box Relay App.IntegratedSystem.battery0.alias = battery App.IntegratedSystem.batteryN.alias = battery {0} @@ -282,6 +309,19 @@ App.FENECON.Home.30.Name.short = FENECON Home 30 App.FENECON.Home.20.Name = FENECON Home 20 App.FENECON.Home.20.Name.short = FENECON Home 20 +App.FENECON.Commercial.92.Name = FENECON Commercial +App.FENECON.Commercial.92.Name.short = FENECON Commercial +App.FENECON.Industrial.L.io0 = Relay +App.FENECON.Industrial.L.Name = FENECON Industrial L +App.FENECON.Industrial.L.Name.short = FENECON Industrial L +App.FENECON.Industrial.L.modbus0.alias = Communication with Cooling Unit +App.FENECON.Industrial.L.essN.alias = Battery Storage {0} + +App.FENECON.Industrial.L.ILK710.Name = FENECON Industrial L ILK710 +App.FENECON.Industrial.L.ILK710.Name.short = ILK710 +App.FENECON.Industrial.L.ILK710.batteryProtectionType.label = Battery Protection Typ +App.FENECON.Industrial.L.ILK710.batteryFirmwareVersion.label = Battery Firmware Version + App.FENECON.Industrial.S.io0 = Relay App.FENECON.Industrial.S.ess0.alias = Battery Storage App.FENECON.Industrial.S.essN.alias = Battery Storage {0} @@ -298,6 +338,7 @@ App.FENECON.Industrial.S.ISK011.Name = FENECON Industrial S ISK011 App.FENECON.Industrial.S.ISK011.Name.short = ISK011 # Meter +App.Meter.alias = Communication with the Meter App.Meter.mountType.label = Mount Type App.Meter.modbusUnitId.description = Modbus Unit-ID of the Meter App.Meter.ip.description = IP address of the Meter @@ -311,6 +352,11 @@ App.Meter.CarloGavazzi.Name.short = CARLO GAVAZZI App.Meter.Janitza.Name = Janitza meter App.Meter.Janitza.Name.short = Janitza App.Meter.Janitza.productModel = Device model +App.Meter.PqPlus.UMD96 = PQ-Plus meter UMD96 +App.Meter.PqPlus.UMD97 = PQ-Plus meter UMD97 +App.Meter.PqPlus.Name = PQ-Plus meter +App.Meter.PqPlus.Name.short = PQ-Plus +App.Meter.PqPlus.productModel = Device model App.Meter.Socomec.Name = SOCOMEC meter App.Meter.Socomec.Name.short = SOCOMEC App.Meter.Kdk.Name = KDK meter @@ -330,6 +376,8 @@ App.Meter.Discovergy.fullSerialNumber.label = Discovergy Full Serial-Number App.Meter.Discovergy.meterId.label = Discovergy MeterId App.Meter.Discovergy.meterId.description = Internal MeterId. This is a hex string with length 32. App.Meter.Discovergy.serialType.label = Type of the serial number +App.Meter.PhoenixContact.Name = PhoenixContact Meter +App.Meter.PhoenixContact.Name.short = PhoenixContact # PeakShaving App.PeakShaving.power.label = Peak-Shaving power @@ -351,6 +399,7 @@ App.PeakShaving.PhaseAccuratePeakShaving.Name.short = Phase accurate peak shavin # PV inverter App.PvInverter.ip.description = IP address of the PV inverter. App.PvInverter.port.description = Port of the PV inverter. +App.PvInverter.modbusUnitId.description = Modbus Unit-ID of the PV inverter. App.PvInverter.phase.label = Phase App.PvInverter.phase.description = Connected phase(s) of the inverter @@ -366,7 +415,7 @@ App.PvInverter.Sma.modbusUnitId.description = The Unit-ID of the Modbus device. App.PvInverter.SolarEdge.Name = SolarEdge PV inverter App.PvInverter.SolarEdge.Name.short = SolarEdge -# Time of use Tarif +# Time of use Tariff App.TimeOfUseTariff.Awattar.Name = Time-of-Use Tariff (Awattar HOURLY) App.TimeOfUseTariff.Awattar.Name.short = Awattar HOURLY App.TimeOfUseTariff.Awattar.zone.label = Zone @@ -441,6 +490,13 @@ App.Ess.FixStateOfCharge.targetSoc.label = Target SoC App.Ess.FixStateOfCharge.targetTime.label = Target time [YYYY-MM-DDTHH:mm:ssTZD eg. 2023-12-15T13:47:20+01:00] App.Ess.FixStateOfCharge.targetTimeBuffer.label = Target time buffer App.Ess.FixStateOfCharge.selfTermination.label = Terminates itself at the end -App.Ess.FixStateOfCharge.terminationBuffer.label = Terminate time buffer in min +App.Ess.FixStateOfCharge.terminationBuffer.label = Terminate time buffer in min App.Ess.FixStateOfCharge.conditionalTermination.label = Terminates itself after separate condition App.Ess.FixStateOfCharge.isRunning.label = Controller active? + +App.Ess.Limiter14a.Name = ESS limiter for ยง14a +App.Ess.Limiter14a.Name.short = ESS limiter ยง14a + +AppManager.DefectiveApp = Defective App detected +AppManager.WrongAppConfiguration = App-Manager configuration is wrong +AppManager.AppsNotSynced = The currently installed apps are not the same as logged in the backend diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckCommercial92.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckCommercial92.java new file mode 100644 index 0000000000..2db34ca6fc --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckCommercial92.java @@ -0,0 +1,51 @@ +package io.openems.edge.core.appmanager.validator; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ServiceScope; + +import io.openems.common.OpenemsConstants; +import io.openems.common.session.Language; + +@Component(// + name = CheckCommercial92.COMPONENT_NAME, // + scope = ServiceScope.PROTOTYPE // +) +public class CheckCommercial92 extends AbstractCheckable implements Checkable { + + public static final String COMPONENT_NAME = "Validator.Checkable.CheckCommercial92"; + + private final Checkable checkAppsNotInstalled; + + @Activate + public CheckCommercial92(// + ComponentContext componentContext, // + @Reference(target = "(" + OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME + "=" + + CheckAppsNotInstalled.COMPONENT_NAME + ")") Checkable checkAppsNotInstalled // + ) { + super(componentContext); + this.checkAppsNotInstalled = checkAppsNotInstalled; + } + + @Override + public boolean check() { + this.checkAppsNotInstalled.setProperties(Checkables.checkAppsNotInstalled(// + "App.FENECON.Commercial.92" // + ).properties()); + + return !this.checkAppsNotInstalled.check(); + } + + @Override + public String getErrorMessage(Language language) { + return AbstractCheckable.getTranslation(language, "Validator.Checkable.CheckCommercial92.Message"); + } + + @Override + public String getInvertedErrorMessage(Language language) { + return AbstractCheckable.getTranslation(language, "Validator.Checkable.CheckCommercial92.Message.Inverted"); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckHome.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckHome.java index 8d58d508b0..45dcf2223e 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckHome.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckHome.java @@ -8,7 +8,6 @@ import io.openems.common.OpenemsConstants; import io.openems.common.session.Language; -import io.openems.edge.common.component.ComponentManager; @Component(// name = CheckHome.COMPONENT_NAME, // @@ -18,37 +17,27 @@ public class CheckHome extends AbstractCheckable implements Checkable { public static final String COMPONENT_NAME = "Validator.Checkable.CheckHome"; - private final ComponentManager componentManager; private final Checkable checkAppsNotInstalled; @Activate public CheckHome(// - @Reference ComponentManager componentManager, // ComponentContext componentContext, // @Reference(target = "(" + OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME + "=" + CheckAppsNotInstalled.COMPONENT_NAME + ")") Checkable checkAppsNotInstalled // ) { super(componentContext); - this.componentManager = componentManager; this.checkAppsNotInstalled = checkAppsNotInstalled; } @Override public boolean check() { - var batteries = this.componentManager.getEdgeConfig().getComponentsByFactory("Battery.Fenecon.Home"); this.checkAppsNotInstalled.setProperties(Checkables.checkAppsNotInstalled(// "App.FENECON.Home", // "App.FENECON.Home.20", // "App.FENECON.Home.30" // ).properties()); - // TODO remove check for batteries - // not every home has the home app installed but if a batterie of an home is - // installed its probably a home and so the app can be used. - // later there should only be checked if the home app is installed because if - // the configuration is wrong there may be no home battery installed and so the - // app wouldn't be available even though it is a home - return !batteries.isEmpty() || !this.checkAppsNotInstalled.check(); + return !this.checkAppsNotInstalled.check(); } @Override diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckOr.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckOr.java new file mode 100644 index 0000000000..eb27767802 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckOr.java @@ -0,0 +1,102 @@ +package io.openems.edge.core.appmanager.validator; + +import java.util.Map; +import java.util.Objects; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ServiceScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.session.Language; +import io.openems.edge.core.appmanager.validator.CheckableFactory.ClosableCheckable; +import io.openems.edge.core.appmanager.validator.ValidatorConfig.CheckableConfig; + +@Component(// + name = CheckOr.COMPONENT_NAME, // + scope = ServiceScope.PROTOTYPE // +) +public class CheckOr extends AbstractCheckable implements Checkable { + + public static final String COMPONENT_NAME = "Validator.Checkable.CheckOr"; + + private final Logger log = LoggerFactory.getLogger(CheckOr.class); + + private final CheckableFactory checkableFactory; + + private CheckableConfig check1Config; + private ClosableCheckable check1; + private CheckableConfig check2Config; + private ClosableCheckable check2; + + @Activate + public CheckOr(// + ComponentContext componentContext, // + @Reference CheckableFactory checkableFactory // + ) { + super(componentContext); + this.checkableFactory = checkableFactory; + } + + @Deactivate + private void deactivate() { + try { + this.check1.close(); + } catch (Exception e) { + this.log.error("Unable to close checkable " + this.check1Config.checkableComponentName(), e); + } + try { + this.check2.close(); + } catch (Exception e) { + this.log.error("Unable to close checkable " + this.check2Config.checkableComponentName(), e); + } + } + + @Override + public void setProperties(Map properties) { + this.check1Config = Objects.requireNonNull((CheckableConfig) properties.get("check1"), + "First check must not be null"); + this.check2Config = Objects.requireNonNull((CheckableConfig) properties.get("check2"), + "Second check must not be null"); + } + + @Override + public boolean check() { + this.check1 = this.checkableFactory.useCheckable(this.check1Config.checkableComponentName()); + this.check1.setProperties(this.check1Config.properties()); + this.check2 = this.checkableFactory.useCheckable(this.check2Config.checkableComponentName()); + this.check2.setProperties(this.check2Config.properties()); + + final var check1Failed = this.check1.check() == this.check1Config.invertResult(); + final var check2Failed = this.check2.check() == this.check2Config.invertResult(); + return !(check1Failed && check2Failed); + } + + @Override + public String getErrorMessage(Language language) { + return AbstractCheckable.getTranslation(language, "Validator.Checkable.CheckOr.Message", + this.getCheck1ErrorMessage(language), this.getCheck2ErrorMessage(language)); + } + + @Override + public String getInvertedErrorMessage(Language language) { + throw new UnsupportedOperationException(); + } + + private String getCheck1ErrorMessage(Language language) { + return this.check1Config.invertResult() // + ? this.check1.getInvertedErrorMessage(language) + : this.check1.getErrorMessage(language); + } + + private String getCheck2ErrorMessage(Language language) { + return this.check2Config.invertResult() // + ? this.check2.getInvertedErrorMessage(language) + : this.check2.getErrorMessage(language); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckableFactory.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckableFactory.java new file mode 100644 index 0000000000..d96603c3d3 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/CheckableFactory.java @@ -0,0 +1,130 @@ +package io.openems.edge.core.appmanager.validator; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +import org.osgi.service.component.ComponentServiceObjects; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.component.annotations.ReferenceScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.OpenemsConstants; +import io.openems.common.session.Language; + +@Component(// + service = CheckableFactory.class // +) +public class CheckableFactory { + + private final Logger log = LoggerFactory.getLogger(CheckableFactory.class); + + private final Map> checkableFactories = new HashMap<>(); + + /** + * Binds a {@link Checkable} {@link ComponentServiceObjects}. + * + * @param cso the cso to bind + */ + @Reference(// + cardinality = ReferenceCardinality.MULTIPLE, // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY, // + // requires prototype for thread safety + scope = ReferenceScope.PROTOTYPE_REQUIRED // + ) + public void bindCso(ComponentServiceObjects cso) { + var sr = cso.getServiceReference(); + var srName = (String) sr.getProperty(OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME); + this.checkableFactories.put(srName, cso); + } + + /** + * Unbinds a {@link Checkable} {@link ComponentServiceObjects}. + * + * @param cso the cso to unbind + */ + public void unbindCso(ComponentServiceObjects cso) { + var sr = cso.getServiceReference(); + var srName = (String) sr.getProperty(OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME); + this.checkableFactories.remove(srName); + } + + @Activate + public CheckableFactory() { + } + + /** + * Gets a {@link Checkable} which component name matches the provided name. + * + * @param checkableComponentName the component name to search for + * @return a found {@link Checkable} service or null if not found + */ + public ClosableCheckable useCheckable(String checkableComponentName) { + final var cso = this.checkableFactories.get(checkableComponentName); + if (cso == null) { + this.log.warn("Unable to find checkable with name '" + checkableComponentName + "'."); + return null; + } + + final var service = cso.getService(); + if (service == null) { + this.log.warn("Unable to create checkable with name '" + checkableComponentName + "'."); + return null; + } + + return new ClosableCheckable(service, t -> { + cso.ungetService(service); + }); + } + + public static class ClosableCheckable implements Checkable, AutoCloseable { + + private final Checkable checkable; + private final Consumer onClose; + + private ClosableCheckable(Checkable checkable, Consumer onClose) { + super(); + this.checkable = checkable; + this.onClose = onClose; + } + + @Override + public String getComponentName() { + return this.checkable.getComponentName(); + } + + @Override + public void setProperties(Map properties) { + this.checkable.setProperties(properties); + } + + @Override + public boolean check() { + return this.checkable.check(); + } + + @Override + public String getErrorMessage(Language language) { + return this.checkable.getErrorMessage(language); + } + + @Override + public String getInvertedErrorMessage(Language language) { + return this.checkable.getInvertedErrorMessage(language); + } + + @Override + public void close() throws Exception { + this.onClose.accept(this.checkable); + } + + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java index 65b03fa36c..32783117be 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/Checkables.java @@ -19,6 +19,32 @@ public static CheckableConfig checkHome() { return empty(CheckHome.COMPONENT_NAME); } + /** + * Creates a {@link CheckableConfig} which checks if the installed system is a + * Home. + * + * @return the {@link CheckableConfig} + */ + public static CheckableConfig checkCommercial92() { + return empty(CheckCommercial92.COMPONENT_NAME); + } + + /** + * Creates a {@link CheckableConfig} which checks if atleast one of the checks + * are successful. + * + * @param check1 the first check + * @param check2 the second check + * @return the {@link CheckableConfig} + */ + public static CheckableConfig checkOr(CheckableConfig check1, CheckableConfig check2) { + return new ValidatorConfig.CheckableConfig(CheckOr.COMPONENT_NAME, + new ValidatorConfig.MapBuilder<>(new TreeMap()) // + .put("check1", check1) // + .put("check2", check2) // + .build()); + } + /** * Creates a {@link CheckableConfig} which checks if the relay with the given * name has at least the given amount of ports available. diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorConfig.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorConfig.java index 8c7c05745a..9598943b06 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorConfig.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorConfig.java @@ -74,6 +74,17 @@ public CheckableConfig invert() { ); } + /** + * Creates a {@link CheckableConfig} which checks if the current check is + * successful or the other check. + * + * @param other the other check + * @return the {@link CheckableConfig} + */ + public CheckableConfig or(CheckableConfig other) { + return Checkables.checkOr(this, other); + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorImpl.java index d8868d85b7..77b03ae425 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/ValidatorImpl.java @@ -5,70 +5,44 @@ import java.util.ArrayList; import java.util.List; -import org.osgi.service.component.ComponentServiceObjects; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.component.annotations.ReferencePolicyOption; -import org.osgi.service.component.annotations.ReferenceScope; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.common.OpenemsConstants; import io.openems.common.session.Language; import io.openems.edge.core.appmanager.validator.ValidatorConfig.CheckableConfig; @Component public class ValidatorImpl implements Validator { - private static final Logger LOG = LoggerFactory.getLogger(ValidatorImpl.class); + private final Logger log = LoggerFactory.getLogger(ValidatorImpl.class); - @Reference(// - cardinality = ReferenceCardinality.MULTIPLE, // - policy = ReferencePolicy.DYNAMIC, // - policyOption = ReferencePolicyOption.GREEDY, // - // requires prototype for thread safety - scope = ReferenceScope.PROTOTYPE_REQUIRED // - ) - private volatile List> checkableFactories; + private final CheckableFactory checkableFactory; @Activate - public ValidatorImpl() { + public ValidatorImpl(@Reference CheckableFactory checkableFactory) { + this.checkableFactory = checkableFactory; } @Override - public List getErrorMessages(List checkableConfigs, Language language, - boolean returnImmediate) { + public List getErrorMessages(// + final List checkableConfigs, // + final Language language, // + final boolean returnImmediate // + ) { if (checkableConfigs.isEmpty()) { return emptyList(); } final var errorMessages = new ArrayList(checkableConfigs.size()); for (var config : checkableConfigs) { - // find the componentServiceObjects base on the given configuration name - final var cso = this.checkableFactories.stream()// - .filter(csoCheckable -> { - var sr = csoCheckable.getServiceReference(); - var srName = (String) sr.getProperty(OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME); - return srName.equals(config.checkableComponentName()); - }).findAny().orElse(null); - - if (cso == null) { - LOG.info("Unable to get Checkable '" + config.checkableComponentName() + "'!"); - continue; - } - - // get the service from the cso - final var checkable = cso.getService(); - - if (checkable == null) { - LOG.info("Unable to get Checkable '" + config.checkableComponentName() + "'!"); - continue; - } + try (final var checkable = this.checkableFactory.useCheckable(config.checkableComponentName())) { + if (checkable == null) { + continue; + } - try { // validate checkable checkable.setProperties(config.properties()); var result = checkable.check(); @@ -78,8 +52,10 @@ public List getErrorMessages(List checkableConfigs, Lan errorMessage = config.invertResult() ? checkable.getInvertedErrorMessage(language) : checkable.getErrorMessage(language); } catch (UnsupportedOperationException e) { - LOG.error("Missing implementation for getting " + (config.invertResult() ? "inverted " : "") - + "error message for check \"" + config.checkableComponentName() + "\"!", e); + this.log.error( + "Missing implementation for getting " + (config.invertResult() ? "inverted " : "") + + "error message for check \"" + config.checkableComponentName() + "\"!", + e); errorMessage = "Check \"" + config.checkableComponentName() + "\" failed."; } errorMessages.add(errorMessage); @@ -87,9 +63,8 @@ public List getErrorMessages(List checkableConfigs, Lan return errorMessages; } } - } finally { - // free checkable from cso - cso.ungetService(checkable); + } catch (Exception e) { + this.log.error("Error while using checkable " + config.checkableComponentName() + "!", e); } } return errorMessages; diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_de.properties index b43cee111a..d5edecc681 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_de.properties @@ -6,6 +6,9 @@ Validator.Checkable.CheckCardinality.Message.Single = Es ist bereits eine App "{ Validator.Checkable.CheckHome.Message = Diese App benรถtigt ein Home System. Validator.Checkable.CheckHome.Message.Inverted = Diese App ist nicht fรผr Home Systeme verfรผgbar. +Validator.Checkable.CheckCommercial92.Message = Diese App benรถtigt ein Commercial System. +Validator.Checkable.CheckCommercial92.Message.Inverted = Diese App ist nicht fรผr Commercial System verfรผgbar. + Validator.Checkable.CheckHost.NotReachable = Gerรคt mit der IP "{0}" ist nicht erreichbar! Validator.Checkable.CheckHost.WrongIp = IP "{0}" ist keine valide IP-Adresse! @@ -13,3 +16,5 @@ Validator.Checkable.CheckNoComponentInstalledOfFactorieId.Message = Komponenten Validator.Checkable.CheckRelayCount.Message = Es sind nicht genug freie Digital-/Relaisausgรคnge verfรผgbar.

    Benรถtigt: {0}
    Verfรผgbar: {1} Validator.Checkable.CheckRelayCount.Message.AdditionalRelay =

    {1} fรผr weitere Ausgรคnge erwerben. + +Validator.Checkable.CheckOr.Message = {0} - oder - {1} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_en.properties index aa0657e25c..204566bcbd 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/validator/translation_en.properties @@ -6,6 +6,9 @@ Validator.Checkable.CheckCardinality.Message.Single = There is already an app "{ Validator.Checkable.CheckHome.Message = This App requires a Home System. Validator.Checkable.CheckHome.Message.Inverted = This App is not available for Home systems. +Validator.Checkable.CheckCommercial92.Message = This App requires a Commercial System. +Validator.Checkable.CheckCommercial92.Message.Inverted = This App is not available for Commercial System. + Validator.Checkable.CheckHost.NotReachable = Device with IP "{0}" is not reachable! Validator.Checkable.CheckHost.WrongIp = IP "{0}" is not a valid IP-Address! @@ -13,3 +16,5 @@ Validator.Checkable.CheckNoComponentInstalledOfFactorieId.Message = Components w Validator.Checkable.CheckRelayCount.Message = There are not enough Digital-/Relay ports available.

    Required: {0}
    Available: {1} Validator.Checkable.CheckRelayCount.Message.AdditionalRelay =

    Buy {1} for more outputs. + +Validator.Checkable.CheckOr.Message = {0} - or - {1} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java index 2dd6105f73..3029e0d6a0 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java @@ -49,6 +49,7 @@ import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest.Property; import io.openems.common.jsonrpc.response.GetEdgeConfigResponse; +import io.openems.common.session.Language; import io.openems.common.session.Role; import io.openems.common.types.ChannelAddress; import io.openems.common.types.EdgeConfig; @@ -368,12 +369,12 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { Handles a GetStateChannelsOfComponent. """); }, call -> { - // TODO could be used for translating channel texts - // final var user = call.get(EdgeKeys.USER_KEY); + final var user = call.get(EdgeKeys.USER_KEY); + final var lang = user.getLanguage(); final var channels = this.getPossiblyDisabledComponent(call.getRequest().componentId()).channels().stream() // .filter(t -> t.channelDoc().getChannelCategory() == ChannelCategory.STATE) // - .map(ComponentManagerImpl::toChannelRecord) // + .map(channel -> ComponentManagerImpl.toChannelRecord(channel, lang)) // .toList(); return new GetStateChannelsOfComponent.Response(channels); @@ -384,10 +385,12 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { Handles a GetStateChannelsOfComponent. """); }, call -> { + + final var user = call.get(EdgeKeys.USER_KEY); + final var lang = user.getLanguage(); final var channels = this.getPossiblyDisabledComponent(call.getRequest().componentId()).channels().stream() // - .map(ComponentManagerImpl::toChannelRecord) // + .map(channel -> ComponentManagerImpl.toChannelRecord(channel, lang)) // .toList(); - return new GetChannelsOfComponent.Response(channels); }); @@ -399,7 +402,9 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { final var request = call.getRequest(); final var channel = this.getChannel(new ChannelAddress(request.componentId(), request.channelId())); - return new GetChannel.Response(toChannelRecord(channel)); + final var user = call.get(EdgeKeys.USER_KEY); + final var lang = user.getLanguage(); + return new GetChannel.Response(toChannelRecord(channel, lang)); }); builder.handleRequest(new GetDigitalInputChannelsOfComponents(), endpoint -> { @@ -408,10 +413,12 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { """); }, call -> { + final var user = call.get(EdgeKeys.USER_KEY); + final var lang = user.getLanguage(); final var result = this.getEnabledComponentsOfType(DigitalInput.class).stream() // .filter(t -> call.getRequest().componentIds().contains(t.id())) // .collect(toMap(OpenemsComponent::id, t -> Arrays.stream(t.digitalInputChannels()) // - .map(ComponentManagerImpl::toChannelRecord) // + .map(channel -> ComponentManagerImpl.toChannelRecord(channel, lang)) // .toList())); return new GetDigitalInputChannelsOfComponents.Response(result); @@ -450,12 +457,12 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { }); } - private static ChannelRecord toChannelRecord(Channel channel) { + private static ChannelRecord toChannelRecord(Channel channel, Language language) { return new GetChannelsOfComponent.ChannelRecord(// channel.channelId().id(), // channel.channelDoc().getAccessMode(), // channel.channelDoc().getPersistencePriority(), // - channel.channelDoc().getText(), // + channel.channelDoc().getText(language), // channel.channelDoc().getType(), // channel.channelDoc().getUnit(), // channel.channelDoc().getChannelCategory(), // diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java index f95d671afd..91ea3e5a53 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java +++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome.java @@ -2,9 +2,12 @@ import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import com.google.gson.JsonObject; @@ -31,7 +34,8 @@ public void beforeEach() throws Exception { Apps::gridOptimizedCharge, // Apps::selfConsumptionOptimization, // Apps::socomecMeter, // - Apps::prepareBatteryExtension // + Apps::prepareBatteryExtension, // + Apps::limiter14a // ); }, null, new PseudoComponentManagerFactory()); @@ -46,52 +50,25 @@ public void testCreateHomeFullSettings() throws Exception { @Test public void testCreateAndUpdateHomeFullSettings() throws Exception { - var fullConfig = JsonUtils.buildJsonObject() // - .addProperty("SAFETY_COUNTRY", "GERMANY") // - .addProperty("RIPPLE_CONTROL_RECEIVER_ACTIV", false) // - .addProperty("MAX_FEED_IN_POWER", 1000) // - .addProperty("FEED_IN_SETTING", "LAGGING_0_95") // - .addProperty("HAS_AC_METER", true) // - .addProperty("HAS_DC_PV1", true) // - .addProperty("DC_PV1_ALIAS", "alias pv 1") // - .addProperty("HAS_DC_PV2", true) // - .addProperty("DC_PV2_ALIAS", "alias pv 2") // - .addProperty("HAS_EMERGENCY_RESERVE", true) // - .addProperty("EMERGENCY_RESERVE_ENABLED", true) // - .addProperty("EMERGENCY_RESERVE_SOC", 15) // - .addProperty("SHADOW_MANAGEMENT_DISABLED", false) // - .build(); var homeInstance = this.createFullHome(); this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, - new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", fullConfig)); + new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", fullSettings())); // expect the same as before // make sure every dependency got installed - assertEquals(this.appManagerTestBundle.sut.getInstantiatedApps().size(), 5); + assertEquals(5, this.appManagerTestBundle.sut.getInstantiatedApps().size()); // check properties of created apps for (var instance : this.appManagerTestBundle.sut.getInstantiatedApps()) { - int expectedDependencies; - switch (instance.appId) { - case "App.FENECON.Home": - expectedDependencies = 4; - break; - case "App.PvSelfConsumption.GridOptimizedCharge": - expectedDependencies = 0; - break; - case "App.PvSelfConsumption.SelfConsumptionOptimization": - expectedDependencies = 0; - break; - case "App.Meter.Socomec": - expectedDependencies = 0; - break; - case "App.Ess.PrepareBatteryExtension": - expectedDependencies = 0; - break; - default: - throw new Exception("App with ID[" + instance.appId + "] should not have been created!"); - } + final var expectedDependencies = switch (instance.appId) { + case "App.FENECON.Home" -> 4; + case "App.PvSelfConsumption.GridOptimizedCharge" -> 0; + case "App.PvSelfConsumption.SelfConsumptionOptimization" -> 0; + case "App.Meter.Socomec" -> 0; + case "App.Ess.PrepareBatteryExtension" -> 0; + default -> throw new Exception("App with ID[" + instance.appId + "] should not have been created!"); + }; if (expectedDependencies == 0 && instance.dependencies == null) { continue; } @@ -108,6 +85,7 @@ public void testRemoveAcMeter() throws Exception { .addProperty("RIPPLE_CONTROL_RECEIVER_ACTIV", false) // .addProperty("MAX_FEED_IN_POWER", 1000) // .addProperty("FEED_IN_SETTING", "LAGGING_0_95") // + .addProperty("HAS_ESS_LIMITER_14A", false) // .addProperty("HAS_AC_METER", false) // .addProperty("HAS_DC_PV1", true) // .addProperty("DC_PV1_ALIAS", "alias pv 1") // @@ -123,27 +101,17 @@ public void testRemoveAcMeter() throws Exception { new UpdateAppInstance.Request(homeInstance.instanceId, "aliasrename", configNoMeter)); // expect the same as before // make sure every dependency got installed - assertEquals(this.appManagerTestBundle.sut.getInstantiatedApps().size(), 4); + assertEquals(4, this.appManagerTestBundle.sut.getInstantiatedApps().size()); // check properties of created apps for (var instance : this.appManagerTestBundle.sut.getInstantiatedApps()) { - int expectedDependencies; - switch (instance.appId) { - case "App.FENECON.Home": - expectedDependencies = 3; - break; - case "App.PvSelfConsumption.GridOptimizedCharge": - expectedDependencies = 0; - break; - case "App.PvSelfConsumption.SelfConsumptionOptimization": - expectedDependencies = 0; - break; - case "App.Ess.PrepareBatteryExtension": - expectedDependencies = 0; - break; - default: - throw new Exception("App with ID[" + instance.appId + "] should not have been created!"); - } + final var expectedDependencies = switch (instance.appId) { + case "App.FENECON.Home" -> 3; + case "App.PvSelfConsumption.GridOptimizedCharge" -> 0; + case "App.PvSelfConsumption.SelfConsumptionOptimization" -> 0; + case "App.Ess.PrepareBatteryExtension" -> 0; + default -> throw new Exception("App with ID[" + instance.appId + "] should not have been created!"); + }; if (expectedDependencies == 0 && instance.dependencies == null) { continue; } @@ -194,6 +162,30 @@ public void testFeedInTypeNoLimitation() throws Exception { assertEquals("DISABLE", batteryInverterProps.get("rcrEnable")); } + @Test + @Ignore + public void testEnableLimiter14a() throws Exception { + final var createSettings = fullSettings(); + createSettings.addProperty(FeneconHome.Property.HAS_ESS_LIMITER_14A.name(), false); + + final var createResponse = this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.FENECON.Home", "key", "alias", createSettings)); + + assertEquals(4, createResponse.instance().dependencies.size()); + assertFalse(this.appManagerTestBundle.sut.getInstantiatedApps().stream() + .anyMatch(a -> a.appId.equals("App.Ess.Limiter14a"))); + + final var updateSettings = fullSettings(); + createSettings.addProperty(FeneconHome.Property.HAS_ESS_LIMITER_14A.name(), true); + final var updateResponse = this.appManagerTestBundle.sut.handleUpdateAppInstanceRequest(DUMMY_ADMIN, + new UpdateAppInstance.Request(createResponse.instance().instanceId, "alias", updateSettings)); + + assertEquals(5, updateResponse.instance().dependencies.size()); + assertTrue(this.appManagerTestBundle.sut.getInstantiatedApps().stream() + .anyMatch(a -> a.appId.equals("App.Ess.Limiter14a"))); + + } + private final OpenemsAppInstance createFullHome() throws Exception { return createFullHome(this.appManagerTestBundle, DUMMY_ADMIN); } @@ -216,7 +208,7 @@ public static final OpenemsAppInstance createFullHome(AppManagerTestBundle appMa assertEquals(4, response.instance().dependencies.size()); // make sure every dependency got installed - assertEquals(appManagerTestBundle.sut.getInstantiatedApps().size(), 5); + assertEquals(5, appManagerTestBundle.sut.getInstantiatedApps().size()); // check properties of created apps for (var instance : appManagerTestBundle.sut.getInstantiatedApps()) { @@ -252,6 +244,7 @@ public static final JsonObject fullSettings() { .addProperty("RIPPLE_CONTROL_RECEIVER_ACTIV", false) // .addProperty("MAX_FEED_IN_POWER", 1000) // .addProperty("FEED_IN_SETTING", "LAGGING_0_95") // + .addProperty("HAS_ESS_LIMITER_14A", false) // .addProperty("HAS_AC_METER", true) // .addProperty("HAS_DC_PV1", true) // .addProperty("DC_PV1_ALIAS", "alias pv 1") // diff --git a/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java b/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java index da9a0d9dee..cb4227e230 100644 --- a/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java +++ b/io.openems.edge.core/test/io/openems/edge/app/timeofusetariff/TestTibber.java @@ -11,7 +11,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.stream.Stream; import org.junit.Before; @@ -25,11 +24,13 @@ import io.openems.common.jsonrpc.request.CreateComponentConfigRequest; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; import io.openems.common.utils.JsonUtils; -import io.openems.edge.app.integratedsystem.TestFeneconHome; import io.openems.edge.core.appmanager.AppManagerTestBundle; import io.openems.edge.core.appmanager.AppManagerTestBundle.PseudoComponentManagerFactory; import io.openems.edge.core.appmanager.Apps; import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.appmanager.validator.CheckAppsNotInstalled; +import io.openems.edge.core.appmanager.validator.CheckCommercial92; +import io.openems.edge.core.appmanager.validator.CheckHome; public class TestTibber { @@ -40,8 +41,7 @@ public class TestTibber { public void beforeEach() throws Exception { this.appManagerTestBundle = new AppManagerTestBundle(null, null, t -> { return ImmutableList.of(// - this.tibber = Apps.tibber(t), // - Apps.feneconHome(t) // + this.tibber = Apps.tibber(t) // ); }, null, new PseudoComponentManagerFactory()); @@ -52,8 +52,6 @@ public void beforeEach() throws Exception { @Test public void testRemoveAccessToken() throws Exception { - this.installHome(); - final var properties = JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); @@ -83,7 +81,6 @@ public void testRemoveAccessToken() throws Exception { @Test public void testAddChannelToPredictor() throws Exception { this.createPredictor(); - this.installHome(); final var properties = JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // @@ -95,7 +92,14 @@ public void testAddChannelToPredictor() throws Exception { } @Test(expected = OpenemsNamedException.class) - public void testOnlyCompatibleWithHome() throws Exception { + public void testOnlyCompatibleWithHomeOrCommercial() throws Exception { + this.appManagerTestBundle.addCheckable(CheckHome.COMPONENT_NAME, + t -> new CheckHome(t, new CheckAppsNotInstalled(this.appManagerTestBundle.sut, + AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)))); + this.appManagerTestBundle.addCheckable(CheckCommercial92.COMPONENT_NAME, + t -> new CheckCommercial92(t, new CheckAppsNotInstalled(this.appManagerTestBundle.sut, + AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)))); + final var properties = JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); @@ -105,7 +109,6 @@ public void testOnlyCompatibleWithHome() throws Exception { @Test public void testSetTokenValue() throws Exception { - this.installHome(); final var properties = JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "g78aw9ht2n112nb453") // .build(); @@ -131,7 +134,6 @@ public void testSetTokenValue() throws Exception { @Test public void testUnsetFilterValue() throws Exception { - this.installHome(); final var properties = JsonUtils.buildJsonObject() // .addProperty(Tibber.Property.ACCESS_TOKEN.name(), "g78aw9ht2n112nb453") // .addProperty(Tibber.Property.MULTIPLE_HOMES_CHECK.name(), true) // @@ -170,11 +172,6 @@ private void createPredictor() throws Exception { ))); } - private void installHome() throws InterruptedException, ExecutionException, OpenemsNamedException { - this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.FENECON.Home", "key", "alias", TestFeneconHome.minSettings())); - } - private void assertChannelsInPredictor(String... channels) throws OpenemsNamedException { final var existingAddresses = this.getChannelsInPredictor(); final var expectedChannels = Stream.of(channels).collect(toSet()); diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java deleted file mode 100644 index 9b79d51b33..0000000000 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImpSynchronizationTest.java +++ /dev/null @@ -1,199 +0,0 @@ -package io.openems.edge.core.appmanager; - -import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import com.google.common.collect.Lists; - -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.utils.JsonUtils; -import io.openems.common.utils.ReflectionUtils; -import io.openems.edge.app.evcs.KebaEvcs; -import io.openems.edge.common.test.ComponentTest; -import io.openems.edge.common.test.DummyComponentContext; -import io.openems.edge.common.test.DummyComponentManager; -import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.core.appmanager.AppManagerTestBundle.CheckablesBundle; -import io.openems.edge.core.appmanager.DummyValidator.TestCheckable; -import io.openems.edge.core.appmanager.dependency.AppManagerAppHelper; -import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; -import io.openems.edge.core.appmanager.jsonrpc.DeleteAppInstance; -import io.openems.edge.core.appmanager.validator.CheckAppsNotInstalled; -import io.openems.edge.core.appmanager.validator.CheckCardinality; -import io.openems.edge.core.appmanager.validator.CheckHome; -import io.openems.edge.core.appmanager.validator.relaycount.CheckRelayCount; - -public class AppManagerImpSynchronizationTest { - - private AppManagerImpl appManager; - - @Before - public void before() throws Exception { - this.appManager = new AppManagerImpl(); - ReflectionUtils.setAttribute(AppManagerImpl.class, this.appManager, "appValidateWorker", - new AppValidateWorker()); - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.lockModifyingApps.unlock(); - assertFalse(this.appManager.waitingForModified); - - final var cm = new DummyConfigurationAdmin(); - final var componentManager = new DummyComponentManager(); - componentManager.setConfigJson(JsonUtils.buildJsonObject() // - .add("components", JsonUtils.buildJsonObject() // - .add("scheduler0", JsonUtils.buildJsonObject() // - .addProperty("factoryId", "Scheduler.AllAlphabetically") // - .add("properties", JsonUtils.buildJsonObject() // - .addProperty("enabled", true) // - .add("controllers.ids", JsonUtils.buildJsonArray() // - .build()) // - .build()) // - .build()) - .build()) - .add("factories", JsonUtils.buildJsonObject() // - .build()) - .build()); - componentManager.setConfigurationAdmin(cm); - - // create config for scheduler - cm.getOrCreateEmptyConfiguration(componentManager.getEdgeConfig().getComponent("scheduler0").get().getPid()); - final var componentUtil = new ComponentUtilImpl(componentManager); - final var appManagerUtil = new AppManagerUtilImpl(componentManager); - final var validator = new DummyValidator(); - - final var checkablesBundle = new CheckablesBundle(// - new TestCheckable(), // - new CheckCardinality(this.appManager, appManagerUtil, - AppManagerTestBundle.getComponentContext(CheckCardinality.COMPONENT_NAME)), // - new CheckRelayCount(componentUtil, - AppManagerTestBundle.getComponentContext(CheckRelayCount.COMPONENT_NAME), null), // - new CheckAppsNotInstalled(this.appManager, - AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)), // - new CheckHome(this.appManager.componentManager, - AppManagerTestBundle.getComponentContext(CheckHome.COMPONENT_NAME), - new CheckAppsNotInstalled(this.appManager, - AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME))) // - ); - - validator.setCheckables(checkablesBundle.all()); - - new ComponentTest(this.appManager) // - .addReference("cm", cm) // - .addReference("componentManager", componentManager) // - .addReference("csoAppManagerAppHelper", - AppManagerTestBundle.cso( - new DummyAppManagerAppHelper(componentManager, componentUtil, appManagerUtil))) // - .addReference("validator", validator) // - .addReference("backendUtil", new DummyAppCenterBackendUtil()) // - .addReference("availableApps", Lists.newArrayList(// - new KebaEvcs(componentManager, - AppManagerTestBundle.getComponentContext("App.PvInverter.SolarEdge"), cm, componentUtil) // - )) // - .activate(MyConfig.create() // - .setApps("[]") // - .build()); - - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.lockModifyingApps.unlock(); - assertFalse(this.appManager.waitingForModified); - } - - @Test - public void testInstallationOfNotAvailableApp() throws Exception { - try { - this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("someAppId", "key", "alias", JsonUtils.buildJsonObject() // - .build())); - } catch (OpenemsNamedException e) { - // expected - } - - // if app is not existing no need to modify - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.lockModifyingApps.unlock(); - assertFalse(this.appManager.waitingForModified); - } - - @Test - public void testRemoveOfNotAvailableInstance() throws Exception { - try { - this.appManager.handleDeleteAppInstanceRequest(DUMMY_ADMIN, - new DeleteAppInstance.Request(UUID.randomUUID())); - } catch (OpenemsNamedException e) { - // expected - } - - // if instance is not existing no need to modify - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.lockModifyingApps.unlock(); - assertFalse(this.appManager.waitingForModified); - } - - @Test - public void testSimulateAfterInstallaion() throws Exception { - this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // - .build())); - - assertTrue(this.appManager.lockModifyingApps.tryLock()); - assertTrue(this.appManager.waitingForModified); - assertFalse(this.appManager.waitingForModifiedCondition.await(1, TimeUnit.MILLISECONDS)); - this.appManager.lockModifyingApps.unlock(); - } - - @Test - @Ignore - public void testSimulateLockWaitingForModification() throws Exception { - this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // - .build())); - - assertTrue(this.appManager.waitingForModified); - - final var second = CompletableFuture.supplyAsync(() -> { - try { - return this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, - new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", - JsonUtils.buildJsonObject() // - .build())); - } catch (OpenemsNamedException e) { - throw new RuntimeException(e); - } - }); - - Thread.sleep(5000); - assertFalse(second.isDone()); - - this.appManager.modified(new DummyComponentContext(), MyConfig.create() // - .setApps("[]") // - .build()); - - Thread.sleep(5000); - assertTrue(second.isDone()); - } - - @Test - public void testSimulateBeforeModified() throws Exception { - // simulate after an instance got created and the configuration was requested to - // update - assertTrue(this.appManager.lockModifyingApps.tryLock()); - this.appManager.waitingForModified = true; - this.appManager.lockModifyingApps.unlock(); - - this.appManager.modified(new DummyComponentContext(), MyConfig.create() // - .setApps("[]") // - .build()); - - assertTrue(this.appManager.lockModifyingApps.tryLock()); - assertFalse(this.appManager.waitingForModified); - } - -} diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplSynchronizationTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplSynchronizationTest.java new file mode 100644 index 0000000000..f5f69288d0 --- /dev/null +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplSynchronizationTest.java @@ -0,0 +1,128 @@ +package io.openems.edge.core.appmanager; + +import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.test.DummyComponentContext; +import io.openems.edge.core.appmanager.AppManagerTestBundle.PseudoComponentManagerFactory; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; +import io.openems.edge.core.appmanager.jsonrpc.DeleteAppInstance; + +public class AppManagerImplSynchronizationTest { + + private AppManagerImpl appManager; + + @Before + public void before() throws Exception { + final var appManagerTestBundle = new AppManagerTestBundle(null, null, t -> { + return ImmutableList.of(// + Apps.kebaEvcs(t), // + Apps.solarEdgePvInverter(t) // + ); + }, null, new PseudoComponentManagerFactory(), new AppManagerImpl()); + + this.appManager = appManagerTestBundle.sut; + + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.lockModifyingApps.unlock(); + assertFalse(this.appManager.waitingForModified); + } + + @Test + public void testInstallationOfNotAvailableApp() throws Exception { + assertThrows(OpenemsNamedException.class, () -> { + this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("someAppId", "key", "alias", JsonUtils.buildJsonObject() // + .build())); + }); + + // if app is not existing no need to modify + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.lockModifyingApps.unlock(); + assertFalse(this.appManager.waitingForModified); + } + + @Test + public void testRemoveOfNotAvailableInstance() throws Exception { + this.appManager.handleDeleteAppInstanceRequest(DUMMY_ADMIN, new DeleteAppInstance.Request(UUID.randomUUID())); + + // if instance is not existing no need to modify + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.lockModifyingApps.unlock(); + assertFalse(this.appManager.waitingForModified); + } + + @Test + public void testSimulateAfterInstallation() throws Exception { + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // + .build())); + + assertTrue(this.appManager.waitingForModified); + assertFalse(this.appManager.waitingForModifiedCondition.await(1, TimeUnit.MILLISECONDS)); + this.appManager.lockModifyingApps.unlock(); + } + + @Test + @Ignore + public void testSimulateLockWaitingForModification() throws Exception { + this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", JsonUtils.buildJsonObject() // + .build())); + + assertTrue(this.appManager.waitingForModified); + + final var second = CompletableFuture.supplyAsync(() -> { + try { + return this.appManager.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request("App.PvInverter.SolarEdge", "key", "alias", + JsonUtils.buildJsonObject() // + .build())); + } catch (OpenemsNamedException e) { + throw new RuntimeException(e); + } + }); + + Thread.sleep(5000); + assertFalse(second.isDone()); + + this.appManager.modified(new DummyComponentContext(), MyConfig.create() // + .setApps("[]") // + .build()); + + Thread.sleep(5000); + assertTrue(second.isDone()); + } + + @Test + public void testSimulateBeforeModified() throws Exception { + // simulate after an instance got created and the configuration was requested to + // update + assertTrue(this.appManager.lockModifyingApps.tryLock()); + this.appManager.waitingForModified = true; + this.appManager.lockModifyingApps.unlock(); + + this.appManager.modified(new DummyComponentContext(), MyConfig.create() // + .setApps("[]") // + .build()); + + assertTrue(this.appManager.lockModifyingApps.tryLock()); + assertFalse(this.appManager.waitingForModified); + } + +} diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplTest.java index 3e74b99489..ca463981dd 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerImplTest.java @@ -323,7 +323,7 @@ public void testFindAppById() { @Test public void testCheckCardinalitySingle() throws Exception { - var checkable = this.appManagerTestBundle.checkablesBundle.checkCardinality(); + var checkable = this.appManagerTestBundle.getCheckCardinality(); checkable.setProperties(new ValidatorConfig.MapBuilder<>(new TreeMap()) // .put("openemsApp", this.homeApp) // .build()); @@ -337,7 +337,7 @@ public void testCheckCardinalityMultiple() throws Exception { UUID.randomUUID(), JsonUtils.buildJsonObject().build(), null)); this.appManagerTestBundle.sut.instantiatedApps.add(new OpenemsAppInstance(this.kebaEvcsApp.getAppId(), "alias", UUID.randomUUID(), JsonUtils.buildJsonObject().build(), null)); - var checkable = this.appManagerTestBundle.checkablesBundle.checkCardinality(); + var checkable = this.appManagerTestBundle.getCheckCardinality(); checkable.setProperties(new ValidatorConfig.MapBuilder<>(new TreeMap()) // .put("openemsApp", this.kebaEvcsApp) // .build()); @@ -349,12 +349,11 @@ public void testCheckCardinalityMultiple() throws Exception { public void testCheckCardinalitySingleInCategorie() throws Exception { this.appManagerTestBundle.sut.instantiatedApps.add(new OpenemsAppInstance(this.awattarApp.getAppId(), "alias", UUID.randomUUID(), JsonUtils.buildJsonObject().build(), null)); - var checkable = this.appManagerTestBundle.checkablesBundle.checkCardinality(); + var checkable = this.appManagerTestBundle.getCheckCardinality(); checkable.setProperties(new ValidatorConfig.MapBuilder<>(new TreeMap()) // .put("openemsApp", this.stromdao) // .build()); assertFalse(checkable.check()); assertNotNull(checkable.getErrorMessage(Language.DEFAULT)); } - } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java index abcc772227..1252dc6b57 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppManagerTestBundle.java @@ -8,10 +8,12 @@ import java.util.Dictionary; import java.util.Hashtable; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; +import org.osgi.framework.Bundle; import org.osgi.framework.ServiceReference; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentConstants; @@ -21,11 +23,12 @@ import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Modified; -import com.google.common.collect.Lists; +import com.google.common.collect.ImmutableMap; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import io.openems.common.OpenemsConstants; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.EdgeConfig; @@ -57,12 +60,12 @@ import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance.Request; import io.openems.edge.core.appmanager.jsonrpc.DeleteAppInstance; import io.openems.edge.core.appmanager.jsonrpc.UpdateAppInstance; -import io.openems.edge.core.appmanager.validator.CheckAppsNotInstalled; import io.openems.edge.core.appmanager.validator.CheckCardinality; -import io.openems.edge.core.appmanager.validator.CheckHome; +import io.openems.edge.core.appmanager.validator.CheckOr; import io.openems.edge.core.appmanager.validator.Checkable; +import io.openems.edge.core.appmanager.validator.CheckableFactory; import io.openems.edge.core.appmanager.validator.Validator; -import io.openems.edge.core.appmanager.validator.relaycount.CheckRelayCount; +import io.openems.edge.core.appmanager.validator.ValidatorImpl; public class AppManagerTestBundle { @@ -78,12 +81,16 @@ public class AppManagerTestBundle { private final AppValidateWorker appValidateWorker; - public final CheckablesBundle checkablesBundle; - public final TestScheduler scheduler; - public AppManagerTestBundle(JsonObject initialComponentConfig, MyConfig initialAppManagerConfig, - Function> availableAppsSupplier) throws Exception { + private final CheckableFactory checkableFactory = new CheckableFactory(); + private final CheckCardinality checkCardinality; + + public AppManagerTestBundle(// + JsonObject initialComponentConfig, // + MyConfig initialAppManagerConfig, // + Function> availableAppsSupplier // + ) throws Exception { this(initialComponentConfig, initialAppManagerConfig, availableAppsSupplier, null, new DefaultComponentManagerFactory()); } @@ -94,6 +101,18 @@ public AppManagerTestBundle(// Function> availableAppsSupplier, // Consumer additionalComponentConfig, // ComponentManagerFactory componentManagerFactory // + ) throws Exception { + this(initialComponentConfig, initialAppManagerConfig, availableAppsSupplier, additionalComponentConfig, + componentManagerFactory, new AppManagerImplAutoUpdateOnConfigChange()); + } + + public AppManagerTestBundle(// + JsonObject initialComponentConfig, // + MyConfig initialAppManagerConfig, // + Function> availableAppsSupplier, // + Consumer additionalComponentConfig, // + ComponentManagerFactory componentManagerFactory, // + AppManagerImpl impl // ) throws Exception { if (initialComponentConfig == null) { initialComponentConfig = JsonUtils.buildJsonObject() // @@ -158,87 +177,20 @@ public AppManagerTestBundle(// this.componentUtil = new ComponentUtilImpl(this.componentManger); - this.sut = new AppManagerImpl() { - - @Activate - @Override - protected void activate(ComponentContext componentContext, Config config) { - super.activate(componentContext, config); - } - - @Modified - @Override - protected void modified(ComponentContext componentContext, Config config) throws OpenemsNamedException { - super.modified(componentContext, config); - } - - @Deactivate - @Override - protected void deactivate() { - super.deactivate(); - } - - @Override - public AddAppInstance.Response handleAddAppInstanceRequest(User user, Request request, - boolean ignoreBackend) throws OpenemsNamedException { - final var response = super.handleAddAppInstanceRequest(user, request, ignoreBackend); - this.modifyWithCurrentConfig(); - return response; - } - - @Override - public DeleteAppInstance.Response handleDeleteAppInstanceRequest(User user, - DeleteAppInstance.Request request) throws OpenemsNamedException { - final var response = super.handleDeleteAppInstanceRequest(user, request); - this.modifyWithCurrentConfig(); - return response; - } - - @Override - public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, - UpdateAppInstance.Request request) throws OpenemsNamedException { - final var response = super.handleUpdateAppInstanceRequest(user, request); - this.modifyWithCurrentConfig(); - return response; - } + this.sut = impl; - private final void modifyWithCurrentConfig() throws OpenemsNamedException { - final var config = MyConfig.create() // - .setApps(this.instantiatedApps.stream() // - .map(OpenemsAppInstance::toJsonObject) // - .collect(JsonUtils.toJsonArray()) // - .toString()) - .setKey("0000-0000-0000-0000") // - .build(); - DummyComponentContext context; - try { - context = DummyComponentContext.from(config); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new OpenemsException(e); - } - this.modified(context, config); - } - - }; componentManagerFactory.afterInit(this.sut, this.cm); this.appManagerUtil = new AppManagerUtilImpl(this.componentManger); this.appCenterBackendUtil = new DummyAppCenterBackendUtil(); ReflectionUtils.setAttribute(this.appManagerUtil.getClass(), this.appManagerUtil, "appManager", this.sut); - this.checkablesBundle = new CheckablesBundle(// - new TestCheckable(), // - new CheckCardinality(this.sut, this.appManagerUtil, - getComponentContext(CheckCardinality.COMPONENT_NAME)), // - new CheckRelayCount(this.componentUtil, getComponentContext(CheckRelayCount.COMPONENT_NAME), null), // - new CheckAppsNotInstalled(this.sut, getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)), // - new CheckHome(this.componentManger, getComponentContext(CheckHome.COMPONENT_NAME), - new CheckAppsNotInstalled(this.sut, getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME))) // - ); + this.addCheckable(TestCheckable.COMPONENT_NAME, t -> new TestCheckable()); + this.addCheckable(CheckOr.COMPONENT_NAME, t -> new CheckOr(t, this.checkableFactory)); + this.checkCardinality = this.addCheckable(CheckCardinality.COMPONENT_NAME, + t -> new CheckCardinality(this.sut, this.appManagerUtil, t)); - var dummyValidator = new DummyValidator(); - dummyValidator.setCheckables(this.checkablesBundle.all()); - this.validator = dummyValidator; + this.validator = new ValidatorImpl(this.checkableFactory); this.appHelper = new DummyAppManagerAppHelper(this.componentManger, this.componentUtil, this.appManagerUtil); final var csoAppManagerAppHelper = cso((AppManagerAppHelper) this.appHelper); @@ -274,6 +226,27 @@ private final void modifyWithCurrentConfig() throws OpenemsNamedException { this.scheduler = new TestScheduler(this.componentManger); } + /** + * Adds a checkable to the current test bundle. + * + * @param the type of the checkable to add + * @param componentName the component name of the checkable + * @param checkableFactory the factory to get a instance of the checkable + * @return the created checkable + */ + public T addCheckable(// + final String componentName, // + final Function checkableFactory // + ) { + final var checkable = checkableFactory.apply(getComponentContext(componentName)); + this.checkableFactory.bindCso(cso(componentName, checkable)); + return checkable; + } + + public CheckCardinality getCheckCardinality() { + return this.checkCardinality; + } + /** * Calls the modified method. * @@ -449,30 +422,6 @@ public PersistencePredictorAggregateTask addPersistencePredictorAggregateTask() return persistencePredictorAggregateTaskImpl; } - public record CheckablesBundle(// - DummyValidator.TestCheckable checkTest, // - CheckCardinality checkCardinality, // - CheckRelayCount checkRelayCount, // - CheckAppsNotInstalled checkAppsNotInstalled, // - CheckHome checkHome // - ) { - - /** - * Gets all {@link Checkable}. - * - * @return the {@link Checkable} - */ - public final List all() { - return Lists.newArrayList(// - this.checkTest(), // - this.checkCardinality(), // - this.checkRelayCount(), // - this.checkAppsNotInstalled(), // - this.checkHome() // - ); - } - } - /** * Gets the {@link ComponentContext} for an {@link OpenemsApp} of the given * appId. @@ -575,6 +524,65 @@ public void afterInit(AppManagerImpl impl, ConfigurationAdmin cm) { * @return the {@link ComponentServiceObjects} */ public static ComponentServiceObjects cso(T service) { + return cso(null, service); + } + + /** + * Creates a {@link ComponentServiceObjects} of a service. + * + * @param the type of the service + * @param componentName the name of the component + * @param service the service + * @return the {@link ComponentServiceObjects} + */ + public static ComponentServiceObjects cso(String componentName, T service) { + final var sr = new ServiceReference() { + + private final Map properties = ImmutableMap.builder() // + .put(OpenemsConstants.PROPERTY_OSGI_COMPONENT_NAME, + componentName != null ? componentName : service.getClass().getCanonicalName()) // + .build(); + + @Override + public Object getProperty(String key) { + return this.properties.get(key); + } + + @Override + public String[] getPropertyKeys() { + return this.properties.keySet().toArray(String[]::new); + } + + @Override + public Bundle getBundle() { + return null; + } + + @Override + public Bundle[] getUsingBundles() { + return null; + } + + @Override + public boolean isAssignableTo(Bundle bundle, String className) { + return false; + } + + @Override + public int compareTo(Object reference) { + return 0; + } + + @Override + public Dictionary getProperties() { + return null; + } + + @Override + public A adapt(Class type) { + return null; + } + }; return new ComponentServiceObjects() { @Override @@ -589,11 +597,79 @@ public void ungetService(T service) { @Override public ServiceReference getServiceReference() { - // not needed for test - return null; + return sr; } }; } + /** + * This implementation is used to automatically update the call the modified + * method when a changes happens thru a app change. + */ + private static class AppManagerImplAutoUpdateOnConfigChange extends AppManagerImpl { + + /** + * activate, modified, deactivate need to be overwritten because of reflection + * usage in tests. + */ + + @Activate + @Override + protected void activate(ComponentContext componentContext, Config config) { + super.activate(componentContext, config); + } + + @Modified + @Override + protected void modified(ComponentContext componentContext, Config config) throws OpenemsNamedException { + super.modified(componentContext, config); + } + + @Deactivate + @Override + protected void deactivate() { + super.deactivate(); + } + + @Override + public AddAppInstance.Response handleAddAppInstanceRequest(User user, Request request, boolean ignoreBackend) + throws OpenemsNamedException { + final var response = super.handleAddAppInstanceRequest(user, request, ignoreBackend); + this.modifyWithCurrentConfig(); + return response; + } + + @Override + public DeleteAppInstance.Response handleDeleteAppInstanceRequest(User user, DeleteAppInstance.Request request) + throws OpenemsNamedException { + final var response = super.handleDeleteAppInstanceRequest(user, request); + this.modifyWithCurrentConfig(); + return response; + } + + @Override + public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, UpdateAppInstance.Request request) + throws OpenemsNamedException { + final var response = super.handleUpdateAppInstanceRequest(user, request); + this.modifyWithCurrentConfig(); + return response; + } + + private final void modifyWithCurrentConfig() throws OpenemsNamedException { + final var config = MyConfig.create() // + .setApps(this.instantiatedApps.stream() // + .map(OpenemsAppInstance::toJsonObject) // + .collect(JsonUtils.toJsonArray()) // + .toString()) + .setKey("0000-0000-0000-0000") // + .build(); + try { + this.modified(DummyComponentContext.from(config), config); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new OpenemsException(e); + } + } + } + } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java index ca6f501674..4fa625f043 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java @@ -19,6 +19,7 @@ import io.openems.edge.app.api.TimedataInfluxDb; import io.openems.edge.app.ess.FixActivePower; import io.openems.edge.app.ess.FixStateOfCharge; +import io.openems.edge.app.ess.Limiter14a; import io.openems.edge.app.ess.PowerPlantController; import io.openems.edge.app.ess.PrepareBatteryExtension; import io.openems.edge.app.evcs.AlpitronicEvcs; @@ -34,13 +35,23 @@ import io.openems.edge.app.integratedsystem.FeneconHome; import io.openems.edge.app.integratedsystem.FeneconHome20; import io.openems.edge.app.integratedsystem.FeneconHome30; +import io.openems.edge.app.integratedsystem.fenecon.commercial.FeneconCommercial92; import io.openems.edge.app.loadcontrol.ManualRelayControl; import io.openems.edge.app.loadcontrol.ThresholdControl; import io.openems.edge.app.meter.CarloGavazziMeter; import io.openems.edge.app.meter.DiscovergyMeter; import io.openems.edge.app.meter.JanitzaMeter; import io.openems.edge.app.meter.MicrocareSdm630Meter; +import io.openems.edge.app.meter.PhoenixContactMeter; +import io.openems.edge.app.meter.PqPlusMeter; import io.openems.edge.app.meter.SocomecMeter; +import io.openems.edge.app.openemshardware.BeagleBoneBlack; +import io.openems.edge.app.openemshardware.Compulab; +import io.openems.edge.app.openemshardware.TechbaseCm3; +import io.openems.edge.app.openemshardware.TechbaseCm4; +import io.openems.edge.app.openemshardware.TechbaseCm4Max; +import io.openems.edge.app.openemshardware.TechbaseCm4s; +import io.openems.edge.app.openemshardware.TechbaseCm4sGen2; import io.openems.edge.app.peakshaving.PeakShaving; import io.openems.edge.app.peakshaving.PhaseAccuratePeakShaving; import io.openems.edge.app.pvinverter.FroniusPvInverter; @@ -59,10 +70,9 @@ import io.openems.edge.app.timeofusetariff.Tibber; import io.openems.edge.common.component.ComponentManager; -public class Apps { +public final class Apps { private Apps() { - super(); } /** @@ -113,6 +123,16 @@ public static final FeneconHome30 feneconHome30(AppManagerTestBundle t) { return app(t, FeneconHome30::new, "App.FENECON.Home.30"); } + /** + * Test method for creating a {@link FeneconCommercial92}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final FeneconCommercial92 feneconCommercial92(AppManagerTestBundle t) { + return app(t, FeneconCommercial92::new, "App.FENECON.Commercial.92"); + } + // TimeOfUseTariff /** @@ -185,6 +205,76 @@ public static final Tibber tibber(AppManagerTestBundle t) { return app(t, Tibber::new, "App.TimeOfUseTariff.Tibber"); } + /** + * Test method for creating a {@link BeagleBoneBlack}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final BeagleBoneBlack beagleBoneBlack(AppManagerTestBundle t) { + return app(t, BeagleBoneBlack::new, "App.OpenemsHardware.BeagleBoneBlack"); + } + + /** + * Test method for creating a {@link Compulab}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final Compulab compulab(AppManagerTestBundle t) { + return app(t, Compulab::new, "App.OpenemsHardware.Compulab"); + } + + /** + * Test method for creating a {@link TechbaseCm3}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm3 techbaseCm3(AppManagerTestBundle t) { + return app(t, TechbaseCm3::new, "App.OpenemsHardware.CM3"); + } + + /** + * Test method for creating a {@link TechbaseCm4}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm4 techbaseCm4(AppManagerTestBundle t) { + return app(t, TechbaseCm4::new, "App.OpenemsHardware.CM4"); + } + + /** + * Test method for creating a {@link TechbaseCm4Max}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm4Max techbaseCm4Max(AppManagerTestBundle t) { + return app(t, TechbaseCm4Max::new, "App.OpenemsHardware.CM4Max"); + } + + /** + * Test method for creating a {@link TechbaseCm4s}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm4s techbaseCm4s(AppManagerTestBundle t) { + return app(t, TechbaseCm4s::new, "App.OpenemsHardware.CM4S"); + } + + /** + * Test method for creating a {@link TechbaseCm4sGen2}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final TechbaseCm4sGen2 techbaseCm4sGen2(AppManagerTestBundle t) { + return app(t, TechbaseCm4sGen2::new, "App.OpenemsHardware.CM4S.Gen2"); + } + // Test /** @@ -469,6 +559,16 @@ public static final JanitzaMeter janitzaMeter(AppManagerTestBundle t) { return app(t, JanitzaMeter::new, "App.Meter.Janitza"); } + /** + * Test method for creating a {@link PqPlusMeter}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final PqPlusMeter pqPlusMeter(AppManagerTestBundle t) { + return app(t, PqPlusMeter::new, "App.Meter.PqPlus"); + } + /** * Test method for creating a {@link MicrocareSdm630Meter}. * @@ -479,6 +579,16 @@ public static final MicrocareSdm630Meter microcareSdm630Meter(AppManagerTestBund return app(t, MicrocareSdm630Meter::new, "App.Meter.Microcare.Sdm630"); } + /** + * Test method for creating a {@link PhoenixContactMeter}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final PhoenixContactMeter phoenixContactMeter(AppManagerTestBundle t) { + return app(t, PhoenixContactMeter::new, "App.Meter.PhoenixContact"); + } + // PV-Inverter /** @@ -595,6 +705,16 @@ public static final PowerPlantController powerPlantController(AppManagerTestBund return app(t, PowerPlantController::new, "App.Ess.PowerPlantController"); } + /** + * Test method for creating a {@link Limiter14a}. + * + * @param t the {@link AppManagerTestBundle} + * @return the {@link OpenemsApp} instance + */ + public static final Limiter14a limiter14a(AppManagerTestBundle t) { + return app(t, Limiter14a::new, "App.Ess.Limiter14a"); + } + private static final T app(AppManagerTestBundle t, DefaultAppConstructor constructor, String appId) { return constructor.create(t.componentManger, AppManagerTestBundle.getComponentContext(appId), t.cm, t.componentUtil); diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyValidator.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyValidator.java index 1297c42b94..03f2548953 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyValidator.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyValidator.java @@ -1,53 +1,17 @@ package io.openems.edge.core.appmanager; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; +import org.osgi.service.component.annotations.Component; + import io.openems.common.session.Language; import io.openems.edge.core.appmanager.validator.Checkable; -import io.openems.edge.core.appmanager.validator.Validator; import io.openems.edge.core.appmanager.validator.ValidatorConfig.CheckableConfig; -public class DummyValidator implements Validator { - - private List checkables; - - @Override - public List getErrorMessages(List checkableConfigs, Language language, - boolean returnImmediate) { - var errors = new ArrayList(); - for (var check : checkableConfigs) { - var checkable = this.findCheckableByName(check.checkableComponentName()); - checkable.setProperties(check.properties()); - if (checkable.check() == check.invertResult()) { - errors.add(check.invertResult() ? checkable.getInvertedErrorMessage(language) - : checkable.getErrorMessage(language)); - if (returnImmediate) { - return errors; - } - } - - } - return errors; - } - - private Checkable findCheckableByName(String name) { - return this.checkables.stream() // - .filter(c -> c.getComponentName().equals(name)) // - .findAny().get(); - } - - public void setCheckables(List checkables) { - this.checkables = checkables; - } - - public List getCheckables() { - return this.checkables; - } +public final class DummyValidator { /** * Creates a {@link CheckableConfig} for a test check. @@ -105,6 +69,7 @@ public static CheckableConfig testCheckable(// return testCheckable(check, (String) null, (String) null); } + @Component(name = TestCheckable.COMPONENT_NAME) public static class TestCheckable implements Checkable { public static final String COMPONENT_NAME = "Test.Validator.Checkable.TestCheckable"; @@ -152,4 +117,7 @@ public String getInvertedErrorMessage(Language language) { } + private DummyValidator() { + } + } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/ResolveOpenemsHardwareTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/ResolveOpenemsHardwareTest.java new file mode 100644 index 0000000000..fc535d9695 --- /dev/null +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/ResolveOpenemsHardwareTest.java @@ -0,0 +1,165 @@ +package io.openems.edge.core.appmanager; + +import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import com.google.common.collect.ImmutableList; +import com.google.gson.JsonObject; + +import io.openems.edge.common.test.DummyComponentContext; +import io.openems.edge.common.test.DummyComponentInstance; +import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; + +public class ResolveOpenemsHardwareTest { + + @Rule + public TemporaryFolder folder = TemporaryFolder.builder() // + .assureDeletion() // + .build(); + + private AppManagerTestBundle appManagerTestBundle; + private OpenemsApp dummyHardwareApp; + private OpenemsApp dummyHardwareApp2; + + @Before + public void setUp() throws Exception { + this.appManagerTestBundle = new AppManagerTestBundle(null, null, t -> { + return ImmutableList.of(// + this.dummyHardwareApp = Apps.techbaseCm4(t), // + this.dummyHardwareApp2 = Apps.techbaseCm3(t) // + ); + }); + System.setProperty("felix.cm.dir", this.folder.getRoot().getPath()); + } + + @Test + public void testSuccessfulInstallation() throws Exception { + this.setHardwareApp(this.dummyHardwareApp.getAppId()); + + final var completed = new CompletableFuture(); + final var context = new DummyComponentContext(new Hashtable(), DummyComponentInstance.create() // + .setDispose(() -> completed.complete(null)) // + .build()); + + final var testExecutor = new TestExecutor(); + final var resolver = new ResolveOpenemsHardware(context, this.appManagerTestBundle.sut, + this.appManagerTestBundle.appManagerUtil, testExecutor); + + resolver.bindApp(this.dummyHardwareApp); + resolver.bindApp(this.dummyHardwareApp2); + testExecutor.runAll(); + + completed.join(); + + assertEquals(1, this.appManagerTestBundle.sut.getInstantiatedApps().size()); + assertFalse(this.appManagerTestBundle.sut.getHardwareMissmatchChannel().getNextValue().get()); + } + + @Test + public void testNotExistingAppId() throws Exception { + this.setHardwareApp("Random.App.Id"); + + final var completed = new CompletableFuture(); + final var context = new DummyComponentContext(new Hashtable(), DummyComponentInstance.create() // + .setDispose(() -> completed.complete(null)) // + .build()); + + final var testExecutor = new TestExecutor(); + final var resolver = new ResolveOpenemsHardware(context, this.appManagerTestBundle.sut, + this.appManagerTestBundle.appManagerUtil, testExecutor); + + resolver.bindApp(this.dummyHardwareApp); + resolver.bindApp(this.dummyHardwareApp2); + testExecutor.runAll(); + + completed.join(); + + assertEquals(0, this.appManagerTestBundle.sut.getInstantiatedApps().size()); + assertTrue(this.appManagerTestBundle.sut.getHardwareMissmatchChannel().getNextValue().get()); + } + + @Test + public void testAppIdNotSet() throws Exception { + final var completed = new CompletableFuture(); + final var context = new DummyComponentContext(new Hashtable(), DummyComponentInstance.create() // + .setDispose(() -> completed.complete(null)) // + .build()); + + final var testExecutor = new TestExecutor(); + final var resolver = new ResolveOpenemsHardware(context, this.appManagerTestBundle.sut, + this.appManagerTestBundle.appManagerUtil, testExecutor); + + resolver.bindApp(this.dummyHardwareApp); + resolver.bindApp(this.dummyHardwareApp2); + testExecutor.runAll(); + + completed.join(); + + assertEquals(0, this.appManagerTestBundle.sut.getInstantiatedApps().size()); + assertFalse(this.appManagerTestBundle.sut.getHardwareMissmatchChannel().getNextValue().get()); + } + + @Test + public void testWrongHardwareAppInstalled() throws Exception { + this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN, + new AddAppInstance.Request(this.dummyHardwareApp2.getAppId(), "key", null, new JsonObject())); + + this.setHardwareApp(this.dummyHardwareApp.getAppId()); + + final var completed = new CompletableFuture(); + final var context = new DummyComponentContext(new Hashtable(), DummyComponentInstance.create() // + .setDispose(() -> completed.complete(null)) // + .build()); + + final var testExecutor = new TestExecutor(); + final var resolver = new ResolveOpenemsHardware(context, this.appManagerTestBundle.sut, + this.appManagerTestBundle.appManagerUtil, testExecutor); + + resolver.bindApp(this.dummyHardwareApp); + resolver.bindApp(this.dummyHardwareApp2); + testExecutor.runAll(); + + completed.join(); + + assertEquals(1, this.appManagerTestBundle.sut.getInstantiatedApps().size()); + assertTrue(this.appManagerTestBundle.sut.getHardwareMissmatchChannel().getNextValue().get()); + } + + private void setHardwareApp(String appId) throws Exception { + final var hardwareInfoFile = this.folder.newFile(ResolveOpenemsHardware.OPENEMS_HARDWARE_FILE_NAME); + try (final var fw = new FileWriter(hardwareInfoFile)) { + fw.write(ResolveOpenemsHardware.OPENEMS_HARDWARE_APP_KEY + "=" + appId); + } + } + + private static class TestExecutor implements Executor { + + private final List tasks = new ArrayList<>(); + + @Override + public void execute(Runnable command) { + this.tasks.add(command); + } + + public void runAll() { + this.tasks.forEach(Runnable::run); + this.tasks.clear(); + } + + } + +} diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java index 1e5ae260b7..c14160b59a 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java @@ -34,6 +34,7 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.feneconHome(t), true, TestFeneconHome.fullSettings())); this.apps.add(new TestTranslation(Apps.feneconHome20(t), true, TestFeneconHome20.fullSettings())); this.apps.add(new TestTranslation(Apps.feneconHome30(t), true, TestFeneconHome30.fullSettings())); + this.apps.add(new TestTranslation(Apps.feneconCommercial92(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.awattarHourly(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.entsoE(t), true, JsonUtils.buildJsonObject() // .addProperty("BIDDING_ZONE", "GERMANY") // @@ -51,6 +52,13 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.tibber(t), true, JsonUtils.buildJsonObject() // .addProperty("ACCESS_TOKEN", "123456789") // .build())); + this.apps.add(new TestTranslation(Apps.beagleBoneBlack(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.compulab(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm3(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm4(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm4Max(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm4s(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.techbaseCm4sGen2(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.modbusTcpApiReadOnly(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.modbusTcpApiReadWrite(t), true, JsonUtils.buildJsonObject() // .addProperty("API_TIMEOUT", 60) // @@ -71,14 +79,14 @@ public void beforeEach() throws Exception { this.apps.add(new TestTranslation(Apps.webastoNext(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.webastoUnite(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.evcsCluster(t), true, new JsonObject())); - this.apps.add(new TestTranslation(Apps.heatPump(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.heatPump(t), true, JsonUtils.buildJsonObject() // .addProperty("OUTPUT_CHANNEL_1", "io0/Relay1") // .addProperty("OUTPUT_CHANNEL_2", "io0/Relay2") // .build())); - this.apps.add(new TestTranslation(Apps.combinedHeatAndPower(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.combinedHeatAndPower(t), true, JsonUtils.buildJsonObject() // .addProperty("OUTPUT_CHANNEL", "io0/Relay1") // .build())); - this.apps.add(new TestTranslation(Apps.heatingElement(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.heatingElement(t), true, JsonUtils.buildJsonObject() // .addProperty("OUTPUT_CHANNEL_PHASE_L1", "io0/Relay1") // .addProperty("OUTPUT_CHANNEL_PHASE_L2", "io0/Relay2") // .addProperty("OUTPUT_CHANNEL_PHASE_L3", "io0/Relay3") // @@ -90,44 +98,46 @@ public void beforeEach() throws Exception { .addProperty("ESS_ID", "ess0") // .addProperty("METER_ID", "meter0") // .build())); - this.apps.add(new TestTranslation(Apps.manualRelayControl(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.manualRelayControl(t), true, JsonUtils.buildJsonObject() // .addProperty("OUTPUT_CHANNEL", "io0/Relay1") // .build())); - this.apps.add(new TestTranslation(Apps.thresholdControl(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.thresholdControl(t), true, JsonUtils.buildJsonObject() // .add("OUTPUT_CHANNELS", JsonUtils.buildJsonArray().add("io0/Relay1").build()) // .build())); this.apps.add(new TestTranslation(Apps.discovergyMeter(t), false, JsonUtils.buildJsonObject() // .addProperty("EMAIL", "test@test.test") // .addProperty("PASSWORD", "xxxx") // .build())); - this.apps.add(new TestTranslation(Apps.socomecMeter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.socomecMeter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .build())); - this.apps.add(new TestTranslation(Apps.carloGavazziMeter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.carloGavazziMeter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("MODBUS_UNIT_ID", 5) // .build())); - this.apps.add(new TestTranslation(Apps.janitzaMeter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.janitzaMeter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .build())); + this.apps.add(new TestTranslation(Apps.pqPlusMeter(t), false, new JsonObject())); + this.apps.add(new TestTranslation(Apps.phoenixContactMeter(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.froniusPvInverter(t), false, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("PORT", 502) // .addProperty("MODBUS_UNIT_ID", 1) // .build())); - this.apps.add(new TestTranslation(Apps.kacoPvInverter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.kacoPvInverter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("PORT", 502) // .build())); - this.apps.add(new TestTranslation(Apps.kostalPvInverter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.kostalPvInverter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("PORT", 502) // .addProperty("MODBUS_UNIT_ID", 1) // .build())); - this.apps.add(new TestTranslation(Apps.smaPvInverter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.smaPvInverter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .build())); - this.apps.add(new TestTranslation(Apps.solarEdgePvInverter(t), false, JsonUtils.buildJsonObject() // + this.apps.add(new TestTranslation(Apps.solarEdgePvInverter(t), true, JsonUtils.buildJsonObject() // .addProperty("MODBUS_ID", "modbus0") // .addProperty("PORT", 502) // .build())); @@ -147,6 +157,10 @@ public void beforeEach() throws Exception { .build())); this.apps.add(new TestTranslation(Apps.powerPlantController(t), true, new JsonObject())); this.apps.add(new TestTranslation(Apps.prepareBatteryExtension(t), true, new JsonObject())); + this.apps.add(new TestTranslation(Apps.limiter14a(t), true, JsonUtils.buildJsonObject() // + .addProperty("ESS_ID", "ess0") // + .addProperty("INPUT_CHANNEL_ADDRESS", "io0/Relay1") // + .build())); return this.apps.stream().map(TestTranslation::app).toList(); }); } diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java index 6174b2d811..54504dd202 100644 --- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java +++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/validator/CheckHomeTest.java @@ -35,13 +35,14 @@ public void setUp() throws Exception { Apps.feneconHome30(t) // ); }, null, new PseudoComponentManagerFactory()); - this.checkHome = this.appManagerTestBundle.checkablesBundle.checkHome(); + this.checkHome = this.appManagerTestBundle.addCheckable(CheckHome.COMPONENT_NAME, + t -> new CheckHome(t, new CheckAppsNotInstalled(this.appManagerTestBundle.sut, + AppManagerTestBundle.getComponentContext(CheckAppsNotInstalled.COMPONENT_NAME)))); } @Test public void testCheck() { - final var checkHome = this.appManagerTestBundle.checkablesBundle.checkHome(); - assertFalse(checkHome.check()); + assertFalse(this.checkHome.check()); assertFalse(PropsUtil.isHomeInstalled(this.appManagerTestBundle.appManagerUtil)); } diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java index 159f8c054c..616c112b51 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java @@ -163,7 +163,7 @@ public void accept(ManagedSymmetricEss ess, Integer value) throws OpenemsNamedEx * */ SET_REACTIVE_POWER_LESS_OR_EQUALS(new IntegerDoc() // - .unit(Unit.VOLT_AMPERE) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // .accessMode(AccessMode.WRITE_ONLY) // .onChannelSetNextWrite(new PowerConstraint("SetReactivePowerLessOrEquals", Phase.ALL, Pwr.REACTIVE, Relationship.LESS_OR_EQUALS))), // @@ -178,7 +178,7 @@ public void accept(ManagedSymmetricEss ess, Integer value) throws OpenemsNamedEx * */ SET_REACTIVE_POWER_GREATER_OR_EQUALS(new IntegerDoc() // - .unit(Unit.WATT) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // .accessMode(AccessMode.WRITE_ONLY) // .onChannelSetNextWrite(new PowerConstraint("SetReactivePowerGreaterOrEquals", Phase.ALL, Pwr.REACTIVE, Relationship.GREATER_OR_EQUALS))), // diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java index 134e6f5561..3fcfec1431 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/AbstractGoodWe.java @@ -287,7 +287,22 @@ protected final ModbusProtocol defineModbusProtocol() { ), new FC3ReadRegistersTask(35250, Priority.LOW, // - m(new BitsWordElement(35250, this) // + + /* + * Table 8-30 Grid Detailed WARNING (35250 - 35253, U64) + */ + new DummyRegisterElement(35250, 35251), // + m(new BitsWordElement(35252, this) // + .bit(0, GoodWe.ChannelId.STATE_86) // + .bit(1, GoodWe.ChannelId.STATE_87) // + .bit(2, GoodWe.ChannelId.STATE_88) // + .bit(3, GoodWe.ChannelId.STATE_89) // + .bit(4, GoodWe.ChannelId.STATE_90) // + .bit(5, GoodWe.ChannelId.STATE_91) // + .bit(6, GoodWe.ChannelId.STATE_92) // + .bit(7, GoodWe.ChannelId.STATE_93) // + ), // + m(new BitsWordElement(35253, this) // .bit(0, GoodWe.ChannelId.STATE_70) // .bit(1, GoodWe.ChannelId.STATE_71) // .bit(2, GoodWe.ChannelId.STATE_72) // @@ -304,18 +319,21 @@ protected final ModbusProtocol defineModbusProtocol() { .bit(13, GoodWe.ChannelId.STATE_83) // .bit(14, GoodWe.ChannelId.STATE_84) // .bit(15, GoodWe.ChannelId.STATE_85)), // - m(new BitsWordElement(35251, this) // - .bit(0, GoodWe.ChannelId.STATE_86) // - .bit(1, GoodWe.ChannelId.STATE_87) // - .bit(2, GoodWe.ChannelId.STATE_88) // - .bit(3, GoodWe.ChannelId.STATE_89) // - .bit(4, GoodWe.ChannelId.STATE_90) // - .bit(5, GoodWe.ChannelId.STATE_91) // - .bit(6, GoodWe.ChannelId.STATE_92) // - .bit(7, GoodWe.ChannelId.STATE_93) // + + /* + * Table 8-31 Inverter detailed error (35254 - 35257, U64) + */ + new DummyRegisterElement(35254, 35255), // + m(new BitsWordElement(35256, this) // + .bit(0, GoodWe.ChannelId.STATE_110) // + .bit(1, GoodWe.ChannelId.STATE_111) // + .bit(2, GoodWe.ChannelId.STATE_112) // + .bit(3, GoodWe.ChannelId.STATE_113) // + .bit(4, GoodWe.ChannelId.STATE_114) // + .bit(5, GoodWe.ChannelId.STATE_115) // + .bit(6, GoodWe.ChannelId.STATE_116) // ), // - new DummyRegisterElement(35252, 35253), // - m(new BitsWordElement(35254, this) // + m(new BitsWordElement(35257, this) // .bit(0, GoodWe.ChannelId.STATE_94) // .bit(1, GoodWe.ChannelId.STATE_95) // .bit(2, GoodWe.ChannelId.STATE_96) // @@ -332,17 +350,19 @@ protected final ModbusProtocol defineModbusProtocol() { .bit(13, GoodWe.ChannelId.STATE_107) // .bit(14, GoodWe.ChannelId.STATE_108) // .bit(15, GoodWe.ChannelId.STATE_109)), // - m(new BitsWordElement(35255, this) // - .bit(0, GoodWe.ChannelId.STATE_110) // - .bit(1, GoodWe.ChannelId.STATE_111) // - .bit(2, GoodWe.ChannelId.STATE_112) // - .bit(3, GoodWe.ChannelId.STATE_113) // - .bit(4, GoodWe.ChannelId.STATE_114) // - .bit(5, GoodWe.ChannelId.STATE_115) // - .bit(6, GoodWe.ChannelId.STATE_116) // + + /* + * Table 8-32 Inverter detailed status (35258 - 35261, U64) + */ + new DummyRegisterElement(35258, 35259), // + m(new BitsWordElement(35260, this) // + .bit(0, GoodWe.ChannelId.STATE_133) // + .bit(1, GoodWe.ChannelId.STATE_134) // + .bit(2, GoodWe.ChannelId.STATE_135) // + .bit(3, GoodWe.ChannelId.STATE_136) // + .bit(4, GoodWe.ChannelId.STATE_137) // ), // - new DummyRegisterElement(35256, 35257), // - m(new BitsWordElement(35258, this) // + m(new BitsWordElement(35261, this) // .bit(0, GoodWe.ChannelId.STATE_117) // .bit(1, GoodWe.ChannelId.STATE_118) // .bit(2, GoodWe.ChannelId.STATE_119) // @@ -359,14 +379,7 @@ protected final ModbusProtocol defineModbusProtocol() { .bit(13, GoodWe.ChannelId.STATE_130) // .bit(14, GoodWe.ChannelId.STATE_131) // .bit(15, GoodWe.ChannelId.STATE_132)), // - m(new BitsWordElement(35259, this) // - .bit(0, GoodWe.ChannelId.STATE_133) // - .bit(1, GoodWe.ChannelId.STATE_134) // - .bit(2, GoodWe.ChannelId.STATE_135) // - .bit(3, GoodWe.ChannelId.STATE_136) // - .bit(4, GoodWe.ChannelId.STATE_137) // - ), // - new DummyRegisterElement(35260, 35267), // + new DummyRegisterElement(35262, 35267), // m(GoodWe.ChannelId.MAX_GRID_FREQ_WITHIN_1_MINUTE, new UnsignedWordElement(35268), SCALE_FACTOR_MINUS_2), // m(GoodWe.ChannelId.MIN_GRID_FREQ_WITHIN_1_MINUTE, new UnsignedWordElement(35269), diff --git a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java index c8e8d37211..aa090eaa2b 100644 --- a/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java +++ b/io.openems.edge.goodwe/src/io/openems/edge/goodwe/common/GoodWe.java @@ -525,92 +525,92 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId STATE_57(Doc.of(Level.INFO).text("Charging under voltage 3")), // // Table 8-8 BMS Warning Code - STATE_58(Doc.of(Level.WARNING).text("Charging over voltage 1 ")), // - STATE_59(Doc.of(Level.WARNING).text("Discharging under voltage 1 ")), // - STATE_60(Doc.of(Level.WARNING).text("Cell high temperature 1 ")), // - STATE_61(Doc.of(Level.WARNING).text("Cell low temperature 1 ")), // - STATE_62(Doc.of(Level.WARNING).text("Charging over current 1 ")), // - STATE_63(Doc.of(Level.WARNING).text("Discharging over current 1 ")), // - STATE_64(Doc.of(Level.WARNING).text("Communication failure 1 ")), // - STATE_65(Doc.of(Level.WARNING).text("System reboot ")), // - STATE_66(Doc.of(Level.WARNING).text("Cell imbalance")), // - STATE_67(Doc.of(Level.WARNING).text("System low temperature 1 ")), // - STATE_68(Doc.of(Level.WARNING).text("System low temperature 1 ")), // - STATE_69(Doc.of(Level.WARNING).text("System high temperature")), // - - // Table 8-30 Grid Detailed Fault - STATE_70(Doc.of(Level.FAULT).text("Power outage")), // - STATE_71(Doc.of(Level.FAULT).text("Grid undervoltage first level fault")), // - STATE_72(Doc.of(Level.FAULT).text("Grid undervoltage second level fault")), // - STATE_73(Doc.of(Level.FAULT).text("Grid undervoltage third level fault")), // - STATE_74(Doc.of(Level.FAULT).text("Grid overvoltage first level fault")), // - STATE_75(Doc.of(Level.FAULT).text("Grid overvoltage second level fault")), // - STATE_76(Doc.of(Level.FAULT).text("Grid overvoltage third level fault")), // - STATE_77(Doc.of(Level.FAULT).text("Grid average voltage high fault")), // - STATE_78(Doc.of(Level.FAULT).text("Grid underfrequency first level fault")), // - STATE_79(Doc.of(Level.FAULT).text("Grid underfrequency second level fault")), // - STATE_80(Doc.of(Level.FAULT).text("Islanding protection underfrequency fault")), // - STATE_81(Doc.of(Level.FAULT).text("Grid overfrequency first level fault")), // - STATE_82(Doc.of(Level.FAULT).text("Grid overfrequency second level fault")), // - STATE_83(Doc.of(Level.FAULT).text("Islanding protection overfrequency fault")), // - STATE_84(Doc.of(Level.FAULT).text("Grid frequency shift fault")), // - STATE_85(Doc.of(Level.FAULT).text("Grid waveform check fault")), // - STATE_86(Doc.of(Level.FAULT).text("Grid line voltage fault flag")), // - STATE_87(Doc.of(Level.FAULT).text("Grid low voltage ride-through flag")), // - STATE_88(Doc.of(Level.FAULT).text("Grid high voltage ride-through flag")), // - STATE_89(Doc.of(Level.FAULT).text("Grid voltage exceeds the upper sampling limit")), // - STATE_90(Doc.of(Level.FAULT).text("Grid connection voltage high")), // - STATE_91(Doc.of(Level.FAULT).text("Grid connection voltage low")), // - STATE_92(Doc.of(Level.FAULT).text("Grid connection frequency high")), // - STATE_93(Doc.of(Level.FAULT).text("Grid connection frequency low")), // + STATE_58(Doc.of(OpenemsType.BOOLEAN).text("Charging over voltage 1 ")), // + STATE_59(Doc.of(OpenemsType.BOOLEAN).text("Discharging under voltage 1 ")), // + STATE_60(Doc.of(OpenemsType.BOOLEAN).text("Cell high temperature 1 ")), // + STATE_61(Doc.of(OpenemsType.BOOLEAN).text("Cell low temperature 1 ")), // + STATE_62(Doc.of(OpenemsType.BOOLEAN).text("Charging over current 1 ")), // + STATE_63(Doc.of(OpenemsType.BOOLEAN).text("Discharging over current 1 ")), // + STATE_64(Doc.of(OpenemsType.BOOLEAN).text("Communication failure 1 ")), // + STATE_65(Doc.of(OpenemsType.BOOLEAN).text("System reboot ")), // + STATE_66(Doc.of(OpenemsType.BOOLEAN).text("Cell imbalance")), // + STATE_67(Doc.of(OpenemsType.BOOLEAN).text("System low temperature 1 ")), // + STATE_68(Doc.of(OpenemsType.BOOLEAN).text("System low temperature 1 ")), // + STATE_69(Doc.of(OpenemsType.BOOLEAN).text("System high temperature")), // + + // Table 8-30 Grid Detailed WARNING + STATE_70(Doc.of(OpenemsType.BOOLEAN).text("Power outage")), // + STATE_71(Doc.of(OpenemsType.BOOLEAN).text("Grid undervoltage first level WARNING")), // + STATE_72(Doc.of(OpenemsType.BOOLEAN).text("Grid undervoltage second level WARNING")), // + STATE_73(Doc.of(OpenemsType.BOOLEAN).text("Grid undervoltage third level WARNING")), // + STATE_74(Doc.of(OpenemsType.BOOLEAN).text("Grid overvoltage first level WARNING")), // + STATE_75(Doc.of(OpenemsType.BOOLEAN).text("Grid overvoltage second level WARNING")), // + STATE_76(Doc.of(OpenemsType.BOOLEAN).text("Grid overvoltage third level WARNING")), // + STATE_77(Doc.of(OpenemsType.BOOLEAN).text("Grid average voltage high WARNING")), // + STATE_78(Doc.of(OpenemsType.BOOLEAN).text("Grid underfrequency first level WARNING")), // + STATE_79(Doc.of(OpenemsType.BOOLEAN).text("Grid underfrequency second level WARNING")), // + STATE_80(Doc.of(OpenemsType.BOOLEAN).text("Islanding protection underfrequency WARNING")), // + STATE_81(Doc.of(OpenemsType.BOOLEAN).text("Grid overfrequency first level WARNING")), // + STATE_82(Doc.of(OpenemsType.BOOLEAN).text("Grid overfrequency second level WARNING")), // + STATE_83(Doc.of(OpenemsType.BOOLEAN).text("Islanding protection overfrequency WARNING")), // + STATE_84(Doc.of(OpenemsType.BOOLEAN).text("Grid frequency shift WARNING")), // + STATE_85(Doc.of(OpenemsType.BOOLEAN).text("Grid waveform check WARNING")), // + STATE_86(Doc.of(OpenemsType.BOOLEAN).text("Grid line voltage WARNING flag")), // + STATE_87(Doc.of(OpenemsType.BOOLEAN).text("Grid low voltage ride-through flag")), // + STATE_88(Doc.of(OpenemsType.BOOLEAN).text("Grid high voltage ride-through flag")), // + STATE_89(Doc.of(OpenemsType.BOOLEAN).text("Grid voltage exceeds the upper sampling limit")), // + STATE_90(Doc.of(OpenemsType.BOOLEAN).text("Grid connection voltage high")), // + STATE_91(Doc.of(OpenemsType.BOOLEAN).text("Grid connection voltage low")), // + STATE_92(Doc.of(OpenemsType.BOOLEAN).text("Grid connection frequency high")), // + STATE_93(Doc.of(OpenemsType.BOOLEAN).text("Grid connection frequency low")), // // Table 8-31 Inverter detailed error - STATE_94(Doc.of(Level.FAULT).text("LLC hardware over current")), // - STATE_95(Doc.of(Level.FAULT).text("Battery boost hardware over current")), // - STATE_96(Doc.of(Level.FAULT).text("Battery boost software over current")), // - STATE_97(Doc.of(Level.FAULT).text("Battery bms fault")), // - STATE_98(Doc.of(Level.FAULT).text("Battery bms discharge disable")), // - STATE_99(Doc.of(Level.FAULT).text("Battery current rms over current")), // - STATE_100(Doc.of(Level.FAULT).text("Off-grid mode exceeds bms current limit")), // - STATE_101(Doc.of(Level.FAULT).text("Bus voltage soft start failed")), // - STATE_102(Doc.of(Level.FAULT).text("Bus voltage is too low")), // - STATE_103(Doc.of(Level.FAULT).text("Bus voltage is too high")), // - STATE_104(Doc.of(Level.FAULT).text("Inverter hardware over current")), // - STATE_105(Doc.of(Level.FAULT).text("Inverter software over current")), // - STATE_106(Doc.of(Level.FAULT).text("Pv boost hardware over current")), // - STATE_107(Doc.of(Level.FAULT).text("Pv boost software over current")), // - STATE_108(Doc.of(Level.FAULT).text("Grid back flow")), // - STATE_109(Doc.of(Level.FAULT).text("Off-grid mode battery voltage is too low")), // - STATE_110(Doc.of(Level.FAULT).text("Off-grid mode AC voltage is too low")), // - STATE_111(Doc.of(Level.FAULT).text("Off-grid mode AC voltage is too high")), // - STATE_112(Doc.of(Level.FAULT).text("Backup over load")), // - STATE_113(Doc.of(Level.FAULT).text("Off-grid zero error")), // - STATE_114(Doc.of(Level.FAULT).text("Power fast retrack error")), // - STATE_115(Doc.of(Level.FAULT).text("Bypass relay switch error")), // - STATE_116(Doc.of(Level.FAULT).text("Backup load relay switch error")), // + STATE_94(Doc.of(OpenemsType.BOOLEAN).text("LLC hardware over current")), // + STATE_95(Doc.of(OpenemsType.BOOLEAN).text("Battery boost hardware over current")), // + STATE_96(Doc.of(OpenemsType.BOOLEAN).text("Battery boost software over current")), // + STATE_97(Doc.of(OpenemsType.BOOLEAN).text("Battery bms WARNING")), // + STATE_98(Doc.of(OpenemsType.BOOLEAN).text("Battery bms discharge disable")), // + STATE_99(Doc.of(OpenemsType.BOOLEAN).text("Battery current rms over current")), // + STATE_100(Doc.of(OpenemsType.BOOLEAN).text("Off-grid mode exceeds bms current limit")), // + STATE_101(Doc.of(OpenemsType.BOOLEAN).text("Bus voltage soft start failed")), // + STATE_102(Doc.of(OpenemsType.BOOLEAN).text("Bus voltage is too low")), // + STATE_103(Doc.of(OpenemsType.BOOLEAN).text("Bus voltage is too high")), // + STATE_104(Doc.of(OpenemsType.BOOLEAN).text("Inverter hardware over current")), // + STATE_105(Doc.of(OpenemsType.BOOLEAN).text("Inverter software over current")), // + STATE_106(Doc.of(OpenemsType.BOOLEAN).text("Pv boost hardware over current")), // + STATE_107(Doc.of(OpenemsType.BOOLEAN).text("Pv boost software over current")), // + STATE_108(Doc.of(OpenemsType.BOOLEAN).text("Grid back flow")), // + STATE_109(Doc.of(OpenemsType.BOOLEAN).text("Off-grid mode battery voltage is too low")), // + STATE_110(Doc.of(OpenemsType.BOOLEAN).text("Off-grid mode AC voltage is too low")), // + STATE_111(Doc.of(OpenemsType.BOOLEAN).text("Off-grid mode AC voltage is too high")), // + STATE_112(Doc.of(OpenemsType.BOOLEAN).text("Backup over load")), // + STATE_113(Doc.of(OpenemsType.BOOLEAN).text("Off-grid zero error")), // + STATE_114(Doc.of(OpenemsType.BOOLEAN).text("Power fast retrack error")), // + STATE_115(Doc.of(OpenemsType.BOOLEAN).text("Bypass relay switch error")), // + STATE_116(Doc.of(OpenemsType.BOOLEAN).text("Backup load relay switch error")), // // Table 8-32 Inverter detailed status - STATE_117(Doc.of(Level.INFO).text("Over frequency curve running")), // - STATE_118(Doc.of(Level.INFO).text("Under frequency curve running")), // - STATE_119(Doc.of(Level.INFO).text("Frequency curve exiting recovery")), // - STATE_120(Doc.of(Level.INFO).text("PU over voltage curve running")), // - STATE_121(Doc.of(Level.INFO).text("PU under voltage curve running")), // - STATE_122(Doc.of(Level.INFO).text("QU curve running")), // - STATE_123(Doc.of(Level.INFO).text("PF curve running")), // - STATE_124(Doc.of(Level.INFO).text("Fixed PF is set")), // - STATE_125(Doc.of(Level.INFO).text("Fixed reactive power is set")), // - STATE_126(Doc.of(Level.INFO).text("Inverter over temp,derating curve operation")), // - STATE_127(Doc.of(Level.INFO).text("Australian DRED electricity sale status")), // - STATE_128(Doc.of(Level.INFO).text("Australian DRED purchase status")), // - STATE_129(Doc.of(Level.INFO).text("Active power limit set")), // - STATE_130(Doc.of(Level.INFO).text("70 percent derating (Germany) has been opened")), // - STATE_131(Doc.of(Level.INFO).text("CEI021 selftest running")), // - STATE_132(Doc.of(Level.INFO).text("Inverter first level over voltage derate")), // - STATE_133(Doc.of(Level.INFO).text("Force off grid flag")), // - STATE_134(Doc.of(Level.INFO).text("Force stop mode flag")), // - STATE_135(Doc.of(Level.INFO).text("Pv charge, off backup output flag")), // - STATE_136(Doc.of(Level.INFO).text("QU curve over voltage flag")), // - STATE_137(Doc.of(Level.INFO).text("QU curve under voltage flag")), // + STATE_117(Doc.of(OpenemsType.BOOLEAN).text("Over frequency curve running")), // + STATE_118(Doc.of(OpenemsType.BOOLEAN).text("Under frequency curve running")), // + STATE_119(Doc.of(OpenemsType.BOOLEAN).text("Frequency curve exiting recovery")), // + STATE_120(Doc.of(OpenemsType.BOOLEAN).text("PU over voltage curve running")), // + STATE_121(Doc.of(OpenemsType.BOOLEAN).text("PU under voltage curve running")), // + STATE_122(Doc.of(OpenemsType.BOOLEAN).text("QU curve running")), // + STATE_123(Doc.of(OpenemsType.BOOLEAN).text("PF curve running")), // + STATE_124(Doc.of(OpenemsType.BOOLEAN).text("Fixed PF is set")), // + STATE_125(Doc.of(OpenemsType.BOOLEAN).text("Fixed reactive power is set")), // + STATE_126(Doc.of(OpenemsType.BOOLEAN).text("Inverter over temp,derating curve operation")), // + STATE_127(Doc.of(OpenemsType.BOOLEAN).text("Australian DRED electricity sale status")), // + STATE_128(Doc.of(OpenemsType.BOOLEAN).text("Australian DRED purchase status")), // + STATE_129(Doc.of(OpenemsType.BOOLEAN).text("Active power limit set")), // + STATE_130(Doc.of(OpenemsType.BOOLEAN).text("70 percent derating (Germany) has been opened")), // + STATE_131(Doc.of(OpenemsType.BOOLEAN).text("CEI021 selftest running")), // + STATE_132(Doc.of(OpenemsType.BOOLEAN).text("Inverter first level over voltage derate")), // + STATE_133(Doc.of(OpenemsType.BOOLEAN).text("Force off grid flag")), // + STATE_134(Doc.of(OpenemsType.BOOLEAN).text("Force stop mode flag")), // + STATE_135(Doc.of(OpenemsType.BOOLEAN).text("Pv charge, off backup output flag")), // + STATE_136(Doc.of(OpenemsType.BOOLEAN).text("QU curve over voltage flag")), // + STATE_137(Doc.of(OpenemsType.BOOLEAN).text("QU curve under voltage flag")), // // BMS Information BATTERY_PROTOCOL(Doc.of(BatteryProtocol.values())), // diff --git a/io.openems.edge.simulator/bnd.bnd b/io.openems.edge.simulator/bnd.bnd index dbc46e6427..f674ba8c3a 100644 --- a/io.openems.edge.simulator/bnd.bnd +++ b/io.openems.edge.simulator/bnd.bnd @@ -13,6 +13,7 @@ Bundle-Version: 1.0.0.${tstamp} io.openems.edge.evcs.api,\ io.openems.edge.io.api,\ io.openems.edge.meter.api,\ + io.openems.edge.predictor.api,\ io.openems.edge.pvinverter.api,\ io.openems.edge.thermometer.api,\ io.openems.edge.timedata.api,\ diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/DataContainer.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/DataContainer.java index b0bf32fbe4..02b08f5525 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/DataContainer.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/DataContainer.java @@ -53,6 +53,22 @@ public Float[] getCurrentRecord() { return this.records.get(this.currentIndex); } + /** + * Gets all values for the key. If no keys exist, get the value of all records. + * + * @param key the Channel-Id + * @return the record values + */ + public List getValues(String key) { + var index = this.getIndex(key); + if (index == null) { + return List.of(); + } + return this.records.stream() // + .map(a -> a[index]) // + .toList(); + } + /** * Gets the value for the key from the current record. If no keys exist, get the * first value of the record. @@ -61,16 +77,9 @@ public Float[] getCurrentRecord() { * @return the record value */ public Optional getValue(String key) { - Integer index; - if (this.keys.isEmpty()) { - // no keys -> first value - index = 0; - } else { - // find index of key - index = this.keys.get(key); - if (index == null) { - return Optional.empty(); - } + var index = this.getIndex(key); + if (index == null) { + return Optional.empty(); } var record = this.getCurrentRecord(); if (index < record.length) { @@ -79,6 +88,22 @@ var record = this.getCurrentRecord(); return Optional.empty(); } + /** + * Gets the index of the kex. + * + * @param key the Channel-Id + * @return the index; possibly null + */ + private Integer getIndex(String key) { + if (this.keys.isEmpty()) { + // no keys -> first value + return 0; + } else { + // find index of key + return this.keys.get(key); + } + } + /** * Switch to the next row of values. */ diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java index a1bce438a7..e646771b00 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/app/SimulatorAppImpl.java @@ -473,6 +473,12 @@ public int getTimeDelta() { return -1; } + @Override + public List getValues(OpenemsType type, ChannelAddress channelAddress) { + // TODO Auto-generated method stub + return List.of(); + } + @Override public T getValue(OpenemsType type, ChannelAddress channelAddress) { if (this.currentSimulation == null) { diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/AbstractCsvDatasource.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/AbstractCsvDatasource.java index 82997c7a8c..33aae79cab 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/AbstractCsvDatasource.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/AbstractCsvDatasource.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.time.Duration; import java.time.LocalDateTime; +import java.util.List; import java.util.Set; import org.osgi.service.component.ComponentContext; @@ -59,6 +60,20 @@ public void handleEvent(Event event) { } } + @SuppressWarnings("unchecked") + @Override + public List getValues(OpenemsType type, ChannelAddress channelAddress) { + // First: try full ChannelAddress + var values = this.data.getValues(channelAddress.toString()); + if (values.isEmpty()) { + // Not found: try Channel-ID only (without Component-ID) + values = this.data.getValues(channelAddress.getChannelId()); + } + return values.stream() // + .map(v -> (T) TypeUtils.getAsType(type, v)) // + .toList(); + } + @Override public T getValue(OpenemsType type, ChannelAddress channelAddress) { // First: try full ChannelAddress diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/SimulatorDatasource.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/SimulatorDatasource.java index cac3c09485..f5d1411d89 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/SimulatorDatasource.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/datasource/api/SimulatorDatasource.java @@ -1,5 +1,6 @@ package io.openems.edge.simulator.datasource.api; +import java.util.List; import java.util.Set; import io.openems.common.types.ChannelAddress; @@ -12,14 +13,24 @@ public interface SimulatorDatasource { * * @return the Channel-Id */ - Set getKeys(); + public Set getKeys(); /** * Returns the delta between two values in seconds. * * @return the delta in seconds */ - int getTimeDelta(); + public int getTimeDelta(); + + /** + * Gets all values for the given key (channelId) in the given type. + * + * @param the type + * @param type the expected type + * @param channelAddress the Channel-Address + * @return the values, possibly empty + */ + public List getValues(OpenemsType type, ChannelAddress channelAddress); /** * Gets the value for the given key (channelId) in the given type. @@ -29,6 +40,6 @@ public interface SimulatorDatasource { * @param channelAddress the Channel-Address * @return the value, possibly null */ - T getValue(OpenemsType type, ChannelAddress channelAddress); + public T getValue(OpenemsType type, ChannelAddress channelAddress); } diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/Config.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/Config.java new file mode 100644 index 0000000000..3498f4b97c --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/Config.java @@ -0,0 +1,38 @@ +package io.openems.edge.simulator.predictor; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.predictor.api.prediction.LogVerbosity; + +@ObjectClassDefinition(// + name = "Simulator Predictor", // + description = "This Predictor simulates predictions from a DataSource") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "timedata0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Channel-Addresses", description = "List of Channel-Addresses this Predictor is used for, e.g. '*/ActivePower', '*/ActualPower'") + String[] channelAddresses() default { // + "_sum/ProductionActivePower", // + "_sum/UnmanagedConsumptionActivePower", // + "_sum/ConsumptionActivePower" }; + + @AttributeDefinition(name = "Datasource-ID", description = "ID of Simulator Datasource.") + String datasource_id() default "datasource0"; + + @AttributeDefinition(name = "Datasource target filter", description = "This is auto-generated by 'Datasource-ID'.") + String datasource_target() default "(enabled=true)"; + + @AttributeDefinition(name = "Log-Verbosity", description = "The log verbosity.") + LogVerbosity logVerbosity() default LogVerbosity.NONE; + + String webconsole_configurationFactory_nameHint() default "Simulator Predictor [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictor.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictor.java new file mode 100644 index 0000000000..0a80bff172 --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictor.java @@ -0,0 +1,23 @@ +package io.openems.edge.simulator.predictor; + +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.predictor.api.prediction.Predictor; + +public interface SimulatorPredictor extends Predictor, OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } +} diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictorImpl.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictorImpl.java new file mode 100644 index 0000000000..59fc9590f5 --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/predictor/SimulatorPredictorImpl.java @@ -0,0 +1,102 @@ +package io.openems.edge.simulator.predictor; + +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.LinkedList; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.propertytypes.EventTopics; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.types.ChannelAddress; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.component.ClockProvider; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.type.TypeUtils; +import io.openems.edge.predictor.api.prediction.AbstractPredictor; +import io.openems.edge.predictor.api.prediction.Prediction; +import io.openems.edge.predictor.api.prediction.Predictor; +import io.openems.edge.simulator.datasource.api.SimulatorDatasource; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Simulator.Predictor", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +@EventTopics({ // + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // +}) +public class SimulatorPredictorImpl extends AbstractPredictor + implements SimulatorPredictor, Predictor, OpenemsComponent { + + @Reference + private ComponentManager componentManager; + + @Reference + private ConfigurationAdmin cm; + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + private SimulatorDatasource datasource; + + public SimulatorPredictorImpl() { + super(// + OpenemsComponent.ChannelId.values(), // + SimulatorPredictor.ChannelId.values() // + ); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsNamedException { + super.activate(context, config.id(), config.alias(), config.enabled(), config.channelAddresses(), + config.logVerbosity()); + + // update filter for 'datasource' + if (OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "datasource", config.datasource_id())) { + return; + } + } + + @Override + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + protected ClockProvider getClockProvider() { + return this.componentManager; + } + + @Override + protected Prediction createNewPrediction(ChannelAddress channelAddress) { + var source = this.datasource.getValues(OpenemsType.INTEGER, channelAddress); + if (source.isEmpty()) { + return Prediction.EMPTY_PREDICTION; + } + // Fill 48 hours starting from midnight; assume Datasource provides one vale per + // 5 minutes + var values = new Integer[48 /* hours */ * 4 /* quarters per hour */]; + var cache = new LinkedList(); + for (var i = 0; i < values.length; i++) { + while (cache.size() < 3) { + cache.addAll(source); + } + values[i] = TypeUtils.averageInt(cache.poll(), cache.poll(), cache.poll()); + } + var today = ZonedDateTime.now(this.componentManager.getClock()).truncatedTo(ChronoUnit.DAYS); + return Prediction.from(today, values); + } +} diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/direct/SimulatorDatasourceCsvDirectImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/direct/SimulatorDatasourceCsvDirectImplTest.java index 22f4942d5d..347a36a453 100644 --- a/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/direct/SimulatorDatasourceCsvDirectImplTest.java +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/datasource/csv/direct/SimulatorDatasourceCsvDirectImplTest.java @@ -11,17 +11,33 @@ public class SimulatorDatasourceCsvDirectImplTest { private static final String COMPONENT_ID = "datasource0"; - @Test - public void test() throws Exception { - new ComponentTest(new SimulatorDatasourceCsvDirectImpl()) // + private static ComponentTest createTest(String componentId, String source) throws Exception { + return new ComponentTest(new SimulatorDatasourceCsvDirectImpl()) // .addReference("componentManager", new DummyComponentManager()) // .activate(MyConfig.create() // - .setId(COMPONENT_ID) // + .setId(componentId) // .setFactor(1) // .setFormat(CsvFormat.ENGLISH) // - .setSource("") // + .setSource(source) // .setTimeDelta(0) // - .build()) // + .build()); // + } + + /** + * Creates and activates a {@link SimulatorDatasourceCsvDirectImpl}. + * + * @param componentId the Component-ID + * @param source the data + * @return a {@link SimulatorDatasourceCsvDirectImpl} object + * @throws Exception on error + */ + public static SimulatorDatasourceCsvDirectImpl create(String componentId, String source) throws Exception { + return (SimulatorDatasourceCsvDirectImpl) createTest(componentId, source).getSut(); + } + + @Test + public void test() throws Exception { + createTest(COMPONENT_ID, "") // .next(new TestCase()) // ; } diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/MyConfig.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/MyConfig.java new file mode 100644 index 0000000000..4d2583743a --- /dev/null +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/MyConfig.java @@ -0,0 +1,80 @@ +package io.openems.edge.simulator.predictor; + +import io.openems.common.test.AbstractComponentConfig; +import io.openems.common.utils.ConfigUtils; +import io.openems.edge.predictor.api.prediction.LogVerbosity; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private String datasourceId; + private String[] channelAddresses; + private LogVerbosity logVerbosity; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setDatasourceId(String datasourceId) { + this.datasourceId = datasourceId; + return this; + } + + public Builder setChannelAddresses(String... channelAddresses) { + this.channelAddresses = channelAddresses; + return this; + } + + public Builder setLogVerbosity(LogVerbosity logVerbosity) { + this.logVerbosity = logVerbosity; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public String[] channelAddresses() { + return this.builder.channelAddresses; + } + + @Override + public String datasource_id() { + return this.builder.datasourceId; + } + + @Override + public String datasource_target() { + return ConfigUtils.generateReferenceTargetFilter(this.id(), this.datasource_id()); + } + + @Override + public LogVerbosity logVerbosity() { + return this.builder.logVerbosity; + } + +} \ No newline at end of file diff --git a/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/SimulatorPredictorImplTest.java b/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/SimulatorPredictorImplTest.java new file mode 100644 index 0000000000..cb52b93658 --- /dev/null +++ b/io.openems.edge.simulator/test/io/openems/edge/simulator/predictor/SimulatorPredictorImplTest.java @@ -0,0 +1,55 @@ +package io.openems.edge.simulator.predictor; + +import static org.junit.Assert.assertEquals; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.test.TimeLeapClock; +import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyComponentManager; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.predictor.api.prediction.LogVerbosity; +import io.openems.edge.simulator.datasource.csv.direct.SimulatorDatasourceCsvDirectImplTest; + +public class SimulatorPredictorImplTest { + + private static final TimeLeapClock CLOCK = new TimeLeapClock(Instant.ofEpochSecond(946684800), ZoneId.of("UTC")); + private static final String COMPONENT_ID = "predictor0"; + private static final String DATASOURCE_ID = "datasource0"; + private static final ChannelAddress SUM_PRODUCTION = new ChannelAddress("_sum", "ProductionActivePower"); + + @Test + public void test() throws OpenemsException, Exception { + final var datasource = SimulatorDatasourceCsvDirectImplTest.create(DATASOURCE_ID, """ + 10 + 20 + 30 + 40 + """); + final var sut = new SimulatorPredictorImpl(); + new ComponentTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("datasource", datasource) // + .addReference("componentManager", new DummyComponentManager(CLOCK)) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setDatasourceId(DATASOURCE_ID) // + .setChannelAddresses(SUM_PRODUCTION.toString()) // + .setLogVerbosity(LogVerbosity.REQUESTED_PREDICTIONS) // + .build()); // + + var p = sut.createNewPrediction(SUM_PRODUCTION); + assertEquals(192, p.asArray().length); + assertEquals(Integer.valueOf(20), p.asArray()[0]); + assertEquals(Integer.valueOf(23), p.asArray()[1]); + assertEquals(Integer.valueOf(27), p.asArray()[2]); + assertEquals(ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")), p.valuePerQuarter.firstKey()); + } + +} diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index b04097ce80..f84be2e897 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -9,12 +9,14 @@ import { OverviewComponent as ConsumptionChartOverviewComponent } from "./edge/h import { DetailsOverviewComponent as GridDetailsOverviewComponent } from "./edge/history/common/grid/details/details.overview"; import { OverviewComponent as GridChartOverviewComponent } from "./edge/history/common/grid/overview/overview"; import { DetailsOverviewComponent } from "./edge/history/common/production/details/details.overview"; -import { DetailsOverviewComponent as DigitalOutputDetailsOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/details/details.overview"; import { OverviewComponent as ProductionChartOverviewComponent } from "./edge/history/common/production/overview/overview"; import { OverviewComponent as SelfconsumptionChartOverviewComponent } from "./edge/history/common/selfconsumption/overview/overview"; import { OverviewComponent as ChannelthresholdChartOverviewComponent } from "./edge/history/Controller/ChannelThreshold/overview/overview"; import { OverviewComponent as GridOptimizedChargeChartOverviewComponent } from "./edge/history/Controller/Ess/GridoptimizedCharge/overview/overview"; import { OverviewComponent as TimeOfUseTariffOverviewComponent } from "./edge/history/Controller/Ess/TimeOfUseTariff/overview/overview"; +import { DetailsOverviewComponent as DigitalOutputDetailsOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/details/details.overview"; +import { OverviewComponent as DigitalOutputChartOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/overview/overview"; +import { OverviewComponent as ModbusTcpApiOverviewComponent } from "./edge/history/Controller/ModbusTcpApi/overview/overview"; import { DelayedSellToGridChartOverviewComponent } from "./edge/history/delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component"; import { HeatingelementChartOverviewComponent } from "./edge/history/heatingelement/heatingelementchartoverview/heatingelementchartoverview.component"; import { HeatPumpChartOverviewComponent } from "./edge/history/heatpump/heatpumpchartoverview/heatpumpchartoverview.component"; @@ -48,14 +50,12 @@ import { SystemExecuteComponent as EdgeSettingsSystemExecuteComponent } from "./ import { SystemLogComponent as EdgeSettingsSystemLogComponent } from "./edge/settings/systemlog/systemlog.component"; import { LoginComponent } from "./index/login.component"; import { OverViewComponent } from "./index/overview/overview.component"; -import { UserComponent } from "./user/user.component"; import { LoadingScreenComponent } from "./index/shared/loading-screen"; import { CurrentAndVoltageOverviewComponent } from "./shared/components/edge/meter/currentVoltage/currentVoltage.overview"; import { DataService } from "./shared/components/shared/dataservice"; import { hasEdgeRole } from "./shared/guards/functional-guards"; import { Role } from "./shared/type/role"; -import { OverviewComponent as DigitalOutputChartOverviewComponent } from "./edge/history/Controller/Io/DigitalOutput/overview/overview"; - +import { UserComponent } from "./user/user.component"; export const routes: Routes = [ @@ -101,6 +101,7 @@ export const routes: Routes = [ { path: "gridchart", component: GridChartOverviewComponent }, { path: "gridchart/:componentId", component: GridDetailsOverviewComponent }, { path: "gridchart/:componentId/currentVoltage", component: CurrentAndVoltageOverviewComponent }, + { path: ":componentId/modbusTcpApi", component: ModbusTcpApiOverviewComponent }, { path: "productionchart", component: ProductionChartOverviewComponent }, { path: "productionchart/:componentId", component: DetailsOverviewComponent }, { path: "productionchart/:componentId/currentVoltage", component: CurrentAndVoltageOverviewComponent }, diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index bcab88af3b..27d05b4410 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -8,6 +8,7 @@ import { Subject, Subscription } from "rxjs"; import { filter, takeUntil } from "rxjs/operators"; import { environment } from "../environments"; import { AppService } from "./app.service"; +import { AppStateTracker } from "./shared/ngrx-store/states"; import { GlobalRouteChangeHandler } from "./shared/service/globalRouteChangeHandler"; import { Service, UserPermission, Websocket } from "./shared/shared"; import { Language } from "./shared/type/language"; @@ -42,6 +43,7 @@ export class AppComponent implements OnInit, OnDestroy { private meta: Meta, private appService: AppService, private title: Title, + private stateService: AppStateTracker, ) { service.setLang(Language.getByKey(localStorage.LANGUAGE) ?? Language.getByBrowserLang(navigator.language)); diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index 8a191a18ba..e8ad40d998 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -23,6 +23,7 @@ import { IndexModule } from "./index/index.module"; import { RegistrationModule } from "./registration/registration.module"; import { StatusSingleComponent } from "./shared/components/status/single/status.component"; import { ChartOptionsPopoverComponent } from "./shared/legacy/chartoptions/popover/popover.component"; +import { AppStateTracker } from "./shared/ngrx-store/states"; import { MyErrorHandler } from "./shared/service/myerrorhandler"; import { Pagination } from "./shared/service/pagination"; import { SharedModule } from "./shared/shared.module"; @@ -64,6 +65,7 @@ import { UserModule } from "./user/user.module"; Pagination, CheckForUpdateService, AppService, + AppStateTracker, ], bootstrap: [AppComponent], }) diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/channels.spec.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/channels.spec.ts new file mode 100644 index 0000000000..d96d89c001 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/channels.spec.ts @@ -0,0 +1,1070 @@ +import { TimeUnit } from "chart.js"; +import { ChartConstants } from "src/app/shared/components/chart/chart.constants"; +import { OeTester } from "src/app/shared/components/shared/testing/common"; +import { OeChartTester } from "src/app/shared/components/shared/testing/tester"; +import { QueryHistoricTimeseriesDataResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; +import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; + +export namespace History { + + export const LINE_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min: number, max: number; }, ticks: { stepSize: number; }; }; }): OeChartTester.Dataset.Option => ({ + type: "option", + options: { + "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": {}, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "index", "callbacks": {} } }, "scales": { + "x": { "stacked": true, "offset": false, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "millisecond": "SSS [ms]", "second": "HH:mm:ss a", "minute": "HH:mm", "hour": "HH:00", "day": "dd", "week": "ll", "month": "MM", "quarter": "[Q]Q - YYYY", "year": "yyyy" } } }, + "left": { + ...options["right"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "beginAtZero": true, "max": 100, "min": 0, "type": "linear", "title": { "text": "%", "display": true, "font": { "size": 11 }, "padding": 5 }, "position": "right", "grid": { "display": false }, + "ticks": { + ...options["right"]?.ticks, + "color": "", + "padding": 5, + "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, + }, + }, + }, + }, + }); + export const BAR_CHART_OPTIONS = (period: string, chartType: "line" | "bar", options: { [key: string]: { scale: { min?: number, max?: number; }, ticks: { stepSize?: number; }; }; }): OeChartTester.Dataset.Option => ({ + type: "option", + options: { + "responsive": true, "maintainAspectRatio": false, "elements": { "point": { "radius": 0, "hitRadius": 0, "hoverRadius": 0 }, "line": { "stepped": false, "fill": true } }, "datasets": { "bar": { "barPercentage": 1 }, "line": {} }, "plugins": { "colors": { "enabled": false }, "legend": { "display": true, "position": "bottom", "labels": { "color": "" } }, "tooltip": { "intersect": false, "mode": "x", "callbacks": {} } }, "scales": { + "x": { "stacked": true, "offset": true, "type": "time", "ticks": { "source": "auto", "maxTicksLimit": 31 }, "bounds": "ticks", "adapters": { "date": { "locale": { "code": "de", "formatLong": {}, "localize": {}, "match": {}, "options": { "weekStartsOn": 1, "firstWeekContainsDate": 4 } } } }, "time": { "unit": period as TimeUnit, "displayFormats": { "datetime": "yyyy-MM-dd HH:mm:ss", "millisecond": "SSS [ms]", "second": "HH:mm:ss a", "minute": "HH:mm", "hour": "HH:00", "day": "dd", "week": "ll", "month": "MM", "quarter": "[Q]Q - YYYY", "year": "yyyy" } } }, + "left": { + ...options["left"]?.scale, ...(chartType === "line" ? { stacked: false } : {}), "title": { "text": "kWh", "display": true, "padding": 5, "font": { "size": 11 } }, "position": "left", "grid": { "display": true }, + "ticks": { + ...options["left"]?.ticks, + "color": "", + "padding": 5, + "maxTicksLimit": ChartConstants.NUMBER_OF_Y_AXIS_TICKS, + }, + }, + }, + }, + }); + + /** + * up to 288 datapoints (5 min aggregated values) from a + * + * {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues} + * */ + export const DAY: OeTester.Types.Channels = ({ + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: {}, + }), + dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { + data: { + "ctrlApiModbusTcp0/Ess0SetActivePowerEquals": [null, + null, + null, + 112, + 262, + 392, + 240, + 230, + 229, + 227, + 317, + 224, + 133, + 135, + 133, + 192, + 209, + 90, + 95, + 96, + 164, + 297, + 184, + 182, + 183, + 198, + 333, + 183, + 93, + 97, + 98, + 197, + 266, + 177, + 144, + 140, + 173, + 304, + 305, + 237, + 232, + 227, + 283, + 344, + 135, + 96, + 95, + null, + null, + null, + null, + 102, + 129, + 140, + 301, + 248, + 267, + 319, + 310, + 452, + 451, + 280, + 234, + 226, + 249, + 390, + 242, + 199, + 179, + 166, + 280, + 239, + 192, + 187, + 187, + 190, + 303, + 146, + 62, + 62, + 64, + 887, + 1119, + 1070, + 1057, + 596, + 138, + 233, + 152, + 209, + 192, + 202, + 308, + 254, + 175, + 122, + 108, + 137, + 216, + 947, + 599, + 203, + 232, + 328, + 299, + 520, + 1213, + 641, + 1030, + 442, + 374, + 1758, + 249, + 260, + 346, + 1879, + 230, + 484, + 1260, + 1317, + 1488, + 1451, + 1892, + 1466, + 1332, + 523, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null], + }, + timestamps: [ + "2023-07-02T22:00:00Z", + "2023-07-02T22:05:00Z", + "2023-07-02T22:10:00Z", + "2023-07-02T22:15:00Z", + "2023-07-02T22:20:00Z", + "2023-07-02T22:25:00Z", + "2023-07-02T22:30:00Z", + "2023-07-02T22:35:00Z", + "2023-07-02T22:40:00Z", + "2023-07-02T22:45:00Z", + "2023-07-02T22:50:00Z", + "2023-07-02T22:55:00Z", + "2023-07-02T23:00:00Z", + "2023-07-02T23:05:00Z", + "2023-07-02T23:10:00Z", + "2023-07-02T23:15:00Z", + "2023-07-02T23:20:00Z", + "2023-07-02T23:25:00Z", + "2023-07-02T23:30:00Z", + "2023-07-02T23:35:00Z", + "2023-07-02T23:40:00Z", + "2023-07-02T23:45:00Z", + "2023-07-02T23:50:00Z", + "2023-07-02T23:55:00Z", + "2023-07-03T00:00:00Z", + "2023-07-03T00:05:00Z", + "2023-07-03T00:10:00Z", + "2023-07-03T00:15:00Z", + "2023-07-03T00:20:00Z", + "2023-07-03T00:25:00Z", + "2023-07-03T00:30:00Z", + "2023-07-03T00:35:00Z", + "2023-07-03T00:40:00Z", + "2023-07-03T00:45:00Z", + "2023-07-03T00:50:00Z", + "2023-07-03T00:55:00Z", + "2023-07-03T01:00:00Z", + "2023-07-03T01:05:00Z", + "2023-07-03T01:10:00Z", + "2023-07-03T01:15:00Z", + "2023-07-03T01:20:00Z", + "2023-07-03T01:25:00Z", + "2023-07-03T01:30:00Z", + "2023-07-03T01:35:00Z", + "2023-07-03T01:40:00Z", + "2023-07-03T01:45:00Z", + "2023-07-03T01:50:00Z", + "2023-07-03T01:55:00Z", + "2023-07-03T02:00:00Z", + "2023-07-03T02:05:00Z", + "2023-07-03T02:10:00Z", + "2023-07-03T02:15:00Z", + "2023-07-03T02:20:00Z", + "2023-07-03T02:25:00Z", + "2023-07-03T02:30:00Z", + "2023-07-03T02:35:00Z", + "2023-07-03T02:40:00Z", + "2023-07-03T02:45:00Z", + "2023-07-03T02:50:00Z", + "2023-07-03T02:55:00Z", + "2023-07-03T03:00:00Z", + "2023-07-03T03:05:00Z", + "2023-07-03T03:10:00Z", + "2023-07-03T03:15:00Z", + "2023-07-03T03:20:00Z", + "2023-07-03T03:25:00Z", + "2023-07-03T03:30:00Z", + "2023-07-03T03:35:00Z", + "2023-07-03T03:40:00Z", + "2023-07-03T03:45:00Z", + "2023-07-03T03:50:00Z", + "2023-07-03T03:55:00Z", + "2023-07-03T04:00:00Z", + "2023-07-03T04:05:00Z", + "2023-07-03T04:10:00Z", + "2023-07-03T04:15:00Z", + "2023-07-03T04:20:00Z", + "2023-07-03T04:25:00Z", + "2023-07-03T04:30:00Z", + "2023-07-03T04:35:00Z", + "2023-07-03T04:40:00Z", + "2023-07-03T04:45:00Z", + "2023-07-03T04:50:00Z", + "2023-07-03T04:55:00Z", + "2023-07-03T05:00:00Z", + "2023-07-03T05:05:00Z", + "2023-07-03T05:10:00Z", + "2023-07-03T05:15:00Z", + "2023-07-03T05:20:00Z", + "2023-07-03T05:25:00Z", + "2023-07-03T05:30:00Z", + "2023-07-03T05:35:00Z", + "2023-07-03T05:40:00Z", + "2023-07-03T05:45:00Z", + "2023-07-03T05:50:00Z", + "2023-07-03T05:55:00Z", + "2023-07-03T06:00:00Z", + "2023-07-03T06:05:00Z", + "2023-07-03T06:10:00Z", + "2023-07-03T06:15:00Z", + "2023-07-03T06:20:00Z", + "2023-07-03T06:25:00Z", + "2023-07-03T06:30:00Z", + "2023-07-03T06:35:00Z", + "2023-07-03T06:40:00Z", + "2023-07-03T06:45:00Z", + "2023-07-03T06:50:00Z", + "2023-07-03T06:55:00Z", + "2023-07-03T07:00:00Z", + "2023-07-03T07:05:00Z", + "2023-07-03T07:10:00Z", + "2023-07-03T07:15:00Z", + "2023-07-03T07:20:00Z", + "2023-07-03T07:25:00Z", + "2023-07-03T07:30:00Z", + "2023-07-03T07:35:00Z", + "2023-07-03T07:40:00Z", + "2023-07-03T07:45:00Z", + "2023-07-03T07:50:00Z", + "2023-07-03T07:55:00Z", + "2023-07-03T08:00:00Z", + "2023-07-03T08:05:00Z", + "2023-07-03T08:10:00Z", + "2023-07-03T08:15:00Z", + "2023-07-03T08:20:00Z", + "2023-07-03T08:25:00Z", + "2023-07-03T08:30:00Z", + "2023-07-03T08:35:00Z", + "2023-07-03T08:40:00Z", + "2023-07-03T08:45:00Z", + "2023-07-03T08:50:00Z", + "2023-07-03T08:55:00Z", + "2023-07-03T09:00:00Z", + "2023-07-03T09:05:00Z", + "2023-07-03T09:10:00Z", + "2023-07-03T09:15:00Z", + "2023-07-03T09:20:00Z", + "2023-07-03T09:25:00Z", + "2023-07-03T09:30:00Z", + "2023-07-03T09:35:00Z", + "2023-07-03T09:40:00Z", + "2023-07-03T09:45:00Z", + "2023-07-03T09:50:00Z", + "2023-07-03T09:55:00Z", + "2023-07-03T10:00:00Z", + "2023-07-03T10:05:00Z", + "2023-07-03T10:10:00Z", + "2023-07-03T10:15:00Z", + "2023-07-03T10:20:00Z", + "2023-07-03T10:25:00Z", + "2023-07-03T10:30:00Z", + "2023-07-03T10:35:00Z", + "2023-07-03T10:40:00Z", + "2023-07-03T10:45:00Z", + "2023-07-03T10:50:00Z", + "2023-07-03T10:55:00Z", + "2023-07-03T11:00:00Z", + "2023-07-03T11:05:00Z", + "2023-07-03T11:10:00Z", + "2023-07-03T11:15:00Z", + "2023-07-03T11:20:00Z", + "2023-07-03T11:25:00Z", + "2023-07-03T11:30:00Z", + "2023-07-03T11:35:00Z", + "2023-07-03T11:40:00Z", + "2023-07-03T11:45:00Z", + "2023-07-03T11:50:00Z", + "2023-07-03T11:55:00Z", + "2023-07-03T12:00:00Z", + "2023-07-03T12:05:00Z", + "2023-07-03T12:10:00Z", + "2023-07-03T12:15:00Z", + "2023-07-03T12:20:00Z", + "2023-07-03T12:25:00Z", + "2023-07-03T12:30:00Z", + "2023-07-03T12:35:00Z", + "2023-07-03T12:40:00Z", + "2023-07-03T12:45:00Z", + "2023-07-03T12:50:00Z", + "2023-07-03T12:55:00Z", + "2023-07-03T13:00:00Z", + "2023-07-03T13:05:00Z", + "2023-07-03T13:10:00Z", + "2023-07-03T13:15:00Z", + "2023-07-03T13:20:00Z", + "2023-07-03T13:25:00Z", + "2023-07-03T13:30:00Z", + "2023-07-03T13:35:00Z", + "2023-07-03T13:40:00Z", + "2023-07-03T13:45:00Z", + "2023-07-03T13:50:00Z", + "2023-07-03T13:55:00Z", + "2023-07-03T14:00:00Z", + "2023-07-03T14:05:00Z", + "2023-07-03T14:10:00Z", + "2023-07-03T14:15:00Z", + "2023-07-03T14:20:00Z", + "2023-07-03T14:25:00Z", + "2023-07-03T14:30:00Z", + "2023-07-03T14:35:00Z", + "2023-07-03T14:40:00Z", + "2023-07-03T14:45:00Z", + "2023-07-03T14:50:00Z", + "2023-07-03T14:55:00Z", + "2023-07-03T15:00:00Z", + "2023-07-03T15:05:00Z", + "2023-07-03T15:10:00Z", + "2023-07-03T15:15:00Z", + "2023-07-03T15:20:00Z", + "2023-07-03T15:25:00Z", + "2023-07-03T15:30:00Z", + "2023-07-03T15:35:00Z", + "2023-07-03T15:40:00Z", + "2023-07-03T15:45:00Z", + "2023-07-03T15:50:00Z", + "2023-07-03T15:55:00Z", + "2023-07-03T16:00:00Z", + "2023-07-03T16:05:00Z", + "2023-07-03T16:10:00Z", + "2023-07-03T16:15:00Z", + "2023-07-03T16:20:00Z", + "2023-07-03T16:25:00Z", + "2023-07-03T16:30:00Z", + "2023-07-03T16:35:00Z", + "2023-07-03T16:40:00Z", + "2023-07-03T16:45:00Z", + "2023-07-03T16:50:00Z", + "2023-07-03T16:55:00Z", + "2023-07-03T17:00:00Z", + "2023-07-03T17:05:00Z", + "2023-07-03T17:10:00Z", + "2023-07-03T17:15:00Z", + "2023-07-03T17:20:00Z", + "2023-07-03T17:25:00Z", + "2023-07-03T17:30:00Z", + "2023-07-03T17:35:00Z", + "2023-07-03T17:40:00Z", + "2023-07-03T17:45:00Z", + "2023-07-03T17:50:00Z", + "2023-07-03T17:55:00Z", + "2023-07-03T18:00:00Z", + "2023-07-03T18:05:00Z", + "2023-07-03T18:10:00Z", + "2023-07-03T18:15:00Z", + "2023-07-03T18:20:00Z", + "2023-07-03T18:25:00Z", + "2023-07-03T18:30:00Z", + "2023-07-03T18:35:00Z", + "2023-07-03T18:40:00Z", + "2023-07-03T18:45:00Z", + "2023-07-03T18:50:00Z", + "2023-07-03T18:55:00Z", + "2023-07-03T19:00:00Z", + "2023-07-03T19:05:00Z", + "2023-07-03T19:10:00Z", + "2023-07-03T19:15:00Z", + "2023-07-03T19:20:00Z", + "2023-07-03T19:25:00Z", + "2023-07-03T19:30:00Z", + "2023-07-03T19:35:00Z", + "2023-07-03T19:40:00Z", + "2023-07-03T19:45:00Z", + "2023-07-03T19:50:00Z", + "2023-07-03T19:55:00Z", + "2023-07-03T20:00:00Z", + "2023-07-03T20:05:00Z", + "2023-07-03T20:10:00Z", + "2023-07-03T20:15:00Z", + "2023-07-03T20:20:00Z", + "2023-07-03T20:25:00Z", + "2023-07-03T20:30:00Z", + "2023-07-03T20:35:00Z", + "2023-07-03T20:40:00Z", + "2023-07-03T20:45:00Z", + "2023-07-03T20:50:00Z", + "2023-07-03T20:55:00Z", + "2023-07-03T21:00:00Z", + "2023-07-03T21:05:00Z", + "2023-07-03T21:10:00Z", + "2023-07-03T21:15:00Z", + "2023-07-03T21:20:00Z", + "2023-07-03T21:25:00Z", + "2023-07-03T21:30:00Z", + "2023-07-03T21:35:00Z", + "2023-07-03T21:40:00Z", + "2023-07-03T21:45:00Z", + "2023-07-03T21:50:00Z", + "2023-07-03T21:55:00Z", + ], + }), + }); + + /** + * up to 164 datapoints(1 hour values) from a {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues} + * */ + export const WEEK: OeTester.Types.Channels = ({ + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: {}, + }), + dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { + data: { + "ctrlApiModbusTcp0/Ess0SetActivePowerEquals": [ + 112, + 262, + 392, + 240, + 230, + 229, + 227, + 317, + 224, + 133, + 135, + 133, + 192, + 209, + 90, + 95, + 96, + 164, + 297, + 184, + 182, + 183, + 198, + 333, + 183, + 93, + 97, + 98, + 197, + 266, + 177, + ], + }, + timestamps: [ + "2023-07-01T00:00:00Z", + "2023-07-02T00:00:00Z", + "2023-07-03T00:00:00Z", + "2023-07-04T00:00:00Z", + "2023-07-05T00:00:00Z", + "2023-07-06T00:00:00Z", + "2023-07-07T00:00:00Z", + "2023-07-08T00:00:00Z", + "2023-07-09T00:00:00Z", + "2023-07-10T00:00:00Z", + "2023-07-11T00:00:00Z", + "2023-07-12T00:00:00Z", + "2023-07-13T00:00:00Z", + "2023-07-14T00:00:00Z", + "2023-07-15T00:00:00Z", + "2023-07-16T00:00:00Z", + "2023-07-17T00:00:00Z", + "2023-07-18T00:00:00Z", + "2023-07-19T00:00:00Z", + "2023-07-20T00:00:00Z", + "2023-07-21T00:00:00Z", + "2023-07-22T00:00:00Z", + "2023-07-23T00:00:00Z", + "2023-07-24T00:00:00Z", + "2023-07-25T00:00:00Z", + "2023-07-26T00:00:00Z", + "2023-07-27T00:00:00Z", + "2023-07-28T00:00:00Z", + "2023-07-29T00:00:00Z", + "2023-07-30T00:00:00Z", + "2023-07-31T00:00:00Z", + ], + }), + }); + + + /** + * up to 31 datapoints(1 day values) from a {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues}*/ + export const MONTH: OeTester.Types.Channels = { + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: { + "_sum/GridBuyActiveEnergy": 773000, + "_sum/ConsumptionActiveEnergy": 9976102, + "_sum/EssDcChargeEnergy": 3944328, + "_sum/EssDcDischargeEnergy": 3394430, + "_sum/GridSellActiveEnergy": 12738000, + "_sum/ProductionActiveEnergy": 22491000, + }, + }), + energyPerPeriodChannelWithValues: + new QueryHistoricTimeseriesEnergyPerPeriodResponse("0", { + data: { + "_sum/ConsumptionActiveEnergy": [320342, + 346615, + 341433, + 333054, + 358458, + 347872, + 289283, + null, + 556510, + 311366, + 314722, + 355556, + 381671, + 384558, + 366190, + 349336, + 303696, + 288727, + 357434, + 388659, + 402625, + null, + 713771, + 320238, + 332099, + null, + 756429, + 384136, + 371322, + null], + "_sum/EssDcChargeEnergy": [ + 113476, + 162917, + 150189, + 157158, + 149782, + 159833, + 155084, + null, + 228757, + 128138, + 157539, + 59414, + 156504, + 107339, + 156392, + 158925, + 158578, + 121505, + 120971, + 154566, + 173235, + null, + 204273, + 156676, + 143745, + null, + 247673, + 157410, + 104249, + null, + ], + "_sum/EssDcDischargeEnergy": [ + 112818, + 126532, + 139622, + 133212, + 169240, + 98705, + 109367, + null, + 204267, + 118504, + 121261, + 74970, + 144175, + 89897, + 141582, + 111261, + 122274, + 106232, + 139405, + 132225, + 143860, + null, + 235044, + 63914, + 123844, + null, + 242102, + 130546, + 59571, + null, + ], + "_sum/GridBuyActiveEnergy": [ + 16000, + 6000, + 3000, + 3000, + 5000, + 48000, + 4000, + null, + 5000, + 26000, + 17000, + 62000, + 8000, + 66000, + 13000, + 21000, + 4000, + 3000, + 18000, + 27000, + 29000, + null, + 118000, + 85000, + 2000, + null, + 72000, + 28000, + 84000, + null, + ], + "_sum/GridSellActiveEnergy": [ + 603000, + 590000, + 551000, + 572000, + 69000, + 236000, + 626000, + null, + 1003000, + 261000, + 518000, + 698000, + 640000, + 388000, + 471000, + 373000, + 373000, + 677000, + 286000, + 406000, + 249000, + null, + 446000, + 369000, + 558000, + null, + 776000, + 425000, + 574000, + null, + ], + "_sum/ProductionActiveEnergy": [ + 908000, + 967000, + 900000, + 926000, + 403000, + 597000, + 957000, + null, + 1579000, + 556000, + 852000, + 976000, + 1026000, + 724000, + 839000, + 749000, + 709000, + 978000, + 607000, + 790000, + 652000, + null, + 1011000, + 697000, + 908000, + null, + 1466000, + 808000, + 906000, + null, + ], + }, + timestamps: [ + "2023-05-31T22:00:00Z", + "2023-06-01T22:00:00Z", + "2023-06-02T22:00:00Z", + "2023-06-03T22:00:00Z", + "2023-06-04T22:00:00Z", + "2023-06-05T22:00:00Z", + "2023-06-06T22:00:00Z", + "2023-06-07T22:00:00Z", + "2023-06-08T22:00:00Z", + "2023-06-09T22:00:00Z", + "2023-06-10T22:00:00Z", + "2023-06-11T22:00:00Z", + "2023-06-12T22:00:00Z", + "2023-06-13T22:00:00Z", + "2023-06-14T22:00:00Z", + "2023-06-15T22:00:00Z", + "2023-06-16T22:00:00Z", + "2023-06-17T22:00:00Z", + "2023-06-18T22:00:00Z", + "2023-06-19T22:00:00Z", + "2023-06-20T22:00:00Z", + "2023-06-21T22:00:00Z", + "2023-06-22T22:00:00Z", + "2023-06-23T22:00:00Z", + "2023-06-24T22:00:00Z", + "2023-06-25T22:00:00Z", + "2023-06-26T22:00:00Z", + "2023-06-27T22:00:00Z", + "2023-06-28T22:00:00Z", + "2023-06-29T22:00:00Z", + ], + }), + }; + + /** + * up to 12 datapoints(1 month values) from a {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues}*/ + export const YEAR: OeTester.Types.Channels = { + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: { + "_sum/GridBuyActiveEnergy": 23209000, + "_sum/ConsumptionActiveEnergy": 58573394, + "_sum/EssDcChargeEnergy": 15296815, + "_sum/EssDcDischargeEnergy": 12898209, + "_sum/GridSellActiveEnergy": 30703000, + "_sum/ProductionActiveEnergy": 68466000, + }, + }), + energyPerPeriodChannelWithValues: + new QueryHistoricTimeseriesEnergyPerPeriodResponse("0", { + data: { + "_sum/ConsumptionActiveEnergy": [11634885, + 8207927, + 8976354, + 8311835, + 10341804, + 9976102, + 975807, + null, + null, + null, + null, + null], + "_sum/EssDcChargeEnergy": [ + 294606, + 1673109, + 3337772, + 3074303, + 2495947, + 3944328, + 372595, + null, + null, + null, + null, + null, + ], + "_sum/EssDcDischargeEnergy": [ + 208491, + 1339036, + 2911126, + 2555138, + 2123751, + 3394430, + 335402, + null, + null, + null, + null, + null, + ], + "_sum/GridBuyActiveEnergy": [9829000, + 4812000, + 2915000, + 2036000, + 2712000, + 773000, + 94000, + null, + null, + null, + null, + null], + "_sum/GridSellActiveEnergy": [20000, + 86000, + 677000, + 3657000, + 12839000, + 12738000, + 627000, + null, + null, + null, + null, + null], + "_sum/ProductionActiveEnergy": [1912000, + 3816000, + 7165000, + 10452000, + 20841000, + 22491000, + 1546000, + null, + null, + null, + null, + null], + }, + timestamps: [ + "2022-12-31T23:00:00Z", + "2023-01-31T23:00:00Z", + "2023-02-28T23:00:00Z", + "2023-03-31T22:00:00Z", + "2023-04-30T22:00:00Z", + "2023-05-31T22:00:00Z", + "2023-06-30T22:00:00Z", + "2023-07-31T22:00:00Z", + "2023-08-31T22:00:00Z", + "2023-09-30T22:00:00Z", + "2023-10-31T23:00:00Z", + "2023-11-30T23:00:00Z", + ], + }), + }; +} diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/chart.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/chart.ts new file mode 100644 index 0000000000..987109ea76 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/chart/chart.ts @@ -0,0 +1,89 @@ +// @ts-strict-ignore +import { Component } from "@angular/core"; +import { TranslateService } from "@ngx-translate/core"; +import { AbstractHistoryChart } from "src/app/shared/components/chart/abstracthistorychart"; +import { ChartAxis, HistoryUtils, YAxisType } from "src/app/shared/service/utils"; +import { ChannelAddress, EdgeConfig } from "src/app/shared/shared"; + +@Component({ + selector: "modbusTcpApiChart", + templateUrl: "../../../../../shared/components/chart/abstracthistorychart.html", +}) +export class ChartComponent extends AbstractHistoryChart { + + public static getChartData(component: EdgeConfig.Component, config: EdgeConfig, chartType: "line" | "bar", translate: TranslateService, showPhases: boolean): HistoryUtils.ChartData { + let writeChannels: string[] = []; + + const colors: string[] = [ + "rgb(191, 144, 33)", + "rgb(162, 191, 33)", + "rgb(86, 191, 33)", + "rgb(33, 191, 165)", + "rgb(33, 115, 191)", + ]; + + const input: HistoryUtils.InputChannel[] = + [{ + name: "SetActivePowerEquals", + powerChannel: ChannelAddress.fromString(component.id + "/Ess0SetActivePowerEquals"), + }]; + + if (component.properties.writeChannels) { + writeChannels = component.properties.writeChannels.filter(c => !c.includes("Ess0SetActivePowerEquals")); + writeChannels.forEach(c => { + input.push({ + name: c, + powerChannel: ChannelAddress.fromString(component.id + `/${c}`), + }); + }); + } + + return { + input, + output: (data: HistoryUtils.ChannelData) => { + const values: HistoryUtils.DisplayValue[] = [{ + name: translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_EQUALS"), + converter: () => data["SetActivePowerEquals"], + color: "rgb(214, 28, 28)", + }]; + if (writeChannels) { + writeChannels.forEach((c: string, index: number) => { + const name: string = c; + // Add translations for active power channels of ess0 + if (c.includes("Ess0SetActive")) { + const channelName = c.replace("Ess0", ""); + switch (channelName) { + case "SetActivePowerEquals": + return translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_EQUALS"); + case "SetActivePowerGreaterOrEquals": + return translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_GREATER_OR_EQUALS"); + case "SetActivePowerLessOrEquals": + return translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_LESS_OR_EQUALS"); + } + } + + values.push({ + name: name, + converter: () => data[c], + color: colors[index], + }); + }); + } + return values; + }, + tooltip: { + formatNumber: "1.1-2", + }, + yAxes: [{ + unit: YAxisType.ENERGY, + position: "left", + yAxisId: ChartAxis.LEFT, + }, + ], + }; + } + + public override getChartData() { + return ChartComponent.getChartData(this.component, this.config, this.chartType, this.translate, this.showPhases); + } +} diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.html b/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.html new file mode 100644 index 0000000000..e7a0c6ad6a --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.html @@ -0,0 +1,5 @@ + + + + diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.ts new file mode 100644 index 0000000000..9a857c7182 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/flat/flat.ts @@ -0,0 +1,21 @@ +import { Component } from "@angular/core"; + +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress } from "src/app/shared/shared"; + +@Component({ + selector: "modbusTcpApiWidget", + templateUrl: "./flat.html", +}) +export class FlatComponent extends AbstractFlatWidget { + + protected TIME_CONVERTER = this.Converter.FORMAT_SECONDS_TO_DURATION("de"); + + protected override getChannelAddresses(): ChannelAddress[] { + + return [ + new ChannelAddress(this.component.id, "CumulatedInactiveTime"), + new ChannelAddress(this.component.id, "CumulatedActiveTime"), + ]; + } +} diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts new file mode 100644 index 0000000000..aef372d5a3 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/modbusTcpApi.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { SharedModule } from "src/app/shared/shared.module"; +import { FlatComponent } from "./flat/flat"; +import { OverviewComponent } from "./overview/overview"; +import { ChartComponent } from "./chart/chart"; + +@NgModule({ + imports: [ + BrowserModule, + SharedModule, + ], + declarations: [ + FlatComponent, + OverviewComponent, + ChartComponent, + ], + exports: [ + FlatComponent, + OverviewComponent, + ChartComponent, + ], +}) +export class ModbusTcpApi { } diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.html b/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.html new file mode 100644 index 0000000000..c08da36f60 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.html @@ -0,0 +1,23 @@ + + +
    + + + + + + + Edge.Index.Widgets.InfoStorageForCharge + + + + + Edge.Index.Widgets.InfoStorageForDischarge + + + + + +
    +
    +
    diff --git a/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.ts b/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.ts new file mode 100644 index 0000000000..51ed8f95a6 --- /dev/null +++ b/ui/src/app/edge/history/Controller/ModbusTcpApi/overview/overview.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; +import { AbstractHistoryChartOverview } from "src/app/shared/components/chart/abstractHistoryChartOverview"; + +@Component({ + templateUrl: "./overview.html", +}) +export class OverviewComponent extends AbstractHistoryChartOverview { } diff --git a/ui/src/app/edge/history/Controller/controller.module.ts b/ui/src/app/edge/history/Controller/controller.module.ts index dec242649f..e009e41d83 100644 --- a/ui/src/app/edge/history/Controller/controller.module.ts +++ b/ui/src/app/edge/history/Controller/controller.module.ts @@ -4,6 +4,7 @@ import { ControllerIo } from "./Io/Io.module"; import { ChannelThreshold } from "./ChannelThreshold/channelThreshold.module"; import { GridOptimizeCharge } from "./Ess/GridoptimizedCharge/gridOptimizeCharge.module"; import { TimeOfUseTariff } from "./Ess/TimeOfUseTariff/timeOfUseTariff.module"; +import { ModbusTcpApi } from "./ModbusTcpApi/modbusTcpApi.module"; @NgModule({ imports: [ @@ -11,6 +12,7 @@ import { TimeOfUseTariff } from "./Ess/TimeOfUseTariff/timeOfUseTariff.module"; ControllerIo, ChannelThreshold, TimeOfUseTariff, + ModbusTcpApi, GridOptimizeCharge, ], exports: [ @@ -18,6 +20,7 @@ import { TimeOfUseTariff } from "./Ess/TimeOfUseTariff/timeOfUseTariff.module"; ControllerIo, ChannelThreshold, TimeOfUseTariff, + ModbusTcpApi, GridOptimizeCharge, ], }) diff --git a/ui/src/app/edge/history/history.component.html b/ui/src/app/edge/history/history.component.html index 8774f678d1..bd86a09bf0 100644 --- a/ui/src/app/edge/history/history.component.html +++ b/ui/src/app/edge/history/history.component.html @@ -38,6 +38,10 @@ + + + + @@ -72,6 +76,13 @@ + + + + + + + diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index 1e3672ca49..e2349530d0 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -5,7 +5,7 @@ import { TranslateService } from "@ngx-translate/core"; import { AppService } from "src/app/app.service"; import { HeaderComponent } from "src/app/shared/components/header/header.component"; import { JsonrpcResponseError } from "src/app/shared/jsonrpc/base"; -import { Edge, EdgeConfig, Service, Widgets } from "src/app/shared/shared"; +import { Edge, EdgeConfig, EdgePermission, Service, Widgets } from "src/app/shared/shared"; import { environment } from "src/environments"; @Component({ @@ -34,6 +34,7 @@ export class HistoryComponent implements OnInit { public config: EdgeConfig | null = null; protected errorResponse: JsonrpcResponseError | null = null; + protected isModbusTcpWidgetAllowed: boolean = false; constructor( public service: Service, @@ -44,6 +45,7 @@ export class HistoryComponent implements OnInit { ngOnInit() { this.service.currentEdge.subscribe((edge) => { this.edge = edge; + this.isModbusTcpWidgetAllowed = EdgePermission.isModbusTcpApiWidgetAllowed(edge); }); this.service.getConfig().then(config => { // gather ControllerIds of Channelthreshold Components diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.html b/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.html new file mode 100644 index 0000000000..9df8ac9fb0 --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.html @@ -0,0 +1,3 @@ + + + diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.ts b/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.ts new file mode 100644 index 0000000000..89b23b8675 --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/flat/flat.ts @@ -0,0 +1,51 @@ +import { Component } from "@angular/core"; +import { AbstractFlatWidget } from "src/app/shared/components/flat/abstract-flat-widget"; +import { ChannelAddress, CurrentData } from "src/app/shared/shared"; +import { OverrideStatus } from "src/app/shared/type/general"; +import { ModalComponent } from "../modal/modal"; + +@Component({ + selector: "Controller_Api_ModbusTcp", + templateUrl: "./flat.html", +}) +export class FlatComponent extends AbstractFlatWidget { + + protected overrideStatus: OverrideStatus | null = null; + + async presentModal() { + if (!this.isInitialized) { + return; + } + const modal = await this.modalController.create({ + component: ModalComponent, + componentProps: { + component: this.component, + }, + }); + return await modal.present(); + } + + + protected override getChannelAddresses(): ChannelAddress[] { + + return [ + new ChannelAddress(this.component.id, "OverrideStatus"), + ]; + } + + protected override onCurrentData(currentData: CurrentData) { + this.overrideStatus = this.getTranslatedState(currentData.allComponents[this.component.id + "/OverrideStatus"]); + } + + private getTranslatedState(state: OverrideStatus) { + switch (state) { + case OverrideStatus.ACTIVE: + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.OVERRIDING"); + case OverrideStatus.ERROR: + return this.translate.instant("EVCS.error"); + default: + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.NOT_OVERRIDING"); + } + } + +} diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.html b/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.html new file mode 100644 index 0000000000..b8468f2295 --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + +
    + +
    + +
    + +
    + {{ 'MODBUS_TCP_API_READ_WRITE.DOWNLOAD_PROTOCOL' | translate }} +
    + +
    diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.ts b/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.ts new file mode 100644 index 0000000000..ae11a7a121 --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/modal/modal.ts @@ -0,0 +1,102 @@ +// @ts-strict-ignore +import { Component } from "@angular/core"; +import { ProfileComponent } from "src/app/edge/settings/profile/profile.component"; +import { AbstractModal } from "src/app/shared/components/modal/abstractModal"; +import { Converter } from "src/app/shared/components/shared/converter"; +import { ChannelAddress, ChannelRegister, CurrentData } from "src/app/shared/shared"; +import { OverrideStatus } from "src/app/shared/type/general"; + +@Component({ + templateUrl: "./modal.html", +}) +export class ModalComponent extends AbstractModal { + + protected readonly CONVERT_TO_WATT = Converter.POWER_IN_WATT; + + protected writeChannelValues: number[] | null = []; + protected writeChannels: ChannelAddress[] | null = []; + protected overrideStatus: string | null = null; + protected formattedWriteChannels: string[] | null = null; + + protected activePowerEqualsChannel: ChannelAddress | null = null; + protected activePowerEqualsValue: number | null = null; + protected channelRegisters = ChannelRegister; + + private profile = new ProfileComponent(this.service, this.route, null, this.translate); + + protected override getChannelAddresses(): ChannelAddress[] { + this.activePowerEqualsChannel = new ChannelAddress(this.component.id, "Ess0SetActivePowerEquals"); + const writeChannelIds = this.config.components[this.component.id]?.properties.writeChannels || []; + this.writeChannels = writeChannelIds.map(channelId => new ChannelAddress(this.component.id, channelId)); + return [ + ...this.writeChannels, + this.activePowerEqualsChannel, + new ChannelAddress(this.component.id, "OverrideStatus"), + ]; + } + + protected override onIsInitialized(): void { + this.edge.getConfig(this.websocket).subscribe((config) => { + const newChannels = (config.components[this.component.id]?.properties?.writeChannels || []) + .map(channelId => new ChannelAddress(this.component.id, channelId)); + + this.writeChannels = newChannels.filter(channel => !channel.channelId.includes("Ess0SetActivePowerEquals")); + this.getFormatChannelNames(); + this.edge.subscribeChannels(this.websocket, this.component.id, this.writeChannels); + }); + } + + protected getModbusProtocol(componentId: string) { + return this.profile.getModbusProtocol(componentId); + } + + protected override onCurrentData(currentData: CurrentData) { + this.activePowerEqualsValue = this.edge.currentData.value.channel[this.activePowerEqualsChannel!.toString()]; + this.writeChannelValues = this.writeChannels?.map(channel => + this.edge.currentData.value.channel[channel.toString()], + ) || []; + this.overrideStatus = this.getTranslatedState(currentData.allComponents[this.component.id + "/OverrideStatus"]); + } + + protected getTranslatedChannel(channel: ChannelAddress): string { + if (channel.channelId.includes("Ess0SetActive")) { + const channelName = channel.channelId.replace("Ess0", ""); + switch (channelName) { + case "SetActivePowerEquals": + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_EQUALS"); + case "SetActivePowerGreaterOrEquals": + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_GREATER_OR_EQUALS"); + case "SetActivePowerLessOrEquals": + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.SET_ACTIVE_POWER_LESS_OR_EQUALS"); + } + } + } + + private getTranslatedState(state: OverrideStatus) { + switch (state) { + case OverrideStatus.ACTIVE: + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.OVERRIDING"); + case OverrideStatus.ERROR: + return this.translate.instant("EVCS.error"); + default: + return this.translate.instant("MODBUS_TCP_API_READ_WRITE.NOT_OVERRIDING"); + } + } + + /** + * This method adds the name and register number of the corresponding channel to + * the modal view. It has to be done dynamically since channels can be overwritten in any order. + */ + private getFormatChannelNames(): void { + this.formattedWriteChannels = []; + this.writeChannels.forEach(channel => { + for (const registerName in ChannelRegister) { + if (channel.channelId.includes(registerName)) { + // If channelId is included in ChannelRegister, get key/value e.g. SetActivePowerEquals/706 + const formattedString = `(${registerName}/${ChannelRegister[registerName]})`; + this.formattedWriteChannels.push(formattedString); + } + } + }); + } +} diff --git a/ui/src/app/edge/live/Controller/ModbusTcpApi/modbusTcpApi.module.ts b/ui/src/app/edge/live/Controller/ModbusTcpApi/modbusTcpApi.module.ts new file mode 100644 index 0000000000..69104d3973 --- /dev/null +++ b/ui/src/app/edge/live/Controller/ModbusTcpApi/modbusTcpApi.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { SharedModule } from "src/app/shared/shared.module"; +import { FlatComponent } from "./flat/flat"; +import { ModalComponent } from "./modal/modal"; + +@NgModule({ + imports: [ + BrowserModule, + SharedModule, + ], + declarations: [ + FlatComponent, + ModalComponent, + ], + exports: [ + FlatComponent, + ], +}) +export class Controller_Api_ModbusTcp { } diff --git a/ui/src/app/edge/live/live.component.html b/ui/src/app/edge/live/live.component.html index edf538ba7a..88a68dd277 100644 --- a/ui/src/app/edge/live/live.component.html +++ b/ui/src/app/edge/live/live.component.html @@ -81,6 +81,13 @@
    + + + + + + diff --git a/ui/src/app/edge/live/live.component.ts b/ui/src/app/edge/live/live.component.ts index e3e022542c..335b7d1fa6 100644 --- a/ui/src/app/edge/live/live.component.ts +++ b/ui/src/app/edge/live/live.component.ts @@ -3,7 +3,7 @@ import { ActivatedRoute } from "@angular/router"; import { RefresherCustomEvent } from "@ionic/angular"; import { Subject } from "rxjs"; import { DataService } from "src/app/shared/components/shared/dataservice"; -import { Edge, EdgeConfig, Service, Utils, Websocket, Widgets } from "src/app/shared/shared"; +import { Edge, EdgeConfig, EdgePermission, Service, Utils, Websocket, Widgets } from "src/app/shared/shared"; @Component({ selector: "live", @@ -14,6 +14,7 @@ export class LiveComponent implements OnInit, OnDestroy { public edge: Edge | null = null; public config: EdgeConfig | null = null; public widgets: Widgets | null = null; + protected isModbusTcpWidgetAllowed: boolean = false; private stopOnDestroy: Subject = new Subject(); constructor( @@ -27,6 +28,7 @@ export class LiveComponent implements OnInit, OnDestroy { public ngOnInit() { this.service.currentEdge.subscribe((edge) => { this.edge = edge; + this.isModbusTcpWidgetAllowed = EdgePermission.isModbusTcpApiWidgetAllowed(edge); }); this.service.getConfig().then(config => { this.config = config; diff --git a/ui/src/app/edge/live/live.module.ts b/ui/src/app/edge/live/live.module.ts index e3d7bbc0de..944e2240b0 100644 --- a/ui/src/app/edge/live/live.module.ts +++ b/ui/src/app/edge/live/live.module.ts @@ -2,21 +2,14 @@ import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { SharedModule } from "./../../shared/shared.module"; -import { Common_Autarchy } from "./common/autarchy/Common_Autarchy"; -import { Common_Consumption } from "./common/consumption/Common_Consumption"; -import { Common_Grid } from "./common/grid/Common_Grid"; -import { Common_Production } from "./common/production/Common_Production"; -import { Common_Selfconsumption } from "./common/selfconsumption/Common_Selfconsumption"; -import { StorageModalComponent } from "./common/storage/modal/modal.component"; -import { StorageComponent } from "./common/storage/storage.component"; import { Controller_ChannelthresholdComponent } from "./Controller/Channelthreshold/Channelthreshold"; import { Controller_ChpSocComponent } from "./Controller/ChpSoc/ChpSoc"; import { Controller_ChpSocModalComponent } from "./Controller/ChpSoc/modal/modal.component"; import { Controller_Ess_FixActivePower } from "./Controller/Ess/FixActivePower/Ess_FixActivePower"; import { Controller_Ess_GridOptimizedCharge } from "./Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge"; import { Controller_Ess_TimeOfUseTariff } from "./Controller/Ess/TimeOfUseTariff/Ess_TimeOfUseTariff"; -import { AdministrationComponent } from "./Controller/Evcs/administration/administration.component"; import { Controller_Evcs } from "./Controller/Evcs/Evcs"; +import { AdministrationComponent } from "./Controller/Evcs/administration/administration.component"; import { Controller_Io_ChannelSingleThresholdComponent } from "./Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold"; import { Controller_Io_ChannelSingleThresholdModalComponent } from "./Controller/Io/ChannelSingleThreshold/modal/modal.component"; import { Controller_Io_FixDigitalOutputComponent } from "./Controller/Io/FixDigitalOutput/Io_FixDigitalOutput"; @@ -24,22 +17,30 @@ import { Controller_Io_FixDigitalOutputModalComponent } from "./Controller/Io/Fi import { Controller_Io_HeatingElement } from "./Controller/Io/HeatingElement/Io_HeatingElement"; import { Controller_Io_HeatpumpComponent } from "./Controller/Io/Heatpump/Io_Heatpump"; import { Controller_Io_HeatpumpModalComponent } from "./Controller/Io/Heatpump/modal/modal.component"; +import { Controller_Api_ModbusTcp } from "./Controller/ModbusTcpApi/modbusTcpApi.module"; import { Controller_Asymmetric_PeakShavingComponent } from "./Controller/PeakShaving/Asymmetric/Asymmetric"; import { Controller_Asymmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Asymmetric/modal/modal.component"; -import { Controller_Symmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric/modal/modal.component"; import { Controller_Symmetric_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric/Symmetric"; -import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component"; +import { Controller_Symmetric_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric/modal/modal.component"; import { Controller_Symmetric_TimeSlot_PeakShavingComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot"; -import { DelayedSellToGridComponent } from "./delayedselltogrid/delayedselltogrid.component"; -import { DelayedSellToGridModalComponent } from "./delayedselltogrid/modal/modal.component"; -import { EnergymonitorModule } from "./energymonitor/energymonitor.module"; -import { InfoComponent } from "./info/info.component"; +import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from "./Controller/PeakShaving/Symmetric_TimeSlot/modal/modal.component"; import { Io_Api_DigitalInputComponent } from "./Io/Api_DigitalInput/Io_Api_DigitalInput"; import { Io_Api_DigitalInput_ModalComponent } from "./Io/Api_DigitalInput/modal/modal.component"; -import { LiveComponent } from "./live.component"; import { Evcs_Api_ClusterComponent } from "./Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster"; import { EvcsChartComponent } from "./Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart"; import { Evcs_Api_ClusterModalComponent } from "./Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page"; +import { Common_Autarchy } from "./common/autarchy/Common_Autarchy"; +import { Common_Consumption } from "./common/consumption/Common_Consumption"; +import { Common_Grid } from "./common/grid/Common_Grid"; +import { Common_Production } from "./common/production/Common_Production"; +import { Common_Selfconsumption } from "./common/selfconsumption/Common_Selfconsumption"; +import { StorageModalComponent } from "./common/storage/modal/modal.component"; +import { StorageComponent } from "./common/storage/storage.component"; +import { DelayedSellToGridComponent } from "./delayedselltogrid/delayedselltogrid.component"; +import { DelayedSellToGridModalComponent } from "./delayedselltogrid/modal/modal.component"; +import { EnergymonitorModule } from "./energymonitor/energymonitor.module"; +import { InfoComponent } from "./info/info.component"; +import { LiveComponent } from "./live.component"; import { OfflineComponent } from "./offline/offline.component"; @NgModule({ @@ -56,6 +57,7 @@ import { OfflineComponent } from "./offline/offline.component"; Controller_Ess_FixActivePower, Controller_Ess_GridOptimizedCharge, Controller_Io_HeatingElement, + Controller_Api_ModbusTcp, EnergymonitorModule, SharedModule, Controller_Evcs, diff --git a/ui/src/app/index/login.component.ts b/ui/src/app/index/login.component.ts index 146cbd3216..4fa20f9aef 100644 --- a/ui/src/app/index/login.component.ts +++ b/ui/src/app/index/login.component.ts @@ -8,6 +8,7 @@ import { environment } from "src/environments"; import { Capacitor } from "@capacitor/core"; import { AppService } from "../app.service"; import { AuthenticateWithPasswordRequest } from "../shared/jsonrpc/request/authenticateWithPasswordRequest"; +import { States } from "../shared/ngrx-store/states"; import { Edge, Service, Utils, Websocket } from "../shared/shared"; @Component({ @@ -93,6 +94,7 @@ export class LoginComponent implements OnInit, AfterContentChecked, OnDestroy { */ public doLogin(param: { username?: string, password: string }) { + this.websocket.state.set(States.AUTHENTICATION_WITH_CREDENTIALS); param = LoginComponent.trimCredentials(param.password, param.username); // Prevent that user submits via keyevent 'enter' multiple times diff --git a/ui/src/app/index/shared/loading-screen.html b/ui/src/app/index/shared/loading-screen.html index 2001205da6..481d177388 100644 --- a/ui/src/app/index/shared/loading-screen.html +++ b/ui/src/app/index/shared/loading-screen.html @@ -1,5 +1,63 @@ - -

    Loading...

    -
    + + + +

    + LOADING_SCREEN.LOADING + + ... +

    +
    + + + +
    + + + + + + + + + + + +
    + +
    +
    + + + + + + + LOADING_SCREEN.SERVER_NOT_ACCESSIBLE + + + + + + + + LOADING_SCREEN.SERVER_NOT_ACCESSIBLE_DESCRIPTION + + + + + + + + + + LOADING_SCREEN.SERVER_NOT_ACCESSIBLE_TRY_RELOADING + + + + + + diff --git a/ui/src/app/index/shared/loading-screen.ts b/ui/src/app/index/shared/loading-screen.ts index 14d5d7b43a..05322949c5 100644 --- a/ui/src/app/index/shared/loading-screen.ts +++ b/ui/src/app/index/shared/loading-screen.ts @@ -1,38 +1,41 @@ // @ts-strict-ignore -import { Component, OnInit } from "@angular/core"; +import { Component, effect } from "@angular/core"; import { Router } from "@angular/router"; +import { AppStateTracker } from "src/app/shared/ngrx-store/states"; +import { Environment, environment } from "src/environments"; import { Service, Websocket } from "../../shared/shared"; @Component({ selector: "index", templateUrl: "./loading-screen.html", }) -export class LoadingScreenComponent implements OnInit { +export class LoadingScreenComponent { protected readonly spinnerId: string = "IndexComponent"; + protected readonly environment: Environment = environment; + protected backendState: "loading" | "failed" | "authenticated" = "loading"; constructor( public service: Service, public websocket: Websocket, private router: Router, - ) { } + private appStateTracker: AppStateTracker, + ) { - ngOnInit() { - - // TODO add websocket status observable - const interval = setInterval(() => { - this.service.startSpinner(this.spinnerId); - if (this.websocket.status === "online") { - this.service.stopSpinner(this.spinnerId); - this.router.navigate(["/overview"]); - clearInterval(interval); - } - if (this.websocket.status === "waiting for credentials") { - this.service.stopSpinner(this.spinnerId); - this.router.navigate(["/login"]); - clearInterval(interval); + effect(() => { + this.backendState = this.appStateTracker.loadingState(); + switch (this.backendState) { + case "loading": + this.service.startSpinner(this.spinnerId); + break; + case "failed": + this.service.stopSpinner(this.spinnerId); + break; + case "authenticated": + this.appStateTracker.navigateAfterAuthentication(); + break; } - }, 1000); + }); } } diff --git a/ui/src/app/shared/components/chart/abstracthistorychart.html b/ui/src/app/shared/components/chart/abstracthistorychart.html index 0c1225b56f..a727e42f4d 100644 --- a/ui/src/app/shared/components/chart/abstracthistorychart.html +++ b/ui/src/app/shared/components/chart/abstracthistorychart.html @@ -11,3 +11,5 @@ [type]="chartType">
    + + diff --git a/ui/src/app/shared/components/chart/abstracthistorychart.ts b/ui/src/app/shared/components/chart/abstracthistorychart.ts index 97d491dc2f..b30e69af4b 100644 --- a/ui/src/app/shared/components/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/components/chart/abstracthistorychart.ts @@ -5,7 +5,7 @@ import { ActivatedRoute } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import * as Chart from "chart.js"; import annotationPlugin from "chartjs-plugin-annotation"; -import { calculateResolution, ChronoUnit, DEFAULT_NUMBER_CHART_OPTIONS, DEFAULT_TIME_CHART_OPTIONS, isLabelVisible, Resolution, setLabelVisible } from "src/app/edge/history/shared"; +import { ChronoUnit, DEFAULT_NUMBER_CHART_OPTIONS, DEFAULT_TIME_CHART_OPTIONS, Resolution, calculateResolution, isLabelVisible, setLabelVisible } from "src/app/edge/history/shared"; import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse"; import { DefaultTypes } from "src/app/shared/service/defaulttypes"; import { v4 as uuidv4 } from "uuid"; @@ -311,6 +311,8 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { return translate.instant("Edge.Index.Widgets.Channeltreshold.ACTIVE_TIME_OVER_PERIOD"); case YAxisType.PERCENTAGE: return translate.instant("General.percentage"); + case YAxisType.REACTIVE: + return "var"; case YAxisType.ENERGY: if (chartType == "bar") { return "kWh"; @@ -556,6 +558,7 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { break; case YAxisType.POWER: case YAxisType.ENERGY: + case YAxisType.REACTIVE: case YAxisType.VOLTAGE: case YAxisType.CURRENT: case YAxisType.NONE: @@ -645,6 +648,9 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { tooltipsLabel = "kW"; } break; + case YAxisType.REACTIVE: + tooltipsLabel = "var"; + break; default: tooltipsLabel = ""; break; @@ -724,6 +730,8 @@ export abstract class AbstractHistoryChart implements OnInit, OnDestroy { return "V"; case YAxisType.CURRENT: return "A"; + case YAxisType.REACTIVE: + return "var"; case YAxisType.ENERGY: if (chartType == "bar") { return "kWh"; diff --git a/ui/src/app/shared/components/edge/edgeconfig.spec.ts b/ui/src/app/shared/components/edge/edgeconfig.spec.ts index 8921e4235d..ec7d23d4a2 100644 --- a/ui/src/app/shared/components/edge/edgeconfig.spec.ts +++ b/ui/src/app/shared/components/edge/edgeconfig.spec.ts @@ -172,6 +172,18 @@ export namespace DummyConfig { "io.openems.edge.evcs.api.Evcs", ], }; + + export const MODBUS_TCP_READWRITE = { + id: "Controller.Api.ModbusTcp.ReadWrite", + natureIds: [ + "io.openems.edge.common.jsonapi.JsonApi", + "io.openems.edge.common.component.OpenemsComponent", + "io.openems.edge.controller.api.modbus.ModbusTcpApi", + "io.openems.edge.controller.api.modbus.readwrite.ControllerApiModbusTcpReadWrite", + "io.openems.edge.controller.api.Controller", + "io.openems.edge.timedata.api.TimedataProvider", + ], + }; } export namespace Component { @@ -295,6 +307,21 @@ export namespace DummyConfig { }, channels: {}, }); + + export const MODBUS_TCP_READWRITE = (id: string, alias?: string): Component => ({ + id: id, + alias: alias ?? id, + factory: Factory.MODBUS_TCP_READWRITE, + properties: { + invert: false, + modbusUnitId: 5, + type: "PRODUCTION", + writeChannels: [ + "Ess0SetActivePowerEquals", + ], + }, + channels: {}, + }); } } diff --git a/ui/src/app/shared/components/header/header.component.ts b/ui/src/app/shared/components/header/header.component.ts index 0c192f2104..fc97026c4e 100644 --- a/ui/src/app/shared/components/header/header.component.ts +++ b/ui/src/app/shared/components/header/header.component.ts @@ -63,7 +63,7 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { const urlArray = url.split("/"); const file = urlArray.pop(); - if (file == "user" || file == "settings" || file == "changelog" || file == "login" || urlArray.length > 3) { + if (file == "user" || file == "settings" || file == "changelog" || file == "login" || file == "index" || urlArray.length > 3) { // disable side-menu; show back-button instead this.enableSideMenu = false; } else { @@ -75,7 +75,7 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { updateBackUrl(url: string) { // disable backUrl & Segment Navigation on initial 'login' page - if (url === "/login" || url === "/overview") { + if (url === "/login" || url === "/overview" || url === "/index") { this.backUrl = false; return; } diff --git a/ui/src/app/shared/components/modal/modal.module.ts b/ui/src/app/shared/components/modal/modal.module.ts index 57ecf5e89e..9f6c54a7b5 100644 --- a/ui/src/app/shared/components/modal/modal.module.ts +++ b/ui/src/app/shared/components/modal/modal.module.ts @@ -26,6 +26,7 @@ import { ModalHorizontalLineComponent } from "./model-horizontal-line/modal-hori PipeModule, ], declarations: [ + HelpButtonComponent, ModalButtonsComponent, ModalInfoLineComponent, ModalLineComponent, @@ -37,6 +38,7 @@ import { ModalHorizontalLineComponent } from "./model-horizontal-line/modal-hori HelpButtonComponent, ], exports: [ + HelpButtonComponent, ModalButtonsComponent, ModalInfoLineComponent, ModalLineComponent, diff --git a/ui/src/app/shared/components/shared/converter.ts b/ui/src/app/shared/components/shared/converter.ts index 136ecff555..b76ad1ace3 100644 --- a/ui/src/app/shared/components/shared/converter.ts +++ b/ui/src/app/shared/components/shared/converter.ts @@ -93,6 +93,34 @@ export namespace Converter { Formatter.FORMAT_WATT(value)); }; + /** + * Formats a Energy value as Kilo watt hours [kWh]. + * + * Value 1000 -> "1,00 kWh". + * Value null -> "-". + * + * @param value the power value + * @returns formatted value; '-' for null + */ + export const WATT_HOURS_IN_KILO_WATT_HOURS: Converter = (raw) => { + return IF_NUMBER(raw, value => + Formatter.FORMAT_KILO_WATT_HOURS(value / 1000)); + }; + + /** + * Formats a Energy value as Kilo watt hours [kWh]. + * + * Value 1000 -> "1000 kWh". + * Value null -> "-". + * + * @param value the power value + * @returns formatted value; '-' for null + */ + export const TO_KILO_WATT_HOURS: Converter = (raw) => { + return IF_NUMBER(raw, value => + Formatter.FORMAT_KILO_WATT_HOURS(value)); + }; + export const STATE_IN_PERCENT: Converter = (raw) => { return IF_NUMBER(raw, value => Formatter.FORMAT_PERCENT(value)); diff --git a/ui/src/app/shared/components/shared/formatter.ts b/ui/src/app/shared/components/shared/formatter.ts index 8f2d5df2c8..798818e17b 100644 --- a/ui/src/app/shared/components/shared/formatter.ts +++ b/ui/src/app/shared/components/shared/formatter.ts @@ -7,6 +7,11 @@ export namespace Formatter { return formatNumber(value, "de", "1.0-0") + " W"; }; + export const FORMAT_KILO_WATT_HOURS = (value: number) => { + // TODO apply correct locale + return formatNumber(value, "de", "1.0-0") + " kWh"; + }; + export const FORMAT_VOLT = (value: number) => { // TODO apply correct locale return formatNumber(value, "de", "1.0-0") + " V"; diff --git a/ui/src/app/shared/ngrx-store/states.ts b/ui/src/app/shared/ngrx-store/states.ts new file mode 100644 index 0000000000..33d8f0aeb0 --- /dev/null +++ b/ui/src/app/shared/ngrx-store/states.ts @@ -0,0 +1,110 @@ +import { Injectable, WritableSignal, effect, signal } from "@angular/core"; +import { Router } from "@angular/router"; + +import { differenceInSeconds } from "date-fns"; +import { environment } from "src/environments"; +import { Pagination } from "../service/pagination"; +import { PreviousRouteService } from "../service/previousRouteService"; +import { Websocket } from "../shared"; + +export enum States { + WEBSOCKET_CONNECTION_CLOSED, + WEBSOCKET_NOT_YET_CONNECTED, + WEBSOCKET_CONNECTING, + WEBSOCKET_CONNECTED, + + // TODO substates + NOT_AUTHENTICATED, + AUTHENTICATING_WITH_TOKEN, + AUTHENTICATION_WITH_CREDENTIALS, + AUTHENTICATED, + EDGE_SELECTED, +} + +@Injectable({ + providedIn: "root", +}) +export class AppStateTracker { + private static readonly LOG_PREFIX: string = "AppState"; + private static readonly TIME_TILL_TIMEOUT: number = 10; + private static readonly ENABLE_ROUTING: boolean = true; + public loadingState: WritableSignal<"failed" | "loading" | "authenticated"> = signal("loading"); + private lastTimeStamp: Date | null = null; + + constructor( + protected router: Router, + protected pagination: Pagination, + private websocket: Websocket, + private previousRouteService: PreviousRouteService, + ) { + if (!localStorage.getItem("AppState")) { + console.log(`${AppStateTracker.LOG_PREFIX} Log deactivated`); + } + + if (!AppStateTracker.ENABLE_ROUTING) { + console.log(`${AppStateTracker.LOG_PREFIX} Routing deactivated`); + } + + effect(() => { + const state = this.websocket.state(); + this.startStateHandler(state); + }, { allowSignalWrites: true }); + } + + /** + * Handles navigation after authentication + */ + public navigateAfterAuthentication() { + const segments = this.router.routerState.snapshot.url.split("/"); + const previousUrl: string = this.previousRouteService.getPreviousUrl(); + + if ((previousUrl === segments[segments.length - 1]) || previousUrl === "/") { + this.router.navigate(["./overview"]); + return; + } + + this.router.navigate(previousUrl.split("/")); + } + + private startStateHandler(state: States): void { + + if (environment.debugMode && localStorage.getItem("AppState")) { + console.log(`${AppStateTracker.LOG_PREFIX} [${States[this.websocket.state()]}]`); + } + + if (!AppStateTracker.ENABLE_ROUTING) { + return; + } + + switch (state) { + case States.WEBSOCKET_CONNECTING: + this.lastTimeStamp = this.handleWebSocketConnecting(this.lastTimeStamp); + break; + case States.WEBSOCKET_CONNECTION_CLOSED: + break; + case States.AUTHENTICATED: + this.loadingState.set("authenticated"); + break; + default: + this.lastTimeStamp = null; + break; + } + } + + + private handleWebSocketConnecting(lastTimeStamp: Date | null): Date | null { + const now = new Date(); + if (lastTimeStamp === null) { + return now; + } + + if (differenceInSeconds(now, lastTimeStamp) > AppStateTracker.TIME_TILL_TIMEOUT) { + console.warn(`Websocket connection couldnt be established in ${AppStateTracker.TIME_TILL_TIMEOUT}s`); + this.loadingState.set("failed"); + this.router.navigate(["index"]); + return null; + } + + return lastTimeStamp; + } +} diff --git a/ui/src/app/shared/pipe/converter/converter.ts b/ui/src/app/shared/pipe/converter/converter.ts new file mode 100644 index 0000000000..34cc2fc664 --- /dev/null +++ b/ui/src/app/shared/pipe/converter/converter.ts @@ -0,0 +1,22 @@ +import { Pipe, PipeTransform } from "@angular/core"; + +import { Converter } from "../../components/shared/converter"; + +@Pipe({ + name: "converter", +}) +export class ConverterPipe implements PipeTransform { + + constructor() { } + + /** + * Transforms the value with a given converter + * + * @param value the passed value + * @param converter the passed converter + * @returns the result of the converter as a string + */ + transform(value: number, converter: Converter): string { + return converter(value); + } +} diff --git a/ui/src/app/shared/pipe/pipe.ts b/ui/src/app/shared/pipe/pipe.ts index ff8f05002e..dba4d59200 100644 --- a/ui/src/app/shared/pipe/pipe.ts +++ b/ui/src/app/shared/pipe/pipe.ts @@ -2,6 +2,7 @@ import { DecimalPipe } from "@angular/common"; import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; import { ClassnamePipe } from "./classname/classname.pipe"; +import { ConverterPipe } from "./converter/converter"; import { FormatSecondsToDurationPipe } from "./formatSecondsToDuration/formatSecondsToDuration.pipe"; import { IsclassPipe } from "./isclass/isclass.pipe"; import { KeysPipe } from "./keys/keys.pipe"; @@ -23,6 +24,7 @@ import { VersionPipe } from "./version/version.pipe"; ClassnamePipe, VersionPipe, TypeofPipe, + ConverterPipe, ], exports: [ UnitvaluePipe, @@ -33,6 +35,7 @@ import { VersionPipe } from "./version/version.pipe"; ClassnamePipe, VersionPipe, TypeofPipe, + ConverterPipe, ], providers: [ DecimalPipe, diff --git a/ui/src/app/shared/service/pagination.ts b/ui/src/app/shared/service/pagination.ts index ed54983711..f75a43c2f7 100644 --- a/ui/src/app/shared/service/pagination.ts +++ b/ui/src/app/shared/service/pagination.ts @@ -4,6 +4,7 @@ import { Router } from "@angular/router"; import { SubscribeEdgesRequest } from "../jsonrpc/request/subscribeEdgesRequest"; import { ChannelAddress, Edge } from "../shared"; import { Service } from "./service"; +import { States } from "../ngrx-store/states"; @Directive() export class Pagination { @@ -22,6 +23,7 @@ export class Pagination { this.edge = edge; this.service.websocket.sendRequest(new SubscribeEdgesRequest({ edges: [edge.id] })); }).then(() => { + this.service.websocket.state.set(States.EDGE_SELECTED); this.edge.subscribeChannels(this.service.websocket, "", [ new ChannelAddress("_sum", "State"), ]); diff --git a/ui/src/app/shared/service/previousRouteService.ts b/ui/src/app/shared/service/previousRouteService.ts new file mode 100644 index 0000000000..f6087a0ea2 --- /dev/null +++ b/ui/src/app/shared/service/previousRouteService.ts @@ -0,0 +1,29 @@ +import { Injectable } from "@angular/core"; +import { NavigationEnd, Router } from "@angular/router"; + +@Injectable() +export class PreviousRouteService { + + private previousUrl: string; + private currentUrl: string; + + constructor(private router: Router) { + this.currentUrl = this.router.url; + this.previousUrl = this.currentUrl; + router.events.subscribe(event => { + if (event instanceof NavigationEnd) { + this.previousUrl = this.currentUrl; + this.currentUrl = event.url; + } + }); + } + + /** + * Gets the previous url, active before this url + * + * @returns the previous url + */ + public getPreviousUrl() { + return this.previousUrl; + } +} diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index 67ce8b1a64..e25fa22fac 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -20,6 +20,7 @@ import { GetEdgeResponse } from "../jsonrpc/response/getEdgeResponse"; import { GetEdgesResponse } from "../jsonrpc/response/getEdgesResponse"; import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; import { User } from "../jsonrpc/shared"; +import { States } from "../ngrx-store/states"; import { ChannelAddress } from "../shared"; import { Language } from "../type/language"; import { Role } from "../type/role"; @@ -198,6 +199,7 @@ export class Service extends AbstractService { public onLogout() { this.currentEdge.next(null); this.metadata.next(null); + this.websocket.state.set(States.NOT_AUTHENTICATED); this.router.navigate(["/login"]); } diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index 36f44a37d4..9e23706034 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -632,6 +632,7 @@ export enum YAxisType { RELAY, ENERGY, VOLTAGE, + REACTIVE, CURRENT, TIME, CURRENCY, diff --git a/ui/src/app/shared/service/websocket.ts b/ui/src/app/shared/service/websocket.ts index a79deefeb7..6df2b0d368 100644 --- a/ui/src/app/shared/service/websocket.ts +++ b/ui/src/app/shared/service/websocket.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { Injectable } from "@angular/core"; +import { Injectable, WritableSignal, signal } from "@angular/core"; import { Router } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; import { CookieService } from "ngx-cookie-service"; @@ -18,6 +18,7 @@ import { EdgeRpcRequest } from "../jsonrpc/request/edgeRpcRequest"; import { LogoutRequest } from "../jsonrpc/request/logoutRequest"; import { RegisterUserRequest } from "../jsonrpc/request/registerUserRequest"; import { AuthenticateResponse } from "../jsonrpc/response/authenticateResponse"; +import { States } from "../ngrx-store/states"; import { Language } from "../type/language"; import { Pagination } from "./pagination"; import { Service } from "./service"; @@ -40,6 +41,8 @@ export class Websocket implements WebsocketInterface { | "failed" // connection failed = "initial"; + public state: WritableSignal = signal(States.WEBSOCKET_NOT_YET_CONNECTED); + private readonly wsdata = new WsData(); private socket: WebSocketSubject; @@ -68,6 +71,7 @@ export class Websocket implements WebsocketInterface { public login(request: AuthenticateWithPasswordRequest | AuthenticateWithTokenRequest): Promise { return new Promise((resolve) => { this.sendRequest(request).then(r => { + this.state.set(States.AUTHENTICATED); const authenticateResponse = (r as AuthenticateResponse).result; const language = Language.getByKey(localStorage.DEMO_LANGUAGE ?? authenticateResponse.user.language.toLocaleLowerCase()); @@ -202,10 +206,12 @@ export class Websocket implements WebsocketInterface { * Opens a connection using a stored token. Called once by constructor */ private connect() { + this.state.set(States.WEBSOCKET_NOT_YET_CONNECTED); if (this.status != "initial") { return; } // trying to connect + this.state.set(States.WEBSOCKET_CONNECTING); this.status = "connecting"; if (environment.debugMode) { @@ -219,6 +225,7 @@ export class Websocket implements WebsocketInterface { url: environment.url, openObserver: { next: (value) => { + this.state.set(States.WEBSOCKET_NOT_YET_CONNECTED); // Websocket connection is open if (environment.debugMode) { console.info("Websocket connection opened"); @@ -226,6 +233,7 @@ export class Websocket implements WebsocketInterface { const token = this.cookieService.get("token"); if (token) { + this.state.set(States.AUTHENTICATING_WITH_TOKEN); // Login with Session Token this.login(new AuthenticateWithTokenRequest({ token: token })); @@ -233,6 +241,7 @@ export class Websocket implements WebsocketInterface { } else { // No Token -> directly ask for Login credentials + this.state.set(States.NOT_AUTHENTICATED); this.status = "waiting for credentials"; this.router.navigate(["login"]); } @@ -241,10 +250,12 @@ export class Websocket implements WebsocketInterface { closeObserver: { next: (value) => { // Websocket connection is closed. Auto-Reconnect starts. + this.state.set(States.WEBSOCKET_CONNECTION_CLOSED); if (environment.debugMode) { console.info("Websocket connection closed"); } // trying to connect + this.state.set(States.WEBSOCKET_CONNECTING); this.status = "connecting"; }, }, diff --git a/ui/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts index 1bf1507d69..2ff830daf9 100644 --- a/ui/src/app/shared/shared.module.ts +++ b/ui/src/app/shared/shared.module.ts @@ -31,8 +31,10 @@ import { HistoryDataErrorModule } from "./components/history-data-error/history- import { PercentageBarComponent } from "./components/percentagebar/percentagebar.component"; import { DirectiveModule } from "./directive/directive"; import { ChartOptionsComponent } from "./legacy/chartoptions/chartoptions.component"; +import { AppStateTracker } from "./ngrx-store/states"; import { PipeModule } from "./pipe/pipe"; import { Logger } from "./service/logger"; +import { PreviousRouteService } from "./service/previousRouteService"; import { Service } from "./service/service"; import { Utils } from "./service/utils"; import { Websocket } from "./shared"; @@ -143,11 +145,13 @@ export function SubnetmaskValidatorMessage(err, field: FormlyFieldConfig) { FormlyFieldWithLoadingAnimationComponent, ], providers: [ + AppStateTracker, appRoutingProviders, + Logger, + PreviousRouteService, Service, Utils, Websocket, - Logger, ], }) diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 4175e96134..6cf1168edc 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -58,6 +58,10 @@ export class EdgePermission { }, []); } + public static isModbusTcpApiWidgetAllowed(edge: Edge): boolean { + return edge?.isVersionAtLeast("2024.9.1"); + } + /** * Determines if the edge has its channels in the edgeconfig * or if they should be obtained with a separate request. @@ -169,6 +173,15 @@ export enum EssStateMachine { ERROR = 30, } +export enum ChannelRegister { + "SetActivePowerEquals" = 706, + "SetReactivePowerEquals" = 708, + "SetActivePowerLessOrEquals" = 710, + "SetReactivePowerLessOrEquals" = 712, + "SetActivePowerGreaterOrEquals" = 714, + "SetReactivePowerGreaterOrEquals" = 716, +} + /** * Presents a simple */ diff --git a/ui/src/app/shared/type/general.ts b/ui/src/app/shared/type/general.ts index 8394178bfc..8d1d82a528 100644 --- a/ui/src/app/shared/type/general.ts +++ b/ui/src/app/shared/type/general.ts @@ -17,3 +17,8 @@ export enum WorkMode { TIME = "TIME", NONE = "NONE", } +export enum OverrideStatus { + ACTIVE = 0, + INACTIVE = 1, + ERROR = 2, +} diff --git a/ui/src/app/shared/type/language.ts b/ui/src/app/shared/type/language.ts index b76c3dd2d8..4858ceca06 100644 --- a/ui/src/app/shared/type/language.ts +++ b/ui/src/app/shared/type/language.ts @@ -4,8 +4,9 @@ import localES from "@angular/common/locales/es"; import localFR from "@angular/common/locales/fr"; import localJA from "@angular/common/locales/ja"; import localNL from "@angular/common/locales/nl"; -import { TranslateLoader } from "@ngx-translate/core"; +import { TranslateLoader, TranslateService } from "@ngx-translate/core"; import { Observable, of } from "rxjs"; +import { filter, take } from "rxjs/operators"; import cz from "src/assets/i18n/cz.json"; import de from "src/assets/i18n/de.json"; import en from "src/assets/i18n/en.json"; @@ -117,15 +118,16 @@ export class Language { * @param translationFile the translation file * @returns translations params */ - public static setAdditionalTranslationFile(translationFile: any): { lang: string, translations: {}, shouldMerge?: boolean } { - let key = localStorage.LANGUAGE ?? Language.DEFAULT.key; - if (!(key in translationFile)) { + public static async setAdditionalTranslationFile(translationFile: any, translate: TranslateService): Promise<{ lang: string; translations: {}; shouldMerge?: boolean; }> { + const lang = (await translate.onLangChange.pipe(filter(lang => !!lang), take(1)).toPromise()).lang; + let translationKey: string = lang; + if (!(lang in translationFile)) { if (environment.debugMode) { - console.warn(`[Advert] No translation available for Language ${key}. Implemented languages are: ${Object.keys(translationFile)}`); + console.warn(`[Advert] No translation available for Language ${lang}. Implemented languages are: ${Object.keys(translationFile)}`); } - key = Language.DEFAULT.key; + translationKey = Language.EN.key; } - return { lang: key, translations: translationFile[key], shouldMerge: true }; + return { lang: lang, translations: translationFile[translationKey], shouldMerge: true }; } } diff --git a/ui/src/app/shared/type/widget.ts b/ui/src/app/shared/type/widget.ts index bd838e1641..5f72e25e0c 100644 --- a/ui/src/app/shared/type/widget.ts +++ b/ui/src/app/shared/type/widget.ts @@ -1,6 +1,7 @@ // @ts-strict-ignore import { Edge } from "../components/edge/edge"; import { EdgeConfig } from "../components/edge/edgeconfig"; +import { EdgePermission } from "../shared"; export enum WidgetClass { "Energymonitor", @@ -21,6 +22,7 @@ export enum WidgetNature { } export enum WidgetFactory { + "Controller.Api.ModbusTcp.ReadWrite", "Controller.Asymmetric.PeakShaving", "Controller.ChannelThreshold", "Controller.CHP.SoC", @@ -104,6 +106,8 @@ export class Widgets { return config.getComponentIdsByFactory("Controller.ChannelThreshold")?.length > 0; case "Controller_Io_Digital_Outputs": return config.getComponentIdsByFactories("Controller.Io.FixDigitalOutput", "Controller.IO.ChannelSingleThreshold")?.length > 0; + case "Controller.Api.ModbusTcp.ReadWrite": + return EdgePermission.isModbusTcpApiWidgetAllowed(edge); default: return false; } diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 5e45735b3c..457f5cb15a 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -858,6 +858,13 @@ }, "CONFIGURATION_MPPT_SELECTION_NOTE": "Weitere Erzeuger kรถnnen im Anschluss รผber das App Center konfiguriert werden." }, + "LOADING_SCREEN": { + "LOADING": "Wird geladen", + "SERVER_NOT_ACCESSIBLE": "Server nicht erreichbar", + "SERVER_NOT_ACCESSIBLE_TRY_RELOADING": "Probieren Sie bitte in 10 Minuten den Browser neu zu laden.", + "SERVER_NOT_ACCESSIBLE_ACCESS_LOCALLY": "Lokal zugreifen", + "SERVER_NOT_ACCESSIBLE_DESCRIPTION": "Der Onlinezugriff auf das Speichersystem ist aktuell nicht mรถglich. Die Daten werden lokal gespeichert und gehen nicht verloren." + }, "Login": { "title": "Login", "preamble": "Bitte geben Sie Ihr Passwort ein oder bestรคtigen Sie die Voreingabe um sich als Gast anzumelden.", @@ -972,6 +979,24 @@ "MORE_CHANNELS": "Weitere Kanรคle hinzufรผgen", "CHANNEL": "Kanal" }, + "MODBUS_TCP_API_READ_WRITE": { + "CURRENT_STATE": "Aktueller Status", + "CUMULATED_ACTIVE_TIME": "Externe Vorgaben berรผcksichtigt", + "CUMULATED_INACTIVE_TIME": "Keine externe Vorgabe vorhanden", + "NO_OVERRIDDEN_CHANNELS": "Es wurden noch keine Kanรคle รผberschrieben.", + "NOT_OVERRIDING": "Keine externe Vorgabe vorhanden", + "OVERRIDING": "Externe Vorgabe wird berรผcksichtigt", + "LAST_COMMAND": "Letzter Schreibbefehl", + "ACTIVE_POWER_LIMITATIONS": "Wirkleistungsvorgabe", + "REGISTER": "Register", + "LIMITATION": "Vorgabe", + "ACTUAL_VALUE": "Tatsรคchlicher Wert", + "INFO_TEXT": "Tatsรคchlicher Wert kann von der Vorgabe abweichen. Negative Werte entsprechen Speicherbeladung - postive Speicherentladung. Eine detaillierte Erklรคrung finden Sie in der Anleitung.", + "SET_ACTIVE_POWER_EQUALS": "Vorgabe Be- bzw. Entladeleistung", + "SET_ACTIVE_POWER_GREATER_OR_EQUALS": "Minimale Beladeleistung", + "SET_ACTIVE_POWER_LESS_OR_EQUALS": "Maximale Beladeleistung", + "DOWNLOAD_PROTOCOL": "Protokoll Herunterladen" + }, "GRID_STATES": { "OFF_GRID": "Netzausfall", "NO_EXTERNAL_LIMITATION": "keine externe Limitierung", diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index 3c555925b2..b3f33f8787 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -860,6 +860,13 @@ }, "CONFIGURATION_MPPT_SELECTION_NOTE": "Additional generators can then be configured via the App Center." }, + "LOADING_SCREEN": { + "LOADING": "Loading", + "SERVER_NOT_ACCESSIBLE": "Server not accessible", + "SERVER_NOT_ACCESSIBLE_DESCRIPTION": "Online view of the storage system is currently not possible. The data is saved locally and will not be lost.", + "SERVER_NOT_ACCESSIBLE_TRY_RELOADING": "Please try reloading the browser in 10 minutes.", + "SERVER_NOT_ACCESSIBLE_ACCESS_LOCALLY": "Access locally" + }, "Login": { "title": "Login", "preamble": "Please enter your password or submit the default value to login as a guest.", @@ -975,6 +982,24 @@ "MORE_CHANNELS": "Add More Channels", "CHANNEL": "Channel" }, + "MODBUS_TCP_API_READ_WRITE": { + "CURRENT_STATE": "Current state", + "CUMULATED_ACTIVE_TIME": "External commands considered", + "CUMULATED_INACTIVE_TIME": "No external commands present", + "NO_OVERRIDDEN_CHANNELS": "No channels have been overridden yet.", + "NOT_OVERRIDING": "No external commands present", + "OVERRIDING": "External command is being considered", + "LAST_COMMAND": "Last override", + "ACTIVE_POWER_LIMITATIONS": "Active power limitations", + "REGISTER": "Register", + "LIMITATION": "Limitation", + "ACTUAL_VALUE": "Actual value", + "INFO_TEXT": "Actual value may deviate from the specification. Negative values correspond to storage loading - positive storage discharging. A detailed explanation can be found in the instructions.", + "SET_ACTIVE_POWER_EQUALS": "Limitation charing/discharging power", + "SET_ACTIVE_POWER_GREATER_OR_EQUALS": "Minimum charging power", + "SET_ACTIVE_POWER_LESS_OR_EQUALS": "Maximum charging power", + "DOWNLOAD_PROTOCOL": "Download Protocol" + }, "GRID_STATES": { "OFF_GRID": "Power outage", "NO_EXTERNAL_LIMITATION": "No external limitation", diff --git a/ui/src/themes/openems/scss/variables.scss b/ui/src/themes/openems/scss/variables.scss index 936fd07be4..abf1541b28 100644 --- a/ui/src/themes/openems/scss/variables.scss +++ b/ui/src/themes/openems/scss/variables.scss @@ -15,6 +15,7 @@ $font-family: var(--ion-font-family); --ion-color-primary-contrast: #000000; --ion-color-primary-contrast-rgb: 0, 0, 0; --ion-color-primary-shade: #cc995d; + --ion-color-primary-shade-rgb: rgb(204, 153, 93); --ion-color-primary-tint: #eab679; /** secondary **/ @@ -106,9 +107,13 @@ $font-family: var(--ion-font-family); } --ion-color-production: #36aed1; - --ion-color-production-rgb: 54, 174, 209; + --ion-color-production-rgb: 54, + 174, + 209; --ion-color-production-contrast: #fff; - --ion-color-production-contrast-rgb: 255, 255, 255; + --ion-color-production-contrast-rgb: 255, + 255, + 255; --ion-color-production-shade: #226e84; --ion-color-production-tint: #41d4ff; From b5f385b704dc345bb53d4583127668accd633d26 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 10 Sep 2024 14:23:39 +0200 Subject: [PATCH 07/24] Update Gradle to 8.10.1 See https://github.com/gradle/gradle/releases/tag/v8.10.1 --- .gradle-wrapper/gradle-wrapper.jar | Bin 43504 -> 43583 bytes .gradle-wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/.gradle-wrapper/gradle-wrapper.jar b/.gradle-wrapper/gradle-wrapper.jar index 2c3521197d7c4586c843d1d3e9090525f1898cde..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 3990 zcmV;H4{7l5(*nQL0Kr1kzC=_KMxQY0|W5(lc#i zH*M1^P4B}|{x<+fkObwl)u#`$GxKKV&3pg*-y6R6txw)0qU|Clf9Uds3x{_-**c=7 z&*)~RHPM>Rw#Hi1R({;bX|7?J@w}DMF>dQQU2}9yj%iLjJ*KD6IEB2^n#gK7M~}6R zkH+)bc--JU^pV~7W=3{E*4|ZFpDpBa7;wh4_%;?XM-5ZgZNnVJ=vm!%a2CdQb?oTa z70>8rTb~M$5Tp!Se+4_OKWOB1LF+7gv~$$fGC95ToUM(I>vrd$>9|@h=O?eARj0MH zT4zo(M>`LWoYvE>pXvqG=d96D-4?VySz~=tPVNyD$XMshoTX(1ZLB5OU!I2OI{kb) zS8$B8Qm>wLT6diNnyJZC?yp{Kn67S{TCOt-!OonOK7$K)e-13U9GlnQXPAb&SJ0#3 z+vs~+4Qovv(%i8g$I#FCpCG^C4DdyQw3phJ(f#y*pvNDQCRZ~MvW<}fUs~PL=4??j zmhPyg<*I4RbTz|NHFE-DC7lf2=}-sGkE5e!RM%3ohM7_I^IF=?O{m*uUPH(V?gqyc(Rp?-Qu(3bBIL4Fz(v?=_Sh?LbK{nqZMD>#9D_hNhaV$0ef3@9V90|0u#|PUNTO>$F=qRhg1duaE z0`v~X3G{8RVT@kOa-pU+z8{JWyP6GF*u2e8eKr7a2t1fuqQy)@d|Qn(%YLZ62TWtoX@$nL}9?atE#Yw`rd(>cr0gY;dT9~^oL;u)zgHUvxc2I*b&ZkGM-iq=&(?kyO(3}=P! zRp=rErEyMT5UE9GjPHZ#T<`cnD)jyIL!8P{H@IU#`e8cAG5jMK zVyKw7--dAC;?-qEu*rMr$5@y535qZ6p(R#+fLA_)G~!wnT~~)|s`}&fA(s6xXN`9j zP#Fd3GBa#HeS{5&8p?%DKUyN^X9cYUc6vq}D_3xJ&d@=6j(6BZKPl?!k1?!`f3z&a zR4ZF60Mx7oBxLSxGuzA*Dy5n-d2K=+)6VMZh_0KetK|{e;E{8NJJ!)=_E~1uu=A=r zrn&gh)h*SFhsQJo!f+wKMIE;-EOaMSMB@aXRU(UcnJhZW^B^mgs|M9@5WF@s6B0p& zm#CTz)yiQCgURE{%hjxHcJ6G&>G9i`7MyftL!QQd5 z@RflRs?7)99?X`kHNt>W3l7YqscBpi*R2+fsgABor>KVOu(i(`03aytf2UA!&SC9v z!E}whj#^9~=XHMinFZ;6UOJjo=mmNaWkv~nC=qH9$s-8roGeyaW-E~SzZ3Gg>j zZ8}<320rg4=$`M0nxN!w(PtHUjeeU?MvYgWKZ6kkzABK;vMN0|U;X9abJleJA(xy<}5h5P(5 z{RzAFPvMnX2m0yH0Jn2Uo-p`daE|(O`YQiC#jB8;6bVIUf?SY(k$#C0`d6qT`>Xe0+0}Oj0=F&*D;PVe=Z<=0AGI<6$gYLwa#r` zm449x*fU;_+J>Mz!wa;T-wldoBB%&OEMJgtm#oaI60TSYCy7;+$5?q!zi5K`u66Wq zvg)Fx$s`V3Em{=OEY{3lmh_7|08ykS&U9w!kp@Ctuzqe1JFOGz6%i5}Kmm9>^=gih z?kRxqLA<3@e=}G4R_?phW{4DVr?`tPfyZSN@R=^;P;?!2bh~F1I|fB7P=V=9a6XU5 z<#0f>RS0O&rhc&nTRFOW7&QhevP0#>j0eq<1@D5yAlgMl5n&O9X|Vq}%RX}iNyRFF z7sX&u#6?E~bm~N|z&YikXC=I0E*8Z$v7PtWfjy)$e_Ez25fnR1Q=q1`;U!~U>|&YS zaOS8y!^ORmr2L4ik!IYR8@Dcx8MTC=(b4P6iE5CnrbI~7j7DmM8em$!da&D!6Xu)!vKPdLG z9f#)se|6=5yOCe)N6xDhPI!m81*dNe7u985zi%IVfOfJh69+#ag4ELzGne?o`eA`42K4T)h3S+s)5IT97%O>du- z0U54L8m4}rkRQ?QBfJ%DLssy^+a7Ajw;0&`NOTY4o;0-ivm9 zBz1C%nr_hQ)X)^QM6T1?=yeLkuG9Lf50(eH}`tFye;01&(p?8i+6h};VV-2B~qdxeC#=X z(JLlzy&fHkyi9Ksbcs~&r^%lh^2COldLz^H@X!s~mr9Dr6z!j+4?zkD@Ls7F8(t(f z9`U?P$Lmn*Y{K}aR4N&1N=?xtQ1%jqf1~pJyQ4SgBrEtR`j4lQuh7cqP49Em5cO=I zB(He2`iPN5M=Y0}h(IU$37ANTGx&|b-u1BYA*#dE(L-lptoOpo&th~E)_)y-`6kSH z3vvyVrcBwW^_XYReJ=JYd9OBQrzv;f2AQdZH#$Y{Y+Oa33M70XFI((fs;mB4e`<<{ ze4dv2B0V_?Ytsi>>g%qs*}oDGd5d(RNZ*6?7qNbdp7wP4T72=F&r?Ud#kZr8Ze5tB z_oNb7{G+(o2ajL$!69FW@jjPQ2a5C)m!MKKRirC$_VYIuVQCpf9rIms0GRDf)8AH${I`q^~5rjot@#3$2#zT2f`(N^P7Z;6(@EK$q*Jgif00I6*^ZGV+XB5uw*1R-@23yTw&WKD{s1;HTL;dO)%5i#`dc6b7;5@^{KU%N|A-$zsYw4)7LA{3`Zp>1 z-?K9_IE&z)dayUM)wd8K^29m-l$lFhi$zj0l!u~4;VGR6Y!?MAfBC^?QD53hy6VdD z@eUZIui}~L%#SmajaRq1J|#> z4m=o$vZ*34=ZWK2!QMNEcp2Lbc5N1q!lEDq(bz0b;WI9;e>l=CG9^n#ro`w>_0F$Q zfZ={2QyTkfByC&gy;x!r*NyXXbk=a%~~(#K?< zTke0HuF5{Q+~?@!KDXR|g+43$+;ab`^flS%miup_0OUTm=nIc%d5nLP)i308PIjl_YMF6cpQ__6&$n6it8K- z8PIjl_YMF6cpQ_!r)L8IivW`WdK8mBs6PXdjR2DYdK8nCs73=4j{uVadK8oNjwX|E wpAeHLsTu^*Y>Trk?aBtSQ(D-o$(D8Px^?ZI-PUB? z*1fv!{YdHme3Fc8%cR@*@zc5A_nq&2=R47Hp@$-JF4Fz*;SLw5}K^y>s-s;V!}b2i=5=M- zComP?ju>8Fe@=H@rlwe1l`J*6BTTo`9b$zjQ@HxrAhp0D#u?M~TxGC_!?ccCHCjt| zF*PgJf@kJB`|Ml}cmsyrAjO#Kjr^E5p29w+#>$C`Q|54BoDv$fQ9D?3n32P9LPMIzu?LjNqggOH=1@T{9bMn*u8(GI z!;MLTtFPHal^S>VcJdiYqX0VU|Rn@A}C1xOlxCribxes0~+n2 z6qDaIA2$?e`opx3_KW!rAgbpzU)gFdjAKXh|5w``#F0R|c)Y)Du0_Ihhz^S?k^pk% zP>9|pIDx)xHH^_~+aA=^$M!<8K~Hy(71nJGf6`HnjtS=4X4=Hk^O71oNia2V{HUCC zoN3RSBS?mZCLw;l4W4a+D8qc)XJS`pUJ5X-f^1ytxwr`@si$lAE?{4G|o; zO0l>`rr?;~c;{ZEFJ!!3=7=FdGJ?Q^xfNQh4A?i;IJ4}B+A?4olTK(fN++3CRBP97 ze~lG9h%oegkn)lpW-4F8o2`*WW0mZHwHez`ko@>U1_;EC_6ig|Drn@=DMV9YEUSCa zIf$kHei3(u#zm9I!Jf(4t`Vm1lltJ&lVHy(eIXE8sy9sUpmz%I_gA#8x^Zv8%w?r2 z{GdkX1SkzRIr>prRK@rqn9j2wG|rUvf6PJbbin=yy-TAXrguvzN8jL$hUrIXzr^s5 zVM?H4;eM-QeRFr06@ifV(ocvk?_)~N@1c2ien56UjWXid6W%6ievIh)>dk|rIs##^kY67ib8Kw%#-oVFaXG7$ERyA9(NSJUvWiOA5H(!{uOpcW zg&-?iqPhds%3%tFspHDqqr;A!e@B#iPQjHd=c>N1LoOEGRehVoPOdxJ>b6>yc#o#+ zl8s8!(|NMeqjsy@0x{8^j0d00SqRZjp{Kj)&4UHYGxG+z9b-)72I*&J70?+8e?p_@ z=>-(>l6z5vYlP~<2%DU02b!mA{7mS)NS_eLe=t)sm&+Pmk?asOEKlkPQ)EUvvfC=;4M&*|I!w}(@V_)eUKLA_t^%`o z0PM9LV|UKTLnk|?M3u!|f2S0?UqZsEIH9*NJS-8lzu;A6-rr-ot=dg9SASoluZUkFH$7X; zP=?kYX!K?JL-b~<#7wU;b;eS)O;@?h%sPPk{4xEBxb{!sm0AY|f9cNvx6>$3F!*0c z75H=dy8JvTyO8}g1w{$9T$p~5en}AeSLoCF>_RT9YPMpChUjl310o*$QocjbH& zbnwg#gssR#jDVN{uEi3n(PZ%PFZ|6J2 z5_rBf0-u>e4sFe0*Km49ATi7>Kn0f9!uc|rRMR1Dtt6m1LW8^>qFlo}h$@br=Rmpi z;mI&>OF64Be{dVeHI8utrh)v^wsZ0jii%x8UgZ8TC%K~@I(4E};GFW&(;WVov}3%H zH;IhRkfD^(vt^DjZz(MyHLZxv8}qzPc(%itBkBwf_fC~sDBgh<3XAv5cxxfF3<2U! z03Xe&z`is!JDHbe;mNmfkH+_LFE*I2^mdL@7(@9DfAcP6O04V-ko;Rpgp<%Cj5r8Z zd0`sXoIjV$j)--;jA6Zy^D5&5v$o^>e%>Q?9GLm{i~p^lAn!%ZtF$I~>39XVZxk0b zROh^Bk9cE0AJBLozZIEmy7xG(yHWGztvfnr0(2ro1%>zsGMS^EMu+S$r=_;9 zWwZkgf7Q7`H9sLf2Go^Xy6&h~a&%s2_T@_Csf19MntF$aVFiFkvE3_hUg(B@&Xw@YJ zpL$wNYf78=0c@!QU6_a$>CPiXT7QAGDM}7Z(0z#_ZA=fmLUj{2z7@Ypo71UDy8GHr z-&TLKf6a5WCf@Adle3VglBt4>Z>;xF}}-S~B7<(%B;Y z0QR55{z-buw>8ilNM3u6I+D$S%?)(p>=eBx-HpvZj{7c*_?K=d()*7q?93us}1dq%FAFYLsW8ZTQ_XZLh`P2*6(NgS}qGcfGXVWpwsp#Rs}IuKbk*`2}&) zI^Vsk6S&Q4@oYS?dJ`NwMVBs6f57+RxdqVub#PvMu?$=^OJy5xEl0<5SLsSRy%%a0 zi}Y#1-F3m;Ieh#Y12UgW?-R)|eX>ZuF-2cc!1>~NS|XSF-6In>zBoZg+ml!6%fk7U zw0LHcz8VQk(jOJ+Yu)|^|15ufl$KQd_1eUZZzj`aC%umU6F1&D5XVWce_wAe(qCSZ zpX-QF4e{EmEVN9~6%bR5U*UT{eMHfcUo`jw*u?4r2s_$`}U{?NjvEm(u&<>B|%mq$Q3weshxk z76<``8vh{+nX`@9CB6IE&z)I%IFjR^LH{s1p|eppv=x za(g_jLU|xjWMAn-V7th$f({|LG8zzIE0g?cyW;%Dmtv%C+0@xVxPE^ zyZzi9P%JAD6ynwHptuzP`Kox7*9h7XSMonCalv;Md0i9Vb-c*!f0ubfk?&T&T}AHh z4m8Bz{JllKcdNg?D^%a5MFQ;#1z|*}H^qHLzW)L}wp?2tY7RejtSh8<;Zw)QGJYUm z|MbTxyj*McKlStlT9I5XlSWtQGN&-LTr2XyNU+`490rg?LYLMRnz-@oKqT1hpCGqP zyRXt4=_Woj$%n5ee<3zhLF>5>`?m9a#xQH+Jk_+|RM8Vi;2*XbK- zEL6sCpaGPzP>k8f4Kh|##_imt#zJMB;ir|JrMPGW`rityK1vHXMLy18%qmMQAm4WZ zP)i30KR&5vs15)C+8dM66&$k~i|ZT;KR&5vs15)C+8dJ(sAmGPijyIz6_bsqKLSFH zlOd=TljEpH0>h4zA*dCTK&emy#FCRCs1=i^sZ9bFmXjf<6_X39E(XY)00000#N437 diff --git a/.gradle-wrapper/gradle-wrapper.properties b/.gradle-wrapper/gradle-wrapper.properties index 9355b41557..0aaefbcaf0 100644 --- a/.gradle-wrapper/gradle-wrapper.properties +++ b/.gradle-wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From b162f2c31e4f0c85fe9f7cbf16227daecd6cdc92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:09:51 +0200 Subject: [PATCH 08/24] Build(deps): Bump org.apache.felix:org.apache.felix.http.jetty from 5.1.24 to 5.1.26 in /cnf (#2798) * Build(deps): Bump org.apache.felix:org.apache.felix.http.jetty in /cnf Bumps org.apache.felix:org.apache.felix.http.jetty from 5.1.24 to 5.1.26. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.http.jetty dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 56115404f1..3ae7771b07 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -203,7 +203,7 @@ org.apache.felix org.apache.felix.http.jetty - 5.1.24 + 5.1.26 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 8edfd8287e..6d374f9dfb 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -108,7 +108,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.24,5.1.25)',\ + org.apache.felix.http.jetty;version='[5.1.26,5.1.27)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 1e489ec354..a6ac193b88 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -404,7 +404,7 @@ org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\ org.apache.felix.eventadmin;version='[1.6.4,1.6.5)',\ org.apache.felix.fileinstall;version='[3.7.4,3.7.5)',\ - org.apache.felix.http.jetty;version='[5.1.24,5.1.25)',\ + org.apache.felix.http.jetty;version='[5.1.26,5.1.27)',\ org.apache.felix.http.servlet-api;version='[3.0.0,3.0.1)',\ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ From c1f5106c81ec7c33a06e24252c7ee5e4496ba197 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:13:31 +0200 Subject: [PATCH 09/24] Build(deps): Bump net.java.dev.jna:jna from 5.14.0 to 5.15.0 in /cnf (#2799) * Build(deps): Bump net.java.dev.jna:jna from 5.14.0 to 5.15.0 in /cnf Bumps [net.java.dev.jna:jna](https://github.com/java-native-access/jna) from 5.14.0 to 5.15.0. - [Changelog](https://github.com/java-native-access/jna/blob/master/CHANGES.md) - [Commits](https://github.com/java-native-access/jna/compare/5.14.0...5.15.0) --- updated-dependencies: - dependency-name: net.java.dev.jna:jna dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 3ae7771b07..7842bce483 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -162,7 +162,7 @@ net.java.dev.jna jna - 5.14.0 + 5.15.0 diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index a6ac193b88..2c44743386 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -203,7 +203,7 @@ com.google.guava;version='[33.3.0,33.3.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.0,3.9.1)',\ - com.sun.jna;version='[5.14.0,5.14.1)',\ + com.sun.jna;version='[5.15.0,5.15.1)',\ io.openems.common;version=snapshot,\ io.openems.edge.application;version=snapshot,\ io.openems.edge.battery.api;version=snapshot,\ From 29eb8df73a41fc92abb6e4778c6101b738eb6dc4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:28:14 +0200 Subject: [PATCH 10/24] Build(deps): Bump org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm from 1.8.1 to 1.9.0 in /cnf (#2796) * Build(deps): Bump org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm](https://github.com/Kotlin/kotlinx.coroutines) from 1.8.1 to 1.9.0. - [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases) - [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md) - [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.8.1...1.9.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update bnd --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.wrapper/bnd.bnd | 2 +- io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 7842bce483..cd3d228f65 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -306,7 +306,7 @@ org.jetbrains.kotlinx kotlinx-coroutines-core-jvm - 1.8.1 + 1.9.0 diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index 250390423e..c709d538e3 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -27,4 +27,4 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea org.dhatim:fastexcel;version='0.18.2',\ org.dhatim:fastexcel-reader;version='0.18.2',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ - org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.7.3',\ + org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.9.0',\ diff --git a/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd b/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd index eaafb47be8..3b276e9c95 100644 --- a/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd +++ b/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd @@ -2,10 +2,10 @@ Bundle-Name: kotlinx-coroutines-core-jvm Bundle-Description: The Java InfluxDB 2.0 Client Core Bundle-DocURL: https://github.com/influxdata/influxdb-client-client Bundle-License: https://opensource.org/licenses/MIT -Bundle-Version: 1.8.1 +Bundle-Version: 1.9.0 Include-Resource: \ - @kotlinx-coroutines-core-jvm-1.8.1.jar,\ + @kotlinx-coroutines-core-jvm-1.9.0.jar,\ Export-Package: \ kotlinx.coroutines,\ From c9463a438a0eedd929a601488e6853a0cf60c860 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:47:58 +0200 Subject: [PATCH 11/24] Build(deps): Bump com.squareup.okio:okio-jvm from 3.9.0 to 3.9.1 in /cnf (#2797) * Build(deps): Bump com.squareup.okio:okio-jvm from 3.9.0 to 3.9.1 in /cnf Bumps [com.squareup.okio:okio-jvm](https://github.com/square/okio) from 3.9.0 to 3.9.1. - [Release notes](https://github.com/square/okio/releases) - [Changelog](https://github.com/square/okio/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okio/compare/parent-3.9.0...3.9.1) --- updated-dependencies: - dependency-name: com.squareup.okio:okio-jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index cd3d228f65..c94a6d272e 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -61,7 +61,7 @@ com.squareup.okio okio-jvm - 3.9.0 + 3.9.1 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 6d374f9dfb..ae6fa89938 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -64,7 +64,7 @@ com.google.gson;version='[2.11.0,2.11.1)',\ com.google.guava;version='[33.3.0,33.3.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ - com.squareup.okio;version='[3.9.0,3.9.1)',\ + com.squareup.okio;version='[3.9.1,3.9.2)',\ com.zaxxer.HikariCP;version='[5.1.0,5.1.1)',\ io.openems.backend.alerting;version=snapshot,\ io.openems.backend.application;version=snapshot,\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 2c44743386..66c4b4ce7b 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -202,7 +202,7 @@ com.google.gson;version='[2.11.0,2.11.1)',\ com.google.guava;version='[33.3.0,33.3.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ - com.squareup.okio;version='[3.9.0,3.9.1)',\ + com.squareup.okio;version='[3.9.1,3.9.2)',\ com.sun.jna;version='[5.15.0,5.15.1)',\ io.openems.common;version=snapshot,\ io.openems.edge.application;version=snapshot,\ From 2cc60e15835c5e934af5b14b6a9fecc731d6ac52 Mon Sep 17 00:00:00 2001 From: "Kai J." Date: Fri, 20 Sep 2024 15:49:16 +0200 Subject: [PATCH 12/24] Codecov: Set flags and components (#2810) --- .github/workflows/build.yml | 2 ++ codecov.yml | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f1d4022ad..b03b5287e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,6 +43,7 @@ jobs: - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4 with: + flags: java token: ${{ secrets.CODECOV_TOKEN }} build-ui: @@ -77,5 +78,6 @@ jobs: - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4 with: + flags: ui directory: ./ui/ token: ${{ secrets.CODECOV_TOKEN }} diff --git a/codecov.yml b/codecov.yml index 00b2350eb7..49e61532ba 100644 --- a/codecov.yml +++ b/codecov.yml @@ -14,3 +14,32 @@ comment: require_base: false require_head: true hide_project_coverage: true + +component_management: + default_rules: + statuses: + - type: project + target: auto + branches: + - "!main" + individual_components: + - component_id: openems_backend + name: "OpenEMS Backend" + paths: + - io.openems.backend.*/** + - io.openems.common/** + - io.openems.oem.*/** + - io.openems.shared.*/** + - io.openems.wrapper/** + - component_id: openems_edge + name: "OpenEMS Edge" + paths: + - io.openems.edge.*/** + - io.openems.common/** + - io.openems.oem.*/** + - io.openems.shared.*/** + - io.openems.wrapper/** + - component_id: openems_ui + name: "OpenEMS UI" + paths: + - ui/** \ No newline at end of file From 3b9c941e05e54a9bb19295d85c7fbcbaf4355fe0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:00:34 +0200 Subject: [PATCH 13/24] Build(deps): Bump org.apache.felix:org.apache.felix.webconsole from 5.0.6 to 5.0.8 in /cnf (#2818) * Build(deps): Bump org.apache.felix:org.apache.felix.webconsole in /cnf Bumps org.apache.felix:org.apache.felix.webconsole from 5.0.6 to 5.0.8. --- updated-dependencies: - dependency-name: org.apache.felix:org.apache.felix.webconsole dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index c94a6d272e..fa62c20f2a 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -237,7 +237,7 @@ org.apache.felix org.apache.felix.webconsole - 5.0.6 + 5.0.8 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index ae6fa89938..ec5126eef1 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -113,7 +113,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.6,5.0.7)',\ + org.apache.felix.webconsole;version='[5.0.8,5.0.9)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.jetbrains.kotlin.osgi-bundle;version='[2.0.20,2.0.21)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 66c4b4ce7b..bfccd5b97b 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -409,7 +409,7 @@ org.apache.felix.inventory;version='[2.0.0,2.0.1)',\ org.apache.felix.metatype;version='[1.2.4,1.2.5)',\ org.apache.felix.scr;version='[2.2.12,2.2.13)',\ - org.apache.felix.webconsole;version='[5.0.6,5.0.7)',\ + org.apache.felix.webconsole;version='[5.0.8,5.0.9)',\ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.eclipse.jetty.client;version='[9.4.28,9.4.29)',\ org.eclipse.jetty.http;version='[9.4.28,9.4.29)',\ From c6fed129cabca97b55a534f42520dcc7b58a2d17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:29:54 +0200 Subject: [PATCH 14/24] Build(deps): Bump com.google.guava:guava from 33.3.0-jre to 33.3.1-jre in /cnf (#2815) * Build(deps): Bump com.google.guava:guava in /cnf Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.3.0-jre to 33.3.1-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/build.bnd | 2 +- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cnf/build.bnd b/cnf/build.bnd index 3a846baa49..00cba399ba 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -40,7 +40,7 @@ buildpath: \ org.osgi.service.metatype;version='1.4.1',\ org.osgi.service.metatype.annotations;version='1.4.1',\ org.osgi.util.promise;version='1.2.0',\ - com.google.guava;version='33.3.0.jre',\ + com.google.guava;version='33.3.1.jre',\ com.google.gson;version='2.11.0',\ testpath: \ diff --git a/cnf/pom.xml b/cnf/pom.xml index fa62c20f2a..916c49e9d6 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -38,7 +38,7 @@ com.google.guava guava - 33.3.0-jre + 33.3.1-jre com.google.guava diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index ec5126eef1..91d486066c 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -62,7 +62,7 @@ Java-WebSocket;version='[1.5.4,1.5.5)',\ com.fasterxml.aalto-xml;version='[1.3.3,1.3.4)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.3.0,33.3.1)',\ + com.google.guava;version='[33.3.1,33.3.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.1,3.9.2)',\ com.zaxxer.HikariCP;version='[5.1.0,5.1.1)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index bfccd5b97b..11442b68bc 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -200,7 +200,7 @@ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.3.0,33.3.1)',\ + com.google.guava;version='[33.3.1,33.3.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.1,3.9.2)',\ com.sun.jna;version='[5.15.0,5.15.1)',\ From 3b885899d26cecc06d11c0aefa22732caf2b8e7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:28:48 +0200 Subject: [PATCH 15/24] Build(deps): Bump the fastexcel group across 1 directory with 2 updates (#2816) * Build(deps): Bump the fastexcel group across 1 directory with 2 updates Bumps the fastexcel group with 2 updates in the /cnf directory: [org.dhatim:fastexcel](https://github.com/dhatim/fastexcel) and [org.dhatim:fastexcel-reader](https://github.com/dhatim/fastexcel). Updates `org.dhatim:fastexcel` from 0.18.2 to 0.18.4 - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.2...0.18.4) Updates `org.dhatim:fastexcel-reader` from 0.18.2 to 0.18.4 - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.18.2...0.18.4) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel dependency-type: direct:production update-type: version-update:semver-patch dependency-group: fastexcel - dependency-name: org.dhatim:fastexcel-reader dependency-type: direct:production update-type: version-update:semver-patch dependency-group: fastexcel ... Signed-off-by: dependabot[bot] * Update bnd --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 4 ++-- io.openems.wrapper/bnd.bnd | 4 ++-- io.openems.wrapper/fastexcel.bnd | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 916c49e9d6..666096bbac 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -260,12 +260,12 @@ org.dhatim fastexcel - 0.18.2 + 0.18.4 org.dhatim fastexcel-reader - 0.18.2 + 0.18.4 diff --git a/io.openems.wrapper/bnd.bnd b/io.openems.wrapper/bnd.bnd index c709d538e3..d024f94a58 100644 --- a/io.openems.wrapper/bnd.bnd +++ b/io.openems.wrapper/bnd.bnd @@ -24,7 +24,7 @@ Bundle-Description: This wraps external java libraries that do not have OSGi hea com.google.gson;version='2.10.1',\ de.bytefish:pgbulkinsert;version='8.1.4',\ fr.turri:aXMLRPC;version='1.13.0',\ - org.dhatim:fastexcel;version='0.18.2',\ - org.dhatim:fastexcel-reader;version='0.18.2',\ + org.dhatim:fastexcel;version='0.18.4',\ + org.dhatim:fastexcel-reader;version='0.18.4',\ org.eclipse.paho.mqttv5.client;version='1.2.5',\ org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm;version='1.9.0',\ diff --git a/io.openems.wrapper/fastexcel.bnd b/io.openems.wrapper/fastexcel.bnd index 5e05cab91a..68c2302413 100644 --- a/io.openems.wrapper/fastexcel.bnd +++ b/io.openems.wrapper/fastexcel.bnd @@ -1,11 +1,11 @@ Bundle-Name: fastexcel Bundle-DocURL: https://github.com/dhatim/fastexcel Bundle-License: https://opensource.org/licenses/Apache-2.0 -Bundle-Version: 0.18.2 +Bundle-Version: 0.18.4 Include-Resource: \ - @fastexcel-0.18.2.jar,\ - @fastexcel-reader-0.18.2.jar,\ + @fastexcel-0.18.4.jar,\ + @fastexcel-reader-0.18.4.jar,\ -dsannotations: * From 94f1cc69dc8395b8d019734fc75592032a0583c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:35:35 +0200 Subject: [PATCH 16/24] Build(deps): Bump com.zaxxer:HikariCP from 5.1.0 to 6.0.0 in /cnf (#2817) * Build(deps): Bump com.zaxxer:HikariCP from 5.1.0 to 6.0.0 in /cnf Bumps [com.zaxxer:HikariCP](https://github.com/brettwooldridge/HikariCP) from 5.1.0 to 6.0.0. - [Changelog](https://github.com/brettwooldridge/HikariCP/blob/dev/CHANGES) - [Commits](https://github.com/brettwooldridge/HikariCP/compare/HikariCP-5.1.0...HikariCP-6.0.0) --- updated-dependencies: - dependency-name: com.zaxxer:HikariCP dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 666096bbac..83b8c69ddd 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -97,7 +97,7 @@ com.zaxxer HikariCP - 5.1.0 + 6.0.0 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 91d486066c..e210938f4f 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -65,7 +65,7 @@ com.google.guava;version='[33.3.1,33.3.2)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ com.squareup.okio;version='[3.9.1,3.9.2)',\ - com.zaxxer.HikariCP;version='[5.1.0,5.1.1)',\ + com.zaxxer.HikariCP;version='[6.0.0,6.0.1)',\ io.openems.backend.alerting;version=snapshot,\ io.openems.backend.application;version=snapshot,\ io.openems.backend.b2brest;version=snapshot,\ From 2f62829b27d69d01cfb447e8d90be4ab166208e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:39:12 +0200 Subject: [PATCH 17/24] Build(deps): Bump swiper from 11.1.11 to 11.1.14 in /ui (#2802) Bumps [swiper](https://github.com/nolimits4web/Swiper) from 11.1.11 to 11.1.14. - [Release notes](https://github.com/nolimits4web/Swiper/releases) - [Changelog](https://github.com/nolimits4web/swiper/blob/master/CHANGELOG.md) - [Commits](https://github.com/nolimits4web/Swiper/compare/v11.1.11...v11.1.14) --- updated-dependencies: - dependency-name: swiper dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 57e8255f84..2c5bd5dfaa 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -51,7 +51,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.11", + "swiper": "11.1.14", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.14.7" @@ -22989,9 +22989,9 @@ } }, "node_modules/swiper": { - "version": "11.1.11", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.11.tgz", - "integrity": "sha512-077Aw3OrlZpkkBRf/6+44bGh/HZY/vsLEyate2db2KkJgYUIR5TvDgvvhcJtW/puXzw79w5KBc30DauEX6GZYQ==", + "version": "11.1.14", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.14.tgz", + "integrity": "sha512-VbQLQXC04io6AoAjIUWuZwW4MSYozkcP9KjLdrsG/00Q/yiwvhz9RQyt0nHXV10hi9NVnDNy1/wv7Dzq1lkOCQ==", "funding": [ { "type": "patreon", @@ -23002,7 +23002,6 @@ "url": "http://opencollective.com/swiper" } ], - "license": "MIT", "engines": { "node": ">= 4.7.0" } diff --git a/ui/package.json b/ui/package.json index 8f0c436942..8bdb4be191 100644 --- a/ui/package.json +++ b/ui/package.json @@ -46,7 +46,7 @@ "ngx-spinner": "^16.0.2", "roboto-fontface": "^0.10.0", "rxjs": "~6.6.7", - "swiper": "11.1.11", + "swiper": "11.1.14", "tslib": "^2.6.2", "uuid": "^10.0.0", "zone.js": "~0.14.7" From c1660e610709da3d56b4350bf86ee05a2d83c9ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:55:28 +0200 Subject: [PATCH 18/24] Build(deps): Bump @capacitor-community/file-opener in /ui (#2787) Bumps [@capacitor-community/file-opener](https://github.com/capacitor-community/file-opener) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/capacitor-community/file-opener/releases) - [Changelog](https://github.com/capacitor-community/file-opener/blob/master/CHANGELOG.md) - [Commits](https://github.com/capacitor-community/file-opener/compare/v6.0.0...v6.0.1) --- updated-dependencies: - dependency-name: "@capacitor-community/file-opener" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 9 ++++----- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 2c5bd5dfaa..482e41f096 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -17,7 +17,7 @@ "@angular/platform-browser-dynamic": "18.0.5", "@angular/router": "18.0.5", "@angular/service-worker": "18.0.5", - "@capacitor-community/file-opener": "^6.0.0", + "@capacitor-community/file-opener": "^6.0.1", "@capacitor/android": "^6.0.0", "@capacitor/app": "^6.0.0", "@capacitor/core": "^6.0.0", @@ -3315,10 +3315,9 @@ } }, "node_modules/@capacitor-community/file-opener": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@capacitor-community/file-opener/-/file-opener-6.0.0.tgz", - "integrity": "sha512-nJ9S5rCqnVDBKfqdjDhrYOIO9JLeScFkRfKLs2G+d6Df73vrJMes8dr+dGSEvKiPhyjRhICW5imDJEbzaD8KpA==", - "license": "MIT", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@capacitor-community/file-opener/-/file-opener-6.0.1.tgz", + "integrity": "sha512-6DMcCVZPWnx1ewlCcciDGQ9n+hZt7ixLuSMv5U2epyZJ44vdLXEKjZvwU+Wpdpmsq5p0pT9jExDODFdc+DNCsw==", "engines": { "node": ">=16.0.0", "npm": ">=8.0.0" diff --git a/ui/package.json b/ui/package.json index 8bdb4be191..54462d2b15 100644 --- a/ui/package.json +++ b/ui/package.json @@ -12,7 +12,7 @@ "@angular/platform-browser-dynamic": "18.0.5", "@angular/router": "18.0.5", "@angular/service-worker": "18.0.5", - "@capacitor-community/file-opener": "^6.0.0", + "@capacitor-community/file-opener": "^6.0.1", "@capacitor/android": "^6.0.0", "@capacitor/app": "^6.0.0", "@capacitor/core": "^6.0.0", From 9c1b60052d3f5d505f784ae855c51fa9dde43cf0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:42:01 +0200 Subject: [PATCH 19/24] Build(deps): Bump serve-static and express in /ui (#2805) Bumps [serve-static](https://github.com/expressjs/serve-static) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together. Updates `serve-static` from 1.15.0 to 1.16.2 - [Release notes](https://github.com/expressjs/serve-static/releases) - [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md) - [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...v1.16.2) Updates `express` from 4.19.2 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) --- updated-dependencies: - dependency-name: serve-static dependency-type: indirect - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 121 ++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 482e41f096..c76483c870 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -8855,11 +8855,10 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -8869,7 +8868,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -12822,7 +12821,6 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12902,38 +12900,37 @@ "license": "Apache-2.0" }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -12959,20 +12956,27 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } }, + "node_modules/express/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -12987,15 +12991,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/express/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -13445,7 +13447,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -17549,11 +17550,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -19475,11 +19478,10 @@ "license": "ISC" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true, - "license": "MIT" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true }, "node_modules/path-type": { "version": "4.0.0", @@ -20394,13 +20396,12 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -21739,11 +21740,10 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -21768,7 +21768,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -21777,15 +21776,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/send/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -21797,15 +21794,13 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/send/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21897,21 +21892,29 @@ "license": "ISC" }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, - "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", From 4b8aeb778bed2c0d2aa612656ff6cac7001a42a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:18:00 +0200 Subject: [PATCH 20/24] Build(deps): Bump vite and @angular-devkit/build-angular in /ui (#2808) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) to 5.4.6 and updates ancestor dependency [@angular-devkit/build-angular](https://github.com/angular/angular-cli). These dependencies need to be updated together. Updates `vite` from 5.4.0 to 5.4.6 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v5.4.6/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v5.4.6/packages/vite) Updates `@angular-devkit/build-angular` from 18.2.2 to 18.2.5 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/18.2.2...18.2.5) --- updated-dependencies: - dependency-name: vite dependency-type: indirect - dependency-name: "@angular-devkit/build-angular" dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 587 ++++++++++++++----------------------------- ui/package.json | 2 +- 2 files changed, 185 insertions(+), 404 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index c76483c870..0241d54a2c 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -57,7 +57,7 @@ "zone.js": "~0.14.7" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.0.5", + "@angular-devkit/build-angular": "^18.2.5", "@angular-devkit/core": "18.0.5", "@angular-devkit/schematics": "18.0.5", "@angular-eslint/builder": "^18.1.0", @@ -118,13 +118,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1802.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.2.tgz", - "integrity": "sha512-LPRl9jhcf0NgshaL6RoUy1uL/cAyNt7oxctoZ9EHUu8eh5E9W/jZGhVowjOLpirwqYhmEzKJJIeS49Ssqs3RQg==", + "version": "0.1802.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.5.tgz", + "integrity": "sha512-c7sVoW85Yqj7IYvNKxtNSGS5I7gWpORorg/xxLZX3OkHWXDrwYbb5LN/2p5/Aytxyb0aXl4o5fFOu6CUwcaLUw==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.2", + "@angular-devkit/core": "18.2.5", "rxjs": "7.8.1" }, "engines": { @@ -134,11 +133,10 @@ } }, "node_modules/@angular-devkit/architect/node_modules/@angular-devkit/core": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.2.tgz", - "integrity": "sha512-Zz0tGptI/QQnUBDdp+1G5wGwQWMjpfe2oO+UohkrDVgFS71yVj4VDnOy51kMTxBvzw+36evTgthPpmzqPIfxBw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", + "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -166,7 +164,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -183,23 +180,21 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.2.tgz", - "integrity": "sha512-7HEnTN2T1jnjuItXKcApOsoYGgfou4+POju3ZbwIQukDZ3B2COskvQkVTxqPNrQ0ZjT2mxZYoVlmGW9M+7N25g==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.5.tgz", + "integrity": "sha512-dIvb0AHoRIMM6tLuG4t6lDDslSAYP77wqytodsN317UzFOuuCPernXbO8NJs+QHxj09nPsem1T5vnvpO2E/PVQ==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.2", - "@angular-devkit/build-webpack": "0.1802.2", - "@angular-devkit/core": "18.2.2", - "@angular/build": "18.2.2", + "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/build-webpack": "0.1802.5", + "@angular-devkit/core": "18.2.5", + "@angular/build": "18.2.5", "@babel/core": "7.25.2", "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", @@ -210,7 +205,7 @@ "@babel/preset-env": "7.25.3", "@babel/runtime": "7.25.0", "@discoveryjs/json-ext": "0.6.1", - "@ngtools/webpack": "18.2.2", + "@ngtools/webpack": "18.2.5", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -250,10 +245,10 @@ "terser": "5.31.6", "tree-kill": "1.2.2", "tslib": "2.6.3", - "vite": "5.4.0", + "vite": "5.4.6", "watchpack": "2.4.1", "webpack": "5.94.0", - "webpack-dev-middleware": "7.3.0", + "webpack-dev-middleware": "7.4.2", "webpack-dev-server": "5.0.4", "webpack-merge": "6.0.1", "webpack-subresource-integrity": "5.1.0" @@ -318,11 +313,10 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.2.tgz", - "integrity": "sha512-Zz0tGptI/QQnUBDdp+1G5wGwQWMjpfe2oO+UohkrDVgFS71yVj4VDnOy51kMTxBvzw+36evTgthPpmzqPIfxBw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", + "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -346,14 +340,13 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.2.tgz", - "integrity": "sha512-okaDdTMXnDhvnnnih6rPQnexL6htfEAPr19bB1Ci9d31gEjVuKZCjlcw2sPZ6BUyilwC9nZlCI5vbH1Ljf6mzA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.5.tgz", + "integrity": "sha512-XWkmjzgeUga0SJ0lYSYcTuYOWTyqcln2mNfBp7Ae/GZ+/7+APbedsIZEiZGZwveOIyOpTM5wguNSoe9khDl5Ig==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.2", + "@angular-devkit/architect": "0.1802.5", "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -375,7 +368,7 @@ "rollup": "4.20.0", "sass": "1.77.6", "semver": "7.6.3", - "vite": "5.4.0", + "vite": "5.4.6", "watchpack": "2.4.1" }, "engines": { @@ -422,7 +415,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -436,7 +428,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -450,7 +441,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -464,7 +454,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -478,7 +467,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -492,7 +480,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -506,7 +493,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -520,7 +506,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -534,7 +519,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -548,7 +532,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -562,7 +545,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -576,7 +558,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -590,7 +571,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -604,7 +584,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -618,7 +597,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -632,7 +610,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -643,7 +620,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -656,11 +632,10 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -673,7 +648,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -685,22 +659,19 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@angular-devkit/build-angular/node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@angular-devkit/build-angular/node_modules/listr2": { "version": "8.2.4", "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, - "license": "MIT", "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", @@ -718,7 +689,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "1.0.5" }, @@ -754,7 +724,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -764,7 +733,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -782,7 +750,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -797,15 +764,13 @@ "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true, - "license": "0BSD" + "dev": true }, "node_modules/@angular-devkit/build-angular/node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", @@ -819,13 +784,12 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.2.tgz", - "integrity": "sha512-Pj+YmKh0nJOKl6QAsqYh3SqfuVJrFqjyp5WrG9BgfsMD9GCMD+5teMHNYJlp+vG/C8e7VdZp4rqOon8K9Xn4Mw==", + "version": "0.1802.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.5.tgz", + "integrity": "sha512-6qkcrWBdkxojCVHGWcdJaz4G+7QTjFvmc+3g8xvLc9sYvJq1I059gfXhDnC0FxiA0MT4cY/26ECYWUHTD5CJLQ==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.2", + "@angular-devkit/architect": "0.1802.5", "rxjs": "7.8.1" }, "engines": { @@ -843,7 +807,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1793,7 +1756,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.24.7" }, @@ -3700,7 +3662,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -3717,7 +3678,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -3734,7 +3694,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -3751,7 +3710,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -3768,7 +3726,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -3785,7 +3742,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -3802,7 +3758,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3819,7 +3774,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3836,7 +3790,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3853,7 +3806,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3870,7 +3822,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3887,7 +3838,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3904,7 +3854,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3921,7 +3870,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3938,7 +3886,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3955,7 +3902,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3972,7 +3918,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3989,7 +3934,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -4006,7 +3950,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -4023,7 +3966,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -4040,7 +3982,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -4057,7 +3998,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -4074,7 +4014,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -4091,7 +4030,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5687,7 +5625,6 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -5704,7 +5641,6 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/base64": "^1.1.1", "@jsonjoy.com/util": "^1.1.2", @@ -5727,7 +5663,6 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -5749,8 +5684,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@listr2/prompt-adapter-inquirer": { "version": "2.0.13", @@ -5776,7 +5710,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5790,7 +5723,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5804,7 +5736,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5818,7 +5749,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5832,7 +5762,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5846,7 +5775,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5860,7 +5788,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5874,7 +5801,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5888,7 +5814,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5902,7 +5827,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5916,7 +5840,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5930,18 +5853,16 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@ngtools/webpack": { - "version": "18.2.2", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.2.tgz", - "integrity": "sha512-YhADmc+lVjLt3kze07A+yLry2yzcghdclu+7D3EDfa6fG2Pk33HK3MY2I0Z0BO+Ivoq7cV7yxm+naR+Od0Y5ng==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.5.tgz", + "integrity": "sha512-L0n4eHObeqEOYRfSP+e4SeF/dmwxOIFy9xYvYCOUwOLrW4b3+a1+kkT30pqyfL72LFtpf0cmUwaWEFIcWl5PCg==", "dev": true, - "license": "MIT", "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -6491,224 +6412,208 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.2.tgz", - "integrity": "sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.0.tgz", + "integrity": "sha512-/IZQvg6ZR0tAkEi4tdXOraQoWeJy9gbQ/cx4I7k9dJaCk9qrXEcdouxRVz5kZXt5C2bQ9pILoAA+KB4C/d3pfw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.2.tgz", - "integrity": "sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.0.tgz", + "integrity": "sha512-ETHi4bxrYnvOtXeM7d4V4kZWixib2jddFacJjsOjwbgYSRsyXYtZHC4ht134OsslPIcnkqT+TKV4eU8rNBKyyQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.2.tgz", - "integrity": "sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.0.tgz", + "integrity": "sha512-ZWgARzhSKE+gVUX7QWaECoRQsPwaD8ZR0Oxb3aUpzdErTvlEadfQpORPXkKSdKbFci9v8MJfkTtoEHnnW9Ulng==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.2.tgz", - "integrity": "sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.0.tgz", + "integrity": "sha512-h0ZAtOfHyio8Az6cwIGS+nHUfRMWBDO5jXB8PQCARVF6Na/G6XS2SFxDl8Oem+S5ZsHQgtsI7RT4JQnI1qrlaw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.2.tgz", - "integrity": "sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.0.tgz", + "integrity": "sha512-9pxQJSPwFsVi0ttOmqLY4JJ9pg9t1gKhK0JDbV1yUEETSx55fdyCjt39eBQ54OQCzAF0nVGO6LfEH1KnCPvelA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.2.tgz", - "integrity": "sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.0.tgz", + "integrity": "sha512-YJ5Ku5BmNJZb58A4qSEo3JlIG4d3G2lWyBi13ABlXzO41SsdnUKi3HQHe83VpwBVG4jHFTW65jOQb8qyoR+qzg==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.2.tgz", - "integrity": "sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.0.tgz", + "integrity": "sha512-U4G4u7f+QCqHlVg1Nlx+qapZy+QoG+NV6ux+upo/T7arNGwKvKP2kmGM4W5QTbdewWFgudQxi3kDNST9GT1/mg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.2.tgz", - "integrity": "sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.0.tgz", + "integrity": "sha512-aQpNlKmx3amwkA3a5J6nlXSahE1ijl0L9KuIjVOUhfOh7uw2S4piR3mtpxpRtbnK809SBtyPsM9q15CPTsY7HQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.2.tgz", - "integrity": "sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.0.tgz", + "integrity": "sha512-9fx6Zj/7vve/Fp4iexUFRKb5+RjLCff6YTRQl4CoDhdMfDoobWmhAxQWV3NfShMzQk1Q/iCnageFyGfqnsmeqQ==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.2.tgz", - "integrity": "sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.0.tgz", + "integrity": "sha512-VWQiCcN7zBgZYLjndIEh5tamtnKg5TGxyZPWcN9zBtXBwfcGSZ5cHSdQZfQH/GB4uRxk0D3VYbOEe/chJhPGLQ==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.2.tgz", - "integrity": "sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.0.tgz", + "integrity": "sha512-EHmPnPWvyYqncObwqrosb/CpH3GOjE76vWVs0g4hWsDRUVhg61hBmlVg5TPXqF+g+PvIbqkC7i3h8wbn4Gp2Fg==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.2.tgz", - "integrity": "sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.0.tgz", + "integrity": "sha512-tsSWy3YQzmpjDKnQ1Vcpy3p9Z+kMFbSIesCdMNgLizDWFhrLZIoN21JSq01g+MZMDFF+Y1+4zxgrlqPjid5ohg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.2.tgz", - "integrity": "sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.0.tgz", + "integrity": "sha512-anr1Y11uPOQrpuU8XOikY5lH4Qu94oS6j0xrulHk3NkLDq19MlX8Ng/pVipjxBJ9a2l3+F39REZYyWQFkZ4/fw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.2.tgz", - "integrity": "sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.0.tgz", + "integrity": "sha512-7LB+Bh+Ut7cfmO0m244/asvtIGQr5pG5Rvjz/l1Rnz1kDzM02pSX9jPaS0p+90H5I1x4d1FkCew+B7MOnoatNw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.2.tgz", - "integrity": "sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.0.tgz", + "integrity": "sha512-+3qZ4rer7t/QsC5JwMpcvCVPRcJt1cJrYS/TMJZzXIJbxWFQEVhrIc26IhB+5Z9fT9umfVc+Es2mOZgl+7jdJQ==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.2.tgz", - "integrity": "sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.0.tgz", + "integrity": "sha512-YdicNOSJONVx/vuPkgPTyRoAPx3GbknBZRCOUkK84FJ/YTfs/F0vl/YsMscrB6Y177d+yDRcj+JWMPMCgshwrA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -7089,7 +6994,6 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, - "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -7100,7 +7004,6 @@ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7110,7 +7013,6 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7120,7 +7022,6 @@ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, - "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -7172,7 +7073,6 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -7185,7 +7085,6 @@ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -7207,8 +7106,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/http-proxy": { "version": "1.17.15", @@ -7290,7 +7188,6 @@ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7327,8 +7224,7 @@ "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", @@ -7353,7 +7249,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } @@ -7363,7 +7258,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -7382,7 +7276,6 @@ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7406,7 +7299,6 @@ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7767,7 +7659,6 @@ "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.6.0" }, @@ -8202,7 +8093,6 @@ "engines": [ "node >= 0.8.0" ], - "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -8311,8 +8201,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/array-ify": { "version": "1.0.0", @@ -8781,8 +8670,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", @@ -8913,7 +8801,6 @@ "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -9098,7 +8985,6 @@ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, - "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" }, @@ -9822,7 +9708,6 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, - "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -9835,7 +9720,6 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -9854,7 +9738,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9864,7 +9747,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -9873,15 +9755,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/concat-map": { "version": "0.0.1", @@ -9911,7 +9791,6 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8" } @@ -9938,7 +9817,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -10226,8 +10104,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cookiejar": { "version": "2.1.4", @@ -10408,7 +10285,6 @@ "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.24.tgz", "integrity": "sha512-Oyqew0FGM0wYUSNqR0L6AteO5MpMoUU0rhKRieXeiKs+PmRTxiJMyaunYB2KF6fQ3dzChXKCpbFOEJx3OQ1v/Q==", "dev": true, - "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -10424,7 +10300,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -10440,7 +10315,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -10457,7 +10331,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -10469,15 +10342,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/critters/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -10487,7 +10358,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -10571,7 +10441,6 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -11242,7 +11111,6 @@ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, - "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" @@ -11259,7 +11127,6 @@ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -11272,7 +11139,6 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -11285,7 +11151,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -11309,7 +11174,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -11322,7 +11186,6 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -11331,8 +11194,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/defaults": { "version": "1.0.4", @@ -11369,7 +11231,6 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -11514,8 +11375,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/dezalgo": { "version": "1.0.4", @@ -11563,7 +11423,6 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, - "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -11602,7 +11461,6 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, - "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -11630,7 +11488,6 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -11646,7 +11503,6 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -12115,7 +11971,6 @@ "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -12946,7 +12801,6 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13114,8 +12968,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fastq": { "version": "1.17.1", @@ -13132,7 +12985,6 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, - "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -13423,7 +13275,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -14082,8 +13933,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/handlebars": { "version": "4.7.8", @@ -14345,7 +14195,6 @@ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, - "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -14357,15 +14206,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14380,15 +14227,13 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -14407,8 +14252,7 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ], - "license": "MIT" + ] }, "node_modules/html-escaper": { "version": "2.0.2", @@ -14429,7 +14273,6 @@ "url": "https://github.com/sponsors/fb55" } ], - "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -14448,8 +14291,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-errors": { "version": "2.0.0", @@ -14482,8 +14324,7 @@ "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-proxy": { "version": "1.18.1", @@ -14577,7 +14418,6 @@ "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.18" } @@ -14920,7 +14760,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10" } @@ -15058,7 +14897,6 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, - "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -15107,7 +14945,6 @@ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, - "license": "MIT", "dependencies": { "is-docker": "^3.0.0" }, @@ -15155,7 +14992,6 @@ "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "dev": true, - "license": "MIT", "engines": { "node": ">=16" }, @@ -15422,7 +15258,6 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, - "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -16388,11 +16223,10 @@ } }, "node_modules/launch-editor": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.1.tgz", - "integrity": "sha512-elBx2l/tp9z99X5H/qev8uyDywVh0VXAwEbjk8kJhnc5grOFkGh7aW6q55me9xnYbss261XtnUrysZ+XvGbhQA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "dev": true, - "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -16708,7 +16542,6 @@ "integrity": "sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "dependencies": { "msgpackr": "^1.10.2", "node-addon-api": "^6.1.0", @@ -16732,8 +16565,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/load-json-file": { "version": "4.0.0", @@ -17275,7 +17107,6 @@ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } @@ -17351,11 +17182,10 @@ } }, "node_modules/memfs": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", - "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.12.0.tgz", + "integrity": "sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", "@jsonjoy.com/util": "^1.3.0", @@ -17740,8 +17570,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/minimatch": { "version": "9.0.5", @@ -18003,7 +17832,6 @@ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -18020,7 +17848,6 @@ "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.0.tgz", "integrity": "sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==", "dev": true, - "license": "MIT", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } @@ -18031,7 +17858,6 @@ "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "dependencies": { "node-gyp-build-optional-packages": "5.2.2" @@ -18053,7 +17879,6 @@ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, - "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -18257,7 +18082,6 @@ "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "!win32" @@ -18285,7 +18109,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, - "license": "MIT", "optional": true }, "node_modules/node-fetch": { @@ -18314,7 +18137,6 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } @@ -18349,7 +18171,6 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", "dev": true, - "license": "MIT", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -18362,7 +18183,6 @@ "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "dev": true, - "license": "MIT", "dependencies": { "detect-libc": "^2.0.1" }, @@ -18914,8 +18734,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/on-finished": { "version": "2.4.1", @@ -18935,7 +18754,6 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -18970,7 +18788,6 @@ "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, - "license": "MIT", "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", @@ -19099,8 +18916,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/os-name": { "version": "4.0.1", @@ -19182,7 +18998,6 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, - "license": "MIT", "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", @@ -19200,7 +19015,6 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } @@ -19376,7 +19190,6 @@ "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, - "license": "MIT", "dependencies": { "entities": "^4.3.0", "parse5": "^7.0.0", @@ -19391,7 +19204,6 @@ "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, - "license": "MIT", "dependencies": { "parse5": "^7.0.0" }, @@ -19508,11 +19320,10 @@ "license": "MIT" }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true, - "license": "ISC" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true }, "node_modules/picomatch": { "version": "4.0.2", @@ -19565,7 +19376,6 @@ "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", "dev": true, - "license": "MIT", "optionalDependencies": { "nice-napi": "^1.0.2" } @@ -19774,8 +19584,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", @@ -20277,7 +20086,6 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -20291,7 +20099,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.10" } @@ -21306,11 +21113,10 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.2.tgz", - "integrity": "sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.0.tgz", + "integrity": "sha512-W21MUIFPZ4+O2Je/EU+GP3iz7PH4pVPUXSbEZdatQnxo29+3rsUjgrJmzuAZU24z7yRAnFN6ukxeAhZh/c7hzg==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "1.0.5" }, @@ -21322,22 +21128,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.21.2", - "@rollup/rollup-android-arm64": "4.21.2", - "@rollup/rollup-darwin-arm64": "4.21.2", - "@rollup/rollup-darwin-x64": "4.21.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.21.2", - "@rollup/rollup-linux-arm-musleabihf": "4.21.2", - "@rollup/rollup-linux-arm64-gnu": "4.21.2", - "@rollup/rollup-linux-arm64-musl": "4.21.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.21.2", - "@rollup/rollup-linux-riscv64-gnu": "4.21.2", - "@rollup/rollup-linux-s390x-gnu": "4.21.2", - "@rollup/rollup-linux-x64-gnu": "4.21.2", - "@rollup/rollup-linux-x64-musl": "4.21.2", - "@rollup/rollup-win32-arm64-msvc": "4.21.2", - "@rollup/rollup-win32-ia32-msvc": "4.21.2", - "@rollup/rollup-win32-x64-msvc": "4.21.2", + "@rollup/rollup-android-arm-eabi": "4.22.0", + "@rollup/rollup-android-arm64": "4.22.0", + "@rollup/rollup-darwin-arm64": "4.22.0", + "@rollup/rollup-darwin-x64": "4.22.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.0", + "@rollup/rollup-linux-arm-musleabihf": "4.22.0", + "@rollup/rollup-linux-arm64-gnu": "4.22.0", + "@rollup/rollup-linux-arm64-musl": "4.22.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.0", + "@rollup/rollup-linux-riscv64-gnu": "4.22.0", + "@rollup/rollup-linux-s390x-gnu": "4.22.0", + "@rollup/rollup-linux-x64-gnu": "4.22.0", + "@rollup/rollup-linux-x64-musl": "4.22.0", + "@rollup/rollup-win32-arm64-msvc": "4.22.0", + "@rollup/rollup-win32-ia32-msvc": "4.22.0", + "@rollup/rollup-win32-x64-msvc": "4.22.0", "fsevents": "~2.3.2" } }, @@ -21356,7 +21162,6 @@ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -21642,8 +21447,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/selenium-webdriver": { "version": "3.6.0", @@ -21717,7 +21521,6 @@ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -21820,7 +21623,6 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -21839,7 +21641,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -21849,7 +21650,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -21859,7 +21659,6 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, - "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -21874,22 +21673,19 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/serve-static": { "version": "1.16.2", @@ -22042,7 +21838,6 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -22347,7 +22142,6 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, - "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -22359,7 +22153,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -22405,11 +22198,10 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -22515,7 +22307,6 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -22532,7 +22323,6 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -23335,7 +23125,6 @@ "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", "dev": true, - "license": "Unlicense", "engines": { "node": ">=10.18" }, @@ -23364,8 +23153,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/tmp": { "version": "0.2.3", @@ -23456,7 +23244,6 @@ "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -24237,15 +24024,14 @@ } }, "node_modules/vite": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", - "integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", + "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.40", - "rollup": "^4.13.0" + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -24304,7 +24090,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -24321,7 +24106,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -24338,7 +24122,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -24355,7 +24138,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -24372,7 +24154,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -24389,7 +24170,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -24406,7 +24186,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24423,7 +24202,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24440,7 +24218,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24457,7 +24234,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24474,7 +24250,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24491,7 +24266,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24508,7 +24282,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24525,7 +24298,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24542,7 +24314,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24559,7 +24330,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24576,7 +24346,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -24593,7 +24362,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -24610,7 +24378,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -24627,7 +24394,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -24644,7 +24410,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -24661,7 +24426,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -24678,7 +24442,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -24693,7 +24456,6 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -24726,6 +24488,34 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/vite/node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -24755,7 +24545,6 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, - "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -24773,8 +24562,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/webdriver-js-extender": { "version": "2.1.0", @@ -25046,11 +24834,10 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.3.0.tgz", - "integrity": "sha512-xD2qnNew+F6KwOGZR7kWdbIou/ud7cVqLEXeK1q0nHcNsX/u7ul/fSdlOTX4ntSL5FNFy7ZJJXbf0piF591JYw==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dev": true, - "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", @@ -25080,7 +24867,6 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", "dev": true, - "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -25140,7 +24926,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, - "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -25161,7 +24946,6 @@ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -25186,7 +24970,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, - "license": "ISC", "dependencies": { "glob": "^10.3.7" }, @@ -25333,7 +25116,6 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -25348,7 +25130,6 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } diff --git a/ui/package.json b/ui/package.json index 54462d2b15..36600afc57 100644 --- a/ui/package.json +++ b/ui/package.json @@ -52,7 +52,7 @@ "zone.js": "~0.14.7" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.0.5", + "@angular-devkit/build-angular": "^18.2.5", "@angular-devkit/core": "18.0.5", "@angular-devkit/schematics": "18.0.5", "@angular-eslint/builder": "^18.1.0", From 6261b09333141c1a53aede44d4085e1be43efe2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:27:47 +0200 Subject: [PATCH 21/24] Build(deps-dev): Bump the eslint group across 1 directory with 3 updates (#2812) Bumps the eslint group with 3 updates in the /ui directory: [@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin), [@typescript-eslint/types](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/types) and [eslint-plugin-unused-imports](https://github.com/sweepline/eslint-plugin-unused-imports). Updates `@stylistic/eslint-plugin` from 2.7.2 to 2.8.0 - [Release notes](https://github.com/eslint-stylistic/eslint-stylistic/releases) - [Changelog](https://github.com/eslint-stylistic/eslint-stylistic/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint-stylistic/eslint-stylistic/commits/v2.8.0/packages/eslint-plugin) Updates `@typescript-eslint/types` from 7.18.0 to 8.7.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/types/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.7.0/packages/types) Updates `eslint-plugin-unused-imports` from 4.1.3 to 4.1.4 - [Commits](https://github.com/sweepline/eslint-plugin-unused-imports/compare/v4.1.3...v4.1.4) --- updated-dependencies: - dependency-name: "@stylistic/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: "@typescript-eslint/types" dependency-type: direct:development update-type: version-update:semver-major dependency-group: eslint - dependency-name: eslint-plugin-unused-imports dependency-type: direct:development update-type: version-update:semver-patch dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 180 +++++++++++++++++++++++++++---------------- ui/package.json | 6 +- 2 files changed, 115 insertions(+), 71 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 0241d54a2c..3fe21c3640 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -72,7 +72,7 @@ "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", "@ionic/cli": "^7.2.0", - "@stylistic/eslint-plugin": "^2.7.2", + "@stylistic/eslint-plugin": "^2.8.0", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/json-schema": "^7.0.15", @@ -83,12 +83,12 @@ "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^7.0.0", - "@typescript-eslint/types": "^7.0.0", + "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-jsdoc": "48.10.0", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^4.1.3", + "eslint-plugin-unused-imports": "^4.1.4", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", @@ -6834,14 +6834,12 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.7.2.tgz", - "integrity": "sha512-3DVLU5HEuk2pQoBmXJlzvrxbKNpu2mJ0SRqz5O/CJjyNCr12ZiPcYMEtuArTyPOk5i7bsAU44nywh1rGfe3gKQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.8.0.tgz", + "integrity": "sha512-Ufvk7hP+bf+pD35R/QfunF793XlSRIC7USr3/EdgduK9j13i2JjmsM0LUz3/foS+jDYp2fzyWZA9N44CPur0Ow==", "dev": true, - "license": "MIT", "dependencies": { - "@types/eslint": "^9.6.1", - "@typescript-eslint/utils": "^8.3.0", + "@typescript-eslint/utils": "^8.4.0", "eslint-visitor-keys": "^4.0.0", "espree": "^10.1.0", "estraverse": "^5.3.0", @@ -7050,17 +7048,6 @@ "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -7337,6 +7324,19 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", @@ -7389,6 +7389,19 @@ } } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", @@ -7407,6 +7420,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/type-utils": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", @@ -7435,6 +7461,19 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", @@ -7459,13 +7498,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", + "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", "dev": true, - "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -7501,38 +7539,29 @@ } } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.3.0.tgz", - "integrity": "sha512-F77WwqxIi/qGkIGOGXNBLV7nykwfjLsdauRB/DOFPdv6LTF3BHHkBpq81/b5iMPSF055oO2BiivDJV4ChvNtXA==", + "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.3.0", - "@typescript-eslint/types": "8.3.0", - "@typescript-eslint/typescript-estree": "8.3.0" - }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.3.0.tgz", - "integrity": "sha512-mz2X8WcN2nVu5Hodku+IR8GgCOl4C0G/Z1ruaWN4dgec64kDBabuXyPAr+/RgJtumv8EEkqIzf3X2U5DUKB2eg==", + "node_modules/@typescript-eslint/utils": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", + "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.3.0", - "@typescript-eslint/visitor-keys": "8.3.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.7.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/typescript-estree": "8.7.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7540,14 +7569,20 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.3.0.tgz", - "integrity": "sha512-y6sSEeK+facMaAyixM36dQ5NVXTnKWunfD1Ft4xraYqxP0lC0POJmIaL/mw72CUMqjY9qfyVfXafMeaUj0noWw==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", + "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", "dev": true, - "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -7557,14 +7592,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.3.0.tgz", - "integrity": "sha512-Mq7FTHl0R36EmWlCJWojIC1qn/ZWo2YiWYc1XVtasJ7FIgjo0MVv9rZWXEE7IK2CGrtwe1dVOxWwqXUdNgfRCA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", + "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.3.0", - "@typescript-eslint/visitor-keys": "8.3.0", + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -7586,13 +7620,12 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.3.0.tgz", - "integrity": "sha512-RmZwrTbQ9QveF15m/Cl28n0LXD6ea2CjkhH5rQ55ewz3H24w+AMCJHPVYaZ8/0HoG8Z3cLLFFycRXxeO2tz9FA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", + "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.3.0", + "@typescript-eslint/types": "8.7.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -7608,7 +7641,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -7634,6 +7666,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", @@ -12321,11 +12366,10 @@ } }, "node_modules/eslint-plugin-unused-imports": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.3.tgz", - "integrity": "sha512-lqrNZIZjFMUr7P06eoKtQLwyVRibvG7N+LtfKtObYGizAAGrcqLkc3tDx+iAik2z7q0j/XI3ihjupIqxhFabFA==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz", + "integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==", "dev": true, - "license": "MIT", "peerDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", "eslint": "^9.0.0 || ^8.0.0" diff --git a/ui/package.json b/ui/package.json index 36600afc57..62d980810a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -67,7 +67,7 @@ "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", "@ionic/cli": "^7.2.0", - "@stylistic/eslint-plugin": "^2.7.2", + "@stylistic/eslint-plugin": "^2.8.0", "@types/jasmine": "~4.3.6", "@types/jasminewd2": "~2.0.13", "@types/json-schema": "^7.0.15", @@ -78,12 +78,12 @@ "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^7.0.0", - "@typescript-eslint/types": "^7.0.0", + "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-jsdoc": "48.10.0", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^4.1.3", + "eslint-plugin-unused-imports": "^4.1.4", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", From 4ae1012da6894dcacf215f357f55a0671308d539 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:06:24 +0200 Subject: [PATCH 22/24] Build(deps): Bump @angular/common from 18.0.5 to 18.2.5 in /ui in the angular group across 1 directory (#2811) * Build(deps): Bump @angular/common Bumps the angular group with 1 update in the /ui directory: [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common). Updates `@angular/common` from 18.0.5 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/common) --- updated-dependencies: - dependency-name: "@angular/common" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: angular ... Signed-off-by: dependabot[bot] * Build(deps-dev): Bump @angular-devkit/core from 18.0.5 to 18.2.5 in /ui Bumps [@angular-devkit/core](https://github.com/angular/angular-cli) from 18.0.5 to 18.2.5. - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/18.0.5...18.2.5) --- updated-dependencies: - dependency-name: "@angular-devkit/core" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Build(deps-dev): Bump @angular-devkit/schematics in /ui Bumps [@angular-devkit/schematics](https://github.com/angular/angular-cli) from 18.0.5 to 18.2.5. - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/18.0.5...18.2.5) --- updated-dependencies: - dependency-name: "@angular-devkit/schematics" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- .github/dependabot.yml | 3 +- ui/package-lock.json | 1909 +++++++---------- ui/package.json | 64 +- .../app/shared/components/edge/edgeconfig.ts | 2 +- ui/src/app/shared/service/defaulttypes.ts | 2 +- 5 files changed, 871 insertions(+), 1109 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 37fcbfbbc5..fe2414bdf3 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -25,6 +25,8 @@ updates: angular: patterns: - "@angular/*" + - "@angular-devkit/*" + - "@angular-eslint/*" capacitor: patterns: - "@capacitor/*" @@ -40,7 +42,6 @@ updates: - "karma" eslint: patterns: - - "@angular-eslint/*" - "@stylistic/eslint-plugin" - "@typescript-eslint/*" - "eslint-*" diff --git a/ui/package-lock.json b/ui/package-lock.json index 3fe21c3640..f0ac38c3c7 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -9,27 +9,27 @@ "version": "2024.10.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { - "@angular/animations": "18.0.5", - "@angular/common": "18.0.5", - "@angular/core": "18.0.5", - "@angular/forms": "18.0.5", - "@angular/platform-browser": "18.0.5", - "@angular/platform-browser-dynamic": "18.0.5", - "@angular/router": "18.0.5", - "@angular/service-worker": "18.0.5", + "@angular/animations": "18.2.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/forms": "18.2.5", + "@angular/platform-browser": "18.2.5", + "@angular/platform-browser-dynamic": "18.2.5", + "@angular/router": "18.2.5", + "@angular/service-worker": "18.2.5", "@capacitor-community/file-opener": "^6.0.1", - "@capacitor/android": "^6.0.0", - "@capacitor/app": "^6.0.0", - "@capacitor/core": "^6.0.0", - "@capacitor/filesystem": "^6.0.0", - "@capacitor/ios": "^6.0.0", - "@capacitor/splash-screen": "^6.0.0", + "@capacitor/android": "^6.1.2", + "@capacitor/app": "^6.0.1", + "@capacitor/core": "^6.1.2", + "@capacitor/filesystem": "^6.0.1", + "@capacitor/ios": "^6.1.2", + "@capacitor/splash-screen": "^6.0.2", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", - "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.6", - "@ngx-formly/schematics": "^6.3.0", + "@ngx-formly/core": "^6.3.7", + "@ngx-formly/ionic": "^6.3.7", + "@ngx-formly/schematics": "^6.3.7", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", "capacitor-blob-writer": "^1.1.17", @@ -58,16 +58,16 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^18.2.5", - "@angular-devkit/core": "18.0.5", - "@angular-devkit/schematics": "18.0.5", - "@angular-eslint/builder": "^18.1.0", - "@angular-eslint/eslint-plugin": "^18.1.0", - "@angular-eslint/eslint-plugin-template": "^18.1.0", - "@angular-eslint/template-parser": "^18.1.0", - "@angular/cli": "18.1.0", - "@angular/compiler": "18.0.5", - "@angular/compiler-cli": "18.0.5", - "@angular/language-service": "18.0.5", + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", + "@angular-eslint/builder": "^18.3.1", + "@angular-eslint/eslint-plugin": "^18.3.1", + "@angular-eslint/eslint-plugin-template": "^18.3.1", + "@angular-eslint/template-parser": "^18.3.1", + "@angular/cli": "18.2.5", + "@angular/compiler": "18.2.5", + "@angular/compiler-cli": "18.2.5", + "@angular/language-service": "18.2.5", "@capacitor/assets": "^3.0.5", "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", @@ -77,7 +77,7 @@ "@types/jasminewd2": "~2.0.13", "@types/json-schema": "^7.0.15", "@types/node": "^20.12.6", - "@types/qs": "^6.9.15", + "@types/qs": "^6.9.16", "@types/range-parser": "^1.2.7", "@types/send": "^0.17.4", "@types/uuid": "^10.0.0", @@ -85,13 +85,13 @@ "@typescript-eslint/parser": "^7.0.0", "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", - "eslint-plugin-import": "2.29.1", - "eslint-plugin-jsdoc": "48.10.0", + "eslint-plugin-import": "2.30.0", + "eslint-plugin-jsdoc": "50.2.4", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-unused-imports": "^4.1.4", - "jasmine-core": "~4.5.0", + "jasmine-core": "~5.3.0", "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.4.2", + "karma": "~6.4.4", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.1", "karma-coverage-istanbul-reporter": "~3.0.3", @@ -132,49 +132,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/architect/node_modules/@angular-devkit/core": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", - "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", - "dev": true, - "dependencies": { - "ajv": "8.17.1", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/architect/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@angular-devkit/architect/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -312,7 +269,50 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1802.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.5.tgz", + "integrity": "sha512-6qkcrWBdkxojCVHGWcdJaz4G+7QTjFvmc+3g8xvLc9sYvJq1I059gfXhDnC0FxiA0MT4cY/26ECYWUHTD5CJLQ==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1802.5", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/core": { "version": "18.2.5", "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", @@ -339,11 +339,147 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.5.tgz", + "integrity": "sha512-NUmz2UQ1Xl4cf4j1AgkwIfsCjBzAPgfeC3IBrD29hSOBE1Y3j6auqjBkvw50v6mbSPxESND995Xy13HpK1Xflw==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "18.2.5", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.11", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-eslint/builder": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.1.tgz", + "integrity": "sha512-cPc7Ye9zDs5M4i+feL6vob+mh7yX5vxvOS5KQIhneUrp5e9D+IGuNFMmBLlOPpmklSc9XJBtuvI5Zjuh4z1ETw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.1.tgz", + "integrity": "sha512-sikmkjfsXPpPTku1aQkQ1MNNEKGBgGGRvUN/WeNS9dhCJ4dxU3O7dZctt1aQWj+W3nbuUtDiimAWF5fZHGFE2Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-eslint/eslint-plugin": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.1.tgz", + "integrity": "sha512-MP4Nm+SHboF8KdnN0KpPEGAaTTzDLPm3+S/4W3Mg8onqWCyadyd4mActh9mK/pvCj8TVlb/SW1zeTtdMYhwonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.1.tgz", + "integrity": "sha512-hBJ3+f7VSidvrtYaXH7Vp0sWvblA9jLK2c6uQzhYGWdEDUcTg7g7VI9ThW39WvMbHqkyzNE4PPOynK69cBEDGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1", + "aria-query": "5.3.0", + "axobject-query": "4.1.0" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/template-parser": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.1.tgz", + "integrity": "sha512-JUUkfWH1G+u/Uk85ZYvJSt/qwN/Ko+jlXFtzBEcknJZsTWTwBcp36v77gPZe5FmKSziJZpyPUd+7Kiy6tuSCTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "eslint-scope": "^8.0.2" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/utils": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.1.tgz", + "integrity": "sha512-sd9niZI7h9H2FQ7OLiQsLFBhjhRQTASh+Q0+4+hyjv9idbSHBJli8Gsi2fqj9zhtMKpAZFTrWzuLUpubJ9UYbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular/animations": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.5.tgz", + "integrity": "sha512-IlXtW/Nj48ZzjHUzH1TykZcSR64ScJx39T3IHnjV2z/bVATzZ36JGoadQHdqpJNKBodYJNgtJCGLCbgAvGWY2g==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/core": "18.2.5" + } + }, + "node_modules/@angular/build": { "version": "18.2.5", "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.5.tgz", "integrity": "sha512-XWkmjzgeUga0SJ0lYSYcTuYOWTyqcln2mNfBp7Ae/GZ+/7+APbedsIZEiZGZwveOIyOpTM5wguNSoe9khDl5Ig==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", "@angular-devkit/architect": "0.1802.5", @@ -407,7 +543,7 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm-eabi": { + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", @@ -415,12 +551,13 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm64": { + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm64": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", @@ -428,12 +565,13 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-arm64": { + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-arm64": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", @@ -441,12 +579,13 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-x64": { + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-x64": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", @@ -454,12 +593,13 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", @@ -467,12 +607,13 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", @@ -480,12 +621,13 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", @@ -493,12 +635,13 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-musl": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", @@ -506,12 +649,13 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", @@ -519,12 +663,13 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", @@ -532,12 +677,13 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-s390x-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", @@ -545,12 +691,13 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-gnu": { + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.20.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", @@ -558,445 +705,102 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", - "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", - "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", - "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", - "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@angular-devkit/build-angular/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/emoji-regex": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", - "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/listr2": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", - "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", - "dev": true, - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/rollup": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", - "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.20.0", - "@rollup/rollup-android-arm64": "4.20.0", - "@rollup/rollup-darwin-arm64": "4.20.0", - "@rollup/rollup-darwin-x64": "4.20.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", - "@rollup/rollup-linux-arm-musleabihf": "4.20.0", - "@rollup/rollup-linux-arm64-gnu": "4.20.0", - "@rollup/rollup-linux-arm64-musl": "4.20.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", - "@rollup/rollup-linux-riscv64-gnu": "4.20.0", - "@rollup/rollup-linux-s390x-gnu": "4.20.0", - "@rollup/rollup-linux-x64-gnu": "4.20.0", - "@rollup/rollup-linux-x64-musl": "4.20.0", - "@rollup/rollup-win32-arm64-msvc": "4.20.0", - "@rollup/rollup-win32-ia32-msvc": "4.20.0", - "@rollup/rollup-win32-x64-msvc": "4.20.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/wrap-ansi": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", - "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.5.tgz", - "integrity": "sha512-6qkcrWBdkxojCVHGWcdJaz4G+7QTjFvmc+3g8xvLc9sYvJq1I059gfXhDnC0FxiA0MT4cY/26ECYWUHTD5CJLQ==", - "dev": true, - "dependencies": { - "@angular-devkit/architect": "0.1802.5", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^5.0.2" - } - }, - "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/core": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.0.5.tgz", - "integrity": "sha512-sGtrS0SqkcBvyuv0QkIfyadwPgDhMroz1r51lMh1hwzJaJ0LNuVMLviEeYIybeBnvAdp9YvYC8I1WgB/FUEFBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.13.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.2.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/core/node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-devkit/core/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/schematics": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.0.5.tgz", - "integrity": "sha512-hZwAq3hwuJzCuh7uqO/7T9IMERhYVxz+ganJlEykpyr58o0IjUM1Q4ZSH5UOYlGRPdBCZJbfiafZ0Sg5w5xBww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "18.0.5", - "jsonc-parser": "3.2.1", - "magic-string": "0.30.10", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-devkit/schematics/node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-eslint/builder": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.0.tgz", - "integrity": "sha512-httEQyqyBw3+0CRtAa7muFxHrauRfkEfk/jmrh5fn2Eiu+I53hAqFPgrwVi1V6AP/kj2zbAiWhd5xM3pMJdoRQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.0.tgz", - "integrity": "sha512-v/59FxUKnMzymVce99gV43huxoqXWMb85aKvzlNvLN+ScDu6ZE4YMiTQNpfapVL2lkxhs0uwB3jH17EYd5TcsA==", + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", + "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.0.tgz", - "integrity": "sha512-Vl7gfPMXxvtHTjYdlzR161aj5xrqW6T57wd8ToQ7Gqzm0qHGfY6kE4SQobUa2LCYckTNSlv+zXe48C4ah/dSjw==", + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", + "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.0", - "@angular-eslint/utils": "18.3.0" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.0.tgz", - "integrity": "sha512-ddR/qwYbUeq9IpyVKrPbfZyRBTy6V8uc5I0JcBKttQ4CZ4joXhqsVgWFsI+JAMi8E66uNj1VC7NuKCOjDINv2Q==", + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", + "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.0", - "@angular-eslint/utils": "18.3.0", - "aria-query": "5.3.0", - "axobject-query": "4.1.0" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@angular-eslint/template-parser": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.0.tgz", - "integrity": "sha512-1mUquqcnugI4qsoxcYZKZ6WMi6RPelDcJZg2YqGyuaIuhWmi3ZqJZLErSSpjP60+TbYZu7wM8Kchqa1bwJtEaQ==", + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", + "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.0", - "eslint-scope": "^8.0.2" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@angular-eslint/utils": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.0.tgz", - "integrity": "sha512-sCrkHkpxBJZLuCikdboZoawCfc2UgbJv+T14tu2uQCv+Vwzeadnu04vkeY2vTkA8GeBdBij/G9/N/nvwmwVw3g==", + "node_modules/@angular/build/node_modules/rollup": { + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", + "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.0" + "@types/estree": "1.0.5" }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular/animations": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.0.5.tgz", - "integrity": "sha512-RYwlS+4I33beAWdzFFmaDPqXZN+r66qPzzMOk9LQguwF76eBJbykHniODalSLvjrY6Iz7CULavByYNpzq2TT7A==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "peerDependencies": { - "@angular/core": "18.0.5" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.20.0", + "@rollup/rollup-android-arm64": "4.20.0", + "@rollup/rollup-darwin-arm64": "4.20.0", + "@rollup/rollup-darwin-x64": "4.20.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", + "@rollup/rollup-linux-arm-musleabihf": "4.20.0", + "@rollup/rollup-linux-arm64-gnu": "4.20.0", + "@rollup/rollup-linux-arm64-musl": "4.20.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", + "@rollup/rollup-linux-riscv64-gnu": "4.20.0", + "@rollup/rollup-linux-s390x-gnu": "4.20.0", + "@rollup/rollup-linux-x64-gnu": "4.20.0", + "@rollup/rollup-linux-x64-musl": "4.20.0", + "@rollup/rollup-win32-arm64-msvc": "4.20.0", + "@rollup/rollup-win32-ia32-msvc": "4.20.0", + "@rollup/rollup-win32-x64-msvc": "4.20.0", + "fsevents": "~2.3.2" } }, "node_modules/@angular/cdk": { @@ -1018,27 +822,27 @@ } }, "node_modules/@angular/cli": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.1.0.tgz", - "integrity": "sha512-2E+b7S/736AOmxf5je9OWoPpgPY240TfJfFXwQiVvq/4KyC+ZR9lBrqRx72Xghn8nu3z8Q2BPZIXVGZppl0USQ==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.5.tgz", + "integrity": "sha512-97uNs0HsOdnMaTlNJKFjIBUXw0wz43uYvSSKmIpBt7eq1LaPLju1G/qpDIHx2YwhMClPrXXrW2H/xdvqZiIw+w==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1801.0", - "@angular-devkit/core": "18.1.0", - "@angular-devkit/schematics": "18.1.0", - "@inquirer/prompts": "5.0.7", - "@listr2/prompt-adapter-inquirer": "2.0.13", - "@schematics/angular": "18.1.0", + "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", + "@inquirer/prompts": "5.3.8", + "@listr2/prompt-adapter-inquirer": "2.0.15", + "@schematics/angular": "18.2.5", "@yarnpkg/lockfile": "1.1.0", "ini": "4.1.3", "jsonc-parser": "3.3.1", - "listr2": "8.2.3", - "npm-package-arg": "11.0.2", - "npm-pick-manifest": "9.0.1", + "listr2": "8.2.4", + "npm-package-arg": "11.0.3", + "npm-pick-manifest": "9.1.0", "pacote": "18.0.6", "resolve": "1.22.8", - "semver": "7.6.2", + "semver": "7.6.3", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -1051,124 +855,10 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { - "version": "0.1801.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1801.0.tgz", - "integrity": "sha512-iZa3J3CrZT6MKiHPw8ijgVwMyCMewCsP4xc75SetUwF/yuqRUHygALs5jJVZQFQjSFUrkg9gqXa1cCjFDwpT8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "18.1.0", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/@angular-devkit/core": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.0.tgz", - "integrity": "sha512-6eXQDzHZCbpSMLv9Ohl+1QyLVDmGEXpuuHz3y64LfUTP0aEiBaxk96FjLXIxzJ4f2pbbW2XHzc+yuboGToRA0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.16.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular/cli/node_modules/@angular-devkit/schematics": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.0.tgz", - "integrity": "sha512-BjrYutLfYFiPOSEcLBWCj3ENkwDn8gMfBSJesaBz7OrZBZGK5j0dVgBLIsGTP96TKo4o4vszJQOvS4AtV6xMGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "18.1.0", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.10", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular/cli/node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/@angular/cli/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular/cli/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular/common": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.0.5.tgz", - "integrity": "sha512-yItVQSu+Rx8gthWJDTOHwbzItY8/lqmmmYA1RMex0u3GkJoX3/3TZSGXbbBXl8GH8vmQOfp9yj3C02JmlwldRg==", - "license": "MIT", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.5.tgz", + "integrity": "sha512-m+KJrtbFXTE36jP/po6UAMeUR/enQxRHpVGLCRcIcE7VWVH1ZcOvoW1yqh2A6k+KxWXeajlq/Z04nnMhcoxMRw==", "dependencies": { "tslib": "^2.3.0" }, @@ -1176,14 +866,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.0.5", + "@angular/core": "18.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.0.5.tgz", - "integrity": "sha512-U1/qjNDjxMukXwQrJZjmr87KVxQmHbD7fxVlg0+qafHLe+YDuCtyOfQSGEZrWhwktxvAYZbl3FK+m3Hnk/D3Nw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.5.tgz", + "integrity": "sha512-vcqe9x4dGGAnMfPhEpcZyiSVgAiqJeK80LqP1vWoAmBR+HeOqAilSv6SflcLAtuTzwgzMMAvD2T+SMCgUvaqww==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1192,7 +882,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.0.5" + "@angular/core": "18.2.5" }, "peerDependenciesMeta": { "@angular/core": { @@ -1201,13 +891,13 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.0.5.tgz", - "integrity": "sha512-aFKDDTsRmc691EkNRj9OkrKNXDOaHdXB42MyUrj3WwJIJFMnSY/UDf6h+CRVF0U+CITszFyWhmeHQRA/3mJWNg==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.5.tgz", + "integrity": "sha512-CCCtZobUTUfId/RTYtuDCw5R1oK0w65hdAUMRP1MdGmd8bb8DKJA86u1QCWwozL3rbXlIIX4ognQ6urQ43k/Gw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "7.24.7", + "@babel/core": "7.25.2", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", @@ -1225,62 +915,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.0.5", - "typescript": ">=5.4 <5.5" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "@angular/compiler": "18.2.5", + "typescript": ">=5.4 <5.6" } }, "node_modules/@angular/core": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.0.5.tgz", - "integrity": "sha512-0UuL+aMMWGYksz09YBsiHq1li7GmL8obB3IC3T5MwDqnn7FGRUBfBUOZEkM6B+pwgg+RAtNdJkbCfbh1z74bFQ==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.5.tgz", + "integrity": "sha512-5BLVc5gXxzanQkADNS9WPsor3vNF5nQcyIHBi5VScErwM5vVZ7ATH1iZwaOg1ykDEVTFVhKDwD0X1aaqGDbhmQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1290,13 +932,13 @@ }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.14.0" + "zone.js": "~0.14.10" } }, "node_modules/@angular/forms": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.0.5.tgz", - "integrity": "sha512-nO7bN+nO2/czgKSvPx6ewqpfb8xXOyns06uovWpAXSH4jYoiZ6CHTHhOKrOL/3SRkhUV9u+EUXTTAOSBkS+OBA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.5.tgz", + "integrity": "sha512-ohKeH+EZCCIyGSiFYlraWLzssGAZc13P92cuYpXB62322PkcA5u0IT72mML9JWGKRqF2zteVsw4koWHVxXM5mA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1305,16 +947,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.5", - "@angular/core": "18.0.5", - "@angular/platform-browser": "18.0.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/platform-browser": "18.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.0.5.tgz", - "integrity": "sha512-ahZnsUk8q/4k+okP9hBcfWRiOiMximSAI7Vq5M/fe9cezykt8cWEzxgRoduTvDKoQPqcRl0nHlDYju2zkXcU6g==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.2.5.tgz", + "integrity": "sha512-JE6ck4UWXayiG8ptJJtkrKCjy+5Ftktgsoj4QGdQzMhbpia7Wge5XDj28o+bwEFndRnP6ihRtud63IvOz9aKFQ==", "dev": true, "license": "MIT", "engines": { @@ -1322,9 +964,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.0.5.tgz", - "integrity": "sha512-hBKaGz7dhsjNhD0aWB8G2/YZQ/MaBhzFIQSAZMPs2ccAqH1Jx772/Y11k57seA3VaPpnL8WZ1apOSJgALUJ//w==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.5.tgz", + "integrity": "sha512-PoX9idwnOpTJBlujzZ2nFGOsmCnZzOH7uNSWIR7trdoq0b1AFXfrxlCQ36qWamk7bbhJI4H28L8YTmKew/nXDA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1333,9 +975,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.0.5", - "@angular/common": "18.0.5", - "@angular/core": "18.0.5" + "@angular/animations": "18.2.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5" }, "peerDependenciesMeta": { "@angular/animations": { @@ -1344,9 +986,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.0.5.tgz", - "integrity": "sha512-i8CXojKcjsKzD2JR2clIisqavlHCW1jw+F2hJVrf/JR9iu6kVpGpZOqb3yYHoQCsPa7hUzQnn0ewYwBvlWsDmw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.5.tgz", + "integrity": "sha512-5u0IuAt1r5e2u2vSKhp3phnaf6hH89B/q7GErfPse1sdDfNI6wHVppxai28PAfAj9gwooJun6MjFWhJFLzS44A==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1355,16 +997,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.5", - "@angular/compiler": "18.0.5", - "@angular/core": "18.0.5", - "@angular/platform-browser": "18.0.5" + "@angular/common": "18.2.5", + "@angular/compiler": "18.2.5", + "@angular/core": "18.2.5", + "@angular/platform-browser": "18.2.5" } }, "node_modules/@angular/router": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.0.5.tgz", - "integrity": "sha512-GmdzD5FZYPKCGP6mV3AZraAU6czfGcjjCym6mIsdJr3DyMwnQSwaaHAu8qlQbPDVfsP+gKVSPh1JxI1lzzarLA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.5.tgz", + "integrity": "sha512-OjZV1PTiSwT0ytmR0ykveLYzs4uQWf0EuIclZmWqM/bb8Q4P+gJl7/sya05nGnZsj6nHGOL0e/LhSZ3N+5p6qg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1373,16 +1015,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.5", - "@angular/core": "18.0.5", - "@angular/platform-browser": "18.0.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/platform-browser": "18.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "18.0.5", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.0.5.tgz", - "integrity": "sha512-Uz3rKHY0pBOvAfxhaGI9X8glS8oaPv03e3GsucZhzuDCijQGHQb1Plaz56NntIGvGaghLMq3zwV7YLPnquarvw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.2.5.tgz", + "integrity": "sha512-MoF2n7z/X+yqK89mIRHQutVHIBTyEUo/fDEL8LcuBP4KOZmX9cRoCEt+vqH49BkArsgOM0jNFMYCM8yt0jg7pw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1394,8 +1036,8 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.5", - "@angular/core": "18.0.5" + "@angular/common": "18.2.5", + "@angular/core": "18.2.5" } }, "node_modules/@babel/code-frame": { @@ -3640,15 +3282,15 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", - "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.48.0.tgz", + "integrity": "sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==", "dev": true, "license": "MIT", "dependencies": { "comment-parser": "1.4.1", "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~4.0.0" + "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { "node": ">=16" @@ -4292,15 +3934,15 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.4.7.tgz", - "integrity": "sha512-5YwCySyV1UEgqzz34gNsC38eKxRBtlRDpJLlKcRtTjlYA/yDKuc1rfw+hjw+2WJxbAZtaDPsRl5Zk7J14SBoBw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.5.0.tgz", + "integrity": "sha512-sMgdETOfi2dUHT8r7TT1BTKOwNvdDGFDXYWtQ2J69SvlYNntk9I/gJe7r5yvMwwsuKnYbuRs3pNhx4tgNck5aA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", + "@inquirer/core": "^9.1.0", "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", + "@inquirer/type": "^1.5.3", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -4323,19 +3965,18 @@ } }, "node_modules/@inquirer/core": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.10.tgz", - "integrity": "sha512-TdESOKSVwf6+YWDz8GhS6nKscwzkIyakEzCLJ5Vh6O3Co2ClhCJ0A4MG909MUWfaWdpJm7DE45ii51/2Kat9tA==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz", + "integrity": "sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", + "@inquirer/figures": "^1.0.6", + "@inquirer/type": "^2.0.0", "@types/mute-stream": "^0.0.4", - "@types/node": "^22.1.0", + "@types/node": "^22.5.5", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", "cli-width": "^4.1.0", "mute-stream": "^1.0.0", "signal-exit": "^4.1.0", @@ -4347,10 +3988,23 @@ "node": ">=18" } }, + "node_modules/@inquirer/core/node_modules/@inquirer/type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz", + "integrity": "sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==", + "dev": true, + "license": "MIT", + "dependencies": { + "mute-stream": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@inquirer/core/node_modules/@types/node": { - "version": "22.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz", - "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==", + "version": "22.6.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.6.1.tgz", + "integrity": "sha512-V48tCfcKb/e6cVUigLAaJDAILdMP0fUW6BidkPK4GpGjXcfbnoHasCZDwz3N3yVt5we2RHm4XTQCpv0KJz9zqw==", "dev": true, "license": "MIT", "dependencies": { @@ -4358,14 +4012,14 @@ } }, "node_modules/@inquirer/editor": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.1.22.tgz", - "integrity": "sha512-K1QwTu7GCK+nKOVRBp5HY9jt3DXOfPGPr6WRDrPImkcJRelG9UTx2cAtK1liXmibRrzJlTWOwqgWT3k2XnS62w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.2.0.tgz", + "integrity": "sha512-9KHOpJ+dIL5SZli8lJ6xdaYLPPzB8xB9GZItg39MBybzhxA16vxmszmQFrRwbOA918WA2rvu8xhDEg/p6LXKbw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", "external-editor": "^3.1.0" }, "engines": { @@ -4373,14 +4027,14 @@ } }, "node_modules/@inquirer/expand": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.1.22.tgz", - "integrity": "sha512-wTZOBkzH+ItPuZ3ZPa9lynBsdMp6kQ9zbjVPYEtSBG7UulGjg2kQiAnUjgyG4SlntpTce5bOmXAPvE4sguXjpA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.3.0.tgz", + "integrity": "sha512-qnJsUcOGCSG1e5DTOErmv2BPQqrtT6uzqn1vI/aYGiPKq+FgslGZmtdnXbhuI7IlT7OByDoEEqdnhUnVR2hhLw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -4388,9 +4042,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", - "integrity": "sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.6.tgz", + "integrity": "sha512-yfZzps3Cso2UbM7WlxKwZQh2Hs6plrbjs1QnzQDZhK2DgyCo6D8AaHps9olkNcUFlcYERMqU3uJSp1gmy3s/qQ==", "dev": true, "license": "MIT", "engines": { @@ -4398,28 +4052,42 @@ } }, "node_modules/@inquirer/input": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.2.9.tgz", - "integrity": "sha512-7Z6N+uzkWM7+xsE+3rJdhdG/+mQgejOVqspoW+w0AbSZnL6nq5tGMEVASaYVWbkoSzecABWwmludO2evU3d31g==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.3.0.tgz", + "integrity": "sha512-XfnpCStx2xgh1LIRqPXrTNEEByqQWoxsWYzNRSEUxJ5c6EQlhMogJ3vHKu8aXuTacebtaZzMAHwEL0kAflKOBw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2" + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-1.1.0.tgz", + "integrity": "sha512-ilUnia/GZUtfSZy3YEErXLJ2Sljo/mf9fiKc08n18DdwdmDbOzRcTv65H1jjDvlsAuvdFXf4Sa/aL7iw/NanVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3" }, "engines": { "node": ">=18" } }, "node_modules/@inquirer/password": { - "version": "2.1.22", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.1.22.tgz", - "integrity": "sha512-5Fxt1L9vh3rAKqjYwqsjU4DZsEvY/2Gll+QkqR4yEpy6wvzLxdSgFhUcxfDAOtO4BEoTreWoznC0phagwLU5Kw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.2.0.tgz", + "integrity": "sha512-5otqIpgsPYIshqhgtEwSspBQE40etouR8VIxzpJkv9i0dVHIpyhiivbkH9/dGiMLdyamT54YRdGJLfl8TFnLHg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", "ansi-escapes": "^4.3.2" }, "engines": { @@ -4427,34 +4095,52 @@ } }, "node_modules/@inquirer/prompts": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.0.7.tgz", - "integrity": "sha512-GFcigCxJTKCH3aECzMIu4FhgLJWnFvMXzpI4CCSoELWFtkOOU2P+goYA61+OKpGrB8fPE7q6n8zAXBSlZRrHjQ==", + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.3.8.tgz", + "integrity": "sha512-b2BudQY/Si4Y2a0PdZZL6BeJtl8llgeZa7U2j47aaJSCeAl1e4UI7y8a9bSkO3o/ZbZrgT5muy/34JbsjfIWxA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^2.3.7", - "@inquirer/confirm": "^3.1.11", - "@inquirer/editor": "^2.1.11", - "@inquirer/expand": "^2.1.11", - "@inquirer/input": "^2.1.11", - "@inquirer/password": "^2.1.11", - "@inquirer/rawlist": "^2.1.11", - "@inquirer/select": "^2.3.7" + "@inquirer/checkbox": "^2.4.7", + "@inquirer/confirm": "^3.1.22", + "@inquirer/editor": "^2.1.22", + "@inquirer/expand": "^2.1.22", + "@inquirer/input": "^2.2.9", + "@inquirer/number": "^1.0.10", + "@inquirer/password": "^2.1.22", + "@inquirer/rawlist": "^2.2.4", + "@inquirer/search": "^1.0.7", + "@inquirer/select": "^2.4.7" }, "engines": { "node": ">=18" } }, "node_modules/@inquirer/rawlist": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.2.4.tgz", - "integrity": "sha512-pb6w9pWrm7EfnYDgQObOurh2d2YH07+eDo3xQBsNAM2GRhliz6wFXGi1thKQ4bN6B0xDd6C3tBsjdr3obsCl3Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.3.0.tgz", + "integrity": "sha512-zzfNuINhFF7OLAtGHfhwOW2TlYJyli7lOUoJUXw/uyklcwalV6WRXBXtFIicN8rTRK1XTiPWB4UY+YuW8dsnLQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", - "@inquirer/type": "^1.5.2", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/search": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-1.1.0.tgz", + "integrity": "sha512-h+/5LSj51dx7hp5xOn4QFnUaKeARwUCLs6mIhtkJ0JYPBLmEYjdHSYh7I6GrLg9LwpJ3xeX0FZgAG1q0QdCpVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^9.1.0", + "@inquirer/figures": "^1.0.5", + "@inquirer/type": "^1.5.3", "yoctocolors-cjs": "^2.1.2" }, "engines": { @@ -4462,15 +4148,15 @@ } }, "node_modules/@inquirer/select": { - "version": "2.4.7", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.4.7.tgz", - "integrity": "sha512-JH7XqPEkBpNWp3gPCqWqY8ECbyMoFcCZANlL6pV9hf59qK6dGmkOlx1ydyhY+KZ0c5X74+W6Mtp+nm2QX0/MAQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.5.0.tgz", + "integrity": "sha512-YmDobTItPP3WcEI86GvPo+T2sRHkxxOq/kXmsBjHS5BVXUgvgZ5AfJjkvQvZr03T81NnI3KrrRuMzeuYUQRFOA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^9.0.10", + "@inquirer/core": "^9.1.0", "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.2", + "@inquirer/type": "^1.5.3", "ansi-escapes": "^4.3.2", "yoctocolors-cjs": "^2.1.2" }, @@ -4479,9 +4165,9 @@ } }, "node_modules/@inquirer/type": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.2.tgz", - "integrity": "sha512-w9qFkumYDCNyDZmNQjf/n6qQuvQ4dMC3BJesY4oF+yr0CxR5vxujflAVeIcS6U336uzi9GM0kAfZlLrZ9UTkpA==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.5.tgz", + "integrity": "sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==", "dev": true, "license": "MIT", "dependencies": { @@ -5687,13 +5373,13 @@ "dev": true }, "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.13.tgz", - "integrity": "sha512-nAl6teTt7EWSjttNavAnv3uFR3w3vPP3OTYmHyPNHzKhAj2NoBDHmbS3MGpvvO8KXXPASnHjEGrrKrdKTMKPnQ==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.15.tgz", + "integrity": "sha512-MZrGem/Ujjd4cPTLYDfCZK2iKKeiO/8OX13S6jqxldLs0Prf2aGqVlJ77nMBqMv7fzqgXEgjrNHLXcKR8l9lOg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/type": "^1.3.3" + "@inquirer/type": "^1.5.1" }, "engines": { "node": ">=18.0.0" @@ -5710,6 +5396,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5723,6 +5410,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5736,6 +5424,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5749,6 +5438,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5762,6 +5452,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5775,6 +5466,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -5788,6 +5480,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5801,6 +5494,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5814,6 +5508,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5827,6 +5522,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5840,6 +5536,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -5853,6 +5550,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -5863,6 +5561,7 @@ "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.5.tgz", "integrity": "sha512-L0n4eHObeqEOYRfSP+e4SeF/dmwxOIFy9xYvYCOUwOLrW4b3+a1+kkT30pqyfL72LFtpf0cmUwaWEFIcWl5PCg==", "dev": true, + "license": "MIT", "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -5875,9 +5574,9 @@ } }, "node_modules/@ngx-formly/core": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.6.tgz", - "integrity": "sha512-0GDllrb9fFBTKG+yT+iQf96N3/CN+qRXIYsSX3uft12+c28qKVfMTsWTPYQsmKfGcrqtOZkMVTc+jGGD2JLZLg==", + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/@ngx-formly/core/-/core-6.3.7.tgz", + "integrity": "sha512-To2mH09YSm3nyThABNHIameIJCPA9C+x3/JFxFtBWek+UbYeW9DYOqNHRCc7P1ToqLqNEuwrmzjB2YSA8pO9Pw==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -5888,22 +5587,22 @@ } }, "node_modules/@ngx-formly/ionic": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.6.tgz", - "integrity": "sha512-GaZav6bGGuQ3BqEVYK9DV+QsdM92jjfPmKbN9qz5s+kXH4ahjGfMqcq6Rm4SP49vvl5Am3mJZbZU4g9XrJI5tQ==", + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/@ngx-formly/ionic/-/ionic-6.3.7.tgz", + "integrity": "sha512-j3jiv51CVNeJGY02bZgizarO24DF5AdzL5HJ7SAtJqBIxJNR++AkQZZvgMYtPYTrvhdOIiZrhkBWh0x+rfQMJQ==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@ionic/angular": "^6.0.0 || ^7.0.0", - "@ngx-formly/core": "6.3.6" + "@ngx-formly/core": "6.3.7" } }, "node_modules/@ngx-formly/schematics": { - "version": "6.3.6", - "resolved": "https://registry.npmjs.org/@ngx-formly/schematics/-/schematics-6.3.6.tgz", - "integrity": "sha512-QdrvdL4YrfhU9AxIXczSyzbZHWq7uuDtsIeEZ3lC0dFyvA0YyTxZRWfNyyMwCXCRXvn70WGlaU8UpeahTXsoAg==", + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/@ngx-formly/schematics/-/schematics-6.3.7.tgz", + "integrity": "sha512-e1Y7RNa6AGK+YEIzNXNX5lvA8MrFQ9UEL/Pj8zwGdotKI8CnNyRVHneQ/1F+QZBo1mLXUtXJnejPoOMkGfo7VQ==", "license": "MIT", "dependencies": { "@angular-devkit/core": "^13.0.3", @@ -6619,63 +6318,23 @@ "win32" ] }, - "node_modules/@schematics/angular": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.1.0.tgz", - "integrity": "sha512-k9Dy6JD7hqvCzDqnMjDm7J8H/P6m5mLuX2yEgQWKRAJ/YMINtBQAaKA1T9qXk97kEX6RNLpHMuDIsrIfK/H31Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "18.1.0", - "@angular-devkit/schematics": "18.1.0", - "jsonc-parser": "3.3.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.0.tgz", - "integrity": "sha512-6eXQDzHZCbpSMLv9Ohl+1QyLVDmGEXpuuHz3y64LfUTP0aEiBaxk96FjLXIxzJ4f2pbbW2XHzc+yuboGToRA0w==", + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.16.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.2", - "rxjs": "7.8.1", - "source-map": "0.7.4" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^3.5.2" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } + "license": "MIT" }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/schematics": { - "version": "18.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.0.tgz", - "integrity": "sha512-BjrYutLfYFiPOSEcLBWCj3ENkwDn8gMfBSJesaBz7OrZBZGK5j0dVgBLIsGTP96TKo4o4vszJQOvS4AtV6xMGg==", + "node_modules/@schematics/angular": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.5.tgz", + "integrity": "sha512-tBXhk9OGT4U6VsBNbuCNl2ITDOF3NYdGrEieIHU+lHSkpJNGZUIGxCgXCETXkmXDq1pe4wFZSKelWjeqYDfX0g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.1.0", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.10", - "ora": "5.4.1", - "rxjs": "7.8.1" + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", + "jsonc-parser": "3.3.1" }, "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", @@ -6683,43 +6342,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@schematics/angular/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@schematics/angular/node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "node_modules/@schematics/angular/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@sigstore/bundle": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.3.2.tgz", @@ -7194,9 +6816,9 @@ "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", "dev": true, "license": "MIT" }, @@ -7324,17 +6946,65 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, "engines": { "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { @@ -7360,6 +7030,37 @@ "eslint": "^8.56.0" } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@typescript-eslint/parser": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", @@ -7367,11 +7068,75 @@ "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/visitor-keys": "7.18.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", + "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4" + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -7380,20 +7145,22 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^8.56.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" + }, "engines": { "node": "^18.18.0 || >=20.0.0" }, @@ -7402,31 +7169,31 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, + "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", + "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.7.0", + "@typescript-eslint/visitor-keys": "8.7.0" + }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -7461,30 +7228,15 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", + "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" + "@typescript-eslint/visitor-keys": "7.18.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -7492,25 +7244,23 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", - "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", + "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/typescript-estree": { + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { "version": "7.18.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", @@ -7539,50 +7289,65 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/types": { + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", + "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.18.0", + "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/typescript-estree": "7.18.0" + }, "engines": { "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", - "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", + "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.7.0", - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/typescript-estree": "8.7.0" + "@typescript-eslint/types": "7.18.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "node_modules/@typescript-eslint/types": { "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz", - "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz", + "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.7.0", - "@typescript-eslint/visitor-keys": "8.7.0" - }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -7591,11 +7356,12 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "node_modules/@typescript-eslint/typescript-estree": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz", "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "8.7.0", "@typescript-eslint/visitor-keys": "8.7.0", @@ -7619,14 +7385,16 @@ } } }, - "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "node_modules/@typescript-eslint/utils": { "version": "8.7.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", - "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz", + "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==", "dev": true, "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.7.0", "@typescript-eslint/types": "8.7.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/typescript-estree": "8.7.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7634,45 +7402,23 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz", + "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/types": "8.7.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -8057,16 +7803,15 @@ } }, "node_modules/ajv": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", - "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -9403,9 +9148,9 @@ } }, "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -9429,9 +9174,9 @@ } }, "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true, "license": "MIT" }, @@ -12201,9 +11946,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.2.tgz", - "integrity": "sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.1.tgz", + "integrity": "sha512-EwcbfLOhwVMAfatfqLecR2yv3dE5+kQ8kx+Rrt0DvDXEVwW86KQ/xbMDQhtp5l42VXukD5SOF8mQQHbaNtO0CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12229,27 +11974,28 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", + "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", "dev": true, "license": "MIT", "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", "array.prototype.flat": "^1.3.2", "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", + "eslint-module-utils": "^2.9.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", "semver": "^6.3.1", "tsconfig-paths": "^3.15.0" }, @@ -12318,17 +12064,18 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.10.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.10.0.tgz", - "integrity": "sha512-BEli0k8E0dzhJairAllwlkGnyYDZVKNn4WDmyKy+v6J5qGNuofjzxwNUi+55BOGmyO9mKBhqaidwGy+dxndn/Q==", + "version": "50.2.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.2.4.tgz", + "integrity": "sha512-020jA+dXaXdb+TML3ZJBvpPmzwbNROjnYuTYi/g6A5QEmEjhptz4oPJDKkOGMIByNxsPpdTLzSU1HYVqebOX1w==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.46.0", + "@es-joy/jsdoccomment": "~0.48.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", - "debug": "^4.3.5", + "debug": "^4.3.6", "escape-string-regexp": "^4.0.0", + "espree": "^10.1.0", "esquery": "^1.6.0", "parse-imports": "^2.1.1", "semver": "^7.6.3", @@ -15492,9 +15239,9 @@ } }, "node_modules/jasmine-core": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.5.0.tgz", - "integrity": "sha512-9PMzyvhtocxb3aXJVOPqBDswdgyAeSB81QnLop4npOpbqnheaTEwPc9ZloQeVswugPManznQBjD8kWDTjlnHuw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.3.0.tgz", + "integrity": "sha512-zsOmeBKESky4toybvWEikRiZ0jHoBEu79wNArLfMdSnlLMZx3Xcp6CSm2sUcYyoJC+Uyj8LBJap/MUbVSfJ27g==", "dev": true, "license": "MIT" }, @@ -15604,9 +15351,9 @@ "license": "MIT" }, "node_modules/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", "dev": true, "license": "MIT", "engines": { @@ -16090,6 +15837,13 @@ "karma-jasmine": "^5.0.0" } }, + "node_modules/karma-jasmine/node_modules/jasmine-core": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.1.tgz", + "integrity": "sha512-VYz/BjjmC3klLJlLwA4Kw8ytk0zDSmbbDLNs794VnWmkcCB7I9aAL/D48VNQtmITyPvea2C3jdUMfc3kAoy0PQ==", + "dev": true, + "license": "MIT" + }, "node_modules/karma-source-map-support": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", @@ -16471,16 +16225,16 @@ "license": "MIT" }, "node_modules/listr2": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", - "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, "license": "MIT", "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", + "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, @@ -16489,9 +16243,9 @@ } }, "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -16515,9 +16269,9 @@ } }, "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true, "license": "MIT" }, @@ -16586,6 +16340,7 @@ "integrity": "sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "msgpackr": "^1.10.2", "node-addon-api": "^6.1.0", @@ -16609,7 +16364,8 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/load-json-file": { "version": "4.0.0", @@ -16940,9 +16696,9 @@ } }, "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "license": "MIT", "engines": { @@ -16982,9 +16738,9 @@ } }, "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true, "license": "MIT" }, @@ -17892,6 +17648,7 @@ "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.0.tgz", "integrity": "sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==", "dev": true, + "license": "MIT", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } @@ -17902,6 +17659,7 @@ "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "dependencies": { "node-gyp-build-optional-packages": "5.2.2" @@ -18227,6 +17985,7 @@ "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "dev": true, + "license": "MIT", "dependencies": { "detect-libc": "^2.0.1" }, @@ -18536,9 +18295,9 @@ } }, "node_modules/npm-package-arg": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", - "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", + "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", "dev": true, "license": "ISC", "dependencies": { @@ -18585,9 +18344,9 @@ } }, "node_modules/npm-pick-manifest": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", - "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", + "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", "dev": true, "license": "ISC", "dependencies": { @@ -18960,7 +18719,8 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/os-name": { "version": "4.0.1", @@ -24606,7 +24366,8 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/webdriver-js-extender": { "version": "2.1.0", diff --git a/ui/package.json b/ui/package.json index 62d980810a..2e1c9fe448 100644 --- a/ui/package.json +++ b/ui/package.json @@ -4,27 +4,27 @@ "license": "AGPL-3.0", "private": true, "dependencies": { - "@angular/animations": "18.0.5", - "@angular/common": "18.0.5", - "@angular/core": "18.0.5", - "@angular/forms": "18.0.5", - "@angular/platform-browser": "18.0.5", - "@angular/platform-browser-dynamic": "18.0.5", - "@angular/router": "18.0.5", - "@angular/service-worker": "18.0.5", + "@angular/animations": "18.2.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/forms": "18.2.5", + "@angular/platform-browser": "18.2.5", + "@angular/platform-browser-dynamic": "18.2.5", + "@angular/router": "18.2.5", + "@angular/service-worker": "18.2.5", "@capacitor-community/file-opener": "^6.0.1", - "@capacitor/android": "^6.0.0", - "@capacitor/app": "^6.0.0", - "@capacitor/core": "^6.0.0", - "@capacitor/filesystem": "^6.0.0", - "@capacitor/ios": "^6.0.0", - "@capacitor/splash-screen": "^6.0.0", + "@capacitor/android": "^6.1.2", + "@capacitor/app": "^6.0.1", + "@capacitor/core": "^6.1.2", + "@capacitor/filesystem": "^6.0.1", + "@capacitor/ios": "^6.1.2", + "@capacitor/splash-screen": "^6.0.2", "@ionic-native/core": "^5.36.0", "@ionic-native/file-opener": "^5.36.0", "@ionic/angular": "^6.7.5", - "@ngx-formly/core": "^6.3.0", - "@ngx-formly/ionic": "^6.3.6", - "@ngx-formly/schematics": "^6.3.0", + "@ngx-formly/core": "^6.3.7", + "@ngx-formly/ionic": "^6.3.7", + "@ngx-formly/schematics": "^6.3.7", "@ngx-translate/core": "^15.0.0", "@nodro7/angular-mydatepicker": "^0.14.0", "capacitor-blob-writer": "^1.1.17", @@ -53,16 +53,16 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^18.2.5", - "@angular-devkit/core": "18.0.5", - "@angular-devkit/schematics": "18.0.5", - "@angular-eslint/builder": "^18.1.0", - "@angular-eslint/eslint-plugin": "^18.1.0", - "@angular-eslint/eslint-plugin-template": "^18.1.0", - "@angular-eslint/template-parser": "^18.1.0", - "@angular/cli": "18.1.0", - "@angular/compiler": "18.0.5", - "@angular/compiler-cli": "18.0.5", - "@angular/language-service": "18.0.5", + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", + "@angular-eslint/builder": "^18.3.1", + "@angular-eslint/eslint-plugin": "^18.3.1", + "@angular-eslint/eslint-plugin-template": "^18.3.1", + "@angular-eslint/template-parser": "^18.3.1", + "@angular/cli": "18.2.5", + "@angular/compiler": "18.2.5", + "@angular/compiler-cli": "18.2.5", + "@angular/language-service": "18.2.5", "@capacitor/assets": "^3.0.5", "@capacitor/cli": "6.1.2", "@ionic/angular-toolkit": "^11.0.1", @@ -72,7 +72,7 @@ "@types/jasminewd2": "~2.0.13", "@types/json-schema": "^7.0.15", "@types/node": "^20.12.6", - "@types/qs": "^6.9.15", + "@types/qs": "^6.9.16", "@types/range-parser": "^1.2.7", "@types/send": "^0.17.4", "@types/uuid": "^10.0.0", @@ -80,13 +80,13 @@ "@typescript-eslint/parser": "^7.0.0", "@typescript-eslint/types": "^8.7.0", "eslint": "^8.57.0", - "eslint-plugin-import": "2.29.1", - "eslint-plugin-jsdoc": "48.10.0", + "eslint-plugin-import": "2.30.0", + "eslint-plugin-jsdoc": "50.2.4", "eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-unused-imports": "^4.1.4", - "jasmine-core": "~4.5.0", + "jasmine-core": "~5.3.0", "jasmine-spec-reporter": "~7.0.0", - "karma": "~6.4.2", + "karma": "~6.4.4", "karma-chrome-launcher": "~3.2.0", "karma-coverage": "~2.2.1", "karma-coverage-istanbul-reporter": "~3.0.3", diff --git a/ui/src/app/shared/components/edge/edgeconfig.ts b/ui/src/app/shared/components/edge/edgeconfig.ts index c06af3db4a..4b12b73aed 100644 --- a/ui/src/app/shared/components/edge/edgeconfig.ts +++ b/ui/src/app/shared/components/edge/edgeconfig.ts @@ -710,7 +710,7 @@ export namespace PersistencePriority { } } -export module EdgeConfig { +export namespace EdgeConfig { export class ComponentChannel { public readonly type!: "BOOLEAN" | "SHORT" | "INTEGER" | "LONG" | "FLOAT" | "DOUBLE" | "STRING"; public readonly accessMode!: "RO" | "RW" | "WO"; diff --git a/ui/src/app/shared/service/defaulttypes.ts b/ui/src/app/shared/service/defaulttypes.ts index c2551ff2e0..b01b987562 100644 --- a/ui/src/app/shared/service/defaulttypes.ts +++ b/ui/src/app/shared/service/defaulttypes.ts @@ -5,7 +5,7 @@ import { endOfMonth, endOfYear, format, getDay, getMonth, getYear, isSameDay, is import { QueryHistoricTimeseriesEnergyResponse } from "../jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; import { ChannelAddress, Service } from "../shared"; -export module DefaultTypes { +export namespace DefaultTypes { export type Backend = "OpenEMS Backend" | "OpenEMS Edge"; From a479107eb12a93f7e2e047e9d6ee6aa31b0e4dfb Mon Sep 17 00:00:00 2001 From: Hiromasa Ihara Date: Mon, 30 Sep 2024 06:25:33 +0900 Subject: [PATCH 23/24] UI: add @stylistic to style rules (#2779) --- ui/.eslintrc.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index c3095af0cf..8a3902ecdd 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -89,8 +89,8 @@ } ], "@typescript-eslint/member-ordering": "error", - "no-multiple-empty-lines": "error", - "quotes": [ + "@stylistic/no-multiple-empty-lines": "error", + "@stylistic/quotes": [ "error", "double" ], From 472e8eafbd3618517d0321d0211613b56c394f00 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 1 Oct 2024 11:45:23 +0200 Subject: [PATCH 24/24] Push version to 2024.10.0 --- .../io/openems/common/OpenemsConstants.java | 2 +- ui/package-lock.json | 1078 +++++++++++------ ui/package.json | 2 +- .../view/component/changelog.constants.ts | 2 +- 4 files changed, 700 insertions(+), 384 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index cbfc12274f..9b7384aae6 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -36,7 +36,7 @@ public class OpenemsConstants { /** * The additional version string. */ - public static final String VERSION_STRING = "SNAPSHOT"; + public static final String VERSION_STRING = ""; /** * The complete version as a SemanticVersion. diff --git a/ui/package-lock.json b/ui/package-lock.json index f0ac38c3c7..fca2ca8fb7 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2024.10.0-SNAPSHOT", + "version": "2024.10.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2024.10.0-SNAPSHOT", + "version": "2024.10.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "18.2.5", @@ -142,16 +142,17 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.5.tgz", - "integrity": "sha512-dIvb0AHoRIMM6tLuG4t6lDDslSAYP77wqytodsN317UzFOuuCPernXbO8NJs+QHxj09nPsem1T5vnvpO2E/PVQ==", + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.6.tgz", + "integrity": "sha512-u12cJZttgs5j7gICHWSmcaTCu0EFXEzKqI8nkYCwq2MtuJlAXiMQSXYuEP9OU3Go4vMAPtQh2kShyOWCX5b4EQ==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.5", - "@angular-devkit/build-webpack": "0.1802.5", - "@angular-devkit/core": "18.2.5", - "@angular/build": "18.2.5", + "@angular-devkit/architect": "0.1802.6", + "@angular-devkit/build-webpack": "0.1802.6", + "@angular-devkit/core": "18.2.6", + "@angular/build": "18.2.6", "@babel/core": "7.25.2", "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", @@ -162,7 +163,7 @@ "@babel/preset-env": "7.25.3", "@babel/runtime": "7.25.0", "@discoveryjs/json-ext": "0.6.1", - "@ngtools/webpack": "18.2.5", + "@ngtools/webpack": "18.2.6", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -269,54 +270,28 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true - }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.5.tgz", - "integrity": "sha512-6qkcrWBdkxojCVHGWcdJaz4G+7QTjFvmc+3g8xvLc9sYvJq1I059gfXhDnC0FxiA0MT4cY/26ECYWUHTD5CJLQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { + "version": "0.1802.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.6.tgz", + "integrity": "sha512-oF7cPFdTLxeuvXkK/opSdIxZ1E4LrBbmuytQ/nCoAGOaKBWdqvwagRZ6jVhaI0Gwu48rkcV7Zhesg/ESNnROdw==", "dev": true, + "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/core": "18.2.6", "rxjs": "7.8.1" }, "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^5.0.2" - } - }, - "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" } }, - "node_modules/@angular-devkit/core": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", - "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.6.tgz", + "integrity": "sha512-la4CFvs5PcRWSkQ/H7TB5cPZirFVA9GoWk5LzIk8si6VjWBJRm8b3keKJoC9LlNeABRUIR5z0ocYkyQQUhdMfg==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -339,150 +314,15 @@ } } }, - "node_modules/@angular-devkit/core/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-devkit/schematics": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.5.tgz", - "integrity": "sha512-NUmz2UQ1Xl4cf4j1AgkwIfsCjBzAPgfeC3IBrD29hSOBE1Y3j6auqjBkvw50v6mbSPxESND995Xy13HpK1Xflw==", - "dev": true, - "dependencies": { - "@angular-devkit/core": "18.2.5", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.11", - "ora": "5.4.1", - "rxjs": "7.8.1" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/@angular-eslint/builder": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.1.tgz", - "integrity": "sha512-cPc7Ye9zDs5M4i+feL6vob+mh7yX5vxvOS5KQIhneUrp5e9D+IGuNFMmBLlOPpmklSc9XJBtuvI5Zjuh4z1ETw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.1.tgz", - "integrity": "sha512-sikmkjfsXPpPTku1aQkQ1MNNEKGBgGGRvUN/WeNS9dhCJ4dxU3O7dZctt1aQWj+W3nbuUtDiimAWF5fZHGFE2Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.1.tgz", - "integrity": "sha512-MP4Nm+SHboF8KdnN0KpPEGAaTTzDLPm3+S/4W3Mg8onqWCyadyd4mActh9mK/pvCj8TVlb/SW1zeTtdMYhwonw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.1", - "@angular-eslint/utils": "18.3.1" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.1.tgz", - "integrity": "sha512-hBJ3+f7VSidvrtYaXH7Vp0sWvblA9jLK2c6uQzhYGWdEDUcTg7g7VI9ThW39WvMbHqkyzNE4PPOynK69cBEDGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.1", - "@angular-eslint/utils": "18.3.1", - "aria-query": "5.3.0", - "axobject-query": "4.1.0" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/template-parser": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.1.tgz", - "integrity": "sha512-JUUkfWH1G+u/Uk85ZYvJSt/qwN/Ko+jlXFtzBEcknJZsTWTwBcp36v77gPZe5FmKSziJZpyPUd+7Kiy6tuSCTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.1", - "eslint-scope": "^8.0.2" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/utils": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.1.tgz", - "integrity": "sha512-sd9niZI7h9H2FQ7OLiQsLFBhjhRQTASh+Q0+4+hyjv9idbSHBJli8Gsi2fqj9zhtMKpAZFTrWzuLUpubJ9UYbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "18.3.1" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": "*" - } - }, - "node_modules/@angular/animations": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.5.tgz", - "integrity": "sha512-IlXtW/Nj48ZzjHUzH1TykZcSR64ScJx39T3IHnjV2z/bVATzZ36JGoadQHdqpJNKBodYJNgtJCGLCbgAvGWY2g==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" - }, - "peerDependencies": { - "@angular/core": "18.2.5" - } - }, - "node_modules/@angular/build": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.5.tgz", - "integrity": "sha512-XWkmjzgeUga0SJ0lYSYcTuYOWTyqcln2mNfBp7Ae/GZ+/7+APbedsIZEiZGZwveOIyOpTM5wguNSoe9khDl5Ig==", + "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.6.tgz", + "integrity": "sha512-TQzX6Mi7uXFvmz7+OVl4Za7WawYPcx+B5Ewm6IY/DdMyB9P/Z4tbKb1LO+ynWUXYwm7avXo6XQQ4m5ArDY5F/A==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/architect": "0.1802.6", "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -501,7 +341,7 @@ "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", "piscina": "4.6.1", - "rollup": "4.20.0", + "rollup": "4.22.4", "sass": "1.77.6", "semver": "7.6.3", "vite": "5.4.6", @@ -543,10 +383,10 @@ } } }, - "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", - "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz", + "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==", "cpu": [ "arm" ], @@ -557,10 +397,10 @@ "android" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", - "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-android-arm64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz", + "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==", "cpu": [ "arm64" ], @@ -571,10 +411,10 @@ "android" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", - "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz", + "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==", "cpu": [ "arm64" ], @@ -585,10 +425,10 @@ "darwin" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-x64": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", - "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz", + "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==", "cpu": [ "x64" ], @@ -599,10 +439,10 @@ "darwin" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", - "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz", + "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==", "cpu": [ "arm" ], @@ -613,10 +453,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", - "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz", + "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==", "cpu": [ "arm" ], @@ -627,10 +467,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", - "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz", + "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==", "cpu": [ "arm64" ], @@ -641,10 +481,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", - "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz", + "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==", "cpu": [ "arm64" ], @@ -655,10 +495,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", - "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz", + "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==", "cpu": [ "ppc64" ], @@ -669,10 +509,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", - "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz", + "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==", "cpu": [ "riscv64" ], @@ -683,10 +523,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", - "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz", + "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==", "cpu": [ "s390x" ], @@ -697,10 +537,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", - "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz", + "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==", "cpu": [ "x64" ], @@ -711,10 +551,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", - "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz", + "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==", "cpu": [ "x64" ], @@ -725,10 +565,10 @@ "linux" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", - "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz", + "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==", "cpu": [ "arm64" ], @@ -739,10 +579,10 @@ "win32" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", - "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz", + "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==", "cpu": [ "ia32" ], @@ -753,10 +593,10 @@ "win32" ] }, - "node_modules/@angular/build/node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", - "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", + "node_modules/@angular-devkit/build-angular/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz", + "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==", "cpu": [ "x64" ], @@ -767,10 +607,17 @@ "win32" ] }, - "node_modules/@angular/build/node_modules/rollup": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", - "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", + "node_modules/@angular-devkit/build-angular/node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/build-angular/node_modules/rollup": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", + "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==", "dev": true, "license": "MIT", "dependencies": { @@ -784,25 +631,276 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.20.0", - "@rollup/rollup-android-arm64": "4.20.0", - "@rollup/rollup-darwin-arm64": "4.20.0", - "@rollup/rollup-darwin-x64": "4.20.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", - "@rollup/rollup-linux-arm-musleabihf": "4.20.0", - "@rollup/rollup-linux-arm64-gnu": "4.20.0", - "@rollup/rollup-linux-arm64-musl": "4.20.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", - "@rollup/rollup-linux-riscv64-gnu": "4.20.0", - "@rollup/rollup-linux-s390x-gnu": "4.20.0", - "@rollup/rollup-linux-x64-gnu": "4.20.0", - "@rollup/rollup-linux-x64-musl": "4.20.0", - "@rollup/rollup-win32-arm64-msvc": "4.20.0", - "@rollup/rollup-win32-ia32-msvc": "4.20.0", - "@rollup/rollup-win32-x64-msvc": "4.20.0", + "@rollup/rollup-android-arm-eabi": "4.22.4", + "@rollup/rollup-android-arm64": "4.22.4", + "@rollup/rollup-darwin-arm64": "4.22.4", + "@rollup/rollup-darwin-x64": "4.22.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.22.4", + "@rollup/rollup-linux-arm-musleabihf": "4.22.4", + "@rollup/rollup-linux-arm64-gnu": "4.22.4", + "@rollup/rollup-linux-arm64-musl": "4.22.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4", + "@rollup/rollup-linux-riscv64-gnu": "4.22.4", + "@rollup/rollup-linux-s390x-gnu": "4.22.4", + "@rollup/rollup-linux-x64-gnu": "4.22.4", + "@rollup/rollup-linux-x64-musl": "4.22.4", + "@rollup/rollup-win32-arm64-msvc": "4.22.4", + "@rollup/rollup-win32-ia32-msvc": "4.22.4", + "@rollup/rollup-win32-x64-msvc": "4.22.4", "fsevents": "~2.3.2" } }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "dev": true + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1802.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.6.tgz", + "integrity": "sha512-JMLcXFaitJplwZMKkqhbYirINCRD6eOPZuIGaIOVynXYGWgvJkLT9t5C2wm9HqSLtp1K7NcYG2Y7PtTVR4krnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/architect": "0.1802.6", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { + "version": "0.1802.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.6.tgz", + "integrity": "sha512-oF7cPFdTLxeuvXkK/opSdIxZ1E4LrBbmuytQ/nCoAGOaKBWdqvwagRZ6jVhaI0Gwu48rkcV7Zhesg/ESNnROdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "18.2.6", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.6.tgz", + "integrity": "sha512-la4CFvs5PcRWSkQ/H7TB5cPZirFVA9GoWk5LzIk8si6VjWBJRm8b3keKJoC9LlNeABRUIR5z0ocYkyQQUhdMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", + "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", + "dev": true, + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.5.tgz", + "integrity": "sha512-NUmz2UQ1Xl4cf4j1AgkwIfsCjBzAPgfeC3IBrD29hSOBE1Y3j6auqjBkvw50v6mbSPxESND995Xy13HpK1Xflw==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "18.2.5", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.11", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@angular-eslint/builder": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.3.1.tgz", + "integrity": "sha512-cPc7Ye9zDs5M4i+feL6vob+mh7yX5vxvOS5KQIhneUrp5e9D+IGuNFMmBLlOPpmklSc9XJBtuvI5Zjuh4z1ETw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.1.tgz", + "integrity": "sha512-sikmkjfsXPpPTku1aQkQ1MNNEKGBgGGRvUN/WeNS9dhCJ4dxU3O7dZctt1aQWj+W3nbuUtDiimAWF5fZHGFE2Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-eslint/eslint-plugin": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.3.1.tgz", + "integrity": "sha512-MP4Nm+SHboF8KdnN0KpPEGAaTTzDLPm3+S/4W3Mg8onqWCyadyd4mActh9mK/pvCj8TVlb/SW1zeTtdMYhwonw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.3.1.tgz", + "integrity": "sha512-hBJ3+f7VSidvrtYaXH7Vp0sWvblA9jLK2c6uQzhYGWdEDUcTg7g7VI9ThW39WvMbHqkyzNE4PPOynK69cBEDGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "@angular-eslint/utils": "18.3.1", + "aria-query": "5.3.0", + "axobject-query": "4.1.0" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/template-parser": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.3.1.tgz", + "integrity": "sha512-JUUkfWH1G+u/Uk85ZYvJSt/qwN/Ko+jlXFtzBEcknJZsTWTwBcp36v77gPZe5FmKSziJZpyPUd+7Kiy6tuSCTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1", + "eslint-scope": "^8.0.2" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular-eslint/utils": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.3.1.tgz", + "integrity": "sha512-sd9niZI7h9H2FQ7OLiQsLFBhjhRQTASh+Q0+4+hyjv9idbSHBJli8Gsi2fqj9zhtMKpAZFTrWzuLUpubJ9UYbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-eslint/bundled-angular-compiler": "18.3.1" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*" + } + }, + "node_modules/@angular/animations": { + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.5.tgz", + "integrity": "sha512-IlXtW/Nj48ZzjHUzH1TykZcSR64ScJx39T3IHnjV2z/bVATzZ36JGoadQHdqpJNKBodYJNgtJCGLCbgAvGWY2g==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/core": "18.2.5" + } + }, "node_modules/@angular/cdk": { "version": "18.2.1", "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.1.tgz", @@ -1398,6 +1496,7 @@ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.24.7" }, @@ -3304,6 +3403,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -3320,6 +3420,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -3336,6 +3437,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -3352,6 +3454,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -3368,6 +3471,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3384,6 +3488,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3400,6 +3505,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3416,6 +3522,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3432,6 +3539,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3448,6 +3556,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3464,6 +3573,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3480,6 +3590,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3496,6 +3607,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3512,6 +3624,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3528,6 +3641,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3544,6 +3658,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3560,6 +3675,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -3576,6 +3692,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -3592,6 +3709,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -3608,6 +3726,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -3624,6 +3743,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -3640,6 +3760,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -3656,6 +3777,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -3672,6 +3794,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -5311,6 +5434,7 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -5327,6 +5451,7 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/base64": "^1.1.1", "@jsonjoy.com/util": "^1.1.2", @@ -5349,6 +5474,7 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -5370,7 +5496,8 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@listr2/prompt-adapter-inquirer": { "version": "2.0.15", @@ -5557,9 +5684,9 @@ ] }, "node_modules/@ngtools/webpack": { - "version": "18.2.5", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.5.tgz", - "integrity": "sha512-L0n4eHObeqEOYRfSP+e4SeF/dmwxOIFy9xYvYCOUwOLrW4b3+a1+kkT30pqyfL72LFtpf0cmUwaWEFIcWl5PCg==", + "version": "18.2.6", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.6.tgz", + "integrity": "sha512-7HwOPE1EOgcHnpt4brSiT8G2CcXB50G0+CbCBaKGy4LYCG3Y3mrlzF5Fup9HvMJ6Tzqd62RqzpKKYBiGUT7hxg==", "dev": true, "license": "MIT", "engines": { @@ -6111,208 +6238,224 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.0.tgz", - "integrity": "sha512-/IZQvg6ZR0tAkEi4tdXOraQoWeJy9gbQ/cx4I7k9dJaCk9qrXEcdouxRVz5kZXt5C2bQ9pILoAA+KB4C/d3pfw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.23.0.tgz", + "integrity": "sha512-8OR+Ok3SGEMsAZispLx8jruuXw0HVF16k+ub2eNXKHDmdxL4cf9NlNpAzhlOhNyXzKDEJuFeq0nZm+XlNb1IFw==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.0.tgz", - "integrity": "sha512-ETHi4bxrYnvOtXeM7d4V4kZWixib2jddFacJjsOjwbgYSRsyXYtZHC4ht134OsslPIcnkqT+TKV4eU8rNBKyyQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.23.0.tgz", + "integrity": "sha512-rEFtX1nP8gqmLmPZsXRMoLVNB5JBwOzIAk/XAcEPuKrPa2nPJ+DuGGpfQUR0XjRm8KjHfTZLpWbKXkA5BoFL3w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.0.tgz", - "integrity": "sha512-ZWgARzhSKE+gVUX7QWaECoRQsPwaD8ZR0Oxb3aUpzdErTvlEadfQpORPXkKSdKbFci9v8MJfkTtoEHnnW9Ulng==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.23.0.tgz", + "integrity": "sha512-ZbqlMkJRMMPeapfaU4drYHns7Q5MIxjM/QeOO62qQZGPh9XWziap+NF9fsqPHT0KzEL6HaPspC7sOwpgyA3J9g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.0.tgz", - "integrity": "sha512-h0ZAtOfHyio8Az6cwIGS+nHUfRMWBDO5jXB8PQCARVF6Na/G6XS2SFxDl8Oem+S5ZsHQgtsI7RT4JQnI1qrlaw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.23.0.tgz", + "integrity": "sha512-PfmgQp78xx5rBCgn2oYPQ1rQTtOaQCna0kRaBlc5w7RlA3TDGGo7m3XaptgitUZ54US9915i7KeVPHoy3/W8tA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.0.tgz", - "integrity": "sha512-9pxQJSPwFsVi0ttOmqLY4JJ9pg9t1gKhK0JDbV1yUEETSx55fdyCjt39eBQ54OQCzAF0nVGO6LfEH1KnCPvelA==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.23.0.tgz", + "integrity": "sha512-WAeZfAAPus56eQgBioezXRRzArAjWJGjNo/M+BHZygUcs9EePIuGI1Wfc6U/Ki+tMW17FFGvhCfYnfcKPh18SA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.0.tgz", - "integrity": "sha512-YJ5Ku5BmNJZb58A4qSEo3JlIG4d3G2lWyBi13ABlXzO41SsdnUKi3HQHe83VpwBVG4jHFTW65jOQb8qyoR+qzg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.23.0.tgz", + "integrity": "sha512-v7PGcp1O5XKZxKX8phTXtmJDVpE20Ub1eF6w9iMmI3qrrPak6yR9/5eeq7ziLMrMTjppkkskXyxnmm00HdtXjA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.0.tgz", - "integrity": "sha512-U4G4u7f+QCqHlVg1Nlx+qapZy+QoG+NV6ux+upo/T7arNGwKvKP2kmGM4W5QTbdewWFgudQxi3kDNST9GT1/mg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.23.0.tgz", + "integrity": "sha512-nAbWsDZ9UkU6xQiXEyXBNHAKbzSAi95H3gTStJq9UGiS1v+YVXwRHcQOQEF/3CHuhX5BVhShKoeOf6Q/1M+Zhg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.0.tgz", - "integrity": "sha512-aQpNlKmx3amwkA3a5J6nlXSahE1ijl0L9KuIjVOUhfOh7uw2S4piR3mtpxpRtbnK809SBtyPsM9q15CPTsY7HQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.23.0.tgz", + "integrity": "sha512-5QT/Di5FbGNPaVw8hHO1wETunwkPuZBIu6W+5GNArlKHD9fkMHy7vS8zGHJk38oObXfWdsuLMogD4sBySLJ54g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.0.tgz", - "integrity": "sha512-9fx6Zj/7vve/Fp4iexUFRKb5+RjLCff6YTRQl4CoDhdMfDoobWmhAxQWV3NfShMzQk1Q/iCnageFyGfqnsmeqQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.23.0.tgz", + "integrity": "sha512-Sefl6vPyn5axzCsO13r1sHLcmPuiSOrKIImnq34CBurntcJ+lkQgAaTt/9JkgGmaZJ+OkaHmAJl4Bfd0DmdtOQ==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.0.tgz", - "integrity": "sha512-VWQiCcN7zBgZYLjndIEh5tamtnKg5TGxyZPWcN9zBtXBwfcGSZ5cHSdQZfQH/GB4uRxk0D3VYbOEe/chJhPGLQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.23.0.tgz", + "integrity": "sha512-o4QI2KU/QbP7ZExMse6ULotdV3oJUYMrdx3rBZCgUF3ur3gJPfe8Fuasn6tia16c5kZBBw0aTmaUygad6VB/hQ==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.0.tgz", - "integrity": "sha512-EHmPnPWvyYqncObwqrosb/CpH3GOjE76vWVs0g4hWsDRUVhg61hBmlVg5TPXqF+g+PvIbqkC7i3h8wbn4Gp2Fg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.23.0.tgz", + "integrity": "sha512-+bxqx+V/D4FGrpXzPGKp/SEZIZ8cIW3K7wOtcJAoCrmXvzRtmdUhYNbgd+RztLzfDEfA2WtKj5F4tcbNPuqgeg==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.0.tgz", - "integrity": "sha512-tsSWy3YQzmpjDKnQ1Vcpy3p9Z+kMFbSIesCdMNgLizDWFhrLZIoN21JSq01g+MZMDFF+Y1+4zxgrlqPjid5ohg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.23.0.tgz", + "integrity": "sha512-I/eXsdVoCKtSgK9OwyQKPAfricWKUMNCwJKtatRYMmDo5N859tbO3UsBw5kT3dU1n6ZcM1JDzPRSGhAUkxfLxw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.0.tgz", - "integrity": "sha512-anr1Y11uPOQrpuU8XOikY5lH4Qu94oS6j0xrulHk3NkLDq19MlX8Ng/pVipjxBJ9a2l3+F39REZYyWQFkZ4/fw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.23.0.tgz", + "integrity": "sha512-4ZoDZy5ShLbbe1KPSafbFh1vbl0asTVfkABC7eWqIs01+66ncM82YJxV2VtV3YVJTqq2P8HMx3DCoRSWB/N3rw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.0.tgz", - "integrity": "sha512-7LB+Bh+Ut7cfmO0m244/asvtIGQr5pG5Rvjz/l1Rnz1kDzM02pSX9jPaS0p+90H5I1x4d1FkCew+B7MOnoatNw==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.23.0.tgz", + "integrity": "sha512-+5Ky8dhft4STaOEbZu3/NU4QIyYssKO+r1cD3FzuusA0vO5gso15on7qGzKdNXnc1gOrsgCqZjRw1w+zL4y4hQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.0.tgz", - "integrity": "sha512-+3qZ4rer7t/QsC5JwMpcvCVPRcJt1cJrYS/TMJZzXIJbxWFQEVhrIc26IhB+5Z9fT9umfVc+Es2mOZgl+7jdJQ==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.23.0.tgz", + "integrity": "sha512-0SPJk4cPZQhq9qA1UhIRumSE3+JJIBBjtlGl5PNC///BoaByckNZd53rOYD0glpTkYFBQSt7AkMeLVPfx65+BQ==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.0.tgz", - "integrity": "sha512-YdicNOSJONVx/vuPkgPTyRoAPx3GbknBZRCOUkK84FJ/YTfs/F0vl/YsMscrB6Y177d+yDRcj+JWMPMCgshwrA==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.23.0.tgz", + "integrity": "sha512-lqCK5GQC8fNo0+JvTSxcG7YB1UKYp8yrNLhsArlvPWN+16ovSZgoehlVHg6X0sSWPUkpjRBR5TuR12ZugowZ4g==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -6614,6 +6757,7 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -6624,6 +6768,7 @@ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6633,6 +6778,7 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6642,6 +6788,7 @@ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, + "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -6671,9 +6818,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, "license": "MIT" }, @@ -6682,6 +6829,7 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -6690,10 +6838,24 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz", + "integrity": "sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -6715,7 +6877,8 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/http-proxy": { "version": "1.17.15", @@ -6797,6 +6960,7 @@ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6833,7 +6997,8 @@ "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", @@ -6858,6 +7023,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } @@ -6867,6 +7033,7 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -6885,6 +7052,7 @@ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6908,6 +7076,7 @@ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7450,6 +7619,7 @@ "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.6.0" }, @@ -7883,6 +8053,7 @@ "engines": [ "node >= 0.8.0" ], + "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -7991,7 +8162,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/array-ify": { "version": "1.0.0", @@ -8460,7 +8632,8 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", @@ -8591,6 +8764,7 @@ "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -8775,6 +8949,7 @@ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, + "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" }, @@ -9498,6 +9673,7 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -9510,6 +9686,7 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -9528,6 +9705,7 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9537,6 +9715,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -9545,13 +9724,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", @@ -9581,6 +9762,7 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -9607,6 +9789,7 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -9894,7 +10077,8 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookiejar": { "version": "2.1.4", @@ -10075,6 +10259,7 @@ "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.24.tgz", "integrity": "sha512-Oyqew0FGM0wYUSNqR0L6AteO5MpMoUU0rhKRieXeiKs+PmRTxiJMyaunYB2KF6fQ3dzChXKCpbFOEJx3OQ1v/Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -10090,6 +10275,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -10105,6 +10291,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -10121,6 +10308,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -10132,13 +10320,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/critters/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10148,6 +10338,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -10231,6 +10422,7 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -10901,6 +11093,7 @@ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, + "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" @@ -10917,6 +11110,7 @@ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -10929,6 +11123,7 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -10941,6 +11136,7 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -10964,6 +11160,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -10976,6 +11173,7 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -10984,7 +11182,8 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/defaults": { "version": "1.0.4", @@ -11021,6 +11220,7 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -11165,7 +11365,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/dezalgo": { "version": "1.0.4", @@ -11213,6 +11414,7 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -11251,6 +11453,7 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -11278,6 +11481,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -11293,6 +11497,7 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -11761,6 +11966,7 @@ "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -12467,6 +12673,7 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12550,6 +12757,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -12592,6 +12800,7 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12601,6 +12810,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -12610,6 +12820,7 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -12619,6 +12830,7 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", @@ -12636,13 +12848,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/express/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -12776,6 +12990,7 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -13066,6 +13281,7 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13089,6 +13305,7 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -13724,7 +13941,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/handlebars": { "version": "4.7.8", @@ -13986,6 +14204,7 @@ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -13997,13 +14216,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -14018,13 +14239,15 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -14043,7 +14266,8 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ] + ], + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", @@ -14064,6 +14288,7 @@ "url": "https://github.com/sponsors/fb55" } ], + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -14082,7 +14307,8 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", @@ -14115,7 +14341,8 @@ "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", @@ -14209,6 +14436,7 @@ "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.18" } @@ -14551,6 +14779,7 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -14688,6 +14917,7 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -14736,6 +14966,7 @@ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, + "license": "MIT", "dependencies": { "is-docker": "^3.0.0" }, @@ -14783,6 +15014,7 @@ "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -15049,6 +15281,7 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, + "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -16025,6 +16258,7 @@ "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "dev": true, + "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -16986,6 +17220,7 @@ "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.12.0.tgz", "integrity": "sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", "@jsonjoy.com/util": "^1.3.0", @@ -17184,6 +17419,7 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -17370,7 +17606,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minimatch": { "version": "9.0.5", @@ -17632,6 +17869,7 @@ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -17681,6 +17919,7 @@ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, + "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -17884,6 +18123,7 @@ "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "!win32" @@ -17911,6 +18151,7 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/node-fetch": { @@ -17939,6 +18180,7 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } @@ -17973,6 +18215,7 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", "dev": true, + "license": "MIT", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -18537,7 +18780,8 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/on-finished": { "version": "2.4.1", @@ -18557,6 +18801,7 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -18591,6 +18836,7 @@ "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, + "license": "MIT", "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", @@ -18716,9 +18962,9 @@ } }, "node_modules/ordered-binary": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.1.tgz", - "integrity": "sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.2.tgz", + "integrity": "sha512-JTo+4+4Fw7FreyAvlSLjb1BBVaxEQAacmjD3jjuyPZclpbEghTvQZbXBb2qPd2LeIMxiHwXBZUcpmG2Gl/mDEA==", "dev": true, "license": "MIT" }, @@ -18802,6 +19048,7 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, + "license": "MIT", "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", @@ -18819,6 +19066,7 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -18994,6 +19242,7 @@ "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, + "license": "MIT", "dependencies": { "entities": "^4.3.0", "parse5": "^7.0.0", @@ -19008,6 +19257,7 @@ "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, + "license": "MIT", "dependencies": { "parse5": "^7.0.0" }, @@ -19097,7 +19347,8 @@ "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", @@ -19180,6 +19431,7 @@ "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", "dev": true, + "license": "MIT", "optionalDependencies": { "nice-napi": "^1.0.2" } @@ -19388,7 +19640,8 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", @@ -19890,6 +20143,7 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -19903,6 +20157,7 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -20917,12 +21172,13 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.0.tgz", - "integrity": "sha512-W21MUIFPZ4+O2Je/EU+GP3iz7PH4pVPUXSbEZdatQnxo29+3rsUjgrJmzuAZU24z7yRAnFN6ukxeAhZh/c7hzg==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.23.0.tgz", + "integrity": "sha512-vXB4IT9/KLDrS2WRXmY22sVB2wTsTwkpxjB8Q3mnakTENcYw3FRmfdYDy/acNmls+lHmDazgrRjK/yQ6hQAtwA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -20932,22 +21188,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.22.0", - "@rollup/rollup-android-arm64": "4.22.0", - "@rollup/rollup-darwin-arm64": "4.22.0", - "@rollup/rollup-darwin-x64": "4.22.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.22.0", - "@rollup/rollup-linux-arm-musleabihf": "4.22.0", - "@rollup/rollup-linux-arm64-gnu": "4.22.0", - "@rollup/rollup-linux-arm64-musl": "4.22.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.22.0", - "@rollup/rollup-linux-riscv64-gnu": "4.22.0", - "@rollup/rollup-linux-s390x-gnu": "4.22.0", - "@rollup/rollup-linux-x64-gnu": "4.22.0", - "@rollup/rollup-linux-x64-musl": "4.22.0", - "@rollup/rollup-win32-arm64-msvc": "4.22.0", - "@rollup/rollup-win32-ia32-msvc": "4.22.0", - "@rollup/rollup-win32-x64-msvc": "4.22.0", + "@rollup/rollup-android-arm-eabi": "4.23.0", + "@rollup/rollup-android-arm64": "4.23.0", + "@rollup/rollup-darwin-arm64": "4.23.0", + "@rollup/rollup-darwin-x64": "4.23.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.23.0", + "@rollup/rollup-linux-arm-musleabihf": "4.23.0", + "@rollup/rollup-linux-arm64-gnu": "4.23.0", + "@rollup/rollup-linux-arm64-musl": "4.23.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.23.0", + "@rollup/rollup-linux-riscv64-gnu": "4.23.0", + "@rollup/rollup-linux-s390x-gnu": "4.23.0", + "@rollup/rollup-linux-x64-gnu": "4.23.0", + "@rollup/rollup-linux-x64-musl": "4.23.0", + "@rollup/rollup-win32-arm64-msvc": "4.23.0", + "@rollup/rollup-win32-ia32-msvc": "4.23.0", + "@rollup/rollup-win32-x64-msvc": "4.23.0", "fsevents": "~2.3.2" } }, @@ -20966,6 +21222,7 @@ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -21251,7 +21508,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/selenium-webdriver": { "version": "3.6.0", @@ -21325,6 +21583,7 @@ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -21351,6 +21610,7 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -21375,6 +21635,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -21383,13 +21644,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -21401,13 +21664,15 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/send/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21427,6 +21692,7 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -21445,6 +21711,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -21454,6 +21721,7 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -21463,6 +21731,7 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -21477,25 +21746,29 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-static": { "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, + "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -21511,6 +21784,7 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -21642,6 +21916,7 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -21946,6 +22221,7 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, + "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -21957,6 +22233,7 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -22111,6 +22388,7 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -22127,6 +22405,7 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -22929,6 +23208,7 @@ "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", "dev": true, + "license": "Unlicense", "engines": { "node": ">=10.18" }, @@ -22957,7 +23237,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmp": { "version": "0.2.3", @@ -23048,6 +23329,7 @@ "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -23832,6 +24114,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -23894,6 +24177,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -23910,6 +24194,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -23926,6 +24211,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -23942,6 +24228,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -23958,6 +24245,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -23974,6 +24262,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -23990,6 +24279,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24006,6 +24296,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -24022,6 +24313,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24038,6 +24330,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24054,6 +24347,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24070,6 +24364,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24086,6 +24381,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24102,6 +24398,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24118,6 +24415,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24134,6 +24432,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24150,6 +24449,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -24166,6 +24466,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -24182,6 +24483,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -24198,6 +24500,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -24214,6 +24517,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -24230,6 +24534,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -24246,6 +24551,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -24260,6 +24566,7 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -24311,6 +24618,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.0", @@ -24349,6 +24657,7 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -24643,6 +24952,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", @@ -24672,6 +24982,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", "dev": true, + "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -24731,6 +25042,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -24751,6 +25063,7 @@ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -24775,6 +25088,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.3.7" }, @@ -24921,6 +25235,7 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -24935,6 +25250,7 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } diff --git a/ui/package.json b/ui/package.json index 2e1c9fe448..fdacf2654a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2024.10.0-SNAPSHOT", + "version": "2024.10.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/changelog/view/component/changelog.constants.ts b/ui/src/app/changelog/view/component/changelog.constants.ts index 700da6a26c..99abdf46dd 100644 --- a/ui/src/app/changelog/view/component/changelog.constants.ts +++ b/ui/src/app/changelog/view/component/changelog.constants.ts @@ -2,7 +2,7 @@ import { Role } from "src/app/shared/type/role"; export class Changelog { - public static readonly UI_VERSION = "2024.10.0-SNAPSHOT"; + public static readonly UI_VERSION = "2024.10.0"; public static product(...products: Product[]) { return products.map(product => Changelog.link(product.name, product.url)).join(", ") + ". ";