Add snippet metadata panel, duplicate, and immediate-load preview (M4.5)

This commit is contained in:
2026-06-06 23:54:59 +03:00
parent 3e89d9a531
commit 80bedd2a8d
13 changed files with 785 additions and 51 deletions
+50
View File
@@ -2,6 +2,7 @@ import { describe, expect, test } from 'vitest';
import {
CURRENT_SNIPPET_VERSION,
createSnippet,
duplicateSnippet,
formatSnippetSize,
generateSnippetName,
hasUnpublishedChanges,
@@ -67,6 +68,55 @@ describe('generateSnippetName', () => {
});
});
describe('duplicateSnippet', () => {
const source = {
...createSnippet({
id: 'src',
name: 'My Chart',
spec: '{"published":1}',
now: new Date('2026-01-01T00:00:00Z'),
}),
draftSpec: '{"draft":1}',
comment: 'a note',
tags: ['imported'],
datasetRefs: ['Sales'],
meta: { createdWith: 'chart-builder' },
};
test('suffixes the name with "(copy)" and takes a new identity + timestamps', () => {
const now = new Date('2026-03-04T05:06:07Z');
const copy = duplicateSnippet(source, { id: 'copy', now });
expect(copy.id).toBe('copy');
expect(copy.id).not.toBe(source.id);
expect(copy.name).toBe('My Chart (copy)');
expect(copy.version).toBe(CURRENT_SNIPPET_VERSION);
expect(copy.created).toBe(now.toISOString());
expect(copy.modified).toBe(now.toISOString());
});
test('carries over both spec versions, comment, tags, refs, and meta', () => {
const copy = duplicateSnippet(source);
expect(copy.spec).toBe('{"published":1}');
expect(copy.draftSpec).toBe('{"draft":1}');
expect(copy.comment).toBe('a note');
expect(copy.tags).toEqual(['imported']);
expect(copy.datasetRefs).toEqual(['Sales']);
expect(copy.meta).toEqual({ createdWith: 'chart-builder' });
});
test('clones mutable members so the copy shares no references with its source', () => {
const copy = duplicateSnippet(source);
expect(copy.tags).not.toBe(source.tags);
expect(copy.datasetRefs).not.toBe(source.datasetRefs);
expect(copy.meta).not.toBe(source.meta);
});
test('generates a unique id by default', () => {
expect(duplicateSnippet(source).id).not.toBe(duplicateSnippet(source).id);
});
});
describe('hasUnpublishedChanges', () => {
test('false when draft matches published, true once draft diverges', () => {
const s = createSnippet({ now: new Date('2026-06-04T00:00:00Z') });