fix: policy and share page api error

This commit is contained in:
Vukasin 2025-05-04 15:49:26 +02:00
parent 655840de14
commit 8b6d9c0903
6 changed files with 261 additions and 253 deletions

View File

@ -0,0 +1,16 @@
DROP POLICY IF EXISTS thread_select_policy ON threads;
CREATE POLICY thread_select_policy ON threads
FOR SELECT
USING (
is_public IS TRUE
OR basejump.has_role_on_account(account_id) = true
OR EXISTS (
SELECT 1 FROM projects
WHERE projects.project_id = threads.project_id
AND (
projects.is_public IS TRUE
OR basejump.has_role_on_account(projects.account_id) = true
)
)
);

View File

@ -601,14 +601,10 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
if (!threadId) throw new Error('Thread ID is required');
// Start loading all data in parallel
const [threadData, agentRuns, messagesData] = await Promise.all([
const [threadData, messagesData] = await Promise.all([
getThread(threadId).catch(err => {
throw new Error('Failed to load thread data: ' + err.message);
}),
getAgentRuns(threadId).catch(err => {
console.warn('Failed to load agent runs:', err);
return [];
}),
getMessages(threadId).catch(err => {
console.warn('Failed to load messages:', err);
return [];
@ -649,14 +645,6 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
setProjectName('Shared Conversation');
}
// Set agent run ID if available
if (agentRuns && agentRuns.length > 0) {
const latestRun = agentRuns[0];
if (latestRun.status === 'running') {
setAgentRunId(latestRun.id);
}
}
// Process messages data
console.log('[SHARE] Raw messages fetched:', messagesData);
@ -954,8 +942,7 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
<div className="space-y-1">
<div className="flex justify-between items-center">
<div className="text-xs font-medium text-muted-foreground">Tool Result</div>
<div className={`px-2 py-0.5 rounded-full text-xs ${
isSuccess
<div className={`px-2 py-0.5 rounded-full text-xs ${isSuccess
? 'bg-green-50 text-green-700 dark:bg-green-900 dark:text-green-300'
: 'bg-red-50 text-red-700 dark:bg-red-900 dark:text-red-300'
}`}>
@ -1701,8 +1688,7 @@ export default function ThreadPage({ params }: { params: Promise<ThreadParams> }
{/* Floating playback controls - moved to be centered in the chat area when side panel is open */}
{messages.length > 0 && (
<div className={`fixed bottom-4 z-10 transform bg-background/90 backdrop-blur rounded-full border shadow-md px-3 py-1.5 transition-all duration-200 ${
isSidePanelOpen
<div className={`fixed bottom-4 z-10 transform bg-background/90 backdrop-blur rounded-full border shadow-md px-3 py-1.5 transition-all duration-200 ${isSidePanelOpen
? 'left-1/2 -translate-x-1/4 sm:left-[calc(50%-225px)] md:left-[calc(50%-250px)] lg:left-[calc(50%-275px)] xl:left-[calc(50%-325px)]'
: 'left-1/2 -translate-x-1/2'
}`}>

View File

@ -54,7 +54,7 @@ export function NavAgents() {
const [isLoading, setIsLoading] = useState(true)
const [loadingThreadId, setLoadingThreadId] = useState<string | null>(null)
const [showShareModal, setShowShareModal] = useState(false)
const [selectedThreadId, setSelectedThreadId] = useState<string | null>(null)
const [selectedItem, setSelectedItem] = useState<{ threadId: string, projectId: string } | null>(null)
const pathname = usePathname()
const router = useRouter()
@ -284,11 +284,11 @@ export function NavAgents() {
align={isMobile ? "end" : "start"}
>
<DropdownMenuItem onClick={() => {
setSelectedThreadId(thread?.threadId)
setSelectedItem({ threadId: thread?.threadId, projectId: thread?.projectId })
setShowShareModal(true)
}}>
<Share2 className="text-muted-foreground" />
<span>Share</span>
<span>Share Chat</span>
</DropdownMenuItem>
<DropdownMenuItem asChild>
<a href={thread.url} target="_blank" rel="noopener noreferrer">
@ -321,7 +321,8 @@ export function NavAgents() {
<ShareModal
isOpen={showShareModal}
onClose={() => setShowShareModal(false)}
threadId={selectedThreadId}
threadId={selectedItem?.threadId}
projectId={selectedItem?.projectId}
/>
</SidebarGroup>
)

View File

@ -7,7 +7,7 @@ import {
} from "@/components/ui/dialog";
import { X, Copy, Share2, Link, Link2Off, Check } from "lucide-react";
import { toast } from "sonner";
import { getThread, toggleThreadPublicStatus } from "@/lib/api";
import { getThread, updateProject, updateThread } from "@/lib/api";
interface SocialShareOption {
name: string;
@ -19,9 +19,10 @@ interface ShareModalProps {
isOpen: boolean;
onClose: () => void;
threadId?: string;
projectId?: string;
}
export function ShareModal({ isOpen, onClose, threadId }: ShareModalProps) {
export function ShareModal({ isOpen, onClose, threadId, projectId }: ShareModalProps) {
const [shareLink, setShareLink] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [isChecking, setIsChecking] = useState(false);
@ -67,7 +68,7 @@ export function ShareModal({ isOpen, onClose, threadId }: ShareModalProps) {
try {
// Use the API to mark the thread as public
await toggleThreadPublicStatus(threadId, true);
await updatePublicStatus(true);
const generatedLink = generateShareLink();
setShareLink(generatedLink);
toast.success("Shareable link created successfully");
@ -86,7 +87,7 @@ export function ShareModal({ isOpen, onClose, threadId }: ShareModalProps) {
try {
// Use the API to mark the thread as private
await toggleThreadPublicStatus(threadId, false);
await updatePublicStatus(false);
setShareLink(null);
toast.success("Shareable link removed");
} catch (error) {
@ -97,6 +98,13 @@ export function ShareModal({ isOpen, onClose, threadId }: ShareModalProps) {
}
};
const updatePublicStatus = async (isPublic: boolean) => {
console.log("Updating public status for thread:", threadId, "and project:", projectId, "to", isPublic);
if (!threadId) return;
await updateProject(projectId, { is_public: isPublic });
await updateThread(threadId, { is_public: isPublic });
};
const copyToClipboard = () => {
if (shareLink) {
setIsCopying(true);

View File

@ -237,6 +237,7 @@ export function SiteHeader({
isOpen={showShareModal}
onClose={() => setShowShareModal(false)}
threadId={threadId}
projectId={projectId}
/>
</>
)

View File

@ -1048,10 +1048,6 @@ export const updateThread = async (threadId: string, data: Partial<Thread>): Pro
return updatedThread;
};
export const toggleThreadPublicStatus = async (threadId: string, isPublic: boolean): Promise<Thread> => {
return updateThread(threadId, { is_public: isPublic });
};
// Function to get public projects
export const getPublicProjects = async (): Promise<Project[]> => {
try {