From a424edf726b9c5d5a3d4636d2d3719ab217022c1 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Fri, 3 Jan 2025 04:44:27 +0100 Subject: [PATCH] before esbuild refactor --- frontend/src/lib/components/Editor.svelte | 118 +++-- .../helpers/RunnableComponent.svelte | 130 +++-- .../components/helpers/executeRunnable.ts | 50 ++ .../apps/editor/AppEditorHeader.svelte | 305 +----------- .../apps/editor/AppJobsDrawer.svelte | 299 ++++++++++++ .../components/apps/editor/AppTimeline.svelte | 13 +- .../InlineScriptEditor.svelte | 1 + .../InlineScriptEditorDrawer.svelte | 3 +- frontend/src/lib/components/apps/types.ts | 27 +- .../lib/components/common/modal/Modal.svelte | 36 +- .../lib/components/common/table/AppRow.svelte | 15 +- .../src/lib/components/icons/CssIcon.svelte | 0 .../components/icons/JavaScriptIcon.svelte | 16 + .../src/lib/components/icons/JsonIcon.svelte | 11 + .../src/lib/components/icons/ReactIcon.svelte | 18 + .../lib/components/icons/SvelteIcon.svelte | 15 + .../src/lib/components/icons/VueIcon.svelte | 13 + .../components/raw_apps/FileEditorIcon.svelte | 26 + .../raw_apps/RawAppBackgroundRunner.svelte | 86 ++++ .../components/raw_apps/RawAppEditor.svelte | 449 ++++++++++++++---- .../raw_apps/RawAppEditorHeader.svelte | 48 +- .../raw_apps/RawAppInlineScripRunnable.svelte | 2 +- .../components/raw_apps/RawAppPreview.svelte | 23 + frontend/src/lib/components/raw_apps/utils.ts | 82 ++++ frontend/src/lib/editorUtils.ts | 14 +- frontend/src/lib/scripts.ts | 13 +- frontend/src/lib/svelteMonarch.ts | 313 ++++++++++++ .../src/routes/(root)/(logged)/+layout.svelte | 9 +- .../(logged)/apps/edit/[...path]/+page.svelte | 15 +- .../(root)/(logged)/apps_raw/add/+page.svelte | 161 +++++-- .../(root)/(logged)/apps_raw/add/templates.ts | 160 +++++++ .../(logged)/apps_raw/edit/[...path]/+page.js | 5 + .../apps_raw/edit/[...path]/+page.svelte | 226 +++++++++ .../(logged)/apps_raw/get/[...path]/+page.js | 5 + .../apps_raw/get/[...path]/+page.svelte | 55 +++ .../[workspace]/[...version]/+page.js | 5 + .../[workspace]/[...version]/+page.svelte | 11 + frontend/static/sandpack | 1 + 38 files changed, 2188 insertions(+), 591 deletions(-) create mode 100644 frontend/src/lib/components/apps/components/helpers/executeRunnable.ts create mode 100644 frontend/src/lib/components/apps/editor/AppJobsDrawer.svelte create mode 100644 frontend/src/lib/components/icons/CssIcon.svelte create mode 100644 frontend/src/lib/components/icons/JavaScriptIcon.svelte create mode 100644 frontend/src/lib/components/icons/JsonIcon.svelte create mode 100644 frontend/src/lib/components/icons/ReactIcon.svelte create mode 100644 frontend/src/lib/components/icons/SvelteIcon.svelte create mode 100644 frontend/src/lib/components/icons/VueIcon.svelte create mode 100644 frontend/src/lib/components/raw_apps/FileEditorIcon.svelte create mode 100644 frontend/src/lib/components/raw_apps/RawAppBackgroundRunner.svelte create mode 100644 frontend/src/lib/components/raw_apps/RawAppPreview.svelte create mode 100644 frontend/src/lib/components/raw_apps/utils.ts create mode 100644 frontend/src/lib/svelteMonarch.ts create mode 100644 frontend/src/routes/(root)/(logged)/apps_raw/add/templates.ts create mode 100644 frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.js create mode 100644 frontend/src/routes/(root)/(logged)/apps_raw/edit/[...path]/+page.svelte create mode 100644 frontend/src/routes/(root)/(logged)/apps_raw/get/[...path]/+page.js create mode 100644 frontend/src/routes/(root)/(logged)/apps_raw/get/[...path]/+page.svelte create mode 100644 frontend/src/routes/apps_raw/[workspace]/[...version]/+page.js create mode 100644 frontend/src/routes/apps_raw/[workspace]/[...version]/+page.svelte create mode 120000 frontend/static/sandpack diff --git a/frontend/src/lib/components/Editor.svelte b/frontend/src/lib/components/Editor.svelte index 5167e899d4a71..59ce3eb4c650b 100644 --- a/frontend/src/lib/components/Editor.svelte +++ b/frontend/src/lib/components/Editor.svelte @@ -177,6 +177,7 @@ import { parseTypescriptDeps } from '$lib/relative_imports' import type { AiProviderTypes } from './copilot/lib' import { scriptLangToEditorLang } from '$lib/scripts' + import * as htmllang from '$lib/svelteMonarch' // import EditorTheme from './EditorTheme.svelte' @@ -203,10 +204,11 @@ export let args: Record | undefined = undefined export let useWebsockets: boolean = true export let small = false - export let scriptLang: Preview['language'] | 'bunnative' | 'tsx' | 'json' + export let scriptLang: Preview['language'] | 'bunnative' | 'tsx' | 'json' | undefined export let disabled: boolean = false export let lineNumbersMinChars = 3 - export let files: Record | undefined = {} + export let files: Record | undefined = {} + export let extraLib: string | undefined = undefined let lang = scriptLangToEditorLang(scriptLang) $: lang = scriptLangToEditorLang(scriptLang) @@ -214,8 +216,6 @@ let filePath = computePath(path) $: filePath = computePath(path) - let models: Record = {} - let initialPath: string | undefined = path $: path != initialPath && @@ -241,20 +241,29 @@ buildWorkerDefinition() function computeUri(filePath: string, scriptLang: string | undefined) { + let file + if (filePath.includes('.')) { + file = filePath + } else { + file = `${filePath}.${scriptLang == 'tsx' ? 'tsx' : langToExt(lang)}` + } + if (file.startsWith('/')) { + file = file.slice(1) + } return !['deno', 'go', 'python3'].includes(scriptLang ?? '') - ? `file:///${filePath}.${scriptLang == 'tsx' ? 'tsx' : langToExt(lang)}` - : `file:///tmp/monaco/${filePath}.${langToExt(lang)}` + ? `file:///${file}` + : `file:///tmp/monaco/${file}` } function computePath(path: string | undefined): string { if ( ['deno', 'go', 'python3'].includes(scriptLang ?? '') || path == '' || - path == undefined || - path.startsWith('/') + path == undefined //||path.startsWith('/') ) { return randomHash() } else { + console.log('path', path) return path as string } } @@ -263,15 +272,17 @@ if (editor) { const uri = mUri.parse(path) console.log('switching to file', path, lang) - if (models[path]) { + // vscode.workspace.fs.writeFile(uri, new TextEncoder().encode(value)) + let nmodel = meditor.getModel(uri) + if (nmodel) { console.log('using existing model', path) - editor.setModel(models[path]) + editor.setModel(nmodel) } else { console.log('creating model', path) - const model = meditor.createModel(value, lang, uri) - models[path] = model - editor.setModel(model) + nmodel = meditor.createModel(value, lang, uri) + editor.setModel(nmodel) } + model = nmodel } } @@ -1135,8 +1146,55 @@ } } + $: files && model && onFileChanges() + + let svelteRegistered = false + function onFileChanges() { + if (files && Object.keys(files).find((x) => x.endsWith('.svelte')) != undefined) { + if (!svelteRegistered) { + svelteRegistered = true + languages.register({ + id: 'svelte', + extensions: ['.svelte'], + aliases: ['Svelte', 'svelte'], + mimetypes: ['application/svelte'] + }) + languages.setLanguageConfiguration('svelte', htmllang.conf as any) + + languages.setMonarchTokensProvider('svelte', htmllang.language as any) + } + } + if (files && model) { + for (const [path, { code, readonly }] of Object.entries(files)) { + const luri = mUri.file(path) + console.log('checking file', model.uri.toString(), luri.toString()) + if (luri.toString() != model.uri.toString()) { + let nmodel = meditor.getModel(luri) + if (nmodel == undefined) { + const lmodel = meditor.createModel(code, extToLang(path?.split('.')?.pop()!), luri) + if (readonly) { + lmodel.onDidChangeContent((evt) => { + // This will effectively undo any new edits + if (lmodel.getValue() != code && code) { + lmodel.setValue(code) + } + }) + } + } else { + const lmodel = meditor.getModel(luri) + if (lmodel && code) { + lmodel.setValue(code) + } + } + } + } + } + } + let timeoutModel: NodeJS.Timeout | undefined = undefined async function loadMonaco() { + console.log('path', uri) + try { console.log("Loading Monaco's language client") await initializeVscode('editor') @@ -1145,6 +1203,19 @@ console.log('error initializing services', e) } + // vscode.languages.registerDefinitionProvider('*', { + // provideDefinition(document, position, token) { + // // Get the word under the cursor (this will be the import or function being clicked) + // const wordRange = document.getWordRangeAtPosition(position) + // const word = document.getText(wordRange) + + // // Do something with the word (for example, log it or handle it) + // console.log('Clicked on import or symbol:', word) + + // // Optionally, you can also return a definition location + // return null // If you don't want to override the default behavior + // } + // }) // console.log('bef ready') // console.log('af ready') @@ -1152,7 +1223,6 @@ try { model = meditor.createModel(code, lang, mUri.parse(uri)) - models[path ?? ''] = model } catch (err) { console.log('model already existed', err) const nmodel = meditor.getModel(mUri.parse(uri)) @@ -1163,17 +1233,7 @@ } model.updateOptions(lang == 'python' ? { tabSize: 4, insertSpaces: true } : updateOptions) - if (files) { - for (const [path, { code }] of Object.entries(files)) { - const luri = mUri.file(path) - if (luri.toString() != model.uri.toString()) { - if (!models[path] && meditor.getModel(luri) == undefined) { - const lmodel = meditor.createModel(code, extToLang(path?.split('.')?.pop()!), luri) - models[path] = lmodel - } - } - } - } + onFileChanges() editor = meditor.create(divEl as HTMLDivElement, { ...editorConfig(code, lang, automaticLayout, fixedOverflowWidgets), @@ -1194,7 +1254,7 @@ timeoutModel = setTimeout(() => { let ncode = getCode() code = ncode - dispatch('change', code) + dispatch('change', ncode) }, 500) ataModel && clearTimeout(ataModel) @@ -1235,7 +1295,6 @@ !websocketAlive.go && !websocketInterval ) { - console.log('reconnecting to language servers on focus') reloadWebsocket() } }) @@ -1263,6 +1322,11 @@ } async function setTypescriptExtraLibsATA() { + if (extraLib) { + const uri = mUri.parse('file:///extraLib.d.ts') + languages.typescript.typescriptDefaults.addExtraLib(extraLib, uri.toString()) + } + console.log('scriptLang ATA', scriptLang) if (lang === 'typescript' && (scriptLang == 'bun' || scriptLang == 'tsx') && ata == undefined) { const hostname = getHostname() diff --git a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte index 66dabfe560e3b..9fe086c18aafe 100644 --- a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte +++ b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte @@ -3,7 +3,7 @@ import Alert from '$lib/components/common/alert/Alert.svelte' import LightweightSchemaForm from '$lib/components/LightweightSchemaForm.svelte' import Popover from '$lib/components/Popover.svelte' - import { AppService, type ExecuteComponentData } from '$lib/gen' + import { type ExecuteComponentData } from '$lib/gen' import { classNames, defaultIfEmptyString, emptySchema, sendUserToast } from '$lib/utils' import { deepEqual } from 'fast-equals' import { Bug } from 'lucide-svelte' @@ -27,6 +27,7 @@ import RefreshButton from '$lib/components/apps/components/helpers/RefreshButton.svelte' import { ctxRegex } from '../../utils' import { computeWorkspaceS3FileInputPolicy } from '../../editor/appUtilsS3' + import { executeRunnable } from './executeRunnable' // Component props export let id: string @@ -329,84 +330,22 @@ try { jobId = await resultJobLoader?.abstractRun(async () => { - const nonStaticRunnableInputs = dynamicArgsOverride ?? {} - const staticRunnableInputs = {} - const allowUserResources: string[] = [] - for (const k of Object.keys(fields ?? {})) { - let field = fields[k] - if (field?.type == 'static' && fields[k]) { - if (isEditor) { - staticRunnableInputs[k] = field.value - } - } else if (field?.type == 'user') { - nonStaticRunnableInputs[k] = args?.[k] - if (isEditor && field.allowUserResources) { - allowUserResources.push(k) - } - } else if (field?.type == 'eval' || (field?.type == 'evalv2' && inputValues[k])) { - const ctxMatch = field.expr.match(ctxRegex) - if (ctxMatch) { - nonStaticRunnableInputs[k] = '$ctx:' + ctxMatch[1] - } else { - nonStaticRunnableInputs[k] = await inputValues[k]?.computeExpr() - } - if (isEditor && field?.type == 'evalv2' && field.allowUserResources) { - allowUserResources.push(k) - } - } else { - if (isEditor && field?.type == 'connected' && field.allowUserResources) { - allowUserResources.push(k) - } - nonStaticRunnableInputs[k] = runnableInputValues[k] - } - } - - const oneOfRunnableInputs = isEditor ? collectOneOfFields(fields, $app) : {} - - const requestBody: ExecuteComponentData['requestBody'] = { - args: nonStaticRunnableInputs, - component: id, - force_viewer_static_fields: !isEditor ? undefined : staticRunnableInputs, - force_viewer_one_of_fields: !isEditor ? undefined : oneOfRunnableInputs, - force_viewer_allow_user_resources: !isEditor ? undefined : allowUserResources - } - - if (runnable?.type === 'runnableByName') { - const { inlineScript } = inlineScriptOverride - ? { inlineScript: inlineScriptOverride } - : runnable - - if (inlineScript) { - if (inlineScript.id !== undefined) { - requestBody['id'] = inlineScript.id - } - requestBody['raw_code'] = { - content: inlineScript.id === undefined ? inlineScript.content : '', - language: inlineScript.language ?? '', - path: $appPath + '/' + inlineScript.id, - lock: inlineScript.id === undefined ? inlineScript.lock : undefined, - cache_ttl: inlineScript.cache_ttl - } - } - } else if (runnable?.type === 'runnableByPath') { - const { path, runType } = runnable - requestBody['path'] = runType !== 'hubscript' ? `${runType}/${path}` : `script/${path}` - } - - if ($app.version !== undefined) { - requestBody['version'] = $app.version - } - - const uuid = await AppService.executeComponent({ + const uuid = await executeRunnable( + runnable, workspace, - path: defaultIfEmptyString($appPath, `u/${$userStore?.username ?? 'unknown'}/newapp`), - requestBody - }) + $app.version, + $userStore?.username, + $appPath, + id, + await buildRequestBody(dynamicArgsOverride), + inlineScriptOverride + ) if (isEditor) { addJob(uuid) } return uuid }, callbacks) + if (setRunnableJobEditorPanel && editorContext) { editorContext.runnableJobEditorPanel.update((p) => { return { @@ -428,6 +367,51 @@ } type Callbacks = { done: (x: any) => void; cancel: () => void; error: (e: any) => void } + export async function buildRequestBody(dynamicArgsOverride: Record | undefined) { + const nonStaticRunnableInputs = dynamicArgsOverride ?? {} + const staticRunnableInputs = {} + const allowUserResources: string[] = [] + for (const k of Object.keys(fields ?? {})) { + let field = fields[k] + if (field?.type == 'static' && fields[k]) { + if (isEditor) { + staticRunnableInputs[k] = field.value + } + } else if (field?.type == 'user') { + nonStaticRunnableInputs[k] = args?.[k] + if (isEditor && field.allowUserResources) { + allowUserResources.push(k) + } + } else if (field?.type == 'eval' || (field?.type == 'evalv2' && inputValues[k])) { + const ctxMatch = field.expr.match(ctxRegex) + if (ctxMatch) { + nonStaticRunnableInputs[k] = '$ctx:' + ctxMatch[1] + } else { + nonStaticRunnableInputs[k] = await inputValues[k]?.computeExpr() + } + if (isEditor && field?.type == 'evalv2' && field.allowUserResources) { + allowUserResources.push(k) + } + } else { + if (isEditor && field?.type == 'connected' && field.allowUserResources) { + allowUserResources.push(k) + } + nonStaticRunnableInputs[k] = runnableInputValues[k] + } + } + + const oneOfRunnableInputs = isEditor ? collectOneOfFields(fields, $app) : {} + + const requestBody: ExecuteComponentData['requestBody'] = { + args: nonStaticRunnableInputs, + component: id, + force_viewer_static_fields: !isEditor ? undefined : staticRunnableInputs, + force_viewer_one_of_fields: !isEditor ? undefined : oneOfRunnableInputs, + force_viewer_allow_user_resources: !isEditor ? undefined : allowUserResources + } + return requestBody + } + export async function runComponent( noToast = true, inlineScriptOverride?: InlineScript, diff --git a/frontend/src/lib/components/apps/components/helpers/executeRunnable.ts b/frontend/src/lib/components/apps/components/helpers/executeRunnable.ts new file mode 100644 index 0000000000000..397f690ae25e0 --- /dev/null +++ b/frontend/src/lib/components/apps/components/helpers/executeRunnable.ts @@ -0,0 +1,50 @@ +import { AppService, type ExecuteComponentData } from '$lib/gen' +import { defaultIfEmptyString } from '$lib/utils' +import type { Runnable } from '../../inputType' +import type { InlineScript } from '../../types' + +export async function executeRunnable( + runnable: Runnable, + workspace: string, + version: number | undefined, + username: string | undefined, + path: string, + id: string, + requestBody: ExecuteComponentData['requestBody'], + inlineScriptOverride?: InlineScript +) { + let appPath = defaultIfEmptyString(path, `u/${username ?? 'unknown'}/newapp`) + if (runnable?.type === 'runnableByName') { + const { inlineScript } = inlineScriptOverride + ? { inlineScript: inlineScriptOverride } + : runnable + + if (inlineScript) { + if (inlineScript.id !== undefined) { + requestBody['id'] = inlineScript.id + } + requestBody['raw_code'] = { + content: inlineScript.id === undefined ? inlineScript.content : '', + language: inlineScript.language ?? '', + path: appPath + '/' + id, + lock: inlineScript.id === undefined ? inlineScript.lock : undefined, + cache_ttl: inlineScript.cache_ttl + } + } + } else if (runnable?.type === 'runnableByPath') { + const { path, runType } = runnable + requestBody['path'] = runType !== 'hubscript' ? `${runType}/${path}` : `script/${path}` + } + + if (version !== undefined) { + requestBody['version'] = version + } + + const uuid = await AppService.executeComponent({ + workspace, + path: appPath, + requestBody + }) + + return uuid +} diff --git a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte index c242dac762a47..2c839ae7e13e7 100644 --- a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte @@ -1,15 +1,10 @@ + + + + + { + open = false + }} + tooltip="Look at latests runs to spot potential bugs." + documentationLink="https://www.windmill.dev/docs/apps/app_debugging" + > + + + +
+ {#if jobs.length > 0} +
+ {#each jobs ?? [] as id} + {@const selectedJob = jobsById[id]} + {#if selectedJob} + + +
{ + selectedJobId = id + rightColumnSelect = 'detail' + }} + > + {truncateRev(selectedJob.job, 20)} + {selectedJob.component} +
+ {/if} + {/each} +
+ {:else} +
No items
+ {/if} +
+
+
+ +
+
+ + Timeline + Details + +
+ {#if rightColumnSelect == 'timeline'} +
+ +
+ {:else if rightColumnSelect == 'detail'} +
+ {#if selectedJobId} + {#if selectedJobId?.includes('Frontend')} + {@const jobResult = jobsById[selectedJobId]} + {#if jobResult?.error !== undefined} + + + + + +
+ +
+
+
+ {:else if jobResult !== undefined} + + + + + +
+ +
+
+
+ {:else} + + {/if} + {:else} +
+ {#if job?.['running']} +
+ +
+ {/if} + {#if job?.args} +
+ +
+ {/if} + {#if job?.raw_code} +
+ +
+ {/if} + + {#if job?.job_kind !== 'flow' && !isFlowPreview(job?.job_kind)} + {@const jobResult = jobsById[selectedJobId]} + + + + + + {#if job != undefined && 'result' in job && job.result != undefined}
+ {:else if testIsLoading} +
+ {:else if job != undefined && 'result' in job && job?.['result'] == undefined} +
Result is undefined
+ {:else} +
+ +
+ {/if} +
+ {#if jobResult?.transformer} + +
Transformer results
+ {#if job != undefined && 'result' in job && job.result != undefined} +
+ +
+ {:else if testIsLoading} +
+ {:else if job != undefined && 'result' in job && job?.['result'] == undefined} +
Result is undefined
+ {:else} +
+ +
+ {/if} +
+ {/if} +
+ {:else} +
+ +
+ {#if job?.id} + { + job = detail + }} + /> + {:else} + + {/if} +
+ {/if} +
+ {/if} + {:else} +
Select a job to see its details
+ {/if} +
+ {/if} +
+ + + + {#if refreshComponents} + + {/if} + + {#if hasErrors} + + {/if} + + + diff --git a/frontend/src/lib/components/apps/editor/AppTimeline.svelte b/frontend/src/lib/components/apps/editor/AppTimeline.svelte index db298553d4eb2..1563eb8bbfa2d 100644 --- a/frontend/src/lib/components/apps/editor/AppTimeline.svelte +++ b/frontend/src/lib/components/apps/editor/AppTimeline.svelte @@ -1,18 +1,19 @@ {#if menuOpen} - {#await import('$lib/components/apps/editor/AppJsonEditor.svelte')} - - {:then Module} + {#await import('$lib/components/apps/editor/AppJsonEditor.svelte') then Module} {/await} {/if} Edit @@ -110,7 +107,7 @@ size="xs" variant="border" startIcon={{ icon: GitFork }} - href="{base}/apps/add?template={app.path}" + href="{base}/apps{app.raw_app ? '_raw' : ''}/add?template={app.path}" > Fork @@ -157,7 +154,7 @@ { displayName: 'Duplicate/Fork', icon: GitFork, - href: `${base}/apps/add?template=${path}`, + href: `${base}/apps${app.raw_app ? '_raw' : ''}/add?template=${path}`, hide: $userStore?.operator }, { diff --git a/frontend/src/lib/components/icons/CssIcon.svelte b/frontend/src/lib/components/icons/CssIcon.svelte new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/frontend/src/lib/components/icons/JavaScriptIcon.svelte b/frontend/src/lib/components/icons/JavaScriptIcon.svelte new file mode 100644 index 0000000000000..23dce0a347c0b --- /dev/null +++ b/frontend/src/lib/components/icons/JavaScriptIcon.svelte @@ -0,0 +1,16 @@ + + + + + + + diff --git a/frontend/src/lib/components/icons/JsonIcon.svelte b/frontend/src/lib/components/icons/JsonIcon.svelte new file mode 100644 index 0000000000000..2736d80406e9c --- /dev/null +++ b/frontend/src/lib/components/icons/JsonIcon.svelte @@ -0,0 +1,11 @@ + + + diff --git a/frontend/src/lib/components/icons/ReactIcon.svelte b/frontend/src/lib/components/icons/ReactIcon.svelte new file mode 100644 index 0000000000000..fc286af4e04c3 --- /dev/null +++ b/frontend/src/lib/components/icons/ReactIcon.svelte @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/lib/components/icons/SvelteIcon.svelte b/frontend/src/lib/components/icons/SvelteIcon.svelte new file mode 100644 index 0000000000000..6f6dfcc528dbb --- /dev/null +++ b/frontend/src/lib/components/icons/SvelteIcon.svelte @@ -0,0 +1,15 @@ + + + + + + diff --git a/frontend/src/lib/components/icons/VueIcon.svelte b/frontend/src/lib/components/icons/VueIcon.svelte new file mode 100644 index 0000000000000..a04b3dd918057 --- /dev/null +++ b/frontend/src/lib/components/icons/VueIcon.svelte @@ -0,0 +1,13 @@ + + + + + + + diff --git a/frontend/src/lib/components/raw_apps/FileEditorIcon.svelte b/frontend/src/lib/components/raw_apps/FileEditorIcon.svelte new file mode 100644 index 0000000000000..f1419b32c73aa --- /dev/null +++ b/frontend/src/lib/components/raw_apps/FileEditorIcon.svelte @@ -0,0 +1,26 @@ + + +{#if file.endsWith('.tsx')} + +{:else if file.endsWith('.json')} + +{:else if file.endsWith('.ts')} + +{:else if file.endsWith('.js')} + +{:else if file.endsWith('.vue')} + +{:else if file.endsWith('.css')} + # +{:else if file.endsWith('.svelte')} + +{/if} diff --git a/frontend/src/lib/components/raw_apps/RawAppBackgroundRunner.svelte b/frontend/src/lib/components/raw_apps/RawAppBackgroundRunner.svelte new file mode 100644 index 0000000000000..b992d6c99ad12 --- /dev/null +++ b/frontend/src/lib/components/raw_apps/RawAppBackgroundRunner.svelte @@ -0,0 +1,86 @@ + + + diff --git a/frontend/src/lib/components/raw_apps/RawAppEditor.svelte b/frontend/src/lib/components/raw_apps/RawAppEditor.svelte index ecefe0be49eb6..9da3fa51bdef1 100644 --- a/frontend/src/lib/components/raw_apps/RawAppEditor.svelte +++ b/frontend/src/lib/components/raw_apps/RawAppEditor.svelte @@ -1,8 +1,7 @@ -
+ { + if (deletingFile) { + delete files[deletingFile] + files = files + activeFile = Object.keys(files)[0] + updateSandbox() + } + deletingFile = undefined + }} + on:canceled={() => (deletingFile = undefined)} + title="Delete File {deletingFile}" + confirmationText="Delete" +> + Once deleted, the file will not be recoverable + + + +
- - -
-
- - - -
- { - if (e.key === 'Enter') { - createNewFile(name) - } - }} - /> - -
-
-
- {#each Object.keys(files) as file} - + + +
+
+ {#if creatingNewFile} + + { + if (e.key == 'Enter') { + createNewFile(name) + } else if (e.key == 'Escape') { + creatingNewFile = false + } + }} + on:blur={() => { + createNewFile(name) + }} + /> + {:else} +
+ + + +
+ {/if} + {#each Object.keys(files).concat(WMILL_TS).sort() as file} + {#if editingFile == file} + + { + if (e.key == 'Enter') { + editFile(name) + } else if (e.key == 'Escape') { + editingFile = undefined + } + }} + on:blur={() => { + if (editingFile == '') { + editingFile = undefined + } else { + editFile(name) + } + }} + /> + {:else} + + {/if} {/each}
-
- { - onPackageJsonChange() - }} - on:change={() => { - timeout && clearTimeout(timeout) - timeout = setTimeout(() => { - onContentChange() - }, 500) - }} - /> - -