fix(resources): wire missing created_by and updated_by
This commit is contained in:
@@ -1570,6 +1570,7 @@
|
||||
.rl-ctx-item--disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.rl-ctx-item--disabled:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@@ -74,4 +74,3 @@ export async function probeFolderAccess(id: string): Promise<boolean> {
|
||||
inflight.set(id, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
@@ -366,8 +366,7 @@
|
||||
<Button
|
||||
icon="star-outline"
|
||||
data-testid="favorites-batch-remove-btn"
|
||||
onclick={() => sel.forEach(unfavorite)}
|
||||
>{t('files.unfavorite', 'Remove favorite')}</Button
|
||||
onclick={() => sel.forEach(unfavorite)}>{t('files.unfavorite', 'Remove favorite')}</Button
|
||||
>
|
||||
{/snippet}
|
||||
</ResourceList>
|
||||
|
||||
@@ -26,7 +26,6 @@ vi.mock('$lib/api/endpoints/folders', () => ({ renameFolder: vi.fn(), deleteFold
|
||||
vi.mock('$lib/stores/dialogs.svelte', () => ({ confirmDialog, promptDialog }));
|
||||
|
||||
import { fetchFavoritesPage, removeFavorite } from '$lib/api/endpoints/favorites';
|
||||
import { deleteFile } from '$lib/api/endpoints/files';
|
||||
import FavoritesPage from './+page.svelte';
|
||||
|
||||
const m = (fn: unknown) => fn as ReturnType<typeof vi.fn>;
|
||||
|
||||
@@ -48,9 +48,12 @@
|
||||
let reversed = $state(false);
|
||||
const owners = useOwnerCache(resolveOwnerName);
|
||||
|
||||
// Envelope shape: `accessed_at` → `ctx.date`, `updated_by` → `ctx.ownerId`
|
||||
// (Recent's provenance semantic — "who touched this recently" — differs
|
||||
// from Favorites'/Files' `created_by`).
|
||||
// Envelope shape: `accessed_at` → `ctx.date`, `created_by` → `ctx.ownerId`.
|
||||
// Recent is a per-user view of items the caller accessed; the "who
|
||||
// touched this last" (`updated_by`) semantic is real but adds noise
|
||||
// (mostly the current user), so we align with Files / Favorites and
|
||||
// show the original author instead. Cross-surface consistency wins
|
||||
// over the finer-grained signal.
|
||||
//
|
||||
// Dotfile hiding is delegated to ResourceList via `showDotfileToggle`
|
||||
// — the component reads `preferences.hideDotfiles` and drops matching
|
||||
@@ -117,10 +120,10 @@
|
||||
raw = reset ? page.items : [...raw, ...page.items];
|
||||
primeContextPage(contextMap, reset, page.items, (it) => [
|
||||
it.resource.id,
|
||||
{ date: it.accessed_at, ownerId: it.resource.updated_by ?? null }
|
||||
{ date: it.accessed_at, ownerId: it.resource.created_by ?? null }
|
||||
]);
|
||||
cursor = page.next_cursor;
|
||||
void owners.resolve(page.items.map((i) => i.resource.updated_by));
|
||||
void owners.resolve(page.items.map((i) => i.resource.created_by));
|
||||
} catch (e) {
|
||||
console.error('recent: load error', e);
|
||||
error = t('errors_loadFailed', 'Failed to load items');
|
||||
@@ -184,7 +187,7 @@
|
||||
raw = [...raw.slice(0, idx), snapshot, ...raw.slice(idx)];
|
||||
contextMap.set(item.id, {
|
||||
date: snapshot.accessed_at,
|
||||
ownerId: snapshot.resource.updated_by ?? null
|
||||
ownerId: snapshot.resource.created_by ?? null
|
||||
});
|
||||
errorToast(e);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ vi.mock('$lib/api/endpoints/folders', () => ({ renameFolder: vi.fn(), deleteFold
|
||||
vi.mock('$lib/stores/dialogs.svelte', () => ({ confirmDialog, promptDialog }));
|
||||
|
||||
import { fetchRecentPage, clearRecent, removeFromRecent } from '$lib/api/endpoints/recent';
|
||||
import { deleteFile } from '$lib/api/endpoints/files';
|
||||
import RecentPage from './+page.svelte';
|
||||
|
||||
const m = (fn: unknown) => fn as ReturnType<typeof vi.fn>;
|
||||
|
||||
@@ -300,17 +300,14 @@
|
||||
standard action-bar sizing and reads consistently with
|
||||
`/recent` and `/favorites` batch clusters.
|
||||
-->
|
||||
<Button
|
||||
icon="undo"
|
||||
data-testid="trash-batch-restore-btn"
|
||||
onclick={() => sel.forEach(restore)}>{t('trash.restore', 'Restore')}</Button
|
||||
<Button icon="undo" data-testid="trash-batch-restore-btn" onclick={() => sel.forEach(restore)}
|
||||
>{t('trash.restore', 'Restore')}</Button
|
||||
>
|
||||
<Button
|
||||
variant="danger"
|
||||
icon="trash"
|
||||
data-testid="trash-batch-delete-btn"
|
||||
onclick={() => sel.forEach(purge)}
|
||||
>{t('trash.delete', 'Delete permanently')}</Button
|
||||
onclick={() => sel.forEach(purge)}>{t('trash.delete', 'Delete permanently')}</Button
|
||||
>
|
||||
{/snippet}
|
||||
{#snippet rowBadge(_item, ctx)}
|
||||
@@ -414,4 +411,17 @@
|
||||
:global(.files-grid-view .file-item .action-cell .btn-action--delete:hover) {
|
||||
color: var(--color-error-text);
|
||||
}
|
||||
|
||||
/* List view: hide the expiry chip that ResourceList paints inside
|
||||
`.file-icon__badge`. In list mode the same info is already in
|
||||
the "Expires at" column (`dateCell` snippet above) — showing
|
||||
the chip on the tiny row icon crops it and duplicates the
|
||||
signal. Grid view keeps the chip: no dedicated column exists
|
||||
there and the badge is the ONLY expiration surface on the
|
||||
card. Scoped to trash because trash is the only section
|
||||
emitting a rowBadge today; if another section starts using it,
|
||||
this rule stays inert for them. */
|
||||
:global(.files-list-view .file-item .file-icon__badge) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user