diff --git a/frontend/src/lib/components/apps/components/RefreshButton.svelte b/frontend/src/lib/components/apps/components/RefreshButton.svelte
deleted file mode 100644
index 4414f17b0a..0000000000
--- a/frontend/src/lib/components/apps/components/RefreshButton.svelte
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
diff --git a/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte b/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte
index 8a56e8091c..5398953997 100644
--- a/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte
+++ b/frontend/src/lib/components/apps/components/display/dbtable/AppDbExplorer.svelte
@@ -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
diff --git a/frontend/src/lib/components/apps/components/display/table/AppAggridExplorerTable.svelte b/frontend/src/lib/components/apps/components/display/table/AppAggridExplorerTable.svelte
index d48a10c8a0..18ab72b618 100644
--- a/frontend/src/lib/components/apps/components/display/table/AppAggridExplorerTable.svelte
+++ b/frontend/src/lib/components/apps/components/display/table/AppAggridExplorerTable.svelte
@@ -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 @@
/>
- {firstRow}{'->'}{lastRow + 1} of {datasource?.rowCount} rows
+ {#if datasource?.rowCount}
+ {firstRow}{'->'}{lastRow + 1} of {datasource?.rowCount} rows
+ {:else}
+ {firstRow}{'->'}{lastRow + 1}
+ {/if}
{:else if resolvedConfig.columnDefs != undefined}
diff --git a/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTable.svelte b/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTable.svelte
new file mode 100644
index 0000000000..19c8622a82
--- /dev/null
+++ b/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTable.svelte
@@ -0,0 +1,177 @@
+
+
+{#each Object.keys(components['aggridcomponent'].initialData.configuration) as key (key)}
+
+{/each}
+
+{#each Object.keys(css ?? {}) as key (key)}
+
+{/each}
+
+
+
+
+
+
diff --git a/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTableEe.svelte b/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTableEe.svelte
new file mode 100644
index 0000000000..e787c13f2b
--- /dev/null
+++ b/frontend/src/lib/components/apps/components/display/table/AppAggridInfiniteTableEe.svelte
@@ -0,0 +1,47 @@
+
+
+
+
+{#if loaded}
+
+{:else}
+
+{/if}
diff --git a/frontend/src/lib/components/apps/components/display/table/AppAggridTable.svelte b/frontend/src/lib/components/apps/components/display/table/AppAggridTable.svelte
index 398f4df9b3..1ffe584a25 100644
--- a/frontend/src/lib/components/apps/components/display/table/AppAggridTable.svelte
+++ b/frontend/src/lib/components/apps/components/display/table/AppAggridTable.svelte
@@ -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}
The result should be an array of objects, received:
- {JSON.stringify(result)}
+
+ {JSON.stringify(result)}
{/if}
diff --git a/frontend/src/lib/components/apps/components/display/table/AppTable.svelte b/frontend/src/lib/components/apps/components/display/table/AppTable.svelte
index 157e678e66..1c13d1c575 100644
--- a/frontend/src/lib/components/apps/components/display/table/AppTable.svelte
+++ b/frontend/src/lib/components/apps/components/display/table/AppTable.svelte
@@ -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
diff --git a/frontend/src/lib/components/apps/components/helpers/RefreshButton.svelte b/frontend/src/lib/components/apps/components/helpers/RefreshButton.svelte
index bf5cc6a2ac..ecb8278cf1 100644
--- a/frontend/src/lib/components/apps/components/helpers/RefreshButton.svelte
+++ b/frontend/src/lib/components/apps/components/helpers/RefreshButton.svelte
@@ -1,21 +1,39 @@
-
+
+
diff --git a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte
index 081045dab9..c41e3c9c40 100644
--- a/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte
+++ b/frontend/src/lib/components/apps/components/helpers/RunnableComponent.svelte
@@ -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}
-
+
{/if}
diff --git a/frontend/src/lib/components/apps/editor/component/Component.svelte b/frontend/src/lib/components/apps/editor/component/Component.svelte
index 7e130a6ee0..63c63ebb74 100644
--- a/frontend/src/lib/components/apps/editor/component/Component.svelte
+++ b/frontend/src/lib/components/apps/editor/component/Component.svelte
@@ -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'}
+
+ {:else if component.type === 'aggridinfinitecomponentee'}
+
{:else if component.type === 'textcomponent'}
& {
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,
diff --git a/frontend/src/lib/components/apps/editor/component/default-codes.ts b/frontend/src/lib/components/apps/editor/component/default-codes.ts
index 1058bfffcd..38f7eaa2e0 100644
--- a/frontend/src/lib/components/apps/editor/component/default-codes.ts
+++ b/frontend/src/lib/components/apps/editor/component/default-codes.ts
@@ -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>
+ Partial>
>
> = {
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: {
diff --git a/frontend/src/lib/components/apps/editor/component/sets.ts b/frontend/src/lib/components/apps/editor/component/sets.ts
index d69961d027..d00943748e 100644
--- a/frontend/src/lib/components/apps/editor/component/sets.ts
+++ b/frontend/src/lib/components/apps/editor/component/sets.ts
@@ -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 = {
diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/componentControlUtils.ts b/frontend/src/lib/components/apps/editor/componentsPanel/componentControlUtils.ts
index 087146d7e2..4c4588cb15 100644
--- a/frontend/src/lib/components/apps/editor/componentsPanel/componentControlUtils.ts
+++ b/frontend/src/lib/components/apps/editor/componentsPanel/componentControlUtils.ts
@@ -98,9 +98,11 @@ export function getComponentControl(type: keyof typeof components): Array
{/if}
diff --git a/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte b/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte
index be517a66b5..1d927f8996 100644
--- a/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte
+++ b/frontend/src/lib/components/apps/editor/settingsPanel/InputsSpecsEditor.svelte
@@ -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}
{#each Object.keys(finalInputSpecsConfiguration) as k}
- {#if finalInputSpecsConfiguration[k]?.type == 'oneOf'}
+ {#if overridenByComponent.includes(k)}
+
+
+ {k}
+
+
Managed by the component
+
+ {:else if finalInputSpecsConfiguration[k]?.type == 'oneOf'}
{/if}
{/if}
{/each}
+ {#if overridenByComponent.length > 0}
+ {#each overridenByComponent.filter((item) => Object.keys(finalInputSpecsConfiguration).indexOf(item) < 0) as k}
+
+
+ {k}
+
+
Managed by the component
+
+ {/each}
+ {/if}
{:else}
No inputs
diff --git a/frontend/src/lib/components/runs/JobLoader.svelte b/frontend/src/lib/components/runs/JobLoader.svelte
index b15c795788..dbfa8aaeef 100644
--- a/frontend/src/lib/components/runs/JobLoader.svelte
+++ b/frontend/src/lib/components/runs/JobLoader.svelte
@@ -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