mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-18 16:03:24 +00:00
fix: resolve add-editor drafts by path
This commit is contained in:
@@ -257,6 +257,46 @@ describe('global AI tools', () => {
|
||||
expect(localStorage.getItem(`userdraft/w/${WORKSPACE}/script/f/scripts/open-editor`)).toBeNull()
|
||||
})
|
||||
|
||||
it('lists and edits a new script draft stored under the empty add-editor key by its assigned path', async () => {
|
||||
const content = 'export async function main() {\n\treturn 1\n}'
|
||||
const handle = UserDraft.use<any>('script', '', { workspace: WORKSPACE })
|
||||
handle.setDraftAndMeta(
|
||||
{
|
||||
path: 'u/admin/assigned_script',
|
||||
summary: '',
|
||||
language: 'bun',
|
||||
content
|
||||
},
|
||||
{}
|
||||
)
|
||||
|
||||
const raw = await callGlobalTool('list_workspace_items', {
|
||||
types: ['script']
|
||||
})
|
||||
|
||||
expect(JSON.parse(raw)).toEqual([
|
||||
expect.objectContaining({
|
||||
type: 'script',
|
||||
path: 'u/admin/assigned_script',
|
||||
isDraft: false
|
||||
})
|
||||
])
|
||||
|
||||
await callGlobalTool('edit_script', {
|
||||
path: 'u/admin/assigned_script',
|
||||
old_string: 'return 1',
|
||||
new_string: 'return 2',
|
||||
replace_all: false
|
||||
})
|
||||
|
||||
expect(UserDraft.get<any>('script', '', { workspace: WORKSPACE })?.content).toContain(
|
||||
'return 2'
|
||||
)
|
||||
expect(
|
||||
UserDraft.get<any>('script', 'u/admin/assigned_script', { workspace: WORKSPACE })
|
||||
).toBeUndefined()
|
||||
})
|
||||
|
||||
it('overlays shared UserDraft entries in list_workspace_items', async () => {
|
||||
await callGlobalTool('write_script', {
|
||||
path: 'f/scripts/listed',
|
||||
|
||||
@@ -81,6 +81,7 @@ import {
|
||||
deleteGlobalDraft,
|
||||
getGlobalCurrentItem,
|
||||
getGlobalDraft,
|
||||
getGlobalDraftStoragePath,
|
||||
listGlobalCurrentItems,
|
||||
triggerKindToUserDraftKind
|
||||
} from './userDraftAdapter'
|
||||
@@ -659,11 +660,11 @@ function buildPersistedRunnable(
|
||||
): PersistedRunnable {
|
||||
const fields = input.staticInputs
|
||||
? Object.fromEntries(
|
||||
Object.entries(input.staticInputs).map(([k, v]) => [
|
||||
k,
|
||||
{ type: 'static', value: v, fieldType: 'object' }
|
||||
])
|
||||
)
|
||||
Object.entries(input.staticInputs).map(([k, v]) => [
|
||||
k,
|
||||
{ type: 'static', value: v, fieldType: 'object' }
|
||||
])
|
||||
)
|
||||
: (existing?.fields ?? {})
|
||||
|
||||
if (input.type === 'inline') {
|
||||
@@ -1696,7 +1697,8 @@ async function writeScriptDraft(
|
||||
const { workspace } = ctx
|
||||
startDraftWrite(ctx, 'script', args.path)
|
||||
|
||||
const existingDraft = UserDraft.get<NewScript>('script', args.path, { workspace })
|
||||
const draftStoragePath = getGlobalDraftStoragePath(workspace, 'script', args.path) ?? args.path
|
||||
const existingDraft = UserDraft.get<NewScript>('script', draftStoragePath, { workspace })
|
||||
const backendExists = existingDraft
|
||||
? false
|
||||
: await ScriptService.existsScriptByPath({ workspace, path: args.path })
|
||||
@@ -1733,7 +1735,7 @@ async function writeScriptDraft(
|
||||
}
|
||||
}
|
||||
|
||||
UserDraft.save('script', args.path, draft, { workspace })
|
||||
UserDraft.save('script', draftStoragePath, draft, { workspace })
|
||||
return finishDraftWrite(
|
||||
getRequiredGlobalDraft(workspace, 'script', args.path),
|
||||
existingDraft !== undefined || backendExists,
|
||||
@@ -1748,13 +1750,14 @@ async function writeFlowDraft(
|
||||
const { workspace } = ctx
|
||||
startDraftWrite(ctx, 'flow', args.path)
|
||||
|
||||
const draftStoragePath = getGlobalDraftStoragePath(workspace, 'flow', args.path) ?? args.path
|
||||
const draftValue = args.flow
|
||||
const value = structuredClone(draftValue.value)
|
||||
if (draftValue.groups !== undefined && draftValue.groups !== null) {
|
||||
value.groups = structuredClone(draftValue.groups)
|
||||
}
|
||||
|
||||
const existingDraft = UserDraft.get<Flow>('flow', args.path, { workspace })
|
||||
const existingDraft = UserDraft.get<Flow>('flow', draftStoragePath, { workspace })
|
||||
const backendExists = existingDraft
|
||||
? false
|
||||
: await FlowService.existsFlowByPath({ workspace, path: args.path })
|
||||
@@ -1790,7 +1793,7 @@ async function writeFlowDraft(
|
||||
}
|
||||
}
|
||||
|
||||
UserDraft.save('flow', args.path, draft, { workspace })
|
||||
UserDraft.save('flow', draftStoragePath, draft, { workspace })
|
||||
return finishDraftWrite(
|
||||
getRequiredGlobalDraft(workspace, 'flow', args.path),
|
||||
existingDraft !== undefined || backendExists,
|
||||
|
||||
@@ -149,7 +149,19 @@ function getItemSummary(value: unknown): string | undefined {
|
||||
return ((value as { summary?: string | null } | undefined)?.summary ?? undefined) || undefined
|
||||
}
|
||||
|
||||
function scriptDraftToWorkspaceItem(path: string, draft: NewScript, isDraft = true): WorkspaceItem {
|
||||
function getItemPath(storagePath: string, value: unknown): string | undefined {
|
||||
const valuePath = (value as { path?: string | null } | undefined)?.path
|
||||
return valuePath?.trim() || storagePath || undefined
|
||||
}
|
||||
|
||||
function scriptDraftToWorkspaceItem(
|
||||
storagePath: string,
|
||||
draft: NewScript,
|
||||
isDraft = true
|
||||
): WorkspaceItem | undefined {
|
||||
const path = getItemPath(storagePath, draft)
|
||||
if (!path) return undefined
|
||||
|
||||
return {
|
||||
type: 'script',
|
||||
path,
|
||||
@@ -174,7 +186,7 @@ function getFlowSchema(value: unknown): Record<string, any> | null {
|
||||
}
|
||||
|
||||
function flowDraftToWorkspaceItem(
|
||||
path: string,
|
||||
storagePath: string,
|
||||
draft: unknown,
|
||||
isDraft = true
|
||||
): WorkspaceItem | undefined {
|
||||
@@ -182,6 +194,8 @@ function flowDraftToWorkspaceItem(
|
||||
|
||||
const value = getFlowValue(draft.value) ?? getFlowValue(draft)
|
||||
if (!value) return undefined
|
||||
const path = getItemPath(storagePath, draft)
|
||||
if (!path) return undefined
|
||||
|
||||
return {
|
||||
type: 'flow',
|
||||
@@ -199,11 +213,14 @@ function flowDraftToWorkspaceItem(
|
||||
}
|
||||
|
||||
function appDraftToWorkspaceItem(
|
||||
path: string,
|
||||
storagePath: string,
|
||||
draft: AppDraftValue,
|
||||
isDraft = true
|
||||
): WorkspaceItem {
|
||||
): WorkspaceItem | undefined {
|
||||
const value = normalizeAppDraftValue(draft)
|
||||
const path = getItemPath(storagePath, value)
|
||||
if (!path) return undefined
|
||||
|
||||
return {
|
||||
type: 'app',
|
||||
path,
|
||||
@@ -214,10 +231,13 @@ function appDraftToWorkspaceItem(
|
||||
}
|
||||
|
||||
function scheduleDraftToWorkspaceItem(
|
||||
path: string,
|
||||
storagePath: string,
|
||||
draft: NewSchedule,
|
||||
isDraft = true
|
||||
): WorkspaceItem {
|
||||
): WorkspaceItem | undefined {
|
||||
const path = getItemPath(storagePath, draft)
|
||||
if (!path) return undefined
|
||||
|
||||
return {
|
||||
type: 'schedule',
|
||||
path,
|
||||
@@ -229,10 +249,13 @@ function scheduleDraftToWorkspaceItem(
|
||||
|
||||
function triggerDraftToWorkspaceItem(
|
||||
kind: TriggerKind,
|
||||
path: string,
|
||||
storagePath: string,
|
||||
draft: TriggerRequestBody,
|
||||
isDraft = true
|
||||
): WorkspaceItem {
|
||||
): WorkspaceItem | undefined {
|
||||
const path = getItemPath(storagePath, draft)
|
||||
if (!path) return undefined
|
||||
|
||||
return {
|
||||
type: 'trigger',
|
||||
triggerKind: kind,
|
||||
@@ -244,10 +267,13 @@ function triggerDraftToWorkspaceItem(
|
||||
}
|
||||
|
||||
function resourceDraftToWorkspaceItem(
|
||||
path: string,
|
||||
storagePath: string,
|
||||
draft: CreateResource,
|
||||
isDraft = true
|
||||
): WorkspaceItem {
|
||||
): WorkspaceItem | undefined {
|
||||
const path = getItemPath(storagePath, draft)
|
||||
if (!path) return undefined
|
||||
|
||||
return {
|
||||
type: 'resource',
|
||||
path,
|
||||
@@ -258,10 +284,13 @@ function resourceDraftToWorkspaceItem(
|
||||
}
|
||||
|
||||
function variableDraftToWorkspaceItem(
|
||||
path: string,
|
||||
storagePath: string,
|
||||
draft: CreateVariable,
|
||||
isDraft = true
|
||||
): WorkspaceItem {
|
||||
): WorkspaceItem | undefined {
|
||||
const path = getItemPath(storagePath, draft)
|
||||
if (!path) return undefined
|
||||
|
||||
return {
|
||||
type: 'variable',
|
||||
path,
|
||||
@@ -301,6 +330,32 @@ function sharedDraftEntryToWorkspaceItem(
|
||||
}
|
||||
}
|
||||
|
||||
type SharedDraftLookup = {
|
||||
storagePath: string
|
||||
value: unknown
|
||||
}
|
||||
|
||||
function findSharedDraft(
|
||||
workspace: string,
|
||||
type: SharedWorkspaceItemType,
|
||||
path: string,
|
||||
triggerKind?: TriggerKind
|
||||
): SharedDraftLookup | undefined {
|
||||
const itemKind = sharedDraftKind(type, triggerKind)
|
||||
if (!itemKind) return undefined
|
||||
|
||||
const direct = UserDraft.get(itemKind, path, { workspace })
|
||||
if (direct !== undefined) return { storagePath: path, value: direct }
|
||||
|
||||
for (const entry of UserDraft.list({ workspace, itemKinds: [itemKind] })) {
|
||||
if (getItemPath(entry.path, entry.value) === path) {
|
||||
return { storagePath: entry.path, value: entry.value }
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
function getSharedDraft(
|
||||
workspace: string,
|
||||
type: SharedWorkspaceItemType,
|
||||
@@ -308,28 +363,31 @@ function getSharedDraft(
|
||||
triggerKind?: TriggerKind,
|
||||
isDraft = true
|
||||
): WorkspaceItem | undefined {
|
||||
const itemKind = sharedDraftKind(type, triggerKind)
|
||||
if (!itemKind) return undefined
|
||||
const draft = UserDraft.get(itemKind, path, { workspace })
|
||||
if (draft === undefined) return undefined
|
||||
const draft = findSharedDraft(workspace, type, path, triggerKind)
|
||||
if (!draft) return undefined
|
||||
|
||||
switch (type) {
|
||||
case 'script':
|
||||
return scriptDraftToWorkspaceItem(path, draft as NewScript, isDraft)
|
||||
return scriptDraftToWorkspaceItem(draft.storagePath, draft.value as NewScript, isDraft)
|
||||
case 'flow':
|
||||
return flowDraftToWorkspaceItem(path, draft, isDraft)
|
||||
return flowDraftToWorkspaceItem(draft.storagePath, draft.value, isDraft)
|
||||
case 'app':
|
||||
return appDraftToWorkspaceItem(path, draft as AppDraftValue, isDraft)
|
||||
return appDraftToWorkspaceItem(draft.storagePath, draft.value as AppDraftValue, isDraft)
|
||||
case 'schedule':
|
||||
return scheduleDraftToWorkspaceItem(path, draft as NewSchedule, isDraft)
|
||||
return scheduleDraftToWorkspaceItem(draft.storagePath, draft.value as NewSchedule, isDraft)
|
||||
case 'trigger':
|
||||
return triggerKind
|
||||
? triggerDraftToWorkspaceItem(triggerKind, path, draft as TriggerRequestBody, isDraft)
|
||||
? triggerDraftToWorkspaceItem(
|
||||
triggerKind,
|
||||
draft.storagePath,
|
||||
draft.value as TriggerRequestBody,
|
||||
isDraft
|
||||
)
|
||||
: undefined
|
||||
case 'resource':
|
||||
return resourceDraftToWorkspaceItem(path, draft as CreateResource, isDraft)
|
||||
return resourceDraftToWorkspaceItem(draft.storagePath, draft.value as CreateResource, isDraft)
|
||||
case 'variable':
|
||||
return variableDraftToWorkspaceItem(path, draft as CreateVariable, isDraft)
|
||||
return variableDraftToWorkspaceItem(draft.storagePath, draft.value as CreateVariable, isDraft)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,7 +399,8 @@ function deleteSharedDraft(
|
||||
): void {
|
||||
const itemKind = sharedDraftKind(type, triggerKind)
|
||||
if (!itemKind) return
|
||||
UserDraft.remove(itemKind, path, { workspace })
|
||||
const draft = findSharedDraft(workspace, type, path, triggerKind)
|
||||
UserDraft.remove(itemKind, draft?.storagePath ?? path, { workspace })
|
||||
}
|
||||
|
||||
export function getGlobalDraft(
|
||||
@@ -373,6 +432,18 @@ export function getGlobalCurrentItem(
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function getGlobalDraftStoragePath(
|
||||
workspace: string,
|
||||
type: WorkspaceItemType,
|
||||
path: string,
|
||||
triggerKind?: TriggerKind
|
||||
): string | undefined {
|
||||
if (isSharedWorkspaceItemType(type)) {
|
||||
return findSharedDraft(workspace, type, path, triggerKind)?.storagePath
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function listGlobalDrafts(workspace: string): WorkspaceItem[] {
|
||||
const drafts = new Map<string, WorkspaceItem>()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user