mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-21 00:02:23 +00:00
improve arraystaticinputeditor
This commit is contained in:
@@ -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}
|
||||
|
||||
+31
-17
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user