feat: consent check, developer mode file installs, install counts and issue links for plugins

This commit is contained in:
LukeGus committed 2026-10-06 14:30:56 -05:00
1 parent 26a474bb3d
commit 08db1fcdde
28 files changed
+2248 -72

No files matched your search

@@ -0,0 +1,77 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import { SettingRow } from "@/components/section-card";
import { useConfirm } from "@/components/surface/surface-scope";
import { getDeveloperMode, setDeveloperMode } from "@/api/plugins-api";
import { AdminToggle } from "./AdminSettingsShared";
/** Lets admins install plugins from a file. Asks before turning it on. */
export function AdminPluginDeveloperMode() {
const { t } = useTranslation();
const confirm = useConfirm();
const [enabled, setEnabled] = useState(false);
const [signedOnly, setSignedOnly] = useState(false);
const [loaded, setLoaded] = useState(false);
const [saving, setSaving] = useState(false);
useEffect(() => {
let cancelled = false;
getDeveloperMode()
.then((state) => {
if (cancelled) return;
setEnabled(state.enabled);
setSignedOnly(state.signedOnly);
setLoaded(true);
})
.catch(() => {});
return () => {
cancelled = true;
};
}, []);
const toggle = async () => {
const next = !enabled;
if (next) {
const ok = await confirm({
title: t("plugins.manager.developer.enableTitle"),
description: t("plugins.manager.developer.enableBody"),
confirmLabel: t("plugins.manager.developer.enable"),
});
if (!ok) return;
}
setSaving(true);
try {
await setDeveloperMode(next);
setEnabled(next);
} catch (error) {
toast.error(
t("plugins.manager.errors.developerMode", {
error: error instanceof Error ? error.message : String(error),
}),
);
} finally {
setSaving(false);
}
};
return (
<>
<SettingRow
label={t("plugins.manager.developer.title")}
description={t("plugins.manager.developer.hint")}
>
<AdminToggle
on={enabled}
onToggle={() => void toggle()}
disabled={!loaded || saving}
/>
</SettingRow>
{enabled && signedOnly && (
<p className="text-[10px] text-destructive">
{t("plugins.manager.developer.signedOnly")}
</p>
)}
</>
);
}
+2
View File
@@ -6,6 +6,7 @@ import { SettingRow } from "@/components/section-card";
import { Database, Lock, RefreshCw, Server, Settings } from "lucide-react";
import { AccordionSection, AdminToggle } from "./AdminSettingsShared";
import { AdminHostTags } from "./AdminHostTags";
import { AdminPluginDeveloperMode } from "./AdminPluginDeveloperMode";
import type { TlsStatus } from "@/api/tls-api";
type GeneralSettingsSectionProps = {
@@ -142,6 +143,7 @@ export function AdminGeneralSettingsSection({
onToggle={handleTogglePasswordReset}
/>
</SettingRow>
<AdminPluginDeveloperMode />
<div className="flex flex-col gap-2 pt-3 mt-2">
<span className="text-[10px] font-bold uppercase tracking-widest text-muted-foreground">
{t("admin.sessionTimeout")}