mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-09 00:04:10 +00:00
add editable resources
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"workspace_id": "starter",
|
||||
"name": "state",
|
||||
"schema": {
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"type": "object"
|
||||
},
|
||||
"description": ""
|
||||
}
|
||||
@@ -54,9 +54,7 @@
|
||||
$: editor && addEditorActions()
|
||||
|
||||
async function loadVariables() {
|
||||
return (await VariableService.listVariable({ workspace: $workspaceStore ?? '' })).map((x) => {
|
||||
return { name: x.path, ...x }
|
||||
})
|
||||
return await VariableService.listVariable({ workspace: $workspaceStore ?? '' })
|
||||
}
|
||||
|
||||
async function loadContextualVariables() {
|
||||
@@ -147,13 +145,10 @@
|
||||
sendUserToast(`${name} inserted at cursor`)
|
||||
}}
|
||||
itemName="Variable"
|
||||
extraField="name"
|
||||
extraField="path"
|
||||
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
|
||||
variant="border"
|
||||
color="blue"
|
||||
@@ -193,7 +188,8 @@
|
||||
sendUserToast(`${path} inserted at cursor`)
|
||||
}}
|
||||
itemName="Resource"
|
||||
extraField="resource_type"
|
||||
buttons={{ edit: (x) => resourceEditor.initEdit(x) }}
|
||||
extraField="description"
|
||||
loadItems={async () =>
|
||||
await ResourceService.listResource({ workspace: $workspaceStore ?? 'NO_W' })}
|
||||
>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { Drawer, Skeleton } from './common'
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import WindmillIcon from './icons/WindmillIcon.svelte'
|
||||
|
||||
type Item = Record<string, any>
|
||||
export let pickCallback: (path: string, f: string) => void
|
||||
@@ -12,6 +11,7 @@
|
||||
export let itemName: string
|
||||
export let closeOnClick = true
|
||||
export let noItemMessage = ''
|
||||
export let buttons: Record<string, (x: string) => void> = {}
|
||||
|
||||
let loading = false
|
||||
let items: Item[] | undefined = []
|
||||
@@ -60,25 +60,55 @@
|
||||
{:else if filteredItems}
|
||||
<ul class="divide-y divide-gray-200">
|
||||
{#each filteredItems as obj}
|
||||
<li
|
||||
class="py-4 px-1 gap-1 flex flex-col hover:bg-white hover:border text-black cursor-pointer"
|
||||
on:click={() => {
|
||||
if (closeOnClick) {
|
||||
drawer.closeDrawer()
|
||||
}
|
||||
pickCallback(obj['path'], obj[extraField])
|
||||
}}
|
||||
>
|
||||
<p class="text-sm font-semibold flex flex-row">
|
||||
<li class="flex flex-row w-full">
|
||||
<button
|
||||
class="py-4 px-1 gap-1 flex flex-row grow hover:bg-white hover:border text-black"
|
||||
on:click={() => {
|
||||
if (closeOnClick) {
|
||||
drawer.closeDrawer()
|
||||
}
|
||||
pickCallback(obj['path'], obj[extraField])
|
||||
}}
|
||||
>
|
||||
{#if `app` in obj}
|
||||
<IconedResourceType silent={true} name={obj['app']} />
|
||||
<span class="mr-2" />
|
||||
<div class="mr-2 text-sm text-left truncate w-24">
|
||||
<IconedResourceType silent={true} name={obj['app']} />
|
||||
</div>
|
||||
{/if}
|
||||
<span class="mr-2">{obj[extraField]}</span><span class="font-normal break-words"
|
||||
>{obj['path'] ?? ''}</span
|
||||
>
|
||||
</p>
|
||||
<p class="text-xs italic">{obj['description'] ?? ''}</p>
|
||||
{#if `resource_type` in obj}
|
||||
<div class="mr-2 truncate text-left w-24 text-sm">
|
||||
<IconedResourceType after={true} name={obj['resource_type']} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex flex-col">
|
||||
<div class="text-sm font-semibold flex flex-col">
|
||||
<span class="mr-2 text-left">{obj[extraField] ?? ''}</span>
|
||||
{#if extraField != 'path'}
|
||||
<span class="font-normal text-xs text-left italic overflow-hidden"
|
||||
>{obj['path'] ?? ''}</span
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{#if extraField != 'description'}
|
||||
<div class="text-xs font-light italic text-left">{obj['description'] ?? ''}</div
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</button>
|
||||
{#if buttons}
|
||||
<div class="flex flex-row">
|
||||
{#each Object.entries(buttons) as [name, button]}
|
||||
<button
|
||||
class="py-4 px-1 gap-1 flex flex-row grow hover:bg-white hover:border text-black"
|
||||
on:click={() => {
|
||||
button(obj['path'] ?? '')
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
@@ -86,7 +116,7 @@
|
||||
<span class="mt-2 text-sm text-red-400">{noItemMessage}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<span slot="submission">
|
||||
<span slot="submission" class="mr-2">
|
||||
<slot name="submission" />
|
||||
</span>
|
||||
</DrawerContent>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import ResourceTypePicker from './ResourceTypePicker.svelte'
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import autosize from 'svelte-autosize'
|
||||
import SimpleEditor from './SimpleEditor.svelte'
|
||||
|
||||
let path = ''
|
||||
let initialPath = ''
|
||||
@@ -37,6 +38,8 @@
|
||||
let variableEditor: VariableEditor
|
||||
let drawer: Drawer
|
||||
|
||||
let rawCode: string | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export async function initNew(rt?: string) {
|
||||
@@ -58,8 +61,8 @@
|
||||
resourceToEdit = await ResourceService.getResource({ workspace: $workspaceStore!, path: p })
|
||||
description = resourceToEdit!.description ?? ''
|
||||
selectedResourceType = resourceToEdit!.resource_type
|
||||
await loadResourceType()
|
||||
args = resourceToEdit!.value
|
||||
await loadResourceType()
|
||||
drawer.openDrawer()
|
||||
}
|
||||
|
||||
@@ -77,6 +80,14 @@
|
||||
async function editResource(): Promise<void> {
|
||||
try {
|
||||
if (resourceToEdit) {
|
||||
if (rawCode != undefined) {
|
||||
try {
|
||||
args = JSON.parse(rawCode)
|
||||
} catch (e) {
|
||||
sendUserToast("Couldn't parse the content as JSON", true)
|
||||
return
|
||||
}
|
||||
}
|
||||
await ResourceService.updateResource({
|
||||
workspace: $workspaceStore!,
|
||||
path: resourceToEdit.path,
|
||||
@@ -95,13 +106,18 @@
|
||||
|
||||
async function loadResourceType(): Promise<void> {
|
||||
if (selectedResourceType) {
|
||||
resourceType = await ResourceService.getResourceType({
|
||||
workspace: $workspaceStore!,
|
||||
path: selectedResourceType
|
||||
})
|
||||
try {
|
||||
resourceType = await ResourceService.getResourceType({
|
||||
workspace: $workspaceStore!,
|
||||
path: selectedResourceType
|
||||
})
|
||||
|
||||
if (resourceType.schema) {
|
||||
resourceSchema = resourceType.schema as Schema
|
||||
if (resourceType.schema) {
|
||||
resourceSchema = resourceType.schema as Schema
|
||||
}
|
||||
} catch (err) {
|
||||
resourceSchema = undefined
|
||||
rawCode = JSON.stringify(args, null, 2)
|
||||
}
|
||||
} else {
|
||||
sendUserToast(`ResourceType cannot be undefined.`, true)
|
||||
@@ -194,7 +210,9 @@
|
||||
</div>
|
||||
{/each}
|
||||
{:else}
|
||||
<div>Invalid schema</div>
|
||||
<div class="h-full w-full">
|
||||
<SimpleEditor class="editor" lang="json" bind:code={rawCode} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -3,8 +3,10 @@ import type { Script } from "./gen"
|
||||
export const PYTHON_INIT_CODE = `import os
|
||||
import wmill
|
||||
|
||||
# You can import any package from PyPI, even if the assistant complains
|
||||
|
||||
"""
|
||||
Use Cmd/Ctrl + S to autoformat the code.
|
||||
Use Cmd/Ctrl + S to autoformat the code. Reset content in the bar to start from a clean template.
|
||||
The client is used to interact with windmill itself through its standard API.
|
||||
One can explore the methods available through autocompletion of \`wmill.XXX\`.
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user