diff --git a/CHANGELOG.md b/CHANGELOG.md index e14d9c94a..462cc5616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,9 @@ All notable changes to homebridge-config-ui-x will be documented in this file. - add power options modal (#1820) - remove hb-ui card from plugins page (#1830) - add some support links (#1833) -- plugin logs feature (#1834) +- add plugin logs feature (#1834) - update module headers (#1836) -- restart modals, tidy plugin card +- use restart modals, tidy plugin card ### Translation Changes @@ -20,6 +20,7 @@ All notable changes to homebridge-config-ui-x will be documented in this file. ### Other Changes - Add Raspberry Pi 5 to list of Pi devices in bug-report template (#1824) (@jsiegenthaler) +- add api work for plugin icons ## 4.53.0 (2023-11-24) diff --git a/package-lock.json b/package-lock.json index 4b27405d0..2dc8ea2b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "commander": "11.1.0", "dayjs": "1.11.10", "fastify": "4.24.3", - "fs-extra": "11.1.1", + "fs-extra": "11.2.0", "jsonwebtoken": "9.0.2", "lodash": "4.17.21", "node-cache": "5.1.2", @@ -78,8 +78,8 @@ "@types/tar": "^6.1.10", "@types/tcp-port-used": "^1.0.4", "@types/unzipper": "^0.10.9", - "@typescript-eslint/eslint-plugin": "^6.12.0", - "@typescript-eslint/parser": "^6.12.0", + "@typescript-eslint/eslint-plugin": "^6.13.0", + "@typescript-eslint/parser": "^6.13.0", "babel-jest": "^29.7.0", "concurrently": "^8.2.2", "eslint": "^8.54.0", @@ -2722,16 +2722,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", - "integrity": "sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.0.tgz", + "integrity": "sha512-HTvbSd0JceI2GW5DHS3R9zbarOqjkM9XDR7zL8eCsBUO/eSiHcoNE7kSL5sjGXmVa9fjH5LCfHDXNnH4QLp7tQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.12.0", - "@typescript-eslint/type-utils": "6.12.0", - "@typescript-eslint/utils": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0", + "@typescript-eslint/scope-manager": "6.13.0", + "@typescript-eslint/type-utils": "6.13.0", + "@typescript-eslint/utils": "6.13.0", + "@typescript-eslint/visitor-keys": "6.13.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2757,15 +2757,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz", - "integrity": "sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.0.tgz", + "integrity": "sha512-VpG+M7GNhHLI/aTDctqAV0XbzB16vf+qDX9DXuMZSe/0bahzDA9AKZB15NDbd+D9M4cDsJvfkbGOA7qiZ/bWJw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.12.0", - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/typescript-estree": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0", + "@typescript-eslint/scope-manager": "6.13.0", + "@typescript-eslint/types": "6.13.0", + "@typescript-eslint/typescript-estree": "6.13.0", + "@typescript-eslint/visitor-keys": "6.13.0", "debug": "^4.3.4" }, "engines": { @@ -2785,13 +2785,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz", - "integrity": "sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.0.tgz", + "integrity": "sha512-2x0K2/CujsokIv+LN2T0l5FVDMtsCjkUyYtlcY4xxnxLAW+x41LXr16duoicHpGtLhmtN7kqvuFJ3zbz00Ikhw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0" + "@typescript-eslint/types": "6.13.0", + "@typescript-eslint/visitor-keys": "6.13.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2802,13 +2802,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz", - "integrity": "sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.0.tgz", + "integrity": "sha512-YHufAmZd/yP2XdoD3YeFEjq+/Tl+myhzv+GJHSOz+ro/NFGS84mIIuLU3pVwUcauSmwlCrVXbBclkn1HfjY0qQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.12.0", - "@typescript-eslint/utils": "6.12.0", + "@typescript-eslint/typescript-estree": "6.13.0", + "@typescript-eslint/utils": "6.13.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2829,9 +2829,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz", - "integrity": "sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.0.tgz", + "integrity": "sha512-oXg7DFxx/GmTrKXKKLSoR2rwiutOC7jCQ5nDH5p5VS6cmHE1TcPTaYQ0VPSSUvj7BnNqCgQ/NXcTBxn59pfPTQ==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2842,13 +2842,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz", - "integrity": "sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.0.tgz", + "integrity": "sha512-IT4O/YKJDoiy/mPEDsfOfp+473A9GVqXlBKckfrAOuVbTqM8xbc0LuqyFCcgeFWpqu3WjQexolgqN2CuWBYbog==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0", + "@typescript-eslint/types": "6.13.0", + "@typescript-eslint/visitor-keys": "6.13.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2869,17 +2869,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz", - "integrity": "sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.0.tgz", + "integrity": "sha512-V+txaxARI8yznDkcQ6FNRXxG+T37qT3+2NsDTZ/nKLxv6VfGrRhTnuvxPUxpVuWWr+eVeIxU53PioOXbz8ratQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.12.0", - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/typescript-estree": "6.12.0", + "@typescript-eslint/scope-manager": "6.13.0", + "@typescript-eslint/types": "6.13.0", + "@typescript-eslint/typescript-estree": "6.13.0", "semver": "^7.5.4" }, "engines": { @@ -2894,12 +2894,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz", - "integrity": "sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.0.tgz", + "integrity": "sha512-UQklteCEMCRoq/1UhKFZsHv5E4dN1wQSzJoxTfABasWk1HgJRdg1xNUve/Kv/Sdymt4x+iEzpESOqRFlQr/9Aw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.12.0", + "@typescript-eslint/types": "6.13.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3897,9 +3897,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001564", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001564.tgz", - "integrity": "sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==", + "version": "1.0.30001565", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", + "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", "dev": true, "funding": [ { @@ -4752,9 +4752,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.594", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.594.tgz", - "integrity": "sha512-xT1HVAu5xFn7bDfkjGQi9dNpMqGchUkebwf1GL7cZN32NSwwlHRPMSDJ1KN6HkS0bWUtndbSQZqvpQftKG2uFQ==", + "version": "1.4.595", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.595.tgz", + "integrity": "sha512-+ozvXuamBhDOKvMNUQvecxfbyICmIAwS4GpLmR0bsiSBlGnLaOcs2Cj7J8XSbW+YEaN3Xl3ffgpm+srTUWFwFQ==", "dev": true }, "node_modules/emittery": { @@ -6077,9 +6077,9 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", diff --git a/package.json b/package.json index 5c81a8d27..228f5c464 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "commander": "11.1.0", "dayjs": "1.11.10", "fastify": "4.24.3", - "fs-extra": "11.1.1", + "fs-extra": "11.2.0", "jsonwebtoken": "9.0.2", "lodash": "4.17.21", "node-cache": "5.1.2", @@ -109,8 +109,8 @@ "@types/tar": "^6.1.10", "@types/tcp-port-used": "^1.0.4", "@types/unzipper": "^0.10.9", - "@typescript-eslint/eslint-plugin": "^6.12.0", - "@typescript-eslint/parser": "^6.12.0", + "@typescript-eslint/eslint-plugin": "^6.13.0", + "@typescript-eslint/parser": "^6.13.0", "babel-jest": "^29.7.0", "concurrently": "^8.2.2", "eslint": "^8.54.0", diff --git a/src/modules/plugins/plugins.service.ts b/src/modules/plugins/plugins.service.ts index 1e018187b..a6c2a4849 100755 --- a/src/modules/plugins/plugins.service.ts +++ b/src/modules/plugins/plugins.service.ts @@ -79,6 +79,11 @@ export class PluginsService { // verified plugins cache private verifiedPlugins: string[] = []; + private verifiedPluginsIcons: { [key: string]: string } = {}; + private verifiedPluginsIconsPrefix = 'https://raw.githubusercontent.com/homebridge/verified/latest/'; + + private verifiedPluginsJson = 'https://raw.githubusercontent.com/homebridge/verified/latest/verified-plugins.json'; + private verifiedPluginsIconsJson = 'https://raw.githubusercontent.com/homebridge/verified/latest/plugin-icons.json'; // misc schemas private miscSchemas = { @@ -293,7 +298,9 @@ export class PluginsService { plugin.links = pkg.package.links; plugin.author = (pkg.package.publisher) ? pkg.package.publisher.username : null; plugin.verifiedPlugin = this.verifiedPlugins.includes(pkg.package.name); - + plugin.icon = this.verifiedPluginsIcons[pkg.package.name] + ? `${this.verifiedPluginsIconsPrefix}${this.verifiedPluginsIcons[pkg.package.name]}` + : null; return plugin; }); @@ -350,6 +357,7 @@ export class PluginsService { description: (pkg.description) ? pkg.description.replace(/(?:https?|ftp):\/\/[\n\S]+/g, '').trim() : pkg.name, verifiedPlugin: this.verifiedPlugins.includes(pkg.name), + icon: this.verifiedPluginsIcons[pkg.name], } as HomebridgePlugin; // it's not installed; finish building the response @@ -364,6 +372,9 @@ export class PluginsService { }; plugin.author = (pkg.maintainers.length) ? pkg.maintainers[0].name : null; plugin.verifiedPlugin = this.verifiedPlugins.includes(pkg.name); + plugin.icon = this.verifiedPluginsIcons[pkg.name] + ? `${this.verifiedPluginsIconsPrefix}${this.verifiedPluginsIcons[pkg.name]}` + : null; return [plugin]; } catch (e) { @@ -1202,6 +1213,9 @@ export class PluginsService { description: (pjson.description) ? pjson.description.replace(/(?:https?|ftp):\/\/[\n\S]+/g, '').trim() : pjson.name, verifiedPlugin: this.verifiedPlugins.includes(pjson.name), + icon: this.verifiedPluginsIcons[pjson.name] + ? `${this.verifiedPluginsIconsPrefix}${this.verifiedPluginsIcons[pjson.name]}` + : null, installedVersion: installPath ? (pjson.version || '0.0.1') : null, globalInstall: (installPath !== this.configService.customPluginPath), settingsSchema: await pathExists(resolve(installPath, pjson.name, 'config.schema.json')) || this.miscSchemas[pjson.name], @@ -1475,7 +1489,13 @@ export class PluginsService { clearTimeout(this.verifiedPluginsRetryTimeout); try { this.verifiedPlugins = ( - await this.httpService.get('https://raw.githubusercontent.com/homebridge/verified/latest/verified-plugins.json', { + await this.httpService.get(this.verifiedPluginsJson, { + httpsAgent: null, + }).toPromise() + ).data; + + this.verifiedPluginsIcons = ( + await this.httpService.get(this.verifiedPluginsIconsJson, { httpsAgent: null, }).toPromise() ).data; diff --git a/src/modules/plugins/types.d.ts b/src/modules/plugins/types.d.ts index 7610da543..066f1ee1e 100644 --- a/src/modules/plugins/types.d.ts +++ b/src/modules/plugins/types.d.ts @@ -4,6 +4,7 @@ export interface HomebridgePlugin { displayName?: string; description?: string; verifiedPlugin?: boolean; + icon?: string; publicPackage?: boolean; installedVersion?: string; latestVersion?: string; diff --git a/ui/package-lock.json b/ui/package-lock.json index 503e3e785..a991bb938 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -4393,6 +4393,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", "dev": true }, "node_modules/abbrev": { @@ -5377,9 +5378,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001564", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001564.tgz", - "integrity": "sha512-DqAOf+rhof+6GVx1y+xzbFPeOumfQnhYzVnZD6LAXijR77yPtm9mfOcqOnT3mpnJiZVT+kwLAFnRlZcIz+c6bg==", + "version": "1.0.30001565", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001565.tgz", + "integrity": "sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==", "funding": [ { "type": "opencollective", @@ -6607,9 +6608,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.594", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.594.tgz", - "integrity": "sha512-xT1HVAu5xFn7bDfkjGQi9dNpMqGchUkebwf1GL7cZN32NSwwlHRPMSDJ1KN6HkS0bWUtndbSQZqvpQftKG2uFQ==" + "version": "1.4.595", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.595.tgz", + "integrity": "sha512-+ozvXuamBhDOKvMNUQvecxfbyICmIAwS4GpLmR0bsiSBlGnLaOcs2Cj7J8XSbW+YEaN3Xl3ffgpm+srTUWFwFQ==" }, "node_modules/emoji-datasource": { "version": "15.0.1", diff --git a/ui/src/app/core/manage-plugins/manage-plugins-modal/manage-plugins-modal.component.ts b/ui/src/app/core/manage-plugins/manage-plugins-modal/manage-plugins-modal.component.ts index d74f48fc9..69737edc9 100644 --- a/ui/src/app/core/manage-plugins/manage-plugins-modal/manage-plugins-modal.component.ts +++ b/ui/src/app/core/manage-plugins/manage-plugins-modal/manage-plugins-modal.component.ts @@ -139,6 +139,7 @@ export class ManagePluginsModalComponent implements OnInit, OnDestroy { termRows: this.term.rows, }).subscribe( () => { + this.activeModal.close(); this.$router.navigate(['/plugins']); this.$modal.open(RestartHomebridgeComponent); }, diff --git a/ui/src/app/modules/plugins/plugin-card/plugin-card.component.ts b/ui/src/app/modules/plugins/plugin-card/plugin-card.component.ts index b6da46408..7030608da 100644 --- a/ui/src/app/modules/plugins/plugin-card/plugin-card.component.ts +++ b/ui/src/app/modules/plugins/plugin-card/plugin-card.component.ts @@ -28,6 +28,7 @@ export class PluginCardComponent implements OnInit { public childBridgeRestartInProgress = false; public recommendChildBridge = false; public isMobile = this.$md.detect.mobile(); + public defaultIcon = 'assets/hb-icon.png'; private io = this.$ws.getExistingNamespace('child-bridges'); private setChildBridges = []; @@ -63,21 +64,24 @@ export class PluginCardComponent implements OnInit { } ngOnInit(): void { + if (!this.plugin.icon) { + this.plugin.icon = this.defaultIcon; + } + if ( - !this.$settings.env.recommendChildBridges - || !this.$settings.env.serviceMode - || ['homebridge', 'homebridge-config-ui-x'].includes(this.plugin.name) + this.$settings.env.recommendChildBridges + && this.$settings.env.serviceMode + && !['homebridge', 'homebridge-config-ui-x'].includes(this.plugin.name) ) { - this.recommendChildBridge = false; - return; + this.$api.get(`/plugins/config-schema/${encodeURIComponent(this.plugin.name)}`, {}).toPromise() + .then((schema) => { + this.recommendChildBridge = schema.pluginType === 'platform'; + }) + .catch(() => { + this.recommendChildBridge = false; + }); } - this.$api.get(`/plugins/config-schema/${encodeURIComponent(this.plugin.name)}`, {}).toPromise() - .then((schema) => { - this.recommendChildBridge = schema.pluginType === 'platform'; - }) - .catch(() => { - this.recommendChildBridge = false; - }); + } openFundingModal(plugin: any) { @@ -173,4 +177,8 @@ export class PluginCardComponent implements OnInit { }, action === 'restart' ? 12000 : action === 'stop' ? 6000 : 1000); } } + + handleIconError() { + this.plugin.icon = this.defaultIcon; + } } diff --git a/ui/src/app/modules/plugins/plugins.component.ts b/ui/src/app/modules/plugins/plugins.component.ts index f88e2bde4..94ed3f841 100644 --- a/ui/src/app/modules/plugins/plugins.component.ts +++ b/ui/src/app/modules/plugins/plugins.component.ts @@ -66,6 +66,7 @@ export class PluginsComponent implements OnInit, OnDestroy { try { const installedPlugins = await this.$api.get('/plugins').toPromise(); this.installedPlugins = installedPlugins.filter((x) => x.name !== 'homebridge-config-ui-x'); + this.appendMetaInfo(); this.loading = false; } catch (err) { this.$toastr.error( @@ -75,6 +76,25 @@ export class PluginsComponent implements OnInit, OnDestroy { } } + async appendMetaInfo() { + // Also get the current configuration for each plugin + await Promise.all(this.installedPlugins + .filter((plugin) => plugin.installedVersion) + .map(async (plugin) => { + try { + const configBlocks = await this.$api.get(`/config-editor/plugin/${encodeURIComponent(plugin.name)}`).toPromise(); + plugin.isConfigured = configBlocks.length > 0; + // eslint-disable-next-line no-underscore-dangle + plugin.hasChildBridges = plugin.isConfigured && configBlocks.some((x) => x._bridge && x._bridge.username); + } catch (err) { + // may not be technically correct, but if we can't load the config, assume it is configured + plugin.isConfigured = true; + plugin.hasChildBridges = true; + } + }), + ); + } + search() { this.installedPlugins = []; this.loading = true; @@ -82,6 +102,7 @@ export class PluginsComponent implements OnInit, OnDestroy { this.$api.get(`/plugins/search/${encodeURIComponent(this.form.value.query)}`).subscribe( (data) => { this.installedPlugins = data.filter((x) => x.name !== 'homebridge-config-ui-x'); + this.appendMetaInfo(); this.loading = false; }, (err) => { diff --git a/ui/src/scss/themes/themes-dark.scss b/ui/src/scss/themes/themes-dark.scss index d6eac435c..062ff3a79 100644 --- a/ui/src/scss/themes/themes-dark.scss +++ b/ui/src/scss/themes/themes-dark.scss @@ -383,6 +383,13 @@ text-shadow: 0 0 5px $darkModePrimary, 0 0 10px $darkModePrimary, 0 0 15px $darkModePrimary; } } + + .plugin-icon-card { + width: 60px; + height: 60px; + border-radius: 15px; + border: 1px solid #222222; + } } } diff --git a/ui/src/scss/themes/themes-light.scss b/ui/src/scss/themes/themes-light.scss index 428cba4ef..c7a03d89b 100644 --- a/ui/src/scss/themes/themes-light.scss +++ b/ui/src/scss/themes/themes-light.scss @@ -121,6 +121,13 @@ text-shadow: 0 0 5px #fff, 0 0 10px #fff; } } + + .plugin-icon-card { + width: 60px; + height: 60px; + border-radius: 15px; + border: 1px solid #dddddd; + } } }