@chrysb/alphaclaw 0.3.2 → 0.3.4-beta.0
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 +47 -2
- package/lib/cli/git-sync.js +25 -0
- package/lib/plugin/usage-tracker/index.js +308 -0
- package/lib/plugin/usage-tracker/openclaw.plugin.json +8 -0
- package/lib/public/css/explorer.css +1033 -0
- package/lib/public/css/shell.css +50 -4
- package/lib/public/css/theme.css +41 -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 +310 -160
- package/lib/public/js/components/action-button.js +12 -1
- package/lib/public/js/components/file-tree.js +497 -0
- package/lib/public/js/components/file-viewer.js +714 -0
- package/lib/public/js/components/icons.js +182 -0
- package/lib/public/js/components/segmented-control.js +33 -0
- package/lib/public/js/components/sidebar-git-panel.js +149 -0
- package/lib/public/js/components/sidebar.js +254 -0
- package/lib/public/js/components/telegram-workspace/index.js +353 -0
- package/lib/public/js/components/telegram-workspace/manage.js +397 -0
- package/lib/public/js/components/telegram-workspace/onboarding.js +616 -0
- package/lib/public/js/components/usage-tab.js +528 -0
- package/lib/public/js/components/watchdog-tab.js +1 -1
- package/lib/public/js/lib/api.js +51 -1
- 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/js/lib/telegram-api.js +78 -0
- package/lib/public/js/lib/ui-settings.js +38 -0
- package/lib/public/setup.html +34 -29
- package/lib/server/alphaclaw-version.js +3 -3
- package/lib/server/constants.js +2 -0
- package/lib/server/onboarding/openclaw.js +15 -0
- package/lib/server/onboarding/workspace.js +3 -2
- package/lib/server/routes/auth.js +5 -1
- package/lib/server/routes/browse.js +295 -0
- package/lib/server/routes/telegram.js +185 -60
- package/lib/server/routes/usage.js +133 -0
- package/lib/server/usage-db.js +570 -0
- package/lib/server.js +45 -4
- package/lib/setup/core-prompts/AGENTS.md +0 -101
- 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/js/components/telegram-workspace.js +0 -1365
package/lib/public/js/app.js
CHANGED
|
@@ -34,14 +34,26 @@ import { Welcome } from "./components/welcome.js";
|
|
|
34
34
|
import { Envars } from "./components/envars.js";
|
|
35
35
|
import { Webhooks } from "./components/webhooks.js";
|
|
36
36
|
import { ToastContainer, showToast } from "./components/toast.js";
|
|
37
|
-
import { TelegramWorkspace } from "./components/telegram-workspace.js";
|
|
37
|
+
import { TelegramWorkspace } from "./components/telegram-workspace/index.js";
|
|
38
38
|
import { ChevronDownIcon } from "./components/icons.js";
|
|
39
39
|
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";
|
|
45
|
+
import { UsageTab } from "./components/usage-tab.js";
|
|
46
|
+
import { readUiSettings, writeUiSettings } from "./lib/ui-settings.js";
|
|
43
47
|
const html = htm.bind(h);
|
|
44
48
|
const kDefaultUiTab = "general";
|
|
49
|
+
const kDefaultSidebarWidthPx = 220;
|
|
50
|
+
const kSidebarMinWidthPx = 180;
|
|
51
|
+
const kSidebarMaxWidthPx = 460;
|
|
52
|
+
const kBrowseLastPathUiSettingKey = "browseLastPath";
|
|
53
|
+
const kLastMenuRouteUiSettingKey = "lastMenuRoute";
|
|
54
|
+
|
|
55
|
+
const clampSidebarWidth = (value) =>
|
|
56
|
+
Math.max(kSidebarMinWidthPx, Math.min(kSidebarMaxWidthPx, value));
|
|
45
57
|
|
|
46
58
|
const getHashPath = () => {
|
|
47
59
|
const hash = window.location.hash.replace(/^#/, "");
|
|
@@ -158,16 +170,12 @@ const GeneralTab = ({
|
|
|
158
170
|
setTimeout(devicePoll.refresh, 2000);
|
|
159
171
|
};
|
|
160
172
|
|
|
161
|
-
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
if (!isActive) return;
|
|
162
175
|
onRefreshStatuses();
|
|
163
176
|
pairingsPoll.refresh();
|
|
164
177
|
devicePoll.refresh();
|
|
165
178
|
setGoogleKey((k) => k + 1);
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
useEffect(() => {
|
|
169
|
-
if (!isActive) return;
|
|
170
|
-
fullRefresh();
|
|
171
179
|
}, [isActive]);
|
|
172
180
|
|
|
173
181
|
useEffect(() => {
|
|
@@ -360,23 +368,12 @@ const GeneralTab = ({
|
|
|
360
368
|
onReject=${handleDeviceReject}
|
|
361
369
|
/>
|
|
362
370
|
</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
371
|
</div>
|
|
376
372
|
`;
|
|
377
373
|
};
|
|
378
374
|
|
|
379
375
|
const App = () => {
|
|
376
|
+
const appShellRef = useRef(null);
|
|
380
377
|
const [onboarded, setOnboarded] = useState(null);
|
|
381
378
|
const [location, setLocation] = useLocation();
|
|
382
379
|
const [acVersion, setAcVersion] = useState(null);
|
|
@@ -386,6 +383,32 @@ const App = () => {
|
|
|
386
383
|
const [acDismissed, setAcDismissed] = useState(false);
|
|
387
384
|
const [authEnabled, setAuthEnabled] = useState(false);
|
|
388
385
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
386
|
+
const [sidebarTab, setSidebarTab] = useState("menu");
|
|
387
|
+
const [sidebarWidthPx, setSidebarWidthPx] = useState(() => {
|
|
388
|
+
const settings = readUiSettings();
|
|
389
|
+
if (!Number.isFinite(settings.sidebarWidthPx)) return kDefaultSidebarWidthPx;
|
|
390
|
+
return clampSidebarWidth(settings.sidebarWidthPx);
|
|
391
|
+
});
|
|
392
|
+
const [lastBrowsePath, setLastBrowsePath] = useState(() => {
|
|
393
|
+
const settings = readUiSettings();
|
|
394
|
+
return typeof settings[kBrowseLastPathUiSettingKey] === "string"
|
|
395
|
+
? settings[kBrowseLastPathUiSettingKey]
|
|
396
|
+
: "";
|
|
397
|
+
});
|
|
398
|
+
const [lastMenuRoute, setLastMenuRoute] = useState(() => {
|
|
399
|
+
const settings = readUiSettings();
|
|
400
|
+
const storedRoute = settings[kLastMenuRouteUiSettingKey];
|
|
401
|
+
if (
|
|
402
|
+
typeof storedRoute === "string" &&
|
|
403
|
+
storedRoute.startsWith("/") &&
|
|
404
|
+
!storedRoute.startsWith("/browse")
|
|
405
|
+
) {
|
|
406
|
+
return storedRoute;
|
|
407
|
+
}
|
|
408
|
+
return `/${kDefaultUiTab}`;
|
|
409
|
+
});
|
|
410
|
+
const [isResizingSidebar, setIsResizingSidebar] = useState(false);
|
|
411
|
+
const [browsePreviewPath, setBrowsePreviewPath] = useState("");
|
|
389
412
|
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
|
390
413
|
const [mobileTopbarScrolled, setMobileTopbarScrolled] = useState(false);
|
|
391
414
|
const [restartRequired, setRestartRequired] = useState(false);
|
|
@@ -568,10 +591,47 @@ const App = () => {
|
|
|
568
591
|
`;
|
|
569
592
|
}
|
|
570
593
|
|
|
594
|
+
const buildBrowseRoute = (relativePath) => {
|
|
595
|
+
const encodedPath = String(relativePath || "")
|
|
596
|
+
.split("/")
|
|
597
|
+
.filter(Boolean)
|
|
598
|
+
.map((segment) => encodeURIComponent(segment))
|
|
599
|
+
.join("/");
|
|
600
|
+
return encodedPath ? `/browse/${encodedPath}` : "/browse";
|
|
601
|
+
};
|
|
571
602
|
const navigateToSubScreen = (screen) => {
|
|
572
603
|
setLocation(`/${screen}`);
|
|
573
604
|
setMobileSidebarOpen(false);
|
|
574
605
|
};
|
|
606
|
+
const navigateToBrowseFile = (relativePath) => {
|
|
607
|
+
setBrowsePreviewPath("");
|
|
608
|
+
setLocation(buildBrowseRoute(relativePath));
|
|
609
|
+
setMobileSidebarOpen(false);
|
|
610
|
+
};
|
|
611
|
+
const handleSidebarLogout = async () => {
|
|
612
|
+
setMenuOpen(false);
|
|
613
|
+
await logout();
|
|
614
|
+
try {
|
|
615
|
+
window.localStorage.clear();
|
|
616
|
+
window.sessionStorage.clear();
|
|
617
|
+
} catch {}
|
|
618
|
+
window.location.href = "/login.html";
|
|
619
|
+
};
|
|
620
|
+
const handleSelectSidebarTab = (nextTab) => {
|
|
621
|
+
setSidebarTab(nextTab);
|
|
622
|
+
if (nextTab === "menu" && location.startsWith("/browse")) {
|
|
623
|
+
setBrowsePreviewPath("");
|
|
624
|
+
setLocation(lastMenuRoute || `/${kDefaultUiTab}`);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
if (nextTab === "browse" && !location.startsWith("/browse")) {
|
|
628
|
+
setLocation(buildBrowseRoute(lastBrowsePath));
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
const handleSelectNavItem = (itemId) => {
|
|
632
|
+
setLocation(`/${itemId}`);
|
|
633
|
+
setMobileSidebarOpen(false);
|
|
634
|
+
};
|
|
575
635
|
const exitSubScreen = () => {
|
|
576
636
|
setLocation(`/${kDefaultUiTab}`);
|
|
577
637
|
setMobileSidebarOpen(false);
|
|
@@ -585,10 +645,16 @@ const App = () => {
|
|
|
585
645
|
|
|
586
646
|
const kNavSections = [
|
|
587
647
|
{
|
|
588
|
-
label: "
|
|
648
|
+
label: "Setup",
|
|
589
649
|
items: [
|
|
590
650
|
{ id: "general", label: "General" },
|
|
651
|
+
],
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
label: "Monitoring",
|
|
655
|
+
items: [
|
|
591
656
|
{ id: "watchdog", label: "Watchdog" },
|
|
657
|
+
{ id: "usage", label: "Usage" },
|
|
592
658
|
],
|
|
593
659
|
},
|
|
594
660
|
{
|
|
@@ -601,18 +667,105 @@ const App = () => {
|
|
|
601
667
|
},
|
|
602
668
|
];
|
|
603
669
|
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
670
|
+
const isBrowseRoute = location.startsWith("/browse");
|
|
671
|
+
const selectedBrowsePath = isBrowseRoute
|
|
672
|
+
? location
|
|
673
|
+
.replace(/^\/browse\/?/, "")
|
|
674
|
+
.split("/")
|
|
675
|
+
.filter(Boolean)
|
|
676
|
+
.map((segment) => {
|
|
677
|
+
try {
|
|
678
|
+
return decodeURIComponent(segment);
|
|
679
|
+
} catch {
|
|
680
|
+
return segment;
|
|
681
|
+
}
|
|
682
|
+
})
|
|
683
|
+
.join("/")
|
|
684
|
+
: "";
|
|
685
|
+
const selectedNavId = isBrowseRoute
|
|
686
|
+
? "browse"
|
|
687
|
+
: location === "/telegram"
|
|
688
|
+
? ""
|
|
689
|
+
: location.startsWith("/providers")
|
|
690
|
+
? "providers"
|
|
691
|
+
: location.startsWith("/watchdog")
|
|
692
|
+
? "watchdog"
|
|
693
|
+
: location.startsWith("/usage")
|
|
694
|
+
? "usage"
|
|
695
|
+
: location.startsWith("/envars")
|
|
696
|
+
? "envars"
|
|
697
|
+
: location.startsWith("/webhooks")
|
|
698
|
+
? "webhooks"
|
|
699
|
+
: "general";
|
|
700
|
+
|
|
701
|
+
useEffect(() => {
|
|
702
|
+
setSidebarTab((currentTab) => {
|
|
703
|
+
if (location.startsWith("/browse")) return "browse";
|
|
704
|
+
if (currentTab === "browse") return "menu";
|
|
705
|
+
return currentTab;
|
|
706
|
+
});
|
|
707
|
+
}, [location]);
|
|
708
|
+
|
|
709
|
+
useEffect(() => {
|
|
710
|
+
if (location.startsWith("/browse")) return;
|
|
711
|
+
setBrowsePreviewPath("");
|
|
712
|
+
}, [location]);
|
|
713
|
+
|
|
714
|
+
useEffect(() => {
|
|
715
|
+
if (location.startsWith("/browse")) return;
|
|
716
|
+
if (location === "/telegram") return;
|
|
717
|
+
setLastMenuRoute((currentRoute) =>
|
|
718
|
+
currentRoute === location ? currentRoute : location,
|
|
719
|
+
);
|
|
720
|
+
}, [location]);
|
|
721
|
+
|
|
722
|
+
useEffect(() => {
|
|
723
|
+
if (!isBrowseRoute) return;
|
|
724
|
+
if (!selectedBrowsePath) return;
|
|
725
|
+
setLastBrowsePath((currentPath) =>
|
|
726
|
+
currentPath === selectedBrowsePath ? currentPath : selectedBrowsePath,
|
|
727
|
+
);
|
|
728
|
+
}, [isBrowseRoute, selectedBrowsePath]);
|
|
729
|
+
|
|
730
|
+
useEffect(() => {
|
|
731
|
+
const settings = readUiSettings();
|
|
732
|
+
settings.sidebarWidthPx = sidebarWidthPx;
|
|
733
|
+
settings[kBrowseLastPathUiSettingKey] = lastBrowsePath;
|
|
734
|
+
settings[kLastMenuRouteUiSettingKey] = lastMenuRoute;
|
|
735
|
+
writeUiSettings(settings);
|
|
736
|
+
}, [sidebarWidthPx, lastBrowsePath, lastMenuRoute]);
|
|
737
|
+
|
|
738
|
+
const resizeSidebarWithClientX = useCallback((clientX) => {
|
|
739
|
+
const shellElement = appShellRef.current;
|
|
740
|
+
if (!shellElement) return;
|
|
741
|
+
const shellBounds = shellElement.getBoundingClientRect();
|
|
742
|
+
const nextWidth = clampSidebarWidth(Math.round(clientX - shellBounds.left));
|
|
743
|
+
setSidebarWidthPx(nextWidth);
|
|
744
|
+
}, []);
|
|
745
|
+
|
|
746
|
+
const onSidebarResizerPointerDown = (event) => {
|
|
747
|
+
event.preventDefault();
|
|
748
|
+
setIsResizingSidebar(true);
|
|
749
|
+
resizeSidebarWithClientX(event.clientX);
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
useEffect(() => {
|
|
753
|
+
if (!isResizingSidebar) return () => {};
|
|
754
|
+
const onPointerMove = (event) => resizeSidebarWithClientX(event.clientX);
|
|
755
|
+
const onPointerUp = () => setIsResizingSidebar(false);
|
|
756
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
757
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
758
|
+
const previousUserSelect = document.body.style.userSelect;
|
|
759
|
+
const previousCursor = document.body.style.cursor;
|
|
760
|
+
document.body.style.userSelect = "none";
|
|
761
|
+
document.body.style.cursor = "col-resize";
|
|
762
|
+
return () => {
|
|
763
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
764
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
765
|
+
document.body.style.userSelect = previousUserSelect;
|
|
766
|
+
document.body.style.cursor = previousCursor;
|
|
767
|
+
};
|
|
768
|
+
}, [isResizingSidebar, resizeSidebarWithClientX]);
|
|
616
769
|
|
|
617
770
|
const renderWebhooks = (hookName = "") => html`
|
|
618
771
|
<div class="pt-4">
|
|
@@ -626,91 +779,54 @@ const App = () => {
|
|
|
626
779
|
`;
|
|
627
780
|
|
|
628
781
|
return html`
|
|
629
|
-
<div
|
|
782
|
+
<div
|
|
783
|
+
class="app-shell"
|
|
784
|
+
ref=${appShellRef}
|
|
785
|
+
style=${{ "--sidebar-width": `${sidebarWidthPx}px` }}
|
|
786
|
+
>
|
|
630
787
|
<${GlobalRestartBanner}
|
|
631
788
|
visible=${restartRequired}
|
|
632
789
|
restarting=${restartingGateway}
|
|
633
790
|
onRestart=${handleGatewayRestart}
|
|
634
791
|
/>
|
|
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
|
-
|
|
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>
|
|
792
|
+
<${AppSidebar}
|
|
793
|
+
mobileSidebarOpen=${mobileSidebarOpen}
|
|
794
|
+
authEnabled=${authEnabled}
|
|
795
|
+
menuRef=${menuRef}
|
|
796
|
+
menuOpen=${menuOpen}
|
|
797
|
+
onToggleMenu=${() => setMenuOpen((open) => !open)}
|
|
798
|
+
onLogout=${handleSidebarLogout}
|
|
799
|
+
sidebarTab=${sidebarTab}
|
|
800
|
+
onSelectSidebarTab=${handleSelectSidebarTab}
|
|
801
|
+
navSections=${kNavSections}
|
|
802
|
+
selectedNavId=${selectedNavId}
|
|
803
|
+
onSelectNavItem=${handleSelectNavItem}
|
|
804
|
+
selectedBrowsePath=${selectedBrowsePath}
|
|
805
|
+
onSelectBrowseFile=${navigateToBrowseFile}
|
|
806
|
+
onPreviewBrowseFile=${setBrowsePreviewPath}
|
|
807
|
+
acHasUpdate=${acHasUpdate}
|
|
808
|
+
acLatest=${acLatest}
|
|
809
|
+
acDismissed=${acDismissed}
|
|
810
|
+
acUpdating=${acUpdating}
|
|
811
|
+
onAcUpdate=${handleAcUpdate}
|
|
812
|
+
/>
|
|
813
|
+
<div
|
|
814
|
+
class=${`sidebar-resizer ${isResizingSidebar ? "is-resizing" : ""}`}
|
|
815
|
+
onpointerdown=${onSidebarResizerPointerDown}
|
|
816
|
+
role="separator"
|
|
817
|
+
aria-orientation="vertical"
|
|
818
|
+
aria-label="Resize sidebar"
|
|
819
|
+
></div>
|
|
707
820
|
|
|
708
821
|
<div
|
|
709
822
|
class=${`mobile-sidebar-overlay ${mobileSidebarOpen ? "active" : ""}`}
|
|
710
823
|
onclick=${() => setMobileSidebarOpen(false)}
|
|
711
824
|
/>
|
|
712
825
|
|
|
713
|
-
<div
|
|
826
|
+
<div
|
|
827
|
+
class=${`app-content ${isBrowseRoute ? "browse-mode" : ""}`}
|
|
828
|
+
onscroll=${handleAppContentScroll}
|
|
829
|
+
>
|
|
714
830
|
<div class=${`mobile-topbar ${mobileTopbarScrolled ? "is-scrolled" : ""}`}>
|
|
715
831
|
<button
|
|
716
832
|
class="mobile-topbar-menu"
|
|
@@ -728,61 +844,95 @@ const App = () => {
|
|
|
728
844
|
<span style="color: var(--accent)">alpha</span>claw
|
|
729
845
|
</span>
|
|
730
846
|
</div>
|
|
731
|
-
<div class
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
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}
|
|
847
|
+
<div class=${isBrowseRoute ? "w-full" : "max-w-2xl w-full mx-auto"}>
|
|
848
|
+
${isBrowseRoute
|
|
849
|
+
? html`
|
|
850
|
+
<${FileViewer}
|
|
851
|
+
filePath=${browsePreviewPath || selectedBrowsePath}
|
|
852
|
+
isPreviewOnly=${Boolean(
|
|
853
|
+
browsePreviewPath &&
|
|
854
|
+
browsePreviewPath !== selectedBrowsePath,
|
|
855
|
+
)}
|
|
768
856
|
/>
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
857
|
+
`
|
|
858
|
+
: html`
|
|
859
|
+
<${Switch}>
|
|
860
|
+
<${Route} path="/telegram">
|
|
861
|
+
<div class="pt-4">
|
|
862
|
+
<${TelegramWorkspace} onBack=${exitSubScreen} />
|
|
863
|
+
</div>
|
|
864
|
+
</${Route}>
|
|
865
|
+
<${Route} path="/general">
|
|
866
|
+
<div class="pt-4">
|
|
867
|
+
<${GeneralTab}
|
|
868
|
+
statusData=${sharedStatus}
|
|
869
|
+
watchdogData=${sharedWatchdogStatus}
|
|
870
|
+
onRefreshStatuses=${refreshSharedStatuses}
|
|
871
|
+
onSwitchTab=${(nextTab) => setLocation(`/${nextTab}`)}
|
|
872
|
+
onNavigate=${navigateToSubScreen}
|
|
873
|
+
isActive=${location === "/general"}
|
|
874
|
+
restartingGateway=${restartingGateway}
|
|
875
|
+
onRestartGateway=${handleGatewayRestart}
|
|
876
|
+
restartSignal=${gatewayRestartSignal}
|
|
877
|
+
/>
|
|
878
|
+
</div>
|
|
879
|
+
</${Route}>
|
|
880
|
+
<${Route} path="/providers">
|
|
881
|
+
<div class="pt-4">
|
|
882
|
+
<${Providers} onRestartRequired=${setRestartRequired} />
|
|
883
|
+
</div>
|
|
884
|
+
</${Route}>
|
|
885
|
+
<${Route} path="/watchdog">
|
|
886
|
+
<div class="pt-4">
|
|
887
|
+
<${WatchdogTab}
|
|
888
|
+
gatewayStatus=${sharedStatus?.gateway || null}
|
|
889
|
+
openclawVersion=${sharedStatus?.openclawVersion || null}
|
|
890
|
+
watchdogStatus=${sharedWatchdogStatus}
|
|
891
|
+
onRefreshStatuses=${refreshSharedStatuses}
|
|
892
|
+
restartingGateway=${restartingGateway}
|
|
893
|
+
onRestartGateway=${handleGatewayRestart}
|
|
894
|
+
restartSignal=${gatewayRestartSignal}
|
|
895
|
+
/>
|
|
896
|
+
</div>
|
|
897
|
+
</${Route}>
|
|
898
|
+
<${Route} path="/usage/:sessionId">
|
|
899
|
+
${(params) => html`
|
|
900
|
+
<div class="pt-4">
|
|
901
|
+
<${UsageTab}
|
|
902
|
+
sessionId=${decodeURIComponent(params.sessionId || "")}
|
|
903
|
+
onSelectSession=${(id) =>
|
|
904
|
+
setLocation(`/usage/${encodeURIComponent(String(id || ""))}`)}
|
|
905
|
+
onBackToSessions=${() => setLocation("/usage")}
|
|
906
|
+
/>
|
|
907
|
+
</div>
|
|
908
|
+
`}
|
|
909
|
+
</${Route}>
|
|
910
|
+
<${Route} path="/usage">
|
|
911
|
+
<div class="pt-4">
|
|
912
|
+
<${UsageTab}
|
|
913
|
+
onSelectSession=${(id) =>
|
|
914
|
+
setLocation(`/usage/${encodeURIComponent(String(id || ""))}`)}
|
|
915
|
+
onBackToSessions=${() => setLocation("/usage")}
|
|
916
|
+
/>
|
|
917
|
+
</div>
|
|
918
|
+
</${Route}>
|
|
919
|
+
<${Route} path="/envars">
|
|
920
|
+
<div class="pt-4">
|
|
921
|
+
<${Envars} onRestartRequired=${setRestartRequired} />
|
|
922
|
+
</div>
|
|
923
|
+
</${Route}>
|
|
924
|
+
<${Route} path="/webhooks/:hookName">
|
|
925
|
+
${(params) =>
|
|
926
|
+
renderWebhooks(decodeURIComponent(params.hookName || ""))}
|
|
927
|
+
</${Route}>
|
|
928
|
+
<${Route} path="/webhooks">
|
|
929
|
+
${() => renderWebhooks("")}
|
|
930
|
+
</${Route}>
|
|
931
|
+
<${Route}>
|
|
932
|
+
<${RouteRedirect} to="/general" />
|
|
933
|
+
</${Route}>
|
|
934
|
+
</${Switch}>
|
|
935
|
+
`}
|
|
786
936
|
</div>
|
|
787
937
|
<${ToastContainer}
|
|
788
938
|
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
|