diff --git a/docs/docs/api.mdx b/docs/docs/api.mdx
index 4b5c581..dff1da2 100644
--- a/docs/docs/api.mdx
+++ b/docs/docs/api.mdx
@@ -56,7 +56,7 @@ FastAPI provides built in support for both [Swagger UI](https://swagger.io/tools
## Example
-```yaml
+```yaml title="hyperglass.yaml"
docs:
base_url: https://lg.example.net
description: ""
diff --git a/docs/docs/cache.mdx b/docs/docs/cache.mdx
index 4145b2c..25a33e5 100644
--- a/docs/docs/cache.mdx
+++ b/docs/docs/cache.mdx
@@ -24,7 +24,7 @@ hyperglass caches every query response to a Redis database, and always responds
## Example
-```yaml
+```yaml title="hyperglass.yaml"
cache:
database: 0
host: localhost
diff --git a/docs/docs/commands.mdx b/docs/docs/commands.mdx
index e3ff59f..6b3b032 100644
--- a/docs/docs/commands.mdx
+++ b/docs/docs/commands.mdx
@@ -44,7 +44,7 @@ Only the command you specify will be overridden.
Each command definition carries the following structure:
-```yaml
+```yaml title="commands.yaml"
command_name:
ipv4_default: ...
bgp_route: ...
diff --git a/docs/docs/configuration.mdx b/docs/docs/configuration.mdx
index 14a6059..1bdb014 100644
--- a/docs/docs/configuration.mdx
+++ b/docs/docs/configuration.mdx
@@ -61,7 +61,7 @@ The `netmiko_delay_factor` parameter should only be used if you're experiencing
#### Example
-```yaml
+```yaml title="hyperglass.yaml"
debug: false
developer_mode: false
org_name: Beloved Hyperglass User
@@ -92,7 +92,7 @@ From the top level, the following subsections may be defined and configured:
To add, as an example, a Cisco router, add the following to your `devices.yaml`, with the relevant details changed for your device:
-```yaml
+```yaml title="devices.yaml"
routers:
- name: router01.pop01
address: 10.0.0.1
diff --git a/docs/docs/devices.mdx b/docs/docs/devices.mdx
index 3a804a3..6c7bc89 100644
--- a/docs/docs/devices.mdx
+++ b/docs/docs/devices.mdx
@@ -16,22 +16,22 @@ import Code from "../src/components/JSXCode";
## All Device Parameters
-| Parameter | Type | Description |
-| :------------------ | :-----: | :-------------------------------------------------------------------------------------------------------------------------------- |
-| `name` | String | Device hostname. This is not user-facing. |
-| `address` | String | Device management hostname or IP address. |
-| `network` | String | Primary network this device is a member of. Used for device grouping. Usually something like 'AS65000'. |
-| `display_name` | String | Device's user-facing name. |
-| `port` | Integer | TCP port used to connect to the device. |
-| `nos` | String | Network Operating System. Must be a supported platform. |
-| `credential` | | Device Credential Configuration |
-| `vrfs` | | Device VRF Configuration |
-| `proxy` | | SSH Proxy Configuration |
-| `ssl` | | SSL Configuration for devices using [hyperglass-agent](https://github.com/checktheroads/hyperglass-agent). |
+| Parameter | Type | Description |
+| :------------------ | :-----: | :----------------------------------------------------------------------------------------------------------------- |
+| `name` | String | Device hostname. This is not user-facing. |
+| `address` | String | Device management hostname or IP address. |
+| `network` | String | Primary network this device is a member of. Used for device grouping. Usually something like 'AS65000'. |
+| `display_name` | String | Device's user-facing name. |
+| `port` | Integer | TCP port used to connect to the device. |
+| `nos` | String | Network Operating System. Must be a supported platform. |
+| `credential` | | [Device Credential Configuration](#credential) |
+| `vrfs` | | [Device VRF Configuration](#vrf) |
+| `proxy` | | [SSH Proxy Configuration](#proxy) |
+| `ssl` | | [SSL Configuration](#ss;) for devices using [hyperglass-agent](https://github.com/checktheroads/hyperglass-agent). |
### `proxy`
-Any device that uses SSH (see platforms for breakdown) can be accessed through an intermediary SSH "proxy". The process is nearly identical to using local SSH tunneling, e.g. `ssh -L local_port:remote_device:remote_port username@proxy_server -p proxy_port`.
+Any device that uses SSH (see [platforms](platforms.mdx) for breakdown) can be accessed through an intermediary SSH "proxy". The process is nearly identical to using local SSH tunneling, e.g. `ssh -L local_port:remote_device:remote_port username@proxy_server -p proxy_port`.
| Parameter | Type | Default | Description |
| :---------------- | :-----: | :------------ | :--------------------------------------------------------------------------------------------------------------------- |
@@ -128,7 +128,7 @@ Each VRF may enable, disable, or customize the contextual help menu for each ena
For example:
-```yaml
+```yaml title="devices.yaml"
info:
bgp_route:
enable: true
@@ -151,7 +151,7 @@ Telnet support is provided via the underlying device connection handling framewo
For example:
-```yaml {3-4}
+```yaml {3-4} title="devices.yaml"
routers:
- name: router01
nos: cisco_ios_telnet
@@ -163,7 +163,7 @@ routers:
Below is a full example with nearly every available knob turned:
-```yaml
+```yaml title="devices.yaml"
routers:
# HTTP/hyperglass-agent device
- name: router01
diff --git a/docs/docs/logging.mdx b/docs/docs/logging.mdx
index 57cfeb8..5d5bb36 100644
--- a/docs/docs/logging.mdx
+++ b/docs/docs/logging.mdx
@@ -105,7 +105,7 @@ If the `provider` field is set to `'generic'`, the webhook will POST JSON data i
## Full example
-```yaml
+```yaml title="hyperglass.yaml"
logging:
directory: /var/log
format: json
diff --git a/docs/docs/messages.mdx b/docs/docs/messages.mdx
index f7dff73..19df58c 100644
--- a/docs/docs/messages.mdx
+++ b/docs/docs/messages.mdx
@@ -32,7 +32,7 @@ All user-facing status messages can be customized if needed.
## Example
-```yaml
+```yaml title="hyperglass.yaml"
messages:
acl_denied: "{target} is a member of {denied_network}, which is not allowed."
acl_not_allowed: "{target} is not allowed."
diff --git a/docs/docs/production.mdx b/docs/docs/production.mdx
index 70771f1..1353bda 100644
--- a/docs/docs/production.mdx
+++ b/docs/docs/production.mdx
@@ -13,7 +13,7 @@ You'll want to run hyperglass behind a reverse proxy in production to serve the
The following file can be placed anywhere, and referenced at runtime with `sudo caddy run -config `. The highlighted lines should be replaced with your installation's specific variables.
-```text {1,2,4,5,8,11}
+```text {1,2,4,5,8,11} title="Caddy"
lg.example.com:443 {
tls person@example.com
file_server {
@@ -38,7 +38,7 @@ The `tls` directive will tell Caddy to automatically use Let's Encrypt to genera
The following file can be placed at `/etc/nginx/sites-enabled/hyperglass`. It supports IPv6, and will automatically redirect to HTTPS. The highlighted lines should be replaced with your installation's specific variables.
-```nginx {4,9,10,17,19}
+```nginx {4,9,10,17,19} title="NGINX"
server {
listen 80;
listen [::]:80;
diff --git a/docs/docs/queries.mdx b/docs/docs/queries.mdx
index 02ed12f..789443b 100644
--- a/docs/docs/queries.mdx
+++ b/docs/docs/queries.mdx
@@ -24,7 +24,7 @@ Each query type may be disabled, enabled, or customized. The `display_name` para
#### Example
-```yaml
+```yaml title="hyperglass.yaml"
queries:
bgp_route:
display_name: BGP Route
@@ -53,7 +53,7 @@ If using `select` mode, you may define a list of communities the users can choos
#### Example
-```yaml
+```yaml title="hyperglass.yaml"
queries:
bgp_community:
enable: true
@@ -80,7 +80,7 @@ If using `input` mode, hyperglass allows you to override the default regular exp
#### Example
-```yaml
+```yaml title="hyperglass.yaml"
queries:
bgp_community:
enable: true
@@ -106,7 +106,7 @@ Regular expression patterns must be enclosed in single quotes, e.g. `'^.*$'`
#### Example
-```yaml
+```yaml title="hyperglass.yaml"
queries:
bgp_aspath:
display_name: BGP AS Path
@@ -137,7 +137,7 @@ AS Path regular expression patterns may also be customized, should you wish to m
#### Example
-```yaml
+```yaml title="hyperglass.yaml"
queries:
ping:
display_name: Ping
@@ -154,7 +154,7 @@ queries:
#### Example
-```yaml
+```yaml title="hyperglass.yaml"
queries:
traceroute:
display_name: Traceroute
diff --git a/docs/docs/ui.mdx b/docs/docs/ui.mdx
index c904b92..84bac95 100644
--- a/docs/docs/ui.mdx
+++ b/docs/docs/ui.mdx
@@ -169,7 +169,7 @@ Currently, only [Google Fonts](https://fonts.google.com/) are supported.
## Example
-```yaml
+```yaml title="hyperglass.yaml"
web:
credit:
enable: true
diff --git a/docs/package.json b/docs/package.json
index 2766523..d61019e 100755
--- a/docs/package.json
+++ b/docs/package.json
@@ -9,9 +9,9 @@
"deploy": "docusaurus deploy"
},
"dependencies": {
- "@docusaurus/core": "^2.0.0-alpha.43",
- "@docusaurus/plugin-sitemap": "^2.0.0-alpha.37",
- "@docusaurus/preset-classic": "^2.0.0-alpha.43",
+ "@docusaurus/core": "^2.0.0-alpha.50",
+ "@docusaurus/plugin-sitemap": "^2.0.0-alpha.50",
+ "@docusaurus/preset-classic": "^2.0.0-alpha.50",
"classnames": "^2.2.6",
"prismjs": "^1.19.0",
"prop-types": "^15.7.2",
diff --git a/docs/src/theme/CodeBlock/index.js b/docs/src/theme/CodeBlock/index.js
old mode 100755
new mode 100644
index 66ed028..1401bbe
--- a/docs/src/theme/CodeBlock/index.js
+++ b/docs/src/theme/CodeBlock/index.js
@@ -1,10 +1,12 @@
/**
- * Copyright (c) 2017-present, Facebook, Inc.
+ * Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
+/* eslint-disable jsx-a11y/no-noninteractive-tabindex */
+
import React, { useEffect, useState, useRef } from "react";
import classnames from "classnames";
import Highlight, { defaultProps } from "prism-react-renderer";
@@ -13,9 +15,79 @@ import defaultTheme from "./dracula";
import Clipboard from "clipboard";
import rangeParser from "parse-numeric-range";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import useThemeContext from "@theme/hooks/useThemeContext";
+
import styles from "./styles.module.css";
const highlightLinesRangeRegex = /{([\d,-]+)}/;
+const getHighlightDirectiveRegex = (
+ languages = ["js", "jsBlock", "jsx", "python", "html"]
+) => {
+ // supported types of comments
+ const comments = {
+ js: {
+ start: "\\/\\/",
+ end: "",
+ },
+ jsBlock: {
+ start: "\\/\\*",
+ end: "\\*\\/",
+ },
+ jsx: {
+ start: "\\{\\s*\\/\\*",
+ end: "\\*\\/\\s*\\}",
+ },
+ python: {
+ start: "#",
+ end: "",
+ },
+ html: {
+ start: "",
+ },
+ };
+ // supported directives
+ const directives = [
+ "highlight-next-line",
+ "highlight-start",
+ "highlight-end",
+ ].join("|");
+ // to be more reliable, the opening and closing comment must match
+ const commentPattern = languages
+ .map(
+ (lang) =>
+ `(?:${comments[lang].start}\\s*(${directives})\\s*${comments[lang].end})`
+ )
+ .join("|");
+ // white space is allowed, but otherwise it should be on it's own line
+ return new RegExp(`^\\s*(?:${commentPattern})\\s*$`);
+};
+// select comment styles based on language
+const highlightDirectiveRegex = (lang) => {
+ switch (lang) {
+ case "js":
+ case "javascript":
+ case "ts":
+ case "typescript":
+ return getHighlightDirectiveRegex(["js", "jsBlock"]);
+
+ case "jsx":
+ case "tsx":
+ return getHighlightDirectiveRegex(["js", "jsBlock", "jsx"]);
+
+ case "html":
+ return getHighlightDirectiveRegex(["js", "jsBlock", "html"]);
+
+ case "python":
+ case "py":
+ return getHighlightDirectiveRegex(["python"]);
+
+ default:
+ // all comment types
+ return getHighlightDirectiveRegex();
+ }
+};
+const codeBlockTitleRegex = /title=".*"/;
export default ({ children, className: languageClassName, metastring }) => {
(typeof global !== "undefined" ? global : window).Prism = Prism;
@@ -26,10 +98,29 @@ export default ({ children, className: languageClassName, metastring }) => {
themeConfig: { prism = {} },
},
} = useDocusaurusContext();
- // const [showCopied, setShowCopied] = useState(false);
+
+ const [showCopied, setShowCopied] = useState(false);
+ const [mounted, setMounted] = useState(false);
+ // The Prism theme on SSR is always the default theme but the site theme
+ // can be in a different mode. React hydration doesn't update DOM styles
+ // that come from SSR. Hence force a re-render after mounting to apply the
+ // current relevant styles. There will be a flash seen of the original
+ // styles seen using this current approach but that's probably ok. Fixing
+ // the flash will require changing the theming approach and is not worth it
+ // at this point.
+ useEffect(() => {
+ setMounted(true);
+ }, []);
+
const target = useRef(null);
const button = useRef(null);
let highlightLines = [];
+ let codeBlockTitle = "";
+
+ const { isDarkTheme } = useThemeContext();
+ const lightModeTheme = prism.theme || defaultTheme;
+ const darkModeTheme = prism.darkTheme || lightModeTheme;
+ const prismTheme = isDarkTheme ? darkModeTheme : lightModeTheme;
if (metastring && highlightLinesRangeRegex.test(metastring)) {
const highlightLinesRange = metastring.match(highlightLinesRangeRegex)[1];
@@ -38,6 +129,13 @@ export default ({ children, className: languageClassName, metastring }) => {
.filter((n) => n > 0);
}
+ if (metastring && codeBlockTitleRegex.test(metastring)) {
+ codeBlockTitle = metastring
+ .match(codeBlockTitleRegex)[0]
+ .split("title=")[1]
+ .replace(/"+/g, "");
+ }
+
useEffect(() => {
let clipboard;
@@ -61,53 +159,113 @@ export default ({ children, className: languageClassName, metastring }) => {
language = prism.defaultLanguage;
}
- // const handleCopyCode = () => {
- // window.getSelection().empty();
- // setShowCopied(true);
+ // only declaration OR directive highlight can be used for a block
+ let code = children.replace(/\n$/, "");
+ if (highlightLines.length === 0 && language !== undefined) {
+ let range = "";
+ const directiveRegex = highlightDirectiveRegex(language);
+ // go through line by line
+ const lines = children.replace(/\n$/, "").split("\n");
+ let blockStart;
+ // loop through lines
+ for (let index = 0; index < lines.length; ) {
+ const line = lines[index];
+ // adjust for 0-index
+ const lineNumber = index + 1;
+ const match = line.match(directiveRegex);
+ if (match !== null) {
+ const directive = match
+ .slice(1)
+ .reduce((final, item) => final || item, undefined);
+ switch (directive) {
+ case "highlight-next-line":
+ range += `${lineNumber},`;
+ break;
- // setTimeout(() => setShowCopied(false), 2000);
- // };
+ case "highlight-start":
+ blockStart = lineNumber;
+ break;
+
+ case "highlight-end":
+ range += `${blockStart}-${lineNumber - 1},`;
+ break;
+
+ default:
+ break;
+ }
+ lines.splice(index, 1);
+ } else {
+ // lines without directives are unchanged
+ index += 1;
+ }
+ }
+ highlightLines = rangeParser.parse(range);
+ code = lines.join("\n");
+ }
+
+ const handleCopyCode = () => {
+ window.getSelection().empty();
+ setShowCopied(true);
+
+ setTimeout(() => setShowCopied(false), 2000);
+ };
return (
{({ className, style, tokens, getLineProps, getTokenProps }) => (
-