fix folders on main page

This commit is contained in:
m
2026-07-29 22:37:23 +02:00
parent eb60aa3068
commit e4b6e393d8
7 changed files with 39 additions and 19 deletions
+2 -2
View File
@@ -23,8 +23,8 @@ VALUES ($1, $2, $3, $4, $5, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
RETURNING *; RETURNING *;
-- name: CreateFolder :one -- name: CreateFolder :one
INSERT INTO resources (name, is_folder, owner_id, created_at, updated_at) INSERT INTO resources (name, is_folder, owner_id, parent_resource_id, created_at, updated_at)
VALUES ($1, true, $2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) VALUES ($1, true, $2, $3, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
RETURNING *; RETURNING *;
-- name: ListResourcesByParentID :many -- name: ListResourcesByParentID :many
+4 -3
View File
@@ -43,18 +43,19 @@ func (q *Queries) CountResourcesByParentAndOwner(ctx context.Context, arg CountR
} }
const createFolder = `-- name: CreateFolder :one const createFolder = `-- name: CreateFolder :one
INSERT INTO resources (name, is_folder, owner_id, created_at, updated_at) INSERT INTO resources (name, is_folder, owner_id, parent_resource_id, created_at, updated_at)
VALUES ($1, true, $2, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) VALUES ($1, true, $2, $3, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
RETURNING id, name, mime_type, size, checksum, ocr_text, is_folder, parent_resource_id, owner_id, created_at, updated_at RETURNING id, name, mime_type, size, checksum, ocr_text, is_folder, parent_resource_id, owner_id, created_at, updated_at
` `
type CreateFolderParams struct { type CreateFolderParams struct {
Name string `json:"name"` Name string `json:"name"`
OwnerID uuid.UUID `json:"owner_id"` OwnerID uuid.UUID `json:"owner_id"`
ParentResourceID uuid.NullUUID `json:"parent_resource_id"`
} }
func (q *Queries) CreateFolder(ctx context.Context, arg CreateFolderParams) (Resource, error) { func (q *Queries) CreateFolder(ctx context.Context, arg CreateFolderParams) (Resource, error) {
row := q.db.QueryRowContext(ctx, createFolder, arg.Name, arg.OwnerID) row := q.db.QueryRowContext(ctx, createFolder, arg.Name, arg.OwnerID, arg.ParentResourceID)
var i Resource var i Resource
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
+2 -1
View File
@@ -336,13 +336,14 @@ func (h *ResourceHandler) CreateFolder(c *gin.Context) {
var body struct { var body struct {
Name string `json:"name" binding:"required"` Name string `json:"name" binding:"required"`
ParentResourceID *string `json:"parent_resource_id"`
} }
if err := c.ShouldBindJSON(&body); err != nil { if err := c.ShouldBindJSON(&body); err != nil {
api.Error(c, http.StatusBadRequest, "INVALID_BODY", "Body must contain 'name'") api.Error(c, http.StatusBadRequest, "INVALID_BODY", "Body must contain 'name'")
return return
} }
folder, err := h.resources.CreateFolder(body.Name, userID) folder, err := h.resources.CreateFolder(body.Name, userID, body.ParentResourceID)
if err != nil { if err != nil {
api.Error(c, http.StatusInternalServerError, "DB_ERROR", "Failed to create folder") api.Error(c, http.StatusInternalServerError, "DB_ERROR", "Failed to create folder")
return return
+8 -1
View File
@@ -271,7 +271,7 @@ func (s *ResourceService) MoveResources(resourceIDs []string, parentResourceID *
}) })
} }
func (s *ResourceService) CreateFolder(name, ownerID string) (*model.Resource, error) { func (s *ResourceService) CreateFolder(name, ownerID string, parentResourceID *string) (*model.Resource, error) {
ownerUUID, _ := uuid.Parse(ownerID) ownerUUID, _ := uuid.Parse(ownerID)
ctx := context.Background() ctx := context.Background()
@@ -283,9 +283,16 @@ func (s *ResourceService) CreateFolder(name, ownerID string) (*model.Resource, e
qtx := s.queries.WithTx(tx) qtx := s.queries.WithTx(tx)
parentID := uuid.NullUUID{Valid: false}
if parentResourceID != nil {
pid, _ := uuid.Parse(*parentResourceID)
parentID = uuid.NullUUID{UUID: pid, Valid: true}
}
r, err := qtx.CreateFolder(ctx, db.CreateFolderParams{ r, err := qtx.CreateFolder(ctx, db.CreateFolderParams{
Name: name, Name: name,
OwnerID: ownerUUID, OwnerID: ownerUUID,
ParentResourceID: parentID,
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("create folder: %w", err) return nil, fmt.Errorf("create folder: %w", err)
+2 -2
View File
@@ -213,13 +213,13 @@ export function FolderScreen() {
if (!name) return; if (!name) return;
const ids = Array.from(selectedIds); const ids = Array.from(selectedIds);
try { try {
const newFolder = await createFolder.mutateAsync(name); const newFolder = await createFolder.mutateAsync({ name, parentResourceId: folderId });
await moveFiles.mutateAsync({ resourceIds: ids, parentResourceId: newFolder.id }); await moveFiles.mutateAsync({ resourceIds: ids, parentResourceId: newFolder.id });
setTagModalVisible(false); setTagModalVisible(false);
setSelectedIds(new Set()); setSelectedIds(new Set());
navigation.navigate('Folder', { folderId: newFolder.id, folderName: newFolder.name }); navigation.navigate('Folder', { folderId: newFolder.id, folderName: newFolder.name });
} catch {} } catch {}
}, [tagInput, selectedIds, createFolder, moveFiles, navigation]); }, [tagInput, selectedIds, createFolder, moveFiles, navigation, folderId]);
const handleMove = useCallback(async (folderId: string | null) => { const handleMove = useCallback(async (folderId: string | null) => {
const ids = Array.from(selectedIds); const ids = Array.from(selectedIds);
+1 -1
View File
@@ -318,7 +318,7 @@ export function HomeScreen() {
if (!name) return; if (!name) return;
const ids = Array.from(selectedIds); const ids = Array.from(selectedIds);
try { try {
const newFolder = await createFolder.mutateAsync(name); const newFolder = await createFolder.mutateAsync({ name });
await moveFiles.mutateAsync({ resourceIds: ids, parentResourceId: newFolder.id }); await moveFiles.mutateAsync({ resourceIds: ids, parentResourceId: newFolder.id });
setTagModalVisible(false); setTagModalVisible(false);
setSelectedIds(new Set()); setSelectedIds(new Set());
+15 -4
View File
@@ -76,6 +76,8 @@ export function useFiles(parentId?: string | null, page: number = 1, limit: numb
const backendRes = await apiClient.get<PaginatedResponse<FileItem>>( const backendRes = await apiClient.get<PaginatedResponse<FileItem>>(
`${ENDPOINTS.RESOURCES}?page=${page}&limit=${limit}&thumbnail=thumbnail_small`, `${ENDPOINTS.RESOURCES}?page=${page}&limit=${limit}&thumbnail=thumbnail_small`,
); );
const returnedIds = new Set(backendRes.data.map((f) => f.id));
fileStore.mergeFromBackend( fileStore.mergeFromBackend(
backendRes.data.map((f) => ({ backendRes.data.map((f) => ({
id: f.id, id: f.id,
@@ -94,8 +96,11 @@ export function useFiles(parentId?: string | null, page: number = 1, limit: numb
); );
const cached = fileStore.getRootFiles(); const cached = fileStore.getRootFiles();
const validFiles = cached.files.filter(
(f) => !f.backendId || returnedIds.has(f.backendId) || f.source === 'local',
);
return { return {
data: cached.files.map((r) => recordToUnifiedItem(r)!).filter(Boolean), data: validFiles.map((r) => recordToUnifiedItem(r)!).filter(Boolean),
meta: { page, total: backendRes.meta?.total ?? cached.total }, meta: { page, total: backendRes.meta?.total ?? cached.total },
}; };
}, },
@@ -164,7 +169,13 @@ export function useMoveResources() {
return useMutation({ return useMutation({
mutationFn: ({ resourceIds, parentResourceId }: { resourceIds: string[]; parentResourceId: string | null }) => mutationFn: ({ resourceIds, parentResourceId }: { resourceIds: string[]; parentResourceId: string | null }) =>
apiClient.post(ENDPOINTS.MOVE, { resource_ids: resourceIds, parent_resource_id: parentResourceId }), apiClient.post(ENDPOINTS.MOVE, { resource_ids: resourceIds, parent_resource_id: parentResourceId }),
onSuccess: () => { onSuccess: (_, { resourceIds, parentResourceId }) => {
for (const id of resourceIds) {
const record = fileStore.getById(id) ?? fileStore.getByBackendId(id);
if (record) {
fileStore.updatePartial(record.id, { parentResourceId: parentResourceId ?? null });
}
}
queryClient.invalidateQueries({ queryKey: ['resources'] }); queryClient.invalidateQueries({ queryKey: ['resources'] });
}, },
}); });
@@ -205,8 +216,8 @@ export function useCreateFolder() {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async (name: string) => { mutationFn: async ({ name, parentResourceId }: { name: string; parentResourceId?: string }) => {
const res = await apiClient.post<{ data: FileItem }>(ENDPOINTS.FOLDERS, { name }); const res = await apiClient.post<{ data: FileItem }>(ENDPOINTS.FOLDERS, { name, parent_resource_id: parentResourceId });
return res.data; return res.data;
}, },
onSuccess: () => { onSuccess: () => {