feat(frontend): array of resources (#4095)

* feat(frontend): wip

* feat(frontend): wip

* feat(frontend): add support for array of resources

* feat(frontend): improve code

* feat(frontend): add support for array of resources in the flow and app editors

* feat(frontend): improve code

* feat(frontend): display the detected resource type

* fix(frontend): Fix PR comments + add warning on the value format

* fix(frontend): improve code
This commit is contained in:
Faton Ramadani
2024-07-17 17:16:58 +02:00
committed by GitHub
parent 361ef53fb5
commit 87e01fe926
6 changed files with 82 additions and 34 deletions
+2 -1
View File
@@ -26,9 +26,10 @@ export interface SchemaProperty {
contentEncoding?: 'base64' | 'binary'
format?: string
items?: {
type?: 'string' | 'number' | 'bytes' | 'object'
type?: 'string' | 'number' | 'bytes' | 'object' | 'resource'
contentEncoding?: 'base64'
enum?: string[]
resourceType?: string
}
min?: number
max?: number
+6 -2
View File
@@ -47,12 +47,14 @@
export let disabled = false
export let itemsType:
| {
type?: 'string' | 'number' | 'bytes' | 'object'
type?: 'string' | 'number' | 'bytes' | 'object' | 'resource'
contentEncoding?: 'base64'
enum?: string[]
multiselect?: string[]
resourceType?: string
}
| undefined = undefined
export let displayHeader = true
export let properties: { [name: string]: SchemaProperty } | undefined = undefined
export let nestedRequired: string[] | undefined = undefined
@@ -372,7 +374,7 @@
on:change={(x) => fileChanged(x, (val) => (value[i] = val))}
multiple={false}
/>
{:else if itemsType?.type == 'object'}
{:else if itemsType?.type == 'object' && itemsType?.resourceType === undefined}
<JsonEditor code={JSON.stringify(v, null, 2)} bind:value={v} />
{:else if Array.isArray(itemsType?.enum)}
<ArgEnum
@@ -392,6 +394,8 @@
enum_={itemsType?.enum ?? []}
enumLabels={extra['enumLabels']}
/>
{:else if itemsType?.type == 'resource' && itemsType?.resourceType}
<ResourcePicker bind:value={v} resourceType={itemsType?.resourceType} />
{:else}
<input type="text" bind:value={v} id="arg-input-array" />
{/if}
@@ -3,16 +3,21 @@
import { Button } from './common'
import { fade } from 'svelte/transition'
import Label from './Label.svelte'
import ResourceTypePicker from './ResourceTypePicker.svelte'
import Badge from './common/badge/Badge.svelte'
import Alert from './common/alert/Alert.svelte'
export let canEditResourceType: boolean = false
export let itemsType:
| {
type?: 'string' | 'number' | 'bytes' | 'object'
type?: 'string' | 'number' | 'bytes' | 'object' | 'resource'
contentEncoding?: 'base64'
enum?: string[]
resourceType?: string
}
| undefined
let selected: 'string' | 'number' | 'object' | 'bytes' | 'enum' | undefined =
let selected: 'string' | 'number' | 'object' | 'bytes' | 'enum' | 'resource' | undefined =
itemsType?.type != 'string'
? itemsType?.type
: Array.isArray(itemsType?.enum)
@@ -20,33 +25,62 @@
: 'string'
</script>
<Label label="Items type">
<select
bind:value={selected}
on:change={() => {
if (selected == 'enum') {
itemsType = { type: 'string', enum: [] }
} else if (selected == 'string') {
itemsType = { type: 'string' }
} else if (selected == 'number') {
itemsType = { type: 'number' }
} else if (selected == 'object') {
itemsType = { type: 'object' }
} else if (selected == 'bytes') {
itemsType = { type: 'string', contentEncoding: 'base64' }
} else {
itemsType = undefined
}
}}
id="array-type-narrowing"
{#if canEditResourceType}
<Label label="Items type">
<select
bind:value={selected}
on:change={() => {
if (selected == 'enum') {
itemsType = { type: 'string', enum: [] }
} else if (selected == 'string') {
itemsType = { type: 'string' }
} else if (selected == 'number') {
itemsType = { type: 'number' }
} else if (selected == 'object') {
itemsType = { type: 'object' }
} else if (selected == 'bytes') {
itemsType = { type: 'string', contentEncoding: 'base64' }
} else if (selected == 'resource') {
itemsType = { type: 'resource', resourceType: itemsType?.resourceType }
} else {
itemsType = undefined
}
}}
id="array-type-narrowing"
>
<option value="string"> Items are strings</option>
<option value="enum">Items are strings from an enum</option>
<option value="object"> Items are objects (JSON)</option>
<option value="resource"> Items are resources</option>
<option value="number">Items are numbers</option>
<option value="bytes">Items are bytes</option>
</select>
</Label>
{:else}
<Label label="Resource type">
<Badge color="blue">
{itemsType?.resourceType}
</Badge>
</Label>
{/if}
{#if itemsType?.type === 'resource'}
<Alert
type="warning"
title="Value"
size="xs"
tooltip="Learn how to use the SDK to get the resource by using the path."
documentationLink="https://www.windmill.dev/docs/code_editor/add_variables_resources#fetching-them-from-within-a-script-by-using-the-wmill-client-in-the-respective-language"
>
<option value="string"> Items are strings</option>
<option value="enum">Items are strings from an enum</option>
<option value="object"> Items are objects (JSON)</option>
<option value="number">Items are numbers</option>
<option value="bytes">Items are bytes</option>
</select>
</Label>
The value passed is the path of the resource, not the resource itself. You can use the SDK to
get the resource by using the path.
</Alert>
{/if}
{#if canEditResourceType && itemsType?.type == 'resource'}
<ResourceTypePicker bind:value={itemsType.resourceType} />
{/if}
{#if Array.isArray(itemsType?.enum)}
<label for="input" class="text-secondary text-xs">
Enums
@@ -40,10 +40,11 @@
export let enum_: EnumType = undefined
export let itemsType:
| {
type?: 'string' | 'number' | 'bytes' | 'object'
type?: 'string' | 'number' | 'bytes' | 'object' | 'resource'
contentEncoding?: 'base64'
enum?: string[]
multiselect?: string[]
resourceType?: string
}
| undefined = undefined
export let displayHeader = true
@@ -329,6 +330,11 @@
<option>{e}</option>
{/each}
</select>
{:else if itemsType?.type == 'resource' && itemsType?.resourceType}
<LightweightResourcePicker
bind:value={v}
resourceType={itemsType?.resourceType}
/>
{:else}
<input type="text" bind:value={v} />
{/if}
@@ -34,9 +34,10 @@
export let order: string[] | undefined = undefined
export let itemsType:
| {
type?: 'string' | 'number' | 'bytes' | 'object'
type?: 'string' | 'number' | 'bytes' | 'object' | 'resource'
contentEncoding?: 'base64'
enum?: string[]
resourceType?: string
multiselect?: string[]
}
| undefined = undefined
@@ -157,7 +158,7 @@
</Label>
{#if type == 'array'}
<ArrayTypeNarrowing bind:itemsType />
<ArrayTypeNarrowing bind:itemsType canEditResourceType={isFlowInput || isAppInput} />
{:else if type == 'string' || ['number', 'integer', 'object'].includes(type ?? '')}
<div>
<Label label="Field settings">
+2
View File
@@ -101,6 +101,8 @@ export function argSigToJsonSchemaType(
newS.items = { type: 'string' }
} else if (t.list && typeof t.list == 'object' && 'str' in t.list) {
newS.items = { type: 'string', enum: t.list.str }
} else if (t.list && typeof t.list == 'object' && 'resource' in t.list && t.list.resource) {
newS.items = { type: 'resource', resourceType: t.list.resource as string }
} else {
newS.items = { type: 'object' }
}