mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 16:02:14 +00:00
feat(frontend): Aggrid infinite (#3592)
* feat(frontend): wip * feat(frontend): wip * feat(frontend): wip * feat(frontend): wip * feat(frontend): wip * feat(frontend): done * feat(frontend): done * feat(frontend): done * feat(frontend): fix initializing * feat(frontend): update all refreshButtons * feat(frontend): fix build
This commit is contained in:
@@ -1,39 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/common'
|
||||
import { LoaderIcon, RefreshCw } from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { AppViewerContext } from '../types'
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
|
||||
export let id: string
|
||||
export let loading: boolean
|
||||
|
||||
const { runnableComponents } = getContext<AppViewerContext>('AppViewerContext')
|
||||
</script>
|
||||
|
||||
<Popover>
|
||||
<Button
|
||||
startIcon={{
|
||||
icon: loading ? LoaderIcon : RefreshCw,
|
||||
classes: twMerge(
|
||||
loading ? 'animate-spin text-blue-800' : '',
|
||||
'transition-all text-gray-500 dark:text-white'
|
||||
)
|
||||
}}
|
||||
color="light"
|
||||
size="xs2"
|
||||
btnClasses={twMerge(loading ? ' bg-blue-100 dark:bg-blue-400' : '', 'transition-all')}
|
||||
on:click={() => {
|
||||
$runnableComponents[id]?.cb?.map((cb) => cb())
|
||||
}}
|
||||
iconOnly
|
||||
/>
|
||||
<svelte:fragment slot="text">
|
||||
{#if loading}
|
||||
Refreshing...
|
||||
{:else}
|
||||
Refresh
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
@@ -39,7 +39,7 @@
|
||||
import { getSelectInput } from './queries/select'
|
||||
import DebouncedInput from '../../helpers/DebouncedInput.svelte'
|
||||
import { CancelablePromise } from '$lib/gen'
|
||||
import RefreshButton from '$lib/components/apps/components/RefreshButton.svelte'
|
||||
import RefreshButton from '$lib/components/apps/components/helpers/RefreshButton.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
|
||||
+10
-4
@@ -27,7 +27,9 @@
|
||||
export let customCss: ComponentCustomCSS<'aggridcomponent'> | undefined = undefined
|
||||
export let containerHeight: number | undefined = undefined
|
||||
export let resolvedConfig: InitConfig<
|
||||
(typeof components)['dbexplorercomponent']['initialData']['configuration']
|
||||
| (typeof components)['dbexplorercomponent']['initialData']['configuration']
|
||||
| (typeof components)['aggridinfinitecomponent']['initialData']['configuration']
|
||||
| (typeof components)['aggridinfinitecomponentee']['initialData']['configuration']
|
||||
>
|
||||
export let datasource: IDatasource
|
||||
export let state: any = undefined
|
||||
@@ -236,8 +238,8 @@
|
||||
return r
|
||||
}
|
||||
|
||||
let firstRow = 0
|
||||
let lastRow = 0
|
||||
let firstRow: number = 0
|
||||
let lastRow: number = 0
|
||||
|
||||
function validateColumnDefs(columnDefs: ColumnDef[]): { isValid: boolean; errors: string[] } {
|
||||
let isValid = true
|
||||
@@ -431,7 +433,11 @@
|
||||
/>
|
||||
</Popover>
|
||||
|
||||
{firstRow}{'->'}{lastRow + 1} of {datasource?.rowCount} rows
|
||||
{#if datasource?.rowCount}
|
||||
{firstRow}{'->'}{lastRow + 1} of {datasource?.rowCount} rows
|
||||
{:else}
|
||||
{firstRow}{'->'}{lastRow + 1}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{:else if resolvedConfig.columnDefs != undefined}
|
||||
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
<script lang="ts">
|
||||
import type { IDatasource } from 'ag-grid-community'
|
||||
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppInput } from '../../../inputType'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../../types'
|
||||
import RunnableWrapper from '../../helpers/RunnableWrapper.svelte'
|
||||
|
||||
import { initConfig, initOutput } from '$lib/components/apps/editor/appUtils'
|
||||
import { components, type TableAction } from '$lib/components/apps/editor/component'
|
||||
import ResolveConfig from '../../helpers/ResolveConfig.svelte'
|
||||
|
||||
import 'ag-grid-community/styles/ag-grid.css'
|
||||
import './theme/windmill-theme.css'
|
||||
|
||||
import { initCss } from '$lib/components/apps/utils'
|
||||
import ResolveStyle from '../../helpers/ResolveStyle.svelte'
|
||||
import AppAggridExplorerTable from './AppAggridExplorerTable.svelte'
|
||||
import type { RunnableComponent } from '../..'
|
||||
import { getPrimaryKeys } from '../dbtable/utils'
|
||||
import InitializeComponent from '../../helpers/InitializeComponent.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let render: boolean
|
||||
export let customCss: ComponentCustomCSS<'aggridcomponent'> | undefined = undefined
|
||||
export let actions: TableAction[] | undefined = undefined
|
||||
let runnableComponent: RunnableComponent | undefined = undefined
|
||||
|
||||
const context = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { app, worldStore } = context
|
||||
|
||||
let css = initCss($app.css?.aggridcomponent, customCss)
|
||||
let result: any[] | undefined = undefined
|
||||
let loading: boolean = false
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['aggridinfinitecomponent'].initialData.configuration,
|
||||
configuration
|
||||
)
|
||||
|
||||
let outputs = initOutput($worldStore, id, {
|
||||
selectedRowIndex: 0,
|
||||
selectedRow: {},
|
||||
selectedRows: [] as any[],
|
||||
result: [] as any[],
|
||||
inputs: {},
|
||||
loading: false,
|
||||
page: 0,
|
||||
newChange: { row: 0, column: '', value: undefined },
|
||||
ready: undefined as boolean | undefined,
|
||||
params: {
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
orderBy: resolvedConfig.columnDefs?.[0]?.field,
|
||||
isDesc: false
|
||||
}
|
||||
})
|
||||
|
||||
let aggrid: AppAggridExplorerTable | undefined = undefined
|
||||
|
||||
function clear() {
|
||||
if (componentInput?.type !== 'runnable') {
|
||||
aggrid?.clearRows()
|
||||
}
|
||||
}
|
||||
|
||||
$: result && clear()
|
||||
|
||||
const datasource: IDatasource = {
|
||||
rowCount: undefined,
|
||||
|
||||
getRows: async function (params) {
|
||||
if (!render) {
|
||||
return
|
||||
}
|
||||
|
||||
const currentParams = {
|
||||
offset: params.startRow,
|
||||
limit: params.endRow - params.startRow,
|
||||
orderBy: params.sortModel?.[0]?.colId ?? resolvedConfig.columnDefs?.[0]?.field,
|
||||
isDesc: params.sortModel?.[0]?.sort === 'desc'
|
||||
}
|
||||
|
||||
outputs.params.set(currentParams)
|
||||
|
||||
if (!runnableComponent && result) {
|
||||
params.successCallback(result, result.length)
|
||||
}
|
||||
|
||||
runnableComponent?.runComponent(undefined, undefined, undefined, currentParams, {
|
||||
done: (items) => {
|
||||
let lastRow = -1
|
||||
|
||||
if (datasource?.rowCount && datasource.rowCount <= params.endRow) {
|
||||
lastRow = datasource.rowCount
|
||||
}
|
||||
|
||||
if (items && Array.isArray(items)) {
|
||||
let processedData = items.map((item) => {
|
||||
let primaryKeys = getPrimaryKeys(resolvedConfig.columnDefs)
|
||||
let o = {}
|
||||
primaryKeys.forEach((pk) => {
|
||||
o[pk] = item[pk]
|
||||
})
|
||||
item['__index'] = JSON.stringify(o)
|
||||
return item
|
||||
})
|
||||
|
||||
if (items.length < params.endRow - params.startRow) {
|
||||
lastRow = params.startRow + items.length
|
||||
}
|
||||
|
||||
datasource.rowCount = undefined
|
||||
|
||||
params.successCallback(processedData, lastRow)
|
||||
} else {
|
||||
params.failCallback()
|
||||
}
|
||||
},
|
||||
cancel: () => {
|
||||
params.failCallback()
|
||||
},
|
||||
error: () => {
|
||||
params.failCallback()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['aggridcomponent'].initialData.configuration) as key (key)}
|
||||
<ResolveConfig
|
||||
{id}
|
||||
{key}
|
||||
bind:resolvedConfig={resolvedConfig[key]}
|
||||
configuration={configuration[key]}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
{#each Object.keys(css ?? {}) as key (key)}
|
||||
<ResolveStyle
|
||||
{id}
|
||||
{customCss}
|
||||
{key}
|
||||
bind:css={css[key]}
|
||||
componentStyle={$app.css?.tablecomponent}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
<InitializeComponent {id} />
|
||||
|
||||
<RunnableWrapper
|
||||
{outputs}
|
||||
{componentInput}
|
||||
{id}
|
||||
bind:initializing
|
||||
bind:result
|
||||
bind:loading
|
||||
bind:runnableComponent
|
||||
{render}
|
||||
autoRefresh={false}
|
||||
allowConcurentRequests
|
||||
>
|
||||
<AppAggridExplorerTable
|
||||
{id}
|
||||
{datasource}
|
||||
{resolvedConfig}
|
||||
{customCss}
|
||||
{outputs}
|
||||
allowDelete={false}
|
||||
{actions}
|
||||
bind:this={aggrid}
|
||||
/>
|
||||
</RunnableWrapper>
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<script context="module">
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import type { AppInput } from '$lib/components/apps/inputType'
|
||||
import type { ComponentCustomCSS, RichConfigurations } from '$lib/components/apps/types'
|
||||
|
||||
import 'ag-grid-community/styles/ag-grid.css'
|
||||
import 'ag-grid-community/styles/ag-theme-alpine.css'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import type { TableAction } from '$lib/components/apps/editor/component'
|
||||
import AppAggridInfiniteTable from './AppAggridInfiniteTable.svelte'
|
||||
|
||||
export let id: string
|
||||
export let license: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let render: boolean
|
||||
export let customCss: ComponentCustomCSS<'aggridinfinitecomponentee'> | undefined = undefined
|
||||
export let actions: TableAction[] = []
|
||||
|
||||
let loaded = false
|
||||
async function load() {
|
||||
await import('ag-grid-enterprise')
|
||||
const { LicenseManager } = await import('ag-grid-enterprise')
|
||||
LicenseManager.setLicenseKey(license)
|
||||
|
||||
loaded = true
|
||||
}
|
||||
|
||||
load()
|
||||
</script>
|
||||
|
||||
{#if loaded}
|
||||
<AppAggridInfiniteTable
|
||||
{id}
|
||||
{componentInput}
|
||||
{configuration}
|
||||
{initializing}
|
||||
{render}
|
||||
{customCss}
|
||||
{actions}
|
||||
/>
|
||||
{:else}
|
||||
<Loader2 class="animate-spin" />
|
||||
{/if}
|
||||
@@ -17,7 +17,7 @@
|
||||
import Alert from '$lib/components/common/alert/Alert.svelte'
|
||||
import ResolveConfig from '../../helpers/ResolveConfig.svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import RefreshButton from '$lib/components/apps/components/RefreshButton.svelte'
|
||||
import RefreshButton from '$lib/components/apps/components/helpers/RefreshButton.svelte'
|
||||
|
||||
import 'ag-grid-community/styles/ag-grid.css'
|
||||
import './theme/windmill-theme.css'
|
||||
@@ -467,8 +467,8 @@
|
||||
{:else if result != undefined}
|
||||
<Alert title="Parsing issues" type="error" size="xs">
|
||||
The result should be an array of objects, received:
|
||||
<pre class="overflow-auto mt-2"
|
||||
>{JSON.stringify(result)}
|
||||
<pre class="overflow-auto mt-2">
|
||||
{JSON.stringify(result)}
|
||||
</pre>
|
||||
</Alert>
|
||||
{/if}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
import { EyeIcon, Plug2 } from 'lucide-svelte'
|
||||
import AppCell from './AppCell.svelte'
|
||||
import sum from 'hash-sum'
|
||||
import RefreshButton from '$lib/components/apps/components/RefreshButton.svelte'
|
||||
import RefreshButton from '$lib/components/apps/components/helpers/RefreshButton.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
|
||||
@@ -1,21 +1,39 @@
|
||||
<script lang="ts">
|
||||
import { RefreshCw } from 'lucide-svelte'
|
||||
import { Button } from '$lib/components/common'
|
||||
import { LoaderIcon, RefreshCw } from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
|
||||
export let componentId: string
|
||||
export let id: string
|
||||
export let loading: boolean
|
||||
const { runnableComponents } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
async function refresh() {
|
||||
await $runnableComponents[componentId]?.cb?.map((cb) => cb())
|
||||
}
|
||||
const { runnableComponents } = getContext<AppViewerContext>('AppViewerContext')
|
||||
</script>
|
||||
|
||||
<button
|
||||
on:pointerdown|preventDefault|stopPropagation
|
||||
on:click|preventDefault|stopPropagation={refresh}
|
||||
class="center-center p-1 rounded border bg-surface/60 hover:bg-surface-hover z-10"
|
||||
>
|
||||
<RefreshCw class={loading ? 'animate-spin' : ''} size={16} />
|
||||
</button>
|
||||
<Popover>
|
||||
<Button
|
||||
startIcon={{
|
||||
icon: loading ? LoaderIcon : RefreshCw,
|
||||
classes: twMerge(
|
||||
loading ? 'animate-spin text-blue-800' : '',
|
||||
'transition-all text-gray-500 dark:text-white'
|
||||
)
|
||||
}}
|
||||
color="light"
|
||||
size="xs2"
|
||||
btnClasses={twMerge(loading ? ' bg-blue-100 dark:bg-blue-400' : '', 'transition-all')}
|
||||
on:click={() => {
|
||||
$runnableComponents[id]?.cb?.map((cb) => cb())
|
||||
}}
|
||||
iconOnly
|
||||
/>
|
||||
<svelte:fragment slot="text">
|
||||
{#if loading}
|
||||
Refreshing...
|
||||
{:else}
|
||||
Refresh
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
} from '../../types'
|
||||
import { computeGlobalContext, eval_like } from './eval'
|
||||
import InputValue from './InputValue.svelte'
|
||||
import RefreshButton from './RefreshButton.svelte'
|
||||
import { selectId } from '../../editor/appUtils'
|
||||
import ResultJobLoader from '$lib/components/ResultJobLoader.svelte'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { get } from 'svelte/store'
|
||||
import RefreshButton from '$lib/components/apps/components/helpers/RefreshButton.svelte'
|
||||
|
||||
// Component props
|
||||
export let id: string
|
||||
@@ -722,7 +722,7 @@
|
||||
{/if}
|
||||
{#if render && !initializing && autoRefresh === true && !hideRefreshButton}
|
||||
<div class="flex absolute top-1 right-1 z-50 app-component-refresh-btn">
|
||||
<RefreshButton {loading} componentId={id} />
|
||||
<RefreshButton {loading} {id} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -73,6 +73,8 @@
|
||||
import AppDateSliderInput from '../../components/inputs/AppDateSliderInput.svelte'
|
||||
import AppTimeInput from '../../components/inputs/AppTimeInput.svelte'
|
||||
import AppDateTimeInput from '../../components/inputs/AppDateTimeInput.svelte'
|
||||
import AppAggridInfiniteTable from '../../components/display/table/AppAggridInfiniteTable.svelte'
|
||||
import AppAggridInfiniteTableEe from '../../components/display/table/AppAggridInfiniteTableEe.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
@@ -366,6 +368,27 @@
|
||||
actions={component.actions ?? []}
|
||||
{render}
|
||||
/>
|
||||
{:else if component.type === 'aggridinfinitecomponent'}
|
||||
<AppAggridInfiniteTable
|
||||
id={component.id}
|
||||
configuration={component.configuration}
|
||||
bind:initializing
|
||||
componentInput={component.componentInput}
|
||||
customCss={component.customCss}
|
||||
actions={component.actions ?? []}
|
||||
{render}
|
||||
/>
|
||||
{:else if component.type === 'aggridinfinitecomponentee'}
|
||||
<AppAggridInfiniteTableEe
|
||||
license={component.license}
|
||||
id={component.id}
|
||||
configuration={component.configuration}
|
||||
bind:initializing
|
||||
componentInput={component.componentInput}
|
||||
customCss={component.customCss}
|
||||
actions={component.actions ?? []}
|
||||
{render}
|
||||
/>
|
||||
{:else if component.type === 'textcomponent'}
|
||||
<AppText
|
||||
id={component.id}
|
||||
|
||||
@@ -151,6 +151,16 @@ export type AggridComponentEe = BaseComponent<'aggridcomponentee'> & {
|
||||
license: string
|
||||
actions: TableAction[]
|
||||
}
|
||||
|
||||
export type AggridInfiniteComponent = BaseComponent<'aggridinfinitecomponent'> & {
|
||||
actions: TableAction[]
|
||||
}
|
||||
|
||||
export type AggridInfiniteComponentEe = BaseComponent<'aggridinfinitecomponentee'> & {
|
||||
actions: TableAction[]
|
||||
license: string
|
||||
}
|
||||
|
||||
export type DisplayComponent = BaseComponent<'displaycomponent'>
|
||||
export type LogComponent = BaseComponent<'logcomponent'>
|
||||
export type JobIdLogComponent = BaseComponent<'jobidlogcomponent'>
|
||||
@@ -305,6 +315,8 @@ export type TypedComponent =
|
||||
| DateSliderComponent
|
||||
| TimeInputComponent
|
||||
| DateTimeInputComponent
|
||||
| AggridInfiniteComponent
|
||||
| AggridInfiniteComponentEe
|
||||
|
||||
export type AppComponent = BaseAppComponent & TypedComponent
|
||||
|
||||
@@ -712,6 +724,101 @@ const aggridcomponentconst = {
|
||||
}
|
||||
} as const
|
||||
|
||||
const aggridinfinitecomponentconst = {
|
||||
name: 'AgGrid Infinite Table',
|
||||
icon: Table2,
|
||||
documentationLink: `${documentationBaseUrl}/aggrid_infinite_table`,
|
||||
dims: '3:10-6:10' as AppComponentDimensions,
|
||||
customCss: {
|
||||
container: { class: '', style: '' }
|
||||
},
|
||||
initialData: {
|
||||
configuration: {
|
||||
columnDefs: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'ag-grid',
|
||||
value: [
|
||||
{ field: 'id', flex: 1 },
|
||||
{ field: 'name', editable: true, flex: 1 },
|
||||
{ field: 'age', flex: 1 }
|
||||
]
|
||||
} as StaticAppInput,
|
||||
flex: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: true,
|
||||
tooltip: 'default col flex is 1 (see ag-grid docs)'
|
||||
},
|
||||
allEditable: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
hide: true,
|
||||
tooltip: 'Configure all columns as Editable by users'
|
||||
},
|
||||
multipleSelectable: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
|
||||
tooltip: 'Make multiple rows selectable at once'
|
||||
},
|
||||
rowMultiselectWithClick: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: true,
|
||||
|
||||
tooltip: 'If multiple selectable, allow multiselect with click'
|
||||
},
|
||||
|
||||
selectFirstRowByDefault: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: true as boolean,
|
||||
tooltip: 'Select the first row by default on start'
|
||||
},
|
||||
extraConfig: {
|
||||
type: 'static',
|
||||
fieldType: 'object',
|
||||
value: {},
|
||||
tooltip: 'any configuration that can be passed to ag-grid top level'
|
||||
},
|
||||
compactness: {
|
||||
type: 'static',
|
||||
fieldType: 'select',
|
||||
value: 'normal',
|
||||
selectOptions: ['normal', 'compact', 'comfortable'],
|
||||
tooltip: 'Change the row height'
|
||||
},
|
||||
wrapActions: {
|
||||
type: 'static',
|
||||
fieldType: 'boolean',
|
||||
value: false,
|
||||
tooltip:
|
||||
'When true, actions will wrap to the next line. Otherwise, the column will grow to fit the actions.'
|
||||
}
|
||||
},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'object',
|
||||
value: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'A cell with a long name',
|
||||
age: 42
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'A briefer cell',
|
||||
age: 84
|
||||
}
|
||||
]
|
||||
} as StaticAppInput
|
||||
}
|
||||
} as const
|
||||
|
||||
const agchartscomponentconst = {
|
||||
name: 'AgCharts',
|
||||
icon: BarChart4,
|
||||
@@ -1734,6 +1841,8 @@ This is a paragraph.
|
||||
},
|
||||
aggridcomponent: aggridcomponentconst,
|
||||
aggridcomponentee: { ...aggridcomponentconst, name: 'AgGrid Table EE' },
|
||||
aggridinfinitecomponent: aggridinfinitecomponentconst,
|
||||
aggridinfinitecomponentee: { ...aggridinfinitecomponentconst, name: 'AgGrid Infinite EE' },
|
||||
checkboxcomponent: {
|
||||
name: 'Toggle',
|
||||
icon: ToggleLeft,
|
||||
|
||||
@@ -5,13 +5,14 @@ export function defaultCode(component: string, language: string): string | undef
|
||||
if (language == 'bun') {
|
||||
lang = 'deno'
|
||||
}
|
||||
|
||||
return DEFAULT_CODES[component]?.[lang]
|
||||
}
|
||||
|
||||
export const DEFAULT_CODES: Partial<
|
||||
Record<
|
||||
AppComponent['type'],
|
||||
Partial<Record<'deno' | 'python3' | 'go' | 'bash' | 'pgsql' | 'mysql', string>>
|
||||
Partial<Record<'deno' | 'python3' | 'go' | 'bash' | 'pgsql' | 'mysql' | 'postgresql', string>>
|
||||
>
|
||||
> = {
|
||||
tablecomponent: {
|
||||
@@ -41,15 +42,7 @@ export const DEFAULT_CODES: Partial<
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]`,
|
||||
pgsql: `import { pgSql } from "npm:windmill-client@${__pkg__.version}";
|
||||
|
||||
type Postgresql = object
|
||||
|
||||
export async function main(db: Postgresql) {
|
||||
const query = await pgSql(db)\`SELECT * FROM demo;\`;
|
||||
return query.rows;
|
||||
}`
|
||||
]`
|
||||
},
|
||||
aggridcomponent: {
|
||||
deno: `export async function main() {
|
||||
@@ -99,6 +92,72 @@ export async function main(db: Postgresql) {
|
||||
# if page0Invalid:
|
||||
# raise Exception("first step invalid")
|
||||
# elif ...
|
||||
`
|
||||
},
|
||||
aggridinfinitecomponent: {
|
||||
deno: `export async function main(offset: number, limit:number, orderBy: string, isDesc: boolean) {
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]
|
||||
}`,
|
||||
python3: `def main(offset: int, limit: int, orderBy: str, isDesc: bool):
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]`,
|
||||
postgresql: `-- $1 limit
|
||||
-- $2 offset
|
||||
SELECT * FROM demo LIMIT $1::INT OFFSET $2::INT;
|
||||
`
|
||||
},
|
||||
aggridinfinitecomponentee: {
|
||||
deno: `export async function main(offset: number, limit:number, orderBy: string, isDesc: boolean) {
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]
|
||||
}`,
|
||||
python3: `def main(offset: int, limit: int, orderBy: str, isDesc: bool):
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]`,
|
||||
postgresql: `-- $1 limit
|
||||
-- $2 offset
|
||||
SELECT * FROM demo LIMIT $1::INT OFFSET $2::INT;
|
||||
`
|
||||
},
|
||||
textcomponent: {
|
||||
|
||||
@@ -77,7 +77,14 @@ const display: ComponentSet = {
|
||||
|
||||
const tables: ComponentSet = {
|
||||
title: 'Tables',
|
||||
components: ['tablecomponent', 'aggridcomponent', 'aggridcomponentee', 'dbexplorercomponent']
|
||||
components: [
|
||||
'tablecomponent',
|
||||
'aggridcomponent',
|
||||
'aggridcomponentee',
|
||||
'dbexplorercomponent',
|
||||
'aggridinfinitecomponent',
|
||||
'aggridinfinitecomponentee'
|
||||
]
|
||||
} as const
|
||||
|
||||
const charts: ComponentSet = {
|
||||
|
||||
@@ -98,9 +98,11 @@ export function getComponentControl(type: keyof typeof components): Array<Compon
|
||||
case 'drawercomponent':
|
||||
return [open, close]
|
||||
case 'aggridcomponent':
|
||||
return [getAgGrid, setSelectedIndex]
|
||||
case 'aggridcomponentee':
|
||||
case 'aggridinfinitecomponent':
|
||||
case 'aggridinfinitecomponentee':
|
||||
return [getAgGrid, setSelectedIndex]
|
||||
|
||||
case 's3fileinputcomponent':
|
||||
return [clearFiles]
|
||||
case 'displaycomponent':
|
||||
|
||||
@@ -610,6 +610,8 @@ export const quickStyleProperties: Record<
|
||||
},
|
||||
aggridcomponent: {},
|
||||
aggridcomponentee: {},
|
||||
aggridinfinitecomponent: {},
|
||||
aggridinfinitecomponentee: {},
|
||||
buttoncomponent: {
|
||||
button: buttonDefaultProps,
|
||||
container: containerDefaultProps
|
||||
|
||||
+2
-6
@@ -93,12 +93,8 @@
|
||||
|
||||
if (componentOutputs.currentStepIndex) {
|
||||
newFields['stepIndex'] = {
|
||||
type: 'connected',
|
||||
connection: {
|
||||
componentId: id,
|
||||
path: 'currentStepIndex'
|
||||
},
|
||||
value: componentOutputs.currentStepIndex.peak(),
|
||||
type: 'evalv2',
|
||||
expr: `${id}.currentStepIndex`,
|
||||
fieldType: 'number'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,6 +315,13 @@
|
||||
recomputeOnInputChanged={componentSettings.item.data.componentInput
|
||||
.recomputeOnInputChanged}
|
||||
showOnDemandOnlyToggle
|
||||
acceptSelf={component.type === 'aggridinfinitecomponent' ||
|
||||
component.type === 'aggridinfinitecomponentee' ||
|
||||
component.type === 'steppercomponent'}
|
||||
overridenByComponent={component.type === 'aggridinfinitecomponent' ||
|
||||
component.type === 'aggridinfinitecomponentee'
|
||||
? ['offset', 'limit', 'orderBy', 'isDesc']
|
||||
: []}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
export let acceptSelf: boolean = false
|
||||
export let recomputeOnInputChanged = true
|
||||
export let showOnDemandOnlyToggle = false
|
||||
export let overridenByComponent: string[] = []
|
||||
|
||||
$: finalInputSpecsConfiguration = inputSpecsConfiguration ?? inputSpecs
|
||||
|
||||
@@ -26,7 +27,14 @@
|
||||
{#if inputSpecs}
|
||||
<div class="w-full flex flex-col gap-4">
|
||||
{#each Object.keys(finalInputSpecsConfiguration) as k}
|
||||
{#if finalInputSpecsConfiguration[k]?.type == 'oneOf'}
|
||||
{#if overridenByComponent.includes(k)}
|
||||
<div>
|
||||
<span class="text-xs font-semibold truncate text-primary">
|
||||
{k}
|
||||
</span>
|
||||
<div class="text-tertiary text-xs">Managed by the component</div>
|
||||
</div>
|
||||
{:else if finalInputSpecsConfiguration[k]?.type == 'oneOf'}
|
||||
<OneOfInputSpecsEditor
|
||||
{acceptSelf}
|
||||
key={k}
|
||||
@@ -71,6 +79,16 @@
|
||||
</div>{/if}
|
||||
{/if}
|
||||
{/each}
|
||||
{#if overridenByComponent.length > 0}
|
||||
{#each overridenByComponent.filter((item) => Object.keys(finalInputSpecsConfiguration).indexOf(item) < 0) as k}
|
||||
<div>
|
||||
<span class="text-xs font-semibold truncate text-primary">
|
||||
{k}
|
||||
</span>
|
||||
<div class="text-tertiary text-xs">Managed by the component</div>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-tertiary text-sm">No inputs</div>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
export let jobs: Job[] | undefined
|
||||
export let user: string | null
|
||||
export let label: string | null
|
||||
export let label: string | null = null
|
||||
export let folder: string | null
|
||||
export let path: string | null
|
||||
export let success: 'success' | 'failure' | 'running' | undefined = undefined
|
||||
|
||||
Reference in New Issue
Block a user