From 90eeab5fd78e23c004beb471da5ab38aaa860713 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Thu, 6 Nov 2025 16:46:30 +0000 Subject: [PATCH 1/4] DOC-5931 initial infra for hierarchy diagrams --- .../_markup/render-codeblock-hierarchy.html | 4 + layouts/_default/baseof.html | 5 + static/js/hierarchy.js | 291 ++++++++++++++++++ 3 files changed, 300 insertions(+) create mode 100644 layouts/_default/_markup/render-codeblock-hierarchy.html create mode 100644 static/js/hierarchy.js diff --git a/layouts/_default/_markup/render-codeblock-hierarchy.html b/layouts/_default/_markup/render-codeblock-hierarchy.html new file mode 100644 index 000000000..012b0ff05 --- /dev/null +++ b/layouts/_default/_markup/render-codeblock-hierarchy.html @@ -0,0 +1,4 @@ +{{- $type := .Attributes.type | default "generic" -}} +
{{ .Inner | htmlEscape | safeHTML }}
+{{ .Page.Store.Set "hasHierarchy" true }} + diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index fac415cc8..45b531979 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -99,5 +99,10 @@ {{ if .Page.Store.Get "hasChecklist" }} {{ end }} + + + {{ if .Page.Store.Get "hasHierarchy" }} + + {{ end }} diff --git a/static/js/hierarchy.js b/static/js/hierarchy.js new file mode 100644 index 000000000..ae12d3d71 --- /dev/null +++ b/static/js/hierarchy.js @@ -0,0 +1,291 @@ +document.addEventListener('DOMContentLoaded', () => { + const hierarchies = document.querySelectorAll('pre.hierarchy-source'); + console.log('Found', hierarchies.length, 'hierarchy(ies)'); + + hierarchies.forEach(pre => { + const hierarchyType = pre.getAttribute('data-hierarchy-type'); + const yamlContent = pre.textContent; + console.log('Processing hierarchy:', hierarchyType); + + createHierarchyFromYAML(yamlContent, hierarchyType, pre); + }); +}); + +// Simple YAML parser for hierarchy format +function parseYAML(yamlText) { + const lines = yamlText.split('\n'); + const root = {}; + const stack = [{ node: root, indent: -1 }]; + const skipLines = new Set(); // Track lines to skip + + for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) { + const line = lines[lineIndex]; + + if (skipLines.has(lineIndex)) continue; + if (!line.trim() || line.trim().startsWith('#')) continue; + + const indent = line.search(/\S/); + const content = line.trim(); + + // Remove trailing colon if present + const keyMatch = content.match(/^"([^"]+)"|^([^:]+)/); + if (!keyMatch) continue; + + const key = keyMatch[1] || keyMatch[2]; + const isMetaKey = key === '_meta'; + + // Pop stack until we find the right parent + while (stack.length > 1 && stack[stack.length - 1].indent >= indent) { + stack.pop(); + } + + const parent = stack[stack.length - 1].node; + + if (isMetaKey) { + // Parse metadata object + parent._meta = {}; + let i = lineIndex + 1; + + while (i < lines.length) { + const nextLine = lines[i]; + if (!nextLine.trim()) { + i++; + continue; + } + const nextIndent = nextLine.search(/\S/); + if (nextIndent <= indent) break; + + const metaMatch = nextLine.trim().match(/^([^:]+):\s*(.+)$/); + if (metaMatch) { + const metaKey = metaMatch[1].trim(); + let metaValue = metaMatch[2].trim(); + + // Parse boolean values + if (metaValue === 'true') metaValue = true; + else if (metaValue === 'false') metaValue = false; + else if (!isNaN(metaValue)) metaValue = parseInt(metaValue); + + parent._meta[metaKey] = metaValue; + } + skipLines.add(i); // Mark this line to skip in main loop + i++; + } + } else { + // Regular node + parent[key] = {}; + stack.push({ node: parent[key], indent: indent }); + } + } + + return root; +} + +function createHierarchyFromYAML(yamlText, hierarchyType, preElement) { + const data = parseYAML(yamlText); + const rootKey = Object.keys(data)[0]; + + if (!rootKey) return; + + // Build flat list of items with depth info + const items = []; + flattenHierarchy(rootKey, data[rootKey], 0, items); + + // Calculate SVG dimensions + const lineHeight = 24; + const charWidth = 8; + const leftMargin = 20; + const topMargin = 10; + const indentWidth = 20; + + // Find max depth and max text width + let maxDepth = 0; + let maxTextWidth = 0; + items.forEach(item => { + maxDepth = Math.max(maxDepth, item.depth); + maxTextWidth = Math.max(maxTextWidth, item.name.length); + }); + + const svgWidth = leftMargin + (maxDepth + 1) * indentWidth + maxTextWidth * charWidth + 20; + const svgHeight = topMargin + items.length * lineHeight + 10; + + // Create SVG + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + svg.setAttribute('width', svgWidth); + svg.setAttribute('height', svgHeight); + svg.setAttribute('class', 'hierarchy-diagram'); + svg.style.marginTop = '1em'; + svg.style.marginBottom = '1em'; + svg.style.fontFamily = '"Space Mono", monospace'; + svg.style.fontSize = '14px'; + + // Draw items and tree lines + items.forEach((item, index) => { + const y = topMargin + index * lineHeight + 12; // Adjusted for middle alignment + const x = leftMargin + item.depth * indentWidth; + + // Draw tree structure lines + if (item.depth > 0) { + drawTreeLines(svg, item, items, index, leftMargin, topMargin, lineHeight, indentWidth); + } else if (item.depth === 0 && items.length > 1) { + // For root item, draw a short horizontal line and pip if there are children + drawRootConnector(svg, item, items, index, leftMargin, topMargin, lineHeight, indentWidth); + } + + // Draw text + const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); + text.setAttribute('x', x + 20); + text.setAttribute('y', y); + text.setAttribute('font-family', '"Space Mono", monospace'); + text.setAttribute('font-size', '14'); + text.setAttribute('fill', '#333'); + text.setAttribute('dominant-baseline', 'middle'); + text.textContent = item.name; + svg.appendChild(text); + + // Add description as title if available + if (item.description) { + const title = document.createElementNS('http://www.w3.org/2000/svg', 'title'); + title.textContent = item.description; + text.appendChild(title); + } + }); + + // Replace the
 element with the SVG
+    preElement.replaceWith(svg);
+}
+
+function flattenHierarchy(name, nodeData, depth, items) {
+    const isEllipsis = nodeData._meta?.ellipsis === true;
+
+    items.push({
+        name: name,
+        depth: depth,
+        description: nodeData._meta?.description || null,
+        isEllipsis: isEllipsis
+    });
+
+    // Only process children if this is not an ellipsis item
+    if (!isEllipsis) {
+        const children = Object.keys(nodeData).filter(k => k !== '_meta');
+        children.forEach(childKey => {
+            flattenHierarchy(childKey, nodeData[childKey], depth + 1, items);
+        });
+    }
+}
+
+function drawTreeLines(svg, item, items, itemIndex, leftMargin, topMargin, lineHeight, indentWidth) {
+    const y = topMargin + itemIndex * lineHeight + 12; // Middle of text
+    const x = leftMargin + item.depth * indentWidth;
+    const parentX = x - indentWidth;
+    const connectorX = parentX + 10; // Line comes from under first letter of parent
+
+    // Find parent item to get its y position
+    let parentY = null;
+    for (let i = itemIndex - 1; i >= 0; i--) {
+        if (items[i].depth === item.depth - 1) {
+            parentY = topMargin + i * lineHeight + 12;
+            break;
+        }
+    }
+
+    // Check if this is the last child at this depth
+    let isLastChild = true;
+    let nextSiblingY = null;
+    for (let i = itemIndex + 1; i < items.length; i++) {
+        if (items[i].depth < item.depth) {
+            isLastChild = true;
+            break;
+        }
+        if (items[i].depth === item.depth) {
+            isLastChild = false;
+            nextSiblingY = topMargin + i * lineHeight + 12;
+            break;
+        }
+    }
+
+    // Draw vertical line from parent (connecting all siblings)
+    if (itemIndex > 0) {
+        // Find first sibling at this depth
+        let firstSiblingY = y;
+        for (let i = itemIndex - 1; i >= 0; i--) {
+            if (items[i].depth < item.depth) break;
+            if (items[i].depth === item.depth) {
+                firstSiblingY = topMargin + i * lineHeight + 12;
+            }
+        }
+
+        // Draw vertical line connecting all siblings, extending up to parent
+        const verticalStartY = parentY !== null ? parentY : Math.min(firstSiblingY, y);
+        const verticalEndY = nextSiblingY || y;
+
+        const vline = document.createElementNS('http://www.w3.org/2000/svg', 'line');
+        vline.setAttribute('x1', connectorX);
+        vline.setAttribute('y1', verticalStartY);
+        vline.setAttribute('x2', connectorX);
+        vline.setAttribute('y2', verticalEndY);
+        vline.setAttribute('stroke', '#999');
+        vline.setAttribute('stroke-width', '1');
+        svg.appendChild(vline);
+    }
+
+    // Draw horizontal line from vertical to item, protruding slightly past the text
+    const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
+    line.setAttribute('x1', connectorX);
+    line.setAttribute('y1', y);
+    line.setAttribute('x2', x + 16); // Protrude slightly to point at text with gap
+    line.setAttribute('y2', y);
+    line.setAttribute('stroke', '#999');
+    line.setAttribute('stroke-width', '1');
+    svg.appendChild(line);
+
+    // For ellipsis items, draw a dotted vertical line segment
+    if (item.isEllipsis) {
+        const dotLine = document.createElementNS('http://www.w3.org/2000/svg', 'line');
+        dotLine.setAttribute('x1', connectorX);
+        dotLine.setAttribute('y1', y);
+        dotLine.setAttribute('x2', connectorX);
+        dotLine.setAttribute('y2', y + lineHeight / 2);
+        dotLine.setAttribute('stroke', '#999');
+        dotLine.setAttribute('stroke-width', '1');
+        dotLine.setAttribute('stroke-dasharray', '2,2');
+        svg.appendChild(dotLine);
+    }
+}
+
+function drawRootConnector(svg, item, items, itemIndex, leftMargin, topMargin, lineHeight, indentWidth) {
+    const y = topMargin + itemIndex * lineHeight + 12; // Middle of text
+    const x = leftMargin + item.depth * indentWidth;
+    const connectorX = x + 10; // Vertical line position
+
+    // Find the first child to determine where the vertical line should extend
+    let firstChildY = null;
+    for (let i = itemIndex + 1; i < items.length; i++) {
+        if (items[i].depth > item.depth) {
+            firstChildY = topMargin + i * lineHeight + 12;
+            break;
+        }
+    }
+
+    if (firstChildY !== null) {
+        // Draw vertical line from root down to first child
+        const vline = document.createElementNS('http://www.w3.org/2000/svg', 'line');
+        vline.setAttribute('x1', connectorX);
+        vline.setAttribute('y1', y);
+        vline.setAttribute('x2', connectorX);
+        vline.setAttribute('y2', firstChildY);
+        vline.setAttribute('stroke', '#999');
+        vline.setAttribute('stroke-width', '1');
+        svg.appendChild(vline);
+
+        // Draw a small horizontal line from root to point at its text
+        const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
+        line.setAttribute('x1', connectorX);
+        line.setAttribute('y1', y);
+        line.setAttribute('x2', x + 16);
+        line.setAttribute('y2', y);
+        line.setAttribute('stroke', '#999');
+        line.setAttribute('stroke-width', '1');
+        svg.appendChild(line);
+    }
+}
+

From 61985894e0291698ae4bcbb01af510a85559e374 Mon Sep 17 00:00:00 2001
From: Andy Stark 
Date: Fri, 7 Nov 2025 11:02:29 +0000
Subject: [PATCH 2/4] DOC-5931 polished filesystem hierarchy slightly

---
 static/js/hierarchy.js | 49 ++++++++++++++++++++++++++++++++----------
 1 file changed, 38 insertions(+), 11 deletions(-)

diff --git a/static/js/hierarchy.js b/static/js/hierarchy.js
index ae12d3d71..f1f624933 100644
--- a/static/js/hierarchy.js
+++ b/static/js/hierarchy.js
@@ -60,10 +60,19 @@ function parseYAML(yamlText) {
                     const metaKey = metaMatch[1].trim();
                     let metaValue = metaMatch[2].trim();
 
-                    // Parse boolean values
-                    if (metaValue === 'true') metaValue = true;
-                    else if (metaValue === 'false') metaValue = false;
-                    else if (!isNaN(metaValue)) metaValue = parseInt(metaValue);
+                    // Remove surrounding quotes if present
+                    if ((metaValue.startsWith('"') && metaValue.endsWith('"')) ||
+                        (metaValue.startsWith("'") && metaValue.endsWith("'"))) {
+                        metaValue = metaValue.slice(1, -1);
+                        // Unescape escaped quotes
+                        metaValue = metaValue.replace(/\\"/g, '"');
+                        metaValue = metaValue.replace(/\\\\/g, '\\');
+                    } else {
+                        // Parse boolean values
+                        if (metaValue === 'true') metaValue = true;
+                        else if (metaValue === 'false') metaValue = false;
+                        else if (!isNaN(metaValue)) metaValue = parseInt(metaValue);
+                    }
 
                     parent._meta[metaKey] = metaValue;
                 }
@@ -96,16 +105,21 @@ function createHierarchyFromYAML(yamlText, hierarchyType, preElement) {
     const leftMargin = 20;
     const topMargin = 10;
     const indentWidth = 20;
+    const commentGap = 40; // Gap between item name and comment
 
     // Find max depth and max text width
     let maxDepth = 0;
     let maxTextWidth = 0;
+    let maxCommentWidth = 0;
     items.forEach(item => {
         maxDepth = Math.max(maxDepth, item.depth);
         maxTextWidth = Math.max(maxTextWidth, item.name.length);
+        if (item.description) {
+            maxCommentWidth = Math.max(maxCommentWidth, item.description.length);
+        }
     });
 
-    const svgWidth = leftMargin + (maxDepth + 1) * indentWidth + maxTextWidth * charWidth + 20;
+    const svgWidth = leftMargin + (maxDepth + 1) * indentWidth + maxTextWidth * charWidth + commentGap + maxCommentWidth * charWidth + 20;
     const svgHeight = topMargin + items.length * lineHeight + 10;
 
     // Create SVG
@@ -131,7 +145,7 @@ function createHierarchyFromYAML(yamlText, hierarchyType, preElement) {
             drawRootConnector(svg, item, items, index, leftMargin, topMargin, lineHeight, indentWidth);
         }
 
-        // Draw text
+        // Draw text for item name
         const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
         text.setAttribute('x', x + 20);
         text.setAttribute('y', y);
@@ -142,11 +156,18 @@ function createHierarchyFromYAML(yamlText, hierarchyType, preElement) {
         text.textContent = item.name;
         svg.appendChild(text);
 
-        // Add description as title if available
+        // Draw description/comment if available
         if (item.description) {
-            const title = document.createElementNS('http://www.w3.org/2000/svg', 'title');
-            title.textContent = item.description;
-            text.appendChild(title);
+            const comment = document.createElementNS('http://www.w3.org/2000/svg', 'text');
+            comment.setAttribute('x', x + 20 + item.name.length * charWidth + commentGap);
+            comment.setAttribute('y', y);
+            comment.setAttribute('font-family', '"Space Mono", monospace');
+            comment.setAttribute('font-size', '12');
+            comment.setAttribute('fill', '#999');
+            comment.setAttribute('font-style', 'italic');
+            comment.setAttribute('dominant-baseline', 'middle');
+            comment.textContent = item.description;
+            svg.appendChild(comment);
         }
     });
 
@@ -154,13 +175,19 @@ function createHierarchyFromYAML(yamlText, hierarchyType, preElement) {
     preElement.replaceWith(svg);
 }
 
+function cleanDescription(text) {
+    // The YAML parser already handles quote removal and unescaping,
+    // so just return the text as-is
+    return text || null;
+}
+
 function flattenHierarchy(name, nodeData, depth, items) {
     const isEllipsis = nodeData._meta?.ellipsis === true;
 
     items.push({
         name: name,
         depth: depth,
-        description: nodeData._meta?.description || null,
+        description: cleanDescription(nodeData._meta?.description),
         isEllipsis: isEllipsis
     });
 

From 4f348fc52aa8a59aecb7cb0a63ec41b55315d185 Mon Sep 17 00:00:00 2001
From: Andy Stark 
Date: Fri, 7 Nov 2025 11:24:56 +0000
Subject: [PATCH 3/4] DOC-5931 final polish on  code block (for now)

---
 .../_markup/render-codeblock-hierarchy.html   |  3 +-
 static/js/hierarchy.js                        | 98 +++++++++++++++++--
 2 files changed, 94 insertions(+), 7 deletions(-)

diff --git a/layouts/_default/_markup/render-codeblock-hierarchy.html b/layouts/_default/_markup/render-codeblock-hierarchy.html
index 012b0ff05..21629cbc0 100644
--- a/layouts/_default/_markup/render-codeblock-hierarchy.html
+++ b/layouts/_default/_markup/render-codeblock-hierarchy.html
@@ -1,4 +1,5 @@
 {{- $type := .Attributes.type | default "generic" -}}
-
{{ .Inner | htmlEscape | safeHTML }}
+{{- $noIcons := .Attributes.noicons | default "" -}} +
{{ .Inner | htmlEscape | safeHTML }}
{{ .Page.Store.Set "hasHierarchy" true }} diff --git a/static/js/hierarchy.js b/static/js/hierarchy.js index f1f624933..e768a394b 100644 --- a/static/js/hierarchy.js +++ b/static/js/hierarchy.js @@ -4,10 +4,12 @@ document.addEventListener('DOMContentLoaded', () => { hierarchies.forEach(pre => { const hierarchyType = pre.getAttribute('data-hierarchy-type'); + const noIconsAttr = pre.getAttribute('data-no-icons'); + const noIcons = noIconsAttr && noIconsAttr !== ''; const yamlContent = pre.textContent; - console.log('Processing hierarchy:', hierarchyType); + console.log('Processing hierarchy:', hierarchyType, 'noIcons attr:', noIconsAttr, 'noIcons bool:', noIcons); - createHierarchyFromYAML(yamlContent, hierarchyType, pre); + createHierarchyFromYAML(yamlContent, hierarchyType, pre, noIcons); }); }); @@ -89,7 +91,7 @@ function parseYAML(yamlText) { return root; } -function createHierarchyFromYAML(yamlText, hierarchyType, preElement) { +function createHierarchyFromYAML(yamlText, hierarchyType, preElement, noIcons) { const data = parseYAML(yamlText); const rootKey = Object.keys(data)[0]; @@ -99,6 +101,9 @@ function createHierarchyFromYAML(yamlText, hierarchyType, preElement) { const items = []; flattenHierarchy(rootKey, data[rootKey], 0, items); + // Determine if we should show icons (filesystem type and not disabled) + const showIcons = hierarchyType === 'filesystem' && !noIcons; + // Calculate SVG dimensions const lineHeight = 24; const charWidth = 8; @@ -106,6 +111,8 @@ function createHierarchyFromYAML(yamlText, hierarchyType, preElement) { const topMargin = 10; const indentWidth = 20; const commentGap = 40; // Gap between item name and comment + const iconSize = 16; // Size of icon + const iconGap = 6; // Gap between icon and text // Find max depth and max text width let maxDepth = 0; @@ -119,7 +126,8 @@ function createHierarchyFromYAML(yamlText, hierarchyType, preElement) { } }); - const svgWidth = leftMargin + (maxDepth + 1) * indentWidth + maxTextWidth * charWidth + commentGap + maxCommentWidth * charWidth + 20; + const iconOffset = showIcons ? iconSize + iconGap : 0; + const svgWidth = leftMargin + (maxDepth + 1) * indentWidth + iconOffset + maxTextWidth * charWidth + commentGap + maxCommentWidth * charWidth + 20; const svgHeight = topMargin + items.length * lineHeight + 10; // Create SVG @@ -145,9 +153,15 @@ function createHierarchyFromYAML(yamlText, hierarchyType, preElement) { drawRootConnector(svg, item, items, index, leftMargin, topMargin, lineHeight, indentWidth); } + // Draw icon if enabled + if (showIcons) { + drawIcon(svg, item, x + 20, y, iconSize); + } + // Draw text for item name + const textX = x + 20 + iconOffset; const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); - text.setAttribute('x', x + 20); + text.setAttribute('x', textX); text.setAttribute('y', y); text.setAttribute('font-family', '"Space Mono", monospace'); text.setAttribute('font-size', '14'); @@ -159,7 +173,7 @@ function createHierarchyFromYAML(yamlText, hierarchyType, preElement) { // Draw description/comment if available if (item.description) { const comment = document.createElementNS('http://www.w3.org/2000/svg', 'text'); - comment.setAttribute('x', x + 20 + item.name.length * charWidth + commentGap); + comment.setAttribute('x', textX + item.name.length * charWidth + commentGap); comment.setAttribute('y', y); comment.setAttribute('font-family', '"Space Mono", monospace'); comment.setAttribute('font-size', '12'); @@ -316,3 +330,75 @@ function drawRootConnector(svg, item, items, itemIndex, leftMargin, topMargin, l } } +function drawIcon(svg, item, x, y, size) { + if (item.name === '(root)') { + // Don't draw icon for root + return; + } + + if (item.isEllipsis) { + // Don't draw icon for ellipsis items (the "..." text is enough) + return; + } else if (item.name.includes('.')) { + // File icon (has extension) + drawFileIcon(svg, x, y, size); + } else { + // Folder icon + drawFolderIcon(svg, x, y, size); + } +} + +function drawFileIcon(svg, x, y, size) { + // File icon with folded corner using a path + const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + + // Create path: start at top-left, go right, then down with folded corner, then left, then up + const w = size * 0.6; + const h = size; + const cornerSize = size * 0.25; + + const pathData = ` + M ${x} ${y - h / 2} + L ${x + w - cornerSize} ${y - h / 2} + L ${x + w} ${y - h / 2 + cornerSize} + L ${x + w} ${y + h / 2} + L ${x} ${y + h / 2} + Z + `; + + path.setAttribute('d', pathData); + path.setAttribute('fill', 'none'); + path.setAttribute('stroke', '#c84c4c'); + path.setAttribute('stroke-width', '1'); + path.setAttribute('stroke-linejoin', 'miter'); + svg.appendChild(path); +} + +function drawFolderIcon(svg, x, y, size) { + // Folder icon as single continuous outline using a path + const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + + const tabWidth = size * 0.5; + const tabHeight = size * 0.35; + const bodyWidth = size; + + // Create path: tab outline, then body outline + const pathData = ` + M ${x} ${y - size / 2 + tabHeight} + L ${x} ${y - size / 2} + L ${x + tabWidth} ${y - size / 2} + L ${x + tabWidth} ${y - size / 2 + tabHeight} + L ${x + bodyWidth} ${y - size / 2 + tabHeight} + L ${x + bodyWidth} ${y + size / 2} + L ${x} ${y + size / 2} + Z + `; + + path.setAttribute('d', pathData); + path.setAttribute('fill', 'none'); + path.setAttribute('stroke', '#c84c4c'); + path.setAttribute('stroke-width', '1'); + path.setAttribute('stroke-linejoin', 'miter'); + svg.appendChild(path); +} + From 04e65f1c9df9a327b4506fd8a10f781e3d925204 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Fri, 7 Nov 2025 11:30:51 +0000 Subject: [PATCH 4/4] DOC-5931 example hierarchy diagrams --- .../develop/clients/jedis/error-handling.md | 30 ++++++++++--------- .../clients/redis-py/error-handling.md | 29 ++++++++++-------- .../data-pipelines/_index.md | 26 +++++++++++++--- 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/content/develop/clients/jedis/error-handling.md b/content/develop/clients/jedis/error-handling.md index 528a6ed08..5a2587049 100644 --- a/content/develop/clients/jedis/error-handling.md +++ b/content/develop/clients/jedis/error-handling.md @@ -16,20 +16,22 @@ app reliability. Jedis organizes exceptions in a hierarchy rooted at `JedisException`, which extends `RuntimeException`. All Jedis exceptions are unchecked exceptions: -``` -JedisException -├── JedisDataException -│ ├── JedisRedirectionException -│ │ ├── JedisMovedDataException -│ │ └── JedisAskDataException -│ ├── AbortedTransactionException -│ ├── JedisAccessControlException -│ └── JedisNoScriptException -├── JedisClusterException -│ ├── JedisClusterOperationException -│ ├── JedisConnectionException -│ └── JedisValidationException -└── InvalidURIException +```hierarchy {type="exception"} +"JedisException": + _meta: + description: "Base class for all Jedis exceptions" + "JedisDataException": + "JedisRedirectionException": + "JedisMovedDataException": + "JedisAskDataException": + "AbortedTransactionException": + "JedisAccessControlException": + "JedisNoScriptException": + "JedisClusterException": + "JedisClusterOperationException": + "JedisConnectionException": + "JedisValidationException": + "InvalidURIException": ``` ### Key exceptions diff --git a/content/develop/clients/redis-py/error-handling.md b/content/develop/clients/redis-py/error-handling.md index 52b85c1cd..14bd34b61 100644 --- a/content/develop/clients/redis-py/error-handling.md +++ b/content/develop/clients/redis-py/error-handling.md @@ -17,18 +17,23 @@ app reliability. ## Exception hierarchy -redis-py organizes exceptions in a hierarchy. The base exception is `redis.RedisError`, with specific subclasses for different error types: - -``` -RedisError (base) -├── ConnectionError -│ ├── TimeoutError -│ └── BusyLoadingError -├── ResponseError -├── InvalidResponse -├── DataError -├── PubSubError -└── ... (others) +redis-py organizes exceptions in a hierarchy. The base exception is `redis.RedisError`, with specific subclasses for different error types, as shown below: + +```hierarchy {type="exception"} +"RedisError": + _meta: + description: "Base class for all redis-py exceptions" + "ConnectionError": + "TimeoutError": + "BusyLoadingError": + "ResponseError": + "InvalidResponse": + "DataError": + "PubSubError": + "...": + _meta: + ellipsis: true + description: "Other exception types" ``` ### Key exceptions diff --git a/content/integrate/redis-data-integration/data-pipelines/_index.md b/content/integrate/redis-data-integration/data-pipelines/_index.md index 26942b2e5..b39bcd128 100644 --- a/content/integrate/redis-data-integration/data-pipelines/_index.md +++ b/content/integrate/redis-data-integration/data-pipelines/_index.md @@ -108,10 +108,28 @@ section. ### 2. Configure the pipeline RDI uses a set of [YAML](https://en.wikipedia.org/wiki/YAML) -files to configure each pipeline. The following diagram shows the folder -structure of the configuration: - -{{< image filename="images/rdi/ingest/ingest-config-folders.webp" width="600px" >}} +files to configure each pipeline. The folder structure of the +configuration is shown below: + +```hierarchy {type="filesystem"} +"(root)": + "config.yaml": + _meta: + description: "\"config.yaml\" is the main pipeline configuration file." + "jobs": + _meta: + description: "The 'jobs' folder containing optional job files." + "default-job.yaml": + _meta: + description: "A default job." + "job1.yaml": + _meta: + description: "Each job file must have a unique name." + "...": + _meta: + ellipsis: true + description: "Other job files, if required." +``` The main configuration for the pipeline is in the `config.yaml` file. This specifies the connection details for the source database (such