* fix(frontend): wip * fix(frontend): wip * fix(frontend): merge main * fix(frontend): fix build * fix(frontend): revert css * fix(frontend): fix alignement + remove id from if deleted * fix(frontend): fix connection height * fix(frontend): done
224 lines
6.1 KiB
Svelte
224 lines
6.1 KiB
Svelte
<script lang="ts">
|
|
import type { Schema } from '$lib/common'
|
|
import { Button, Drawer, DrawerContent, Tab, Tabs } from '$lib/components/common'
|
|
import FlowScriptPicker from '$lib/components/flows/pickers/FlowScriptPicker.svelte'
|
|
import PickHubScript from '$lib/components/flows/pickers/PickHubScript.svelte'
|
|
import Tooltip from '$lib/components/Tooltip.svelte'
|
|
import { Script, type Preview } from '$lib/gen'
|
|
import { inferArgs } from '$lib/infer'
|
|
import { initialCode } from '$lib/script_helpers'
|
|
import { capitalize, emptySchema, getScriptByPath } from '$lib/utils'
|
|
import { faCodeBranch } from '@fortawesome/free-solid-svg-icons'
|
|
import { Building, Globe2 } from 'lucide-svelte'
|
|
import { createEventDispatcher, getContext } from 'svelte'
|
|
import { fly } from 'svelte/transition'
|
|
import type { AppViewerContext } from '../../types'
|
|
import { defaultCode } from '../component'
|
|
import InlineScriptList from '../settingsPanel/mainInput/InlineScriptList.svelte'
|
|
import WorkspaceScriptList from '../settingsPanel/mainInput/WorkspaceScriptList.svelte'
|
|
|
|
export let name: string
|
|
export let componentType: string | undefined = undefined
|
|
|
|
let tab = 'inlinescripts'
|
|
let filter: string = ''
|
|
let picker: Drawer
|
|
|
|
const { appPath, app } = getContext<AppViewerContext>('AppViewerContext')
|
|
const dispatch = createEventDispatcher()
|
|
|
|
async function inferInlineScriptSchema(
|
|
language: Preview.language,
|
|
content: string,
|
|
schema: Schema
|
|
): Promise<Schema> {
|
|
try {
|
|
await inferArgs(language, content, schema)
|
|
} catch (e) {
|
|
console.error("Couldn't infer args", e)
|
|
}
|
|
|
|
return schema
|
|
}
|
|
|
|
async function createInlineScriptByLanguage(
|
|
language: Preview.language,
|
|
path: string,
|
|
subkind: 'pgsql' | 'mysql' | undefined = undefined
|
|
) {
|
|
const content =
|
|
defaultCode(componentType ?? '', language) ??
|
|
initialCode(language, Script.kind.SCRIPT, subkind ?? 'flow')
|
|
|
|
return newInlineScript(content, language, path)
|
|
}
|
|
|
|
async function newInlineScript(content: string, language: Preview.language, path: string) {
|
|
const fullPath = `${appPath}/${path}`
|
|
|
|
let schema: Schema = emptySchema()
|
|
|
|
schema = await inferInlineScriptSchema(language, content, schema)
|
|
const newInlineScript = {
|
|
content,
|
|
language,
|
|
path: fullPath,
|
|
schema
|
|
}
|
|
dispatch('new', newInlineScript)
|
|
}
|
|
|
|
async function pickScript(path: string) {
|
|
const script = await getScriptByPath(path)
|
|
newInlineScript(script.content, script.language, path)
|
|
}
|
|
|
|
async function pickHubScript(path: string) {
|
|
const script = await getScriptByPath(path)
|
|
newInlineScript(script.content, script.language, path)
|
|
}
|
|
|
|
function pickInlineScript(name: string) {
|
|
const unusedInlineScriptIndex = $app.unusedInlineScripts?.findIndex(
|
|
(script) => script.name === name
|
|
)
|
|
const unusedInlineScript = $app.unusedInlineScripts?.[unusedInlineScriptIndex]
|
|
|
|
$app.unusedInlineScripts.splice(unusedInlineScriptIndex, 1)
|
|
$app = $app
|
|
dispatch('new', unusedInlineScript.inlineScript)
|
|
}
|
|
|
|
const langs = ['deno', 'python3', 'go', 'bash'] as Script.language[]
|
|
</script>
|
|
|
|
<Drawer bind:this={picker} size="1000px">
|
|
<DrawerContent title="Script/Flow Picker" on:close={picker.closeDrawer}>
|
|
<div>
|
|
<div class="max-w-6xl">
|
|
<Tabs bind:selected={tab}>
|
|
<Tab size="sm" value="inlinescripts">
|
|
<div class="flex gap-2 items-center my-1">
|
|
<Building size={18} />
|
|
Detached Inline Scripts
|
|
</div>
|
|
</Tab>
|
|
<Tab size="sm" value="workspacescripts">
|
|
<div class="flex gap-2 items-center my-1">
|
|
<Building size={18} />
|
|
Workspace Scripts
|
|
</div>
|
|
</Tab>
|
|
|
|
<Tab size="sm" value="hubscripts">
|
|
<div class="flex gap-2 items-center my-1">
|
|
<Globe2 size={18} />
|
|
Hub Scripts
|
|
</div>
|
|
</Tab>
|
|
</Tabs>
|
|
<div class="my-2" />
|
|
<div class="flex flex-col gap-y-16">
|
|
<div class="flex flex-col">
|
|
{#if tab == 'inlinescripts'}
|
|
<InlineScriptList
|
|
on:pick={(e) => pickInlineScript(e.detail)}
|
|
inlineScripts={$app.unusedInlineScripts
|
|
? $app.unusedInlineScripts.map((uis) => uis.name)
|
|
: []}
|
|
/>
|
|
{:else if tab == 'workspacescripts'}
|
|
<WorkspaceScriptList on:pick={(e) => pickScript(e.detail)} />
|
|
{:else if tab == 'hubscripts'}
|
|
<PickHubScript bind:filter on:pick={(e) => pickHubScript(e.detail.path)} />
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</DrawerContent>
|
|
</Drawer>
|
|
|
|
<div class="flex flex-col px-4 py-2 gap-2 text-sm" in:fly={{ duration: 50 }}>
|
|
<div class="mt-4 flex justify-between gap-8 mb-2">
|
|
<div class="font-bold items-baseline">Choose a language:</div>
|
|
<div class="flex gap-2">
|
|
<Button
|
|
on:click={() => picker?.openDrawer()}
|
|
size="xs"
|
|
color="blue"
|
|
startIcon={{ icon: faCodeBranch }}
|
|
btnClasses="truncate"
|
|
>
|
|
fork a detached script
|
|
</Button>
|
|
<Button
|
|
on:click={() => dispatch('delete')}
|
|
size="xs"
|
|
color="red"
|
|
variant="border"
|
|
btnClasses="truncate"
|
|
>
|
|
Cancel
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
<div class="flex gap-2 flex-row flex-wrap">
|
|
{#each langs as lang}
|
|
<FlowScriptPicker
|
|
label={capitalize(lang)}
|
|
{lang}
|
|
on:click={() => {
|
|
createInlineScriptByLanguage(lang, name)
|
|
}}
|
|
/>
|
|
{/each}
|
|
|
|
<FlowScriptPicker
|
|
label={`PostgreSQL`}
|
|
lang="pgsql"
|
|
on:click={() => {
|
|
createInlineScriptByLanguage(Script.language.DENO, name, 'pgsql')
|
|
}}
|
|
/>
|
|
|
|
<!-- <FlowScriptPicker
|
|
label={`MySQL`}
|
|
lang="mysql"
|
|
on:click={() => {
|
|
createInlineScriptByLanguage(Script.language.DENO, name, 'mysql')
|
|
}}
|
|
/> -->
|
|
</div>
|
|
<div>
|
|
<div class="text-xs mb-1 mt-2"
|
|
>Script executed in the client's browser directly: <Tooltip
|
|
>Frontend scripts are executed in the browser and can manipulate the app context directly</Tooltip
|
|
></div
|
|
>
|
|
<FlowScriptPicker
|
|
label={`JavaScript`}
|
|
lang="javascript"
|
|
on:click={() => {
|
|
const newInlineScript = {
|
|
content: `// read outputs and ctx
|
|
console.log(ctx.email)
|
|
|
|
// access a global state store
|
|
if (!state.foo) { state.foo = 0 }
|
|
state.foo += 1
|
|
|
|
// you can also navigate to another page
|
|
//await goto("?foo=bar")
|
|
|
|
return state.foo`,
|
|
language: 'frontend',
|
|
path: 'frontend script',
|
|
schema: undefined
|
|
}
|
|
dispatch('new', newInlineScript)
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|