Skip to content

feat: add Try It button to CLI code examples#3380

Open
paoloredis wants to merge 17 commits into
mainfrom
DOC-6675
Open

feat: add Try It button to CLI code examples#3380
paoloredis wants to merge 17 commits into
mainfrom
DOC-6675

Conversation

@paoloredis

@paoloredis paoloredis commented May 28, 2026

Copy link
Copy Markdown
Collaborator

Adds a 'Try it' button to code examples that opens redis.io/cli with pre-populated commands and autorun enabled.

  • Extracts CLI commands from shortcode inner content (lines with '> ' or 'redis> ' prefix)
  • Renders a red 'Try it' button in the codetabs header
  • Button only visible when the Redis CLI tab is selected
  • Clicking opens https://redis.io/cli?commands=[...]&autorun=true in a new tab

Note

Low Risk
Documentation and client-side Hugo/JS changes only; no server auth or data-path changes. Main review surface is correct command extraction and WAF-safe external CLI URLs.

Overview
Adds a Try it control on codetabs and standalone redis-cli snippets that opens redis.io/cli with URL-safe base64 command payloads and autorun=true, including optional replay of a set’s prereq="true" setup when needs_prereq="true" is set (used on the JSONPath tutorial chain).

Example UX: The Redis CLI tab in clients-example blocks is now an inline interactive terminal (form.redis-cli + cli.js on develop pages) instead of a static highlight; runnable="false" keeps a static block with no Try it for unsafe commands. Duplicate per-page {{% redis-cli %}} “interactive console” sections are removed across many command docs in favor of a single clients-example block with > / redis> command lines.

Supporting behavior: cli.js shares one API session and serializes requests across widgets; codetabs copy uses registered CLI source when the active tab is the terminal; Try it visibility is tied to the Redis CLI language tab.

Reviewed by Cursor Bugbot for commit d6f817d. Bugbot is set up for automated code reviews on this repo. Configure here.

Adds a 'Try it' button to code examples that opens redis.io/cli
with pre-populated commands and autorun enabled.

- Extracts CLI commands from shortcode inner content (lines with '> ' or 'redis> ' prefix)
- Renders a red 'Try it' button in the codetabs header
- Button only visible when the Redis CLI tab is selected
- Clicking opens https://redis.io/cli?commands=[...]&autorun=true in a new tab
@github-actions

github-actions Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

DOC-6675

@jit-ci

jit-ci Bot commented May 28, 2026

Copy link
Copy Markdown

🛡️ Jit Security Scan Results

CRITICAL HIGH MEDIUM

✅ No security findings were detected in this PR


Security scan by Jit

The htmlEscape filter was applied on top of Hugo's automatic attribute
escaping, causing double-encoding (e.g. " instead of ").
This broke JSON.parse in the browser when clicking the Try It button.
Comment thread layouts/partials/tabs/wrapper.html Outdated
HTML data attributes with JSON values suffer from double-escaping issues
in Hugo (jsonify returns template.HTML, htmlEscape returns string which
Hugo then re-escapes). Moving the commands to a JavaScript object
(window._tryItCommands) populated via safeJS avoids all escaping issues.
Use printf with safeHTMLAttr to produce the complete attribute
key-value pair, preventing Hugo's contextual auto-escaping from
double-encoding the htmlEscape output. This matches the correct
Hugo pattern for embedding JSON in HTML attributes.
Comment thread layouts/partials/tabs/wrapper.html
JSON-stringified commands produced repeated %5C%22 sequences in the URL after encodeURIComponent, which Cloudflare's managed SQLi/XSS-bypass rules flagged, returning a 'you have been blocked' page instead of the CLI.

Encode the JSON payload as URL-safe base64 (no padding) before placing it in the commands query parameter, and add a getCommandsFromUrl helper in cli.js that decodes the payload when autorun=true is set.
Comment thread layouts/partials/tabs/wrapper.html Outdated
@paoloredis

Copy link
Copy Markdown
Collaborator Author

This change adds a Try it button for redis-cli commands, which when clicked launches redis.io/cli with the commands specific to the code block. What do you think?

https://redis.io/docs/staging/DOC-6675/develop/data-types/strings/#set_get?lang=redis-cli

@andy-stark-redis

Copy link
Copy Markdown
Contributor

@paoloredis It would definitely be useful to have a feature to run CLI examples like this. However, the commands don't seem to appear in the CLI page when you go to it (you get a working prompt, but it just doesn't seem to receive the commands in the example).

Also, we've already got those interactive CLIs that work within the page (eg, https://redis.io/docs/latest/commands/set/#examples). Is there a way we could incorporate those into the CLI tab so that the CLI example just works the same as the client lib examples?

@dwdougherty

dwdougherty commented May 28, 2026

Copy link
Copy Markdown
Collaborator

@paoloredis It would definitely be useful to have a feature to run CLI examples like this. However, the commands don't seem to appear in the CLI page when you go to it (you get a working prompt, but it just doesn't seem to receive the commands in the example).

I tried this example, https://redis.io/docs/staging/DOC-6675/commands/hset/#hset?lang=redis-cli, and I see the following output:

1:C 2026-05-28T13:45:04.464Z # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 2026-05-28T13:45:04.464Z # Configuration loaded
                  _._
            _.-``__ ''-._
      _.-``    `.  `_.  ''-._            Redis 8.8.0 (00000000/1) 64 bit
    .-`` .-```.  ```/    _.,_ ''-._
  (    '      ,       .-`  | `,    )     Running in standalone mode
  |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
  |    `-._   `._    /     _.-'    |     PID: 1
  `-._    `-._  `-./  _.-'    _.-'
  |`-._`-._    `-.__.-'    _.-'_.-'|
  |    `-._`-._        _.-'_.-'    |           https://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
  |`-._`-._    `-.__.-'    _.-'_.-'|
  |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

1:M 2026-05-28T13:45:04.464Z # Server initialized
1:M 2026-05-28T13:45:04.464Z * Ready to accept connections
redis:6379> HSET myhash field1 "Hello"
(integer) 1
redis:6379> HGET myhash field1
"Hello"
redis:6379> HSET myhash field2 "Hi" field3 "World"
(integer) 2
redis:6379> HGET myhash field2
"Hi"
redis:6379> HGET myhash field3
"World"
redis:6379> HGETALL myhash
1) "field1"
2) "Hello"
3) "field2"
4) "Hi"
5) "field3"
6) "World"
redis:6379>

Also, we've already got those interactive CLIs that work within the page (eg, https://redis.io/docs/latest/commands/set/#examples). Is there a way we could incorporate those into the CLI tab so that the CLI example just works the same as the client lib examples?

We have both the TCE and CLI widget on some command pages, though we could certainly change that.

One other thought... a lot of examples aren't complete (for example, they rely on a dataset that might not be present in the fenced code block), so this can't really be global.

@andy-stark-redis

Copy link
Copy Markdown
Contributor

@dwdougherty Did you try that in a local build? Maybe it's just the staging that doesn't show the command correctly.

Also, regarding the missing dataset issue, maybe we could have hidden sections in the CLI text to set the data up? They wouldn't be shown in the page but still get run during an interactive session.

@dwdougherty

dwdougherty commented May 28, 2026

Copy link
Copy Markdown
Collaborator

@andy-stark-redis I forget to include the URL (I just added it to my comment). I used a staging link that @paoloredis gave to me in Slack.

Er... okay, it's there now. 🫠

@paoloredis

Copy link
Copy Markdown
Collaborator Author

@andy-stark-redis is it working for you now? so are you suggesting we make the redis cli examples in the tabbed code examples interactive, without the external button taking you to redis.io/cli ?

@andy-stark-redis

Copy link
Copy Markdown
Contributor

@andy-stark-redis is it working for you now?

Yes, the staging link works fine now, thanks.

so are you suggesting we make the redis cli examples in the tabbed code examples interactive, without the external button taking you to redis.io/cli ?

Yeah, I'm just thinking that the system we've got for the client examples where they can run in the page is really nice.
I guess the interactive CLIs we have on the command pages aren't exactly the same as this because they don't run the commands before your eyes (they just show results and let you type new stuff).

If the in-page client examples rely on a Jupyter kernel behind the scenes then I guess one (crazy) idea might be to implement our own Jupyter kernel for Redis CLI commands? Probably not all that far-fetched when we've got our AI friends to do the work :-)

Anyway, TBH, it's really good just to have the "Try it" button you've already implemented, so I'd certainly approve going ahead with that. I just thought I'd throw in a few ideas while we're thinking about it.

@andy-stark-redis

Copy link
Copy Markdown
Contributor

@paoloredis @dwdougherty OK, I've had Claude look into this and it turns out you can add new "magic" commands to a notebook quite easily (you start off with Python and register Python handlers for the commands). So, we could have essentially a Python notebook with something like this in the first cell:

%load_ext redis_magic
%redis_connect redis://localhost:6379
>>>     Connected to redis://localhost:6379

Then, in subsequent cells we would have:

%%redis
     SET user:1 "alice"
     SET user:2 "bob"
     HSET profile:1 name alice age 30
     HGETALL profile:1
     ──────
 >>> OK
     OK
     (integer) 2
     1) "name"
     2) "alice"
     3) "age"
     4) "30"

I don't know if this is more trouble than it's worth, but possibly worth exploring if it enables in-page examples for CLI?

- Render the redis-cli tab in clients-example blocks as an interactive
  form.redis-cli terminal instead of a static highlighted code block
- Load cli.js on develop single pages so the terminals initialize
- Guard codetabs copy button against interactive cli panels (no <code>),
  copying commands from data-cli-source instead
- Add Try It button to the redis-cli shortcode header bar
Comment thread static/js/codetabs.js
@paoloredis

Copy link
Copy Markdown
Collaborator Author

@andy-stark-redis @dwdougherty I've now modified the tabbed code examples so that redis-cli code is executable. What do you think? This means that some pages like redis.io/docs/commands/hget/ will need to be updated to only include the tabbed code example. With this feature should we keep the "Try it" button or maybe not?

@andy-stark-redis

Copy link
Copy Markdown
Contributor

@andy-stark-redis @dwdougherty I've now modified the tabbed code examples so that redis-cli code is executable. What do you think?

That's basically what I was thinking of. I'd say that looks really neat now :-)

With this feature should we keep the "Try it" button or maybe not?

If we go ahead with the notebooks then maybe it could just say "Run in browser" like the others? I guess having links to redis.io/cli is a good idea though, since it's a nice feature. Maybe we could have a link in the footer? ("Try online or check out our other client tools...")

@paoloredis

Copy link
Copy Markdown
Collaborator Author

To be honest I'm not really sure I see the point in having a jupyter notebook for the redis cli commands.
What if we keep the "Try it" button for the redis-cli and we change the "Run in browser" jupyter links to use the same "Try it" button? To have some consistency

@dwdougherty

dwdougherty commented May 29, 2026

Copy link
Copy Markdown
Collaborator

@andy-stark-redis, @paoloredis: do you want me to go ahead and remove the CLI widget from pages that also have TCEs? It's only a handful of command pages:

AUTH,DEL,EXISTS,EXPIRE,FLUSHALL,GET,HDEL,HEXPIRE,HGET,HGETALL,HMGET,HSET,HVALS,INCR,INFO,KEYS,LLEN,LPOP,LPUSH,LRANGE,MGET,RPOP,RPUSH,SADD,SCAN,SET,SMEMBERS,TTL,XADD,ZADD,ZRANGE

@andy-stark-redis

Copy link
Copy Markdown
Contributor

@andy-stark-redis, @paoloredis: do you want me to go ahead and remove the CLI widget from pages that also have TCEs? It's only a handful of command pages...

I think the CLI widgets sometimes have different commands from the ones used in the nearby TCEs (eg, here)? The TCEs don't have Redis CLI tabs in those cases, so you'd need to create a new CLI example corresponding to the client code. So, only a handful of pages but maybe a big-ish job. However, if you're up for it then I think it would tidy those pages up very nicely.

Comment thread layouts/partials/tabbed-clients-example.html
Comment thread layouts/partials/tabbed-clients-example.html
Comment thread static/js/cli.js Outdated
Comment thread layouts/partials/tabbed-clients-example.html
Deduplicate the standalone redis-cli widgets that repeated commands already
present in the tabbed clients-example. For pages where the tabbed example
lacked the CLI commands (get, set), merge them into the tabbed example. Add
'>' prefixes on hexpire, hdel, info, and exists so their interactive CLI tab
runs only commands.
@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Staging links:
https://redis.io/docs/staging/DOC-6675/commands/del/
https://redis.io/docs/staging/DOC-6675/commands/exists/
https://redis.io/docs/staging/DOC-6675/commands/expire/
https://redis.io/docs/staging/DOC-6675/commands/get/
https://redis.io/docs/staging/DOC-6675/commands/hdel/
https://redis.io/docs/staging/DOC-6675/commands/hexpire/
https://redis.io/docs/staging/DOC-6675/commands/hget/
https://redis.io/docs/staging/DOC-6675/commands/hgetall/
https://redis.io/docs/staging/DOC-6675/commands/hmget/
https://redis.io/docs/staging/DOC-6675/commands/hset/
https://redis.io/docs/staging/DOC-6675/commands/hvals/
https://redis.io/docs/staging/DOC-6675/commands/incr/
https://redis.io/docs/staging/DOC-6675/commands/info/
https://redis.io/docs/staging/DOC-6675/commands/keys/
https://redis.io/docs/staging/DOC-6675/commands/llen/
https://redis.io/docs/staging/DOC-6675/commands/lpop/
https://redis.io/docs/staging/DOC-6675/commands/lpush/
https://redis.io/docs/staging/DOC-6675/commands/lrange/
https://redis.io/docs/staging/DOC-6675/commands/mget/
https://redis.io/docs/staging/DOC-6675/commands/rpop/
https://redis.io/docs/staging/DOC-6675/commands/rpush/
https://redis.io/docs/staging/DOC-6675/commands/sadd/
https://redis.io/docs/staging/DOC-6675/commands/set/
https://redis.io/docs/staging/DOC-6675/commands/smembers/
https://redis.io/docs/staging/DOC-6675/commands/ttl/
https://redis.io/docs/staging/DOC-6675/commands/zadd/
https://redis.io/docs/staging/DOC-6675/commands/zrange/
https://redis.io/docs/staging/DOC-6675/develop/data-types/json/path/

Comment thread layouts/partials/tabbed-clients-example.html Outdated
Comment thread layouts/shortcodes/redis-cli.html
@paoloredis

Copy link
Copy Markdown
Collaborator Author

I think the CLI widgets sometimes have different commands from the ones used in the nearby TCEs (eg, here)? The TCEs don't have Redis CLI tabs in those cases, so you'd need to create a new CLI example corresponding to the client code. So, only a handful of pages but maybe a big-ish job. However, if you're up for it then I think it would tidy those pages up very nicely.

I've addressed this now @andy-stark-redis @dwdougherty

@andy-stark-redis

Copy link
Copy Markdown
Contributor

@paoloredis Awesome - thanks for all your work on this :-)

The interactive redis-cli widgets previously shared a single module-level
session id, but each widget's auto-run fired in parallel with an undefined
id, so the backend forked them into separate sessions and the global id kept
only the last responder. Typed commands then ran against the wrong session
(e.g. INCREX mykey1 resetting to 1 on the multi-widget increx page).

Serialize all requests through a queue so the first establishes the session
id and every subsequent auto-run or typed command reuses it. All widgets on
a page (tabbed examples and standalone snippets) now share one namespace:
auto-run data accumulates into a single database and users can query or
extend it from any widget.
Comment thread static/js/cli.js
Introduce two clients-example params: prereq="true" marks a block as its
set's setup cell, and needs_prereq="true" makes that block's Try-it replay
only the set's prerequisite commands (via window._tryItPrereqs[set]) before
its own, instead of the full transitive buildsUpon chain. buildsUpon is
retained for the markdown/LLM "Builds upon" exports and as the legacy
fallback for blocks without needs_prereq.

Apply to develop/data-types/json/path: mark set_bikes as prereq and flag
every dependent example with needs_prereq.
Comment thread layouts/partials/tabbed-clients-example.html Outdated
Try-it now seeds the CLI session solely from the explicit prereq model
(prereq / needs_prereq); data-builds-upon is treated as metadata only
(AI/markdown export) and is no longer walked by openTryItCli.

Also drop the spurious buildsUpon="set_get" from the strings incr and
mset examples, which are self-contained and don't depend on bike:1.
Restore buildsUpon="set_get" on the strings incr and mset examples;
keep them unchanged as metadata. Try-it behaviour is unaffected since
openTryItCli no longer consults buildsUpon.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0f3112e. Configure here.

Comment thread content/develop/data-types/json/path.md
Comment thread layouts/shortcodes/redis-cli.html
@paoloredis

Copy link
Copy Markdown
Collaborator Author

Going to hold off merging until #3398 is fixed

Integrate PR 3497 (clients-example snippet slice/dedup) and other main
changes. Layout/JS auto-merged: tabbed-clients-example.html now carries
both the Try-it interactive CLI tab and PR 3497's per-step slicing +
per-page full-file dedup.

Resolved 9 content/commands conflicts: kept the interactive
clients-example widgets (exists, get, set), kept main's canonical prose
while dropping the duplicated redis-cli console (incr, expire, lrange,
zadd, zrange), and took main's INFO optional-arguments docs (info).
Introduce a runnable parameter (default true) on the clients-example
shortcode. When runnable="false" the redis-cli tab renders as a static,
non-executable block (div.redis-cli.redis-cli-static > pre) with no
"Try it" button and no tryItCommands payload, so unsafe blocking
commands (e.g. BRPOP) are shown but not runnable in the browser.
Defaults preserve interactive form.redis-cli behavior.
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants