From c5783d95c56f7290ea96188bcd34a5ec4b0f2984 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Wed, 5 Nov 2025 16:33:40 +0000 Subject: [PATCH 1/6] DOC-5922 added AI-friendly render hook for checklists --- .../_markup/render-codeblock-checklist.html | 4 + layouts/_default/baseof.html | 5 + static/js/checklist.js | 159 ++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 layouts/_default/_markup/render-codeblock-checklist.html create mode 100644 static/js/checklist.js diff --git a/layouts/_default/_markup/render-codeblock-checklist.html b/layouts/_default/_markup/render-codeblock-checklist.html new file mode 100644 index 0000000000..cd0f490bac --- /dev/null +++ b/layouts/_default/_markup/render-codeblock-checklist.html @@ -0,0 +1,4 @@ +{{- $id := .Attributes.id | default "checklist" -}} +
{{ .Inner | htmlEscape | safeHTML }}
+{{ .Page.Store.Set "hasChecklist" true }} + diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index a15d1e0625..bce33e0547 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -79,5 +79,10 @@ {{ partial "toc-js.html" . }} {{ partial "search-modal.html" . }} + + + {{ if .Page.Store.Get "hasChecklist" }} + + {{ end }} diff --git a/static/js/checklist.js b/static/js/checklist.js new file mode 100644 index 0000000000..c38fdbacb7 --- /dev/null +++ b/static/js/checklist.js @@ -0,0 +1,159 @@ +document.addEventListener('DOMContentLoaded', () => { + // Find all checklist code blocks + const checklists = document.querySelectorAll('pre.checklist-source'); + console.log('Found', checklists.length, 'checklist(s)'); + + checklists.forEach(pre => { + const checklistId = pre.getAttribute('data-checklist-id'); + const markdownContent = pre.textContent; + console.log('Processing checklist:', checklistId); + + // Parse markdown and create interactive checklist + createChecklistFromMarkdown(markdownContent, checklistId, pre); + }); +}); + +function createChecklistFromMarkdown(markdown, formId, preElement) { + const lines = markdown.split('\n'); + const items = []; + + // Parse checklist items from markdown + lines.forEach(line => { + const trimmed = line.trim(); + if (trimmed.match(/^- \[[\sx]\]/)) { + items.push(trimmed); + } + }); + + if (items.length === 0) return; + + // Create form + const form = document.createElement('form'); + form.id = formId; + + const ul = document.createElement('ul'); + ul.style.listStyleType = 'none'; + ul.style.paddingLeft = '0px'; + + // Parse each item + items.forEach(item => { + const li = document.createElement('li'); + + // Create select dropdown + const select = document.createElement('select'); + select.onchange = () => clChange(formId); + + const options = [ + { value: 'R', label: '❌' }, + { value: 'G', label: '✅' }, + { value: 'A', label: '🔍' }, + { value: 'X', label: '∅' } + ]; + + options.forEach(opt => { + const option = document.createElement('option'); + option.value = opt.value; + option.innerHTML = opt.label; + select.appendChild(option); + }); + + li.appendChild(select); + + // Parse link and text from markdown + // Format: - [ ] [text](#anchor) or - [ ] text + const linkMatch = item.match(/\[([^\]]+)\]\(([^\)]+)\)/); + if (linkMatch) { + const a = document.createElement('a'); + a.href = linkMatch[2]; + a.textContent = linkMatch[1]; + li.appendChild(a); + } else { + // Just text after the checkbox + const text = item.replace(/^- \[[\sx]\]\s*/, ''); + li.appendChild(document.createTextNode(text)); + } + + ul.appendChild(li); + }); + + form.appendChild(ul); + + // Add counters + const countersDiv = document.createElement('div'); + countersDiv.innerHTML = ` + + 0/0, + + 0/0, + + 0/0 +
+ ( + 0) + `; + form.appendChild(countersDiv); + + // Replace the entire
 element with the interactive form
+    preElement.replaceWith(form);
+    
+    // Initialize
+    let itemString = localStorage.getItem(formId);
+    if (itemString) {
+        setCLItemsFromString(formId, itemString);
+    } else {
+        clChange(formId);
+    }
+}
+
+function getStringFromCLItems(formId) {
+    let result = "";
+    let form = document.getElementById(formId);
+    let listItems = form.getElementsByTagName("li");
+
+    for (let elem of listItems) {
+        let menu = elem.getElementsByTagName("select")[0];
+        result += menu.value;
+    }
+
+    return result;
+}
+
+function setCLItemsFromString(formId, clString) {
+    let counts = {R: 0, G: 0, A: 0, X:0};
+
+    let form = document.getElementById(formId);
+    let listItems = form.getElementsByTagName("li");
+
+    if (clString.length < listItems.length) {
+        clString = clString.padEnd(listItems.length, "R");
+    } else if (clString.length > listItems.length) {
+        clString = clString.substring(0, listItems.length);
+    }
+
+    for (let i = 0; i < clString.length; i++) {
+        let char = clString.charAt(i);
+        counts[char]++;
+        let menu = listItems[i].getElementsByTagName("select")[0];
+        menu.value = char;
+    }
+
+    form.elements["gcount"].value = counts["G"];
+    form.elements["rcount"].value = counts["R"];
+    form.elements["acount"].value = counts["A"];
+    form.elements["xcount"].value = counts["X"];
+
+    let numClItems = listItems.length - counts["X"];
+
+    document.getElementById(formId + "-rtotal").textContent = numClItems;
+    document.getElementById(formId + "-gtotal").textContent = numClItems;
+    document.getElementById(formId + "-atotal").textContent = numClItems;
+
+    let itemChoices = getStringFromCLItems(formId);
+    localStorage.setItem(formId, itemChoices);
+}
+
+function clChange(formId) {
+    let itemChoices = getStringFromCLItems(formId);
+    setCLItemsFromString(formId, itemChoices);
+}
+

From cf443e9b2e8870cca899859632a23ef901efd877 Mon Sep 17 00:00:00 2001
From: Andy Stark 
Date: Wed, 5 Nov 2025 16:34:37 +0000
Subject: [PATCH 2/6] DOC-5922 replaced Python prod usage checklist with
 Markdown

---
 content/develop/clients/redis-py/produsage.md | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/content/develop/clients/redis-py/produsage.md b/content/develop/clients/redis-py/produsage.md
index 89859cd3c6..eea12f9a05 100644
--- a/content/develop/clients/redis-py/produsage.md
+++ b/content/develop/clients/redis-py/produsage.md
@@ -24,14 +24,14 @@ Each item in the checklist below links to the section
 for a recommendation. Use the checklist icons to record your
 progress in implementing the recommendations.
 
-{{< checklist "pyprodlist" >}}
-    {{< checklist-item "#client-side-caching" >}}Client-side caching{{< /checklist-item >}}
-    {{< checklist-item "#retries" >}}Retries{{< /checklist-item >}}
-    {{< checklist-item "#health-checks" >}}Health checks{{< /checklist-item >}}
-    {{< checklist-item "#exception-handling" >}}Exception handling{{< /checklist-item >}}
-    {{< checklist-item "#timeouts" >}}Timeouts{{< /checklist-item >}}
-    {{< checklist-item "#seamless-client-experience" >}}Smart client handoffs{{< /checklist-item >}}
-{{< /checklist >}}
+```checklist {id="pyprodlist"}
+- [ ] [Client-side caching](#client-side-caching)
+- [ ] [Retries](#retries)
+- [ ] [Health checks](#health-checks)
+- [ ] [Exception handling](#exception-handling)
+- [ ] [Timeouts](#timeouts)
+- [ ] [Smart client handoffs](#smart-client-handoffs)
+```
 
 ## Recommendations
 

From 6e9b129183b2ce9e5e51601aad6592f97e6f2cee Mon Sep 17 00:00:00 2001
From: Andy Stark 
Date: Wed, 5 Nov 2025 16:38:48 +0000
Subject: [PATCH 3/6] DOC-5922 updated NRedisStack prod usage checklist

---
 content/develop/clients/dotnet/produsage.md | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/content/develop/clients/dotnet/produsage.md b/content/develop/clients/dotnet/produsage.md
index 1dc8d5a8d0..7792a6449f 100644
--- a/content/develop/clients/dotnet/produsage.md
+++ b/content/develop/clients/dotnet/produsage.md
@@ -24,12 +24,12 @@ Each item in the checklist below links to the section
 for a recommendation. Use the checklist icons to record your
 progress in implementing the recommendations.
 
-{{< checklist "dotnetprodlist" >}}
-    {{< checklist-item "#event-handling" >}}Event handling{{< /checklist-item >}}
-    {{< checklist-item "#timeouts" >}}Timeouts{{< /checklist-item >}}
-    {{< checklist-item "#exception-handling" >}}Exception handling{{< /checklist-item >}}
-    {{< checklist-item "#retries" >}}Retries{{< /checklist-item >}}
-{{< /checklist >}}
+```checklist {id="dotnetprodlist"}
+- [ ] [Event handling](#event-handling)
+- [ ] [Timeouts](#timeouts)
+- [ ] [Exception handling](#exception-handling)
+- [ ] [Retries](#retries)
+```
 
 ## Recommendations
 

From dedcff94bd41b1e522b0312d0ec703a8bd60897b Mon Sep 17 00:00:00 2001
From: Andy Stark 
Date: Wed, 5 Nov 2025 16:43:44 +0000
Subject: [PATCH 4/6] DOC-5922 added remaining prod usage checklist updates

---
 content/develop/clients/go/produsage.md      | 16 ++++++++--------
 content/develop/clients/jedis/produsage.md   | 18 +++++++++---------
 content/develop/clients/lettuce/produsage.md | 16 ++++++++--------
 content/develop/clients/nodejs/produsage.md  | 14 +++++++-------
 4 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/content/develop/clients/go/produsage.md b/content/develop/clients/go/produsage.md
index 80b11cfa0f..695ffd1015 100644
--- a/content/develop/clients/go/produsage.md
+++ b/content/develop/clients/go/produsage.md
@@ -24,14 +24,14 @@ Each item in the checklist below links to the section
 for a recommendation. Use the checklist icons to record your
 progress in implementing the recommendations.
 
-{{< checklist "goprodlist" >}}
-    {{< checklist-item "#health-checks" >}}Health checks{{< /checklist-item >}}
-    {{< checklist-item "#error-handling" >}}Error handling{{< /checklist-item >}}
-    {{< checklist-item "#monitor-performance-and-errors">}}Monitor performance and errors{{< /checklist-item >}}
-    {{< checklist-item "#retries" >}}Retries{{< /checklist-item >}}
-    {{< checklist-item "#timeouts" >}}Timeouts{{< /checklist-item >}}
-    {{< checklist-item "#seamless-client-experience" >}}Smart client handoffs{{< /checklist-item >}}
-{{< /checklist >}}
+```checklist {id="goprodlist"}
+- [ ] [Health checks](#health-checks)
+- [ ] [Error handling](#error-handling)
+- [ ] [Monitor performance and errors](#monitor-performance-and-errors)
+- [ ] [Retries](#retries)
+- [ ] [Timeouts](#timeouts)
+- [ ] [Smart client handoffs](#seamless-client-experience)
+```
 
 ## Recommendations
 
diff --git a/content/develop/clients/jedis/produsage.md b/content/develop/clients/jedis/produsage.md
index 7b6a4fe293..4aa92ed6a5 100644
--- a/content/develop/clients/jedis/produsage.md
+++ b/content/develop/clients/jedis/produsage.md
@@ -24,15 +24,15 @@ Each item in the checklist below links to the section
 for a recommendation. Use the checklist icons to record your
 progress in implementing the recommendations.
 
-{{< checklist "prodlist" >}}
-    {{< checklist-item "#connection-pooling" >}}Connection pooling{{< /checklist-item >}}
-    {{< checklist-item "#connection-retries" >}}Connection retries{{< /checklist-item >}}
-    {{< checklist-item "#client-side-caching" >}}Client-side caching{{< /checklist-item >}}
-    {{< checklist-item "#timeouts" >}}Timeouts{{< /checklist-item >}}
-    {{< checklist-item "#health-checks" >}}Health checks{{< /checklist-item >}}
-    {{< checklist-item "#exception-handling" >}}Exception handling{{< /checklist-item >}}
-    {{< checklist-item "#dns-cache-and-redis" >}}DNS cache and Redis{{< /checklist-item >}}
-{{< /checklist >}}
+```checklist {id="jedisprodlist"}
+- [ ] [Connection pooling](#connection-pooling)
+- [ ] [Connection retries](#connection-retries)
+- [ ] [Client-side caching](#client-side-caching)
+- [ ] [Timeouts](#timeouts)
+- [ ] [Health checks](#health-checks)
+- [ ] [Exception handling](#exception-handling)
+- [ ] [DNS cache and Redis](#dns-cache-and-redis)
+```
 
 ## Recommendations
 
diff --git a/content/develop/clients/lettuce/produsage.md b/content/develop/clients/lettuce/produsage.md
index 3e636a8141..6c4dcb1766 100644
--- a/content/develop/clients/lettuce/produsage.md
+++ b/content/develop/clients/lettuce/produsage.md
@@ -24,14 +24,14 @@ Each item in the checklist below links to the section
 for a recommendation. Use the checklist icons to record your
 progress in implementing the recommendations.
 
-{{< checklist "lettuceprodlist" >}}
-    {{< checklist-item "#timeouts" >}}Timeouts{{< /checklist-item >}}
-    {{< checklist-item "#cluster-topology-refresh">}}Cluster topology refresh{{< /checklist-item >}}
-    {{< checklist-item "#dns-cache-and-redis" >}}DNS cache and Redis{{< /checklist-item >}}
-    {{< checklist-item "#exception-handling" >}}Exception handling{{< /checklist-item >}}
-    {{< checklist-item "#connection-and-execution-reliability" >}}Connection and execution reliability{{< /checklist-item >}}
-    {{< checklist-item "#seamless-client-experience" >}}Smart client handoffs{{< /checklist-item >}}
-{{< /checklist >}}
+```checklist {id="lettuceprodlist"}
+- [ ] [Timeouts](#timeouts)
+- [ ] [Cluster topology refresh](#cluster-topology-refresh)
+- [ ] [DNS cache and Redis](#dns-cache-and-redis)
+- [ ] [Exception handling](#exception-handling)
+- [ ] [Connection and execution reliability](#connection-and-execution-reliability)
+- [ ] [Smart client handoffs](#seamless-client-experience)
+```
 
 ## Recommendations
 
diff --git a/content/develop/clients/nodejs/produsage.md b/content/develop/clients/nodejs/produsage.md
index 992dc7c37e..74dc20f0dd 100644
--- a/content/develop/clients/nodejs/produsage.md
+++ b/content/develop/clients/nodejs/produsage.md
@@ -24,13 +24,13 @@ Each item in the checklist below links to the section
 for a recommendation. Use the checklist icons to record your
 progress in implementing the recommendations.
 
-{{< checklist "nodeprodlist" >}}
-    {{< checklist-item "#handling-errors" >}}Handling errors{{< /checklist-item >}}
-    {{< checklist-item "#handling-reconnections" >}}Handling reconnections{{< /checklist-item >}}
-    {{< checklist-item "#connection-timeouts" >}}Connection timeouts{{< /checklist-item >}}
-    {{< checklist-item "#command-execution-reliability" >}}Command execution reliability{{< /checklist-item >}}
-    {{< checklist-item "#seamless-client-experience" >}}Smart client handoffs{{< /checklist-item >}}
-{{< /checklist >}}
+```checklist {id="nodeprodlist"}
+- [ ] [Handling errors](#handling-errors)
+- [ ] [Handling reconnections](#handling-reconnections)
+- [ ] [Connection timeouts](#connection-timeouts)
+- [ ] [Command execution reliability](#command-execution-reliability)
+- [ ] [Smart client handoffs](#seamless-client-experience)
+```
 
 ## Recommendations
 

From b400610719bdf9c067df6998faca0c04a46661df Mon Sep 17 00:00:00 2001
From: Andy Stark 
Date: Thu, 6 Nov 2025 10:38:17 +0000
Subject: [PATCH 5/6] DOC-5922 changed JS file to avoid XSS risk

---
 static/js/checklist.js | 52 +++++++++++++++++++++++++++++++++---------
 1 file changed, 41 insertions(+), 11 deletions(-)

diff --git a/static/js/checklist.js b/static/js/checklist.js
index c38fdbacb7..8a961e7fbe 100644
--- a/static/js/checklist.js
+++ b/static/js/checklist.js
@@ -80,17 +80,47 @@ function createChecklistFromMarkdown(markdown, formId, preElement) {
     
     // Add counters
     const countersDiv = document.createElement('div');
-    countersDiv.innerHTML = `
-        
-        0/0,
-        
-        0/0,
-        
-        0/0
-        
- ( - 0) - `; + + // Create counter elements safely without innerHTML + const createCounterLabel = (emoji, countId, totalId, isDisabled = false) => { + const label = document.createElement('label'); + label.htmlFor = countId; + label.textContent = emoji + ' = '; + + const countOutput = document.createElement('output'); + countOutput.name = countId.replace(formId + '-', ''); + countOutput.id = countId; + countOutput.textContent = '0'; + + const fragment = document.createDocumentFragment(); + fragment.appendChild(label); + fragment.appendChild(countOutput); + + if (!isDisabled) { + fragment.appendChild(document.createTextNode('/')); + const totalOutput = document.createElement('output'); + totalOutput.id = totalId; + totalOutput.textContent = '0'; + fragment.appendChild(totalOutput); + fragment.appendChild(document.createTextNode(', ')); + } else { + fragment.appendChild(document.createTextNode(')')); + } + + return fragment; + }; + + countersDiv.appendChild(createCounterLabel('✅', formId + '-gcount', formId + '-gtotal')); + countersDiv.appendChild(createCounterLabel('❌', formId + '-rcount', formId + '-rtotal')); + countersDiv.appendChild(createCounterLabel('🔍', formId + '-acount', formId + '-atotal')); + + const brElement = document.createElement('br'); + countersDiv.appendChild(brElement); + + const openParen = document.createTextNode('('); + countersDiv.appendChild(openParen); + countersDiv.appendChild(createCounterLabel('∅', formId + '-xcount', '', true)); + form.appendChild(countersDiv); // Replace the entire
 element with the interactive form

From 2a1372be04cd52b55fc3c5ab9affdc072be2f1fb Mon Sep 17 00:00:00 2001
From: Andy Stark 
Date: Thu, 6 Nov 2025 10:43:53 +0000
Subject: [PATCH 6/6] DOC-5922 fixed another instance of

---
 static/js/checklist.js | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/static/js/checklist.js b/static/js/checklist.js
index 8a961e7fbe..37ba3dc489 100644
--- a/static/js/checklist.js
+++ b/static/js/checklist.js
@@ -44,16 +44,16 @@ function createChecklistFromMarkdown(markdown, formId, preElement) {
         select.onchange = () => clChange(formId);
         
         const options = [
-            { value: 'R', label: '❌' },
-            { value: 'G', label: '✅' },
-            { value: 'A', label: '🔍' },
-            { value: 'X', label: '∅' }
+            { value: 'R', label: '❌' },
+            { value: 'G', label: '✅' },
+            { value: 'A', label: '🔍' },
+            { value: 'X', label: '∅' }
         ];
-        
+
         options.forEach(opt => {
             const option = document.createElement('option');
             option.value = opt.value;
-            option.innerHTML = opt.label;
+            option.textContent = opt.label;
             select.appendChild(option);
         });