forked from mirrors/thatmattlove-hyperglass
Move UI Params into Pydantic model
This commit is contained in:
parent
281895e259
commit
99c7489441
13 changed files with 240 additions and 153 deletions
|
|
@ -18,6 +18,7 @@ from starlette.middleware.cors import CORSMiddleware
|
|||
from hyperglass.log import log
|
||||
from hyperglass.util import cpu_count
|
||||
from hyperglass.constants import TRANSPORT_REST, __version__
|
||||
from hyperglass.models.ui import UIParameters
|
||||
from hyperglass.api.events import on_startup, on_shutdown
|
||||
from hyperglass.api.routes import (
|
||||
docs,
|
||||
|
|
@ -25,8 +26,8 @@ from hyperglass.api.routes import (
|
|||
query,
|
||||
queries,
|
||||
routers,
|
||||
communities,
|
||||
ui_props,
|
||||
communities,
|
||||
import_certificate,
|
||||
)
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
|
|
@ -246,6 +247,8 @@ app.add_api_route(
|
|||
endpoint=ui_props,
|
||||
methods=["GET", "OPTIONS"],
|
||||
response_class=JSONResponse,
|
||||
response_model=UIParameters,
|
||||
response_model_by_alias=True,
|
||||
)
|
||||
|
||||
# Enable certificate import route only if a device using
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ from hyperglass.api.tasks import process_headers, import_public_key
|
|||
from hyperglass.constants import __version__
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
from hyperglass.models.api import Query, EncodedRequest
|
||||
from hyperglass.configuration import REDIS_CONFIG, params, devices, frontend_params
|
||||
from hyperglass.configuration import REDIS_CONFIG, params, devices, ui_params
|
||||
from hyperglass.execution.main import execute
|
||||
|
||||
# Local
|
||||
|
|
@ -266,7 +266,7 @@ async def info():
|
|||
|
||||
async def ui_props():
|
||||
"""Serve UI configration."""
|
||||
return frontend_params
|
||||
return ui_params
|
||||
|
||||
|
||||
endpoints = [query, docs, routers, info, ui_props]
|
||||
|
|
|
|||
|
|
@ -10,5 +10,17 @@ from .main import (
|
|||
params,
|
||||
devices,
|
||||
commands,
|
||||
frontend_params,
|
||||
ui_params,
|
||||
)
|
||||
|
||||
__all__ = (
|
||||
"URL_DEV",
|
||||
"URL_PROD",
|
||||
"CONFIG_PATH",
|
||||
"STATIC_PATH",
|
||||
"REDIS_CONFIG",
|
||||
"params",
|
||||
"devices",
|
||||
"commands",
|
||||
"ui_params",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
# Standard Library
|
||||
import os
|
||||
import json
|
||||
from typing import Dict, List, Generator
|
||||
from pathlib import Path
|
||||
|
||||
|
|
@ -20,6 +19,7 @@ from hyperglass.log import (
|
|||
from hyperglass.util import set_app_path, set_cache_env, current_log_level
|
||||
from hyperglass.defaults import CREDIT
|
||||
from hyperglass.constants import PARSED_RESPONSE_FIELDS, __version__
|
||||
from hyperglass.models.ui import UIParameters
|
||||
from hyperglass.util.files import check_path
|
||||
from hyperglass.exceptions.private import ConfigError, ConfigMissing
|
||||
from hyperglass.models.config.params import Params
|
||||
|
|
@ -204,35 +204,6 @@ except KeyError:
|
|||
pass
|
||||
|
||||
|
||||
def _build_networks() -> List[Dict]:
|
||||
"""Build filtered JSON Structure of networks & devices for Jinja templates."""
|
||||
networks = []
|
||||
_networks = list(set({device.network.display_name for device in devices.objects}))
|
||||
|
||||
for _network in _networks:
|
||||
network_def = {"display_name": _network, "locations": []}
|
||||
for device in devices.objects:
|
||||
if device.network.display_name == _network:
|
||||
network_def["locations"].append(
|
||||
{
|
||||
"_id": device._id,
|
||||
"name": device.name,
|
||||
"network": device.network.display_name,
|
||||
"directives": [c.frontend(params) for c in device.commands],
|
||||
}
|
||||
)
|
||||
networks.append(network_def)
|
||||
|
||||
if not networks:
|
||||
raise ConfigError(message="Unable to build network to device mapping")
|
||||
return networks
|
||||
|
||||
|
||||
content_params = json.loads(
|
||||
params.json(include={"primary_asn", "org_name", "site_title", "site_description"})
|
||||
)
|
||||
|
||||
|
||||
content_greeting = get_markdown(
|
||||
config_path=params.web.greeting,
|
||||
default="",
|
||||
|
|
@ -242,38 +213,17 @@ content_greeting = get_markdown(
|
|||
|
||||
content_credit = CREDIT.format(version=__version__)
|
||||
|
||||
networks = _build_networks()
|
||||
_ui_params = params.frontend()
|
||||
_ui_params["web"]["logo"]["light_format"] = params.web.logo.light.suffix
|
||||
_ui_params["web"]["logo"]["dark_format"] = params.web.logo.dark.suffix
|
||||
|
||||
_include_fields = {
|
||||
"cache": {"show_text", "timeout"},
|
||||
"debug": ...,
|
||||
"developer_mode": ...,
|
||||
"primary_asn": ...,
|
||||
"request_timeout": ...,
|
||||
"org_name": ...,
|
||||
"google_analytics": ...,
|
||||
"site_title": ...,
|
||||
"site_description": ...,
|
||||
"site_keywords": ...,
|
||||
"web": ...,
|
||||
"messages": ...,
|
||||
}
|
||||
_frontend_params = params.dict(include=_include_fields)
|
||||
|
||||
|
||||
_frontend_params["web"]["logo"]["light_format"] = params.web.logo.light.suffix
|
||||
_frontend_params["web"]["logo"]["dark_format"] = params.web.logo.dark.suffix
|
||||
|
||||
_frontend_params.update(
|
||||
{
|
||||
"hyperglass_version": __version__,
|
||||
"queries": {**params.queries.map, "list": params.queries.list},
|
||||
"networks": networks,
|
||||
"parsed_data_fields": PARSED_RESPONSE_FIELDS,
|
||||
"content": {"credit": content_credit, "greeting": content_greeting},
|
||||
}
|
||||
ui_params = UIParameters(
|
||||
**_ui_params,
|
||||
version=__version__,
|
||||
networks=devices.networks(params),
|
||||
parsed_data_fields=PARSED_RESPONSE_FIELDS,
|
||||
content={"credit": content_credit, "greeting": content_greeting},
|
||||
)
|
||||
frontend_params = _frontend_params
|
||||
|
||||
URL_DEV = f"http://localhost:{str(params.listen_port)}/"
|
||||
URL_PROD = "/api/"
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ from .configuration import (
|
|||
CONFIG_PATH,
|
||||
REDIS_CONFIG,
|
||||
params,
|
||||
frontend_params,
|
||||
ui_params,
|
||||
)
|
||||
from .util.frontend import build_frontend
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ async def build_ui() -> bool:
|
|||
dev_mode=params.developer_mode,
|
||||
dev_url=URL_DEV,
|
||||
prod_url=URL_PROD,
|
||||
params=frontend_params,
|
||||
params=ui_params,
|
||||
app_path=CONFIG_PATH,
|
||||
)
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
# Standard Library
|
||||
import re
|
||||
import json
|
||||
from typing import Dict, List, Union, Literal, Optional
|
||||
from ipaddress import IPv4Network, IPv6Network, ip_network
|
||||
|
||||
|
|
@ -267,20 +266,10 @@ class Directive(HyperglassModel):
|
|||
}
|
||||
|
||||
if self.info is not None:
|
||||
content_params = json.loads(
|
||||
params.json(
|
||||
include={
|
||||
"primary_asn",
|
||||
"org_name",
|
||||
"site_title",
|
||||
"site_description",
|
||||
}
|
||||
)
|
||||
)
|
||||
with self.info.open() as md:
|
||||
value["info"] = {
|
||||
"enable": True,
|
||||
"params": content_params,
|
||||
"params": params.content_params(),
|
||||
"content": md.read(),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,15 +10,20 @@ from pydantic import SecretStr, StrictInt, StrictStr, StrictBool, IPvAnyAddress
|
|||
from ..main import HyperglassModel
|
||||
|
||||
|
||||
class Cache(HyperglassModel):
|
||||
class CachePublic(HyperglassModel):
|
||||
"""Public cache parameters."""
|
||||
|
||||
timeout: StrictInt = 120
|
||||
show_text: StrictBool = True
|
||||
|
||||
|
||||
class Cache(CachePublic):
|
||||
"""Validation model for params.cache."""
|
||||
|
||||
host: Union[IPvAnyAddress, StrictStr] = "localhost"
|
||||
port: StrictInt = 6379
|
||||
database: StrictInt = 1
|
||||
password: Optional[SecretStr]
|
||||
timeout: StrictInt = 120
|
||||
show_text: StrictBool = True
|
||||
|
||||
class Config:
|
||||
"""Pydantic model configuration."""
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ from hyperglass.models.commands.generic import Directive
|
|||
from .ssl import Ssl
|
||||
from ..main import HyperglassModel, HyperglassModelExtra
|
||||
from .proxy import Proxy
|
||||
from .params import Params
|
||||
from ..fields import SupportedDriver
|
||||
from .network import Network
|
||||
from .credential import Credential
|
||||
|
|
@ -274,3 +275,23 @@ class Devices(HyperglassModelExtra):
|
|||
return device
|
||||
|
||||
raise AttributeError(f"No device named '{accessor}'")
|
||||
|
||||
def networks(self, params: Params) -> List[Dict[str, Any]]:
|
||||
"""Group devices by network."""
|
||||
names = {device.network.display_name for device in self.objects}
|
||||
return [
|
||||
{
|
||||
"display_name": name,
|
||||
"locations": [
|
||||
{
|
||||
"id": device._id,
|
||||
"name": device.name,
|
||||
"network": device.network.display_name,
|
||||
"directives": [c.frontend(params) for c in device.commands],
|
||||
}
|
||||
for device in self.objects
|
||||
if device.network.display_name in names
|
||||
],
|
||||
}
|
||||
for name in names
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,19 +1,11 @@
|
|||
"""Configuration validation entry point."""
|
||||
|
||||
# Standard Library
|
||||
from typing import List, Union, Optional
|
||||
from typing import Any, Dict, List, Union, Literal, Optional
|
||||
from ipaddress import ip_address
|
||||
|
||||
# Third Party
|
||||
from pydantic import (
|
||||
Field,
|
||||
StrictInt,
|
||||
StrictStr,
|
||||
StrictBool,
|
||||
IPvAnyAddress,
|
||||
constr,
|
||||
validator,
|
||||
)
|
||||
from pydantic import Field, StrictInt, StrictStr, StrictBool, IPvAnyAddress, validator
|
||||
|
||||
# Local
|
||||
from .web import Web
|
||||
|
|
@ -26,13 +18,12 @@ from .queries import Queries
|
|||
from .messages import Messages
|
||||
from .structured import Structured
|
||||
|
||||
Localhost = constr(regex=r"localhost")
|
||||
Localhost = Literal["localhost"]
|
||||
|
||||
|
||||
class Params(HyperglassModel):
|
||||
"""Validation model for all configuration variables."""
|
||||
class ParamsPublic(HyperglassModel):
|
||||
"""Public configuration parameters."""
|
||||
|
||||
# Top Level Params
|
||||
debug: StrictBool = Field(
|
||||
False,
|
||||
title="Debug",
|
||||
|
|
@ -43,10 +34,10 @@ class Params(HyperglassModel):
|
|||
title="Developer Mode",
|
||||
description='Enable developer mode. If enabled, the hyperglass backend (Python) and frontend (React/Javascript) applications are "unlinked", so that React tools can be used for front end development. A `<Debugger />` convenience component is also displayed in the UI for easier UI development.',
|
||||
)
|
||||
fake_output: StrictBool = Field(
|
||||
False,
|
||||
title="Fake Output",
|
||||
description="If enabled, the hyperglass backend will return static fake output for development/testing purposes.",
|
||||
request_timeout: StrictInt = Field(
|
||||
90,
|
||||
title="Request Timeout",
|
||||
description="Global timeout in seconds for all requests. The frontend application (UI) uses this field's exact value when submitting queries. The backend application uses this field's value, minus one second, for its own timeout handling. This is to ensure a contextual timeout error is presented to the end user in the event of a backend application timeout.",
|
||||
)
|
||||
primary_asn: Union[StrictInt, StrictStr] = Field(
|
||||
"65001",
|
||||
|
|
@ -58,6 +49,7 @@ class Params(HyperglassModel):
|
|||
title="Organization Name",
|
||||
description="Your organization's name. This field is used in the UI & API documentation to set fields such as `<meta/>` HTML tags for SEO and the terms & conditions footer component.",
|
||||
)
|
||||
google_analytics: Optional[StrictStr]
|
||||
site_title: StrictStr = Field(
|
||||
"hyperglass",
|
||||
title="Site Title",
|
||||
|
|
@ -90,10 +82,17 @@ class Params(HyperglassModel):
|
|||
title="Site Keywords",
|
||||
description='Keywords pertaining to your hyperglass site. This field is used to generate `<meta name="keywords"/>` HTML tags, which helps tremendously with SEO.',
|
||||
)
|
||||
request_timeout: StrictInt = Field(
|
||||
90,
|
||||
title="Request Timeout",
|
||||
description="Global timeout in seconds for all requests. The frontend application (UI) uses this field's exact value when submitting queries. The backend application uses this field's value, minus one second, for its own timeout handling. This is to ensure a contextual timeout error is presented to the end user in the event of a backend application timeout.",
|
||||
|
||||
|
||||
class Params(ParamsPublic, HyperglassModel):
|
||||
"""Validation model for all configuration variables."""
|
||||
|
||||
# Top Level Params
|
||||
|
||||
fake_output: StrictBool = Field(
|
||||
False,
|
||||
title="Fake Output",
|
||||
description="If enabled, the hyperglass backend will return static fake output for development/testing purposes.",
|
||||
)
|
||||
listen_address: Optional[Union[IPvAnyAddress, Localhost]] = Field(
|
||||
None,
|
||||
|
|
@ -115,7 +114,6 @@ class Params(HyperglassModel):
|
|||
title="Netmiko Delay Factor",
|
||||
description="Override the netmiko global delay factor.",
|
||||
)
|
||||
google_analytics: Optional[StrictStr]
|
||||
|
||||
# Sub Level Params
|
||||
cache: Cache = Cache()
|
||||
|
|
@ -183,3 +181,29 @@ class Params(HyperglassModel):
|
|||
if not isinstance(value, str):
|
||||
value = str(value)
|
||||
return value
|
||||
|
||||
def content_params(self) -> Dict[str, Any]:
|
||||
"""Export content-specific parameters."""
|
||||
return self.dict(
|
||||
include={"primary_asn", "org_name", "site_title", "site_description"}
|
||||
)
|
||||
|
||||
def frontend(self) -> Dict[str, Any]:
|
||||
"""Export UI-specific parameters."""
|
||||
|
||||
return self.dict(
|
||||
include={
|
||||
"cache": {"show_text", "timeout"},
|
||||
"debug": ...,
|
||||
"developer_mode": ...,
|
||||
"primary_asn": ...,
|
||||
"request_timeout": ...,
|
||||
"org_name": ...,
|
||||
"google_analytics": ...,
|
||||
"site_title": ...,
|
||||
"site_description": ...,
|
||||
"site_keywords": ...,
|
||||
"web": ...,
|
||||
"messages": ...,
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -125,6 +125,13 @@ class Logo(HyperglassModel):
|
|||
height: Optional[Union[StrictInt, Percentage]]
|
||||
|
||||
|
||||
class LogoPublic(Logo):
|
||||
"""Public logo configuration."""
|
||||
|
||||
light_format: StrictStr
|
||||
dark_format: StrictStr
|
||||
|
||||
|
||||
class Text(HyperglassModel):
|
||||
"""Validation model for params.branding.text."""
|
||||
|
||||
|
|
@ -258,3 +265,9 @@ class Web(HyperglassModel):
|
|||
opengraph: OpenGraph = OpenGraph()
|
||||
text: Text = Text()
|
||||
theme: Theme = Theme()
|
||||
|
||||
|
||||
class WebPublic(Web):
|
||||
"""Public web configuration."""
|
||||
|
||||
logo: LogoPublic
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
|
||||
# Standard Library
|
||||
import re
|
||||
from typing import Type, TypeVar
|
||||
|
||||
# Third Party
|
||||
from pydantic import HttpUrl, BaseModel
|
||||
|
||||
_WEBHOOK_TITLE = "hyperglass received a valid query with the following data"
|
||||
_ICON_URL = "https://res.cloudinary.com/hyperglass/image/upload/v1593192484/icon.png"
|
||||
# Project
|
||||
from hyperglass.util import snake_to_camel
|
||||
|
||||
|
||||
def clean_name(_name: str) -> str:
|
||||
|
|
@ -22,11 +23,14 @@ def clean_name(_name: str) -> str:
|
|||
return _scrubbed.lower()
|
||||
|
||||
|
||||
AsUIModel = TypeVar("AsUIModel", bound="BaseModel")
|
||||
|
||||
|
||||
class HyperglassModel(BaseModel):
|
||||
"""Base model for all hyperglass configuration models."""
|
||||
|
||||
class Config:
|
||||
"""Default Pydantic configuration.
|
||||
"""Pydantic model configuration.
|
||||
|
||||
See https://pydantic-docs.helpmanual.io/usage/model_config
|
||||
"""
|
||||
|
|
@ -38,40 +42,28 @@ class HyperglassModel(BaseModel):
|
|||
json_encoders = {HttpUrl: lambda v: str(v)}
|
||||
|
||||
def export_json(self, *args, **kwargs):
|
||||
"""Return instance as JSON.
|
||||
"""Return instance as JSON."""
|
||||
|
||||
Returns:
|
||||
{str} -- Stringified JSON.
|
||||
"""
|
||||
export_kwargs = {"by_alias": True, "exclude_unset": False}
|
||||
|
||||
export_kwargs = {
|
||||
"by_alias": True,
|
||||
"exclude_unset": False,
|
||||
**kwargs,
|
||||
}
|
||||
for key in export_kwargs.keys():
|
||||
export_kwargs.pop(key, None)
|
||||
|
||||
return self.json(*args, **export_kwargs)
|
||||
return self.json(*args, **export_kwargs, **kwargs)
|
||||
|
||||
def export_dict(self, *args, **kwargs):
|
||||
"""Return instance as dictionary.
|
||||
"""Return instance as dictionary."""
|
||||
|
||||
Returns:
|
||||
{dict} -- Python dictionary.
|
||||
"""
|
||||
export_kwargs = {
|
||||
"by_alias": True,
|
||||
"exclude_unset": False,
|
||||
**kwargs,
|
||||
}
|
||||
export_kwargs = {"by_alias": True, "exclude_unset": False}
|
||||
|
||||
return self.dict(*args, **export_kwargs)
|
||||
for key in export_kwargs.keys():
|
||||
export_kwargs.pop(key, None)
|
||||
|
||||
return self.dict(*args, **export_kwargs, **kwargs)
|
||||
|
||||
def export_yaml(self, *args, **kwargs):
|
||||
"""Return instance as YAML.
|
||||
"""Return instance as YAML."""
|
||||
|
||||
Returns:
|
||||
{str} -- Stringified YAML.
|
||||
"""
|
||||
# Standard Library
|
||||
import json
|
||||
|
||||
|
|
@ -91,9 +83,22 @@ class HyperglassModel(BaseModel):
|
|||
class HyperglassModelExtra(HyperglassModel):
|
||||
"""Model for hyperglass configuration models with dynamic fields."""
|
||||
|
||||
pass
|
||||
|
||||
class Config:
|
||||
"""Default pydantic configuration."""
|
||||
"""Pydantic model configuration."""
|
||||
|
||||
extra = "allow"
|
||||
|
||||
|
||||
class HyperglassUIModel(HyperglassModel):
|
||||
"""Base class for UI configuration parameters."""
|
||||
|
||||
class Config:
|
||||
"""Pydantic model configuration."""
|
||||
|
||||
alias_generator = snake_to_camel
|
||||
allow_population_by_field_name = True
|
||||
|
||||
|
||||
def as_ui_model(name: str, model: Type[AsUIModel]) -> Type[AsUIModel]:
|
||||
"""Override a model's configuration to confirm to a UI model."""
|
||||
return type(name, (model, HyperglassUIModel), {})
|
||||
|
|
|
|||
76
hyperglass/models/ui.py
Normal file
76
hyperglass/models/ui.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
"""UI Configuration models."""
|
||||
|
||||
# Standard Library
|
||||
from typing import Any, Dict, List, Tuple, Union, Literal, Optional
|
||||
|
||||
# Third Party
|
||||
from pydantic import StrictStr, StrictBool
|
||||
|
||||
# Local
|
||||
from .main import HyperglassUIModel, as_ui_model
|
||||
from .config.web import WebPublic
|
||||
from .config.cache import CachePublic
|
||||
from .config.params import ParamsPublic
|
||||
from .config.messages import Messages
|
||||
|
||||
Alignment = Union[Literal["left"], Literal["center"], Literal["right"], None]
|
||||
StructuredDataField = Tuple[str, str, Alignment]
|
||||
|
||||
CacheUI = as_ui_model("CacheUI", CachePublic)
|
||||
WebUI = as_ui_model("WebUI", WebPublic)
|
||||
MessagesUI = as_ui_model("MessagesUI", Messages)
|
||||
|
||||
|
||||
class UIDirectiveInfo(HyperglassUIModel):
|
||||
"""UI: Directive Info."""
|
||||
|
||||
enable: StrictBool
|
||||
params: Dict[str, str]
|
||||
content: StrictStr
|
||||
|
||||
|
||||
class UIDirective(HyperglassUIModel):
|
||||
"""UI: Directive."""
|
||||
|
||||
id: StrictStr
|
||||
name: StrictStr
|
||||
field_type: StrictStr
|
||||
groups: List[StrictStr]
|
||||
description: StrictStr
|
||||
info: Optional[UIDirectiveInfo] = None
|
||||
options: Optional[List[Dict[str, Any]]]
|
||||
|
||||
|
||||
class UILocation(HyperglassUIModel):
|
||||
"""UI: Location (Device)."""
|
||||
|
||||
id: StrictStr
|
||||
name: StrictStr
|
||||
network: StrictStr
|
||||
directives: List[UIDirective] = []
|
||||
|
||||
|
||||
class UINetwork(HyperglassUIModel):
|
||||
"""UI: Network."""
|
||||
|
||||
display_name: StrictStr
|
||||
locations: List[UILocation] = []
|
||||
|
||||
|
||||
class UIContent(HyperglassUIModel):
|
||||
"""UI: Content."""
|
||||
|
||||
credit: StrictStr
|
||||
greeting: StrictStr
|
||||
|
||||
|
||||
class UIParameters(HyperglassUIModel, ParamsPublic):
|
||||
"""UI Configuration Parameters."""
|
||||
|
||||
cache: CacheUI
|
||||
web: WebUI
|
||||
messages: MessagesUI
|
||||
version: StrictStr
|
||||
networks: List[UINetwork] = []
|
||||
parsed_data_fields: Tuple[StructuredDataField, ...]
|
||||
content: UIContent
|
||||
|
|
@ -12,6 +12,7 @@ from pathlib import Path
|
|||
|
||||
# Project
|
||||
from hyperglass.log import log
|
||||
from hyperglass.models.ui import UIParameters
|
||||
|
||||
# Local
|
||||
from .files import copyfiles, check_path
|
||||
|
|
@ -221,7 +222,7 @@ def generate_opengraph(
|
|||
return True
|
||||
|
||||
|
||||
def migrate_images(app_path: Path, params: dict):
|
||||
def migrate_images(app_path: Path, params: UIParameters):
|
||||
"""Migrate images from source code to install directory."""
|
||||
images_dir = app_path / "static" / "images"
|
||||
favicon_dir = images_dir / "favicons"
|
||||
|
|
@ -230,7 +231,7 @@ def migrate_images(app_path: Path, params: dict):
|
|||
dst_files = ()
|
||||
|
||||
for image in ("light", "dark", "favicon"):
|
||||
src = Path(params["web"]["logo"][image])
|
||||
src: Path = getattr(params.web.logo, image)
|
||||
dst = images_dir / f"{image + src.suffix}"
|
||||
src_files += (src,)
|
||||
dst_files += (dst,)
|
||||
|
|
@ -241,7 +242,7 @@ async def build_frontend( # noqa: C901
|
|||
dev_mode: bool,
|
||||
dev_url: str,
|
||||
prod_url: str,
|
||||
params: Dict,
|
||||
params: UIParameters,
|
||||
app_path: Path,
|
||||
force: bool = False,
|
||||
timeout: int = 180,
|
||||
|
|
@ -259,18 +260,6 @@ async def build_frontend( # noqa: C901
|
|||
|
||||
After the build is successful, the temporary file is automatically
|
||||
closed during garbage collection.
|
||||
|
||||
Arguments:
|
||||
dev_mode {bool} -- Development Mode
|
||||
dev_url {str} -- Development Mode URL
|
||||
prod_url {str} -- Production Mode URL
|
||||
params {dict} -- Frontend Config paramters
|
||||
|
||||
Raises:
|
||||
RuntimeError: Raised if errors occur during build process.
|
||||
|
||||
Returns:
|
||||
{bool} -- True if successful
|
||||
"""
|
||||
# Standard Library
|
||||
import hashlib
|
||||
|
|
@ -326,7 +315,7 @@ async def build_frontend( # noqa: C901
|
|||
if not favicon_dir.exists():
|
||||
favicon_dir.mkdir()
|
||||
async with Favicons(
|
||||
source=params["web"]["logo"]["favicon"],
|
||||
source=params.web.logo.favicon,
|
||||
output_directory=favicon_dir,
|
||||
base_url="/images/favicons/",
|
||||
) as favicons:
|
||||
|
|
@ -334,7 +323,7 @@ async def build_frontend( # noqa: C901
|
|||
log.debug("Generated {} favicons", favicons.completed)
|
||||
env_vars["hyperglass"].update({"favicons": favicons.formats()})
|
||||
build_data = {
|
||||
"params": params,
|
||||
"params": params.export_dict(),
|
||||
"version": __version__,
|
||||
"package_json": package_json,
|
||||
}
|
||||
|
|
@ -379,11 +368,11 @@ async def build_frontend( # noqa: C901
|
|||
migrate_images(app_path, params)
|
||||
|
||||
generate_opengraph(
|
||||
Path(params["web"]["opengraph"]["image"]),
|
||||
params.web.opengraph.image,
|
||||
1200,
|
||||
630,
|
||||
images_dir,
|
||||
params["web"]["theme"]["colors"]["black"],
|
||||
params.web.theme.colors.black,
|
||||
)
|
||||
|
||||
except Exception as err:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue