feat(frontend): deeper integration with the hub
This commit is contained in:
@@ -17,6 +17,10 @@
|
||||
a {
|
||||
@apply text-blue-500;
|
||||
}
|
||||
|
||||
.flex pre code.hljs {
|
||||
@apply text-sm;
|
||||
}
|
||||
|
||||
#table-custom th {
|
||||
@apply py-3.5 text-left text-sm font-semibold text-gray-900 capitalize;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService, ScriptService, VariableService } from '$lib/gen'
|
||||
import { sendUserToast } from '$lib/utils'
|
||||
import { getScriptByPath, loadHubScripts, sendUserToast } from '$lib/utils'
|
||||
|
||||
import Icon from 'svelte-awesome'
|
||||
import { faSearch } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { workspaceStore, hubScripts } from '$lib/stores'
|
||||
import ItemPicker from './ItemPicker.svelte'
|
||||
import VariableEditor from './VariableEditor.svelte'
|
||||
import ResourceEditor from './ResourceEditor.svelte'
|
||||
@@ -26,6 +26,7 @@
|
||||
let resourceEditor: ResourceEditor
|
||||
|
||||
let codeViewer: Modal
|
||||
let codeLang: 'python3' | 'deno' = 'deno'
|
||||
let codeContent: string = ''
|
||||
|
||||
async function loadVariables() {
|
||||
@@ -44,7 +45,13 @@
|
||||
}
|
||||
|
||||
async function loadScripts(): Promise<{ path: string; summary?: string }[]> {
|
||||
return await ScriptService.listScripts({ workspace: $workspaceStore ?? 'NO_W' })
|
||||
const workspaceScripts: { path: string; summary?: string }[] = await ScriptService.listScripts({
|
||||
workspace: $workspaceStore ?? 'NO_W'
|
||||
})
|
||||
await loadHubScripts()
|
||||
const hubScripts_ = $hubScripts ?? []
|
||||
|
||||
return workspaceScripts.concat(hubScripts_)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -55,12 +62,9 @@
|
||||
<ItemPicker
|
||||
bind:this={scriptPicker}
|
||||
pickCallback={async (path, _) => {
|
||||
codeContent = (
|
||||
await ScriptService.getScriptByPath({
|
||||
workspace: $workspaceStore ?? '',
|
||||
path
|
||||
})
|
||||
).content
|
||||
const { language, content } = await getScriptByPath(path ?? '')
|
||||
codeContent = content
|
||||
codeLang = language
|
||||
codeViewer.openModal()
|
||||
}}
|
||||
closeOnClick={false}
|
||||
@@ -72,9 +76,9 @@
|
||||
<Modal bind:this={codeViewer}>
|
||||
<div slot="title">Code</div>
|
||||
<div slot="content">
|
||||
{#if lang == 'python3'}
|
||||
{#if codeLang == 'python3'}
|
||||
<Highlight language={python} code={codeContent} />
|
||||
{:else if lang == 'deno'}
|
||||
{:else if codeLang == 'deno'}
|
||||
<Highlight language={typescript} code={codeContent} />
|
||||
{/if}
|
||||
</div></Modal
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { page } from '$app/stores'
|
||||
import { FlowService, ScriptService, type Flow } from '$lib/gen'
|
||||
import { clearPreviewResults, hubScripts, workspaceStore } from '$lib/stores'
|
||||
import { sendUserToast, setQueryWithoutLoad } from '$lib/utils'
|
||||
import { loadHubScripts, sendUserToast, setQueryWithoutLoad } from '$lib/utils'
|
||||
import { faFileExport, faFileImport } from '@fortawesome/free-solid-svg-icons'
|
||||
import { onMount } from 'svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
@@ -20,16 +20,6 @@
|
||||
|
||||
$: step = Number($page.url.searchParams.get('step')) || 1
|
||||
|
||||
async function loadSearchData() {
|
||||
const scripts = await ScriptService.listHubScripts()
|
||||
$hubScripts = scripts.map((x) => ({
|
||||
path: `hub/${x.id}/${x.summary.toLowerCase().replaceAll(/\s+/g, '_')}`,
|
||||
summary: `${x.summary} (${x.app})`,
|
||||
approved: x.approved,
|
||||
is_trigger: x.is_trigger
|
||||
}))
|
||||
}
|
||||
|
||||
async function saveFlow(): Promise<void> {
|
||||
const newFlow = flowToMode($flowStore, mode)
|
||||
|
||||
@@ -70,7 +60,7 @@
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
loadSearchData()
|
||||
loadHubScripts()
|
||||
clearPreviewResults()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import { python, typescript } from 'svelte-highlight/languages'
|
||||
|
||||
import github from 'svelte-highlight/styles/github'
|
||||
import { getScript, getScriptByPath } from '$lib/utils'
|
||||
|
||||
export let scriptPath: string | undefined = undefined
|
||||
export let allowFlow = false
|
||||
@@ -30,20 +31,6 @@
|
||||
allowFlow && options.push(['Flow', 'flow'])
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
async function getScript() {
|
||||
if (itemKind == 'hub') {
|
||||
code = await ScriptService.getHubScriptContentByPath({ path: scriptPath! })
|
||||
lang = Script.language.DENO
|
||||
} else {
|
||||
const script = await ScriptService.getScriptByPath({
|
||||
workspace: $workspaceStore!,
|
||||
path: scriptPath!
|
||||
})
|
||||
code = script.content
|
||||
lang = script.language
|
||||
}
|
||||
}
|
||||
|
||||
async function loadItems(): Promise<void> {
|
||||
if (itemKind == 'flow') {
|
||||
items = await FlowService.listFlows({ workspace: $workspaceStore! })
|
||||
@@ -92,7 +79,9 @@
|
||||
<button
|
||||
class="text-xs text-blue-500"
|
||||
on:click={async () => {
|
||||
await getScript()
|
||||
const { language, content } = await getScriptByPath(scriptPath ?? '')
|
||||
code = content
|
||||
lang = language
|
||||
modalViewer.openModal()
|
||||
}}>show code</button
|
||||
>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { FlowModuleValue, Script, type FlowModule } from '$lib/gen'
|
||||
import { getScriptByPath } from '$lib/utils'
|
||||
import { faCode, faCodeBranch, faSave, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import Icon from 'svelte-awesome'
|
||||
import { Highlight } from 'svelte-highlight'
|
||||
@@ -7,7 +8,7 @@
|
||||
import github from 'svelte-highlight/styles/github'
|
||||
import Modal from '../Modal.svelte'
|
||||
import { createScriptFromInlineScript, fork, removeModule } from './flowStore'
|
||||
import { getScriptByPath, scrollIntoView } from './utils'
|
||||
import { scrollIntoView } from './utils'
|
||||
|
||||
export let open: number
|
||||
export let i: number
|
||||
@@ -16,7 +17,7 @@
|
||||
|
||||
let modalViewer: Modal
|
||||
let modalViewerContent = ''
|
||||
let modalViewerLanguage: Script.language = Script.language.DENO
|
||||
let modalViewerLanguage: 'deno' | 'python3' = 'deno'
|
||||
|
||||
async function viewCode() {
|
||||
const { content, language } = await getScriptByPath(mod.value.path!)
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import { loadSchema } from '$lib/scripts'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import { emptySchema, getScriptByPath } from '$lib/utils'
|
||||
import { get } from 'svelte/store'
|
||||
import type { FlowMode } from './flowStore'
|
||||
|
||||
@@ -79,34 +79,14 @@ export async function getFirstStepSchema(flow: Flow): Promise<Schema> {
|
||||
return emptySchema()
|
||||
}
|
||||
|
||||
export async function getScriptByPath(path: string): Promise<{
|
||||
content: string
|
||||
language: FlowModuleValue.language
|
||||
}> {
|
||||
if (path.startsWith('hub/')) {
|
||||
const content = await ScriptService.getHubScriptContentByPath({ path })
|
||||
return {
|
||||
content,
|
||||
language: FlowModuleValue.language.DENO
|
||||
}
|
||||
} else {
|
||||
const script = await ScriptService.getScriptByPath({
|
||||
workspace: get(workspaceStore)!,
|
||||
path: path ?? ''
|
||||
})
|
||||
return {
|
||||
content: script.content,
|
||||
language: script.language
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function createInlineScriptModuleFromPath(path: string): Promise<FlowModuleValue> {
|
||||
const { content, language } = await getScriptByPath(path)
|
||||
|
||||
return {
|
||||
type: FlowModuleValue.type.RAWSCRIPT,
|
||||
language: language,
|
||||
language: language as FlowModuleValue.language,
|
||||
content: content,
|
||||
path
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ export const hubScripts = writable<
|
||||
path: string
|
||||
summary: string
|
||||
approved: boolean
|
||||
is_trigger: boolean
|
||||
is_trigger: boolean,
|
||||
app: string
|
||||
}>
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
import { goto } from '$app/navigation'
|
||||
import type { User } from '$lib/gen'
|
||||
import { Script, ScriptService, type User } from '$lib/gen'
|
||||
import { toast } from '@zerodevx/svelte-toast'
|
||||
import { get } from 'svelte/store'
|
||||
import type { Schema } from './common'
|
||||
import type { UserExt } from './stores'
|
||||
import { hubScripts, workspaceStore, type UserExt } from './stores'
|
||||
|
||||
|
||||
|
||||
@@ -405,8 +406,43 @@ export function setInputCat(type: string | undefined, format: string | undefined
|
||||
|
||||
export function scriptPathToHref(path: string): string {
|
||||
if (path.startsWith('hub/')) {
|
||||
return 'https://hub.windmill.dev/scripts/get/' + path.substring(4)
|
||||
return 'https://hub.windmill.dev/from_version/' + path.substring(4)
|
||||
} else {
|
||||
return `/scripts/get/${path}`
|
||||
}
|
||||
}
|
||||
|
||||
export async function getScriptByPath(path: string): Promise<{
|
||||
content: string
|
||||
language: 'deno' | 'python3',
|
||||
}> {
|
||||
if (path.startsWith('hub/')) {
|
||||
const content = await ScriptService.getHubScriptContentByPath({ path })
|
||||
return {
|
||||
content,
|
||||
language: 'deno'
|
||||
}
|
||||
} else {
|
||||
const script = await ScriptService.getScriptByPath({
|
||||
workspace: get(workspaceStore)!,
|
||||
path: path ?? ''
|
||||
})
|
||||
return {
|
||||
content: script.content,
|
||||
language: script.language
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export async function loadHubScripts() {
|
||||
const scripts = await ScriptService.listHubScripts()
|
||||
hubScripts.set(scripts.map((x) => ({
|
||||
path: `hub/${x.id}/${x.summary.toLowerCase().replaceAll(/\s+/g, '_')}`,
|
||||
summary: `${x.summary} (${x.app})`,
|
||||
approved: x.approved,
|
||||
is_trigger: x.is_trigger,
|
||||
app: x.app
|
||||
})))
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
'Model not found',
|
||||
'Connection is disposed.',
|
||||
'Connection got disposed.',
|
||||
'Stopping the server timed out'
|
||||
'Stopping the server timed out',
|
||||
'Canceled'
|
||||
]
|
||||
|
||||
async function loadUser() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { page } from '$app/stores'
|
||||
|
||||
import FlowBuilder from '$lib/components/FlowBuilder.svelte'
|
||||
import { addModule, initFlow } from '$lib/components/flows/flowStore'
|
||||
import { initFlow } from '$lib/components/flows/flowStore'
|
||||
import type { Flow } from '$lib/gen'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
import Icon from 'svelte-awesome'
|
||||
import type { Script } from '$lib/gen'
|
||||
import { ScriptService } from '$lib/gen'
|
||||
import { superadmin, userStore, workspaceStore } from '$lib/stores'
|
||||
import { canWrite, groupBy, sendUserToast, truncateHash } from '$lib/utils'
|
||||
import { superadmin, userStore, workspaceStore, hubScripts } from '$lib/stores'
|
||||
import { canWrite, getScriptByPath, groupBy, loadHubScripts, sendUserToast, truncateHash } from '$lib/utils'
|
||||
import Badge from '$lib/components/Badge.svelte'
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import Dropdown from '$lib/components/Dropdown.svelte'
|
||||
@@ -24,13 +24,18 @@
|
||||
import ShareModal from '$lib/components/ShareModal.svelte'
|
||||
import Tabs from '$lib/components/Tabs.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import TableCustom from '$lib/components/TableCustom.svelte'
|
||||
import { Highlight } from 'svelte-highlight'
|
||||
import { typescript } from 'svelte-highlight/languages'
|
||||
import github from 'svelte-highlight/styles/github'
|
||||
|
||||
type Tab = 'all' | 'personal' | 'groups' | 'shared' | 'community'
|
||||
type Tab = 'all' | 'personal' | 'groups' | 'shared' | 'examples' | 'hub'
|
||||
type Section = [string, ScriptW[]]
|
||||
type ScriptW = Script & { canWrite: boolean; tab: Tab }
|
||||
let scripts: ScriptW[] = []
|
||||
let filteredScripts: ScriptW[]
|
||||
let scriptFilter = ''
|
||||
let hubFilter = ''
|
||||
let groupedScripts: Section[] = []
|
||||
let communityScripts: Section[] = []
|
||||
|
||||
@@ -50,9 +55,23 @@
|
||||
|
||||
const templateFuse: Fuse<Script> = new Fuse(templateScripts, fuseOptions)
|
||||
|
||||
const hubScriptsFuse: Fuse<any> = new Fuse($hubScripts ?? [], {
|
||||
includeScore: false,
|
||||
keys: ['app', 'path', 'summary']
|
||||
})
|
||||
|
||||
let codeViewer: Modal
|
||||
let codeViewerContent: string = ''
|
||||
let codeViewerPath: string = ''
|
||||
|
||||
$: filteredScripts =
|
||||
scriptFilter.length > 0 ? fuse.search(scriptFilter).map((value) => value.item) : scripts
|
||||
|
||||
$: filteredHub =
|
||||
hubFilter.length > 0
|
||||
? hubScriptsFuse.search(hubFilter).map((value) => value.item)
|
||||
: $hubScripts ?? []
|
||||
|
||||
$: filteredTemplates =
|
||||
templateFilter.length > 0
|
||||
? templateFuse.search(templateFilter).map((value) => value.item)
|
||||
@@ -68,11 +87,11 @@
|
||||
defaults = defaults.concat($userStore?.groups.map((x) => `g/${x}`) ?? [])
|
||||
}
|
||||
groupedScripts = groupBy(
|
||||
filteredScripts.filter((x) => x.tab != 'community'),
|
||||
filteredScripts.filter((x) => x.tab != 'examples'),
|
||||
(sc: Script) => sc.path.split('/').slice(0, 2).join('/'),
|
||||
defaults
|
||||
)
|
||||
communityScripts = [['community', filteredScripts.filter((x) => x.tab == 'community')]]
|
||||
communityScripts = [['examples', filteredScripts.filter((x) => x.tab == 'examples')]]
|
||||
}
|
||||
|
||||
async function loadTemplateScripts(): Promise<void> {
|
||||
@@ -97,7 +116,7 @@
|
||||
async function loadScripts(): Promise<void> {
|
||||
const allScripts = (await ScriptService.listScripts({ workspace: $workspaceStore! })).map(
|
||||
(x: Script) => {
|
||||
let t: Tab = x.workspace_id == $workspaceStore ? tabFromPath(x.path) : 'community'
|
||||
let t: Tab = x.workspace_id == $workspaceStore ? tabFromPath(x.path) : 'examples'
|
||||
return {
|
||||
canWrite:
|
||||
canWrite(x.path, x.extra_perms, $userStore) && x.workspace_id == $workspaceStore,
|
||||
@@ -116,19 +135,36 @@
|
||||
sendUserToast(`Successfully archived script ${path}`)
|
||||
}
|
||||
|
||||
async function viewCode(path) {
|
||||
codeViewerContent = (await getScriptByPath(path)).content
|
||||
codeViewerPath = path
|
||||
codeViewer.openModal()
|
||||
}
|
||||
$: {
|
||||
if ($workspaceStore && ($userStore || $superadmin)) {
|
||||
loadScripts()
|
||||
loadHubScripts()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
{@html github}
|
||||
</svelte:head>
|
||||
|
||||
<Modal bind:this={codeViewer}>
|
||||
<div slot="title">{codeViewerPath}</div>
|
||||
<div slot="content">
|
||||
<Highlight language={typescript} code={codeViewerContent} />
|
||||
</div></Modal
|
||||
>
|
||||
|
||||
<CenteredPage>
|
||||
<PageHeader
|
||||
title="Scripts"
|
||||
tooltip="Scripts are the building blocks of windmill. A script has an auto-generated UI from its
|
||||
parameters whom you can access clicking on 'Run...'. Like everything in windmill, scripts have
|
||||
owners (users or groups) and can be shared to other users and other groups. It is enough to have
|
||||
tooltip="Scripts are the building blocks of windmill. A script can either be used standalone or as part of a Flow.
|
||||
When standalone, it has an auto-generated UI from its parameters whom you can access clicking on 'Run...'. L
|
||||
ike everything in windmill, scripts have owners (users or groups) and can be shared to other users and other groups. It is enough to have
|
||||
read-access on a script to be able to execute it. However, you will also need to have been
|
||||
granted visibility on the resources and variables it uses, otherwise it will behave as if those
|
||||
items did not exist at runtime of the script."
|
||||
@@ -153,14 +189,17 @@
|
||||
['personal', `personal space (${$userStore?.username})`],
|
||||
['groups', 'groups'],
|
||||
['shared', 'shared'],
|
||||
['community', 'community']
|
||||
['examples', 'examples'],
|
||||
['hub', 'hub']
|
||||
]}
|
||||
bind:tab
|
||||
on:update={loadScripts}
|
||||
/>
|
||||
<input placeholder="Search scripts" bind:value={scriptFilter} class="search-bar mt-2" />
|
||||
{#if tab != 'hub'}
|
||||
<input placeholder="Search scripts" bind:value={scriptFilter} class="search-bar mt-2" />
|
||||
{/if}
|
||||
<div class="grid grid-cols-1 divide-y">
|
||||
{#each tab == 'all' ? ['personal', 'groups', 'shared', 'community'] : [tab] as sectionTab}
|
||||
{#each tab == 'all' ? ['personal', 'groups', 'shared', 'examples', 'hub'] : [tab] as sectionTab}
|
||||
<div class="shadow p-4 my-2">
|
||||
{#if sectionTab == 'personal'}
|
||||
<h2 class="">
|
||||
@@ -168,32 +207,71 @@
|
||||
</h2>
|
||||
<p class="italic text-xs text-gray-600 mb-4">
|
||||
All scripts owned by you (and visible only to you if you do not explicitely share them)
|
||||
will be displayed below
|
||||
</p>
|
||||
{:else if sectionTab == 'groups'}
|
||||
<h2 class="">Groups that I am member of</h2>
|
||||
<p class="italic text-xs text-gray-600">
|
||||
All scripts being owned by groups that you are member of will be displayed below
|
||||
All scripts being owned by groups that you are member of
|
||||
</p>
|
||||
{:else if sectionTab == 'shared'}
|
||||
<h2 class="">Shared with me</h2>
|
||||
<p class="italic text-xs text-gray-600">
|
||||
All scripts visible to you because they have been shared to you will be displayed below
|
||||
All scripts visible to you because they have been shared to you
|
||||
</p>
|
||||
{:else if sectionTab == 'community'}
|
||||
<h2 class="">Community templates & examples</h2>
|
||||
{:else if sectionTab == 'examples'}
|
||||
<h2 class="">Shared across all workspaces of this instance</h2>
|
||||
<p class="italic text-xs text-gray-600 mb-8">
|
||||
All scripts by the community that went through a review process and merged to the
|
||||
<a href="https://github.com/windmill-labs/windmill">official github repo</a> will be displayed
|
||||
below. Contributions welcome as Github PR.
|
||||
Template and examples shared across all workspaces of this instance. They are managed
|
||||
from a special workspace called 'starter' that only superadmin can change.
|
||||
</p>
|
||||
{:else if sectionTab == 'hub'}
|
||||
<h2 class="">Approved scripts from the WindmillHub</h2>
|
||||
<p class="italic text-xs text-gray-600 mb-8">
|
||||
All approved Deno scripts from the <a href="https://hub.windmill.dev">WindmillHub</a>.
|
||||
Approved scripts have been reviewed by the Windmill team and are safe to use in
|
||||
production. The hub only offers Deno scripts because Hub scripts are meant to be solely
|
||||
used as building blocks of flows and are much more efficient to execute than their
|
||||
Python counterparts.
|
||||
</p>
|
||||
<input placeholder="Search hub scripts" bind:value={hubFilter} class="search-bar mt-2" />
|
||||
<div class="relative">
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
<th>App</th>
|
||||
<th>Summary</th>
|
||||
<th />
|
||||
</tr>
|
||||
<tbody slot="body">
|
||||
{#each filteredHub ?? [] as { path, summary, app }}
|
||||
<tr>
|
||||
<td class="font-black">{app}</td>
|
||||
<td><button on:click={() => viewCode(path)}>{summary}</button></td>
|
||||
<td
|
||||
><button class="text-blue-500" on:click={() => viewCode(path)}
|
||||
>view code</button
|
||||
>
|
||||
|
|
||||
<a
|
||||
target="_blank"
|
||||
href={`https://hub.windmill.dev/from_version/${path
|
||||
.split('/')
|
||||
.slice(1, 3)
|
||||
.join('/')}`}>hub's page</a
|
||||
>
|
||||
| <a href={`/scripts/add?hub=${encodeURIComponent(path)}`}>fork</a>
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</TableCustom>
|
||||
</div>
|
||||
{/if}
|
||||
{#each sectionTab == 'community' ? communityScripts : groupedScripts.filter((x) => tabFromPath(x[0]) == sectionTab) as [section, scripts]}
|
||||
{#if sectionTab != 'personal' && sectionTab != 'community'}
|
||||
{#each sectionTab == 'examples' ? communityScripts : groupedScripts.filter((x) => tabFromPath(x[0]) == sectionTab) as [section, scripts]}
|
||||
{#if sectionTab != 'personal' && sectionTab != 'examples'}
|
||||
<h3 class="mt-2 mb-2">
|
||||
owner: {section}
|
||||
{#if section == 'g/all'}
|
||||
<Tooltip class="mx-1"
|
||||
<Tooltip
|
||||
>'g/all' is the namespace for the group all. Every user is a member of all.
|
||||
Everything in this namespace is visible by all users. At the opposite, 'u/myuser'
|
||||
are private user namespaces.</Tooltip
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { ScriptService, type Script } from '$lib/gen'
|
||||
import { Script, ScriptService } from '$lib/gen'
|
||||
|
||||
import { page } from '$app/stores'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import ScriptBuilder from '$lib/components/ScriptBuilder.svelte'
|
||||
import type { Schema } from '$lib/common'
|
||||
import { emptySchema, sendUserToast } from '$lib/utils'
|
||||
import { emptySchema, getScriptByPath, sendUserToast } from '$lib/utils'
|
||||
|
||||
// Default
|
||||
let schema: Schema = emptySchema()
|
||||
|
||||
$: templatePath = $page.url.searchParams.get('template')
|
||||
$: hubPath = $page.url.searchParams.get('hub')
|
||||
|
||||
const initialState = $page.url.searchParams.get('state')
|
||||
|
||||
@@ -47,9 +48,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function loadHub(): Promise<void> {
|
||||
if (hubPath) {
|
||||
const template = await getScriptByPath(hubPath)
|
||||
script.summary = `Fork of ${hubPath}`
|
||||
script.content = template.content
|
||||
script.language = Script.language.DENO
|
||||
sendUserToast(`Code has been loaded from hub script ${hubPath}.`)
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
if ($workspaceStore) {
|
||||
loadTemplate()
|
||||
loadHub()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user