refactor: rename snapshot types to PublicChatSnapshot prefix

This commit is contained in:
CREDO23 2026-02-02 16:05:23 +02:00
parent e62e4faaa5
commit d890c562d4
9 changed files with 95 additions and 91 deletions

View file

@ -45,9 +45,9 @@ from app.schemas.new_chat import (
NewChatThreadUpdate,
NewChatThreadVisibilityUpdate,
NewChatThreadWithMessages,
PublicChatSnapshotCreateResponse,
PublicChatSnapshotListResponse,
RegenerateRequest,
SnapshotCreateResponse,
SnapshotListResponse,
ThreadHistoryLoadResponse,
ThreadListItem,
ThreadListResponse,
@ -736,7 +736,7 @@ async def update_thread_visibility(
# =============================================================================
@router.post("/threads/{thread_id}/snapshots", response_model=SnapshotCreateResponse)
@router.post("/threads/{thread_id}/snapshots", response_model=PublicChatSnapshotCreateResponse)
async def create_thread_snapshot(
thread_id: int,
session: AsyncSession = Depends(get_async_session),
@ -756,7 +756,7 @@ async def create_thread_snapshot(
)
@router.get("/threads/{thread_id}/snapshots", response_model=SnapshotListResponse)
@router.get("/threads/{thread_id}/snapshots", response_model=PublicChatSnapshotListResponse)
async def list_thread_snapshots(
thread_id: int,
session: AsyncSession = Depends(get_async_session),
@ -769,7 +769,7 @@ async def list_thread_snapshots(
"""
from app.services.public_chat_service import list_snapshots_for_thread
return SnapshotListResponse(
return PublicChatSnapshotListResponse(
snapshots=await list_snapshots_for_thread(
session=session,
thread_id=thread_id,

View file

@ -514,7 +514,7 @@ async def list_search_space_snapshots(
Requires PUBLIC_SHARING_VIEW permission.
"""
from app.schemas.new_chat import SearchSpaceSnapshotListResponse
from app.schemas.new_chat import PublicChatSnapshotsBySpaceResponse
from app.services.public_chat_service import list_snapshots_for_search_space
snapshots = await list_snapshots_for_search_space(
@ -522,4 +522,4 @@ async def list_search_space_snapshots(
search_space_id=search_space_id,
user=user,
)
return SearchSpaceSnapshotListResponse(snapshots=snapshots)
return PublicChatSnapshotsBySpaceResponse(snapshots=snapshots)

View file

@ -211,17 +211,17 @@ class RegenerateRequest(BaseModel):
# =============================================================================
class SnapshotCreateResponse(BaseModel):
"""Response after creating a public snapshot."""
class PublicChatSnapshotCreateResponse(BaseModel):
"""Response after creating a public chat snapshot."""
snapshot_id: int
share_token: str
public_url: str
is_new: bool # False if existing snapshot returned (same content)
is_new: bool
class SnapshotInfo(BaseModel):
"""Info about a single snapshot."""
class PublicChatSnapshotInfo(BaseModel):
"""Info about a single public chat snapshot."""
id: int
share_token: str
@ -230,14 +230,14 @@ class SnapshotInfo(BaseModel):
message_count: int
class SnapshotListResponse(BaseModel):
"""List of snapshots for a thread."""
class PublicChatSnapshotListResponse(BaseModel):
"""List of public chat snapshots for a thread."""
snapshots: list[SnapshotInfo]
snapshots: list[PublicChatSnapshotInfo]
class SearchSpaceSnapshotInfo(BaseModel):
"""Snapshot info with thread context for search space listing."""
class PublicChatSnapshotDetail(BaseModel):
"""Public chat snapshot with thread context."""
id: int
share_token: str
@ -248,10 +248,10 @@ class SearchSpaceSnapshotInfo(BaseModel):
thread_title: str
class SearchSpaceSnapshotListResponse(BaseModel):
"""List of all snapshots in a search space."""
class PublicChatSnapshotsBySpaceResponse(BaseModel):
"""List of public chat snapshots for a search space."""
snapshots: list[SearchSpaceSnapshotInfo]
snapshots: list[PublicChatSnapshotDetail]
# =============================================================================

View file

@ -1,17 +1,16 @@
import { atomWithMutation } from "jotai-tanstack-query";
import { toast } from "sonner";
import type {
CreateSnapshotRequest,
CreateSnapshotResponse,
PublicChatSnapshotCreateRequest,
PublicChatSnapshotCreateResponse,
} from "@/contracts/types/chat-threads.types";
import { chatThreadsApiService } from "@/lib/apis/chat-threads-api.service";
export const createSnapshotMutationAtom = atomWithMutation(() => ({
mutationFn: async (request: CreateSnapshotRequest) => {
return chatThreadsApiService.createSnapshot(request);
export const createPublicChatSnapshotMutationAtom = atomWithMutation(() => ({
mutationFn: async (request: PublicChatSnapshotCreateRequest) => {
return chatThreadsApiService.createPublicChatSnapshot(request);
},
onSuccess: (response: CreateSnapshotResponse) => {
// Construct URL using frontend origin (backend returns its own URL which differs)
onSuccess: (response: PublicChatSnapshotCreateResponse) => {
const publicUrl = `${window.location.origin}/public/${response.share_token}`;
navigator.clipboard.writeText(publicUrl);
if (response.is_new) {

View file

@ -3,18 +3,18 @@ import { activeSearchSpaceIdAtom } from "@/atoms/search-spaces/search-space-quer
import { chatThreadsApiService } from "@/lib/apis/chat-threads-api.service";
import { cacheKeys } from "@/lib/query-client/cache-keys";
export const searchSpaceSnapshotsAtom = atomWithQuery((get) => {
export const publicChatSnapshotsAtom = atomWithQuery((get) => {
const searchSpaceId = get(activeSearchSpaceIdAtom);
return {
queryKey: cacheKeys.snapshots.bySearchSpace(Number(searchSpaceId) || 0),
queryKey: cacheKeys.publicChatSnapshots.bySearchSpace(Number(searchSpaceId) || 0),
enabled: !!searchSpaceId,
staleTime: 5 * 60 * 1000,
queryFn: async () => {
if (!searchSpaceId) {
return { snapshots: [] };
}
return chatThreadsApiService.listSearchSpaceSnapshots({
return chatThreadsApiService.listPublicChatSnapshotsForSearchSpace({
search_space_id: Number(searchSpaceId),
});
},

View file

@ -5,7 +5,7 @@ import { useAtomValue, useSetAtom } from "jotai";
import { Globe, User, Users } from "lucide-react";
import { useCallback, useMemo, useState } from "react";
import { toast } from "sonner";
import { createSnapshotMutationAtom } from "@/atoms/chat/chat-thread-mutation.atoms";
import { createPublicChatSnapshotMutationAtom } from "@/atoms/chat/chat-thread-mutation.atoms";
import { currentThreadAtom, setThreadVisibilityAtom } from "@/atoms/chat/current-thread.atom";
import { myAccessAtom } from "@/atoms/members/members-query.atoms";
import { Button } from "@/components/ui/button";
@ -54,7 +54,7 @@ export function ChatShareButton({ thread, onVisibilityChange, className }: ChatS
// Snapshot creation mutation
const { mutateAsync: createSnapshot, isPending: isCreatingSnapshot } = useAtomValue(
createSnapshotMutationAtom
createPublicChatSnapshotMutationAtom
);
// Permission check for public sharing

View file

@ -1,9 +1,9 @@
import { z } from "zod";
/**
* Snapshot info
* Public chat snapshot info
*/
export const snapshotInfo = z.object({
export const publicChatSnapshotInfo = z.object({
id: z.number(),
share_token: z.string(),
public_url: z.string(),
@ -12,13 +12,13 @@ export const snapshotInfo = z.object({
});
/**
* Create snapshot
* Create public chat snapshot
*/
export const createSnapshotRequest = z.object({
export const publicChatSnapshotCreateRequest = z.object({
thread_id: z.number(),
});
export const createSnapshotResponse = z.object({
export const publicChatSnapshotCreateResponse = z.object({
snapshot_id: z.number(),
share_token: z.string(),
public_url: z.string(),
@ -26,28 +26,28 @@ export const createSnapshotResponse = z.object({
});
/**
* List snapshots
* List public chat snapshots for thread
*/
export const listSnapshotsRequest = z.object({
export const publicChatSnapshotListRequest = z.object({
thread_id: z.number(),
});
export const listSnapshotsResponse = z.object({
snapshots: z.array(snapshotInfo),
export const publicChatSnapshotListResponse = z.object({
snapshots: z.array(publicChatSnapshotInfo),
});
/**
* Delete snapshot
* Delete public chat snapshot
*/
export const deleteSnapshotRequest = z.object({
export const publicChatSnapshotDeleteRequest = z.object({
thread_id: z.number(),
snapshot_id: z.number(),
});
/**
* Search space snapshot info (includes thread context)
* Public chat snapshot with thread context
*/
export const searchSpaceSnapshotInfo = z.object({
export const publicChatSnapshotDetail = z.object({
id: z.number(),
share_token: z.string(),
public_url: z.string(),
@ -58,23 +58,23 @@ export const searchSpaceSnapshotInfo = z.object({
});
/**
* List snapshots for search space
* List public chat snapshots for search space
*/
export const listSearchSpaceSnapshotsRequest = z.object({
export const publicChatSnapshotsBySpaceRequest = z.object({
search_space_id: z.number(),
});
export const listSearchSpaceSnapshotsResponse = z.object({
snapshots: z.array(searchSpaceSnapshotInfo),
export const publicChatSnapshotsBySpaceResponse = z.object({
snapshots: z.array(publicChatSnapshotDetail),
});
// Type exports
export type SnapshotInfo = z.infer<typeof snapshotInfo>;
export type CreateSnapshotRequest = z.infer<typeof createSnapshotRequest>;
export type CreateSnapshotResponse = z.infer<typeof createSnapshotResponse>;
export type ListSnapshotsRequest = z.infer<typeof listSnapshotsRequest>;
export type ListSnapshotsResponse = z.infer<typeof listSnapshotsResponse>;
export type DeleteSnapshotRequest = z.infer<typeof deleteSnapshotRequest>;
export type SearchSpaceSnapshotInfo = z.infer<typeof searchSpaceSnapshotInfo>;
export type ListSearchSpaceSnapshotsRequest = z.infer<typeof listSearchSpaceSnapshotsRequest>;
export type ListSearchSpaceSnapshotsResponse = z.infer<typeof listSearchSpaceSnapshotsResponse>;
export type PublicChatSnapshotInfo = z.infer<typeof publicChatSnapshotInfo>;
export type PublicChatSnapshotCreateRequest = z.infer<typeof publicChatSnapshotCreateRequest>;
export type PublicChatSnapshotCreateResponse = z.infer<typeof publicChatSnapshotCreateResponse>;
export type PublicChatSnapshotListRequest = z.infer<typeof publicChatSnapshotListRequest>;
export type PublicChatSnapshotListResponse = z.infer<typeof publicChatSnapshotListResponse>;
export type PublicChatSnapshotDeleteRequest = z.infer<typeof publicChatSnapshotDeleteRequest>;
export type PublicChatSnapshotDetail = z.infer<typeof publicChatSnapshotDetail>;
export type PublicChatSnapshotsBySpaceRequest = z.infer<typeof publicChatSnapshotsBySpaceRequest>;
export type PublicChatSnapshotsBySpaceResponse = z.infer<typeof publicChatSnapshotsBySpaceResponse>;

View file

@ -1,28 +1,30 @@
import {
type CreateSnapshotRequest,
type CreateSnapshotResponse,
createSnapshotRequest,
createSnapshotResponse,
type DeleteSnapshotRequest,
deleteSnapshotRequest,
type ListSearchSpaceSnapshotsRequest,
type ListSearchSpaceSnapshotsResponse,
type ListSnapshotsRequest,
type ListSnapshotsResponse,
listSearchSpaceSnapshotsRequest,
listSearchSpaceSnapshotsResponse,
listSnapshotsRequest,
listSnapshotsResponse,
type PublicChatSnapshotCreateRequest,
type PublicChatSnapshotCreateResponse,
type PublicChatSnapshotDeleteRequest,
type PublicChatSnapshotListRequest,
type PublicChatSnapshotListResponse,
type PublicChatSnapshotsBySpaceRequest,
type PublicChatSnapshotsBySpaceResponse,
publicChatSnapshotCreateRequest,
publicChatSnapshotCreateResponse,
publicChatSnapshotDeleteRequest,
publicChatSnapshotListRequest,
publicChatSnapshotListResponse,
publicChatSnapshotsBySpaceRequest,
publicChatSnapshotsBySpaceResponse,
} from "@/contracts/types/chat-threads.types";
import { ValidationError } from "../error";
import { baseApiService } from "./base-api.service";
class ChatThreadsApiService {
/**
* Create a public snapshot for a thread.
* Create a public chat snapshot for a thread.
*/
createSnapshot = async (request: CreateSnapshotRequest): Promise<CreateSnapshotResponse> => {
const parsed = createSnapshotRequest.safeParse(request);
createPublicChatSnapshot = async (
request: PublicChatSnapshotCreateRequest
): Promise<PublicChatSnapshotCreateResponse> => {
const parsed = publicChatSnapshotCreateRequest.safeParse(request);
if (!parsed.success) {
const errorMessage = parsed.error.issues.map((issue) => issue.message).join(", ");
@ -31,15 +33,17 @@ class ChatThreadsApiService {
return baseApiService.post(
`/api/v1/threads/${parsed.data.thread_id}/snapshots`,
createSnapshotResponse
publicChatSnapshotCreateResponse
);
};
/**
* List all snapshots for a thread.
* List all public chat snapshots for a thread.
*/
listSnapshots = async (request: ListSnapshotsRequest): Promise<ListSnapshotsResponse> => {
const parsed = listSnapshotsRequest.safeParse(request);
listPublicChatSnapshots = async (
request: PublicChatSnapshotListRequest
): Promise<PublicChatSnapshotListResponse> => {
const parsed = publicChatSnapshotListRequest.safeParse(request);
if (!parsed.success) {
const errorMessage = parsed.error.issues.map((issue) => issue.message).join(", ");
@ -48,15 +52,15 @@ class ChatThreadsApiService {
return baseApiService.get(
`/api/v1/threads/${parsed.data.thread_id}/snapshots`,
listSnapshotsResponse
publicChatSnapshotListResponse
);
};
/**
* Delete a specific snapshot.
* Delete a public chat snapshot.
*/
deleteSnapshot = async (request: DeleteSnapshotRequest): Promise<void> => {
const parsed = deleteSnapshotRequest.safeParse(request);
deletePublicChatSnapshot = async (request: PublicChatSnapshotDeleteRequest): Promise<void> => {
const parsed = publicChatSnapshotDeleteRequest.safeParse(request);
if (!parsed.success) {
const errorMessage = parsed.error.issues.map((issue) => issue.message).join(", ");
@ -69,12 +73,12 @@ class ChatThreadsApiService {
};
/**
* List all snapshots for a search space.
* List all public chat snapshots for a search space.
*/
listSearchSpaceSnapshots = async (
request: ListSearchSpaceSnapshotsRequest
): Promise<ListSearchSpaceSnapshotsResponse> => {
const parsed = listSearchSpaceSnapshotsRequest.safeParse(request);
listPublicChatSnapshotsForSearchSpace = async (
request: PublicChatSnapshotsBySpaceRequest
): Promise<PublicChatSnapshotsBySpaceResponse> => {
const parsed = publicChatSnapshotsBySpaceRequest.safeParse(request);
if (!parsed.success) {
const errorMessage = parsed.error.issues.map((issue) => issue.message).join(", ");
@ -83,7 +87,7 @@ class ChatThreadsApiService {
return baseApiService.get(
`/api/v1/searchspaces/${parsed.data.search_space_id}/snapshots`,
listSearchSpaceSnapshotsResponse
publicChatSnapshotsBySpaceResponse
);
};
}

View file

@ -82,7 +82,8 @@ export const cacheKeys = {
publicChat: {
byToken: (shareToken: string) => ["public-chat", shareToken] as const,
},
snapshots: {
bySearchSpace: (searchSpaceId: number) => ["snapshots", "search-space", searchSpaceId] as const,
publicChatSnapshots: {
bySearchSpace: (searchSpaceId: number) =>
["public-chat-snapshots", "search-space", searchSpaceId] as const,
},
};