mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 00:02:19 +00:00
simplify resource picker
This commit is contained in:
@@ -1,24 +1,59 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import { emptySchema, emptyString } from '$lib/utils'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import SimpleEditor from './SimpleEditor.svelte'
|
||||
|
||||
export let resource_type: string
|
||||
export let args: Record<string, any> = {}
|
||||
export let args: Record<string, any> | any = {}
|
||||
export let password: string
|
||||
export let isValid = true
|
||||
|
||||
let schema = emptySchema()
|
||||
let notFound = false
|
||||
async function loadSchema() {
|
||||
const rt = await ResourceService.getResourceType({
|
||||
workspace: $workspaceStore!,
|
||||
path: resource_type
|
||||
})
|
||||
schema = rt.schema
|
||||
try {
|
||||
const rt = await ResourceService.getResourceType({
|
||||
workspace: $workspaceStore!,
|
||||
path: resource_type
|
||||
})
|
||||
schema = rt.schema
|
||||
notFound = false
|
||||
} catch (e) {
|
||||
rawCode = '{}'
|
||||
|
||||
notFound = true
|
||||
}
|
||||
}
|
||||
$: {
|
||||
$workspaceStore && loadSchema()
|
||||
}
|
||||
$: notFound && rawCode && parseJson()
|
||||
|
||||
function parseJson() {
|
||||
try {
|
||||
args = JSON.parse(rawCode)
|
||||
error = ''
|
||||
isValid = true
|
||||
} catch (e) {
|
||||
isValid = false
|
||||
error = e.message
|
||||
}
|
||||
}
|
||||
let error = ''
|
||||
let rawCode = ''
|
||||
</script>
|
||||
|
||||
<SchemaForm {password} isValid {schema} bind:args />
|
||||
{#if notFound}
|
||||
<p class="italic text-gray-500 text-xs mb-4"
|
||||
>No corresponding resource type found in your workspace for {resource_type}. Define the value in
|
||||
JSON directly</p
|
||||
>
|
||||
{#if !emptyString(error)}<span class="text-red-400 text-xs mb-1 flex flex-row-reverse"
|
||||
>{error}</span
|
||||
>{:else}<div class="py-2" />{/if}
|
||||
<SimpleEditor autoHeight lang="json" bind:code={rawCode} fixedOverflowWidgets={false} />
|
||||
{:else}
|
||||
<SchemaForm {password} isValid {schema} bind:args />
|
||||
{/if}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
let connectsManual:
|
||||
| [string, { img?: string; instructions: string[]; key?: string }][]
|
||||
| undefined = undefined
|
||||
let args = {}
|
||||
let args: any = {}
|
||||
|
||||
$: key =
|
||||
apiTokenApps[resource_type]?.key ??
|
||||
@@ -237,12 +237,15 @@
|
||||
(step == 1 && resource_type == '') ||
|
||||
(step == 2 &&
|
||||
value == '' &&
|
||||
args &&
|
||||
args['token'] == '' &&
|
||||
args['password'] == '' &&
|
||||
args['api_key'] == '' &&
|
||||
key != undefined) ||
|
||||
(step == 3 && pathError != '')
|
||||
(step == 3 && pathError != '') ||
|
||||
!isValid
|
||||
|
||||
let isValid = true
|
||||
let filteredConnects: [string, { scopes: string[]; extra_params?: Record<string, string> }][] = []
|
||||
let filteredConnectsManual: [string, { img?: string; instructions: string[]; key?: string }][] =
|
||||
[]
|
||||
@@ -401,7 +404,7 @@
|
||||
|
||||
<h2 class="mt-4">Value</h2>
|
||||
<div class="mt-4">
|
||||
<ApiConnectForm password={key ?? ''} {resource_type} bind:args />
|
||||
<ApiConnectForm password={key ?? ''} {resource_type} bind:args bind:isValid />
|
||||
</div>
|
||||
{:else}
|
||||
<Path
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
import { getScriptByPath, loadHubScripts, sendUserToast } from '$lib/utils'
|
||||
|
||||
import {
|
||||
faCode,
|
||||
faCube,
|
||||
faDollarSign,
|
||||
faEye,
|
||||
@@ -246,7 +245,7 @@
|
||||
on:click={variablePicker.openDrawer}
|
||||
size="xs"
|
||||
spacingSize="md"
|
||||
startIcon={{ icon: faWallet }}
|
||||
startIcon={{ icon: faDollarSign }}
|
||||
{iconOnly}
|
||||
>
|
||||
+Variable
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService } from '$lib/gen'
|
||||
import { logout } from '$lib/logout'
|
||||
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { ToggleButton, ToggleButtonGroup } from './common'
|
||||
import ResourcePicker from './ResourcePicker.svelte'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import SimpleEditor from './SimpleEditor.svelte'
|
||||
|
||||
export let format: string
|
||||
export let value: any
|
||||
export let compact: boolean
|
||||
|
||||
function isString(value: any) {
|
||||
return typeof value === 'string' || value instanceof String
|
||||
@@ -20,11 +15,8 @@
|
||||
let args: Record<string, any> = {}
|
||||
|
||||
let schema: any | undefined = undefined
|
||||
let isValid = true
|
||||
let resourceTypeName: string = ''
|
||||
|
||||
let option: 'resource' | 'raw' = isString(value) || value == undefined ? 'resource' : 'raw'
|
||||
|
||||
$: format.startsWith('resource-') && loadSchema(format)
|
||||
|
||||
async function loadSchema(format: string) {
|
||||
@@ -41,10 +33,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function argToValue() {
|
||||
value = args
|
||||
}
|
||||
|
||||
function resourceToValue() {
|
||||
value = `$res:${path}`
|
||||
}
|
||||
@@ -60,8 +48,6 @@
|
||||
|
||||
if (isResource()) {
|
||||
path = value.substr('$res:'.length)
|
||||
} else if (value !== undefined && value !== '') {
|
||||
option = 'raw'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,44 +55,13 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row w-full flex-wrap gap-x-2 gap-y-0.5">
|
||||
<ToggleButtonGroup
|
||||
col
|
||||
bind:selected={option}
|
||||
on:selected={(e) => {
|
||||
if (e.detail === 'resource') {
|
||||
resourceToValue()
|
||||
} else {
|
||||
argToValue()
|
||||
}
|
||||
<ResourcePicker
|
||||
on:refresh={() => loadSchema(format)}
|
||||
on:change={(e) => {
|
||||
path = e.detail
|
||||
resourceToValue()
|
||||
}}
|
||||
>
|
||||
<ToggleButton light position="center" value="resource" size="xs">Resource</ToggleButton>
|
||||
<ToggleButton light position="center" value="raw" size="xs">Raw</ToggleButton>
|
||||
</ToggleButtonGroup>
|
||||
|
||||
<div class="grow flex items-center">
|
||||
{#if option == 'resource'}
|
||||
<ResourcePicker
|
||||
on:refresh={() => loadSchema(format)}
|
||||
on:change={(e) => {
|
||||
path = e.detail
|
||||
resourceToValue()
|
||||
}}
|
||||
bind:value={path}
|
||||
resourceType={format.split('-').length > 1
|
||||
? format.substring('resource-'.length)
|
||||
: undefined}
|
||||
/>
|
||||
{:else}
|
||||
<div class="border rounded p-2 w-full">
|
||||
{#if schema != undefined}
|
||||
{#if !isString(args)}
|
||||
<SchemaForm {compact} {schema} bind:isValid bind:args />
|
||||
{/if}
|
||||
{:else}
|
||||
<SimpleEditor autoHeight lang="json" bind:value={args} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
bind:value={path}
|
||||
resourceType={format.split('-').length > 1 ? format.substring('resource-'.length) : undefined}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { type Resource, ResourceService, type ResourceType, VariableService } from '$lib/gen'
|
||||
import { canWrite, sendUserToast } from '$lib/utils'
|
||||
import { canWrite, emptyString, sendUserToast } from '$lib/utils'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { Schema } from '$lib/common'
|
||||
import Path from './Path.svelte'
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
let path = ''
|
||||
let initialPath = ''
|
||||
let pathError = ''
|
||||
|
||||
let resourceToEdit: Resource | undefined
|
||||
|
||||
@@ -28,8 +27,6 @@
|
||||
let can_write = true
|
||||
let loadingSchema = false
|
||||
|
||||
let error: string | undefined
|
||||
|
||||
let drawer: Drawer
|
||||
|
||||
let rawCode: string | undefined = undefined
|
||||
@@ -56,14 +53,6 @@
|
||||
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,
|
||||
@@ -103,6 +92,18 @@
|
||||
}
|
||||
|
||||
let isValid = true
|
||||
let jsonError = ''
|
||||
|
||||
$: rawCode && parseJson()
|
||||
|
||||
function parseJson() {
|
||||
try {
|
||||
args = JSON.parse(rawCode ?? '')
|
||||
jsonError = ''
|
||||
} catch (e) {
|
||||
jsonError = e.message
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={drawer} size="800px">
|
||||
@@ -120,11 +121,8 @@
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<span class="text-red-600 text-2xs grow">{error ?? ''}</span>
|
||||
<Path
|
||||
disabled={!can_write}
|
||||
bind:error={pathError}
|
||||
bind:path
|
||||
{initialPath}
|
||||
namePlaceholder="my_resource"
|
||||
@@ -155,16 +153,30 @@
|
||||
{:else if !can_write}
|
||||
<input type="text" disabled value={rawCode} />
|
||||
{:else}
|
||||
<p class="italic text-gray-500 text-xs mb-4"
|
||||
>No corresponding resource type found in your workspace for {selectedResourceType}.
|
||||
Define the value in JSON directly</p
|
||||
>
|
||||
{#if !emptyString(jsonError)}<span
|
||||
class="text-red-400 text-xs mb-1 flex flex-row-reverse">{jsonError}</span
|
||||
>{:else}<div class="py-2" />{/if}
|
||||
<div class="h-full w-full">
|
||||
<SimpleEditor class="editor" lang="json" bind:code={rawCode} />
|
||||
<SimpleEditor
|
||||
class="editor"
|
||||
lang="json"
|
||||
bind:code={rawCode}
|
||||
fixedOverflowWidgets={false}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="submission" class="flex gap-4 mr-2">
|
||||
<Button startIcon={{ icon: faSave }} on:click={editResource} disabled={!can_write || !isValid}
|
||||
>Save</Button
|
||||
<Button
|
||||
startIcon={{ icon: faSave }}
|
||||
on:click={editResource}
|
||||
disabled={!can_write || !isValid || jsonError != ''}>Save</Button
|
||||
>
|
||||
</span>
|
||||
</DrawerContent>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService, type Resource } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { faPlus, faRotateRight } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faPen, faPlus, faRotateRight } from '@fortawesome/free-solid-svg-icons'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
import { Button } from './common'
|
||||
import Select from 'svelte-select'
|
||||
import AppConnect from './AppConnect.svelte'
|
||||
import ResourceEditor from './ResourceEditor.svelte'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let resources: Resource[] = []
|
||||
@@ -32,6 +33,7 @@
|
||||
label: `${x.path}${x.description ? ' | ' + x.description : ''}`
|
||||
}))
|
||||
let appConnect: AppConnect
|
||||
let resourceEditor: ResourceEditor
|
||||
</script>
|
||||
|
||||
<AppConnect
|
||||
@@ -43,14 +45,22 @@
|
||||
bind:this={appConnect}
|
||||
/>
|
||||
|
||||
<ResourceEditor bind:this={resourceEditor} on:refresh={() => loadResources(resourceType)} />
|
||||
|
||||
<div class="flex flex-row gap-x-1 w-full">
|
||||
<Select
|
||||
value={collection.find((x) => x.value == value)}
|
||||
bind:justValue={value}
|
||||
items={collection}
|
||||
class="grow"
|
||||
class="text-clip grow min-w-0"
|
||||
placeholder="Pick a {resourceType} resource"
|
||||
/>
|
||||
{#if value && value != ''}
|
||||
<Button variant="border" size="xs" on:click={() => resourceEditor?.initEdit?.(value ?? '')}>
|
||||
<Icon scale={0.8} data={faPen} /></Button
|
||||
>
|
||||
{/if}
|
||||
|
||||
<Button variant="border" size="xs" on:click={() => appConnect?.open?.(resourceType)}>
|
||||
<Icon scale={0.8} data={faPlus} /></Button
|
||||
>
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
export let extraLib: string = ''
|
||||
export let shouldBindKey: boolean = true
|
||||
export let autoHeight = false
|
||||
export let fixedOverflowWidgets = true
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -107,7 +108,7 @@
|
||||
|
||||
editor = monaco.editor.create(
|
||||
divEl as HTMLDivElement,
|
||||
editorConfig(model, code, lang, automaticLayout, true)
|
||||
editorConfig(model, code, lang, automaticLayout, fixedOverflowWidgets)
|
||||
)
|
||||
|
||||
let timeoutModel: NodeJS.Timeout | undefined = undefined
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
faPlay,
|
||||
faRobot,
|
||||
faUsersCog,
|
||||
faWallet,
|
||||
faCog,
|
||||
faStar
|
||||
faStar,
|
||||
faDollarSign
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||
import MenuLink from './MenuLink.svelte'
|
||||
@@ -19,7 +19,7 @@
|
||||
const mainMenuLinks = [
|
||||
{ label: 'Home', href: '/', icon: faHomeAlt },
|
||||
{ label: 'Runs', href: '/runs', icon: faPlay },
|
||||
{ label: 'Variables', href: '/variables', icon: faWallet },
|
||||
{ label: 'Variables', href: '/variables', icon: faDollarSign },
|
||||
{ label: 'Resources', href: '/resources', icon: faCubes }
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user