mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-21 08:02:26 +00:00
feat(frontend): improve table actions (#4040)
* feat(frontend): wip * feat(frontend): fix table actions width, hovering behavior and fixed connection * feat(frontend): support infinite list + Db Explorer
This commit is contained in:
+8
-2
@@ -2,7 +2,7 @@
|
||||
import { GridApi, createGrid, type IDatasource } from 'ag-grid-community'
|
||||
import { sendUserToast } from '$lib/utils'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import type { AppViewerContext, ComponentCustomCSS } from '../../../types'
|
||||
import type { AppViewerContext, ComponentCustomCSS, ContextPanelContext } from '../../../types'
|
||||
|
||||
import type { TableAction, components } from '$lib/components/apps/editor/component'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
@@ -39,6 +39,7 @@
|
||||
let inputs = {}
|
||||
|
||||
const context = getContext<AppViewerContext>('AppViewerContext')
|
||||
const contextPanel = getContext<ContextPanelContext>('ContextPanel')
|
||||
const { app, selectedComponent, componentControl, darkMode } = context
|
||||
|
||||
let css = initCss($app.css?.aggridcomponent, customCss)
|
||||
@@ -120,6 +121,11 @@
|
||||
const rowIndex = p.node.rowIndex ?? 0
|
||||
const row = p.data
|
||||
|
||||
const componentContext = new Map<string, any>([
|
||||
['AppViewerContext', context],
|
||||
['ContextPanel', contextPanel]
|
||||
])
|
||||
|
||||
new AppAggridTableActions({
|
||||
target: c.eGui,
|
||||
props: {
|
||||
@@ -155,7 +161,7 @@
|
||||
outputs?.inputs.set(inputs, true)
|
||||
}
|
||||
},
|
||||
context: new Map([['AppViewerContext', context]])
|
||||
context: componentContext
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import type {
|
||||
AppViewerContext,
|
||||
ComponentCustomCSS,
|
||||
ContextPanelContext,
|
||||
ListContext,
|
||||
ListInputs,
|
||||
RichConfigurations
|
||||
@@ -50,7 +51,7 @@
|
||||
export let actions: TableAction[] | undefined = undefined
|
||||
|
||||
const context = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
const contextPanel = getContext<ContextPanelContext>('ContextPanel')
|
||||
const iterContext = getContext<ListContext>('ListWrapperContext')
|
||||
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
|
||||
|
||||
@@ -196,6 +197,11 @@
|
||||
const rowIndex = p.node.rowIndex ?? 0
|
||||
const row = p.data
|
||||
|
||||
const componentContext = new Map<string, any>([
|
||||
['AppViewerContext', context],
|
||||
['ContextPanel', contextPanel]
|
||||
])
|
||||
|
||||
new AppAggridTableActions({
|
||||
target: c.eGui,
|
||||
props: {
|
||||
@@ -231,7 +237,7 @@
|
||||
outputs?.inputs.set(inputs, true)
|
||||
}
|
||||
},
|
||||
context: new Map([['AppViewerContext', context]])
|
||||
context: componentContext
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
+70
-43
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import { createEventDispatcher, getContext, onMount } from 'svelte'
|
||||
import type { AppViewerContext } from '../../../types'
|
||||
import type { TableAction } from '$lib/components/apps/editor/component'
|
||||
|
||||
@@ -30,6 +30,18 @@
|
||||
const dispatch = createEventDispatcher()
|
||||
const { selectedComponent, hoverStore, mode, connectingInput } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let rowDiv: HTMLDivElement | undefined = undefined
|
||||
|
||||
onMount(() => {
|
||||
// apply w-full to the the parent of the parent of the rowDiv
|
||||
if (rowDiv) {
|
||||
const parent = rowDiv.parentElement?.parentElement?.parentElement
|
||||
if (parent) {
|
||||
parent.classList.add('w-full')
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<RowWrapper value={row} index={rowIndex} {onSet} {onRemove}>
|
||||
@@ -38,6 +50,7 @@
|
||||
'flex flex-row justify-center items-center gap-4 h-full px-4 py-1 w-full',
|
||||
wrapActions ? 'flex-wrap' : ''
|
||||
)}
|
||||
bind:this={rowDiv}
|
||||
>
|
||||
{#each actions as action, actionIndex}
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
@@ -56,13 +69,20 @@
|
||||
}}
|
||||
on:pointerdown|stopPropagation={(e) => {
|
||||
selectRow()
|
||||
$selectedComponent = [action.id]
|
||||
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [action.id]
|
||||
}
|
||||
}}
|
||||
class={twMerge(
|
||||
($selectedComponent?.includes(action.id) || $hoverStore === action.id) &&
|
||||
$mode !== 'preview'
|
||||
? 'outline outline-indigo-500 outline-1 outline-offset-1 relative z-50'
|
||||
: 'relative'
|
||||
? 'outline outline-indigo-500 outline-1 outline-offset-1 relative '
|
||||
: 'relative',
|
||||
$hoverStore === action.id && $selectedComponent?.[0] !== action.id
|
||||
? 'outline-blue-500'
|
||||
: '',
|
||||
'w-full cursor-pointer'
|
||||
)}
|
||||
>
|
||||
{#if $mode !== 'preview'}
|
||||
@@ -73,6 +93,9 @@
|
||||
class={twMerge(
|
||||
'px-2 text-2xs font-bold absolute shadow -top-2 -left-4 border z-50 rounded-sm w-8 !h-5 flex justify-center items-center',
|
||||
'bg-indigo-500/90 border-indigo-600 text-white',
|
||||
$hoverStore === action.id && $selectedComponent?.[0] !== action.id
|
||||
? 'bg-blue-500/90 border-blue-600'
|
||||
: '',
|
||||
$selectedComponent?.includes(action.id) || $hoverStore === action.id
|
||||
? 'opacity-100'
|
||||
: 'opacity-0'
|
||||
@@ -101,8 +124,16 @@
|
||||
</svelte:fragment>
|
||||
<ComponentOutputViewer
|
||||
suffix="table"
|
||||
on:select={({ detail }) =>
|
||||
connectOutput(connectingInput, 'buttoncomponent', action.id, detail)}
|
||||
on:select={({ detail }) => {
|
||||
const tableId = action.id.split('_')[0]
|
||||
|
||||
connectOutput(
|
||||
connectingInput,
|
||||
action.type,
|
||||
tableId,
|
||||
`inputs.${action.id}[${rowIndex}].${detail}`
|
||||
)
|
||||
}}
|
||||
componentId={action.id}
|
||||
/>
|
||||
</Popup>
|
||||
@@ -171,25 +202,23 @@
|
||||
{controls}
|
||||
/>
|
||||
{:else if action.type == 'selectcomponent'}
|
||||
<div class="w-40">
|
||||
<AppSelect
|
||||
noDefault
|
||||
noInitialize
|
||||
extraKey={'idx' + rowIndex}
|
||||
{render}
|
||||
--font-size="10px"
|
||||
id={action.id}
|
||||
customCss={action.customCss}
|
||||
configuration={action.configuration}
|
||||
recomputeIds={action.recomputeIds}
|
||||
onSelect={action.onSelect}
|
||||
preclickAction={async () => {
|
||||
dispatch('toggleRow')
|
||||
selectRow()
|
||||
}}
|
||||
{controls}
|
||||
/>
|
||||
</div>
|
||||
<AppSelect
|
||||
noDefault
|
||||
noInitialize
|
||||
extraKey={'idx' + rowIndex}
|
||||
{render}
|
||||
--font-size="10px"
|
||||
id={action.id}
|
||||
customCss={action.customCss}
|
||||
configuration={action.configuration}
|
||||
recomputeIds={action.recomputeIds}
|
||||
onSelect={action.onSelect}
|
||||
preclickAction={async () => {
|
||||
dispatch('toggleRow')
|
||||
selectRow()
|
||||
}}
|
||||
{controls}
|
||||
/>
|
||||
{/if}
|
||||
{:else if action.type == 'buttoncomponent'}
|
||||
<AppButton
|
||||
@@ -227,24 +256,22 @@
|
||||
}}
|
||||
/>
|
||||
{:else if action.type == 'selectcomponent'}
|
||||
<div class="w-40">
|
||||
<AppSelect
|
||||
noDefault
|
||||
noInitialize
|
||||
extraKey={'idx' + rowIndex}
|
||||
{render}
|
||||
--font-size="10px"
|
||||
id={action.id}
|
||||
customCss={action.customCss}
|
||||
configuration={action.configuration}
|
||||
recomputeIds={action.recomputeIds}
|
||||
onSelect={action.onSelect}
|
||||
preclickAction={async () => {
|
||||
dispatch('toggleRow')
|
||||
selectRow()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<AppSelect
|
||||
noDefault
|
||||
noInitialize
|
||||
extraKey={'idx' + rowIndex}
|
||||
{render}
|
||||
--font-size="10px"
|
||||
id={action.id}
|
||||
customCss={action.customCss}
|
||||
configuration={action.configuration}
|
||||
recomputeIds={action.recomputeIds}
|
||||
onSelect={action.onSelect}
|
||||
preclickAction={async () => {
|
||||
dispatch('toggleRow')
|
||||
selectRow()
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -102,6 +102,12 @@
|
||||
outTimeout && clearTimeout(outTimeout)
|
||||
outTimeout = setTimeout(() => {
|
||||
if ($hoverStore !== undefined) {
|
||||
// In order to avoid flickering when hovering over table actions,
|
||||
// we leave the actions to manage the hover state
|
||||
if ($hoverStore.startsWith(`${component.id}_`)) {
|
||||
return
|
||||
}
|
||||
|
||||
$hoverStore = undefined
|
||||
}
|
||||
}, 50)
|
||||
|
||||
@@ -33,11 +33,11 @@
|
||||
return
|
||||
}
|
||||
|
||||
if (!$flowStateStore) {
|
||||
if (!$flowInputsStore) {
|
||||
$flowInputsStore = {}
|
||||
}
|
||||
|
||||
$flowInputsStore![module?.id] = {
|
||||
$flowInputsStore[module?.id] = {
|
||||
requiredInputsFilled: initRequiredInputFilled(
|
||||
module.value,
|
||||
$flowStateStore?.[module?.id]?.schema ?? {}
|
||||
|
||||
Reference in New Issue
Block a user