Make Time Travel modal-only
Add a Time Travel entry directly under Files in the sidebar dropdown and route it through the existing modal. Stop Time Travel from registering or mounting a right-canvas surface, and keep modal refresh tied to the modal state.
Alessandro committed
May 2, 2026 at 17:20 UTC
ae94f158df8a4f2cb6ba7eb1866d6ea09ffad57a
5 files changed
+19
-47
plugins/_time_travel/extensions/webui/apply_snapshot_before/refresh-time-travel.js
+3
-2
@@ -1,7 +1,8 @@
1
export default function refreshTimeTravelOnContextChange(ctx) {
2
const store = globalThis.Alpine?.store?.("timeTravel");
3
- const canvas = globalThis.Alpine?.store?.("rightCanvas");
4
- if (!store || !canvas?.isOpen || canvas.activeSurfaceId !== "time-travel") return;
3
+ const modalOpen = globalThis.isModalOpen?.("/plugins/_time_travel/webui/main.html")
4
+ || globalThis.isModalOpen?.("plugins/_time_travel/webui/main.html");
5
+ if (!store || !modalOpen) return;
6
const nextContextId = String(ctx?.snapshot?.context || "");
7
if (nextContextId && nextContextId !== store.contextId) {
8
store.scheduleRefresh({ contextId: nextContextId, reason: "context-change" });
plugins/_time_travel/extensions/webui/right-canvas-panels/time-travel-panel.html
+1
-8
@@ -1,8 +1 @@
1
-<div
2
- class="right-canvas-surface-panel time-travel-canvas-surface"
3
- data-surface-id="time-travel"
4
- x-show="$store.rightCanvas && $store.rightCanvas.isOpen && $store.rightCanvas.activeSurfaceId === 'time-travel'"
5
- style="display: none;"
6
->
7
- <x-component path="/plugins/_time_travel/webui/time-travel-panel.html" mode="canvas"></x-component>
8
-</div>
1
+<!-- Time Travel is modal-only; the right canvas must not mount its panel. -->
plugins/_time_travel/extensions/webui/right_canvas_register_surfaces/register-time-travel.js
+2
-36
@@ -1,37 +1,3 @@
1
-function waitForElement(selector, timeoutMs = 3000) {
2
- const found = document.querySelector(selector);
3
- if (found) return Promise.resolve(found);
4
- return new Promise((resolve) => {
5
- const timeout = globalThis.setTimeout(() => {
6
- observer.disconnect();
7
- resolve(document.querySelector(selector));
8
- }, timeoutMs);
9
- const observer = new MutationObserver(() => {
10
- const element = document.querySelector(selector);
11
- if (!element) return;
12
- globalThis.clearTimeout(timeout);
13
- observer.disconnect();
14
- resolve(element);
15
- });
16
- observer.observe(document.body, { childList: true, subtree: true });
17
- });
18
-}
19
-
20
-export default async function registerTimeTravelSurface(canvas) {
21
- canvas.registerSurface({
22
- id: "time-travel",
23
- title: "Time Travel",
24
- icon: "history",
25
- order: 30,
26
- modalPath: "/plugins/_time_travel/webui/main.html",
27
- async open(payload = {}) {
28
- await waitForElement('[data-surface-id="time-travel"] .time-travel-panel');
29
- const store = globalThis.Alpine?.store?.("timeTravel");
30
- await store?.onOpen?.(payload);
31
- },
32
- async close() {
33
- const store = globalThis.Alpine?.store?.("timeTravel");
34
- store?.cleanup?.();
35
- },
36
- });
1
+export default async function registerTimeTravelSurface() {
2
+ // Time Travel is opened from the sidebar dropdown as a modal-only surface.
3
}
plugins/_time_travel/extensions/webui/sidebar-quick-actions-dropdown-start/time-travel-entry.html
new
+12
@@ -0,0 +1,12 @@
1
+<!-- Time Travel -->
2
+<div x-data>
3
+ <button
4
+ x-move-after="#sidebar-files-dropdown"
5
+ class="dropdown-item"
6
+ id="time-travel-dropdown"
7
+ title="Time Travel"
8
+ @click="ensureModalOpen('/plugins/_time_travel/webui/main.html'); $store.sidebar.menuClose()">
9
+ <span class="material-symbols-outlined">history</span>
10
+ <span>Time Travel</span>
11
+ </button>
12
+</div>
webui/components/sidebar/top-section/header-icons.html
+1
-1
@@ -83,7 +83,7 @@
83
<span>Projects</span>
84
</button>
85
86
- <button class="dropdown-item" @click="$store.chatInput.browseFiles(); $store.sidebar.menuClose()">
86
+ <button id="sidebar-files-dropdown" class="dropdown-item" @click="$store.chatInput.browseFiles(); $store.sidebar.menuClose()">
87
<span class="material-symbols-outlined">folder</span>
88
<span>Files</span>
89
</button>