fix folders on main page
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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: () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user