mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 08:01:35 +00:00
add multiselect novelties to <AppSelect />, harmonize, clean <AppSelect />
This commit is contained in:
@@ -60,11 +60,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: resolvedConfig.defaultItems && handleDefaultItems()
|
||||
$: resolvedConfig.defaultValues && handleDefaultValues()
|
||||
|
||||
function handleDefaultItems() {
|
||||
if (Array.isArray(resolvedConfig.defaultItems)) {
|
||||
const nvalue = resolvedConfig.defaultItems?.map((label) => {
|
||||
function handleDefaultValues() {
|
||||
if (Array.isArray(resolvedConfig.defaultValues)) {
|
||||
const nvalue = resolvedConfig.defaultValues?.map((label) => {
|
||||
return typeof label === 'string' ? label : `NOT_STRING`
|
||||
})
|
||||
value = [...new Set(nvalue)]
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
import { offset, flip, shift } from 'svelte-floating-ui/dom'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
import MultiSelect from '$lib/components/multiselect/MultiSelect.svelte'
|
||||
import { isObjectOptionArray, isStringArray, type ObjectOption } from '../../../multiselect/types'
|
||||
import type { ObjectOption } from '../../../multiselect/types'
|
||||
import { parseConfigOptions } from './utils'
|
||||
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'multiselectcomponent'> | undefined = undefined
|
||||
@@ -56,7 +57,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: resolvedConfig.defaultItems && parseDefaultItems()
|
||||
$: if (resolvedConfig.defaultValues) {
|
||||
selectOptionsByValue(resolvedConfig.defaultValues)
|
||||
}
|
||||
|
||||
$: outerDiv &&
|
||||
portalRef &&
|
||||
@@ -75,65 +78,14 @@
|
||||
}
|
||||
|
||||
function selectOptionsByValue(values: any[]) {
|
||||
if (!Array.isArray(values)) {
|
||||
outputs?.result.set([])
|
||||
}
|
||||
|
||||
selectedOptions = findOptionsByValue(values)
|
||||
outputs?.result.set([...(selectedOptions.map((option) => option.value) ?? [])])
|
||||
}
|
||||
|
||||
function parseConfigOptions(resolvedConfigItems) {
|
||||
if (!resolvedConfigItems) {
|
||||
return []
|
||||
}
|
||||
if (isObjectOptionArray(resolvedConfigItems)) {
|
||||
return parseLabeledItems(resolvedConfigItems)
|
||||
} else if (isStringArray(resolvedConfigItems)) {
|
||||
return parseStringItems(resolvedConfigItems)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
function parseLabeledItems(resolvedConfigItems: ObjectOption[]) {
|
||||
return resolvedConfigItems?.map((item: ObjectOption) => {
|
||||
if (!item || typeof item !== 'object') {
|
||||
console.error(
|
||||
'When labeled, MultiSelect component items should be an array of { label: string, value: string }.'
|
||||
)
|
||||
return {
|
||||
label: 'not object',
|
||||
value: 'not object'
|
||||
}
|
||||
}
|
||||
return {
|
||||
label: item?.label ?? 'undefined',
|
||||
value:
|
||||
typeof item?.value === 'object' ? JSON.stringify(item.value) : item?.value ?? 'undefined'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function parseStringItems(resolvedConfigItems: any[]): ObjectOption[] {
|
||||
return resolvedConfigItems?.map((option: string) => {
|
||||
if (option === null || option === undefined || typeof option !== 'string') {
|
||||
console.error(
|
||||
'When not labeled, MultiSelect component items should be an array of strings.'
|
||||
)
|
||||
return { label: 'not string', value: 'not string' }
|
||||
}
|
||||
if (option === '') {
|
||||
return { label: 'empty string', value: 'empty string' }
|
||||
}
|
||||
return { label: option, value: option }
|
||||
})
|
||||
}
|
||||
|
||||
function parseDefaultItems() {
|
||||
if (!Array.isArray(resolvedConfig.defaultItems)) {
|
||||
outputs?.result.set([])
|
||||
return
|
||||
}
|
||||
|
||||
selectOptionsByValue(resolvedConfig.defaultItems)
|
||||
}
|
||||
|
||||
function setOuterDivStyle(outerDiv: HTMLDivElement, portalRef: HTMLDivElement, style: string) {
|
||||
outerDiv.setAttribute('style', style)
|
||||
// find ul in portalRef and set style
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
import type { ObjectOption } from '$lib/components/multiselect/types'
|
||||
import { parseConfigOptions } from './utils'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
@@ -42,8 +43,8 @@
|
||||
} = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
$componentControl[id] = {
|
||||
setValue(nvalue: string) {
|
||||
setValue(JSON.stringify(nvalue))
|
||||
setValue(newValue: any) {
|
||||
setValue(newValue)
|
||||
}
|
||||
}
|
||||
if (controls) {
|
||||
@@ -60,13 +61,12 @@
|
||||
})
|
||||
|
||||
// The library expects double quotes around the value
|
||||
let value: string | undefined = noDefault
|
||||
? undefined
|
||||
: outputs?.result.peak()
|
||||
? JSON.stringify(outputs?.result.peak())
|
||||
: undefined
|
||||
let selectedValue: string | undefined
|
||||
|
||||
$: resolvedConfig.items && handleItems()
|
||||
$: if (resolvedConfig.items) {
|
||||
options = parseConfigOptions(resolvedConfig.items)
|
||||
updateSelectedValue()
|
||||
}
|
||||
|
||||
$: resolvedConfig.defaultValue != undefined && handleDefault()
|
||||
let filterText = ''
|
||||
@@ -74,35 +74,20 @@
|
||||
|
||||
let previsousFilter = ''
|
||||
|
||||
function handleItems() {
|
||||
options = Array.isArray(resolvedConfig.items)
|
||||
? resolvedConfig.items.map((item) => {
|
||||
if (!item || typeof item !== 'object') {
|
||||
console.error('Select component items should be an array of objects')
|
||||
return {
|
||||
label: 'not object',
|
||||
value: 'not object'
|
||||
}
|
||||
}
|
||||
return {
|
||||
label: item?.label ?? 'undefined',
|
||||
value: item?.value != undefined ? JSON.stringify(item.value) : 'undefined'
|
||||
}
|
||||
})
|
||||
: []
|
||||
|
||||
if (value != undefined && options.some((x) => x.value === value)) {
|
||||
function updateSelectedValue() {
|
||||
if (selectedValue != undefined && options.some((x) => x.value === selectedValue)) {
|
||||
return
|
||||
}
|
||||
let rawValue
|
||||
let newValue: string | undefined
|
||||
if (resolvedConfig.defaultValue !== undefined) {
|
||||
rawValue = resolvedConfig.defaultValue
|
||||
newValue = resolvedConfig.defaultValue
|
||||
} else if (options.length > 0 && resolvedConfig?.preselectFirst) {
|
||||
rawValue = resolvedConfig.items[0].value
|
||||
newValue = resolvedConfig.items[0].value
|
||||
}
|
||||
if (rawValue !== undefined && rawValue !== null) {
|
||||
value = JSON.stringify(rawValue)
|
||||
outputs?.result.set(rawValue)
|
||||
|
||||
if (newValue !== undefined && newValue !== null) {
|
||||
selectedValue = newValue
|
||||
outputs?.result.set(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,13 +113,9 @@
|
||||
setValue(value)
|
||||
}
|
||||
|
||||
function setValue(nvalue: any) {
|
||||
let result: any = undefined
|
||||
try {
|
||||
result = JSON.parse(nvalue)
|
||||
} catch (_) {}
|
||||
value = nvalue
|
||||
outputs?.result.set(result)
|
||||
function setValue(newValue: any) {
|
||||
selectedValue = newValue
|
||||
outputs?.result.set(newValue)
|
||||
|
||||
if (recomputeIds) {
|
||||
recomputeIds.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((f) => f()))
|
||||
@@ -142,11 +123,11 @@
|
||||
}
|
||||
|
||||
function onClear() {
|
||||
value = undefined
|
||||
selectedValue = undefined
|
||||
outputs?.result.set(undefined, true)
|
||||
}
|
||||
|
||||
function handleFilter(e) {
|
||||
function handleFilter() {
|
||||
if (resolvedConfig.create && filterText !== previsousFilter) {
|
||||
previsousFilter = filterText
|
||||
if (filterText.length > 0) {
|
||||
@@ -156,21 +137,18 @@
|
||||
(item) => item.label.toString().toLowerCase() === filterText.toLowerCase()
|
||||
)
|
||||
if (!exists) {
|
||||
options = [
|
||||
...prev,
|
||||
{ value: JSON.stringify(filterText), label: filterText, created: true }
|
||||
]
|
||||
options = [...prev, { value: filterText, label: filterText, created: true }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleDefault() {
|
||||
if (resolvedConfig.defaultValue != undefined) {
|
||||
const nvalue = resolvedConfig.defaultValue
|
||||
value = JSON.stringify(nvalue)
|
||||
outputs?.result.set(nvalue)
|
||||
if (!!noDefault || resolvedConfig.defaultValue !== undefined) {
|
||||
return
|
||||
}
|
||||
selectedValue = resolvedConfig.defaultValue
|
||||
outputs?.result.set(resolvedConfig.defaultValue)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -215,7 +193,7 @@
|
||||
<option value="" disabled selected>{resolvedConfig.placeholder}</option>
|
||||
{/if}
|
||||
{#each options as item (item.value)}
|
||||
<option value={item.value} selected={item.value === value}>{item.label}</option>
|
||||
<option value={item.value} selected={item.value === selectedValue}>{item.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
@@ -234,7 +212,7 @@
|
||||
containerStyles={($darkMode
|
||||
? SELECT_INPUT_DEFAULT_STYLE.containerStylesDark
|
||||
: SELECT_INPUT_DEFAULT_STYLE.containerStyles) + css?.input?.style}
|
||||
{value}
|
||||
value={selectedValue}
|
||||
class={css?.input?.class}
|
||||
placeholder={resolvedConfig.placeholder}
|
||||
disabled={resolvedConfig.disabled}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
type ObjectOption,
|
||||
isObjectOptionArray,
|
||||
isStringArray
|
||||
} from '$lib/components/multiselect/types'
|
||||
import type { StaticAppInput } from '../../inputType'
|
||||
|
||||
export function parseConfigOptions(resolvedConfigItems: StaticAppInput) {
|
||||
if (!resolvedConfigItems) {
|
||||
return []
|
||||
}
|
||||
if (isObjectOptionArray(resolvedConfigItems)) {
|
||||
return parseLabeledItems(resolvedConfigItems)
|
||||
} else if (isStringArray(resolvedConfigItems)) {
|
||||
return parseStringItems(resolvedConfigItems)
|
||||
}
|
||||
return []
|
||||
}
|
||||
export function parseLabeledItems(resolvedConfigItems: ObjectOption[]) {
|
||||
return resolvedConfigItems?.map((item: ObjectOption) => {
|
||||
if (!item || typeof item !== 'object') {
|
||||
console.error(
|
||||
'When labeled, MultiSelect component items should be an array of { label: string, value: string }.'
|
||||
)
|
||||
return {
|
||||
label: 'not object',
|
||||
value: 'not object'
|
||||
}
|
||||
}
|
||||
return {
|
||||
label: item?.label ?? 'undefined',
|
||||
value:
|
||||
typeof item?.value === 'object' ? JSON.stringify(item.value) : item?.value ?? 'undefined'
|
||||
}
|
||||
})
|
||||
}
|
||||
export function parseStringItems(resolvedConfigItems: string[]): ObjectOption[] {
|
||||
return resolvedConfigItems?.map((option: string) => {
|
||||
if (option === null || option === undefined || typeof option !== 'string') {
|
||||
console.error('When not labeled, MultiSelect component items should be an array of strings.')
|
||||
return { label: 'not string', value: 'not string' }
|
||||
}
|
||||
if (option === '') {
|
||||
return { label: 'empty string', value: 'empty string' }
|
||||
}
|
||||
return { label: option, value: option }
|
||||
})
|
||||
}
|
||||
@@ -2079,7 +2079,8 @@ This is a paragraph.
|
||||
value: [
|
||||
{ value: 'foo', label: 'Foo' },
|
||||
{ value: 'bar', label: 'Bar' }
|
||||
]
|
||||
],
|
||||
hasLabeledMode: true
|
||||
} as StaticAppInput,
|
||||
create: {
|
||||
type: 'static',
|
||||
@@ -2150,7 +2151,7 @@ This is a paragraph.
|
||||
subFieldType: 'text',
|
||||
value: ['Foo', 'Bar']
|
||||
} as StaticAppInput,
|
||||
defaultItems: {
|
||||
defaultValues: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'text',
|
||||
@@ -2203,7 +2204,7 @@ This is a paragraph.
|
||||
value: ['Foo', 'Bar'],
|
||||
hasLabeledMode: true
|
||||
} as StaticAppInput,
|
||||
defaultItems: {
|
||||
defaultValues: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'simplestringselect',
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
dispatch('componentInputChange', newComponentInput)
|
||||
}
|
||||
|
||||
/** Transforms items string[] to ObjectOption[ and vice versa. Mutating items will fire handleItemsChange. */
|
||||
/** Transforms items string[] to ObjectOption] and vice versa. Mutating items will fire handleItemsChange. */
|
||||
function handleLabeledChange() {
|
||||
if (labeled && isStringArray(items.map((item) => item.value))) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
|
||||
Reference in New Issue
Block a user