forked from mirrors/thatmattlove-hyperglass
Add info support back to directives
This commit is contained in:
parent
292aa7612b
commit
c479a2f2b4
9 changed files with 52 additions and 86 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# Standard Library
|
# Standard Library
|
||||||
import re
|
import re
|
||||||
from typing import Any, Set, Dict, List, Tuple, Union, Optional
|
import typing as t
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from ipaddress import IPv4Address, IPv6Address
|
from ipaddress import IPv4Address, IPv6Address
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ ALL_DEVICE_TYPES = {*DRIVER_MAP.keys(), *CLASS_MAPPER.keys()}
|
||||||
class DirectiveOptions(HyperglassModel, extra="ignore"):
|
class DirectiveOptions(HyperglassModel, extra="ignore"):
|
||||||
"""Per-device directive options."""
|
"""Per-device directive options."""
|
||||||
|
|
||||||
builtins: Union[StrictBool, List[StrictStr]] = True
|
builtins: t.Union[StrictBool, t.List[StrictStr]] = True
|
||||||
|
|
||||||
|
|
||||||
class Device(HyperglassModelWithId, extra="allow"):
|
class Device(HyperglassModelWithId, extra="allow"):
|
||||||
|
|
@ -41,21 +41,21 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
|
|
||||||
id: StrictStr
|
id: StrictStr
|
||||||
name: StrictStr
|
name: StrictStr
|
||||||
description: Optional[StrictStr]
|
description: t.Optional[StrictStr]
|
||||||
avatar: Optional[FilePath]
|
avatar: t.Optional[FilePath]
|
||||||
address: Union[IPv4Address, IPv6Address, StrictStr]
|
address: t.Union[IPv4Address, IPv6Address, StrictStr]
|
||||||
group: Optional[StrictStr]
|
group: t.Optional[StrictStr]
|
||||||
credential: Credential
|
credential: Credential
|
||||||
proxy: Optional[Proxy]
|
proxy: t.Optional[Proxy]
|
||||||
display_name: Optional[StrictStr]
|
display_name: t.Optional[StrictStr]
|
||||||
port: StrictInt = 22
|
port: StrictInt = 22
|
||||||
http: HttpConfiguration = HttpConfiguration()
|
http: HttpConfiguration = HttpConfiguration()
|
||||||
platform: StrictStr
|
platform: StrictStr
|
||||||
structured_output: Optional[StrictBool]
|
structured_output: t.Optional[StrictBool]
|
||||||
directives: Directives = Directives()
|
directives: Directives = Directives()
|
||||||
driver: Optional[SupportedDriver]
|
driver: t.Optional[SupportedDriver]
|
||||||
driver_config: Dict[str, Any] = {}
|
driver_config: t.Dict[str, t.Any] = {}
|
||||||
attrs: Dict[str, str] = {}
|
attrs: t.Dict[str, str] = {}
|
||||||
|
|
||||||
def __init__(self, **kw) -> None:
|
def __init__(self, **kw) -> None:
|
||||||
"""Check legacy fields and ensure an `id` is set."""
|
"""Check legacy fields and ensure an `id` is set."""
|
||||||
|
|
@ -70,7 +70,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
return str(self.address)
|
return str(self.address)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _with_id(values: Dict) -> str:
|
def _with_id(values: t.Dict) -> str:
|
||||||
"""Generate device id & handle legacy display_name field."""
|
"""Generate device id & handle legacy display_name field."""
|
||||||
|
|
||||||
def generate_id(name: str) -> str:
|
def generate_id(name: str) -> str:
|
||||||
|
|
@ -94,7 +94,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
|
|
||||||
return {"id": device_id, "name": display_name, "display_name": None, **values}
|
return {"id": device_id, "name": display_name, "display_name": None, **values}
|
||||||
|
|
||||||
def export_api(self) -> Dict[str, Any]:
|
def export_api(self) -> t.Dict[str, t.Any]:
|
||||||
"""Export API-facing device fields."""
|
"""Export API-facing device fields."""
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
|
|
@ -103,7 +103,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def directive_commands(self) -> List[str]:
|
def directive_commands(self) -> t.List[str]:
|
||||||
"""Get all commands associated with the device."""
|
"""Get all commands associated with the device."""
|
||||||
return [
|
return [
|
||||||
command
|
command
|
||||||
|
|
@ -113,7 +113,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def directive_ids(self) -> List[str]:
|
def directive_ids(self) -> t.List[str]:
|
||||||
"""Get all directive IDs associated with the device."""
|
"""Get all directive IDs associated with the device."""
|
||||||
return [directive.id for directive in self.directives]
|
return [directive.id for directive in self.directives]
|
||||||
|
|
||||||
|
|
@ -146,7 +146,9 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
)
|
)
|
||||||
|
|
||||||
@validator("address")
|
@validator("address")
|
||||||
def validate_address(cls, value, values):
|
def validate_address(
|
||||||
|
cls, value: t.Union[IPv4Address, IPv6Address, str], values: t.Dict[str, t.Any]
|
||||||
|
) -> t.Union[IPv4Address, IPv6Address, str]:
|
||||||
"""Ensure a hostname is resolvable."""
|
"""Ensure a hostname is resolvable."""
|
||||||
|
|
||||||
if not isinstance(value, (IPv4Address, IPv6Address)):
|
if not isinstance(value, (IPv4Address, IPv6Address)):
|
||||||
|
|
@ -160,8 +162,8 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
|
|
||||||
@validator("avatar")
|
@validator("avatar")
|
||||||
def validate_avatar(
|
def validate_avatar(
|
||||||
cls, value: Union[FilePath, None], values: Dict[str, Any]
|
cls, value: t.Union[FilePath, None], values: t.Dict[str, t.Any]
|
||||||
) -> Union[FilePath, None]:
|
) -> t.Union[FilePath, None]:
|
||||||
"""Migrate avatar to static directory."""
|
"""Migrate avatar to static directory."""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
# Standard Library
|
# Standard Library
|
||||||
|
|
@ -181,7 +183,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@validator("platform", pre=True, always=True)
|
@validator("platform", pre=True, always=True)
|
||||||
def validate_platform(cls: "Device", value: Any, values: Dict[str, Any]) -> str:
|
def validate_platform(cls: "Device", value: t.Any, values: t.Dict[str, t.Any]) -> str:
|
||||||
"""Validate & rewrite device platform, set default `directives`."""
|
"""Validate & rewrite device platform, set default `directives`."""
|
||||||
|
|
||||||
if value is None:
|
if value is None:
|
||||||
|
|
@ -202,7 +204,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@validator("structured_output", pre=True, always=True)
|
@validator("structured_output", pre=True, always=True)
|
||||||
def validate_structured_output(cls, value: bool, values: Dict[str, Any]) -> bool:
|
def validate_structured_output(cls, value: bool, values: t.Dict[str, t.Any]) -> bool:
|
||||||
"""Validate structured output is supported on the device & set a default."""
|
"""Validate structured output is supported on the device & set a default."""
|
||||||
|
|
||||||
if value is True:
|
if value is True:
|
||||||
|
|
@ -221,7 +223,9 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@validator("directives", pre=True, always=True)
|
@validator("directives", pre=True, always=True)
|
||||||
def validate_directives(cls: "Device", value, values) -> "Directives":
|
def validate_directives(
|
||||||
|
cls: "Device", value: t.Optional[t.List[str]], values: t.Dict[str, t.Any]
|
||||||
|
) -> "Directives":
|
||||||
"""Associate directive IDs to loaded directive objects."""
|
"""Associate directive IDs to loaded directive objects."""
|
||||||
directives = use_state("directives")
|
directives = use_state("directives")
|
||||||
|
|
||||||
|
|
@ -234,7 +238,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
**{
|
**{
|
||||||
k: v
|
k: v
|
||||||
for statement in directive_ids
|
for statement in directive_ids
|
||||||
if isinstance(statement, Dict)
|
if isinstance(statement, t.Dict)
|
||||||
for k, v in statement.items()
|
for k, v in statement.items()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -253,14 +257,14 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
if directive_options.builtins is True:
|
if directive_options.builtins is True:
|
||||||
# Add all builtins.
|
# Add all builtins.
|
||||||
device_directives += builtins
|
device_directives += builtins
|
||||||
elif isinstance(directive_options.builtins, List):
|
elif isinstance(directive_options.builtins, t.List):
|
||||||
# If the user provides a list of builtin directives to include, add only those.
|
# If the user provides a list of builtin directives to include, add only those.
|
||||||
device_directives += builtins.matching(*directive_options.builtins)
|
device_directives += builtins.matching(*directive_options.builtins)
|
||||||
|
|
||||||
return device_directives
|
return device_directives
|
||||||
|
|
||||||
@validator("driver")
|
@validator("driver")
|
||||||
def validate_driver(cls, value: Optional[str], values: Dict) -> Dict:
|
def validate_driver(cls: "Device", value: t.Optional[str], values: t.Dict[str, t.Any]) -> str:
|
||||||
"""Set the correct driver and override if supported."""
|
"""Set the correct driver and override if supported."""
|
||||||
return get_driver(values["platform"], value)
|
return get_driver(values["platform"], value)
|
||||||
|
|
||||||
|
|
@ -268,25 +272,25 @@ class Device(HyperglassModelWithId, extra="allow"):
|
||||||
class Devices(MultiModel, model=Device, unique_by="id"):
|
class Devices(MultiModel, model=Device, unique_by="id"):
|
||||||
"""Container for all devices."""
|
"""Container for all devices."""
|
||||||
|
|
||||||
def __init__(self, *items: Dict[str, Any]) -> None:
|
def __init__(self: "Devices", *items: t.Dict[str, t.Any]) -> None:
|
||||||
"""Generate IDs prior to validation."""
|
"""Generate IDs prior to validation."""
|
||||||
with_id = (Device._with_id(item) for item in items)
|
with_id = (Device._with_id(item) for item in items)
|
||||||
super().__init__(*with_id)
|
super().__init__(*with_id)
|
||||||
|
|
||||||
def export_api(self) -> List[Dict[str, Any]]:
|
def export_api(self: "Devices") -> t.List[t.Dict[str, t.Any]]:
|
||||||
"""Export API-facing device fields."""
|
"""Export API-facing device fields."""
|
||||||
return [d.export_api() for d in self]
|
return [d.export_api() for d in self]
|
||||||
|
|
||||||
def valid_id_or_name(self, value: str) -> bool:
|
def valid_id_or_name(self: "Devices", value: str) -> bool:
|
||||||
"""Determine if a value is a valid device name or ID."""
|
"""Determine if a value is a valid device name or ID."""
|
||||||
for device in self:
|
for device in self:
|
||||||
if value == device.id or value == device.name:
|
if value == device.id or value == device.name:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def directive_plugins(self) -> Dict[Path, Tuple[StrictStr]]:
|
def directive_plugins(self: "Devices") -> t.Dict[Path, t.Tuple[StrictStr]]:
|
||||||
"""Get a mapping of plugin paths to associated directive IDs."""
|
"""Get a mapping of plugin paths to associated directive IDs."""
|
||||||
result: Dict[Path, Set[StrictStr]] = {}
|
result: t.Dict[Path, t.Set[StrictStr]] = {}
|
||||||
# Unique set of all directives.
|
# Unique set of all directives.
|
||||||
directives = {directive for device in self for directive in device.directives}
|
directives = {directive for device in self for directive in device.directives}
|
||||||
# Unique set of all plugin file names.
|
# Unique set of all plugin file names.
|
||||||
|
|
@ -301,9 +305,8 @@ class Devices(MultiModel, model=Device, unique_by="id"):
|
||||||
# Convert the directive set to a tuple.
|
# Convert the directive set to a tuple.
|
||||||
return {k: tuple(v) for k, v in result.items()}
|
return {k: tuple(v) for k, v in result.items()}
|
||||||
|
|
||||||
def frontend(self) -> List[Dict[str, Any]]:
|
def frontend(self: "Devices") -> t.List[t.Dict[str, t.Any]]:
|
||||||
"""Export grouped devices for UIParameters."""
|
"""Export grouped devices for UIParameters."""
|
||||||
params = use_state("params")
|
|
||||||
groups = {device.group for device in self}
|
groups = {device.group for device in self}
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|
@ -317,7 +320,7 @@ class Devices(MultiModel, model=Device, unique_by="id"):
|
||||||
if device.avatar is not None
|
if device.avatar is not None
|
||||||
else None,
|
else None,
|
||||||
"description": device.description,
|
"description": device.description,
|
||||||
"directives": [d.frontend(params) for d in device.directives],
|
"directives": [d.frontend() for d in device.directives],
|
||||||
}
|
}
|
||||||
for device in self
|
for device in self
|
||||||
if device.group == group
|
if device.group == group
|
||||||
|
|
|
||||||
|
|
@ -143,10 +143,6 @@ class Params(ParamsPublic, HyperglassModel):
|
||||||
"""Get all validated external common plugins as Path objects."""
|
"""Get all validated external common plugins as Path objects."""
|
||||||
return tuple(Path(p) for p in self.plugins)
|
return tuple(Path(p) for p in self.plugins)
|
||||||
|
|
||||||
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]:
|
def frontend(self) -> Dict[str, Any]:
|
||||||
"""Export UI-specific parameters."""
|
"""Export UI-specific parameters."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,6 @@ from hyperglass.exceptions.private import InputValidationError
|
||||||
from .main import MultiModel, HyperglassModel, HyperglassUniqueModel
|
from .main import MultiModel, HyperglassModel, HyperglassUniqueModel
|
||||||
from .fields import Action
|
from .fields import Action
|
||||||
|
|
||||||
if t.TYPE_CHECKING:
|
|
||||||
# Local
|
|
||||||
from .config.params import Params
|
|
||||||
|
|
||||||
IPv4PrefixLength = conint(ge=0, le=32)
|
IPv4PrefixLength = conint(ge=0, le=32)
|
||||||
IPv6PrefixLength = conint(ge=0, le=128)
|
IPv6PrefixLength = conint(ge=0, le=128)
|
||||||
IPNetwork = t.Union[IPv4Network, IPv6Network]
|
IPNetwork = t.Union[IPv4Network, IPv6Network]
|
||||||
|
|
@ -277,7 +273,7 @@ class Directive(HyperglassUniqueModel, unique_by=("id", "table_output")):
|
||||||
return [str(f) for f in matching_plugins]
|
return [str(f) for f in matching_plugins]
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def frontend(self: "Directive", params: "Params") -> t.Dict[str, t.Any]:
|
def frontend(self: "Directive") -> t.Dict[str, t.Any]:
|
||||||
"""Prepare a representation of the directive for the UI."""
|
"""Prepare a representation of the directive for the UI."""
|
||||||
|
|
||||||
value = {
|
value = {
|
||||||
|
|
@ -291,11 +287,7 @@ class Directive(HyperglassUniqueModel, unique_by=("id", "table_output")):
|
||||||
|
|
||||||
if self.info is not None:
|
if self.info is not None:
|
||||||
with self.info.open() as md:
|
with self.info.open() as md:
|
||||||
value["info"] = {
|
value["info"] = md.read()
|
||||||
"enable": True,
|
|
||||||
"params": params.content_params(),
|
|
||||||
"content": md.read(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.field.is_select:
|
if self.field.is_select:
|
||||||
value["options"] = [o.export_dict() for o in self.field.options if o is not None]
|
value["options"] = [o.export_dict() for o in self.field.options if o is not None]
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,6 @@ Alignment = Union[Literal["left"], Literal["center"], Literal["right"], None]
|
||||||
StructuredDataField = Tuple[str, str, Alignment]
|
StructuredDataField = Tuple[str, str, Alignment]
|
||||||
|
|
||||||
|
|
||||||
class UIDirectiveInfo(HyperglassModel):
|
|
||||||
"""UI: Directive Info."""
|
|
||||||
|
|
||||||
enable: StrictBool
|
|
||||||
params: Dict[str, str]
|
|
||||||
content: StrictStr
|
|
||||||
|
|
||||||
|
|
||||||
class UIDirective(HyperglassModel):
|
class UIDirective(HyperglassModel):
|
||||||
"""UI: Directive."""
|
"""UI: Directive."""
|
||||||
|
|
||||||
|
|
@ -33,7 +25,7 @@ class UIDirective(HyperglassModel):
|
||||||
field_type: StrictStr
|
field_type: StrictStr
|
||||||
groups: List[StrictStr]
|
groups: List[StrictStr]
|
||||||
description: StrictStr
|
description: StrictStr
|
||||||
info: Optional[UIDirectiveInfo] = None
|
info: Optional[str] = None
|
||||||
options: Optional[List[Dict[str, Any]]]
|
options: Optional[List[Dict[str, Any]]]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,15 @@ import {
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { DynamicIcon, Markdown } from '~/components';
|
import { DynamicIcon, Markdown } from '~/components';
|
||||||
import { useColorValue } from '~/context';
|
import { useColorValue } from '~/context';
|
||||||
import { isQueryContent } from '~/types';
|
|
||||||
|
|
||||||
import type { THelpModal } from './types';
|
import type { THelpModal } from './types';
|
||||||
|
|
||||||
export const HelpModal = (props: THelpModal): JSX.Element => {
|
export const HelpModal = (props: THelpModal): JSX.Element => {
|
||||||
const { visible, item, name, ...rest } = props;
|
const { visible, item, name, title, ...rest } = props;
|
||||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||||
const bg = useColorValue('whiteSolid.50', 'blackSolid.800');
|
const bg = useColorValue('whiteSolid.50', 'blackSolid.800');
|
||||||
const color = useColorValue('black', 'white');
|
const color = useColorValue('black', 'white');
|
||||||
if (!isQueryContent(item)) {
|
if (item === null) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|
@ -33,19 +32,19 @@ export const HelpModal = (props: THelpModal): JSX.Element => {
|
||||||
minW={3}
|
minW={3}
|
||||||
size="md"
|
size="md"
|
||||||
variant="link"
|
variant="link"
|
||||||
icon={<DynamicIcon icon={{ fi: 'FiInfo' }} />}
|
|
||||||
onClick={onOpen}
|
onClick={onOpen}
|
||||||
colorScheme="blue"
|
colorScheme="blue"
|
||||||
aria-label={`${name}_help`}
|
aria-label={`${name}_help`}
|
||||||
|
icon={<DynamicIcon icon={{ fi: 'FiInfo' }} />}
|
||||||
/>
|
/>
|
||||||
</ScaleFade>
|
</ScaleFade>
|
||||||
<Modal isOpen={isOpen} onClose={onClose} size="xl" motionPreset="slideInRight">
|
<Modal isOpen={isOpen} onClose={onClose} size="xl" motionPreset="slideInRight">
|
||||||
<ModalOverlay />
|
<ModalOverlay />
|
||||||
<ModalContent bg={bg} color={color} py={4} borderRadius="md" {...rest}>
|
<ModalContent bg={bg} color={color} py={4} borderRadius="md" {...rest}>
|
||||||
<ModalHeader>{item.params.title}</ModalHeader>
|
<ModalHeader>{title}</ModalHeader>
|
||||||
<ModalCloseButton />
|
<ModalCloseButton />
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Markdown content={item.content} />
|
<Markdown content={item} />
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import type { ModalContentProps } from '@chakra-ui/react';
|
import type { ModalContentProps } from '@chakra-ui/react';
|
||||||
import type { QueryContent } from '~/types';
|
|
||||||
|
|
||||||
export interface THelpModal extends ModalContentProps {
|
export interface THelpModal extends Omit<ModalContentProps, 'title'> {
|
||||||
item: QueryContent | null;
|
title: string | null;
|
||||||
|
item: string | null;
|
||||||
name: string;
|
name: string;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,9 +189,10 @@ export const LookingGlass = (): JSX.Element => {
|
||||||
label={web.text.queryType}
|
label={web.text.queryType}
|
||||||
labelAddOn={
|
labelAddOn={
|
||||||
<HelpModal
|
<HelpModal
|
||||||
visible={directive?.info !== null}
|
|
||||||
item={directive?.info ?? null}
|
|
||||||
name="queryType"
|
name="queryType"
|
||||||
|
title={directive?.name ?? null}
|
||||||
|
item={directive?.info ?? null}
|
||||||
|
visible={directive?.info !== null}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ type _DirectiveBase = {
|
||||||
field_type: 'text' | 'select' | null;
|
field_type: 'text' | 'select' | null;
|
||||||
description: string;
|
description: string;
|
||||||
groups: string[];
|
groups: string[];
|
||||||
info: _QueryContent | null;
|
info: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
type _DirectiveOption = {
|
type _DirectiveOption = {
|
||||||
|
|
@ -136,18 +136,6 @@ interface _Device {
|
||||||
description: string | null;
|
description: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface _QueryContent {
|
|
||||||
content: string;
|
|
||||||
enable: boolean;
|
|
||||||
params: {
|
|
||||||
primary_asn: _Config['primary_asn'];
|
|
||||||
org_name: _Config['org_name'];
|
|
||||||
site_title: _Config['site_title'];
|
|
||||||
title: string;
|
|
||||||
[k: string]: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface _Content {
|
interface _Content {
|
||||||
credit: string;
|
credit: string;
|
||||||
greeting: string;
|
greeting: string;
|
||||||
|
|
@ -196,7 +184,6 @@ export interface Favicon {
|
||||||
export type Config = CamelCasedPropertiesDeep<_ConfigDeep> & CamelCasedProperties<_ConfigShallow>;
|
export type Config = CamelCasedPropertiesDeep<_ConfigDeep> & CamelCasedProperties<_ConfigShallow>;
|
||||||
export type ThemeConfig = CamelCasedProperties<_ThemeConfig>;
|
export type ThemeConfig = CamelCasedProperties<_ThemeConfig>;
|
||||||
export type Content = CamelCasedProperties<_Content>;
|
export type Content = CamelCasedProperties<_Content>;
|
||||||
export type QueryContent = CamelCasedPropertiesDeep<_QueryContent>;
|
|
||||||
export type Device = CamelCasedPropertiesDeep<_Device>;
|
export type Device = CamelCasedPropertiesDeep<_Device>;
|
||||||
export type DeviceGroup = CamelCasedPropertiesDeep<_DeviceGroup>;
|
export type DeviceGroup = CamelCasedPropertiesDeep<_DeviceGroup>;
|
||||||
export type Directive = CamelCasedPropertiesDeep<_Directive>;
|
export type Directive = CamelCasedPropertiesDeep<_Directive>;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { FormData, TStringTableData, TQueryResponseString } from './data';
|
import type { FormData, TStringTableData, TQueryResponseString } from './data';
|
||||||
import type { QueryContent, DirectiveSelect, Directive } from './config';
|
import type { DirectiveSelect, Directive } from './config';
|
||||||
|
|
||||||
export function isString(a: unknown): a is string {
|
export function isString(a: unknown): a is string {
|
||||||
return typeof a === 'string';
|
return typeof a === 'string';
|
||||||
|
|
@ -25,10 +25,6 @@ export function isStringOutput(data: unknown): data is TQueryResponseString {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isQueryContent(content: unknown): content is QueryContent {
|
|
||||||
return isObject(content) && 'content' in content;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if a form field name is a valid form key name.
|
* Determine if a form field name is a valid form key name.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue