Add HACS, Themes
This commit is contained in:
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.
167
custom_components/hacs/hacs_frontend/c.ecfeb892.js
Normal file
167
custom_components/hacs/hacs_frontend/c.ecfeb892.js
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user