improve arraystaticinputeditor

This commit is contained in:
Ruben Fiszel
2025-06-29 09:03:35 +00:00
parent 2c7705b78c
commit 8a6426bb4e
2 changed files with 116 additions and 80 deletions
@@ -1,5 +1,7 @@
<script lang="ts">
import { getContext, onDestroy, onMount } from 'svelte'
import { stopPropagation } from 'svelte/legacy'
import { getContext, onDestroy, onMount, untrack } from 'svelte'
import type {
AppViewerContext,
BaseAppComponent,
@@ -56,21 +58,32 @@
import RefreshButton from '$lib/components/apps/components/helpers/RefreshButton.svelte'
import Popover from '$lib/components/meltComponents/Popover.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: RichConfigurations
export let actionButtons: (BaseAppComponent &
(ButtonComponent | CheckboxComponent | SelectComponent))[]
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'tablecomponent'> | undefined = undefined
export let render: boolean
interface Props {
id: string
componentInput: AppInput | undefined
configuration: RichConfigurations
actionButtons: (BaseAppComponent & (ButtonComponent | CheckboxComponent | SelectComponent))[]
initializing?: boolean | undefined
customCss?: ComponentCustomCSS<'tablecomponent'> | undefined
render: boolean
}
let {
id,
componentInput,
configuration,
actionButtons,
initializing = $bindable(undefined),
customCss = undefined,
render
}: Props = $props()
const iterContext = getContext<ListContext>('ListWrapperContext')
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
type T = Record<string, any>
let result: Record<string, any>[] | undefined = undefined
let result: Record<string, any>[] | undefined = $state(undefined)
const {
app,
@@ -82,7 +95,7 @@
connectingInput
} = getContext<AppViewerContext>('AppViewerContext')
let searchValue = ''
let searchValue = $state('')
let outputs = initOutput($worldStore, id, {
selectedRowIndex: 0,
@@ -94,10 +107,8 @@
page: 1
})
let inputs = {}
let loading: boolean = false
$: setSearch(searchValue)
let inputs = $state({})
let loading: boolean = $state(false)
function setSearch(srch: string) {
$table.setPageIndex(0)
@@ -110,14 +121,13 @@
columns: []
})
let table = createSvelteTable(options)
let table = $state(createSvelteTable(options))
let resolvedConfig = initConfig(
components['tablecomponent'].initialData.configuration,
configuration
let resolvedConfig = $state(
initConfig(components['tablecomponent'].initialData.configuration, configuration)
)
let selectedRowIndex = -1
let selectedRowIndex = $state(-1)
function toggleRow(row: Record<string, any>, force: boolean = false) {
let data = { ...row.original }
@@ -139,20 +149,11 @@
listInputs?.remove(id)
})
let mounted = false
let mounted = $state(false)
onMount(() => {
mounted = true
})
$: resolvedConfig?.selectFirstRowByDefault != false &&
selectedRowIndex === -1 &&
Array.isArray(result) &&
result.length > 0 &&
// We need to wait until the component is mounted so the world is created
mounted &&
outputs &&
toggleRow({ original: { ...result[0], __index: 0 } })
function searchInResult(result: Array<Record<string, any>>, searchValue: string) {
if (searchValue === '') {
return result
@@ -171,7 +172,7 @@
}
}
let filteredResult: Array<Record<string, any>> = []
let filteredResult: Array<Record<string, any>> = $state([])
function setFilteredResult() {
console.log('setting filtered result')
@@ -185,10 +186,6 @@
filteredResult = searchInResult(wIndex ?? [], searchValue)
}
}
$: (result || resolvedConfig.search || searchValue || resolvedConfig.pagination) &&
setFilteredResult()
$: outputs.page.set($table.getState().pagination.pageIndex)
function rerender() {
if (!Array.isArray(result)) {
@@ -238,9 +235,7 @@
}
}
$: filteredResult != undefined && rerender()
let css = initCss($app.css?.tablecomponent, customCss)
let css = $state(initCss($app.css?.tablecomponent, customCss))
$componentControl[id] = {
right: (skipActions: boolean | undefined) => {
@@ -294,27 +289,25 @@
}
}
function updateTable(resolvedConfig, searchValue) {
function updateTable(resolvedConfig) {
if (resolvedConfig?.columnDefs) {
$table.getAllLeafColumns().map((column) => {
const columnConfig = resolvedConfig.columnDefs.find(
// @ts-ignore
(columnDef) => columnDef.field === column.columnDef.accessorKey
)
if (columnConfig?.hideColumn === column.getIsVisible()) {
column.toggleVisibility()
}
})
$table.setColumnOrder(() =>
resolvedConfig.columnDefs.map((columnDef: { field: any }) => columnDef.field)
const newColumnOrder = resolvedConfig.columnDefs.map(
(columnDef: { field: any }) => columnDef.field
)
$table.setColumnOrder(() => newColumnOrder)
}
}
$: $table && updateTable(resolvedConfig, searchValue)
function updateCellValue(rowIndex: number, columnIndex: number, newCellValue: string) {
if (result && rowIndex < result.length) {
const updatedRow = { ...result[rowIndex] }
@@ -330,6 +323,34 @@
outputs?.result.set([result])
}
}
$effect(() => {
;[searchValue]
untrack(() => setSearch(searchValue))
})
$effect(() => {
resolvedConfig?.selectFirstRowByDefault != false &&
selectedRowIndex === -1 &&
Array.isArray(result) &&
result.length > 0 &&
// We need to wait until the component is mounted so the world is created
mounted &&
outputs &&
toggleRow({ original: { ...result[0], __index: 0 } })
})
$effect(() => {
;[result, resolvedConfig.search, searchValue, resolvedConfig.pagination]
untrack(() => setFilteredResult())
})
$effect(() => {
outputs.page.set($table.getState().pagination.pageIndex)
})
$effect(() => {
filteredResult != undefined && untrack(() => rerender())
})
$effect(() => {
resolvedConfig.columnDefs
untrack(() => updateTable(resolvedConfig))
})
</script>
{#each Object.keys(components['tablecomponent'].initialData.configuration) as key (key)}
@@ -421,12 +442,13 @@
{#if displayName}
{displayName}
{:else if !header.isPlaceholder && component}
<svelte:component this={component} />
{@const SvelteComponent = component}
<SvelteComponent />
{/if}
{#if header.column.getIsVisible()}
<button
class="w-6 flex justify-center items-center"
on:click={() => {
onclick={() => {
header.column.toggleVisibility()
}}
>
@@ -495,13 +517,13 @@
{#if actionButtons.length > 0}
<td
class="p-2"
on:keypress={() => toggleRow(row)}
on:click={() => toggleRow(row)}
onkeypress={() => toggleRow(row)}
onclick={() => toggleRow(row)}
style="width: {(actionButtons ?? []).length * 130}px"
>
<div class="center-center h-full w-full flex-wrap gap-2">
{#each actionButtons as actionButton, actionIndex (actionButton?.id)}
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<RowWrapper
value={row.original}
index={rowIndex}
@@ -527,18 +549,18 @@
outputs?.inputs.set(inputs, true)
}}
>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
<div
on:mouseover|stopPropagation={() => {
onmouseover={stopPropagation(() => {
if (actionButton.id !== $hoverStore) {
$hoverStore = actionButton.id
}
}}
on:mouseout|stopPropagation={() => {
})}
onmouseout={stopPropagation(() => {
if ($hoverStore !== undefined) {
$hoverStore = undefined
}
}}
})}
class={classNames(
($selectedComponent?.includes(actionButton.id) ||
$hoverStore === actionButton.id) &&
@@ -548,8 +570,8 @@
)}
>
{#if $mode !== 'preview'}
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<span
title={`Id: ${actionButton.id}`}
class={classNames(
@@ -560,9 +582,9 @@
? 'opacity-100'
: 'opacity-0'
)}
on:click|stopPropagation={() => {
onclick={stopPropagation(() => {
$selectedComponent = [actionButton.id]
}}
})}
>
{actionButton.id}
</span>
@@ -577,14 +599,14 @@
closeOnOtherPopoverOpen
contentClasses="p-4"
>
<svelte:fragment slot="trigger">
{#snippet trigger()}
<button
class="bg-red-500/70 border border-red-600 px-1 py-0.5"
title="Outputs"
aria-label="Open output"><Plug2 size={12} /></button
>
</svelte:fragment>
<svelte:fragment slot="content">
{/snippet}
{#snippet content()}
<ComponentOutputViewer
suffix="table"
on:select={({ detail }) =>
@@ -596,7 +618,7 @@
)}
componentId={actionButton.id}
/>
</svelte:fragment>
{/snippet}
</Popover>
</div>
{/if}
@@ -1,4 +1,6 @@
<script lang="ts">
import { preventDefault, stopPropagation } from 'svelte/legacy'
import { Button } from '$lib/components/common'
import { GripVertical, Loader2, Plus, X } from 'lucide-svelte'
import { createEventDispatcher } from 'svelte'
@@ -10,12 +12,21 @@
import QuickAddColumn from './QuickAddColumn.svelte'
import RefreshDatabaseStudioTable from './RefreshDatabaseStudioTable.svelte'
export let componentInput: StaticInput<any[]> & { loading?: boolean }
export let subFieldType: InputType | undefined = undefined
export let selectOptions: StaticOptions['selectOptions'] | undefined = undefined
export let id: string | undefined
interface Props {
componentInput: StaticInput<any[]> & { loading?: boolean }
subFieldType?: InputType | undefined
selectOptions?: StaticOptions['selectOptions'] | undefined
id: string | undefined
}
let items: ReturnType<typeof getItems> = []
let {
componentInput = $bindable(),
subFieldType = undefined,
selectOptions = undefined,
id
}: Props = $props()
let items: ReturnType<typeof getItems> = $state([])
items = getItems(componentInput)
const dispatch = createEventDispatcher()
@@ -212,17 +223,19 @@
}
}
$: subFieldType === 'db-explorer' && clearTableOnComponentReset(componentInput?.value)
$: items != undefined && handleItemsChange()
function handleItemsChange() {
componentInput.value = items.map((item) => item.value).filter((item) => item != undefined)
}
let raw: boolean = false
let raw: boolean = $state(false)
let refreshCount = 0
let refreshCount = $state(0)
$effect(() => {
subFieldType === 'db-explorer' && clearTableOnComponentReset(componentInput?.value)
})
$effect(() => {
items != undefined && handleItemsChange()
})
</script>
<div class="flex gap-2 flex-col mt-2 w-full">
@@ -274,12 +287,12 @@
flipDurationMs,
dropTargetStyle: {}
}}
on:consider={handleConsider}
on:finalize={handleFinalize}
onconsider={handleConsider}
onfinalize={handleFinalize}
>
{#each items as item, index (item.id)}
<div class="border-0 outline-none w-full">
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
<div class="flex flex-row gap-2 items-center relative my-1 w-full">
<div class="grow min-w-0">
@@ -293,7 +306,7 @@
</div>
<div class="flex justify-between flex-col items-center">
<!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="w-4 h-4 cursor-move handle" use:dragHandle>
<GripVertical size={16} />
</div>
@@ -301,7 +314,7 @@
<button
class="z-10 rounded-full p-1 duration-200 hover:bg-surface-hover"
aria-label="Remove item"
on:click|preventDefault|stopPropagation={() => deleteElementByType(index)}
onclick={stopPropagation(preventDefault(() => deleteElementByType(index)))}
>
<X size={14} />
</button>
@@ -339,7 +352,6 @@
} else if (subFieldType === 'ag-grid') {
componentInput.value.push({ field: detail, headerName: detail, flex: 1 })
}
componentInput = componentInput
if (componentInput.value) {
let value = componentInput.value[componentInput.value.length - 1]
@@ -350,6 +362,8 @@
})
}
}
componentInput.value = $state.snapshot(componentInput.value)
componentInput = componentInput
}}
/>
{/if}