fixes
This commit is contained in:
@@ -32,7 +32,8 @@ export function OllamaModelsModal({ open, onClose }: { open: boolean; onClose: (
|
||||
|
||||
async function refreshInstalled() {
|
||||
try {
|
||||
const res = await api.models();
|
||||
// Admin view: force a fresh upstream fetch, bypassing the 60s user cache.
|
||||
const res = await api.models({ refresh: true });
|
||||
setInstalled(res.models.filter((m) => m.driver === "ollama"));
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export function SharePage({ publicId }: { publicId: string }) {
|
||||
{chat?.messages.map((m, i) => (
|
||||
<div key={i} className="flex gap-3">
|
||||
{m.role === "user"
|
||||
? <Avatar name={chat.authorName} size={32} />
|
||||
? <Avatar name={chat.authorName} url={chat.authorAvatarUrl || undefined} size={32} />
|
||||
: <AssistantAvatar size={32} />}
|
||||
<div className="min-w-0 max-w-[90%] flex-1">
|
||||
<div className="mb-1 flex items-center gap-1.5 text-xs opacity-60">
|
||||
|
||||
@@ -794,7 +794,7 @@ function SecuritySection({ onKeyRotated }: { onKeyRotated?: () => void }) {
|
||||
<div>
|
||||
<p className="mb-1 flex items-center gap-1.5 text-sm font-medium"><KeyRound size={14} className="opacity-60" /> Access key</p>
|
||||
<p className="mb-2 text-xs opacity-60">Rotate your access key. Old sessions are revoked immediately — you'll log back in with the new key.</p>
|
||||
<Button size="sm" variant="secondary" disabled={busy} onClick={rotate}>
|
||||
<Button size="sm" variant="secondary" type="button" disabled={busy} onClick={rotate}>
|
||||
{armingRotate ? "Click again to confirm rotation" : "Rotate my access key"}
|
||||
</Button>
|
||||
</div>
|
||||
@@ -805,7 +805,7 @@ function SecuritySection({ onKeyRotated }: { onKeyRotated?: () => void }) {
|
||||
{totpOn === false && !secret && (
|
||||
<>
|
||||
<p className="mb-2 text-xs opacity-60">Add a 6-digit code from your authenticator app on top of your access key.</p>
|
||||
<Button size="sm" variant="secondary" disabled={busy} onClick={startTotp}>Enable two-factor</Button>
|
||||
<Button size="sm" variant="secondary" type="button" disabled={busy} onClick={startTotp}>Enable two-factor</Button>
|
||||
</>
|
||||
)}
|
||||
{secret && (
|
||||
@@ -825,7 +825,7 @@ function SecuritySection({ onKeyRotated }: { onKeyRotated?: () => void }) {
|
||||
inputMode="numeric"
|
||||
className="text-center tracking-[0.4em]"
|
||||
/>
|
||||
<Button size="sm" disabled={busy || code.length !== 6} onClick={confirmTotp}>Confirm</Button>
|
||||
<Button size="sm" type="button" disabled={busy || code.length !== 6} onClick={confirmTotp}>Confirm</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -843,7 +843,7 @@ function SecuritySection({ onKeyRotated }: { onKeyRotated?: () => void }) {
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
<Button size="sm" variant="secondary" disabled={busy || code.length !== 6} onClick={disableTotp} className="!text-red-600 dark:!text-red-400">
|
||||
<Button size="sm" variant="secondary" type="button" disabled={busy || code.length !== 6} onClick={disableTotp} className="!text-red-600 dark:!text-red-400">
|
||||
Disable 2FA
|
||||
</Button>
|
||||
</div>
|
||||
@@ -863,7 +863,7 @@ function SecuritySection({ onKeyRotated }: { onKeyRotated?: () => void }) {
|
||||
<Trash2 size={14} /> Danger zone
|
||||
</p>
|
||||
<p className="mb-2 text-xs opacity-60">Permanently delete your account with all chats, shares and sessions. Cannot be undone.</p>
|
||||
<Button size="sm" variant="secondary" disabled={busy} onClick={() => setConfirmDelete(true)} className="!text-red-600 dark:!text-red-400">
|
||||
<Button size="sm" variant="secondary" type="button" disabled={busy} onClick={() => setConfirmDelete(true)} className="!text-red-600 dark:!text-red-400">
|
||||
Delete my account
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -11,9 +11,10 @@ type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
size?: "sm" | "md" | "lg" | "icon";
|
||||
};
|
||||
|
||||
export function Button({ variant = "primary", size = "md", className, ...props }: ButtonProps) {
|
||||
export function Button({ variant = "primary", size = "md", type = "button", className, ...props }: ButtonProps) {
|
||||
return (
|
||||
<button
|
||||
type={type}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center gap-2 rounded-full font-medium transition active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-50",
|
||||
size === "sm" && "px-3.5 py-1.5 text-sm",
|
||||
@@ -566,6 +567,7 @@ export function CopyButton({ text, label }: { text: string; label?: string }) {
|
||||
const [done, setDone] = useState(false);
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
setDone(true);
|
||||
|
||||
@@ -139,7 +139,8 @@ export const api = {
|
||||
unshare: (id: string) => req<{ ok: boolean }>(`/api/conversations/${id}/share`, { method: "DELETE" }),
|
||||
publicShare: (publicId: string) => req<SharedChat>(`/api/share/${publicId}`, {}, false),
|
||||
|
||||
models: () => req<{ models: DriverModel[] }>("/api/models"),
|
||||
models: (opts: { refresh?: boolean } = {}) =>
|
||||
req<{ models: DriverModel[] }>(`/api/models${opts.refresh ? "?refresh=1" : ""}`),
|
||||
|
||||
/** Access-request wishlist (public, no auth). */
|
||||
accessRequest: (a: { username: string; email: string; message: string }) =>
|
||||
|
||||
@@ -50,6 +50,7 @@ export interface SharedChat {
|
||||
topic: string;
|
||||
model: string;
|
||||
authorName: string;
|
||||
authorAvatarUrl: string;
|
||||
sharedAt: number;
|
||||
messages: ChatMessage[];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user