mirror of
https://github.com/checktheroads/hyperglass
synced 2024-05-11 05:55:08 +00:00
refactor front end params
This commit is contained in:
@@ -164,7 +164,7 @@ def build_ui():
|
|||||||
|
|
||||||
status("Starting new UI build...")
|
status("Starting new UI build...")
|
||||||
|
|
||||||
if params.general.developer_mode:
|
if params.developer_mode:
|
||||||
dev_mode = "production"
|
dev_mode = "production"
|
||||||
else:
|
else:
|
||||||
dev_mode = "development"
|
dev_mode = "development"
|
||||||
@@ -172,8 +172,8 @@ def build_ui():
|
|||||||
try:
|
try:
|
||||||
success = asyncio.run(
|
success = asyncio.run(
|
||||||
build_frontend(
|
build_frontend(
|
||||||
dev_mode=params.general.developer_mode,
|
dev_mode=params.developer_mode,
|
||||||
dev_url=f"http://localhost:{str(params.general.listen_port)}/api/",
|
dev_url=f"http://localhost:{str(params.listen_port)}/api/",
|
||||||
prod_url="/api/",
|
prod_url="/api/",
|
||||||
params=frontend_params,
|
params=frontend_params,
|
||||||
force=True,
|
force=True,
|
||||||
|
@@ -332,19 +332,6 @@ def _build_vrfs():
|
|||||||
return vrfs
|
return vrfs
|
||||||
|
|
||||||
|
|
||||||
def _build_queries():
|
|
||||||
"""Build a dict of supported query types and their display names.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
{list} -- Supported query list
|
|
||||||
"""
|
|
||||||
queries = []
|
|
||||||
for query in SUPPORTED_QUERY_TYPES:
|
|
||||||
query_params = getattr(params.queries, query)
|
|
||||||
queries.append({"name": query, "display_name": query_params.display_name})
|
|
||||||
return queries
|
|
||||||
|
|
||||||
|
|
||||||
content_params = json.loads(
|
content_params = json.loads(
|
||||||
params.json(include={"primary_asn", "org_name", "site_title", "site_description"})
|
params.json(include={"primary_asn", "org_name", "site_title", "site_description"})
|
||||||
)
|
)
|
||||||
@@ -409,7 +396,6 @@ content_terms = asyncio.run(
|
|||||||
content_credit = CREDIT
|
content_credit = CREDIT
|
||||||
|
|
||||||
vrfs = _build_vrfs()
|
vrfs = _build_vrfs()
|
||||||
queries = _build_queries()
|
|
||||||
networks = _build_networks()
|
networks = _build_networks()
|
||||||
frontend_networks = _build_frontend_networks()
|
frontend_networks = _build_frontend_networks()
|
||||||
frontend_devices = _build_frontend_devices()
|
frontend_devices = _build_frontend_devices()
|
||||||
@@ -421,19 +407,12 @@ _frontend_fields = {
|
|||||||
"google_analytics": ...,
|
"google_analytics": ...,
|
||||||
"site_description": ...,
|
"site_description": ...,
|
||||||
"web": ...,
|
"web": ...,
|
||||||
"queries": {
|
|
||||||
"bgp_route": {"enable", "display_name"},
|
|
||||||
"bgp_community": {"enable", "display_name"},
|
|
||||||
"bgp_aspath": {"enable", "display_name"},
|
|
||||||
"ping": {"enable", "display_name"},
|
|
||||||
"traceroute": {"enable", "display_name"},
|
|
||||||
},
|
|
||||||
"messages": ...,
|
"messages": ...,
|
||||||
}
|
}
|
||||||
_frontend_params = params.dict(include=_frontend_fields)
|
_frontend_params = params.dict(include=_frontend_fields)
|
||||||
_frontend_params.update(
|
_frontend_params.update(
|
||||||
{
|
{
|
||||||
"queries": queries,
|
"queries": {**params.queries.map, "list": params.queries.list},
|
||||||
"devices": frontend_devices,
|
"devices": frontend_devices,
|
||||||
"networks": networks,
|
"networks": networks,
|
||||||
"vrfs": vrfs,
|
"vrfs": vrfs,
|
||||||
|
@@ -32,7 +32,7 @@ class Params(HyperglassModel):
|
|||||||
debug: StrictBool = False
|
debug: StrictBool = False
|
||||||
developer_mode: StrictBool = False
|
developer_mode: StrictBool = False
|
||||||
primary_asn: Union[StrictInt, StrictStr] = "65001"
|
primary_asn: Union[StrictInt, StrictStr] = "65001"
|
||||||
org_name: StrictStr = "The Company"
|
org_name: StrictStr = "Beloved Hyperglass User"
|
||||||
site_title: StrictStr = "hyperglass"
|
site_title: StrictStr = "hyperglass"
|
||||||
site_description: StrictStr = "{org_name} Network Looking Glass"
|
site_description: StrictStr = "{org_name} Network Looking Glass"
|
||||||
site_keywords: List[StrictStr] = [
|
site_keywords: List[StrictStr] = [
|
||||||
|
@@ -8,6 +8,7 @@ from pydantic import constr
|
|||||||
|
|
||||||
# Project Imports
|
# Project Imports
|
||||||
from hyperglass.configuration.models._utils import HyperglassModel
|
from hyperglass.configuration.models._utils import HyperglassModel
|
||||||
|
from hyperglass.constants import SUPPORTED_QUERY_TYPES
|
||||||
|
|
||||||
|
|
||||||
class BgpCommunity(HyperglassModel):
|
class BgpCommunity(HyperglassModel):
|
||||||
@@ -77,6 +78,42 @@ class Queries(HyperglassModel):
|
|||||||
"Prefix length must be smaller than /{m}. <b>{i}</b> is too specific."
|
"Prefix length must be smaller than /{m}. <b>{i}</b> is too specific."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def map(self):
|
||||||
|
"""Return a dict of all query display names, internal names, and enable state.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
{dict} -- Dict of queries.
|
||||||
|
"""
|
||||||
|
_map = {}
|
||||||
|
for query in SUPPORTED_QUERY_TYPES:
|
||||||
|
query_obj = getattr(self, query)
|
||||||
|
_map[query] = {
|
||||||
|
"name": query,
|
||||||
|
"display_name": query_obj.display_name,
|
||||||
|
"enable": query_obj.enable,
|
||||||
|
}
|
||||||
|
return _map
|
||||||
|
|
||||||
|
@property
|
||||||
|
def list(self):
|
||||||
|
"""Return a list of all query display names, internal names, and enable state.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
{list} -- Dict of queries.
|
||||||
|
"""
|
||||||
|
_list = []
|
||||||
|
for query in SUPPORTED_QUERY_TYPES:
|
||||||
|
query_obj = getattr(self, query)
|
||||||
|
_list.append(
|
||||||
|
{
|
||||||
|
"name": query,
|
||||||
|
"display_name": query_obj.display_name,
|
||||||
|
"enable": query_obj.enable,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return _list
|
||||||
|
|
||||||
bgp_route: BgpRoute = BgpRoute()
|
bgp_route: BgpRoute = BgpRoute()
|
||||||
bgp_community: BgpCommunity = BgpCommunity()
|
bgp_community: BgpCommunity = BgpCommunity()
|
||||||
bgp_aspath: BgpAsPath = BgpAsPath()
|
bgp_aspath: BgpAsPath = BgpAsPath()
|
||||||
|
@@ -18,201 +18,242 @@ from pydantic.color import Color
|
|||||||
# Project Imports
|
# Project Imports
|
||||||
from hyperglass.configuration.models._utils import HyperglassModel
|
from hyperglass.configuration.models._utils import HyperglassModel
|
||||||
from hyperglass.configuration.models.opengraph import OpenGraph
|
from hyperglass.configuration.models.opengraph import OpenGraph
|
||||||
|
from hyperglass.constants import FUNC_COLOR_MAP
|
||||||
|
|
||||||
|
|
||||||
class Web(HyperglassModel):
|
class Analytics(HyperglassModel):
|
||||||
"""Validation model for params.branding."""
|
"""Validation model for Google Analytics."""
|
||||||
|
|
||||||
class Analytics(HyperglassModel):
|
enable: StrictBool = False
|
||||||
"""Validation model for Google Analytics."""
|
id: Optional[StrictStr]
|
||||||
|
|
||||||
enable: StrictBool = False
|
@validator("id")
|
||||||
id: Optional[StrictStr]
|
def validate_id(cls, value, values):
|
||||||
|
"""Ensure ID is set if analytics is enabled.
|
||||||
|
|
||||||
@validator("id")
|
Arguments:
|
||||||
def validate_id(cls, value, values):
|
value {str|None} -- Google Analytics ID
|
||||||
"""Ensure ID is set if analytics is enabled.
|
values {[type]} -- Already-validated model parameters
|
||||||
|
|
||||||
Arguments:
|
Raises:
|
||||||
value {str|None} -- Google Analytics ID
|
ValueError: Raised if analytics is enabled but no ID is set.
|
||||||
values {[type]} -- Already-validated model parameters
|
|
||||||
|
|
||||||
Raises:
|
Returns:
|
||||||
ValueError: Raised if analytics is enabled but no ID is set.
|
{str|None} -- Google Analytics ID if enabled.
|
||||||
|
"""
|
||||||
|
if values["enable"] and value is None:
|
||||||
|
raise ValueError("Analytics is enabled, but no ID is set.")
|
||||||
|
return value
|
||||||
|
|
||||||
Returns:
|
|
||||||
{str|None} -- Google Analytics ID if enabled.
|
class Credit(HyperglassModel):
|
||||||
"""
|
"""Validation model for developer credit."""
|
||||||
if values["enable"] and value is None:
|
|
||||||
raise ValueError("Analytics is enabled, but no ID is set.")
|
enable: StrictBool = True
|
||||||
return value
|
|
||||||
|
|
||||||
|
class ExternalLink(HyperglassModel):
|
||||||
|
"""Validation model for external link."""
|
||||||
|
|
||||||
|
enable: StrictBool = True
|
||||||
|
title: StrictStr = "PeeringDB"
|
||||||
|
url: HttpUrl = "https://www.peeringdb.com/AS{primary_asn}"
|
||||||
|
|
||||||
|
|
||||||
|
class Font(HyperglassModel):
|
||||||
|
"""Validation model for params.branding.font."""
|
||||||
|
|
||||||
|
class Primary(HyperglassModel):
|
||||||
|
"""Validation model for params.branding.font.primary."""
|
||||||
|
|
||||||
|
name: StrictStr = "Nunito"
|
||||||
|
size: StrictStr = "1rem"
|
||||||
|
|
||||||
|
class Mono(HyperglassModel):
|
||||||
|
"""Validation model for params.branding.font.mono."""
|
||||||
|
|
||||||
|
name: StrictStr = "Fira Code"
|
||||||
|
size: StrictStr = "87.5%"
|
||||||
|
|
||||||
|
primary: Primary = Primary()
|
||||||
|
mono: Mono = Mono()
|
||||||
|
|
||||||
|
|
||||||
|
class HelpMenu(HyperglassModel):
|
||||||
|
"""Validation model for generic help menu."""
|
||||||
|
|
||||||
|
enable: StrictBool = True
|
||||||
|
file: Optional[FilePath]
|
||||||
|
title: StrictStr = "Help"
|
||||||
|
|
||||||
|
|
||||||
|
class Logo(HyperglassModel):
|
||||||
|
"""Validation model for logo configuration."""
|
||||||
|
|
||||||
|
light: Optional[FilePath]
|
||||||
|
dark: Optional[FilePath]
|
||||||
|
width: StrictInt = 384
|
||||||
|
height: Optional[StrictInt]
|
||||||
|
favicons: StrictStr = "ui/images/favicons/"
|
||||||
|
|
||||||
|
@validator("favicons")
|
||||||
|
def favicons_trailing_slash(cls, value):
|
||||||
|
"""If the favicons path does not end in a '/', append it."""
|
||||||
|
chars = list(value)
|
||||||
|
if chars[len(chars) - 1] != "/":
|
||||||
|
chars.append("/")
|
||||||
|
return "".join(chars)
|
||||||
|
|
||||||
|
@root_validator(pre=True)
|
||||||
|
def validate_logo_model(cls, values):
|
||||||
|
"""Set default opengraph image location.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
values {dict} -- Unvalidated model
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
{dict} -- Modified model
|
||||||
|
"""
|
||||||
|
logo_light = values.get("light")
|
||||||
|
logo_dark = values.get("dark")
|
||||||
|
default_logo_light = (
|
||||||
|
Path(__file__).parent.parent.parent / "static/images/hyperglass-light.png"
|
||||||
|
)
|
||||||
|
default_logo_dark = (
|
||||||
|
Path(__file__).parent.parent.parent / "static/images/hyperglass-dark.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use light logo as dark logo if dark logo is undefined.
|
||||||
|
if logo_light is not None and logo_dark is None:
|
||||||
|
values["dark"] = logo_light
|
||||||
|
|
||||||
|
# Use dark logo as light logo if light logo is undefined.
|
||||||
|
if logo_dark is not None and logo_light is None:
|
||||||
|
values["light"] = logo_dark
|
||||||
|
|
||||||
|
# Set default logo paths if logo is undefined.
|
||||||
|
if logo_light is None and logo_dark is None:
|
||||||
|
values["light"] = default_logo_light
|
||||||
|
values["dark"] = default_logo_dark
|
||||||
|
|
||||||
|
return values
|
||||||
|
|
||||||
|
@validator("light", "dark")
|
||||||
|
def validate_logos(cls, value):
|
||||||
|
"""Convert file path to URL path.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value {FilePath} -- Path to logo file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
{str} -- Formatted logo path
|
||||||
|
"""
|
||||||
|
return "".join(str(value).split("static")[1::])
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
"""Override pydantic config."""
|
||||||
|
|
||||||
|
fields = {"logo_path": "path"}
|
||||||
|
|
||||||
|
|
||||||
|
class Terms(HyperglassModel):
|
||||||
|
"""Validation model for terms & conditions."""
|
||||||
|
|
||||||
|
enable: StrictBool = True
|
||||||
|
file: Optional[FilePath]
|
||||||
|
title: StrictStr = "Terms"
|
||||||
|
|
||||||
|
|
||||||
|
class Text(HyperglassModel):
|
||||||
|
"""Validation model for params.branding.text."""
|
||||||
|
|
||||||
|
title_mode: constr(regex=("logo_only|text_only|logo_title|all")) = "logo_only"
|
||||||
|
title: StrictStr = "hyperglass"
|
||||||
|
subtitle: StrictStr = "AS{primary_asn}"
|
||||||
|
query_location: StrictStr = "Location"
|
||||||
|
query_type: StrictStr = "Query Type"
|
||||||
|
query_target: StrictStr = "Target"
|
||||||
|
query_vrf: StrictStr = "Routing Table"
|
||||||
|
fqdn_tooltip: StrictStr = "Use {protocol}" # Formatted by Javascript
|
||||||
|
cache: StrictStr = "Results will be cached for {timeout} {period}."
|
||||||
|
|
||||||
|
class Error404(HyperglassModel):
|
||||||
|
"""Validation model for 404 Error Page."""
|
||||||
|
|
||||||
|
title: StrictStr = "Error"
|
||||||
|
subtitle: StrictStr = "{uri} isn't a thing"
|
||||||
|
button: StrictStr = "Home"
|
||||||
|
|
||||||
|
class Error500(HyperglassModel):
|
||||||
|
"""Validation model for 500 Error Page."""
|
||||||
|
|
||||||
|
title: StrictStr = "Error"
|
||||||
|
subtitle: StrictStr = "Something Went Wrong"
|
||||||
|
button: StrictStr = "Home"
|
||||||
|
|
||||||
|
error404: Error404 = Error404()
|
||||||
|
error500: Error500 = Error500()
|
||||||
|
|
||||||
|
|
||||||
|
class Theme(HyperglassModel):
|
||||||
|
"""Validation model for theme variables."""
|
||||||
|
|
||||||
class Colors(HyperglassModel):
|
class Colors(HyperglassModel):
|
||||||
"""Validation model for params.colors."""
|
"""Validation model for theme colors."""
|
||||||
|
|
||||||
primary: Color = "#40798c"
|
black: Color = "#262626"
|
||||||
secondary: Color = "#330036"
|
white: Color = "#f7f7f7"
|
||||||
danger: Color = "#a21024"
|
gray: Color = "#c1c7cc"
|
||||||
warning: Color = "#eec643"
|
red: Color = "#d84b4b"
|
||||||
light: Color = "#fbfffe"
|
orange: Color = "ff6b35"
|
||||||
dark: Color = "#383541"
|
yellow: Color = "#edae49"
|
||||||
background: Color = "#fbfffe"
|
green: Color = "#35b246"
|
||||||
|
blue: Color = "#314cb6"
|
||||||
|
teal: Color = "#35b299"
|
||||||
|
cyan: Color = "#118ab2"
|
||||||
|
pink: Color = "#f2607d"
|
||||||
|
purple: Color = "#8d30b5"
|
||||||
|
primary: Optional[Color]
|
||||||
|
secondary: Optional[Color]
|
||||||
|
success: Optional[Color]
|
||||||
|
warning: Optional[Color]
|
||||||
|
error: Optional[Color]
|
||||||
|
danger: Optional[Color]
|
||||||
|
|
||||||
|
@validator(*FUNC_COLOR_MAP.keys(), pre=True, always=True)
|
||||||
|
def validate_colors(cls, value, values, field):
|
||||||
|
"""Set default functional color mapping.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value {str|None} -- Functional color
|
||||||
|
values {str} -- Already-validated colors
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
{str} -- Mapped color.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if value is None:
|
||||||
|
default_color = FUNC_COLOR_MAP[field.name]
|
||||||
|
value = str(values[default_color])
|
||||||
|
return value
|
||||||
|
|
||||||
def dict(self, *args, **kwargs):
|
def dict(self, *args, **kwargs):
|
||||||
"""Return dict for colors only."""
|
"""Return dict for colors only."""
|
||||||
_dict = {}
|
return {k: v.as_hex() for k, v in self.__dict__.items()}
|
||||||
for k, v in self.__dict__.items():
|
|
||||||
_dict.update({k: v.as_hex()})
|
|
||||||
return _dict
|
|
||||||
|
|
||||||
class Credit(HyperglassModel):
|
class Fonts(HyperglassModel):
|
||||||
"""Validation model for params.branding.credit."""
|
"""Validation model for theme fonts."""
|
||||||
|
|
||||||
enable: StrictBool = True
|
body: StrictStr = "Nunito"
|
||||||
|
mono: StrictStr = "Fira Code"
|
||||||
class Font(HyperglassModel):
|
|
||||||
"""Validation model for params.branding.font."""
|
|
||||||
|
|
||||||
class Primary(HyperglassModel):
|
|
||||||
"""Validation model for params.branding.font.primary."""
|
|
||||||
|
|
||||||
name: StrictStr = "Nunito"
|
|
||||||
size: StrictStr = "1rem"
|
|
||||||
|
|
||||||
class Mono(HyperglassModel):
|
|
||||||
"""Validation model for params.branding.font.mono."""
|
|
||||||
|
|
||||||
name: StrictStr = "Fira Code"
|
|
||||||
size: StrictStr = "87.5%"
|
|
||||||
|
|
||||||
primary: Primary = Primary()
|
|
||||||
mono: Mono = Mono()
|
|
||||||
|
|
||||||
class HelpMenu(HyperglassModel):
|
|
||||||
"""Validation model for params.branding.help_menu."""
|
|
||||||
|
|
||||||
enable: StrictBool = True
|
|
||||||
file: Optional[FilePath]
|
|
||||||
title: StrictStr = "Help"
|
|
||||||
|
|
||||||
class Logo(HyperglassModel):
|
|
||||||
"""Validation model for params.branding.logo."""
|
|
||||||
|
|
||||||
light: Optional[FilePath]
|
|
||||||
dark: Optional[FilePath]
|
|
||||||
width: StrictInt = 384
|
|
||||||
height: Optional[StrictInt]
|
|
||||||
favicons: StrictStr = "ui/images/favicons/"
|
|
||||||
|
|
||||||
@validator("favicons")
|
|
||||||
def favicons_trailing_slash(cls, value):
|
|
||||||
"""If the favicons path does not end in a '/', append it."""
|
|
||||||
chars = list(value)
|
|
||||||
if chars[len(chars) - 1] != "/":
|
|
||||||
chars.append("/")
|
|
||||||
return "".join(chars)
|
|
||||||
|
|
||||||
@root_validator(pre=True)
|
|
||||||
def validate_logo_model(cls, values):
|
|
||||||
"""Set default opengraph image location.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
values {dict} -- Unvalidated model
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
{dict} -- Modified model
|
|
||||||
"""
|
|
||||||
logo_light = values.get("light")
|
|
||||||
logo_dark = values.get("dark")
|
|
||||||
default_logo_light = (
|
|
||||||
Path(__file__).parent.parent.parent
|
|
||||||
/ "static/images/hyperglass-light.png"
|
|
||||||
)
|
|
||||||
default_logo_dark = (
|
|
||||||
Path(__file__).parent.parent.parent
|
|
||||||
/ "static/images/hyperglass-dark.png"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Use light logo as dark logo if dark logo is undefined.
|
|
||||||
if logo_light is not None and logo_dark is None:
|
|
||||||
values["dark"] = logo_light
|
|
||||||
|
|
||||||
# Use dark logo as light logo if light logo is undefined.
|
|
||||||
if logo_dark is not None and logo_light is None:
|
|
||||||
values["light"] = logo_dark
|
|
||||||
|
|
||||||
# Set default logo paths if logo is undefined.
|
|
||||||
if logo_light is None and logo_dark is None:
|
|
||||||
values["light"] = default_logo_light
|
|
||||||
values["dark"] = default_logo_dark
|
|
||||||
|
|
||||||
return values
|
|
||||||
|
|
||||||
@validator("light", "dark")
|
|
||||||
def validate_logos(cls, value):
|
|
||||||
"""Convert file path to URL path.
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
value {FilePath} -- Path to logo file.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
{str} -- Formatted logo path
|
|
||||||
"""
|
|
||||||
return "".join(str(value).split("static")[1::])
|
|
||||||
|
|
||||||
class Config:
|
|
||||||
"""Override pydantic config."""
|
|
||||||
|
|
||||||
fields = {"logo_path": "path"}
|
|
||||||
|
|
||||||
class ExternalLink(HyperglassModel):
|
|
||||||
"""Validation model for params.branding.external_link."""
|
|
||||||
|
|
||||||
enable: StrictBool = True
|
|
||||||
title: StrictStr = "PeeringDB"
|
|
||||||
url: HttpUrl = "https://www.peeringdb.com/AS{primary_asn}"
|
|
||||||
|
|
||||||
class Terms(HyperglassModel):
|
|
||||||
"""Validation model for params.branding.terms."""
|
|
||||||
|
|
||||||
enable: StrictBool = True
|
|
||||||
file: Optional[FilePath]
|
|
||||||
title: StrictStr = "Terms"
|
|
||||||
|
|
||||||
class Text(HyperglassModel):
|
|
||||||
"""Validation model for params.branding.text."""
|
|
||||||
|
|
||||||
title_mode: constr(regex=("logo_only|text_only|logo_title|all")) = "logo_only"
|
|
||||||
title: StrictStr = "hyperglass"
|
|
||||||
subtitle: StrictStr = "AS{primary_asn}"
|
|
||||||
query_location: StrictStr = "Location"
|
|
||||||
query_type: StrictStr = "Query Type"
|
|
||||||
query_target: StrictStr = "Target"
|
|
||||||
query_vrf: StrictStr = "Routing Table"
|
|
||||||
terms: StrictStr = "Terms"
|
|
||||||
info: StrictStr = "Help"
|
|
||||||
peeringdb = "PeeringDB"
|
|
||||||
fqdn_tooltip: StrictStr = "Use {protocol}"
|
|
||||||
cache: StrictStr = "Results will be cached for {timeout} {period}."
|
|
||||||
|
|
||||||
class Error404(HyperglassModel):
|
|
||||||
"""Validation model for 404 Error Page."""
|
|
||||||
|
|
||||||
title: StrictStr = "Error"
|
|
||||||
subtitle: StrictStr = "{uri} isn't a thing"
|
|
||||||
button: StrictStr = "Home"
|
|
||||||
|
|
||||||
class Error500(HyperglassModel):
|
|
||||||
"""Validation model for 500 Error Page."""
|
|
||||||
|
|
||||||
title: StrictStr = "Error"
|
|
||||||
subtitle: StrictStr = "Something Went Wrong"
|
|
||||||
button: StrictStr = "Home"
|
|
||||||
|
|
||||||
error404: Error404 = Error404()
|
|
||||||
error500: Error500 = Error500()
|
|
||||||
|
|
||||||
colors: Colors = Colors()
|
colors: Colors = Colors()
|
||||||
|
fonts: Fonts = Fonts()
|
||||||
|
|
||||||
|
|
||||||
|
class Web(HyperglassModel):
|
||||||
|
"""Validation model for all web/browser-related configuration."""
|
||||||
|
|
||||||
credit: Credit = Credit()
|
credit: Credit = Credit()
|
||||||
external_link: ExternalLink = ExternalLink()
|
external_link: ExternalLink = ExternalLink()
|
||||||
font: Font = Font()
|
font: Font = Font()
|
||||||
@@ -221,3 +262,4 @@ class Web(HyperglassModel):
|
|||||||
opengraph: OpenGraph = OpenGraph()
|
opengraph: OpenGraph = OpenGraph()
|
||||||
terms: Terms = Terms()
|
terms: Terms = Terms()
|
||||||
text: Text = Text()
|
text: Text = Text()
|
||||||
|
theme: Theme = Theme()
|
||||||
|
@@ -168,6 +168,15 @@ SUPPORTED_QUERY_TYPES = (
|
|||||||
"traceroute",
|
"traceroute",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
FUNC_COLOR_MAP = {
|
||||||
|
"primary": "cyan",
|
||||||
|
"secondary": "blue",
|
||||||
|
"success": "green",
|
||||||
|
"warning": "yellow",
|
||||||
|
"error": "orange",
|
||||||
|
"danger": "red",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Supported:
|
class Supported:
|
||||||
"""Define items supported by hyperglass.
|
"""Define items supported by hyperglass.
|
||||||
|
@@ -22,9 +22,9 @@ const Footer = () => {
|
|||||||
const [helpVisible, showHelp] = useState(false);
|
const [helpVisible, showHelp] = useState(false);
|
||||||
const [termsVisible, showTerms] = useState(false);
|
const [termsVisible, showTerms] = useState(false);
|
||||||
const [creditVisible, showCredit] = useState(false);
|
const [creditVisible, showCredit] = useState(false);
|
||||||
const extUrl = config.external_link.url.includes("{primary_asn}")
|
const extUrl = config.web.external_link.url.includes("{primary_asn}")
|
||||||
? config.external_link.url.format({ primary_asn: config.primary_asn })
|
? config.web.external_link.url.format({ primary_asn: config.primary_asn })
|
||||||
: config.external_link.url || "/";
|
: config.web.external_link.url || "/";
|
||||||
const handleCollapse = i => {
|
const handleCollapse = i => {
|
||||||
if (i === "help") {
|
if (i === "help") {
|
||||||
showTerms(false);
|
showTerms(false);
|
||||||
@@ -42,31 +42,31 @@ const Footer = () => {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{config.help.enable && (
|
{config.web.help_menu.enable && (
|
||||||
<FooterContent
|
<FooterContent
|
||||||
isOpen={helpVisible}
|
isOpen={helpVisible}
|
||||||
content={config.content.help_menu}
|
content={config.content.help_menu}
|
||||||
title={config.help.title}
|
title={config.web.help_menu.title}
|
||||||
bg={footerBg[colorMode]}
|
bg={footerBg[colorMode]}
|
||||||
borderColor={contentBorder[colorMode]}
|
borderColor={contentBorder[colorMode]}
|
||||||
side="left"
|
side="left"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{config.terms.enable && (
|
{config.web.terms.enable && (
|
||||||
<FooterContent
|
<FooterContent
|
||||||
isOpen={termsVisible}
|
isOpen={termsVisible}
|
||||||
content={config.content.terms}
|
content={config.content.terms}
|
||||||
title={config.terms.title}
|
title={config.web.terms.title}
|
||||||
bg={footerBg[colorMode]}
|
bg={footerBg[colorMode]}
|
||||||
borderColor={contentBorder[colorMode]}
|
borderColor={contentBorder[colorMode]}
|
||||||
side="left"
|
side="left"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{config.credit.enable && (
|
{config.web.credit.enable && (
|
||||||
<FooterContent
|
<FooterContent
|
||||||
isOpen={creditVisible}
|
isOpen={creditVisible}
|
||||||
content={config.content.credit}
|
content={config.content.credit}
|
||||||
title={config.credit.title}
|
title={config.web.credit.title}
|
||||||
bg={footerBg[colorMode]}
|
bg={footerBg[colorMode]}
|
||||||
borderColor={contentBorder[colorMode]}
|
borderColor={contentBorder[colorMode]}
|
||||||
side="right"
|
side="right"
|
||||||
@@ -84,14 +84,14 @@ const Footer = () => {
|
|||||||
color={footerColor[colorMode]}
|
color={footerColor[colorMode]}
|
||||||
justifyContent="space-between"
|
justifyContent="space-between"
|
||||||
>
|
>
|
||||||
{config.terms.enable && (
|
{config.web.terms.enable && (
|
||||||
<FooterButton side="left" onClick={() => handleCollapse("terms")}>
|
<FooterButton side="left" onClick={() => handleCollapse("terms")}>
|
||||||
{config.terms.title}
|
{config.web.terms.title}
|
||||||
</FooterButton>
|
</FooterButton>
|
||||||
)}
|
)}
|
||||||
{config.help.enable && (
|
{config.web.help_menu.enable && (
|
||||||
<FooterButton side="left" onClick={() => handleCollapse("help")}>
|
<FooterButton side="left" onClick={() => handleCollapse("help")}>
|
||||||
{config.help.title}
|
{config.web.help_menu.title}
|
||||||
</FooterButton>
|
</FooterButton>
|
||||||
)}
|
)}
|
||||||
<Flex
|
<Flex
|
||||||
@@ -102,12 +102,12 @@ const Footer = () => {
|
|||||||
marginRight="auto"
|
marginRight="auto"
|
||||||
p={0}
|
p={0}
|
||||||
/>
|
/>
|
||||||
{config.credit.enable && (
|
{config.web.credit.enable && (
|
||||||
<FooterButton side="right" onClick={() => handleCollapse("credit")}>
|
<FooterButton side="right" onClick={() => handleCollapse("credit")}>
|
||||||
<FiCode />
|
<FiCode />
|
||||||
</FooterButton>
|
</FooterButton>
|
||||||
)}
|
)}
|
||||||
{config.external_link.enable && (
|
{config.web.external_link.enable && (
|
||||||
<FooterButton
|
<FooterButton
|
||||||
as="a"
|
as="a"
|
||||||
href={extUrl}
|
href={extUrl}
|
||||||
@@ -117,7 +117,7 @@ const Footer = () => {
|
|||||||
rightIcon={GoLinkExternal}
|
rightIcon={GoLinkExternal}
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
{config.external_link.title}
|
{config.web.external_link.title}
|
||||||
</FooterButton>
|
</FooterButton>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@@ -133,7 +133,7 @@ const HyperglassForm = React.forwardRef(
|
|||||||
vrfContent && <HelpModal item={vrfContent} name="query_type" />
|
vrfContent && <HelpModal item={vrfContent} name="query_type" />
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<QueryType onChange={handleChange} queryTypes={config.queries} />
|
<QueryType onChange={handleChange} queryTypes={config.queries.list} />
|
||||||
</FormField>
|
</FormField>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<FormRow>
|
<FormRow>
|
||||||
|
@@ -14,7 +14,7 @@ const HyperglassContext = createContext(null);
|
|||||||
|
|
||||||
export const HyperglassProvider = ({ config, children }) => {
|
export const HyperglassProvider = ({ config, children }) => {
|
||||||
const value = useMemo(() => config, [config]);
|
const value = useMemo(() => config, [config]);
|
||||||
const userTheme = value && makeTheme(value.web);
|
const userTheme = value && makeTheme(value.web.theme);
|
||||||
const theme = value ? userTheme : defaultTheme;
|
const theme = value ? userTheme : defaultTheme;
|
||||||
return (
|
return (
|
||||||
<HyperglassContext.Provider value={value}>
|
<HyperglassContext.Provider value={value}>
|
||||||
|
229
ui/theme.js
229
ui/theme.js
@@ -35,6 +35,8 @@ const alphaColors = color => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const generateColors = colorInput => {
|
const generateColors = colorInput => {
|
||||||
|
const colorMap = {};
|
||||||
|
|
||||||
const lightnessMap = [0.95, 0.85, 0.75, 0.65, 0.55, 0.45, 0.35, 0.25, 0.15, 0.05];
|
const lightnessMap = [0.95, 0.85, 0.75, 0.65, 0.55, 0.45, 0.35, 0.25, 0.15, 0.05];
|
||||||
const saturationMap = [0.32, 0.16, 0.08, 0.04, 0, 0, 0.04, 0.08, 0.16, 0.32];
|
const saturationMap = [0.32, 0.16, 0.08, 0.04, 0, 0, 0.04, 0.08, 0.16, 0.32];
|
||||||
|
|
||||||
@@ -59,7 +61,6 @@ const generateColors = colorInput => {
|
|||||||
|
|
||||||
const getColorNumber = index => (index === 0 ? 50 : index * 100);
|
const getColorNumber = index => (index === 0 ? 50 : index * 100);
|
||||||
|
|
||||||
const colorMap = {};
|
|
||||||
colors.map((color, i) => {
|
colors.map((color, i) => {
|
||||||
const colorIndex = getColorNumber(i);
|
const colorIndex = getColorNumber(i);
|
||||||
colorMap[colorIndex] = color.hex();
|
colorMap[colorIndex] = color.hex();
|
||||||
@@ -67,61 +68,62 @@ const generateColors = colorInput => {
|
|||||||
return colorMap;
|
return colorMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultBasePalette = {
|
// const defaultBasePalette = {
|
||||||
black: "#262626",
|
// black: "#262626",
|
||||||
white: "#f7f7f7",
|
// white: "#f7f7f7",
|
||||||
gray: "#c1c7cc",
|
// gray: "#c1c7cc",
|
||||||
red: "#d84b4b",
|
// red: "#d84b4b",
|
||||||
orange: "ff6b35",
|
// orange: "ff6b35",
|
||||||
yellow: "#edae49",
|
// yellow: "#edae49",
|
||||||
green: "#35b246",
|
// green: "#35b246",
|
||||||
blue: "#314cb6",
|
// blue: "#314cb6",
|
||||||
teal: "#35b299",
|
// teal: "#35b299",
|
||||||
cyan: "#118ab2",
|
// cyan: "#118ab2",
|
||||||
pink: "#f2607d",
|
// pink: "#f2607d",
|
||||||
purple: "#8d30b5"
|
// purple: "#8d30b5"
|
||||||
};
|
// };
|
||||||
|
|
||||||
const defaultSwatchPalette = {
|
// const defaultSwatchPalette = {
|
||||||
black: defaultBasePalette.black,
|
// black: defaultBasePalette.black,
|
||||||
white: defaultBasePalette.white,
|
// white: defaultBasePalette.white,
|
||||||
gray: generateColors(defaultBasePalette.gray),
|
// gray: generateColors(defaultBasePalette.gray),
|
||||||
red: generateColors(defaultBasePalette.red),
|
// red: generateColors(defaultBasePalette.red),
|
||||||
orange: generateColors(defaultBasePalette.orange),
|
// orange: generateColors(defaultBasePalette.orange),
|
||||||
yellow: generateColors(defaultBasePalette.yellow),
|
// yellow: generateColors(defaultBasePalette.yellow),
|
||||||
green: generateColors(defaultBasePalette.green),
|
// green: generateColors(defaultBasePalette.green),
|
||||||
blue: generateColors(defaultBasePalette.blue),
|
// blue: generateColors(defaultBasePalette.blue),
|
||||||
teal: generateColors(defaultBasePalette.teal),
|
// teal: generateColors(defaultBasePalette.teal),
|
||||||
cyan: generateColors(defaultBasePalette.cyan),
|
// cyan: generateColors(defaultBasePalette.cyan),
|
||||||
pink: generateColors(defaultBasePalette.pink),
|
// pink: generateColors(defaultBasePalette.pink),
|
||||||
purple: generateColors(defaultBasePalette.purple)
|
// purple: generateColors(defaultBasePalette.purple)
|
||||||
};
|
// };
|
||||||
const defaultAlphaPalette = {
|
|
||||||
blackAlpha: alphaColors(defaultBasePalette.black),
|
|
||||||
whiteAlpha: alphaColors(defaultBasePalette.white)
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultFuncSwatchPalette = {
|
// const defaultAlphaPalette = {
|
||||||
primary: generateColors(defaultBasePalette.cyan),
|
// blackAlpha: alphaColors(defaultBasePalette.black),
|
||||||
secondary: generateColors(defaultBasePalette.blue),
|
// whiteAlpha: alphaColors(defaultBasePalette.white)
|
||||||
dark: generateColors(defaultBasePalette.black),
|
// };
|
||||||
light: generateColors(defaultBasePalette.white),
|
|
||||||
success: generateColors(defaultBasePalette.green),
|
|
||||||
warning: generateColors(defaultBasePalette.yellow),
|
|
||||||
error: generateColors(defaultBasePalette.orange),
|
|
||||||
danger: generateColors(defaultBasePalette.red)
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultColors = {
|
// const defaultFuncSwatchPalette = {
|
||||||
transparent: "transparent",
|
// primary: generateColors(defaultBasePalette.cyan),
|
||||||
current: "currentColor",
|
// secondary: generateColors(defaultBasePalette.blue),
|
||||||
...defaultFuncSwatchPalette,
|
// dark: generateColors(defaultBasePalette.black),
|
||||||
...defaultAlphaPalette,
|
// light: generateColors(defaultBasePalette.white),
|
||||||
...defaultSwatchPalette
|
// success: generateColors(defaultBasePalette.green),
|
||||||
};
|
// warning: generateColors(defaultBasePalette.yellow),
|
||||||
|
// error: generateColors(defaultBasePalette.orange),
|
||||||
|
// danger: generateColors(defaultBasePalette.red)
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const defaultColors = {
|
||||||
|
// transparent: "transparent",
|
||||||
|
// current: "currentColor",
|
||||||
|
// ...defaultFuncSwatchPalette,
|
||||||
|
// ...defaultAlphaPalette,
|
||||||
|
// ...defaultSwatchPalette
|
||||||
|
// };
|
||||||
|
|
||||||
const defaultBodyFonts = [
|
const defaultBodyFonts = [
|
||||||
"Nunito",
|
// "Nunito",
|
||||||
"-apple-system",
|
"-apple-system",
|
||||||
"BlinkMacSystemFont",
|
"BlinkMacSystemFont",
|
||||||
'"Segoe UI"',
|
'"Segoe UI"',
|
||||||
@@ -134,7 +136,7 @@ const defaultBodyFonts = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const defaultMonoFonts = [
|
const defaultMonoFonts = [
|
||||||
'"Fira Code"',
|
// '"Fira Code"',
|
||||||
"SFMono-Regular",
|
"SFMono-Regular",
|
||||||
"Melno",
|
"Melno",
|
||||||
"Monaco",
|
"Monaco",
|
||||||
@@ -144,53 +146,63 @@ const defaultMonoFonts = [
|
|||||||
"monospace"
|
"monospace"
|
||||||
];
|
];
|
||||||
|
|
||||||
const defaultFonts = {
|
// const defaultFonts = {
|
||||||
body: defaultBodyFonts.join(", "),
|
// body: defaultBodyFonts.join(", "),
|
||||||
heading: defaultBodyFonts.join(", "),
|
// heading: defaultBodyFonts.join(", "),
|
||||||
mono: defaultMonoFonts.join(", ")
|
// mono: defaultMonoFonts.join(", ")
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const defaultTheme = {
|
||||||
|
// ...chakraTheme,
|
||||||
|
// colors: defaultColors,
|
||||||
|
// fonts: defaultFonts
|
||||||
|
// };
|
||||||
|
|
||||||
|
const generatePalette = palette => {
|
||||||
|
const generatedPalette = {};
|
||||||
|
Object.keys(palette).map(color => {
|
||||||
|
if (!["black", "white"].includes(color)) {
|
||||||
|
generatedPalette[color] = generateColors(palette[color]);
|
||||||
|
} else {
|
||||||
|
generatedPalette[color] = palette[color];
|
||||||
|
generatedPalette[`${color}Alpha`] = alphaColors(palette[color]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return generatedPalette;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultTheme = {
|
// const generateFuncPalette = palette => ({
|
||||||
...chakraTheme,
|
// primary: generateColors(palette.cyan),
|
||||||
colors: defaultColors,
|
// secondary: generateColors(palette.blue),
|
||||||
fonts: defaultFonts
|
// dark: generateColors(palette.black),
|
||||||
|
// light: generateColors(palette.white),
|
||||||
|
// success: generateColors(palette.green),
|
||||||
|
// warning: generateColors(palette.yellow),
|
||||||
|
// error: generateColors(palette.orange),
|
||||||
|
// danger: generateColors(palette.red)
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const generateAlphaPalette = palette => ({
|
||||||
|
// blackAlpha: alphaColors(palette.black),
|
||||||
|
// whiteAlpha: alphaColors(palette.white)
|
||||||
|
// });
|
||||||
|
|
||||||
|
const formatFont = font => {
|
||||||
|
const fontList = font.split(" ");
|
||||||
|
const fontFmt = fontList.length >= 2 ? `'${fontList.join(" ")}'` : fontList.join(" ");
|
||||||
|
return fontFmt;
|
||||||
};
|
};
|
||||||
|
|
||||||
const generatePalette = palette => ({
|
|
||||||
black: palette.black,
|
|
||||||
white: palette.white,
|
|
||||||
gray: generateColors(palette.gray),
|
|
||||||
red: generateColors(palette.red),
|
|
||||||
orange: generateColors(palette.orange),
|
|
||||||
yellow: generateColors(palette.yellow),
|
|
||||||
green: generateColors(palette.green),
|
|
||||||
blue: generateColors(palette.blue),
|
|
||||||
teal: generateColors(palette.teal),
|
|
||||||
cyan: generateColors(palette.cyan),
|
|
||||||
pink: generateColors(palette.pink),
|
|
||||||
purple: generateColors(palette.purple)
|
|
||||||
});
|
|
||||||
|
|
||||||
const generateFuncPalette = palette => ({
|
|
||||||
primary: generateColors(palette.cyan),
|
|
||||||
secondary: generateColors(palette.blue),
|
|
||||||
dark: generateColors(palette.black),
|
|
||||||
light: generateColors(palette.white),
|
|
||||||
success: generateColors(palette.green),
|
|
||||||
warning: generateColors(palette.yellow),
|
|
||||||
error: generateColors(palette.orange),
|
|
||||||
danger: generateColors(palette.red)
|
|
||||||
});
|
|
||||||
|
|
||||||
const generateAlphaPalette = palette => ({
|
|
||||||
blackAlpha: alphaColors(palette.black),
|
|
||||||
whiteAlpha: alphaColors(palette.white)
|
|
||||||
});
|
|
||||||
|
|
||||||
const importFonts = userFonts => {
|
const importFonts = userFonts => {
|
||||||
const [body, mono] = [defaultBodyFonts, defaultMonoFonts];
|
const [body, mono] = [defaultBodyFonts, defaultMonoFonts];
|
||||||
userFonts.primary.name && body.unshift(`'${userFonts.primary.name}'`);
|
const bodyFmt = formatFont(userFonts.body);
|
||||||
userFonts.mono.name && mono.unshift(`'${userFonts.mono.name}'`);
|
const monoFmt = formatFont(userFonts.mono);
|
||||||
|
if (userFonts.body && !body.includes(bodyFmt)) {
|
||||||
|
body.unshift(bodyFmt);
|
||||||
|
}
|
||||||
|
if (userFonts.mono && !mono.includes(monoFmt)) {
|
||||||
|
mono.unshift(monoFmt);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
body: body.join(", "),
|
body: body.join(", "),
|
||||||
heading: body.join(", "),
|
heading: body.join(", "),
|
||||||
@@ -199,26 +211,29 @@ const importFonts = userFonts => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const importColors = (userColors = {}) => {
|
const importColors = (userColors = {}) => {
|
||||||
const baseColors = {
|
// const baseColors = {
|
||||||
...defaultBasePalette,
|
// ...defaultBasePalette,
|
||||||
...userColors
|
// ...userColors
|
||||||
};
|
// };
|
||||||
const swatchColors = generatePalette(baseColors);
|
|
||||||
const funcColors = generateFuncPalette(baseColors);
|
const generatedColors = generatePalette(userColors);
|
||||||
const bwAlphaColors = generateAlphaPalette(baseColors);
|
// const swatchColors = generatePalette(baseColors);
|
||||||
|
// const funcColors = generateFuncPalette(baseColors);
|
||||||
|
// const bwAlphaColors = generateAlphaPalette(userColors);
|
||||||
return {
|
return {
|
||||||
transparent: "transparent",
|
transparent: "transparent",
|
||||||
current: "currentColor",
|
current: "currentColor",
|
||||||
...swatchColors,
|
// ...swatchColors,
|
||||||
...funcColors,
|
// ...funcColors,
|
||||||
...bwAlphaColors
|
...generatedColors
|
||||||
|
// ...bwAlphaColors
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeTheme = branding => ({
|
const makeTheme = userTheme => ({
|
||||||
...chakraTheme,
|
...chakraTheme,
|
||||||
colors: importColors(branding.colors),
|
colors: importColors(userTheme.colors),
|
||||||
fonts: importFonts(branding.font)
|
fonts: importFonts(userTheme.fonts)
|
||||||
});
|
});
|
||||||
|
|
||||||
export { makeTheme, defaultTheme };
|
export { makeTheme, chakraTheme as defaultTheme };
|
||||||
|
Reference in New Issue
Block a user