mirror of https://github.com/kortix-ai/suna.git
fix: policy and share page api error
This commit is contained in:
parent
655840de14
commit
8b6d9c0903
|
@ -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
|
||||
)
|
||||
)
|
||||
);
|
|
@ -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'
|
||||
}`}>
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -237,6 +237,7 @@ export function SiteHeader({
|
|||
isOpen={showShareModal}
|
||||
onClose={() => setShowShareModal(false)}
|
||||
threadId={threadId}
|
||||
projectId={projectId}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue