Add HACS, Themes
This commit is contained in:
@@ -42,25 +42,14 @@ http:
|
||||
- !secret gateway_ip4
|
||||
|
||||
# Configure Lovelace/Dashboards for YAML Configuration
|
||||
lovelace:
|
||||
mode: yaml
|
||||
resources: !include lovelace/resources.yaml
|
||||
dashboards: !include lovelace/dashboards.yaml
|
||||
# lovelace:
|
||||
# mode: yaml
|
||||
# resources: !include lovelace/resources.yaml
|
||||
# dashboards: !include lovelace/dashboards.yaml
|
||||
|
||||
# MQTT Broker Connection
|
||||
mqtt:
|
||||
broker: mqtt.ha.kraussnet.com
|
||||
port: 8883
|
||||
username: !secret mqtt_username
|
||||
password: !secret mqtt_password
|
||||
certificate: /config/network-ca-chain.pem
|
||||
discovery: true
|
||||
birth_message:
|
||||
topic: 'hass/status'
|
||||
payload: 'online'
|
||||
will_message:
|
||||
topic: 'hass/status'
|
||||
payload: 'offline'
|
||||
|
||||
# Configure Logging
|
||||
logger:
|
||||
@@ -82,8 +71,6 @@ config:
|
||||
|
||||
# Enable the Front End
|
||||
frontend:
|
||||
|
||||
# Add Themes
|
||||
themes: !include_dir_merge_named themes
|
||||
|
||||
# Configure FontAwesome Icons
|
||||
|
||||
209
custom_components/hacs/__init__.py
Normal file
209
custom_components/hacs/__init__.py
Normal file
@@ -0,0 +1,209 @@
|
||||
"""
|
||||
HACS gives you a powerful UI to handle downloads of all your custom needs.
|
||||
|
||||
For more details about this integration, please refer to the documentation at
|
||||
https://hacs.xyz/
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from aiogithubapi import AIOGitHubAPIException, GitHub, GitHubAPI
|
||||
from aiogithubapi.const import ACCEPT_HEADERS
|
||||
from awesomeversion import AwesomeVersion
|
||||
from homeassistant.components.lovelace.system_health import system_health_info
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, __version__ as HAVERSION
|
||||
from homeassistant.core import CoreState, HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.event import async_call_later
|
||||
from homeassistant.loader import async_get_integration
|
||||
import voluptuous as vol
|
||||
|
||||
from .base import HacsBase
|
||||
from .const import DOMAIN, STARTUP
|
||||
from .enums import ConfigurationType, HacsDisabledReason, HacsStage, LovelaceMode
|
||||
from .tasks.manager import HacsTaskManager
|
||||
from .utils.configuration_schema import hacs_config_combined
|
||||
from .utils.data import HacsData
|
||||
from .utils.queue_manager import QueueManager
|
||||
from .validate.manager import ValidationManager
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({DOMAIN: hacs_config_combined()}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
async def async_initialize_integration(
|
||||
hass: HomeAssistant,
|
||||
*,
|
||||
config_entry: ConfigEntry | None = None,
|
||||
config: dict[str, Any] | None = None,
|
||||
) -> bool:
|
||||
"""Initialize the integration"""
|
||||
hass.data[DOMAIN] = hacs = HacsBase()
|
||||
hacs.enable_hacs()
|
||||
|
||||
if config is not None:
|
||||
if DOMAIN not in config:
|
||||
return True
|
||||
if hacs.configuration.config_type == ConfigurationType.CONFIG_ENTRY:
|
||||
return True
|
||||
hacs.configuration.update_from_dict(
|
||||
{
|
||||
"config_type": ConfigurationType.YAML,
|
||||
**config[DOMAIN],
|
||||
"config": config[DOMAIN],
|
||||
}
|
||||
)
|
||||
|
||||
if config_entry is not None:
|
||||
if config_entry.source == SOURCE_IMPORT:
|
||||
hass.async_create_task(hass.config_entries.async_remove(config_entry.entry_id))
|
||||
return False
|
||||
|
||||
hacs.configuration.update_from_dict(
|
||||
{
|
||||
"config_entry": config_entry,
|
||||
"config_type": ConfigurationType.CONFIG_ENTRY,
|
||||
**config_entry.data,
|
||||
**config_entry.options,
|
||||
}
|
||||
)
|
||||
|
||||
integration = await async_get_integration(hass, DOMAIN)
|
||||
|
||||
await hacs.async_set_stage(None)
|
||||
|
||||
hacs.log.info(STARTUP, integration.version)
|
||||
|
||||
clientsession = async_get_clientsession(hass)
|
||||
|
||||
hacs.integration = integration
|
||||
hacs.version = integration.version
|
||||
hacs.configuration.dev = integration.version == "0.0.0"
|
||||
hacs.hass = hass
|
||||
hacs.queue = QueueManager(hass=hass)
|
||||
hacs.data = HacsData(hacs=hacs)
|
||||
hacs.system.running = True
|
||||
hacs.session = clientsession
|
||||
hacs.tasks = HacsTaskManager(hacs=hacs, hass=hass)
|
||||
hacs.validation = ValidationManager(hacs=hacs, hass=hass)
|
||||
|
||||
hacs.core.lovelace_mode = LovelaceMode.YAML
|
||||
try:
|
||||
lovelace_info = await system_health_info(hacs.hass)
|
||||
hacs.core.lovelace_mode = LovelaceMode(lovelace_info.get("mode", "yaml"))
|
||||
except BaseException: # lgtm [py/catch-base-exception] pylint: disable=broad-except
|
||||
# If this happens, the users YAML is not valid, we assume YAML mode
|
||||
pass
|
||||
hacs.log.debug("Configuration type: %s", hacs.configuration.config_type)
|
||||
hacs.core.config_path = hacs.hass.config.path()
|
||||
|
||||
if hacs.core.ha_version is None:
|
||||
hacs.core.ha_version = AwesomeVersion(HAVERSION)
|
||||
|
||||
await hacs.tasks.async_load()
|
||||
|
||||
## Legacy GitHub client
|
||||
hacs.github = GitHub(
|
||||
hacs.configuration.token,
|
||||
clientsession,
|
||||
headers={
|
||||
"User-Agent": f"HACS/{hacs.version}",
|
||||
"Accept": ACCEPT_HEADERS["preview"],
|
||||
},
|
||||
)
|
||||
|
||||
## New GitHub client
|
||||
hacs.githubapi = GitHubAPI(
|
||||
token=hacs.configuration.token,
|
||||
session=clientsession,
|
||||
**{"client_name": f"HACS/{hacs.version}"},
|
||||
)
|
||||
|
||||
async def async_startup():
|
||||
"""HACS startup tasks."""
|
||||
hacs.enable_hacs()
|
||||
|
||||
await hacs.async_set_stage(HacsStage.SETUP)
|
||||
if hacs.system.disabled:
|
||||
return False
|
||||
|
||||
# Setup startup tasks
|
||||
if hacs.hass.state == CoreState.running:
|
||||
async_call_later(hacs.hass, 5, hacs.startup_tasks)
|
||||
else:
|
||||
hacs.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED, hacs.startup_tasks)
|
||||
|
||||
await hacs.async_set_stage(HacsStage.WAITING)
|
||||
hacs.log.info("Setup complete, waiting for Home Assistant before startup tasks starts")
|
||||
|
||||
return not hacs.system.disabled
|
||||
|
||||
async def async_try_startup(_=None):
|
||||
"""Startup wrapper for yaml config."""
|
||||
try:
|
||||
startup_result = await async_startup()
|
||||
except AIOGitHubAPIException:
|
||||
startup_result = False
|
||||
if not startup_result:
|
||||
hacs.log.info("Could not setup HACS, trying again in 15 min")
|
||||
async_call_later(hass, 900, async_try_startup)
|
||||
return
|
||||
hacs.enable_hacs()
|
||||
|
||||
await async_try_startup()
|
||||
|
||||
# Mischief managed!
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
|
||||
"""Set up this integration using yaml."""
|
||||
return await async_initialize_integration(hass=hass, config=config)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Set up this integration using UI."""
|
||||
config_entry.async_on_unload(config_entry.add_update_listener(async_reload_entry))
|
||||
return await async_initialize_integration(hass=hass, config_entry=config_entry)
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Handle removal of an entry."""
|
||||
hacs: HacsBase = hass.data[DOMAIN]
|
||||
|
||||
# Clear out pending queue
|
||||
hacs.queue.clear()
|
||||
|
||||
for task in hacs.recuring_tasks:
|
||||
# Cancel all pending tasks
|
||||
task()
|
||||
|
||||
# Store data
|
||||
await hacs.data.async_write(force=True)
|
||||
|
||||
try:
|
||||
if hass.data.get("frontend_panels", {}).get("hacs"):
|
||||
hacs.log.info("Removing sidepanel")
|
||||
hass.components.frontend.async_remove_panel("hacs")
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
platforms = ["sensor"]
|
||||
if hacs.core.ha_version >= "2022.4.0.dev0" and hacs.configuration.experimental:
|
||||
platforms.append("update")
|
||||
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(config_entry, platforms)
|
||||
|
||||
await hacs.async_set_stage(None)
|
||||
hacs.disable_hacs(HacsDisabledReason.REMOVED)
|
||||
|
||||
hass.data.pop(DOMAIN, None)
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
||||
async def async_reload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
||||
"""Reload the HACS config entry."""
|
||||
await async_unload_entry(hass, config_entry)
|
||||
await async_setup_entry(hass, config_entry)
|
||||
654
custom_components/hacs/base.py
Normal file
654
custom_components/hacs/base.py
Normal file
@@ -0,0 +1,654 @@
|
||||
"""Base HACS class."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from dataclasses import asdict, dataclass, field
|
||||
import gzip
|
||||
import json
|
||||
import logging
|
||||
import math
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
from typing import TYPE_CHECKING, Any, Awaitable, Callable
|
||||
|
||||
from aiogithubapi import (
|
||||
AIOGitHubAPIException,
|
||||
GitHub,
|
||||
GitHubAPI,
|
||||
GitHubAuthenticationException,
|
||||
GitHubException,
|
||||
GitHubNotModifiedException,
|
||||
GitHubRatelimitException,
|
||||
)
|
||||
from aiogithubapi.objects.repository import AIOGitHubAPIRepository
|
||||
from aiohttp.client import ClientSession, ClientTimeout
|
||||
from awesomeversion import AwesomeVersion
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.loader import Integration
|
||||
from homeassistant.util import dt
|
||||
|
||||
from .const import TV
|
||||
from .enums import (
|
||||
ConfigurationType,
|
||||
HacsCategory,
|
||||
HacsDisabledReason,
|
||||
HacsGitHubRepo,
|
||||
HacsStage,
|
||||
LovelaceMode,
|
||||
)
|
||||
from .exceptions import (
|
||||
AddonRepositoryException,
|
||||
HacsException,
|
||||
HacsExpectedException,
|
||||
HacsRepositoryArchivedException,
|
||||
HacsRepositoryExistException,
|
||||
HomeAssistantCoreRepositoryException,
|
||||
)
|
||||
from .repositories import RERPOSITORY_CLASSES
|
||||
from .utils.decode import decode_content
|
||||
from .utils.logger import get_hacs_logger
|
||||
from .utils.queue_manager import QueueManager
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .repositories.base import HacsRepository
|
||||
from .tasks.manager import HacsTaskManager
|
||||
from .utils.data import HacsData
|
||||
from .validate.manager import ValidationManager
|
||||
|
||||
|
||||
@dataclass
|
||||
class RemovedRepository:
|
||||
"""Removed repository."""
|
||||
|
||||
repository: str | None = None
|
||||
reason: str | None = None
|
||||
link: str | None = None
|
||||
removal_type: str = None # archived, not_compliant, critical, dev, broken
|
||||
acknowledged: bool = False
|
||||
|
||||
def update_data(self, data: dict):
|
||||
"""Update data of the repository."""
|
||||
for key in data:
|
||||
if data[key] is None:
|
||||
continue
|
||||
if key in (
|
||||
"reason",
|
||||
"link",
|
||||
"removal_type",
|
||||
"acknowledged",
|
||||
):
|
||||
self.__setattr__(key, data[key])
|
||||
|
||||
def to_json(self):
|
||||
"""Return a JSON representation of the data."""
|
||||
return {
|
||||
"repository": self.repository,
|
||||
"reason": self.reason,
|
||||
"link": self.link,
|
||||
"removal_type": self.removal_type,
|
||||
"acknowledged": self.acknowledged,
|
||||
}
|
||||
|
||||
|
||||
@dataclass
|
||||
class HacsConfiguration:
|
||||
"""HacsConfiguration class."""
|
||||
|
||||
appdaemon_path: str = "appdaemon/apps/"
|
||||
appdaemon: bool = False
|
||||
config: dict[str, Any] = field(default_factory=dict)
|
||||
config_entry: ConfigEntry | None = None
|
||||
config_type: ConfigurationType | None = None
|
||||
country: str = "ALL"
|
||||
debug: bool = False
|
||||
dev: bool = False
|
||||
experimental: bool = False
|
||||
frontend_compact: bool = False
|
||||
frontend_mode: str = "Grid"
|
||||
frontend_repo_url: str = ""
|
||||
frontend_repo: str = ""
|
||||
netdaemon_path: str = "netdaemon/apps/"
|
||||
netdaemon: bool = False
|
||||
onboarding_done: bool = False
|
||||
plugin_path: str = "www/community/"
|
||||
python_script_path: str = "python_scripts/"
|
||||
python_script: bool = False
|
||||
release_limit: int = 5
|
||||
sidepanel_icon: str = "hacs:hacs"
|
||||
sidepanel_title: str = "HACS"
|
||||
theme_path: str = "themes/"
|
||||
theme: bool = False
|
||||
token: str = None
|
||||
|
||||
def to_json(self) -> str:
|
||||
"""Return a json string."""
|
||||
return asdict(self)
|
||||
|
||||
def update_from_dict(self, data: dict) -> None:
|
||||
"""Set attributes from dicts."""
|
||||
if not isinstance(data, dict):
|
||||
raise HacsException("Configuration is not valid.")
|
||||
|
||||
for key in data:
|
||||
self.__setattr__(key, data[key])
|
||||
|
||||
|
||||
@dataclass
|
||||
class HacsCore:
|
||||
"""HACS Core info."""
|
||||
|
||||
config_path: pathlib.Path | None = None
|
||||
ha_version: AwesomeVersion | None = None
|
||||
lovelace_mode = LovelaceMode("yaml")
|
||||
|
||||
|
||||
@dataclass
|
||||
class HacsCommon:
|
||||
"""Common for HACS."""
|
||||
|
||||
categories: set[str] = field(default_factory=set)
|
||||
renamed_repositories: dict[str, str] = field(default_factory=dict)
|
||||
archived_repositories: list[str] = field(default_factory=list)
|
||||
ignored_repositories: list[str] = field(default_factory=list)
|
||||
skip: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
class HacsStatus:
|
||||
"""HacsStatus."""
|
||||
|
||||
startup: bool = True
|
||||
new: bool = False
|
||||
reloading_data: bool = False
|
||||
upgrading_all: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class HacsSystem:
|
||||
"""HACS System info."""
|
||||
|
||||
disabled_reason: HacsDisabledReason | None = None
|
||||
running: bool = False
|
||||
stage = HacsStage.SETUP
|
||||
action: bool = False
|
||||
|
||||
@property
|
||||
def disabled(self) -> bool:
|
||||
"""Return if HACS is disabled."""
|
||||
return self.disabled_reason is not None
|
||||
|
||||
|
||||
@dataclass
|
||||
class HacsRepositories:
|
||||
"""HACS Repositories."""
|
||||
|
||||
_default_repositories: set[str] = field(default_factory=set)
|
||||
_repositories: list[HacsRepository] = field(default_factory=list)
|
||||
_repositories_by_full_name: dict[str, str] = field(default_factory=dict)
|
||||
_repositories_by_id: dict[str, str] = field(default_factory=dict)
|
||||
_removed_repositories: list[RemovedRepository] = field(default_factory=list)
|
||||
|
||||
@property
|
||||
def list_all(self) -> list[HacsRepository]:
|
||||
"""Return a list of repositories."""
|
||||
return self._repositories
|
||||
|
||||
@property
|
||||
def list_removed(self) -> list[RemovedRepository]:
|
||||
"""Return a list of removed repositories."""
|
||||
return self._removed_repositories
|
||||
|
||||
@property
|
||||
def list_downloaded(self) -> list[HacsRepository]:
|
||||
"""Return a list of downloaded repositories."""
|
||||
return [repo for repo in self._repositories if repo.data.installed]
|
||||
|
||||
def register(self, repository: HacsRepository, default: bool = False) -> None:
|
||||
"""Register a repository."""
|
||||
repo_id = str(repository.data.id)
|
||||
|
||||
if repo_id == "0":
|
||||
return
|
||||
|
||||
if self.is_registered(repository_id=repo_id):
|
||||
return
|
||||
|
||||
if repository not in self._repositories:
|
||||
self._repositories.append(repository)
|
||||
|
||||
self._repositories_by_id[repo_id] = repository
|
||||
self._repositories_by_full_name[repository.data.full_name_lower] = repository
|
||||
|
||||
if default:
|
||||
self.mark_default(repository)
|
||||
|
||||
def unregister(self, repository: HacsRepository) -> None:
|
||||
"""Unregister a repository."""
|
||||
repo_id = str(repository.data.id)
|
||||
|
||||
if repo_id == "0":
|
||||
return
|
||||
|
||||
if not self.is_registered(repository_id=repo_id):
|
||||
return
|
||||
|
||||
if self.is_default(repo_id):
|
||||
self._default_repositories.remove(repo_id)
|
||||
|
||||
if repository in self._repositories:
|
||||
self._repositories.remove(repository)
|
||||
|
||||
self._repositories_by_id.pop(repo_id, None)
|
||||
self._repositories_by_full_name.pop(repository.data.full_name_lower, None)
|
||||
|
||||
def mark_default(self, repository: HacsRepository) -> None:
|
||||
"""Mark a repository as default."""
|
||||
repo_id = str(repository.data.id)
|
||||
|
||||
if repo_id == "0":
|
||||
return
|
||||
|
||||
if not self.is_registered(repository_id=repo_id):
|
||||
return
|
||||
|
||||
self._default_repositories.add(repo_id)
|
||||
|
||||
def set_repository_id(self, repository, repo_id):
|
||||
"""Update a repository id."""
|
||||
existing_repo_id = str(repository.data.id)
|
||||
if existing_repo_id == repo_id:
|
||||
return
|
||||
if existing_repo_id != "0":
|
||||
raise ValueError(
|
||||
f"The repo id for {repository.data.full_name_lower} "
|
||||
f"is already set to {existing_repo_id}"
|
||||
)
|
||||
repository.data.id = repo_id
|
||||
self.register(repository)
|
||||
|
||||
def is_default(self, repository_id: str | None = None) -> bool:
|
||||
"""Check if a repository is default."""
|
||||
if not repository_id:
|
||||
return False
|
||||
return repository_id in self._default_repositories
|
||||
|
||||
def is_registered(
|
||||
self,
|
||||
repository_id: str | None = None,
|
||||
repository_full_name: str | None = None,
|
||||
) -> bool:
|
||||
"""Check if a repository is registered."""
|
||||
if repository_id is not None:
|
||||
return repository_id in self._repositories_by_id
|
||||
if repository_full_name is not None:
|
||||
return repository_full_name in self._repositories_by_full_name
|
||||
return False
|
||||
|
||||
def is_downloaded(
|
||||
self,
|
||||
repository_id: str | None = None,
|
||||
repository_full_name: str | None = None,
|
||||
) -> bool:
|
||||
"""Check if a repository is registered."""
|
||||
if repository_id is not None:
|
||||
repo = self.get_by_id(repository_id)
|
||||
if repository_full_name is not None:
|
||||
repo = self.get_by_full_name(repository_full_name)
|
||||
if repo is None:
|
||||
return False
|
||||
return repo.data.installed
|
||||
|
||||
def get_by_id(self, repository_id: str | None) -> HacsRepository | None:
|
||||
"""Get repository by id."""
|
||||
if not repository_id:
|
||||
return None
|
||||
return self._repositories_by_id.get(str(repository_id))
|
||||
|
||||
def get_by_full_name(self, repository_full_name: str | None) -> HacsRepository | None:
|
||||
"""Get repository by full name."""
|
||||
if not repository_full_name:
|
||||
return None
|
||||
return self._repositories_by_full_name.get(repository_full_name.lower())
|
||||
|
||||
def is_removed(self, repository_full_name: str) -> bool:
|
||||
"""Check if a repository is removed."""
|
||||
return repository_full_name in (
|
||||
repository.repository for repository in self._removed_repositories
|
||||
)
|
||||
|
||||
def removed_repository(self, repository_full_name: str) -> RemovedRepository:
|
||||
"""Get repository by full name."""
|
||||
if self.is_removed(repository_full_name):
|
||||
if removed := [
|
||||
repository
|
||||
for repository in self._removed_repositories
|
||||
if repository.repository == repository_full_name
|
||||
]:
|
||||
return removed[0]
|
||||
|
||||
removed = RemovedRepository(repository=repository_full_name)
|
||||
self._removed_repositories.append(removed)
|
||||
return removed
|
||||
|
||||
|
||||
class HacsBase:
|
||||
"""Base HACS class."""
|
||||
|
||||
common = HacsCommon()
|
||||
configuration = HacsConfiguration()
|
||||
core = HacsCore()
|
||||
data: HacsData | None = None
|
||||
frontend_version: str | None = None
|
||||
github: GitHub | None = None
|
||||
githubapi: GitHubAPI | None = None
|
||||
hass: HomeAssistant | None = None
|
||||
integration: Integration | None = None
|
||||
log: logging.Logger = get_hacs_logger()
|
||||
queue: QueueManager | None = None
|
||||
recuring_tasks = []
|
||||
repositories: HacsRepositories = HacsRepositories()
|
||||
repository: AIOGitHubAPIRepository | None = None
|
||||
session: ClientSession | None = None
|
||||
stage: HacsStage | None = None
|
||||
status = HacsStatus()
|
||||
system = HacsSystem()
|
||||
tasks: HacsTaskManager | None = None
|
||||
validation: ValidationManager | None = None
|
||||
version: str | None = None
|
||||
|
||||
@property
|
||||
def integration_dir(self) -> pathlib.Path:
|
||||
"""Return the HACS integration dir."""
|
||||
return self.integration.file_path
|
||||
|
||||
async def async_set_stage(self, stage: HacsStage | None) -> None:
|
||||
"""Set HACS stage."""
|
||||
if stage and self.stage == stage:
|
||||
return
|
||||
|
||||
self.stage = stage
|
||||
if stage is not None:
|
||||
self.log.info("Stage changed: %s", self.stage)
|
||||
self.hass.bus.async_fire("hacs/stage", {"stage": self.stage})
|
||||
await self.tasks.async_execute_runtume_tasks()
|
||||
|
||||
def disable_hacs(self, reason: HacsDisabledReason) -> None:
|
||||
"""Disable HACS."""
|
||||
if self.system.disabled_reason == reason:
|
||||
return
|
||||
|
||||
self.system.disabled_reason = reason
|
||||
if reason != HacsDisabledReason.REMOVED:
|
||||
self.log.error("HACS is disabled - %s", reason)
|
||||
|
||||
def enable_hacs(self) -> None:
|
||||
"""Enable HACS."""
|
||||
if self.system.disabled_reason is not None:
|
||||
self.system.disabled_reason = None
|
||||
self.log.info("HACS is enabled")
|
||||
|
||||
def enable_hacs_category(self, category: HacsCategory) -> None:
|
||||
"""Enable HACS category."""
|
||||
if category not in self.common.categories:
|
||||
self.log.info("Enable category: %s", category)
|
||||
self.common.categories.add(category)
|
||||
|
||||
def disable_hacs_category(self, category: HacsCategory) -> None:
|
||||
"""Disable HACS category."""
|
||||
if category in self.common.categories:
|
||||
self.log.info("Disabling category: %s", category)
|
||||
self.common.categories.pop(category)
|
||||
|
||||
async def async_save_file(self, file_path: str, content: Any) -> bool:
|
||||
"""Save a file."""
|
||||
|
||||
def _write_file():
|
||||
with open(
|
||||
file_path,
|
||||
mode="w" if isinstance(content, str) else "wb",
|
||||
encoding="utf-8" if isinstance(content, str) else None,
|
||||
errors="ignore" if isinstance(content, str) else None,
|
||||
) as file_handler:
|
||||
file_handler.write(content)
|
||||
|
||||
# Create gz for .js files
|
||||
if os.path.isfile(file_path):
|
||||
if file_path.endswith(".js"):
|
||||
with open(file_path, "rb") as f_in:
|
||||
with gzip.open(file_path + ".gz", "wb") as f_out:
|
||||
shutil.copyfileobj(f_in, f_out)
|
||||
|
||||
# LEGACY! Remove with 2.0
|
||||
if "themes" in file_path and file_path.endswith(".yaml"):
|
||||
filename = file_path.split("/")[-1]
|
||||
base = file_path.split("/themes/")[0]
|
||||
combined = f"{base}/themes/{filename}"
|
||||
if os.path.exists(combined):
|
||||
self.log.info("Removing old theme file %s", combined)
|
||||
os.remove(combined)
|
||||
|
||||
try:
|
||||
await self.hass.async_add_executor_job(_write_file)
|
||||
except BaseException as error: # lgtm [py/catch-base-exception] pylint: disable=broad-except
|
||||
self.log.error("Could not write data to %s - %s", file_path, error)
|
||||
return False
|
||||
|
||||
return os.path.exists(file_path)
|
||||
|
||||
async def async_can_update(self) -> int:
|
||||
"""Helper to calculate the number of repositories we can fetch data for."""
|
||||
try:
|
||||
response = await self.async_github_api_method(self.githubapi.rate_limit)
|
||||
if ((limit := response.data.resources.core.remaining or 0) - 1000) >= 10:
|
||||
return math.floor((limit - 1000) / 10)
|
||||
reset = dt.as_local(dt.utc_from_timestamp(response.data.resources.core.reset))
|
||||
self.log.info(
|
||||
"GitHub API ratelimited - %s remaining (%s)",
|
||||
response.data.resources.core.remaining,
|
||||
f"{reset.hour}:{reset.minute}:{reset.second}",
|
||||
)
|
||||
self.disable_hacs(HacsDisabledReason.RATE_LIMIT)
|
||||
except BaseException as exception: # lgtm [py/catch-base-exception] pylint: disable=broad-except
|
||||
self.log.exception(exception)
|
||||
|
||||
return 0
|
||||
|
||||
async def async_github_get_hacs_default_file(self, filename: str) -> list:
|
||||
"""Get the content of a default file."""
|
||||
response = await self.async_github_api_method(
|
||||
method=self.githubapi.repos.contents.get,
|
||||
repository=HacsGitHubRepo.DEFAULT,
|
||||
path=filename,
|
||||
)
|
||||
if response is None:
|
||||
return []
|
||||
|
||||
return json.loads(decode_content(response.data.content))
|
||||
|
||||
async def async_github_api_method(
|
||||
self,
|
||||
method: Callable[[], Awaitable[TV]],
|
||||
*args,
|
||||
raise_exception: bool = True,
|
||||
**kwargs,
|
||||
) -> TV | None:
|
||||
"""Call a GitHub API method"""
|
||||
_exception = None
|
||||
|
||||
try:
|
||||
return await method(*args, **kwargs)
|
||||
except GitHubAuthenticationException as exception:
|
||||
self.disable_hacs(HacsDisabledReason.INVALID_TOKEN)
|
||||
_exception = exception
|
||||
except GitHubRatelimitException as exception:
|
||||
self.disable_hacs(HacsDisabledReason.RATE_LIMIT)
|
||||
_exception = exception
|
||||
except GitHubNotModifiedException as exception:
|
||||
raise exception
|
||||
except GitHubException as exception:
|
||||
_exception = exception
|
||||
except BaseException as exception: # lgtm [py/catch-base-exception] pylint: disable=broad-except
|
||||
self.log.exception(exception)
|
||||
_exception = exception
|
||||
|
||||
if raise_exception and _exception is not None:
|
||||
raise HacsException(_exception)
|
||||
return None
|
||||
|
||||
async def async_register_repository(
|
||||
self,
|
||||
repository_full_name: str,
|
||||
category: HacsCategory,
|
||||
*,
|
||||
check: bool = True,
|
||||
ref: str | None = None,
|
||||
repository_id: str | None = None,
|
||||
default: bool = False,
|
||||
) -> None:
|
||||
"""Register a repository."""
|
||||
if repository_full_name in self.common.skip:
|
||||
if repository_full_name != HacsGitHubRepo.INTEGRATION:
|
||||
raise HacsExpectedException(f"Skipping {repository_full_name}")
|
||||
|
||||
if repository_full_name == "home-assistant/core":
|
||||
raise HomeAssistantCoreRepositoryException()
|
||||
|
||||
if repository_full_name == "home-assistant/addons" or repository_full_name.startswith(
|
||||
"hassio-addons/"
|
||||
):
|
||||
raise AddonRepositoryException()
|
||||
|
||||
if category not in RERPOSITORY_CLASSES:
|
||||
raise HacsException(f"{category} is not a valid repository category.")
|
||||
|
||||
if (renamed := self.common.renamed_repositories.get(repository_full_name)) is not None:
|
||||
repository_full_name = renamed
|
||||
|
||||
repository: HacsRepository = RERPOSITORY_CLASSES[category](self, repository_full_name)
|
||||
if check:
|
||||
try:
|
||||
await repository.async_registration(ref)
|
||||
if self.status.new:
|
||||
repository.data.new = False
|
||||
if repository.validate.errors:
|
||||
self.common.skip.append(repository.data.full_name)
|
||||
if not self.status.startup:
|
||||
self.log.error("Validation for %s failed.", repository_full_name)
|
||||
if self.system.action:
|
||||
raise HacsException(
|
||||
f"::error:: Validation for {repository_full_name} failed."
|
||||
)
|
||||
return repository.validate.errors
|
||||
if self.system.action:
|
||||
repository.logger.info("%s Validation completed", repository.string)
|
||||
else:
|
||||
repository.logger.info("%s Registration completed", repository.string)
|
||||
except (HacsRepositoryExistException, HacsRepositoryArchivedException):
|
||||
return
|
||||
except AIOGitHubAPIException as exception:
|
||||
self.common.skip.append(repository.data.full_name)
|
||||
raise HacsException(
|
||||
f"Validation for {repository_full_name} failed with {exception}."
|
||||
) from exception
|
||||
|
||||
if repository_id is not None:
|
||||
repository.data.id = repository_id
|
||||
|
||||
if str(repository.data.id) != "0" and (
|
||||
exists := self.repositories.get_by_id(repository.data.id)
|
||||
):
|
||||
self.repositories.unregister(exists)
|
||||
|
||||
else:
|
||||
if self.hass is not None and ((check and repository.data.new) or self.status.new):
|
||||
self.hass.bus.async_fire(
|
||||
"hacs/repository",
|
||||
{
|
||||
"action": "registration",
|
||||
"repository": repository.data.full_name,
|
||||
"repository_id": repository.data.id,
|
||||
},
|
||||
)
|
||||
self.repositories.register(repository, default)
|
||||
|
||||
async def startup_tasks(self, _event=None) -> None:
|
||||
"""Tasks that are started after setup."""
|
||||
await self.async_set_stage(HacsStage.STARTUP)
|
||||
self.status.startup = False
|
||||
|
||||
self.hass.bus.async_fire("hacs/status", {})
|
||||
|
||||
await self.async_set_stage(HacsStage.RUNNING)
|
||||
|
||||
self.hass.bus.async_fire("hacs/reload", {"force": True})
|
||||
|
||||
if queue_task := self.tasks.get("prosess_queue"):
|
||||
await queue_task.execute_task()
|
||||
|
||||
self.hass.bus.async_fire("hacs/status", {})
|
||||
|
||||
async def async_download_file(self, url: str, *, headers: dict | None = None) -> bytes | None:
|
||||
"""Download files, and return the content."""
|
||||
if url is None:
|
||||
return None
|
||||
|
||||
if "tags/" in url:
|
||||
url = url.replace("tags/", "")
|
||||
|
||||
self.log.debug("Downloading %s", url)
|
||||
timeouts = 0
|
||||
|
||||
while timeouts < 5:
|
||||
try:
|
||||
request = await self.session.get(
|
||||
url=url,
|
||||
timeout=ClientTimeout(total=60),
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
# Make sure that we got a valid result
|
||||
if request.status == 200:
|
||||
return await request.read()
|
||||
|
||||
raise HacsException(
|
||||
f"Got status code {request.status} when trying to download {url}"
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
self.log.warning(
|
||||
"A timeout of 60! seconds was encountered while downloading %s, "
|
||||
"using over 60 seconds to download a single file is not normal. "
|
||||
"This is not a problem with HACS but how your host communicates with GitHub. "
|
||||
"Retrying up to 5 times to mask/hide your host/network problems to "
|
||||
"stop the flow of issues opened about it. "
|
||||
"Tries left %s",
|
||||
url,
|
||||
(4 - timeouts),
|
||||
)
|
||||
timeouts += 1
|
||||
await asyncio.sleep(1)
|
||||
continue
|
||||
|
||||
except BaseException as exception: # lgtm [py/catch-base-exception] pylint: disable=broad-except
|
||||
self.log.exception("Download failed - %s", exception)
|
||||
|
||||
return None
|
||||
|
||||
async def async_recreate_entities(self) -> None:
|
||||
"""Recreate entities."""
|
||||
if (
|
||||
self.configuration == ConfigurationType.YAML
|
||||
or not self.core.ha_version >= "2022.4.0.dev0"
|
||||
or not self.configuration.experimental
|
||||
):
|
||||
return
|
||||
|
||||
platforms = ["sensor", "update"]
|
||||
|
||||
await self.hass.config_entries.async_unload_platforms(
|
||||
entry=self.configuration.config_entry,
|
||||
platforms=platforms,
|
||||
)
|
||||
|
||||
self.hass.config_entries.async_setup_platforms(self.configuration.config_entry, platforms)
|
||||
159
custom_components/hacs/config_flow.py
Normal file
159
custom_components/hacs/config_flow.py
Normal file
@@ -0,0 +1,159 @@
|
||||
"""Adds config flow for HACS."""
|
||||
from aiogithubapi import GitHubDeviceAPI, GitHubException
|
||||
from aiogithubapi.common.const import OAUTH_USER_LOGIN
|
||||
from awesomeversion import AwesomeVersion
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import __version__ as HAVERSION
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers import aiohttp_client
|
||||
from homeassistant.helpers.event import async_call_later
|
||||
from homeassistant.loader import async_get_integration
|
||||
import voluptuous as vol
|
||||
|
||||
from .base import HacsBase
|
||||
from .const import CLIENT_ID, DOMAIN, MINIMUM_HA_VERSION
|
||||
from .enums import ConfigurationType
|
||||
from .utils.configuration_schema import RELEASE_LIMIT, hacs_config_option_schema
|
||||
from .utils.logger import get_hacs_logger
|
||||
|
||||
|
||||
class HacsFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Config flow for HACS."""
|
||||
|
||||
VERSION = 1
|
||||
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize."""
|
||||
self._errors = {}
|
||||
self.device = None
|
||||
self.activation = None
|
||||
self.log = get_hacs_logger()
|
||||
self._progress_task = None
|
||||
self._login_device = None
|
||||
|
||||
async def async_step_user(self, user_input):
|
||||
"""Handle a flow initialized by the user."""
|
||||
self._errors = {}
|
||||
if self._async_current_entries():
|
||||
return self.async_abort(reason="single_instance_allowed")
|
||||
if self.hass.data.get(DOMAIN):
|
||||
return self.async_abort(reason="single_instance_allowed")
|
||||
|
||||
if user_input:
|
||||
if [x for x in user_input if not user_input[x]]:
|
||||
self._errors["base"] = "acc"
|
||||
return await self._show_config_form(user_input)
|
||||
|
||||
return await self.async_step_device(user_input)
|
||||
|
||||
## Initial form
|
||||
return await self._show_config_form(user_input)
|
||||
|
||||
async def async_step_device(self, _user_input):
|
||||
"""Handle device steps"""
|
||||
|
||||
async def _wait_for_activation(_=None):
|
||||
if self._login_device is None or self._login_device.expires_in is None:
|
||||
async_call_later(self.hass, 1, _wait_for_activation)
|
||||
return
|
||||
|
||||
response = await self.device.activation(device_code=self._login_device.device_code)
|
||||
self.activation = response.data
|
||||
self.hass.async_create_task(
|
||||
self.hass.config_entries.flow.async_configure(flow_id=self.flow_id)
|
||||
)
|
||||
|
||||
if not self.activation:
|
||||
integration = await async_get_integration(self.hass, DOMAIN)
|
||||
if not self.device:
|
||||
self.device = GitHubDeviceAPI(
|
||||
client_id=CLIENT_ID,
|
||||
session=aiohttp_client.async_get_clientsession(self.hass),
|
||||
**{"client_name": f"HACS/{integration.version}"},
|
||||
)
|
||||
async_call_later(self.hass, 1, _wait_for_activation)
|
||||
try:
|
||||
response = await self.device.register()
|
||||
self._login_device = response.data
|
||||
return self.async_show_progress(
|
||||
step_id="device",
|
||||
progress_action="wait_for_device",
|
||||
description_placeholders={
|
||||
"url": OAUTH_USER_LOGIN,
|
||||
"code": self._login_device.user_code,
|
||||
},
|
||||
)
|
||||
except GitHubException as exception:
|
||||
self.log.error(exception)
|
||||
return self.async_abort(reason="github")
|
||||
|
||||
return self.async_show_progress_done(next_step_id="device_done")
|
||||
|
||||
async def _show_config_form(self, user_input):
|
||||
"""Show the configuration form to edit location data."""
|
||||
|
||||
if not user_input:
|
||||
user_input = {}
|
||||
|
||||
if AwesomeVersion(HAVERSION) < MINIMUM_HA_VERSION:
|
||||
return self.async_abort(
|
||||
reason="min_ha_version",
|
||||
description_placeholders={"version": MINIMUM_HA_VERSION},
|
||||
)
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required("acc_logs", default=user_input.get("acc_logs", False)): bool,
|
||||
vol.Required("acc_addons", default=user_input.get("acc_addons", False)): bool,
|
||||
vol.Required(
|
||||
"acc_untested", default=user_input.get("acc_untested", False)
|
||||
): bool,
|
||||
vol.Required("acc_disable", default=user_input.get("acc_disable", False)): bool,
|
||||
}
|
||||
),
|
||||
errors=self._errors,
|
||||
)
|
||||
|
||||
async def async_step_device_done(self, _user_input):
|
||||
"""Handle device steps"""
|
||||
return self.async_create_entry(title="", data={"token": self.activation.access_token})
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(config_entry):
|
||||
return HacsOptionsFlowHandler(config_entry)
|
||||
|
||||
|
||||
class HacsOptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""HACS config flow options handler."""
|
||||
|
||||
def __init__(self, config_entry):
|
||||
"""Initialize HACS options flow."""
|
||||
self.config_entry = config_entry
|
||||
|
||||
async def async_step_init(self, _user_input=None):
|
||||
"""Manage the options."""
|
||||
return await self.async_step_user()
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle a flow initialized by the user."""
|
||||
hacs: HacsBase = self.hass.data.get(DOMAIN)
|
||||
if user_input is not None:
|
||||
limit = int(user_input.get(RELEASE_LIMIT, 5))
|
||||
if limit <= 0 or limit > 100:
|
||||
return self.async_abort(reason="release_limit_value")
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
||||
if hacs is None or hacs.configuration is None:
|
||||
return self.async_abort(reason="not_setup")
|
||||
|
||||
if hacs.configuration.config_type == ConfigurationType.YAML:
|
||||
schema = {vol.Optional("not_in_use", default=""): str}
|
||||
else:
|
||||
schema = hacs_config_option_schema(self.config_entry.options)
|
||||
del schema["frontend_repo"]
|
||||
del schema["frontend_repo_url"]
|
||||
|
||||
return self.async_show_form(step_id="user", data_schema=vol.Schema(schema))
|
||||
289
custom_components/hacs/const.py
Normal file
289
custom_components/hacs/const.py
Normal file
@@ -0,0 +1,289 @@
|
||||
"""Constants for HACS"""
|
||||
from typing import TypeVar
|
||||
|
||||
from aiogithubapi.common.const import ACCEPT_HEADERS
|
||||
|
||||
NAME_SHORT = "HACS"
|
||||
DOMAIN = "hacs"
|
||||
CLIENT_ID = "395a8e669c5de9f7c6e8"
|
||||
MINIMUM_HA_VERSION = "2021.9.0"
|
||||
|
||||
TV = TypeVar("TV")
|
||||
|
||||
PACKAGE_NAME = "custom_components.hacs"
|
||||
|
||||
DEFAULT_CONCURRENT_TASKS = 15
|
||||
DEFAULT_CONCURRENT_BACKOFF_TIME = 1
|
||||
|
||||
HACS_ACTION_GITHUB_API_HEADERS = {
|
||||
"User-Agent": "HACS/action",
|
||||
"Accept": ACCEPT_HEADERS["preview"],
|
||||
}
|
||||
|
||||
VERSION_STORAGE = "6"
|
||||
STORENAME = "hacs"
|
||||
|
||||
HACS_SYSTEM_ID = "0717a0cd-745c-48fd-9b16-c8534c9704f9-bc944b0f-fd42-4a58-a072-ade38d1444cd"
|
||||
|
||||
STARTUP = """
|
||||
-------------------------------------------------------------------
|
||||
HACS (Home Assistant Community Store)
|
||||
|
||||
Version: %s
|
||||
This is a custom integration
|
||||
If you have any issues with this you need to open an issue here:
|
||||
https://github.com/hacs/integration/issues
|
||||
-------------------------------------------------------------------
|
||||
"""
|
||||
|
||||
LOCALE = [
|
||||
"ALL",
|
||||
"AF",
|
||||
"AL",
|
||||
"DZ",
|
||||
"AS",
|
||||
"AD",
|
||||
"AO",
|
||||
"AI",
|
||||
"AQ",
|
||||
"AG",
|
||||
"AR",
|
||||
"AM",
|
||||
"AW",
|
||||
"AU",
|
||||
"AT",
|
||||
"AZ",
|
||||
"BS",
|
||||
"BH",
|
||||
"BD",
|
||||
"BB",
|
||||
"BY",
|
||||
"BE",
|
||||
"BZ",
|
||||
"BJ",
|
||||
"BM",
|
||||
"BT",
|
||||
"BO",
|
||||
"BQ",
|
||||
"BA",
|
||||
"BW",
|
||||
"BV",
|
||||
"BR",
|
||||
"IO",
|
||||
"BN",
|
||||
"BG",
|
||||
"BF",
|
||||
"BI",
|
||||
"KH",
|
||||
"CM",
|
||||
"CA",
|
||||
"CV",
|
||||
"KY",
|
||||
"CF",
|
||||
"TD",
|
||||
"CL",
|
||||
"CN",
|
||||
"CX",
|
||||
"CC",
|
||||
"CO",
|
||||
"KM",
|
||||
"CG",
|
||||
"CD",
|
||||
"CK",
|
||||
"CR",
|
||||
"HR",
|
||||
"CU",
|
||||
"CW",
|
||||
"CY",
|
||||
"CZ",
|
||||
"CI",
|
||||
"DK",
|
||||
"DJ",
|
||||
"DM",
|
||||
"DO",
|
||||
"EC",
|
||||
"EG",
|
||||
"SV",
|
||||
"GQ",
|
||||
"ER",
|
||||
"EE",
|
||||
"ET",
|
||||
"FK",
|
||||
"FO",
|
||||
"FJ",
|
||||
"FI",
|
||||
"FR",
|
||||
"GF",
|
||||
"PF",
|
||||
"TF",
|
||||
"GA",
|
||||
"GM",
|
||||
"GE",
|
||||
"DE",
|
||||
"GH",
|
||||
"GI",
|
||||
"GR",
|
||||
"GL",
|
||||
"GD",
|
||||
"GP",
|
||||
"GU",
|
||||
"GT",
|
||||
"GG",
|
||||
"GN",
|
||||
"GW",
|
||||
"GY",
|
||||
"HT",
|
||||
"HM",
|
||||
"VA",
|
||||
"HN",
|
||||
"HK",
|
||||
"HU",
|
||||
"IS",
|
||||
"IN",
|
||||
"ID",
|
||||
"IR",
|
||||
"IQ",
|
||||
"IE",
|
||||
"IM",
|
||||
"IL",
|
||||
"IT",
|
||||
"JM",
|
||||
"JP",
|
||||
"JE",
|
||||
"JO",
|
||||
"KZ",
|
||||
"KE",
|
||||
"KI",
|
||||
"KP",
|
||||
"KR",
|
||||
"KW",
|
||||
"KG",
|
||||
"LA",
|
||||
"LV",
|
||||
"LB",
|
||||
"LS",
|
||||
"LR",
|
||||
"LY",
|
||||
"LI",
|
||||
"LT",
|
||||
"LU",
|
||||
"MO",
|
||||
"MK",
|
||||
"MG",
|
||||
"MW",
|
||||
"MY",
|
||||
"MV",
|
||||
"ML",
|
||||
"MT",
|
||||
"MH",
|
||||
"MQ",
|
||||
"MR",
|
||||
"MU",
|
||||
"YT",
|
||||
"MX",
|
||||
"FM",
|
||||
"MD",
|
||||
"MC",
|
||||
"MN",
|
||||
"ME",
|
||||
"MS",
|
||||
"MA",
|
||||
"MZ",
|
||||
"MM",
|
||||
"NA",
|
||||
"NR",
|
||||
"NP",
|
||||
"NL",
|
||||
"NC",
|
||||
"NZ",
|
||||
"NI",
|
||||
"NE",
|
||||
"NG",
|
||||
"NU",
|
||||
"NF",
|
||||
"MP",
|
||||
"NO",
|
||||
"OM",
|
||||
"PK",
|
||||
"PW",
|
||||
"PS",
|
||||
"PA",
|
||||
"PG",
|
||||
"PY",
|
||||
"PE",
|
||||
"PH",
|
||||
"PN",
|
||||
"PL",
|
||||
"PT",
|
||||
"PR",
|
||||
"QA",
|
||||
"RO",
|
||||
"RU",
|
||||
"RW",
|
||||
"RE",
|
||||
"BL",
|
||||
"SH",
|
||||
"KN",
|
||||
"LC",
|
||||
"MF",
|
||||
"PM",
|
||||
"VC",
|
||||
"WS",
|
||||
"SM",
|
||||
"ST",
|
||||
"SA",
|
||||
"SN",
|
||||
"RS",
|
||||
"SC",
|
||||
"SL",
|
||||
"SG",
|
||||
"SX",
|
||||
"SK",
|
||||
"SI",
|
||||
"SB",
|
||||
"SO",
|
||||
"ZA",
|
||||
"GS",
|
||||
"SS",
|
||||
"ES",
|
||||
"LK",
|
||||
"SD",
|
||||
"SR",
|
||||
"SJ",
|
||||
"SZ",
|
||||
"SE",
|
||||
"CH",
|
||||
"SY",
|
||||
"TW",
|
||||
"TJ",
|
||||
"TZ",
|
||||
"TH",
|
||||
"TL",
|
||||
"TG",
|
||||
"TK",
|
||||
"TO",
|
||||
"TT",
|
||||
"TN",
|
||||
"TR",
|
||||
"TM",
|
||||
"TC",
|
||||
"TV",
|
||||
"UG",
|
||||
"UA",
|
||||
"AE",
|
||||
"GB",
|
||||
"US",
|
||||
"UM",
|
||||
"UY",
|
||||
"UZ",
|
||||
"VU",
|
||||
"VE",
|
||||
"VN",
|
||||
"VG",
|
||||
"VI",
|
||||
"WF",
|
||||
"EH",
|
||||
"YE",
|
||||
"ZM",
|
||||
"ZW",
|
||||
]
|
||||
82
custom_components/hacs/diagnostics.py
Normal file
82
custom_components/hacs/diagnostics.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""Diagnostics support for HACS."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from aiogithubapi import GitHubException
|
||||
from homeassistant.components.diagnostics import async_redact_data
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .base import HacsBase
|
||||
from .const import DOMAIN
|
||||
from .utils.configuration_schema import TOKEN
|
||||
|
||||
|
||||
async def async_get_config_entry_diagnostics(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
) -> dict[str, Any]:
|
||||
"""Return diagnostics for a config entry."""
|
||||
hacs: HacsBase = hass.data[DOMAIN]
|
||||
|
||||
data = {
|
||||
"entry": entry.as_dict(),
|
||||
"hacs": {
|
||||
"stage": hacs.stage,
|
||||
"version": hacs.version,
|
||||
"disabled_reason": hacs.system.disabled_reason,
|
||||
"new": hacs.status.new,
|
||||
"startup": hacs.status.startup,
|
||||
"categories": hacs.common.categories,
|
||||
"renamed_repositories": hacs.common.renamed_repositories,
|
||||
"archived_repositories": hacs.common.archived_repositories,
|
||||
"ignored_repositories": hacs.common.ignored_repositories,
|
||||
"lovelace_mode": hacs.core.lovelace_mode,
|
||||
"configuration": {},
|
||||
},
|
||||
"custom_repositories": [
|
||||
repo.data.full_name
|
||||
for repo in hacs.repositories.list_all
|
||||
if not hacs.repositories.is_default(str(repo.data.id))
|
||||
],
|
||||
"repositories": [],
|
||||
}
|
||||
|
||||
for key in (
|
||||
"appdaemon",
|
||||
"country",
|
||||
"debug",
|
||||
"dev",
|
||||
"experimental",
|
||||
"netdaemon",
|
||||
"python_script",
|
||||
"release_limit",
|
||||
"theme",
|
||||
):
|
||||
data["hacs"]["configuration"][key] = getattr(hacs.configuration, key, None)
|
||||
|
||||
for repository in hacs.repositories.list_downloaded:
|
||||
data["repositories"].append(
|
||||
{
|
||||
"data": repository.data.to_json(),
|
||||
"integration_manifest": repository.integration_manifest,
|
||||
"repository_manifest": repository.repository_manifest.to_dict(),
|
||||
"ref": repository.ref,
|
||||
"paths": {
|
||||
"localpath": repository.localpath.replace(hacs.core.config_path, "/config"),
|
||||
"local": repository.content.path.local.replace(
|
||||
hacs.core.config_path, "/config"
|
||||
),
|
||||
"remote": repository.content.path.remote,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
try:
|
||||
rate_limit_response = await hacs.githubapi.rate_limit()
|
||||
data["rate_limit"] = rate_limit_response.data.as_dict
|
||||
except GitHubException as exception:
|
||||
data["rate_limit"] = str(exception)
|
||||
|
||||
return async_redact_data(data, (TOKEN,))
|
||||
126
custom_components/hacs/entity.py
Normal file
126
custom_components/hacs/entity.py
Normal file
@@ -0,0 +1,126 @@
|
||||
"""HACS Base entities."""
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.core import Event, callback
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from custom_components.hacs.enums import HacsGitHubRepo
|
||||
|
||||
from .base import HacsBase
|
||||
from .const import DOMAIN, HACS_SYSTEM_ID, NAME_SHORT
|
||||
from .repositories.base import HacsRepository
|
||||
|
||||
|
||||
def system_info(hacs: HacsBase) -> dict:
|
||||
"""Return system info."""
|
||||
info = {
|
||||
"identifiers": {(DOMAIN, HACS_SYSTEM_ID)},
|
||||
"name": NAME_SHORT,
|
||||
"manufacturer": "hacs.xyz",
|
||||
"model": "",
|
||||
"sw_version": str(hacs.version),
|
||||
"configuration_url": "homeassistant://hacs",
|
||||
}
|
||||
# LEGACY can be removed when min HA version is 2021.12
|
||||
if hacs.core.ha_version >= "2021.12.0b0":
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||
|
||||
info["entry_type"] = DeviceEntryType.SERVICE
|
||||
else:
|
||||
info["entry_type"] = "service"
|
||||
return info
|
||||
|
||||
|
||||
class HacsBaseEntity(Entity):
|
||||
"""Base HACS entity."""
|
||||
|
||||
repository: HacsRepository | None = None
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(self, hacs: HacsBase) -> None:
|
||||
"""Initialize."""
|
||||
self.hacs = hacs
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register for status events."""
|
||||
self.async_on_remove(
|
||||
self.hass.bus.async_listen(
|
||||
event_type="hacs/repository",
|
||||
event_filter=self._filter_events,
|
||||
listener=self._update_and_write_state,
|
||||
)
|
||||
)
|
||||
|
||||
@callback
|
||||
def _update(self) -> None:
|
||||
"""Update the sensor."""
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Manual updates of the sensor."""
|
||||
self._update()
|
||||
|
||||
@callback
|
||||
def _filter_events(self, event: Event) -> bool:
|
||||
"""Filter the events."""
|
||||
if self.repository is None:
|
||||
# System entities
|
||||
return True
|
||||
return event.data.get("repository_id") == self.repository.data.id
|
||||
|
||||
@callback
|
||||
def _update_and_write_state(self, *_) -> None:
|
||||
"""Update the entity and write state."""
|
||||
self._update()
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class HacsSystemEntity(HacsBaseEntity):
|
||||
"""Base system entity."""
|
||||
|
||||
_attr_icon = "hacs:hacs"
|
||||
_attr_unique_id = HACS_SYSTEM_ID
|
||||
|
||||
@property
|
||||
def device_info(self) -> dict[str, any]:
|
||||
"""Return device information about HACS."""
|
||||
return system_info(self.hacs)
|
||||
|
||||
|
||||
class HacsRepositoryEntity(HacsBaseEntity):
|
||||
"""Base repository entity."""
|
||||
|
||||
def __init__(self, hacs: HacsBase, repository: HacsRepository) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(hacs=hacs)
|
||||
self.repository = repository
|
||||
self._attr_unique_id = str(repository.data.id)
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
return self.hacs.repositories.is_downloaded(repository_id=str(self.repository.data.id))
|
||||
|
||||
@property
|
||||
def device_info(self) -> dict[str, any]:
|
||||
"""Return device information about HACS."""
|
||||
if self.repository.data.full_name == HacsGitHubRepo.INTEGRATION:
|
||||
return system_info(self.hacs)
|
||||
|
||||
info = {
|
||||
"identifiers": {(DOMAIN, str(self.repository.data.id))},
|
||||
"name": self.repository.display_name,
|
||||
"model": self.repository.data.category,
|
||||
"manufacturer": ", ".join(
|
||||
author.replace("@", "") for author in self.repository.data.authors
|
||||
),
|
||||
"configuration_url": "homeassistant://hacs",
|
||||
}
|
||||
# LEGACY can be removed when min HA version is 2021.12
|
||||
if self.hacs.core.ha_version >= "2021.12.0b0":
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType
|
||||
|
||||
info["entry_type"] = DeviceEntryType.SERVICE
|
||||
else:
|
||||
info["entry_type"] = "service"
|
||||
return info
|
||||
62
custom_components/hacs/enums.py
Normal file
62
custom_components/hacs/enums.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""Helper constants."""
|
||||
# pylint: disable=missing-class-docstring
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class HacsGitHubRepo(str, Enum):
|
||||
"""HacsGitHubRepo."""
|
||||
|
||||
DEFAULT = "hacs/default"
|
||||
INTEGRATION = "hacs/integration"
|
||||
|
||||
|
||||
class HacsCategory(str, Enum):
|
||||
APPDAEMON = "appdaemon"
|
||||
INTEGRATION = "integration"
|
||||
LOVELACE = "lovelace"
|
||||
PLUGIN = "plugin" # Kept for legacy purposes
|
||||
NETDAEMON = "netdaemon"
|
||||
PYTHON_SCRIPT = "python_script"
|
||||
THEME = "theme"
|
||||
REMOVED = "removed"
|
||||
|
||||
def __str__(self):
|
||||
return str(self.value)
|
||||
|
||||
|
||||
class RepositoryFile(str, Enum):
|
||||
"""Repository file names."""
|
||||
|
||||
HACS_JSON = "hacs.json"
|
||||
MAINIFEST_JSON = "manifest.json"
|
||||
|
||||
|
||||
class ConfigurationType(str, Enum):
|
||||
YAML = "yaml"
|
||||
CONFIG_ENTRY = "config_entry"
|
||||
|
||||
|
||||
class LovelaceMode(str, Enum):
|
||||
"""Lovelace Modes."""
|
||||
|
||||
STORAGE = "storage"
|
||||
AUTO = "auto"
|
||||
AUTO_GEN = "auto-gen"
|
||||
YAML = "yaml"
|
||||
|
||||
|
||||
class HacsStage(str, Enum):
|
||||
SETUP = "setup"
|
||||
STARTUP = "startup"
|
||||
WAITING = "waiting"
|
||||
RUNNING = "running"
|
||||
BACKGROUND = "background"
|
||||
|
||||
|
||||
class HacsDisabledReason(str, Enum):
|
||||
RATE_LIMIT = "rate_limit"
|
||||
REMOVED = "removed"
|
||||
INVALID_TOKEN = "invalid_token"
|
||||
CONSTRAINS = "constrains"
|
||||
LOAD_HACS = "load_hacs"
|
||||
RESTORE = "restore"
|
||||
49
custom_components/hacs/exceptions.py
Normal file
49
custom_components/hacs/exceptions.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""Custom Exceptions for HACS."""
|
||||
|
||||
|
||||
class HacsException(Exception):
|
||||
"""Super basic."""
|
||||
|
||||
|
||||
class HacsRepositoryArchivedException(HacsException):
|
||||
"""For repositories that are archived."""
|
||||
|
||||
|
||||
class HacsNotModifiedException(HacsException):
|
||||
"""For responses that are not modified."""
|
||||
|
||||
|
||||
class HacsExpectedException(HacsException):
|
||||
"""For stuff that are expected."""
|
||||
|
||||
|
||||
class HacsRepositoryExistException(HacsException):
|
||||
"""For repositories that are already exist."""
|
||||
|
||||
|
||||
class HacsExecutionStillInProgress(HacsException):
|
||||
"""Exception to raise if execution is still in progress."""
|
||||
|
||||
|
||||
class AddonRepositoryException(HacsException):
|
||||
"""Exception to raise when user tries to add add-on repository."""
|
||||
|
||||
exception_message = (
|
||||
"The repository does not seem to be a integration, "
|
||||
"but an add-on repository. HACS does not manage add-ons."
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__(self.exception_message)
|
||||
|
||||
|
||||
class HomeAssistantCoreRepositoryException(HacsException):
|
||||
"""Exception to raise when user tries to add the home-assistant/core repository."""
|
||||
|
||||
exception_message = (
|
||||
"You can not add homeassistant/core, to use core integrations "
|
||||
"check the Home Assistant documentation for how to add them."
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__(self.exception_message)
|
||||
5
custom_components/hacs/hacs_frontend/__init__.py
Normal file
5
custom_components/hacs/hacs_frontend/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
"""HACS Frontend"""
|
||||
from .version import VERSION
|
||||
|
||||
def locate_dir():
|
||||
return __path__[0]
|
||||
61
custom_components/hacs/hacs_frontend/c.0083326c.js
Normal file
61
custom_components/hacs/hacs_frontend/c.0083326c.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import{a as r,f as o,e as a,r as e,$ as t,n as d}from"./main-f3e781b1.js";const i=(r,o)=>r&&r.config.components.includes(o);r([d("ha-card")],(function(r,o){return{F:class extends o{constructor(...o){super(...o),r(this)}},d:[{kind:"field",decorators:[a()],key:"header",value:void 0},{kind:"field",decorators:[a({type:Boolean,reflect:!0})],key:"outlined",value:()=>!1},{kind:"get",static:!0,key:"styles",value:function(){return e`
|
||||
:host {
|
||||
background: var(
|
||||
--ha-card-background,
|
||||
var(--card-background-color, white)
|
||||
);
|
||||
border-radius: var(--ha-card-border-radius, 4px);
|
||||
box-shadow: var(
|
||||
--ha-card-box-shadow,
|
||||
0px 2px 1px -1px rgba(0, 0, 0, 0.2),
|
||||
0px 1px 1px 0px rgba(0, 0, 0, 0.14),
|
||||
0px 1px 3px 0px rgba(0, 0, 0, 0.12)
|
||||
);
|
||||
color: var(--primary-text-color);
|
||||
display: block;
|
||||
transition: all 0.3s ease-out;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
:host([outlined]) {
|
||||
box-shadow: none;
|
||||
border-width: var(--ha-card-border-width, 1px);
|
||||
border-style: solid;
|
||||
border-color: var(
|
||||
--ha-card-border-color,
|
||||
var(--divider-color, #e0e0e0)
|
||||
);
|
||||
}
|
||||
|
||||
.card-header,
|
||||
:host ::slotted(.card-header) {
|
||||
color: var(--ha-card-header-color, --primary-text-color);
|
||||
font-family: var(--ha-card-header-font-family, inherit);
|
||||
font-size: var(--ha-card-header-font-size, 24px);
|
||||
letter-spacing: -0.012em;
|
||||
line-height: 48px;
|
||||
padding: 12px 16px 16px;
|
||||
display: block;
|
||||
margin-block-start: 0px;
|
||||
margin-block-end: 0px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
:host ::slotted(.card-content:not(:first-child)),
|
||||
slot:not(:first-child)::slotted(.card-content) {
|
||||
padding-top: 0px;
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
||||
:host ::slotted(.card-content) {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
:host ::slotted(.card-actions) {
|
||||
border-top: 1px solid var(--divider-color, #e8e8e8);
|
||||
padding: 5px 16px;
|
||||
}
|
||||
`}},{kind:"method",key:"render",value:function(){return t`
|
||||
${this.header?t`<h1 class="card-header">${this.header}</h1>`:t``}
|
||||
<slot></slot>
|
||||
`}}]}}),o);export{i};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.0083326c.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.0083326c.js.gz
Normal file
Binary file not shown.
67
custom_components/hacs/hacs_frontend/c.02169b19.js
Normal file
67
custom_components/hacs/hacs_frontend/c.02169b19.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import{a as i,f as a,e as t,t as s,$ as o,a1 as e,j as n,I as r,r as l,n as c}from"./main-f3e781b1.js";import"./c.fb46b4a0.js";import"./c.4c7d1a78.js";import"./c.3dc7ab21.js";import"./c.9f27b448.js";import"./c.0a038163.js";i([c("dialog-box")],(function(i,a){return{F:class extends a{constructor(...a){super(...a),i(this)}},d:[{kind:"field",decorators:[t({attribute:!1})],key:"hass",value:void 0},{kind:"field",decorators:[s()],key:"_params",value:void 0},{kind:"field",decorators:[s()],key:"_value",value:void 0},{kind:"method",key:"showDialog",value:async function(i){this._params=i,i.prompt&&(this._value=i.defaultValue)}},{kind:"method",key:"closeDialog",value:function(){var i,a;return!(null!==(i=this._params)&&void 0!==i&&i.confirmation||null!==(a=this._params)&&void 0!==a&&a.prompt)&&(!this._params||(this._dismiss(),!0))}},{kind:"method",key:"render",value:function(){if(!this._params)return o``;const i=this._params.confirmation||this._params.prompt;return o`
|
||||
<ha-dialog
|
||||
open
|
||||
?scrimClickAction=${i}
|
||||
?escapeKeyAction=${i}
|
||||
@closed=${this._dialogClosed}
|
||||
defaultAction="ignore"
|
||||
.heading=${o`${this._params.warning?o`<ha-svg-icon
|
||||
.path=${e}
|
||||
style="color: var(--warning-color)"
|
||||
></ha-svg-icon> `:""}${this._params.title?this._params.title:this._params.confirmation&&this.hass.localize("ui.dialogs.generic.default_confirmation_title")}`}
|
||||
>
|
||||
<div>
|
||||
${this._params.text?o`
|
||||
<p class=${this._params.prompt?"no-bottom-padding":""}>
|
||||
${this._params.text}
|
||||
</p>
|
||||
`:""}
|
||||
${this._params.prompt?o`
|
||||
<ha-textfield
|
||||
dialogInitialFocus
|
||||
.value=${this._value||""}
|
||||
@keyup=${this._handleKeyUp}
|
||||
@change=${this._valueChanged}
|
||||
.label=${this._params.inputLabel?this._params.inputLabel:""}
|
||||
.type=${this._params.inputType?this._params.inputType:"text"}
|
||||
></ha-textfield>
|
||||
`:""}
|
||||
</div>
|
||||
${i&&o`
|
||||
<mwc-button @click=${this._dismiss} slot="secondaryAction">
|
||||
${this._params.dismissText?this._params.dismissText:this.hass.localize("ui.dialogs.generic.cancel")}
|
||||
</mwc-button>
|
||||
`}
|
||||
<mwc-button
|
||||
@click=${this._confirm}
|
||||
?dialogInitialFocus=${!this._params.prompt}
|
||||
slot="primaryAction"
|
||||
>
|
||||
${this._params.confirmText?this._params.confirmText:this.hass.localize("ui.dialogs.generic.ok")}
|
||||
</mwc-button>
|
||||
</ha-dialog>
|
||||
`}},{kind:"method",key:"_valueChanged",value:function(i){this._value=i.target.value}},{kind:"method",key:"_dismiss",value:function(){var i;null!==(i=this._params)&&void 0!==i&&i.cancel&&this._params.cancel(),this._close()}},{kind:"method",key:"_handleKeyUp",value:function(i){13===i.keyCode&&this._confirm()}},{kind:"method",key:"_confirm",value:function(){this._params.confirm&&this._params.confirm(this._value),this._close()}},{kind:"method",key:"_dialogClosed",value:function(i){"ignore"!==i.detail.action&&this._dismiss()}},{kind:"method",key:"_close",value:function(){this._params&&(this._params=void 0,n(this,"dialog-closed",{dialog:this.localName}))}},{kind:"get",static:!0,key:"styles",value:function(){return[r,l`
|
||||
:host([inert]) {
|
||||
pointer-events: initial !important;
|
||||
cursor: initial !important;
|
||||
}
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 24px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.no-bottom-padding {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.secondary {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
ha-dialog {
|
||||
/* Place above other dialogs */
|
||||
--dialog-z-index: 104;
|
||||
}
|
||||
`]}}]}}),a);
|
||||
BIN
custom_components/hacs/hacs_frontend/c.02169b19.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.02169b19.js.gz
Normal file
Binary file not shown.
49
custom_components/hacs/hacs_frontend/c.02cb8bae.js
Normal file
49
custom_components/hacs/hacs_frontend/c.02cb8bae.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import{a as e,f as t,e as i,$ as n,r as o,n as r}from"./main-f3e781b1.js";import"./c.549fa845.js";e([r("ha-settings-row")],(function(e,t){return{F:class extends t{constructor(...t){super(...t),e(this)}},d:[{kind:"field",decorators:[i({type:Boolean,reflect:!0})],key:"narrow",value:void 0},{kind:"field",decorators:[i({type:Boolean,attribute:"three-line"})],key:"threeLine",value:()=>!1},{kind:"method",key:"render",value:function(){return n`
|
||||
<div class="prefix-wrap">
|
||||
<slot name="prefix"></slot>
|
||||
<paper-item-body
|
||||
?two-line=${!this.threeLine}
|
||||
?three-line=${this.threeLine}
|
||||
>
|
||||
<slot name="heading"></slot>
|
||||
<div secondary><slot name="description"></slot></div>
|
||||
</paper-item-body>
|
||||
</div>
|
||||
<slot></slot>
|
||||
`}},{kind:"get",static:!0,key:"styles",value:function(){return o`
|
||||
:host {
|
||||
display: flex;
|
||||
padding: 0 16px;
|
||||
align-content: normal;
|
||||
align-self: auto;
|
||||
align-items: center;
|
||||
}
|
||||
paper-item-body {
|
||||
padding: 8px 16px 8px 0;
|
||||
}
|
||||
paper-item-body[two-line] {
|
||||
min-height: calc(
|
||||
var(--paper-item-body-two-line-min-height, 72px) - 16px
|
||||
);
|
||||
flex: 1;
|
||||
}
|
||||
:host([narrow]) {
|
||||
align-items: normal;
|
||||
flex-direction: column;
|
||||
border-top: 1px solid var(--divider-color);
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
::slotted(ha-switch) {
|
||||
padding: 16px 0;
|
||||
}
|
||||
div[secondary] {
|
||||
white-space: normal;
|
||||
}
|
||||
.prefix-wrap {
|
||||
display: contents;
|
||||
}
|
||||
:host([narrow]) .prefix-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
`}}]}}),t);
|
||||
BIN
custom_components/hacs/hacs_frontend/c.02cb8bae.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.02cb8bae.js.gz
Normal file
Binary file not shown.
124
custom_components/hacs/hacs_frontend/c.074779bb.js
Normal file
124
custom_components/hacs/hacs_frontend/c.074779bb.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import{_ as e,n as t,a as i,H as s,e as a,b as r,m as o,$ as l,o as n,c,s as d,d as h,r as p}from"./main-f3e781b1.js";import{f as u}from"./c.dee01337.js";import"./c.c2b18de6.js";import{s as f,S as m,a as g}from"./c.9a62bd84.js";import"./c.145b2350.js";import"./c.02cb8bae.js";import{b as v}from"./c.c9bcea67.js";import"./c.f41a074f.js";import"./c.3dc7ab21.js";import"./c.9f27b448.js";import"./c.30e53b1f.js";import"./c.549fa845.js";import"./c.fb46b4a0.js";import"./c.0a038163.js";let y=class extends m{};y.styles=[f],y=e([t("mwc-select")],y);const _=["stars","last_updated","name"];let k=i([t("hacs-add-repository-dialog")],(function(e,t){return{F:class extends t{constructor(...t){super(...t),e(this)}},d:[{kind:"field",decorators:[a({attribute:!1})],key:"filters",value:()=>[]},{kind:"field",decorators:[a({type:Number})],key:"_load",value:()=>30},{kind:"field",decorators:[a({type:Number})],key:"_top",value:()=>0},{kind:"field",decorators:[a()],key:"_searchInput",value:()=>""},{kind:"field",decorators:[a()],key:"_sortBy",value:()=>_[0]},{kind:"field",decorators:[a()],key:"section",value:void 0},{kind:"method",key:"shouldUpdate",value:function(e){return e.forEach(((e,t)=>{"hass"===t&&(this.sidebarDocked='"docked"'===window.localStorage.getItem("dockedSidebar"))})),e.has("narrow")||e.has("filters")||e.has("active")||e.has("_searchInput")||e.has("_load")||e.has("_sortBy")}},{kind:"field",key:"_repositoriesInActiveCategory",value(){return(e,t)=>null==e?void 0:e.filter((e=>{var i,s;return!e.installed&&(null===(i=this.hacs.sections)||void 0===i||null===(s=i.find((e=>e.id===this.section)).categories)||void 0===s?void 0:s.includes(e.category))&&!e.installed&&(null==t?void 0:t.includes(e.category))}))}},{kind:"method",key:"firstUpdated",value:async function(){var e;if(this.addEventListener("filter-change",(e=>this._updateFilters(e))),0===(null===(e=this.filters)||void 0===e?void 0:e.length)){var t;const e=null===(t=r(this.hacs.language,this.route))||void 0===t?void 0:t.categories;null==e||e.filter((e=>{var t;return null===(t=this.hacs.configuration)||void 0===t?void 0:t.categories.includes(e)})).forEach((e=>{this.filters.push({id:e,value:e,checked:!0})})),this.requestUpdate("filters")}}},{kind:"method",key:"_updateFilters",value:function(e){const t=this.filters.find((t=>t.id===e.detail.id));this.filters.find((e=>e.id===t.id)).checked=!t.checked,this.requestUpdate("filters")}},{kind:"field",key:"_filterRepositories",value:()=>o(u)},{kind:"method",key:"render",value:function(){var e;if(!this.active)return l``;this._searchInput=window.localStorage.getItem("hacs-search")||"";let t=this._filterRepositories(this._repositoriesInActiveCategory(this.repositories,null===(e=this.hacs.configuration)||void 0===e?void 0:e.categories),this._searchInput);return 0!==this.filters.length&&(t=t.filter((e=>{var t;return null===(t=this.filters.find((t=>t.id===e.category)))||void 0===t?void 0:t.checked}))),l`
|
||||
<hacs-dialog
|
||||
.active=${this.active}
|
||||
.hass=${this.hass}
|
||||
.title=${this.hacs.localize("dialog_add_repo.title")}
|
||||
hideActions
|
||||
scrimClickAction
|
||||
maxWidth
|
||||
>
|
||||
<div class="searchandfilter" ?narrow=${this.narrow}>
|
||||
<search-input
|
||||
.hass=${this.hass}
|
||||
.label=${this.hacs.localize("search.placeholder")}
|
||||
.filter=${this._searchInput}
|
||||
@value-changed=${this._inputValueChanged}
|
||||
?narrow=${this.narrow}
|
||||
></search-input>
|
||||
<mwc-select
|
||||
?narrow=${this.narrow}
|
||||
.label=${this.hacs.localize("dialog_add_repo.sort_by")}
|
||||
.value=${this._sortBy}
|
||||
@selected=${e=>this._sortBy=e.currentTarget.value}
|
||||
@closed=${g}
|
||||
>
|
||||
${_.map((e=>l`<mwc-list-item .value=${e}>
|
||||
${this.hacs.localize(`dialog_add_repo.sort_by_values.${e}`)||e}
|
||||
</mwc-list-item>`))}
|
||||
</mwc-select>
|
||||
</div>
|
||||
${this.filters.length>1?l`<div class="filters">
|
||||
<hacs-filter .hacs=${this.hacs} .filters="${this.filters}"></hacs-filter>
|
||||
</div>`:""}
|
||||
<div class=${n({content:!0,narrow:this.narrow})} @scroll=${this._loadMore}>
|
||||
<div class=${n({list:!0,narrow:this.narrow})}>
|
||||
${t.sort(((e,t)=>"name"===this._sortBy?e.name.toLocaleLowerCase()<t.name.toLocaleLowerCase()?-1:1:e[this._sortBy]>t[this._sortBy]?-1:1)).slice(0,this._load).map((e=>l` <ha-settings-row
|
||||
class=${n({narrow:this.narrow})}
|
||||
@click=${()=>this._openInformation(e)}
|
||||
>
|
||||
${this.narrow?"":"integration"===e.category?l`
|
||||
<img
|
||||
slot="prefix"
|
||||
loading="lazy"
|
||||
.src=${v({domain:e.domain,darkOptimized:this.hass.themes.darkMode,type:"icon"})}
|
||||
referrerpolicy="no-referrer"
|
||||
@error=${this._onImageError}
|
||||
@load=${this._onImageLoad}
|
||||
/>
|
||||
`:""}
|
||||
<span slot="heading"> ${e.name} </span>
|
||||
<span slot="description">${e.description}</span>
|
||||
${"integration"!==e.category?l`<ha-chip>${this.hacs.localize(`common.${e.category}`)}</ha-chip> `:""}
|
||||
</ha-settings-row>`))}
|
||||
${0===t.length?l`<p>${this.hacs.localize("dialog_add_repo.no_match")}</p>`:""}
|
||||
</div>
|
||||
</div>
|
||||
</hacs-dialog>
|
||||
`}},{kind:"method",key:"_loadMore",value:function(e){const t=e.target.scrollTop;t>=this._top?this._load+=1:this._load-=1,this._top=t}},{kind:"method",key:"_inputValueChanged",value:function(e){this._searchInput=e.detail.value,window.localStorage.setItem("hacs-search",this._searchInput)}},{kind:"method",key:"_openInformation",value:function(e){this.dispatchEvent(new CustomEvent("hacs-dialog-secondary",{detail:{type:"repository-info",repository:e.id},bubbles:!0,composed:!0}))}},{kind:"method",key:"_onImageLoad",value:function(e){e.target.style.visibility="initial"}},{kind:"method",key:"_onImageError",value:function(e){var t;if(null!==(t=e.target)&&void 0!==t&&t.outerHTML)try{e.target.outerHTML=`<ha-svg-icon path="${c}" slot="prefix"></ha-svg-icon>`}catch(e){}}},{kind:"get",static:!0,key:"styles",value:function(){return[d,h,p`
|
||||
.content {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.filter {
|
||||
margin-top: -12px;
|
||||
display: flex;
|
||||
width: 200px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.list {
|
||||
margin-top: 16px;
|
||||
width: 1024px;
|
||||
max-width: 100%;
|
||||
}
|
||||
ha-svg-icon {
|
||||
--mdc-icon-size: 36px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
search-input {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 75%;
|
||||
}
|
||||
search-input[narrow],
|
||||
mwc-select[narrow] {
|
||||
width: 100%;
|
||||
margin: 4px 0;
|
||||
}
|
||||
img {
|
||||
align-items: center;
|
||||
display: block;
|
||||
justify-content: center;
|
||||
margin-right: 6px;
|
||||
margin-bottom: 16px;
|
||||
max-height: 36px;
|
||||
max-width: 36px;
|
||||
}
|
||||
|
||||
.filters {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
hacs-filter {
|
||||
width: 100%;
|
||||
margin-left: -32px;
|
||||
}
|
||||
|
||||
ha-settings-row {
|
||||
padding: 0px 16px 0 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.searchandfilter {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: self-end;
|
||||
}
|
||||
|
||||
.searchandfilter[narrow] {
|
||||
flex-direction: column;
|
||||
}
|
||||
`]}}]}}),s);export{k as HacsAddRepositoryDialog};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.074779bb.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.074779bb.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.0a038163.js
Normal file
1
custom_components/hacs/hacs_frontend/c.0a038163.js
Normal file
@@ -0,0 +1 @@
|
||||
function t(t){const a=t.language||"en";return t.translationMetadata.translations[a]&&t.translationMetadata.translations[a].isRTL||!1}function a(a){return t(a)?"rtl":"ltr"}export{t as a,a as c};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.0a038163.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.0a038163.js.gz
Normal file
Binary file not shown.
6
custom_components/hacs/hacs_frontend/c.1149f406.js
Normal file
6
custom_components/hacs/hacs_frontend/c.1149f406.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import{a as t,H as e,e as i,m as o,$ as s,n as r}from"./main-f3e781b1.js";import{m as a}from"./c.ac33c45a.js";import"./c.f41a074f.js";import"./c.b85cccfb.js";import"./c.3f18632e.js";import"./c.fb46b4a0.js";import"./c.9f27b448.js";import"./c.0a038163.js";let d=t([r("hacs-generic-dialog")],(function(t,e){return{F:class extends e{constructor(...e){super(...e),t(this)}},d:[{kind:"field",decorators:[i({type:Boolean})],key:"markdown",value:()=>!1},{kind:"field",decorators:[i()],key:"repository",value:void 0},{kind:"field",decorators:[i()],key:"header",value:void 0},{kind:"field",decorators:[i()],key:"content",value:void 0},{kind:"field",key:"_getRepository",value:()=>o(((t,e)=>null==t?void 0:t.find((t=>t.id===e))))},{kind:"method",key:"render",value:function(){if(!this.active||!this.repository)return s``;const t=this._getRepository(this.hacs.repositories,this.repository);return s`
|
||||
<hacs-dialog .active=${this.active} .narrow=${this.narrow} .hass=${this.hass}>
|
||||
<div slot="header">${this.header||""}</div>
|
||||
${this.markdown?this.repository?a.html(this.content||"",t):a.html(this.content||""):this.content||""}
|
||||
</hacs-dialog>
|
||||
`}}]}}),e);export{d as HacsGenericDialog};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.1149f406.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.1149f406.js.gz
Normal file
Binary file not shown.
39
custom_components/hacs/hacs_frontend/c.145b2350.js
Normal file
39
custom_components/hacs/hacs_frontend/c.145b2350.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import{a as c,f as o,e as i,$ as a,r,G as n,n as t}from"./main-f3e781b1.js";import{c as e}from"./c.30e53b1f.js";c([t("ha-chip")],(function(c,o){return{F:class extends o{constructor(...o){super(...o),c(this)}},d:[{kind:"field",decorators:[i({type:Boolean})],key:"hasIcon",value:()=>!1},{kind:"field",decorators:[i({type:Boolean})],key:"noText",value:()=>!1},{kind:"method",key:"render",value:function(){return a`
|
||||
<div class="mdc-chip ${this.noText?"no-text":""}">
|
||||
${this.hasIcon?a`<div class="mdc-chip__icon mdc-chip__icon--leading">
|
||||
<slot name="icon"></slot>
|
||||
</div>`:null}
|
||||
<div class="mdc-chip__ripple"></div>
|
||||
<span role="gridcell">
|
||||
<span role="button" tabindex="0" class="mdc-chip__primary-action">
|
||||
<span class="mdc-chip__text"><slot></slot></span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
`}},{kind:"get",static:!0,key:"styles",value:function(){return r`
|
||||
${n(e)}
|
||||
.mdc-chip {
|
||||
background-color: var(
|
||||
--ha-chip-background-color,
|
||||
rgba(var(--rgb-primary-text-color), 0.15)
|
||||
);
|
||||
color: var(--ha-chip-text-color, var(--primary-text-color));
|
||||
}
|
||||
|
||||
.mdc-chip.no-text {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.mdc-chip:hover {
|
||||
color: var(--ha-chip-text-color, var(--primary-text-color));
|
||||
}
|
||||
|
||||
.mdc-chip__icon--leading {
|
||||
--mdc-icon-size: 20px;
|
||||
color: var(--ha-chip-icon-color, var(--ha-chip-text-color));
|
||||
}
|
||||
.mdc-chip.no-text
|
||||
.mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden) {
|
||||
margin-right: -4px;
|
||||
}
|
||||
`}}]}}),o);
|
||||
BIN
custom_components/hacs/hacs_frontend/c.145b2350.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.145b2350.js.gz
Normal file
Binary file not shown.
609
custom_components/hacs/hacs_frontend/c.16a173f1.js
Normal file
609
custom_components/hacs/hacs_frontend/c.16a173f1.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.16a173f1.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.16a173f1.js.gz
Normal file
Binary file not shown.
818
custom_components/hacs/hacs_frontend/c.2b092eff.js
Normal file
818
custom_components/hacs/hacs_frontend/c.2b092eff.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.2b092eff.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.2b092eff.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.30e53b1f.js
Normal file
1
custom_components/hacs/hacs_frontend/c.30e53b1f.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.30e53b1f.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.30e53b1f.js.gz
Normal file
Binary file not shown.
114
custom_components/hacs/hacs_frontend/c.3dc7ab21.js
Normal file
114
custom_components/hacs/hacs_frontend/c.3dc7ab21.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.3dc7ab21.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.3dc7ab21.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.3f18632e.js
Normal file
1
custom_components/hacs/hacs_frontend/c.3f18632e.js
Normal file
@@ -0,0 +1 @@
|
||||
var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function o(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function t(e,o){return e(o={exports:{}},o.exports),o.exports}function n(e){return e&&e.default||e}export{e as a,t as c,n as g,o as u};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.3f18632e.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.3f18632e.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.4a76f115.js
Normal file
1
custom_components/hacs/hacs_frontend/c.4a76f115.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.4a76f115.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.4a76f115.js.gz
Normal file
Binary file not shown.
50
custom_components/hacs/hacs_frontend/c.4c7d1a78.js
Normal file
50
custom_components/hacs/hacs_frontend/c.4c7d1a78.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import{x as e,y as t,M as c,_ as i,e as r,D as s,i as o,p as d,t as a,E as n,B as h,R as l,C as p,$ as u,q as m,r as b,j as w,a as f,P as k,Q as v,n as _}from"./main-f3e781b1.js";import{o as y}from"./c.9f27b448.js";var g={CHECKED:"mdc-switch--checked",DISABLED:"mdc-switch--disabled"},C={ARIA_CHECKED_ATTR:"aria-checked",NATIVE_CONTROL_SELECTOR:".mdc-switch__native-control",RIPPLE_SURFACE_SELECTOR:".mdc-switch__thumb-underlay"},x=function(c){function i(e){return c.call(this,t(t({},i.defaultAdapter),e))||this}return e(i,c),Object.defineProperty(i,"strings",{get:function(){return C},enumerable:!1,configurable:!0}),Object.defineProperty(i,"cssClasses",{get:function(){return g},enumerable:!1,configurable:!0}),Object.defineProperty(i,"defaultAdapter",{get:function(){return{addClass:function(){},removeClass:function(){},setNativeControlChecked:function(){},setNativeControlDisabled:function(){},setNativeControlAttr:function(){}}},enumerable:!1,configurable:!0}),i.prototype.setChecked=function(e){this.adapter.setNativeControlChecked(e),this.updateAriaChecked(e),this.updateCheckedStyling(e)},i.prototype.setDisabled=function(e){this.adapter.setNativeControlDisabled(e),e?this.adapter.addClass(g.DISABLED):this.adapter.removeClass(g.DISABLED)},i.prototype.handleChange=function(e){var t=e.target;this.updateAriaChecked(t.checked),this.updateCheckedStyling(t.checked)},i.prototype.updateCheckedStyling=function(e){e?this.adapter.addClass(g.CHECKED):this.adapter.removeClass(g.CHECKED)},i.prototype.updateAriaChecked=function(e){this.adapter.setNativeControlAttr(C.ARIA_CHECKED_ATTR,""+!!e)},i}(c);class R extends h{constructor(){super(...arguments),this.checked=!1,this.disabled=!1,this.shouldRenderRipple=!1,this.mdcFoundationClass=x,this.rippleHandlers=new l((()=>(this.shouldRenderRipple=!0,this.ripple)))}changeHandler(e){this.mdcFoundation.handleChange(e),this.checked=this.formElement.checked}createAdapter(){return Object.assign(Object.assign({},p(this.mdcRoot)),{setNativeControlChecked:e=>{this.formElement.checked=e},setNativeControlDisabled:e=>{this.formElement.disabled=e},setNativeControlAttr:(e,t)=>{this.formElement.setAttribute(e,t)}})}renderRipple(){return this.shouldRenderRipple?u`
|
||||
<mwc-ripple
|
||||
.accent="${this.checked}"
|
||||
.disabled="${this.disabled}"
|
||||
unbounded>
|
||||
</mwc-ripple>`:""}focus(){const e=this.formElement;e&&(this.rippleHandlers.startFocus(),e.focus())}blur(){const e=this.formElement;e&&(this.rippleHandlers.endFocus(),e.blur())}click(){this.formElement&&!this.disabled&&(this.formElement.focus(),this.formElement.click())}firstUpdated(){super.firstUpdated(),this.shadowRoot&&this.mdcRoot.addEventListener("change",(e=>{this.dispatchEvent(new Event("change",e))}))}render(){return u`
|
||||
<div class="mdc-switch">
|
||||
<div class="mdc-switch__track"></div>
|
||||
<div class="mdc-switch__thumb-underlay">
|
||||
${this.renderRipple()}
|
||||
<div class="mdc-switch__thumb">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="basic-switch"
|
||||
class="mdc-switch__native-control"
|
||||
role="switch"
|
||||
aria-label="${m(this.ariaLabel)}"
|
||||
aria-labelledby="${m(this.ariaLabelledBy)}"
|
||||
@change="${this.changeHandler}"
|
||||
@focus="${this.handleRippleFocus}"
|
||||
@blur="${this.handleRippleBlur}"
|
||||
@mousedown="${this.handleRippleMouseDown}"
|
||||
@mouseenter="${this.handleRippleMouseEnter}"
|
||||
@mouseleave="${this.handleRippleMouseLeave}"
|
||||
@touchstart="${this.handleRippleTouchStart}"
|
||||
@touchend="${this.handleRippleDeactivate}"
|
||||
@touchcancel="${this.handleRippleDeactivate}">
|
||||
</div>
|
||||
</div>
|
||||
</div>`}handleRippleMouseDown(e){const t=()=>{window.removeEventListener("mouseup",t),this.handleRippleDeactivate()};window.addEventListener("mouseup",t),this.rippleHandlers.startPress(e)}handleRippleTouchStart(e){this.rippleHandlers.startPress(e)}handleRippleDeactivate(){this.rippleHandlers.endPress()}handleRippleMouseEnter(){this.rippleHandlers.startHover()}handleRippleMouseLeave(){this.rippleHandlers.endHover()}handleRippleFocus(){this.rippleHandlers.startFocus()}handleRippleBlur(){this.rippleHandlers.endFocus()}}i([r({type:Boolean}),y((function(e){this.mdcFoundation.setChecked(e)}))],R.prototype,"checked",void 0),i([r({type:Boolean}),y((function(e){this.mdcFoundation.setDisabled(e)}))],R.prototype,"disabled",void 0),i([s,r({attribute:"aria-label"})],R.prototype,"ariaLabel",void 0),i([s,r({attribute:"aria-labelledby"})],R.prototype,"ariaLabelledBy",void 0),i([o(".mdc-switch")],R.prototype,"mdcRoot",void 0),i([o("input")],R.prototype,"formElement",void 0),i([d("mwc-ripple")],R.prototype,"ripple",void 0),i([a()],R.prototype,"shouldRenderRipple",void 0),i([n({passive:!0})],R.prototype,"handleRippleMouseDown",null),i([n({passive:!0})],R.prototype,"handleRippleTouchStart",null);const E=b`.mdc-switch__thumb-underlay{left:-14px;right:initial;top:-17px;width:48px;height:48px}[dir=rtl] .mdc-switch__thumb-underlay,.mdc-switch__thumb-underlay[dir=rtl]{left:initial;right:-14px}.mdc-switch__native-control{width:64px;height:48px}.mdc-switch{display:inline-block;position:relative;outline:none;user-select:none}.mdc-switch.mdc-switch--checked .mdc-switch__track{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786)}.mdc-switch.mdc-switch--checked .mdc-switch__thumb{background-color:#018786;background-color:var(--mdc-theme-secondary, #018786);border-color:#018786;border-color:var(--mdc-theme-secondary, #018786)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__track{background-color:#000;background-color:var(--mdc-theme-on-surface, #000)}.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb{background-color:#fff;background-color:var(--mdc-theme-surface, #fff);border-color:#fff;border-color:var(--mdc-theme-surface, #fff)}.mdc-switch__native-control{left:0;right:initial;position:absolute;top:0;margin:0;opacity:0;cursor:pointer;pointer-events:auto;transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1)}[dir=rtl] .mdc-switch__native-control,.mdc-switch__native-control[dir=rtl]{left:initial;right:0}.mdc-switch__track{box-sizing:border-box;width:36px;height:14px;border:1px solid transparent;border-radius:7px;opacity:.38;transition:opacity 90ms cubic-bezier(0.4, 0, 0.2, 1),background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-switch__thumb-underlay{display:flex;position:absolute;align-items:center;justify-content:center;transform:translateX(0);transition:transform 90ms cubic-bezier(0.4, 0, 0.2, 1),background-color 90ms cubic-bezier(0.4, 0, 0.2, 1),border-color 90ms cubic-bezier(0.4, 0, 0.2, 1)}.mdc-switch__thumb{box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2),0px 2px 2px 0px rgba(0, 0, 0, 0.14),0px 1px 5px 0px rgba(0,0,0,.12);box-sizing:border-box;width:20px;height:20px;border:10px solid;border-radius:50%;pointer-events:none;z-index:1}.mdc-switch--checked .mdc-switch__track{opacity:.54}.mdc-switch--checked .mdc-switch__thumb-underlay{transform:translateX(16px)}[dir=rtl] .mdc-switch--checked .mdc-switch__thumb-underlay,.mdc-switch--checked .mdc-switch__thumb-underlay[dir=rtl]{transform:translateX(-16px)}.mdc-switch--checked .mdc-switch__native-control{transform:translateX(-16px)}[dir=rtl] .mdc-switch--checked .mdc-switch__native-control,.mdc-switch--checked .mdc-switch__native-control[dir=rtl]{transform:translateX(16px)}.mdc-switch--disabled{opacity:.38;pointer-events:none}.mdc-switch--disabled .mdc-switch__thumb{border-width:1px}.mdc-switch--disabled .mdc-switch__native-control{cursor:default;pointer-events:none}:host{display:inline-flex;outline:none;-webkit-tap-highlight-color:transparent}`;f([_("ha-switch")],(function(e,t){class c extends t{constructor(...t){super(...t),e(this)}}return{F:c,d:[{kind:"field",decorators:[r({type:Boolean})],key:"haptic",value:()=>!1},{kind:"method",key:"firstUpdated",value:function(){k(v(c.prototype),"firstUpdated",this).call(this),this.addEventListener("change",(()=>{this.haptic&&w(window,"haptic","light")}))}},{kind:"field",static:!0,key:"styles",value:()=>[E,b`
|
||||
:host {
|
||||
--mdc-theme-secondary: var(--switch-checked-color);
|
||||
}
|
||||
.mdc-switch.mdc-switch--checked .mdc-switch__thumb {
|
||||
background-color: var(--switch-checked-button-color);
|
||||
border-color: var(--switch-checked-button-color);
|
||||
}
|
||||
.mdc-switch.mdc-switch--checked .mdc-switch__track {
|
||||
background-color: var(--switch-checked-track-color);
|
||||
border-color: var(--switch-checked-track-color);
|
||||
}
|
||||
.mdc-switch:not(.mdc-switch--checked) .mdc-switch__thumb {
|
||||
background-color: var(--switch-unchecked-button-color);
|
||||
border-color: var(--switch-unchecked-button-color);
|
||||
}
|
||||
.mdc-switch:not(.mdc-switch--checked) .mdc-switch__track {
|
||||
background-color: var(--switch-unchecked-track-color);
|
||||
border-color: var(--switch-unchecked-track-color);
|
||||
}
|
||||
`]}]}}),R);
|
||||
BIN
custom_components/hacs/hacs_frontend/c.4c7d1a78.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.4c7d1a78.js.gz
Normal file
Binary file not shown.
34
custom_components/hacs/hacs_frontend/c.549fa845.js
Normal file
34
custom_components/hacs/hacs_frontend/c.549fa845.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import{S as e,T as o}from"./main-f3e781b1.js";e({_template:o`
|
||||
<style>
|
||||
:host {
|
||||
overflow: hidden; /* needed for text-overflow: ellipsis to work on ff */
|
||||
@apply --layout-vertical;
|
||||
@apply --layout-center-justified;
|
||||
@apply --layout-flex;
|
||||
}
|
||||
|
||||
:host([two-line]) {
|
||||
min-height: var(--paper-item-body-two-line-min-height, 72px);
|
||||
}
|
||||
|
||||
:host([three-line]) {
|
||||
min-height: var(--paper-item-body-three-line-min-height, 88px);
|
||||
}
|
||||
|
||||
:host > ::slotted(*) {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
:host > ::slotted([secondary]) {
|
||||
@apply --paper-font-body1;
|
||||
|
||||
color: var(--paper-item-body-secondary-color, var(--secondary-text-color));
|
||||
|
||||
@apply --paper-item-body-secondary;
|
||||
}
|
||||
</style>
|
||||
|
||||
<slot></slot>
|
||||
`,is:"paper-item-body"});
|
||||
BIN
custom_components/hacs/hacs_frontend/c.549fa845.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.549fa845.js.gz
Normal file
Binary file not shown.
51
custom_components/hacs/hacs_frontend/c.5a8108e9.js
Normal file
51
custom_components/hacs/hacs_frontend/c.5a8108e9.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.5a8108e9.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.5a8108e9.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.5c703026.js
Normal file
1
custom_components/hacs/hacs_frontend/c.5c703026.js
Normal file
@@ -0,0 +1 @@
|
||||
const e=()=>new Promise((e=>{var t;t=e,requestAnimationFrame((()=>setTimeout(t,0)))}));export{e as n};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.5c703026.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.5c703026.js.gz
Normal file
Binary file not shown.
84
custom_components/hacs/hacs_frontend/c.66be6e45.js
Normal file
84
custom_components/hacs/hacs_frontend/c.66be6e45.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import{a as o,H as s,e as t,t as i,$ as e,W as a,X as r,Y as c,Z as d,s as n,d as h,r as l,n as p}from"./main-f3e781b1.js";import{a as m}from"./c.0a038163.js";import"./c.c4dc5ba3.js";import"./c.74dbf101.js";import"./c.02cb8bae.js";import"./c.f41a074f.js";import"./c.c2b18de6.js";import"./c.9f27b448.js";import"./c.3dc7ab21.js";import"./c.e6514d94.js";import"./c.f1b17fae.js";import"./c.9a62bd84.js";import"./c.5c703026.js";import"./c.549fa845.js";import"./c.fb46b4a0.js";let u=o([p("hacs-custom-repositories-dialog")],(function(o,s){return{F:class extends s{constructor(...s){super(...s),o(this)}},d:[{kind:"field",decorators:[t()],key:"_error",value:void 0},{kind:"field",decorators:[i()],key:"_progress",value:()=>!1},{kind:"field",decorators:[i()],key:"_addRepositoryData",value:()=>({category:void 0,repository:void 0})},{kind:"field",decorators:[i()],key:"_customRepositories",value:void 0},{kind:"method",key:"shouldUpdate",value:function(o){return o.has("narrow")||o.has("active")||o.has("_error")||o.has("_addRepositoryData")||o.has("_customRepositories")||o.has("_progress")}},{kind:"method",key:"render",value:function(){var o,s;if(!this.active)return e``;const t=[{type:"string",name:"repository"},{type:"select",name:"category",optional:!0,options:this.hacs.configuration.categories.map((o=>[o,this.hacs.localize(`common.${o}`)]))}];return e`
|
||||
<hacs-dialog
|
||||
.active=${this.active}
|
||||
.hass=${this.hass}
|
||||
.title=${this.hacs.localize("dialog_custom_repositories.title")}
|
||||
scrimClickAction
|
||||
escapeKeyAction
|
||||
maxWidth
|
||||
>
|
||||
<div class="content">
|
||||
<div class="list" ?narrow=${this.narrow}>
|
||||
${null!==(o=this._error)&&void 0!==o&&o.message?e`<ha-alert alert-type="error" .rtl=${m(this.hass)}>
|
||||
${this._error.message}
|
||||
</ha-alert>`:""}
|
||||
${null===(s=this._customRepositories)||void 0===s?void 0:s.filter((o=>this.hacs.configuration.categories.includes(o.category))).map((o=>e`<ha-settings-row
|
||||
@click=${()=>this._showReopsitoryInfo(String(o.id))}
|
||||
>
|
||||
<span slot="heading">${o.name}</span>
|
||||
<span slot="description">${o.full_name} (${o.category})</span>
|
||||
|
||||
<mwc-icon-button
|
||||
@click=${s=>{s.stopPropagation(),this._removeRepository(o.id)}}
|
||||
>
|
||||
<ha-svg-icon class="delete" .path=${a}></ha-svg-icon>
|
||||
</mwc-icon-button>
|
||||
</ha-settings-row>`))}
|
||||
</div>
|
||||
<ha-form
|
||||
?narrow=${this.narrow}
|
||||
.data=${this._addRepositoryData}
|
||||
.schema=${t}
|
||||
.computeLabel=${o=>"category"===o.name?this.hacs.localize("dialog_custom_repositories.category"):this.hacs.localize("common.repository")}
|
||||
@value-changed=${this._valueChanged}
|
||||
>
|
||||
</ha-form>
|
||||
</div>
|
||||
<mwc-button
|
||||
slot="primaryaction"
|
||||
raised
|
||||
.disabled=${void 0===this._addRepositoryData.category||void 0===this._addRepositoryData.repository}
|
||||
@click=${this._addRepository}
|
||||
>
|
||||
${this._progress?e`<ha-circular-progress active size="small"></ha-circular-progress>`:this.hacs.localize("common.add")}
|
||||
</mwc-button>
|
||||
</hacs-dialog>
|
||||
`}},{kind:"method",key:"firstUpdated",value:function(){var o;this.hass.connection.subscribeEvents((o=>this._error=o.data),"hacs/error"),this._customRepositories=null===(o=this.hacs.repositories)||void 0===o?void 0:o.filter((o=>o.custom))}},{kind:"method",key:"_valueChanged",value:function(o){this._addRepositoryData=o.detail.value}},{kind:"method",key:"_addRepository",value:async function(){if(this._error=void 0,this._progress=!0,!this._addRepositoryData.category)return void(this._error={message:this.hacs.localize("dialog_custom_repositories.no_category")});if(!this._addRepositoryData.repository)return void(this._error={message:this.hacs.localize("dialog_custom_repositories.no_repository")});await r(this.hass,this._addRepositoryData.repository,this._addRepositoryData.category);const o=await c(this.hass);this.dispatchEvent(new CustomEvent("update-hacs",{detail:{repositories:o},bubbles:!0,composed:!0})),this._customRepositories=o.filter((o=>o.custom)),this._progress=!1}},{kind:"method",key:"_removeRepository",value:async function(o){this._error=void 0,await d(this.hass,o);const s=await c(this.hass);this.dispatchEvent(new CustomEvent("update-hacs",{detail:{repositories:s},bubbles:!0,composed:!0})),this._customRepositories=s.filter((o=>o.custom))}},{kind:"method",key:"_showReopsitoryInfo",value:async function(o){this.dispatchEvent(new CustomEvent("hacs-dialog-secondary",{detail:{type:"repository-info",repository:o},bubbles:!0,composed:!0}))}},{kind:"get",static:!0,key:"styles",value:function(){return[n,h,l`
|
||||
.list {
|
||||
position: relative;
|
||||
max-height: calc(100vh - 500px);
|
||||
overflow: auto;
|
||||
}
|
||||
ha-form {
|
||||
display: block;
|
||||
padding: 25px 0;
|
||||
}
|
||||
ha-form[narrow] {
|
||||
background-color: var(--card-background-color);
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
width: calc(100% - 48px);
|
||||
}
|
||||
ha-svg-icon {
|
||||
--mdc-icon-size: 36px;
|
||||
}
|
||||
ha-svg-icon:not(.delete) {
|
||||
margin-right: 4px;
|
||||
}
|
||||
ha-settings-row {
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
}
|
||||
.list[narrow] > ha-settings-row:last-of-type {
|
||||
margin-bottom: 162px;
|
||||
}
|
||||
.delete {
|
||||
color: var(--hcv-color-error);
|
||||
}
|
||||
|
||||
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||
.list {
|
||||
max-height: calc(100vh - 162px);
|
||||
}
|
||||
}
|
||||
`]}}]}}),s);export{u as HacsCustomRepositoriesDialog};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.66be6e45.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.66be6e45.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.69351b0c.js
Normal file
1
custom_components/hacs/hacs_frontend/c.69351b0c.js
Normal file
@@ -0,0 +1 @@
|
||||
import{m as o}from"./c.ac33c45a.js";import{a as t}from"./c.ecc9713e.js";const e=async(e,n)=>t(e,{title:"Home Assistant Community Store",confirmText:n.localize("common.close"),text:o.html(`\n **${n.localize("dialog_about.integration_version")}:** | ${n.configuration.version}\n --|--\n **${n.localize("dialog_about.frontend_version")}:** | 20220401183545\n **${n.localize("common.repositories")}:** | ${n.repositories.length}\n **${n.localize("dialog_about.downloaded_repositories")}:** | ${n.repositories.filter((o=>o.installed)).length}\n\n **${n.localize("dialog_about.useful_links")}:**\n\n - [General documentation](https://hacs.xyz/)\n - [Configuration](https://hacs.xyz/docs/configuration/start)\n - [FAQ](https://hacs.xyz/docs/faq/what)\n - [GitHub](https://github.com/hacs)\n - [Discord](https://discord.gg/apgchf8)\n - [Become a GitHub sponsor? ❤️](https://github.com/sponsors/ludeeus)\n - [BuyMe~~Coffee~~Beer? 🍺🙈](https://buymeacoffee.com/ludeeus)\n\n ***\n\n _Everything you find in HACS is **not** tested by Home Assistant, that includes HACS itself.\n The HACS and Home Assistant teams do not support **anything** you find here._`)});export{e as s};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.69351b0c.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.69351b0c.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.69bec4b9.js
Normal file
1
custom_components/hacs/hacs_frontend/c.69bec4b9.js
Normal file
@@ -0,0 +1 @@
|
||||
import{al as e,am as s,ag as a,an as r,ao as u}from"./main-f3e781b1.js";async function i(i,o,n){const t=new e("updateLovelaceResources"),l=await s(i),c=`/hacsfiles/${o.full_name.split("/")[1]}`,d=a({repository:o,version:n}),p=l.find((e=>e.url.includes(c)));t.debug({namespace:c,url:d,exsisting:p}),p&&p.url!==d?(t.debug(`Updating exsusting resource for ${c}`),await r(i,{url:d,resource_id:p.id,res_type:p.type})):l.map((e=>e.url)).includes(d)||(t.debug(`Adding ${d} to Lovelace resources`),await u(i,{url:d,res_type:"module"}))}export{i as u};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.69bec4b9.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.69bec4b9.js.gz
Normal file
Binary file not shown.
63
custom_components/hacs/hacs_frontend/c.6e79c449.js
Normal file
63
custom_components/hacs/hacs_frontend/c.6e79c449.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import{a as t,H as o,e as s,t as i,m as e,af as a,Y as r,$ as l,ag as h,ah as n,ai as c,aj as d,ak as p,ae as _,d as y,r as m,n as u}from"./main-f3e781b1.js";import{a as v}from"./c.0a038163.js";import"./c.c4dc5ba3.js";import"./c.74dbf101.js";import{s as g}from"./c.ecc9713e.js";import{u as b}from"./c.69bec4b9.js";import"./c.b85cccfb.js";import"./c.f41a074f.js";import"./c.c2b18de6.js";import"./c.9f27b448.js";import"./c.3dc7ab21.js";import"./c.e6514d94.js";import"./c.f1b17fae.js";import"./c.9a62bd84.js";import"./c.5c703026.js";import"./c.fb46b4a0.js";let f=t([u("hacs-download-dialog")],(function(t,o){return{F:class extends o{constructor(...o){super(...o),t(this)}},d:[{kind:"field",decorators:[s()],key:"repository",value:void 0},{kind:"field",decorators:[i()],key:"_toggle",value:()=>!0},{kind:"field",decorators:[i()],key:"_installing",value:()=>!1},{kind:"field",decorators:[i()],key:"_error",value:void 0},{kind:"field",decorators:[i()],key:"_repository",value:void 0},{kind:"field",decorators:[i()],key:"_downloadRepositoryData",value:()=>({beta:!1,version:""})},{kind:"method",key:"shouldUpdate",value:function(t){return t.forEach(((t,o)=>{"hass"===o&&(this.sidebarDocked='"docked"'===window.localStorage.getItem("dockedSidebar")),"repositories"===o&&(this._repository=this._getRepository(this.hacs.repositories,this.repository))})),t.has("sidebarDocked")||t.has("narrow")||t.has("active")||t.has("_toggle")||t.has("_error")||t.has("_repository")||t.has("_downloadRepositoryData")||t.has("_installing")}},{kind:"field",key:"_getRepository",value:()=>e(((t,o)=>null==t?void 0:t.find((t=>t.id===o))))},{kind:"field",key:"_getInstallPath",value:()=>e((t=>{let o=t.local_path;return"theme"===t.category&&(o=`${o}/${t.file_name}`),o}))},{kind:"method",key:"firstUpdated",value:async function(){var t,o;if(this._repository=this._getRepository(this.hacs.repositories,this.repository),null===(t=this._repository)||void 0===t||!t.updated_info){await a(this.hass,this._repository.id);const t=await r(this.hass);this.dispatchEvent(new CustomEvent("update-hacs",{detail:{repositories:t},bubbles:!0,composed:!0})),this._repository=this._getRepository(t,this.repository)}this._toggle=!1,this.hass.connection.subscribeEvents((t=>this._error=t.data),"hacs/error"),this._downloadRepositoryData.beta=this._repository.beta,this._downloadRepositoryData.version="version"===(null===(o=this._repository)||void 0===o?void 0:o.version_or_commit)?this._repository.releases[0]:""}},{kind:"method",key:"render",value:function(){var t;if(!this.active||!this._repository)return l``;const o=this._getInstallPath(this._repository),s=[{type:"boolean",name:"beta"},{type:"select",name:"version",optional:!0,options:"version"===this._repository.version_or_commit?this._repository.releases.map((t=>[t,t])).concat("hacs/integration"===this._repository.full_name||this._repository.hide_default_branch?[]:[[this._repository.default_branch,this._repository.default_branch]]):[]}];return l`
|
||||
<hacs-dialog
|
||||
.active=${this.active}
|
||||
.narrow=${this.narrow}
|
||||
.hass=${this.hass}
|
||||
.secondary=${this.secondary}
|
||||
.title=${this._repository.name}
|
||||
>
|
||||
<div class="content">
|
||||
${"version"===this._repository.version_or_commit?l`
|
||||
<ha-form
|
||||
.disabled=${this._toggle}
|
||||
?narrow=${this.narrow}
|
||||
.data=${this._downloadRepositoryData}
|
||||
.schema=${s}
|
||||
.computeLabel=${t=>"beta"===t.name?this.hacs.localize("dialog_download.show_beta"):this.hacs.localize("dialog_download.select_version")}
|
||||
@value-changed=${this._valueChanged}
|
||||
>
|
||||
</ha-form>
|
||||
`:""}
|
||||
${this._repository.can_install?"":l`<ha-alert alert-type="error" .rtl=${v(this.hass)}>
|
||||
${this.hacs.localize("confirm.home_assistant_version_not_correct",{haversion:this.hass.config.version,minversion:this._repository.homeassistant})}
|
||||
</ha-alert>`}
|
||||
<div class="note">
|
||||
${this.hacs.localize("dialog_download.note_downloaded",{location:l`<code>'${o}'</code>`})}
|
||||
${"plugin"===this._repository.category&&"storage"!==this.hacs.status.lovelace_mode?l`
|
||||
<p>${this.hacs.localize("dialog_download.lovelace_instruction")}</p>
|
||||
<pre>
|
||||
url: ${h({repository:this._repository,skipTag:!0})}
|
||||
type: module
|
||||
</pre
|
||||
>
|
||||
`:""}
|
||||
${"integration"===this._repository.category?l`<p>${this.hacs.localize("dialog_download.restart")}</p>`:""}
|
||||
</div>
|
||||
${null!==(t=this._error)&&void 0!==t&&t.message?l`<ha-alert alert-type="error" .rtl=${v(this.hass)}>
|
||||
${this._error.message}
|
||||
</ha-alert>`:""}
|
||||
</div>
|
||||
<mwc-button
|
||||
raised
|
||||
slot="primaryaction"
|
||||
?disabled=${!(this._repository.can_install&&!this._toggle&&"version"!==this._repository.version_or_commit)&&!this._downloadRepositoryData.version}
|
||||
@click=${this._installRepository}
|
||||
>
|
||||
${this._installing?l`<ha-circular-progress active size="small"></ha-circular-progress>`:this.hacs.localize("common.download")}
|
||||
</mwc-button>
|
||||
<hacs-link slot="secondaryaction" .url="https://github.com/${this._repository.full_name}">
|
||||
<mwc-button> ${this.hacs.localize("common.repository")} </mwc-button>
|
||||
</hacs-link>
|
||||
</hacs-dialog>
|
||||
`}},{kind:"method",key:"_valueChanged",value:async function(t){let o=!1;if(this._downloadRepositoryData.beta!==t.detail.value.beta&&(o=!0,this._toggle=!0,await n(this.hass,this.repository)),t.detail.value.version&&(o=!0,this._toggle=!0,await c(this.hass,this.repository,t.detail.value.version)),o){const t=await r(this.hass);this.dispatchEvent(new CustomEvent("update-hacs",{detail:{repositories:t},bubbles:!0,composed:!0})),this._repository=this._getRepository(t,this.repository),this._toggle=!1}this._downloadRepositoryData=t.detail.value}},{kind:"method",key:"_installRepository",value:async function(){var t;if(this._installing=!0,!this._repository)return;const o=this._downloadRepositoryData.version||this._repository.available_version||this._repository.default_branch;"commit"!==(null===(t=this._repository)||void 0===t?void 0:t.version_or_commit)?await d(this.hass,this._repository.id,o):await p(this.hass,this._repository.id),this.hacs.log.debug(this._repository.category,"_installRepository"),this.hacs.log.debug(this.hacs.status.lovelace_mode,"_installRepository"),"plugin"===this._repository.category&&"storage"===this.hacs.status.lovelace_mode&&await b(this.hass,this._repository,o),this._installing=!1,this.dispatchEvent(new Event("hacs-secondary-dialog-closed",{bubbles:!0,composed:!0})),this.dispatchEvent(new Event("hacs-dialog-closed",{bubbles:!0,composed:!0})),"plugin"===this._repository.category&&g(this,{title:this.hacs.localize("common.reload"),text:l`${this.hacs.localize("dialog.reload.description")}<br />${this.hacs.localize("dialog.reload.confirm")}`,dismissText:this.hacs.localize("common.cancel"),confirmText:this.hacs.localize("common.reload"),confirm:()=>{_.location.href=_.location.href}})}},{kind:"get",static:!0,key:"styles",value:function(){return[y,m`
|
||||
.note {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.lovelace {
|
||||
margin-top: 8px;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-line;
|
||||
user-select: all;
|
||||
}
|
||||
`]}}]}}),o);export{f as HacsDonwloadDialog};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.6e79c449.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.6e79c449.js.gz
Normal file
Binary file not shown.
23
custom_components/hacs/hacs_frontend/c.6f86bede.js
Normal file
23
custom_components/hacs/hacs_frontend/c.6f86bede.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.6f86bede.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.6f86bede.js.gz
Normal file
Binary file not shown.
1498
custom_components/hacs/hacs_frontend/c.74dbf101.js
Normal file
1498
custom_components/hacs/hacs_frontend/c.74dbf101.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.74dbf101.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.74dbf101.js.gz
Normal file
Binary file not shown.
176
custom_components/hacs/hacs_frontend/c.7ae69098.js
Normal file
176
custom_components/hacs/hacs_frontend/c.7ae69098.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.7ae69098.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.7ae69098.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.8b18e31f.js
Normal file
1
custom_components/hacs/hacs_frontend/c.8b18e31f.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.8b18e31f.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.8b18e31f.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.8d42c2c7.js
Normal file
1
custom_components/hacs/hacs_frontend/c.8d42c2c7.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.8d42c2c7.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.8d42c2c7.js.gz
Normal file
Binary file not shown.
2823
custom_components/hacs/hacs_frontend/c.928461f0.js
Normal file
2823
custom_components/hacs/hacs_frontend/c.928461f0.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.928461f0.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.928461f0.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.938c75c9.js
Normal file
1
custom_components/hacs/hacs_frontend/c.938c75c9.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.938c75c9.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.938c75c9.js.gz
Normal file
Binary file not shown.
86
custom_components/hacs/hacs_frontend/c.9a62bd84.js
Normal file
86
custom_components/hacs/hacs_frontend/c.9a62bd84.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.9a62bd84.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.9a62bd84.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.9f27b448.js
Normal file
1
custom_components/hacs/hacs_frontend/c.9f27b448.js
Normal file
@@ -0,0 +1 @@
|
||||
const r=r=>(s,o)=>{if(s.constructor._observers){if(!s.constructor.hasOwnProperty("_observers")){const r=s.constructor._observers;s.constructor._observers=new Map,r.forEach(((r,o)=>s.constructor._observers.set(o,r)))}}else{s.constructor._observers=new Map;const r=s.updated;s.updated=function(s){r.call(this,s),s.forEach(((r,s)=>{const o=this.constructor._observers.get(s);void 0!==o&&o.call(this,this[s],r)}))}}s.constructor._observers.set(o,r)};export{r as o};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.9f27b448.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.9f27b448.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.aa8feaf8.js
Normal file
1
custom_components/hacs/hacs_frontend/c.aa8feaf8.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.aa8feaf8.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.aa8feaf8.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.ac33c45a.js
Normal file
1
custom_components/hacs/hacs_frontend/c.ac33c45a.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.ac33c45a.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.ac33c45a.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.b3b88849.js
Normal file
1
custom_components/hacs/hacs_frontend/c.b3b88849.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.b3b88849.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.b3b88849.js.gz
Normal file
Binary file not shown.
7
custom_components/hacs/hacs_frontend/c.b85cccfb.js
Normal file
7
custom_components/hacs/hacs_frontend/c.b85cccfb.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import{a as t,f as e,e as r,$ as n,ad as i,ae as a,r as o,n as s}from"./main-f3e781b1.js";t([s("hacs-link")],(function(t,e){return{F:class extends e{constructor(...e){super(...e),t(this)}},d:[{kind:"field",decorators:[r({type:Boolean})],key:"newtab",value:()=>!1},{kind:"field",decorators:[r({type:Boolean})],key:"parent",value:()=>!1},{kind:"field",decorators:[r()],key:"title",value:()=>""},{kind:"field",decorators:[r()],key:"url",value:void 0},{kind:"method",key:"render",value:function(){return n`<span title=${this.title||this.url} @click=${this._open}><slot></slot></span>`}},{kind:"method",key:"_open",value:function(){var t;if(this.url.startsWith("/")&&!this.newtab)return void i(this.url,{replace:!0});const e=null===(t=this.url)||void 0===t?void 0:t.startsWith("http");let r="",n="_blank";e&&(r="noreferrer=true"),e||this.newtab||(n="_blank"),e||this.parent||(n="_parent"),a.open(this.url,n,r)}},{kind:"get",static:!0,key:"styles",value:function(){return o`
|
||||
span {
|
||||
cursor: pointer;
|
||||
color: var(--hcv-text-color-link);
|
||||
text-decoration: var(--hcv-text-decoration-link);
|
||||
}
|
||||
`}}]}}),e);
|
||||
BIN
custom_components/hacs/hacs_frontend/c.b85cccfb.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.b85cccfb.js.gz
Normal file
Binary file not shown.
14
custom_components/hacs/hacs_frontend/c.c00f6df2.js
Normal file
14
custom_components/hacs/hacs_frontend/c.c00f6df2.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import{a as i,H as t,e,$ as s,n as o}from"./main-f3e781b1.js";import"./c.f41a074f.js";import"./c.fb46b4a0.js";import"./c.9f27b448.js";import"./c.0a038163.js";let c=i([o("hacs-progress-dialog")],(function(i,t){return{F:class extends t{constructor(...t){super(...t),i(this)}},d:[{kind:"field",decorators:[e()],key:"title",value:void 0},{kind:"field",decorators:[e()],key:"content",value:void 0},{kind:"field",decorators:[e()],key:"confirmText",value:void 0},{kind:"field",decorators:[e()],key:"confirm",value:void 0},{kind:"field",decorators:[e({type:Boolean})],key:"_inProgress",value:()=>!1},{kind:"method",key:"shouldUpdate",value:function(i){return i.has("active")||i.has("title")||i.has("content")||i.has("confirmText")||i.has("confirm")||i.has("_inProgress")}},{kind:"method",key:"render",value:function(){return this.active?s`
|
||||
<hacs-dialog .active=${this.active} .hass=${this.hass} title=${this.title||""}>
|
||||
<div class="content">
|
||||
${this.content||""}
|
||||
</div>
|
||||
<mwc-button slot="secondaryaction" ?disabled=${this._inProgress} @click=${this._close}>
|
||||
${this.hacs.localize("common.cancel")}
|
||||
</mwc-button>
|
||||
<mwc-button slot="primaryaction" @click=${this._confirmed}>
|
||||
${this._inProgress?s`<ha-circular-progress active size="small"></ha-circular-progress>`:this.confirmText||this.hacs.localize("common.yes")}</mwc-button
|
||||
>
|
||||
</mwc-button>
|
||||
</hacs-dialog>
|
||||
`:s``}},{kind:"method",key:"_confirmed",value:async function(){this._inProgress=!0,await this.confirm(),this._inProgress=!1,this._close()}},{kind:"method",key:"_close",value:function(){this.active=!1,this.dispatchEvent(new Event("hacs-dialog-closed",{bubbles:!0,composed:!0}))}}]}}),t);export{c as HacsProgressDialog};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.c00f6df2.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.c00f6df2.js.gz
Normal file
Binary file not shown.
132
custom_components/hacs/hacs_frontend/c.c2b18de6.js
Normal file
132
custom_components/hacs/hacs_frontend/c.c2b18de6.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.c2b18de6.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.c2b18de6.js.gz
Normal file
Binary file not shown.
115
custom_components/hacs/hacs_frontend/c.c4dc5ba3.js
Normal file
115
custom_components/hacs/hacs_frontend/c.c4dc5ba3.js
Normal file
@@ -0,0 +1,115 @@
|
||||
import{a as e,f as t,e as i,$ as o,o as r,h as s,j as n,r as a,n as c,a0 as l,a1 as d,a2 as p,a3 as u}from"./main-f3e781b1.js";const y={info:l,warning:d,error:p,success:u};e([c("ha-alert")],(function(e,t){return{F:class extends t{constructor(...t){super(...t),e(this)}},d:[{kind:"field",decorators:[i()],key:"title",value:()=>""},{kind:"field",decorators:[i({attribute:"alert-type"})],key:"alertType",value:()=>"info"},{kind:"field",decorators:[i({type:Boolean})],key:"dismissable",value:()=>!1},{kind:"field",decorators:[i({type:Boolean})],key:"rtl",value:()=>!1},{kind:"method",key:"render",value:function(){return o`
|
||||
<div
|
||||
class="issue-type ${r({rtl:this.rtl,[this.alertType]:!0})}"
|
||||
role="alert"
|
||||
>
|
||||
<div class="icon ${this.title?"":"no-title"}">
|
||||
<slot name="icon">
|
||||
<ha-svg-icon .path=${y[this.alertType]}></ha-svg-icon>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="main-content">
|
||||
${this.title?o`<div class="title">${this.title}</div>`:""}
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div class="action">
|
||||
<slot name="action">
|
||||
${this.dismissable?o`<ha-icon-button
|
||||
@click=${this._dismiss_clicked}
|
||||
label="Dismiss alert"
|
||||
.path=${s}
|
||||
></ha-icon-button>`:""}
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`}},{kind:"method",key:"_dismiss_clicked",value:function(){n(this,"alert-dismissed-clicked")}},{kind:"field",static:!0,key:"styles",value:()=>a`
|
||||
.issue-type {
|
||||
position: relative;
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
margin: 4px 0;
|
||||
}
|
||||
.issue-type.rtl {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
.issue-type::after {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
opacity: 0.12;
|
||||
pointer-events: none;
|
||||
content: "";
|
||||
border-radius: 4px;
|
||||
}
|
||||
.icon {
|
||||
z-index: 1;
|
||||
}
|
||||
.icon.no-title {
|
||||
align-self: center;
|
||||
}
|
||||
.issue-type.rtl > .content {
|
||||
flex-direction: row-reverse;
|
||||
text-align: right;
|
||||
}
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
.action {
|
||||
z-index: 1;
|
||||
width: min-content;
|
||||
--mdc-theme-primary: var(--primary-text-color);
|
||||
}
|
||||
.main-content {
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
margin-left: 8px;
|
||||
margin-right: 0;
|
||||
}
|
||||
.issue-type.rtl > .content > .main-content {
|
||||
margin-left: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.title {
|
||||
margin-top: 2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.action mwc-button,
|
||||
.action ha-icon-button {
|
||||
--mdc-theme-primary: var(--primary-text-color);
|
||||
--mdc-icon-button-size: 36px;
|
||||
}
|
||||
.issue-type.info > .icon {
|
||||
color: var(--info-color);
|
||||
}
|
||||
.issue-type.info::after {
|
||||
background-color: var(--info-color);
|
||||
}
|
||||
|
||||
.issue-type.warning > .icon {
|
||||
color: var(--warning-color);
|
||||
}
|
||||
.issue-type.warning::after {
|
||||
background-color: var(--warning-color);
|
||||
}
|
||||
|
||||
.issue-type.error > .icon {
|
||||
color: var(--error-color);
|
||||
}
|
||||
.issue-type.error::after {
|
||||
background-color: var(--error-color);
|
||||
}
|
||||
|
||||
.issue-type.success > .icon {
|
||||
color: var(--success-color);
|
||||
}
|
||||
.issue-type.success::after {
|
||||
background-color: var(--success-color);
|
||||
}
|
||||
`}]}}),t);
|
||||
BIN
custom_components/hacs/hacs_frontend/c.c4dc5ba3.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.c4dc5ba3.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.c9bcea67.js
Normal file
1
custom_components/hacs/hacs_frontend/c.c9bcea67.js
Normal file
@@ -0,0 +1 @@
|
||||
const a=a=>`https://brands.home-assistant.io/${a.useFallback?"_/":""}${a.domain}/${a.darkOptimized?"dark_":""}${a.type}.png`,s=a=>a.split("/")[4];export{a as b,s as e};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.c9bcea67.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.c9bcea67.js.gz
Normal file
Binary file not shown.
180
custom_components/hacs/hacs_frontend/c.d3537c2e.js
Normal file
180
custom_components/hacs/hacs_frontend/c.d3537c2e.js
Normal file
@@ -0,0 +1,180 @@
|
||||
import{a as e,f as a,e as s,i,$ as t,at as o,o as n,j as r,r as l,n as c,H as d,m as h,P as p,Q as m,au as u,av as v,aj as g,ak as y,ae as f,s as _,d as x}from"./main-f3e781b1.js";import{a as b}from"./c.0a038163.js";import"./c.c4dc5ba3.js";import{n as k}from"./c.5c703026.js";import{s as $}from"./c.ecc9713e.js";import{m as w}from"./c.ac33c45a.js";import{u as z}from"./c.69bec4b9.js";import"./c.b85cccfb.js";import"./c.f41a074f.js";import"./c.3f18632e.js";import"./c.fb46b4a0.js";import"./c.9f27b448.js";e([c("ha-expansion-panel")],(function(e,a){return{F:class extends a{constructor(...a){super(...a),e(this)}},d:[{kind:"field",decorators:[s({type:Boolean,reflect:!0})],key:"expanded",value:()=>!1},{kind:"field",decorators:[s({type:Boolean,reflect:!0})],key:"outlined",value:()=>!1},{kind:"field",decorators:[s()],key:"header",value:void 0},{kind:"field",decorators:[s()],key:"secondary",value:void 0},{kind:"field",decorators:[i(".container")],key:"_container",value:void 0},{kind:"method",key:"render",value:function(){return t`
|
||||
<div class="summary" @click=${this._toggleContainer}>
|
||||
<slot class="header" name="header">
|
||||
${this.header}
|
||||
<slot class="secondary" name="secondary">${this.secondary}</slot>
|
||||
</slot>
|
||||
<ha-svg-icon
|
||||
.path=${o}
|
||||
class="summary-icon ${n({expanded:this.expanded})}"
|
||||
></ha-svg-icon>
|
||||
</div>
|
||||
<div
|
||||
class="container ${n({expanded:this.expanded})}"
|
||||
@transitionend=${this._handleTransitionEnd}
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
`}},{kind:"method",key:"_handleTransitionEnd",value:function(){this._container.style.removeProperty("height")}},{kind:"method",key:"_toggleContainer",value:async function(){const e=!this.expanded;r(this,"expanded-will-change",{expanded:e}),e&&await k();const a=this._container.scrollHeight;this._container.style.height=`${a}px`,e||setTimeout((()=>{this._container.style.height="0px"}),0),this.expanded=e,r(this,"expanded-changed",{expanded:this.expanded})}},{kind:"get",static:!0,key:"styles",value:function(){return l`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
:host([outlined]) {
|
||||
box-shadow: none;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: var(
|
||||
--ha-card-border-color,
|
||||
var(--divider-color, #e0e0e0)
|
||||
);
|
||||
border-radius: var(--ha-card-border-radius, 4px);
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.summary {
|
||||
display: flex;
|
||||
padding: var(--expansion-panel-summary-padding, 0);
|
||||
min-height: 48px;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.summary-icon {
|
||||
transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.summary-icon.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.container {
|
||||
overflow: hidden;
|
||||
transition: height 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.container.expanded {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
display: block;
|
||||
color: var(--secondary-text-color);
|
||||
font-size: 12px;
|
||||
}
|
||||
`}}]}}),a);let j=e([c("hacs-update-dialog")],(function(e,a){class i extends a{constructor(...a){super(...a),e(this)}}return{F:i,d:[{kind:"field",decorators:[s()],key:"repository",value:void 0},{kind:"field",decorators:[s({type:Boolean})],key:"_updating",value:()=>!1},{kind:"field",decorators:[s()],key:"_error",value:void 0},{kind:"field",decorators:[s({attribute:!1})],key:"_releaseNotes",value:()=>[]},{kind:"field",key:"_getRepository",value:()=>h(((e,a)=>e.find((e=>e.id===a))))},{kind:"method",key:"firstUpdated",value:async function(e){p(m(i.prototype),"firstUpdated",this).call(this,e);const a=this._getRepository(this.hacs.repositories,this.repository);a&&("commit"!==a.version_or_commit&&(this._releaseNotes=await u(this.hass,a.id),this._releaseNotes=this._releaseNotes.filter((e=>e.tag>a.installed_version))),this.hass.connection.subscribeEvents((e=>this._error=e.data),"hacs/error"))}},{kind:"method",key:"render",value:function(){var e;if(!this.active)return t``;const a=this._getRepository(this.hacs.repositories,this.repository);return a?t`
|
||||
<hacs-dialog
|
||||
.active=${this.active}
|
||||
.title=${this.hacs.localize("dialog_update.title")}
|
||||
.hass=${this.hass}
|
||||
>
|
||||
<div class=${n({content:!0,narrow:this.narrow})}>
|
||||
<p class="message">
|
||||
${this.hacs.localize("dialog_update.message",{name:a.name})}
|
||||
</p>
|
||||
<div class="version-container">
|
||||
<div class="version-element">
|
||||
<span class="version-number">${a.installed_version}</span>
|
||||
<small class="version-text">${this.hacs.localize("dialog_update.downloaded_version")}</small>
|
||||
</div>
|
||||
|
||||
<span class="version-separator">
|
||||
<ha-svg-icon
|
||||
.path=${v}
|
||||
></ha-svg-icon>
|
||||
</span>
|
||||
|
||||
<div class="version-element">
|
||||
<span class="version-number">${a.available_version}</span>
|
||||
<small class="version-text">${this.hacs.localize("dialog_update.available_version")}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${this._releaseNotes.length>0?this._releaseNotes.map((e=>t`
|
||||
<ha-expansion-panel
|
||||
.header=${e.name&&e.name!==e.tag?`${e.tag}: ${e.name}`:e.tag}
|
||||
outlined
|
||||
?expanded=${1===this._releaseNotes.length}
|
||||
>
|
||||
${e.body?w.html(e.body,a):this.hacs.localize("dialog_update.no_info")}
|
||||
</ha-expansion-panel>
|
||||
`)):""}
|
||||
${a.can_install?"":t`<ha-alert alert-type="error" .rtl=${b(this.hass)}>
|
||||
${this.hacs.localize("confirm.home_assistant_version_not_correct",{haversion:this.hass.config.version,minversion:a.homeassistant})}
|
||||
</ha-alert>`}
|
||||
${"integration"===a.category?t`<p>${this.hacs.localize("dialog_download.restart")}</p>`:""}
|
||||
${null!==(e=this._error)&&void 0!==e&&e.message?t`<ha-alert alert-type="error" .rtl=${b(this.hass)}>
|
||||
${this._error.message}
|
||||
</ha-alert>`:""}
|
||||
</div>
|
||||
<mwc-button
|
||||
slot="primaryaction"
|
||||
?disabled=${!a.can_install}
|
||||
@click=${this._updateRepository}
|
||||
raised
|
||||
>
|
||||
${this._updating?t`<ha-circular-progress active size="small"></ha-circular-progress>`:this.hacs.localize("common.update")}
|
||||
</mwc-button
|
||||
>
|
||||
<div class="secondary" slot="secondaryaction">
|
||||
<hacs-link .url=${this._getChanglogURL()||""}>
|
||||
<mwc-button>${this.hacs.localize("dialog_update.changelog")}
|
||||
</mwc-button>
|
||||
</hacs-link>
|
||||
<hacs-link .url="https://github.com/${a.full_name}">
|
||||
<mwc-button>${this.hacs.localize("common.repository")}
|
||||
</mwc-button>
|
||||
</hacs-link>
|
||||
</div>
|
||||
</hacs-dialog>
|
||||
`:t``}},{kind:"method",key:"_updateRepository",value:async function(){this._updating=!0;const e=this._getRepository(this.hacs.repositories,this.repository);e&&("commit"!==e.version_or_commit?await g(this.hass,e.id,e.available_version):await y(this.hass,e.id),"plugin"===e.category&&"storage"===this.hacs.status.lovelace_mode&&await z(this.hass,e,e.available_version),this._updating=!1,this.dispatchEvent(new Event("hacs-dialog-closed",{bubbles:!0,composed:!0})),"plugin"===e.category&&$(this,{title:this.hacs.localize("common.reload"),text:t`${this.hacs.localize("dialog.reload.description")}<br />${this.hacs.localize("dialog.reload.confirm")}`,dismissText:this.hacs.localize("common.cancel"),confirmText:this.hacs.localize("common.reload"),confirm:()=>{f.location.href=f.location.href}}))}},{kind:"method",key:"_getChanglogURL",value:function(){const e=this._getRepository(this.hacs.repositories,this.repository);if(e)return"commit"===e.version_or_commit?`https://github.com/${e.full_name}/compare/${e.installed_version}...${e.available_version}`:`https://github.com/${e.full_name}/releases`}},{kind:"get",static:!0,key:"styles",value:function(){return[_,x,l`
|
||||
.content {
|
||||
width: 360px;
|
||||
display: contents;
|
||||
}
|
||||
ha-expansion-panel {
|
||||
margin: 8px 0;
|
||||
}
|
||||
ha-expansion-panel[expanded] {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
display: flex;
|
||||
}
|
||||
.message {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
.version-container {
|
||||
margin: 24px 0 12px 0;
|
||||
width: 360px;
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.version-element {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding: 0 12px;
|
||||
text-align: center;
|
||||
}
|
||||
.version-text {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.version-number {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
`]}}]}}),d);export{j as HacsUpdateDialog};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.d3537c2e.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.d3537c2e.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.d65945e9.js
Normal file
1
custom_components/hacs/hacs_frontend/c.d65945e9.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.d65945e9.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.d65945e9.js.gz
Normal file
Binary file not shown.
30
custom_components/hacs/hacs_frontend/c.d6f61db0.js
Normal file
30
custom_components/hacs/hacs_frontend/c.d6f61db0.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import{a as i,H as s,e as t,$ as e,d as a,r as o,ap as r,aq as l,am as n,ar as c,as as h,n as d}from"./main-f3e781b1.js";import"./c.f41a074f.js";import"./c.fb46b4a0.js";import"./c.9f27b448.js";import"./c.0a038163.js";let u=i([d("hacs-removed-dialog")],(function(i,s){return{F:class extends s{constructor(...s){super(...s),i(this)}},d:[{kind:"field",decorators:[t({attribute:!1})],key:"repository",value:void 0},{kind:"field",decorators:[t({type:Boolean})],key:"_updating",value:()=>!1},{kind:"method",key:"render",value:function(){if(!this.active)return e``;const i=this.hacs.removed.find((i=>i.repository===this.repository.full_name));return e`
|
||||
<hacs-dialog
|
||||
.active=${this.active}
|
||||
.hass=${this.hass}
|
||||
.title=${this.hacs.localize("entry.messages.removed_repository",{repository:this.repository.full_name})}
|
||||
>
|
||||
<div class="content">
|
||||
<div><b>${this.hacs.localize("dialog_removed.name")}:</b> ${this.repository.name}</div>
|
||||
${i.removal_type?e` <div>
|
||||
<b>${this.hacs.localize("dialog_removed.type")}:</b> ${i.removal_type}
|
||||
</div>`:""}
|
||||
${i.reason?e` <div>
|
||||
<b>${this.hacs.localize("dialog_removed.reason")}:</b> ${i.reason}
|
||||
</div>`:""}
|
||||
${i.link?e` <div>
|
||||
</b><hacs-link .url=${i.link}>${this.hacs.localize("dialog_removed.link")}</hacs-link>
|
||||
</div>`:""}
|
||||
</div>
|
||||
<mwc-button slot="secondaryaction" @click=${this._ignoreRepository}>
|
||||
${this.hacs.localize("common.ignore")}
|
||||
</mwc-button>
|
||||
<mwc-button class="uninstall" slot="primaryaction" @click=${this._uninstallRepository}
|
||||
>${this._updating?e`<ha-circular-progress active size="small"></ha-circular-progress>`:this.hacs.localize("common.remove")}</mwc-button
|
||||
>
|
||||
</hacs-dialog>
|
||||
`}},{kind:"get",static:!0,key:"styles",value:function(){return[a,o`
|
||||
.uninstall {
|
||||
--mdc-theme-primary: var(--hcv-color-error);
|
||||
}
|
||||
`]}},{kind:"method",key:"_lovelaceUrl",value:function(){var i,s;return`/hacsfiles/${null===(i=this.repository)||void 0===i?void 0:i.full_name.split("/")[1]}/${null===(s=this.repository)||void 0===s?void 0:s.file_name}`}},{kind:"method",key:"_ignoreRepository",value:async function(){await r(this.hass,this.repository.full_name);const i=await l(this.hass);this.dispatchEvent(new CustomEvent("update-hacs",{detail:{removed:i},bubbles:!0,composed:!0})),this.dispatchEvent(new Event("hacs-dialog-closed",{bubbles:!0,composed:!0}))}},{kind:"method",key:"_uninstallRepository",value:async function(){if(this._updating=!0,"plugin"===this.repository.category&&this.hacs.status&&"yaml"!==this.hacs.status.lovelace_mode){(await n(this.hass)).filter((i=>i.url===this._lovelaceUrl())).forEach((i=>{c(this.hass,String(i.id))}))}await h(this.hass,this.repository.id),this._updating=!1,this.active=!1}}]}}),s);export{u as HacsRemovedDialog};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.d6f61db0.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.d6f61db0.js.gz
Normal file
Binary file not shown.
82
custom_components/hacs/hacs_frontend/c.dee01337.js
Normal file
82
custom_components/hacs/hacs_frontend/c.dee01337.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import{a as e,f as i,e as t,i as a,$ as n,g as l,h as o,j as s,r as c,n as r,m as d,d as u}from"./main-f3e781b1.js";import"./c.3dc7ab21.js";import"./c.c2b18de6.js";e([r("search-input")],(function(e,i){return{F:class extends i{constructor(...i){super(...i),e(this)}},d:[{kind:"field",decorators:[t({attribute:!1})],key:"hass",value:void 0},{kind:"field",decorators:[t()],key:"filter",value:void 0},{kind:"field",decorators:[t({type:Boolean})],key:"suffix",value:()=>!1},{kind:"field",decorators:[t({type:Boolean})],key:"autofocus",value:()=>!1},{kind:"field",decorators:[t({type:String})],key:"label",value:void 0},{kind:"method",key:"focus",value:function(){var e;null===(e=this._input)||void 0===e||e.focus()}},{kind:"field",decorators:[a("ha-textfield",!0)],key:"_input",value:void 0},{kind:"method",key:"render",value:function(){return n`
|
||||
<ha-textfield
|
||||
.autofocus=${this.autofocus}
|
||||
.label=${this.label||"Search"}
|
||||
.value=${this.filter||""}
|
||||
.icon=${!0}
|
||||
.iconTrailing=${this.filter||this.suffix}
|
||||
@input=${this._filterInputChanged}
|
||||
>
|
||||
<slot name="prefix" slot="leadingIcon">
|
||||
<ha-svg-icon
|
||||
tabindex="-1"
|
||||
class="prefix"
|
||||
.path=${l}
|
||||
></ha-svg-icon>
|
||||
</slot>
|
||||
<div class="trailing" slot="trailingIcon">
|
||||
${this.filter&&n`
|
||||
<ha-icon-button
|
||||
@click=${this._clearSearch}
|
||||
.label=${this.hass.localize("ui.common.clear")}
|
||||
.path=${o}
|
||||
class="clear-button"
|
||||
></ha-icon-button>
|
||||
`}
|
||||
<slot name="suffix"></slot>
|
||||
</div>
|
||||
</ha-textfield>
|
||||
`}},{kind:"method",key:"_filterChanged",value:async function(e){s(this,"value-changed",{value:String(e)})}},{kind:"method",key:"_filterInputChanged",value:async function(e){this._filterChanged(e.target.value)}},{kind:"method",key:"_clearSearch",value:async function(){this._filterChanged("")}},{kind:"get",static:!0,key:"styles",value:function(){return c`
|
||||
:host {
|
||||
display: inline-flex;
|
||||
}
|
||||
ha-svg-icon,
|
||||
ha-icon-button {
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
ha-svg-icon {
|
||||
outline: none;
|
||||
}
|
||||
.clear-button {
|
||||
--mdc-icon-size: 20px;
|
||||
}
|
||||
ha-textfield {
|
||||
display: inherit;
|
||||
}
|
||||
.trailing {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
`}}]}}),i);const h=d(((e,i)=>e.filter((e=>f(e.name).includes(f(i))||f(e.description).includes(f(i))||f(e.category).includes(f(i))||f(e.full_name).includes(f(i))||f(e.authors).includes(f(i))||f(e.domain).includes(f(i)))))),f=d((e=>String(e||"").toLocaleLowerCase().replace(/-|_| /g,"")));e([r("hacs-filter")],(function(e,i){return{F:class extends i{constructor(...i){super(...i),e(this)}},d:[{kind:"field",decorators:[t({attribute:!1})],key:"filters",value:void 0},{kind:"field",decorators:[t({attribute:!1})],key:"hacs",value:void 0},{kind:"method",key:"render",value:function(){var e;return n`
|
||||
<div class="filter">
|
||||
${null===(e=this.filters)||void 0===e?void 0:e.map((e=>n`
|
||||
<ha-formfield
|
||||
class="checkbox"
|
||||
.label=${this.hacs.localize(`common.${e.id}`)||e.value}
|
||||
>
|
||||
<ha-checkbox
|
||||
.checked=${e.checked||!1}
|
||||
.id=${e.id}
|
||||
@click=${this._filterClick}
|
||||
>
|
||||
</ha-checkbox>
|
||||
</ha-formfield>
|
||||
`))}
|
||||
</div>
|
||||
`}},{kind:"method",key:"_filterClick",value:function(e){const i=e.currentTarget;this.dispatchEvent(new CustomEvent("filter-change",{detail:{id:i.id},bubbles:!0,composed:!0}))}},{kind:"get",static:!0,key:"styles",value:function(){return[u,c`
|
||||
.filter {
|
||||
display: flex;
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
height: 32px;
|
||||
line-height: 4px;
|
||||
background-color: var(--sidebar-background-color);
|
||||
padding: 0 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.checkbox:not(:first-child) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
`]}}]}}),i);export{h as f};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.dee01337.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.dee01337.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.e6514d94.js
Normal file
1
custom_components/hacs/hacs_frontend/c.e6514d94.js
Normal file
File diff suppressed because one or more lines are too long
BIN
custom_components/hacs/hacs_frontend/c.e6514d94.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.e6514d94.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.eb6f9145.js
Normal file
1
custom_components/hacs/hacs_frontend/c.eb6f9145.js
Normal file
@@ -0,0 +1 @@
|
||||
Intl.PluralRules&&"function"==typeof Intl.PluralRules.__addLocaleData&&Intl.PluralRules.__addLocaleData({data:{categories:{cardinal:["one","other"],ordinal:["one","two","few","other"]},fn:function(e,l){var a=String(e).split("."),t=!a[1],o=Number(a[0])==e,n=o&&a[0].slice(-1),r=o&&a[0].slice(-2);return l?1==n&&11!=r?"one":2==n&&12!=r?"two":3==n&&13!=r?"few":"other":1==e&&t?"one":"other"}},locale:"en"});
|
||||
BIN
custom_components/hacs/hacs_frontend/c.eb6f9145.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.eb6f9145.js.gz
Normal file
Binary file not shown.
1
custom_components/hacs/hacs_frontend/c.ecc9713e.js
Normal file
1
custom_components/hacs/hacs_frontend/c.ecc9713e.js
Normal file
@@ -0,0 +1 @@
|
||||
import{j as o}from"./main-f3e781b1.js";const a=()=>import("./c.02169b19.js"),i=(i,l,m)=>new Promise((n=>{const r=l.cancel,s=l.confirm;o(i,"show-dialog",{dialogTag:"dialog-box",dialogImport:a,dialogParams:{...l,...m,cancel:()=>{n(!(null==m||!m.prompt)&&null),r&&r()},confirm:o=>{n(null==m||!m.prompt||o),s&&s(o)}}})})),l=(o,a)=>i(o,a),m=(o,a)=>i(o,a,{confirmation:!0}),n=(o,a)=>i(o,a,{prompt:!0});export{l as a,n as b,m as s};
|
||||
BIN
custom_components/hacs/hacs_frontend/c.ecc9713e.js.gz
Normal file
BIN
custom_components/hacs/hacs_frontend/c.ecc9713e.js.gz
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user