mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-29 06:35:24 +00:00
feat: load plugin frontends at runtime and remove plugin ids from the shell
This commit is contained in:
1 parent
49f0286a14
commit
e88d5a52e3
721 files changed
+54265
-44416
No files matched your search
@@ -74,9 +74,8 @@ import {
|
||||
User,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { readHiddenRailTabs } from "@/sidebar/hidden-rail-tabs";
|
||||
import { SettingRow, FakeSwitch } from "@/components/section-card";
|
||||
import { visibleRailItems } from "./rail-items";
|
||||
import { NavigationVisibilityToggles } from "./NavigationVisibilityToggles";
|
||||
import { InterfacePresetSettings } from "./InterfacePresetSettings";
|
||||
import { useUiPreferencesContext } from "@/contexts/UiPreferencesContext";
|
||||
import { KeybindingsDialog } from "./KeybindingsDialog";
|
||||
@@ -693,57 +692,12 @@ export function UserProfilePanel({
|
||||
return v !== null ? v === "true" : true;
|
||||
});
|
||||
const [keybindingsDialogOpen, setKeybindingsDialogOpen] = useState(false);
|
||||
const [aiAssistantEnabled, setAiAssistantEnabled] = useState(false);
|
||||
const [aiReadOnlyCommands, setAiReadOnlyCommands] = useState(false);
|
||||
// Null until the status call answers; the whole section stays hidden while
|
||||
// unknown so a user who cannot have the feature never sees it mentioned.
|
||||
const [aiGloballyEnabled, setAiGloballyEnabled] = useState<boolean | null>(
|
||||
null,
|
||||
);
|
||||
// Sidebar display customization (density, tags, tray trigger, status
|
||||
// colors) now lives in the dedicated Customize Sidebar panel opened from
|
||||
// the Hosts toolbar, not here -- resetToDefaults still needs write access.
|
||||
const { update: updateSidebarPrefs } = useHostSidebarPreferences();
|
||||
const uiPrefs = useUiPreferencesContext();
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
import("@/api/ai-api")
|
||||
.then(({ getAiStatus }) => getAiStatus())
|
||||
.then((status) => {
|
||||
if (cancelled) return;
|
||||
setAiGloballyEnabled(status.globallyEnabled);
|
||||
setAiAssistantEnabled(status.enabled);
|
||||
setAiReadOnlyCommands(status.allowReadOnlyCommands);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setAiGloballyEnabled(false);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Turning the assistant off also hides its rail tab, so declining removes
|
||||
* the feature from view entirely rather than leaving an inert entry behind.
|
||||
*/
|
||||
const applyAiEnabled = (enabled: boolean) => {
|
||||
setAiAssistantEnabled(enabled);
|
||||
|
||||
const hidden = readHiddenRailTabs();
|
||||
if (enabled) hidden.delete("ai");
|
||||
else hidden.add("ai");
|
||||
|
||||
const serialized = JSON.stringify([...hidden]);
|
||||
localStorage.setItem("hiddenRailTabs", serialized);
|
||||
setHiddenRailTabs(hidden);
|
||||
window.dispatchEvent(new Event("hiddenRailTabsChanged"));
|
||||
|
||||
if (storageMode === "cloud") {
|
||||
saveToCloud({ aiAssistantEnabled: enabled, hiddenRailTabs: serialized });
|
||||
}
|
||||
};
|
||||
const [pinAppRail, setPinAppRail] = useState(() =>
|
||||
readRailPreference("pinAppRail"),
|
||||
);
|
||||
@@ -947,12 +901,6 @@ export function UserProfilePanel({
|
||||
String(prefs.commandPaletteEnabled),
|
||||
);
|
||||
}
|
||||
if (prefs.aiAssistantEnabled != null) {
|
||||
setAiAssistantEnabled(prefs.aiAssistantEnabled);
|
||||
}
|
||||
if (prefs.aiReadOnlyCommands != null) {
|
||||
setAiReadOnlyCommands(prefs.aiReadOnlyCommands);
|
||||
}
|
||||
// showHostTags/hostTrayOnClick/compactHostView/statusColorScheme are
|
||||
// no longer restored here -- useHostSidebarPreferences independently
|
||||
// fetches its own authoritative copy from /host-sidebar/preferences.
|
||||
@@ -2082,34 +2030,6 @@ export function UserProfilePanel({
|
||||
}}
|
||||
/>
|
||||
</SettingRow>
|
||||
{aiGloballyEnabled && (
|
||||
<>
|
||||
<SettingRow
|
||||
label={t("ai.enableTitle")}
|
||||
description={t("ai.enableDescription")}
|
||||
>
|
||||
<FakeSwitch
|
||||
checked={aiAssistantEnabled}
|
||||
onChange={applyAiEnabled}
|
||||
/>
|
||||
</SettingRow>
|
||||
{aiAssistantEnabled && (
|
||||
<SettingRow
|
||||
label={t("ai.readOnlyCommands")}
|
||||
description={t("ai.readOnlyCommandsDescription")}
|
||||
>
|
||||
<FakeSwitch
|
||||
checked={aiReadOnlyCommands}
|
||||
onChange={(v) => {
|
||||
setAiReadOnlyCommands(v);
|
||||
if (storageMode === "cloud")
|
||||
saveToCloud({ aiReadOnlyCommands: v });
|
||||
}}
|
||||
/>
|
||||
</SettingRow>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<SettingRow
|
||||
label={t("newUi.sidebar.userProfile.reopenTabsOnLogin")}
|
||||
description={t("newUi.sidebar.userProfile.reopenTabsOnLoginDesc")}
|
||||
@@ -2211,35 +2131,17 @@ export function UserProfilePanel({
|
||||
<p className="text-[10px] text-muted-foreground mb-2">
|
||||
{t("newUi.sidebar.userProfile.navigationTabsDesc")}
|
||||
</p>
|
||||
{visibleRailItems()
|
||||
.filter((tab) => tab.id !== "ai" || aiGloballyEnabled)
|
||||
.map((tab) => (
|
||||
<div
|
||||
key={tab.id}
|
||||
className="flex items-center justify-between py-1.5"
|
||||
>
|
||||
<span className="flex items-center gap-1.5 text-xs font-medium text-foreground">
|
||||
<span className="text-muted-foreground">
|
||||
<tab.icon size={12} />
|
||||
</span>
|
||||
{t(tab.labelKey)}
|
||||
</span>
|
||||
<FakeSwitch
|
||||
checked={!hiddenRailTabs.has(tab.id)}
|
||||
onChange={(visible) => {
|
||||
const next = new Set(hiddenRailTabs);
|
||||
if (visible) next.delete(tab.id);
|
||||
else next.add(tab.id);
|
||||
setHiddenRailTabs(next);
|
||||
const serialized = JSON.stringify([...next]);
|
||||
localStorage.setItem("hiddenRailTabs", serialized);
|
||||
window.dispatchEvent(new Event("hiddenRailTabsChanged"));
|
||||
if (storageMode === "cloud")
|
||||
saveToCloud({ hiddenRailTabs: serialized });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
<NavigationVisibilityToggles
|
||||
hidden={hiddenRailTabs}
|
||||
onChange={(next) => {
|
||||
setHiddenRailTabs(next);
|
||||
const serialized = JSON.stringify([...next]);
|
||||
localStorage.setItem("hiddenRailTabs", serialized);
|
||||
window.dispatchEvent(new Event("hiddenRailTabsChanged"));
|
||||
if (storageMode === "cloud")
|
||||
saveToCloud({ hiddenRailTabs: serialized });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1 border-t border-border pt-3">
|
||||
|
||||
Reference in new issue
Block a user