Skip to content

Commit b4ddd1c

Browse files
DOC-5804 updated spec for BinderHub example tab link
1 parent 6dac075 commit b4ddd1c

File tree

1 file changed

+209
-0
lines changed

1 file changed

+209
-0
lines changed

build/tcedocs/SPECIFICATION.md

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ The code example system provides a multi-language, tabbed code example interface
4848
### Key Features
4949

5050
- **Multi-language support**: Display the same example in multiple programming languages
51+
- **Interactive execution**: "Run in browser" links via BinderHub integration (Jupyter notebooks supporting multiple languages)
5152
- **Tabbed interface**: Users can switch between languages using a dropdown selector
5253
- **Code hiding/highlighting**: Support for hiding boilerplate code and highlighting relevant sections
5354
- **Named steps**: Break examples into logical steps that can be referenced individually
@@ -602,6 +603,7 @@ r = redis.Redis(host='localhost', port=6379, decode_responses=True)
602603
- Language selector dropdown
603604
- Visibility toggle button (show/hide hidden code)
604605
- Copy to clipboard button
606+
- BinderHub "Run in browser" link (conditional)
605607
- Tab panels with syntax-highlighted code
606608
- Footer with quickstart links and GitHub source links
607609
- Responsive design with Tailwind CSS
@@ -616,6 +618,118 @@ The interactive features are implemented in JavaScript (location varies by theme
616618

617619
> **Note**: JavaScript implementation details are theme-specific and not covered in this specification.
618620
621+
#### BinderHub Integration ("Run in Browser" Link)
622+
623+
**Purpose**: Provide interactive Jupyter notebook environment for running examples
624+
625+
**Feature Description**:
626+
627+
The code example boxes can display a "Run this example in the browser" link that launches the example in a BinderHub-powered Jupyter notebook environment. This link appears in the top bar of the example box, next to the three-dot menu icon.
628+
629+
**Conditional Display**:
630+
- Only shown if the example has a `binderId` value in its metadata
631+
- If no `binderId` exists, the link is not rendered (no placeholder, no broken link)
632+
- The `binderId` is language-specific, so different languages in the same example set may have different BinderHub links
633+
- BinderHub uses Jupyter notebooks which can run code in multiple languages (Python, Node.js, Java, etc.)
634+
635+
**Link URL Format**:
636+
```
637+
https://redis.io/binder/v2/gh/redis/binder-launchers/<binderId>?urlpath=%2Fdoc%2Ftree%2Fdemo.ipynb
638+
```
639+
640+
**URL Components**:
641+
- **Base URL**: `https://redis.io/binder/v2/gh/redis/binder-launchers/`
642+
- **Binder ID**: The Git commit SHA from `binderId` field (40 hexadecimal characters)
643+
- **URL Path**: `?urlpath=%2Fdoc%2Ftree%2Fdemo.ipynb` (constant, URL-encoded path to notebook)
644+
- **Notebook filename**: Always `demo.ipynb` - do NOT change per example
645+
646+
**Example**:
647+
```
648+
https://redis.io/binder/v2/gh/redis/binder-launchers/6bbed3da294e8de5a8c2ad99abf883731a50d4dd?urlpath=%2Fdoc%2Ftree%2Fdemo.ipynb
649+
```
650+
651+
**Implementation in Hugo Template**:
652+
653+
The `layouts/shortcodes/clients-example.html` template should implement this feature as follows:
654+
655+
**1. Access the binderId from template context**:
656+
657+
```go-html-template
658+
{{- $exampleSet := .Get "set" -}}
659+
{{- $exampleData := index $.Site.Data.examples $exampleSet -}}
660+
661+
{{- range $lang, $langConfig := $.Site.Params.clientsexamples -}}
662+
{{- $langData := index $exampleData $langConfig.label -}}
663+
{{- if $langData -}}
664+
{{- $binderId := $langData.binderId -}}
665+
{{- /* binderId is now available for this language */ -}}
666+
{{- end -}}
667+
{{- end -}}
668+
```
669+
670+
**2. Construct the BinderHub URL**:
671+
672+
```go-html-template
673+
{{- if $binderId -}}
674+
{{- $binderUrl := printf "https://redis.io/binder/v2/gh/redis/binder-launchers/%s?urlpath=%%2Fdoc%%2Ftree%%2Fdemo.ipynb" $binderId -}}
675+
{{- end -}}
676+
```
677+
678+
**3. Render the link in the top bar**:
679+
680+
The link should be placed in the top bar of the example box, alongside the existing menu icon. The exact HTML structure depends on the theme, but conceptually:
681+
682+
```html
683+
<div class="example-top-bar">
684+
<!-- Language selector -->
685+
<select>...</select>
686+
687+
<!-- BinderHub link (conditional) -->
688+
{{ if $binderId }}
689+
<a href="{{ $binderUrl }}"
690+
target="_blank"
691+
rel="noopener noreferrer"
692+
class="binder-link"
693+
title="Run this example in an interactive Jupyter notebook">
694+
Run this example in the browser
695+
</a>
696+
{{ end }}
697+
698+
<!-- Menu icon -->
699+
<button class="menu-icon">...</button>
700+
</div>
701+
```
702+
703+
**4. Styling considerations**:
704+
705+
- Link should be visually distinct but not overwhelming
706+
- Should work on mobile devices (may need to be icon-only on small screens)
707+
- Should indicate it opens in a new tab/window
708+
- Consider adding a BinderHub icon for visual recognition
709+
710+
**Data Flow**:
711+
712+
1. **Build time**: Python scripts extract `BINDER_ID` from source files → store in `data/examples.json`
713+
2. **Hugo build**: Template reads `binderId` from `$.Site.Data.examples[exampleSet][language].binderId`
714+
3. **Template logic**: If `binderId` exists, construct URL and render link
715+
4. **Runtime**: User clicks link → opens BinderHub in new tab
716+
717+
**Important Notes**:
718+
719+
- **Language-specific**: Each language in an example set can have its own `binderId`
720+
- **Multi-language support**: BinderHub uses Jupyter notebooks which can execute code in multiple languages (Python, Node.js, Java, etc.) through language kernels
721+
- **Notebook filename is constant**: Always use `demo.ipynb` - the BinderHub launcher repository handles routing to the correct example
722+
- **URL encoding**: The `?urlpath=%2Fdoc%2Ftree%2Fdemo.ipynb` part is URL-encoded (`%2F` = `/`)
723+
- **External dependency**: Requires the `redis/binder-launchers` repository to be properly configured with the commit referenced by `binderId`
724+
725+
**Relationship to Manual Links**:
726+
727+
Some documentation pages may have manual BinderHub links in the markdown content (e.g., "You can try this code out in a Jupyter notebook on Binder"). The automated link in the example box serves the same purpose but is:
728+
- Automatically generated from metadata
729+
- Consistently placed across all examples
730+
- Easier to maintain (no manual URL construction in markdown)
731+
- Visually integrated with the code example UI
732+
619733
#### `layouts/partials/tabs/source.html`
620734

621735
**Purpose**: Read and highlight source code files
@@ -857,6 +971,7 @@ cat examples/example_id/processed_file.py
857971
-**Minimal**: Only essential code (use REMOVE for test setup)
858972
-**Self-contained**: Doesn't depend on external state
859973
-**Commented**: Explains non-obvious parts
974+
-**Interactive** (optional): Includes `BINDER_ID` for "Run in browser" functionality via Jupyter notebooks
860975
-**Stepped**: Uses STEP_START for multi-part examples
861976
-**Avoid**: Complex logic, multiple concepts, undocumented magic
862977

@@ -931,6 +1046,59 @@ cat data/examples.json | grep my_new_example
9311046
hugo serve
9321047
```
9331048

1049+
**5. Add BinderHub Support (Optional)**:
1050+
1051+
If you want to enable the "Run in browser" link for an example:
1052+
1053+
**Step 1: Create or update the BinderHub launcher**:
1054+
1055+
The `redis/binder-launchers` repository contains Jupyter notebooks for each example. Jupyter notebooks can run code in multiple languages (Python, Node.js, Java, etc.) through language kernels. You need to:
1056+
1. Create a notebook file (e.g., `demo.ipynb`) that runs your example in the appropriate language
1057+
2. Ensure the necessary language kernel is configured in the BinderHub environment
1058+
3. Commit and push to the `redis/binder-launchers` repository
1059+
4. Note the commit SHA (40-character hexadecimal hash)
1060+
1061+
**Step 2: Add BINDER_ID to your example**:
1062+
1063+
Add the `BINDER_ID` marker as the second line of your example file (after `EXAMPLE:`):
1064+
1065+
```python
1066+
# EXAMPLE: my_new_example
1067+
# BINDER_ID 6bbed3da294e8de5a8c2ad99abf883731a50d4dd
1068+
import redis
1069+
1070+
# STEP_START connect
1071+
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
1072+
# STEP_END
1073+
```
1074+
1075+
**Step 3: Rebuild and verify**:
1076+
1077+
```bash
1078+
# Process examples
1079+
python3 build/local_examples.py
1080+
1081+
# Verify binderId appears in metadata
1082+
python3 -c "import json; data = json.load(open('data/examples.json')); print(data['my_new_example']['Python'].get('binderId'))"
1083+
# Should output: 6bbed3da294e8de5a8c2ad99abf883731a50d4dd
1084+
1085+
# Verify BINDER_ID line is removed from processed file
1086+
cat examples/my_new_example/local_*.py | grep BINDER_ID
1087+
# Should output nothing (line removed)
1088+
1089+
# Build Hugo and check the page
1090+
hugo serve
1091+
# Navigate to the page and verify "Run this example in the browser" link appears
1092+
```
1093+
1094+
**Important notes**:
1095+
- BinderHub uses **Jupyter notebooks** which support multiple languages through kernels (Python, Node.js, Java, etc.)
1096+
- The commit hash must exist in the `redis/binder-launchers` repository
1097+
- The notebook filename is always `demo.ipynb` (hardcoded in the URL)
1098+
- The link will only appear if `binderId` exists in the metadata
1099+
- Update the `BINDER_ID` hash whenever you update the notebook in the launcher repository
1100+
- Ensure the appropriate language kernel is installed in the BinderHub environment for your example's language
1101+
9341102
### When to Rebuild
9351103

9361104
**Full rebuild required** (`make all` or `python3 build/make.py`):
@@ -1189,6 +1357,47 @@ ModuleNotFoundError: No module named 'pytoml'
11891357
- **Debug**: Check the regex pattern includes capture group: `([a-f0-9]{40})`
11901358
- **Fix**: Ensure using `match.group(1)` to extract the captured hash
11911359

1360+
**BinderHub "Run in browser" link issues**:
1361+
- **Symptom 1**: Link not appearing in example box
1362+
- **Cause 1**: No `binderId` in metadata
1363+
- **Debug**: Check `data/examples.json` for the example set and language
1364+
- **Fix**: Add `BINDER_ID` marker to source file and rebuild
1365+
- **Cause 2**: Template conditional not checking for `binderId`
1366+
- **Debug**: Inspect `layouts/shortcodes/clients-example.html` template
1367+
- **Fix**: Ensure template has `{{ if $binderId }}` conditional around link
1368+
- **Cause 3**: Wrong variable name in template
1369+
- **Debug**: Check template is accessing `$langData.binderId` correctly
1370+
- **Fix**: Verify variable names match the data structure in `examples.json`
1371+
1372+
- **Symptom 2**: Link appears but URL is malformed
1373+
- **Cause 1**: Missing URL encoding in template
1374+
- **Expected**: `?urlpath=%2Fdoc%2Ftree%2Fdemo.ipynb`
1375+
- **Wrong**: `?urlpath=/doc/tree/demo.ipynb`
1376+
- **Fix**: Use `%%2F` (double percent) in `printf` to get `%2F` in output
1377+
- **Cause 2**: Wrong notebook filename
1378+
- **Fix**: Always use `demo.ipynb` - do not change per example
1379+
- **Cause 3**: `binderId` variable is empty or undefined
1380+
- **Debug**: Add template debugging: `{{ printf "%#v" $binderId }}`
1381+
- **Fix**: Ensure `binderId` is extracted from correct language data
1382+
1383+
- **Symptom 3**: Link opens but BinderHub shows error
1384+
- **Cause 1**: Invalid commit hash in `binderId`
1385+
- **Debug**: Verify hash exists in `redis/binder-launchers` repository
1386+
- **Fix**: Update `BINDER_ID` in source file to valid commit SHA
1387+
- **Cause 2**: BinderHub launcher not configured for this commit
1388+
- **Debug**: Check `redis/binder-launchers` repository for the commit
1389+
- **Fix**: Ensure the commit has the necessary notebook and configuration files
1390+
1391+
- **Symptom 4**: Link appears but example doesn't work in BinderHub
1392+
- **Cause**: Language kernel not installed in BinderHub environment
1393+
- **Fix**: Ensure the `redis/binder-launchers` repository has the necessary kernel configuration
1394+
- **Note**: Jupyter notebooks can run multiple languages (Python, Node.js, Java, etc.) through kernels
1395+
1396+
- **Symptom 5**: Link text or styling is wrong
1397+
- **Cause**: CSS classes or HTML structure doesn't match theme
1398+
- **Debug**: Inspect browser developer tools for CSS issues
1399+
- **Fix**: Update template HTML/CSS to match theme's design system
1400+
11921401
### Performance Issues
11931402

11941403
**Build takes too long**:

0 commit comments

Comments
 (0)