mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-23 00:00:33 +00:00
feat(frontend): Add app sub grids (#1208)
* feat(frontend): Add app sub grids * feat(frontend): remove temp file * feat(frontend): update package.json * feat(frontend): fix build * fixes * feat(frontend): wip * feat(frontend): wip * feat(frontend): update dependencies * feat(frontend): update dependencies * feat(frontend): fix scrolling issues * feat(frontend): fix preview + delete * feat(frontend): done * feat(frontend): remove dead code * feat(frontend): fix selection * feat(frontend): add container * feat(frontend): fix package.json * feat(frontend): fix package.json * feat(frontend): fix package.json * feat(frontend): fix package.json * feat(frontend): fix package.json * feat(frontend): restore npm package * feat(frontend): add missing dependencies * feat(frontend): remove missing dependencies * feat(frontend): fix package.json * feat(frontend): fix package.json * feat(frontend): fix package.json * feat(frontend): revert * feat(frontend): fix package-lock * feat(frontend): fix package-lock * fix package-lock.json * update --------- Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
This commit is contained in:
Generated
+18
-22
@@ -11,9 +11,11 @@
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||
"@leeoniya/ufuzzy": "^0.9.1",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"@redocly/json-to-json-schema": "^0.0.1",
|
||||
"@tanstack/svelte-table": "^8.7.6",
|
||||
"async-mutex": "^0.4.0",
|
||||
"chart.js": "^3.9.1",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"chartjs-plugin-zoom": "^2.0.0",
|
||||
"date-fns": "^2.29.3",
|
||||
@@ -41,6 +43,7 @@
|
||||
"@types/vscode": "~1.74.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.49.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
"@windmill-labs/svelte-grid": "^5.1.3",
|
||||
"@windmill-labs/svelvet": "^4.0.20",
|
||||
"@zerodevx/svelte-toast": "^0.8.1",
|
||||
"autoprefixer": "^10.4.13",
|
||||
@@ -60,7 +63,6 @@
|
||||
"svelte": "^3.55.1",
|
||||
"svelte-awesome": "^3.0.0",
|
||||
"svelte-check": "^3.0.2",
|
||||
"svelte-grid": "^5.1.1",
|
||||
"svelte-highlight": "^6.2.1",
|
||||
"svelte-overlay": "^1.4.1",
|
||||
"svelte-popperjs": "^1.3.2",
|
||||
@@ -775,8 +777,6 @@
|
||||
"version": "2.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
|
||||
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
@@ -1262,6 +1262,12 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@windmill-labs/svelte-grid": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.3.tgz",
|
||||
"integrity": "sha512-SzfuJ2qYkBYC73x3l+x9l7WcgU+kMlRoFkCgSCOfggi3z5zJU9eX1VYsV1wDjtQVU9OUaAciv1xlUR4OPxrFlg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@windmill-labs/svelvet": {
|
||||
"version": "4.0.20",
|
||||
"resolved": "https://registry.npmjs.org/@windmill-labs/svelvet/-/svelvet-4.0.20.tgz",
|
||||
@@ -1865,8 +1871,7 @@
|
||||
"node_modules/chart.js": {
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
|
||||
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==",
|
||||
"peer": true
|
||||
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
|
||||
},
|
||||
"node_modules/chartjs-adapter-date-fns": {
|
||||
"version": "3.0.0",
|
||||
@@ -6198,12 +6203,6 @@
|
||||
"typescript": "^4.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-grid": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-grid/-/svelte-grid-5.1.1.tgz",
|
||||
"integrity": "sha512-PJTC4PUejb8RzcUjymWnf1HALqseUBwxl+p+i5uJlDIC1+zXKok1J16IDoHQxXhNj+INcF9KHE7hIm++NurSAQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/svelte-highlight": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-highlight/-/svelte-highlight-6.2.1.tgz",
|
||||
@@ -7597,9 +7596,7 @@
|
||||
"@popperjs/core": {
|
||||
"version": "2.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
|
||||
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
|
||||
},
|
||||
"@redocly/json-to-json-schema": {
|
||||
"version": "0.0.1",
|
||||
@@ -7906,6 +7903,12 @@
|
||||
"eslint-visitor-keys": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@windmill-labs/svelte-grid": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@windmill-labs/svelte-grid/-/svelte-grid-5.1.3.tgz",
|
||||
"integrity": "sha512-SzfuJ2qYkBYC73x3l+x9l7WcgU+kMlRoFkCgSCOfggi3z5zJU9eX1VYsV1wDjtQVU9OUaAciv1xlUR4OPxrFlg==",
|
||||
"dev": true
|
||||
},
|
||||
"@windmill-labs/svelvet": {
|
||||
"version": "4.0.20",
|
||||
"resolved": "https://registry.npmjs.org/@windmill-labs/svelvet/-/svelvet-4.0.20.tgz",
|
||||
@@ -8321,8 +8324,7 @@
|
||||
"chart.js": {
|
||||
"version": "3.9.1",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
|
||||
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==",
|
||||
"peer": true
|
||||
"integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
|
||||
},
|
||||
"chartjs-adapter-date-fns": {
|
||||
"version": "3.0.0",
|
||||
@@ -11513,12 +11515,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"svelte-grid": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-grid/-/svelte-grid-5.1.1.tgz",
|
||||
"integrity": "sha512-PJTC4PUejb8RzcUjymWnf1HALqseUBwxl+p+i5uJlDIC1+zXKok1J16IDoHQxXhNj+INcF9KHE7hIm++NurSAQ==",
|
||||
"dev": true
|
||||
},
|
||||
"svelte-highlight": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/svelte-highlight/-/svelte-highlight-6.2.1.tgz",
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"@types/vscode": "~1.74.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.49.0",
|
||||
"@typescript-eslint/parser": "^5.48.0",
|
||||
"@windmill-labs/svelte-grid": "^5.1.3",
|
||||
"@windmill-labs/svelvet": "^4.0.20",
|
||||
"@zerodevx/svelte-toast": "^0.8.1",
|
||||
"autoprefixer": "^10.4.13",
|
||||
@@ -44,7 +45,6 @@
|
||||
"svelte": "^3.55.1",
|
||||
"svelte-awesome": "^3.0.0",
|
||||
"svelte-check": "^3.0.2",
|
||||
"svelte-grid": "^5.1.1",
|
||||
"svelte-highlight": "^6.2.1",
|
||||
"svelte-overlay": "^1.4.1",
|
||||
"svelte-popperjs": "^1.3.2",
|
||||
@@ -63,9 +63,11 @@
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||
"@leeoniya/ufuzzy": "^0.9.1",
|
||||
"@popperjs/core": "^2.11.6",
|
||||
"@redocly/json-to-json-schema": "^0.0.1",
|
||||
"@tanstack/svelte-table": "^8.7.6",
|
||||
"async-mutex": "^0.4.0",
|
||||
"chart.js": "^3.9.1",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"chartjs-plugin-zoom": "^2.0.0",
|
||||
"date-fns": "^2.29.3",
|
||||
|
||||
Vendored
+5
-5
@@ -9,7 +9,7 @@ declare namespace svelte.JSX {
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'svelte-grid' {
|
||||
declare module '@windmill-labs/svelte-grid' {
|
||||
import type { SvelteComponentTyped } from 'svelte'
|
||||
|
||||
export interface Size {
|
||||
@@ -37,7 +37,7 @@ declare module 'svelte-grid' {
|
||||
|
||||
export interface Props<T> {
|
||||
fillSpace?: boolean
|
||||
items: FilledItem<T>[],
|
||||
items: FilledItem<T>[]
|
||||
rowHeight: number
|
||||
cols: [number, number][]
|
||||
gap?: [number, number]
|
||||
@@ -60,11 +60,11 @@ declare module 'svelte-grid' {
|
||||
mount: CustomEvent<>
|
||||
},
|
||||
Slots<T>
|
||||
> { }
|
||||
> {}
|
||||
}
|
||||
|
||||
declare module 'svelte-grid/build/helper/index.mjs' {
|
||||
import { ItemLayout } from 'svelte-grid'
|
||||
declare module '@windmill-labs/svelte-grid/build/helper/index.mjs' {
|
||||
import { ItemLayout } from '@windmill-labs/svelte-grid'
|
||||
|
||||
const x: {
|
||||
normalize(items: any[], col: any): unknown[]
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import SubGridEditor from '../editor/SubGridEditor.svelte'
|
||||
import type { AppInput } from '../inputType'
|
||||
import type { AppEditorContext, GridItem } from '../types'
|
||||
import InputValue from './helpers/InputValue.svelte'
|
||||
import RunnableWrapper from './helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let subGrids: GridItem[][] | undefined = undefined
|
||||
export let componentContainerHeight: number
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result']
|
||||
const { focusedGrid, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let result: string[] | undefined = undefined
|
||||
let gridContent: string[] | undefined = undefined
|
||||
|
||||
function onFocus() {
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
}
|
||||
|
||||
$: $selectedComponent === id && onFocus()
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.gridContent} bind:value={gridContent} />
|
||||
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
|
||||
{#if subGrids && subGrids[0]}
|
||||
<SubGridEditor
|
||||
bind:subGrid={subGrids[0]}
|
||||
containerHeight={componentContainerHeight}
|
||||
on:focus={() => {
|
||||
$selectedComponent = id
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</RunnableWrapper>
|
||||
@@ -0,0 +1,73 @@
|
||||
<script lang="ts">
|
||||
import { Tab, Tabs } from '$lib/components/common'
|
||||
import { getContext } from 'svelte'
|
||||
import SubGridEditor from '../editor/SubGridEditor.svelte'
|
||||
import type { AppInput } from '../inputType'
|
||||
import type { Output } from '../rx'
|
||||
import type { AppEditorContext, GridItem } from '../types'
|
||||
import InputValue from './helpers/InputValue.svelte'
|
||||
import RunnableWrapper from './helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let configuration: Record<string, AppInput>
|
||||
export let subGrids: GridItem[][] | undefined = undefined
|
||||
export let componentContainerHeight: number
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result', 'selectedTabIndex']
|
||||
const { worldStore, focusedGrid, selectedComponent } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let result: string[] | undefined = undefined
|
||||
let gridContent: string[] | undefined = undefined
|
||||
let selected: string = ''
|
||||
|
||||
$: selectedIndex = result?.indexOf(selected) ?? -1
|
||||
|
||||
$: if (result && selected === '') {
|
||||
selected = result[0]
|
||||
}
|
||||
|
||||
$: outputs = $worldStore?.outputsById[id] as {
|
||||
selectedTabIndex: Output<number | null>
|
||||
}
|
||||
|
||||
function handleTabSelection() {
|
||||
outputs?.selectedTabIndex.set(selectedIndex)
|
||||
}
|
||||
|
||||
$: selectedIndex >= 0 && handleTabSelection()
|
||||
let tabHeight: number = 0
|
||||
|
||||
function onFocus() {
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: selectedIndex ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
$: $selectedComponent === id && selectedIndex >= 0 && onFocus()
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.gridContent} bind:value={gridContent} />
|
||||
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
|
||||
<div bind:clientHeight={tabHeight}>
|
||||
<Tabs bind:selected>
|
||||
{#each result ?? [] as res}
|
||||
<Tab value={res}>
|
||||
<span class="font-semibold">{res}</span>
|
||||
</Tab>
|
||||
{/each}
|
||||
</Tabs>
|
||||
</div>
|
||||
{#if subGrids && subGrids[selectedIndex]}
|
||||
<SubGridEditor
|
||||
bind:subGrid={subGrids[selectedIndex]}
|
||||
containerHeight={componentContainerHeight - tabHeight}
|
||||
on:focus={() => {
|
||||
$selectedComponent = id
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</RunnableWrapper>
|
||||
@@ -11,6 +11,7 @@
|
||||
CategoryScale,
|
||||
BarElement
|
||||
} from 'chart.js'
|
||||
import type { ChartOptions } from 'chart.js'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
@@ -45,7 +46,18 @@
|
||||
theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e']
|
||||
}[theme]
|
||||
|
||||
const options = {
|
||||
const lineOptions: ChartOptions<'line'> = {
|
||||
responsive: true,
|
||||
animation: false,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const barOptions: ChartOptions<'bar'> = {
|
||||
responsive: true,
|
||||
animation: false,
|
||||
maintainAspectRatio: false,
|
||||
@@ -73,9 +85,9 @@
|
||||
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
|
||||
{#if result}
|
||||
{#if lineChart}
|
||||
<Line {data} {options} />
|
||||
<Line {data} options={lineOptions} />
|
||||
{:else}
|
||||
<Bar {data} {options} />
|
||||
<Bar {data} options={barOptions} />
|
||||
{/if}
|
||||
{/if}
|
||||
</RunnableWrapper>
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
LinearScale,
|
||||
PointElement,
|
||||
CategoryScale,
|
||||
BarElement
|
||||
BarElement,
|
||||
type Point
|
||||
} from 'chart.js'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import Scatter from 'svelte-chartjs/Scatter.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import type { ChartOptions, ChartData } from 'chart.js'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
@@ -59,11 +61,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} as ChartOptions<'scatter'>
|
||||
|
||||
$: data = {
|
||||
datasets: result ?? []
|
||||
}
|
||||
} as ChartData<'scatter', (number | Point)[], unknown>
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.zoomable} bind:value={zoomable} />
|
||||
|
||||
@@ -12,12 +12,14 @@
|
||||
CategoryScale,
|
||||
BarElement,
|
||||
TimeScale,
|
||||
LogarithmicScale
|
||||
LogarithmicScale,
|
||||
type Point
|
||||
} from 'chart.js'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import Scatter from 'svelte-chartjs/Scatter.svelte'
|
||||
import { Scatter } from 'svelte-chartjs'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import type { ChartOptions, ChartData } from 'chart.js'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
@@ -73,11 +75,11 @@
|
||||
type: logarithmicScale ? 'logarithmic' : 'linear'
|
||||
}
|
||||
}
|
||||
}
|
||||
} as ChartOptions<'scatter'>
|
||||
|
||||
$: data = {
|
||||
datasets: result ?? []
|
||||
}
|
||||
} as ChartData<'scatter', (number | Point)[], unknown>
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.logarithmicScale} bind:value={logarithmicScale} />
|
||||
|
||||
@@ -35,7 +35,9 @@
|
||||
accept={acceptedFileTypes?.length ? acceptedFileTypes?.join(', ') : undefined}
|
||||
multiple={allowMultiple}
|
||||
convertToBase64
|
||||
on:change={({detail}) => {handleChange(detail)}}
|
||||
on:change={({ detail }) => {
|
||||
handleChange(detail)
|
||||
}}
|
||||
class="w-full h-full"
|
||||
>
|
||||
{text}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
result: Output<boolean>
|
||||
}
|
||||
|
||||
$: defaultValue != undefined && outputs.result.set(defaultValue)
|
||||
$: defaultValue != undefined && outputs?.result.set(defaultValue)
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.label} bind:value={labelValue} />
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
AppEditorContext,
|
||||
ConnectingInput,
|
||||
EditorBreakpoint,
|
||||
EditorMode
|
||||
EditorMode,
|
||||
FocusedGrid
|
||||
} from '../types'
|
||||
import AppEditorHeader from './AppEditorHeader.svelte'
|
||||
import GridEditor from './GridEditor.svelte'
|
||||
@@ -59,6 +60,8 @@
|
||||
const runnableComponents = writable<Record<string, () => Promise<void>>>({})
|
||||
const errorByComponent = writable<Record<string, { error: string; componentId: string }>>({})
|
||||
|
||||
const focusedGrid = writable<FocusedGrid | undefined>(undefined)
|
||||
|
||||
setContext<AppEditorContext>('AppEditorContext', {
|
||||
worldStore,
|
||||
staticOutputs,
|
||||
@@ -78,7 +81,8 @@
|
||||
staticExporter: writable({}),
|
||||
noBackend: false,
|
||||
errorByComponent,
|
||||
openDebugRun: writable(undefined)
|
||||
openDebugRun: writable(undefined),
|
||||
focusedGrid
|
||||
})
|
||||
|
||||
let timeout: NodeJS.Timeout | undefined = undefined
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
import {
|
||||
faBug,
|
||||
faClipboard,
|
||||
faCode,
|
||||
faExternalLink,
|
||||
faFileExport,
|
||||
faGlobe,
|
||||
@@ -37,7 +36,8 @@
|
||||
MoreVertical,
|
||||
Pencil,
|
||||
SlidersHorizontal,
|
||||
Smartphone
|
||||
Smartphone,
|
||||
X
|
||||
} from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
@@ -77,7 +77,9 @@
|
||||
jobs,
|
||||
staticExporter,
|
||||
errorByComponent,
|
||||
openDebugRun
|
||||
openDebugRun,
|
||||
focusedGrid,
|
||||
selectedComponent
|
||||
} = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
const loading = {
|
||||
@@ -459,6 +461,22 @@
|
||||
</ToggleButtonGroup>
|
||||
</div>
|
||||
</div>
|
||||
{#if $focusedGrid !== undefined}
|
||||
<Badge color="indigo">
|
||||
<div class="flex flex-row gap-2 justify-center items-center">
|
||||
<div>{`Sub grid: ${$focusedGrid.parentComponentId} (${$focusedGrid.subGridIndex})`}</div>
|
||||
<button
|
||||
on:click={() => {
|
||||
$focusedGrid = undefined
|
||||
$selectedComponent = undefined
|
||||
}}
|
||||
>
|
||||
<X size={14} />
|
||||
</button>
|
||||
</div>
|
||||
</Badge>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-row gap-2 justify-end items-center overflow-visible">
|
||||
<Dropdown
|
||||
placement="bottom-end"
|
||||
|
||||
@@ -61,7 +61,8 @@
|
||||
staticExporter: writable({}),
|
||||
noBackend,
|
||||
errorByComponent: writable({}),
|
||||
openDebugRun: writable(undefined)
|
||||
openDebugRun: writable(undefined),
|
||||
focusedGrid: writable(undefined)
|
||||
})
|
||||
|
||||
let mounted = false
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
Code2,
|
||||
SlidersHorizontal,
|
||||
PlusSquare,
|
||||
ListOrdered,
|
||||
Box
|
||||
} from 'lucide-svelte'
|
||||
import type { Size } from '@windmill-labs/svelte-grid'
|
||||
import {
|
||||
Smile,
|
||||
DollarSign,
|
||||
SeparatorHorizontal,
|
||||
@@ -24,7 +29,6 @@
|
||||
Paperclip,
|
||||
Image
|
||||
} from 'lucide-svelte'
|
||||
import type { Size } from 'svelte-grid'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
type BaseComponent<T extends string> = {
|
||||
@@ -78,6 +82,8 @@
|
||||
export type HorizontalDividerComponent = BaseComponent<'horizontaldividercomponent'>
|
||||
export type VerticalDividerComponent = BaseComponent<'verticaldividercomponent'>
|
||||
export type FileInputComponent = BaseComponent<'fileinputcomponent'>
|
||||
export type TabsComponent = BaseComponent<'tabscomponent'>
|
||||
export type ContainerComponent = BaseComponent<'containercomponent'>
|
||||
|
||||
export type AppComponent = BaseAppComponent &
|
||||
(
|
||||
@@ -104,6 +110,8 @@
|
||||
| FormButtonComponent
|
||||
| VegaLiteComponent
|
||||
| PlotlyComponent
|
||||
| TabsComponent
|
||||
| ContainerComponent
|
||||
| IconComponent
|
||||
| HorizontalDividerComponent
|
||||
| VerticalDividerComponent
|
||||
@@ -111,22 +119,24 @@
|
||||
| ImageComponent
|
||||
)
|
||||
|
||||
export type AppComponentDimensions =
|
||||
`${IntRange<1, typeof NARROW_GRID_COLUMNS>}:${number}-${IntRange<1, typeof WIDE_GRID_COLUMNS>}:${number}`
|
||||
export type AppComponentDimensions = `${IntRange<
|
||||
1,
|
||||
typeof NARROW_GRID_COLUMNS
|
||||
>}:${number}-${IntRange<1, typeof WIDE_GRID_COLUMNS>}:${number}`
|
||||
|
||||
export type AppComponentConfig = {
|
||||
name: string
|
||||
icon: any
|
||||
/**
|
||||
* Dimensions key formula:
|
||||
* [**mobile width**]:[**mobile height**]-[**desktop width**]:[**desktop height**]
|
||||
*/
|
||||
dims: AppComponentDimensions
|
||||
data: AppComponent
|
||||
cssIds?: string[]
|
||||
}
|
||||
export type AppComponentConfig = {
|
||||
name: string
|
||||
icon: any
|
||||
/**
|
||||
* Dimensions key formula:
|
||||
* [**mobile width**]:[**mobile height**]-[**desktop width**]:[**desktop height**]
|
||||
*/
|
||||
dims: AppComponentDimensions
|
||||
data: AppComponent
|
||||
cssIds?: string[]
|
||||
}
|
||||
|
||||
export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
displaycomponent: {
|
||||
name: 'Rich Result',
|
||||
icon: Monitor,
|
||||
@@ -144,6 +154,26 @@
|
||||
card: false
|
||||
}
|
||||
},
|
||||
containercomponent: {
|
||||
name: 'Container',
|
||||
icon: Box,
|
||||
dims: '2:8-6:8',
|
||||
data: {
|
||||
softWrap: true,
|
||||
verticalAlignment: 'center',
|
||||
id: '',
|
||||
type: 'containercomponent',
|
||||
configuration: {},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'text',
|
||||
value: ['First Tab', 'Second Tab']
|
||||
},
|
||||
card: false,
|
||||
subGrids: [[]]
|
||||
}
|
||||
},
|
||||
textcomponent: {
|
||||
name: 'Text',
|
||||
icon: Type,
|
||||
@@ -977,6 +1007,26 @@
|
||||
card: false
|
||||
}
|
||||
},
|
||||
tabscomponent: {
|
||||
name: 'Tabs',
|
||||
icon: ListOrdered,
|
||||
dims: '2:8-6:8',
|
||||
data: {
|
||||
softWrap: true,
|
||||
verticalAlignment: 'center',
|
||||
id: '',
|
||||
type: 'tabscomponent',
|
||||
configuration: {},
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'text',
|
||||
value: ['First Tab', 'Second Tab']
|
||||
},
|
||||
card: false,
|
||||
subGrids: [[], []]
|
||||
}
|
||||
},
|
||||
iconcomponent: {
|
||||
name: 'Icon',
|
||||
icon: Smile,
|
||||
@@ -1081,10 +1131,7 @@
|
||||
configuration: {
|
||||
acceptedFileTypes: {
|
||||
type: 'static',
|
||||
value: [
|
||||
'image/*',
|
||||
'application/pdf'
|
||||
],
|
||||
value: ['image/*', 'application/pdf'],
|
||||
fieldType: 'array',
|
||||
onlyStatic: true
|
||||
},
|
||||
@@ -1100,7 +1147,7 @@
|
||||
value: 'Drag and drop files or click to select them',
|
||||
fieldType: 'text',
|
||||
onlyStatic: true
|
||||
},
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
card: false
|
||||
@@ -1136,19 +1183,19 @@
|
||||
value: '',
|
||||
fieldType: 'text',
|
||||
onlyStatic: true,
|
||||
tooltip: 'This text will appear if the image can\'t be loaded for any reason'
|
||||
tooltip: "This text will appear if the image can't be loaded for any reason"
|
||||
},
|
||||
customStyles: {
|
||||
type: 'static',
|
||||
value: '',
|
||||
fieldType: 'textarea',
|
||||
onlyStatic: true,
|
||||
},
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {},
|
||||
card: false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const inputs: ComponentSet = {
|
||||
@@ -1187,6 +1234,8 @@
|
||||
'scatterchartcomponent',
|
||||
'timeseriescomponent',
|
||||
'displaycomponent',
|
||||
'tabscomponent',
|
||||
'containercomponent',
|
||||
'horizontaldividercomponent',
|
||||
'verticaldividercomponent'
|
||||
]
|
||||
@@ -1556,6 +1605,7 @@
|
||||
import PlotlyHtml from '../components/dataDisplay/PlotlyHtml.svelte'
|
||||
import { defaultAlignement } from './componentsPanel/componentDefaultProps'
|
||||
import AppRangeInput from '../components/numberInputs/AppRangeInput.svelte'
|
||||
import AppTabs from '../components/AppTabs.svelte'
|
||||
import AppIcon from '../components/dataDisplay/AppIcon.svelte'
|
||||
import AppCurrencyInput from '../components/numberInputs/AppCurrencyInput.svelte'
|
||||
import AppDivider from '../components/AppDivider.svelte'
|
||||
@@ -1563,6 +1613,8 @@
|
||||
import type { IntRange } from '../../../common'
|
||||
import type { NARROW_GRID_COLUMNS, WIDE_GRID_COLUMNS } from '../gridUtils'
|
||||
import AppImage from '../components/dataDisplay/AppImage.svelte'
|
||||
import { set_data } from 'svelte/internal'
|
||||
import AppContainer from '../components/AppContainer.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
@@ -1573,6 +1625,7 @@
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
let hover = false
|
||||
let initializing: boolean | undefined = undefined
|
||||
let componentContainerHeight: number = 0
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -1604,6 +1657,7 @@
|
||||
$app.css?.['app']?.['component']?.class
|
||||
)}
|
||||
style={$app.css?.['app']?.['component']?.style}
|
||||
bind:clientHeight={componentContainerHeight}
|
||||
>
|
||||
{#if component.type === 'displaycomponent'}
|
||||
<AppDisplayComponent
|
||||
@@ -1724,6 +1778,18 @@
|
||||
<AppDivider {...component} position="vertical" />
|
||||
{:else if component.type === 'rangecomponent'}
|
||||
<AppRangeInput {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'tabscomponent'}
|
||||
<AppTabs
|
||||
{...component}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
{componentContainerHeight}
|
||||
/>
|
||||
{:else if component.type === 'containercomponent'}
|
||||
<AppContainer
|
||||
{...component}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
{componentContainerHeight}
|
||||
/>
|
||||
{:else if component.type === 'iconcomponent'}
|
||||
<AppIcon {...component} bind:staticOutputs={$staticOutputs[component.id]} />
|
||||
{:else if component.type === 'fileinputcomponent'}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import { Alert, Button } from '$lib/components/common'
|
||||
import type { AppComponent } from './Component.svelte'
|
||||
import type { Output } from '../rx'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
@@ -15,7 +16,8 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const { errorByComponent, openDebugRun } = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { errorByComponent, openDebugRun, focusedGrid, worldStore } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
$: error = Object.values($errorByComponent).find((e) => e.componentId === component.id)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { getContext, afterUpdate } from 'svelte'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import Grid from 'svelte-grid'
|
||||
import type { AppEditorContext, GridItem } from '../types'
|
||||
import Grid from '@windmill-labs/svelte-grid'
|
||||
import { classNames } from '$lib/utils'
|
||||
import { columnConfiguration, disableDrag, enableDrag, isFixed, toggleFixed } from '../gridUtils'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
@@ -21,18 +21,29 @@
|
||||
staticOutputs,
|
||||
runnableComponents,
|
||||
lazyGrid,
|
||||
summary
|
||||
summary,
|
||||
focusedGrid
|
||||
} = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
// The drag is disabled when the user is connecting an input
|
||||
// or when the user is previewing the app
|
||||
// or when the focused grid is a subgrid
|
||||
$: setAllDrags($mode === 'preview' || $connectingInput.opened)
|
||||
|
||||
function setAllDrags(enable: boolean) {
|
||||
if (enable) {
|
||||
$app.grid.map((gridItem) => disableDrag(gridItem))
|
||||
} else {
|
||||
$app.grid.map((gridItem) => enableDrag(gridItem))
|
||||
}
|
||||
const fct = enable ? disableDrag : enableDrag
|
||||
|
||||
$app.grid.map((gridItem) => {
|
||||
const disabledGridItem = fct(gridItem)
|
||||
|
||||
if (disabledGridItem.data.subGrids) {
|
||||
disabledGridItem.data.subGrids = disabledGridItem.data.subGrids.map((subgrid: GridItem[]) =>
|
||||
subgrid.map((subgridItem: GridItem) => fct(subgridItem))
|
||||
)
|
||||
}
|
||||
|
||||
return disabledGridItem
|
||||
})
|
||||
}
|
||||
|
||||
function removeGridElement(component) {
|
||||
@@ -129,10 +140,11 @@
|
||||
{#if !$connectingInput.opened}
|
||||
<RecomputeAllComponents />
|
||||
{/if}
|
||||
<div class="text-2xs text-gray-600"
|
||||
>{policy.on_behalf_of ? `on behalf of ${policy.on_behalf_of_email}` : ''}</div
|
||||
>
|
||||
<div class="text-2xs text-gray-600">
|
||||
{policy.on_behalf_of ? `on behalf of ${policy.on_behalf_of_email}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={$app.css?.['app']?.['grid']?.style}
|
||||
class={twMerge('px-4 pt-4 pb-2 overflow-visible', $app.css?.['app']?.['grid']?.class ?? '')}
|
||||
|
||||
@@ -14,6 +14,20 @@
|
||||
<ComponentPanel bind:component={gridItem.data} />
|
||||
{:else if gridItem.data.type === 'tablecomponent'}
|
||||
<TablePanel bind:component={gridItem.data} />
|
||||
{:else if gridItem.data.subGrids}
|
||||
{#each gridItem.data.subGrids as subGrid}
|
||||
{#each subGrid as subGridItem, index (subGridItem.data.id)}
|
||||
{#if subGridItem.data.id === $selectedComponent}
|
||||
<ComponentPanel
|
||||
bind:component={subGridItem.data}
|
||||
onDelete={() => {
|
||||
subGrid.splice(index, 1)
|
||||
subGrid = subGrid
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{/each}
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
<script lang="ts">
|
||||
import { classNames } from '$lib/utils'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import Grid from '@windmill-labs/svelte-grid'
|
||||
import { columnConfiguration, isFixed, toggleFixed } from '../gridUtils'
|
||||
import type { AppEditorContext, GridItem } from '../types'
|
||||
import Component from './Component.svelte'
|
||||
|
||||
export let subGrid: GridItem[]
|
||||
export let containerHeight: number
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const { app, connectingInput, selectedComponent, focusedGrid } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let pointerdown = false
|
||||
|
||||
let onComponent: string | undefined = undefined
|
||||
|
||||
const onpointerdown = (e) => {
|
||||
if (onComponent === undefined) {
|
||||
dispatch('focus')
|
||||
} else {
|
||||
onComponent = undefined
|
||||
}
|
||||
pointerdown = true
|
||||
}
|
||||
|
||||
const onpointerup = () => {
|
||||
pointerdown = false
|
||||
}
|
||||
|
||||
function selectComponent(id: string) {
|
||||
onComponent = id
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = id
|
||||
}
|
||||
}
|
||||
|
||||
function lock(gridComponent: GridItem) {
|
||||
let fComponent = $app.grid.find((c) => c.id === gridComponent.id)
|
||||
if (fComponent) {
|
||||
fComponent = toggleFixed(fComponent)
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
let container
|
||||
|
||||
$: if ($focusedGrid?.parentComponentId !== $selectedComponent) {
|
||||
const gridItemIds = $app.grid
|
||||
.map((gridItem: GridItem) => {
|
||||
if (gridItem.data.id === $focusedGrid?.parentComponentId) {
|
||||
const subGrids = gridItem.data.subGrids ?? []
|
||||
return [
|
||||
gridItem.data.id,
|
||||
...subGrids.map((subGrid: GridItem[]) =>
|
||||
subGrid.map((gridItem: GridItem) => gridItem.data.id)
|
||||
)
|
||||
]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
})
|
||||
.flat(2)
|
||||
|
||||
if (!gridItemIds.includes($selectedComponent)) {
|
||||
$focusedGrid = undefined
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="relative w-full subgrid " bind:this={container}>
|
||||
<div
|
||||
class="px-4 pt-4 overflow-auto {$connectingInput?.opened ? '' : ''}"
|
||||
on:pointerdown|stopPropagation={onpointerdown}
|
||||
on:pointerleave={onpointerup}
|
||||
on:pointerup={onpointerup}
|
||||
style="height: {containerHeight}px;"
|
||||
>
|
||||
<div>
|
||||
<Grid
|
||||
bind:items={subGrid}
|
||||
let:dataItem
|
||||
rowHeight={36}
|
||||
cols={columnConfiguration}
|
||||
fastStart={true}
|
||||
gap={[4, 2]}
|
||||
scroller={container}
|
||||
>
|
||||
{#each subGrid as gridComponent (gridComponent.id)}
|
||||
{#if gridComponent.data.id === dataItem.data.id}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
{#if $connectingInput.opened}
|
||||
{#if $connectingInput.opened}
|
||||
<div
|
||||
on:pointerenter={() =>
|
||||
($connectingInput.hoveredComponent = gridComponent.data.id)}
|
||||
on:pointerleave={() => ($connectingInput.hoveredComponent = undefined)}
|
||||
class="absolute w-full h-full bg-black border-2 bg-opacity-25 z-20 flex justify-center items-center"
|
||||
/>
|
||||
{/if}
|
||||
<div
|
||||
style="transform: translate(-50%, -50%);"
|
||||
class="absolute w-fit justify-center bg-indigo-500/90 left-[50%] top-[50%] z-50 px-6 rounded border text-white py-2 text-5xl center-center"
|
||||
>
|
||||
{dataItem.data.id}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
on:pointerdown={() => selectComponent(dataItem.data.id)}
|
||||
class={classNames(
|
||||
'h-full w-full center-center',
|
||||
$selectedComponent === dataItem.data.id ? 'active-grid-item' : '',
|
||||
gridComponent.data.card ? 'border border-gray-100' : '',
|
||||
'top-0'
|
||||
)}
|
||||
>
|
||||
<Component
|
||||
{pointerdown}
|
||||
bind:component={gridComponent.data}
|
||||
selected={$selectedComponent === dataItem.data.id}
|
||||
locked={isFixed(gridComponent)}
|
||||
on:lock={() => lock(gridComponent)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</Grid>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3,7 +3,7 @@
|
||||
import Icon from 'svelte-awesome'
|
||||
import type { AppEditorContext, GridItem } from '../../types'
|
||||
|
||||
import gridHelp from 'svelte-grid/build/helper/index.mjs'
|
||||
import gridHelp from '@windmill-labs/svelte-grid/src/utils/helper'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getNextId } from '$lib/components/flows/flowStateUtils'
|
||||
import { faAngleDown } from '@fortawesome/free-solid-svg-icons'
|
||||
@@ -17,13 +17,10 @@
|
||||
type AppComponent
|
||||
} from '../Component.svelte'
|
||||
|
||||
const { app, selectedComponent } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function addComponent(appComponentType: AppComponent['type']) {
|
||||
$dirtyStore = true
|
||||
const grid = $app.grid ?? []
|
||||
const id = getNextId(grid.map((gridItem) => gridItem.data.id))
|
||||
const { app, selectedComponent, focusedGrid } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
// The grid is needed to find a space for the new component
|
||||
function createNewGridItem(grid: GridItem[], id: string, appComponentType: string): GridItem {
|
||||
const appComponent = componentsRecord[appComponentType].data
|
||||
|
||||
appComponent.id = id
|
||||
@@ -59,9 +56,45 @@
|
||||
newItem[column] = { ...newItem[column], ...position }
|
||||
})
|
||||
|
||||
$app.grid = [...grid, newItem]
|
||||
return newItem
|
||||
}
|
||||
|
||||
$selectedComponent = id
|
||||
function addComponent(appComponentType: AppComponent['type']): void {
|
||||
// When a new component is added, we need to mark the app as dirty,
|
||||
// so a confirmation modal will appear if the user tries to leave the page
|
||||
$dirtyStore = true
|
||||
|
||||
const grid = $app.grid ?? []
|
||||
|
||||
const gridItemIds = grid
|
||||
.map((gridItem: GridItem) => {
|
||||
const subGrids = gridItem.data.subGrids ?? []
|
||||
return [
|
||||
gridItem.data.id,
|
||||
...subGrids.map((subGrid: GridItem[]) =>
|
||||
subGrid.map((gridItem: GridItem) => gridItem.data.id)
|
||||
)
|
||||
]
|
||||
})
|
||||
.flat(2)
|
||||
|
||||
const id = getNextId(gridItemIds)
|
||||
|
||||
if ($focusedGrid) {
|
||||
const { parentComponentId, subGridIndex } = $focusedGrid
|
||||
|
||||
const gridItemIndex = $app.grid.findIndex((gridItem) => gridItem.id === parentComponentId)
|
||||
const subGrids = $app.grid[gridItemIndex].data.subGrids ?? []
|
||||
const newItem = createNewGridItem(subGrids[subGridIndex] ?? [], id, appComponentType)
|
||||
const subGrid = subGrids[subGridIndex] ?? []
|
||||
|
||||
$app.grid[gridItemIndex].data.subGrids[subGridIndex] = [...subGrid, newItem]
|
||||
$selectedComponent = id
|
||||
} else {
|
||||
const newItem = createNewGridItem(grid, id, appComponentType)
|
||||
$app.grid = [...grid, newItem]
|
||||
$selectedComponent = id
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
||||
@@ -46,7 +46,6 @@ export type EvalInput = {
|
||||
expr: string
|
||||
}
|
||||
|
||||
|
||||
export type RowInput = {
|
||||
type: 'row'
|
||||
column: string
|
||||
@@ -81,7 +80,7 @@ export type Runnable = RunnableByPath | RunnableByName | undefined
|
||||
// Runnable input, set by the developer in the component panel
|
||||
export type ResultInput = {
|
||||
runnable: Runnable
|
||||
fields: Record<string, (StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput)>
|
||||
fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
type: 'runnable'
|
||||
value?: any
|
||||
}
|
||||
@@ -101,16 +100,16 @@ type AppInputSpec<T extends InputType, U, V extends InputType = never> = (
|
||||
type InputConfiguration<T extends InputType, U, V extends InputType> = {
|
||||
fieldType: T
|
||||
subFieldType?: V
|
||||
format?: string | undefined,
|
||||
format?: string | undefined
|
||||
fileUpload?: {
|
||||
/** Use `*` to accept anything. */
|
||||
accept: string
|
||||
/**
|
||||
/**
|
||||
* Controls if user is allowed to select multiple files.
|
||||
* @default false
|
||||
*/
|
||||
multiple?: boolean
|
||||
/**
|
||||
/**
|
||||
* Controls if the uploaded file(s) will be returned as `Base64` strings.
|
||||
* @default false
|
||||
*/
|
||||
@@ -137,6 +136,12 @@ export type AppInput =
|
||||
| AppInputSpec<'any', any>
|
||||
| AppInputSpec<'object', Record<string | number, any>>
|
||||
| AppInputSpec<'object', string>
|
||||
| (AppInputSpec<'select', string> & {
|
||||
/**
|
||||
* One of the keys of `staticValues` from `lib/components/apps/editor/componentsPanel/componentStaticValues`
|
||||
*/
|
||||
optionValuesKey: keyof typeof staticValues
|
||||
})
|
||||
| (AppInputSpec<'select', string> & StaticOptions)
|
||||
| AppInputSpec<'icon-select', string>
|
||||
| AppInputSpec<'array', string[], 'text'>
|
||||
@@ -147,6 +152,9 @@ export type AppInput =
|
||||
| AppInputSpec<'array', string[], 'time'>
|
||||
| AppInputSpec<'array', string[], 'datetime'>
|
||||
| AppInputSpec<'array', object[], 'object'>
|
||||
| (AppInputSpec<'array', string[], 'select'> & {
|
||||
optionValuesKey: keyof typeof staticValues
|
||||
})
|
||||
| (AppInputSpec<'array', string[], 'select'> & StaticOptions)
|
||||
|
||||
export type RowAppInput = Extract<AppInput, { type: 'row' }>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Schema } from '$lib/common'
|
||||
import type { Preview } from '$lib/gen'
|
||||
import type { FilledItem } from 'svelte-grid'
|
||||
import type { FilledItem } from '@windmill-labs/svelte-grid'
|
||||
import type { Writable } from 'svelte/store'
|
||||
import type { AppComponent } from './editor/Component.svelte'
|
||||
import type {
|
||||
@@ -15,7 +15,6 @@ import type {
|
||||
} from './inputType'
|
||||
import type { World } from './rx'
|
||||
|
||||
|
||||
export type HorizontalAlignment = 'left' | 'center' | 'right'
|
||||
export type VerticalAlignment = 'top' | 'center' | 'bottom'
|
||||
|
||||
@@ -35,30 +34,33 @@ export interface BaseAppComponent extends Partial<Aligned> {
|
||||
componentInput: AppInput | undefined
|
||||
configuration: Record<
|
||||
string,
|
||||
GeneralAppInput & (
|
||||
StaticAppInput
|
||||
| ConnectedAppInput
|
||||
| UserAppInput
|
||||
| RowAppInput
|
||||
| EvalAppInput
|
||||
| UploadAppInput
|
||||
)
|
||||
GeneralAppInput &
|
||||
(
|
||||
| StaticAppInput
|
||||
| ConnectedAppInput
|
||||
| UserAppInput
|
||||
| RowAppInput
|
||||
| EvalAppInput
|
||||
| UploadAppInput
|
||||
)
|
||||
>
|
||||
card: boolean | undefined
|
||||
customCss?: Record<string, {
|
||||
class: string
|
||||
style: string
|
||||
}>
|
||||
customCss?: Record<
|
||||
string,
|
||||
{
|
||||
class: string
|
||||
style: string
|
||||
}
|
||||
>
|
||||
/**
|
||||
* If `true` then the wrapper will allow items to flow outside of it's borders.
|
||||
*
|
||||
* *For example when the component has a popup like `Select`*
|
||||
*/
|
||||
softWrap?: boolean
|
||||
subGrids?: GridItem[][]
|
||||
}
|
||||
|
||||
|
||||
|
||||
export type ComponentSet = {
|
||||
title: string
|
||||
components: AppComponent['type'][]
|
||||
@@ -95,7 +97,10 @@ export type App = {
|
||||
inlineScript: InlineScript | undefined
|
||||
fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
}>
|
||||
css?: Record<'viewer' | 'grid' | AppComponent['type'], Record<string, { style?: string, class?: string }>>
|
||||
css?: Record<
|
||||
'viewer' | 'grid' | AppComponent['type'],
|
||||
Record<string, { style?: string; class?: string }>
|
||||
>
|
||||
}
|
||||
|
||||
export type ConnectingInput = {
|
||||
@@ -125,8 +130,11 @@ export type AppEditorContext = {
|
||||
noBackend: boolean
|
||||
errorByComponent: Writable<Record<string, { error: string; componentId: string }>>
|
||||
openDebugRun: Writable<((componentID: string) => void) | undefined>
|
||||
focusedGrid: Writable<FocusedGrid | undefined>
|
||||
}
|
||||
|
||||
export type FocusedGrid = { parentComponentId: string; subGridIndex: number }
|
||||
|
||||
export type EditorMode = 'dnd' | 'preview'
|
||||
export type EditorBreakpoint = 'sm' | 'lg'
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import type { Schema } from '$lib/common'
|
||||
import { Script, ScriptService, type FlowModule, type PathFlow, type PathScript, type RawScript } from '$lib/gen'
|
||||
import {
|
||||
Script,
|
||||
ScriptService,
|
||||
type FlowModule,
|
||||
type PathFlow,
|
||||
type PathScript,
|
||||
type RawScript
|
||||
} from '$lib/gen'
|
||||
import { initialCode } from '$lib/script_helpers'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { getScriptByPath } from '$lib/utils'
|
||||
@@ -20,7 +27,11 @@ export async function loadFlowModuleState(flowModule: FlowModule): Promise<FlowM
|
||||
try {
|
||||
const { input_transforms, schema } = await loadSchemaFromModule(flowModule)
|
||||
|
||||
if (flowModule.value.type == 'script' || flowModule.value.type == 'rawscript' || flowModule.value.type == 'flow') {
|
||||
if (
|
||||
flowModule.value.type == 'script' ||
|
||||
flowModule.value.type == 'rawscript' ||
|
||||
flowModule.value.type == 'flow'
|
||||
) {
|
||||
flowModule.value.input_transforms = input_transforms
|
||||
}
|
||||
return { schema, previewResult: NEVER_TESTED_THIS_FAR }
|
||||
@@ -77,7 +88,7 @@ export async function pickScript(
|
||||
export async function pickFlow(
|
||||
path: string,
|
||||
summary: string,
|
||||
id: string,
|
||||
id: string
|
||||
): Promise<[FlowModule & { value: PathFlow }, FlowModuleState]> {
|
||||
const flowModule: FlowModule & { value: PathFlow } = {
|
||||
id,
|
||||
@@ -156,7 +167,7 @@ export async function createFlow(id: string): Promise<[FlowModule, FlowModuleSta
|
||||
value: {
|
||||
type: 'flow',
|
||||
path: '',
|
||||
input_transforms: {},
|
||||
input_transforms: {}
|
||||
},
|
||||
summary: ''
|
||||
}
|
||||
|
||||
Vendored
+4
-4
@@ -2,7 +2,7 @@ import type { AppComponent } from '$lib/components/apps/types'
|
||||
|
||||
declare module 'simple-svelte-autocomplete'
|
||||
|
||||
declare module 'svelte-grid' {
|
||||
declare module '@windmill-labs/svelte-grid' {
|
||||
import type { SvelteComponentTyped } from 'svelte'
|
||||
|
||||
export interface Size {
|
||||
@@ -46,11 +46,11 @@ declare module 'svelte-grid' {
|
||||
default: { item: ItemLayout; dataItem: Item<T> & { data: AppComponent } }
|
||||
}
|
||||
|
||||
export default class Grid<T = {}> extends SvelteComponentTyped<Props<T>, {}, Slots<T>> { }
|
||||
export default class Grid<T = {}> extends SvelteComponentTyped<Props<T>, {}, Slots<T>> {}
|
||||
}
|
||||
|
||||
declare module 'svelte-grid/build/helper/index.mjs' {
|
||||
import { ItemLayout } from 'svelte-grid'
|
||||
declare module '@windmill-labs/svelte-grid/build/helper/index.mjs' {
|
||||
import { ItemLayout } from '@windmill-labs/svelte-grid'
|
||||
|
||||
const x: {
|
||||
normalize(items: any[], col: any): unknown[]
|
||||
|
||||
Reference in New Issue
Block a user