mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-05 00:02:24 +00:00
fix: turn the default raw app into a feature tour (#11417)
* feat: turn the default raw app into a feature tour Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: don't present ctx fields as unforgeable in the starter app Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: format raw app templates Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
05bcc361af
commit
83b8954ae2
@@ -53,8 +53,7 @@ import { evalValue } from '$lib/components/flows/utils.svelte'
|
||||
import { updateRawAppPolicy } from '$lib/components/raw_apps/rawAppPolicy'
|
||||
import {
|
||||
FRAMEWORK_TEMPLATES,
|
||||
STARTER_RUNNABLE,
|
||||
STARTER_RUNNABLE_KEY,
|
||||
STARTER_RUNNABLES,
|
||||
type FrameworkKey
|
||||
} from '$lib/components/raw_apps/templates'
|
||||
import {
|
||||
@@ -6411,13 +6410,13 @@ async function initApp(
|
||||
const value: AppDraftValue = {
|
||||
summary,
|
||||
files: { ...template },
|
||||
runnables: { [STARTER_RUNNABLE_KEY]: { ...STARTER_RUNNABLE } }
|
||||
runnables: structuredClone(STARTER_RUNNABLES)
|
||||
}
|
||||
await recomputeAppPolicy(value)
|
||||
const result = await saveAppDraft(workspace, path, value)
|
||||
return finishAppDraftWrite(result, ctx, () => ({
|
||||
content: `Saved app "${path}" draft (${framework})`,
|
||||
message: `Initialized a per-user draft app "${path}" from the ${framework} template with a starter runnable "${STARTER_RUNNABLE_KEY}" (saved server-side, not a deployed workspace item). Use write_app_file / write_app_runnable to evolve it.`
|
||||
message: `Initialized a per-user draft app "${path}" from the ${framework} template (saved server-side, not a deployed workspace item). The template is a demo tour with starter runnables ${Object.keys(STARTER_RUNNABLES).join(', ')}: replace its UI and delete the runnables the app does not need (delete_app_runnable). Use write_app_file / write_app_runnable to evolve it.`
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,23 @@ describe('genWmillTs', () => {
|
||||
expect(dts).toContain('myflow: (args: { string_input: string }) => Promise<any>;')
|
||||
})
|
||||
|
||||
it('leaves ctx fields out of the args type, the server fills them', () => {
|
||||
const runnables: Record<string, Runnable> = {
|
||||
myflow: {
|
||||
type: 'path',
|
||||
runType: 'flow',
|
||||
path: 'u/dev/my_flow',
|
||||
name: 'My flow',
|
||||
schema: flowSchema,
|
||||
fields: {
|
||||
string_input: { type: 'ctx', ctx: 'username', fieldType: 'text' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(genWmillTs(runnables)).toContain('myflow: (args: { count?: number }) => Promise<any>;')
|
||||
})
|
||||
|
||||
it('quotes flow input names that are not valid identifiers', () => {
|
||||
const runnables: Record<string, Runnable> = {
|
||||
myflow: {
|
||||
|
||||
@@ -291,8 +291,14 @@ export function unsandboxedRawAppHtml(
|
||||
</html>`
|
||||
}
|
||||
|
||||
function removeStaticFields(schema: Schema, fields: Record<string, { type: string }>): Schema {
|
||||
const staticFields = Object.keys(fields).filter((k) => fields[k].type == 'static')
|
||||
// The app fills static and ctx fields itself, so the frontend never passes them.
|
||||
function removeServerFilledFields(
|
||||
schema: Schema,
|
||||
fields: Record<string, { type: string }>
|
||||
): Schema {
|
||||
const staticFields = Object.keys(fields).filter(
|
||||
(k) => fields[k].type == 'static' || fields[k].type == 'ctx'
|
||||
)
|
||||
return {
|
||||
...schema,
|
||||
properties: {
|
||||
@@ -307,14 +313,16 @@ function hiddenRunnableToTsType(runnable: Runnable) {
|
||||
if (isRunnableByName(runnable)) {
|
||||
if (runnable?.inlineScript?.schema) {
|
||||
return schemaToTsType(
|
||||
removeStaticFields(runnable?.inlineScript?.schema, runnable?.fields ?? {})
|
||||
removeServerFilledFields(runnable?.inlineScript?.schema, runnable?.fields ?? {})
|
||||
)
|
||||
} else {
|
||||
return '{}'
|
||||
}
|
||||
} else if (isRunnableByPath(runnable)) {
|
||||
if (runnable?.schema) {
|
||||
return schemaToTsType(removeStaticFields(runnable.schema as Schema, runnable?.fields ?? {}))
|
||||
return schemaToTsType(
|
||||
removeServerFilledFields(runnable.schema as Schema, runnable?.fields ?? {})
|
||||
)
|
||||
} else {
|
||||
return '{}'
|
||||
}
|
||||
|
||||
@@ -30,11 +30,7 @@
|
||||
import RawAppTemplatePicker, {
|
||||
type RawAppTemplatePickerResult
|
||||
} from '$lib/components/raw_apps/RawAppTemplatePicker.svelte'
|
||||
import {
|
||||
react19Template,
|
||||
STARTER_RUNNABLE,
|
||||
STARTER_RUNNABLE_KEY
|
||||
} from '$lib/components/raw_apps/templates'
|
||||
import { react19Template, STARTER_RUNNABLES } from '$lib/components/raw_apps/templates'
|
||||
import { aiChatManager, AIMode } from '$lib/components/copilot/chat/AIChatManager.svelte'
|
||||
|
||||
type RawAppDraft = {
|
||||
@@ -273,7 +269,7 @@
|
||||
// Seed the React 19 template so the editor has a usable state even if the
|
||||
// user dismisses the picker without selecting.
|
||||
const seedFiles = { ...react19Template }
|
||||
const seedRunnables = { [STARTER_RUNNABLE_KEY]: STARTER_RUNNABLE }
|
||||
const seedRunnables = structuredClone(STARTER_RUNNABLES)
|
||||
savedApp = {
|
||||
summary: '',
|
||||
value: { files: seedFiles as any, runnables: seedRunnables as any },
|
||||
@@ -524,7 +520,7 @@
|
||||
|
||||
function onTemplatePickerStart(result: RawAppTemplatePickerResult, withPrompt: boolean) {
|
||||
files = { ...result.files }
|
||||
runnables = { ...result.runnables, [STARTER_RUNNABLE_KEY]: STARTER_RUNNABLE }
|
||||
runnables = { ...result.runnables, ...structuredClone(STARTER_RUNNABLES) }
|
||||
data = result.data
|
||||
summary = result.summary
|
||||
policy = result.policy
|
||||
|
||||
Reference in New Issue
Block a user