Skip to content

Commit

Permalink
feat: allow labeled values in app multiselect
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenfiszel committed Nov 21, 2024
1 parent c99d360 commit d5da75c
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import { offset, flip, shift } from 'svelte-floating-ui/dom'
import ResolveStyle from '../helpers/ResolveStyle.svelte'
import MultiSelect from '$lib/components/multiselect/MultiSelect.svelte'
import { deepEqual } from 'fast-equals'
export let id: string
export let configuration: RichConfigurations
Expand All @@ -30,7 +31,7 @@
const { app, worldStore, selectedComponent, componentControl } =
getContext<AppViewerContext>('AppViewerContext')
let items: string[]
let items: (string | { value: string; label: any })[] = []
const resolvedConfig = initConfig(
components['multiselectcomponent'].initialData.configuration,
Expand All @@ -41,34 +42,67 @@
result: [] as string[]
})
let value: string[] | undefined = [...new Set(outputs?.result.peak())] as string[]
let selectedItems: (string | { value: string; label: any })[] | undefined = [
...new Set(outputs?.result.peak())
] as string[]
function setResultsFromSelectedItems() {
outputs?.result.set([
...(selectedItems?.map((item) => {
if (typeof item == 'object' && item.value != undefined && item.label != undefined) {
return item?.value ?? `NOT_STRING`
} else if (typeof item == 'string') {
return item
} else if (typeof item == 'object' && item.label != undefined) {
return item.label
} else {
return 'NOT_STRING'
}
}) ?? [])
])
}
$componentControl[id] = {
setValue(nvalue: string[]) {
value = [...new Set(nvalue)]
outputs?.result.set([...(value ?? [])])
if (Array.isArray(nvalue)) {
setSelectedItemsFromValues(nvalue)
} else {
console.error('Invalid value for multiselect component, expected array', nvalue)
}
}
}
$: resolvedConfig.items && handleItems()
function handleItems() {
if (Array.isArray(resolvedConfig.items)) {
items = resolvedConfig.items?.map((label) => {
return typeof label === 'string' ? label : `NOT_STRING`
items = resolvedConfig.items?.map((item) => {
if (typeof item == 'object' && item.value != undefined && item.label != undefined) {
return item
}
return typeof item === 'string' ? item : `NOT_STRING`
})
}
}
$: resolvedConfig.defaultItems && handleDefaultItems()
function handleDefaultItems() {
if (Array.isArray(resolvedConfig.defaultItems)) {
const nvalue = resolvedConfig.defaultItems?.map((label) => {
return typeof label === 'string' ? label : `NOT_STRING`
})
value = [...new Set(nvalue)]
outputs?.result.set([...(value ?? [])])
$: resolvedConfig.defaultItems && setSelectedItemsFromValues(resolvedConfig.defaultItems)
function setSelectedItemsFromValues(values: any[]) {
if (Array.isArray(values)) {
const nvalue = values
.map((value) => {
return (
items.find((item) => {
if (typeof item == 'object' && item.value != undefined && item.label != undefined) {
return deepEqual(item.value, value)
}
return item == value
}) ?? (typeof value == 'string' ? value : undefined)
)
})
.filter((item) => item != undefined)
selectedItems = [...new Set(nvalue)]
setResultsFromSelectedItems()
}
}
Expand Down Expand Up @@ -143,23 +177,23 @@
use:floatingRef
bind:clientWidth={w}
>
{#if !value || Array.isArray(value)}
{#if !selectedItems || Array.isArray(selectedItems)}
<MultiSelect
bind:outerDiv
outerDivClass={`${resolvedConfig.allowOverflow ? '' : 'h-full'}`}
ulSelectedClass={`${resolvedConfig.allowOverflow ? '' : 'overflow-auto max-h-full'} `}
--sms-border={'none'}
--sms-min-height={'32px'}
--sms-focus-border={'none'}
bind:selected={value}
bind:selected={selectedItems}
options={items}
placeholder={resolvedConfig.placeholder}
allowUserOptions={resolvedConfig.create}
on:change={(event) => {
if (event?.detail?.type === 'removeAll') {
outputs?.result.set([])
} else {
outputs?.result.set([...(value ?? [])])
setResultsFromSelectedItems()
}
}}
on:open={() => {
Expand All @@ -181,7 +215,7 @@
e.target?.['parentElement']?.dispatchEvent(newe)
}}
>
{option}
{typeof option == 'object' ? option?.label ?? 'NO_LABEL' : option}
</div>
</MultiSelect>
<Portal name="app-multiselect-v2">
Expand All @@ -197,7 +231,7 @@
</div>
</Portal>
{:else}
Value {value} is not an array
Value {selectedItems} is not an array
{/if}
</div>
</AlignWrapper>
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,12 @@
function handleItems() {
listItems = Array.isArray(resolvedConfig.items)
? resolvedConfig.items.map((item) => {
if (!item || typeof item !== 'object') {
if (typeof item == 'string') {
return {
label: item,
value: JSON.stringify(item)
}
} else if (!item || typeof item !== 'object') {
console.error('Select component items should be an array of objects')
return {
label: 'not object',
Expand All @@ -113,7 +118,12 @@
if (resolvedConfig.defaultValue !== undefined) {
rawValue = resolvedConfig.defaultValue
} else if (listItems.length > 0 && resolvedConfig?.preselectFirst) {
rawValue = resolvedConfig.items[0].value
let firstItem = resolvedConfig.items[0]
if (typeof firstItem === 'string') {
rawValue = firstItem
} else {
rawValue = resolvedConfig.items[0].value
}
}
if (rawValue !== undefined && rawValue !== null) {
value = JSON.stringify(rawValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,23 @@
$componentControl[id] = {
setValue(nvalue: string) {
selected = nvalue
selectedIndex = resolvedConfig.items.findIndex((item) => item.value === nvalue)
selectedIndex = resolvedConfig.items.findIndex((item) => getValue(item) === nvalue)
},
setTab(index) {
selected = resolvedConfig.items?.[index]?.value
let item = resolvedConfig.items?.[index]
selected = getValue(item)
selectedIndex = index
}
}
function setDefaultValue() {
if (resolvedConfig.defaultValue != undefined) {
selectedIndex = resolvedConfig.items.findIndex(
(item) => item.value === resolvedConfig.defaultValue
(item) => getValue(item) === resolvedConfig.defaultValue
)
}
if (selectedIndex === -1 || resolvedConfig.defaultValue == undefined) {
selected = resolvedConfig.items[0].value
selected = getValue(resolvedConfig.items[0])
} else if (resolvedConfig.defaultValue) {
selected = resolvedConfig.items[selectedIndex].value
}
Expand All @@ -72,6 +73,13 @@
}
}
function getValue(item: string | { label: string; value: string }) {
return typeof item == 'string' ? item : item.value
}
function getLabel(item: string | { label: string; value: string }) {
return typeof item == 'string' ? item : item.label
}
let css = initCss($app.css?.selectstepcomponent, customCss)
$: selected && handleSelection(selected)
</script>
Expand Down Expand Up @@ -106,14 +114,15 @@
>
<div class="w-full" on:pointerdown={onPointerDown}>
<Stepper
tabs={(resolvedConfig?.items ?? []).map((item) => item.label)}
tabs={(resolvedConfig?.items ?? []).map((item) => getLabel(item))}
hasValidations={false}
allowStepNavigation={true}
{selectedIndex}
on:click={(e) => {
const index = e.detail.index
selectedIndex = index
outputs?.result.set(resolvedConfig?.items[index].value)
let item = resolvedConfig?.items[index]
outputs?.result.set(getValue(item))
}}
/>
</div>
Expand Down
16 changes: 6 additions & 10 deletions frontend/src/lib/components/apps/editor/component/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2199,13 +2199,12 @@ This is a paragraph.
items: {
type: 'static',
fieldType: 'array',
subFieldType: 'text',
value: ['Foo', 'Bar']
subFieldType: 'labeledselect',
value: ['Foo', 'Bar'] as (string | { label: string; value: string })[]
} as StaticAppInput,
defaultItems: {
type: 'static',
fieldType: 'array',
subFieldType: 'text',
fieldType: 'object',
value: []
} as StaticAppInput,
placeholder: {
Expand Down Expand Up @@ -3384,7 +3383,7 @@ See date-fns format for more information. By default, it is 'dd.MM.yyyy HH:mm'
value: [
{ value: 'foo', label: 'Foo' },
{ value: 'bar', label: 'Bar' }
]
] as (string | { label: string; value: string })[]
} as StaticAppInput,

defaultValue: {
Expand Down Expand Up @@ -3419,14 +3418,11 @@ See date-fns format for more information. By default, it is 'dd.MM.yyyy HH:mm'
type: 'static',
fieldType: 'array',
subFieldType: 'labeledselect',
value: [
{ value: 'foo', label: 'Foo' },
{ value: 'bar', label: 'Bar' }
]
value: ['Foo', 'Bar'] as (string | { label: string; value: string })[]
} as StaticAppInput,
defaultValue: {
type: 'static',
value: undefined as { value: string; label: string } | undefined,
value: undefined as any,
fieldType: 'object'
}
}
Expand Down
Loading

0 comments on commit d5da75c

Please sign in to comment.