750d74a2af
- omp-share.js: an admin's switch (S3) runs omp's own auth broker + gateway as the host on loopback; a member's omp pane reaches it as a scoped client keyed by its pane token (clients file = live omp panes only), runs on --model agenthub/<model>, never holds a credential. - omp catalog: --allow-home, so a workspace at the account's home keeps its sessions there (they were recorded under a temp dir and dropped). - Settings → Appearance → Open Markdown as: Preview (default) or Raw, for Files/Changes, the config viewer and a chat's file panel. - First-login password change and password rules, avatar URLs, Artifacts "Mine" includes installed shared skills/plugins, a member's own hook pages.
69 lines
2.3 KiB
TypeScript
69 lines
2.3 KiB
TypeScript
/**
|
|
* @file OmpSharingSettings — Settings → AI tools → Oh My Pi login sharing: the
|
|
* admin's server-wide switch that lets every member's omp pane run on the
|
|
* HOST account's omp login through omp's own auth broker + gateway, without
|
|
* any member holding a credential (`GET/PUT /api/ai-tools/omp-sharing`,
|
|
* `server/lib/omp-share.js`). Renders nothing outside server mode with
|
|
* per-user accounts (S3), or for anyone but an admin.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { api, type OmpSharingState } from "../../lib/api";
|
|
import { toast } from "../../lib/toast";
|
|
import { usePermissions } from "../AuthGate";
|
|
import { SettingsSection, SettingsSwitchRow } from "./SettingsRow";
|
|
|
|
export function OmpSharingSettings() {
|
|
const { t } = useTranslation("settings");
|
|
const { isAdmin, local } = usePermissions();
|
|
const [state, setState] = useState<OmpSharingState | null>(null);
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (local || !isAdmin) return;
|
|
api.aiTools
|
|
.ompSharing()
|
|
.then(setState)
|
|
.catch(() => setState(null));
|
|
}, [local, isAdmin]);
|
|
|
|
if (local || !isAdmin || !state?.available) return null;
|
|
const error = state.broker.error || state.gateway.error;
|
|
const status = !state.enabled
|
|
? null
|
|
: !state.installed
|
|
? t("ompSharing.notInstalled")
|
|
: state.broker.running && state.gateway.running
|
|
? t("ompSharing.running")
|
|
: error
|
|
? t("ompSharing.failed", { error })
|
|
: t("ompSharing.starting");
|
|
return (
|
|
<SettingsSection id="omp-sharing" title={t("ompSharing.title")}>
|
|
<SettingsSwitchRow
|
|
label={t("ompSharing.switch")}
|
|
description={t("ompSharing.hint")}
|
|
checked={state.enabled}
|
|
disabled={busy}
|
|
onChange={async (on) => {
|
|
setBusy(true);
|
|
try {
|
|
setState(await api.aiTools.setOmpSharing(on));
|
|
} catch (err) {
|
|
toast.error(err);
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
}}
|
|
/>
|
|
{status && (
|
|
<p data-testid="omp-sharing-status" className="text-xs text-fg-muted">
|
|
{status}
|
|
</p>
|
|
)}
|
|
</SettingsSection>
|
|
);
|
|
}
|