mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-22 00:01:34 +00:00
feat: add editor bar to inline scripts of flows
This commit is contained in:
Generated
+13
@@ -33,6 +33,7 @@
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"openapi-typescript-codegen": "^0.23.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"postcss": "^8.4.5",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"prettier": "^2.7.1",
|
||||
@@ -2886,6 +2887,12 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/path-browserify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"dev": true,
|
||||
@@ -6585,6 +6592,12 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"path-browserify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
|
||||
"dev": true
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"dev": true,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"openapi-typescript-codegen": "^0.23.0",
|
||||
"path-browserify": "^1.0.1",
|
||||
"postcss": "^8.4.5",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"prettier": "^2.7.1",
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService, ScriptService, VariableService } from '$lib/gen'
|
||||
import { sendUserToast } from '$lib/utils'
|
||||
|
||||
import Icon from 'svelte-awesome'
|
||||
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import ItemPicker from './ItemPicker.svelte'
|
||||
import VariableEditor from './VariableEditor.svelte'
|
||||
import ResourceEditor from './ResourceEditor.svelte'
|
||||
import { Highlight } from 'svelte-highlight'
|
||||
import { python, typescript } from 'svelte-highlight/languages'
|
||||
import github from 'svelte-highlight/styles/github'
|
||||
import Modal from './Modal.svelte'
|
||||
import type Editor from './Editor.svelte'
|
||||
|
||||
export let lang: 'python3' | 'deno'
|
||||
export let editor: Editor
|
||||
export let websocketAlive: { pyright: boolean; black: boolean; deno: boolean }
|
||||
|
||||
let variablePicker: ItemPicker
|
||||
let resourcePicker: ItemPicker
|
||||
let scriptPicker: ItemPicker
|
||||
let variableEditor: VariableEditor
|
||||
let resourceEditor: ResourceEditor
|
||||
|
||||
let codeViewer: Modal
|
||||
let codeContent: string = ''
|
||||
|
||||
async function loadVariables() {
|
||||
let r: { name: string; path?: string; description?: string }[] = []
|
||||
const variables = (
|
||||
await VariableService.listVariable({ workspace: $workspaceStore ?? 'NO_W' })
|
||||
).map((x) => {
|
||||
return { name: x.path, ...x }
|
||||
})
|
||||
|
||||
const rvariables = await VariableService.listContextualVariables({
|
||||
workspace: $workspaceStore ?? 'NO_W'
|
||||
})
|
||||
r = r.concat(variables).concat(rvariables)
|
||||
return r
|
||||
}
|
||||
|
||||
async function loadScripts(): Promise<{ path: string; summary?: string }[]> {
|
||||
return await ScriptService.listScripts({ workspace: $workspaceStore ?? 'NO_W' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
{@html github}
|
||||
</svelte:head>
|
||||
|
||||
<ItemPicker
|
||||
bind:this={scriptPicker}
|
||||
pickCallback={async (path, _) => {
|
||||
codeContent = (
|
||||
await ScriptService.getScriptByPath({
|
||||
workspace: $workspaceStore ?? '',
|
||||
path
|
||||
})
|
||||
).content
|
||||
codeViewer.openModal()
|
||||
}}
|
||||
closeOnClick={false}
|
||||
itemName="script"
|
||||
extraField="summary"
|
||||
loadItems={loadScripts}
|
||||
/>
|
||||
|
||||
<Modal bind:this={codeViewer}>
|
||||
<div slot="title">Code</div>
|
||||
<div slot="content">
|
||||
{#if lang == 'python3'}
|
||||
<Highlight language={python} code={codeContent} />
|
||||
{:else if lang == 'deno'}
|
||||
<Highlight language={typescript} code={codeContent} />
|
||||
{/if}
|
||||
</div></Modal
|
||||
>
|
||||
|
||||
<ItemPicker
|
||||
bind:this={variablePicker}
|
||||
pickCallback={(path, name) => {
|
||||
if (!path) {
|
||||
if (lang == 'deno') {
|
||||
editor.insertAtCursor(`Deno.env.get('${name}')`)
|
||||
} else {
|
||||
if (!editor.getCode().includes('import os')) {
|
||||
editor.insertAtBeginning('import os\n')
|
||||
}
|
||||
editor.insertAtCursor(`os.environ.get("${name}")`)
|
||||
}
|
||||
sendUserToast(`${name} inserted at cursor`)
|
||||
} else {
|
||||
if (lang == 'deno') {
|
||||
if (!editor.getCode().includes('import * as wmill from')) {
|
||||
editor.insertAtBeginning(
|
||||
`import * as wmill from 'https://deno.land/x/windmill@v${__pkg__.version}/index.ts'\n`
|
||||
)
|
||||
}
|
||||
editor.insertAtCursor(`(await wmill.getVariable('${path}'))`)
|
||||
} else {
|
||||
if (!editor.getCode().includes('import wmill')) {
|
||||
editor.insertAtBeginning('import wmill\n')
|
||||
}
|
||||
editor.insertAtCursor(`wmill.get_variable("${path}")`)
|
||||
}
|
||||
sendUserToast(`${name} inserted at cursor`)
|
||||
}
|
||||
}}
|
||||
itemName="Variable"
|
||||
extraField="name"
|
||||
loadItems={loadVariables}
|
||||
>
|
||||
<div slot="submission" class="flex flex-row">
|
||||
<div class="text-xs mr-2 align-middle">
|
||||
The variable you were looking for does not exist yet?
|
||||
</div>
|
||||
<button
|
||||
class="default-button-secondary"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
variableEditor.initNew()
|
||||
}}
|
||||
>
|
||||
Create a new variable
|
||||
</button>
|
||||
</div>
|
||||
</ItemPicker>
|
||||
|
||||
<ItemPicker
|
||||
bind:this={resourcePicker}
|
||||
pickCallback={(path, _) => {
|
||||
if (lang == 'deno') {
|
||||
if (!editor.getCode().includes('import * as wmill from')) {
|
||||
editor.insertAtBeginning(
|
||||
`import * as wmill from 'https://deno.land/x/windmill@v${__pkg__.version}/index.ts'\n`
|
||||
)
|
||||
}
|
||||
editor.insertAtCursor(`(await wmill.getResource('${path}'))`)
|
||||
} else {
|
||||
if (!editor.getCode().includes('import wmill')) {
|
||||
editor.insertAtBeginning('import wmill\n')
|
||||
}
|
||||
editor.insertAtCursor(`wmill.get_resource("${path}")`)
|
||||
}
|
||||
sendUserToast(`${path} inserted at cursor`)
|
||||
}}
|
||||
itemName="Resource"
|
||||
extraField="resource_type"
|
||||
loadItems={async () =>
|
||||
await ResourceService.listResource({ workspace: $workspaceStore ?? 'NO_W' })}
|
||||
>
|
||||
<div slot="submission" class="flex flex-row">
|
||||
<div class="text-xs mr-2 align-middle">
|
||||
The resource you were looking for does not exist yet?
|
||||
</div>
|
||||
<button
|
||||
class="default-button-secondary"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
resourceEditor.initNew()
|
||||
}}
|
||||
>
|
||||
Create a new resource
|
||||
</button>
|
||||
</div>
|
||||
</ItemPicker>
|
||||
|
||||
<ResourceEditor bind:this={resourceEditor} on:refresh={resourcePicker.openModal} />
|
||||
|
||||
<VariableEditor bind:this={variableEditor} on:create={variablePicker.openModal} />
|
||||
|
||||
<div class="flex flex-row justify-around w-full">
|
||||
<button
|
||||
class="default-button-secondary font-semibold py-px mr-2 text-xs align-middle max-h-8"
|
||||
on:click|stopPropagation={() => {
|
||||
variablePicker.openModal()
|
||||
}}
|
||||
>Variable picker <Icon data={faSearch} scale={0.7} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="default-button-secondary font-semibold py-px text-xs mr-2 align-middle max-h-8"
|
||||
on:click|stopPropagation={() => {
|
||||
resourcePicker.openModal()
|
||||
}}
|
||||
>Resource picker <Icon data={faSearch} scale={0.7} />
|
||||
</button>
|
||||
<button
|
||||
class="default-button-secondary font-semibold py-px text-xs mr-2 align-middle max-h-8"
|
||||
on:click|stopPropagation={() => {
|
||||
scriptPicker.openModal()
|
||||
}}
|
||||
>Script explorer <Icon data={faSearch} scale={0.7} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="default-button-secondary py-px max-h-8 text-xs"
|
||||
on:click|stopPropagation={() => {
|
||||
editor.reloadWebsocket()
|
||||
}}
|
||||
>
|
||||
Reload assistants (status: {#if lang == 'deno'}<span
|
||||
class={websocketAlive.deno ? 'text-green-600' : 'text-red-600'}>deno</span
|
||||
>{:else if lang == 'python3'}<span
|
||||
class={websocketAlive.pyright ? 'text-green-600' : 'text-red-600'}>pyright</span
|
||||
>
|
||||
<span class={websocketAlive.black ? 'text-green-600' : 'text-red-600'}> black</span>{/if})
|
||||
</button>
|
||||
</div>
|
||||
@@ -5,6 +5,7 @@
|
||||
import { faRobot } from '@fortawesome/free-solid-svg-icons'
|
||||
import Icon from 'svelte-awesome'
|
||||
import Editor from './Editor.svelte'
|
||||
import EditorBar from './EditorBar.svelte'
|
||||
import FlowPreview from './FlowPreview.svelte'
|
||||
import FlowInputs from './flows/FlowInputs.svelte'
|
||||
import FlowModuleHeader from './flows/FlowModuleHeader.svelte'
|
||||
@@ -25,6 +26,9 @@
|
||||
export let mod: FlowModule
|
||||
export let args: Record<string, any> = {}
|
||||
|
||||
let editor: Editor
|
||||
let websocketAlive = { pyright: false, black: false, deno: false }
|
||||
|
||||
$: schema = $schemasStore[i]
|
||||
$: shouldPick = mod.value.path === '' && mod.value.language === undefined
|
||||
$: previousSchema = i === 0 ? schemaToObject($flowStore?.schema) : $previewResults[i]
|
||||
@@ -78,7 +82,11 @@
|
||||
/>
|
||||
{/if}
|
||||
{#if mod.value.type === FlowModuleValue.type.RAWSCRIPT}
|
||||
<div class="p-1">
|
||||
<EditorBar {editor} {websocketAlive} lang={mod.value.language ?? 'deno'} />
|
||||
</div>
|
||||
<Editor
|
||||
bind:this={editor}
|
||||
class="h-80 border p-2 rounded"
|
||||
bind:code={mod.value.content}
|
||||
deno={mod.value.language === FlowModuleValue.language.DENO}
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
JobService,
|
||||
Job,
|
||||
CompletedJob,
|
||||
VariableService,
|
||||
ResourceService,
|
||||
ScriptService
|
||||
} from '$lib/gen'
|
||||
import { sendUserToast, emptySchema, displayDate } from '$lib/utils'
|
||||
import { JobService, Job, CompletedJob, VariableService, ScriptService } from '$lib/gen'
|
||||
import { emptySchema, displayDate } from '$lib/utils'
|
||||
import type { Schema } from '$lib/common'
|
||||
import { fade } from 'svelte/transition'
|
||||
import Icon from 'svelte-awesome'
|
||||
@@ -17,7 +10,6 @@
|
||||
faChevronUp,
|
||||
faExclamationTriangle,
|
||||
faMagic,
|
||||
faSearch,
|
||||
faSpinner,
|
||||
faTimes
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
@@ -28,12 +20,7 @@
|
||||
import TableCustom from './TableCustom.svelte'
|
||||
import { check } from 'svelte-awesome/icons'
|
||||
import Modal from './Modal.svelte'
|
||||
import { Highlight } from 'svelte-highlight'
|
||||
import { json, python, typescript } from 'svelte-highlight/languages'
|
||||
import github from 'svelte-highlight/styles/github'
|
||||
import ItemPicker from './ItemPicker.svelte'
|
||||
import VariableEditor from './VariableEditor.svelte'
|
||||
import ResourceEditor from './ResourceEditor.svelte'
|
||||
|
||||
import { inferArgs } from '$lib/infer'
|
||||
|
||||
// @ts-ignore
|
||||
@@ -41,6 +28,9 @@
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import DisplayResult from './DisplayResult.svelte'
|
||||
import type { Preview } from '$lib/gen/models/Preview'
|
||||
import EditorBar from './EditorBar.svelte'
|
||||
import { Highlight } from 'svelte-highlight'
|
||||
import { json, python, typescript } from 'svelte-highlight/languages'
|
||||
|
||||
// Exported
|
||||
export let schema: Schema = emptySchema()
|
||||
@@ -55,6 +45,10 @@
|
||||
|
||||
let websocketAlive = { pyright: false, black: false, deno: false }
|
||||
|
||||
let modalViewerTitle: string = ''
|
||||
let modalViewerContent: any
|
||||
let modalViewerMode: 'logs' | 'result' | 'code' = 'logs'
|
||||
|
||||
// Internal state
|
||||
let editor: Editor
|
||||
|
||||
@@ -69,15 +63,6 @@
|
||||
let pastPreviews: CompletedJob[] = []
|
||||
|
||||
let modalViewer: Modal
|
||||
let modalViewerTitle: string = ''
|
||||
let modalViewerContent: any
|
||||
let modalViewerMode: 'logs' | 'result' | 'code' = 'logs'
|
||||
|
||||
let variablePicker: ItemPicker
|
||||
let resourcePicker: ItemPicker
|
||||
let scriptPicker: ItemPicker
|
||||
let variableEditor: VariableEditor
|
||||
let resourceEditor: ResourceEditor
|
||||
|
||||
let syncIteration: number = 0
|
||||
let ITERATIONS_BEFORE_SLOW_REFRESH = 100
|
||||
@@ -196,25 +181,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function loadVariables() {
|
||||
let r: { name: string; path?: string; description?: string }[] = []
|
||||
const variables = (
|
||||
await VariableService.listVariable({ workspace: $workspaceStore ?? 'NO_W' })
|
||||
).map((x) => {
|
||||
return { name: x.path, ...x }
|
||||
})
|
||||
|
||||
const rvariables = await VariableService.listContextualVariables({
|
||||
workspace: $workspaceStore ?? 'NO_W'
|
||||
})
|
||||
r = r.concat(variables).concat(rvariables)
|
||||
return r
|
||||
}
|
||||
|
||||
async function loadScripts(): Promise<{ path: string; summary?: string }[]> {
|
||||
return await ScriptService.listScripts({ workspace: $workspaceStore ?? 'NO_W' })
|
||||
}
|
||||
|
||||
let syncCode: NodeJS.Timer
|
||||
onMount(() => {
|
||||
syncCode = setInterval(() => {
|
||||
@@ -237,29 +203,6 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
{@html github}
|
||||
</svelte:head>
|
||||
|
||||
<ItemPicker
|
||||
bind:this={scriptPicker}
|
||||
pickCallback={async (path, _) => {
|
||||
modalViewerMode = 'code'
|
||||
modalViewerTitle = 'Script ' + path
|
||||
modalViewerContent = (
|
||||
await ScriptService.getScriptByPath({
|
||||
workspace: $workspaceStore ?? '',
|
||||
path
|
||||
})
|
||||
).content
|
||||
modalViewer.openModal()
|
||||
}}
|
||||
closeOnClick={false}
|
||||
itemName="script"
|
||||
extraField="summary"
|
||||
loadItems={loadScripts}
|
||||
/>
|
||||
|
||||
<Modal bind:this={modalViewer}>
|
||||
<div slot="title">{modalViewerTitle}</div>
|
||||
<div slot="content">
|
||||
@@ -279,99 +222,6 @@
|
||||
</div></Modal
|
||||
>
|
||||
|
||||
<ItemPicker
|
||||
bind:this={variablePicker}
|
||||
pickCallback={(path, name) => {
|
||||
if (!path) {
|
||||
if (lang == 'deno') {
|
||||
getEditor().insertAtCursor(`Deno.env.get('${name}')`)
|
||||
} else {
|
||||
if (!getEditor().getCode().includes('import os')) {
|
||||
getEditor().insertAtBeginning('import os\n')
|
||||
}
|
||||
getEditor().insertAtCursor(`os.environ.get("${name}")`)
|
||||
}
|
||||
sendUserToast(`${name} inserted at cursor`)
|
||||
} else {
|
||||
if (lang == 'deno') {
|
||||
if (!getEditor().getCode().includes('import * as wmill from')) {
|
||||
getEditor().insertAtBeginning(
|
||||
`import * as wmill from 'https://deno.land/x/windmill@v${__pkg__.version}/index.ts'\n`
|
||||
)
|
||||
}
|
||||
getEditor().insertAtCursor(`(await wmill.getVariable('${path}'))`)
|
||||
} else {
|
||||
if (!getEditor().getCode().includes('import wmill')) {
|
||||
getEditor().insertAtBeginning('import wmill\n')
|
||||
}
|
||||
getEditor().insertAtCursor(`wmill.get_variable("${path}")`)
|
||||
}
|
||||
sendUserToast(`${name} inserted at cursor`)
|
||||
}
|
||||
}}
|
||||
itemName="Variable"
|
||||
extraField="name"
|
||||
loadItems={loadVariables}
|
||||
>
|
||||
<div slot="submission" class="flex flex-row">
|
||||
<div class="text-xs mr-2 align-middle">
|
||||
The variable you were looking for does not exist yet?
|
||||
</div>
|
||||
<button
|
||||
class="default-button-secondary"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
variableEditor.initNew()
|
||||
}}
|
||||
>
|
||||
Create a new variable
|
||||
</button>
|
||||
</div>
|
||||
</ItemPicker>
|
||||
|
||||
<ItemPicker
|
||||
bind:this={resourcePicker}
|
||||
pickCallback={(path, _) => {
|
||||
if (lang == 'deno') {
|
||||
if (!getEditor().getCode().includes('import * as wmill from')) {
|
||||
getEditor().insertAtBeginning(
|
||||
`import * as wmill from 'https://deno.land/x/windmill@v${__pkg__.version}/index.ts'\n`
|
||||
)
|
||||
}
|
||||
getEditor().insertAtCursor(`(await wmill.getResource('${path}'))`)
|
||||
} else {
|
||||
if (!getEditor().getCode().includes('import wmill')) {
|
||||
getEditor().insertAtBeginning('import wmill\n')
|
||||
}
|
||||
getEditor().insertAtCursor(`wmill.get_resource("${path}")`)
|
||||
}
|
||||
sendUserToast(`${path} inserted at cursor`)
|
||||
}}
|
||||
itemName="Resource"
|
||||
extraField="resource_type"
|
||||
loadItems={async () =>
|
||||
await ResourceService.listResource({ workspace: $workspaceStore ?? 'NO_W' })}
|
||||
>
|
||||
<div slot="submission" class="flex flex-row">
|
||||
<div class="text-xs mr-2 align-middle">
|
||||
The resource you were looking for does not exist yet?
|
||||
</div>
|
||||
<button
|
||||
class="default-button-secondary"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
resourceEditor.initNew()
|
||||
}}
|
||||
>
|
||||
Create a new resource
|
||||
</button>
|
||||
</div>
|
||||
</ItemPicker>
|
||||
|
||||
<ResourceEditor bind:this={resourceEditor} on:refresh={resourcePicker.openModal} />
|
||||
|
||||
<VariableEditor bind:this={variableEditor} on:create={variablePicker.openModal} />
|
||||
|
||||
<VSplitPane
|
||||
class="h-full"
|
||||
topPanelSize={viewPreview ? '75%' : '90%'}
|
||||
@@ -385,46 +235,7 @@
|
||||
<top slot="top">
|
||||
<div class="flex flex-col h-full">
|
||||
<div class="header">
|
||||
<div class="flex flex-row justify-around w-full">
|
||||
<button
|
||||
class="default-button-secondary font-semibold py-px mr-2 text-xs align-middle max-h-8"
|
||||
on:click|stopPropagation={() => {
|
||||
variablePicker.openModal()
|
||||
}}
|
||||
>Variable picker <Icon data={faSearch} scale={0.7} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="default-button-secondary font-semibold py-px text-xs mr-2 align-middle max-h-8"
|
||||
on:click|stopPropagation={() => {
|
||||
resourcePicker.openModal()
|
||||
}}
|
||||
>Resource picker <Icon data={faSearch} scale={0.7} />
|
||||
</button>
|
||||
<button
|
||||
class="default-button-secondary font-semibold py-px text-xs mr-2 align-middle max-h-8"
|
||||
on:click|stopPropagation={() => {
|
||||
scriptPicker.openModal()
|
||||
}}
|
||||
>Script explorer <Icon data={faSearch} scale={0.7} />
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="default-button-secondary py-px max-h-8 text-xs"
|
||||
on:click|stopPropagation={() => {
|
||||
editor.reloadWebsocket()
|
||||
}}
|
||||
>
|
||||
Reload assistants (status: {#if lang == 'deno'}<span
|
||||
class={websocketAlive.deno ? 'text-green-600' : 'text-red-600'}>deno</span
|
||||
>{:else if lang == 'python3'}<span
|
||||
class={websocketAlive.pyright ? 'text-green-600' : 'text-red-600'}>pyright</span
|
||||
>
|
||||
<span class={websocketAlive.black ? 'text-green-600' : 'text-red-600'}>
|
||||
black</span
|
||||
>{/if})
|
||||
</button>
|
||||
</div>
|
||||
<EditorBar {editor} {lang} {websocketAlive} />
|
||||
</div>
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<Editor
|
||||
@@ -438,6 +249,7 @@
|
||||
formatAction={() => {
|
||||
code = getEditor().getCode()
|
||||
localStorage.setItem(path ?? 'last_save', code)
|
||||
lastSave = code
|
||||
}}
|
||||
class="h-full"
|
||||
deno={lang == 'deno'}
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
<h2 class="mt-2 md:mt-6">
|
||||
Schedule<Tooltip class="mx-2">Schedules use CRON syntax. Milliseconds are mandatory.</Tooltip>
|
||||
Schedule<Tooltip>Schedules use CRON syntax. Milliseconds are mandatory.</Tooltip>
|
||||
</h2>
|
||||
<div class="text-purple-500 text-2xs grow">{cronError}</div>
|
||||
<div class="flex flex-row items-end max-w-5xl">
|
||||
|
||||
@@ -24,6 +24,11 @@ const config = {
|
||||
'highlight.js/lib/core',
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
path: "path-browserify",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
Reference in New Issue
Block a user