mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-07 16:03:21 +00:00
fix: improve aggrid actions column (#6600)
* aggrid improvements actions column * cleanup * header preference * force redraw * simplify types * reactivity * fixing potential race condition
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
import ResolveStyle from '../../helpers/ResolveStyle.svelte'
|
||||
|
||||
import AppAggridTableActions from './AppAggridTableActions.svelte'
|
||||
import { cellRendererFactory, defaultCellRenderer } from './utils'
|
||||
import { cellRendererFactory, transformColumnDefs, type WindmillColumnDef } from './utils'
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import { Button } from '$lib/components/common'
|
||||
import InputValue from '../../helpers/InputValue.svelte'
|
||||
@@ -303,6 +303,12 @@
|
||||
taComponent.props.rowIndex = params.node.rowIndex ?? 0
|
||||
taComponent.props.row = params.data
|
||||
taComponent.props.p = params
|
||||
const nextActions: TableAction[] | undefined = computedOrder
|
||||
? (computedOrder
|
||||
.map((key) => actions?.find((a) => a.id === key))
|
||||
.filter(Boolean) as TableAction[])
|
||||
: actions
|
||||
taComponent.props.actions = nextActions
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -317,36 +323,25 @@
|
||||
// console.log(resolvedConfig?.extraConfig)
|
||||
if (eGui) {
|
||||
try {
|
||||
let columnDefs =
|
||||
Array.isArray(resolvedConfig?.columnDefs) && resolvedConfig.columnDefs.every(isObject)
|
||||
? [...resolvedConfig?.columnDefs] // Clone to avoid direct mutation
|
||||
: []
|
||||
|
||||
// Add the action column if actions are defined
|
||||
if (actions && actions.length > 0) {
|
||||
columnDefs.push({
|
||||
headerName: resolvedConfig?.customActionsHeader
|
||||
? resolvedConfig?.customActionsHeader
|
||||
: 'Actions',
|
||||
cellRenderer: tableActionsFactory,
|
||||
autoHeight: true,
|
||||
cellStyle: { textAlign: 'center' },
|
||||
cellClass: 'grid-cell-centered',
|
||||
...(!resolvedConfig?.wrapActions ? { minWidth: 130 * actions?.length } : {})
|
||||
})
|
||||
}
|
||||
const agColumnDefs = transformColumnDefs({
|
||||
columnDefs:
|
||||
Array.isArray(resolvedConfig?.columnDefs) && resolvedConfig.columnDefs.every(isObject)
|
||||
? [...resolvedConfig?.columnDefs] as WindmillColumnDef[]
|
||||
: [],
|
||||
actions,
|
||||
customActionsHeader: resolvedConfig?.customActionsHeader,
|
||||
wrapActions: resolvedConfig?.wrapActions,
|
||||
tableActionsFactory,
|
||||
onInvalidColumnDefs: (errors) => {
|
||||
sendUserToast(`Invalid columnDefs: ${errors.join('\n')}`, true)
|
||||
}
|
||||
})
|
||||
|
||||
createGrid(
|
||||
eGui,
|
||||
{
|
||||
rowData: value,
|
||||
columnDefs: columnDefs.map((fields) => {
|
||||
let cr = defaultCellRenderer(fields.cellRendererType)
|
||||
return {
|
||||
...fields,
|
||||
...(cr ? { cellRenderer: cr } : {})
|
||||
}
|
||||
}),
|
||||
columnDefs: agColumnDefs,
|
||||
pagination: resolvedConfig?.pagination,
|
||||
paginationAutoPageSize: resolvedConfig?.pagination,
|
||||
suppressPaginationPanel: true,
|
||||
@@ -476,34 +471,23 @@
|
||||
|
||||
function updateOptions() {
|
||||
try {
|
||||
const columnDefs =
|
||||
Array.isArray(resolvedConfig?.columnDefs) && resolvedConfig.columnDefs.every(isObject)
|
||||
? [...resolvedConfig?.columnDefs] // Clone to avoid direct mutation
|
||||
: []
|
||||
|
||||
// Add the action column if actions are defined
|
||||
if (actions && actions.length > 0) {
|
||||
columnDefs.push({
|
||||
headerName: resolvedConfig?.customActionsHeader
|
||||
? resolvedConfig?.customActionsHeader
|
||||
: 'Actions',
|
||||
cellRenderer: tableActionsFactory,
|
||||
autoHeight: true,
|
||||
cellStyle: { textAlign: 'center' },
|
||||
cellClass: 'grid-cell-centered',
|
||||
...(!resolvedConfig?.wrapActions ? { minWidth: 130 * actions?.length } : {})
|
||||
})
|
||||
}
|
||||
const agColumnDefs = transformColumnDefs({
|
||||
columnDefs:
|
||||
Array.isArray(resolvedConfig?.columnDefs) && resolvedConfig.columnDefs.every(isObject)
|
||||
? [...resolvedConfig?.columnDefs] as WindmillColumnDef[]
|
||||
: [],
|
||||
actions,
|
||||
customActionsHeader: resolvedConfig?.customActionsHeader,
|
||||
wrapActions: resolvedConfig?.wrapActions,
|
||||
tableActionsFactory,
|
||||
onInvalidColumnDefs: (errors) => {
|
||||
sendUserToast(`Invalid columnDefs: ${errors.join('\n')}`, true)
|
||||
}
|
||||
})
|
||||
|
||||
api?.updateGridOptions({
|
||||
rowData: value,
|
||||
columnDefs: columnDefs.map((fields) => {
|
||||
let cr = defaultCellRenderer(fields.cellRendererType)
|
||||
return {
|
||||
...fields,
|
||||
...(cr ? { cellRenderer: cr } : {})
|
||||
}
|
||||
}),
|
||||
columnDefs: agColumnDefs,
|
||||
pagination: resolvedConfig?.pagination,
|
||||
paginationAutoPageSize: resolvedConfig?.pagination,
|
||||
suppressPaginationPanel: true,
|
||||
@@ -523,6 +507,10 @@
|
||||
...resolvedConfig?.extraConfig?.['defaultColDef']
|
||||
}
|
||||
})
|
||||
// Force refresh to re-render cell renderers after actions change
|
||||
api?.refreshCells({ force: true })
|
||||
// Force complete redraw to clear stale inline styles
|
||||
api?.redrawRows()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
sendUserToast("Couldn't update the grid:" + e, true)
|
||||
@@ -609,7 +597,13 @@
|
||||
bind:loading
|
||||
hideRefreshButton={true}
|
||||
>
|
||||
<SyncColumnDefs {id} columnDefs={resolvedConfig.columnDefs} {result}>
|
||||
<SyncColumnDefs
|
||||
{id}
|
||||
columnDefs={resolvedConfig.columnDefs}
|
||||
{result}
|
||||
actionsPresent={Array.isArray(actions) && actions.length > 0}
|
||||
customActionsHeader={resolvedConfig?.customActionsHeader}
|
||||
>
|
||||
<div
|
||||
class={twMerge(
|
||||
'flex flex-col h-full component-wrapper divide-y',
|
||||
|
||||
@@ -7,13 +7,20 @@
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
import Alert from '$lib/components/common/alert/Alert.svelte'
|
||||
import { isObject } from '$lib/utils'
|
||||
import type { WindmillColumnDef } from './utils'
|
||||
|
||||
type ColumnDefsConfiguration =
|
||||
| { type: 'static'; value: WindmillColumnDef[] }
|
||||
| { type: 'evalv2'; expr: string }
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
columnDefs?: Array<any>
|
||||
result?: Array<any> | undefined
|
||||
columnDefs?: WindmillColumnDef[]
|
||||
result?: Array<Record<string, any>> | undefined
|
||||
allowColumnDefsActions?: boolean
|
||||
children?: import('svelte').Snippet
|
||||
actionsPresent?: boolean
|
||||
customActionsHeader?: string | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -21,31 +28,113 @@
|
||||
columnDefs = [],
|
||||
result = [],
|
||||
allowColumnDefsActions = true,
|
||||
children
|
||||
children,
|
||||
actionsPresent = false,
|
||||
customActionsHeader = undefined
|
||||
}: Props = $props()
|
||||
|
||||
const { app, mode, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let syncInProgress = false
|
||||
|
||||
function hasActionsPlaceholder(cols: WindmillColumnDef[] | undefined): boolean {
|
||||
if (!Array.isArray(cols)) return false
|
||||
return cols.findIndex((c) => c?._isActionsColumn === true) > -1
|
||||
}
|
||||
|
||||
function addActionsPlaceholder(cols: WindmillColumnDef[] | undefined): WindmillColumnDef[] {
|
||||
const hdr = customActionsHeader ?? 'Actions'
|
||||
const placeholder: WindmillColumnDef = {
|
||||
field: '__actions__',
|
||||
_isActionsColumn: true,
|
||||
headerName: hdr,
|
||||
flex: 1
|
||||
}
|
||||
if (!Array.isArray(cols)) return [placeholder]
|
||||
return [...cols, placeholder]
|
||||
}
|
||||
|
||||
function removeActionsPlaceholder(cols: WindmillColumnDef[] | undefined): WindmillColumnDef[] {
|
||||
if (!Array.isArray(cols)) return []
|
||||
return cols.filter((c) => c?._isActionsColumn !== true)
|
||||
}
|
||||
|
||||
async function ensureActionsColumn() {
|
||||
// Only act in editor (DND) mode
|
||||
if ($mode !== 'dnd') return
|
||||
const gridItem = findGridItem($app, id)
|
||||
if (!gridItem) return
|
||||
|
||||
// Type the configuration more safely
|
||||
const rawConf = gridItem.data.configuration?.columnDefs
|
||||
if (!rawConf) return
|
||||
|
||||
// Type guard for configuration structure
|
||||
const conf = rawConf as ColumnDefsConfiguration
|
||||
if (!conf.type || (conf.type !== 'static' && conf.type !== 'evalv2')) return
|
||||
|
||||
let currentColumns: WindmillColumnDef[] | undefined
|
||||
if (conf.type === 'static') {
|
||||
currentColumns = Array.isArray(conf.value) ? conf.value : []
|
||||
} else if (conf.type === 'evalv2') {
|
||||
try {
|
||||
const parsed = JSON.parse(conf.expr ?? '[]')
|
||||
currentColumns = Array.isArray(parsed) ? parsed : []
|
||||
} catch (e) {
|
||||
console.warn('Failed to parse columnDefs expression:', e)
|
||||
currentColumns = []
|
||||
}
|
||||
}
|
||||
|
||||
const hasPlaceholder = hasActionsPlaceholder(currentColumns)
|
||||
|
||||
// Auto-sync logic: add missing actions column, remove when actions gone
|
||||
const needsAdd = actionsPresent && !hasPlaceholder
|
||||
const needsRemove = !actionsPresent && hasPlaceholder
|
||||
|
||||
if (!needsAdd && !needsRemove) return
|
||||
|
||||
let nextColumns = currentColumns || []
|
||||
if (needsAdd) nextColumns = addActionsPlaceholder(nextColumns)
|
||||
if (needsRemove) nextColumns = removeActionsPlaceholder(nextColumns)
|
||||
|
||||
// Update configuration with proper typing
|
||||
if (conf.type === 'static') {
|
||||
conf.value = nextColumns
|
||||
} else if (conf.type === 'evalv2') {
|
||||
conf.expr = JSON.stringify(nextColumns)
|
||||
}
|
||||
|
||||
await updateConfiguration()
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
const shouldSync = actionsPresent !== undefined || columnDefs?.length !== undefined
|
||||
if (shouldSync && !syncInProgress) {
|
||||
syncInProgress = true
|
||||
ensureActionsColumn().finally(() => {
|
||||
syncInProgress = false
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
async function syncColumns() {
|
||||
let gridItem = findGridItem($app, id)
|
||||
const gridItem = findGridItem($app, id)
|
||||
|
||||
if (gridItem && result) {
|
||||
const keys = Object.keys(result[0] ?? {}) ?? []
|
||||
const conf = gridItem.data.configuration.columnDefs as ColumnDefsConfiguration
|
||||
|
||||
if (gridItem.data.configuration.columnDefs.type === 'static') {
|
||||
gridItem.data.configuration.columnDefs.value = keys.map((key) => ({
|
||||
field: key,
|
||||
headerName: key,
|
||||
flex: 1
|
||||
}))
|
||||
} else if (gridItem.data.configuration.columnDefs.type === 'evalv2') {
|
||||
gridItem.data.configuration.columnDefs.expr = JSON.stringify(
|
||||
keys.map((key, index) => ({
|
||||
field: key,
|
||||
headerName: key,
|
||||
flex: 1
|
||||
}))
|
||||
)
|
||||
const newColumns: WindmillColumnDef[] = keys.map((key) => ({
|
||||
field: key,
|
||||
headerName: key,
|
||||
flex: 1
|
||||
}))
|
||||
|
||||
if (conf.type === 'static') {
|
||||
conf.value = newColumns
|
||||
} else if (conf.type === 'evalv2') {
|
||||
conf.expr = JSON.stringify(newColumns)
|
||||
}
|
||||
|
||||
await updateConfiguration()
|
||||
@@ -53,12 +142,16 @@
|
||||
}
|
||||
|
||||
async function setEmptyColumns() {
|
||||
let gridItem = findGridItem($app, id)
|
||||
if (gridItem && gridItem.data.configuration.columnDefs.type === 'static') {
|
||||
gridItem.data.configuration.columnDefs.value = []
|
||||
const gridItem = findGridItem($app, id)
|
||||
if (!gridItem) return
|
||||
|
||||
const conf = gridItem.data.configuration.columnDefs as ColumnDefsConfiguration
|
||||
|
||||
if (conf.type === 'static') {
|
||||
conf.value = []
|
||||
await updateConfiguration()
|
||||
} else if (gridItem && gridItem.data.configuration.columnDefs.type === 'evalv2') {
|
||||
gridItem.data.configuration.columnDefs.expr = '[]'
|
||||
} else if (conf.type === 'evalv2') {
|
||||
conf.expr = '[]'
|
||||
await updateConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,21 @@
|
||||
* See: https://stackoverflow.com/a/72608215
|
||||
*/
|
||||
import type { ColDef, ColGroupDef, ICellRendererComp, ICellRendererParams } from 'ag-grid-community'
|
||||
import { ColumnIdentity, type ColumnDef } from '../dbtable/utils'
|
||||
import { ColumnIdentity } from '../dbtable/utils'
|
||||
import type { TableAction } from '$lib/components/apps/editor/component'
|
||||
import { mount, unmount } from 'svelte'
|
||||
import { Button } from '$lib/components/common'
|
||||
import { Trash2 } from 'lucide-svelte'
|
||||
|
||||
export type WindmillColumnDef = ColDef & {
|
||||
_isActionsColumn?: boolean
|
||||
cellRendererType?: string
|
||||
ignored?: boolean
|
||||
hideInsert?: boolean
|
||||
isidentity?: ColumnIdentity
|
||||
children?: WindmillColumnDef[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for defining a cell renderer.
|
||||
* If you don't need to define a separate class you could use cellRendererFactory
|
||||
@@ -125,7 +134,7 @@ export function transformColumnDefs({
|
||||
onDelete,
|
||||
onInvalidColumnDefs
|
||||
}: {
|
||||
columnDefs: ColumnDef[]
|
||||
columnDefs: WindmillColumnDef[]
|
||||
actions?: TableAction[]
|
||||
customActionsHeader?: string
|
||||
wrapActions?: boolean
|
||||
@@ -146,6 +155,13 @@ export function transformColumnDefs({
|
||||
|
||||
let r: any[] = columnDefs?.filter((x) => x && !x.ignored) ?? []
|
||||
|
||||
// Allow an explicit "actions" placeholder in columnDefs so users can manage it like any column.
|
||||
// When present, replace it with the computed actions colDef. When not present but actions exist,
|
||||
// we will append the actions column after validation below.
|
||||
const actionsIndex = r.findIndex((c) => {
|
||||
return c?._isActionsColumn === true
|
||||
})
|
||||
|
||||
if (onDelete) {
|
||||
r.push({
|
||||
field: 'delete',
|
||||
@@ -189,16 +205,41 @@ export function transformColumnDefs({
|
||||
}
|
||||
|
||||
if (actions?.length) {
|
||||
r.push({
|
||||
headerName: customActionsHeader ?? 'Actions',
|
||||
const computedActionsCol = {
|
||||
field: '__actions__',
|
||||
_isActionsColumn: true,
|
||||
headerName: 'Actions',
|
||||
cellRenderer: tableActionsFactory,
|
||||
autoHeight: true,
|
||||
cellStyle: { textAlign: 'center' },
|
||||
cellClass: 'grid-cell-centered',
|
||||
lockPosition: 'right',
|
||||
// Only lock position to right if user hasn't explicitly positioned the actions column
|
||||
...(actionsIndex === -1 ? { lockPosition: 'right' } : {}),
|
||||
// Set default minWidth based on number of actions (if not wrapping)
|
||||
...(!wrapActions ? { minWidth: 130 * actions?.length } : {}),
|
||||
// Respect user-specified overrides when placeholder present (these should override defaults)
|
||||
...(
|
||||
actionsIndex > -1
|
||||
? {
|
||||
// keep width/pin/flex/align/hide from placeholder when provided
|
||||
...(['width', 'minWidth', 'maxWidth', 'flex', 'pinned', 'headerName', 'cellStyle', 'cellClass', 'autoHeight', 'hide']
|
||||
.reduce((acc, key) => {
|
||||
if (r[actionsIndex] && r[actionsIndex][key] !== undefined) acc[key] = r[actionsIndex][key]
|
||||
return acc
|
||||
}, {} as any))
|
||||
}
|
||||
: {}
|
||||
),
|
||||
...(customActionsHeader?.trim() ? { headerName: customActionsHeader } : {})
|
||||
}
|
||||
|
||||
...(!wrapActions ? { minWidth: 130 * actions?.length } : {})
|
||||
})
|
||||
if (actionsIndex > -1) {
|
||||
// Replace the placeholder with computed column
|
||||
r.splice(actionsIndex, 1, computedActionsCol)
|
||||
} else {
|
||||
// Backward compatible: append if not explicitly placed
|
||||
r.push(computedActionsCol)
|
||||
}
|
||||
}
|
||||
|
||||
return r.map((fields) => {
|
||||
@@ -210,7 +251,7 @@ export function transformColumnDefs({
|
||||
})
|
||||
}
|
||||
|
||||
export function validateColumnDefs(columnDefs: ColumnDef[]): {
|
||||
export function validateColumnDefs(columnDefs: WindmillColumnDef[]): {
|
||||
isValid: boolean
|
||||
errors: string[]
|
||||
} {
|
||||
|
||||
+32
-3
@@ -3,7 +3,7 @@
|
||||
|
||||
import { Button } from '$lib/components/common'
|
||||
import { GripVertical, Loader2, Plus, X } from 'lucide-svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, getContext, tick } from 'svelte'
|
||||
import type { InputType, StaticInput, StaticOptions } from '../../inputType'
|
||||
import SubTypeEditor from './SubTypeEditor.svelte'
|
||||
import { dragHandle, dragHandleZone } from '@windmill-labs/svelte-dnd-action'
|
||||
@@ -11,6 +11,8 @@
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import QuickAddColumn from './QuickAddColumn.svelte'
|
||||
import RefreshDatabaseStudioTable from './RefreshDatabaseStudioTable.svelte'
|
||||
import { findGridItem } from '$lib/components/apps/editor/appUtils'
|
||||
import type { AppViewerContext } from '$lib/components/apps/types'
|
||||
|
||||
interface Props {
|
||||
componentInput: StaticInput<any[]> & { loading?: boolean }
|
||||
@@ -26,6 +28,9 @@
|
||||
id
|
||||
}: Props = $props()
|
||||
|
||||
const appContext = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { app, selectedComponent } = appContext || {}
|
||||
|
||||
let items: ReturnType<typeof getItems> = $state([])
|
||||
items = getItems(componentInput)
|
||||
|
||||
@@ -185,10 +190,34 @@
|
||||
items = getItems(componentInput)
|
||||
}
|
||||
|
||||
function deleteElementByType(index: number) {
|
||||
async function updateConfiguration() {
|
||||
if (selectedComponent && id) {
|
||||
$selectedComponent = undefined
|
||||
await tick()
|
||||
$selectedComponent = [id]
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteElementByType(index: number) {
|
||||
if (componentInput.value) {
|
||||
const item = componentInput.value[index]
|
||||
// If deleting actions column, clear all table actions
|
||||
if (subFieldType === 'ag-grid' && item && item._isActionsColumn === true) {
|
||||
const gridItem = id ? findGridItem($app, id) : null
|
||||
if (gridItem && (
|
||||
gridItem.data.type === 'aggridcomponent' ||
|
||||
gridItem.data.type === 'aggridcomponentee' ||
|
||||
gridItem.data.type === 'aggridinfinitecomponent' ||
|
||||
gridItem.data.type === 'aggridinfinitecomponentee'
|
||||
) && Array.isArray(gridItem.data.actions)) {
|
||||
gridItem.data.actions.length = 0
|
||||
}
|
||||
await updateConfiguration()
|
||||
return
|
||||
}
|
||||
|
||||
componentInput.value.splice(index, 1)
|
||||
items.splice(index, 1) // Add this
|
||||
items.splice(index, 1)
|
||||
items = items
|
||||
componentInput.value = componentInput.value
|
||||
dispatch('deleteArrayItem', { index })
|
||||
|
||||
+13
-5
@@ -299,11 +299,19 @@
|
||||
{:else if fieldType === 'ag-grid'}
|
||||
<div class="flex flex-row rounded-md bg-surface items-center h-full">
|
||||
<div class="relative w-full">
|
||||
<input
|
||||
class="text-xs px-2 border-y w-full flex flex-row items-center border-r rounded-r-md h-8"
|
||||
bind:value={componentInput.value.field}
|
||||
placeholder="Field"
|
||||
/>
|
||||
{#if componentInput.value._isActionsColumn === true}
|
||||
<div
|
||||
class="text-xs px-2 border w-full flex flex-row items-center rounded-r-md h-8 text-primary"
|
||||
>
|
||||
Actions Column
|
||||
</div>
|
||||
{:else}
|
||||
<input
|
||||
class="text-xs px-2 border-y w-full flex flex-row items-center border-r rounded-r-md h-8"
|
||||
bind:value={componentInput.value.field}
|
||||
placeholder="Field"
|
||||
/>
|
||||
{/if}
|
||||
<div class="absolute top-1 right-1">
|
||||
<AgGridWizard bind:value={componentInput.value}>
|
||||
{#snippet trigger()}
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
}
|
||||
|
||||
let { value = $bindable(), trigger: trigger_render }: Props = $props()
|
||||
|
||||
const isActionsColumn = $derived((value as any)?._isActionsColumn === true)
|
||||
|
||||
const presets = [
|
||||
{
|
||||
@@ -123,16 +125,18 @@
|
||||
<input type="text" placeholder="Header name" bind:value={value.headerName} />
|
||||
</Label>
|
||||
|
||||
<Label label="Editable value">
|
||||
<Toggle
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
}}
|
||||
options={{ right: 'Editable' }}
|
||||
bind:checked={value.editable}
|
||||
size="xs"
|
||||
/>
|
||||
</Label>
|
||||
{#if !isActionsColumn}
|
||||
<Label label="Editable value">
|
||||
<Toggle
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
}}
|
||||
options={{ right: 'Editable' }}
|
||||
bind:checked={value.editable}
|
||||
size="xs"
|
||||
/>
|
||||
</Label>
|
||||
{/if}
|
||||
|
||||
<Label label="Min width (px)">
|
||||
<input type="number" placeholder="width" bind:value={value.minWidth} />
|
||||
@@ -155,8 +159,8 @@
|
||||
</Tooltip>
|
||||
{/snippet}
|
||||
|
||||
<input type="range" step="1" bind:value={value.flex} min={1} max={12} />
|
||||
<div class="text-xs">{value.flex}</div>
|
||||
<input type="range" step="1" bind:value={value.flex} min={0} max={12} />
|
||||
<div class="text-xs">{value.flex ?? 0}</div>
|
||||
</Label>
|
||||
|
||||
<Label label="Hide">
|
||||
@@ -170,7 +174,8 @@
|
||||
/>
|
||||
</Label>
|
||||
|
||||
<Label label="Value formatter">
|
||||
{#if !isActionsColumn}
|
||||
<Label label="Value formatter">
|
||||
{#snippet header()}
|
||||
<Tooltip
|
||||
documentationLink="https://www.ag-grid.com/javascript-data-grid/value-formatters/"
|
||||
@@ -228,83 +233,84 @@
|
||||
{/key}
|
||||
</div>
|
||||
|
||||
<Label label="Sort">
|
||||
<select bind:value={value.sort}>
|
||||
<Label label="Sort">
|
||||
<select bind:value={value.sort}>
|
||||
<option value={null}>None</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</Label>
|
||||
|
||||
<Label label="Filter">
|
||||
{#snippet header()}
|
||||
<Tooltip documentationLink="https://www.ag-grid.com/javascript-data-grid/filtering/">
|
||||
Filtering allows you to limit the rows displayed in your grid to those that match
|
||||
criteria you specify.
|
||||
</Tooltip>
|
||||
{/snippet}
|
||||
<Toggle
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
}}
|
||||
options={{ right: 'Enable filter' }}
|
||||
bind:checked={value.filter}
|
||||
size="xs"
|
||||
/>
|
||||
</Label>
|
||||
|
||||
<!--
|
||||
EE only
|
||||
|
||||
<Label label="Aggregation function">
|
||||
<SimpleEditor autoHeight lang="javascript" bind:code={value.aggFunc} />
|
||||
</Label>
|
||||
|
||||
<Label label="Pivot">
|
||||
<Toggle bind:checked={value.pivot} size="xs" />
|
||||
</Label>
|
||||
|
||||
<Label label="Pivot index">
|
||||
<input type="number" placeholder="pivot index" bind:value={value.pivotIndex} />
|
||||
</Label>
|
||||
|
||||
<Label label="Pinned">
|
||||
<select bind:value={value.pinned}>
|
||||
<option value={null}>None</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
<option value="left">Left</option>
|
||||
<option value="right">Right</option>
|
||||
</select>
|
||||
</Label>
|
||||
|
||||
<Label label="Filter">
|
||||
{#snippet header()}
|
||||
<Tooltip documentationLink="https://www.ag-grid.com/javascript-data-grid/filtering/">
|
||||
Filtering allows you to limit the rows displayed in your grid to those that match
|
||||
criteria you specify.
|
||||
</Tooltip>
|
||||
{/snippet}
|
||||
<Toggle
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
}}
|
||||
options={{ right: 'Enable filter' }}
|
||||
bind:checked={value.filter}
|
||||
size="xs"
|
||||
/>
|
||||
<Label label="Row group">
|
||||
<Toggle bind:checked={value.rowGroup} size="xs" />
|
||||
</Label>
|
||||
|
||||
<!--
|
||||
EE only
|
||||
|
||||
<Label label="Aggregation function">
|
||||
<SimpleEditor autoHeight lang="javascript" bind:code={value.aggFunc} />
|
||||
</Label>
|
||||
|
||||
<Label label="Pivot">
|
||||
<Toggle bind:checked={value.pivot} size="xs" />
|
||||
</Label>
|
||||
|
||||
<Label label="Pivot index">
|
||||
<input type="number" placeholder="pivot index" bind:value={value.pivotIndex} />
|
||||
</Label>
|
||||
|
||||
<Label label="Pinned">
|
||||
<select bind:value={value.pinned}>
|
||||
<option value={null}>None</option>
|
||||
<option value="left">Left</option>
|
||||
<option value="right">Right</option>
|
||||
</select>
|
||||
</Label>
|
||||
|
||||
<Label label="Row group">
|
||||
<Toggle bind:checked={value.rowGroup} size="xs" />
|
||||
</Label>
|
||||
|
||||
<Label label="Row group index">
|
||||
<input type="number" placeholder="row group index" bind:value={value.rowGroupIndex} />
|
||||
</Label>
|
||||
-->
|
||||
|
||||
<Label label="Type">
|
||||
<select bind:value={value.cellRendererType}>
|
||||
<option value="text">Text</option>
|
||||
<option value="link">Link</option>
|
||||
</select>
|
||||
<Label label="Row group index">
|
||||
<input type="number" placeholder="row group index" bind:value={value.rowGroupIndex} />
|
||||
</Label>
|
||||
-->
|
||||
|
||||
{#if value.cellRendererType === 'link'}
|
||||
<Alert type="info" title="Label" size="xs">
|
||||
They are two ways to define a link:
|
||||
<ul class="list-disc list-inside">
|
||||
<li>
|
||||
<strong>String</strong>: The string will be used as the link and the label.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Object</strong>: The object must have a <code>href</code> and a
|
||||
<code>label</code> property.
|
||||
</li>
|
||||
</ul>
|
||||
</Alert>
|
||||
<Label label="Type">
|
||||
<select bind:value={value.cellRendererType}>
|
||||
<option value="text">Text</option>
|
||||
<option value="link">Link</option>
|
||||
</select>
|
||||
</Label>
|
||||
|
||||
{#if value.cellRendererType === 'link'}
|
||||
<Alert type="info" title="Label" size="xs">
|
||||
They are two ways to define a link:
|
||||
<ul class="list-disc list-inside">
|
||||
<li>
|
||||
<strong>String</strong>: The string will be used as the link and the label.
|
||||
</li>
|
||||
<li>
|
||||
<strong>Object</strong>: The object must have a <code>href</code> and a
|
||||
<code>label</code> property.
|
||||
</li>
|
||||
</ul>
|
||||
</Alert>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user