web(review): switch cause tabs to PhotoGrid, add date-from-path suggestion
- CauseGroupCard now wraps PhotoGrid so selection, keyboard nav, and preview flow through the standard timeline plumbing. Per-tile hover Approve/Archive and the group-wide Approve all are gone — the bottom BulkActionBar's review-section Keep/Archive handle single + bulk. - Low Resolution tab opts into a new PhotoTile dimensionBadge prop so WxH stays visible on each tile. - New suggestDateFromPath util parses YYYY-MM-DD from filename or folder path. RightSidebar surfaces it as an amber Apply row above the Taken-at input whenever the photo lacks a trusted TakenAt. - BulkActionBar gains a "Accept date & Keep" button (review section only) that patches each selected photo's TakenAt from its path suggestion when available, then approves. - Drop the Same folder / Same camera / Same year strips and the RelatedStrip component from the metadata sidebar. Also bundles in-progress Notes route + tile components and small tweaks to LeftSidebar, DuplicatesView, CrossFolderGroupCard, and photoprism.ts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -478,6 +478,33 @@ export interface AggregatedKeyword {
|
||||
sampleHash: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Photos carrying a non-empty user note. mule-image's "Note" is
|
||||
* PhotoPrism's `Caption` field (see RightSidebar's Note textarea), which
|
||||
* is a top-level scalar — present on the list response, so a single
|
||||
* round-trip is enough.
|
||||
*/
|
||||
export interface PhotoWithNote {
|
||||
photo: PpPhoto;
|
||||
note: string;
|
||||
}
|
||||
|
||||
export async function listPhotosWithNotes(): Promise<PhotoWithNote[]> {
|
||||
const list = await listPhotos({ count: 1000, order: 'newest', merged: true });
|
||||
const out: PhotoWithNote[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (const p of list) {
|
||||
// `merged: true` can repeat a photo across file-rows; dedupe by UID
|
||||
// so the same tile doesn't render twice.
|
||||
if (seen.has(p.UID)) continue;
|
||||
seen.add(p.UID);
|
||||
const note = p.Caption?.trim();
|
||||
if (!note) continue;
|
||||
out.push({ photo: p, note });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export async function aggregateKeywords(): Promise<AggregatedKeyword[]> {
|
||||
const list = await listPhotos({ count: 1000, merged: true });
|
||||
const buckets = new Map<string, AggregatedKeyword>();
|
||||
|
||||
Reference in New Issue
Block a user