diff --git a/.gitignore b/.gitignore index 1f477121..50ea95d8 100755 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,9 @@ home-assistant_v2.db *.sqlite deps __pycache__ +hacs +alexa_media +custom_components tts secrets.yaml secrets @@ -30,6 +33,5 @@ nest.conf ipchange.yaml ip_bans.yaml production_auth.json -hacs -alexa_media -custom_components + + diff --git a/config/.HA_VERSION b/config/.HA_VERSION index 63e2ef19..86e0c321 100755 --- a/config/.HA_VERSION +++ b/config/.HA_VERSION @@ -1 +1 @@ -0.110.0 \ No newline at end of file +0.110.1 \ No newline at end of file diff --git a/config/custom_components/hacs/.translations/da.json b/config/custom_components/hacs/.translations/da.json index 95587993..89d82d11 100644 --- a/config/custom_components/hacs/.translations/da.json +++ b/config/custom_components/hacs/.translations/da.json @@ -2,25 +2,35 @@ "common": { "about": "Om", "appdaemon_apps": "AppDaemon-apps", + "appdaemon_plural": "AppDaemon-apps", "background_task": "Baggrundsopgave kører. Denne side vil genindlæses automatisk.", "check_log_file": "Tjek din logfil for flere detaljer.", "continue": "Fortsæt", "disabled": "Deaktiveret", "documentation": "Dokumentation", + "element": "element", "hacs_is_disabled": "HACS er deaktiveret", "installed": "installeret", "integration": "Integration", + "integration_plural": "Integrationer", "integrations": "Integrationer", + "lovelace": "Lovelace", + "lovelace_element": "Lovelace-element", + "lovelace_elements": "Lovelace-elementer", "manage": "administrer", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDaemon-apps", - "plugin": "Plugin", - "plugins": "Plugins", + "netdaemon_plural": "NetDaemon-apps", + "plugin": "Lovelace", + "plugin_plural": "Lovelace-elementer", + "plugins": "Lovelace-elementer", "python_script": "Python-script", + "python_script_plural": "Python-scripts", "python_scripts": "Python-scripts", "repositories": "Repositories", "settings": "indstillinger", "theme": "Tema", + "theme_plural": "Temaer", "themes": "Temaer", "version": "Version" }, @@ -90,7 +100,7 @@ "integration_not_loaded": "Denne integration er ikke indlæst i Home Assistant.", "no_restart_required": "Ingen genstart påkrævet", "not_loaded": "Ikke indlæst", - "plugin_not_loaded": "Dette plugin er ikke føjet til dine Lovelace-ressourcer.", + "plugin_not_loaded": "Dette element er ikke føjet til dine Lovelace-ressourcer.", "restart": "Du skal genstarte Home Assistant.", "restart_pending": "Afventer genstart" }, @@ -111,7 +121,7 @@ "installed": "Installeret", "lovelace_copy_example": "Kopiér eksemplet til din Udklipsholder", "lovelace_instruction": "Tilføj dette til din lovelace-konfiguration", - "lovelace_no_js_type": "Kunne ikke afgøre typen af dette plugin, tjek venligst repository.", + "lovelace_no_js_type": "Kunne ikke afgøre typen af dette element, tjek venligst repository'et.", "newest": "nyeste", "note_appdaemon": "Du skal stadig føje den til filen 'apps.yaml'", "note_installed": "Når det er installeret, vil dette være placeret i", @@ -119,7 +129,7 @@ "note_plugin": "du skal stadig tilføje det til din lovelace-konfiguration ('ui-lovelace.yaml' eller Tekstbaseret redigering)", "note_plugin_post_107": "du skal stadig tilføje det til din lovelace-konfiguration ('configuration.yaml' eller ressourceeditoren '\/config\/lovelace\/resources')", "open_issue": "Opret issue", - "open_plugin": "Åbn plugin", + "open_plugin": "Åbn element", "reinstall": "Geninstaller", "repository": "Repository", "restart_home_assistant": "Genstart Home Assistant", @@ -128,6 +138,25 @@ "update_information": "Opdater oplysninger", "upgrade": "Opdater" }, + "sections": { + "about": { + "description": "Vis information om HACS", + "title": "Om" + }, + "automation": { + "description": "Det er her, du finder python_scripts, AppDaemon-apps og NetDaemon-apps", + "title": "Automatisering" + }, + "frontend": { + "description": "Det er her, du finder temaer, brugerdefinerede kort og andre elementer til lovelace", + "title": "Frontend" + }, + "integrations": { + "description": "Det er her, du finder brugerdefinerede integrationer (custom_components)", + "title": "Integrationer" + }, + "pending_repository_upgrade": "Du kører version {installed}, version {available} er tilgængelig" + }, "settings": { "add_custom_repository": "TILFØJ ET BRUGERDEFINERET REPOSITORY", "adding_new_repo": "Tilføjer nyt repository '{repo}'", diff --git a/config/custom_components/hacs/.translations/de.json b/config/custom_components/hacs/.translations/de.json index f96ac009..963b72fc 100644 --- a/config/custom_components/hacs/.translations/de.json +++ b/config/custom_components/hacs/.translations/de.json @@ -3,25 +3,35 @@ "about": "Über", "appdaemon": "AppDaemon", "appdaemon_apps": "AppDaemon Apps", + "appdaemon_plural": "AppDaemon Apps", "background_task": "Hintergrundprozess läuft. Diese Seite lädt neu, sobald dieser fertig ist.", "check_log_file": "Überprüfe die Logdatei für weitere Informationen.", "continue": "Fortfahren", "disabled": "Deaktiviert", "documentation": "Dokumentation", + "element": "Element", "hacs_is_disabled": "HACS ist deaktiviert", "installed": "Installiert", "integration": "Integration", + "integration_plural": "Integrationen", "integrations": "Integrationen", + "lovelace": "Lovelace", + "lovelace_element": "Lovelace-Element", + "lovelace_elements": "Lovelace-Elemente", "manage": "verwalten", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDaemon Apps", - "plugin": "Plugin", - "plugins": "Plugins", + "netdaemon_plural": "NetDaemon Apps", + "plugin": "Lovelace", + "plugin_plural": "Lovelace-Elemente", + "plugins": "Lovelace-Elemente", "python_script": "Python Skript", + "python_script_plural": "Python Skripte", "python_scripts": "Python Skripte", "repositories": "Repositories", "settings": "Einstellungen", "theme": "Theme", + "theme_plural": "Themes", "themes": "Themes", "version": "Version" }, @@ -93,7 +103,7 @@ "integration_not_loaded": "Diese Integration ist in Home Assistant nicht geladen.", "no_restart_required": "Kein Neustart erforderlich", "not_loaded": "Nicht geladen", - "plugin_not_loaded": "Dieses Plugin wurde deinen Lovelace-Ressourcen nicht hinzugefügt.", + "plugin_not_loaded": "Dieses Element wird nicht zu Ihren Lovelace-Ressourcen hinzugefügt.", "restart": "Du musst Home Assistant neu starten.", "restart_pending": "Neustart ausstehend" }, @@ -114,7 +124,7 @@ "installed": "Installiert", "lovelace_copy_example": "Beispiel in die Zwischenablage kopieren", "lovelace_instruction": "Zum Hinzufügen zu deinen Lovelace-Einstellungen, benutze Folgendes", - "lovelace_no_js_type": "Konnte die Art dieses Plugins nicht erkennen. Prüfe das Repository.", + "lovelace_no_js_type": "Der Typ dieses Elements konnte nicht ermittelt werden. Überprüfen Sie das Repository.", "newest": "neueste", "note_appdaemon": "du musst es dann noch in die Datei 'apps.yaml' hinzufügen", "note_installed": "Wird installiert nach", @@ -122,7 +132,7 @@ "note_plugin": "du musst es dann noch in deine Lovelace-Einstellungen ('ui-lovelace.yaml' oder im Raw-Konfigurationseditor) hinzufügen", "note_plugin_post_107": "Du musst es noch zu deiner Lovelace-Konfiguration hinzufügen ('configuration.yaml' oder der Ressourceneditor '\/config\/lovelace\/resources')", "open_issue": "Problem melden", - "open_plugin": "Plugin öffnen", + "open_plugin": "Element öffnen", "reinstall": "Neu installieren", "repository": "Repository", "restart_home_assistant": "Home Assistant neu starten", @@ -131,6 +141,25 @@ "update_information": "Aktualisierungsinformationen", "upgrade": "Aktualisieren" }, + "sections": { + "about": { + "description": "Informationen zu HACS anzeigen", + "title": "Über" + }, + "automation": { + "description": "Hier finden Sie python_scripts, AppDaemon-Apps und NetDaemon-Apps", + "title": "Automatisierung" + }, + "frontend": { + "description": "Hier finden Sie Themen, individuelle Karten und andere Elemente für Lovelace", + "title": "Frontend" + }, + "integrations": { + "description": "Hier finden Sie benutzerdefinierte Integrationen (custom_components)", + "title": "Integrationen" + }, + "pending_repository_upgrade": "Sie verwenden Version {installed}, Version {available} ist verfügbar" + }, "settings": { "add_custom_repository": "BENUTZERDEFINIERTES REPOSITORY HINZUFÜGEN", "adding_new_repo": "Hinzufügen eines neuen Repository '{repo}'", diff --git a/config/custom_components/hacs/.translations/en.json b/config/custom_components/hacs/.translations/en.json index 387c89fc..22efc2fd 100644 --- a/config/custom_components/hacs/.translations/en.json +++ b/config/custom_components/hacs/.translations/en.json @@ -1,28 +1,43 @@ { "common": { "about": "About", + "add": "add", "appdaemon": "AppDaemon", "appdaemon_apps": "AppDaemon Apps", + "appdaemon_plural": "AppDaemon Apps", "background_task": "Background task running, this page will reload when it's done.", "check_log_file": "Check your log file for more details.", "continue": "Continue", "disabled": "Disabled", "documentation": "Documentation", + "element": "element", "hacs_is_disabled": "HACS is disabled", + "install": "Install", "installed": "installed", "integration": "Integration", + "integration_plural": "Integrations", "integrations": "Integrations", + "lovelace": "Lovelace", + "lovelace_element": "Lovelace element", + "lovelace_elements": "Lovelace elements", "manage": "manage", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDaemon Apps", + "netdaemon_plural": "NetDaemon Apps", "plugin": "Plugin", + "plugin_plural": "Lovelace elements", "plugins": "Plugins", "python_script": "Python Script", + "python_script_plural": "Python Scripts", "python_scripts": "Python Scripts", "repositories": "Repositories", + "repository": "Repository", "settings": "settings", "theme": "Theme", + "theme_plural": "Themes", "themes": "Themes", + "uninstall": "Uninstall", + "update": "Update", "version": "Version" }, "config": { @@ -70,6 +85,74 @@ "upgrade_all": "This will upgrade all of these repositories, make sure that you have read the release notes for all of them before proceeding.", "yes": "Yes" }, + "dialog_about": { + "frontend_version": "Frontend version", + "installed_repositories": "Installed repositories", + "integration_version": "Integration version", + "useful_links": "Useful links" + }, + "dialog_add_repo": { + "limit": "Only the first 100 repositories are shown, use the search to filter what you need", + "no_match": "No repositories found matching your filter", + "title": "Add repository" + }, + "dialog_custom_repositories": { + "category": "Category", + "no_category": "Missing category", + "no_repository": "Missing repository", + "title": "Custom repositories", + "url_placeholder": "Add custom repository URL" + }, + "dialog_info": { + "author": "Author", + "downloads": "Downloads", + "install": "Install this repository in HACS", + "loading": "Loading information...", + "no_info": "The developer has not provided any more information for this repository", + "open_issues": "Open issues", + "open_repo": "Open repository", + "stars": "Stars", + "version_installed": "Version installed" + }, + "dialog_install": { + "select_version": "Select version", + "show_beta": "Show beta versions", + "type": "Type", + "url": "URL" + }, + "dialog_update": { + "available_version": "Available version", + "changelog": "Changelog", + "installed_version": "Installed version", + "title": "Update pending" + }, + "entry": { + "information": "Information", + "intro": "Updates and important messages will show here if there are any", + "messages": { + "disabled": { + "content": "Check your log file for more details", + "title": "HACS is disabled" + }, + "has_pending_tasks": { + "content": "Some repositories might not show untill this is completed", + "title": "Background tasks pending" + }, + "startup": { + "content": "HACS is starting up, during this time some information might be missing or incorrect", + "title": "HACS is starting up" + } + }, + "pending_updates": "Pending updates" + }, + "menu": { + "about": "About HACS", + "clear": "Clear all new", + "custom_repositories": "Custom repositories", + "documentation": "Documentation", + "open_issue": "Open issue", + "reload": "Reload window" + }, "options": { "step": { "user": { @@ -97,6 +180,17 @@ "restart": "You need to restart Home Assistant.", "restart_pending": "Restart pending" }, + "repository_card": { + "hide": "Hide", + "information": "Information", + "new_repository": "New repository", + "open_issue": "Open issue", + "open_source": "Open source", + "pending_update": "Pending update", + "reinstall": "Reinstall", + "report": "Report for removal", + "update_information": "Update information" + }, "repository": { "add_to_lovelace": "Add to Lovelace", "authors": "Authors", @@ -131,6 +225,28 @@ "update_information": "Update information", "upgrade": "Update" }, + "search": { + "placeholder": "Search for repository" + }, + "sections": { + "about": { + "description": "Show information about HACS", + "title": "About" + }, + "automation": { + "description": "This is where you find python_scripts, AppDaemon apps and NetDaemon apps", + "title": "Automation" + }, + "frontend": { + "description": "This is where you find themes, custom cards and other elements for lovelace", + "title": "Frontend" + }, + "integrations": { + "description": "This is where you find custom integrations (custom_components)", + "title": "Integrations" + }, + "pending_repository_upgrade": "You are running version {installed}, version {available} is available" + }, "settings": { "add_custom_repository": "ADD CUSTOM REPOSITORY", "adding_new_repo": "Adding new repository '{repo}'", @@ -162,6 +278,9 @@ "last_updated": "Last updated", "name": "Name", "new_repositories": "New Repositories", + "no_repositories": "No repositories", + "no_repositories_desc1": "It seems like you don't have any repositories installed in this section yet.", + "no_repositories_desc2": "Click on the + in the bottom corner to add your first!", "pending_upgrades": "Pending upgrades", "placeholder_search": "Please enter a search term...", "sort": "sort", diff --git a/config/custom_components/hacs/.translations/es.json b/config/custom_components/hacs/.translations/es.json index b4a43665..d5ac0fbf 100644 --- a/config/custom_components/hacs/.translations/es.json +++ b/config/custom_components/hacs/.translations/es.json @@ -3,25 +3,35 @@ "about": "Acerca de", "appdaemon": "AppDaemon", "appdaemon_apps": "AppDaemon Apps", + "appdaemon_plural": "AppDaemon Apps", "background_task": "Ejecutando tareas en segundo plano. Se refrescará automaticamente esta página al finalizar.", "check_log_file": "Compruebe el archivo de registro para obtener más detalles.", "continue": "Continuar", "disabled": "Deshabilitado", "documentation": "Documentación", + "element": "elemento", "hacs_is_disabled": "HACS está deshabilitado", "installed": "instalado", "integration": "Integración", + "integration_plural": "Integraciones", "integrations": "Integraciones", + "lovelace": "Lovelace", + "lovelace_element": "Elemento de Lovelace", + "lovelace_elements": "Elementos de Lovelace", "manage": "Administrar", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDaemon Apps", + "netdaemon_plural": "Aplicaciones NetDaemon", "plugin": "Plugin", + "plugin_plural": "Elementos de Lovelace", "plugins": "Plugins", "python_script": "Python Script", + "python_script_plural": "Python Scripts", "python_scripts": "Python Scripts", "repositories": "Repositorios", "settings": "configuraciones", "theme": "Tema", + "theme_plural": "Temas", "themes": "Temas", "version": "Versión" }, @@ -93,7 +103,7 @@ "integration_not_loaded": "Esta integración no se carga en Home Assistant.", "no_restart_required": "No es necesario reiniciar", "not_loaded": "No está cargado", - "plugin_not_loaded": "Este plugin no se añade a sus recursos de Lovelace.", + "plugin_not_loaded": "Este plugin aun no se ha añadido a sus recursos de Lovelace.", "restart": "Es necesario reiniciar Home Assistant.", "restart_pending": "Reinicio pendiente" }, @@ -131,6 +141,25 @@ "update_information": "Actualizar información", "upgrade": "Actualizar" }, + "sections": { + "about": { + "description": "Mostrar información sobre HACS", + "title": "Acerca de" + }, + "automation": { + "description": "Aquí es donde se encuentran python_scripts, aplicaciones AppDaemon y aplicaciones NetDaemon", + "title": "Automatización" + }, + "frontend": { + "description": "Aquí es donde encontrarás temas, tarjetas personalizadas y otros elementos para lovelace", + "title": "Interfaz" + }, + "integrations": { + "description": "Aquí es donde se encuentran las integraciones personalizadas (custom_components)", + "title": "Integraciones" + }, + "pending_repository_upgrade": "Está ejecutando la versión {installed}, la versión {available} está disponible" + }, "settings": { "add_custom_repository": "AGREGAR REPOSITORIO PERSONALIZADO", "adding_new_repo": "Añadiendo un nuevo repositorio '{repo}'.", diff --git a/config/custom_components/hacs/.translations/hu.json b/config/custom_components/hacs/.translations/hu.json index a9db28e4..a5f08ba2 100644 --- a/config/custom_components/hacs/.translations/hu.json +++ b/config/custom_components/hacs/.translations/hu.json @@ -3,25 +3,35 @@ "about": "Névjegy", "appdaemon": "AppDaemon", "appdaemon_apps": "AppDaemon Appok", + "appdaemon_plural": "AppDaemon appok", "background_task": "Éppen háttérfeladat fut, ez az oldal frissülni fog, ha kész.", "check_log_file": "További részletekért ellenőrizd a naplófájlt.", "continue": "Folytatás", "disabled": "Tiltva", "documentation": "Dokumentáció", + "element": "bővítmény", "hacs_is_disabled": "A HACS le van tiltva", "installed": "Telepített", "integration": "Integráció", + "integration_plural": "Integrációk", "integrations": "Integrációk", + "lovelace": "Lovelace", + "lovelace_element": "Lovelace bővítmény", + "lovelace_elements": "Lovelace bővítmények", "manage": "kezelés", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDaemon Appok", - "plugin": "Bővítmény", - "plugins": "Bővítmények", + "netdaemon_plural": "NetDaemon appok", + "plugin": "Lovelace", + "plugin_plural": "Lovelace bővítmények", + "plugins": "Lovelace bővítmények", "python_script": "Python Szkript", + "python_script_plural": "Python szkriptek", "python_scripts": "Python Szkriptek", "repositories": "Tárolók", "settings": "beállítások", "theme": "Téma", + "theme_plural": "Témák", "themes": "Témák", "version": "Verzió" }, @@ -93,7 +103,7 @@ "integration_not_loaded": "Ez az integráció nincs betöltve a Home Assistantban.", "no_restart_required": "Nincs szükség újraindításra", "not_loaded": "Nincs betöltve", - "plugin_not_loaded": "Ez a bővítmény nincs hozzáadva a Lovelace erőforrásokhoz.", + "plugin_not_loaded": "Ez a bővítmény nincs hozzáadva a Lovelace erőforrásaidhoz.", "restart": "Indítsd újra a Home Assistant programot.", "restart_pending": "Újraindítás függőben" }, @@ -114,7 +124,7 @@ "installed": "Telepített", "lovelace_copy_example": "Példa másolása a vágólapra", "lovelace_instruction": "Amikor hozzáadod ezt a lovelace konfigurációdhoz, használd ezt", - "lovelace_no_js_type": "Nem sikerült meghatározni a beépülő modul típusát, ellenőrizd a tárolót.", + "lovelace_no_js_type": "Nem sikerült meghatározni a bővítmény típusát, ellenőrizd a tárolót.", "newest": "legújabb", "note_appdaemon": "de még hozzá kell adnod az 'apps.yaml' fájlhoz", "note_installed": "Telepítéskor a következő helyre kerül:", @@ -131,6 +141,25 @@ "update_information": "Frissítési információk", "upgrade": "Frissítés" }, + "sections": { + "about": { + "description": "Információk megjelenítése a HACS-ről", + "title": "Névjegy" + }, + "automation": { + "description": "Itt Python szkripteket, AppDaemon és NetDaemon appokat találsz", + "title": "Automatizálás" + }, + "frontend": { + "description": "Itt témákat, egyéni kártyákat és más bővítményeket találsz a Lovelace-hez", + "title": "Frontend" + }, + "integrations": { + "description": "Itt találod az egyéni integrációkat (custom_components)", + "title": "Integrációk" + }, + "pending_repository_upgrade": "A(z) {installed} verziót futtatod, a(z) {available} verzió már elérhető" + }, "settings": { "add_custom_repository": "EGYÉNI TÁROLÓ HOZZÁADÁSA", "adding_new_repo": "Új tároló hozzáadása '{repo}'", diff --git a/config/custom_components/hacs/.translations/nb.json b/config/custom_components/hacs/.translations/nb.json index 77840962..5a8cf343 100644 --- a/config/custom_components/hacs/.translations/nb.json +++ b/config/custom_components/hacs/.translations/nb.json @@ -1,28 +1,43 @@ { "common": { "about": "Om", + "add": "legg til", "appdaemon": "AppDaemon", "appdaemon_apps": "AppDaemon Apper", + "appdaemon_plural": "AppDaemon-apper", "background_task": "Bakgrunnsoppgaven kjører. Denne siden lastes inn på nytt når den er ferdig.", "check_log_file": "Sjekk loggfilen din for mer informasjon.", "continue": "Fortsett", "disabled": "Deaktivert", "documentation": "dokumentasjon", + "element": "element", "hacs_is_disabled": "HACS er deaktivert", + "install": "Installer", "installed": "Installert", "integration": "Integrasjon", + "integration_plural": "Integrasjoner", "integrations": "Integrasjoner", + "lovelace": "Lovelace", + "lovelace_element": "Lovelace-element", + "lovelace_elements": "Lovelace-elementer", "manage": "manage", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDaemon Apper", - "plugin": "Plugin", - "plugins": "Plugins", + "netdaemon_plural": "NetDaemon-apper", + "plugin": "Lovelace", + "plugin_plural": "Lovelace-elementer", + "plugins": "Lovelace-elementer", "python_script": "Python-skript", + "python_script_plural": "Python-skript", "python_scripts": "Python-skript", "repositories": "Repositories", + "repository": "Repository", "settings": "Innstillinger", "theme": "Tema", + "theme_plural": "Temaer", "themes": "Temaer", + "uninstall": "Avinstaller", + "update": "Oppdater", "version": "Versjon" }, "config": { @@ -70,6 +85,74 @@ "upgrade_all": "Dette vil oppgradere alle disse repositorene, sørg for at du har lest utgivelses notatene for dem alle før du fortsetter.", "yes": "Ja" }, + "dialog_about": { + "frontend_version": "Frontend versjon", + "installed_repositories": "Installerte repositories", + "integration_version": "Integrasjonsversjon", + "useful_links": "Nyttige lenker" + }, + "dialog_add_repo": { + "limit": "Bare de første 100 elementene vises, bruk søket til å filtrere det du trenger", + "no_match": "Ingen elementer funnet som samsvarer med filteret ditt", + "title": "Legg til repository" + }, + "dialog_custom_repositories": { + "category": "Kategori", + "no_category": "Mangler kategori", + "no_repository": "Mangler repository", + "title": "Custom repositories", + "url_placeholder": "Legg til custom repository" + }, + "dialog_info": { + "author": "Utgiver", + "downloads": "Nedlastinger", + "install": "Installer dette elementet i HACS", + "loading": "Laster inn informasjon ...", + "no_info": "Utvikleren har ikke gitt mer informasjon for dette elementet", + "open_issues": "Åpne problemer", + "open_repo": "Åpne repository", + "stars": "Stjerner", + "version_installed": "Versjon installert" + }, + "dialog_install": { + "select_version": "Velg versjon", + "show_beta": "Vis betaversjoner", + "type": "Type", + "url": "URL" + }, + "dialog_update": { + "available_version": "Tilgjengelig versjon", + "changelog": "Endringslogg", + "installed_version": "Installert versjon", + "title": "Oppdatering venter" + }, + "entry": { + "information": "Informasjon", + "intro": "Oppdateringer og viktige meldinger vises her hvis det er noen", + "messages": { + "disabled": { + "content": "Sjekk loggfilen din for mer informasjon", + "title": "HACS er deaktivert" + }, + "has_pending_tasks": { + "content": "Noen elementer vises kanskje ikke før dette er fullført", + "title": "Venter på bakgrunnsoppgaver" + }, + "startup": { + "content": "HACS starter opp, i løpet av denne tiden kan det hende at noe informasjon mangler eller er feil", + "title": "HACS starter opp" + } + }, + "pending_updates": "Oppdateringer er klare" + }, + "menu": { + "about": "Om HACS", + "clear": "Fjern alt nytt", + "custom_repositories": "Custom repositories", + "documentation": "Dokumentasjon", + "open_issue": "Meld et problem", + "reload": "Last inn vinduet på nytt" + }, "options": { "step": { "user": { @@ -93,10 +176,21 @@ "integration_not_loaded": "Integrasjonen er ikke lastet inn i Home Assistant.", "no_restart_required": "Ingen omstart kreves", "not_loaded": "Ikke lastet inn", - "plugin_not_loaded": "Denne pluginen er ikke lagt til i lovelace under \"resource\" delen av konfigurasjonen.", + "plugin_not_loaded": "Dette elementet er ikke lagt til i lovelace under \"resource\" delen av konfigurasjonen.", "restart": "Du må restart Home Assistant", "restart_pending": "Restart er nødvendig" }, + "repository_card": { + "hide": "Skjul", + "information": "Informasjon", + "new_repository": "Ny", + "open_issue": "Meld et problem", + "open_source": "Åpne kilde", + "pending_update": "Oppdatering venter", + "reinstall": "Installer på nytt", + "report": "Rapporter for fjerning", + "update_information": "Oppdater informasjon" + }, "repository": { "add_to_lovelace": "Legg til i Lovelace", "authors": "Laget av", @@ -113,7 +207,7 @@ "installed": "Installert", "lovelace_copy_example": "Kopier eksemplet til utklippstavlen", "lovelace_instruction": "Når du legger til dette i lovelace-konfigurasjonen din, bruk dette", - "lovelace_no_js_type": "Kunne ikke bestemme typen for denne plugin, sjekk repository.", + "lovelace_no_js_type": "Kunne ikke bestemme typen for dettte elementet, sjekk repository.", "newest": "Nyeste", "note_appdaemon": "du må fortsatt legge den til i 'apps.yaml' filen", "note_installed": "Når det er installert, vil dette ligge i", @@ -121,7 +215,7 @@ "note_plugin": "du må fortsatt legge den til i lovelace-konfigurasjonen ('ui-lovelace.yaml' eller den rå UI-konfigurasjonsredigereren)", "note_plugin_post_107": "du må fortsatt legge den til i lovelace konfigurasjonen ('configuration.yaml' eller via resource behanleren i grensesnittet '\/config\/lovelace\/resources')", "open_issue": "Meld et problem", - "open_plugin": "Åpne plugin", + "open_plugin": "Åpne kilde", "reinstall": "Installer på nytt", "repository": "Repository", "restart_home_assistant": "Start Home Assistant på nytt", @@ -130,6 +224,28 @@ "update_information": "Oppdater informasjon", "upgrade": "Oppdater" }, + "search": { + "placeholder": "Søk etter repository" + }, + "sections": { + "about": { + "description": "Vis informasjon om HACS", + "title": "Om" + }, + "automation": { + "description": "Det er her du finner python_scripts, AppDaemon-apper og NetDaemon-apper", + "title": "Automasjon" + }, + "frontend": { + "description": "Det er her du finner temaer, tilpassede kort og andre elementer for lovelace", + "title": "Frontend" + }, + "integrations": { + "description": "Det er her du finner tilpassede integrasjoner (custom_components)", + "title": "Integrasjoner" + }, + "pending_repository_upgrade": "Du kjører versjon {installed} , versjon {available} er tilgjengelig" + }, "settings": { "add_custom_repository": "LEGG TIL REPOSITORY", "adding_new_repo": "Legger til ny repository '{repo}'", @@ -161,6 +277,9 @@ "last_updated": "Sist oppdatert", "name": "Navn", "new_repositories": "Nye repositories", + "no_repositories": "Ingen repositories", + "no_repositories_desc1": "Det virker som om du ikke har noen elementer installert i denne delen ennå.", + "no_repositories_desc2": "Klikk på + i nederste hjørne for å legge til din første!", "pending_upgrades": "Venter på oppgradering", "placeholder_search": "Skriv inn et søkeord ...", "sort": "sorter", diff --git a/config/custom_components/hacs/.translations/nn.json b/config/custom_components/hacs/.translations/nn.json index 5c1fc0c4..fe8f97b5 100644 --- a/config/custom_components/hacs/.translations/nn.json +++ b/config/custom_components/hacs/.translations/nn.json @@ -3,25 +3,35 @@ "about": "Om", "appdaemon": "AppDaemon", "appdaemon_apps": "AppDeamon-appar", + "appdaemon_plural": "AppDaemon-appar", "background_task": "Bakgrunnsoppgåve køyrer. Denne sida kjem til å laste seg omatt når ho er ferdig.", "check_log_file": "Sjå i loggfila di for meir detaljar.", "continue": "Hald fram", "disabled": "Deaktivert", "documentation": "Dokumentasjon", + "element": "element", "hacs_is_disabled": "HACS er deaktivert", "installed": "Installert", "integration": "Integrasjon", + "integration_plural": "Integrasjonar", "integrations": "Integrasjonar", + "lovelace": "Lovelace", + "lovelace_element": "Lovelace-element", + "lovelace_elements": "Lovelace-element", "manage": "Handtere", "netdaemon": "NetDaemon", "netdaemon_apps": "NetDeamon-appar", + "netdaemon_plural": "NetDaemon-appar", "plugin": "Tillegg", + "plugin_plural": "Lovelace-element", "plugins": "Tillegg", "python_script": "Pythonskript", + "python_script_plural": "Pythonskript", "python_scripts": "Pythonskript", "repositories": "Repositories", "settings": "innstillingar", "theme": "Tema", + "theme_plural": "Tema", "themes": "Tema", "version": "Versjon" }, @@ -59,7 +69,7 @@ "exist": "{item} eksisterer allereie", "generic": "Er du sikker?", "home_assistant_is_restarting": "Vent... Home Assistant starter på nytt no.", - "home_assistant_version_not_correct": "Du køyrer Home Assistant-versjonen '{haversion}', men dette kodedepoet krev minimum versjon '{minversion}' for å bli installert.", + "home_assistant_version_not_correct": "Du køyrer Home Assistant-versjonen '{haversion}', men dette kodedepoet krev minst versjon '{minversion}' for å bli installert.", "no": "Nei", "no_upgrades": "Ingen ventande oppgradringer", "ok": "OK", @@ -120,6 +130,7 @@ "note_installed": "Når dette er installert, kjem den til å vere plassert i", "note_integration": "du må framleis legge dette til i \"configuration.yaml\"-fila di", "note_plugin": "du må framleis dette til i Lovelace-konfigurasjonen (\"ui-lovelace.yaml\" eller i rå-brukargrensesnittredigeraren", + "note_plugin_post_107": "du må framleis legge dette til i lovelace-konfigurasjonen ('configuration.yaml' eller i kjelderedigeraren ''\/config\/lovelace\/resources')", "open_issue": "Opne problem", "open_plugin": "Opne tillegg", "reinstall": "Installer på nytt", @@ -130,6 +141,25 @@ "update_information": "Oppdater informasjonen", "upgrade": "Oppdater" }, + "sections": { + "about": { + "description": "Vis informasjon om HACS", + "title": "Om" + }, + "automation": { + "description": "Her finn du python_scripts, AppDaemon-appar og NetDaemon-appar", + "title": "Automasjon" + }, + "frontend": { + "description": "Her finn du tema, eigendefinerte kort og andre element for lovelace", + "title": "Frontend" + }, + "integrations": { + "description": "Her finn du eigendefinerte ingtegrasjonar (custom_components)", + "title": "Integrasjonar" + }, + "pending_repository_upgrade": "Du køyrer versjon {installed}, og versjon {available} er tilgjengeleg" + }, "settings": { "add_custom_repository": "LEGG TIL EIN ANNAN REPOSITORY", "adding_new_repo": "Legger til ny repository '{repo}'", diff --git a/config/custom_components/hacs/.translations/pl.json b/config/custom_components/hacs/.translations/pl.json index 26e9c808..6c71e312 100644 --- a/config/custom_components/hacs/.translations/pl.json +++ b/config/custom_components/hacs/.translations/pl.json @@ -3,6 +3,7 @@ "about": "O", "appdaemon": "AppDaemon", "appdaemon_apps": "Aplikacje AppDaemon", + "appdaemon_plural": "Aplikacje AppDaemon", "background_task": "Wykonywanie zadania w tle, ta strona zostanie odświeżona, gdy zadanie zostanie ukończone.", "check_log_file": "Sprawdź plik dziennika, aby uzyskać więcej informacji.", "continue": "Kontynuuj", @@ -11,17 +12,25 @@ "hacs_is_disabled": "HACS jest wyłączony", "installed": "zainstalowane", "integration": "Integracja", + "integration_plural": "Integracje", "integrations": "Integracje", + "lovelace": "Lovelace", + "lovelace_element": "Element Lovelace", + "lovelace_elements": "Elementy Lovelace", "manage": "zarządzaj", "netdaemon": "NetDaemon", "netdaemon_apps": "Aplikacje NetDaemon", + "netdaemon_plural": "Aplikacje NetDaemon", "plugin": "Wtyczka", + "plugin_plural": "Elementy Lovelace", "plugins": "Wtyczki", "python_script": "Skrypt Python", + "python_script_plural": "Skrypty języka Python", "python_scripts": "Skrypty Python", "repositories": "Repozytoria", "settings": "ustawienia", "theme": "Motyw", + "theme_plural": "Motywy", "themes": "Motywy", "version": "Wersja" }, @@ -131,6 +140,22 @@ "update_information": "Uaktualnij informacje", "upgrade": "Uaktualnij" }, + "sections": { + "about": { + "description": "Pokaż informacje o HACS" + }, + "automation": { + "description": "Tutaj znajdziesz skrypty Pythona, aplikacje AppDaemon i NetDaemon", + "title": "Automatyzacja" + }, + "frontend": { + "description": "Tutaj znajdziesz motywy, niestandardowe karty i inne elementy dla Lovelace" + }, + "integrations": { + "description": "Tutaj znajdziesz niestandardowe integracje (custom_components)", + "title": "Integracje" + } + }, "settings": { "add_custom_repository": "DODAJ REPOZYTORIUM NIESTANDARDOWE", "adding_new_repo": "Dodawanie nowego repozytorium '{repo}'", diff --git a/config/custom_components/hacs/__init__.py b/config/custom_components/hacs/__init__.py index 2f212e1b..a322baae 100644 --- a/config/custom_components/hacs/__init__.py +++ b/config/custom_components/hacs/__init__.py @@ -6,7 +6,7 @@ https://hacs.xyz/ """ import voluptuous as vol -from aiogithubapi import AIOGitHub, AIOGitHubException +from aiogithubapi import GitHub, AIOGitHubAPIException from homeassistant import config_entries from homeassistant.const import EVENT_HOMEASSISTANT_START from homeassistant.const import __version__ as HAVERSION @@ -15,12 +15,9 @@ from homeassistant.exceptions import ConfigEntryNotReady, ServiceNotFound from homeassistant.helpers.aiohttp_client import async_create_clientsession from homeassistant.helpers.event import async_call_later -from custom_components.hacs.configuration_schema import ( - hacs_base_config_schema, - hacs_config_option_schema, -) +from custom_components.hacs.configuration_schema import hacs_config_combined from custom_components.hacs.const import DOMAIN, ELEMENT_TYPES, STARTUP, VERSION -from custom_components.hacs.constrains import check_constans, check_requirements +from custom_components.hacs.constrains import check_constrains from custom_components.hacs.helpers.remaining_github_calls import get_fetch_updates_for from custom_components.hacs.hacsbase.configuration import Configuration from custom_components.hacs.hacsbase.data import HacsData @@ -34,9 +31,7 @@ from custom_components.hacs.globals import get_hacs from custom_components.hacs.helpers.network import internet_connectivity_check -SCHEMA = hacs_base_config_schema() -SCHEMA[vol.Optional("options")] = hacs_config_option_schema() -CONFIG_SCHEMA = vol.Schema({DOMAIN: SCHEMA}, extra=vol.ALLOW_EXTRA) +CONFIG_SCHEMA = vol.Schema({DOMAIN: hacs_config_combined()}, extra=vol.ALLOW_EXTRA) async def async_setup(hass, config): @@ -49,17 +44,10 @@ async def async_setup(hass, config): hass.data[DOMAIN] = config hacs.hass = hass hacs.session = async_create_clientsession(hass) - hacs.configuration = Configuration.from_dict( - config[DOMAIN], config[DOMAIN].get("options") - ) + hacs.configuration = Configuration.from_dict(config[DOMAIN]) hacs.configuration.config = config hacs.configuration.config_type = "yaml" await startup_wrapper_for_yaml() - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={} - ) - ) return True @@ -67,11 +55,10 @@ async def async_setup_entry(hass, config_entry): """Set up this integration using UI.""" hacs = get_hacs() conf = hass.data.get(DOMAIN) + if conf is not None: + return False if config_entry.source == config_entries.SOURCE_IMPORT: - if conf is None: - hass.async_create_task( - hass.config_entries.async_remove(config_entry.entry_id) - ) + hass.async_create_task(hass.config_entries.async_remove(config_entry.entry_id)) return False hacs.hass = hass hacs.session = async_create_clientsession(hass) @@ -83,7 +70,7 @@ async def async_setup_entry(hass, config_entry): config_entry.add_update_listener(reload_hacs) try: startup_result = await hacs_startup() - except AIOGitHubException: + except AIOGitHubAPIException: startup_result = False if not startup_result: hacs.system.disabled = True @@ -97,7 +84,7 @@ async def startup_wrapper_for_yaml(): hacs = get_hacs() try: startup_result = await hacs_startup() - except AIOGitHubException: + except AIOGitHubAPIException: startup_result = False if not startup_result: hacs.system.disabled = True @@ -115,8 +102,6 @@ async def startup_wrapper_for_yaml(): async def hacs_startup(): """HACS startup tasks.""" hacs = get_hacs() - if not check_requirements(): - return False if hacs.configuration.debug: try: await hacs.hass.services.async_call( @@ -142,7 +127,7 @@ async def hacs_startup(): hacs.system.lovelace_mode = lovelace_info.get("mode", "yaml") hacs.system.disabled = False - hacs.github = AIOGitHub( + hacs.github = GitHub( hacs.configuration.token, async_create_clientsession(hacs.hass) ) hacs.data = HacsData() @@ -154,7 +139,7 @@ async def hacs_startup(): hacs.logger.debug(f"Can update {can_update} repositories") # Check HACS Constrains - if not await hacs.hass.async_add_executor_job(check_constans): + if not await hacs.hass.async_add_executor_job(check_constrains): if hacs.configuration.config_type == "flow": if hacs.configuration.config_entry is not None: await async_remove_entry(hacs.hass, hacs.configuration.config_entry) @@ -189,18 +174,6 @@ async def hacs_startup(): hacs.common.categories.append("appdaemon") if hacs.configuration.netdaemon: hacs.common.categories.append("netdaemon") - if hacs.configuration.python_script: - hacs.configuration.python_script = False - if hacs.configuration.config_type == "yaml": - hacs.logger.warning( - "Configuration option 'python_script' is deprecated and you should remove it from your configuration, HACS will know if you use 'python_script' in your Home Assistant configuration, this option will be removed in a future release." - ) - if hacs.configuration.theme: - hacs.configuration.theme = False - if hacs.configuration.config_type == "yaml": - hacs.logger.warning( - "Configuration option 'theme' is deprecated and you should remove it from your configuration, HACS will know if you use 'theme' in your Home Assistant configuration, this option will be removed in a future release." - ) # Setup startup tasks if hacs.configuration.config_type == "yaml": diff --git a/config/custom_components/hacs/config_flow.py b/config/custom_components/hacs/config_flow.py index 1f5e274c..7f55b4c7 100644 --- a/config/custom_components/hacs/config_flow.py +++ b/config/custom_components/hacs/config_flow.py @@ -2,7 +2,7 @@ # pylint: disable=dangerous-default-value import logging import voluptuous as vol -from aiogithubapi import AIOGitHubException, AIOGitHubAuthentication +from aiogithubapi import AIOGitHubAPIException, AIOGitHubAPIAuthenticationException from homeassistant import config_entries from homeassistant.core import callback from homeassistant.helpers import aiohttp_client @@ -47,7 +47,7 @@ class HacsFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Show the configuration form to edit location data.""" return self.async_show_form( step_id="user", - data_schema=vol.Schema(hacs_base_config_schema(user_input, True)), + data_schema=vol.Schema(hacs_base_config_schema(user_input)), errors=self._errors, ) @@ -56,23 +56,16 @@ class HacsFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): def async_get_options_flow(config_entry): return HacsOptionsFlowHandler(config_entry) - async def async_step_import(self, user_input): - """Import a config entry. - Special type of import, we're not actually going to store any data. - Instead, we're going to rely on the values that are in config file. - """ - if self._async_current_entries(): - return self.async_abort(reason="single_instance_allowed") - - return self.async_create_entry(title="configuration.yaml", data={}) - async def _test_token(self, token): """Return true if token is valid.""" try: session = aiohttp_client.async_get_clientsession(self.hass) await get_repository(session, token, "hacs/org") return True - except (AIOGitHubException, AIOGitHubAuthentication) as exception: + except ( + AIOGitHubAPIException, + AIOGitHubAPIAuthenticationException, + ) as exception: _LOGGER.error(exception) return False diff --git a/config/custom_components/hacs/configuration_schema.py b/config/custom_components/hacs/configuration_schema.py index 704ea4ff..92bfe758 100644 --- a/config/custom_components/hacs/configuration_schema.py +++ b/config/custom_components/hacs/configuration_schema.py @@ -9,8 +9,6 @@ SIDEPANEL_TITLE = "sidepanel_title" SIDEPANEL_ICON = "sidepanel_icon" APPDAEMON = "appdaemon" NETDAEMON = "netdaemon" -PYTHON_SCRIPT = "python_script" -THEME = "theme" # Options: COUNTRY = "country" @@ -19,46 +17,39 @@ RELEASE_LIMIT = "release_limit" EXPERIMENTAL = "experimental" -def hacs_base_config_schema(config: dict = {}, config_flow: bool = False) -> dict: +def hacs_base_config_schema(config: dict = {}) -> dict: """Return a shcema configuration dict for HACS.""" if not config: config = { TOKEN: "xxxxxxxxxxxxxxxxxxxxxxxxxxx", - SIDEPANEL_ICON: "mdi:alpha-c-box", - SIDEPANEL_TITLE: "HACS", - APPDAEMON: False, - NETDAEMON: False, - PYTHON_SCRIPT: False, - THEME: False, - } - if config_flow: - return { - vol.Required(TOKEN, default=config.get(TOKEN)): str, - vol.Optional(SIDEPANEL_TITLE, default=config.get(SIDEPANEL_TITLE)): str, - vol.Optional(SIDEPANEL_ICON, default=config.get(SIDEPANEL_ICON)): str, - vol.Optional(APPDAEMON, default=config.get(APPDAEMON)): bool, - vol.Optional(NETDAEMON, default=config.get(NETDAEMON)): bool, } return { vol.Required(TOKEN, default=config.get(TOKEN)): str, - vol.Optional(SIDEPANEL_TITLE, default=config.get(SIDEPANEL_TITLE)): str, - vol.Optional(SIDEPANEL_ICON, default=config.get(SIDEPANEL_ICON)): str, - vol.Optional(APPDAEMON, default=config.get(APPDAEMON)): bool, - vol.Optional(NETDAEMON, default=config.get(NETDAEMON)): bool, - vol.Optional(PYTHON_SCRIPT, default=config.get(PYTHON_SCRIPT)): bool, - vol.Optional(THEME, default=config.get(THEME)): bool, } def hacs_config_option_schema(options: dict = {}) -> dict: """Return a shcema for HACS configuration options.""" if not options: - options = {COUNTRY: "ALL", DEBUG: False, RELEASE_LIMIT: 5, EXPERIMENTAL: False} + options = { + APPDAEMON: False, + COUNTRY: "ALL", + DEBUG: False, + EXPERIMENTAL: False, + NETDAEMON: False, + RELEASE_LIMIT: 5, + SIDEPANEL_ICON: "hacs:hacs", + SIDEPANEL_TITLE: "HACS", + } return { - vol.Optional(COUNTRY, default=options.get(COUNTRY)): vol.In(LOCALE), + vol.Optional(SIDEPANEL_TITLE, default=options.get(SIDEPANEL_TITLE)): str, + vol.Optional(SIDEPANEL_ICON, default=options.get(SIDEPANEL_ICON)): str, vol.Optional(RELEASE_LIMIT, default=options.get(RELEASE_LIMIT)): int, - vol.Optional(EXPERIMENTAL, default=options.get(EXPERIMENTAL)): bool, + vol.Optional(COUNTRY, default=options.get(COUNTRY)): vol.In(LOCALE), + vol.Optional(APPDAEMON, default=options.get(APPDAEMON)): bool, + vol.Optional(NETDAEMON, default=options.get(NETDAEMON)): bool, vol.Optional(DEBUG, default=options.get(DEBUG)): bool, + vol.Optional(EXPERIMENTAL, default=options.get(EXPERIMENTAL)): bool, } diff --git a/config/custom_components/hacs/const.py b/config/custom_components/hacs/const.py index c623ba27..f74c5f89 100644 --- a/config/custom_components/hacs/const.py +++ b/config/custom_components/hacs/const.py @@ -1,7 +1,7 @@ """Constants for HACS""" NAME_LONG = "HACS (Home Assistant Community Store)" NAME_SHORT = "HACS" -VERSION = "0.24.5" +VERSION = "1.0.0" DOMAIN = "hacs" PROJECT_URL = "https://github.com/hacs/integration/" CUSTOM_UPDATER_LOCATIONS = [ @@ -15,8 +15,8 @@ DOMAIN_DATA = f"{NAME_SHORT.lower()}_data" ELEMENT_TYPES = ["integration", "plugin"] IFRAME = { - "title": "Community", - "icon": "mdi:alpha-c-box", + "title": "HACS", + "icon": "hacs:hacs", "url": "/community_overview", "path": "community", "require_admin": True, diff --git a/config/custom_components/hacs/constrains.py b/config/custom_components/hacs/constrains.py index 7ae709b2..bc8e2575 100644 --- a/config/custom_components/hacs/constrains.py +++ b/config/custom_components/hacs/constrains.py @@ -7,10 +7,10 @@ from .helpers.misc import version_left_higher_then_right from custom_components.hacs.globals import get_hacs -MINIMUM_HA_VERSION = "0.98.0" +MINIMUM_HA_VERSION = "0.110.0" -def check_constans(): +def check_constrains(): """Check HACS constrains.""" if not constrain_translations(): return False @@ -54,46 +54,3 @@ def constrain_translations(): hacs.logger.critical("You are missing the translations directory.") return False return True - - -def check_requirements(): - """Check the requirements""" - missing = [] - try: - from aiogithubapi import AIOGitHubException # pylint: disable=unused-import - except ImportError: - missing.append("aiogithubapi") - - try: - from hacs_frontend import locate_gz # pylint: disable=unused-import - except ImportError: - missing.append("hacs_frontend") - - try: - import semantic_version # pylint: disable=unused-import - except ImportError: - missing.append("semantic_version") - - try: - from integrationhelper import Logger # pylint: disable=unused-import - except ImportError: - missing.append("integrationhelper") - - try: - import backoff # pylint: disable=unused-import - except ImportError: - missing.append("backoff") - - try: - import aiofiles # pylint: disable=unused-import - except ImportError: - missing.append("aiofiles") - - if missing: - hacs = get_hacs() - for requirement in missing: - hacs.logger.critical( - f"Required python requirement '{requirement}' is not installed" - ) - return False - return True diff --git a/config/custom_components/hacs/globals.py b/config/custom_components/hacs/globals.py index 91d8314e..7c74b7df 100644 --- a/config/custom_components/hacs/globals.py +++ b/config/custom_components/hacs/globals.py @@ -1,6 +1,7 @@ # pylint: disable=invalid-name, missing-docstring hacs = [] removed_repositories = [] +rules = {} def get_hacs(): diff --git a/config/custom_components/hacs/hacsbase/__init__.py b/config/custom_components/hacs/hacsbase/__init__.py index 3cd59e44..35a4fb94 100644 --- a/config/custom_components/hacs/hacsbase/__init__.py +++ b/config/custom_components/hacs/hacsbase/__init__.py @@ -6,7 +6,7 @@ from datetime import timedelta from homeassistant.helpers.event import async_call_later, async_track_time_interval -from aiogithubapi import AIOGitHubException, AIOGitHubRatelimit +from aiogithubapi import AIOGitHubAPIException, AIOGitHubAPIRatelimitException from integrationhelper import Logger from queueman import QueueManager @@ -115,7 +115,7 @@ class Hacs: """Get repository by ID.""" try: for repository in self.repositories: - if repository.information.uid == repository_id: + if str(repository.data.id) == str(repository_id): return repository except Exception: # pylint: disable=broad-except pass @@ -131,11 +131,9 @@ class Hacs: pass return None - def is_known(self, repository_full_name): + def is_known(self, repository_id): """Return a bool if the repository is known.""" - return repository_full_name.lower() in [ - x.data.full_name.lower() for x in self.repositories - ] + return str(repository_id) in [str(x.data.id) for x in self.repositories] @property def sorted_by_name(self): @@ -156,8 +154,6 @@ class Hacs: self.system.status.background_task = True await self.hass.async_add_executor_job(setup_extra_stores) self.hass.bus.async_fire("hacs/status", {}) - self.logger.debug(self.github.ratelimits.remaining) - self.logger.debug(self.github.ratelimits.reset_utc) await self.handle_critical_repositories_startup() await self.handle_critical_repositories() @@ -186,7 +182,6 @@ class Hacs: await self.prosess_queue() self.system.status.startup = False - self.system.status.new = False self.system.status.background_task = False self.hass.bus.async_fire("hacs/status", {}) await self.data.async_write() @@ -216,7 +211,7 @@ class Hacs: try: critical = await self.data_repo.get_contents("critical") critical = json.loads(critical.content) - except AIOGitHubException: + except AIOGitHubAPIException: pass if not critical: @@ -290,11 +285,10 @@ class Hacs: ) self.system.status.background_task = True self.hass.bus.async_fire("hacs/status", {}) - self.logger.debug(self.github.ratelimits.remaining) - self.logger.debug(self.github.ratelimits.reset_utc) + for repository in self.repositories: if ( - repository.status.installed + repository.data.installed and repository.data.category in self.common.categories ): self.queue.add(self.factory.safe_update(repository)) @@ -311,8 +305,7 @@ class Hacs: await self.hass.async_add_executor_job(setup_extra_stores) self.system.status.background_task = True self.hass.bus.async_fire("hacs/status", {}) - self.logger.debug(self.github.ratelimits.remaining) - self.logger.debug(self.github.ratelimits.reset_utc) + for repository in self.repositories: if repository.data.category in self.common.categories: self.queue.add(self.factory.safe_common_update(repository)) @@ -329,9 +322,9 @@ class Hacs: """Clear out blaclisted repositories.""" need_to_save = False for removed in removed_repositories: - if self.is_known(removed.repository): - repository = self.get_by_name(removed.repository) - if repository.status.installed and removed.removal_type != "critical": + repository = self.get_by_name(removed.repository) + if repository is not None: + if repository.data.installed and removed.removal_type != "critical": self.logger.warning( f"You have {repository.data.full_name} installed with HACS " + f"this repository has been removed, please consider removing it. " @@ -354,11 +347,6 @@ class Hacs: org = await get_default_repos_orgs(self.github, category) for repo in org: repositories[category].append(repo) - - for category in repositories: - for repo in repositories[category]: - if repo not in self.common.default: - self.common.default.append(repo) return repositories async def load_known_repositories(self): @@ -378,6 +366,11 @@ class Hacs: for repo in repositories[category]: if is_removed(repo): continue - if self.is_known(repo): + repository = self.get_by_name(repo) + if repository is not None: + if str(repository.data.id) not in self.common.default: + self.common.default.append(str(repository.data.id)) + else: + continue continue self.queue.add(self.factory.safe_register(repo, category)) diff --git a/config/custom_components/hacs/hacsbase/configuration.py b/config/custom_components/hacs/hacsbase/configuration.py index c16ab96f..91dfb0f5 100644 --- a/config/custom_components/hacs/hacsbase/configuration.py +++ b/config/custom_components/hacs/hacsbase/configuration.py @@ -25,8 +25,8 @@ class Configuration: plugin_path: str = "www/community/" python_script_path: str = "python_scripts/" python_script: bool = False - sidepanel_icon: str = "mdi:alpha-c-box" - sidepanel_title: str = "Community" + sidepanel_icon: str = "hacs:hacs" + sidepanel_title: str = "HACS" theme_path: str = "themes/" theme: bool = False token: str = None @@ -50,7 +50,7 @@ class Configuration: logger.debug(f"{key}: {config[key]}") @staticmethod - def from_dict(configuration: dict, options: dict): + def from_dict(configuration: dict, options: dict = None): """Set attributes from dicts.""" if isinstance(options, bool) or isinstance(configuration.get("options"), bool): raise HacsException("Configuration is not valid.") diff --git a/config/custom_components/hacs/hacsbase/data.py b/config/custom_components/hacs/hacsbase/data.py index 8590aa16..7c7c889c 100644 --- a/config/custom_components/hacs/hacsbase/data.py +++ b/config/custom_components/hacs/hacsbase/data.py @@ -42,28 +42,39 @@ class HacsData: repository_manifest = repository.repository_manifest.manifest else: repository_manifest = None - content[repository.information.uid] = { + data = { "authors": repository.data.authors, "category": repository.data.category, "description": repository.data.description, - "downloads": repository.releases.downloads, + "domain": repository.data.domain, + "downloads": repository.data.downloads, "full_name": repository.data.full_name, "first_install": repository.status.first_install, - "hide": repository.status.hide, - "installed_commit": repository.versions.installed_commit, - "installed": repository.status.installed, - "last_commit": repository.versions.available_commit, - "last_release_tag": repository.versions.available, - "last_updated": repository.information.last_updated, + "installed_commit": repository.data.installed_commit, + "installed": repository.data.installed, + "last_commit": repository.data.last_commit, + "last_release_tag": repository.data.last_version, + "last_updated": repository.data.last_updated, "name": repository.data.name, - "new": repository.status.new, + "new": repository.data.new, "repository_manifest": repository_manifest, - "selected_tag": repository.status.selected_tag, - "show_beta": repository.status.show_beta, + "selected_tag": repository.data.selected_tag, + "show_beta": repository.data.show_beta, "stars": repository.data.stargazers_count, "topics": repository.data.topics, - "version_installed": repository.versions.installed, + "version_installed": repository.data.installed_version, } + if data: + if repository.data.installed and ( + repository.data.installed_commit + or repository.data.installed_version + ): + await async_save_to_store( + self.hacs.hass, + f"hacs/{repository.data.id}.hacs", + repository.data.to_json(), + ) + content[str(repository.data.id)] = data await async_save_to_store(self.hacs.hass, "repositories", content) self.hacs.hass.bus.async_fire("hacs/repository", {}) @@ -79,6 +90,7 @@ class HacsData: self.hacs.system.status.new = True return True self.logger.info("Restore started") + self.hacs.system.status.new = False # Hacs self.hacs.configuration.frontend_mode = hacs.get("view", "Grid") @@ -88,21 +100,40 @@ class HacsData: # Repositories for entry in repositories: repo = repositories[entry] - if not self.hacs.is_known(repo["full_name"]): + if not self.hacs.is_known(entry): await register_repository( repo["full_name"], repo["category"], False ) - repository = self.hacs.get_by_name(repo["full_name"]) - if repository is None: - self.logger.error(f"Did not find {repo['full_name']}") + repository = [ + x + for x in self.hacs.repositories + if str(x.data.id) == str(entry) + or x.data.full_name == repo["full_name"] + ] + if not repository: + self.logger.error(f"Did not find {repo['full_name']} ({entry})") continue + repository = repository[0] + # Restore repository attributes - repository.information.uid = entry + repository.data.id = entry await self.hacs.hass.async_add_executor_job( restore_repository_data, repository, repo ) + restored = await async_load_from_store( + self.hacs.hass, f"hacs/{entry}.hacs" + ) + + if restored: + repository.data.update_data(restored) + if not repository.data.installed: + repository.logger.debug( + "Should be installed but is not... Fixing that!" + ) + repository.data.installed = True + self.logger.info("Restore done") except Exception as exception: # pylint: disable=broad-except self.logger.critical(f"[{exception}] Restore Failed!") @@ -117,27 +148,28 @@ def restore_repository_data( repository.data.authors = repository_data.get("authors", []) repository.data.description = repository_data.get("description") repository.releases.last_release_object_downloads = repository_data.get("downloads") - repository.information.last_updated = repository_data.get("last_updated") + repository.data.last_updated = repository_data.get("last_updated") repository.data.topics = repository_data.get("topics", []) + repository.data.domain = repository_data.get("domain", None) repository.data.stargazers_count = repository_data.get("stars", 0) repository.releases.last_release = repository_data.get("last_release_tag") - repository.status.hide = repository_data.get("hide", False) - repository.status.installed = repository_data.get("installed", False) - repository.status.new = repository_data.get("new", True) - repository.status.selected_tag = repository_data.get("selected_tag") - repository.status.show_beta = repository_data.get("show_beta", False) - repository.versions.available = repository_data.get("last_release_tag") - repository.versions.available_commit = repository_data.get("last_commit") - repository.versions.installed = repository_data.get("version_installed") - repository.versions.installed_commit = repository_data.get("installed_commit") + repository.data.hide = repository_data.get("hide", False) + repository.data.installed = repository_data.get("installed", False) + repository.data.new = repository_data.get("new", True) + repository.data.selected_tag = repository_data.get("selected_tag") + repository.data.show_beta = repository_data.get("show_beta", False) + repository.data.last_version = repository_data.get("last_release_tag") + repository.data.last_commit = repository_data.get("last_commit") + repository.data.installed_version = repository_data.get("version_installed") + repository.data.installed_commit = repository_data.get("installed_commit") repository.repository_manifest = HacsManifest.from_dict( repository_data.get("repository_manifest", {}) ) - if repository.status.installed: + if repository.data.installed: repository.status.first_install = False if repository_data["full_name"] == "hacs/integration": - repository.versions.installed = VERSION - repository.status.installed = True + repository.data.installed_version = VERSION + repository.data.installed = True diff --git a/config/custom_components/hacs/hacsbase/task_factory.py b/config/custom_components/hacs/hacsbase/task_factory.py index 8b32aa9a..564a489e 100644 --- a/config/custom_components/hacs/hacsbase/task_factory.py +++ b/config/custom_components/hacs/hacsbase/task_factory.py @@ -3,7 +3,7 @@ import logging import time from datetime import timedelta import asyncio -from aiogithubapi import AIOGitHubException +from aiogithubapi import AIOGitHubAPIException from custom_components.hacs.hacsbase.exceptions import HacsException from custom_components.hacs.helpers.register_repository import register_repository @@ -48,7 +48,7 @@ class HacsTaskFactory: async with max_concurrent_tasks: try: await repository.common_update() - except (AIOGitHubException, HacsException) as exception: + except (AIOGitHubAPIException, HacsException) as exception: logger.error("%s - %s", repository.data.full_name, exception) # Due to GitHub ratelimits we need to sleep a bit @@ -58,7 +58,7 @@ class HacsTaskFactory: async with max_concurrent_tasks: try: await repository.update_repository() - except (AIOGitHubException, HacsException) as exception: + except (AIOGitHubAPIException, HacsException) as exception: logger.error("%s - %s", repository.data.full_name, exception) # Due to GitHub ratelimits we need to sleep a bit @@ -68,7 +68,7 @@ class HacsTaskFactory: async with max_concurrent_tasks: try: await register_repository(repo, category) - except (AIOGitHubException, HacsException) as exception: + except (AIOGitHubAPIException, HacsException) as exception: logger.error("%s - %s", repo, exception) # Due to GitHub ratelimits we need to sleep a bit diff --git a/config/custom_components/hacs/handler/template.py b/config/custom_components/hacs/handler/template.py index 48a998cd..a07038cd 100644 --- a/config/custom_components/hacs/handler/template.py +++ b/config/custom_components/hacs/handler/template.py @@ -16,10 +16,10 @@ def render_template(content, context): try: render = Template(content) render = render.render( - installed=context.status.installed, + installed=context.data.installed, pending_update=context.pending_upgrade, prerelease=prerelease, - selected_tag=context.status.selected_tag, + selected_tag=context.data.selected_tag, version_available=context.releases.last_release, version_installed=context.display_installed_version, ) diff --git a/config/custom_components/hacs/helpers/download.py b/config/custom_components/hacs/helpers/download.py index 17818f9b..9718e0c7 100644 --- a/config/custom_components/hacs/helpers/download.py +++ b/config/custom_components/hacs/helpers/download.py @@ -26,7 +26,7 @@ def should_try_releases(repository): return False if repository.data.category not in ["plugin", "theme"]: return False - if not repository.releases.releases: + if not repository.data.releases: return False return True diff --git a/config/custom_components/hacs/helpers/get_defaults.py b/config/custom_components/hacs/helpers/get_defaults.py index 744540da..faeafdbd 100644 --- a/config/custom_components/hacs/helpers/get_defaults.py +++ b/config/custom_components/hacs/helpers/get_defaults.py @@ -1,11 +1,12 @@ """Helpers to get default repositories.""" import json -from aiogithubapi import AIOGitHub, AIOGitHubException +from aiogithubapi import GitHub, AIOGitHubAPIException from integrationhelper import Logger +from custom_components.hacs.hacsbase.exceptions import HacsException from custom_components.hacs.helpers.information import get_repository -async def get_default_repos_orgs(github: type(AIOGitHub), category: str) -> dict: +async def get_default_repos_orgs(github: type(GitHub), category: str) -> dict: """Gets default org repositories.""" repositories = [] logger = Logger("hacs") @@ -22,7 +23,7 @@ async def get_default_repos_orgs(github: type(AIOGitHub), category: str) -> dict for repo in repos: repositories.append(repo.full_name) - except AIOGitHubException as exception: + except AIOGitHubAPIException as exception: logger.error(exception) return repositories @@ -38,7 +39,7 @@ async def get_default_repos_lists(session, token, default: str) -> dict: content = await repo.get_contents(default) repositories = json.loads(content.content) - except AIOGitHubException as exception: + except (AIOGitHubAPIException, HacsException) as exception: logger.error(exception) return repositories diff --git a/config/custom_components/hacs/helpers/information.py b/config/custom_components/hacs/helpers/information.py index da6adbd8..003497cd 100644 --- a/config/custom_components/hacs/helpers/information.py +++ b/config/custom_components/hacs/helpers/information.py @@ -1,6 +1,6 @@ """Return repository information if any.""" import json -from aiogithubapi import AIOGitHubException, AIOGitHub +from aiogithubapi import AIOGitHubAPIException, GitHub from custom_components.hacs.handler.template import render_template from custom_components.hacs.hacsbase.exceptions import HacsException @@ -29,7 +29,7 @@ async def get_info_md_content(repository): return "" info = info.content.replace("= "107": - logger = Logger("hacs.deprecated") - logger.warning( - "The '/community_plugin/*' is deprecated and will be removed in an upcoming version of HACS, it has been replaced by '/hacsfiles/*', if you use the UI to manage your lovelace configuration, you can update this by going to the settings tab in HACS, if you use YAML to manage your lovelace configuration, you manually need to replace the URL in your resources." - ) - - return await get_file_response(requested_file) - - async def get_file_response(requested_file): """Get file.""" hacs = get_hacs() diff --git a/config/custom_components/hacs/iconset.js b/config/custom_components/hacs/iconset.js index a099db68..ef425f29 100644 --- a/config/custom_components/hacs/iconset.js +++ b/config/custom_components/hacs/iconset.js @@ -1,20 +1,7 @@ -const hacsIconPath = "m 20.064849,22.306912 c -0.0319,0.369835 -0.280561,0.707789 -0.656773,0.918212 -0.280572,0.153036 -0.605773,0.229553 -0.950094,0.229553 -0.0765,0 -0.146661,-0.0064 -0.216801,-0.01275 -0.605774,-0.05739 -1.135016,-0.344329 -1.402827,-0.7588 l 0.784304,-0.516495 c 0.0893,0.146659 0.344331,0.312448 0.707793,0.34433 0.235931,0.02551 0.471852,-0.01913 0.637643,-0.108401 0.101998,-0.05101 0.172171,-0.127529 0.17854,-0.191295 0.0065,-0.08289 -0.0255,-0.369835 -0.733293,-0.439975 -1.013854,-0.09565 -1.645127,-0.688661 -1.568606,-1.460214 0.0319,-0.382589 0.280561,-0.714165 0.663153,-0.930965 0.331571,-0.172165 0.752423,-0.25506 1.166895,-0.210424 0.599382,0.05739 1.128635,0.344329 1.402816,0.7588 l -0.784304,0.510118 c -0.0893,-0.140282 -0.344331,-0.299694 -0.707782,-0.331576 -0.235932,-0.02551 -0.471863,0.01913 -0.637654,0.10202 -0.0956,0.05739 -0.165791,0.133906 -0.17216,0.191295 -0.0255,0.293317 0.465482,0.420847 0.726913,0.439976 v 0.0064 c 1.020234,0.09565 1.638757,0.66953 1.562237,1.460213 z m -7.466854,-0.988354 c 0,-1.192401 0.962855,-2.155249 2.15525,-2.155249 0.599393,0 1.179645,0.25506 1.594117,0.707789 l -0.695033,0.624895 c -0.235931,-0.25506 -0.561133,-0.401718 -0.899084,-0.401718 -0.675903,0 -1.217906,0.542 -1.217906,1.217906 0,0.66953 0.542003,1.217908 1.217906,1.217908 0.337951,0 0.663153,-0.140283 0.899084,-0.401718 l 0.695033,0.631271 c -0.414472,0.452729 -0.988355,0.707788 -1.594117,0.707788 -1.192395,0 -2.15525,-0.969224 -2.15525,-2.148872 z M 8.6573365,23.461054 10.353474,19.14418 h 0.624893 l 1.568618,4.316874 H 11.52037 L 11.265308,22.734136 H 9.964513 l -0.274192,0.726918 z m 1.6833885,-1.68339 h 0.580263 L 10.646796,21.012487 Z M 8.1089536,19.156932 v 4.297745 H 7.1461095 v -1.645131 h -1.606867 v 1.645131 H 4.5763876 v -4.297745 h 0.9628549 v 1.696143 h 1.606867 V 19.156932 Z M 20.115859,4.2997436 C 20.090359,4.159461 19.969198,4.0574375 19.822548,4.0574375 H 14.141102 10.506516 4.8250686 c -0.14665,0 -0.2678112,0.1020202 -0.2933108,0.2423061 L 3.690064,8.8461703 c -0.00651,0.01913 -0.00651,0.03826 -0.00651,0.057391 v 1.5239797 c 0,0.165789 0.133911,0.299694 0.2996911,0.299694 H 4.5762579 20.0711 20.664112 c 0.165781,0 0.299691,-0.133905 0.299691,-0.299694 V 8.8971848 c 0,-0.01913 0,-0.03826 -0.0065,-0.05739 z M 4.5763876,17.358767 c 0,0.184917 0.1466608,0.331577 0.3315819,0.331577 h 5.5985465 3.634586 0.924594 c 0.184911,0 0.331571,-0.14666 0.331571,-0.331577 v -4.744098 c 0,-0.184918 0.146661,-0.331577 0.331582,-0.331577 h 2.894913 c 0.184921,0 0.331582,0.146659 0.331582,0.331577 v 4.744098 c 0,0.184917 0.146661,0.331577 0.331571,0.331577 h 0.446363 c 0.18491,0 0.331571,-0.14666 0.331571,-0.331577 v -5.636804 c 0,-0.184918 -0.146661,-0.331577 -0.331571,-0.331577 H 4.9079695 c -0.1849211,0 -0.3315819,0.146659 -0.3315819,0.331577 z m 1.6578879,-4.852498 h 5.6495565 c 0.15303,0 0.280561,0.12753 0.280561,0.280564 v 3.513438 c 0,0.153036 -0.127531,0.280566 -0.280561,0.280566 H 6.2342755 c -0.1530412,0 -0.2805719,-0.12753 -0.2805719,-0.280566 v -3.513438 c 0,-0.159411 0.1275307,-0.280564 0.2805719,-0.280564 z M 19.790657,3.3879075 H 4.8569594 c -0.1530412,0 -0.2805718,-0.1275296 -0.2805718,-0.2805642 V 1.3665653 C 4.5763876,1.2135296 4.7039182,1.086 4.8569594,1.086 H 19.790657 c 0.153041,0 0.280572,0.1275296 0.280572,0.2805653 v 1.740778 c 0,0.1530346 -0.127531,0.2805642 -0.280572,0.2805642 z" -const haIconSet = window.customElements.get("ha-iconset-svg") - -if (haIconSet === undefined) { - window.customIconsets = window.customIconsets || {} - window.customIconsets["hacs"] = async () => { return { hacs: { path: hacsIconPath } } } -} else { - const iconset = document.createElement("ha-iconset-svg"); - iconset.name = "hacs"; - iconset.size = "24"; - iconset.innerHTML = ` - - - - - - - ` - document.body.appendChild(iconset); -} \ No newline at end of file +window.customIconsets = window.customIconsets || {}; +window.customIconsets["hacs"] = async () => { + return { + path: + "m 20.064849,22.306912 c -0.0319,0.369835 -0.280561,0.707789 -0.656773,0.918212 -0.280572,0.153036 -0.605773,0.229553 -0.950094,0.229553 -0.0765,0 -0.146661,-0.0064 -0.216801,-0.01275 -0.605774,-0.05739 -1.135016,-0.344329 -1.402827,-0.7588 l 0.784304,-0.516495 c 0.0893,0.146659 0.344331,0.312448 0.707793,0.34433 0.235931,0.02551 0.471852,-0.01913 0.637643,-0.108401 0.101998,-0.05101 0.172171,-0.127529 0.17854,-0.191295 0.0065,-0.08289 -0.0255,-0.369835 -0.733293,-0.439975 -1.013854,-0.09565 -1.645127,-0.688661 -1.568606,-1.460214 0.0319,-0.382589 0.280561,-0.714165 0.663153,-0.930965 0.331571,-0.172165 0.752423,-0.25506 1.166895,-0.210424 0.599382,0.05739 1.128635,0.344329 1.402816,0.7588 l -0.784304,0.510118 c -0.0893,-0.140282 -0.344331,-0.299694 -0.707782,-0.331576 -0.235932,-0.02551 -0.471863,0.01913 -0.637654,0.10202 -0.0956,0.05739 -0.165791,0.133906 -0.17216,0.191295 -0.0255,0.293317 0.465482,0.420847 0.726913,0.439976 v 0.0064 c 1.020234,0.09565 1.638757,0.66953 1.562237,1.460213 z m -7.466854,-0.988354 c 0,-1.192401 0.962855,-2.155249 2.15525,-2.155249 0.599393,0 1.179645,0.25506 1.594117,0.707789 l -0.695033,0.624895 c -0.235931,-0.25506 -0.561133,-0.401718 -0.899084,-0.401718 -0.675903,0 -1.217906,0.542 -1.217906,1.217906 0,0.66953 0.542003,1.217908 1.217906,1.217908 0.337951,0 0.663153,-0.140283 0.899084,-0.401718 l 0.695033,0.631271 c -0.414472,0.452729 -0.988355,0.707788 -1.594117,0.707788 -1.192395,0 -2.15525,-0.969224 -2.15525,-2.148872 z M 8.6573365,23.461054 10.353474,19.14418 h 0.624893 l 1.568618,4.316874 H 11.52037 L 11.265308,22.734136 H 9.964513 l -0.274192,0.726918 z m 1.6833885,-1.68339 h 0.580263 L 10.646796,21.012487 Z M 8.1089536,19.156932 v 4.297745 H 7.1461095 v -1.645131 h -1.606867 v 1.645131 H 4.5763876 v -4.297745 h 0.9628549 v 1.696143 h 1.606867 V 19.156932 Z M 20.115859,4.2997436 C 20.090359,4.159461 19.969198,4.0574375 19.822548,4.0574375 H 14.141102 10.506516 4.8250686 c -0.14665,0 -0.2678112,0.1020202 -0.2933108,0.2423061 L 3.690064,8.8461703 c -0.00651,0.01913 -0.00651,0.03826 -0.00651,0.057391 v 1.5239797 c 0,0.165789 0.133911,0.299694 0.2996911,0.299694 H 4.5762579 20.0711 20.664112 c 0.165781,0 0.299691,-0.133905 0.299691,-0.299694 V 8.8971848 c 0,-0.01913 0,-0.03826 -0.0065,-0.05739 z M 4.5763876,17.358767 c 0,0.184917 0.1466608,0.331577 0.3315819,0.331577 h 5.5985465 3.634586 0.924594 c 0.184911,0 0.331571,-0.14666 0.331571,-0.331577 v -4.744098 c 0,-0.184918 0.146661,-0.331577 0.331582,-0.331577 h 2.894913 c 0.184921,0 0.331582,0.146659 0.331582,0.331577 v 4.744098 c 0,0.184917 0.146661,0.331577 0.331571,0.331577 h 0.446363 c 0.18491,0 0.331571,-0.14666 0.331571,-0.331577 v -5.636804 c 0,-0.184918 -0.146661,-0.331577 -0.331571,-0.331577 H 4.9079695 c -0.1849211,0 -0.3315819,0.146659 -0.3315819,0.331577 z m 1.6578879,-4.852498 h 5.6495565 c 0.15303,0 0.280561,0.12753 0.280561,0.280564 v 3.513438 c 0,0.153036 -0.127531,0.280566 -0.280561,0.280566 H 6.2342755 c -0.1530412,0 -0.2805719,-0.12753 -0.2805719,-0.280566 v -3.513438 c 0,-0.159411 0.1275307,-0.280564 0.2805719,-0.280564 z M 19.790657,3.3879075 H 4.8569594 c -0.1530412,0 -0.2805718,-0.1275296 -0.2805718,-0.2805642 V 1.3665653 C 4.5763876,1.2135296 4.7039182,1.086 4.8569594,1.086 H 19.790657 c 0.153041,0 0.280572,0.1275296 0.280572,0.2805653 v 1.740778 c 0,0.1530346 -0.127531,0.2805642 -0.280572,0.2805642 z", + }; +}; diff --git a/config/custom_components/hacs/manifest.json b/config/custom_components/hacs/manifest.json index e1835c97..269a338c 100644 --- a/config/custom_components/hacs/manifest.json +++ b/config/custom_components/hacs/manifest.json @@ -1,24 +1,22 @@ { - "codeowners": [ - "@ludeeus" - ], - "config_flow": true, - "dependencies": [ - "websocket_api", - "frontend", - "persistent_notification", - "lovelace" - ], - "documentation": "https://hacs.xyz/docs/configuration/start", - "domain": "hacs", - "name": "HACS (Home Assistant Community Store)", - "requirements": [ - "aiofiles==0.5.0", - "aiogithubapi==0.5.0", - "backoff==1.10.0", - "hacs_frontend==20200426112021", - "integrationhelper==0.2.2", - "semantic_version==2.8.5", - "queueman==0.5" - ] -} \ No newline at end of file + "codeowners": ["@ludeeus"], + "config_flow": true, + "dependencies": [ + "websocket_api", + "frontend", + "persistent_notification", + "lovelace" + ], + "documentation": "https://hacs.xyz/docs/configuration/start", + "domain": "hacs", + "name": "HACS", + "requirements": [ + "aiofiles==0.5.0", + "aiogithubapi==1.0.4", + "backoff==1.10.0", + "hacs_frontend==20200521162326", + "integrationhelper==0.2.2", + "semantic_version==2.8.5", + "queueman==0.5" + ] +} diff --git a/config/custom_components/hacs/repositories/appdaemon.py b/config/custom_components/hacs/repositories/appdaemon.py index 750ad464..7a34fdce 100644 --- a/config/custom_components/hacs/repositories/appdaemon.py +++ b/config/custom_components/hacs/repositories/appdaemon.py @@ -1,5 +1,5 @@ """Class for appdaemon apps in HACS.""" -from aiogithubapi import AIOGitHubException +from aiogithubapi import AIOGitHubAPIException from integrationhelper import Logger from .repository import HacsRepository @@ -30,7 +30,7 @@ class HacsAppdaemon(HacsRepository): # Custom step 1: Validate content. try: addir = await self.repository_object.get_contents("apps", self.ref) - except AIOGitHubException: + except AIOGitHubAPIException: raise HacsException( f"Repostitory structure for {self.ref.replace('tags/','')} is not compliant" ) @@ -64,11 +64,9 @@ class HacsAppdaemon(HacsRepository): # Set local path self.content.path.local = self.localpath - async def update_repository(self): + async def update_repository(self, ignore_issues=False): """Update.""" - if self.hacs.github.ratelimits.remaining == 0: - return - await self.common_update() + await self.common_update(ignore_issues) # Get appdaemon objects. if self.repository_manifest: diff --git a/config/custom_components/hacs/repositories/integration.py b/config/custom_components/hacs/repositories/integration.py index 5f9bad49..2aa6f641 100644 --- a/config/custom_components/hacs/repositories/integration.py +++ b/config/custom_components/hacs/repositories/integration.py @@ -74,11 +74,9 @@ class HacsIntegration(HacsRepository): # Set local path self.content.path.local = self.localpath - async def update_repository(self): + async def update_repository(self, ignore_issues=False): """Update.""" - if self.hacs.github.ratelimits.remaining == 0: - return - await self.common_update() + await self.common_update(ignore_issues) if self.data.content_in_root: self.content.path.remote = "" diff --git a/config/custom_components/hacs/repositories/netdaemon.py b/config/custom_components/hacs/repositories/netdaemon.py index d9b14a22..3691acb3 100644 --- a/config/custom_components/hacs/repositories/netdaemon.py +++ b/config/custom_components/hacs/repositories/netdaemon.py @@ -72,11 +72,9 @@ class HacsNetdaemon(HacsRepository): # Set local path self.content.path.local = self.localpath - async def update_repository(self): + async def update_repository(self, ignore_issues=False): """Update.""" - if self.hacs.github.ratelimits.remaining == 0: - return - await self.common_update() + await self.common_update(ignore_issues) # Get appdaemon objects. if self.repository_manifest: diff --git a/config/custom_components/hacs/repositories/plugin.py b/config/custom_components/hacs/repositories/plugin.py index 50f0eb3c..a0b2db08 100644 --- a/config/custom_components/hacs/repositories/plugin.py +++ b/config/custom_components/hacs/repositories/plugin.py @@ -57,19 +57,13 @@ class HacsPlugin(HacsRepository): # Run common registration steps. await self.common_registration() - async def update_repository(self): + async def update_repository(self, ignore_issues=False): """Update.""" - if self.hacs.github.ratelimits.remaining == 0: - return - # Run common update steps. - await self.common_update() + await self.common_update(ignore_issues) # Get plugin objects. find_file_name(self) - # Get JS type - await self.parse_readme_for_jstype() - if self.content.path.remote is None: self.validate.errors.append("Repostitory structure not compliant") @@ -86,25 +80,3 @@ class HacsPlugin(HacsRepository): self.data.authors = package["author"] except Exception: # pylint: disable=broad-except pass - - async def parse_readme_for_jstype(self): - """Parse the readme looking for js type.""" - readme = None - readme_files = ["readme", "readme.md"] - root = await self.repository_object.get_contents("") - for file in root: - if file.name.lower() in readme_files: - readme = await self.repository_object.get_contents(file.name) - break - - if readme is None: - return - - readme = readme.content - for line in readme.splitlines(): - if "type: module" in line: - self.information.javascript_type = "module" - break - elif "type: js" in line: - self.information.javascript_type = "js" - break diff --git a/config/custom_components/hacs/repositories/python_script.py b/config/custom_components/hacs/repositories/python_script.py index 6defbf7e..2440dd46 100644 --- a/config/custom_components/hacs/repositories/python_script.py +++ b/config/custom_components/hacs/repositories/python_script.py @@ -63,12 +63,9 @@ class HacsPythonScript(HacsRepository): # Set name find_file_name(self) - async def update_repository(self): # lgtm[py/similar-function] + async def update_repository(self, ignore_issues=False): """Update.""" - if self.hacs.github.ratelimits.remaining == 0: - return - # Run common update steps. - await self.common_update() + await self.common_update(ignore_issues) # Get python_script objects. if self.data.content_in_root: diff --git a/config/custom_components/hacs/repositories/repository.py b/config/custom_components/hacs/repositories/repository.py index 69ff7b4f..8e6bb95e 100644 --- a/config/custom_components/hacs/repositories/repository.py +++ b/config/custom_components/hacs/repositories/repository.py @@ -5,7 +5,7 @@ import os import tempfile import zipfile from integrationhelper import Validate -from aiogithubapi import AIOGitHubException +from aiogithubapi import AIOGitHubAPIException from .manifest import HacsManifest from ..helpers.misc import get_repository_name from ..handler.download import async_download_file, async_save_file @@ -13,6 +13,7 @@ from ..helpers.misc import version_left_higher_then_right from ..helpers.install import install_repository, version_to_install from custom_components.hacs.hacsbase.exceptions import HacsException +from custom_components.hacs.store import async_remove_store from custom_components.hacs.globals import get_hacs from custom_components.hacs.helpers.information import ( get_info_md_content, @@ -126,31 +127,22 @@ class HacsRepository: """Return pending upgrade.""" if not self.can_install: return False - if self.status.installed: - if self.status.selected_tag is not None: - if self.status.selected_tag == self.data.default_branch: - if self.versions.installed_commit != self.versions.available_commit: + if self.data.installed: + if self.data.selected_tag is not None: + if self.data.selected_tag == self.data.default_branch: + if self.data.installed_commit != self.data.last_commit: return True return False if self.display_installed_version != self.display_available_version: return True return False - @property - def config_flow(self): - """Return bool if integration has config_flow.""" - if self.integration_manifest: - if self.data.full_name == "hacs/integration": - return False - return self.integration_manifest.get("config_flow", False) - return False - @property def custom(self): """Return flag if the repository is custom.""" if self.data.full_name.split("/")[0] in ["custom-components", "custom-cards"]: return False - if self.data.full_name.lower() in [x.lower() for x in self.hacs.common.default]: + if str(self.data.id) in [str(x) for x in self.hacs.common.default]: return False if self.data.full_name == "hacs/integration": return False @@ -160,14 +152,13 @@ class HacsRepository: def can_install(self): """Return bool if repository can be installed.""" target = None - if self.information.homeassistant_version is not None: - target = self.information.homeassistant_version - if self.repository_manifest is not None: - if self.data.homeassistant is not None: - target = self.data.homeassistant + if self.data.homeassistant is not None: + target = self.data.homeassistant + if self.data.homeassistant is not None: + target = self.data.homeassistant if target is not None: - if self.releases.releases: + if self.data.releases: if not version_left_higher_then_right( self.hacs.system.ha_version, target ): @@ -182,13 +173,13 @@ class HacsRepository: @property def display_status(self): """Return display_status.""" - if self.status.new: + if self.data.new: status = "new" elif self.pending_restart: status = "pending-restart" elif self.pending_upgrade: status = "pending-upgrade" - elif self.status.installed: + elif self.data.installed: status = "installed" else: status = "default" @@ -209,11 +200,11 @@ class HacsRepository: @property def display_installed_version(self): """Return display_authors""" - if self.versions.installed is not None: - installed = self.versions.installed + if self.data.installed_version is not None: + installed = self.data.installed_version else: - if self.versions.installed_commit is not None: - installed = self.versions.installed_commit + if self.data.installed_commit is not None: + installed = self.data.installed_commit else: installed = "" return installed @@ -221,11 +212,11 @@ class HacsRepository: @property def display_available_version(self): """Return display_authors""" - if self.versions.available is not None: - available = self.versions.available + if self.data.last_version is not None: + available = self.data.last_version else: - if self.versions.available_commit is not None: - available = self.versions.available_commit + if self.data.last_commit is not None: + available = self.data.last_commit else: available = "" return available @@ -233,7 +224,7 @@ class HacsRepository: @property def display_version_or_commit(self): """Does the repositoriy use releases or commits?""" - if self.releases.releases: + if self.data.releases: version_or_commit = "version" else: version_or_commit = "commit" @@ -251,9 +242,9 @@ class HacsRepository: } return actions[self.display_status] - async def common_validate(self): + async def common_validate(self, ignore_issues=False): """Common validation steps of the repository.""" - await common_validate(self) + await common_validate(self, ignore_issues) async def common_registration(self): """Common registration steps of the repository.""" @@ -264,9 +255,6 @@ class HacsRepository: ) self.data.update_data(self.repository_object.attributes) - # Set id - self.information.uid = str(self.data.id) - # Set topics self.data.topics = self.data.topics @@ -280,21 +268,19 @@ class HacsRepository: if self.data.description is None or len(self.data.description) == 0: raise HacsException("Missing repository description") - async def common_update(self): + async def common_update(self, ignore_issues=False): """Common information update steps of the repository.""" self.logger.debug("Getting repository information") # Attach repository - await common_update_data(self) + await common_update_data(self, ignore_issues) # Update last updaeted - self.information.last_updated = self.repository_object.attributes.get( - "pushed_at", 0 - ) + self.data.last_updated = self.repository_object.attributes.get("pushed_at", 0) # Update last available commit await self.repository_object.set_last_commit() - self.versions.available_commit = self.repository_object.last_commit + self.data.last_commit = self.repository_object.last_commit # Get the content of hacs.json await self.get_repository_manifest_content() @@ -357,30 +343,30 @@ class HacsRepository: raise HacsException("No hacs.json file in the root of the repository.") return if self.hacs.action: - self.logger.debug("Found hacs.json") + self.logger.info("Found hacs.json") + + self.ref = version_to_install(self) - if self.ref is None: - self.ref = version_to_install(self) try: manifest = await self.repository_object.get_contents("hacs.json", self.ref) self.repository_manifest = HacsManifest.from_dict( json.loads(manifest.content) ) self.data.update_data(json.loads(manifest.content)) - except (AIOGitHubException, Exception) as exception: # Gotta Catch 'Em All + except (AIOGitHubAPIException, Exception) as exception: # Gotta Catch 'Em All if self.hacs.action: raise HacsException(f"hacs.json file is not valid ({exception}).") if self.hacs.action: - self.logger.debug("hacs.json is valid") + self.logger.info("hacs.json is valid") def remove(self): """Run remove tasks.""" self.logger.info("Starting removal") - if self.information.uid in self.hacs.common.installed: - self.hacs.common.installed.remove(self.information.uid) + if self.data.id in self.hacs.common.installed: + self.hacs.common.installed.remove(self.data.id) for repository in self.hacs.repositories: - if repository.information.uid == self.information.uid: + if repository.data.id == self.data.id: self.hacs.repositories.remove(repository) async def uninstall(self): @@ -388,9 +374,9 @@ class HacsRepository: self.logger.info("Uninstalling") if not await self.remove_local_directory(): raise HacsException("Could not uninstall") - self.status.installed = False + self.data.installed = False if self.data.category == "integration": - if self.config_flow: + if self.data.config_flow: await self.reload_custom_components() else: self.pending_restart = True @@ -403,8 +389,11 @@ class HacsRepository: pass if self.data.full_name in self.hacs.common.installed: self.hacs.common.installed.remove(self.data.full_name) - self.versions.installed = None - self.versions.installed_commit = None + + await async_remove_store(self.hacs.hass, f"hacs/{self.data.id}.hacs") + + self.data.installed_version = None + self.data.installed_commit = None self.hacs.hass.bus.async_fire( "hacs/repository", {"id": 1337, "action": "uninstall", "repository": self.data.full_name}, diff --git a/config/custom_components/hacs/repositories/repositorydata.py b/config/custom_components/hacs/repositories/repositorydata.py index 60b67753..17ec7a76 100644 --- a/config/custom_components/hacs/repositories/repositorydata.py +++ b/config/custom_components/hacs/repositories/repositorydata.py @@ -8,32 +8,52 @@ import attr class RepositoryData: """RepositoryData class.""" - id: int = 0 - full_name: str = "" - pushed_at: str = "" - category: str = "" archived: bool = False - description: str = "" - manifest_name: str = None - topics: List[str] = [] - fork: bool = False - domain: str = "" - default_branch: str = None - stargazers_count: int = 0 - last_commit: str = "" - file_name: str = "" - content_in_root: bool = False - zip_release: bool = False - filename: str = "" - render_readme: bool = False - hide_default_branch: bool = False - domains: List[str] = [] - country: List[str] = [] authors: List[str] = [] - homeassistant: str = None # Minimum Home Assistant version + category: str = "" + content_in_root: bool = False + country: List[str] = [] + config_flow: bool = False + default_branch: str = None + description: str = "" + domain: str = "" + domains: List[str] = [] + downloads: int = 0 + file_name: str = "" + filename: str = "" + first_install: bool = False + fork: bool = False + full_name: str = "" hacs: str = None # Minimum HACS version - persistent_directory: str = None + hide: bool = False + hide_default_branch: bool = False + homeassistant: str = None # Minimum Home Assistant version + id: int = 0 iot_class: str = None + installed: bool = False + installed_commit: str = None + installed_version: str = None + open_issues: int = 0 + last_commit: str = None + last_version: str = None + last_updated: str = 0 + manifest_name: str = None + new: bool = True + persistent_directory: str = None + pushed_at: str = "" + releases: bool = False + render_readme: bool = False + published_tags: List[str] = [] + selected_tag: str = None + show_beta: bool = False + stargazers_count: int = 0 + topics: List[str] = [] + zip_release: bool = False + + @property + def stars(self): + """Return the stargazers count.""" + return self.stargazers_count or 0 @property def name(self): @@ -53,9 +73,20 @@ class RepositoryData: for key in source: if key in data.__dict__: if key == "pushed_at": - setattr( - data, key, datetime.strptime(source[key], "%Y-%m-%dT%H:%M:%SZ") - ) + if "Z" in source[key]: + setattr( + data, + key, + datetime.strptime(source[key], "%Y-%m-%dT%H:%M:%SZ"), + ) + else: + setattr( + data, + key, + datetime.strptime(source[key], "%Y-%m-%dT%H:%M:%S"), + ) + elif key == "id": + setattr(data, key, str(source[key])) elif key == "county": if isinstance(source[key], str): setattr(data, key, [source[key]]) @@ -70,9 +101,18 @@ class RepositoryData: for key in data: if key in self.__dict__: if key == "pushed_at": - setattr( - self, key, datetime.strptime(data[key], "%Y-%m-%dT%H:%M:%SZ") - ) + if "Z" in data[key]: + setattr( + self, + key, + datetime.strptime(data[key], "%Y-%m-%dT%H:%M:%SZ"), + ) + else: + setattr( + self, key, datetime.strptime(data[key], "%Y-%m-%dT%H:%M:%S") + ) + elif key == "id": + setattr(self, key, str(data[key])) elif key == "county": if isinstance(data[key], str): setattr(self, key, [data[key]]) diff --git a/config/custom_components/hacs/repositories/theme.py b/config/custom_components/hacs/repositories/theme.py index 63f91ae7..a631f1c9 100644 --- a/config/custom_components/hacs/repositories/theme.py +++ b/config/custom_components/hacs/repositories/theme.py @@ -59,12 +59,9 @@ class HacsTheme(HacsRepository): find_file_name(self) self.content.path.local = f"{self.hacs.system.config_path}/themes/{self.data.file_name.replace('.yaml', '')}" - async def update_repository(self): # lgtm[py/similar-function] + async def update_repository(self, ignore_issues=False): """Update.""" - if self.hacs.github.ratelimits.remaining == 0: - return - # Run common update steps. - await self.common_update() + await self.common_update(ignore_issues) # Get theme objects. if self.data.content_in_root: diff --git a/config/custom_components/hacs/sensor.py b/config/custom_components/hacs/sensor.py index c4a5f3dc..f91ea147 100644 --- a/config/custom_components/hacs/sensor.py +++ b/config/custom_components/hacs/sensor.py @@ -89,8 +89,8 @@ class HACSSensor(HACSDevice): { "name": repository.data.full_name, "display_name": repository.display_name, - "installed version": repository.display_installed_version, - "available version": repository.display_available_version, + "installed_version": repository.display_installed_version, + "available_version": repository.display_available_version, } ) return {"repositories": data} diff --git a/config/custom_components/hacs/setup.py b/config/custom_components/hacs/setup.py index af7f9a0f..746b5d98 100644 --- a/config/custom_components/hacs/setup.py +++ b/config/custom_components/hacs/setup.py @@ -21,9 +21,9 @@ async def load_hacs_repository(): repository = hacs.get_by_name("hacs/integration") if repository is None: raise HacsException("Unknown error") - repository.status.installed = True - repository.versions.installed = VERSION - repository.status.new = False + repository.data.installed = True + repository.data.installed_version = VERSION + repository.data.new = False hacs.repo = repository.repository_object hacs.data_repo = await get_repository( hacs.session, hacs.configuration.token, "hacs/default" @@ -72,7 +72,7 @@ def add_sensor(): async def setup_frontend(): """Configure the HACS frontend elements.""" - from .http import HacsFrontend, HacsPluginViewLegacy + from .http import HacsFrontend from .ws_api_handlers import setup_ws_api hacs = get_hacs() @@ -80,9 +80,6 @@ async def setup_frontend(): hacs.hass.http.register_view(HacsFrontend()) hacs.frontend.version_running = FE_VERSION - # Legacy views, remove with 2.0 - hacs.hass.http.register_view(HacsPluginViewLegacy()) - # Add to sidepanel custom_panel_config = { "name": "hacs-frontend", diff --git a/config/custom_components/hacs/store.py b/config/custom_components/hacs/store.py index 848d4af7..c4d19b9a 100644 --- a/config/custom_components/hacs/store.py +++ b/config/custom_components/hacs/store.py @@ -6,7 +6,8 @@ from .hacsbase.const import STORAGE_VERSION async def async_load_from_store(hass, key): """Load the retained data from store and return de-serialized data.""" - store = Store(hass, STORAGE_VERSION, f"hacs.{key}", encoder=JSONEncoder) + key = key if "/" in key else f"hacs.{key}" + store = Store(hass, STORAGE_VERSION, key, encoder=JSONEncoder) restored = await store.async_load() if restored is None: return {} @@ -15,5 +16,14 @@ async def async_load_from_store(hass, key): async def async_save_to_store(hass, key, data): """Generate dynamic data to store and save it to the filesystem.""" - store = Store(hass, STORAGE_VERSION, f"hacs.{key}", encoder=JSONEncoder) + key = key if "/" in key else f"hacs.{key}" + store = Store(hass, STORAGE_VERSION, key, encoder=JSONEncoder) await store.async_save(data) + + +async def async_remove_store(hass, key): + """Remove a store element that should no longer be used""" + if "/" not in key: + return + store = Store(hass, STORAGE_VERSION, key, encoder=JSONEncoder) + await store.async_remove() diff --git a/config/custom_components/hacs/ws_api_handlers.py b/config/custom_components/hacs/ws_api_handlers.py index b01ceb3a..ec982058 100644 --- a/config/custom_components/hacs/ws_api_handlers.py +++ b/config/custom_components/hacs/ws_api_handlers.py @@ -3,7 +3,7 @@ import sys import os import voluptuous as vol -from aiogithubapi import AIOGitHubException +from aiogithubapi import AIOGitHubAPIException from homeassistant.components import websocket_api import homeassistant.helpers.config_validation as cv from .hacsbase.exceptions import HacsException @@ -61,7 +61,7 @@ async def hacs_settings(hass, connection, msg): hass.bus.async_fire("hacs/status", {}) for repository in hacs.repositories: if repository.pending_upgrade: - repository.status.selected_tag = None + repository.data.selected_tag = None await repository.install() hacs.system.status.upgrading_all = False hacs.system.status.background_task = False @@ -70,14 +70,14 @@ async def hacs_settings(hass, connection, msg): elif action == "clear_new": for repo in hacs.repositories: - if msg.get("category") == repo.data.category: - if repo.status.new: - hacs.logger.debug(f"Clearing new flag from '{repo.data.full_name}'") - repo.status.new = False + if repo.data.new: + hacs.logger.debug(f"Clearing new flag from '{repo.data.full_name}'") + repo.data.new = False else: hacs.logger.error(f"WS action '{action}' is not valid") hass.bus.async_fire("hacs/config", {}) await hacs.data.async_write() + connection.send_message(websocket_api.result_message(msg["id"], {})) @websocket_api.async_response @@ -113,6 +113,7 @@ async def hacs_status(hass, connection, msg): "reloading_data": hacs.system.status.reloading_data, "upgrading_all": hacs.system.status.upgrading_all, "disabled": hacs.system.disabled, + "has_pending_tasks": hacs.queue.has_pending_tasks, } connection.send_message(websocket_api.result_message(msg["id"], content)) @@ -130,35 +131,36 @@ async def hacs_repositories(hass, connection, msg): "additional_info": repo.information.additional_info, "authors": repo.data.authors, "available_version": repo.display_available_version, - "beta": repo.status.show_beta, + "beta": repo.data.show_beta, "can_install": repo.can_install, "category": repo.data.category, "country": repo.data.country, - "config_flow": repo.config_flow, + "config_flow": repo.data.config_flow, "custom": repo.custom, "default_branch": repo.data.default_branch, "description": repo.data.description, - "domain": repo.integration_manifest.get("domain"), - "downloads": repo.releases.downloads, + "domain": repo.data.domain, + "downloads": repo.data.downloads, "file_name": repo.data.file_name, "first_install": repo.status.first_install, "full_name": repo.data.full_name, - "hide": repo.status.hide, + "hide": repo.data.hide, "hide_default_branch": repo.data.hide_default_branch, "homeassistant": repo.data.homeassistant, - "id": repo.information.uid, + "id": repo.data.id, "info": repo.information.info, "installed_version": repo.display_installed_version, - "installed": repo.status.installed, + "installed": repo.data.installed, + "issues": repo.data.open_issues, "javascript_type": repo.information.javascript_type, - "last_updated": repo.information.last_updated, + "last_updated": repo.data.last_updated, "local_path": repo.content.path.local, "main_action": repo.main_action, "name": repo.display_name, - "new": repo.status.new, + "new": repo.data.new, "pending_upgrade": repo.pending_upgrade, - "releases": repo.releases.published_tags, - "selected_tag": repo.status.selected_tag, + "releases": repo.data.published_tags, + "selected_tag": repo.data.selected_tag, "stars": repo.data.stargazers_count, "state": repo.state, "status_description": repo.display_status_description, @@ -195,42 +197,48 @@ async def hacs_repository(hass, connection, msg): hacs.logger.debug(f"Running {action} for {repository.data.full_name}") if action == "update": - await repository.update_repository() + await repository.update_repository(True) repository.status.updated_info = True - repository.status.new = False elif action == "install": - was_installed = repository.status.installed + was_installed = repository.data.installed await repository.install() if not was_installed: hass.bus.async_fire("hacs/reload", {"force": True}) + elif action == "not_new": + repository.data.new = False + elif action == "uninstall": await repository.uninstall() elif action == "hide": - repository.status.hide = True + repository.data.hide = True elif action == "unhide": - repository.status.hide = False + repository.data.hide = False elif action == "show_beta": - repository.status.show_beta = True + repository.data.show_beta = True await repository.update_repository() elif action == "hide_beta": - repository.status.show_beta = False + repository.data.show_beta = False + await repository.update_repository() + + elif action == "toggle_beta": + repository.data.show_beta = not repository.data.show_beta await repository.update_repository() elif action == "delete": - repository.status.show_beta = False + repository.data.show_beta = False repository.remove() elif action == "set_version": if msg["version"] == repository.data.default_branch: - repository.status.selected_tag = None + repository.data.selected_tag = None else: - repository.status.selected_tag = msg["version"] + repository.data.selected_tag = msg["version"] await repository.update_repository() hass.bus.async_fire("hacs/reload", {"force": True}) @@ -240,11 +248,11 @@ async def hacs_repository(hass, connection, msg): await hacs.data.async_write() message = None - except AIOGitHubException as exception: + except AIOGitHubAPIException as exception: message = str(exception) hass.bus.async_fire("hacs/error", {"message": str(exception)}) except AttributeError as exception: - message = f"Could not use repository with ID {repo_id}" + message = f"Could not use repository with ID {repo_id} ({exception})" except Exception as exception: # pylint: disable=broad-except message = str(exception) @@ -253,6 +261,7 @@ async def hacs_repository(hass, connection, msg): hass.bus.async_fire("hacs/error", {"message": message}) repository.state = None + connection.send_message(websocket_api.result_message(msg["id"], {})) @websocket_api.async_response @@ -318,10 +327,19 @@ async def hacs_repository_data(hass, connection, msg): repository.state = data elif action == "set_version": - repository.status.selected_tag = data + repository.data.selected_tag = data await repository.update_repository() repository.state = None + elif action == "install": + was_installed = repository.data.installed + repository.data.selected_tag = data + await repository.update_repository() + await repository.install() + repository.state = None + if not was_installed: + hass.bus.async_fire("hacs/reload", {"force": True}) + elif action == "add": repository.state = None @@ -330,6 +348,7 @@ async def hacs_repository_data(hass, connection, msg): hacs.logger.error(f"WS action '{action}' is not valid") await hacs.data.async_write() + connection.send_message(websocket_api.result_message(msg["id"], {})) @websocket_api.async_response