mirror of
https://github.com/simstudioai/sim.git
synced 2026-10-30 19:32:46 +08:00
feat(files): default sort by updated and add updated sort option (#4279)
* feat(files): default sort by updated and add updated sort option * feat(files): show Last Updated column Matches the visible-column pattern already used on Knowledge and Tables so users can see the value they're sorting by. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
3b11c814f8
commit
0ae19dab85
@@ -97,6 +97,7 @@ const COLUMNS: ResourceColumn[] = [
|
||||
{ id: 'type', header: 'Type' },
|
||||
{ id: 'created', header: 'Created' },
|
||||
{ id: 'owner', header: 'Owner' },
|
||||
{ id: 'updated', header: 'Last Updated' },
|
||||
]
|
||||
|
||||
const MIME_TYPE_LABELS: Record<string, string> = {
|
||||
@@ -249,7 +250,7 @@ export function Files() {
|
||||
result = result.filter((f) => uploadedByFilter.includes(f.uploadedBy))
|
||||
}
|
||||
|
||||
const col = activeSort?.column ?? 'created'
|
||||
const col = activeSort?.column ?? 'updated'
|
||||
const dir = activeSort?.direction ?? 'desc'
|
||||
return [...result].sort((a, b) => {
|
||||
let cmp = 0
|
||||
@@ -266,6 +267,9 @@ export function Files() {
|
||||
case 'created':
|
||||
cmp = new Date(a.uploadedAt).getTime() - new Date(b.uploadedAt).getTime()
|
||||
break
|
||||
case 'updated':
|
||||
cmp = new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime()
|
||||
break
|
||||
case 'owner':
|
||||
cmp = (members?.find((m) => m.userId === a.uploadedBy)?.name ?? '').localeCompare(
|
||||
members?.find((m) => m.userId === b.uploadedBy)?.name ?? ''
|
||||
@@ -310,6 +314,7 @@ export function Files() {
|
||||
},
|
||||
created: timeCell(file.uploadedAt),
|
||||
owner: ownerCell(file.uploadedBy, members),
|
||||
updated: timeCell(file.updatedAt),
|
||||
},
|
||||
}
|
||||
nextCache.set(file.id, { row, file, members })
|
||||
@@ -875,6 +880,7 @@ export function Files() {
|
||||
{ id: 'size', label: 'Size' },
|
||||
{ id: 'type', label: 'Type' },
|
||||
{ id: 'created', label: 'Created' },
|
||||
{ id: 'updated', label: 'Last Updated' },
|
||||
{ id: 'owner', label: 'Owner' },
|
||||
],
|
||||
active: activeSort,
|
||||
|
||||
+1
@@ -124,6 +124,7 @@ export const ResourceContent = memo(function ResourceContent({
|
||||
type,
|
||||
uploadedBy: '',
|
||||
uploadedAt: STREAMING_EPOCH,
|
||||
updatedAt: STREAMING_EPOCH,
|
||||
}
|
||||
}, [workspaceId, streamFileName])
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ export function Knowledge() {
|
||||
result = result.filter((kb) => ownerFilter.includes(kb.userId))
|
||||
}
|
||||
|
||||
const col = activeSort?.column ?? 'created'
|
||||
const col = activeSort?.column ?? 'updated'
|
||||
const dir = activeSort?.direction ?? 'desc'
|
||||
return [...result].sort((a, b) => {
|
||||
let cmp = 0
|
||||
|
||||
@@ -123,7 +123,7 @@ export function Tables() {
|
||||
if (ownerFilter.length > 0) {
|
||||
result = result.filter((t) => ownerFilter.includes(t.createdBy))
|
||||
}
|
||||
const col = activeSort?.column ?? 'created'
|
||||
const col = activeSort?.column ?? 'updated'
|
||||
const dir = activeSort?.direction ?? 'desc'
|
||||
return [...result].sort((a, b) => {
|
||||
let cmp = 0
|
||||
|
||||
@@ -29,6 +29,7 @@ function toFileRecord(row: typeof workspaceFiles.$inferSelect) {
|
||||
uploadedBy: row.userId,
|
||||
deletedAt: row.deletedAt,
|
||||
uploadedAt: row.uploadedAt,
|
||||
updatedAt: row.updatedAt,
|
||||
storageContext: 'mothership' as const,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ function toWorkspaceFileRecord(row: typeof workspaceFiles.$inferSelect): Workspa
|
||||
uploadedBy: row.userId,
|
||||
deletedAt: row.deletedAt,
|
||||
uploadedAt: row.uploadedAt,
|
||||
updatedAt: row.updatedAt,
|
||||
storageContext: 'mothership',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ export interface WorkspaceFileRecord {
|
||||
uploadedBy: string
|
||||
deletedAt?: Date | null
|
||||
uploadedAt: Date
|
||||
updatedAt: Date
|
||||
/** Pass-through to `downloadFile` when not default `workspace` (e.g. chat mothership uploads). */
|
||||
storageContext?: 'workspace' | 'mothership'
|
||||
}
|
||||
@@ -375,6 +376,7 @@ export async function getWorkspaceFileByName(
|
||||
uploadedBy: file.userId,
|
||||
deletedAt: file.deletedAt,
|
||||
uploadedAt: file.uploadedAt,
|
||||
updatedAt: file.updatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,6 +425,7 @@ export async function listWorkspaceFiles(
|
||||
uploadedBy: file.userId,
|
||||
deletedAt: file.deletedAt,
|
||||
uploadedAt: file.uploadedAt,
|
||||
updatedAt: file.updatedAt,
|
||||
}))
|
||||
} catch (error) {
|
||||
logger.error(`Failed to list workspace files for ${workspaceId}:`, error)
|
||||
@@ -560,6 +563,7 @@ export async function getWorkspaceFile(
|
||||
uploadedBy: file.userId,
|
||||
deletedAt: file.deletedAt,
|
||||
uploadedAt: file.uploadedAt,
|
||||
updatedAt: file.updatedAt,
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Failed to get workspace file ${fileId}:`, error)
|
||||
@@ -638,7 +642,7 @@ export async function updateWorkspaceFileContent(
|
||||
|
||||
await db
|
||||
.update(workspaceFiles)
|
||||
.set({ size: content.length, contentType: nextContentType })
|
||||
.set({ size: content.length, contentType: nextContentType, updatedAt: new Date() })
|
||||
.where(
|
||||
and(
|
||||
eq(workspaceFiles.id, fileId),
|
||||
@@ -707,7 +711,7 @@ export async function renameWorkspaceFile(
|
||||
try {
|
||||
updated = await db
|
||||
.update(workspaceFiles)
|
||||
.set({ originalName: trimmedName })
|
||||
.set({ originalName: trimmedName, updatedAt: new Date() })
|
||||
.where(
|
||||
and(
|
||||
eq(workspaceFiles.id, fileId),
|
||||
@@ -807,7 +811,7 @@ export async function restoreWorkspaceFile(workspaceId: string, fileId: string):
|
||||
|
||||
await db
|
||||
.update(workspaceFiles)
|
||||
.set({ deletedAt: null, originalName: newName })
|
||||
.set({ deletedAt: null, originalName: newName, updatedAt: new Date() })
|
||||
.where(
|
||||
and(
|
||||
eq(workspaceFiles.id, fileId),
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE "workspace_files" ADD COLUMN "updated_at" timestamp DEFAULT now() NOT NULL;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1373,6 +1373,13 @@
|
||||
"when": 1776916912442,
|
||||
"tag": "0196_retention_org_level",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 197,
|
||||
"version": "7",
|
||||
"when": 1776980739421,
|
||||
"tag": "0197_unknown_the_captain",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1138,6 +1138,7 @@ export const workspaceFiles = pgTable(
|
||||
size: integer('size').notNull(),
|
||||
deletedAt: timestamp('deleted_at'),
|
||||
uploadedAt: timestamp('uploaded_at').notNull().defaultNow(),
|
||||
updatedAt: timestamp('updated_at').notNull().defaultNow(),
|
||||
},
|
||||
(table) => ({
|
||||
keyActiveUniqueIdx: uniqueIndex('workspace_files_key_active_unique')
|
||||
|
||||
Reference in New Issue
Block a user