feat(metadata): show file path for in-place imported books (#4508)
In-place imports point at a file the user keeps under one of their external library folders (book.filePath set), as opposed to hash-copy imports that live anonymously under Books/<hash>/. The book details view didn't surface where an entry actually lives on disk, so users had no way to tell the two storage modes apart or locate the source file. Add a 'File Path' row to the metadata grid that renders only when book.filePath is set, breaks long paths across lines, and exposes the full string via a hover title for paths that overflow the row.
This commit is contained in:
@@ -13,7 +13,9 @@ vi.mock('@/store/settingsStore', () => ({
|
||||
useSettingsStore: () => ({
|
||||
settings: {
|
||||
metadataSeriesCollapsed: true,
|
||||
metadataOthersCollapsed: true,
|
||||
// The "File Path" entry lives under the Metadata section; tests below
|
||||
// depend on it being expanded by default so the row is in the DOM.
|
||||
metadataOthersCollapsed: false,
|
||||
metadataDescriptionCollapsed: true,
|
||||
},
|
||||
}),
|
||||
@@ -100,3 +102,24 @@ describe('BookDetailView delete dropdown layout', () => {
|
||||
expect(menu!.className).toContain('!relative');
|
||||
});
|
||||
});
|
||||
|
||||
describe('BookDetailView file path row', () => {
|
||||
// book.filePath is only set for in-place imports (and OS-handed paths like
|
||||
// Android "Open with Readest"). Hash-copy imports leave it undefined, so
|
||||
// surfacing it lets users tell the two storage modes apart at a glance.
|
||||
it('shows the actual file path when book.filePath is set', () => {
|
||||
const filePath = '/Users/me/Library/Books/sample.epub';
|
||||
const { getByText } = renderView({ book: makeBook({ filePath }) });
|
||||
|
||||
expect(getByText('File Path')).toBeTruthy();
|
||||
const value = getByText(filePath);
|
||||
expect(value).toBeTruthy();
|
||||
// Long paths must remain hoverable for the full string.
|
||||
expect(value.getAttribute('title')).toBe(filePath);
|
||||
});
|
||||
|
||||
it('omits the file path row for hash-copy books (no filePath)', () => {
|
||||
const { queryByText } = renderView({ book: makeBook() });
|
||||
expect(queryByText('File Path')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -222,6 +222,21 @@ const BookDetailView: React.FC<BookDetailViewProps> = ({
|
||||
{metadata?.identifier || _('Unknown')}
|
||||
</p>
|
||||
</div>
|
||||
{/*
|
||||
Only books imported in-place (or files opened directly via the
|
||||
OS, e.g. Android "Open with Readest") keep a `filePath`; books
|
||||
copied into Books/<hash>/ have it left undefined. Surfacing the
|
||||
path lets the user verify which on-disk file the entry points at
|
||||
and tell apart in-place vs hash-copy imports at a glance.
|
||||
*/}
|
||||
{book.filePath && (
|
||||
<div className='col-span-2 overflow-hidden sm:col-span-3'>
|
||||
<span className='font-bold'>{_('File Path')}</span>
|
||||
<p className='text-neutral-content text-sm break-all' title={book.filePath}>
|
||||
{book.filePath}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user