mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-04 22:02:16 +02:00
refactor(api): rename personal access tokens to API keys and update related UI components for consistency
This commit is contained in:
parent
96b64166b1
commit
d5e2540e51
9 changed files with 162 additions and 81 deletions
|
|
@ -1,10 +1,20 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Check, Copy, Info, Plus, Trash2 } from "lucide-react";
|
import { Check, Copy, Info, Trash2 } from "lucide-react";
|
||||||
import { useCallback, useMemo, useState } from "react";
|
import { useCallback, useMemo, useState } from "react";
|
||||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle,
|
||||||
|
} from "@/components/ui/alert-dialog";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Card, CardContent } from "@/components/ui/card";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
|
@ -16,6 +26,7 @@ import {
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
|
import { Spinner } from "@/components/ui/spinner";
|
||||||
import { usePats } from "@/hooks/use-pats";
|
import { usePats } from "@/hooks/use-pats";
|
||||||
import { copyToClipboard as copyToClipboardUtil } from "@/lib/utils";
|
import { copyToClipboard as copyToClipboardUtil } from "@/lib/utils";
|
||||||
|
|
||||||
|
|
@ -26,6 +37,7 @@ export function ApiKeyContent() {
|
||||||
const [label, setLabel] = useState("");
|
const [label, setLabel] = useState("");
|
||||||
const [expiresInDays, setExpiresInDays] = useState("");
|
const [expiresInDays, setExpiresInDays] = useState("");
|
||||||
const [copiedToken, setCopiedToken] = useState(false);
|
const [copiedToken, setCopiedToken] = useState(false);
|
||||||
|
const [deleteTarget, setDeleteTarget] = useState<{ id: number; label: string } | null>(null);
|
||||||
|
|
||||||
const sortedTokens = useMemo(() => tokens, [tokens]);
|
const sortedTokens = useMemo(() => tokens, [tokens]);
|
||||||
|
|
||||||
|
|
@ -51,93 +63,112 @@ export function ApiKeyContent() {
|
||||||
}
|
}
|
||||||
}, [createdToken]);
|
}, [createdToken]);
|
||||||
|
|
||||||
const handleDelete = useCallback(
|
const handleConfirmDelete = useCallback(async () => {
|
||||||
async (id: number, tokenLabel: string) => {
|
if (!deleteTarget) return;
|
||||||
if (!window.confirm(`Delete personal access token "${tokenLabel}"? This cannot be undone.`)) {
|
|
||||||
return;
|
await deleteToken(deleteTarget.id);
|
||||||
}
|
setDeleteTarget(null);
|
||||||
await deleteToken(id);
|
}, [deleteTarget, deleteToken]);
|
||||||
},
|
|
||||||
[deleteToken]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6 min-w-0 overflow-hidden">
|
<div className="space-y-6 min-w-0">
|
||||||
<Alert>
|
<Alert>
|
||||||
<Info />
|
<Info />
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
Personal access tokens are long-lived credentials for extensions, Obsidian, and
|
API keys let extensions, Obsidian, and other apps connect to SurfSense.
|
||||||
programmatic API clients. Copy a token when you create it; it is shown only once.
|
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-semibold tracking-tight">Personal access tokens</h3>
|
<h3 className="text-sm font-semibold tracking-tight">API keys</h3>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Expired tokens stay listed until you delete them.
|
Expired API keys stay listed until you delete them.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Button size="sm" onClick={() => setCreateOpen(true)}>
|
<Button size="sm" onClick={() => setCreateOpen(true)}>
|
||||||
<Plus className="mr-2 h-4 w-4" />
|
Create API key
|
||||||
Create token
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="min-w-0 overflow-hidden rounded-lg border border-border/60">
|
{isLoading ? (
|
||||||
{isLoading ? (
|
<div className="-m-1 grid grid-cols-1 gap-3 p-1">
|
||||||
<div className="space-y-3 p-4">
|
{["skeleton-a", "skeleton-b"].map((key) => (
|
||||||
<Skeleton className="h-12 w-full" />
|
<Card
|
||||||
<Skeleton className="h-12 w-full" />
|
key={key}
|
||||||
</div>
|
className="group relative overflow-hidden transition-all duration-200 border-accent bg-accent/20 hover:shadow-md h-full"
|
||||||
) : sortedTokens.length > 0 ? (
|
>
|
||||||
<div className="divide-y divide-border/60">
|
<CardContent className="p-4 flex flex-col gap-3 h-full min-h-24">
|
||||||
{sortedTokens.map((token) => {
|
<Skeleton className="h-4 w-32 md:w-40 bg-accent" />
|
||||||
const expiresAt = token.expires_at ? new Date(token.expires_at) : null;
|
<Skeleton className="h-3 w-full bg-accent" />
|
||||||
const isExpired = expiresAt ? expiresAt.getTime() <= Date.now() : false;
|
<Skeleton className="h-3 w-24 md:w-28 bg-accent" />
|
||||||
return (
|
</CardContent>
|
||||||
<div key={token.id} className="flex items-center gap-3 p-4">
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : sortedTokens.length > 0 ? (
|
||||||
|
<div className="-m-1 grid grid-cols-1 gap-3 p-1">
|
||||||
|
{sortedTokens.map((token) => {
|
||||||
|
const expiresAt = token.expires_at ? new Date(token.expires_at) : null;
|
||||||
|
const isExpired = expiresAt ? expiresAt.getTime() <= Date.now() : false;
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
key={token.id}
|
||||||
|
className="group relative overflow-hidden transition-all duration-200 border-accent bg-accent/20 hover:shadow-md h-full"
|
||||||
|
>
|
||||||
|
<CardContent className="flex min-h-24 items-center gap-3 p-4">
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex flex-col gap-1">
|
||||||
<p className="truncate text-sm font-medium">{token.label}</p>
|
<div className="flex items-center gap-2">
|
||||||
{isExpired ? <Badge variant="secondary">Expired</Badge> : null}
|
<h4 className="truncate text-sm font-semibold tracking-tight">
|
||||||
|
{token.label}
|
||||||
|
</h4>
|
||||||
|
{isExpired ? (
|
||||||
|
<span className="rounded-md border-0 bg-muted px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground">
|
||||||
|
Expired
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
<p className="truncate font-mono text-xs text-muted-foreground">
|
||||||
|
{token.prefix}...
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Expires: {expiresAt ? expiresAt.toLocaleDateString() : "Never"} · Last used:{" "}
|
||||||
|
{token.last_used_at ? new Date(token.last_used_at).toLocaleString() : "Never"}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="font-mono text-xs text-muted-foreground">{token.prefix}...</p>
|
|
||||||
<p className="text-xs text-muted-foreground">
|
|
||||||
Expires: {expiresAt ? expiresAt.toLocaleDateString() : "Never"} · Last used:{" "}
|
|
||||||
{token.last_used_at ? new Date(token.last_used_at).toLocaleString() : "Never"}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
disabled={isMutating}
|
disabled={isMutating}
|
||||||
onClick={() => handleDelete(token.id, token.label)}
|
onClick={() => setDeleteTarget({ id: token.id, label: token.label })}
|
||||||
|
className="h-7 w-7 shrink-0 rounded-lg text-muted-foreground transition-opacity duration-150 hover:text-accent-foreground sm:opacity-0 sm:pointer-events-none sm:group-hover:opacity-100 sm:group-hover:pointer-events-auto"
|
||||||
>
|
>
|
||||||
<Trash2 className="h-4 w-4 text-muted-foreground" />
|
<Trash2 className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</CardContent>
|
||||||
);
|
</Card>
|
||||||
})}
|
);
|
||||||
</div>
|
})}
|
||||||
) : (
|
</div>
|
||||||
<p className="p-6 text-center text-sm text-muted-foreground">
|
) : (
|
||||||
No personal access tokens yet.
|
<p className="py-6 text-center text-sm text-muted-foreground">
|
||||||
</p>
|
No API keys yet.
|
||||||
)}
|
</p>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
<Dialog open={createOpen} onOpenChange={setCreateOpen}>
|
<Dialog open={createOpen} onOpenChange={setCreateOpen}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Create personal access token</DialogTitle>
|
<DialogTitle>Create API key</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
Name this token so you can recognize where it is used later.
|
Name this API key so you can recognize where it is used later.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="pat-label">Label</Label>
|
<Label htmlFor="pat-label">Name</Label>
|
||||||
<Input
|
<Input
|
||||||
id="pat-label"
|
id="pat-label"
|
||||||
value={label}
|
value={label}
|
||||||
|
|
@ -158,11 +189,24 @@ export function ApiKeyContent() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="outline" onClick={() => setCreateOpen(false)}>
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setCreateOpen(false)}
|
||||||
|
disabled={isMutating}
|
||||||
|
className="text-sm h-9"
|
||||||
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button disabled={isMutating || !label.trim()} onClick={handleCreate}>
|
<Button
|
||||||
Create token
|
size="sm"
|
||||||
|
disabled={isMutating || !label.trim()}
|
||||||
|
onClick={handleCreate}
|
||||||
|
className="relative text-sm h-9 min-w-[128px]"
|
||||||
|
>
|
||||||
|
<span className={isMutating ? "opacity-0" : ""}>Create API key</span>
|
||||||
|
{isMutating && <Spinner size="sm" className="absolute" />}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
@ -171,16 +215,21 @@ export function ApiKeyContent() {
|
||||||
<Dialog open={!!createdToken} onOpenChange={(open) => !open && setCreatedToken(null)}>
|
<Dialog open={!!createdToken} onOpenChange={(open) => !open && setCreatedToken(null)}>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Copy your token now</DialogTitle>
|
<DialogTitle>Copy your API key now</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
This token is shown only once. Store it somewhere secure before closing this dialog.
|
This API key is shown only once. Store it somewhere secure before closing this dialog.
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="flex items-center gap-2 rounded-md border border-border/60 bg-muted/30 p-2">
|
<div className="flex items-center gap-2 rounded-md border border-border/60 bg-muted/30 p-2">
|
||||||
<code className="min-w-0 flex-1 overflow-x-auto whitespace-nowrap text-xs">
|
<code className="min-w-0 flex-1 overflow-x-auto whitespace-nowrap text-xs">
|
||||||
{createdToken?.token}
|
{createdToken?.token}
|
||||||
</code>
|
</code>
|
||||||
<Button variant="outline" size="sm" onClick={copyCreatedToken}>
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={copyCreatedToken}
|
||||||
|
className="border-0 bg-muted/30 hover:bg-muted/50"
|
||||||
|
>
|
||||||
{copiedToken ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
{copiedToken ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -189,6 +238,41 @@ export function ApiKeyContent() {
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
<AlertDialog
|
||||||
|
open={deleteTarget !== null}
|
||||||
|
onOpenChange={(open) => !open && setDeleteTarget(null)}
|
||||||
|
>
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>Delete API key?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
<span className="font-medium text-foreground">{deleteTarget?.label}</span> will be
|
||||||
|
permanently removed. This cannot be undone.
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel disabled={isMutating}>Cancel</AlertDialogCancel>
|
||||||
|
<AlertDialogAction
|
||||||
|
disabled={isMutating}
|
||||||
|
className="bg-destructive text-white hover:bg-destructive/90"
|
||||||
|
onClick={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
void handleConfirmDelete();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isMutating ? (
|
||||||
|
<span className="inline-flex items-center gap-2">
|
||||||
|
<Spinner size="xs" />
|
||||||
|
Deleting...
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
"Delete"
|
||||||
|
)}
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,13 @@ export function CommunityPromptsContent() {
|
||||||
const list = prompts ?? [];
|
const list = prompts ?? [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6 min-w-0 overflow-hidden">
|
<div className="space-y-6 min-w-0">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Prompts shared by other users. Add any to your collection with one click.
|
Prompts shared by other users. Add any to your collection with one click.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="space-y-2">
|
<div className="-m-1 space-y-2 p-1">
|
||||||
{["skeleton-a", "skeleton-b", "skeleton-c"].map((key) => (
|
{["skeleton-a", "skeleton-b", "skeleton-c"].map((key) => (
|
||||||
<Card key={key} className="border-accent bg-accent/20">
|
<Card key={key} className="border-accent bg-accent/20">
|
||||||
<CardContent className="p-4 flex flex-col gap-3 min-h-24">
|
<CardContent className="p-4 flex flex-col gap-3 min-h-24">
|
||||||
|
|
@ -76,7 +76,7 @@ export function CommunityPromptsContent() {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isLoading && !isError && list.length > 0 && (
|
{!isLoading && !isError && list.length > 0 && (
|
||||||
<div className="space-y-2">
|
<div className="-m-1 space-y-2 p-1">
|
||||||
{list.map((prompt) => (
|
{list.map((prompt) => (
|
||||||
<Card
|
<Card
|
||||||
key={prompt.id}
|
key={prompt.id}
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ export function PromptsContent() {
|
||||||
const list = prompts ?? [];
|
const list = prompts ?? [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6 min-w-0 overflow-hidden">
|
<div className="space-y-6 min-w-0">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Create prompt templates triggered with <ShortcutKbd keys={["/"]} className="ml-0" /> in
|
Create prompt templates triggered with <ShortcutKbd keys={["/"]} className="ml-0" /> in
|
||||||
|
|
@ -276,7 +276,7 @@ export function PromptsContent() {
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<div className="space-y-2">
|
<div className="-m-1 space-y-2 p-1">
|
||||||
{["skeleton-a", "skeleton-b", "skeleton-c"].map((key) => (
|
{["skeleton-a", "skeleton-b", "skeleton-c"].map((key) => (
|
||||||
<Card key={key} className="border-accent bg-accent/20">
|
<Card key={key} className="border-accent bg-accent/20">
|
||||||
<CardContent className="p-4 flex flex-col gap-3 min-h-24">
|
<CardContent className="p-4 flex flex-col gap-3 min-h-24">
|
||||||
|
|
@ -308,7 +308,7 @@ export function PromptsContent() {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isLoading && !isError && list.length > 0 && (
|
{!isLoading && !isError && list.length > 0 && (
|
||||||
<div className="space-y-2">
|
<div className="-m-1 space-y-2 p-1">
|
||||||
{list.map((prompt) => (
|
{list.map((prompt) => (
|
||||||
<div
|
<div
|
||||||
key={prompt.id}
|
key={prompt.id}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ export const deletePublicChatSnapshotMutationAtom = atomWithMutation(() => ({
|
||||||
toast.success("Public link deleted");
|
toast.success("Public link deleted");
|
||||||
},
|
},
|
||||||
onError: (error: Error) => {
|
onError: (error: Error) => {
|
||||||
console.error("Failed to delete public chat link:", error);
|
console.error("Failed to delete public chat:", error);
|
||||||
toast.error("Failed to delete public link");
|
toast.error("Failed to delete public link");
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,9 @@ This update brings **public sharing, image generation**, a redesigned Documents
|
||||||
|
|
||||||
#### Public Sharing
|
#### Public Sharing
|
||||||
|
|
||||||
- **Public Chat Links**: Share snapshots of chats via public links.
|
- **Public Chats**: Share snapshots of chats via public links.
|
||||||
- **Sharing Permissions**: Search Space owners control who can create and manage public links.
|
- **Sharing Permissions**: Search Space owners control who can create and manage public links.
|
||||||
- **Link Management Page**: View and revoke all public chat links from Search Space Settings.
|
- **Link Management Page**: View and revoke all public chats from Search Space Settings.
|
||||||
|
|
||||||
#### Auto (Load Balanced) Mode
|
#### Auto (Load Balanced) Mode
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
import { Link2Off } from "lucide-react";
|
|
||||||
|
|
||||||
interface PublicChatSnapshotsEmptyStateProps {
|
interface PublicChatSnapshotsEmptyStateProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PublicChatSnapshotsEmptyState({
|
export function PublicChatSnapshotsEmptyState({
|
||||||
title = "No public chat links",
|
title = "No public chats",
|
||||||
description = "When you create public links to share chats, they will appear here.",
|
description = "When you create public links to share chats, they will appear here.",
|
||||||
}: PublicChatSnapshotsEmptyStateProps) {
|
}: PublicChatSnapshotsEmptyStateProps) {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ export function PublicChatSnapshotsManager({
|
||||||
<Alert variant="destructive">
|
<Alert variant="destructive">
|
||||||
<AlertCircle className="h-4 w-4" />
|
<AlertCircle className="h-4 w-4" />
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
Failed to load public chat links. Please try again later.
|
Failed to load public chats. Please try again later.
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
|
|
@ -127,7 +127,7 @@ export function PublicChatSnapshotsManager({
|
||||||
<Alert>
|
<Alert>
|
||||||
<Info />
|
<Info />
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
You don't have permission to view public chat links in this search space.
|
You don't have permission to view public chats in this search space.
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
|
|
@ -140,8 +140,8 @@ export function PublicChatSnapshotsManager({
|
||||||
<Alert>
|
<Alert>
|
||||||
<Info />
|
<Info />
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
Public chat links allow anyone with the URL to view a snapshot of a chat. These links do
|
Public chats allow anyone with the URL to view a snapshot of a chat. They do not update
|
||||||
not update when the original chat changes.
|
when the original chat changes.
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -208,10 +208,9 @@ export function GeneralSettingsManager({ searchSpaceId }: GeneralSettingsManager
|
||||||
|
|
||||||
<div className="border-t pt-6 flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
<div className="border-t pt-6 flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label htmlFor="api-access-enabled">Programmatic API access</Label>
|
<Label htmlFor="api-access-enabled">API key access</Label>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
Allow personal access tokens to use this search space. Web and desktop sessions are not
|
Allow API keys to access this search space.
|
||||||
affected.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Switch
|
<Switch
|
||||||
|
|
|
||||||
|
|
@ -746,8 +746,8 @@
|
||||||
"nav_agent_models_desc": "Models with prompts & citations",
|
"nav_agent_models_desc": "Models with prompts & citations",
|
||||||
"nav_system_instructions": "System Instructions",
|
"nav_system_instructions": "System Instructions",
|
||||||
"nav_system_instructions_desc": "SearchSpace-wide AI instructions",
|
"nav_system_instructions_desc": "SearchSpace-wide AI instructions",
|
||||||
"nav_public_links": "Public Chat Links",
|
"nav_public_links": "Public Chats",
|
||||||
"nav_public_links_desc": "Manage publicly shared chat links",
|
"nav_public_links_desc": "Manage publicly shared chats",
|
||||||
"nav_team_roles": "Team Roles",
|
"nav_team_roles": "Team Roles",
|
||||||
"nav_team_roles_desc": "Manage team roles & permissions",
|
"nav_team_roles_desc": "Manage team roles & permissions",
|
||||||
"general_name_label": "Name",
|
"general_name_label": "Name",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue