fix: Accept time:0 entries and precompute history entry URLs
Code-review follow-ups: - validateEntry no longer rejects entries whose time is 0 (epoch); it now checks `typeof time === 'number'`, so restoring/uploading such entries works instead of silently dropping them. - History.svelte serializes each entry's "open in new tab" URL once via a $derived list instead of calling serializeState (pako deflate) per row on every render. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8dd9cb49a0
commit
2db9355b7b
@@ -105,6 +105,11 @@
|
||||
// Absolute editor URL for an entry, so the link can be opened in a new tab or copied.
|
||||
const entryUrl = (state: State): string =>
|
||||
`${window.location.origin}${window.location.pathname}#${serializeState(state)}`;
|
||||
|
||||
// Serialize each entry's URL once per change rather than per row on every render.
|
||||
const entriesWithUrl = $derived(
|
||||
historyState.entries.map((entry) => ({ ...entry, openUrl: entryUrl(entry.state) }))
|
||||
);
|
||||
</script>
|
||||
|
||||
<Card onselect={tabSelectHandler} isOpen isClosable={false} {tabs} activeTabID={historyState.mode}>
|
||||
@@ -143,8 +148,8 @@
|
||||
</div>
|
||||
{/snippet}
|
||||
<ul class="flex h-full min-w-fit flex-col gap-2 overflow-auto p-2" id="historyList">
|
||||
{#if historyState.entries.length > 0}
|
||||
{#each historyState.entries as { id, state, time, name, url, type } (id)}
|
||||
{#if entriesWithUrl.length > 0}
|
||||
{#each entriesWithUrl as { id, state, time, name, url, type, openUrl } (id)}
|
||||
<li class="flex flex-col gap-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex flex-col">
|
||||
@@ -167,7 +172,7 @@
|
||||
{dayjs(time).fromNow()}
|
||||
</span>
|
||||
<Button
|
||||
href={entryUrl(state)}
|
||||
href={openUrl}
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
size="icon"
|
||||
|
||||
@@ -158,7 +158,7 @@ export const clearActive = (): void => {
|
||||
};
|
||||
|
||||
const validateEntry = (entry: HistoryEntry): boolean =>
|
||||
Boolean(entry && entry.type && entry.state && entry.time);
|
||||
Boolean(entry && entry.type && entry.state) && typeof entry.time === 'number';
|
||||
|
||||
export interface RestoreResult {
|
||||
restored: number;
|
||||
|
||||
@@ -241,6 +241,15 @@ describe('restoreEntries', () => {
|
||||
]);
|
||||
expect(entriesFor('manual').map((e) => e.time)).toEqual([30, 20, 10]);
|
||||
});
|
||||
|
||||
it('restores entries whose time is 0 (epoch) instead of treating them as invalid', () => {
|
||||
const result = restoreEntries([
|
||||
{ id: 'm0', name: 'epoch', state: defaultState, time: 0, type: 'manual' }
|
||||
]);
|
||||
expect(result.restored).toBe(1);
|
||||
expect(result.invalid).toBe(0);
|
||||
expect(entriesFor('manual')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('injectHistoryIDs migration', () => {
|
||||
|
||||
Reference in New Issue
Block a user