From 4e4882b9fa9c499d2db815c4a992fdb04284823d Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 22 Jan 2026 13:30:33 +0100 Subject: [PATCH] Remove supervisor build (#29132) --- .github/labeler.yml | 5 - .github/workflows/ci.yaml | 24 - .github/workflows/relative-ci.yaml | 2 +- .github/workflows/release.yaml | 29 - .vscode/tasks.json | 55 - README.md | 1 - build-scripts/bundle.cjs | 29 +- build-scripts/gulp/clean.js | 4 - build-scripts/gulp/compress.js | 27 - build-scripts/gulp/entry-html.js | 25 - build-scripts/gulp/gather-static.js | 11 - build-scripts/gulp/hassio.js | 45 - build-scripts/gulp/index.mjs | 1 - build-scripts/gulp/rspack.js | 26 - build-scripts/gulp/translations.js | 16 +- build-scripts/paths.cjs | 10 - build-scripts/rspack.cjs | 25 +- eslint.config.mjs | 1 - hassio/config.cjs | 9 - hassio/script/build_hassio | 9 - hassio/script/develop | 9 - .../addon-store/hassio-addon-repository.ts | 149 -- hassio/src/addon-store/hassio-addon-store.ts | 248 --- .../addon-view/config/hassio-addon-audio.ts | 207 --- .../config/hassio-addon-config-tab.ts | 113 -- .../addon-view/config/hassio-addon-config.ts | 507 ------ .../addon-view/config/hassio-addon-network.ts | 264 --- .../hassio-addon-documentation-tab.ts | 97 -- .../src/addon-view/hassio-addon-dashboard.ts | 294 ---- hassio/src/addon-view/hassio-addon-router.ts | 62 - .../addon-view/info/hassio-addon-info-tab.ts | 65 - .../src/addon-view/info/hassio-addon-info.ts | 1443 ----------------- .../info/hassio-addon-system-managed.ts | 59 - .../addon-view/log/hassio-addon-log-tab.ts | 92 -- hassio/src/backups/hassio-backups.ts | 425 ----- hassio/src/components/hassio-card-content.ts | 151 -- hassio/src/components/hassio-filter-addons.ts | 15 - hassio/src/components/hassio-upload-backup.ts | 89 - .../components/supervisor-backup-content.ts | 460 ------ .../components/supervisor-formfield-label.ts | 60 - hassio/src/components/supervisor-metric.ts | 75 - hassio/src/dashboard/hassio-addons.ts | 162 -- hassio/src/dashboard/hassio-dashboard.ts | 150 -- hassio/src/dashboard/hassio-update.ts | 158 -- .../backup/dialog-hassio-backup-location.ts | 155 -- .../backup/dialog-hassio-backup-upload.ts | 113 -- .../dialogs/backup/dialog-hassio-backup.ts | 339 ---- .../backup/dialog-hassio-create-backup.ts | 158 -- .../backup/show-dialog-backup-upload.ts | 19 - .../show-dialog-hassio-backu-location.ts | 17 - .../backup/show-dialog-hassio-backup.ts | 21 - .../show-dialog-hassio-create-backup.ts | 18 - .../datadisk/dialog-hassio-datadisk.ts | 184 --- .../datadisk/show-dialog-hassio-datadisk.ts | 17 - .../hardware/dialog-hassio-hardware.ts | 199 --- .../hardware/show-dialog-hassio-hardware.ts | 19 - .../markdown/dialog-hassio-markdown.ts | 70 - .../markdown/show-dialog-hassio-markdown.ts | 17 - .../dialogs/network/dialog-hassio-network.ts | 647 -------- .../dialogs/network/show-dialog-network.ts | 19 - .../registries/dialog-hassio-registries.ts | 255 --- .../registries/show-dialog-registries.ts | 18 - .../dialog-hassio-repositories.ts | 278 ---- .../repositories/show-dialog-repositories.ts | 19 - hassio/src/dialogs/suggestAddonRestart.ts | 38 - .../system-managed/dialog-system-managed.ts | 190 --- .../show-dialog-system-managed.ts | 19 - hassio/src/entrypoint.js.template | 23 - hassio/src/entrypoint.ts | 28 - hassio/src/hassio-main.ts | 146 -- hassio/src/hassio-my-redirect.ts | 155 -- hassio/src/hassio-panel-router.ts | 53 - hassio/src/hassio-panel.ts | 55 - hassio/src/hassio-router.ts | 91 -- hassio/src/hassio-tabs.ts | 34 - .../src/ingress-view/hassio-ingress-view.ts | 377 ----- hassio/src/resources/hassio-style.ts | 55 - hassio/src/supervisor-base-element.ts | 231 --- hassio/src/system/hassio-core-info.ts | 206 --- hassio/src/system/hassio-host-info.ts | 453 ------ hassio/src/system/hassio-supervisor-info.ts | 469 ------ hassio/src/system/hassio-supervisor-log.ts | 162 -- hassio/src/system/hassio-system.ts | 93 -- .../update-available/update-available-card.ts | 506 ------ .../update-available-dashboard.ts | 60 - hassio/src/util/addon.ts | 30 - script/core | 16 +- src/components/ha-code-editor.ts | 9 +- src/components/ha-menu-button.ts | 14 - src/data/hassio/addon.ts | 2 +- src/data/hassio/resolution.ts | 4 +- src/data/iconsets.ts | 14 +- src/data/supervisor/supervisor.ts | 8 - src/layouts/hass-subpage.ts | 3 - src/layouts/hass-tabs-subpage.ts | 3 - src/panels/config/ha-panel-config.ts | 1 - src/panels/config/logs/error-log-card.ts | 7 +- src/state/quick-bar-mixin.ts | 13 +- src/translations/en.json | 691 +------- src/types.ts | 1 - test/vitest.config.ts | 1 - 101 files changed, 80 insertions(+), 12471 deletions(-) delete mode 100644 build-scripts/gulp/hassio.js delete mode 100644 hassio/config.cjs delete mode 100755 hassio/script/build_hassio delete mode 100755 hassio/script/develop delete mode 100644 hassio/src/addon-store/hassio-addon-repository.ts delete mode 100644 hassio/src/addon-store/hassio-addon-store.ts delete mode 100644 hassio/src/addon-view/config/hassio-addon-audio.ts delete mode 100644 hassio/src/addon-view/config/hassio-addon-config-tab.ts delete mode 100644 hassio/src/addon-view/config/hassio-addon-config.ts delete mode 100644 hassio/src/addon-view/config/hassio-addon-network.ts delete mode 100644 hassio/src/addon-view/documentation/hassio-addon-documentation-tab.ts delete mode 100644 hassio/src/addon-view/hassio-addon-dashboard.ts delete mode 100644 hassio/src/addon-view/hassio-addon-router.ts delete mode 100644 hassio/src/addon-view/info/hassio-addon-info-tab.ts delete mode 100644 hassio/src/addon-view/info/hassio-addon-info.ts delete mode 100644 hassio/src/addon-view/info/hassio-addon-system-managed.ts delete mode 100644 hassio/src/addon-view/log/hassio-addon-log-tab.ts delete mode 100644 hassio/src/backups/hassio-backups.ts delete mode 100644 hassio/src/components/hassio-card-content.ts delete mode 100644 hassio/src/components/hassio-filter-addons.ts delete mode 100644 hassio/src/components/hassio-upload-backup.ts delete mode 100644 hassio/src/components/supervisor-backup-content.ts delete mode 100644 hassio/src/components/supervisor-formfield-label.ts delete mode 100644 hassio/src/components/supervisor-metric.ts delete mode 100644 hassio/src/dashboard/hassio-addons.ts delete mode 100644 hassio/src/dashboard/hassio-dashboard.ts delete mode 100644 hassio/src/dashboard/hassio-update.ts delete mode 100644 hassio/src/dialogs/backup/dialog-hassio-backup-location.ts delete mode 100644 hassio/src/dialogs/backup/dialog-hassio-backup-upload.ts delete mode 100644 hassio/src/dialogs/backup/dialog-hassio-backup.ts delete mode 100644 hassio/src/dialogs/backup/dialog-hassio-create-backup.ts delete mode 100644 hassio/src/dialogs/backup/show-dialog-backup-upload.ts delete mode 100644 hassio/src/dialogs/backup/show-dialog-hassio-backu-location.ts delete mode 100644 hassio/src/dialogs/backup/show-dialog-hassio-backup.ts delete mode 100644 hassio/src/dialogs/backup/show-dialog-hassio-create-backup.ts delete mode 100644 hassio/src/dialogs/datadisk/dialog-hassio-datadisk.ts delete mode 100644 hassio/src/dialogs/datadisk/show-dialog-hassio-datadisk.ts delete mode 100644 hassio/src/dialogs/hardware/dialog-hassio-hardware.ts delete mode 100644 hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts delete mode 100644 hassio/src/dialogs/markdown/dialog-hassio-markdown.ts delete mode 100644 hassio/src/dialogs/markdown/show-dialog-hassio-markdown.ts delete mode 100644 hassio/src/dialogs/network/dialog-hassio-network.ts delete mode 100644 hassio/src/dialogs/network/show-dialog-network.ts delete mode 100644 hassio/src/dialogs/registries/dialog-hassio-registries.ts delete mode 100644 hassio/src/dialogs/registries/show-dialog-registries.ts delete mode 100644 hassio/src/dialogs/repositories/dialog-hassio-repositories.ts delete mode 100644 hassio/src/dialogs/repositories/show-dialog-repositories.ts delete mode 100644 hassio/src/dialogs/suggestAddonRestart.ts delete mode 100644 hassio/src/dialogs/system-managed/dialog-system-managed.ts delete mode 100644 hassio/src/dialogs/system-managed/show-dialog-system-managed.ts delete mode 100644 hassio/src/entrypoint.js.template delete mode 100644 hassio/src/entrypoint.ts delete mode 100644 hassio/src/hassio-main.ts delete mode 100644 hassio/src/hassio-my-redirect.ts delete mode 100644 hassio/src/hassio-panel-router.ts delete mode 100644 hassio/src/hassio-panel.ts delete mode 100644 hassio/src/hassio-router.ts delete mode 100644 hassio/src/hassio-tabs.ts delete mode 100644 hassio/src/ingress-view/hassio-ingress-view.ts delete mode 100644 hassio/src/resources/hassio-style.ts delete mode 100644 hassio/src/supervisor-base-element.ts delete mode 100644 hassio/src/system/hassio-core-info.ts delete mode 100644 hassio/src/system/hassio-host-info.ts delete mode 100644 hassio/src/system/hassio-supervisor-info.ts delete mode 100644 hassio/src/system/hassio-supervisor-log.ts delete mode 100644 hassio/src/system/hassio-system.ts delete mode 100644 hassio/src/update-available/update-available-card.ts delete mode 100644 hassio/src/update-available/update-available-dashboard.ts delete mode 100644 hassio/src/util/addon.ts diff --git a/.github/labeler.yml b/.github/labeler.yml index e772cc81a5..244a249378 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -44,8 +44,3 @@ GitHub Actions: - any-glob-to-any-file: - .github/workflows/** - .github/*.yml - -Supervisor: - - changed-files: - - any-glob-to-any-file: - - hassio/src/** diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2a6a870fc2..143c9d34ba 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -101,27 +101,3 @@ jobs: path: hass_frontend/ if-no-files-found: error retention-days: 7 - supervisor: - name: Build supervisor - needs: [lint, test] - runs-on: ubuntu-latest - steps: - - name: Check out files from GitHub - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Setup Node - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version-file: ".nvmrc" - cache: yarn - - name: Install dependencies - run: yarn install --immutable - - name: Build Application - run: ./node_modules/.bin/gulp build-hassio - env: - IS_TEST: "true" - - name: Upload bundle stats - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: supervisor-bundle-stats - path: build/stats/*.json - if-no-files-found: error diff --git a/.github/workflows/relative-ci.yaml b/.github/workflows/relative-ci.yaml index ec9f79d2ad..22bb409b8f 100644 --- a/.github/workflows/relative-ci.yaml +++ b/.github/workflows/relative-ci.yaml @@ -12,7 +12,7 @@ jobs: if: ${{ github.event.workflow_run.conclusion == 'success' }} strategy: matrix: - bundle: [frontend, supervisor] + bundle: [frontend] build: [modern, legacy] runs-on: ubuntu-latest steps: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d8c59ba296..405e601a1e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -118,32 +118,3 @@ jobs: uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 with: files: landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz - - release-supervisor: - name: Release supervisor frontend - if: github.event.release.prerelease == false - runs-on: ubuntu-latest - permissions: - contents: write # Required to upload release assets - steps: - - name: Checkout the repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Setup Node - uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 - with: - node-version-file: ".nvmrc" - cache: yarn - - name: Install dependencies - run: yarn install - - name: Download Translations - run: ./script/translations_download - env: - LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }} - - name: Build supervisor - run: hassio/script/build_hassio - - name: Tar folder - run: tar -czf hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz -C hassio/build . - - name: Upload release asset - uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 - with: - files: hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 401f183930..49291d22ba 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -73,37 +73,6 @@ "instanceLimit": 1 } }, - { - "label": "Develop Supervisor panel", - "type": "gulp", - "task": "develop-hassio", - "problemMatcher": { - "owner": "ha-build", - "source": "ha-build", - "fileLocation": "absolute", - "severity": "error", - "pattern": [ - { - "regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)", - "severity": 1, - "file": 2, - "message": 3, - "line": 4, - "column": 5 - } - ], - "background": { - "activeOnStart": true, - "beginsPattern": "Changes detected. Starting compilation", - "endsPattern": "Build done @" - } - }, - "isBackground": true, - "group": "build", - "runOptions": { - "instanceLimit": 1 - } - }, { "label": "Develop Gallery", "type": "gulp", @@ -246,20 +215,6 @@ "instanceLimit": 1 } }, - { - "label": "Run HA Core for Supervisor in devcontainer", - "type": "shell", - "command": "SUPERVISOR=${input:supervisorHost} SUPERVISOR_TOKEN=${input:supervisorToken} script/core", - "isBackground": true, - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": [], - "runOptions": { - "instanceLimit": 1 - } - }, { "label": "Setup and fetch nightly translations", "type": "gulp", @@ -268,16 +223,6 @@ } ], "inputs": [ - { - "id": "supervisorHost", - "type": "promptString", - "description": "The IP of the Supervisor host running the Remote API proxy add-on" - }, - { - "id": "supervisorToken", - "type": "promptString", - "description": "The token for the Remote API proxy add-on" - }, { "id": "coreUrl", "type": "promptString", diff --git a/README.md b/README.md index 0e6f470a01..4c3d20c4b8 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,6 @@ This is the repository for the official [Home Assistant](https://home-assistant. - Development: [Instructions](https://developers.home-assistant.io/docs/frontend/development/) - Production build: `script/build_frontend` - Gallery: `cd gallery && script/develop_gallery` -- Supervisor: [Instructions](https://developers.home-assistant.io/docs/supervisor/developing) ## Frontend development diff --git a/build-scripts/bundle.cjs b/build-scripts/bundle.cjs index 5381e40730..2778a32306 100644 --- a/build-scripts/bundle.cjs +++ b/build-scripts/bundle.cjs @@ -18,14 +18,14 @@ module.exports.sourceMapURL = () => { module.exports.ignorePackages = () => []; // Files from NPM packages that we should replace with empty file -module.exports.emptyPackages = ({ isHassioBuild, isLandingPageBuild }) => +module.exports.emptyPackages = ({ isLandingPageBuild }) => [ - // Icons in supervisor conflict with icons in HA so we don't load. - (isHassioBuild || isLandingPageBuild) && + // Icons in landingpage conflict with icons in HA so we don't load. + isLandingPageBuild && require.resolve( path.resolve(paths.root_dir, "src/components/ha-icon.ts") ), - (isHassioBuild || isLandingPageBuild) && + isLandingPageBuild && require.resolve( path.resolve(paths.root_dir, "src/components/ha-icon-picker.ts") ), @@ -36,7 +36,6 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({ __BUILD__: JSON.stringify(latestBuild ? "modern" : "legacy"), __VERSION__: JSON.stringify(env.version()), __DEMO__: false, - __SUPERVISOR__: false, __BACKWARDS_COMPAT__: false, __STATIC_PATH__: "/static/", __HASS_URL__: `\`${ @@ -289,26 +288,6 @@ module.exports.config = { }; }, - hassio({ isProdBuild, latestBuild, isStatsBuild, isTestBuild }) { - return { - name: "supervisor" + nameSuffix(latestBuild), - entry: { - entrypoint: path.resolve(paths.hassio_dir, "src/entrypoint.ts"), - }, - outputPath: outputPath(paths.hassio_output_root, latestBuild), - publicPath: publicPath(latestBuild, paths.hassio_publicPath), - isProdBuild, - latestBuild, - isStatsBuild, - isTestBuild, - isHassioBuild: true, - defineOverlay: { - __SUPERVISOR__: true, - __STATIC_PATH__: `"${paths.hassio_publicPath}/static/"`, - }, - }; - }, - gallery({ isProdBuild, latestBuild }) { return { name: "gallery" + nameSuffix(latestBuild), diff --git a/build-scripts/gulp/clean.js b/build-scripts/gulp/clean.js index b7c570c9d4..0c4cc0a76b 100644 --- a/build-scripts/gulp/clean.js +++ b/build-scripts/gulp/clean.js @@ -24,10 +24,6 @@ gulp.task( ) ); -gulp.task("clean-hassio", async () => - deleteSync([paths.hassio_output_root, paths.build_dir]) -); - gulp.task( "clean-gallery", gulp.parallel("clean-translations", async () => diff --git a/build-scripts/gulp/compress.js b/build-scripts/gulp/compress.js index 81e1c87abe..62df03ed54 100644 --- a/build-scripts/gulp/compress.js +++ b/build-scripts/gulp/compress.js @@ -43,29 +43,11 @@ const compressAppModernBrotli = () => const compressAppModernZopfli = () => compressModern(paths.app_output_root, paths.app_output_latest, "zopfli"); -const compressHassioModernBrotli = () => - compressModern( - paths.hassio_output_root, - paths.hassio_output_latest, - "brotli" - ); -const compressHassioModernZopfli = () => - compressModern( - paths.hassio_output_root, - paths.hassio_output_latest, - "zopfli" - ); - const compressAppOtherBrotli = () => compressOther(paths.app_output_root, paths.app_output_latest, "brotli"); const compressAppOtherZopfli = () => compressOther(paths.app_output_root, paths.app_output_latest, "zopfli"); -const compressHassioOtherBrotli = () => - compressOther(paths.hassio_output_root, paths.hassio_output_latest, "brotli"); -const compressHassioOtherZopfli = () => - compressOther(paths.hassio_output_root, paths.hassio_output_latest, "zopfli"); - gulp.task( "compress-app", gulp.parallel( @@ -75,12 +57,3 @@ gulp.task( compressAppOtherZopfli ) ); -gulp.task( - "compress-hassio", - gulp.parallel( - compressHassioModernBrotli, - compressHassioOtherBrotli, - compressHassioModernZopfli, - compressHassioOtherZopfli - ) -); diff --git a/build-scripts/gulp/entry-html.js b/build-scripts/gulp/entry-html.js index d41dd8f457..4eb8e91e88 100644 --- a/build-scripts/gulp/entry-html.js +++ b/build-scripts/gulp/entry-html.js @@ -266,28 +266,3 @@ gulp.task( paths.landingPage_output_es5 ) ); - -const HASSIO_PAGE_ENTRIES = { "entrypoint.js": ["entrypoint"] }; - -gulp.task( - "gen-pages-hassio-dev", - genPagesDevTask( - HASSIO_PAGE_ENTRIES, - paths.hassio_dir, - paths.hassio_output_root, - "src", - paths.hassio_publicPath - ) -); - -gulp.task( - "gen-pages-hassio-prod", - genPagesProdTask( - HASSIO_PAGE_ENTRIES, - paths.hassio_dir, - paths.hassio_output_root, - paths.hassio_output_latest, - paths.hassio_output_es5, - "src" - ) -); diff --git a/build-scripts/gulp/gather-static.js b/build-scripts/gulp/gather-static.js index 0c8637c21c..88b1f4d3cc 100644 --- a/build-scripts/gulp/gather-static.js +++ b/build-scripts/gulp/gather-static.js @@ -123,22 +123,11 @@ gulp.task("copy-translations-app", async () => { copyTranslations(staticDir); }); -gulp.task("copy-translations-supervisor", async () => { - const staticDir = paths.hassio_output_static; - copyTranslations(staticDir); -}); - gulp.task("copy-translations-landing-page", async () => { const staticDir = paths.landingPage_output_static; copyTranslations(staticDir); }); -gulp.task("copy-static-supervisor", async () => { - const staticDir = paths.hassio_output_static; - copyLocaleData(staticDir); - copyFonts(staticDir); -}); - gulp.task("copy-static-app", async () => { const staticDir = paths.app_output_static; // Basic static files diff --git a/build-scripts/gulp/hassio.js b/build-scripts/gulp/hassio.js deleted file mode 100644 index a09c0d1ea4..0000000000 --- a/build-scripts/gulp/hassio.js +++ /dev/null @@ -1,45 +0,0 @@ -import gulp from "gulp"; -import env from "../env.cjs"; -import "./clean.js"; -import "./compress.js"; -import "./entry-html.js"; -import "./gather-static.js"; -import "./gen-icons-json.js"; -import "./translations.js"; -import "./rspack.js"; - -gulp.task( - "develop-hassio", - gulp.series( - async function setEnv() { - process.env.NODE_ENV = "development"; - }, - "clean-hassio", - "gen-dummy-icons-json", - "gen-pages-hassio-dev", - "build-supervisor-translations", - "copy-translations-supervisor", - "build-locale-data", - "copy-static-supervisor", - "rspack-watch-hassio" - ) -); - -gulp.task( - "build-hassio", - gulp.series( - async function setEnv() { - process.env.NODE_ENV = "production"; - }, - "clean-hassio", - "gen-dummy-icons-json", - "build-supervisor-translations", - "copy-translations-supervisor", - "build-locale-data", - "copy-static-supervisor", - "rspack-prod-hassio", - "gen-pages-hassio-prod", - ...// Don't compress running tests - (env.isTestBuild() ? [] : ["compress-hassio"]) - ) -); diff --git a/build-scripts/gulp/index.mjs b/build-scripts/gulp/index.mjs index 8ae6311ff2..e7cdcc3368 100644 --- a/build-scripts/gulp/index.mjs +++ b/build-scripts/gulp/index.mjs @@ -9,7 +9,6 @@ import "./fetch-nightly-translations.js"; import "./gallery.js"; import "./gather-static.js"; import "./gen-icons-json.js"; -import "./hassio.js"; import "./landing-page.js"; import "./locale-data.js"; import "./rspack.js"; diff --git a/build-scripts/gulp/rspack.js b/build-scripts/gulp/rspack.js index 84f9d71079..2080c84a87 100644 --- a/build-scripts/gulp/rspack.js +++ b/build-scripts/gulp/rspack.js @@ -13,7 +13,6 @@ import { createCastConfig, createDemoConfig, createGalleryConfig, - createHassioConfig, createLandingPageConfig, } from "../rspack.cjs"; @@ -159,31 +158,6 @@ gulp.task("rspack-prod-cast", () => ) ); -gulp.task("rspack-watch-hassio", () => { - // This command will run forever because we don't close compiler - rspack( - createHassioConfig({ - isProdBuild: false, - latestBuild: true, - }) - ).watch({ ignored: /build/, poll: isWsl }, doneHandler()); - - gulp.watch( - path.join(paths.translations_src, "en.json"), - gulp.series("build-supervisor-translations", "copy-translations-supervisor") - ); -}); - -gulp.task("rspack-prod-hassio", () => - prodBuild( - bothBuilds(createHassioConfig, { - isProdBuild: true, - isStatsBuild: env.isStatsBuild(), - isTestBuild: env.isTestBuild(), - }) - ) -); - gulp.task("rspack-dev-server-gallery", () => runDevServer({ compiler: rspack( diff --git a/build-scripts/gulp/translations.js b/build-scripts/gulp/translations.js index 76af601e89..c5d4275dbf 100755 --- a/build-scripts/gulp/translations.js +++ b/build-scripts/gulp/translations.js @@ -170,9 +170,7 @@ const setFragment = (fragment) => async () => { }; const panelFragment = (fragment) => - fragment !== "base" && - fragment !== "supervisor" && - fragment !== "landing-page"; + fragment !== "base" && fragment !== "landing-page"; const HASHES = new Map(); @@ -207,18 +205,15 @@ const createTranslations = async () => { FRAGMENTS.map((fragment) => { switch (fragment) { case "base": - // Remove the panels and supervisor to create the base translations + // Remove the panels and landing-page to create the base translations return [ flatten({ ...data, ui: { ...data.ui, panel: undefined }, - supervisor: undefined, + "landing-page": undefined, }), "", ]; - case "supervisor": - // Supervisor key is at the top level - return [flatten(data.supervisor), ""]; case "landing-page": // landing-page key is at the top level return [flatten(data["landing-page"]), ""]; @@ -318,11 +313,6 @@ gulp.task( ) ); -gulp.task( - "build-supervisor-translations", - gulp.series(setFragment("supervisor"), "build-translations") -); - gulp.task( "build-landing-page-translations", gulp.series(setFragment("landing-page"), "build-translations") diff --git a/build-scripts/paths.cjs b/build-scripts/paths.cjs index b181ee7c00..43a784ab35 100644 --- a/build-scripts/paths.cjs +++ b/build-scripts/paths.cjs @@ -49,15 +49,5 @@ module.exports = { "../landing-page/dist/static" ), - hassio_dir: path.resolve(__dirname, "../hassio"), - hassio_output_root: path.resolve(__dirname, "../hassio/build"), - hassio_output_static: path.resolve(__dirname, "../hassio/build/static"), - hassio_output_latest: path.resolve( - __dirname, - "../hassio/build/frontend_latest" - ), - hassio_output_es5: path.resolve(__dirname, "../hassio/build/frontend_es5"), - hassio_publicPath: "/api/hassio/app", - translations_src: path.resolve(__dirname, "../src/translations"), }; diff --git a/build-scripts/rspack.cjs b/build-scripts/rspack.cjs index 600f8ef615..207cd10131 100644 --- a/build-scripts/rspack.cjs +++ b/build-scripts/rspack.cjs @@ -40,7 +40,6 @@ const createRspackConfig = ({ latestBuild, isStatsBuild, isTestBuild, - isHassioBuild, isLandingPageBuild, dontHash, }) => { @@ -168,13 +167,9 @@ const createRspackConfig = ({ ); }, }), - bundle.emptyPackages({ isHassioBuild, isLandingPageBuild }).length + bundle.emptyPackages({ isLandingPageBuild }).length ? new rspack.NormalModuleReplacementPlugin( - new RegExp( - bundle - .emptyPackages({ isHassioBuild, isLandingPageBuild }) - .join("|") - ), + new RegExp(bundle.emptyPackages({ isLandingPageBuild }).join("|")), path.resolve(paths.root_dir, "src/util/empty.js") ) : false, @@ -326,21 +321,6 @@ const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => const createCastConfig = ({ isProdBuild, latestBuild }) => createRspackConfig(bundle.config.cast({ isProdBuild, latestBuild })); -const createHassioConfig = ({ - isProdBuild, - latestBuild, - isStatsBuild, - isTestBuild, -}) => - createRspackConfig( - bundle.config.hassio({ - isProdBuild, - latestBuild, - isStatsBuild, - isTestBuild, - }) - ); - const createGalleryConfig = ({ isProdBuild, latestBuild }) => createRspackConfig(bundle.config.gallery({ isProdBuild, latestBuild })); @@ -351,7 +331,6 @@ module.exports = { createAppConfig, createDemoConfig, createCastConfig, - createHassioConfig, createGalleryConfig, createRspackConfig, createLandingPageConfig, diff --git a/eslint.config.mjs b/eslint.config.mjs index 401abeb4ec..a1aa9e96fa 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -43,7 +43,6 @@ export default tseslint.config( __BUILD__: false, __VERSION__: false, __STATIC_PATH__: false, - __SUPERVISOR__: false, }, parser: tseslint.parser, diff --git a/hassio/config.cjs b/hassio/config.cjs deleted file mode 100644 index 732fb98c68..0000000000 --- a/hassio/config.cjs +++ /dev/null @@ -1,9 +0,0 @@ -const path = require("path"); - -module.exports = { - // Target directory for the build. - buildDir: path.resolve(__dirname, "build"), - nodeDir: path.resolve(__dirname, "../node_modules"), - // Path where the Hass.io frontend will be publicly available. - publicPath: "/api/hassio/app", -}; diff --git a/hassio/script/build_hassio b/hassio/script/build_hassio deleted file mode 100755 index 193cbb0687..0000000000 --- a/hassio/script/build_hassio +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# Builds the Hass.io app for production - -# Stop on errors -set -e - -cd "$(dirname "$0")/../.." - -./node_modules/.bin/gulp build-hassio diff --git a/hassio/script/develop b/hassio/script/develop deleted file mode 100755 index 0b62666b10..0000000000 --- a/hassio/script/develop +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -# Run the Hass.io development server - -# Stop on errors -set -e - -cd "$(dirname "$0")/../.." - -./node_modules/.bin/gulp develop-hassio diff --git a/hassio/src/addon-store/hassio-addon-repository.ts b/hassio/src/addon-store/hassio-addon-repository.ts deleted file mode 100644 index 1f92d035d4..0000000000 --- a/hassio/src/addon-store/hassio-addon-repository.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js"; -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { atLeastVersion } from "../../../src/common/config/version"; -import { navigate } from "../../../src/common/navigate"; -import { caseInsensitiveStringCompare } from "../../../src/common/string/compare"; -import "../../../src/components/ha-card"; -import type { HassioAddonRepository } from "../../../src/data/hassio/addon"; -import type { StoreAddon } from "../../../src/data/supervisor/store"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import type { HomeAssistant } from "../../../src/types"; -import "../components/hassio-card-content"; -import { filterAndSort } from "../components/hassio-filter-addons"; -import { hassioStyle } from "../resources/hassio-style"; - -@customElement("hassio-addon-repository") -export class HassioAddonRepositoryEl extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public repo!: HassioAddonRepository; - - @property({ attribute: false }) public addons!: StoreAddon[]; - - @property() public filter!: string; - - private _getAddons = memoizeOne((addons: StoreAddon[], filter?: string) => { - if (filter) { - return filterAndSort(addons, filter); - } - return addons.sort((a, b) => - caseInsensitiveStringCompare(a.name, b.name, this.hass.locale.language) - ); - }); - - protected render(): TemplateResult { - const repo = this.repo; - let _addons = this.addons; - if (!this.hass.userData?.showAdvanced) { - _addons = _addons.filter( - (addon) => !addon.advanced && addon.stage === "stable" - ); - } - const addons = this._getAddons(_addons, this.filter); - - if (this.filter && addons.length < 1) { - return html` -
-

- ${this.supervisor.localize("store.no_results_found", { - repository: repo.name, - })} -

-
- `; - } - return html` -
-

${repo.name}

-
- ${addons.map( - (addon) => html` - -
- -
-
- ` - )} -
-
- `; - } - - private _addonTapped(ev) { - navigate(`/hassio/addon/${ev.currentTarget.addon.slug}?store=true`); - } - - static get styles(): CSSResultGroup { - return [ - hassioStyle, - css` - ha-card { - cursor: pointer; - overflow: hidden; - } - .not_available { - opacity: 0.6; - } - a.repo { - color: var(--primary-text-color); - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-repository": HassioAddonRepositoryEl; - } -} diff --git a/hassio/src/addon-store/hassio-addon-store.ts b/hassio/src/addon-store/hassio-addon-store.ts deleted file mode 100644 index 6f8f7dfa23..0000000000 --- a/hassio/src/addon-store/hassio-addon-store.ts +++ /dev/null @@ -1,248 +0,0 @@ -import type { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; - -import { mdiDotsVertical } from "@mdi/js"; -import type { PropertyValues, TemplateResult } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { atLeastVersion } from "../../../src/common/config/version"; -import { fireEvent } from "../../../src/common/dom/fire_event"; -import { navigate } from "../../../src/common/navigate"; -import { extractSearchParam } from "../../../src/common/url/search-params"; -import "../../../src/components/ha-button-menu"; -import "../../../src/components/ha-icon-button"; -import "../../../src/components/ha-list-item"; -import "../../../src/components/search-input"; -import type { HassioAddonRepository } from "../../../src/data/hassio/addon"; -import { reloadHassioAddons } from "../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import type { StoreAddon } from "../../../src/data/supervisor/store"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box"; -import "../../../src/layouts/hass-loading-screen"; -import "../../../src/layouts/hass-subpage"; -import type { HomeAssistant, Route } from "../../../src/types"; -import { showRegistriesDialog } from "../dialogs/registries/show-dialog-registries"; -import { showRepositoriesDialog } from "../dialogs/repositories/show-dialog-repositories"; -import "./hassio-addon-repository"; - -const sortRepos = (a: HassioAddonRepository, b: HassioAddonRepository) => { - if (a.slug === "local") { - return -1; - } - if (b.slug === "local") { - return 1; - } - if (a.slug === "core") { - return -1; - } - if (b.slug === "core") { - return 1; - } - return a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1; -}; - -@customElement("hassio-addon-store") -export class HassioAddonStore extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public route!: Route; - - @state() private _filter?: string; - - public async refreshData() { - try { - await reloadHassioAddons(this.hass); - } catch (err) { - showAlertDialog(this, { - text: extractApiErrorMessage(err), - }); - } finally { - this._loadData(); - } - } - - protected render() { - let repos: (TemplateResult | typeof nothing)[] = []; - - if (this.supervisor.store.repositories) { - repos = this.addonRepositories( - this.supervisor.store.repositories, - this.supervisor.store.addons, - this._filter - ); - } - - return html` - - - - - ${this.supervisor.localize("store.check_updates")} - - - ${this.supervisor.localize("store.repositories")} - - ${this.hass.userData?.showAdvanced && - atLeastVersion(this.hass.config.version, 0, 117) - ? html` - ${this.supervisor.localize("store.registries")} - ` - : ""} - - ${repos.length === 0 - ? html`` - : html` - - - ${repos} - `} - ${!this.hass.userData?.showAdvanced - ? html` - - ` - : ""} - - `; - } - - protected firstUpdated(changedProps: PropertyValues) { - super.firstUpdated(changedProps); - const repositoryUrl = extractSearchParam("repository_url"); - navigate("/hassio/store", { replace: true }); - if (repositoryUrl) { - this._manageRepositories(repositoryUrl); - } - - this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev)); - this._loadData(); - } - - private addonRepositories = memoizeOne( - ( - repositories: HassioAddonRepository[], - addons: StoreAddon[], - filter?: string - ) => - repositories.sort(sortRepos).map((repo) => { - const filteredAddons = addons.filter( - (addon) => addon.repository === repo.slug - ); - - return filteredAddons.length !== 0 - ? html` - - ` - : nothing; - }) - ); - - private _handleAction(ev: CustomEvent) { - switch (ev.detail.index) { - case 0: - this.refreshData(); - break; - case 1: - this._manageRepositoriesClicked(); - break; - case 2: - this._manageRegistries(); - break; - } - } - - private _apiCalled(ev) { - if (ev.detail.success) { - this._loadData(); - } - } - - private _manageRepositoriesClicked() { - this._manageRepositories(); - } - - private _manageRepositories(url?: string) { - showRepositoriesDialog(this, { - supervisor: this.supervisor, - url, - }); - } - - private _manageRegistries() { - showRegistriesDialog(this, { supervisor: this.supervisor }); - } - - private _loadData() { - fireEvent(this, "supervisor-collection-refresh", { collection: "addon" }); - fireEvent(this, "supervisor-collection-refresh", { - collection: "supervisor", - }); - } - - private _filterChanged(e) { - this._filter = e.detail.value; - } - - static styles = css` - hassio-addon-repository { - margin-top: 24px; - } - .search { - position: sticky; - top: 0; - z-index: 2; - } - search-input { - display: block; - --mdc-text-field-fill-color: var(--sidebar-background-color); - --mdc-text-field-idle-line-color: var(--divider-color); - } - .advanced { - padding: 12px; - display: flex; - flex-wrap: wrap; - color: var(--primary-text-color); - } - .advanced a { - margin-left: 0.5em; - margin-inline-start: 0.5em; - margin-inline-end: initial; - color: var(--primary-color); - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-store": HassioAddonStore; - } -} diff --git a/hassio/src/addon-view/config/hassio-addon-audio.ts b/hassio/src/addon-view/config/hassio-addon-audio.ts deleted file mode 100644 index 623fd1a3bb..0000000000 --- a/hassio/src/addon-view/config/hassio-addon-audio.ts +++ /dev/null @@ -1,207 +0,0 @@ -import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { stopPropagation } from "../../../../src/common/dom/stop_propagation"; -import "../../../../src/components/buttons/ha-progress-button"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-card"; -import "../../../../src/components/ha-list-item"; -import "../../../../src/components/ha-select"; -import type { - HassioAddonDetails, - HassioAddonSetOptionParams, -} from "../../../../src/data/hassio/addon"; -import { setHassioAddonOption } from "../../../../src/data/hassio/addon"; -import type { HassioHardwareAudioDevice } from "../../../../src/data/hassio/hardware"; -import { fetchHassioHardwareAudio } from "../../../../src/data/hassio/hardware"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { haStyle } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart"; -import { hassioStyle } from "../../resources/hassio-style"; - -@customElement("hassio-addon-audio") -class HassioAddonAudio extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public addon!: HassioAddonDetails; - - @property({ type: Boolean }) public disabled = false; - - @state() private _error?: string; - - @state() private _inputDevices?: HassioHardwareAudioDevice[]; - - @state() private _outputDevices?: HassioHardwareAudioDevice[]; - - @state() private _selectedInput!: null | string; - - @state() private _selectedOutput!: null | string; - - protected render(): TemplateResult { - return html` - -
- ${this._error - ? html`${this._error}` - : nothing} - ${this._inputDevices && - html` - ${this._inputDevices.map( - (item) => html` - - ${item.name} - - ` - )} - `} - ${this._outputDevices && - html` - ${this._outputDevices.map( - (item) => html` - ${item.name} - ` - )} - `} -
-
- - ${this.supervisor.localize("common.save")} - -
-
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - :host, - ha-card { - display: block; - } - .card-actions { - text-align: right; - } - ha-select { - width: 100%; - } - ha-select:last-child { - margin-top: 8px; - } - `, - ]; - } - - protected willUpdate(changedProperties: PropertyValues): void { - super.willUpdate(changedProperties); - if (changedProperties.has("addon")) { - this._addonChanged(); - } - } - - private _setInputDevice(ev): void { - const device = ev.target.value; - this._selectedInput = device; - } - - private _setOutputDevice(ev): void { - const device = ev.target.value; - this._selectedOutput = device; - } - - private async _addonChanged(): Promise { - this._selectedInput = - this.addon.audio_input === null ? "default" : this.addon.audio_input; - this._selectedOutput = - this.addon.audio_output === null ? "default" : this.addon.audio_output; - if (this._outputDevices) { - return; - } - - const noDevice: HassioHardwareAudioDevice = { - device: "default", - name: this.supervisor.localize("app.configuration.audio.default"), - }; - - try { - const { audio } = await fetchHassioHardwareAudio(this.hass); - const input = Object.keys(audio.input).map((key) => ({ - device: key, - name: audio.input[key], - })); - const output = Object.keys(audio.output).map((key) => ({ - device: key, - name: audio.output[key], - })); - - this._inputDevices = [noDevice, ...input]; - this._outputDevices = [noDevice, ...output]; - } catch { - this._error = "Failed to fetch audio hardware"; - this._inputDevices = [noDevice]; - this._outputDevices = [noDevice]; - } - } - - private async _saveSettings(ev: CustomEvent): Promise { - if (this.disabled) { - return; - } - - const button = ev.currentTarget as any; - button.progress = true; - - this._error = undefined; - const data: HassioAddonSetOptionParams = { - audio_input: - this._selectedInput === "default" ? null : this._selectedInput, - audio_output: - this._selectedOutput === "default" ? null : this._selectedOutput, - }; - try { - await setHassioAddonOption(this.hass, this.addon.slug, data); - if (this.addon?.state === "started") { - await suggestAddonRestart(this, this.hass, this.supervisor, this.addon); - } - } catch { - this._error = "Failed to set addon audio device"; - } - - button.progress = false; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-audio": HassioAddonAudio; - } -} diff --git a/hassio/src/addon-view/config/hassio-addon-config-tab.ts b/hassio/src/addon-view/config/hassio-addon-config-tab.ts deleted file mode 100644 index 4d9c6fe6cf..0000000000 --- a/hassio/src/addon-view/config/hassio-addon-config-tab.ts +++ /dev/null @@ -1,113 +0,0 @@ -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property } from "lit/decorators"; -import "../../../../src/components/ha-spinner"; -import type { HassioAddonDetails } from "../../../../src/data/hassio/addon"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { haStyle } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import { hassioStyle } from "../../resources/hassio-style"; -import "../info/hassio-addon-system-managed"; -import "./hassio-addon-audio"; -import "./hassio-addon-config"; -import "./hassio-addon-network"; - -@customElement("hassio-addon-config-tab") -class HassioAddonConfigDashboard extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public addon?: HassioAddonDetails; - - @property({ type: Boolean }) public narrow = false; - - @property({ type: Boolean, attribute: "control-enabled" }) - public controlEnabled = false; - - protected render(): TemplateResult { - if (!this.addon) { - return html``; - } - const hasConfiguration = - (this.addon.options && Object.keys(this.addon.options).length) || - (this.addon.schema && Object.keys(this.addon.schema).length); - - return html` -
- ${this.addon.system_managed && - (hasConfiguration || this.addon.network || this.addon.audio) - ? html` - - ` - : nothing} - ${hasConfiguration || this.addon.network || this.addon.audio - ? html` - ${hasConfiguration - ? html` - - ` - : nothing} - ${this.addon.network - ? html` - - ` - : nothing} - ${this.addon.audio - ? html` - - ` - : nothing} - ` - : this.supervisor.localize("app.configuration.no_configuration")} -
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - .content { - margin: auto; - padding: 8px; - max-width: 1024px; - } - hassio-addon-network, - hassio-addon-audio, - hassio-addon-config { - margin-bottom: 24px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-config-tab": HassioAddonConfigDashboard; - } -} diff --git a/hassio/src/addon-view/config/hassio-addon-config.ts b/hassio/src/addon-view/config/hassio-addon-config.ts deleted file mode 100644 index 52ad922e50..0000000000 --- a/hassio/src/addon-view/config/hassio-addon-config.ts +++ /dev/null @@ -1,507 +0,0 @@ -import type { ActionDetail } from "@material/mwc-list"; -import { mdiDotsVertical } from "@mdi/js"; -import { DEFAULT_SCHEMA, Type } from "js-yaml"; -import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "../../../../src/components/buttons/ha-progress-button"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-button-menu"; -import "../../../../src/components/ha-card"; -import "../../../../src/components/ha-form/ha-form"; -import type { - HaFormSchema, - HaFormDataContainer, -} from "../../../../src/components/ha-form/types"; -import "../../../../src/components/ha-formfield"; -import "../../../../src/components/ha-icon-button"; -import "../../../../src/components/ha-list-item"; -import "../../../../src/components/ha-switch"; -import "../../../../src/components/ha-yaml-editor"; -import type { HaYamlEditor } from "../../../../src/components/ha-yaml-editor"; -import type { - HassioAddonDetails, - HassioAddonSetOptionParams, -} from "../../../../src/data/hassio/addon"; -import { - setHassioAddonOption, - validateHassioAddonOption, -} from "../../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { showConfirmationDialog } from "../../../../src/dialogs/generic/show-dialog-box"; -import { haStyle } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart"; -import { hassioStyle } from "../../resources/hassio-style"; -import type { ObjectSelector, Selector } from "../../../../src/data/selector"; - -const SUPPORTED_UI_TYPES = [ - "string", - "select", - "boolean", - "integer", - "float", - "schema", -]; - -const ADDON_YAML_SCHEMA = DEFAULT_SCHEMA.extend([ - new Type("!secret", { - kind: "scalar", - construct: (data) => `!secret ${data}`, - }), -]); - -const MASKED_FIELDS = ["password", "secret", "token"]; - -@customElement("hassio-addon-config") -class HassioAddonConfig extends LitElement { - @property({ attribute: false }) public addon!: HassioAddonDetails; - - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ type: Boolean }) public disabled = false; - - @state() private _configHasChanged = false; - - @state() private _valid = true; - - @state() private _canShowSchema = false; - - @state() private _showOptional = false; - - @state() private _error?: string; - - @state() private _options?: Record; - - @state() private _yamlMode = false; - - @query("ha-yaml-editor") private _editor?: HaYamlEditor; - - private _getTranslationEntry( - language: string, - entry: HaFormSchema, - options?: { path?: string[] } - ) { - let parent = this.addon.translations[language]?.configuration; - if (!parent) return undefined; - if (options?.path) { - for (const key of options.path) { - parent = parent[key]?.fields; - if (!parent) return undefined; - } - } - return parent[entry.name]; - } - - public computeLabel = ( - entry: HaFormSchema, - _data: HaFormDataContainer, - options?: { path?: string[] } - ): string => - this._getTranslationEntry(this.hass.language, entry, options)?.name || - this._getTranslationEntry("en", entry, options)?.name || - entry.name; - - public computeHelper = ( - entry: HaFormSchema, - options?: { path?: string[] } - ): string => - this._getTranslationEntry(this.hass.language, entry, options) - ?.description || - this._getTranslationEntry("en", entry, options)?.description || - ""; - - private _convertSchema = memoizeOne( - // Convert supervisor schema to selectors - (schema: readonly HaFormSchema[]): HaFormSchema[] => - this._convertSchemaElements(schema) - ); - - private _convertSchemaElements( - schema: readonly HaFormSchema[] - ): HaFormSchema[] { - return schema.map((entry) => this._convertSchemaElement(entry)); - } - - private _convertSchemaElement(entry: any): HaFormSchema { - if (entry.type === "schema" && !entry.multiple) { - return { - name: entry.name, - type: "expandable", - required: entry.required, - schema: this._convertSchemaElements(entry.schema), - }; - } - const selector = this._convertSchemaElementToSelector(entry, false); - if (selector) { - return { - name: entry.name, - required: entry.required, - selector, - }; - } - return entry; - } - - private _convertSchemaElementToSelector( - entry: any, - force: boolean - ): Selector | null { - if (entry.type === "select") { - return { select: { options: entry.options } }; - } - if (entry.type === "string") { - return entry.multiple - ? { select: { options: [], multiple: true, custom_value: true } } - : { - text: { - type: entry.format - ? entry.format - : MASKED_FIELDS.includes(entry.name) - ? "password" - : "text", - }, - }; - } - if (entry.type === "boolean") { - return { boolean: {} }; - } - if (entry.type === "schema") { - const fields: NonNullable["fields"] = {}; - for (const child_entry of entry.schema) { - fields[child_entry.name] = { - required: child_entry.required, - selector: this._convertSchemaElementToSelector(child_entry, true)!, - }; - } - return { - object: { - multiple: entry.multiple, - fields, - }, - }; - } - if (entry.type === "float" || entry.type === "integer") { - return { - number: { - mode: "box", - step: entry.type === "float" ? "any" : undefined, - }, - }; - } - if (force) { - return { object: {} }; - } - return null; - } - - private _filteredSchema = memoizeOne( - (options: Record, schema: HaFormSchema[]) => - schema.filter((entry) => entry.name in options || entry.required) - ); - - protected render(): TemplateResult { - const showForm = - !this._yamlMode && this._canShowSchema && this.addon.schema; - const hasHiddenOptions = - showForm && - JSON.stringify(this.addon.schema) !== - JSON.stringify( - this._filteredSchema(this.addon.options, this.addon.schema!) - ); - return html` -

${this.addon.name}

- -
-

- ${this.supervisor.localize("app.configuration.options.header")} -

-
- - - - ${this._yamlMode - ? this.supervisor.localize( - "app.configuration.options.edit_in_ui" - ) - : this.supervisor.localize( - "app.configuration.options.edit_in_yaml" - )} - - - ${this.supervisor.localize("common.reset_defaults")} - - -
-
- -
- ${showForm - ? html`` - : html``} - ${this._error - ? html`${this._error}` - : ""} - ${!this._yamlMode || - (this._canShowSchema && this.addon.schema) || - this._valid - ? "" - : html` - - ${this.supervisor.localize( - "app.configuration.options.invalid_yaml" - )} - - `} -
- ${hasHiddenOptions - ? html` - - - ` - : ""} -
- - ${this.supervisor.localize("common.save")} - -
-
- `; - } - - protected firstUpdated(changedProps) { - super.firstUpdated(changedProps); - this._canShowSchema = !this.addon.schema!.find( - (entry) => - // @ts-ignore - !SUPPORTED_UI_TYPES.includes(entry.type) - ); - this._yamlMode = !this._canShowSchema; - } - - protected updated(changedProperties: PropertyValues): void { - if (changedProperties.has("addon")) { - this._options = { ...this.addon.options }; - } - super.updated(changedProperties); - if ( - changedProperties.has("_yamlMode") || - changedProperties.has("_options") - ) { - if (this._yamlMode) { - const editor = this._editor; - if (editor) { - editor.setValue(this._options!); - } - } - } - } - - private _handleAction(ev: CustomEvent) { - switch (ev.detail.index) { - case 0: - this._yamlMode = !this._yamlMode; - break; - case 1: - this._resetTapped(ev); - break; - } - } - - private _toggleOptional() { - this._showOptional = !this._showOptional; - } - - private _configChanged(ev): void { - if (this.addon.schema && this._canShowSchema && !this._yamlMode) { - this._valid = true; - this._configHasChanged = true; - this._options = ev.detail.value; - } else { - this._configHasChanged = true; - this._valid = ev.detail.isValid; - } - } - - private async _resetTapped(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - const confirmed = await showConfirmationDialog(this, { - title: this.supervisor.localize("confirm.reset_options.title"), - text: this.supervisor.localize("confirm.reset_options.text"), - confirmText: this.supervisor.localize("common.reset_options"), - dismissText: this.supervisor.localize("common.cancel"), - destructive: true, - }); - - if (!confirmed) { - button.progress = false; - return; - } - - this._error = undefined; - const data: HassioAddonSetOptionParams = { - options: null, - }; - try { - await setHassioAddonOption(this.hass, this.addon.slug, data); - this._configHasChanged = false; - const eventdata = { - success: true, - response: undefined, - path: "options", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - this._error = this.supervisor.localize("app.failed_to_reset", { - error: extractApiErrorMessage(err), - }); - } - button.progress = false; - } - - private async _saveTapped(ev: CustomEvent): Promise { - if (this.disabled || !this._configHasChanged || !this._valid) { - return; - } - - const button = ev.currentTarget as any; - const options: Record = this._yamlMode - ? this._editor?.value - : this._options; - const eventdata = { - success: true, - response: undefined, - path: "options", - }; - button.progress = true; - - this._error = undefined; - - try { - const validation = await validateHassioAddonOption( - this.hass, - this.addon.slug, - options - ); - if (!validation.valid) { - throw Error(validation.message); - } - await setHassioAddonOption(this.hass, this.addon.slug, { - options, - }); - - this._configHasChanged = false; - if (this.addon?.state === "started") { - await suggestAddonRestart(this, this.hass, this.supervisor, this.addon); - } - } catch (err: any) { - this._error = this.supervisor.localize("app.failed_to_save", { - error: extractApiErrorMessage(err), - }); - eventdata.success = false; - } - button.progress = false; - fireEvent(this, "hass-api-called", eventdata); - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - :host { - display: block; - } - ha-card { - display: block; - } - .card-actions { - display: flex; - justify-content: space-between; - } - - .card-menu { - float: right; - z-index: 3; - --mdc-theme-text-primary-on-background: var(--primary-text-color); - } - ha-list-item[disabled] { - --mdc-theme-text-primary-on-background: var(--disabled-text-color); - } - .header { - display: flex; - justify-content: space-between; - } - .header h2 { - color: var(--ha-card-header-color, var(--primary-text-color)); - font-family: var(--ha-card-header-font-family, inherit); - font-size: var(--ha-card-header-font-size, var(--ha-font-size-2xl)); - letter-spacing: -0.012em; - line-height: var(--ha-line-height-expanded); - padding: 12px 16px 16px; - display: block; - margin-block: 0px; - font-weight: var(--ha-font-weight-normal); - } - .card-actions.right { - justify-content: flex-end; - } - - .show-additional { - padding: 16px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-config": HassioAddonConfig; - } -} diff --git a/hassio/src/addon-view/config/hassio-addon-network.ts b/hassio/src/addon-view/config/hassio-addon-network.ts deleted file mode 100644 index a3b9a1d996..0000000000 --- a/hassio/src/addon-view/config/hassio-addon-network.ts +++ /dev/null @@ -1,264 +0,0 @@ -import type { CSSResultGroup, PropertyValues } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "../../../../src/components/buttons/ha-progress-button"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-card"; -import "../../../../src/components/ha-formfield"; -import "../../../../src/components/ha-form/ha-form"; -import type { HaFormSchema } from "../../../../src/components/ha-form/types"; -import type { - HassioAddonDetails, - HassioAddonSetOptionParams, -} from "../../../../src/data/hassio/addon"; -import { setHassioAddonOption } from "../../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { haStyle } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart"; -import { hassioStyle } from "../../resources/hassio-style"; - -@customElement("hassio-addon-network") -class HassioAddonNetwork extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public addon!: HassioAddonDetails; - - @property({ type: Boolean }) public disabled = false; - - @state() private _showOptional = false; - - @state() private _configHasChanged = false; - - @state() private _error?: string; - - @state() private _config?: Record; - - public connectedCallback(): void { - super.connectedCallback(); - this._setNetworkConfig(); - } - - protected render() { - if (!this._config) { - return nothing; - } - - const hasHiddenOptions = Object.keys(this._config).find( - (entry) => this._config![entry] === null - ); - - return html` - -
-

- ${this.supervisor.localize( - "app.configuration.network.introduction" - )} -

- ${this._error - ? html`${this._error}` - : nothing} - - -
- ${hasHiddenOptions - ? html` - - - ` - : nothing} -
- - ${this.supervisor.localize("common.reset_defaults")} - - - ${this.supervisor.localize("common.save")} - -
-
- `; - } - - protected update(changedProperties: PropertyValues): void { - super.update(changedProperties); - if (changedProperties.has("addon")) { - this._setNetworkConfig(); - } - } - - private _createSchema = memoizeOne( - ( - config: Record, - showOptional: boolean, - advanced: boolean - ): HaFormSchema[] => - (showOptional - ? Object.keys(config) - : Object.keys(config).filter((entry) => config[entry] !== null) - ).map((entry) => ({ - name: entry, - selector: { - number: { - mode: "box", - min: 0, - max: 65535, - unit_of_measurement: advanced ? entry : undefined, - }, - }, - })) - ); - - private _computeLabel = (_: HaFormSchema): string => ""; - - private _computeHelper = (item: HaFormSchema): string => - this.addon.translations[this.hass.language]?.network?.[item.name] || - this.addon.translations.en?.network?.[item.name] || - this.addon.network_description?.[item.name] || - item.name; - - private _setNetworkConfig(): void { - this._config = this.addon.network || {}; - } - - private async _configChanged(ev: CustomEvent): Promise { - this._configHasChanged = true; - this._config = ev.detail.value; - } - - private async _resetTapped(ev: CustomEvent): Promise { - if (this.disabled) { - return; - } - - const button = ev.currentTarget as any; - const data: HassioAddonSetOptionParams = { - network: null, - }; - - try { - await setHassioAddonOption(this.hass, this.addon.slug, data); - this._configHasChanged = false; - const eventdata = { - success: true, - response: undefined, - path: "option", - }; - button.actionSuccess(); - fireEvent(this, "hass-api-called", eventdata); - if (this.addon?.state === "started") { - await suggestAddonRestart(this, this.hass, this.supervisor, this.addon); - } - } catch (err: any) { - this._error = this.supervisor.localize("app.failed_to_reset", { - error: extractApiErrorMessage(err), - }); - button.actionError(); - } - } - - private _toggleOptional() { - this._showOptional = !this._showOptional; - } - - private async _saveTapped(ev: CustomEvent): Promise { - if (!this._configHasChanged || this.disabled) { - return; - } - - const button = ev.currentTarget as any; - - this._error = undefined; - const networkconfiguration = {}; - Object.entries(this._config!).forEach(([key, value]) => { - networkconfiguration[key] = value ?? null; - }); - - const data: HassioAddonSetOptionParams = { - network: networkconfiguration, - }; - - try { - await setHassioAddonOption(this.hass, this.addon.slug, data); - this._configHasChanged = false; - const eventdata = { - success: true, - response: undefined, - path: "option", - }; - button.actionSuccess(); - fireEvent(this, "hass-api-called", eventdata); - if (this.addon?.state === "started") { - await suggestAddonRestart(this, this.hass, this.supervisor, this.addon); - } - } catch (err: any) { - this._error = this.supervisor.localize("app.failed_to_save", { - error: extractApiErrorMessage(err), - }); - button.actionError(); - } - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - :host { - display: block; - } - ha-card { - display: block; - } - .card-actions { - display: flex; - justify-content: space-between; - } - .show-optional { - padding: 16px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-network": HassioAddonNetwork; - } -} diff --git a/hassio/src/addon-view/documentation/hassio-addon-documentation-tab.ts b/hassio/src/addon-view/documentation/hassio-addon-documentation-tab.ts deleted file mode 100644 index 4f1aa8fc03..0000000000 --- a/hassio/src/addon-view/documentation/hassio-addon-documentation-tab.ts +++ /dev/null @@ -1,97 +0,0 @@ -import "../../../../src/components/ha-card"; -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-spinner"; -import "../../../../src/components/ha-markdown"; -import { customElement, property, state } from "lit/decorators"; -import type { HassioAddonDetails } from "../../../../src/data/hassio/addon"; -import { fetchHassioAddonDocumentation } from "../../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import "../../../../src/layouts/hass-loading-screen"; -import { haStyle } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import { hassioStyle } from "../../resources/hassio-style"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; - -@customElement("hassio-addon-documentation-tab") -class HassioAddonDocumentationDashboard extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public addon?: HassioAddonDetails; - - @state() private _error?: string; - - @state() private _content?: string; - - public async connectedCallback(): Promise { - super.connectedCallback(); - await this._loadData(); - } - - protected render(): TemplateResult { - if (!this.addon) { - return html``; - } - return html` -
- - ${this._error - ? html`${this._error}` - : ""} -
- ${this._content - ? html`` - : html``} -
-
-
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - ha-card { - display: block; - } - .content { - margin: auto; - padding: 8px; - max-width: 1024px; - } - ha-markdown { - padding: 16px; - } - `, - ]; - } - - private async _loadData(): Promise { - this._error = undefined; - try { - this._content = await fetchHassioAddonDocumentation( - this.hass, - this.addon!.slug - ); - } catch (err: any) { - this._error = this.supervisor.localize( - "app.documentation.get_documentation", - { error: extractApiErrorMessage(err) } - ); - } - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-documentation-tab": HassioAddonDocumentationDashboard; - } -} diff --git a/hassio/src/addon-view/hassio-addon-dashboard.ts b/hassio/src/addon-view/hassio-addon-dashboard.ts deleted file mode 100644 index f45a2a7c04..0000000000 --- a/hassio/src/addon-view/hassio-addon-dashboard.ts +++ /dev/null @@ -1,294 +0,0 @@ -import { - mdiCogs, - mdiFileDocument, - mdiInformationVariant, - mdiTextBoxOutline, -} from "@mdi/js"; -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { fireEvent } from "../../../src/common/dom/fire_event"; -import { navigate } from "../../../src/common/navigate"; -import { extractSearchParam } from "../../../src/common/url/search-params"; -import type { HassioAddonDetails } from "../../../src/data/hassio/addon"; -import { - fetchAddonInfo, - fetchHassioAddonInfo, - fetchHassioAddonsInfo, -} from "../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import type { StoreAddonDetails } from "../../../src/data/supervisor/store"; -import { - addStoreRepository, - fetchSupervisorStore, -} from "../../../src/data/supervisor/store"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { showConfirmationDialog } from "../../../src/dialogs/generic/show-dialog-box"; -import "../../../src/layouts/hass-error-screen"; -import "../../../src/layouts/hass-loading-screen"; -import "../../../src/layouts/hass-tabs-subpage"; -import type { PageNavigation } from "../../../src/layouts/hass-tabs-subpage"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant, Route } from "../../../src/types"; -import { hassioStyle } from "../resources/hassio-style"; -import "./config/hassio-addon-audio"; -import "./config/hassio-addon-config"; -import "./config/hassio-addon-network"; -import "./hassio-addon-router"; -import "./info/hassio-addon-info"; - -@customElement("hassio-addon-dashboard") -class HassioAddonDashboard extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public route!: Route; - - @property({ attribute: false }) public addon?: - | HassioAddonDetails - | StoreAddonDetails; - - @property({ type: Boolean }) public narrow = false; - - @state() - private _controlEnabled = false; - - @state() private _error?: string; - - private _backPath = new URLSearchParams(window.parent.location.search).get( - "store" - ) - ? "/hassio/store" - : "/hassio/dashboard"; - - private _computeTail = memoizeOne((route: Route) => { - const dividerPos = route.path.indexOf("/", 1); - return dividerPos === -1 - ? { - prefix: route.prefix + route.path, - path: "", - } - : { - prefix: route.prefix + route.path.substr(0, dividerPos), - path: route.path.substr(dividerPos), - }; - }); - - protected render(): TemplateResult { - if (this._error) { - return html``; - } - - if (!this.addon || !this.supervisor?.addon) { - return html``; - } - - const addonTabs: PageNavigation[] = [ - { - translationKey: "app.panel.info", - path: `/hassio/addon/${this.addon.slug}/info`, - iconPath: mdiInformationVariant, - }, - ]; - - if (this.addon.documentation) { - addonTabs.push({ - translationKey: "app.panel.documentation", - path: `/hassio/addon/${this.addon.slug}/documentation`, - iconPath: mdiFileDocument, - }); - } - - if (this.addon.version) { - addonTabs.push( - { - translationKey: "app.panel.configuration", - path: `/hassio/addon/${this.addon.slug}/config`, - iconPath: mdiCogs, - }, - { - translationKey: "app.panel.log", - path: `/hassio/addon/${this.addon.slug}/logs`, - iconPath: mdiTextBoxOutline, - } - ); - } - - const route = this._computeTail(this.route); - - return html` - - ${this.addon.name} - - - `; - } - - private _enableControl() { - this._controlEnabled = true; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - :host { - color: var(--primary-text-color); - } - .content { - padding: 24px 0 32px; - display: flex; - flex-direction: column; - align-items: center; - } - hassio-addon-info, - hassio-addon-network, - hassio-addon-audio, - hassio-addon-config { - margin-bottom: 24px; - width: 600px; - } - @media only screen and (max-width: 600px) { - hassio-addon-info, - hassio-addon-network, - hassio-addon-audio, - hassio-addon-config { - max-width: 100%; - min-width: 100%; - } - } - `, - ]; - } - - protected async firstUpdated(): Promise { - if (this.route.path === "") { - const requestedAddon = extractSearchParam("addon"); - const requestedAddonRepository = extractSearchParam("repository_url"); - if (requestedAddonRepository) { - const storeInfo = await fetchSupervisorStore(this.hass); - if ( - !storeInfo.repositories.find( - (repo) => repo.source === requestedAddonRepository - ) - ) { - if ( - !(await showConfirmationDialog(this, { - title: this.supervisor.localize("my.add_app_repository_title"), - text: this.supervisor.localize( - "my.add_app_repository_description", - { app: requestedAddon, repository: requestedAddonRepository } - ), - confirmText: this.supervisor.localize("common.add"), - dismissText: this.supervisor.localize("common.cancel"), - })) - ) { - this._error = this.supervisor.localize( - "my.error_repository_not_found" - ); - return; - } - - try { - await addStoreRepository(this.hass, requestedAddonRepository); - } catch (err: any) { - this._error = extractApiErrorMessage(err); - } - } - } - - if (requestedAddon) { - const store = await fetchSupervisorStore(this.hass); - const validAddon = store.addons.some( - (addon) => addon.slug === requestedAddon - ); - if (!validAddon) { - this._error = this.supervisor.localize("my.error_app_not_found"); - } else { - navigate(`/hassio/addon/${requestedAddon}`, { replace: true }); - } - } - } - this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev)); - } - - private async _apiCalled(ev): Promise { - if (!ev.detail.success) { - return; - } - - const pathSplit: string[] = ev.detail.path?.split("/"); - - if (!pathSplit || pathSplit.length === 0) { - return; - } - - const path: string = pathSplit[pathSplit.length - 1]; - - if (["uninstall", "install", "update", "start", "stop"].includes(path)) { - fireEvent(this, "supervisor-collection-refresh", { - collection: "addon", - }); - } - - if (path === "uninstall") { - if (this.isConnected) { - navigate(this._backPath); - } - } else if (path === "install") { - this.addon = await fetchHassioAddonInfo(this.hass, this.addon!.slug); - } else { - await this._routeDataChanged(); - } - } - - protected updated(changedProperties) { - if (changedProperties.has("route") && !this.addon) { - this._routeDataChanged(); - } - } - - private async _routeDataChanged(): Promise { - const addon = this.route.path.split("/")[1]; - if (!addon) { - return; - } - try { - if (!this.supervisor.addon) { - const addonsInfo = await fetchHassioAddonsInfo(this.hass); - fireEvent(this, "supervisor-update", { addon: addonsInfo }); - } - this.addon = await fetchAddonInfo(this.hass, this.supervisor, addon); - } catch (err: any) { - this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`; - this.addon = undefined; - } - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-dashboard": HassioAddonDashboard; - } -} diff --git a/hassio/src/addon-view/hassio-addon-router.ts b/hassio/src/addon-view/hassio-addon-router.ts deleted file mode 100644 index 1213ff9c12..0000000000 --- a/hassio/src/addon-view/hassio-addon-router.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { customElement, property } from "lit/decorators"; -import type { HassioAddonDetails } from "../../../src/data/hassio/addon"; -import type { StoreAddonDetails } from "../../../src/data/supervisor/store"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import type { RouterOptions } from "../../../src/layouts/hass-router-page"; -import { HassRouterPage } from "../../../src/layouts/hass-router-page"; -import type { HomeAssistant } from "../../../src/types"; -import "./config/hassio-addon-config-tab"; -import "./documentation/hassio-addon-documentation-tab"; -// Don't codesplit the others, because it breaks the UI when pushed to a Pi -import "./info/hassio-addon-info-tab"; -import "./log/hassio-addon-log-tab"; - -@customElement("hassio-addon-router") -class HassioAddonRouter extends HassRouterPage { - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public addon!: - | HassioAddonDetails - | StoreAddonDetails; - - @property({ type: Boolean, attribute: "control-enabled" }) - public controlEnabled = false; - - protected routerOptions: RouterOptions = { - defaultPage: "info", - showLoading: true, - routes: { - info: { - tag: "hassio-addon-info-tab", - }, - documentation: { - tag: "hassio-addon-documentation-tab", - }, - config: { - tag: "hassio-addon-config-tab", - }, - logs: { - tag: "hassio-addon-log-tab", - }, - }, - }; - - protected updatePageEl(el) { - el.route = this.routeTail; - el.hass = this.hass; - el.supervisor = this.supervisor; - el.addon = this.addon; - el.narrow = this.narrow; - el.controlEnabled = this.controlEnabled; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-router": HassioAddonRouter; - } -} diff --git a/hassio/src/addon-view/info/hassio-addon-info-tab.ts b/hassio/src/addon-view/info/hassio-addon-info-tab.ts deleted file mode 100644 index 719efb8c75..0000000000 --- a/hassio/src/addon-view/info/hassio-addon-info-tab.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import "../../../../src/components/ha-spinner"; -import type { HassioAddonDetails } from "../../../../src/data/hassio/addon"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { haStyle } from "../../../../src/resources/styles"; -import type { HomeAssistant, Route } from "../../../../src/types"; -import { hassioStyle } from "../../resources/hassio-style"; -import "./hassio-addon-info"; - -@customElement("hassio-addon-info-tab") -class HassioAddonInfoDashboard extends LitElement { - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public route!: Route; - - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public addon?: HassioAddonDetails; - - @property({ type: Boolean, attribute: "control-enabled" }) - public controlEnabled = false; - - protected render(): TemplateResult { - if (!this.addon) { - return html``; - } - - return html` -
- -
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - .content { - margin: auto; - padding: 8px; - max-width: 1024px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-info-tab": HassioAddonInfoDashboard; - } -} diff --git a/hassio/src/addon-view/info/hassio-addon-info.ts b/hassio/src/addon-view/info/hassio-addon-info.ts deleted file mode 100644 index 44aca5c329..0000000000 --- a/hassio/src/addon-view/info/hassio-addon-info.ts +++ /dev/null @@ -1,1443 +0,0 @@ -import { - mdiCheckCircle, - mdiChip, - mdiCircleOffOutline, - mdiCursorDefaultClickOutline, - mdiDocker, - mdiExclamationThick, - mdiFlask, - mdiKey, - mdiLinkLock, - mdiNetwork, - mdiNumeric1, - mdiNumeric2, - mdiNumeric3, - mdiNumeric4, - mdiNumeric5, - mdiNumeric6, - mdiNumeric7, - mdiNumeric8, - mdiPlayCircle, - mdiPound, - mdiShield, -} from "@mdi/js"; -import type { CSSResultGroup, TemplateResult } from "lit"; -import { LitElement, css, html, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { classMap } from "lit/directives/class-map"; -import { ifDefined } from "lit/directives/if-defined"; -import memoizeOne from "memoize-one"; -import { atLeastVersion } from "../../../../src/common/config/version"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import { navigate } from "../../../../src/common/navigate"; -import { capitalizeFirstLetter } from "../../../../src/common/string/capitalize-first-letter"; -import "../../../../src/components/buttons/ha-progress-button"; -import "../../../../src/components/chips/ha-assist-chip"; -import "../../../../src/components/chips/ha-chip-set"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-button"; -import "../../../../src/components/ha-card"; -import "../../../../src/components/ha-formfield"; -import "../../../../src/components/ha-markdown"; -import "../../../../src/components/ha-settings-row"; -import "../../../../src/components/ha-svg-icon"; -import "../../../../src/components/ha-switch"; -import type { HaSwitch } from "../../../../src/components/ha-switch"; -import type { - AddonCapability, - HassioAddonDetails, - HassioAddonSetOptionParams, - HassioAddonSetSecurityParams, -} from "../../../../src/data/hassio/addon"; -import { - fetchHassioAddonChangelog, - fetchHassioAddonInfo, - installHassioAddon, - rebuildLocalAddon, - restartHassioAddon, - setHassioAddonOption, - setHassioAddonSecurity, - startHassioAddon, - stopHassioAddon, - uninstallHassioAddon, - validateHassioAddonOption, -} from "../../../../src/data/hassio/addon"; -import type { HassioStats } from "../../../../src/data/hassio/common"; -import { - extractApiErrorMessage, - fetchHassioStats, -} from "../../../../src/data/hassio/common"; -import type { - StoreAddon, - StoreAddonDetails, -} from "../../../../src/data/supervisor/store"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { - showAlertDialog, - showConfirmationDialog, -} from "../../../../src/dialogs/generic/show-dialog-box"; -import { mdiHomeAssistant } from "../../../../src/resources/home-assistant-logo-svg"; -import { haStyle } from "../../../../src/resources/styles"; -import type { HomeAssistant, Route } from "../../../../src/types"; -import { bytesToString } from "../../../../src/util/bytes-to-string"; -import "../../components/hassio-card-content"; -import "../../components/supervisor-metric"; -import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown"; -import { showSystemManagedDialog } from "../../dialogs/system-managed/show-dialog-system-managed"; -import { hassioStyle } from "../../resources/hassio-style"; -import "../../update-available/update-available-card"; -import { addonArchIsSupported, extractChangelog } from "../../util/addon"; -import "./hassio-addon-system-managed"; - -const STAGE_ICON = { - stable: mdiCheckCircle, - experimental: mdiFlask, - deprecated: mdiExclamationThick, -}; - -const RATING_ICON = { - 1: mdiNumeric1, - 2: mdiNumeric2, - 3: mdiNumeric3, - 4: mdiNumeric4, - 5: mdiNumeric5, - 6: mdiNumeric6, - 7: mdiNumeric7, - 8: mdiNumeric8, -}; - -@customElement("hassio-addon-info") -class HassioAddonInfo extends LitElement { - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public route!: Route; - - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public addon!: - | HassioAddonDetails - | StoreAddonDetails; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ type: Boolean, attribute: "control-enabled" }) - public controlEnabled = false; - - @state() private _metrics?: HassioStats; - - @state() private _error?: string; - - private _fetchDataTimeout?: number; - - private _addonStoreInfo = memoizeOne( - (slug: string, storeAddons: StoreAddon[]) => - storeAddons.find((addon) => addon.slug === slug) - ); - - public disconnectedCallback() { - super.disconnectedCallback(); - - if (this._fetchDataTimeout) { - clearInterval(this._fetchDataTimeout); - this._fetchDataTimeout = undefined; - } - } - - protected render(): TemplateResult { - const addonStoreInfo = - !this.addon.detached && !this.addon.available - ? this._addonStoreInfo(this.addon.slug, this.supervisor.store.addons) - : undefined; - const metrics = [ - { - description: this.supervisor.localize("app.dashboard.cpu_usage"), - value: this._metrics?.cpu_percent, - }, - { - description: this.supervisor.localize("app.dashboard.ram_usage"), - value: this._metrics?.memory_percent, - tooltip: `${bytesToString(this._metrics?.memory_usage)}/${bytesToString( - this._metrics?.memory_limit - )}`, - }, - ]; - - const systemManaged = this._isSystemManaged(this.addon); - - return html` - ${this.addon.update_available - ? html` - - ` - : nothing} - ${"protected" in this.addon && !this.addon.protected - ? html` - - ${this.supervisor.localize( - "app.dashboard.protection_mode.content" - )} - - ${this.supervisor.localize( - "app.dashboard.protection_mode.enable" - )} - - - ` - : nothing} - ${systemManaged - ? html` - - ` - : nothing} - - -
-
- ${!this.narrow ? this.addon.name : nothing} -
- ${this.addon.version - ? html` - ${this._computeIsRunning - ? html` - - ` - : html` - - `} - ` - : html` ${this.addon.version_latest} `} -
-
-
- ${this.addon.version - ? html` - ${this.supervisor.localize("app.dashboard.current_version", { - version: this.addon.version, - })} -
- (${this.supervisor.localize( - "app.dashboard.changelog" - )}) -
- ` - : html`${this.supervisor.localize("app.dashboard.changelog")}`} -
- - - ${this.addon.stage !== "stable" - ? html` - - - - - ` - : nothing} - - = 6, - yellow: [3, 4, 5].includes(Number(this.addon.rating)), - red: Number(this.addon.rating) >= 2, - })} - @click=${this._showMoreInfo} - id="rating" - .label=${capitalizeFirstLetter( - this.supervisor.localize( - "app.dashboard.capability.label.rating" - ) - )} - > - - - - ${this.addon.host_network - ? html` - - - - ` - : nothing} - ${this.addon.full_access - ? html` - - - - ` - : nothing} - ${this.addon.homeassistant_api - ? html` - - - - ` - : nothing} - ${this._computeHassioApi - ? html` - - - - ` - : nothing} - ${this.addon.docker_api - ? html` - - - - ` - : nothing} - ${this.addon.host_pid - ? html` - - - - ` - : nothing} - ${this.addon.apparmor !== "default" - ? html` - - - - ` - : nothing} - ${this.addon.auth_api - ? html` - - - - ` - : nothing} - ${this.addon.ingress - ? html` - - - - ` - : nothing} - ${this.addon.signed - ? html` - - - - ` - : nothing} - ${systemManaged - ? html` - - - - ` - : nothing} - - -
- ${this.addon.description}.
- ${this.supervisor.localize("app.dashboard.visit_app_page", { - name: html`${this.addon.name}`, - })} -
-
-
- ${this.addon.logo - ? html` - - ` - : nothing} - ${this.addon.version - ? html` -
- - - ${this.supervisor.localize( - "app.dashboard.option.boot.title" - )} - - - ${this.supervisor.localize( - "app.dashboard.option.boot.description" - )} - - - - - ${this.addon.startup !== "once" - ? html` - - - ${this.supervisor.localize( - "app.dashboard.option.watchdog.title" - )} - - - ${this.supervisor.localize( - "app.dashboard.option.watchdog.description" - )} - - - - ` - : nothing} - ${this.addon.auto_update || - this.hass.userData?.showAdvanced - ? html` - - - ${this.supervisor.localize( - "app.dashboard.option.auto_update.title" - )} - - - ${this.supervisor.localize( - "app.dashboard.option.auto_update.description" - )} - - - - ` - : nothing} - ${!this._computeCannotIngressSidebar && this.addon.ingress - ? html` - - - ${this.supervisor.localize( - "app.dashboard.option.ingress_panel.title" - )} - - - ${this.supervisor.localize( - "app.dashboard.option.ingress_panel.description" - )} - - - - ` - : nothing} - ${this._computeUsesProtectedOptions - ? html` - - - ${this.supervisor.localize( - "app.dashboard.option.protected.title" - )} - - - ${this.supervisor.localize( - "app.dashboard.option.protected.description" - )} - - - - ` - : nothing} -
- ` - : nothing} -
-
- ${this.addon.version && this.addon.state === "started" - ? html` - - ${this.supervisor.localize("app.dashboard.hostname")} - - ${this.addon.hostname} - - ${metrics.map( - (metric) => html` - - ` - )}` - : nothing} -
-
- ${this._error - ? html`${this._error}` - : nothing} - ${!this.addon.version && addonStoreInfo && !this.addon.available - ? !addonArchIsSupported( - this.supervisor.info.supported_arch, - this.addon.arch - ) - ? html` - - ${this.supervisor.localize( - "app.dashboard.not_available_arch" - )} - - ` - : html` - - ${this.supervisor.localize( - "app.dashboard.not_available_version", - { - core_version_installed: this.supervisor.core.version, - core_version_needed: addonStoreInfo!.homeassistant, - } - )} - - ` - : nothing} -
-
-
- ${this.addon.version - ? this._computeIsRunning - ? html` - - ${this.supervisor.localize("app.dashboard.stop")} - - - ${this.supervisor.localize("app.dashboard.restart")} - - ` - : html` - - ${this.supervisor.localize("app.dashboard.start")} - - ` - : nothing} -
-
- ${this.addon.version - ? html` - - ${this.supervisor.localize("app.dashboard.uninstall")} - - ${this.addon.build - ? html` - - ${this.supervisor.localize("app.dashboard.rebuild")} - - ` - : nothing} - ${this._computeShowWebUI || this._computeShowIngressUI - ? html` - - ${this.supervisor.localize( - "app.dashboard.open_web_ui" - )} - - ` - : nothing} - ` - : html` - - ${this.supervisor.localize("app.dashboard.install")} - - `} -
-
-
- - ${this.addon.long_description - ? html` - -
- -
-
- ` - : nothing} - `; - } - - protected updated(changedProps) { - super.updated(changedProps); - if (changedProps.has("addon")) { - this._loadData(); - if ( - !this._fetchDataTimeout && - this.addon && - "state" in this.addon && - this.addon.state === "startup" - ) { - // App is starting up, wait for it to start - this._scheduleDataUpdate(); - } - } - } - - private _scheduleDataUpdate() { - this._fetchDataTimeout = window.setTimeout(async () => { - const addon = await fetchHassioAddonInfo(this.hass, this.addon.slug); - if (addon.state !== "startup") { - this._fetchDataTimeout = undefined; - this.addon = addon; - const eventdata = { - success: true, - response: undefined, - path: "start", - }; - fireEvent(this, "hass-api-called", eventdata); - } else { - this._scheduleDataUpdate(); - } - }, 500); - } - - private async _loadData(): Promise { - if ("state" in this.addon && this.addon.state === "started") { - this._metrics = await fetchHassioStats( - this.hass, - `addons/${this.addon.slug}` - ); - } - } - - private get _computeHassioApi(): boolean { - return ( - this.addon.hassio_api && - (this.addon.hassio_role === "manager" || - this.addon.hassio_role === "admin") - ); - } - - private get _computeApparmorClassName(): string { - if (this.addon.apparmor === "profile") { - return "green"; - } - if (this.addon.apparmor === "disable") { - return "red"; - } - return ""; - } - - private _showMoreInfo(ev): void { - const id = ev.currentTarget.id as AddonCapability; - showHassioMarkdownDialog(this, { - title: this.supervisor.localize(`app.dashboard.capability.${id}.title`), - content: - id === "stage" - ? this.supervisor.localize( - `app.dashboard.capability.${id}.description`, - { - icon_stable: ``, - icon_experimental: ``, - icon_deprecated: ``, - } - ) - : this.supervisor.localize( - `app.dashboard.capability.${id}.description` - ), - }); - } - - private _showSystemManagedDialog() { - showSystemManagedDialog(this, { - addon: this.addon as HassioAddonDetails, - supervisor: this.supervisor, - }); - } - - private get _computeIsRunning(): boolean { - return (this.addon as HassioAddonDetails)?.state === "started"; - } - - private get _pathWebui(): string | null { - return (this.addon as HassioAddonDetails).webui!.replace( - "[HOST]", - document.location.hostname - ); - } - - private get _computeShowWebUI(): boolean | "" | null { - return ( - !this.addon.ingress && - (this.addon as HassioAddonDetails).webui && - this._computeIsRunning - ); - } - - private _openIngress(): void { - navigate(`/hassio/ingress/${this.addon.slug}`); - } - - private get _computeShowIngressUI(): boolean { - return this.addon.ingress && this._computeIsRunning; - } - - private get _computeCannotIngressSidebar(): boolean { - return ( - !this.addon.ingress || !atLeastVersion(this.hass.config.version, 0, 92) - ); - } - - private get _computeUsesProtectedOptions(): boolean { - return ( - this.addon.docker_api || this.addon.full_access || this.addon.host_pid - ); - } - - private async _startOnBootToggled(): Promise { - this._error = undefined; - const data: HassioAddonSetOptionParams = { - boot: - (this.addon as HassioAddonDetails).boot === "auto" ? "manual" : "auto", - }; - try { - await setHassioAddonOption(this.hass, this.addon.slug, data); - const eventdata = { - success: true, - response: undefined, - path: "option", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - this._error = this.supervisor.localize("app.failed_to_save", { - error: extractApiErrorMessage(err), - }); - } - } - - private async _watchdogToggled(): Promise { - this._error = undefined; - const data: HassioAddonSetOptionParams = { - watchdog: !(this.addon as HassioAddonDetails).watchdog, - }; - try { - await setHassioAddonOption(this.hass, this.addon.slug, data); - const eventdata = { - success: true, - response: undefined, - path: "option", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - this._error = this.supervisor.localize("app.failed_to_save", { - error: extractApiErrorMessage(err), - }); - } - } - - private async _autoUpdateToggled(): Promise { - this._error = undefined; - const data: HassioAddonSetOptionParams = { - auto_update: !(this.addon as HassioAddonDetails).auto_update, - }; - try { - await setHassioAddonOption(this.hass, this.addon.slug, data); - const eventdata = { - success: true, - response: undefined, - path: "option", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - this._error = this.supervisor.localize("app.failed_to_save", { - error: extractApiErrorMessage(err), - }); - } - } - - private async _protectionToggled(): Promise { - this._error = undefined; - const data: HassioAddonSetSecurityParams = { - protected: !(this.addon as HassioAddonDetails).protected, - }; - try { - await setHassioAddonSecurity(this.hass, this.addon.slug, data); - const eventdata = { - success: true, - response: undefined, - path: "security", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - this._error = this.supervisor.localize("app.failed_to_save", { - error: extractApiErrorMessage(err), - }); - } - } - - private async _panelToggled(): Promise { - this._error = undefined; - const data: HassioAddonSetOptionParams = { - ingress_panel: !(this.addon as HassioAddonDetails).ingress_panel, - }; - try { - await setHassioAddonOption(this.hass, this.addon.slug, data); - const eventdata = { - success: true, - response: undefined, - path: "option", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - this._error = this.supervisor.localize("app.failed_to_save", { - error: extractApiErrorMessage(err), - }); - } - } - - private async _openChangelog(): Promise { - try { - const content = await fetchHassioAddonChangelog( - this.hass, - this.addon.slug - ); - - showHassioMarkdownDialog(this, { - title: this.supervisor.localize("app.dashboard.changelog"), - content: extractChangelog(this.addon as HassioAddonDetails, content), - }); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize( - "app.dashboard.action_error.get_changelog" - ), - text: extractApiErrorMessage(err), - }); - } - } - - private _updateComplete() { - const eventdata = { - success: true, - response: undefined, - path: "install", - }; - fireEvent(this, "hass-api-called", eventdata); - } - - private async _installClicked(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - try { - await installHassioAddon(this.hass, this.addon.slug); - const eventdata = { - success: true, - response: undefined, - path: "install", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("app.dashboard.action_error.install"), - text: extractApiErrorMessage(err), - }); - } - button.progress = false; - } - - private async _stopClicked(ev: CustomEvent): Promise { - if (this._isSystemManaged(this.addon) && !this.controlEnabled) { - return; - } - - const button = ev.currentTarget as any; - button.progress = true; - - try { - await stopHassioAddon(this.hass, this.addon.slug); - const eventdata = { - success: true, - response: undefined, - path: "stop", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("app.dashboard.action_error.stop"), - text: extractApiErrorMessage(err), - }); - } - button.progress = false; - } - - private async _restartClicked(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - try { - await restartHassioAddon(this.hass, this.addon.slug); - const eventdata = { - success: true, - response: undefined, - path: "stop", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("app.dashboard.action_error.restart"), - text: extractApiErrorMessage(err), - }); - } - button.progress = false; - } - - private async _rebuildClicked(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - try { - await rebuildLocalAddon(this.hass, this.addon.slug); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("app.dashboard.action_error.rebuild"), - text: extractApiErrorMessage(err), - }); - } - button.progress = false; - } - - private async _startClicked(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - try { - const validate = await validateHassioAddonOption( - this.hass, - this.addon.slug - ); - if (!validate.valid) { - await showConfirmationDialog(this, { - title: this.supervisor.localize( - "app.dashboard.action_error.start_invalid_config" - ), - text: validate.message.split(" Got ")[0], - confirm: () => this._openConfiguration(), - confirmText: this.supervisor.localize( - "app.dashboard.action_error.go_to_config" - ), - dismissText: this.supervisor.localize("common.cancel"), - }); - button.actionError(); - button.progress = false; - return; - } - } catch (err: any) { - button.actionError(); - button.progress = false; - showAlertDialog(this, { - title: "Failed to validate app configuration", - text: extractApiErrorMessage(err), - }); - return; - } - - try { - await startHassioAddon(this.hass, this.addon.slug); - this.addon = await fetchHassioAddonInfo(this.hass, this.addon.slug); - const eventdata = { - success: true, - response: undefined, - path: "start", - }; - fireEvent(this, "hass-api-called", eventdata); - } catch (err: any) { - button.actionError(); - button.progress = false; - showAlertDialog(this, { - title: this.supervisor.localize("app.dashboard.action_error.start"), - text: extractApiErrorMessage(err), - }); - return; - } - button.actionSuccess(); - button.progress = false; - } - - private _openConfiguration(): void { - navigate(`/hassio/addon/${this.addon.slug}/config`); - } - - private async _uninstallClicked(ev: CustomEvent): Promise { - if (this._isSystemManaged(this.addon) && !this.controlEnabled) { - return; - } - - const button = ev.currentTarget as any; - button.progress = true; - let removeData = false; - const _removeDataToggled = (e: Event) => { - removeData = (e.target as HaSwitch).checked; - }; - - const confirmed = await showConfirmationDialog(this, { - title: this.supervisor.localize("dialog.uninstall_app.title", { - name: this.addon.name, - }), - text: html` - - ${this.supervisor.localize("dialog.uninstall_app.remove_data")} -

`} - > - -
- `, - confirmText: this.supervisor.localize("dialog.uninstall_app.uninstall"), - dismissText: this.supervisor.localize("common.cancel"), - destructive: true, - }); - - if (!confirmed) { - button.progress = false; - return; - } - - this._error = undefined; - try { - await uninstallHassioAddon(this.hass, this.addon.slug, removeData); - const eventdata = { - success: true, - response: undefined, - path: "uninstall", - }; - fireEvent(this, "hass-api-called", eventdata); - button.actionSuccess(); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("app.dashboard.action_error.uninstall"), - text: extractApiErrorMessage(err), - }); - button.actionError(); - } - button.progress = false; - } - - private _isSystemManaged = memoizeOne( - (addon: HassioAddonDetails | StoreAddonDetails) => - "system_managed" in addon && addon.system_managed - ); - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - :host { - display: block; - } - ha-card { - display: block; - margin-bottom: 16px; - } - ha-card.warning { - background-color: var(--error-color); - color: white; - } - ha-card.warning .card-header { - color: white; - } - ha-card.warning .card-content { - color: white; - } - ha-card.warning ha-button { - --mdc-theme-primary: white !important; - } - .warning { - color: var(--error-color); - --mdc-theme-primary: var(--error-color); - } - .light-color { - color: var(--secondary-text-color); - } - .addon-header { - padding-left: 8px; - padding-inline-start: 8px; - padding-inline-end: initial; - font-size: var(--ha-font-size-2xl); - color: var(--ha-card-header-color, var(--primary-text-color)); - } - .addon-version { - float: var(--float-end); - font-size: var(--ha-font-size-l); - vertical-align: middle; - } - .errors { - color: var(--error-color); - margin-bottom: 16px; - } - .description { - margin-bottom: 16px; - } - img.logo { - max-width: 100%; - max-height: 60px; - margin: 16px 0; - display: block; - } - - ha-switch { - display: flex; - } - ha-svg-icon.running { - color: var(--success-color); - } - ha-svg-icon.stopped { - color: var(--error-color); - } - protection-enable ha-button { - --mdc-theme-primary: white; - } - .description a { - color: var(--primary-color); - } - .long-description { - direction: ltr; - } - ha-assist-chip { - --md-sys-color-primary: var(--text-primary-color); - --md-sys-color-on-surface: var(--text-primary-color); - --ha-assist-chip-filled-container-color: var(--primary-color); - } - - .red { - --ha-assist-chip-filled-container-color: var( - --label-badge-red, - #df4c1e - ); - } - .blue { - --ha-assist-chip-filled-container-color: var( - --label-badge-blue, - #039be5 - ); - } - .green { - --ha-assist-chip-filled-container-color: var( - --label-badge-green, - #0da035 - ); - } - .yellow { - --ha-assist-chip-filled-container-color: var( - --label-badge-yellow, - #f4b400 - ); - } - .capabilities { - margin-bottom: 16px; - } - .card-actions { - justify-content: space-between; - display: flex; - direction: var(--direction); - } - .changelog { - display: contents; - } - .changelog-link { - color: var(--primary-color); - text-decoration: underline; - cursor: pointer; - } - ha-markdown { - padding: 16px; - } - ha-settings-row { - padding: 0; - height: 54px; - width: 100%; - } - ha-settings-row > span[slot="description"] { - white-space: normal; - color: var(--secondary-text-color); - } - ha-settings-row[three-line] { - height: 74px; - } - - .addon-options { - max-width: 90%; - } - - .addon-container { - display: grid; - grid-auto-flow: column; - grid-template-columns: 60% 40%; - } - - .addon-container > div:last-of-type { - align-self: end; - } - - ha-alert ha-button { - --mdc-theme-primary: var(--primary-text-color); - } - - :host > ha-alert { - display: block; - margin-bottom: 16px; - } - - a { - text-decoration: none; - } - - update-available-card { - padding-bottom: 16px; - } - - @media (max-width: 720px) { - .addon-options { - max-width: 100%; - } - .addon-container { - display: block; - } - } - `, - ]; - } -} -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-info": HassioAddonInfo; - } -} diff --git a/hassio/src/addon-view/info/hassio-addon-system-managed.ts b/hassio/src/addon-view/info/hassio-addon-system-managed.ts deleted file mode 100644 index e2cace3c2c..0000000000 --- a/hassio/src/addon-view/info/hassio-addon-system-managed.ts +++ /dev/null @@ -1,59 +0,0 @@ -import type { TemplateResult } from "lit"; -import { LitElement, css, html, nothing } from "lit"; -import { customElement, property } from "lit/decorators"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-button"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; - -@customElement("hassio-addon-system-managed") -class HassioAddonSystemManaged extends LitElement { - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ type: Boolean, attribute: "hide-button" }) public hideButton = - false; - - protected render(): TemplateResult { - return html` - - ${this.supervisor.localize("app.system_managed.description")} - ${!this.hideButton - ? html` - - ${this.supervisor.localize("app.system_managed.take_control")} - - ` - : nothing} - - `; - } - - private _takeControl() { - fireEvent(this, "system-managed-take-control"); - } - - static styles = css` - ha-alert { - display: block; - margin-bottom: 16px; - } - ha-button { - white-space: nowrap; - } - `; -} -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-system-managed": HassioAddonSystemManaged; - } - - interface HASSDomEvents { - "system-managed-take-control": undefined; - } -} diff --git a/hassio/src/addon-view/log/hassio-addon-log-tab.ts b/hassio/src/addon-view/log/hassio-addon-log-tab.ts deleted file mode 100644 index 2a2e05da05..0000000000 --- a/hassio/src/addon-view/log/hassio-addon-log-tab.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { - css, - type CSSResultGroup, - html, - LitElement, - type TemplateResult, -} from "lit"; -import { customElement, property, state } from "lit/decorators"; -import "../../../../src/components/ha-spinner"; -import type { HassioAddonDetails } from "../../../../src/data/hassio/addon"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { haStyle } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import { hassioStyle } from "../../resources/hassio-style"; -import "../../../../src/panels/config/logs/error-log-card"; -import "../../../../src/components/search-input"; -import { extractSearchParam } from "../../../../src/common/url/search-params"; - -@customElement("hassio-addon-log-tab") -class HassioAddonLogDashboard extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public addon?: HassioAddonDetails; - - @state() private _filter = extractSearchParam("filter") || ""; - - protected render(): TemplateResult { - if (!this.addon) { - return html` `; - } - return html` - -
- - -
- `; - } - - private async _filterChanged(ev) { - this._filter = ev.detail.value; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - .content { - margin: auto; - padding: 8px; - } - .search { - position: sticky; - top: 0; - z-index: 2; - } - search-input { - display: block; - --mdc-text-field-fill-color: var(--sidebar-background-color); - --mdc-text-field-idle-line-color: var(--divider-color); - } - @media all and (max-width: 870px) { - :host { - --error-log-card-height: calc(100vh - 304px); - } - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addon-log-tab": HassioAddonLogDashboard; - } -} diff --git a/hassio/src/backups/hassio-backups.ts b/hassio/src/backups/hassio-backups.ts deleted file mode 100644 index cd73cd3790..0000000000 --- a/hassio/src/backups/hassio-backups.ts +++ /dev/null @@ -1,425 +0,0 @@ -import type { ActionDetail } from "@material/mwc-list"; - -import { mdiBackupRestore, mdiDelete, mdiDotsVertical, mdiPlus } from "@mdi/js"; -import type { CSSResultGroup, PropertyValues } from "lit"; -import { LitElement, css, html, nothing } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; -import { classMap } from "lit/directives/class-map"; -import memoizeOne from "memoize-one"; -import { atLeastVersion } from "../../../src/common/config/version"; -import { relativeTime } from "../../../src/common/datetime/relative_time"; -import type { HASSDomEvent } from "../../../src/common/dom/fire_event"; -import type { - DataTableColumnContainer, - RowClickedEvent, - SelectionChangedEvent, -} from "../../../src/components/data-table/ha-data-table"; -import "../../../src/components/ha-button-menu"; -import "../../../src/components/ha-fab"; -import "../../../src/components/ha-button"; -import "../../../src/components/ha-icon-button"; -import "../../../src/components/ha-list-item"; -import "../../../src/components/ha-svg-icon"; -import type { HassioBackup } from "../../../src/data/hassio/backup"; -import { - fetchHassioBackups, - friendlyFolderName, - reloadHassioBackups, - removeBackup, -} from "../../../src/data/hassio/backup"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { - showAlertDialog, - showConfirmationDialog, -} from "../../../src/dialogs/generic/show-dialog-box"; -import "../../../src/layouts/hass-loading-screen"; -import "../../../src/layouts/hass-tabs-subpage-data-table"; -import type { HaTabsSubpageDataTable } from "../../../src/layouts/hass-tabs-subpage-data-table"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant, Route } from "../../../src/types"; -import { showBackupUploadDialog } from "../dialogs/backup/show-dialog-backup-upload"; -import { showHassioBackupLocationDialog } from "../dialogs/backup/show-dialog-hassio-backu-location"; -import { showHassioBackupDialog } from "../dialogs/backup/show-dialog-hassio-backup"; -import { showHassioCreateBackupDialog } from "../dialogs/backup/show-dialog-hassio-create-backup"; -import { supervisorTabs } from "../hassio-tabs"; -import { hassioStyle } from "../resources/hassio-style"; - -type BackupItem = HassioBackup & { - secondary: string; -}; - -@customElement("hassio-backups") -export class HassioBackups extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public route!: Route; - - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: "is-wide", type: Boolean }) public isWide = false; - - @state() private _selectedBackups: string[] = []; - - @state() private _backups?: HassioBackup[] = []; - - @state() private _isLoading = false; - - @query("hass-tabs-subpage-data-table", true) - private _dataTable!: HaTabsSubpageDataTable; - - private _firstUpdatedCalled = false; - - public connectedCallback(): void { - super.connectedCallback(); - if (this.hass && this._firstUpdatedCalled) { - this._fetchBackups(); - } - } - - private _computeBackupContent = (backup: HassioBackup): string => { - if (backup.type === "full") { - return this.supervisor.localize("backup.full_backup"); - } - const content: string[] = []; - if (backup.content.homeassistant) { - content.push("Home Assistant"); - } - if (backup.content.folders.length !== 0) { - for (const folder of backup.content.folders) { - content.push(friendlyFolderName[folder] || folder); - } - } - - if (backup.content.addons.length !== 0) { - for (const addon of backup.content.addons) { - content.push( - this.supervisor.addon.addons.find((entry) => entry.slug === addon) - ?.name || addon - ); - } - } - - return content.join(", "); - }; - - protected firstUpdated(changedProperties: PropertyValues): void { - super.firstUpdated(changedProperties); - if (this.hass && this.isConnected) { - this._fetchBackups(); - } - this._firstUpdatedCalled = true; - } - - private _columns = memoizeOne( - (narrow: boolean): DataTableColumnContainer => ({ - name: { - title: this.supervisor.localize("backup.name"), - main: true, - sortable: true, - filterable: true, - flex: 2, - template: (backup) => - html`${backup.name || backup.slug} -
${backup.secondary}
`, - }, - size: { - title: this.supervisor.localize("backup.size"), - hidden: narrow, - filterable: true, - sortable: true, - template: (backup) => Math.ceil(backup.size * 10) / 10 + " MB", - }, - location: { - title: this.supervisor.localize("backup.location"), - hidden: narrow, - filterable: true, - sortable: true, - template: (backup) => - backup.location || this.supervisor.localize("backup.data_disk"), - }, - date: { - title: this.supervisor.localize("backup.created"), - direction: "desc", - hidden: narrow, - filterable: true, - sortable: true, - template: (backup) => - relativeTime(new Date(backup.date), this.hass.locale), - }, - secondary: { - title: "", - hidden: true, - filterable: true, - }, - }) - ); - - private _backupData = memoizeOne((backups: HassioBackup[]): BackupItem[] => - backups.map((backup) => ({ - ...backup, - secondary: this._computeBackupContent(backup), - })) - ); - - protected render() { - if (!this.supervisor) { - return nothing; - } - - if (this._isLoading) { - return html``; - } - - return html` - - - - - ${this.supervisor.localize("common.reload")} - - - ${this.supervisor.localize("dialog.backup_location.title")} - - ${atLeastVersion(this.hass.config.version, 0, 116) - ? html` - ${this.supervisor.localize("backup.upload_backup")} - ` - : ""} - - - ${this._selectedBackups.length - ? html`
-

- ${this.supervisor.localize("backup.selected", { - number: this._selectedBackups.length, - })} -

-
- ${!this.narrow - ? html` - - ${this.supervisor.localize("backup.delete_selected")} - - ` - : html` - - `} -
-
` - : ""} - - - - -
- `; - } - - private _handleAction(ev: CustomEvent) { - switch (ev.detail.index) { - case 0: - this._fetchBackups(); - break; - case 1: - showHassioBackupLocationDialog(this, { supervisor: this.supervisor }); - break; - case 2: - this._showUploadBackupDialog(); - break; - } - } - - private _handleSelectionChanged( - ev: HASSDomEvent - ): void { - this._selectedBackups = ev.detail.value; - } - - private _showUploadBackupDialog() { - showBackupUploadDialog(this, { - showBackup: (slug: string) => - showHassioBackupDialog(this, { - slug, - supervisor: this.supervisor, - onDelete: () => this._fetchBackups(), - }), - reloadBackup: () => this._fetchBackups(), - }); - } - - private async _fetchBackups() { - this._isLoading = true; - await reloadHassioBackups(this.hass); - this._backups = await fetchHassioBackups(this.hass); - this._isLoading = false; - } - - private async _deleteSelected() { - const confirm = await showConfirmationDialog(this, { - title: this.supervisor.localize("backup.delete_backup_title"), - text: this.supervisor.localize("backup.delete_backup_text", { - number: this._selectedBackups.length, - }), - confirmText: this.supervisor.localize("backup.delete_backup_confirm"), - destructive: true, - }); - - if (!confirm) { - return; - } - - try { - await Promise.all( - this._selectedBackups.map((slug) => removeBackup(this.hass, slug)) - ); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("backup.failed_to_delete"), - text: extractApiErrorMessage(err), - }); - return; - } - await this._fetchBackups(); - this._dataTable.clearSelection(); - } - - private _handleRowClicked(ev: HASSDomEvent) { - const slug = ev.detail.id; - showHassioBackupDialog(this, { - slug, - supervisor: this.supervisor, - onDelete: () => this._fetchBackups(), - }); - } - - private _createBackup() { - if (this.supervisor!.info.state !== "running") { - showAlertDialog(this, { - title: this.supervisor!.localize("backup.could_not_create"), - text: this.supervisor!.localize("backup.create_blocked_not_running", { - state: this.supervisor!.info.state, - }), - }); - return; - } - showHassioCreateBackupDialog(this, { - supervisor: this.supervisor!, - onCreate: () => this._fetchBackups(), - }); - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - :host { - color: var(--primary-text-color); - } - .table-header { - display: flex; - justify-content: space-between; - align-items: center; - height: 58px; - border-bottom: 1px solid rgba(var(--rgb-primary-text-color), 0.12); - } - .header-toolbar { - display: flex; - justify-content: space-between; - align-items: center; - color: var(--secondary-text-color); - position: relative; - top: -4px; - } - .selected-txt { - font-weight: var(--ha-font-weight-bold); - padding-left: 16px; - padding-inline-start: 16px; - padding-inline-end: initial; - color: var(--primary-text-color); - } - .table-header .selected-txt { - margin-top: 20px; - } - .header-toolbar .selected-txt { - font-size: var(--ha-font-size-l); - } - .header-toolbar .header-btns { - margin-right: -12px; - margin-inline-end: -12px; - margin-inline-start: initial; - } - .header-btns > ha-button, - .header-btns > ha-icon-button { - margin: 8px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-backups": HassioBackups; - } -} diff --git a/hassio/src/components/hassio-card-content.ts b/hassio/src/components/hassio-card-content.ts deleted file mode 100644 index 9343022093..0000000000 --- a/hassio/src/components/hassio-card-content.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { mdiHelpCircle } from "@mdi/js"; -import type { TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import "../../../src/components/ha-svg-icon"; -import type { HomeAssistant } from "../../../src/types"; - -@customElement("hassio-card-content") -class HassioCardContent extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - // eslint-disable-next-line lit/no-native-attributes - @property() public title!: string; - - @property() public description?: string; - - @property({ type: Boolean }) public available = true; - - @property({ attribute: false }) public showTopbar = false; - - @property({ attribute: false }) public topbarClass?: string; - - @property({ attribute: false }) public iconTitle?: string; - - @property({ attribute: false }) public iconClass?: string; - - @property() public icon = mdiHelpCircle; - - @property({ attribute: false }) public iconImage?: string; - - protected render(): TemplateResult { - return html` - ${this.showTopbar - ? html`
` - : ""} - ${this.iconImage - ? html` -
- ${this.iconTitle -
-
- ` - : html` - - `} -
-
${this.title}
-
- ${this.description} - ${ - /* treat as available when undefined */ - this.available === false ? " (Not available)" : "" - } -
-
- `; - } - - static styles = css` - :host { - direction: ltr; - } - - ha-svg-icon { - margin-right: 24px; - margin-left: 8px; - margin-top: 12px; - float: left; - color: var(--secondary-text-color); - } - ha-svg-icon.update { - color: var(--warning-color); - } - ha-svg-icon.running, - ha-svg-icon.installed { - color: var(--success-color); - } - ha-svg-icon.hassupdate, - ha-svg-icon.backup { - color: var(--state-icon-color); - } - ha-svg-icon.not_available { - color: var(--error-color); - } - .title { - color: var(--primary-text-color); - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - .addition { - color: var(--secondary-text-color); - overflow: hidden; - position: relative; - height: 2.4em; - line-height: var(--ha-line-height-condensed); - } - .icon_image img { - max-height: 40px; - max-width: 40px; - margin-top: 4px; - margin-right: 16px; - float: left; - } - .icon_image.stopped, - .icon_image.not_available { - filter: grayscale(1); - } - .dot { - position: absolute; - background-color: var(--warning-color); - width: 12px; - height: 12px; - top: 8px; - right: 8px; - border-radius: var(--ha-border-radius-circle); - } - .topbar { - position: absolute; - width: 100%; - height: 2px; - top: 0; - left: 0; - border-top-left-radius: 2px; - border-top-right-radius: 2px; - } - .topbar.installed { - background-color: var(--primary-color); - } - .topbar.update { - background-color: var(--accent-color); - } - .topbar.unavailable { - background-color: var(--error-color); - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-card-content": HassioCardContent; - } -} diff --git a/hassio/src/components/hassio-filter-addons.ts b/hassio/src/components/hassio-filter-addons.ts deleted file mode 100644 index 21e5d0e29f..0000000000 --- a/hassio/src/components/hassio-filter-addons.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { IFuseOptions } from "fuse.js"; -import Fuse from "fuse.js"; -import type { StoreAddon } from "../../../src/data/supervisor/store"; - -export function filterAndSort(addons: StoreAddon[], filter: string) { - const options: IFuseOptions = { - keys: ["name", "description", "slug"], - isCaseSensitive: false, - minMatchCharLength: Math.min(filter.length, 2), - threshold: 0.2, - ignoreDiacritics: true, - }; - const fuse = new Fuse(addons, options); - return fuse.search(filter).map((result) => result.item); -} diff --git a/hassio/src/components/hassio-upload-backup.ts b/hassio/src/components/hassio-upload-backup.ts deleted file mode 100644 index fee23e10a9..0000000000 --- a/hassio/src/components/hassio-upload-backup.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { mdiFolderUpload } from "@mdi/js"; -import type { TemplateResult } from "lit"; -import { html, LitElement } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { fireEvent } from "../../../src/common/dom/fire_event"; -import "../../../src/components/ha-file-upload"; -import type { HassioBackup } from "../../../src/data/hassio/backup"; -import { uploadBackup } from "../../../src/data/hassio/backup"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box"; -import type { HomeAssistant } from "../../../src/types"; -import type { LocalizeFunc } from "../../../src/common/translations/localize"; - -declare global { - interface HASSDomEvents { - "hassio-backup-uploaded": { backup: HassioBackup }; - "backup-cleared": undefined; - } -} - -@customElement("hassio-upload-backup") -export class HassioUploadBackup extends LitElement { - public hass?: HomeAssistant; - - @property({ attribute: false }) public localize?: LocalizeFunc; - - @state() public value: string | null = null; - - @state() private _uploading = false; - - public render(): TemplateResult { - return html` - - `; - } - - private _clear() { - this.value = null; - fireEvent(this, "backup-cleared"); - } - - private async _uploadFile(ev) { - const file = ev.detail.files[0]; - - if (!["application/x-tar"].includes(file.type)) { - showAlertDialog(this, { - title: "Unsupported file format", - text: "Please choose a Home Assistant backup file (.tar)", - confirmText: "ok", - }); - return; - } - this._uploading = true; - try { - const backup = await uploadBackup(this.hass, file); - fireEvent(this, "hassio-backup-uploaded", { backup: backup.data }); - } catch (err: any) { - showAlertDialog(this, { - title: "Upload failed", - text: extractApiErrorMessage(err), - confirmText: "ok", - }); - } finally { - this._uploading = false; - } - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-upload-backup": HassioUploadBackup; - } -} diff --git a/hassio/src/components/supervisor-backup-content.ts b/hassio/src/components/supervisor-backup-content.ts deleted file mode 100644 index 285bc205b7..0000000000 --- a/hassio/src/components/supervisor-backup-content.ts +++ /dev/null @@ -1,460 +0,0 @@ -import { mdiFolder, mdiPuzzle } from "@mdi/js"; -import type { TemplateResult } from "lit"; -import { LitElement, css, html, nothing } from "lit"; -import { customElement, property, query } from "lit/decorators"; -import { atLeastVersion } from "../../../src/common/config/version"; -import { formatDate } from "../../../src/common/datetime/format_date"; -import { formatDateTime } from "../../../src/common/datetime/format_date_time"; -import "../../../src/components/ha-checkbox"; -import "../../../src/components/ha-formfield"; -import "../../../src/components/ha-textfield"; -import "../../../src/components/ha-password-field"; -import "../../../src/components/ha-radio"; -import type { HaRadio } from "../../../src/components/ha-radio"; -import type { - HassioBackupDetail, - HassioFullBackupCreateParams, - HassioPartialBackupCreateParams, -} from "../../../src/data/hassio/backup"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { mdiHomeAssistant } from "../../../src/resources/home-assistant-logo-svg"; -import type { HomeAssistant } from "../../../src/types"; -import "./supervisor-formfield-label"; -import type { HaTextField } from "../../../src/components/ha-textfield"; - -interface CheckboxItem { - slug: string; - checked: boolean; - name: string; -} - -interface AddonCheckboxItem extends CheckboxItem { - version: string; -} - -const _computeFolders = (folders): CheckboxItem[] => { - const list: CheckboxItem[] = []; - if (folders.includes("ssl")) { - list.push({ slug: "ssl", name: "SSL", checked: false }); - } - if (folders.includes("share")) { - list.push({ slug: "share", name: "Share", checked: false }); - } - if (folders.includes("media")) { - list.push({ slug: "media", name: "Media", checked: false }); - } - if (folders.includes("addons/local")) { - list.push({ slug: "addons/local", name: "Local add-ons", checked: false }); - } - return list.sort((a, b) => (a.name > b.name ? 1 : -1)); -}; - -const _computeAddons = (addons): AddonCheckboxItem[] => - addons - .map((addon) => ({ - slug: addon.slug, - name: addon.name, - version: addon.version, - checked: false, - })) - .sort((a, b) => (a.name > b.name ? 1 : -1)); - -@customElement("supervisor-backup-content") -export class SupervisorBackupContent extends LitElement { - @property({ attribute: false }) public hass?: HomeAssistant; - - @property({ attribute: false }) public supervisor?: Supervisor; - - @property({ attribute: false }) public backup?: HassioBackupDetail; - - @property({ attribute: false }) - public backupType: HassioBackupDetail["type"] = "full"; - - @property({ attribute: false }) public folders?: CheckboxItem[]; - - @property({ attribute: false }) public addons?: AddonCheckboxItem[]; - - @property({ attribute: false }) public homeAssistant = false; - - @property({ attribute: false }) public backupHasPassword = false; - - @property({ type: Boolean }) public onboarding = false; - - @property({ attribute: false }) public backupName = ""; - - @property({ attribute: false }) public backupPassword = ""; - - @property({ attribute: false }) public confirmBackupPassword = ""; - - @query("ha-textfield, ha-radio, ha-checkbox", true) private _focusTarget; - - public willUpdate(changedProps) { - super.willUpdate(changedProps); - if (!this.hasUpdated) { - this.folders = _computeFolders( - this.backup - ? this.backup.folders - : ["ssl", "share", "media", "addons/local"] - ); - this.addons = _computeAddons( - this.backup ? this.backup.addons : this.supervisor?.addon.addons - ); - this.backupType = this.backup?.type || "full"; - this.backupName = this.backup?.name || ""; - this.backupHasPassword = this.backup?.protected || false; - } - } - - public override focus() { - this._focusTarget?.focus(); - } - - protected render() { - if (!this.onboarding && !this.supervisor) { - return nothing; - } - const foldersSection = - this.backupType === "partial" ? this._getSection("folders") : undefined; - const addonsSection = - this.backupType === "partial" ? this._getSection("addons") : undefined; - - return html` - ${this.backup - ? html`
- ${this.backup.type === "full" - ? this.supervisor?.localize("backup.full_backup") - : this.supervisor?.localize("backup.partial_backup")} - (${Math.ceil(this.backup.size * 10) / 10 + " MB"})
- ${this.hass - ? formatDateTime( - new Date(this.backup.date), - this.hass.locale, - this.hass.config - ) - : this.backup.date} -
` - : html` - `} - ${!this.backup || this.backup.type === "full" - ? html`
- ${!this.backup - ? this.supervisor?.localize("backup.type") - : this.supervisor?.localize("backup.select_type")} -
-
- - - - - - - - -
` - : ""} - ${this.backupType === "partial" - ? html`
- ${!this.backup || this.backup.homeassistant - ? html` - `} - > - - - ` - : ""} - ${foldersSection?.templates.length - ? html` - - `} - > - - - -
${foldersSection.templates}
- ` - : ""} - ${addonsSection?.templates.length - ? html` - - `} - > - - - -
${addonsSection.templates}
- ` - : ""} -
` - : ""} - ${this.backupType === "partial" && - (!this.backup || this.backupHasPassword) - ? html`
` - : ""} - ${!this.backup - ? html` - - - ` - : ""} - ${this.backupHasPassword - ? html` - - - ${!this.backup - ? html` - ` - : ""} - ` - : ""} - `; - } - - private _toggleHomeAssistant() { - this.homeAssistant = !this.homeAssistant; - } - - static styles = css` - .partial-picker ha-formfield { - display: block; - } - .partial-picker ha-checkbox { - --mdc-checkbox-touch-target-size: 32px; - } - .partial-picker { - display: block; - margin: 0px -6px; - } - supervisor-formfield-label { - display: inline-flex; - align-items: center; - } - hr { - border-color: var(--divider-color); - border-bottom: none; - margin: 16px 0; - } - .details { - color: var(--secondary-text-color); - } - .section-content { - display: flex; - flex-direction: column; - margin-left: 30px; - margin-inline-start: 30px; - margin-inline-end: initial; - } - ha-formfield.password { - display: block; - margin: 0 -14px -16px; - } - .backup-types { - display: flex; - margin-left: -13px; - margin-inline-start: -13px; - margin-inline-end: initial; - } - .sub-header { - margin-top: 8px; - } - `; - - public backupDetails(): - | HassioPartialBackupCreateParams - | HassioFullBackupCreateParams { - const data: any = {}; - - if (!this.backup && this.hass) { - data.name = - this.backupName || - formatDate(new Date(), this.hass.locale, this.hass.config); - } - - if (this.backupHasPassword) { - data.password = this.backupPassword; - if (!this.backup) { - data.confirm_password = this.confirmBackupPassword; - } - } - - if (this.backupType === "full") { - return data; - } - - const addons = this.addons - ?.filter((addon) => addon.checked) - .map((addon) => addon.slug); - const folders = this.folders - ?.filter((folder) => folder.checked) - .map((folder) => folder.slug); - - if (addons?.length) { - data.addons = addons; - } - if (folders?.length) { - data.folders = folders; - } - - // onboarding needs at least homeassistant to restore - data.homeassistant = this.onboarding || this.homeAssistant; - - return data; - } - - private _getSection(section: string) { - const templates: TemplateResult[] = []; - const addons = - section === "addons" - ? new Map( - this.supervisor?.addon.addons.map((item) => [item.slug, item]) - ) - : undefined; - let checkedItems = 0; - this[section].forEach((item) => { - templates.push( - html` - `} - > - - - ` - ); - - if (item.checked) { - checkedItems++; - } - }); - - const checked = checkedItems === this[section].length; - - return { - templates, - checked, - indeterminate: !checked && checkedItems !== 0, - }; - } - - private _handleRadioValueChanged(ev: CustomEvent) { - const input = ev.currentTarget as HaRadio; - this[input.name] = input.value; - } - - private _handleTextValueChanged(ev: InputEvent) { - const input = ev.currentTarget as HaTextField; - this[input.name!] = input.value; - } - - private _toggleHasPassword(): void { - this.backupHasPassword = !this.backupHasPassword; - } - - private _toggleSection(ev): void { - const section = ev.currentTarget.section; - - this[section] = (section === "addons" ? this.addons : this.folders)!.map( - (item) => ({ - ...item, - checked: ev.currentTarget.checked, - }) - ); - } - - private _updateSectionEntry(ev): void { - const item = ev.currentTarget.item; - const section = ev.currentTarget.section; - this[section] = this[section].map((entry) => - entry.slug === item.slug - ? { - ...entry, - checked: ev.currentTarget.checked, - } - : entry - ); - } -} - -declare global { - interface HTMLElementTagNameMap { - "supervisor-backup-content": SupervisorBackupContent; - } -} diff --git a/hassio/src/components/supervisor-formfield-label.ts b/hassio/src/components/supervisor-formfield-label.ts deleted file mode 100644 index ce04c6d8d6..0000000000 --- a/hassio/src/components/supervisor-formfield-label.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import "../../../src/components/ha-svg-icon"; - -@customElement("supervisor-formfield-label") -class SupervisorFormfieldLabel extends LitElement { - @property({ type: String }) public label!: string; - - @property({ attribute: false }) public imageUrl?: string; - - @property({ attribute: false }) public iconPath?: string; - - @property({ type: String }) public version?: string; - - protected render(): TemplateResult { - return html` - ${this.imageUrl - ? html`` - : this.iconPath - ? html`` - : ""} - ${this.label} - ${this.version - ? html`(${this.version})` - : ""} - `; - } - - static styles = css` - :host { - display: flex; - align-items: center; - } - .label { - margin-right: 4px; - margin-inline-end: 4px; - margin-inline-start: initial; - } - .version { - color: var(--secondary-text-color); - } - .icon { - max-height: 22px; - max-width: 22px; - margin-right: 8px; - margin-inline-end: 8px; - margin-inline-start: initial; - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "supervisor-formfield-label": SupervisorFormfieldLabel; - } -} diff --git a/hassio/src/components/supervisor-metric.ts b/hassio/src/components/supervisor-metric.ts deleted file mode 100644 index 19c33cfbc8..0000000000 --- a/hassio/src/components/supervisor-metric.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import { classMap } from "lit/directives/class-map"; -import "../../../src/components/ha-bar"; -import "../../../src/components/ha-settings-row"; -import { roundWithOneDecimal } from "../../../src/util/calculate"; - -@customElement("supervisor-metric") -class SupervisorMetric extends LitElement { - @property({ type: Number }) public value!: number; - - @property({ type: String }) public description!: string; - - @property({ type: String }) public tooltip?: string; - - protected render(): TemplateResult { - const roundedValue = roundWithOneDecimal(this.value); - return html` - ${this.description} -
- ${roundedValue} % - 50, - "target-critical": roundedValue > 85, - })} - .value=${this.value} - > -
-
`; - } - - static styles = css` - ha-settings-row { - padding: 0; - height: 54px; - width: 100%; - } - ha-settings-row > div[slot="description"] { - white-space: normal; - color: var(--secondary-text-color); - display: flex; - justify-content: space-between; - } - ha-bar { - --ha-bar-primary-color: var(--hassio-bar-ok-color, var(--success-color)); - } - .target-warning { - --ha-bar-primary-color: var( - --hassio-bar-warning-color, - var(--warning-color) - ); - } - .target-critical { - --ha-bar-primary-color: var( - --hassio-bar-critical-color, - var(--error-color) - ); - } - .value { - width: 48px; - padding-right: 4px; - padding-inline-start: initial; - padding-inline-end: 4px; - flex-shrink: 0; - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "supervisor-metric": SupervisorMetric; - } -} diff --git a/hassio/src/dashboard/hassio-addons.ts b/hassio/src/dashboard/hassio-addons.ts deleted file mode 100644 index 69da0d48e4..0000000000 --- a/hassio/src/dashboard/hassio-addons.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js"; -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { atLeastVersion } from "../../../src/common/config/version"; -import { navigate } from "../../../src/common/navigate"; -import { caseInsensitiveStringCompare } from "../../../src/common/string/compare"; -import "../../../src/components/ha-card"; -import "../../../src/components/search-input"; -import type { HassioAddonInfo } from "../../../src/data/hassio/addon"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant } from "../../../src/types"; -import "../components/hassio-card-content"; -import { hassioStyle } from "../resources/hassio-style"; - -@customElement("hassio-addons") -class HassioAddons extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ type: Boolean }) public narrow = false; - - @state() private _filter?: string; - - protected render(): TemplateResult { - return html` - -
- ${!atLeastVersion(this.hass.config.version, 2021, 12) - ? html`

${this.supervisor.localize("dashboard.apps")}

` - : ""} -
- ${!this.supervisor.addon.addons.length - ? html` - -
- -
-
- ` - : this._getAddons(this.supervisor.addon.addons, this._filter).map( - (addon) => html` - -
- -
-
- ` - )} -
-
- `; - } - - private _getAddons = memoizeOne( - (addons: HassioAddonInfo[], filter?: string) => { - if (filter) { - addons = addons.filter((addon) => { - const lowerCaseFilter = filter.toLowerCase(); - return ( - addon.name.toLowerCase().includes(lowerCaseFilter) || - addon.description.toLowerCase().includes(lowerCaseFilter) || - addon.slug.toLowerCase().includes(lowerCaseFilter) - ); - }); - } - return addons.sort((a, b) => - caseInsensitiveStringCompare(a.name, b.name, this.hass.locale.language) - ); - } - ); - - private _handleSearchChange(ev: CustomEvent) { - this._filter = ev.detail.value; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - ha-card { - cursor: pointer; - overflow: hidden; - direction: ltr; - } - .search { - position: sticky; - top: 0; - z-index: 2; - } - search-input { - display: block; - --mdc-text-field-fill-color: var(--sidebar-background-color); - --mdc-text-field-idle-line-color: var(--divider-color); - } - .content { - margin-bottom: 72px; - } - `, - ]; - } - - private _addonTapped(ev: any): void { - navigate(`/hassio/addon/${ev.currentTarget.addon.slug}/info`); - } - - private _openStore(): void { - navigate("/hassio/store"); - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-addons": HassioAddons; - } -} diff --git a/hassio/src/dashboard/hassio-dashboard.ts b/hassio/src/dashboard/hassio-dashboard.ts deleted file mode 100644 index 2dbb1a27be..0000000000 --- a/hassio/src/dashboard/hassio-dashboard.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { mdiRefresh, mdiStorePlus } from "@mdi/js"; -import type { CSSResultGroup, TemplateResult } from "lit"; -import { LitElement, css, html } from "lit"; -import { customElement, property } from "lit/decorators"; -import { atLeastVersion } from "../../../src/common/config/version"; -import { fireEvent } from "../../../src/common/dom/fire_event"; -import "../../../src/components/ha-fab"; -import { reloadHassioAddons } from "../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box"; -import "../../../src/layouts/hass-subpage"; -import "../../../src/layouts/hass-tabs-subpage"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant, Route } from "../../../src/types"; -import { supervisorTabs } from "../hassio-tabs"; -import "./hassio-addons"; - -@customElement("hassio-dashboard") -class HassioDashboard extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public route!: Route; - - firstUpdated() { - if (!atLeastVersion(this.hass.config.version, 2022, 5)) { - import("./hassio-update"); - } - } - - protected render(): TemplateResult { - if (atLeastVersion(this.hass.config.version, 2022, 5)) { - return html` - - - - - - `; - } - - return html` - - - ${this.supervisor.localize( - atLeastVersion(this.hass.config.version, 2021, 12) - ? "panel.apps" - : "panel.dashboard" - )} - -
- ${!atLeastVersion(this.hass.config.version, 2021, 12) - ? html` - - ` - : ""} - -
- - - - -
- `; - } - - private async _handleCheckUpdates() { - try { - await reloadHassioAddons(this.hass); - } catch (err) { - showAlertDialog(this, { - text: extractApiErrorMessage(err), - }); - } finally { - fireEvent(this, "supervisor-collection-refresh", { collection: "addon" }); - } - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - css` - .content { - margin: 0 auto; - } - ha-fab.non-tabs { - position: fixed; - right: calc(16px + var(--safe-area-inset-right)); - bottom: calc(16px + var(--safe-area-inset-bottom)); - inset-inline-end: calc(16px + var(--safe-area-inset-right)); - inset-inline-start: initial; - z-index: 1; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-dashboard": HassioDashboard; - } -} diff --git a/hassio/src/dashboard/hassio-update.ts b/hassio/src/dashboard/hassio-update.ts deleted file mode 100644 index e62e4ea327..0000000000 --- a/hassio/src/dashboard/hassio-update.ts +++ /dev/null @@ -1,158 +0,0 @@ -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import "../../../src/components/ha-card"; -import "../../../src/components/ha-button"; -import "../../../src/components/ha-settings-row"; -import "../../../src/components/ha-svg-icon"; -import type { HassioHassOSInfo } from "../../../src/data/hassio/host"; -import type { - HassioHomeAssistantInfo, - HassioSupervisorInfo, -} from "../../../src/data/hassio/supervisor"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { mdiHomeAssistant } from "../../../src/resources/home-assistant-logo-svg"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant } from "../../../src/types"; -import { hassioStyle } from "../resources/hassio-style"; - -const computeVersion = (key: string, version: string): string => - key === "os" ? version : `${key}-${version}`; - -@customElement("hassio-update") -export class HassioUpdate extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - private _pendingUpdates = memoizeOne( - (supervisor: Supervisor): number => - Object.keys(supervisor).filter( - (value) => supervisor[value].update_available - ).length - ); - - protected render() { - if (!this.supervisor) { - return nothing; - } - - const updatesAvailable = this._pendingUpdates(this.supervisor); - if (!updatesAvailable) { - return nothing; - } - - return html` -
-

- ${this.supervisor.localize("common.update_available", { - count: updatesAvailable, - })} - 🎉 -

-
- ${this._renderUpdateCard( - "Home Assistant Core", - "core", - this.supervisor.core - )} - ${this._renderUpdateCard( - "Supervisor", - "supervisor", - this.supervisor.supervisor - )} - ${this.supervisor.host.features.includes("haos") - ? this._renderUpdateCard( - "Operating System", - "os", - this.supervisor.os - ) - : ""} -
-
- `; - } - - private _renderUpdateCard( - name: string, - key: string, - object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo - ) { - if (!object.update_available) { - return nothing; - } - return html` - -
-
- -
-
${name}
- - - ${this.supervisor.localize("common.version")} - - - ${computeVersion(key, object.version!)} - - - - - - ${this.supervisor.localize("common.newest_version")} - - - ${computeVersion(key, object.version_latest!)} - - -
-
- - ${this.supervisor.localize("common.show")} - -
-
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - .icon { - --mdc-icon-size: 48px; - float: right; - margin: 0 0 2px 10px; - color: var(--primary-text-color); - } - .update-heading { - font-size: var(--ha-font-size-l); - font-weight: var(--ha-font-weight-medium); - margin-bottom: 0.5em; - color: var(--primary-text-color); - } - .card-content { - height: calc(100% - 47px); - box-sizing: border-box; - } - .card-actions { - text-align: right; - } - a { - text-decoration: none; - } - ha-settings-row { - padding: 0; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-update": HassioUpdate; - } -} diff --git a/hassio/src/dialogs/backup/dialog-hassio-backup-location.ts b/hassio/src/dialogs/backup/dialog-hassio-backup-location.ts deleted file mode 100644 index 5d5ec48370..0000000000 --- a/hassio/src/dialogs/backup/dialog-hassio-backup-location.ts +++ /dev/null @@ -1,155 +0,0 @@ -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "../../../../src/components/ha-dialog"; -import "../../../../src/components/ha-button"; -import "../../../../src/components/ha-form/ha-form"; -import type { SchemaUnion } from "../../../../src/components/ha-form/types"; -import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import { changeMountOptions } from "../../../../src/data/supervisor/mounts"; -import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import type { HassioBackupLocationDialogParams } from "./show-dialog-hassio-backu-location"; - -const SCHEMA = memoizeOne( - () => - [ - { - name: "default_backup_mount", - required: true, - selector: { backup_location: {} }, - }, - ] as const -); - -@customElement("dialog-hassio-backup-location") -class HassioBackupLocationDialog extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @state() private _dialogParams?: HassioBackupLocationDialogParams; - - @state() private _data?: { default_backup_mount: string | null }; - - @state() private _waiting?: boolean; - - @state() private _error?: string; - - public async showDialog( - dialogParams: HassioBackupLocationDialogParams - ): Promise { - this._dialogParams = dialogParams; - } - - public closeDialog(): void { - this._data = undefined; - this._error = undefined; - this._waiting = undefined; - this._dialogParams = undefined; - fireEvent(this, "dialog-closed", { dialog: this.localName }); - } - - protected render() { - if (!this._dialogParams) { - return nothing; - } - return html` - - ${this._error - ? html`${this._error}` - : nothing} - - - - ${this._dialogParams.supervisor.localize("common.cancel")} - - - ${this._dialogParams.supervisor.localize("common.save")} - - - `; - } - - private _computeLabelCallback = ( - // @ts-ignore - schema: SchemaUnion> - ): string => - this._dialogParams!.supervisor.localize( - `dialog.backup_location.options.${schema.name}.name` - ) || schema.name; - - private _computeHelperCallback = ( - // @ts-ignore - schema: SchemaUnion> - ): string => - this._dialogParams!.supervisor.localize( - `dialog.backup_location.options.${schema.name}.description` - ); - - private _valueChanged(ev: CustomEvent) { - const newLocation = ev.detail.value.default_backup_mount; - this._data = { - default_backup_mount: newLocation === "/backup" ? null : newLocation, - }; - } - - private async _changeMount() { - if (!this._data) { - return; - } - this._error = undefined; - this._waiting = true; - try { - await changeMountOptions(this.hass, this._data); - } catch (err: any) { - this._error = extractApiErrorMessage(err); - this._waiting = false; - return; - } - this.closeDialog(); - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - haStyleDialog, - css` - .delete-btn { - --mdc-theme-primary: var(--error-color); - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-backup-location": HassioBackupLocationDialog; - } -} diff --git a/hassio/src/dialogs/backup/dialog-hassio-backup-upload.ts b/hassio/src/dialogs/backup/dialog-hassio-backup-upload.ts deleted file mode 100644 index f96ac681f7..0000000000 --- a/hassio/src/dialogs/backup/dialog-hassio-backup-upload.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { mdiClose } from "@mdi/js"; -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "../../../../src/components/ha-header-bar"; -import "../../../../src/components/ha-icon-button"; -import "../../../../src/components/ha-dialog"; -import type { HassDialog } from "../../../../src/dialogs/make-dialog-manager"; -import { haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import "../../components/hassio-upload-backup"; -import type { HassioBackupUploadDialogParams } from "./show-dialog-backup-upload"; - -@customElement("dialog-hassio-backup-upload") -export class DialogHassioBackupUpload - extends LitElement - implements HassDialog -{ - @property({ attribute: false }) public hass?: HomeAssistant; - - @state() private _dialogParams?: HassioBackupUploadDialogParams; - - public async showDialog( - dialogParams: HassioBackupUploadDialogParams - ): Promise { - this._dialogParams = dialogParams; - await this.updateComplete; - } - - public closeDialog() { - if (this._dialogParams && !this._dialogParams.onboarding) { - if (this._dialogParams.reloadBackup) { - this._dialogParams.reloadBackup(); - } - } - this._dialogParams = undefined; - fireEvent(this, "dialog-closed", { dialog: this.localName }); - return true; - } - - protected render() { - if (!this._dialogParams) { - return nothing; - } - - return html` - -
- - ${this.hass?.localize( - "ui.panel.page-onboarding.restore.upload_backup" - ) || "Upload backup"} - - -
- -
- `; - } - - private _backupUploaded(ev) { - const backup = ev.detail.backup; - this._dialogParams?.showBackup(backup.slug); - this.closeDialog(); - } - - static get styles(): CSSResultGroup { - return [ - haStyleDialog, - css` - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - flex-shrink: 0; - } - /* overrule the ha-style-dialog max-height on small screens */ - @media all and (max-width: 450px), all and (max-height: 500px) { - ha-header-bar { - --mdc-theme-primary: var(--app-header-background-color); - --mdc-theme-on-primary: var(--app-header-text-color, white); - } - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-backup-upload": DialogHassioBackupUpload; - } -} diff --git a/hassio/src/dialogs/backup/dialog-hassio-backup.ts b/hassio/src/dialogs/backup/dialog-hassio-backup.ts deleted file mode 100644 index c3df55c919..0000000000 --- a/hassio/src/dialogs/backup/dialog-hassio-backup.ts +++ /dev/null @@ -1,339 +0,0 @@ -import type { ActionDetail } from "@material/mwc-list"; - -import { mdiClose, mdiDotsVertical } from "@mdi/js"; -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; -import { atLeastVersion } from "../../../../src/common/config/version"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import { stopPropagation } from "../../../../src/common/dom/stop_propagation"; -import { slugify } from "../../../../src/common/string/slugify"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-button"; -import "../../../../src/components/ha-button-menu"; -import "../../../../src/components/ha-dialog-header"; -import "../../../../src/components/ha-header-bar"; -import "../../../../src/components/ha-icon-button"; -import "../../../../src/components/ha-list-item"; -import "../../../../src/components/ha-md-dialog"; -import type { HaMdDialog } from "../../../../src/components/ha-md-dialog"; -import "../../../../src/components/ha-spinner"; -import { getSignedPath } from "../../../../src/data/auth"; -import type { HassioBackupDetail } from "../../../../src/data/hassio/backup"; -import { - fetchHassioBackupInfo, - removeBackup, - restoreBackup, -} from "../../../../src/data/hassio/backup"; -import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import { - showAlertDialog, - showConfirmationDialog, -} from "../../../../src/dialogs/generic/show-dialog-box"; -import type { HassDialog } from "../../../../src/dialogs/make-dialog-manager"; -import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import { fileDownload } from "../../../../src/util/file_download"; -import "../../components/supervisor-backup-content"; -import type { SupervisorBackupContent } from "../../components/supervisor-backup-content"; -import type { HassioBackupDialogParams } from "./show-dialog-hassio-backup"; - -@customElement("dialog-hassio-backup") -class HassioBackupDialog - extends LitElement - implements HassDialog -{ - @property({ attribute: false }) public hass!: HomeAssistant; - - @state() private _error?: string; - - @state() private _backup?: HassioBackupDetail; - - @state() private _dialogParams?: HassioBackupDialogParams; - - @state() private _restoringBackup = false; - - @query("supervisor-backup-content") - private _backupContent!: SupervisorBackupContent; - - @query("ha-md-dialog") private _dialog?: HaMdDialog; - - public async showDialog(dialogParams: HassioBackupDialogParams) { - this._dialogParams = dialogParams; - this._backup = await fetchHassioBackupInfo(this.hass, dialogParams.slug); - if (!this._backup) { - this._error = this._dialogParams.supervisor?.localize( - "backup.no_backup_found" - ); - } else if (this._dialogParams.onboarding && !this._backup.homeassistant) { - this._error = this._dialogParams.supervisor?.localize( - "backup.restore_no_home_assistant" - ); - } - this._restoringBackup = false; - } - - private _dialogClosed(): void { - this._backup = undefined; - this._dialogParams = undefined; - this._restoringBackup = false; - this._error = undefined; - fireEvent(this, "dialog-closed", { dialog: this.localName }); - } - - public closeDialog() { - this._dialog?.close(); - return true; - } - - protected render() { - if (!this._dialogParams || !this._backup) { - return nothing; - } - return html` - - - - ${this._backup.name} - ${!this._dialogParams.onboarding && this._dialogParams.supervisor - ? html` - - ${this._dialogParams.supervisor.localize( - "backup.download_backup" - )} - ${this._dialogParams.supervisor.localize( - "backup.delete_backup_title" - )} - ` - : nothing} - -
- ${this._error - ? html`${this._error}` - : this._restoringBackup - ? html`
- -
` - : html` - - - `} -
-
- - ${this._dialogParams.supervisor?.localize("backup.restore")} - -
-
- `; - } - - private _handleMenuAction(ev: CustomEvent) { - switch (ev.detail.index) { - case 0: - this._downloadClicked(); - break; - case 1: - this._deleteClicked(); - break; - } - } - - private async _restoreClicked() { - const backupDetails = this._backupContent.backupDetails(); - this._restoringBackup = true; - - const supervisor = this._dialogParams?.supervisor; - if (supervisor !== undefined && supervisor.info.state !== "running") { - await showAlertDialog(this, { - title: supervisor.localize("backup.could_not_restore"), - text: supervisor.localize("backup.restore_blocked_not_running", { - state: supervisor.info.state, - }), - }); - this._restoringBackup = false; - return; - } - if ( - !(await showConfirmationDialog(this, { - title: supervisor?.localize( - `backup.${ - this._backup!.type === "full" - ? "confirm_restore_full_backup_title" - : "confirm_restore_partial_backup_title" - }` - ), - text: supervisor?.localize( - `backup.${ - this._backup!.type === "full" - ? "confirm_restore_full_backup_text" - : "confirm_restore_partial_backup_text" - }` - ), - confirmText: supervisor?.localize("backup.restore"), - dismissText: supervisor?.localize("backup.cancel"), - })) - ) { - this._restoringBackup = false; - return; - } - - try { - await restoreBackup( - this.hass, - this._backup!.type, - this._backup!.slug, - { ...backupDetails, background: this._dialogParams?.onboarding }, - !!this.hass && atLeastVersion(this.hass.config.version, 2021, 9) - ); - - this._dialogParams?.onRestoring?.(); - this.closeDialog(); - } catch (error: any) { - this._error = - error?.body?.message || - supervisor?.localize("backup.restore_start_failed"); - } finally { - this._restoringBackup = false; - } - } - - private async _deleteClicked() { - const supervisor = this._dialogParams?.supervisor; - if (!supervisor) return; - - if ( - !(await showConfirmationDialog(this, { - title: supervisor!.localize("backup.confirm_delete_title"), - text: supervisor!.localize("backup.confirm_delete_text"), - confirmText: supervisor!.localize("backup.delete"), - dismissText: supervisor!.localize("backup.cancel"), - destructive: true, - })) - ) { - return; - } - - try { - await removeBackup(this.hass!, this._backup!.slug); - if (this._dialogParams!.onDelete) { - this._dialogParams!.onDelete(); - } - this.closeDialog(); - } catch (err: any) { - this._error = err.body.message; - } - } - - private async _downloadClicked() { - const supervisor = this._dialogParams?.supervisor; - if (!supervisor) return; - - let signedPath: { path: string }; - try { - signedPath = await getSignedPath( - this.hass!, - `/api/hassio/${ - atLeastVersion(this.hass!.config.version, 2021, 9) - ? "backups" - : "snapshots" - }/${this._backup!.slug}/download` - ); - } catch (err: any) { - await showAlertDialog(this, { - text: extractApiErrorMessage(err), - }); - return; - } - - if (window.location.href.includes("ui.nabu.casa")) { - const confirm = await showConfirmationDialog(this, { - title: supervisor.localize("backup.remote_download_title"), - text: supervisor.localize("backup.remote_download_text"), - confirmText: supervisor.localize("backup.download"), - dismissText: supervisor?.localize("backup.cancel"), - }); - if (!confirm) { - return; - } - } - - fileDownload( - signedPath.path, - `home_assistant_backup_${slugify(this._computeName)}.tar` - ); - } - - private get _computeName() { - return this._backup - ? this._backup.name || this._backup.slug - : this._dialogParams!.supervisor?.localize("backup.unnamed_backup") || ""; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - haStyleDialog, - css` - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - flex-shrink: 0; - display: block; - } - ha-icon-button { - color: var(--secondary-text-color); - } - .loading { - width: 100%; - display: flex; - height: 100%; - justify-content: center; - align-items: center; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-backup": HassioBackupDialog; - } -} diff --git a/hassio/src/dialogs/backup/dialog-hassio-create-backup.ts b/hassio/src/dialogs/backup/dialog-hassio-create-backup.ts deleted file mode 100644 index 8c2c05d946..0000000000 --- a/hassio/src/dialogs/backup/dialog-hassio-create-backup.ts +++ /dev/null @@ -1,158 +0,0 @@ -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-button"; -import "../../../../src/components/ha-spinner"; -import { createCloseHeading } from "../../../../src/components/ha-dialog"; -import { - createHassioFullBackup, - createHassioPartialBackup, -} from "../../../../src/data/hassio/backup"; -import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box"; -import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import "../../components/supervisor-backup-content"; -import type { SupervisorBackupContent } from "../../components/supervisor-backup-content"; -import type { HassioCreateBackupDialogParams } from "./show-dialog-hassio-create-backup"; - -@customElement("dialog-hassio-create-backup") -class HassioCreateBackupDialog extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @state() private _dialogParams?: HassioCreateBackupDialogParams; - - @state() private _error?: string; - - @state() private _creatingBackup = false; - - @query("supervisor-backup-content") - private _backupContent!: SupervisorBackupContent; - - public showDialog(dialogParams: HassioCreateBackupDialogParams) { - this._dialogParams = dialogParams; - this._creatingBackup = false; - } - - public closeDialog() { - this._dialogParams = undefined; - this._creatingBackup = false; - this._error = undefined; - fireEvent(this, "dialog-closed", { dialog: this.localName }); - } - - protected render() { - if (!this._dialogParams) { - return nothing; - } - return html` - - ${this._creatingBackup - ? html`` - : html` - `} - ${this._error - ? html`${this._error}` - : ""} - - ${this._dialogParams.supervisor.localize("common.close")} - - - ${this._dialogParams.supervisor.localize("backup.create")} - - - `; - } - - private async _createBackup(): Promise { - if (this._dialogParams!.supervisor.info.state !== "running") { - showAlertDialog(this, { - title: this._dialogParams!.supervisor.localize( - "backup.could_not_create" - ), - text: this._dialogParams!.supervisor.localize( - "backup.create_blocked_not_running", - { state: this._dialogParams!.supervisor.info.state } - ), - }); - return; - } - const backupDetails = this._backupContent.backupDetails(); - this._creatingBackup = true; - - this._error = ""; - if (backupDetails.password && !backupDetails.password.length) { - this._error = this._dialogParams!.supervisor.localize( - "backup.enter_password" - ); - this._creatingBackup = false; - return; - } - if ( - backupDetails.password && - backupDetails.password !== backupDetails.confirm_password - ) { - this._error = this._dialogParams!.supervisor.localize( - "backup.passwords_not_matching" - ); - this._creatingBackup = false; - return; - } - - delete backupDetails.confirm_password; - - try { - if (this._backupContent.backupType === "full") { - await createHassioFullBackup(this.hass, backupDetails); - } else { - await createHassioPartialBackup(this.hass, backupDetails); - } - - this._dialogParams!.onCreate(); - this.closeDialog(); - } catch (err: any) { - this._error = extractApiErrorMessage(err); - } - this._creatingBackup = false; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - haStyleDialog, - css` - :host { - direction: var(--direction); - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-create-backup": HassioCreateBackupDialog; - } -} diff --git a/hassio/src/dialogs/backup/show-dialog-backup-upload.ts b/hassio/src/dialogs/backup/show-dialog-backup-upload.ts deleted file mode 100644 index 861f192595..0000000000 --- a/hassio/src/dialogs/backup/show-dialog-backup-upload.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "./dialog-hassio-backup-upload"; - -export interface HassioBackupUploadDialogParams { - showBackup: (slug: string) => void; - reloadBackup?: () => Promise; - onboarding?: boolean; -} - -export const showBackupUploadDialog = ( - element: HTMLElement, - dialogParams: HassioBackupUploadDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-backup-upload", - dialogImport: () => import("./dialog-hassio-backup-upload"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/backup/show-dialog-hassio-backu-location.ts b/hassio/src/dialogs/backup/show-dialog-hassio-backu-location.ts deleted file mode 100644 index 12ac69bc82..0000000000 --- a/hassio/src/dialogs/backup/show-dialog-hassio-backu-location.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; - -export interface HassioBackupLocationDialogParams { - supervisor: Supervisor; -} - -export const showHassioBackupLocationDialog = ( - element: HTMLElement, - dialogParams: HassioBackupLocationDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-backup-location", - dialogImport: () => import("./dialog-hassio-backup-location"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/backup/show-dialog-hassio-backup.ts b/hassio/src/dialogs/backup/show-dialog-hassio-backup.ts deleted file mode 100644 index 57b354f087..0000000000 --- a/hassio/src/dialogs/backup/show-dialog-hassio-backup.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; - -export interface HassioBackupDialogParams { - slug: string; - onDelete?: () => void; - onRestoring?: () => void; - onboarding?: boolean; - supervisor?: Supervisor; -} - -export const showHassioBackupDialog = ( - element: HTMLElement, - dialogParams: HassioBackupDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-backup", - dialogImport: () => import("./dialog-hassio-backup"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/backup/show-dialog-hassio-create-backup.ts b/hassio/src/dialogs/backup/show-dialog-hassio-create-backup.ts deleted file mode 100644 index aada29d196..0000000000 --- a/hassio/src/dialogs/backup/show-dialog-hassio-create-backup.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; - -export interface HassioCreateBackupDialogParams { - supervisor: Supervisor; - onCreate: () => void; -} - -export const showHassioCreateBackupDialog = ( - element: HTMLElement, - dialogParams: HassioCreateBackupDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-create-backup", - dialogImport: () => import("./dialog-hassio-create-backup"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/datadisk/dialog-hassio-datadisk.ts b/hassio/src/dialogs/datadisk/dialog-hassio-datadisk.ts deleted file mode 100644 index 9cd6c4d087..0000000000 --- a/hassio/src/dialogs/datadisk/dialog-hassio-datadisk.ts +++ /dev/null @@ -1,184 +0,0 @@ -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "../../../../src/components/ha-dialog"; -import "../../../../src/components/ha-button"; -import "../../../../src/components/ha-list-item"; -import "../../../../src/components/ha-select"; -import "../../../../src/components/ha-spinner"; -import { - extractApiErrorMessage, - ignoreSupervisorError, -} from "../../../../src/data/hassio/common"; -import type { DatadiskList } from "../../../../src/data/hassio/host"; -import { listDatadisks, moveDatadisk } from "../../../../src/data/hassio/host"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box"; -import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import type { HassioDatatiskDialogParams } from "./show-dialog-hassio-datadisk"; - -const calculateMoveTime = memoizeOne((supervisor: Supervisor): number => { - // Assume a speed of 30 MB/s. - const moveTime = (supervisor.host.disk_used * 1000) / 60 / 30; - const rebootTime = (supervisor.host.startup_time * 4) / 60; - return Math.ceil((moveTime + rebootTime) / 10) * 10; -}); - -@customElement("dialog-hassio-datadisk") -class HassioDatadiskDialog extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @state() private dialogParams?: HassioDatatiskDialogParams; - - @state() private selectedDevice?: string; - - @state() private devices?: DatadiskList["devices"]; - - @state() private moving = false; - - public showDialog(params: HassioDatatiskDialogParams) { - this.dialogParams = params; - listDatadisks(this.hass).then((data) => { - this.devices = data.devices; - }); - } - - public closeDialog(): void { - this.dialogParams = undefined; - this.selectedDevice = undefined; - this.devices = undefined; - this.moving = false; - fireEvent(this, "dialog-closed", { dialog: this.localName }); - } - - protected render() { - if (!this.dialogParams) { - return nothing; - } - return html` - - ${this.moving - ? html` -

- ${this.dialogParams.supervisor.localize( - "dialog.datadisk_move.moving_desc" - )} -

` - : html` ${this.devices?.length - ? html` - ${this.dialogParams.supervisor.localize( - "dialog.datadisk_move.description", - { - current_path: this.dialogParams.supervisor.os.data_disk, - time: calculateMoveTime(this.dialogParams.supervisor), - } - )} -

- - - ${this.devices.map( - (device) => - html`${device}` - )} - - ` - : this.devices === undefined - ? this.dialogParams.supervisor.localize( - "dialog.datadisk_move.loading_devices" - ) - : this.dialogParams.supervisor.localize( - "dialog.datadisk_move.no_devices" - )} - - - ${this.dialogParams.supervisor.localize( - "dialog.datadisk_move.cancel" - )} - - - - ${this.dialogParams.supervisor.localize( - "dialog.datadisk_move.move" - )} - `} -
- `; - } - - private _selectDevice(ev) { - this.selectedDevice = ev.target.value; - } - - private async _moveDatadisk() { - this.moving = true; - try { - await moveDatadisk(this.hass, this.selectedDevice!); - } catch (err: any) { - if (this.hass.connection.connected && !ignoreSupervisorError(err)) { - showAlertDialog(this, { - title: this.dialogParams!.supervisor.localize( - "system.host.failed_to_move" - ), - text: extractApiErrorMessage(err), - }); - this.closeDialog(); - } - } - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - haStyleDialog, - css` - ha-select { - width: 100%; - } - ha-spinner { - display: block; - margin: 32px; - text-align: center; - } - - .progress-text { - text-align: center; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-datadisk": HassioDatadiskDialog; - } -} diff --git a/hassio/src/dialogs/datadisk/show-dialog-hassio-datadisk.ts b/hassio/src/dialogs/datadisk/show-dialog-hassio-datadisk.ts deleted file mode 100644 index bef5dd64c8..0000000000 --- a/hassio/src/dialogs/datadisk/show-dialog-hassio-datadisk.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; - -export interface HassioDatatiskDialogParams { - supervisor: Supervisor; -} - -export const showHassioDatadiskDialog = ( - element: HTMLElement, - dialogParams: HassioDatatiskDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-datadisk", - dialogImport: () => import("./dialog-hassio-datadisk"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/hardware/dialog-hassio-hardware.ts b/hassio/src/dialogs/hardware/dialog-hassio-hardware.ts deleted file mode 100644 index 440a6c44c1..0000000000 --- a/hassio/src/dialogs/hardware/dialog-hassio-hardware.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { mdiClose } from "@mdi/js"; -import { dump } from "js-yaml"; -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import { stringCompare } from "../../../../src/common/string/compare"; -import "../../../../src/components/ha-dialog"; -import "../../../../src/components/ha-expansion-panel"; -import "../../../../src/components/ha-icon-button"; -import "../../../../src/components/search-input"; -import type { HassioHardwareInfo } from "../../../../src/data/hassio/hardware"; -import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import type { HassioHardwareDialogParams } from "./show-dialog-hassio-hardware"; - -const _filterDevices = memoizeOne( - (hardware: HassioHardwareInfo, filter: string, language: string) => - hardware.devices - .filter( - (device) => - device.by_id?.toLowerCase().includes(filter) || - device.name.toLowerCase().includes(filter) || - device.dev_path.toLocaleLowerCase().includes(filter) || - JSON.stringify(device.attributes).toLocaleLowerCase().includes(filter) - ) - .sort((a, b) => stringCompare(a.name, b.name, language)) -); - -@customElement("dialog-hassio-hardware") -class HassioHardwareDialog extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @state() private _dialogParams?: HassioHardwareDialogParams; - - @state() private _filter?: string; - - public showDialog(dialogParams: HassioHardwareDialogParams) { - this._dialogParams = dialogParams; - } - - public closeDialog() { - this._dialogParams = undefined; - fireEvent(this, "dialog-closed", { dialog: this.localName }); - } - - protected render() { - if (!this._dialogParams) { - return nothing; - } - - const devices = _filterDevices( - this._dialogParams.hardware, - (this._filter || "").toLowerCase(), - this.hass.locale.language - ); - - return html` - -
-

- ${this._dialogParams.supervisor.localize("dialog.hardware.title")} -

- - - -
- - ${devices.map( - (device) => - html` -
- - ${this._dialogParams!.supervisor.localize( - "dialog.hardware.subsystem" - )}: - - ${device.subsystem} -
-
- - ${this._dialogParams!.supervisor.localize( - "dialog.hardware.device_path" - )}: - - ${device.dev_path} -
- ${device.by_id - ? html`
- - ${this._dialogParams!.supervisor.localize( - "dialog.hardware.id" - )}: - - ${device.by_id} -
` - : ""} -
- - ${this._dialogParams!.supervisor.localize( - "dialog.hardware.attributes" - )}: - -
${dump(device.attributes, { indent: 2 })}
-
-
` - )} -
- `; - } - - private _handleSearchChange(ev: CustomEvent) { - this._filter = ev.detail.value; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - haStyleDialog, - css` - ha-icon-button { - position: absolute; - right: 16px; - inset-inline-end: 16px; - inset-inline-start: initial; - top: 10px; - text-decoration: none; - color: var(--primary-text-color); - } - h2 { - margin: 18px 42px 0 18px; - margin-inline-start: 18px; - margin-inline-end: 42px; - color: var(--primary-text-color); - } - - ha-expansion-panel { - margin: 4px 0; - } - pre, - code { - background-color: var(--markdown-code-background-color, none); - border-radius: var(--ha-border-radius-sm); - } - pre { - padding: 16px; - overflow: auto; - line-height: 1.45; - font-family: var(--ha-font-family-code); - } - code { - font-size: var(--ha-font-size-s); - padding: 0.2em 0.4em; - } - search-input { - margin: 8px 16px 0; - display: block; - } - .device-property { - display: flex; - justify-content: space-between; - } - .attributes { - margin-top: 12px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-hardware": HassioHardwareDialog; - } -} diff --git a/hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts b/hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts deleted file mode 100644 index b43410bb65..0000000000 --- a/hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import type { HassioHardwareInfo } from "../../../../src/data/hassio/hardware"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; - -export interface HassioHardwareDialogParams { - supervisor: Supervisor; - hardware: HassioHardwareInfo; -} - -export const showHassioHardwareDialog = ( - element: HTMLElement, - dialogParams: HassioHardwareDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-hardware", - dialogImport: () => import("./dialog-hassio-hardware"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts b/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts deleted file mode 100644 index 740ee1dcfc..0000000000 --- a/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { createCloseHeading } from "../../../../src/components/ha-dialog"; -import "../../../../src/components/ha-markdown"; -import { haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import { hassioStyle } from "../../resources/hassio-style"; -import type { HassioMarkdownDialogParams } from "./show-dialog-hassio-markdown"; - -@customElement("dialog-hassio-markdown") -class HassioMarkdownDialog extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - // eslint-disable-next-line lit/no-native-attributes - @property() public title!: string; - - @property() public content!: string; - - @state() private _opened = false; - - public showDialog(params: HassioMarkdownDialogParams) { - this.title = params.title; - this.content = params.content; - this._opened = true; - } - - public closeDialog() { - this._opened = false; - } - - protected render() { - if (!this._opened) { - return nothing; - } - return html` - - - - `; - } - - static get styles(): CSSResultGroup { - return [ - haStyleDialog, - hassioStyle, - css` - @media all and (max-width: 450px), all and (max-height: 500px) { - ha-markdown { - padding: 16px; - } - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-markdown": HassioMarkdownDialog; - } -} diff --git a/hassio/src/dialogs/markdown/show-dialog-hassio-markdown.ts b/hassio/src/dialogs/markdown/show-dialog-hassio-markdown.ts deleted file mode 100644 index 0d758a54af..0000000000 --- a/hassio/src/dialogs/markdown/show-dialog-hassio-markdown.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; - -export interface HassioMarkdownDialogParams { - title: string; - content: string; -} - -export const showHassioMarkdownDialog = ( - element: HTMLElement, - dialogParams: HassioMarkdownDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-markdown", - dialogImport: () => import("./dialog-hassio-markdown"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/network/dialog-hassio-network.ts b/hassio/src/dialogs/network/dialog-hassio-network.ts deleted file mode 100644 index a0797018dc..0000000000 --- a/hassio/src/dialogs/network/dialog-hassio-network.ts +++ /dev/null @@ -1,647 +0,0 @@ -import { mdiClose } from "@mdi/js"; -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { cache } from "lit/directives/cache"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-button"; -import "../../../../src/components/ha-dialog"; -import "../../../../src/components/ha-expansion-panel"; -import "../../../../src/components/ha-formfield"; -import "../../../../src/components/ha-header-bar"; -import "../../../../src/components/ha-icon-button"; -import "../../../../src/components/ha-list"; -import "../../../../src/components/ha-list-item"; -import "../../../../src/components/ha-password-field"; -import "../../../../src/components/ha-radio"; -import "../../../../src/components/ha-tab-group"; -import "../../../../src/components/ha-tab-group-tab"; -import "../../../../src/components/ha-textfield"; -import type { HaTextField } from "../../../../src/components/ha-textfield"; -import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import type { - AccessPoints, - NetworkInterface, - WifiConfiguration, -} from "../../../../src/data/hassio/network"; -import { - accesspointScan, - updateNetworkInterface, -} from "../../../../src/data/hassio/network"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { - showAlertDialog, - showConfirmationDialog, -} from "../../../../src/dialogs/generic/show-dialog-box"; -import type { HassDialog } from "../../../../src/dialogs/make-dialog-manager"; -import { haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import type { HassioNetworkDialogParams } from "./show-dialog-network"; - -const IP_VERSIONS = ["ipv4", "ipv6"]; - -@customElement("dialog-hassio-network") -export class DialogHassioNetwork - extends LitElement - implements HassDialog -{ - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @state() private _accessPoints?: AccessPoints; - - @state() private _curTabIndex = 0; - - @state() private _dirty = false; - - @state() private _interface?: NetworkInterface; - - @state() private _interfaces!: NetworkInterface[]; - - @state() private _params?: HassioNetworkDialogParams; - - @state() private _processing = false; - - @state() private _scanning = false; - - @state() private _wifiConfiguration?: WifiConfiguration; - - public async showDialog(params: HassioNetworkDialogParams): Promise { - this._params = params; - this._dirty = false; - this._curTabIndex = 0; - this.supervisor = params.supervisor; - this._interfaces = params.supervisor.network.interfaces.sort((a, b) => - a.primary > b.primary ? -1 : 1 - ); - this._interface = { ...this._interfaces[this._curTabIndex] }; - - await this.updateComplete; - } - - public closeDialog() { - this._params = undefined; - this._processing = false; - fireEvent(this, "dialog-closed", { dialog: this.localName }); - return true; - } - - protected render() { - if (!this._params || !this._interface) { - return nothing; - } - - return html` - -
- - - ${this.supervisor.localize("dialog.network.title")} - - - - ${this._interfaces.length > 1 - ? html`${this._interfaces.map( - (device, index) => - html` - ${device.interface} - ` - )} - ` - : ""} -
- ${cache(this._renderTab())} -
- `; - } - - private _renderTab() { - return html`
- ${IP_VERSIONS.map((version) => - this._interface![version] ? this._renderIPConfiguration(version) : "" - )} - ${this._interface?.type === "wireless" - ? html` - - ${this._interface?.wifi?.ssid - ? html`

- ${this.supervisor.localize( - "dialog.network.connected_to", - { ssid: this._interface?.wifi?.ssid } - )} -

` - : ""} - - ${this.supervisor.localize("dialog.network.scan_ap")} - - ${this._accessPoints && - this._accessPoints.accesspoints && - this._accessPoints.accesspoints.length !== 0 - ? html` - - ${this._accessPoints.accesspoints - .filter((ap) => ap.ssid) - .map( - (ap) => html` - - ${ap.ssid} - - ${ap.mac} - - ${this.supervisor.localize( - "dialog.network.signal_strength" - )}: - ${ap.signal} - - - ` - )} - - ` - : ""} - ${this._wifiConfiguration - ? html` -
- - - - - - - - - - - - -
- ${this._wifiConfiguration.auth === "wpa-psk" || - this._wifiConfiguration.auth === "wep" - ? html` - - - ` - : ""} - ` - : ""} -
- ` - : ""} - ${this._dirty - ? html` - ${this.supervisor.localize("dialog.network.warning")} - ` - : ""} -
-
- - ${this.supervisor.localize("common.cancel")} - - - ${this.supervisor.localize("common.save")} - -
`; - } - - private _selectAP(event) { - this._wifiConfiguration = event.currentTarget.ap; - this._dirty = true; - } - - private async _scanForAP() { - if (!this._interface) { - return; - } - this._scanning = true; - try { - this._accessPoints = await accesspointScan( - this.hass, - this._interface.interface - ); - } catch (err: any) { - showAlertDialog(this, { - title: "Failed to scan for accesspoints", - text: extractApiErrorMessage(err), - }); - } finally { - this._scanning = false; - } - } - - private _renderIPConfiguration(version: string) { - return html` - -
- - - - - - - - - - - - -
- ${this._interface![version].method === "static" - ? html` - - - - - - - ` - : ""} -
- `; - } - - private _toArray(data: string | string[]): string[] { - if (Array.isArray(data)) { - if (data && typeof data[0] === "string") { - data = data[0]; - } - } - if (!data) { - return []; - } - if (typeof data === "string") { - return data.replace(/ /g, "").split(","); - } - return data; - } - - private _toString(data: string | string[]): string { - if (!data) { - return ""; - } - if (Array.isArray(data)) { - return data.join(", "); - } - return data; - } - - private async _updateNetwork() { - this._processing = true; - let interfaceOptions: Partial = {}; - - IP_VERSIONS.forEach((version) => { - interfaceOptions[version] = { - method: this._interface![version]?.method || "auto", - }; - if (this._interface![version]?.method === "static") { - interfaceOptions[version] = { - ...interfaceOptions[version], - address: this._toArray(this._interface![version]?.address), - gateway: this._interface![version]?.gateway, - nameservers: this._toArray(this._interface![version]?.nameservers), - }; - } - }); - - if (this._wifiConfiguration) { - interfaceOptions = { - ...interfaceOptions, - wifi: { - ssid: this._wifiConfiguration.ssid, - mode: this._wifiConfiguration.mode, - auth: this._wifiConfiguration.auth || "open", - }, - }; - if (interfaceOptions.wifi!.auth !== "open") { - interfaceOptions.wifi = { - ...interfaceOptions.wifi, - psk: this._wifiConfiguration.psk, - }; - } - } - - interfaceOptions.enabled = - this._wifiConfiguration !== undefined || - interfaceOptions.ipv4?.method !== "disabled" || - interfaceOptions.ipv6?.method !== "disabled"; - - try { - await updateNetworkInterface( - this.hass, - this._interface!.interface, - interfaceOptions - ); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("dialog.network.failed_to_change"), - text: extractApiErrorMessage(err), - }); - this._processing = false; - return; - } - this._params?.loadData(); - this.closeDialog(); - } - - private async _handleTabActivated(ev: CustomEvent): Promise { - if (this._dirty) { - const confirm = await showConfirmationDialog(this, { - text: this.supervisor.localize("dialog.network.unsaved"), - confirmText: this.supervisor.localize("common.yes"), - dismissText: this.supervisor.localize("common.no"), - }); - if (!confirm) { - this.requestUpdate("_interface"); - return; - } - } - this._curTabIndex = Number(ev.detail.name); - this._interface = { ...this._interfaces[this._curTabIndex] }; - } - - private _handleRadioValueChanged(ev: CustomEvent): void { - const value = (ev.target as any).value as "disabled" | "auto" | "static"; - const version = (ev.target as any).version as "ipv4" | "ipv6"; - - if ( - !value || - !this._interface || - this._interface[version]!.method === value - ) { - return; - } - this._dirty = true; - - this._interface[version]!.method = value; - this.requestUpdate("_interface"); - } - - private _handleRadioValueChangedAp(ev: CustomEvent): void { - const value = (ev.target as any).value as string as - | "open" - | "wep" - | "wpa-psk"; - this._wifiConfiguration!.auth = value; - this._dirty = true; - this.requestUpdate("_wifiConfiguration"); - } - - private _handleInputValueChanged(ev: Event): void { - const source = ev.target as HaTextField; - const value = source.value; - const version = (ev.target as any).version as "ipv4" | "ipv6"; - const id = source.id; - - if ( - !value || - !this._interface || - this._toString(this._interface[version]![id]) === this._toString(value) - ) { - return; - } - - this._dirty = true; - this._interface[version]![id] = value; - } - - private _handleInputValueChangedWifi(ev: Event): void { - const source = ev.target as HaTextField; - const value = source.value; - const id = source.id; - - if ( - !value || - !this._wifiConfiguration || - this._wifiConfiguration![id] === value - ) { - return; - } - this._dirty = true; - this._wifiConfiguration![id] = value; - } - - static get styles(): CSSResultGroup { - return [ - haStyleDialog, - css` - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - flex-shrink: 0; - } - - ha-dialog { - --dialog-content-position: static; - --dialog-content-padding: 0; - --dialog-z-index: 6; - } - - @media all and (min-width: 451px) and (min-height: 501px) { - .container { - width: 400px; - } - } - - .content { - display: block; - padding: 20px 24px; - } - - /* overrule the ha-style-dialog max-height on small screens */ - @media all and (max-width: 450px), all and (max-height: 500px) { - ha-header-bar { - --mdc-theme-primary: var(--app-header-background-color); - --mdc-theme-on-primary: var(--app-header-text-color, white); - } - } - - ha-button.scan { - margin-left: 8px; - margin-inline-start: 8px; - margin-inline-end: initial; - } - - .container { - padding: 0 8px 4px; - } - .form { - margin-bottom: 53px; - } - .buttons { - position: absolute; - bottom: 0; - width: 100%; - box-sizing: border-box; - border-top: 1px solid - var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12)); - display: flex; - justify-content: space-between; - padding: 16px; - padding-bottom: max(var(--safe-area-inset-bottom), 16px); - background-color: var(--mdc-theme-surface, #fff); - } - .warning { - color: var(--error-color); - --primary-color: var(--error-color); - } - div.warning { - margin: 12px 4px -12px; - } - - ha-expansion-panel { - --expansion-panel-summary-padding: 0 16px; - margin: 4px 0; - } - ha-textfield { - padding: 0 14px; - } - ha-list-item { - --mdc-list-side-padding: 10px; - } - - ha-tab-group-tab { - flex: 1; - } - ha-tab-group-tab::part(base) { - width: 100%; - justify-content: center; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-network": DialogHassioNetwork; - } -} diff --git a/hassio/src/dialogs/network/show-dialog-network.ts b/hassio/src/dialogs/network/show-dialog-network.ts deleted file mode 100644 index 507b4938d3..0000000000 --- a/hassio/src/dialogs/network/show-dialog-network.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import "./dialog-hassio-network"; - -export interface HassioNetworkDialogParams { - supervisor: Supervisor; - loadData: () => Promise; -} - -export const showNetworkDialog = ( - element: HTMLElement, - dialogParams: HassioNetworkDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-network", - dialogImport: () => import("./dialog-hassio-network"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/registries/dialog-hassio-registries.ts b/hassio/src/dialogs/registries/dialog-hassio-registries.ts deleted file mode 100644 index b5e4225d20..0000000000 --- a/hassio/src/dialogs/registries/dialog-hassio-registries.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { mdiDelete, mdiPlus } from "@mdi/js"; -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import "../../../../src/components/ha-button"; -import { createCloseHeading } from "../../../../src/components/ha-dialog"; -import "../../../../src/components/ha-form/ha-form"; -import type { SchemaUnion } from "../../../../src/components/ha-form/types"; -import "../../../../src/components/ha-icon-button"; -import "../../../../src/components/ha-settings-row"; -import "../../../../src/components/ha-svg-icon"; -import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import { - addHassioDockerRegistry, - fetchHassioDockerRegistries, - removeHassioDockerRegistry, -} from "../../../../src/data/hassio/docker"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box"; -import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import type { RegistriesDialogParams } from "./show-dialog-registries"; - -const SCHEMA = [ - { - name: "registry", - required: true, - selector: { text: {} }, - }, - { - name: "username", - required: true, - selector: { text: {} }, - }, - { - name: "password", - required: true, - selector: { text: { type: "password" } }, - }, -] as const; - -@customElement("dialog-hassio-registries") -class HassioRegistriesDialog extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @state() private _registries?: { - registry: string; - username: string; - }[]; - - @state() private _input: { - registry?: string; - username?: string; - password?: string; - } = {}; - - @state() private _opened = false; - - @state() private _addingRegistry = false; - - protected render(): TemplateResult { - return html` - - ${this._addingRegistry - ? html` - -
- - - ${this.supervisor.localize("dialog.registries.add_registry")} - -
- ` - : html`${this._registries?.length - ? this._registries.map( - (entry) => html` - - ${entry.registry} - - ${this.supervisor.localize( - "dialog.registries.username" - )}: - ${entry.username} - - - - ` - ) - : html` - - ${this.supervisor.localize( - "dialog.registries.no_registries" - )} - - `} -
- - - ${this.supervisor.localize( - "dialog.registries.add_new_registry" - )} - -
`} -
- `; - } - - private _computeLabel = (schema: SchemaUnion) => - this.supervisor.localize(`dialog.registries.${schema.name}`); - - private _valueChanged(ev: CustomEvent) { - this._input = ev.detail.value; - } - - public async showDialog(dialogParams: RegistriesDialogParams): Promise { - this._opened = true; - this._input = {}; - this.supervisor = dialogParams.supervisor; - await this._loadRegistries(); - await this.updateComplete; - } - - public closeDialog(): void { - this._addingRegistry = false; - this._opened = false; - this._input = {}; - } - - public focus(): void { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() - ); - } - - private async _loadRegistries(): Promise { - const registries = await fetchHassioDockerRegistries(this.hass); - this._registries = Object.keys(registries!.registries).map((key) => ({ - registry: key, - username: registries.registries[key].username, - })); - } - - private _addRegistry(): void { - this._addingRegistry = true; - } - - private async _addNewRegistry(): Promise { - const data = {}; - data[this._input.registry!] = { - username: this._input.username, - password: this._input.password, - }; - - try { - await addHassioDockerRegistry(this.hass, data); - await this._loadRegistries(); - this._addingRegistry = false; - this._input = {}; - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("dialog.registries.failed_to_add"), - text: extractApiErrorMessage(err), - }); - } - } - - private async _removeRegistry(ev: Event): Promise { - const entry = (ev.currentTarget as any).entry; - - try { - await removeHassioDockerRegistry(this.hass, entry.registry); - await this._loadRegistries(); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("dialog.registries.failed_to_remove"), - text: extractApiErrorMessage(err), - }); - } - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - haStyleDialog, - css` - .registry { - border: 1px solid var(--divider-color); - border-radius: var(--ha-border-radius-sm); - margin-top: 4px; - } - .action { - margin-top: 24px; - width: 100%; - display: flex; - justify-content: flex-end; - } - ha-icon-button { - color: var(--error-color); - margin-right: -10px; - margin-inline-end: -10px; - margin-inline-start: initial; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-registries": HassioRegistriesDialog; - } -} diff --git a/hassio/src/dialogs/registries/show-dialog-registries.ts b/hassio/src/dialogs/registries/show-dialog-registries.ts deleted file mode 100644 index 0ca9bf67dc..0000000000 --- a/hassio/src/dialogs/registries/show-dialog-registries.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import "./dialog-hassio-registries"; - -export interface RegistriesDialogParams { - supervisor: Supervisor; -} - -export const showRegistriesDialog = ( - element: HTMLElement, - dialogParams: RegistriesDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-registries", - dialogImport: () => import("./dialog-hassio-registries"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts b/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts deleted file mode 100644 index 5be1c9d269..0000000000 --- a/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts +++ /dev/null @@ -1,278 +0,0 @@ -import { mdiDelete, mdiDeleteOff, mdiPlus } from "@mdi/js"; -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import { caseInsensitiveStringCompare } from "../../../../src/common/string/compare"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-button"; -import { createCloseHeading } from "../../../../src/components/ha-dialog"; -import "../../../../src/components/ha-icon-button"; -import "../../../../src/components/ha-md-list"; -import "../../../../src/components/ha-md-list-item"; -import "../../../../src/components/ha-svg-icon"; -import "../../../../src/components/ha-textfield"; -import type { HaTextField } from "../../../../src/components/ha-textfield"; -import "../../../../src/components/ha-tooltip"; -import type { - HassioAddonInfo, - HassioAddonRepository, -} from "../../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; -import { - addStoreRepository, - fetchStoreRepositories, - removeStoreRepository, -} from "../../../../src/data/supervisor/store"; -import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import type { HassioRepositoryDialogParams } from "./show-dialog-repositories"; - -@customElement("dialog-hassio-repositories") -class HassioRepositoriesDialog extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @query("#repository_input", true) private _optionInput?: HaTextField; - - @state() private _repositories?: HassioAddonRepository[]; - - @state() private _dialogParams?: HassioRepositoryDialogParams; - - @state() private _opened = false; - - @state() private _processing = false; - - @state() private _error?: string; - - public async showDialog( - dialogParams: HassioRepositoryDialogParams - ): Promise { - this._dialogParams = dialogParams; - this._opened = true; - await this._loadData(); - await this.updateComplete; - } - - public closeDialog(): void { - this._dialogParams = undefined; - this._opened = false; - this._error = ""; - } - - private _filteredRepositories = memoizeOne((repos: HassioAddonRepository[]) => - repos - .filter( - (repo) => - repo.slug !== "core" && // The core apps repository - repo.slug !== "local" && // Locally managed apps - repo.slug !== "a0d7b954" && // Home Assistant Community Apps - repo.slug !== "5c53de3b" && // The ESPHome repository - repo.slug !== "d5369777" // Music Assistant repository - ) - .sort((a, b) => - caseInsensitiveStringCompare(a.name, b.name, this.hass.locale.language) - ) - ); - - private _filteredUsedRepositories = memoizeOne( - (repos: HassioAddonRepository[], addons: HassioAddonInfo[]) => - repos - .filter((repo) => - addons.some((addon) => addon.repository === repo.slug) - ) - .map((repo) => repo.slug) - ); - - protected render() { - if (!this._dialogParams?.supervisor || this._repositories === undefined) { - return nothing; - } - const repositories = this._filteredRepositories(this._repositories); - const usedRepositories = this._filteredUsedRepositories( - repositories, - this._dialogParams.supervisor.addon.addons - ); - return html` - - ${this._error - ? html`${this._error}` - : ""} -
- - ${repositories.length - ? repositories.map( - (repo) => html` - - ${repo.name} -
-
${repo.maintainer}
-
${repo.url}
-
- - ${this._dialogParams!.supervisor.localize( - usedRepositories.includes(repo.slug) - ? "dialog.repositories.used" - : "dialog.repositories.remove" - )} - -
- - -
-
- ` - ) - : html`${this._dialogParams!.supervisor.localize( - "dialog.repositories.no_repositories" - )}`} -
-
- - - - ${this._dialogParams!.supervisor.localize( - "dialog.repositories.add" - )} - -
-
- - ${this._dialogParams?.supervisor.localize("common.close")} - -
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - haStyleDialog, - css` - ha-dialog.button-left { - --justify-action-buttons: flex-start; - } - .form { - color: var(--primary-text-color); - } - .option { - border: 1px solid var(--divider-color); - border-radius: var(--ha-border-radius-sm); - margin-top: 4px; - } - ha-button { - margin-left: 8px; - margin-inline-start: 8px; - margin-inline-end: initial; - } - div.delete ha-icon-button { - color: var(--error-color); - } - ha-md-list-item { - position: relative; - --md-item-overflow: visible; - } - `, - ]; - } - - public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() - ); - } - - private _handleKeyAdd(ev: KeyboardEvent) { - ev.stopPropagation(); - if (ev.key !== "Enter") { - return; - } - this._addRepository(); - } - - private async _loadData(): Promise { - try { - this._repositories = await fetchStoreRepositories(this.hass); - - fireEvent(this, "supervisor-collection-refresh", { collection: "addon" }); - } catch (err: any) { - this._error = extractApiErrorMessage(err); - } - } - - private async _addRepository() { - const input = this._optionInput; - if (!input || !input.value) { - return; - } - this._processing = true; - - try { - await addStoreRepository(this.hass, input.value); - await this._loadData(); - - fireEvent(this, "supervisor-collection-refresh", { collection: "store" }); - - input.value = ""; - } catch (err: any) { - this._error = extractApiErrorMessage(err); - } - this._processing = false; - } - - private async _removeRepository(ev: Event) { - const slug = (ev.currentTarget as any).slug; - try { - await removeStoreRepository(this.hass, slug); - await this._loadData(); - - fireEvent(this, "supervisor-collection-refresh", { collection: "store" }); - } catch (err: any) { - this._error = extractApiErrorMessage(err); - } - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-hassio-repositories": HassioRepositoriesDialog; - } -} diff --git a/hassio/src/dialogs/repositories/show-dialog-repositories.ts b/hassio/src/dialogs/repositories/show-dialog-repositories.ts deleted file mode 100644 index 1b540c883c..0000000000 --- a/hassio/src/dialogs/repositories/show-dialog-repositories.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import "./dialog-hassio-repositories"; - -export interface HassioRepositoryDialogParams { - supervisor: Supervisor; - url?: string; -} - -export const showRepositoriesDialog = ( - element: HTMLElement, - dialogParams: HassioRepositoryDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-hassio-repositories", - dialogImport: () => import("./dialog-hassio-repositories"), - dialogParams, - }); -}; diff --git a/hassio/src/dialogs/suggestAddonRestart.ts b/hassio/src/dialogs/suggestAddonRestart.ts deleted file mode 100644 index 60b469b447..0000000000 --- a/hassio/src/dialogs/suggestAddonRestart.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { LitElement } from "lit"; -import type { HassioAddonDetails } from "../../../src/data/hassio/addon"; -import { restartHassioAddon } from "../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { - showAlertDialog, - showConfirmationDialog, -} from "../../../src/dialogs/generic/show-dialog-box"; -import type { HomeAssistant } from "../../../src/types"; - -export const suggestAddonRestart = async ( - element: LitElement, - hass: HomeAssistant, - supervisor: Supervisor, - addon: HassioAddonDetails -): Promise => { - const confirmed = await showConfirmationDialog(element, { - title: supervisor.localize("dialog.restart_app.title", { - name: addon.name, - }), - text: supervisor.localize("dialog.restart_app.text"), - confirmText: supervisor.localize("dialog.restart_app.restart"), - dismissText: supervisor.localize("common.cancel"), - }); - if (confirmed) { - try { - await restartHassioAddon(hass, addon.slug); - } catch (err: any) { - showAlertDialog(element, { - title: supervisor.localize("common.failed_to_restart_name", { - name: addon.name, - }), - text: extractApiErrorMessage(err), - }); - } - } -}; diff --git a/hassio/src/dialogs/system-managed/dialog-system-managed.ts b/hassio/src/dialogs/system-managed/dialog-system-managed.ts deleted file mode 100644 index d8cf7c53fd..0000000000 --- a/hassio/src/dialogs/system-managed/dialog-system-managed.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { mdiClose, mdiPuzzle, mdiSwapHorizontal } from "@mdi/js"; -import type { CSSResultGroup } from "lit"; -import { css, html, LitElement, nothing } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; -import { atLeastVersion } from "../../../../src/common/config/version"; -import "../../../../src/components/ha-dialog-header"; -import "../../../../src/components/ha-icon-button"; -import "../../../../src/components/ha-icon-next"; -import "../../../../src/components/ha-md-dialog"; -import type { HaMdDialog } from "../../../../src/components/ha-md-dialog"; -import "../../../../src/components/ha-md-list"; -import "../../../../src/components/ha-md-list-item"; -import "../../../../src/components/ha-svg-icon"; -import { - getConfigEntry, - type ConfigEntry, -} from "../../../../src/data/config_entries"; -import type { HassioAddonDetails } from "../../../../src/data/hassio/addon"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; -import { mdiHomeAssistant } from "../../../../src/resources/home-assistant-logo-svg"; -import { haStyle } from "../../../../src/resources/styles"; -import type { HomeAssistant } from "../../../../src/types"; -import { brandsUrl } from "../../../../src/util/brands-url"; -import type { SystemManagedDialogParams } from "./show-dialog-system-managed"; - -@customElement("dialog-system-managed") -class HassioSystemManagedDialog extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @state() private _supervisor?: Supervisor; - - @state() private _addon?: HassioAddonDetails; - - @state() private _open = false; - - @state() private _configEntry?: ConfigEntry; - - @query("ha-md-dialog") private _dialog?: HaMdDialog; - - public async showDialog( - dialogParams: SystemManagedDialogParams - ): Promise { - this._addon = dialogParams.addon; - this._supervisor = dialogParams.supervisor; - this._open = true; - this._loadConfigEntry(); - } - - private _dialogClosed() { - this._addon = undefined; - this._supervisor = undefined; - this._configEntry = undefined; - this._open = false; - } - - public closeDialog() { - this._dialog?.close(); - return true; - } - - protected render() { - if (!this._addon || !this._open || !this._supervisor) { - return nothing; - } - - const addonImage = - atLeastVersion(this.hass.config.version, 0, 105) && this._addon.icon - ? `/api/hassio/addons/${this._addon.slug}/icon` - : undefined; - - return html` - - - - ${this._addon?.name} - -
-
- - - ${addonImage - ? html`${this._addon.name}` - : html``} -
- ${this._supervisor.localize("app.system_managed.title")}.
- ${this._supervisor.localize("app.system_managed.description")} - ${this._configEntry - ? html` -

- ${this._supervisor.localize("app.system_managed.managed_by")}: -

- - - ${this._configEntry.title} - ${this._configEntry.title} - - - - ` - : nothing} -
-
- `; - } - - private _onImageLoad(ev) { - ev.target.style.visibility = "initial"; - } - - private _onImageError(ev) { - ev.target.style.visibility = "hidden"; - } - - private async _loadConfigEntry() { - if (this._addon?.system_managed_config_entry) { - try { - const { config_entry } = await getConfigEntry( - this.hass, - this._addon.system_managed_config_entry - ); - this._configEntry = config_entry; - } catch (err) { - // eslint-disable-next-line no-console - console.error(err); - } - } - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - css` - .icons { - display: flex; - justify-content: center; - align-items: center; - gap: var(--ha-space-4); - --mdc-icon-size: 48px; - margin-bottom: 32px; - } - .icons img { - width: 48px; - } - .icons .primary { - color: var(--primary-color); - } - .actions { - display: flex; - justify-content: space-between; - } - .integration-icon { - width: 24px; - } - ha-md-list-item { - --md-list-item-leading-space: 4px; - --md-list-item-trailing-space: 4px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-system-managed": HassioSystemManagedDialog; - } -} diff --git a/hassio/src/dialogs/system-managed/show-dialog-system-managed.ts b/hassio/src/dialogs/system-managed/show-dialog-system-managed.ts deleted file mode 100644 index 3e198d4afb..0000000000 --- a/hassio/src/dialogs/system-managed/show-dialog-system-managed.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { fireEvent } from "../../../../src/common/dom/fire_event"; -import type { HassioAddonDetails } from "../../../../src/data/hassio/addon"; -import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; - -export interface SystemManagedDialogParams { - addon: HassioAddonDetails; - supervisor: Supervisor; -} - -export const showSystemManagedDialog = ( - element: HTMLElement, - dialogParams: SystemManagedDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-system-managed", - dialogImport: () => import("./dialog-system-managed"), - dialogParams, - }); -}; diff --git a/hassio/src/entrypoint.js.template b/hassio/src/entrypoint.js.template deleted file mode 100644 index db0cf25251..0000000000 --- a/hassio/src/entrypoint.js.template +++ /dev/null @@ -1,23 +0,0 @@ -(function () { - function loadES5(src) { - var el = document.createElement("script"); - el.src = src; - document.body.appendChild(el); - } - if (<%= modernRegex %>.test(navigator.userAgent)) { - try { - <% for (const entry of latestEntryJS) { %> - new Function("import('<%= entry %>')")(); - <% } %> - } catch (err) { - <% for (const entry of es5EntryJS) { %> - loadES5("<%= entry %>"); - <% } %> - } - } else { - <% for (const entry of es5EntryJS) { %> - loadES5("<%= entry %>"); - <% } %> - } -})(); - \ No newline at end of file diff --git a/hassio/src/entrypoint.ts b/hassio/src/entrypoint.ts deleted file mode 100644 index 73fa378323..0000000000 --- a/hassio/src/entrypoint.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - haFontFamilyBody, - haFontSmoothing, - haMozOsxFontSmoothing, -} from "../../src/resources/theme/typography.globals"; -import "./hassio-main"; - -import("../../src/resources/append-ha-style"); - -const styleEl = document.createElement("style"); -styleEl.textContent = ` -body { - font-family: ${haFontFamilyBody}; - -moz-osx-font-smoothing: ${haMozOsxFontSmoothing}; - -webkit-font-smoothing: ${haFontSmoothing}; - font-weight: var(--ha-font-weight-normal); - margin: 0; - padding: 0; - height: 100vh; -} -@media (prefers-color-scheme: dark) { - body { - background-color: #111111; - color: #e1e1e1; - } -} -`; -document.head.appendChild(styleEl); diff --git a/hassio/src/hassio-main.ts b/hassio/src/hassio-main.ts deleted file mode 100644 index 7afbf5d333..0000000000 --- a/hassio/src/hassio-main.ts +++ /dev/null @@ -1,146 +0,0 @@ -import type { PropertyValues } from "lit"; -import { html } from "lit"; -import { customElement, property } from "lit/decorators"; -import { atLeastVersion } from "../../src/common/config/version"; -import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element"; -import { fireEvent } from "../../src/common/dom/fire_event"; -import { mainWindow } from "../../src/common/dom/get_main_window"; -import { isNavigationClick } from "../../src/common/dom/is-navigation-click"; -import { navigate } from "../../src/common/navigate"; -import type { HassioPanelInfo } from "../../src/data/hassio/supervisor"; -import type { Supervisor } from "../../src/data/supervisor/supervisor"; -import { makeDialogManager } from "../../src/dialogs/make-dialog-manager"; -import type { HomeAssistant } from "../../src/types"; -import "./hassio-router"; -import { SupervisorBaseElement } from "./supervisor-base-element"; - -@customElement("hassio-main") -export class HassioMain extends SupervisorBaseElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public panel!: HassioPanelInfo; - - @property({ type: Boolean }) public narrow = false; - - protected firstUpdated(changedProps: PropertyValues) { - super.firstUpdated(changedProps); - - this._applyTheme(); - - // Paulus - March 17, 2019 - // We went to a single hass-toggle-menu event in HA 0.90. However, the - // supervisor UI can also run under older versions of Home Assistant. - // So here we are going to translate toggle events into the appropriate - // open and close events. These events are a no-op in newer versions of - // Home Assistant. - this.addEventListener("hass-toggle-menu", () => { - fireEvent( - (window.parent as any).customPanel, - // @ts-ignore - this.hass.dockedSidebar ? "hass-close-menu" : "hass-open-menu" - ); - }); - // Paulus - March 19, 2019 - // We changed the navigate event to fire directly on the window, as that's - // where we are listening for it. However, the older panel_custom will - // listen on this element for navigation events, so we need to forward them. - - // Joakim - April 26, 2021 - // Due to changes in behavior in Google Chrome, we changed navigate to listen on the top element - mainWindow.addEventListener("location-changed", (ev) => - // @ts-ignore - fireEvent(this, ev.type, ev.detail, { - bubbles: false, - }) - ); - - // Paulus - May 17, 2021 - // Convert the tags to native nav in Home Assistant < 2021.6 - document.body.addEventListener("click", (ev) => { - const href = isNavigationClick(ev); - if (href) { - navigate(href); - } - }); - - // Forward haptic events to parent window. - window.addEventListener("haptic", (ev) => { - // @ts-ignore - fireEvent(window.parent, ev.type, ev.detail, { - bubbles: false, - }); - }); - - // Forward keydown events to the main window for quickbar access - document.body.addEventListener("keydown", (ev: KeyboardEvent) => { - if (ev.altKey || ev.ctrlKey || ev.shiftKey || ev.metaKey) { - // Ignore if modifier keys are pressed - return; - } - // @ts-ignore - fireEvent(mainWindow, "hass-quick-bar-trigger", ev, { - bubbles: false, - }); - }); - - makeDialogManager(this, this.shadowRoot!); - } - - protected updated(changedProps: PropertyValues) { - super.updated(changedProps); - const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (!oldHass) { - return; - } - if (oldHass.themes !== this.hass.themes) { - this._applyTheme(); - } - } - - protected render() { - return html` - - `; - } - - private _applyTheme() { - let themeName: string; - let themeSettings: Partial | undefined; - - if (atLeastVersion(this.hass.config.version, 0, 114)) { - themeName = - this.hass.selectedTheme?.theme || - (this.hass.themes.darkMode && this.hass.themes.default_dark_theme - ? this.hass.themes.default_dark_theme! - : this.hass.themes.default_theme); - - themeSettings = this.hass.selectedTheme; - } else { - themeName = - (this.hass.selectedTheme as unknown as string) || - this.hass.themes.default_theme; - } - - applyThemesOnElement( - this.parentElement, - this.hass.themes, - themeName, - themeSettings, - true - ); - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-main": HassioMain; - } -} diff --git a/hassio/src/hassio-my-redirect.ts b/hassio/src/hassio-my-redirect.ts deleted file mode 100644 index 12f311038e..0000000000 --- a/hassio/src/hassio-my-redirect.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { sanitizeUrl } from "@braintree/sanitize-url"; -import type { TemplateResult } from "lit"; -import { html, LitElement, nothing } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { navigate } from "../../src/common/navigate"; -import { - createSearchParam, - extractSearchParamsObject, -} from "../../src/common/url/search-params"; -import type { Supervisor } from "../../src/data/supervisor/supervisor"; -import "../../src/layouts/hass-error-screen"; -import type { - ParamType, - Redirect, - Redirects, -} from "../../src/panels/my/ha-panel-my"; -import type { HomeAssistant, Route } from "../../src/types"; - -export const REDIRECTS: Redirects = { - supervisor: { - redirect: "/hassio/dashboard", - }, - supervisor_logs: { - redirect: "/hassio/system", - }, - supervisor_info: { - redirect: "/hassio/system", - }, - supervisor_snapshots: { - redirect: "/hassio/backups", - }, - supervisor_backups: { - redirect: "/hassio/backups", - }, - supervisor_store: { - redirect: "/hassio/store", - }, - supervisor_addons: { - redirect: "/hassio/dashboard", - }, - supervisor_addon: { - redirect: "/hassio/addon", - params: { - addon: "string", - }, - optional_params: { - repository_url: "url", - }, - }, - supervisor_ingress: { - redirect: "/hassio/ingress", - params: { - addon: "string", - }, - }, - supervisor_add_addon_repository: { - redirect: "/hassio/store", - params: { - repository_url: "url", - }, - }, -}; - -@customElement("hassio-my-redirect") -class HassioMyRedirect extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public route!: Route; - - @state() public _error?: TemplateResult | string; - - connectedCallback() { - super.connectedCallback(); - const path = this.route.path.substr(1); - const redirect = REDIRECTS[path]; - - if (!redirect) { - this._error = this.supervisor.localize("my.not_supported", { - link: html` - ${this.supervisor.localize("my.faq_link")} - `, - }); - return; - } - - let url: string; - try { - url = this._createRedirectUrl(redirect); - } catch (_err: any) { - this._error = this.supervisor.localize("my.error"); - return; - } - - navigate(url, { replace: true }); - } - - protected render() { - if (this._error) { - return html``; - } - return nothing; - } - - private _createRedirectUrl(redirect: Redirect): string { - const params = this._createRedirectParams(redirect); - return `${redirect.redirect}${params}`; - } - - private _createRedirectParams(redirect: Redirect): string { - const params = extractSearchParamsObject(); - if (!redirect.params && !Object.keys(params).length) { - return ""; - } - const resultParams = {}; - Object.entries(redirect.params || {}).forEach(([key, type]) => { - if (!params[key] || !this._checkParamType(type, params[key])) { - throw Error(); - } - resultParams[key] = params[key]; - }); - Object.entries(redirect.optional_params || {}).forEach(([key, type]) => { - if (params[key]) { - if (!this._checkParamType(type, params[key])) { - throw Error(); - } - resultParams[key] = params[key]; - } - }); - return `?${createSearchParam(resultParams)}`; - } - - private _checkParamType(type: ParamType, value: string) { - if (type === "string") { - return true; - } - if (type === "url") { - return value && value === sanitizeUrl(value); - } - return false; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-my-redirect": HassioMyRedirect; - } -} diff --git a/hassio/src/hassio-panel-router.ts b/hassio/src/hassio-panel-router.ts deleted file mode 100644 index 42eff379f5..0000000000 --- a/hassio/src/hassio-panel-router.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { customElement, property } from "lit/decorators"; -import type { Supervisor } from "../../src/data/supervisor/supervisor"; -import type { RouterOptions } from "../../src/layouts/hass-router-page"; -import { HassRouterPage } from "../../src/layouts/hass-router-page"; -import type { HomeAssistant, Route } from "../../src/types"; -// Don't codesplit it, that way the dashboard always loads fast. -import "./dashboard/hassio-dashboard"; - -@customElement("hassio-panel-router") -class HassioPanelRouter extends HassRouterPage { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public route!: Route; - - @property({ type: Boolean }) public narrow = false; - - protected routerOptions: RouterOptions = { - beforeRender: (page: string) => - page === "snapshots" ? "backups" : undefined, - routes: { - dashboard: { - tag: "hassio-dashboard", - }, - store: { - tag: "hassio-addon-store", - load: () => import("./addon-store/hassio-addon-store"), - }, - backups: { - tag: "hassio-backups", - load: () => import("./backups/hassio-backups"), - }, - system: { - tag: "hassio-system", - load: () => import("./system/hassio-system"), - }, - }, - }; - - protected updatePageEl(el) { - el.hass = this.hass; - el.supervisor = this.supervisor; - el.route = this.route; - el.narrow = this.narrow; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-panel-router": HassioPanelRouter; - } -} diff --git a/hassio/src/hassio-panel.ts b/hassio/src/hassio-panel.ts deleted file mode 100644 index c0922f463d..0000000000 --- a/hassio/src/hassio-panel.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import type { Supervisor } from "../../src/data/supervisor/supervisor"; -import { supervisorCollection } from "../../src/data/supervisor/supervisor"; -import "../../src/layouts/hass-loading-screen"; -import type { HomeAssistant, Route } from "../../src/types"; -import "./hassio-panel-router"; - -@customElement("hassio-panel") -class HassioPanel extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public route!: Route; - - protected render(): TemplateResult { - if (!this.hass) { - return html``; - } - - if ( - Object.keys(supervisorCollection).some( - (collection) => !this.supervisor[collection] - ) - ) { - return html``; - } - return html` - - `; - } - - static styles = css` - :host { - --app-header-background-color: var(--sidebar-background-color); - --app-header-text-color: var(--sidebar-text-color); - --app-header-border-bottom: 1px solid var(--divider-color); - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-panel": HassioPanel; - } -} diff --git a/hassio/src/hassio-router.ts b/hassio/src/hassio-router.ts deleted file mode 100644 index a886fe2ae4..0000000000 --- a/hassio/src/hassio-router.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { customElement, property } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import type { HassioPanelInfo } from "../../src/data/hassio/supervisor"; -import type { Supervisor } from "../../src/data/supervisor/supervisor"; -import type { RouterOptions } from "../../src/layouts/hass-router-page"; -import { HassRouterPage } from "../../src/layouts/hass-router-page"; -import type { HomeAssistant } from "../../src/types"; -// Don't codesplit it, that way the dashboard always loads fast. -import "./hassio-panel"; - -@customElement("hassio-router") -class HassioRouter extends HassRouterPage { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public panel!: HassioPanelInfo; - - @property({ type: Boolean }) public narrow = false; - - protected routerOptions: RouterOptions = { - // Hass.io has a page with tabs, so we route all non-matching routes to it. - defaultPage: "dashboard", - beforeRender: (page: string) => { - if (page === "snapshots") { - return "backups"; - } - if (page === "dashboard" && this.panel.config?.ingress) { - return "ingress"; - } - return undefined; - }, - showLoading: true, - routes: { - dashboard: { - tag: "hassio-panel", - cache: true, - }, - backups: "dashboard", - store: "dashboard", - system: "dashboard", - "update-available": { - tag: "update-available-dashboard", - load: () => import("./update-available/update-available-dashboard"), - }, - addon: { - tag: "hassio-addon-dashboard", - load: () => import("./addon-view/hassio-addon-dashboard"), - }, - ingress: { - tag: "hassio-ingress-view", - load: () => import("./ingress-view/hassio-ingress-view"), - }, - _my_redirect: { - tag: "hassio-my-redirect", - load: () => import("./hassio-my-redirect"), - }, - }, - }; - - protected updatePageEl(el) { - // the tabs page does its own routing so needs full route. - const hassioPanel = el.localName === "hassio-panel"; - const ingressPanel = el.localName === "hassio-ingress-view"; - const route = hassioPanel - ? this.route - : ingressPanel && this.panel.config?.ingress - ? this._ingressRoute(this.panel.config?.ingress) - : this.routeTail; - - el.hass = this.hass; - el.narrow = this.narrow; - el.route = route; - el.supervisor = this.supervisor; - - if (ingressPanel) { - el.ingressPanel = Boolean(this.panel.config?.ingress); - } - } - - private _ingressRoute = memoizeOne((ingress: string) => ({ - prefix: "/hassio/ingress", - path: `/${ingress}`, - })); -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-router": HassioRouter; - } -} diff --git a/hassio/src/hassio-tabs.ts b/hassio/src/hassio-tabs.ts deleted file mode 100644 index 4722125d65..0000000000 --- a/hassio/src/hassio-tabs.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { - mdiBackupRestore, - mdiCogs, - mdiPuzzle, - mdiViewDashboard, -} from "@mdi/js"; -import { atLeastVersion } from "../../src/common/config/version"; -import type { PageNavigation } from "../../src/layouts/hass-tabs-subpage"; -import type { HomeAssistant } from "../../src/types"; - -export const supervisorTabs = (hass: HomeAssistant): PageNavigation[] => - atLeastVersion(hass.config.version, 2022, 5) - ? [] - : [ - { - translationKey: atLeastVersion(hass.config.version, 2021, 12) - ? "panel.apps" - : "panel.dashboard", - path: `/hassio/dashboard`, - iconPath: atLeastVersion(hass.config.version, 2021, 12) - ? mdiPuzzle - : mdiViewDashboard, - }, - { - translationKey: "panel.backups", - path: `/hassio/backups`, - iconPath: mdiBackupRestore, - }, - { - translationKey: "panel.system", - path: `/hassio/system`, - iconPath: mdiCogs, - }, - ]; diff --git a/hassio/src/ingress-view/hassio-ingress-view.ts b/hassio/src/ingress-view/hassio-ingress-view.ts deleted file mode 100644 index 76d51739ab..0000000000 --- a/hassio/src/ingress-view/hassio-ingress-view.ts +++ /dev/null @@ -1,377 +0,0 @@ -import { mdiMenu } from "@mdi/js"; -import type { PropertyValues, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { fireEvent } from "../../../src/common/dom/fire_event"; -import { goBack, navigate } from "../../../src/common/navigate"; -import { extractSearchParam } from "../../../src/common/url/search-params"; -import { nextRender } from "../../../src/common/util/render-status"; -import "../../../src/components/ha-icon-button"; -import type { HassioAddonDetails } from "../../../src/data/hassio/addon"; -import { - fetchHassioAddonInfo, - startHassioAddon, -} from "../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import { - createHassioSession, - validateHassioSession, -} from "../../../src/data/hassio/ingress"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { - showAlertDialog, - showConfirmationDialog, -} from "../../../src/dialogs/generic/show-dialog-box"; -import "../../../src/layouts/hass-loading-screen"; -import "../../../src/layouts/hass-subpage"; -import type { HomeAssistant, Route } from "../../../src/types"; - -@customElement("hassio-ingress-view") -class HassioIngressView extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public route!: Route; - - @property({ attribute: false }) public ingressPanel = false; - - @property({ type: Boolean }) public narrow = false; - - @state() private _addon?: HassioAddonDetails; - - @state() private _loadingMessage?: string; - - private _sessionKeepAlive?: number; - - private _fetchDataTimeout?: number; - - public disconnectedCallback() { - super.disconnectedCallback(); - - if (this._sessionKeepAlive) { - clearInterval(this._sessionKeepAlive); - this._sessionKeepAlive = undefined; - } - if (this._fetchDataTimeout) { - clearInterval(this._fetchDataTimeout); - this._fetchDataTimeout = undefined; - } - } - - protected render(): TemplateResult { - if (!this._addon) { - return html``; - } - - const iframe = html``; - - if (!this.ingressPanel) { - return html` - ${iframe} - `; - } - - return html`${this.narrow || this.hass.dockedSidebar === "always_hidden" - ? html`
- -
${this._addon.name}
-
- ${iframe}` - : iframe}`; - } - - protected async firstUpdated(): Promise { - if (this.route.path === "") { - const requestedAddon = extractSearchParam("addon"); - let addonInfo: HassioAddonDetails; - if (requestedAddon) { - try { - addonInfo = await fetchHassioAddonInfo(this.hass, requestedAddon); - } catch (err: any) { - await showAlertDialog(this, { - text: extractApiErrorMessage(err), - title: requestedAddon, - }); - await nextRender(); - navigate("/hassio/store", { replace: true }); - return; - } - if (!addonInfo.version) { - await showAlertDialog(this, { - text: this.supervisor.localize("my.error_app_not_installed"), - title: addonInfo.name, - }); - await nextRender(); - navigate(`/hassio/addon/${addonInfo.slug}/info`, { replace: true }); - } else if (!addonInfo.ingress) { - await showAlertDialog(this, { - text: this.supervisor.localize("my.error_app_no_ingress"), - title: addonInfo.name, - }); - await nextRender(); - navigate(`/hassio/addon/${addonInfo.slug}/info`, { replace: true }); - } else { - navigate(`/hassio/ingress/${addonInfo.slug}`, { replace: true }); - } - } - } - } - - protected willUpdate(changedProps: PropertyValues) { - super.willUpdate(changedProps); - - if (!changedProps.has("route")) { - return; - } - - const addon = this.route.path.substring(1); - - const oldRoute = changedProps.get("route") as this["route"] | undefined; - const oldAddon = oldRoute ? oldRoute.path.substring(1) : undefined; - - if (addon && addon !== oldAddon) { - this._loadingMessage = undefined; - this._fetchData(addon); - } - } - - private async _fetchData(addonSlug: string) { - const createSessionPromise = createHassioSession(this.hass); - - let addon: HassioAddonDetails; - - try { - addon = await fetchHassioAddonInfo(this.hass, addonSlug); - } catch (_err: any) { - await this.updateComplete; - await showAlertDialog(this, { - text: - this.supervisor.localize("ingress.error_app_info") || - "Unable to fetch app info to start Ingress", - title: "Supervisor", - }); - await nextRender(); - navigate("/hassio/store", { replace: true }); - return; - } - - if (!addon.version) { - await this.updateComplete; - await showAlertDialog(this, { - text: - this.supervisor.localize("ingress.error_app_not_installed") || - "The app is not installed. Please install it first", - title: addon.name, - }); - await nextRender(); - navigate(`/hassio/addon/${addon.slug}/info`, { replace: true }); - return; - } - - if (!addon.ingress_url) { - await this.updateComplete; - await showAlertDialog(this, { - text: - this.supervisor.localize("ingress.error_app_not_supported") || - "This app does not support Ingress", - title: addon.name, - }); - await nextRender(); - goBack(); - return; - } - - if (!addon.state || !["startup", "started"].includes(addon.state)) { - await this.updateComplete; - const confirm = await showConfirmationDialog(this, { - text: - this.supervisor.localize("ingress.error_app_not_running") || - "The app is not running. Do you want to start it now?", - title: addon.name, - confirmText: - this.supervisor.localize("ingress.start_app") || "Start app", - dismissText: this.supervisor.localize("common.no") || "No", - }); - if (confirm) { - try { - this._loadingMessage = - this.supervisor.localize("ingress.app_starting") || - "The app is starting, this can take some time..."; - await startHassioAddon(this.hass, addonSlug); - fireEvent(this, "supervisor-collection-refresh", { - collection: "addon", - }); - this._fetchData(addonSlug); - return; - } catch (_err) { - await showAlertDialog(this, { - text: - this.supervisor.localize("ingress.error_starting_app") || - "Error starting the app", - title: addon.name, - }); - await nextRender(); - navigate(`/hassio/addon/${addon.slug}/logs`, { replace: true }); - return; - } - } else { - await nextRender(); - navigate(`/hassio/addon/${addon.slug}/info`, { replace: true }); - return; - } - } - - if (addon.state === "startup") { - // App is starting up, wait for it to start - this._loadingMessage = - this.supervisor.localize("ingress.app_starting") || - "The app is starting, this can take some time..."; - - this._fetchDataTimeout = window.setTimeout(() => { - this._fetchData(addonSlug); - }, 500); - return; - } - - if (addon.state !== "started") { - return; - } - - this._loadingMessage = undefined; - - if (this._fetchDataTimeout) { - clearInterval(this._fetchDataTimeout); - this._fetchDataTimeout = undefined; - } - - let session: string; - - try { - session = await createSessionPromise; - } catch (_err: any) { - if (this._sessionKeepAlive) { - clearInterval(this._sessionKeepAlive); - } - await showAlertDialog(this, { - text: - this.supervisor.localize("ingress.error_creating_session") || - "Unable to create an Ingress session", - title: addon.name, - }); - await nextRender(); - goBack(); - return; - } - - if (this._sessionKeepAlive) { - clearInterval(this._sessionKeepAlive); - } - this._sessionKeepAlive = window.setInterval(async () => { - try { - await validateHassioSession(this.hass, session); - } catch (_err: any) { - session = await createHassioSession(this.hass); - } - }, 60000); - - this._addon = addon; - } - - private async _checkLoaded(ev): Promise { - if (!this._addon) { - return; - } - if (ev.target.contentDocument.body.textContent === "502: Bad Gateway") { - await this.updateComplete; - showConfirmationDialog(this, { - text: - this.supervisor.localize("ingress.error_app_not_ready") || - "The app seems to not be ready, it might still be starting. Do you want to try again?", - title: this._addon.name, - confirmText: this.supervisor.localize("ingress.retry") || "Retry", - dismissText: this.supervisor.localize("common.no") || "No", - confirm: async () => { - const addon = this._addon; - this._addon = undefined; - await Promise.all([ - this.updateComplete, - new Promise((resolve) => { - setTimeout(resolve, 500); - }), - ]); - this._addon = addon; - }, - }); - } - } - - private _toggleMenu(): void { - fireEvent(this, "hass-toggle-menu"); - } - - static styles = css` - iframe { - display: block; - width: 100%; - height: 100%; - border: 0; - } - - .header + iframe { - height: calc(100% - 40px); - } - - .header { - display: flex; - align-items: center; - font-size: var(--ha-font-size-l); - height: 40px; - padding: 0 16px; - pointer-events: none; - background-color: var(--app-header-background-color); - font-weight: var(--ha-font-weight-normal); - color: var(--app-header-text-color, white); - border-bottom: var(--app-header-border-bottom, none); - box-sizing: border-box; - --mdc-icon-size: 20px; - } - - .main-title { - margin: var(--margin-title); - line-height: var(--ha-line-height-condensed); - flex-grow: 1; - } - - ha-icon-button { - pointer-events: auto; - } - - hass-subpage { - --app-header-background-color: var(--sidebar-background-color); - --app-header-text-color: var(--sidebar-text-color); - --app-header-border-bottom: 1px solid var(--divider-color); - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-ingress-view": HassioIngressView; - } -} diff --git a/hassio/src/resources/hassio-style.ts b/hassio/src/resources/hassio-style.ts deleted file mode 100644 index e1872faabb..0000000000 --- a/hassio/src/resources/hassio-style.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { css } from "lit"; - -export const hassioStyle = css` - .content { - margin: 8px; - } - h1, - .description, - .card-content { - color: var(--primary-text-color); - } - h1 { - font-size: 2em; - margin-bottom: 8px; - font-family: var(--ha-font-family-body); - -webkit-font-smoothing: var(--ha-font-smoothing); - -moz-osx-font-smoothing: var(--ha-moz-osx-font-smoothing); - font-size: var(--ha-font-size-2xl); - font-weight: var(--ha-font-weight-normal); - line-height: var(--ha-line-height-condensed); - padding-left: 8px; - padding-inline-start: 8px; - padding-inline-end: initial; - } - .description { - margin-top: 4px; - padding-left: 8px; - padding-inline-start: 8px; - padding-inline-end: initial; - } - .card-group { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - grid-gap: var(--ha-space-2); - } - @media screen and (min-width: 640px) { - .card-group { - grid-template-columns: repeat(auto-fit, minmax(300px, 0.5fr)); - } - } - @media screen and (min-width: 1020px) { - .card-group { - grid-template-columns: repeat(auto-fit, minmax(300px, 0.333fr)); - } - } - @media screen and (min-width: 1300px) { - .card-group { - grid-template-columns: repeat(auto-fit, minmax(300px, 0.25fr)); - } - } - .error { - color: var(--error-color); - margin-top: 16px; - } -`; diff --git a/hassio/src/supervisor-base-element.ts b/hassio/src/supervisor-base-element.ts deleted file mode 100644 index c1b826762c..0000000000 --- a/hassio/src/supervisor-base-element.ts +++ /dev/null @@ -1,231 +0,0 @@ -import type { Collection, UnsubscribeFunc } from "home-assistant-js-websocket"; -import type { PropertyValues } from "lit"; -import { LitElement } from "lit"; -import { property, state } from "lit/decorators"; -import { atLeastVersion } from "../../src/common/config/version"; -import { computeLocalize } from "../../src/common/translations/localize"; -import { fetchHassioAddonsInfo } from "../../src/data/hassio/addon"; -import type { HassioResponse } from "../../src/data/hassio/common"; -import { - fetchHassioHassOsInfo, - fetchHassioHostInfo, -} from "../../src/data/hassio/host"; -import { fetchNetworkInfo } from "../../src/data/hassio/network"; -import { fetchHassioResolution } from "../../src/data/hassio/resolution"; -import { - fetchHassioHomeAssistantInfo, - fetchHassioInfo, - fetchHassioSupervisorInfo, -} from "../../src/data/hassio/supervisor"; -import { fetchSupervisorStore } from "../../src/data/supervisor/store"; -import type { - Supervisor, - SupervisorObject, - SupervisorKeys, -} from "../../src/data/supervisor/supervisor"; -import { - getSupervisorEventCollection, - supervisorCollection, - cleanupSupervisorCollection, -} from "../../src/data/supervisor/supervisor"; -import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin"; -import { urlSyncMixin } from "../../src/state/url-sync-mixin"; -import type { HomeAssistant, Route } from "../../src/types"; -import { getTranslation } from "../../src/util/common-translation"; -import { - computeRTLDirection, - setDirectionStyles, -} from "../../src/common/util/compute_rtl"; - -declare global { - interface HASSDomEvents { - "supervisor-update": Partial; - "supervisor-collection-refresh": { collection: SupervisorObject }; - } -} - -export class SupervisorBaseElement extends urlSyncMixin( - ProvideHassLitMixin(LitElement) -) { - @property({ attribute: false }) public route?: Route; - - @property({ attribute: false }) public supervisor: Partial = { - localize: () => "", - }; - - @state() private _unsubs: Record = {}; - - @state() private _collections: Record> = {}; - - @state() private _language = "en"; - - public connectedCallback(): void { - super.connectedCallback(); - if (!this.hasUpdated) { - return; - } - if (this.route?.prefix === "/hassio") { - this._initSupervisor(); - } - } - - public disconnectedCallback() { - super.disconnectedCallback(); - Object.keys(this._unsubs).forEach((unsub) => { - this._unsubs[unsub](); - delete this._unsubs[unsub]; - }); - Object.keys(this._collections).forEach((collection) => { - cleanupSupervisorCollection(this.hass.connection, collection); - }); - this._collections = {}; - this.removeEventListener( - "supervisor-collection-refresh", - this._handleSupervisorStoreRefreshEvent - ); - } - - protected willUpdate(changedProperties: PropertyValues) { - if (!this.hasUpdated) { - if (this.route?.prefix === "/hassio") { - this._initSupervisor(); - } - } - if (changedProperties.has("hass")) { - const oldHass = changedProperties.get("hass") as - | HomeAssistant - | undefined; - if (oldHass?.language !== this.hass.language) { - this._language = this.hass.language; - } - } - - if (changedProperties.has("_language") || !this.hasUpdated) { - this._initializeLocalize(); - this._applyDirection(this.hass); - } - } - - protected _updateSupervisor(update: Partial): void { - this.supervisor = { ...this.supervisor, ...update }; - } - - private async _initializeLocalize() { - const { language, data } = await getTranslation(null, this._language); - - this._updateSupervisor({ - localize: await computeLocalize( - this.constructor.prototype, - language, - { - [language]: data, - } - ), - }); - } - - private async _handleSupervisorStoreRefreshEvent(ev) { - const collection = ev.detail.collection; - if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) { - if (collection in this._collections) { - this._collections[collection].refresh(); - } - return; - } - - const response = await this.hass.callApi>( - "GET", - `hassio${supervisorCollection[collection]}` - ); - this._updateSupervisor({ [collection]: response.data }); - } - - private _subscribeCollection(collection: string) { - if (this._unsubs[collection]) { - this._unsubs[collection](); - } - try { - this._unsubs[collection] = this._collections[collection].subscribe( - (data) => - this._updateSupervisor({ - [collection]: data, - }) - ); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - } - } - - private async _initSupervisor(): Promise { - this.addEventListener( - "supervisor-collection-refresh", - this._handleSupervisorStoreRefreshEvent - ); - - if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) { - Object.keys(supervisorCollection).forEach((collection) => { - if (collection in this._collections) { - this._subscribeCollection(collection); - this._collections[collection].refresh(); - } else { - this._collections[collection] = getSupervisorEventCollection( - this.hass.connection, - collection, - supervisorCollection[collection] - ); - if (this._collections[collection].state) { - // happens when the grace period of the collection unsubscribe has not passed yet - this._updateSupervisor({ - [collection]: this._collections[collection].state, - }); - } - this._subscribeCollection(collection); - } - }); - } else { - const [ - addon, - supervisor, - host, - core, - info, - os, - network, - resolution, - store, - ] = await Promise.all([ - fetchHassioAddonsInfo(this.hass), - fetchHassioSupervisorInfo(this.hass), - fetchHassioHostInfo(this.hass), - fetchHassioHomeAssistantInfo(this.hass), - fetchHassioInfo(this.hass), - fetchHassioHassOsInfo(this.hass), - fetchNetworkInfo(this.hass), - fetchHassioResolution(this.hass), - fetchSupervisorStore(this.hass), - ]); - - this._updateSupervisor({ - addon, - supervisor, - host, - core, - info, - os, - network, - resolution, - store, - }); - - this.addEventListener("supervisor-update", (ev) => - this._updateSupervisor(ev.detail) - ); - } - } - - private _applyDirection(hass: HomeAssistant) { - const direction = computeRTLDirection(hass); - setDirectionStyles(direction, this); - } -} diff --git a/hassio/src/system/hassio-core-info.ts b/hassio/src/system/hassio-core-info.ts deleted file mode 100644 index 7206c13859..0000000000 --- a/hassio/src/system/hassio-core-info.ts +++ /dev/null @@ -1,206 +0,0 @@ -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { atLeastVersion } from "../../../src/common/config/version"; -import "../../../src/components/buttons/ha-progress-button"; -import "../../../src/components/ha-button"; -import "../../../src/components/ha-button-menu"; -import "../../../src/components/ha-card"; -import "../../../src/components/ha-settings-row"; -import type { HassioStats } from "../../../src/data/hassio/common"; -import { - extractApiErrorMessage, - fetchHassioStats, -} from "../../../src/data/hassio/common"; -import { restartCore } from "../../../src/data/supervisor/core"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { - showAlertDialog, - showConfirmationDialog, -} from "../../../src/dialogs/generic/show-dialog-box"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant } from "../../../src/types"; -import { bytesToString } from "../../../src/util/bytes-to-string"; -import "../components/supervisor-metric"; -import { hassioStyle } from "../resources/hassio-style"; - -@customElement("hassio-core-info") -class HassioCoreInfo extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @state() private _metrics?: HassioStats; - - protected render(): TemplateResult | undefined { - const metrics = [ - { - description: this.supervisor.localize("system.core.cpu_usage"), - value: this._metrics?.cpu_percent, - }, - { - description: this.supervisor.localize("system.core.ram_usage"), - value: this._metrics?.memory_percent, - tooltip: `${bytesToString(this._metrics?.memory_usage)}/${bytesToString( - this._metrics?.memory_limit - )}`, - }, - ]; - - return html` - -
-
- - - ${this.supervisor.localize("common.version")} - - - core-${this.supervisor.core.version} - - - - - ${this.supervisor.localize("common.newest_version")} - - - core-${this.supervisor.core.version_latest} - - ${!atLeastVersion(this.hass.config.version, 2021, 12) && - this.supervisor.core.update_available - ? html` - - ${this.supervisor.localize("common.show")} - - ` - : ""} - -
-
- ${metrics.map( - (metric) => html` - - ` - )} -
-
-
- - ${this.supervisor.localize("common.restart_name", { name: "Core" })} - -
-
- `; - } - - protected firstUpdated(): void { - this._loadData(); - } - - private async _loadData(): Promise { - this._metrics = await fetchHassioStats(this.hass, "core"); - } - - private async _coreRestart(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - const confirmed = await showConfirmationDialog(this, { - title: this.supervisor.localize("confirm.restart.title", { - name: "Home Assistant Core", - }), - text: this.supervisor.localize("confirm.restart.text", { - name: "Home Assistant Core", - }), - confirmText: this.supervisor.localize("common.restart"), - dismissText: this.supervisor.localize("common.cancel"), - }); - - if (!confirmed) { - button.progress = false; - return; - } - - try { - await restartCore(this.hass); - } catch (err: any) { - if (this.hass.connection.connected) { - showAlertDialog(this, { - title: this.supervisor.localize("common.failed_to_restart_name", { - name: "Home Assistant Core", - }), - text: extractApiErrorMessage(err), - }); - } - } finally { - button.progress = false; - } - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - ha-card { - height: 100%; - justify-content: space-between; - flex-direction: column; - display: flex; - } - .card-actions { - height: 48px; - border-top: none; - display: flex; - justify-content: flex-end; - align-items: center; - } - .card-content { - display: flex; - flex-direction: column; - height: calc(100% - 124px); - justify-content: space-between; - } - ha-settings-row { - padding: 0; - height: 54px; - width: 100%; - } - ha-settings-row[three-line] { - height: 74px; - } - ha-settings-row > span[slot="description"] { - white-space: normal; - color: var(--secondary-text-color); - } - ha-button-menu { - color: var(--secondary-text-color); - --mdc-menu-min-width: 200px; - } - a { - text-decoration: none; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-core-info": HassioCoreInfo; - } -} diff --git a/hassio/src/system/hassio-host-info.ts b/hassio/src/system/hassio-host-info.ts deleted file mode 100644 index 69c935701f..0000000000 --- a/hassio/src/system/hassio-host-info.ts +++ /dev/null @@ -1,453 +0,0 @@ -import { mdiDotsVertical } from "@mdi/js"; -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { atLeastVersion } from "../../../src/common/config/version"; -import { fireEvent } from "../../../src/common/dom/fire_event"; -import "../../../src/components/buttons/ha-progress-button"; -import "../../../src/components/ha-button"; -import "../../../src/components/ha-button-menu"; -import "../../../src/components/ha-card"; -import "../../../src/components/ha-icon-button"; -import "../../../src/components/ha-list-item"; -import "../../../src/components/ha-settings-row"; -import { - extractApiErrorMessage, - ignoreSupervisorError, -} from "../../../src/data/hassio/common"; -import { fetchHassioHardwareInfo } from "../../../src/data/hassio/hardware"; -import { - changeHostOptions, - configSyncOS, - rebootHost, - shutdownHost, -} from "../../../src/data/hassio/host"; -import type { NetworkInfo } from "../../../src/data/hassio/network"; -import { fetchNetworkInfo } from "../../../src/data/hassio/network"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { - showAlertDialog, - showConfirmationDialog, - showPromptDialog, -} from "../../../src/dialogs/generic/show-dialog-box"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant } from "../../../src/types"; -import { - getValueInPercentage, - roundWithOneDecimal, -} from "../../../src/util/calculate"; -import "../components/supervisor-metric"; -import { showHassioDatadiskDialog } from "../dialogs/datadisk/show-dialog-hassio-datadisk"; -import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware"; -import { showNetworkDialog } from "../dialogs/network/show-dialog-network"; -import { hassioStyle } from "../resources/hassio-style"; - -@customElement("hassio-host-info") -class HassioHostInfo extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - protected render(): TemplateResult | undefined { - const primaryIpAddress = this.supervisor.host.features.includes("network") - ? this._primaryIpAddress(this.supervisor.network!) - : ""; - - const metrics = [ - { - description: this.supervisor.localize("system.host.used_space"), - value: this._getUsedSpace( - this.supervisor.host.disk_used, - this.supervisor.host.disk_total - ), - tooltip: `${this.supervisor.host.disk_used} GB/${this.supervisor.host.disk_total} GB`, - }, - ]; - return html` - -
-
- ${this.supervisor.host.features.includes("hostname") - ? html` - - ${this.supervisor.localize("system.host.hostname")} - - - ${this.supervisor.host.hostname} - - - ${this.supervisor.localize("system.host.change")} - - ` - : ""} - ${this.supervisor.host.features.includes("network") - ? html` - - ${this.supervisor.localize("system.host.ip_address")} - - ${primaryIpAddress} - - ${this.supervisor.localize("system.host.change")} - - ` - : ""} - - - - ${this.supervisor.localize("system.host.operating_system")} - - - ${this.supervisor.host.operating_system} - - ${!atLeastVersion(this.hass.config.version, 2021, 12) && - this.supervisor.os.update_available - ? html` - - ${this.supervisor.localize("common.show")} - - ` - : ""} - - ${!this.supervisor.host.features.includes("haos") - ? html` - - ${this.supervisor.localize("system.host.docker_version")} - - - ${this.supervisor.info.docker} - - ` - : ""} - ${this.supervisor.host.deployment - ? html` - - ${this.supervisor.localize("system.host.deployment")} - - - ${this.supervisor.host.deployment} - - ` - : ""} -
-
- ${this.supervisor.host.disk_life_time !== null - ? html` - - ${this.supervisor.localize("system.host.lifetime_used")} - - - ${this.supervisor.host.disk_life_time} % - - ` - : ""} - ${metrics.map( - (metric) => html` - - ` - )} -
-
-
- ${this.supervisor.host.features.includes("reboot") - ? html` - - ${this.supervisor.localize("system.host.reboot_host")} - - ` - : ""} - ${this.supervisor.host.features.includes("shutdown") - ? html` - - ${this.supervisor.localize("system.host.shutdown_host")} - - ` - : ""} - - - - - ${this.supervisor.localize("system.host.hardware")} - - ${this.supervisor.host.features.includes("haos") - ? html` - - ${this.supervisor.localize("system.host.import_from_usb")} - - ${this.supervisor.host.features.includes("os_agent") && - atLeastVersion(this.supervisor.host.agent_version, 1, 2, 0) - ? html` - - ${this.supervisor.localize( - "system.host.move_datadisk" - )} - - ` - : ""} - ` - : ""} - -
-
- `; - } - - protected firstUpdated(): void { - this._loadData(); - } - - private _getUsedSpace = memoizeOne((used: number, total: number) => - roundWithOneDecimal(getValueInPercentage(used, 0, total)) - ); - - private _primaryIpAddress = memoizeOne((network_info: NetworkInfo) => { - if (!network_info || !network_info.interfaces) { - return ""; - } - return network_info.interfaces.find((a) => a.primary)?.ipv4?.address![0]; - }); - - private async _handleMenuAction(ev) { - switch ((ev.target as any).action) { - case "hardware": - await this._showHardware(); - break; - case "import_from_usb": - await this._importFromUSB(); - break; - case "move_datadisk": - await this._moveDatadisk(); - break; - } - } - - private _moveDatadisk(): void { - showHassioDatadiskDialog(this, { - supervisor: this.supervisor, - }); - } - - private async _showHardware(): Promise { - let hardware; - try { - hardware = await fetchHassioHardwareInfo(this.hass); - } catch (err: any) { - await showAlertDialog(this, { - title: this.supervisor.localize( - "system.host.failed_to_get_hardware_list" - ), - text: extractApiErrorMessage(err), - }); - return; - } - showHassioHardwareDialog(this, { supervisor: this.supervisor, hardware }); - } - - private async _hostReboot(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - const confirmed = await showConfirmationDialog(this, { - title: this.supervisor.localize("system.host.reboot_host"), - text: this.supervisor.localize("system.host.confirm_reboot"), - confirmText: this.supervisor.localize("system.host.reboot_host"), - dismissText: this.supervisor.localize("common.cancel"), - }); - - if (!confirmed) { - button.progress = false; - return; - } - - try { - await rebootHost(this.hass); - } catch (err: any) { - // Ignore connection errors, these are all expected - if (this.hass.connection.connected && !ignoreSupervisorError(err)) { - showAlertDialog(this, { - title: this.supervisor.localize("system.host.failed_to_reboot"), - text: extractApiErrorMessage(err), - }); - } - } - button.progress = false; - } - - private async _hostShutdown(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - const confirmed = await showConfirmationDialog(this, { - title: this.supervisor.localize("system.host.shutdown_host"), - text: this.supervisor.localize("system.host.confirm_shutdown"), - confirmText: this.supervisor.localize("system.host.shutdown_host"), - dismissText: this.supervisor.localize("common.cancel"), - }); - - if (!confirmed) { - button.progress = false; - return; - } - - try { - await shutdownHost(this.hass); - } catch (err: any) { - // Ignore connection errors, these are all expected - if (this.hass.connection.connected && !ignoreSupervisorError(err)) { - showAlertDialog(this, { - title: this.supervisor.localize("system.host.failed_to_shutdown"), - text: extractApiErrorMessage(err), - }); - } - } - button.progress = false; - } - - private async _changeNetworkClicked(): Promise { - showNetworkDialog(this, { - supervisor: this.supervisor, - loadData: () => this._loadData(), - }); - } - - private async _changeHostnameClicked(): Promise { - const curHostname: string = this.supervisor.host.hostname; - const hostname = await showPromptDialog(this, { - title: this.supervisor.localize("system.host.change_hostname"), - inputLabel: this.supervisor.localize("system.host.new_hostname"), - inputType: "string", - defaultValue: curHostname, - confirmText: this.supervisor.localize("common.update"), - }); - - if (hostname && hostname !== curHostname) { - try { - await changeHostOptions(this.hass, { hostname }); - fireEvent(this, "supervisor-collection-refresh", { - collection: "host", - }); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("system.host.failed_to_set_hostname"), - text: extractApiErrorMessage(err), - }); - } - } - } - - private async _importFromUSB(): Promise { - try { - await configSyncOS(this.hass); - fireEvent(this, "supervisor-collection-refresh", { - collection: "host", - }); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize( - "system.host.failed_to_import_from_usb" - ), - text: extractApiErrorMessage(err), - }); - } - } - - private async _loadData(): Promise { - if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) { - fireEvent(this, "supervisor-collection-refresh", { - collection: "network", - }); - } else { - const network = await fetchNetworkInfo(this.hass); - fireEvent(this, "supervisor-update", { network }); - } - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - ha-card { - height: 100%; - justify-content: space-between; - flex-direction: column; - display: flex; - } - .card-actions { - height: 48px; - border-top: none; - display: flex; - justify-content: space-between; - align-items: center; - } - .card-content { - display: flex; - flex-direction: column; - height: calc(100% - 124px); - justify-content: space-between; - } - ha-settings-row { - padding: 0; - height: 54px; - width: 100%; - } - ha-settings-row[three-line] { - height: 74px; - } - ha-settings-row > span[slot="description"] { - white-space: normal; - color: var(--secondary-text-color); - } - - ha-button-menu { - color: var(--secondary-text-color); - --mdc-menu-min-width: 200px; - } - ha-list-item ha-svg-icon { - color: var(--secondary-text-color); - } - a { - text-decoration: none; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-host-info": HassioHostInfo; - } -} diff --git a/hassio/src/system/hassio-supervisor-info.ts b/hassio/src/system/hassio-supervisor-info.ts deleted file mode 100644 index e47bfe42df..0000000000 --- a/hassio/src/system/hassio-supervisor-info.ts +++ /dev/null @@ -1,469 +0,0 @@ -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { atLeastVersion } from "../../../src/common/config/version"; -import { fireEvent } from "../../../src/common/dom/fire_event"; -import "../../../src/components/buttons/ha-progress-button"; -import "../../../src/components/ha-alert"; -import "../../../src/components/ha-button"; -import "../../../src/components/ha-card"; -import "../../../src/components/ha-settings-row"; -import "../../../src/components/ha-switch"; -import type { HassioStats } from "../../../src/data/hassio/common"; -import { - extractApiErrorMessage, - fetchHassioStats, -} from "../../../src/data/hassio/common"; -import type { SupervisorOptions } from "../../../src/data/hassio/supervisor"; -import { - reloadSupervisor, - restartSupervisor, - setSupervisorOption, -} from "../../../src/data/hassio/supervisor"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { - showAlertDialog, - showConfirmationDialog, -} from "../../../src/dialogs/generic/show-dialog-box"; -import { showJoinBetaDialog } from "../../../src/panels/config/core/updates/show-dialog-join-beta"; -import { - UNHEALTHY_REASON_URL, - UNSUPPORTED_REASON_URL, -} from "../../../src/panels/config/repairs/dialog-system-information"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant } from "../../../src/types"; -import { bytesToString } from "../../../src/util/bytes-to-string"; -import { documentationUrl } from "../../../src/util/documentation-url"; -import "../components/supervisor-metric"; -import { hassioStyle } from "../resources/hassio-style"; - -@customElement("hassio-supervisor-info") -class HassioSupervisorInfo extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @state() private _metrics?: HassioStats; - - protected render(): TemplateResult | undefined { - const metrics = [ - { - description: this.supervisor.localize("system.supervisor.cpu_usage"), - value: this._metrics?.cpu_percent, - }, - { - description: this.supervisor.localize("system.supervisor.ram_usage"), - value: this._metrics?.memory_percent, - tooltip: `${bytesToString(this._metrics?.memory_usage)}/${bytesToString( - this._metrics?.memory_limit - )}`, - }, - ]; - return html` - -
-
- - - ${this.supervisor.localize("common.version")} - - - supervisor-${this.supervisor.supervisor.version} - - - - - ${this.supervisor.localize("common.newest_version")} - - - supervisor-${this.supervisor.supervisor.version_latest} - - ${!atLeastVersion(this.hass.config.version, 2021, 12) && - this.supervisor.supervisor.update_available - ? html` - - ${this.supervisor.localize("common.show")} - - ` - : ""} - - - - ${this.supervisor.localize("system.supervisor.channel")} - - - ${this.supervisor.supervisor.channel} - - ${this.supervisor.supervisor.channel === "beta" - ? html` - - ${this.supervisor.localize( - "system.supervisor.leave_beta_action" - )} - - ` - : this.supervisor.supervisor.channel === "stable" - ? html` - - ${this.supervisor.localize( - "system.supervisor.join_beta_action" - )} - - ` - : ""} - - - ${this.supervisor.supervisor.supported - ? !atLeastVersion(this.hass.config.version, 2021, 4) - ? html` - - ${this.supervisor.localize( - "system.supervisor.share_diagnostics" - )} - -
- ${this.supervisor.localize( - "system.supervisor.share_diagnostics_description" - )} - -
- -
` - : "" - : html` - ${this.supervisor.localize( - "system.supervisor.unsupported_title" - )} - - ${this.supervisor.localize("common.learn_more")} - - `} - ${!this.supervisor.supervisor.healthy - ? html` - ${this.supervisor.localize( - "system.supervisor.unhealthy_title" - )} - - ${this.supervisor.localize("common.learn_more")} - - ` - : ""} -
-
- ${metrics.map( - (metric) => html` - - ` - )} -
-
-
- - ${this.supervisor.localize("system.supervisor.reload_supervisor")} - - - ${this.supervisor.localize("common.restart_name", { - name: "Supervisor", - })} - -
-
- `; - } - - protected firstUpdated(): void { - this._loadData(); - } - - private async _loadData(): Promise { - this._metrics = await fetchHassioStats(this.hass, "supervisor"); - } - - private async _toggleBeta(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - if (this.supervisor.supervisor.channel === "stable") { - showJoinBetaDialog(this, { - join: async () => { - await this._setChannel("beta"); - button.progress = false; - }, - cancel: () => { - button.progress = false; - }, - }); - } else { - await this._setChannel("stable"); - button.progress = false; - } - } - - private async _setChannel( - channel: SupervisorOptions["channel"] - ): Promise { - try { - const data: Partial = { - channel, - }; - await setSupervisorOption(this.hass, data); - await this._reloadSupervisor(); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize( - "system.supervisor.failed_to_set_option" - ), - text: extractApiErrorMessage(err), - }); - } - } - - private async _supervisorReload(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - try { - await this._reloadSupervisor(); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("system.supervisor.failed_to_reload"), - text: extractApiErrorMessage(err), - }); - } finally { - button.progress = false; - } - } - - private async _reloadSupervisor(): Promise { - await reloadSupervisor(this.hass); - fireEvent(this, "supervisor-collection-refresh", { - collection: "supervisor", - }); - } - - private async _supervisorRestart(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - - const confirmed = await showConfirmationDialog(this, { - title: this.supervisor.localize("confirm.restart.title", { - name: "Supervisor", - }), - text: this.supervisor.localize("confirm.restart.text", { - name: "Supervisor", - }), - confirmText: this.supervisor.localize("common.restart"), - dismissText: this.supervisor.localize("common.cancel"), - }); - - if (!confirmed) { - button.progress = false; - return; - } - - try { - await restartSupervisor(this.hass); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize("common.failed_to_restart_name", { - name: "Supervisor", - }), - text: extractApiErrorMessage(err), - }); - } finally { - button.progress = false; - } - } - - private async _diagnosticsInformationDialog(): Promise { - await showAlertDialog(this, { - title: this.supervisor.localize( - "system.supervisor.share_diagonstics_title" - ), - text: this.supervisor.localize( - "system.supervisor.share_diagonstics_description", - { line_break: html`

` } - ), - }); - } - - private async _unsupportedDialog(): Promise { - await showAlertDialog(this, { - title: this.supervisor.localize("system.supervisor.unsupported_title"), - text: html`${this.supervisor.localize( - "system.supervisor.unsupported_description" - )}

- `, - }); - } - - private async _unhealthyDialog(): Promise { - await showAlertDialog(this, { - title: this.supervisor.localize("system.supervisor.unhealthy_title"), - text: html`${this.supervisor.localize( - "system.supervisor.unhealthy_description" - )}

- `, - }); - } - - private async _toggleDiagnostics(): Promise { - try { - const data: SupervisorOptions = { - diagnostics: !this.supervisor.supervisor?.diagnostics, - }; - await setSupervisorOption(this.hass, data); - } catch (err: any) { - showAlertDialog(this, { - title: this.supervisor.localize( - "system.supervisor.failed_to_set_option" - ), - text: extractApiErrorMessage(err), - }); - } - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - ha-card { - height: 100%; - justify-content: space-between; - flex-direction: column; - display: flex; - } - .card-actions { - height: 48px; - border-top: none; - display: flex; - justify-content: space-between; - align-items: center; - } - .card-content { - display: flex; - flex-direction: column; - height: calc(100% - 124px); - justify-content: space-between; - } - .metrics-block { - margin-top: 16px; - } - button.link { - color: var(--primary-color); - } - ha-settings-row { - padding: 0; - height: 54px; - width: 100%; - } - ha-settings-row[three-line] { - height: 74px; - } - ha-settings-row > div[slot="description"] { - white-space: normal; - color: var(--secondary-text-color); - } - a { - text-decoration: none; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-supervisor-info": HassioSupervisorInfo; - } -} diff --git a/hassio/src/system/hassio-supervisor-log.ts b/hassio/src/system/hassio-supervisor-log.ts deleted file mode 100644 index 13f2e6540f..0000000000 --- a/hassio/src/system/hassio-supervisor-log.ts +++ /dev/null @@ -1,162 +0,0 @@ -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import "../../../src/components/buttons/ha-progress-button"; -import "../../../src/components/ha-alert"; -import "../../../src/components/ha-ansi-to-html"; -import "../../../src/components/ha-card"; -import "../../../src/components/ha-select"; -import "../../../src/components/ha-list-item"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import { fetchHassioLogs } from "../../../src/data/hassio/supervisor"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import "../../../src/layouts/hass-loading-screen"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant } from "../../../src/types"; -import { hassioStyle } from "../resources/hassio-style"; - -interface LogProvider { - key: string; - name: string; -} - -const logProviders: LogProvider[] = [ - { - key: "supervisor", - name: "Supervisor", - }, - { - key: "core", - name: "Core", - }, - { - key: "host", - name: "Host", - }, - { - key: "dns", - name: "DNS", - }, - { - key: "audio", - name: "Audio", - }, - { - key: "multicast", - name: "Multicast", - }, -]; - -@customElement("hassio-supervisor-log") -class HassioSupervisorLog extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @state() private _error?: string; - - @state() private _selectedLogProvider = "supervisor"; - - @state() private _content?: string; - - public async connectedCallback(): Promise { - super.connectedCallback(); - await this._loadData(); - } - - protected render(): TemplateResult | undefined { - return html` - - ${this._error - ? html`${this._error}` - : ""} - ${this.hass.userData?.showAdvanced - ? html` - - ${logProviders.map( - (provider) => html` - - ${provider.name} - - ` - )} - - ` - : ""} - -
- ${this._content - ? html` - ` - : html``} -
-
- - ${this.supervisor.localize("common.refresh")} - -
-
- `; - } - - private async _setLogProvider(ev): Promise { - const provider = ev.target.value; - this._selectedLogProvider = provider; - this._loadData(); - } - - private async _refresh(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - await this._loadData(); - button.progress = false; - } - - private async _loadData(): Promise { - this._error = undefined; - - try { - const response = await fetchHassioLogs( - this.hass, - this._selectedLogProvider - ); - - this._content = await response.text(); - } catch (err: any) { - this._error = this.supervisor.localize("system.log.get_logs", { - provider: this._selectedLogProvider, - error: extractApiErrorMessage(err), - }); - } - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - ha-card { - margin-top: 8px; - width: 100%; - } - pre { - white-space: pre-wrap; - } - ha-select { - width: 100%; - margin-bottom: 4px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-supervisor-log": HassioSupervisorLog; - } -} diff --git a/hassio/src/system/hassio-system.ts b/hassio/src/system/hassio-system.ts deleted file mode 100644 index 643b9f3530..0000000000 --- a/hassio/src/system/hassio-system.ts +++ /dev/null @@ -1,93 +0,0 @@ -import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import { atLeastVersion } from "../../../src/common/config/version"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import "../../../src/layouts/hass-tabs-subpage"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant, Route } from "../../../src/types"; -import { supervisorTabs } from "../hassio-tabs"; -import { hassioStyle } from "../resources/hassio-style"; -import "./hassio-core-info"; -import "./hassio-host-info"; -import "./hassio-supervisor-info"; -import "./hassio-supervisor-log"; - -@customElement("hassio-system") -class HassioSystem extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public route!: Route; - - protected render(): TemplateResult | undefined { - return html` - - ${this.supervisor.localize("panel.system")} -
-
- - - -
- -
-
- `; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - hassioStyle, - css` - .content { - margin: 8px; - color: var(--primary-text-color); - } - .title { - margin-top: 24px; - color: var(--primary-text-color); - font-size: 2em; - padding-left: 8px; - padding-inline-start: 8px; - padding-inline-end: initial; - margin-bottom: 8px; - } - hassio-supervisor-log { - width: 100%; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hassio-system": HassioSystem; - } -} diff --git a/hassio/src/update-available/update-available-card.ts b/hassio/src/update-available/update-available-card.ts deleted file mode 100644 index fd31d52892..0000000000 --- a/hassio/src/update-available/update-available-card.ts +++ /dev/null @@ -1,506 +0,0 @@ -import { - css, - type CSSResultGroup, - html, - LitElement, - nothing, - type PropertyValues, -} from "lit"; -import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { atLeastVersion } from "../../../src/common/config/version"; -import { fireEvent } from "../../../src/common/dom/fire_event"; -import "../../../src/components/buttons/ha-progress-button"; -import "../../../src/components/ha-alert"; -import "../../../src/components/ha-card"; -import "../../../src/components/ha-checkbox"; -import "../../../src/components/ha-faded"; -import "../../../src/components/ha-icon-button"; -import "../../../src/components/ha-markdown"; -import "../../../src/components/ha-md-list"; -import "../../../src/components/ha-md-list-item"; -import "../../../src/components/ha-spinner"; -import "../../../src/components/ha-svg-icon"; -import "../../../src/components/ha-switch"; -import type { HaSwitch } from "../../../src/components/ha-switch"; -import type { HassioAddonDetails } from "../../../src/data/hassio/addon"; -import { - fetchHassioAddonChangelog, - fetchHassioAddonInfo, - updateHassioAddon, -} from "../../../src/data/hassio/addon"; -import { - extractApiErrorMessage, - ignoreSupervisorError, -} from "../../../src/data/hassio/common"; -import { fetchHassioHassOsInfo, updateOS } from "../../../src/data/hassio/host"; -import { - fetchHassioHomeAssistantInfo, - fetchHassioSupervisorInfo, - updateSupervisor, -} from "../../../src/data/hassio/supervisor"; -import { updateCore } from "../../../src/data/supervisor/core"; -import type { StoreAddon } from "../../../src/data/supervisor/store"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box"; -import { haStyle } from "../../../src/resources/styles"; -import type { HomeAssistant, Route } from "../../../src/types"; -import { addonArchIsSupported, extractChangelog } from "../util/addon"; - -declare global { - interface HASSDomEvents { - "update-complete": undefined; - } -} - -const SUPERVISOR_UPDATE_NAMES = { - core: "Home Assistant Core", - os: "Home Assistant Operating System", - supervisor: "Home Assistant Supervisor", -}; - -type UpdateType = "os" | "supervisor" | "core" | "addon"; - -const changelogUrl = ( - entry: UpdateType, - version: string -): string | undefined => { - if (entry === "addon") { - return undefined; - } - if (entry === "core") { - return version.includes("dev") - ? "https://github.com/home-assistant/core/commits/dev" - : version.includes("b") - ? "https://next.home-assistant.io/latest-release-notes/" - : "https://www.home-assistant.io/latest-release-notes/"; - } - if (entry === "os") { - return version.includes("dev") - ? "https://github.com/home-assistant/operating-system/commits/dev" - : `https://github.com/home-assistant/operating-system/releases/tag/${version}`; - } - if (entry === "supervisor") { - return version.includes("dev") - ? "https://github.com/home-assistant/supervisor/commits/main" - : `https://github.com/home-assistant/supervisor/releases/tag/${version}`; - } - return undefined; -}; - -@customElement("update-available-card") -class UpdateAvailableCard extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ attribute: false }) public route!: Route; - - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public addonSlug?: string; - - @state() private _updateType?: UpdateType; - - @state() private _changelogContent?: string; - - @state() private _addonInfo?: HassioAddonDetails; - - @state() private _updating = false; - - @state() private _error?: string; - - private _addonStoreInfo = memoizeOne( - (slug: string, storeAddons: StoreAddon[]) => - storeAddons.find((addon) => addon.slug === slug) - ); - - protected render() { - if ( - !this._updateType || - (this._updateType === "addon" && !this._addonInfo) - ) { - return nothing; - } - - const changelog = changelogUrl(this._updateType, this._version_latest); - - const createBackupTexts = this._computeCreateBackupTexts(); - - return html` - -
- ${this._error - ? html`${this._error}` - : ""} - ${this._version === this._version_latest - ? html`

- ${this.supervisor.localize("update_available.no_update", { - name: this._name, - })} -

` - : !this._updating - ? html` - ${this._changelogContent - ? html` - - - - - ` - : nothing} -
-

- ${this.supervisor.localize( - "update_available.description", - { - name: this._name, - version: this._version, - newest_version: this._version_latest, - } - )} -

-
- ${createBackupTexts - ? html` -
- - - - ${createBackupTexts.title} - - - ${createBackupTexts.description - ? html` - - ${createBackupTexts.description} - - ` - : nothing} - - - - ` - : nothing} - ` - : html` -

- ${this.supervisor.localize("update_available.updating", { - name: this._name, - version: this._version_latest, - })} -

`} -
- ${this._version !== this._version_latest && !this._updating - ? html` -
- ${changelog - ? html` - - ${this.supervisor.localize( - "update_available.open_release_notes" - )} - - ` - : nothing} - - - ${this.supervisor.localize("common.update")} - -
- ` - : nothing} -
- `; - } - - protected firstUpdated(changedProps: PropertyValues) { - super.firstUpdated(changedProps); - const pathPart = this.route?.path.substring(1, this.route.path.length); - const updateType = ["core", "os", "supervisor"].includes(pathPart) - ? pathPart - : "addon"; - this._updateType = updateType as UpdateType; - - switch (updateType) { - case "addon": - if (!this.addonSlug) { - this.addonSlug = pathPart; - } - this._loadAddonData(); - break; - case "core": - this._loadCoreData(); - break; - case "supervisor": - this._loadSupervisorData(); - break; - case "os": - this._loadOsData(); - break; - } - } - - private _computeCreateBackupTexts(): - | { title: string; description?: string } - | undefined { - // App backup - if ( - this._updateType === "addon" && - atLeastVersion(this.hass.config.version, 2025, 2, 0) - ) { - const version = this._version; - return { - title: this.supervisor.localize("update_available.create_backup.app"), - description: this.supervisor.localize( - "update_available.create_backup.app_description", - { version: version } - ), - }; - } - - // Old behavior - if (this._updateType && ["core", "addon"].includes(this._updateType)) { - return { - title: this.supervisor.localize( - "update_available.create_backup.generic" - ), - }; - } - return undefined; - } - - get _shouldCreateBackup(): boolean { - if (this._updateType && !["core", "addon"].includes(this._updateType)) { - return false; - } - const createBackupSwitch = this.shadowRoot?.getElementById( - "create-backup" - ) as HaSwitch; - if (createBackupSwitch) { - return createBackupSwitch.checked; - } - return true; - } - - get _version(): string { - return this._updateType - ? this._updateType === "addon" - ? this._addonInfo!.version - : this.supervisor[this._updateType]?.version || "" - : ""; - } - - get _version_latest(): string { - return this._updateType - ? this._updateType === "addon" - ? this._addonInfo!.version_latest - : this.supervisor[this._updateType]?.version_latest || "" - : ""; - } - - get _name(): string { - return this._updateType - ? this._updateType === "addon" - ? this._addonInfo!.name - : SUPERVISOR_UPDATE_NAMES[this._updateType] - : ""; - } - - private async _loadAddonData() { - try { - this._addonInfo = await fetchHassioAddonInfo(this.hass, this.addonSlug!); - } catch (err) { - showAlertDialog(this, { - title: this._updateType, - text: extractApiErrorMessage(err), - }); - return; - } - const addonStoreInfo = - !this._addonInfo.detached && !this._addonInfo.available - ? this._addonStoreInfo( - this._addonInfo.slug, - this.supervisor.store.addons - ) - : undefined; - - if (this._addonInfo.changelog) { - try { - const content = await fetchHassioAddonChangelog( - this.hass, - this.addonSlug! - ); - this._changelogContent = extractChangelog(this._addonInfo, content); - } catch (err) { - this._error = extractApiErrorMessage(err); - return; - } - } - - if (!this._addonInfo.available && addonStoreInfo) { - if ( - !addonArchIsSupported( - this.supervisor.info.supported_arch, - this._addonInfo.arch - ) - ) { - this._error = this.supervisor.localize( - "app.dashboard.not_available_arch" - ); - } else { - this._error = this.supervisor.localize( - "app.dashboard.not_available_version", - { - core_version_installed: this.supervisor.core.version, - core_version_needed: addonStoreInfo.homeassistant, - } - ); - } - } - } - - private async _loadSupervisorData() { - try { - const supervisor = await fetchHassioSupervisorInfo(this.hass); - fireEvent(this, "supervisor-update", { supervisor }); - } catch (err) { - showAlertDialog(this, { - title: this._updateType, - text: extractApiErrorMessage(err), - }); - } - } - - private async _loadCoreData() { - try { - const core = await fetchHassioHomeAssistantInfo(this.hass); - fireEvent(this, "supervisor-update", { core }); - } catch (err) { - showAlertDialog(this, { - title: this._updateType, - text: extractApiErrorMessage(err), - }); - } - } - - private async _loadOsData() { - try { - const os = await fetchHassioHassOsInfo(this.hass); - fireEvent(this, "supervisor-update", { os }); - } catch (err) { - showAlertDialog(this, { - title: this._updateType, - text: extractApiErrorMessage(err), - }); - } - } - - private async _update() { - if (this._shouldCreateBackup && this.supervisor.info.state === "freeze") { - this._error = this.supervisor.localize("backup.backup_already_running"); - return; - } - this._error = undefined; - this._updating = true; - - try { - if (this._updateType === "addon") { - await updateHassioAddon( - this.hass, - this.addonSlug!, - this._shouldCreateBackup - ); - } else if (this._updateType === "core") { - await updateCore(this.hass, this._shouldCreateBackup); - } else if (this._updateType === "os") { - await updateOS(this.hass); - } else if (this._updateType === "supervisor") { - await updateSupervisor(this.hass); - } - } catch (err: any) { - if (this.hass.connection.connected && !ignoreSupervisorError(err)) { - this._error = extractApiErrorMessage(err); - this._updating = false; - return; - } - } - fireEvent(this, "update-complete"); - this._updating = false; - } - - static get styles(): CSSResultGroup { - return [ - haStyle, - css` - :host { - display: block; - } - ha-card { - margin: auto; - } - a { - text-decoration: none; - color: var(--primary-text-color); - } - .card-actions { - display: flex; - justify-content: space-between; - } - - ha-spinner { - display: block; - margin: 32px; - text-align: center; - } - - .progress-text { - text-align: center; - } - - ha-markdown { - padding-bottom: 8px; - } - - hr { - border-color: var(--divider-color); - border-bottom: none; - margin: 16px 0 0 0; - } - - ha-md-list { - padding: 0; - margin-bottom: -16px; - } - - ha-md-list-item { - --md-list-item-leading-space: 0; - --md-list-item-trailing-space: 0; - --md-item-overflow: visible; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "update-available-card": UpdateAvailableCard; - } -} diff --git a/hassio/src/update-available/update-available-dashboard.ts b/hassio/src/update-available/update-available-dashboard.ts deleted file mode 100644 index d53820dd4d..0000000000 --- a/hassio/src/update-available/update-available-dashboard.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; -import { customElement, property } from "lit/decorators"; -import type { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { goBack } from "../../../src/common/navigate"; -import "../../../src/layouts/hass-subpage"; -import type { HomeAssistant, Route } from "../../../src/types"; -import "./update-available-card"; - -@customElement("update-available-dashboard") -class UpdateAvailableDashboard extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @property({ attribute: false }) public supervisor!: Supervisor; - - @property({ type: Boolean }) public narrow = false; - - @property({ attribute: false }) public route!: Route; - - protected render(): TemplateResult { - return html` - - - - `; - } - - private _updateComplete() { - goBack(); - } - - static styles = css` - hass-subpage { - --app-header-background-color: var(--primary-background-color); - --app-header-text-color: var(--sidebar-text-color); - } - update-available-card { - margin: auto; - margin-top: 16px; - margin-bottom: 24px; - max-width: 600px; - } - `; -} - -declare global { - interface HTMLElementTagNameMap { - "update-available-dashboard": UpdateAvailableDashboard; - } -} diff --git a/hassio/src/util/addon.ts b/hassio/src/util/addon.ts deleted file mode 100644 index fe9f5f9a9c..0000000000 --- a/hassio/src/util/addon.ts +++ /dev/null @@ -1,30 +0,0 @@ -import memoizeOne from "memoize-one"; -import type { HassioAddonDetails } from "../../../src/data/hassio/addon"; -import type { SupervisorArch } from "../../../src/data/supervisor/supervisor"; - -export const addonArchIsSupported = memoizeOne( - (supported_archs: SupervisorArch[], addon_archs: SupervisorArch[]) => - addon_archs.some((arch) => supported_archs.includes(arch)) -); - -export const extractChangelog = ( - addon: HassioAddonDetails, - content: string -): string => { - if (content.startsWith("# Changelog")) { - content = content.substr(12, content.length); - } - if ( - content.includes(`# ${addon.version}`) && - content.includes(`# ${addon.version_latest}`) - ) { - const newcontent = content.split(`# ${addon.version}`)[0]; - if (newcontent.includes(`# ${addon.version_latest}`)) { - // Only change the content if the new version still exist - // if the changelog does not have the newests version on top - // this will not be true, and we don't modify the content - content = newcontent; - } - } - return content; -}; diff --git a/script/core b/script/core index c9848c4625..0f83afbdf1 100755 --- a/script/core +++ b/script/core @@ -53,23 +53,9 @@ logger: default: info logs: homeassistant.components.frontend: debug -" >> "${WD}/config/configuration.yaml" - if [ -n "${HASSIO}" ]; then - echo " -# frontend: -# development_repo: ${WD} - -hassio: - development_repo: ${WD}" >> "${WD}/config/configuration.yaml" - else - echo " frontend: - development_repo: ${WD} - -# hassio: -# development_repo: ${WD}" >> "${WD}/config/configuration.yaml" - fi + development_repo: ${WD}" >> "${WD}/config/configuration.yaml" >> "${WD}/config/configuration.yaml" if [ -n "${CODESPACES}" ]; then echo " diff --git a/src/components/ha-code-editor.ts b/src/components/ha-code-editor.ts index b3085aa775..9e028801e5 100644 --- a/src/components/ha-code-editor.ts +++ b/src/components/ha-code-editor.ts @@ -691,15 +691,10 @@ export class HaCodeEditor extends ReactiveElement { private _getIconItems = async (): Promise => { if (!this._iconList) { - let iconList: { + const iconList: { name: string; keywords: string[]; - }[]; - if (__SUPERVISOR__) { - iconList = []; - } else { - iconList = (await import("../../build/mdi/iconList.json")).default; - } + }[] = (await import("../../build/mdi/iconList.json")).default; this._iconList = iconList.map((icon) => ({ type: "variable", diff --git a/src/components/ha-menu-button.ts b/src/components/ha-menu-button.ts index 58688927de..547fac3089 100644 --- a/src/components/ha-menu-button.ts +++ b/src/components/ha-menu-button.ts @@ -9,8 +9,6 @@ import "./ha-icon-button"; @customElement("ha-menu-button") class HaMenuButton extends LitElement { - @property({ type: Boolean }) public hassio = false; - @property({ type: Boolean }) public narrow = false; @property({ attribute: false }) public hass!: HomeAssistant; @@ -59,18 +57,6 @@ class HaMenuButton extends LitElement { `; } - protected firstUpdated(changedProps) { - super.firstUpdated(changedProps); - if (!this.hassio) { - return; - } - // This component is used on Hass.io too, but Hass.io might run the UI - // on older frontends too, that don't have an always visible menu button - // in the sidebar. - this._alwaysVisible = - (Number((window.parent as any).frontendVersion) || 0) < 20190710; - } - protected willUpdate(changedProps) { super.willUpdate(changedProps); diff --git a/src/data/hassio/addon.ts b/src/data/hassio/addon.ts index 3288da1aa1..bebc60a6a5 100644 --- a/src/data/hassio/addon.ts +++ b/src/data/hassio/addon.ts @@ -8,7 +8,7 @@ import type { HassioResponse } from "./common"; import { extractApiErrorMessage, hassioApiResultExtractor } from "./common"; export type AddonCapability = Exclude< - keyof TranslationDict["supervisor"]["app"]["dashboard"]["capability"], + keyof TranslationDict["ui"]["panel"]["config"]["apps"]["dashboard"]["capability"], "label" | "role" | "stages" >; export type AddonStage = "stable" | "experimental" | "deprecated"; diff --git a/src/data/hassio/resolution.ts b/src/data/hassio/resolution.ts index 5b228dc386..09dc255280 100644 --- a/src/data/hassio/resolution.ts +++ b/src/data/hassio/resolution.ts @@ -4,8 +4,8 @@ import type { HassioResponse } from "./common"; import { hassioApiResultExtractor } from "./common"; export interface HassioResolution { - unsupported: (keyof TranslationDict["supervisor"]["system"]["supervisor"]["unsupported_reason"])[]; - unhealthy: (keyof TranslationDict["supervisor"]["system"]["supervisor"]["unhealthy_reason"])[]; + unsupported: (keyof TranslationDict["ui"]["dialogs"]["unsupported"]["reasons"])[]; + unhealthy: (keyof TranslationDict["ui"]["dialogs"]["unhealthy"]["reasons"])[]; issues: string[]; suggestions: string[]; } diff --git a/src/data/iconsets.ts b/src/data/iconsets.ts index 8dbc53259e..4c469993f7 100644 --- a/src/data/iconsets.ts +++ b/src/data/iconsets.ts @@ -12,15 +12,13 @@ const getStore = memoizeOne(async () => { const iconStore = createStore("hass-icon-db", "mdi-icon-store"); // Supervisor doesn't use icons, and should not update/downgrade the icon DB. - if (!__SUPERVISOR__) { - const version = await get("_version", iconStore); + const version = await get("_version", iconStore); - if (!version) { - set("_version", iconMetadata.version, iconStore); - } else if (version !== iconMetadata.version) { - await clear(iconStore); - set("_version", iconMetadata.version, iconStore); - } + if (!version) { + set("_version", iconMetadata.version, iconStore); + } else if (version !== iconMetadata.version) { + await clear(iconStore); + set("_version", iconMetadata.version, iconStore); } return iconStore; diff --git a/src/data/supervisor/supervisor.ts b/src/data/supervisor/supervisor.ts index 38a2cc63a4..c62f0910dd 100644 --- a/src/data/supervisor/supervisor.ts +++ b/src/data/supervisor/supervisor.ts @@ -1,11 +1,6 @@ import type { Connection } from "home-assistant-js-websocket"; import { getCollection } from "home-assistant-js-websocket"; import type { Store } from "home-assistant-js-websocket/dist/store"; -import type { - FlattenObjectKeys, - LocalizeFunc, -} from "../../common/translations/localize"; -import type { TranslationDict } from "../../types"; import type { HassioAddonsInfo } from "../hassio/addon"; import type { HassioHassOSInfo, HassioHostInfo } from "../hassio/host"; import type { NetworkInfo } from "../hassio/network"; @@ -61,8 +56,6 @@ export interface SupervisorEvent { [key: string]: any; } -export type SupervisorKeys = FlattenObjectKeys; - export interface Supervisor { host: HassioHostInfo; supervisor: HassioSupervisorInfo; @@ -73,7 +66,6 @@ export interface Supervisor { os: HassioHassOSInfo; addon: HassioAddonsInfo; store: SupervisorStore; - localize: LocalizeFunc; } export const supervisorApiWsRequest = ( diff --git a/src/layouts/hass-subpage.ts b/src/layouts/hass-subpage.ts index 1a9394284b..a7ac562877 100644 --- a/src/layouts/hass-subpage.ts +++ b/src/layouts/hass-subpage.ts @@ -22,8 +22,6 @@ class HassSubpage extends LitElement { @property({ type: Boolean, reflect: true }) public narrow = false; - @property({ type: Boolean }) public supervisor = false; - // @ts-ignore @restoreScroll(".content") private _savedScrollPos?: number; @@ -34,7 +32,6 @@ class HassSubpage extends LitElement { ${this.mainPage || history.state?.root ? html` diff --git a/src/layouts/hass-tabs-subpage.ts b/src/layouts/hass-tabs-subpage.ts index ee17076a6a..0951fedff2 100644 --- a/src/layouts/hass-tabs-subpage.ts +++ b/src/layouts/hass-tabs-subpage.ts @@ -34,8 +34,6 @@ export interface PageNavigation { class HassTabsSubpage extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property({ type: Boolean }) public supervisor = false; - @property({ attribute: false }) public localizeFunc?: LocalizeFunc; @property({ type: String, attribute: "back-path" }) public backPath?: string; @@ -139,7 +137,6 @@ class HassTabsSubpage extends LitElement { ${this.mainPage || (!this.backPath && history.state?.root) ? html` diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index 7bf255a04e..b1a5c220e8 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -57,7 +57,6 @@ declare global { // for fire event interface HASSDomEvents { "ha-refresh-cloud-status": undefined; - "ha-refresh-supervisor": undefined; } } diff --git a/src/panels/config/logs/error-log-card.ts b/src/panels/config/logs/error-log-card.ts index 194e11a782..e9f410788b 100644 --- a/src/panels/config/logs/error-log-card.ts +++ b/src/panels/config/logs/error-log-card.ts @@ -311,8 +311,11 @@ class ErrorLogCard extends LitElement { protected willUpdate(changedProps: PropertyValues) { super.willUpdate(changedProps); if (!this.hasUpdated) { - this._streamSupported = - !__SUPERVISOR__ || atLeastVersion(this.hass.config.version, 2024, 11); + this._streamSupported = atLeastVersion( + this.hass.config.version, + 2024, + 11 + ); // just needs to be loaded once, because only the host endpoints provide boots information this._loadBoots(); diff --git a/src/state/quick-bar-mixin.ts b/src/state/quick-bar-mixin.ts index f0dd705560..34df400102 100644 --- a/src/state/quick-bar-mixin.ts +++ b/src/state/quick-bar-mixin.ts @@ -12,7 +12,6 @@ import type { import { showQuickBar } from "../dialogs/quick-bar/show-dialog-quick-bar"; import { showShortcutsDialog } from "../dialogs/shortcuts/show-shortcuts-dialog"; import { showVoiceCommandDialog } from "../dialogs/voice-command-dialog/show-ha-voice-command-dialog"; -import type { Redirects } from "../panels/my/ha-panel-my"; import type { Constructor, HomeAssistant } from "../types"; import { storeState } from "../util/ha-pref-storage"; import { showToast } from "../util/toast"; @@ -146,16 +145,8 @@ export default >(superClass: T) => const targetPath = mainWindow.location.pathname; const myParams = new URLSearchParams(); - let redirects: Redirects; - - if (targetPath.startsWith("/hassio")) { - const myPanelSupervisor = - await import("../../hassio/src/hassio-my-redirect"); - redirects = myPanelSupervisor.REDIRECTS; - } else { - const myPanel = await import("../panels/my/ha-panel-my"); - redirects = myPanel.getMyRedirects(); - } + const myPanel = await import("../panels/my/ha-panel-my"); + const redirects = myPanel.getMyRedirects(); for (const [slug, redirect] of Object.entries(redirects)) { if (!targetPath.startsWith(redirect.redirect)) { diff --git a/src/translations/en.json b/src/translations/en.json index 3e5f77b146..d39ebbda8f 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -414,7 +414,7 @@ "cancel": "Cancel", "delete": "Delete", "delete_all": "Delete all", - "download": "[%key:supervisor::backup::download%]", + "download": "Download", "duplicate": "Duplicate", "remove": "Remove", "enable": "Enable", @@ -2017,37 +2017,37 @@ "triggers": "Triggers" }, "unsupported": { - "title": "[%key:supervisor::system::supervisor::unsupported_title%]", - "description": "[%key:supervisor::system::supervisor::unsupported_description%]", + "title": "You are running an unsupported installation", + "description": "Below is a list of issues found with your installation, open the links to learn how you can resolve the issues.", "reasons": { - "apparmor": "[%key:supervisor::system::supervisor::unsupported_reason::apparmor%]", - "content_trust": "[%key:supervisor::system::supervisor::unsupported_reason::content_trust%]", - "dbus": "[%key:supervisor::system::supervisor::unsupported_reason::dbus%]", - "docker_configuration": "[%key:supervisor::system::supervisor::unsupported_reason::docker_configuration%]", - "docker_version": "[%key:supervisor::system::supervisor::unsupported_reason::docker_version%]", - "job_conditions": "[%key:supervisor::system::supervisor::unsupported_reason::job_conditions%]", - "lxc": "[%key:supervisor::system::supervisor::unsupported_reason::lxc%]", - "network_manager": "[%key:supervisor::system::supervisor::unsupported_reason::network_manager%]", - "os": "[%key:supervisor::system::supervisor::unsupported_reason::os%]", - "os_agent": "[%key:supervisor::system::supervisor::unsupported_reason::os_agent%]", - "privileged": "[%key:supervisor::system::supervisor::unsupported_reason::privileged%]", - "software": "[%key:supervisor::system::supervisor::unsupported_reason::software%]", - "source_mods": "[%key:supervisor::system::supervisor::unsupported_reason::source_mods%]", - "systemd": "[%key:supervisor::system::supervisor::unsupported_reason::systemd%]", - "systemd_resolved": "[%key:supervisor::system::supervisor::unsupported_reason::systemd_resolved%]" + "apparmor": "AppArmor is not enabled on the host", + "content_trust": "Content-trust validation is disabled", + "dbus": "DBUS", + "docker_configuration": "Docker configuration", + "docker_version": "Docker version", + "job_conditions": "Ignored job conditions", + "lxc": "LXC", + "network_manager": "Network manager", + "os": "Operating system", + "os_agent": "OS Agent", + "privileged": "Supervisor is not privileged", + "software": "Unsupported software detected", + "source_mods": "Source modifications", + "systemd": "Systemd", + "systemd_resolved": "Systemd-Resolved" } }, "unhealthy": { - "title": "[%key:supervisor::system::supervisor::unhealthy_title%]", - "description": "[%key:supervisor::system::supervisor::unhealthy_description%]", + "title": "Your installation is unhealthy", + "description": "Running an unhealthy installation will cause issues. Below is a list of issues found with your installation, open the links to learn how you can resolve the issues.", "reasons": { - "docker": "[%key:supervisor::system::supervisor::unhealthy_reason::docker%]", - "oserror_bad_message": "[%key:supervisor::system::supervisor::unhealthy_reason::oserror_bad_message%]", - "duplicate_os_installation": "[%key:supervisor::system::supervisor::unhealthy_reason::duplicate_os_installation%]", - "privileged": "[%key:supervisor::system::supervisor::unhealthy_reason::privileged%]", - "supervisor": "[%key:supervisor::system::supervisor::unhealthy_reason::supervisor%]", - "setup": "[%key:supervisor::system::supervisor::unhealthy_reason::setup%]", - "untrusted": "[%key:supervisor::system::supervisor::unhealthy_reason::untrusted%]" + "docker": "The Docker environment is not working properly", + "oserror_bad_message": "Operating System error: Bad message", + "duplicate_os_installation": "Duplicate Home Assistant OS installation", + "privileged": "Supervisor is not privileged", + "supervisor": "Supervisor was not able to update", + "setup": "Setup of the Supervisor failed", + "untrusted": "Detected untrusted content" } }, "join_beta_channel": { @@ -2414,8 +2414,8 @@ "more_updates": "Show all updates", "show": "show", "show_skipped": "Show skipped updates", - "join_beta": "[%key:supervisor::system::supervisor::join_beta_action%]", - "leave_beta": "[%key:supervisor::system::supervisor::leave_beta_action%]", + "join_beta": "Join beta channel", + "leave_beta": "Leave beta channel", "skipped": "Skipped", "update_in_progress": "Update in progress", "no_area": "No area" @@ -2836,15 +2836,15 @@ "caption": "Backups", "description": "Last backup {relative_time}", "description_no_backup": "Manage backups and restore Home Assistant to a previous state", - "create_backup": "[%key:supervisor::backup::create_backup%]", + "create_backup": "Create backup", "creating_backup": "Backup is currently being created", - "download_backup": "[%key:supervisor::backup::download_backup%]", + "download_backup": "Download backup", "remove_backup": "Delete backup", - "name": "[%key:supervisor::backup::name%]", + "name": "Backup name", "path": "Path", - "size": "[%key:supervisor::backup::size%]", - "created": "[%key:supervisor::backup::created%]", - "no_backups": "[%key:supervisor::backup::no_backups%]", + "size": "Size", + "created": "Created", + "no_backups": "You don't have any backups yet.", "backup_type": "Type", "type": { "manual": "Manual", @@ -9982,7 +9982,7 @@ "apps": "[%key:ui::panel::config::backup::data_picker::apps%]", "ssl": "[%key:ui::panel::config::backup::data_picker::ssl%]" }, - "restore_no_home_assistant": "[%key:supervisor::backup::restore_no_home_assistant%]", + "restore_no_home_assistant": "Backup does not contain Home Assistant data. To restore Home Assistant you need a backup of Home Assistant Core.", "in_progress": "Restore in progress", "in_progress_description": "The restore process is running in the background. Home Assistant will automatically start again once the restore is complete. Please be patient, this can take a while. Do not close or refresh this page.", "failed": "Restore failed", @@ -9993,27 +9993,27 @@ "upload_drop": "[%key:ui::components::file-upload::secondary%]", "show_log": "Show full log", "hide_log": "Hide full log", - "full_backup": "[%key:supervisor::backup::full_backup%]", - "partial_backup": "[%key:supervisor::backup::partial_backup%]", - "name": "[%key:supervisor::backup::name%]", - "select_type": "[%key:supervisor::backup::select_type%]", - "folders": "[%key:supervisor::backup::folders%]", - "apps": "[%key:supervisor::backup::apps%]", - "password_protection": "[%key:supervisor::backup::password_protection%]", - "password": "[%key:supervisor::backup::password%]", - "confirm_password": "[%key:supervisor::backup::confirm_password%]", - "confirm_restore_partial_backup_title": "[%key:supervisor::backup::confirm_restore_partial_backup_title%]", + "full_backup": "Full backup", + "partial_backup": "Partial backup", + "name": "Backup name", + "select_type": "Select what to restore", + "folders": "Folders", + "apps": "Apps", + "password_protection": "Password protection", + "password": "Backup encryption key", + "confirm_password": "Confirm encryption key", + "confirm_restore_partial_backup_title": "Restore partial backup", "confirm_restore_partial_backup_text": "The backup will be restored. Depending on the size of the backup, this can take up to 45 min. Home Assistant needs to shut down and the restore progress is running in the background. If it succeeds, Home Assistant will automatically start again and you see the login screen. If it fails it will bring you back to the onboarding.", - "confirm_restore_full_backup_title": "[%key:supervisor::backup::confirm_restore_full_backup_title%]", + "confirm_restore_full_backup_title": "Restore full backup", "confirm_restore_full_backup_text": "Depending on the size of the backup, this can take up to 45 minutes. Home Assistant will restart and you will see the login screen when it’s restored.", - "restore": "[%key:supervisor::backup::restore%]", + "restore": "Restore", "close": "[%key:ui::common::close%]", "cancel": "[%key:ui::common::cancel%]", "retry": "Retry", "back": "[%key:ui::common::back%]", - "restore_start_failed": "[%key:supervisor::backup::restore_start_failed%]", - "no_backup_found": "[%key:supervisor::backup::no_backup_found%]", - "unnamed_backup": "[%key:supervisor::backup::unnamed_backup%]", + "restore_start_failed": "Failed to start restore. Unknown error.", + "no_backup_found": "No backup found.", + "unnamed_backup": "Unnamed backup", "cancel_restore": { "title": "Cancel restore process?", "text": "Are you sure you want to cancel the restore process and return to the onboarding?", @@ -10175,594 +10175,5 @@ } } } - }, - "supervisor": { - "app": { - "failed_to_reset": "Failed to reset app configuration, {error}", - "failed_to_save": "Failed to save app configuration, {error}", - "state": { - "installed": "App is installed", - "not_installed": "App is not installed", - "not_available": "App is not available on your system" - }, - "panel": { - "configuration": "Configuration", - "documentation": "Documentation", - "info": "Info", - "log": "Log" - }, - "configuration": { - "no_configuration": "This app has no configuration.", - "audio": { - "header": "Audio", - "default": "Default", - "input": "Input", - "output": "Output" - }, - "options": { - "header": "Options", - "edit_in_ui": "Edit in UI", - "edit_in_yaml": "Edit in YAML", - "invalid_yaml": "Invalid YAML", - "show_unused_optional": "Show unused optional configuration options" - }, - "network": { - "container": "Container", - "disabled": "Disabled", - "header": "Network", - "show_disabled": "Show disabled ports", - "introduction": "Change the ports on your host that are exposed by the app" - } - }, - "dashboard": { - "changelog": "Changelog", - "current_version": "Current version: {version}", - "cpu_usage": "App CPU usage", - "ram_usage": "App RAM usage", - "hostname": "Hostname", - "new_update_available": "{name} {version} is available", - "not_available_arch": "This app is not compatible with the processor of your device or the operating system you have installed on your device.", - "not_available_version": "You are running Home Assistant {core_version_installed}, to update to this version of the app you need at least version {core_version_needed} of Home Assistant", - "visit_app_page": "Visit the {name} page for more details.", - "restart": "Restart", - "start": "Start", - "stop": "Stop", - "install": "Install", - "uninstall": "Uninstall", - "rebuild": "Rebuild", - "open_web_ui": "Open web UI", - "protection_mode": { - "title": "Protection mode is disabled!", - "content": "Protection mode on this app is disabled! This gives the app full access to the entire system, which adds security risks, and could damage your system when used incorrectly. Only disable the protection mode if you know, need AND trust the source of this app.", - "enable": "[%key:ui::common::enable%]" - }, - "capability": { - "stage": { - "title": "App stage", - "description": "Apps can have one of three stages:\n\n{icon_stable} **Stable**: These are apps ready to be used in production.\n\n{icon_experimental} **Experimental**: These may contain bugs, and may be unfinished.\n\n{icon_deprecated} **Deprecated**: These apps will no longer receive any updates." - }, - "rating": { - "title": "App security rating", - "description": "Home Assistant provides a security rating to each of the apps, which indicates the risks involved when using this app. The more access an app requires on your system, the lower the score, thus raising the possible security risks.\n\nA score is on a scale from 1 to 8. Where 1 is the lowest score (considered the most insecure and highest risk) and a score of 8 is the highest score (considered the most secure and lowest risk)." - }, - "host_network": { - "title": "Host network", - "description": "Apps usually run in their own isolated network layer, which prevents them from accessing the network of the host operating system. In some cases, this network isolation can limit apps in providing their services and therefore, the isolation can be lifted by the app author, giving the app full access to the network capabilities of the host machine. This gives the app more networking capabilities but lowers the security, hence, the security rating of the app will be lowered when this option is used by the app." - }, - "homeassistant_api": { - "title": "Home Assistant API access", - "description": "This app is allowed to access your running Home Assistant instance directly via the Home Assistant API. This mode handles authentication for the app as well, which enables an app to interact with Home Assistant without the need for additional authentication tokens." - }, - "full_access": { - "title": "Full hardware access", - "description": "This app is given full access to the hardware of your system, by request of the app author. Access is comparable to the privileged mode in Docker. Since this opens up possible security risks, this feature impacts the app security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the app manually. Only disable the protection mode if you know, need AND trust the source of this app." - }, - "hassio_api": { - "title": "Supervisor API access", - "description": "The app was given access to the Supervisor API, by request of the app author. By default, the app can access general version information of your system. When the app requests 'manager' or 'admin' level access to the API, it will gain access to control multiple parts of your Home Assistant system. This permission is indicated by this badge and will impact the security score of the app negatively." - }, - "docker_api": { - "title": "Full Docker access", - "description": "The app author has requested the app to have management access to the Docker instance running on your system. This mode gives the app full access and control to your entire Home Assistant system, which adds security risks, and could damage your system when misused. Therefore, this feature impacts the app security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the app manually. Only disable the protection mode if you know, need AND trust the source of this app." - }, - "host_pid": { - "title": "Host processes namespace", - "description": "Usually, the processes run by the app are isolated from all other system processes. The app author has requested the app to have access to the system processes running on the host system instance, and allow the app to spawn processes on the host system as well. This mode gives the app full access and control to your entire Home Assistant system, which adds security risks and could damage your system when misused. Therefore, this feature impacts the app security score negatively.\n\nThis level of access is not granted automatically and needs to be confirmed by you. To do this, you need to disable the protection mode on the app manually. Only disable the protection mode if you know, need AND trust the source of this app." - }, - "apparmor": { - "title": "AppArmor", - "description": "AppArmor ('Application Armor') is a Linux kernel security module that restricts app capabilities like network access, raw socket access, and permission to read, write, or execute specific files.\n\nApp authors can provide their security profiles, optimized for the app, or request it to be disabled. If AppArmor is disabled, it will raise security risks and therefore, has a negative impact on the security score of the app." - }, - "auth_api": { - "title": "Home Assistant authentication", - "description": "An app can authenticate users against Home Assistant, allowing apps to give users the possibility to log in to applications running inside apps, using their Home Assistant username/password. This badge indicates if the app author requests this capability." - }, - "ingress": { - "title": "Ingress", - "description": "This app is using Ingress to embed its interface securely into Home Assistant." - }, - "signed": { - "title": "Signed", - "description": "This app signed and verified with Codenotary Community Attestation Service (CAS)." - }, - "label": { - "core": "Core", - "rating": "rating", - "hardware": "hardware", - "host": "host", - "hassio": "hassio", - "docker": "docker", - "host_pid": "host pid", - "apparmor": "apparmor", - "auth": "auth", - "ingress": "ingress", - "signed": "Signed" - }, - "stages": { - "experimental": "Experimental", - "deprecated": "Deprecated" - }, - "role": { - "manager": "manager", - "default": "default", - "homeassistant": "homeassistant", - "backup": "backup", - "admin": "admin" - } - }, - "option": { - "boot": { - "title": "Start on boot", - "description": "Make the app start during a system boot" - }, - "watchdog": { - "title": "Watchdog", - "description": "This will restart the app if it crashes" - }, - "auto_update": { - "title": "Automatically update", - "description": "Automatically update the app when a new version is available" - }, - "ingress_panel": { - "title": "Add to sidebar", - "description": "Allows users to show or hide the app" - }, - "protected": { - "title": "Protection mode", - "description": "Blocks elevated system access from the app" - } - }, - "action_error": { - "uninstall": "Failed to uninstall app", - "install": "Failed to install app", - "stop": "Failed to stop app", - "rebuild": "Failed to rebuild app", - "restart": "Failed to restart app", - "start": "Failed to start app", - "go_to_config": "Edit config", - "start_invalid_config": "Go to configuration", - "validate_config": "Failed to validate app configuration", - "get_changelog": "Failed to get app changelog" - } - }, - "documentation": { - "get_documentation": "Failed to get app documentation, {error}" - }, - "logs": { - "get_logs": "Failed to get app logs, {error}" - }, - "system_managed": { - "badge": "System-managed", - "title": "This app is managed by Home Assistant", - "description": "Manually modifying this configuration may cause the app or integration to stop working properly.", - "managed_by": "Managed by", - "take_control": "Take control" - } - }, - "common": { - "cancel": "[%key:ui::common::cancel%]", - "yes": "[%key:ui::common::yes%]", - "no": "[%key:ui::common::no%]", - "add": "[%key:supervisor::dialog::repositories::add%]", - "failed_to_restart_name": "Failed to restart {name}", - "failed_to_update_name": "Failed to update {name}", - "learn_more": "Learn more", - "new_version_available": "New version available", - "newest_version": "Newest version", - "refresh": "[%key:ui::common::refresh%]", - "release_notes": "Release notes", - "reload": "Reload", - "reset_defaults": "Reset to defaults", - "reset_options": "Reset options", - "restart_name": "Restart {name}", - "restart": "Restart", - "running_version": "You are currently running version {version}", - "save": "[%key:ui::common::save%]", - "close": "[%key:ui::common::close%]", - "back": "[%key:ui::common::back%]", - "menu": "[%key:ui::common::menu%]", - "show": "[%key:ui::panel::config::updates::show%]", - "show_more": "Show more information about this", - "update_available": "{count, plural,\n one {Update}\n other {{count} updates}\n} pending", - "update": "Update", - "version": "Version", - "error": { - "unknown": "Unknown error", - "update_failed": "Update failed" - } - }, - "update_available": { - "update_name": "Update {name}", - "open_release_notes": "Open release notes", - "description": "You have {version} installed. Press update to update to version {newest_version}", - "updating": "Updating {name} to version {version}", - "no_update": "No update available for {name}", - "create_backup": { - "app": "[%key:ui::dialogs::more_info_control::update::create_backup::app%]", - "app_description": "[%key:ui::dialogs::more_info_control::update::create_backup::app_description%]", - "generic": "[%key:ui::dialogs::more_info_control::update::create_backup::generic%]" - } - }, - "confirm": { - "restart": { - "title": "[%key:supervisor::common::restart_name%]", - "text": "Are you sure you want to restart {name}?" - }, - "reset_options": { - "title": "Reset options", - "text": "Are you sure you want to reset all your options?" - } - }, - "dashboard": { - "app_new_version": "New version available", - "app_running": "App is running", - "app_stopped": "App is stopped", - "apps": "Installed apps", - "no_apps": "You don't have any apps installed yet. Head over to the app store to get started!", - "search_apps": "Search apps" - }, - "store": { - "missing_apps": "Missing apps? Enable advanced mode in your user profile page", - "no_results_found": "No results found in {repository}.", - "registries": "Registries", - "repositories": "Repositories", - "check_updates": "Check for updates" - }, - "panel": { - "apps": "Apps", - "dashboard": "Dashboard", - "backups": "Backups", - "store": "App store", - "system": "System" - }, - "my": { - "not_supported": "[%key:ui::panel::my::not_supported%]", - "faq_link": "[%key:ui::panel::my::faq_link%]", - "add_app_repository_title": "Missing app repository", - "add_app_repository_description": "The app ''{app}'' is a part of the app repository ''{repository}'', this repository is missing on your system, do you want to add that now?", - "error": "[%key:ui::panel::my::error%]", - "error_app_not_found": "App not found", - "error_repository_not_found": "The required repository for this app was not found", - "error_app_not_installed": "The requested app is not installed. Please install it first", - "error_app_no_ingress": "The requested app does not support Ingress" - }, - "ingress": { - "error_app_info": "Unable to fetch app info to start Ingress", - "error_app_not_installed": "The app is not installed. Please install it first", - "error_app_not_supported": "This app does not support Ingress", - "error_app_not_running": "The app is not running. Do you want to start it now?", - "start_app": "Start app", - "app_starting": "The app is starting, this can take some time...", - "error_starting_app": "Error starting the app", - "error_creating_session": "Unable to create an Ingress session", - "error_app_not_ready": "The app seems to not be ready, it might still be starting. Do you want to try again?", - "retry": "Retry" - }, - "system": { - "log": { - "log_provider": "Log provider", - "get_logs": "Failed to get {provider} logs, {error}" - }, - "supervisor": { - "cpu_usage": "Supervisor CPU usage", - "ram_usage": "Supervisor RAM usage", - "failed_to_set_option": "Failed to set Supervisor option", - "failed_to_reload": "Failed to reload the Supervisor", - "failed_to_update": "Failed to update the Supervisor", - "unsupported_title": "You are running an unsupported installation", - "unsupported_description": "Below is a list of issues found with your installation, open the links to learn how you can resolve the issues.", - "unhealthy_title": "Your installation is unhealthy", - "unhealthy_description": "Running an unhealthy installation will cause issues. Below is a list of issues found with your installation, open the links to learn how you can resolve the issues.", - "update_supervisor": "Update the Supervisor", - "channel": "Channel", - "leave_beta_action": "Leave beta channel", - "leave_beta_description": "Get stable updates for Home Assistant OS, Core, Supervisor and Frontend", - "join_beta_action": "Join beta channel", - "join_beta_description": "Get beta updates for Home Assistant OS, Core, Supervisor and Frontend", - "share_diagnostics": "Share diagnostics", - "share_diagnostics_description": "Share crash reports and diagnostic information.", - "reload_supervisor": "Reload Supervisor", - "warning": "WARNING", - "search": "Search", - "share_diagonstics_title": "Help improve Home Assistant", - "share_diagonstics_description": "Would you want to automatically share crash reports and diagnostic information when the Supervisor encounters unexpected errors? {line_break} This will allow us to fix the problems, the information is only accessible to the Home Assistant Core team and will not be shared with others.{line_break} The data does not include any private/sensitive information and you can disable this in settings at any time you want.", - "unsupported_reason": { - "apparmor": "AppArmor is not enabled on the host", - "content_trust": "Content-trust validation is disabled", - "dbus": "DBUS", - "docker_configuration": "Docker configuration", - "docker_version": "Docker version", - "job_conditions": "Ignored job conditions", - "lxc": "LXC", - "network_manager": "Network manager", - "os": "Operating system", - "os_agent": "OS Agent", - "privileged": "Supervisor is not privileged", - "software": "Unsupported software detected", - "source_mods": "Source modifications", - "systemd": "Systemd", - "systemd_resolved": "Systemd-Resolved" - }, - "unhealthy_reason": { - "docker": "The Docker environment is not working properly", - "duplicate_os_installation": "Duplicate Home Assistant OS installation", - "oserror_bad_message": "Operating System error: Bad message", - "privileged": "Supervisor is not privileged", - "setup": "Setup of the Supervisor failed", - "supervisor": "Supervisor was not able to update", - "untrusted": "Detected untrusted content" - } - }, - "host": { - "failed_to_get_hardware_list": "Failed to get hardware list", - "failed_to_reboot": "Failed to reboot the host", - "failed_to_shutdown": "Failed to shut down the host", - "failed_to_set_hostname": "Setting hostname failed", - "failed_to_import_from_usb": "Failed to import from USB", - "failed_to_move": "Failed to move data disk", - "used_space": "Used space", - "hostname": "Hostname", - "change_hostname": "Change hostname", - "new_hostname": "Please enter a new hostname:", - "ip_address": "IP address", - "change": "Change", - "operating_system": "Operating system", - "docker_version": "Docker version", - "deployment": "Deployment", - "lifetime_used": "Lifetime used", - "reboot_host": "Reboot host", - "confirm_reboot": "Are you sure you want to reboot the host?", - "confirm_shutdown": "Are you sure you want to shut down the host?", - "shutdown_host": "Shut down host", - "hardware": "Hardware", - "import_from_usb": "Import from USB", - "move_datadisk": "Move data disk" - }, - "core": { - "cpu_usage": "Core CPU usage", - "ram_usage": "Core RAM usage" - } - }, - "backup": { - "search": "[%key:ui::panel::config::backup::picker::search%]", - "loading_backups": "Loading backups. This can take a few seconds.", - "no_backups": "You don't have any backups yet.", - "create_blocked_not_running": "Creating a backup is not possible right now because the system is in \"{state}\" state.", - "restore_blocked_not_running": "Restoring a backup is not possible right now because the system is in \"{state}\" state.", - "delete_selected": "Delete selected backups", - "delete_backup_title": "Delete backups?", - "delete_backup_text": "Do you want to delete {number} {number, plural,\n one {backup}\n other {backups}\n}?", - "delete_backup_confirm": "delete", - "selected": "{number} selected", - "failed_to_delete": "Failed to delete", - "could_not_create": "Could not create backup", - "could_not_restore": "Could not restore backup", - "upload_backup": "Upload backup", - "download_backup": "Download backup", - "create_backup": "Create backup", - "create": "Create", - "location": "Location", - "data_disk": "Data disk", - "created": "Created", - "name": "Backup name", - "type": "Backup type", - "select_type": "Select what to restore", - "full_backup": "Full backup", - "partial_backup": "Partial backup", - "apps": "Apps", - "folders": "Folders", - "size": "Size", - "password": "Backup encryption key", - "confirm_password": "Confirm encryption key", - "password_protection": "Password protection", - "enter_password": "Please enter a password.", - "passwords_not_matching": "The passwords do not match", - "backup_already_running": "A backup or restore is already running. Creating a new backup is currently not possible, try again later.", - "confirm_restore_partial_backup_title": "Restore partial backup", - "confirm_restore_partial_backup_text": "The backup will be restored. Depending on the size of the backup, this can take up to 45 min. Home Assistant needs to shut down and the restore progress is running in the background. If it succeeds, Home Assistant will automatically start again.", - "confirm_restore_full_backup_title": "Restore full backup", - "confirm_restore_full_backup_text": "Your entire system will be wiped and the backup will be restored. Depending on the size of the backup, this can take up to 45 min. Home Assistant needs to shut down and the restore progress is running in the background. If it succeeds, Home Assistant will automatically start again.", - "confirm_delete_title": "Delete backup", - "confirm_delete_text": "This backup will be permanently deleted and cannot be restored later.", - "restore": "Restore", - "close": "[%key:ui::common::close%]", - "cancel": "[%key:ui::common::cancel%]", - "delete": "[%key:ui::common::delete%]", - "download": "Download", - "more_actions": "More actions", - "remote_download_title": "Potentially slow download", - "remote_download_text": "You are accessing Home Assistant via remote access. Downloading backups over the Nabu Casa URL will take some time. If you are at home, cancel this dialog and enter your local URL, such as 'http://homeassistant.local:8123'", - "restore_start_failed": "Failed to start restore. Unknown error.", - "no_backup_found": "No backup found.", - "restore_no_home_assistant": "Backup does not contain Home Assistant data. To restore Home Assistant you need a backup of Home Assistant Core.", - "unnamed_backup": "Unnamed backup" - }, - "dialog": { - "network": { - "title": "Network settings", - "connected_to": "Connected to {ssid}", - "scan_ap": "Scan for access points", - "signal_strength": "[%key:ui::panel::config::network::supervisor::signal_strength%]", - "open": "Open", - "wep": "WEP", - "wpa": "WPA-PSK", - "wifi": "[%key:ui::panel::config::network::supervisor::wifi%]", - "wifi_password": "[%key:ui::panel::config::network::supervisor::wifi_password%]", - "warning": "If you are changing the Wi-Fi, IP or gateway addresses, you might lose the connection!", - "static": "Static", - "auto": "Automatic", - "disabled": "Disabled", - "ip_netmask": "IP address/netmask", - "netmask": "Netmask", - "gateway": "Gateway address", - "dns_servers": "DNS servers", - "unsaved": "You have unsaved changes, these will get lost if you change tabs, do you want to continue?", - "failed_to_change": "Failed to change network settings" - }, - "registries": { - "title_add": "Add new container registry", - "title_manage": "Manage container registries", - "registry": "Registry", - "username": "Username", - "password": "Password", - "no_registries": "No registries configured", - "add_registry": "Add registry", - "add_new_registry": "Add new registry", - "remove": "Remove", - "failed_to_add": "Failed to add registry", - "failed_to_remove": "Failed to remove registry" - }, - "repositories": { - "title": "Manage app repositories", - "add": "Add", - "remove": "Remove", - "used": "Repository is in use for installed apps and can't be removed.", - "no_repositories": "No repositories" - }, - "restart_app": { - "title": "Restart {name}?", - "text": "To use the new saved configuration this app must be restarted.", - "restart": "Restart" - }, - "uninstall_app": { - "title": "Uninstall {name}?", - "remove_data": "Also permanently delete this app's data", - "uninstall": "Uninstall" - }, - "hardware": { - "title": "Hardware", - "search": "Search hardware", - "subsystem": "Subsystem", - "id": "ID", - "attributes": "Attributes", - "device_path": "Device path" - }, - "backup_location": { - "title": "Change default backup location", - "options": { - "default_backup_mount": { - "name": "Default backup location", - "description": "The default location for backups." - } - } - }, - "datadisk_move": { - "title": "[%key:supervisor::system::host::move_datadisk%]", - "description": "You are currently using ''{current_path}'' as data disk. Moving data disks will reboot your device and it's estimated to take {time} minutes. Your Home Assistant installation will not be accessible during this period. Do not disconnect the power during the move!", - "select_device": "Select new data disk", - "no_devices": "No suitable attached devices found", - "moving_desc": "Rebooting and moving data disk. Please have patience", - "moving": "Moving data disk", - "loading_devices": "Loading devices", - "cancel": "[%key:ui::common::cancel%]", - "move": "Move" - } - }, - "ui": { - "components": { - "subpage-data-table": { - "filters": "[%key:ui::components::subpage-data-table::filters%]", - "show_results": "[%key:ui::components::subpage-data-table::show_results%]", - "clear_filter": "[%key:ui::components::subpage-data-table::clear_filter%]", - "close_filter": "[%key:ui::components::subpage-data-table::close_filter%]", - "exit_selection_mode": "[%key:ui::components::subpage-data-table::exit_selection_mode%]", - "enter_selection_mode": "[%key:ui::components::subpage-data-table::enter_selection_mode%]", - "sort_by": "[%key:ui::components::subpage-data-table::sort_by%]", - "group_by": "[%key:ui::components::subpage-data-table::group_by%]", - "dont_group_by": "[%key:ui::components::subpage-data-table::dont_group_by%]", - "collapse_all_groups": "[%key:ui::components::subpage-data-table::collapse_all_groups%]", - "expand_all_groups": "[%key:ui::components::subpage-data-table::expand_all_groups%]", - "select": "[%key:ui::components::subpage-data-table::select%]", - "selected": "[%key:ui::components::subpage-data-table::selected%]", - "select_all": "[%key:ui::components::subpage-data-table::select_all%]", - "select_none": "[%key:ui::components::subpage-data-table::select_none%]", - "settings": "[%key:ui::components::subpage-data-table::settings%]" - }, - "data-table": { - "settings": { - "header": "[%key:ui::components::data-table::settings::header%]", - "hide": "[%key:ui::components::data-table::settings::hide%]", - "show": "[%key:ui::components::data-table::settings::show%]", - "done": "[%key:ui::components::data-table::settings::done%]", - "restore": "[%key:ui::components::data-table::settings::restore%]" - } - } - }, - "panel": { - "config": { - "logs": { - "caption": "[%key:ui::panel::config::logs::caption%]", - "description": "[%key:ui::panel::config::logs::description%]", - "details": "[%key:ui::panel::config::logs::details%]", - "search": "[%key:ui::panel::config::logs::search%]", - "failed_get_logs": "[%key:ui::panel::config::logs::failed_get_logs%]", - "no_issues_search": "[%key:ui::panel::config::logs::no_issues_search%]", - "load_logs": "[%key:ui::panel::config::logs::load_logs%]", - "nr_of_lines": "[%key:ui::panel::config::logs::nr_of_lines%]", - "loading_log": "[%key:ui::panel::config::logs::loading_log%]", - "no_errors": "[%key:ui::panel::config::logs::no_errors%]", - "no_issues": "[%key:ui::panel::config::logs::no_issues%]", - "clear": "[%key:ui::panel::config::logs::clear%]", - "refresh": "[%key:ui::panel::config::logs::refresh%]", - "copy": "[%key:ui::panel::config::logs::copy%]", - "log_provider": "[%key:ui::panel::config::logs::log_provider%]", - "multiple_messages": "[%key:ui::panel::config::logs::multiple_messages%]", - "level": { - "critical": "[%key:ui::panel::config::logs::level::critical%]", - "error": "[%key:ui::panel::config::logs::level::error%]", - "warning": "[%key:ui::panel::config::logs::level::warning%]", - "info": "[%key:ui::panel::config::logs::level::info%]", - "debug": "[%key:ui::panel::config::logs::level::debug%]" - }, - "custom_integration": "[%key:ui::panel::config::logs::custom_integration%]", - "error_from_custom_integration": "[%key:ui::panel::config::logs::error_from_custom_integration%]", - "show_full_logs": "[%key:ui::panel::config::logs::show_full_logs%]", - "select_number_of_lines": "[%key:ui::panel::config::logs::select_number_of_lines%]", - "lines": "[%key:ui::panel::config::logs::lines%]", - "download_logs": "[%key:ui::panel::config::logs::download_logs%]", - "scroll_down_button": "[%key:ui::panel::config::logs::scroll_down_button%]", - "provider_not_found": "[%key:ui::panel::config::logs::provider_not_found%]", - "provider_not_available": "[%key:ui::panel::config::logs::provider_not_available%]", - "haos_boots_title": "[%key:ui::panel::config::logs::haos_boots_title%]", - "show_haos_boots": "[%key:ui::panel::config::logs::show_haos_boots%]", - "hide_haos_boots": "[%key:ui::panel::config::logs::hide_haos_boots%]", - "full_width": "[%key:ui::panel::config::logs::full_width%]", - "wrap_lines": "[%key:ui::panel::config::logs::wrap_lines%]", - "current": "[%key:ui::panel::config::logs::current%]", - "previous": "[%key:ui::panel::config::logs::previous%]", - "startups_ago": "[%key:ui::panel::config::logs::startups_ago%]", - "detail": { - "logger": "[%key:ui::panel::config::logs::detail::logger%]", - "source": "[%key:ui::panel::config::logs::detail::source%]", - "integration": "[%key:ui::panel::config::integrations::integration%]", - "documentation": "[%key:ui::panel::config::logs::detail::documentation%]", - "issues": "[%key:ui::panel::config::logs::detail::issues%]", - "first_occurred": "[%key:ui::panel::config::logs::detail::first_occurred%]", - "last_logged": "[%key:ui::panel::config::logs::detail::last_logged%]" - } - } - } - } - } } } diff --git a/src/types.ts b/src/types.ts index 80f523820e..7b5381a1d6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -37,7 +37,6 @@ declare global { var __VERSION__: string; var __STATIC_PATH__: string; var __BACKWARDS_COMPAT__: boolean; - var __SUPERVISOR__: boolean; var __HASS_URL__: string; /* eslint-enable @typescript-eslint/naming-convention */ diff --git a/test/vitest.config.ts b/test/vitest.config.ts index 6c2fff36f7..d9c1cd4b80 100644 --- a/test/vitest.config.ts +++ b/test/vitest.config.ts @@ -15,7 +15,6 @@ export default defineConfig({ "src/data/**/*", "src/common/**/*", "src/external_app/**/*", - "src/hassio/**/*", "src/panels/**/*", "src/util/**/*", ],