@chrysb/alphaclaw 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/alphaclaw.js +29 -2
- package/lib/cli/git-sync.js +25 -0
- package/lib/public/css/explorer.css +983 -0
- package/lib/public/css/shell.css +48 -4
- package/lib/public/css/theme.css +6 -1
- package/lib/public/icons/folder-line.svg +1 -0
- package/lib/public/icons/hashtag.svg +3 -0
- package/lib/public/icons/home-5-line.svg +1 -0
- package/lib/public/icons/save-fill.svg +3 -0
- package/lib/public/js/app.js +259 -158
- package/lib/public/js/components/action-button.js +12 -1
- package/lib/public/js/components/file-tree.js +322 -0
- package/lib/public/js/components/file-viewer.js +691 -0
- package/lib/public/js/components/icons.js +182 -0
- package/lib/public/js/components/sidebar-git-panel.js +149 -0
- package/lib/public/js/components/sidebar.js +272 -0
- package/lib/public/js/lib/api.js +26 -0
- package/lib/public/js/lib/browse-draft-state.js +109 -0
- package/lib/public/js/lib/file-highlighting.js +6 -0
- package/lib/public/js/lib/file-tree-utils.js +12 -0
- package/lib/public/js/lib/syntax-highlighters/css.js +124 -0
- package/lib/public/js/lib/syntax-highlighters/frontmatter.js +49 -0
- package/lib/public/js/lib/syntax-highlighters/html.js +209 -0
- package/lib/public/js/lib/syntax-highlighters/index.js +28 -0
- package/lib/public/js/lib/syntax-highlighters/javascript.js +134 -0
- package/lib/public/js/lib/syntax-highlighters/json.js +61 -0
- package/lib/public/js/lib/syntax-highlighters/markdown.js +37 -0
- package/lib/public/js/lib/syntax-highlighters/utils.js +13 -0
- package/lib/public/setup.html +1 -0
- package/lib/server/constants.js +1 -0
- package/lib/server/onboarding/workspace.js +3 -2
- package/lib/server/routes/browse.js +295 -0
- package/lib/server.js +24 -3
- package/lib/setup/core-prompts/TOOLS.md +3 -1
- package/lib/setup/skills/control-ui/SKILL.md +12 -20
- package/package.json +1 -1
package/lib/public/css/shell.css
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
.app-shell {
|
|
4
4
|
display: grid;
|
|
5
|
-
grid-template-columns: 220px 1fr;
|
|
5
|
+
grid-template-columns: 220px 0 minmax(0, 1fr);
|
|
6
6
|
grid-template-rows: auto 1fr 24px;
|
|
7
7
|
height: 100vh;
|
|
8
8
|
position: relative;
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
.app-content {
|
|
45
|
+
grid-column: 3;
|
|
45
46
|
grid-row: 2;
|
|
46
47
|
overflow-y: auto;
|
|
47
48
|
padding: 24px 32px;
|
|
@@ -52,16 +53,54 @@
|
|
|
52
53
|
/* ── Sidebar ───────────────────────────────────── */
|
|
53
54
|
|
|
54
55
|
.app-sidebar {
|
|
56
|
+
grid-column: 1;
|
|
55
57
|
grid-row: 2;
|
|
56
58
|
background:
|
|
57
|
-
linear-gradient(180deg, rgba(255, 255, 255, 0.
|
|
59
|
+
linear-gradient(180deg, rgba(255, 255, 255, 0.018) 0%, rgba(255, 255, 255, 0.006) 100%),
|
|
60
|
+
linear-gradient(180deg, rgba(0, 0, 0, 0.1) 0%, rgba(0, 0, 0, 0.16) 100%),
|
|
58
61
|
var(--bg-sidebar);
|
|
59
|
-
border-right: 1px solid var(--border
|
|
62
|
+
border-right: 1px solid var(--border);
|
|
60
63
|
overflow-y: auto;
|
|
61
64
|
display: flex;
|
|
62
65
|
flex-direction: column;
|
|
63
66
|
}
|
|
64
67
|
|
|
68
|
+
.sidebar-resizer {
|
|
69
|
+
grid-column: 2;
|
|
70
|
+
grid-row: 2;
|
|
71
|
+
cursor: col-resize;
|
|
72
|
+
position: relative;
|
|
73
|
+
width: 6px;
|
|
74
|
+
margin-left: -3px;
|
|
75
|
+
z-index: 4;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.sidebar-resizer::before {
|
|
79
|
+
content: "";
|
|
80
|
+
position: absolute;
|
|
81
|
+
left: 0;
|
|
82
|
+
top: 0;
|
|
83
|
+
bottom: 0;
|
|
84
|
+
width: 6px;
|
|
85
|
+
background: transparent;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.sidebar-resizer::after {
|
|
89
|
+
content: "";
|
|
90
|
+
position: absolute;
|
|
91
|
+
left: 2px;
|
|
92
|
+
top: 0;
|
|
93
|
+
bottom: 0;
|
|
94
|
+
width: 2px;
|
|
95
|
+
background: transparent;
|
|
96
|
+
transition: background 0.12s;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.sidebar-resizer:hover::after,
|
|
100
|
+
.sidebar-resizer.is-resizing::after {
|
|
101
|
+
background: rgba(99, 235, 255, 0.55);
|
|
102
|
+
}
|
|
103
|
+
|
|
65
104
|
.sidebar-brand {
|
|
66
105
|
padding: 16px;
|
|
67
106
|
font-size: 14px;
|
|
@@ -122,7 +161,7 @@
|
|
|
122
161
|
.sidebar-footer:empty { display: none; }
|
|
123
162
|
|
|
124
163
|
.sidebar-footer:not(:empty) {
|
|
125
|
-
padding: 12px 16px;
|
|
164
|
+
padding: 0 16px 12px 16px;
|
|
126
165
|
border-top: 1px solid var(--border);
|
|
127
166
|
}
|
|
128
167
|
|
|
@@ -267,10 +306,15 @@
|
|
|
267
306
|
transform: none;
|
|
268
307
|
}
|
|
269
308
|
.app-content {
|
|
309
|
+
grid-column: 1;
|
|
270
310
|
grid-row: 2;
|
|
271
311
|
padding: 0 14px 12px;
|
|
272
312
|
}
|
|
273
313
|
|
|
314
|
+
.sidebar-resizer {
|
|
315
|
+
display: none;
|
|
316
|
+
}
|
|
317
|
+
|
|
274
318
|
.mobile-topbar {
|
|
275
319
|
display: flex;
|
|
276
320
|
align-items: center;
|
package/lib/public/css/theme.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
:root {
|
|
2
2
|
--bg: #0d121b;
|
|
3
|
-
--bg-sidebar: #
|
|
3
|
+
--bg-sidebar: #0f141f;
|
|
4
4
|
--bg-content: #0f1521;
|
|
5
5
|
--bg-hover: rgba(99, 235, 255, 0.05);
|
|
6
6
|
--bg-active: rgba(99, 235, 255, 0.08);
|
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
--accent: #63ebff;
|
|
13
13
|
--accent-dim: rgba(99, 235, 255, 0.4);
|
|
14
14
|
--accent-link: rgba(99, 235, 255, 0.6);
|
|
15
|
+
--orange: #d98a58;
|
|
16
|
+
--comment: #6a737d;
|
|
17
|
+
--keyword: #ff7b72;
|
|
18
|
+
--string: #a5d6ff;
|
|
19
|
+
--number: #79c0ff;
|
|
15
20
|
--panel-bg-contrast: rgba(255, 255, 255, 0.028);
|
|
16
21
|
--panel-border-contrast: rgba(255, 255, 255, 0.11);
|
|
17
22
|
--field-bg-contrast: rgba(0, 0, 0, 0.3);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M4 5V19H20V7H11.5858L9.58579 5H4ZM12.4142 5H21C21.5523 5 22 5.44772 22 6V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H10.4142L12.4142 5Z"></path></svg>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
|
2
|
+
<path d="M7.78428 14L8.2047 10H4V8H8.41491L8.94043 3H10.9514L10.4259 8H14.4149L14.9404 3H16.9514L16.4259 8H20V10H16.2157L15.7953 14H20V16H15.5851L15.0596 21H13.0486L13.5741 16H9.58509L9.05957 21H7.04855L7.57407 16H4V14H7.78428ZM9.7953 14H13.7843L14.2047 10H10.2157L9.7953 14Z"></path>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M13 19H19V9.97815L12 4.53371L5 9.97815V19H11V13H13V19ZM21 20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V9.48907C3 9.18048 3.14247 8.88917 3.38606 8.69972L11.3861 2.47749C11.7472 2.19663 12.2528 2.19663 12.6139 2.47749L20.6139 8.69972C20.8575 8.88917 21 9.18048 21 9.48907V20Z"></path></svg>
|
package/lib/public/js/app.js
CHANGED
|
@@ -40,8 +40,32 @@ import { UpdateActionButton } from "./components/update-action-button.js";
|
|
|
40
40
|
import { GlobalRestartBanner } from "./components/global-restart-banner.js";
|
|
41
41
|
import { LoadingSpinner } from "./components/loading-spinner.js";
|
|
42
42
|
import { WatchdogTab } from "./components/watchdog-tab.js";
|
|
43
|
+
import { FileViewer } from "./components/file-viewer.js";
|
|
44
|
+
import { AppSidebar } from "./components/sidebar.js";
|
|
43
45
|
const html = htm.bind(h);
|
|
44
46
|
const kDefaultUiTab = "general";
|
|
47
|
+
const kUiSettingsStorageKey = "alphaclaw.uiSettings";
|
|
48
|
+
const kLegacyUiSettingsStorageKey = "alphaclawUiSettings";
|
|
49
|
+
const kDefaultSidebarWidthPx = 220;
|
|
50
|
+
const kSidebarMinWidthPx = 180;
|
|
51
|
+
const kSidebarMaxWidthPx = 460;
|
|
52
|
+
const kBrowseLastPathUiSettingKey = "browseLastPath";
|
|
53
|
+
|
|
54
|
+
const clampSidebarWidth = (value) =>
|
|
55
|
+
Math.max(kSidebarMinWidthPx, Math.min(kSidebarMaxWidthPx, value));
|
|
56
|
+
|
|
57
|
+
const readUiSettings = () => {
|
|
58
|
+
try {
|
|
59
|
+
const raw =
|
|
60
|
+
window.localStorage.getItem(kUiSettingsStorageKey) ||
|
|
61
|
+
window.localStorage.getItem(kLegacyUiSettingsStorageKey);
|
|
62
|
+
if (!raw) return {};
|
|
63
|
+
const parsed = JSON.parse(raw);
|
|
64
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
65
|
+
} catch {
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
};
|
|
45
69
|
|
|
46
70
|
const getHashPath = () => {
|
|
47
71
|
const hash = window.location.hash.replace(/^#/, "");
|
|
@@ -158,16 +182,12 @@ const GeneralTab = ({
|
|
|
158
182
|
setTimeout(devicePoll.refresh, 2000);
|
|
159
183
|
};
|
|
160
184
|
|
|
161
|
-
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
if (!isActive) return;
|
|
162
187
|
onRefreshStatuses();
|
|
163
188
|
pairingsPoll.refresh();
|
|
164
189
|
devicePoll.refresh();
|
|
165
190
|
setGoogleKey((k) => k + 1);
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
useEffect(() => {
|
|
169
|
-
if (!isActive) return;
|
|
170
|
-
fullRefresh();
|
|
171
191
|
}, [isActive]);
|
|
172
192
|
|
|
173
193
|
useEffect(() => {
|
|
@@ -360,23 +380,12 @@ const GeneralTab = ({
|
|
|
360
380
|
onReject=${handleDeviceReject}
|
|
361
381
|
/>
|
|
362
382
|
</div>
|
|
363
|
-
|
|
364
|
-
<p class="text-center text-gray-600 text-xs">
|
|
365
|
-
<a
|
|
366
|
-
href="#"
|
|
367
|
-
onclick=${(e) => {
|
|
368
|
-
e.preventDefault();
|
|
369
|
-
fullRefresh();
|
|
370
|
-
}}
|
|
371
|
-
class="text-gray-500 hover:text-gray-300"
|
|
372
|
-
>Refresh all</a
|
|
373
|
-
>
|
|
374
|
-
</p>
|
|
375
383
|
</div>
|
|
376
384
|
`;
|
|
377
385
|
};
|
|
378
386
|
|
|
379
387
|
const App = () => {
|
|
388
|
+
const appShellRef = useRef(null);
|
|
380
389
|
const [onboarded, setOnboarded] = useState(null);
|
|
381
390
|
const [location, setLocation] = useLocation();
|
|
382
391
|
const [acVersion, setAcVersion] = useState(null);
|
|
@@ -386,6 +395,19 @@ const App = () => {
|
|
|
386
395
|
const [acDismissed, setAcDismissed] = useState(false);
|
|
387
396
|
const [authEnabled, setAuthEnabled] = useState(false);
|
|
388
397
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
398
|
+
const [sidebarTab, setSidebarTab] = useState("menu");
|
|
399
|
+
const [sidebarWidthPx, setSidebarWidthPx] = useState(() => {
|
|
400
|
+
const settings = readUiSettings();
|
|
401
|
+
if (!Number.isFinite(settings.sidebarWidthPx)) return kDefaultSidebarWidthPx;
|
|
402
|
+
return clampSidebarWidth(settings.sidebarWidthPx);
|
|
403
|
+
});
|
|
404
|
+
const [lastBrowsePath, setLastBrowsePath] = useState(() => {
|
|
405
|
+
const settings = readUiSettings();
|
|
406
|
+
return typeof settings[kBrowseLastPathUiSettingKey] === "string"
|
|
407
|
+
? settings[kBrowseLastPathUiSettingKey]
|
|
408
|
+
: "";
|
|
409
|
+
});
|
|
410
|
+
const [isResizingSidebar, setIsResizingSidebar] = useState(false);
|
|
389
411
|
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
|
390
412
|
const [mobileTopbarScrolled, setMobileTopbarScrolled] = useState(false);
|
|
391
413
|
const [restartRequired, setRestartRequired] = useState(false);
|
|
@@ -568,10 +590,45 @@ const App = () => {
|
|
|
568
590
|
`;
|
|
569
591
|
}
|
|
570
592
|
|
|
593
|
+
const buildBrowseRoute = (relativePath) => {
|
|
594
|
+
const encodedPath = String(relativePath || "")
|
|
595
|
+
.split("/")
|
|
596
|
+
.filter(Boolean)
|
|
597
|
+
.map((segment) => encodeURIComponent(segment))
|
|
598
|
+
.join("/");
|
|
599
|
+
return encodedPath ? `/browse/${encodedPath}` : "/browse";
|
|
600
|
+
};
|
|
571
601
|
const navigateToSubScreen = (screen) => {
|
|
572
602
|
setLocation(`/${screen}`);
|
|
573
603
|
setMobileSidebarOpen(false);
|
|
574
604
|
};
|
|
605
|
+
const navigateToBrowseFile = (relativePath) => {
|
|
606
|
+
setLocation(buildBrowseRoute(relativePath));
|
|
607
|
+
setMobileSidebarOpen(false);
|
|
608
|
+
};
|
|
609
|
+
const handleSidebarLogout = async () => {
|
|
610
|
+
setMenuOpen(false);
|
|
611
|
+
await logout();
|
|
612
|
+
try {
|
|
613
|
+
window.localStorage.clear();
|
|
614
|
+
window.sessionStorage.clear();
|
|
615
|
+
} catch {}
|
|
616
|
+
window.location.href = "/login.html";
|
|
617
|
+
};
|
|
618
|
+
const handleSelectSidebarTab = (nextTab) => {
|
|
619
|
+
setSidebarTab(nextTab);
|
|
620
|
+
if (nextTab === "menu" && location.startsWith("/browse")) {
|
|
621
|
+
setLocation("/general");
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
if (nextTab === "browse" && !location.startsWith("/browse")) {
|
|
625
|
+
setLocation(buildBrowseRoute(lastBrowsePath));
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
const handleSelectNavItem = (itemId) => {
|
|
629
|
+
setLocation(`/${itemId}`);
|
|
630
|
+
setMobileSidebarOpen(false);
|
|
631
|
+
};
|
|
575
632
|
const exitSubScreen = () => {
|
|
576
633
|
setLocation(`/${kDefaultUiTab}`);
|
|
577
634
|
setMobileSidebarOpen(false);
|
|
@@ -601,18 +658,91 @@ const App = () => {
|
|
|
601
658
|
},
|
|
602
659
|
];
|
|
603
660
|
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
661
|
+
const isBrowseRoute = location.startsWith("/browse");
|
|
662
|
+
const selectedBrowsePath = isBrowseRoute
|
|
663
|
+
? location
|
|
664
|
+
.replace(/^\/browse\/?/, "")
|
|
665
|
+
.split("/")
|
|
666
|
+
.filter(Boolean)
|
|
667
|
+
.map((segment) => {
|
|
668
|
+
try {
|
|
669
|
+
return decodeURIComponent(segment);
|
|
670
|
+
} catch {
|
|
671
|
+
return segment;
|
|
672
|
+
}
|
|
673
|
+
})
|
|
674
|
+
.join("/")
|
|
675
|
+
: "";
|
|
676
|
+
const selectedNavId = isBrowseRoute
|
|
677
|
+
? "browse"
|
|
678
|
+
: location === "/telegram"
|
|
679
|
+
? ""
|
|
680
|
+
: location.startsWith("/providers")
|
|
681
|
+
? "providers"
|
|
682
|
+
: location.startsWith("/watchdog")
|
|
683
|
+
? "watchdog"
|
|
684
|
+
: location.startsWith("/envars")
|
|
685
|
+
? "envars"
|
|
686
|
+
: location.startsWith("/webhooks")
|
|
687
|
+
? "webhooks"
|
|
688
|
+
: "general";
|
|
689
|
+
|
|
690
|
+
useEffect(() => {
|
|
691
|
+
setSidebarTab((currentTab) => {
|
|
692
|
+
if (location.startsWith("/browse")) return "browse";
|
|
693
|
+
if (currentTab === "browse") return "menu";
|
|
694
|
+
return currentTab;
|
|
695
|
+
});
|
|
696
|
+
}, [location]);
|
|
697
|
+
|
|
698
|
+
useEffect(() => {
|
|
699
|
+
if (!isBrowseRoute) return;
|
|
700
|
+
if (!selectedBrowsePath) return;
|
|
701
|
+
setLastBrowsePath((currentPath) =>
|
|
702
|
+
currentPath === selectedBrowsePath ? currentPath : selectedBrowsePath,
|
|
703
|
+
);
|
|
704
|
+
}, [isBrowseRoute, selectedBrowsePath]);
|
|
705
|
+
|
|
706
|
+
useEffect(() => {
|
|
707
|
+
const settings = readUiSettings();
|
|
708
|
+
settings.sidebarWidthPx = sidebarWidthPx;
|
|
709
|
+
settings[kBrowseLastPathUiSettingKey] = lastBrowsePath;
|
|
710
|
+
try {
|
|
711
|
+
window.localStorage.setItem(kUiSettingsStorageKey, JSON.stringify(settings));
|
|
712
|
+
} catch {}
|
|
713
|
+
}, [sidebarWidthPx, lastBrowsePath]);
|
|
714
|
+
|
|
715
|
+
const resizeSidebarWithClientX = useCallback((clientX) => {
|
|
716
|
+
const shellElement = appShellRef.current;
|
|
717
|
+
if (!shellElement) return;
|
|
718
|
+
const shellBounds = shellElement.getBoundingClientRect();
|
|
719
|
+
const nextWidth = clampSidebarWidth(Math.round(clientX - shellBounds.left));
|
|
720
|
+
setSidebarWidthPx(nextWidth);
|
|
721
|
+
}, []);
|
|
722
|
+
|
|
723
|
+
const onSidebarResizerPointerDown = (event) => {
|
|
724
|
+
event.preventDefault();
|
|
725
|
+
setIsResizingSidebar(true);
|
|
726
|
+
resizeSidebarWithClientX(event.clientX);
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
useEffect(() => {
|
|
730
|
+
if (!isResizingSidebar) return () => {};
|
|
731
|
+
const onPointerMove = (event) => resizeSidebarWithClientX(event.clientX);
|
|
732
|
+
const onPointerUp = () => setIsResizingSidebar(false);
|
|
733
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
734
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
735
|
+
const previousUserSelect = document.body.style.userSelect;
|
|
736
|
+
const previousCursor = document.body.style.cursor;
|
|
737
|
+
document.body.style.userSelect = "none";
|
|
738
|
+
document.body.style.cursor = "col-resize";
|
|
739
|
+
return () => {
|
|
740
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
741
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
742
|
+
document.body.style.userSelect = previousUserSelect;
|
|
743
|
+
document.body.style.cursor = previousCursor;
|
|
744
|
+
};
|
|
745
|
+
}, [isResizingSidebar, resizeSidebarWithClientX]);
|
|
616
746
|
|
|
617
747
|
const renderWebhooks = (hookName = "") => html`
|
|
618
748
|
<div class="pt-4">
|
|
@@ -626,91 +756,53 @@ const App = () => {
|
|
|
626
756
|
`;
|
|
627
757
|
|
|
628
758
|
return html`
|
|
629
|
-
<div
|
|
759
|
+
<div
|
|
760
|
+
class="app-shell"
|
|
761
|
+
ref=${appShellRef}
|
|
762
|
+
style=${{ gridTemplateColumns: `${sidebarWidthPx}px 0px minmax(0, 1fr)` }}
|
|
763
|
+
>
|
|
630
764
|
<${GlobalRestartBanner}
|
|
631
765
|
visible=${restartRequired}
|
|
632
766
|
restarting=${restartingGateway}
|
|
633
767
|
onRestart=${handleGatewayRestart}
|
|
634
768
|
/>
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
window.sessionStorage.clear();
|
|
663
|
-
} catch {}
|
|
664
|
-
window.location.href = "/login.html";
|
|
665
|
-
}}
|
|
666
|
-
>Log out</a>
|
|
667
|
-
</div>
|
|
668
|
-
`}
|
|
669
|
-
</div>
|
|
670
|
-
`}
|
|
671
|
-
</div>
|
|
672
|
-
${kNavSections.map(
|
|
673
|
-
(section) => html`
|
|
674
|
-
<div class="sidebar-label">${section.label}</div>
|
|
675
|
-
<nav class="sidebar-nav">
|
|
676
|
-
${section.items.map(
|
|
677
|
-
(item) => html`
|
|
678
|
-
<a
|
|
679
|
-
class=${selectedNavId === item.id ? "active" : ""}
|
|
680
|
-
onclick=${() => {
|
|
681
|
-
setLocation(`/${item.id}`);
|
|
682
|
-
setMobileSidebarOpen(false);
|
|
683
|
-
}}
|
|
684
|
-
>
|
|
685
|
-
${item.label}
|
|
686
|
-
</a>
|
|
687
|
-
`,
|
|
688
|
-
)}
|
|
689
|
-
</nav>
|
|
690
|
-
`,
|
|
691
|
-
)}
|
|
692
|
-
<div class="sidebar-footer">
|
|
693
|
-
${acHasUpdate && acLatest && !acDismissed
|
|
694
|
-
? html`
|
|
695
|
-
<${UpdateActionButton}
|
|
696
|
-
onClick=${handleAcUpdate}
|
|
697
|
-
loading=${acUpdating}
|
|
698
|
-
warning=${true}
|
|
699
|
-
idleLabel=${`Update to v${acLatest}`}
|
|
700
|
-
loadingLabel="Updating..."
|
|
701
|
-
className="w-full justify-center"
|
|
702
|
-
/>
|
|
703
|
-
`
|
|
704
|
-
: null}
|
|
705
|
-
</div>
|
|
706
|
-
</div>
|
|
769
|
+
<${AppSidebar}
|
|
770
|
+
mobileSidebarOpen=${mobileSidebarOpen}
|
|
771
|
+
authEnabled=${authEnabled}
|
|
772
|
+
menuRef=${menuRef}
|
|
773
|
+
menuOpen=${menuOpen}
|
|
774
|
+
onToggleMenu=${() => setMenuOpen((open) => !open)}
|
|
775
|
+
onLogout=${handleSidebarLogout}
|
|
776
|
+
sidebarTab=${sidebarTab}
|
|
777
|
+
onSelectSidebarTab=${handleSelectSidebarTab}
|
|
778
|
+
navSections=${kNavSections}
|
|
779
|
+
selectedNavId=${selectedNavId}
|
|
780
|
+
onSelectNavItem=${handleSelectNavItem}
|
|
781
|
+
selectedBrowsePath=${selectedBrowsePath}
|
|
782
|
+
onSelectBrowseFile=${navigateToBrowseFile}
|
|
783
|
+
acHasUpdate=${acHasUpdate}
|
|
784
|
+
acLatest=${acLatest}
|
|
785
|
+
acDismissed=${acDismissed}
|
|
786
|
+
acUpdating=${acUpdating}
|
|
787
|
+
onAcUpdate=${handleAcUpdate}
|
|
788
|
+
/>
|
|
789
|
+
<div
|
|
790
|
+
class=${`sidebar-resizer ${isResizingSidebar ? "is-resizing" : ""}`}
|
|
791
|
+
onpointerdown=${onSidebarResizerPointerDown}
|
|
792
|
+
role="separator"
|
|
793
|
+
aria-orientation="vertical"
|
|
794
|
+
aria-label="Resize sidebar"
|
|
795
|
+
></div>
|
|
707
796
|
|
|
708
797
|
<div
|
|
709
798
|
class=${`mobile-sidebar-overlay ${mobileSidebarOpen ? "active" : ""}`}
|
|
710
799
|
onclick=${() => setMobileSidebarOpen(false)}
|
|
711
800
|
/>
|
|
712
801
|
|
|
713
|
-
<div
|
|
802
|
+
<div
|
|
803
|
+
class=${`app-content ${isBrowseRoute ? "browse-mode" : ""}`}
|
|
804
|
+
onscroll=${handleAppContentScroll}
|
|
805
|
+
>
|
|
714
806
|
<div class=${`mobile-topbar ${mobileTopbarScrolled ? "is-scrolled" : ""}`}>
|
|
715
807
|
<button
|
|
716
808
|
class="mobile-topbar-menu"
|
|
@@ -728,61 +820,70 @@ const App = () => {
|
|
|
728
820
|
<span style="color: var(--accent)">alpha</span>claw
|
|
729
821
|
</span>
|
|
730
822
|
</div>
|
|
731
|
-
<div class
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
</div>
|
|
737
|
-
</${Route}>
|
|
738
|
-
<${Route} path="/general">
|
|
739
|
-
<div class="pt-4">
|
|
740
|
-
<${GeneralTab}
|
|
741
|
-
statusData=${sharedStatus}
|
|
742
|
-
watchdogData=${sharedWatchdogStatus}
|
|
743
|
-
onRefreshStatuses=${refreshSharedStatuses}
|
|
744
|
-
onSwitchTab=${(nextTab) => setLocation(`/${nextTab}`)}
|
|
745
|
-
onNavigate=${navigateToSubScreen}
|
|
746
|
-
isActive=${location === "/general"}
|
|
747
|
-
restartingGateway=${restartingGateway}
|
|
748
|
-
onRestartGateway=${handleGatewayRestart}
|
|
749
|
-
restartSignal=${gatewayRestartSignal}
|
|
750
|
-
/>
|
|
751
|
-
</div>
|
|
752
|
-
</${Route}>
|
|
753
|
-
<${Route} path="/providers">
|
|
754
|
-
<div class="pt-4">
|
|
755
|
-
<${Providers} onRestartRequired=${setRestartRequired} />
|
|
756
|
-
</div>
|
|
757
|
-
</${Route}>
|
|
758
|
-
<${Route} path="/watchdog">
|
|
759
|
-
<div class="pt-4">
|
|
760
|
-
<${WatchdogTab}
|
|
761
|
-
gatewayStatus=${sharedStatus?.gateway || null}
|
|
762
|
-
openclawVersion=${sharedStatus?.openclawVersion || null}
|
|
763
|
-
watchdogStatus=${sharedWatchdogStatus}
|
|
764
|
-
onRefreshStatuses=${refreshSharedStatuses}
|
|
765
|
-
restartingGateway=${restartingGateway}
|
|
766
|
-
onRestartGateway=${handleGatewayRestart}
|
|
767
|
-
restartSignal=${gatewayRestartSignal}
|
|
823
|
+
<div class=${isBrowseRoute ? "w-full" : "max-w-2xl w-full mx-auto"}>
|
|
824
|
+
${isBrowseRoute
|
|
825
|
+
? html`
|
|
826
|
+
<${FileViewer}
|
|
827
|
+
filePath=${selectedBrowsePath}
|
|
768
828
|
/>
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
829
|
+
`
|
|
830
|
+
: html`
|
|
831
|
+
<${Switch}>
|
|
832
|
+
<${Route} path="/telegram">
|
|
833
|
+
<div class="pt-4">
|
|
834
|
+
<${TelegramWorkspace} onBack=${exitSubScreen} />
|
|
835
|
+
</div>
|
|
836
|
+
</${Route}>
|
|
837
|
+
<${Route} path="/general">
|
|
838
|
+
<div class="pt-4">
|
|
839
|
+
<${GeneralTab}
|
|
840
|
+
statusData=${sharedStatus}
|
|
841
|
+
watchdogData=${sharedWatchdogStatus}
|
|
842
|
+
onRefreshStatuses=${refreshSharedStatuses}
|
|
843
|
+
onSwitchTab=${(nextTab) => setLocation(`/${nextTab}`)}
|
|
844
|
+
onNavigate=${navigateToSubScreen}
|
|
845
|
+
isActive=${location === "/general"}
|
|
846
|
+
restartingGateway=${restartingGateway}
|
|
847
|
+
onRestartGateway=${handleGatewayRestart}
|
|
848
|
+
restartSignal=${gatewayRestartSignal}
|
|
849
|
+
/>
|
|
850
|
+
</div>
|
|
851
|
+
</${Route}>
|
|
852
|
+
<${Route} path="/providers">
|
|
853
|
+
<div class="pt-4">
|
|
854
|
+
<${Providers} onRestartRequired=${setRestartRequired} />
|
|
855
|
+
</div>
|
|
856
|
+
</${Route}>
|
|
857
|
+
<${Route} path="/watchdog">
|
|
858
|
+
<div class="pt-4">
|
|
859
|
+
<${WatchdogTab}
|
|
860
|
+
gatewayStatus=${sharedStatus?.gateway || null}
|
|
861
|
+
openclawVersion=${sharedStatus?.openclawVersion || null}
|
|
862
|
+
watchdogStatus=${sharedWatchdogStatus}
|
|
863
|
+
onRefreshStatuses=${refreshSharedStatuses}
|
|
864
|
+
restartingGateway=${restartingGateway}
|
|
865
|
+
onRestartGateway=${handleGatewayRestart}
|
|
866
|
+
restartSignal=${gatewayRestartSignal}
|
|
867
|
+
/>
|
|
868
|
+
</div>
|
|
869
|
+
</${Route}>
|
|
870
|
+
<${Route} path="/envars">
|
|
871
|
+
<div class="pt-4">
|
|
872
|
+
<${Envars} onRestartRequired=${setRestartRequired} />
|
|
873
|
+
</div>
|
|
874
|
+
</${Route}>
|
|
875
|
+
<${Route} path="/webhooks/:hookName">
|
|
876
|
+
${(params) =>
|
|
877
|
+
renderWebhooks(decodeURIComponent(params.hookName || ""))}
|
|
878
|
+
</${Route}>
|
|
879
|
+
<${Route} path="/webhooks">
|
|
880
|
+
${() => renderWebhooks("")}
|
|
881
|
+
</${Route}>
|
|
882
|
+
<${Route}>
|
|
883
|
+
<${RouteRedirect} to="/general" />
|
|
884
|
+
</${Route}>
|
|
885
|
+
</${Switch}>
|
|
886
|
+
`}
|
|
786
887
|
</div>
|
|
787
888
|
<${ToastContainer}
|
|
788
889
|
className="fixed bottom-10 right-4 z-50 space-y-2 pointer-events-none"
|
|
@@ -43,6 +43,8 @@ export const ActionButton = ({
|
|
|
43
43
|
loadingLabel = "Working...",
|
|
44
44
|
loadingMode = "replace",
|
|
45
45
|
className = "",
|
|
46
|
+
idleIcon = null,
|
|
47
|
+
idleIconClassName = "h-3 w-3",
|
|
46
48
|
}) => {
|
|
47
49
|
const isDisabled = disabled || loading;
|
|
48
50
|
const isInteractive = !isDisabled;
|
|
@@ -57,7 +59,16 @@ export const ActionButton = ({
|
|
|
57
59
|
: "";
|
|
58
60
|
const spinnerSizeClass = size === "md" || size === "lg" ? "h-4 w-4" : "h-3 w-3";
|
|
59
61
|
const isInlineLoading = loadingMode === "inline";
|
|
60
|
-
const
|
|
62
|
+
const IdleIcon = idleIcon;
|
|
63
|
+
const idleContent = IdleIcon
|
|
64
|
+
? html`
|
|
65
|
+
<span class="inline-flex items-center gap-1.5 leading-none">
|
|
66
|
+
<${IdleIcon} className=${idleIconClassName} />
|
|
67
|
+
${idleLabel}
|
|
68
|
+
</span>
|
|
69
|
+
`
|
|
70
|
+
: idleLabel;
|
|
71
|
+
const currentLabel = loading && !isInlineLoading ? loadingLabel : idleContent;
|
|
61
72
|
|
|
62
73
|
return html`
|
|
63
74
|
<button
|