From bb22fcb3a4e66d723310497f7fd4e9918fcd1634 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 20 Jan 2026 08:37:11 +0000 Subject: [PATCH] raw app improvements --- cli/src/commands/app/app.ts | 2 ++ cli/src/commands/app/dev.ts | 8 ++++-- cli/src/commands/sync/sync.ts | 28 +++++++++++++++++++ frontend/scripts/untar_ui_builder.js | 2 +- .../raw_apps/RawAppEditorHeader.svelte | 6 ++++ .../(root)/(logged)/user/cli/+page.svelte | 6 ++-- 6 files changed, 47 insertions(+), 5 deletions(-) diff --git a/cli/src/commands/app/app.ts b/cli/src/commands/app/app.ts index a37ac6af3d..8eedc2a2c2 100644 --- a/cli/src/commands/app/app.ts +++ b/cli/src/commands/app/app.ts @@ -35,6 +35,8 @@ function respecializeFields(fields: Record) { if (typeof v == "object") { if (v.value !== undefined) { fields[k] = { value: v.value, type: "static" }; + } else if (v.ctx !== undefined) { + fields[k] = { ctx: v.ctx, type: "ctx" }; } else if (v.expr !== undefined) { fields[k] = { expr: v.expr, diff --git a/cli/src/commands/app/dev.ts b/cli/src/commands/app/dev.ts index c2412fe282..86d335c5ac 100644 --- a/cli/src/commands/app/dev.ts +++ b/cli/src/commands/app/dev.ts @@ -28,7 +28,7 @@ import * as wmill from "../../../gen/services.gen.ts"; import { resolveWorkspace } from "../../core/context.ts"; import { requireLogin } from "../../core/auth.ts"; import { GLOBAL_CONFIG_OPT } from "../../core/conf.ts"; -import { replaceInlineScripts } from "./app.ts"; +import { replaceInlineScripts, repopulateFields } from "./app.ts"; import { Runnable } from "./metadata.ts"; import { APP_BACKEND_FOLDER, @@ -1439,6 +1439,7 @@ async function loadRunnables(): Promise> { convertRunnablesToApiFormat(runnables); replaceInlineScripts(runnables, backendPath + SEP, true); + repopulateFields(runnables); return runnables; } catch (error: any) { @@ -1462,11 +1463,14 @@ async function executeRunnable( force_viewer_allow_user_resources: [], }; - // Handle static fields + // Handle fields (static, ctx, user) if (runnable.fields) { for (const [key, field] of Object.entries(runnable.fields)) { if (field?.type === "static") { requestBody.force_viewer_static_fields[key] = field.value; + } else if (field?.type === "ctx" && field?.ctx) { + // Convert ctx fields to $ctx:property format for backend resolution + requestBody.args[key] = `$ctx:${field.ctx}`; } if (field?.type === "user" && field?.allowUserResources) { requestBody.force_viewer_allow_user_resources.push(key); diff --git a/cli/src/commands/sync/sync.ts b/cli/src/commands/sync/sync.ts index 5429d4f8de..43e408603e 100644 --- a/cli/src/commands/sync/sync.ts +++ b/cli/src/commands/sync/sync.ts @@ -932,6 +932,29 @@ function ZipFSElement( }; } + // Helper to simplify fields for YAML output + // { type: 'static', value: X } -> { value: X } + // { type: 'ctx', ctx: X } -> { ctx: X } + function simplifyFields(fields: Record | undefined) { + if (!fields) return undefined; + const simplified: Record = {}; + for (const [k, v] of Object.entries(fields)) { + if (typeof v === "object" && v !== null) { + if (v.type === "static" && v.value !== undefined) { + simplified[k] = { value: v.value }; + } else if (v.type === "ctx" && v.ctx !== undefined) { + simplified[k] = { ctx: v.ctx }; + } else { + // Keep other field types as-is + simplified[k] = v; + } + } else { + simplified[k] = v; + } + } + return simplified; + } + // Yield each runnable as a separate YAML file in the backend folder // For inline scripts, simplify the YAML - inlineScript is not needed since // content/lock/language can be derived from sibling files @@ -969,6 +992,11 @@ function ZipFSElement( simplifiedRunnable = runnableObj; } + // Simplify fields for cleaner YAML output + if (simplifiedRunnable.fields) { + simplifiedRunnable.fields = simplifyFields(simplifiedRunnable.fields); + } + yield { isDirectory: false, path: path.join( diff --git a/frontend/scripts/untar_ui_builder.js b/frontend/scripts/untar_ui_builder.js index 8108575ccc..e8e4b9a162 100644 --- a/frontend/scripts/untar_ui_builder.js +++ b/frontend/scripts/untar_ui_builder.js @@ -20,7 +20,7 @@ console.log('Running postinstall for root project'); import { x } from 'tar' -const tarUrl = 'https://pub-06154ed168a24e73a86ab84db6bf15d8.r2.dev/ui_builder-e2864ec.tar.gz' +const tarUrl = 'https://pub-06154ed168a24e73a86ab84db6bf15d8.r2.dev/ui_builder-c37c2f6.tar.gz' const outputTarPath = path.join(process.cwd(), 'ui_builder.tar.gz') const extractTo = path.join(process.cwd(), 'static/ui_builder/') diff --git a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte index ec9eb07397..7232318d8c 100644 --- a/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte +++ b/frontend/src/lib/components/raw_apps/RawAppEditorHeader.svelte @@ -162,6 +162,9 @@ sendUserToast(`App hasn't been loaded yet`, true) return } + if (!policy.execution_mode) { + policy.execution_mode = 'publisher' + } await computeTriggerables() try { const { js, css } = await getBundle() @@ -266,6 +269,9 @@ } const { js, css } = await getBundle() await computeTriggerables() + if (!policy.execution_mode) { + policy.execution_mode = 'publisher' + } await AppService.updateAppRaw({ workspace: $workspaceStore!, path: appPath!, diff --git a/frontend/src/routes/(root)/(logged)/user/cli/+page.svelte b/frontend/src/routes/(root)/(logged)/user/cli/+page.svelte index 6cf654a957..42125fa36e 100644 --- a/frontend/src/routes/(root)/(logged)/user/cli/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/user/cli/+page.svelte @@ -4,7 +4,7 @@ import { base } from '$lib/base' import CenteredModal from '$lib/components/CenteredModal.svelte' import { Button } from '$lib/components/common' - import { workspaceStore } from '$lib/stores' + import { userStore, workspaceStore } from '$lib/stores' let port = Number($page.url.searchParams.get('port')) let host: string = $page.url.searchParams.get('host') || 'localhost' @@ -12,9 +12,11 @@ port = port == 0 || Number.isNaN(port) ? 80 : port async function authorizeToken(): Promise { + const username = $userStore?.username + const label = username ? `cli-${username}` : 'cli' const newToken = await UserService.createToken({ requestBody: { - label: 'External tool token', + label, expiration: undefined } })