mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-25 08:03:45 +00:00
* fix(frontend): persist raw-app draft path edits in the session editor Renaming a raw app's path in the session preview editor never triggered a draft save: the header surfaced the typed path as `pendingDraftPath`, but RawAppEditorView ignored it (it never reached runtime.rawApp.val), and the RawAppDraft codec didn't serialize a path field — so the autosave signature (JSON.stringify(draft)) was unchanged and nothing was written. The rename was lost and the home/review/Drafts lists kept the original `draft_path`. - appDraftCodec: make `draft_path` a real draft + runtime field, serialized by runtimeRawAppToDraft and round-tripped by applyDraftToRuntimeRawApp, so a path change moves the sig and fires a save. - sessionRuntime.loadRawApp (+ inline rawApp.val type): seed `draft_path` from the loaded draft so it survives reloads. - RawAppEditorView: bind the header's `pendingDraftPath`, mirror it into runtime.rawApp.val.draft_path (guarded so the initial undefined can't clobber the seed or fire a spurious save), and seed the path widget from `draft_path ?? path`. Mirrors the full-page /apps_raw/edit route. - appDraftCodec.test: add a draft_path round-trip test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): per-line tooltips in workspace item diff rows The summary line now shows the full summary on hover and the path line the full path, instead of one row-level title surfacing the path everywhere. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): persist flow/script draft path edits in the session editor The session sync dedups on a per-kind signature that omitted the path, so a rename never moved the signature and never autosaved. Add path/draft_path to the flow signature, and derive draft_path in the script codec (scripts bind the Path widget to script.path directly) so the rename both autosaves and shows the typed name in the home/Drafts lists. Mirrors the raw-app fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): commit editor summary edits live instead of on blur EditableInput only fired onSave on Enter/blur, so the summary in the shared editor header only updated when the field lost focus. Add an opt-in commitOnInput that fires onSave per keystroke and enable it for the header summary, so flow/script/raw-app summaries autosave as you type. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): preserve renamed never-deployed script path on session re-seed loadScript seeded a draft-only script's baseline path from the storage key, so re-running it with the draft still in memory (e.g. a script→script switch) reset the path to draft_<uuid> and the next autosave dropped draft_path, clobbering the rename. Seed from the draft's own draft_path/path instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(frontend): clear raw-app draft_path when the path rename is reverted The mirror effect only ever set draft_path, so reverting/clearing the path field left a stale friendly name in the draft (persisted by the codec and shown in the home/Drafts lists). Track whether a real typed path was surfaced so a revert clears draft_path while the initial pre-bind undefined still can't clobber the loadRawApp-seeded value. Mirrors the script codec's drop-on-revert. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
81 lines
2.5 KiB
TypeScript
81 lines
2.5 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import {
|
|
runtimeRawAppToDraft,
|
|
applyDraftToRuntimeRawApp,
|
|
type RuntimeRawApp,
|
|
type RawAppDraft
|
|
} from './appDraftCodec'
|
|
|
|
function runtime(over: Partial<RuntimeRawApp> = {}): RuntimeRawApp {
|
|
return {
|
|
summary: 'app',
|
|
path: 'f/foo/app',
|
|
files: { '/index.tsx': 'x' },
|
|
runnables: {},
|
|
data: { tables: [] } as any,
|
|
policy: { execution_mode: 'publisher' },
|
|
...over
|
|
}
|
|
}
|
|
|
|
describe('appDraftCodec — custom_path round-trip', () => {
|
|
it('carries custom_path from runtime → draft', () => {
|
|
const draft = runtimeRawAppToDraft(runtime({ custom_path: 'my-url' }))
|
|
expect(draft.custom_path).toBe('my-url')
|
|
})
|
|
|
|
it('carries custom_path from draft → runtime', () => {
|
|
const base = runtime({ custom_path: undefined })
|
|
const dv: RawAppDraft = {
|
|
summary: 'app',
|
|
files: {},
|
|
runnables: {},
|
|
data: { tables: [] } as any,
|
|
policy: { execution_mode: 'publisher' },
|
|
custom_path: 'kept-url'
|
|
}
|
|
expect(applyDraftToRuntimeRawApp(base, dv).custom_path).toBe('kept-url')
|
|
})
|
|
|
|
it('survives a full runtime → draft → runtime round-trip', () => {
|
|
const original = runtime({ custom_path: 'round-trip-url' })
|
|
const back = applyDraftToRuntimeRawApp(
|
|
runtime({ custom_path: undefined }),
|
|
runtimeRawAppToDraft(original)
|
|
)
|
|
expect(back.custom_path).toBe('round-trip-url')
|
|
// runtime-only `path` is preserved from the target, not the draft
|
|
expect(back.path).toBe('f/foo/app')
|
|
})
|
|
|
|
it('falls back to the runtime custom_path when the draft omits it', () => {
|
|
const base = runtime({ custom_path: 'existing' })
|
|
const dv: RawAppDraft = {
|
|
summary: 'app',
|
|
files: {},
|
|
runnables: {},
|
|
data: { tables: [] } as any
|
|
}
|
|
expect(applyDraftToRuntimeRawApp(base, dv).custom_path).toBe('existing')
|
|
})
|
|
})
|
|
|
|
describe('appDraftCodec — draft_path round-trip', () => {
|
|
it('serializes draft_path so a path edit changes the draft (and its sig)', () => {
|
|
const draft = runtimeRawAppToDraft(runtime({ draft_path: 'u/admin/friendly' }))
|
|
expect(draft.draft_path).toBe('u/admin/friendly')
|
|
// The autosave keys on JSON.stringify(draft); without draft_path a rename
|
|
// would be invisible and never persist.
|
|
expect(JSON.stringify(draft)).toContain('u/admin/friendly')
|
|
})
|
|
|
|
it('survives a full runtime → draft → runtime round-trip', () => {
|
|
const original = runtime({ draft_path: 'u/admin/renamed' })
|
|
const back = applyDraftToRuntimeRawApp(
|
|
runtime({ draft_path: undefined }),
|
|
runtimeRawAppToDraft(original)
|
|
)
|
|
expect(back.draft_path).toBe('u/admin/renamed')
|
|
})
|
|
})
|