mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-10 08:07:03 +00:00
* fix(frontend): ignore hash/assets in script diffs and drafts The script editor's draft value is seeded from the full `getScriptByPath` DB row (since #9351), so it carries `hash` (the deployed version's identity) and `assets` (re-derived from the script content by the editor). Neither is editable draft content, yet both were persisted into the draft row and surfaced as spurious changes in the workspace/fork compare diff view. - Add `hash`, `assets`, and the read-time-computed `inherited_labels` to `CLEANED_VALUE_KEYS` so the shared diff/unsaved-change strip ignores them everywhere (DiffDrawer + WorkspaceItemDiffViewer). - Strip `hash` and `assets` from script drafts at the single persistence chokepoint (`UserDraftDbSyncer.save`) so every path — reactive autosave, Ctrl/Cmd+S flush, the pagehide keepalive — sends the same trimmed payload. On reload the deployed row re-supplies them. Fixes WIN-2071 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(frontend): clarify draft sanitizer vs diff-strip relationship The two field lists are intentionally not equal — only the hash/assets overlap must stay consistent. Reword the comment so a future maintainer doesn't add keys to one expecting parity with the other. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
55 lines
2.0 KiB
TypeScript
55 lines
2.0 KiB
TypeScript
import { describe, it, expect, vi } from 'vitest'
|
|
|
|
// Importing the syncer pulls in the generated client and its localStorage /
|
|
// pagehide wiring; stub the same surfaces the other syncer test does so the
|
|
// pure-function import stays side-effect free.
|
|
vi.mock('./gen', () => ({
|
|
DraftService: { updateDraft: vi.fn() }
|
|
}))
|
|
vi.mock('./gen/core/OpenAPI', () => ({ OpenAPI: { BASE: '' } }))
|
|
vi.mock('./localDraftHints.svelte', () => ({ setLocalDraftHint: vi.fn() }))
|
|
|
|
import { sanitizeDraftValueForSave } from './userDraftDbSyncer.svelte'
|
|
|
|
describe('sanitizeDraftValueForSave', () => {
|
|
it('strips hash and assets from a script draft', () => {
|
|
const value = {
|
|
path: 'u/me/foo',
|
|
summary: 'hi',
|
|
content: 'export function main() {}',
|
|
hash: '123456789',
|
|
assets: [{ path: 's3://bucket/x', kind: 's3object' }]
|
|
}
|
|
const cleaned = sanitizeDraftValueForSave('script', value) as any
|
|
expect(cleaned).not.toHaveProperty('hash')
|
|
expect(cleaned).not.toHaveProperty('assets')
|
|
expect(cleaned.content).toBe('export function main() {}')
|
|
expect(cleaned.summary).toBe('hi')
|
|
})
|
|
|
|
it('does not mutate the input object', () => {
|
|
const value = { path: 'u/me/foo', hash: 'h', assets: [] }
|
|
sanitizeDraftValueForSave('script', value)
|
|
expect(value).toHaveProperty('hash', 'h')
|
|
expect(value).toHaveProperty('assets')
|
|
})
|
|
|
|
it('returns the same reference when no omitted field is present', () => {
|
|
const value = { path: 'u/me/foo', summary: 'hi' }
|
|
expect(sanitizeDraftValueForSave('script', value)).toBe(value)
|
|
})
|
|
|
|
it('leaves non-script kinds untouched even if they carry hash/assets', () => {
|
|
const value = { hash: 'h', assets: [] }
|
|
expect(sanitizeDraftValueForSave('flow', value)).toBe(value)
|
|
expect(sanitizeDraftValueForSave('app', value)).toBe(value)
|
|
})
|
|
|
|
it('passes through null (the delete signal) and non-objects', () => {
|
|
expect(sanitizeDraftValueForSave('script', null)).toBeNull()
|
|
expect(sanitizeDraftValueForSave('script', 'hello')).toBe('hello')
|
|
const arr = [1, 2, 3]
|
|
expect(sanitizeDraftValueForSave('script', arr)).toBe(arr)
|
|
})
|
|
})
|