mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-21 00:02:23 +00:00
finish migrating app editor to svelte 5 (#6090)
* all * all * all * all
This commit is contained in:
@@ -3,10 +3,15 @@
|
||||
import type { Writable } from 'svelte/store'
|
||||
import type { GroupContext } from '../types'
|
||||
|
||||
export let context: Writable<Record<string, any>>
|
||||
export let id: string
|
||||
interface Props {
|
||||
context: Writable<Record<string, any>>
|
||||
id: string
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { context, id, children }: Props = $props()
|
||||
|
||||
setContext<GroupContext>('GroupContext', { id, context })
|
||||
</script>
|
||||
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
|
||||
@@ -22,18 +22,28 @@
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'barchartcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
initializing?: boolean | undefined
|
||||
customCss?: ComponentCustomCSS<'barchartcomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
initializing = $bindable(undefined),
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['barchartcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['barchartcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
let outputs = initOutput($worldStore, id, {
|
||||
@@ -52,15 +62,17 @@
|
||||
BarElement
|
||||
)
|
||||
|
||||
let result: { data: number[]; labels?: string[] } | undefined = undefined
|
||||
let result = $state(undefined) as { data: number[]; labels?: string[] } | undefined
|
||||
|
||||
$: backgroundColor = {
|
||||
theme1: ['#FF6384', '#4BC0C0', '#FFCE56', '#E7E9ED', '#36A2EB'],
|
||||
// blue theme
|
||||
theme2: ['#4e73df', '#1cc88a', '#36b9cc', '#f6c23e', '#e74a3b'],
|
||||
// red theme
|
||||
theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e']
|
||||
}[resolvedConfig.theme ?? 'theme1']
|
||||
let backgroundColor = $derived(
|
||||
{
|
||||
theme1: ['#FF6384', '#4BC0C0', '#FFCE56', '#E7E9ED', '#36A2EB'],
|
||||
// blue theme
|
||||
theme2: ['#4e73df', '#1cc88a', '#36b9cc', '#f6c23e', '#e74a3b'],
|
||||
// red theme
|
||||
theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e']
|
||||
}[resolvedConfig.theme ?? 'theme1']
|
||||
)
|
||||
|
||||
const lineOptions: ChartOptions<'line'> = {
|
||||
responsive: true,
|
||||
@@ -84,7 +96,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: data = {
|
||||
let data = $derived({
|
||||
labels: result?.labels ?? [],
|
||||
|
||||
datasets: [
|
||||
@@ -105,9 +117,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let css = initCss($app.css?.barchartcomponent, customCss)
|
||||
let css = $state(initCss($app.css?.barchartcomponent, customCss))
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['barchartcomponent'].initialData.configuration) as key (key)}
|
||||
|
||||
@@ -12,12 +12,23 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'chartjscomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
initializing?: boolean | undefined
|
||||
customCss?: ComponentCustomCSS<'chartjscomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
initializing = $bindable(undefined),
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -28,20 +39,19 @@
|
||||
|
||||
ChartJS.register(...registerables)
|
||||
|
||||
let result: undefined = undefined
|
||||
let result: undefined = $state(undefined)
|
||||
|
||||
const resolvedConfig = initConfig(
|
||||
components['chartjscomponent'].initialData.configuration,
|
||||
configuration
|
||||
const resolvedConfig = $state(
|
||||
initConfig(components['chartjscomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
$: options = {
|
||||
let options = $derived({
|
||||
responsive: true,
|
||||
animation: false,
|
||||
maintainAspectRatio: false,
|
||||
...(resolvedConfig.options ?? {})
|
||||
} as ChartOptions
|
||||
} as ChartOptions)
|
||||
|
||||
let css = initCss($app.css?.chartjscomponent, customCss)
|
||||
let css = $state(initCss($app.css?.chartjscomponent, customCss))
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['chartjscomponent'].initialData.configuration) as key (key)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getContext, onMount, untrack } from 'svelte'
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
|
||||
@@ -22,10 +22,14 @@
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let render: boolean
|
||||
export let componentInput: AppInput | undefined
|
||||
export let customComponent: CustomComponentConfig
|
||||
interface Props {
|
||||
id: string
|
||||
render: boolean
|
||||
componentInput: AppInput | undefined
|
||||
customComponent: CustomComponentConfig
|
||||
}
|
||||
|
||||
let { id, render, componentInput, customComponent }: Props = $props()
|
||||
|
||||
let divId = `custom-component-${id}`
|
||||
const { worldStore, workspace } = getContext<AppViewerContext>('AppViewerContext')
|
||||
@@ -36,8 +40,8 @@
|
||||
loading: false
|
||||
})
|
||||
|
||||
let setInput
|
||||
let setRender
|
||||
let setInput = $state() as ((input: any) => void) | undefined
|
||||
let setRender = $state() as ((render: boolean) => void) | undefined
|
||||
let ccProps: CCProps<any> = {
|
||||
render,
|
||||
id: divId,
|
||||
@@ -49,7 +53,7 @@
|
||||
outputs.output.set(output)
|
||||
}
|
||||
}
|
||||
let loaded = false
|
||||
let loaded = $state(false)
|
||||
let renderer: ((props: CCProps<number>) => void) | undefined = undefined
|
||||
// $: renderer && divEl && renderer(ccProps)
|
||||
onMount(async () => {
|
||||
@@ -96,18 +100,22 @@
|
||||
}
|
||||
console.log('mounted', render, setRender)
|
||||
})
|
||||
let result
|
||||
let result = $state()
|
||||
|
||||
$: render != undefined && setRender && handleRender()
|
||||
function handleRender() {
|
||||
setRender?.(render)
|
||||
}
|
||||
|
||||
$: result != undefined && setInput && handleResult()
|
||||
function handleResult() {
|
||||
setInput?.(result)
|
||||
}
|
||||
// $: result && setInput && setInput(result)
|
||||
$effect(() => {
|
||||
render != undefined && setRender && untrack(() => handleRender())
|
||||
})
|
||||
$effect(() => {
|
||||
result != undefined && setInput && untrack(() => handleResult())
|
||||
})
|
||||
</script>
|
||||
|
||||
<InitializeComponent {id} />
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts" context="module">
|
||||
<script lang="ts" module>
|
||||
import { writable, type Writable } from 'svelte/store'
|
||||
let selected: Writable<string | undefined> = writable(undefined)
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getContext, onMount, untrack } from 'svelte'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
import { type NavbarItem } from '../../editor/component'
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
@@ -14,20 +14,29 @@
|
||||
import type { Output } from '../../rx'
|
||||
import ResolveNavbarItemPath from './ResolveNavbarItemPath.svelte'
|
||||
|
||||
export let navbarItem: NavbarItem
|
||||
export let id: string
|
||||
export let borderColor: string | undefined = undefined
|
||||
export let index: number
|
||||
export let output: {
|
||||
result: Output<{
|
||||
currentPath: string
|
||||
}>
|
||||
interface Props {
|
||||
navbarItem: NavbarItem
|
||||
id: string
|
||||
borderColor?: string | undefined
|
||||
index: number
|
||||
output: {
|
||||
result: Output<{
|
||||
currentPath: string
|
||||
}>
|
||||
}
|
||||
orientation?: 'horizontal' | 'vertical' | undefined
|
||||
}
|
||||
export let orientation: 'horizontal' | 'vertical' | undefined = undefined
|
||||
|
||||
let icon: any
|
||||
let {
|
||||
navbarItem,
|
||||
id,
|
||||
borderColor = undefined,
|
||||
index,
|
||||
output = $bindable(),
|
||||
orientation = undefined
|
||||
}: Props = $props()
|
||||
|
||||
$: navbarItem.icon && icon && handleIcon()
|
||||
let icon: any = $state()
|
||||
|
||||
async function handleIcon() {
|
||||
if (navbarItem.icon) {
|
||||
@@ -38,10 +47,10 @@
|
||||
const { appPath, replaceStateFn, gotoFn, isEditor, worldStore } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedPath: string | undefined = undefined
|
||||
let resolvedLabel: string | undefined = undefined
|
||||
let resolvedDisabled: boolean | undefined = undefined
|
||||
let resolvedHidden: boolean | undefined = undefined
|
||||
let resolvedPath: string | undefined = $state(undefined)
|
||||
let resolvedLabel: string | undefined = $state(undefined)
|
||||
let resolvedDisabled: boolean | undefined = $state(undefined)
|
||||
let resolvedHidden: boolean | undefined = $state(undefined)
|
||||
|
||||
function extractPathDetails() {
|
||||
const url = window.location.pathname + window.location.search + window.location.hash
|
||||
@@ -53,7 +62,7 @@
|
||||
$selected = resolvedPath === extractPathDetails() ? resolvedPath : undefined
|
||||
})
|
||||
|
||||
let initialized: boolean = false
|
||||
let initialized: boolean = $state(false)
|
||||
|
||||
function initSelection() {
|
||||
initialized = true
|
||||
@@ -63,8 +72,6 @@
|
||||
$selected = resolvedPath === extractPathDetails() ? resolvedPath : undefined
|
||||
}
|
||||
|
||||
$: !initialized && resolvedPath && initSelection()
|
||||
|
||||
function getButtonProps(resolvedPath: string | undefined) {
|
||||
if ($appPath && resolvedPath?.includes($appPath)) {
|
||||
return {
|
||||
@@ -112,7 +119,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: buttonProps = getButtonProps(resolvedPath)
|
||||
$effect(() => {
|
||||
navbarItem.icon && icon && untrack(() => handleIcon())
|
||||
})
|
||||
$effect(() => {
|
||||
!initialized && resolvedPath && untrack(() => initSelection())
|
||||
})
|
||||
let buttonProps = $derived(getButtonProps(resolvedPath))
|
||||
</script>
|
||||
|
||||
<ResolveNavbarItemPath {navbarItem} {id} {index} bind:resolvedPath />
|
||||
|
||||
@@ -21,12 +21,23 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'piechartcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
initializing?: boolean | undefined
|
||||
customCss?: ComponentCustomCSS<'piechartcomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
initializing = $bindable(undefined),
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -46,17 +57,19 @@
|
||||
ArcElement
|
||||
)
|
||||
|
||||
let result: { data: number[]; labels?: string[] } | undefined = undefined
|
||||
let theme: string = 'theme1'
|
||||
let doughnut = false
|
||||
let result = $state(undefined) as { data: number[]; labels?: string[] } | undefined
|
||||
let theme: string = $state('theme1')
|
||||
let doughnut = $state(false)
|
||||
|
||||
$: backgroundColor = {
|
||||
theme1: ['#FF6384', '#4BC0C0', '#FFCE56', '#E7E9ED', '#36A2EB'],
|
||||
// blue theme
|
||||
theme2: ['#4e73df', '#1cc88a', '#36b9cc', '#f6c23e', '#e74a3b'],
|
||||
// red theme
|
||||
theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e']
|
||||
}[theme]
|
||||
let backgroundColor = $derived(
|
||||
{
|
||||
theme1: ['#FF6384', '#4BC0C0', '#FFCE56', '#E7E9ED', '#36A2EB'],
|
||||
// blue theme
|
||||
theme2: ['#4e73df', '#1cc88a', '#36b9cc', '#f6c23e', '#e74a3b'],
|
||||
// red theme
|
||||
theme3: ['#e74a3b', '#4e73df', '#1cc88a', '#36b9cc', '#f6c23e']
|
||||
}[theme]
|
||||
)
|
||||
|
||||
const options = {
|
||||
responsive: true,
|
||||
@@ -64,7 +77,7 @@
|
||||
maintainAspectRatio: false
|
||||
}
|
||||
|
||||
$: data = {
|
||||
let data = $derived({
|
||||
labels: result?.labels ?? [],
|
||||
datasets: [
|
||||
{
|
||||
@@ -72,9 +85,9 @@
|
||||
backgroundColor: backgroundColor
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
let css = initCss($app.css?.piechartcomponent, customCss)
|
||||
let css = $state(initCss($app.css?.piechartcomponent, customCss))
|
||||
</script>
|
||||
|
||||
{#each Object.keys(css ?? {}) as key (key)}
|
||||
|
||||
@@ -24,15 +24,26 @@
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
import { Scatter } from '$lib/components/chartjs-wrappers/chartJs'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'scatterchartcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
initializing?: boolean | undefined
|
||||
customCss?: ComponentCustomCSS<'scatterchartcomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let zoomable = false
|
||||
let pannable = false
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
initializing = $bindable(undefined),
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
let zoomable = $state(false)
|
||||
let pannable = $state(false)
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -53,9 +64,9 @@
|
||||
zoomPlugin
|
||||
)
|
||||
|
||||
let result: { data: { x: any[]; y: string[] } } | undefined = undefined
|
||||
let result: { data: { x: any[]; y: string[] } } | undefined = $state(undefined)
|
||||
|
||||
$: options = {
|
||||
let options = $derived({
|
||||
responsive: true,
|
||||
animation: false,
|
||||
maintainAspectRatio: false,
|
||||
@@ -74,13 +85,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
} as ChartOptions<'scatter'>
|
||||
} as ChartOptions<'scatter'>)
|
||||
|
||||
$: data = {
|
||||
let data = $derived({
|
||||
datasets: result ?? []
|
||||
} as ChartData<'scatter', (number | Point)[], unknown>
|
||||
} as ChartData<'scatter', (number | Point)[], unknown>)
|
||||
|
||||
let css = initCss($app.css?.scatterchartcomponent, customCss)
|
||||
let css = $state(initCss($app.css?.scatterchartcomponent, customCss))
|
||||
</script>
|
||||
|
||||
{#each Object.keys(css ?? {}) as key (key)}
|
||||
|
||||
@@ -27,12 +27,23 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'timeseriescomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
initializing?: boolean | undefined
|
||||
customCss?: ComponentCustomCSS<'timeseriescomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
initializing = $bindable(undefined),
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -41,9 +52,9 @@
|
||||
loading: false
|
||||
})
|
||||
|
||||
let logarithmicScale = false
|
||||
let zoomable = false
|
||||
let pannable = false
|
||||
let logarithmicScale = $state(false)
|
||||
let zoomable = $state(false)
|
||||
let pannable = $state(false)
|
||||
|
||||
ChartJS.register(
|
||||
Title,
|
||||
@@ -59,9 +70,9 @@
|
||||
LogarithmicScale
|
||||
)
|
||||
|
||||
let result: { data: { x: any[]; y: string[] } } | undefined = undefined
|
||||
let result: { data: { x: any[]; y: string[] } } | undefined = $state(undefined)
|
||||
|
||||
$: options = {
|
||||
let options = $derived({
|
||||
responsive: true,
|
||||
animation: false,
|
||||
maintainAspectRatio: false,
|
||||
@@ -88,13 +99,13 @@
|
||||
type: logarithmicScale ? 'logarithmic' : 'linear'
|
||||
}
|
||||
}
|
||||
} as ChartOptions<'scatter'>
|
||||
} as ChartOptions<'scatter'>)
|
||||
|
||||
$: data = {
|
||||
let data = $derived({
|
||||
datasets: result ?? []
|
||||
} as ChartData<'scatter', (number | Point)[], unknown>
|
||||
} as ChartData<'scatter', (number | Point)[], unknown>)
|
||||
|
||||
let css = initCss($app.css?.timeseriescomponent, customCss)
|
||||
let css = $state(initCss($app.css?.timeseriescomponent, customCss))
|
||||
</script>
|
||||
|
||||
{#each Object.keys(css ?? {}) as key (key)}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { createBubbler } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { Alert } from '$lib/components/common'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getContext, onMount, untrack } from 'svelte'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import { components } from '../../editor/component'
|
||||
import type { AppInput } from '../../inputType'
|
||||
@@ -8,18 +11,26 @@
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
initializing?: boolean | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let render: boolean
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
initializing = $bindable(undefined),
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { worldStore, darkMode } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['plotlycomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['plotlycomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
@@ -27,10 +38,10 @@
|
||||
loading: false
|
||||
})
|
||||
|
||||
let result: object | undefined = undefined
|
||||
let divEl: HTMLDivElement | null = null
|
||||
let result: object | undefined = $state(undefined)
|
||||
let divEl: HTMLDivElement | null = $state(null)
|
||||
|
||||
let Plotly
|
||||
let Plotly = $state() as any
|
||||
onMount(async () => {
|
||||
//@ts-ignore
|
||||
await import(
|
||||
@@ -43,26 +54,16 @@
|
||||
Plotly = window['Plotly']
|
||||
})
|
||||
|
||||
let h: number | undefined = undefined
|
||||
let w: number | undefined = undefined
|
||||
let h: number | undefined = $state(undefined)
|
||||
let w: number | undefined = $state(undefined)
|
||||
|
||||
let shouldeUpdate = 1
|
||||
let shouldeUpdate = $state(1)
|
||||
|
||||
darkMode.subscribe(() => {
|
||||
shouldeUpdate++
|
||||
})
|
||||
|
||||
$: Plotly &&
|
||||
render &&
|
||||
result &&
|
||||
resolvedConfig.layout &&
|
||||
divEl &&
|
||||
h &&
|
||||
w &&
|
||||
shouldeUpdate &&
|
||||
plot()
|
||||
|
||||
let error = ''
|
||||
let error = $state('')
|
||||
function plot() {
|
||||
try {
|
||||
Plotly.newPlot(
|
||||
@@ -92,6 +93,17 @@
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
$effect.pre(() => {
|
||||
Plotly &&
|
||||
render &&
|
||||
result &&
|
||||
resolvedConfig.layout &&
|
||||
divEl &&
|
||||
h &&
|
||||
w &&
|
||||
shouldeUpdate &&
|
||||
untrack(() => plot())
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['plotlycomponent'].initialData.configuration) as key (key)}
|
||||
@@ -113,7 +125,7 @@
|
||||
</Alert>
|
||||
</div>
|
||||
{/if}
|
||||
<div on:pointerdown bind:this={divEl}></div>
|
||||
<div onpointerdown={bubble('pointerdown')} bind:this={divEl}></div>
|
||||
</RunnableWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { createBubbler } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { Alert } from '$lib/components/common'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getContext, onMount, untrack } from 'svelte'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import { components } from '../../editor/component'
|
||||
import type { AppInput } from '../../inputType'
|
||||
@@ -8,20 +11,30 @@
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let datasets: RichConfiguration | undefined
|
||||
export let xData: RichConfiguration | undefined
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
datasets: RichConfiguration | undefined
|
||||
xData: RichConfiguration | undefined
|
||||
initializing?: boolean | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let render: boolean
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
datasets,
|
||||
xData,
|
||||
initializing = $bindable(undefined),
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { worldStore, darkMode } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['plotlycomponentv2'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['plotlycomponentv2'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
@@ -29,10 +42,10 @@
|
||||
loading: false
|
||||
})
|
||||
|
||||
let result: object | undefined = undefined
|
||||
let divEl: HTMLDivElement | null = null
|
||||
let result: object | undefined = $state(undefined)
|
||||
let divEl: HTMLDivElement | null = $state(null)
|
||||
|
||||
let Plotly
|
||||
let Plotly = $state() as any
|
||||
onMount(async () => {
|
||||
//@ts-ignore
|
||||
await import(
|
||||
@@ -44,53 +57,16 @@
|
||||
Plotly = window['Plotly']
|
||||
})
|
||||
|
||||
let h: number | undefined = undefined
|
||||
let w: number | undefined = undefined
|
||||
let h: number | undefined = $state(undefined)
|
||||
let w: number | undefined = $state(undefined)
|
||||
|
||||
let shouldeUpdate = 1
|
||||
let shouldeUpdate = $state(1)
|
||||
|
||||
darkMode.subscribe(() => {
|
||||
shouldeUpdate++
|
||||
})
|
||||
|
||||
$: Plotly && render && resolvedConfig.layout && divEl && h && w && shouldeUpdate && plot(data)
|
||||
|
||||
$: data =
|
||||
datasets && xData && resolvedDatasets
|
||||
? resolvedDatasets.map((d, index) => {
|
||||
const fields =
|
||||
d.type === 'pie'
|
||||
? {
|
||||
values: resolvedDatasetsValues[index]
|
||||
}
|
||||
: {
|
||||
x: resolvedXData,
|
||||
y: resolvedDatasetsValues[index]
|
||||
}
|
||||
|
||||
return {
|
||||
type: d.type,
|
||||
color: d.color,
|
||||
text: d.tooltip,
|
||||
...fields,
|
||||
marker: {
|
||||
color: d.color
|
||||
},
|
||||
transforms: [
|
||||
{
|
||||
type: 'aggregate',
|
||||
groups: resolvedXData,
|
||||
aggregations: [{ target: 'y', func: d.aggregation_method, enabled: true }]
|
||||
}
|
||||
],
|
||||
...(d?.extraOptions ?? {})
|
||||
}
|
||||
})
|
||||
: Array.isArray(result)
|
||||
? result
|
||||
: [result]
|
||||
|
||||
let error = ''
|
||||
let error = $state('')
|
||||
function plot(data) {
|
||||
try {
|
||||
Plotly.newPlot(
|
||||
@@ -110,6 +86,11 @@
|
||||
yaxis: {
|
||||
color: $darkMode ? '#f3f6f8' : '#000',
|
||||
...(resolvedConfig?.layout?.['yaxis'] ?? {})
|
||||
},
|
||||
legend: {
|
||||
font: {
|
||||
color: $darkMode ? '#f3f6f8' : '#000'
|
||||
}
|
||||
}
|
||||
},
|
||||
{ responsive: true, displayModeBar: false }
|
||||
@@ -131,9 +112,56 @@
|
||||
extraOptions?: { mode: 'markers' | 'lines' | 'lines+markers' } | undefined
|
||||
}
|
||||
|
||||
let resolvedDatasets: Dataset[]
|
||||
let resolvedDatasetsValues: Array<number[]> = []
|
||||
let resolvedXData: number[] = []
|
||||
let resolvedDatasets: Dataset[] | undefined = $state()
|
||||
let resolvedDatasetsValues: Array<number[]> = $state([])
|
||||
let resolvedXData: number[] = $state([])
|
||||
let data = $derived.by(() => {
|
||||
return datasets && xData && resolvedDatasets
|
||||
? resolvedDatasets.map((d, index) => {
|
||||
const fields =
|
||||
d.type === 'pie'
|
||||
? {
|
||||
values: resolvedDatasetsValues[index]
|
||||
}
|
||||
: {
|
||||
x: resolvedXData,
|
||||
y: resolvedDatasetsValues[index]
|
||||
}
|
||||
|
||||
return {
|
||||
type: d.type,
|
||||
color: d.color,
|
||||
text: d.tooltip,
|
||||
name: d.name,
|
||||
...fields,
|
||||
marker: {
|
||||
color: d.color
|
||||
},
|
||||
transforms: [
|
||||
{
|
||||
type: 'aggregate',
|
||||
groups: resolvedXData,
|
||||
aggregations: [{ target: 'y', func: d.aggregation_method, enabled: true }]
|
||||
}
|
||||
],
|
||||
...(d?.extraOptions ?? {})
|
||||
}
|
||||
})
|
||||
: Array.isArray(result)
|
||||
? result
|
||||
: [result]
|
||||
})
|
||||
$effect(() => {
|
||||
Plotly &&
|
||||
render &&
|
||||
resolvedConfig.layout &&
|
||||
divEl &&
|
||||
h &&
|
||||
w &&
|
||||
shouldeUpdate &&
|
||||
data &&
|
||||
untrack(() => plot(data))
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['plotlycomponentv2'].initialData.configuration) as key (key)}
|
||||
@@ -179,7 +207,7 @@
|
||||
</Alert>
|
||||
</div>
|
||||
{/if}
|
||||
<div on:pointerdown bind:this={divEl}></div>
|
||||
<div onpointerdown={bubble('pointerdown')} bind:this={divEl}></div>
|
||||
</RunnableWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -3,20 +3,25 @@
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
import { initConfig } from '../../editor/appUtils'
|
||||
|
||||
export let navbarItem: NavbarItem
|
||||
export let id: string
|
||||
export let index: number
|
||||
interface Props {
|
||||
navbarItem: NavbarItem
|
||||
id: string
|
||||
index: number
|
||||
resolvedPath?: string | undefined
|
||||
}
|
||||
|
||||
export let resolvedPath: string | undefined = undefined
|
||||
let { navbarItem, id, index, resolvedPath = $bindable(undefined) }: Props = $props()
|
||||
|
||||
let resolvedConfig = initConfig({ path: navbarItem.path }, { path: navbarItem.path })
|
||||
let resolvedConfig = $state(initConfig({ path: navbarItem.path }, { path: navbarItem.path }))
|
||||
|
||||
$: resolvedPath = (
|
||||
resolvedConfig?.path?.selected === 'href'
|
||||
? resolvedConfig?.path?.configuration?.href?.href
|
||||
: resolvedConfig?.path?.configuration?.app?.path +
|
||||
(resolvedConfig?.path?.configuration?.app?.queryParamsOrHash ?? '')
|
||||
) as string | undefined
|
||||
$effect.pre(() => {
|
||||
resolvedPath = (
|
||||
resolvedConfig?.path?.selected === 'href'
|
||||
? resolvedConfig?.path?.configuration?.href?.href
|
||||
: resolvedConfig?.path?.configuration?.app?.path +
|
||||
(resolvedConfig?.path?.configuration?.app?.queryParamsOrHash ?? '')
|
||||
) as string | undefined
|
||||
})
|
||||
</script>
|
||||
|
||||
<ResolveConfig
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { createBubbler } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
import type { AppInput } from '../../inputType'
|
||||
@@ -6,14 +9,24 @@
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
initializing?: boolean | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let result: object | undefined = undefined
|
||||
let divEl: HTMLDivElement | null = null
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
initializing = $bindable(undefined),
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
let result: object | undefined = $state(undefined)
|
||||
let divEl: HTMLDivElement | null = $state(null)
|
||||
|
||||
const { worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -22,7 +35,7 @@
|
||||
loading: false
|
||||
})
|
||||
|
||||
let vegaEmbed
|
||||
let vegaEmbed = $state() as any
|
||||
onMount(async () => {
|
||||
//@ts-ignore
|
||||
await import(/* webpackIgnore: true */ 'https://cdn.jsdelivr.net/npm/vega@5.22.1')
|
||||
@@ -34,35 +47,37 @@
|
||||
vegaEmbed = window['vegaEmbed']
|
||||
})
|
||||
|
||||
let h: number | undefined = undefined
|
||||
let w: number | undefined = undefined
|
||||
let canvas = false
|
||||
let h: number | undefined = $state(undefined)
|
||||
let w: number | undefined = $state(undefined)
|
||||
let canvas = $state(false)
|
||||
|
||||
$: vegaEmbed &&
|
||||
result &&
|
||||
divEl &&
|
||||
h &&
|
||||
w &&
|
||||
vegaEmbed(
|
||||
divEl,
|
||||
{
|
||||
...result,
|
||||
...{
|
||||
width: w - 100,
|
||||
config: {
|
||||
legend: { orient: 'bottom', ...(result?.['config']?.['legend'] ?? {}) },
|
||||
...(result?.['config'] ?? {})
|
||||
$effect(() => {
|
||||
vegaEmbed &&
|
||||
result &&
|
||||
divEl &&
|
||||
h &&
|
||||
w &&
|
||||
vegaEmbed(
|
||||
divEl,
|
||||
{
|
||||
...result,
|
||||
...{
|
||||
width: w - 100,
|
||||
config: {
|
||||
legend: { orient: 'bottom', ...(result?.['config']?.['legend'] ?? {}) },
|
||||
...(result?.['config'] ?? {})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
mode: 'vega-lite',
|
||||
actions: false,
|
||||
renderer: canvas ? 'canvas' : 'svg',
|
||||
height: h - 75,
|
||||
width: w - 100
|
||||
}
|
||||
},
|
||||
{
|
||||
mode: 'vega-lite',
|
||||
actions: false,
|
||||
renderer: canvas ? 'canvas' : 'svg',
|
||||
height: h - 75,
|
||||
width: w - 100
|
||||
}
|
||||
)
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
<InputValue key={'canvas'} {id} input={configuration.canvas} bind:value={canvas} />
|
||||
@@ -70,7 +85,7 @@
|
||||
{#if render}
|
||||
<div class="w-full h-full" bind:clientHeight={h} bind:clientWidth={w}>
|
||||
<RunnableWrapper {outputs} {render} {componentInput} {id} bind:initializing bind:result>
|
||||
<div on:pointerdown bind:this={divEl}></div>
|
||||
<div onpointerdown={bubble('pointerdown')} bind:this={divEl}></div>
|
||||
</RunnableWrapper>
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<script lang="ts">
|
||||
import RunnableWrapper from '../../helpers/RunnableWrapper.svelte'
|
||||
import type { AppInput } from '../../../inputType'
|
||||
import type {
|
||||
AppViewerContext,
|
||||
ComponentCustomCSS,
|
||||
RichConfiguration,
|
||||
RichConfigurations
|
||||
} from '../../../types'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../../types'
|
||||
import { initCss } from '../../../utils'
|
||||
import { getContext, tick, untrack } from 'svelte'
|
||||
import { initConfig, initOutput } from '../../../editor/appUtils'
|
||||
@@ -24,8 +19,7 @@
|
||||
initializing?: boolean | undefined
|
||||
customCss?: ComponentCustomCSS<'agchartscomponent'> | undefined
|
||||
render: boolean
|
||||
datasets: RichConfiguration | undefined
|
||||
xData: RichConfiguration | undefined
|
||||
|
||||
license?: string | undefined
|
||||
ee?: boolean
|
||||
}
|
||||
@@ -37,23 +31,13 @@
|
||||
initializing = $bindable(undefined),
|
||||
customCss = undefined,
|
||||
render,
|
||||
datasets,
|
||||
xData,
|
||||
|
||||
license = undefined,
|
||||
ee = false
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
type Dataset = {
|
||||
value: RichConfiguration
|
||||
name: string
|
||||
type: 'bar' | 'line' | 'scatter' | 'area' | 'range-bar' | 'range-area'
|
||||
}
|
||||
|
||||
let resolvedDatasets = $state(undefined) as Dataset[] | undefined
|
||||
let resolvedXData: number[] = $state([])
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: undefined as
|
||||
| {
|
||||
@@ -115,80 +99,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function updateChart() {
|
||||
if (!chartInstance) {
|
||||
return
|
||||
}
|
||||
|
||||
let data = [] as any[]
|
||||
if (!resolvedDatasets) {
|
||||
return
|
||||
}
|
||||
for (let i = 0; i < resolvedXData.length; i++) {
|
||||
const o = {
|
||||
x: resolvedXData[i]
|
||||
}
|
||||
if (!resolvedDatasetsValues) {
|
||||
return
|
||||
}
|
||||
for (let j = 0; j < resolvedDatasets.length; j++) {
|
||||
if (!resolvedDatasetsValues[j]) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (
|
||||
resolvedDatasetsValues[j].type === 'range-bar' ||
|
||||
resolvedDatasetsValues[j].type === 'range-area'
|
||||
) {
|
||||
o[`y-${j}-low`] = resolvedDatasetsValues[j].value[i]?.[0]
|
||||
o[`y-${j}-high`] = resolvedDatasetsValues[j].value[i]?.[1]
|
||||
} else {
|
||||
o[`y-${j}`] = resolvedDatasetsValues[j].value[i]
|
||||
}
|
||||
}
|
||||
|
||||
data.push(o)
|
||||
}
|
||||
|
||||
const options = {
|
||||
container: document.getElementById(`agchart-${id}`) as HTMLElement,
|
||||
data: data,
|
||||
series:
|
||||
(resolvedDatasets?.map((d, index) => {
|
||||
if (!resolvedDatasetsValues) {
|
||||
return
|
||||
}
|
||||
const type = resolvedDatasetsValues?.[index]?.type
|
||||
if (!type) {
|
||||
return
|
||||
}
|
||||
if (type === 'range-bar' || type === 'range-area') {
|
||||
return {
|
||||
type: type,
|
||||
xKey: 'x',
|
||||
yLowKey: `y-${index}-low`,
|
||||
yHighKey: `y-${index}-high`,
|
||||
yName: d.name
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
type: type,
|
||||
xKey: 'x',
|
||||
yKey: `y-${index}`,
|
||||
yName: d.name
|
||||
}
|
||||
}
|
||||
}) as any[]) ?? [],
|
||||
...getChartStyleByTheme()
|
||||
}
|
||||
|
||||
outputs.result.set({
|
||||
data: options.data,
|
||||
series: options.series
|
||||
})
|
||||
AgChartsInstance?.update(chartInstance, options)
|
||||
}
|
||||
|
||||
function updateChartByResult() {
|
||||
if (!result || !chartInstance) {
|
||||
return
|
||||
@@ -248,100 +158,7 @@
|
||||
}
|
||||
|
||||
let darkMode = $state(false)
|
||||
let resolvedDatasetsValues = $derived(
|
||||
resolvedDatasets?.map((d) => {
|
||||
const config = initConfig(
|
||||
{
|
||||
value: {
|
||||
type: 'oneOf',
|
||||
selected: 'bar',
|
||||
labels: {
|
||||
bar: 'Bar',
|
||||
scatter: 'Scatter',
|
||||
line: 'Line',
|
||||
area: 'Area',
|
||||
['range-bar']: 'Range Bar',
|
||||
['range-area']: 'Range Area'
|
||||
},
|
||||
configuration: {
|
||||
bar: {
|
||||
value: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'number',
|
||||
value: [25, 25, 50]
|
||||
}
|
||||
},
|
||||
scatter: {
|
||||
value: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'number',
|
||||
value: [25, 25, 50]
|
||||
}
|
||||
},
|
||||
line: {
|
||||
value: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'number',
|
||||
value: [25, 25, 50]
|
||||
}
|
||||
},
|
||||
area: {
|
||||
value: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'number',
|
||||
value: [25, 25, 50]
|
||||
}
|
||||
},
|
||||
['range-bar']: {
|
||||
value: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'number-tuple',
|
||||
value: [
|
||||
[10, 15],
|
||||
[20, 25],
|
||||
[18, 27]
|
||||
]
|
||||
}
|
||||
},
|
||||
['range-area']: {
|
||||
value: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'number-tuple',
|
||||
value: [
|
||||
[10, 15],
|
||||
[20, 25],
|
||||
[18, 27]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value: d.value
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
type: d.value['selected'],
|
||||
// @ts-ignore
|
||||
value: config.value?.['configuration']?.[d.value['selected']].value
|
||||
}
|
||||
})
|
||||
)
|
||||
$effect(() => {
|
||||
resolvedXData &&
|
||||
resolvedDatasets &&
|
||||
resolvedDatasetsValues &&
|
||||
chartInstance &&
|
||||
untrack(() => updateChart())
|
||||
})
|
||||
$effect(() => {
|
||||
result && chartInstance && untrack(() => updateChartByResult())
|
||||
})
|
||||
@@ -364,38 +181,11 @@
|
||||
bind:darkMode
|
||||
on:change={(e) => {
|
||||
tick().then(() => {
|
||||
chartInstance && resolvedDatasetsValues && updateChart()
|
||||
chartInstance && updateChartByResult()
|
||||
})
|
||||
}}
|
||||
/>
|
||||
|
||||
{#if datasets}
|
||||
<ResolveConfig
|
||||
{id}
|
||||
key={'datasets'}
|
||||
bind:resolvedConfig={resolvedDatasets}
|
||||
configuration={datasets}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if xData}
|
||||
<ResolveConfig {id} key={'xData'} bind:resolvedConfig={resolvedXData} configuration={xData} />
|
||||
{/if}
|
||||
|
||||
{#if resolvedDatasets}
|
||||
{#each resolvedDatasets as resolvedDataset, index (resolvedDataset.name + index)}
|
||||
{#if resolvedDatasetsValues}
|
||||
<ResolveConfig
|
||||
{id}
|
||||
key={'datasets' + index}
|
||||
extraKey={resolvedDataset.name}
|
||||
bind:resolvedConfig={resolvedDatasetsValues[index]}
|
||||
configuration={resolvedDataset.value}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
{#each Object.keys(components['agchartscomponent'].initialData.configuration) as key (key)}
|
||||
<ResolveConfig
|
||||
{id}
|
||||
|
||||
+32
-17
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getContext, tick } from 'svelte'
|
||||
import { getContext, tick, untrack } from 'svelte'
|
||||
import type { AppInput } from '../../../inputType'
|
||||
import type { AppViewerContext } from '../../../types'
|
||||
import type RunnableComponent from '../../helpers/RunnableComponent.svelte'
|
||||
@@ -8,14 +8,27 @@
|
||||
import { type ColumnDef, type DbType } from './utils'
|
||||
import { getCountInput } from './queries/count'
|
||||
|
||||
export let id: string
|
||||
export let table: string | undefined
|
||||
export let resource: string | undefined
|
||||
export let renderCount: number
|
||||
export let quicksearch: string
|
||||
export let resourceType: string
|
||||
export let columnDefs: ColumnDef[]
|
||||
export let whereClause: string | undefined
|
||||
interface Props {
|
||||
id: string
|
||||
table: string | undefined
|
||||
resource: string | undefined
|
||||
renderCount: number
|
||||
quicksearch: string
|
||||
resourceType: string
|
||||
columnDefs: ColumnDef[]
|
||||
whereClause: string | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
table,
|
||||
resource,
|
||||
renderCount,
|
||||
quicksearch,
|
||||
resourceType,
|
||||
columnDefs,
|
||||
whereClause
|
||||
}: Props = $props()
|
||||
|
||||
const { worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -25,17 +38,15 @@
|
||||
jobId: undefined
|
||||
})
|
||||
|
||||
let runnableComponent: RunnableComponent
|
||||
let loading = false
|
||||
let input: AppInput | undefined = undefined
|
||||
let runnableComponent: RunnableComponent | undefined = $state()
|
||||
let loading = $state(false)
|
||||
let input: AppInput | undefined = $state(undefined)
|
||||
let lastTableCount: string | undefined = undefined
|
||||
let renderCountLast = -1
|
||||
let quicksearchLast: string | undefined = undefined
|
||||
|
||||
let localColumnDefs = columnDefs
|
||||
let lastTable = table
|
||||
|
||||
$: lastTable != undefined && table && onTableChange()
|
||||
let lastTable = $state(table)
|
||||
|
||||
function onTableChange() {
|
||||
if (table !== lastTable) {
|
||||
@@ -44,8 +55,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: table && renderCount != undefined && quicksearch != undefined && computeCount()
|
||||
|
||||
export async function computeCount(forceCompute?: boolean | undefined) {
|
||||
if (!forceCompute) {
|
||||
if (
|
||||
@@ -76,6 +85,12 @@
|
||||
})
|
||||
}
|
||||
}
|
||||
$effect(() => {
|
||||
lastTable != undefined && table && untrack(() => onTableChange())
|
||||
})
|
||||
$effect(() => {
|
||||
table && renderCount != undefined && quicksearch != undefined && untrack(() => computeCount())
|
||||
})
|
||||
</script>
|
||||
|
||||
<RunnableWrapper
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { getUpdateInput } from './queries/update'
|
||||
|
||||
export let id: string
|
||||
interface Props {
|
||||
id: string
|
||||
}
|
||||
|
||||
let { id }: Props = $props()
|
||||
|
||||
const { worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -19,9 +23,9 @@
|
||||
jobId: undefined
|
||||
})
|
||||
|
||||
let runnableComponent: RunnableComponent
|
||||
let loading = false
|
||||
let input: AppInput | undefined = undefined
|
||||
let runnableComponent: RunnableComponent | undefined = $state(undefined)
|
||||
let loading = $state(false)
|
||||
let input: AppInput | undefined = $state(undefined)
|
||||
|
||||
export async function triggerUpdate(
|
||||
resource: string,
|
||||
|
||||
+23
-10
@@ -1,4 +1,4 @@
|
||||
<script context="module">
|
||||
<script module>
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -11,16 +11,29 @@
|
||||
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[] = []
|
||||
interface Props {
|
||||
id: string
|
||||
license: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
initializing?: boolean | undefined
|
||||
render: boolean
|
||||
customCss?: ComponentCustomCSS<'aggridinfinitecomponentee'> | undefined
|
||||
actions?: TableAction[]
|
||||
}
|
||||
|
||||
let loaded = false
|
||||
let {
|
||||
id,
|
||||
license,
|
||||
componentInput,
|
||||
configuration,
|
||||
initializing = $bindable(undefined),
|
||||
render,
|
||||
customCss = undefined,
|
||||
actions = []
|
||||
}: Props = $props()
|
||||
|
||||
let loaded = $state(false)
|
||||
async function load() {
|
||||
await import('ag-grid-enterprise')
|
||||
const { LicenseManager } = await import('ag-grid-enterprise')
|
||||
|
||||
+43
-27
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import type { AppViewerContext } from '../../../types'
|
||||
import type { TableAction } from '$lib/components/apps/editor/component'
|
||||
@@ -18,16 +20,31 @@
|
||||
import type { ICellRendererParams } from 'ag-grid-community'
|
||||
import Popover from '$lib/components/meltComponents/Popover.svelte'
|
||||
|
||||
export let p: ICellRendererParams<any>
|
||||
export let id: string
|
||||
export let render: boolean
|
||||
export let actions: TableAction[] = []
|
||||
export let rowIndex: number
|
||||
export let row: { original: Record<string, any> }
|
||||
export let onSet: (id: string, value: any, rowIndex: number) => void
|
||||
export let onRemove: (id: string, rowIndex: number) => void
|
||||
export let wrapActions: boolean | undefined = undefined
|
||||
export let selectRow: (params: ICellRendererParams<any>) => void
|
||||
interface Props {
|
||||
p: ICellRendererParams<any>
|
||||
id: string
|
||||
render: boolean
|
||||
actions?: TableAction[]
|
||||
rowIndex: number
|
||||
row: { original: Record<string, any> }
|
||||
onSet: (id: string, value: any, rowIndex: number) => void
|
||||
onRemove: (id: string, rowIndex: number) => void
|
||||
wrapActions?: boolean | undefined
|
||||
selectRow: (params: ICellRendererParams<any>) => void
|
||||
}
|
||||
|
||||
let {
|
||||
p,
|
||||
id,
|
||||
render,
|
||||
actions = [],
|
||||
rowIndex,
|
||||
row,
|
||||
onSet,
|
||||
onRemove,
|
||||
wrapActions = undefined,
|
||||
selectRow
|
||||
}: Props = $props()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const { selectedComponent, hoverStore, mode, connectingInput } =
|
||||
@@ -47,27 +64,26 @@
|
||||
)}
|
||||
>
|
||||
{#each actions as action, actionIndex}
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<!-- svelte-ignore missing-declaration -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
on:mouseover|stopPropagation={() => {
|
||||
onmouseover={stopPropagation(() => {
|
||||
if (action.id !== $hoverStore) {
|
||||
$hoverStore = action.id
|
||||
}
|
||||
}}
|
||||
on:mouseout|stopPropagation={() => {
|
||||
})}
|
||||
onmouseout={stopPropagation(() => {
|
||||
if ($hoverStore !== undefined) {
|
||||
$hoverStore = undefined
|
||||
}
|
||||
}}
|
||||
on:pointerdown|stopPropagation={(e) => {
|
||||
})}
|
||||
onpointerdown={stopPropagation((e) => {
|
||||
selectRow(p)
|
||||
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [action.id]
|
||||
}
|
||||
}}
|
||||
})}
|
||||
class={twMerge(
|
||||
($selectedComponent?.includes(action.id) || $hoverStore === action.id) &&
|
||||
$mode !== 'preview'
|
||||
@@ -80,8 +96,8 @@
|
||||
)}
|
||||
>
|
||||
{#if $mode !== 'preview'}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
title={`Id: ${action.id}`}
|
||||
class={twMerge(
|
||||
@@ -94,9 +110,9 @@
|
||||
? 'opacity-100'
|
||||
: 'opacity-0'
|
||||
)}
|
||||
on:click|stopPropagation={() => {
|
||||
onclick={stopPropagation(() => {
|
||||
$selectedComponent = [action.id]
|
||||
}}
|
||||
})}
|
||||
>
|
||||
{action.id}
|
||||
</div>
|
||||
@@ -111,14 +127,14 @@
|
||||
closeOnOtherPopoverOpen
|
||||
contentClasses="p-4"
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
{#snippet trigger()}
|
||||
<button
|
||||
class="bg-red-500/70 border border-red-600 px-1 py-0.5"
|
||||
title="Outputs"
|
||||
aria-label="Open output"><Plug2 size={12} /></button
|
||||
>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
<ComponentOutputViewer
|
||||
suffix="table"
|
||||
on:select={({ detail }) => {
|
||||
@@ -133,7 +149,7 @@
|
||||
}}
|
||||
componentId={action.id}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script context="module">
|
||||
<script module>
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -15,17 +15,31 @@
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import type { TableAction } from '$lib/components/apps/editor/component'
|
||||
|
||||
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<'aggridcomponent'> | undefined = undefined
|
||||
export let actions: TableAction[] = []
|
||||
export let actionsOrder: RichConfiguration | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
license: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
initializing?: boolean | undefined
|
||||
render: boolean
|
||||
customCss?: ComponentCustomCSS<'aggridcomponent'> | undefined
|
||||
actions?: TableAction[]
|
||||
actionsOrder?: RichConfiguration | undefined
|
||||
}
|
||||
|
||||
let loaded = false
|
||||
let {
|
||||
id,
|
||||
license,
|
||||
componentInput,
|
||||
configuration,
|
||||
initializing = $bindable(undefined),
|
||||
render,
|
||||
customCss = undefined,
|
||||
actions = [],
|
||||
actionsOrder = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let loaded = $state(false)
|
||||
async function load() {
|
||||
await import('ag-grid-enterprise')
|
||||
const { LicenseManager } = await import('ag-grid-enterprise')
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { createBubbler } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
import { createEventDispatcher, tick } from 'svelte'
|
||||
import { writable } from 'svelte/store'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { isLinkObject } from './utils'
|
||||
|
||||
export let type: 'text' | 'badge' | 'link' = 'text'
|
||||
export let value: any
|
||||
export let width: number
|
||||
interface Props {
|
||||
type?: 'text' | 'badge' | 'link'
|
||||
value: any
|
||||
width: number
|
||||
}
|
||||
|
||||
let { type = 'text', value = $bindable(), width }: Props = $props()
|
||||
|
||||
let isEditable = writable(false)
|
||||
let tempValue = value
|
||||
let tempValue = $state(value)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -42,8 +49,8 @@
|
||||
</script>
|
||||
|
||||
<td
|
||||
on:keydown
|
||||
on:click
|
||||
onkeydown={bubble('keydown')}
|
||||
onclick={bubble('click')}
|
||||
class={twMerge(
|
||||
'p-4 whitespace-pre-wrap truncate text-xs text-primary',
|
||||
$isEditable && 'bg-gray-100'
|
||||
@@ -66,20 +73,20 @@
|
||||
<input
|
||||
type="text"
|
||||
value={tempValue}
|
||||
on:input={handleInput}
|
||||
on:blur={saveEdit}
|
||||
oninput={handleInput}
|
||||
onblur={saveEdit}
|
||||
id="cell"
|
||||
class="!appearance-none !bg-transparent !border-none !p-0 !m-0 leading-normal !text-xs"
|
||||
style="outline: none; box-shadow: none; height: auto; resize: none;"
|
||||
on:keypress={(e) => {
|
||||
onkeypress={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
saveEdit()
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div on:dblclick={toggleEdit}>
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div ondblclick={toggleEdit}>
|
||||
{#if typeof value == 'object'}
|
||||
{JSON.stringify(value)}
|
||||
{:else}
|
||||
|
||||
@@ -1,18 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { createBubbler, stopPropagation } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { onMount } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let placeholder: string = 'Search...'
|
||||
// Using 'any' so 'type="number"' can be passed to the input
|
||||
// which should return a number
|
||||
export let value: any
|
||||
export let debounceDelay: number = 100
|
||||
|
||||
let parentClass: string | undefined = undefined
|
||||
export { parentClass as class }
|
||||
interface Props {
|
||||
placeholder?: string
|
||||
// which should return a number
|
||||
value: any
|
||||
debounceDelay?: number
|
||||
class?: string | undefined
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
let {
|
||||
placeholder = 'Search...',
|
||||
value = $bindable(),
|
||||
debounceDelay = 100,
|
||||
class: parentClass = undefined,
|
||||
...rest
|
||||
}: Props = $props()
|
||||
|
||||
let timer: NodeJS.Timeout
|
||||
let inputElement: HTMLInputElement | null = null
|
||||
let inputElement: HTMLInputElement | null = $state(null)
|
||||
|
||||
function debounce(event: KeyboardEvent): void {
|
||||
clearTimeout(timer)
|
||||
@@ -33,9 +46,9 @@
|
||||
<input
|
||||
bind:this={inputElement}
|
||||
{placeholder}
|
||||
on:pointerdown|stopPropagation
|
||||
on:keyup={debounce}
|
||||
on:keydown|stopPropagation
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
onkeyup={debounce}
|
||||
onkeydown={stopPropagation(bubble('keydown'))}
|
||||
class={twMerge(parentClass, 'mb-1 h-8 !rounded-md !shadow-none')}
|
||||
{...$$restProps}
|
||||
{...rest}
|
||||
/>
|
||||
|
||||
@@ -6,13 +6,18 @@
|
||||
import RunnableComponent from './RunnableComponent.svelte'
|
||||
import InitializeComponent from './InitializeComponent.svelte'
|
||||
|
||||
export let id: string
|
||||
export let runnable: HiddenRunnable
|
||||
interface Props {
|
||||
id: string
|
||||
runnable: HiddenRunnable
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { id, runnable, children }: Props = $props()
|
||||
|
||||
const { worldStore, staticExporter, noBackend, runnableComponents } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let result: any = noBackend ? runnable.noBackendValue : undefined
|
||||
let result: any = $state(noBackend ? runnable.noBackendValue : undefined)
|
||||
|
||||
export function onSuccess() {
|
||||
if (runnable.recomputeIds) {
|
||||
@@ -49,7 +54,7 @@
|
||||
on:success={onSuccess}
|
||||
{outputs}
|
||||
>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</RunnableComponent>
|
||||
{:else}
|
||||
<InitializeComponent {id} />
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
import { getContext, onDestroy, onMount } from 'svelte'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
|
||||
export let id: string
|
||||
interface Props {
|
||||
id: string
|
||||
}
|
||||
|
||||
let { id }: Props = $props()
|
||||
const { initialized } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
onMount(() => {
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from 'svelte'
|
||||
|
||||
type InputType = string | number | boolean
|
||||
export let input: HTMLInputElement | undefined = undefined
|
||||
export let defaultValue: InputType | undefined = undefined
|
||||
interface Props {
|
||||
input?: HTMLInputElement | undefined
|
||||
defaultValue?: InputType | undefined
|
||||
}
|
||||
|
||||
let { input = $bindable(undefined), defaultValue = undefined }: Props = $props()
|
||||
|
||||
function setInputValueToDefaultValue() {
|
||||
if (defaultValue !== undefined && input) {
|
||||
@@ -15,8 +21,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: input && defaultValue && setInputValueToDefaultValue()
|
||||
$: input &&
|
||||
(defaultValue === '' || defaultValue === undefined || defaultValue === null) &&
|
||||
clearInputValue()
|
||||
$effect.pre(() => {
|
||||
input && defaultValue && untrack(() => setInputValueToDefaultValue())
|
||||
})
|
||||
$effect.pre(() => {
|
||||
input &&
|
||||
(defaultValue === '' || defaultValue === undefined || defaultValue === null) &&
|
||||
untrack(() => clearInputValue())
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -347,6 +347,10 @@
|
||||
) &&
|
||||
untrack(() => debounceTemplate())
|
||||
})
|
||||
|
||||
// $effect(() => {
|
||||
// console.log('handleConnection4', input)
|
||||
// })
|
||||
$effect(() => {
|
||||
input?.type == 'static' && input.value
|
||||
input && $worldStore && untrack(() => debounce(handleConnection))
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
|
||||
export let loading: boolean
|
||||
interface Props {
|
||||
loading: boolean
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { loading, children }: Props = $props()
|
||||
</script>
|
||||
|
||||
{#if !loading}
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
{:else}
|
||||
<div class="w-full h-full">
|
||||
<div class="absolute inset-0 center-center flex-col bg-surface text-tertiary border">
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<script lang="ts">
|
||||
import type { AppInput } from '../../inputType'
|
||||
|
||||
export let input: AppInput
|
||||
interface Props {
|
||||
input: AppInput
|
||||
}
|
||||
|
||||
let { input }: Props = $props()
|
||||
</script>
|
||||
|
||||
{#if input.type === 'connected'}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
resolvedConfig: any | { type: 'oneOf'; configuration: any; selected: string }
|
||||
configuration: RichConfiguration
|
||||
initialConfig?: RichConfiguration | undefined
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -18,15 +19,17 @@
|
||||
key,
|
||||
resolvedConfig = $bindable(),
|
||||
configuration,
|
||||
initialConfig = undefined
|
||||
initialConfig = undefined,
|
||||
debug = false
|
||||
}: Props = $props()
|
||||
|
||||
function handleSelected(selected: string) {
|
||||
if (resolvedConfig?.selected != undefined && resolvedConfig?.selected != selected) {
|
||||
resolvedConfig.selected = selected
|
||||
}
|
||||
// console.log('handleSelected', JSON.stringify({ resolvedConfig, configuration }))
|
||||
}
|
||||
$effect(() => {
|
||||
$effect.pre(() => {
|
||||
configuration?.type == 'oneOf' &&
|
||||
configuration.selected &&
|
||||
untrack(() => handleSelected(configuration.selected))
|
||||
@@ -50,6 +53,13 @@
|
||||
{/if}
|
||||
{/each}
|
||||
{:else}
|
||||
{#if debug}
|
||||
<pre class="text-2xs">
|
||||
key: {key}
|
||||
{JSON.stringify({ r: resolvedConfig })}
|
||||
{JSON.stringify(configuration)}</pre
|
||||
>
|
||||
{/if}
|
||||
<InputValue
|
||||
field={key}
|
||||
key={key + extraKey}
|
||||
|
||||
@@ -2,17 +2,28 @@
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import type { ComponentCssProperty } from '../../types'
|
||||
import InputValue from './InputValue.svelte'
|
||||
import { untrack } from 'svelte'
|
||||
|
||||
export let css: ComponentCssProperty
|
||||
export let id: string
|
||||
export let key: string
|
||||
export let extraKey: string = ''
|
||||
interface Props {
|
||||
css: ComponentCssProperty
|
||||
id: string
|
||||
key: string
|
||||
extraKey?: string
|
||||
customCss?: Record<string, ComponentCssProperty> | undefined
|
||||
componentStyle?: Record<string, ComponentCssProperty> | undefined
|
||||
}
|
||||
|
||||
export let customCss: Record<string, ComponentCssProperty> | undefined = undefined
|
||||
export let componentStyle: Record<string, ComponentCssProperty> | undefined = undefined
|
||||
let {
|
||||
css = $bindable(),
|
||||
id,
|
||||
key,
|
||||
extraKey = '',
|
||||
customCss = undefined,
|
||||
componentStyle = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let evalClassValue: string | undefined = undefined
|
||||
let evalClassValueGlobal: string | undefined = undefined
|
||||
let evalClassValue: string | undefined = $state(undefined)
|
||||
let evalClassValueGlobal: string | undefined = $state(undefined)
|
||||
|
||||
function updateCss(
|
||||
componentStyle: Record<string, ComponentCssProperty> | undefined,
|
||||
@@ -36,17 +47,24 @@
|
||||
}
|
||||
|
||||
// When any of the values change, update the css
|
||||
$: updateCss(componentStyle, customCss, evalClassValue, evalClassValueGlobal)
|
||||
$effect(() => {
|
||||
;[componentStyle, customCss, evalClassValue, evalClassValueGlobal]
|
||||
untrack(() => updateCss(componentStyle, customCss, evalClassValue, evalClassValueGlobal))
|
||||
})
|
||||
|
||||
// We need to clear the evalClassValue if the user has disabled the evalClass
|
||||
$: if (customCss?.[key]?.evalClass === undefined && evalClassValue !== undefined) {
|
||||
evalClassValue = undefined
|
||||
}
|
||||
$effect(() => {
|
||||
if (customCss?.[key]?.evalClass === undefined && evalClassValue !== undefined) {
|
||||
evalClassValue = undefined
|
||||
}
|
||||
})
|
||||
|
||||
// We need to clear the evalClassValue if the user has disabled the evalClass
|
||||
$: if (componentStyle?.[key]?.evalClass === undefined && evalClassValueGlobal !== undefined) {
|
||||
evalClassValueGlobal = undefined
|
||||
}
|
||||
$effect(() => {
|
||||
if (componentStyle?.[key]?.evalClass === undefined && evalClassValueGlobal !== undefined) {
|
||||
evalClassValueGlobal = undefined
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if customCss}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { createBubbler, stopPropagation } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
@@ -11,23 +14,34 @@
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let inputType: 'date'
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'dateinputcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let onChange: string[] | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
inputType: 'date'
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
customCss?: ComponentCustomCSS<'dateinputcomponent'> | undefined
|
||||
render: boolean
|
||||
onChange?: string[] | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
inputType,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
render,
|
||||
onChange = undefined
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore, selectedComponent, componentControl, runnableComponents } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['dateinputcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['dateinputcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
let value: string | undefined = undefined
|
||||
let value: string | undefined = $state(undefined)
|
||||
|
||||
$componentControl[id] = {
|
||||
setValue(nvalue: string) {
|
||||
@@ -44,8 +58,6 @@
|
||||
result: undefined as string | undefined
|
||||
})
|
||||
|
||||
$: handleDefault(resolvedConfig.defaultValue)
|
||||
|
||||
function formatDate(dateString: string, formatString: string = 'dd.MM.yyyy') {
|
||||
if (formatString === '') {
|
||||
formatString = 'dd.MM.yyyy'
|
||||
@@ -59,15 +71,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
if (value) {
|
||||
outputs?.result.set(formatDate(value, resolvedConfig.outputFormat))
|
||||
} else {
|
||||
outputs?.result.set(undefined)
|
||||
}
|
||||
fireOnChange()
|
||||
}
|
||||
|
||||
function fireOnChange() {
|
||||
if (onChange) {
|
||||
onChange.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb()))
|
||||
@@ -77,7 +80,19 @@
|
||||
function handleDefault(defaultValue: string | undefined) {
|
||||
value = defaultValue
|
||||
}
|
||||
let css = initCss($app.css?.dateinputcomponent, customCss)
|
||||
let css = $state(initCss($app.css?.dateinputcomponent, customCss))
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.defaultValue
|
||||
untrack(() => handleDefault(resolvedConfig.defaultValue))
|
||||
})
|
||||
$effect.pre(() => {
|
||||
if (value) {
|
||||
outputs?.result.set(formatDate(value, resolvedConfig.outputFormat))
|
||||
} else {
|
||||
outputs?.result.set(undefined)
|
||||
}
|
||||
untrack(() => fireOnChange())
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['dateinputcomponent'].initialData.configuration) as key (key)}
|
||||
@@ -104,11 +119,11 @@
|
||||
<AlignWrapper {render} {verticalAlignment}>
|
||||
{#if inputType === 'date'}
|
||||
<input
|
||||
on:keydown={(e) => {
|
||||
onkeydown={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
on:focus={() => ($selectedComponent = [id])}
|
||||
on:pointerdown|stopPropagation
|
||||
onfocus={() => ($selectedComponent = [id])}
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
type="date"
|
||||
bind:value
|
||||
disabled={resolvedConfig.disabled}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import { initCss } from '../../utils'
|
||||
@@ -14,20 +14,29 @@
|
||||
import Select from '$lib/components/select/Select.svelte'
|
||||
import { safeSelectItems } from '$lib/components/select/utils.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'dateselectcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
customCss?: ComponentCustomCSS<'dateselectcomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore, componentControl } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['dateselectcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['dateselectcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
let value: string | undefined = undefined
|
||||
let value: string | undefined = $state(undefined)
|
||||
|
||||
$componentControl[id] = {
|
||||
setValue(nvalue: string) {
|
||||
@@ -41,8 +50,6 @@
|
||||
year: undefined as number | undefined
|
||||
})
|
||||
|
||||
$: !value && handleDefault(resolvedConfig.defaultValue)
|
||||
|
||||
function getLocale(locale: string = 'en-US') {
|
||||
const localeMapping: { [key: string]: Locale } = {
|
||||
'en-US': enUS,
|
||||
@@ -83,13 +90,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.dateinputcomponent, customCss)
|
||||
let css = $state(initCss($app.css?.dateinputcomponent, customCss))
|
||||
|
||||
let selectedDay: string | undefined = undefined
|
||||
let selectedMonth: string | undefined = undefined
|
||||
let selectedYear: string | undefined = undefined
|
||||
|
||||
$: monthItems = computeMonthItems(resolvedConfig?.locale)
|
||||
let selectedDay: string | undefined = $state(undefined)
|
||||
let selectedMonth: string | undefined = $state(undefined)
|
||||
let selectedYear: string | undefined = $state(undefined)
|
||||
|
||||
function updateOutputs(enableDay?: boolean, enableMonth?: boolean, enableYear?: boolean) {
|
||||
if (enableDay) {
|
||||
@@ -113,8 +118,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: updateOutputs(resolvedConfig.enableDay, resolvedConfig.enableMonth, resolvedConfig.enableYear)
|
||||
|
||||
function computeMonthItems(locale: string = 'en-US') {
|
||||
return [
|
||||
{
|
||||
@@ -193,6 +196,17 @@
|
||||
|
||||
return daysInMonth
|
||||
}
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.defaultValue
|
||||
untrack(() => !value && handleDefault(resolvedConfig.defaultValue))
|
||||
})
|
||||
let monthItems = $derived(computeMonthItems(resolvedConfig?.locale))
|
||||
$effect.pre(() => {
|
||||
;[resolvedConfig.enableDay, resolvedConfig.enableMonth, resolvedConfig.enableYear]
|
||||
untrack(() =>
|
||||
updateOutputs(resolvedConfig.enableDay, resolvedConfig.enableMonth, resolvedConfig.enableYear)
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['dateselectcomponent'].initialData.configuration) as key (key)}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import RangeSlider from 'svelte-range-slider-pips'
|
||||
import { getContext, onDestroy } from 'svelte'
|
||||
import { getContext, onDestroy, untrack } from 'svelte'
|
||||
import type {
|
||||
ListInputs,
|
||||
AppViewerContext,
|
||||
@@ -18,11 +20,21 @@
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
import { parseISO, format as formatDateFns } from 'date-fns'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'dateslidercomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
customCss?: ComponentCustomCSS<'dateslidercomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const iterContext = getContext<ListContext>('ListWrapperContext')
|
||||
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
|
||||
@@ -30,22 +42,19 @@
|
||||
const { app, worldStore, selectedComponent, componentControl } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['dateslidercomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['dateslidercomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
onDestroy(() => {
|
||||
listInputs?.remove(id)
|
||||
})
|
||||
|
||||
let values: [number] = [
|
||||
let values: [number] = $state([
|
||||
resolvedConfig.defaultValue
|
||||
? new Date(resolvedConfig.defaultValue).getTime()
|
||||
: new Date().getTime()
|
||||
]
|
||||
|
||||
$: resolvedConfig.defaultValue != undefined && handleDefault()
|
||||
])
|
||||
|
||||
function handleDefault() {
|
||||
values = [
|
||||
@@ -55,7 +64,7 @@
|
||||
]
|
||||
}
|
||||
|
||||
let slider: HTMLElement
|
||||
let slider: HTMLElement | undefined = $state()
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: null as string | null
|
||||
@@ -67,8 +76,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: values && handleValues()
|
||||
|
||||
function formatDate(dateString: string, formatString: string = 'dd.MM.yyyy') {
|
||||
if (formatString === '') {
|
||||
formatString = 'dd.MM.yyyy'
|
||||
@@ -92,18 +99,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.dateslidercomponent, customCss)
|
||||
let css = $state(initCss($app.css?.dateslidercomponent, customCss))
|
||||
|
||||
let lastStyle: string | undefined = undefined
|
||||
$: if (css && slider && lastStyle !== css?.handle?.style) {
|
||||
const handle = slider.querySelector<HTMLSpanElement>('.rangeNub')
|
||||
if (handle) {
|
||||
lastStyle = css?.handle?.style
|
||||
handle.style.cssText = css?.handle?.style ?? ''
|
||||
}
|
||||
}
|
||||
let lastStyle: string | undefined = $state(undefined)
|
||||
|
||||
let width = 0
|
||||
let width = $state(0)
|
||||
|
||||
const spanClass =
|
||||
'text-center text-sm font-medium bg-blue-100 text-blue-800 rounded px-2.5 py-0.5'
|
||||
@@ -123,9 +123,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: if (resolvedConfig.max != undefined && resolvedConfig.step && render) {
|
||||
computeWidth()
|
||||
}
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.defaultValue != undefined && untrack(() => handleDefault())
|
||||
})
|
||||
$effect.pre(() => {
|
||||
values?.[0] && untrack(() => handleValues())
|
||||
})
|
||||
$effect.pre(() => {
|
||||
if (css && slider && lastStyle !== css?.handle?.style) {
|
||||
const handle = slider.querySelector<HTMLSpanElement>('.rangeNub')
|
||||
if (handle) {
|
||||
lastStyle = css?.handle?.style
|
||||
handle.style.cssText = css?.handle?.style ?? ''
|
||||
}
|
||||
}
|
||||
})
|
||||
$effect.pre(() => {
|
||||
if (resolvedConfig.max != undefined && resolvedConfig.step && render) {
|
||||
untrack(() => computeWidth())
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['dateslidercomponent'].initialData.configuration) as key (key)}
|
||||
@@ -169,7 +186,7 @@
|
||||
resolvedConfig?.vertical ? 'h-full' : 'w-full'
|
||||
)}
|
||||
style={css?.bar?.style}
|
||||
on:pointerdown|stopPropagation={() => ($selectedComponent = [id])}
|
||||
onpointerdown={stopPropagation(() => ($selectedComponent = [id]))}
|
||||
>
|
||||
<RangeSlider
|
||||
springValues={{ stiffness: 1, damping: 1 }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onDestroy } from 'svelte'
|
||||
import { getContext, onDestroy, untrack } from 'svelte'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import type {
|
||||
AppViewerContext,
|
||||
@@ -19,22 +19,33 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { parseISO, format as formatDateFns } from 'date-fns'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let inputType: 'date'
|
||||
export let verticalAlignment: VerticalAlignment | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'datetimeinputcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let onChange: string[] | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
inputType: 'date'
|
||||
verticalAlignment?: VerticalAlignment | undefined
|
||||
customCss?: ComponentCustomCSS<'datetimeinputcomponent'> | undefined
|
||||
render: boolean
|
||||
onChange?: string[] | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
inputType,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
render,
|
||||
onChange = undefined
|
||||
}: Props = $props()
|
||||
const { app, worldStore, componentControl, selectedComponent, runnableComponents } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
const iterContext = getContext<ListContext>('ListWrapperContext')
|
||||
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['datetimeinputcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['datetimeinputcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
let outputs = initOutput($worldStore, id, {
|
||||
@@ -43,8 +54,9 @@
|
||||
})
|
||||
|
||||
let initValue = outputs?.result.peak()
|
||||
let value: string | undefined =
|
||||
let value: string | undefined = $state(
|
||||
!iterContext && initValue != undefined ? initValue : resolvedConfig.defaultValue
|
||||
)
|
||||
|
||||
$componentControl[id] = {
|
||||
setValue(nvalue: string) {
|
||||
@@ -59,8 +71,6 @@
|
||||
|
||||
let initialHandleDefault = true
|
||||
|
||||
$: handleDefault(resolvedConfig.defaultValue)
|
||||
|
||||
function formatDate(dateString: string, formatString: string = 'dd.MM.yyyy HH:mm') {
|
||||
if (formatString === '') {
|
||||
formatString = 'dd.MM.yyyy HH:mm'
|
||||
@@ -74,7 +84,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
function fireOnChange() {
|
||||
if (onChange) {
|
||||
onChange.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb()))
|
||||
}
|
||||
}
|
||||
|
||||
function handleDefault(defaultValue: string | undefined) {
|
||||
if (initialHandleDefault) {
|
||||
initialHandleDefault = false
|
||||
if (value != undefined) {
|
||||
return
|
||||
}
|
||||
}
|
||||
value = defaultValue
|
||||
}
|
||||
|
||||
let css = $state(initCss($app.css?.datetimeinputcomponent, customCss))
|
||||
$effect.pre(() => {
|
||||
;[resolvedConfig.defaultValue]
|
||||
untrack(() => handleDefault(resolvedConfig.defaultValue))
|
||||
})
|
||||
$effect.pre(() => {
|
||||
if (value) {
|
||||
const r = formatDate(value, resolvedConfig.outputFormat)
|
||||
outputs?.result.set(r)
|
||||
@@ -120,25 +151,7 @@
|
||||
}
|
||||
}
|
||||
fireOnChange()
|
||||
}
|
||||
|
||||
function fireOnChange() {
|
||||
if (onChange) {
|
||||
onChange.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb()))
|
||||
}
|
||||
}
|
||||
|
||||
function handleDefault(defaultValue: string | undefined) {
|
||||
if (initialHandleDefault) {
|
||||
initialHandleDefault = false
|
||||
if (value != undefined) {
|
||||
return
|
||||
}
|
||||
}
|
||||
value = defaultValue
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.datetimeinputcomponent, customCss)
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['datetimeinputcomponent'].initialData.configuration) as key (key)}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { FileInput } from '../../../common'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
@@ -10,12 +10,23 @@
|
||||
import { components } from '../../editor/component'
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'fileinputcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let onFileChange: string[] | undefined = undefined
|
||||
export let extraKey: string | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
customCss?: ComponentCustomCSS<'fileinputcomponent'> | undefined
|
||||
render: boolean
|
||||
onFileChange?: string[] | undefined
|
||||
extraKey?: string | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
customCss = undefined,
|
||||
render,
|
||||
onFileChange = undefined,
|
||||
extraKey = undefined
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore, componentControl, mode, runnableComponents } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
@@ -24,9 +35,8 @@
|
||||
result: [] as { name: string; data: string }[] | undefined
|
||||
})
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['fileinputcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['fileinputcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
// Receives Base64 encoded strings from the input component
|
||||
@@ -41,9 +51,9 @@
|
||||
onFileChange?.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb?.()))
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.fileinputcomponent, customCss)
|
||||
let css = $state(initCss($app.css?.fileinputcomponent, customCss))
|
||||
|
||||
let fileInput: FileInput | undefined = undefined
|
||||
let fileInput: FileInput | undefined = $state(undefined)
|
||||
|
||||
$componentControl[id] = {
|
||||
clearFiles: () => {
|
||||
@@ -51,7 +61,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
let files: File[] | undefined = undefined
|
||||
let files: File[] | undefined = $state(undefined)
|
||||
|
||||
function preFillFiles() {
|
||||
const data = outputs?.result?.peak()
|
||||
@@ -61,7 +71,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: outputs.result && files === undefined && $mode === 'dnd' && preFillFiles()
|
||||
$effect.pre(() => {
|
||||
outputs.result && files === undefined && $mode === 'dnd' && untrack(() => preFillFiles())
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(css ?? {}) as key (key)}
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InitializeComponent from '../helpers/InitializeComponent.svelte'
|
||||
|
||||
export let id: string
|
||||
export let render: boolean
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
render: boolean
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
}
|
||||
|
||||
let { id, render, verticalAlignment = undefined }: Props = $props()
|
||||
</script>
|
||||
|
||||
<InitializeComponent {id} />
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onDestroy } from 'svelte'
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import { getContext, onDestroy, untrack } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import type {
|
||||
@@ -16,20 +18,30 @@
|
||||
import { components } from '../../editor/component'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'numberinputcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let onChange: string[] | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
customCss?: ComponentCustomCSS<'numberinputcomponent'> | undefined
|
||||
render: boolean
|
||||
onChange?: string[] | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
render,
|
||||
onChange = undefined
|
||||
}: Props = $props()
|
||||
const { app, worldStore, selectedComponent, componentControl, runnableComponents } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
const iterContext = getContext<ListContext>('ListWrapperContext')
|
||||
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['numberinputcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['numberinputcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
onDestroy(() => {
|
||||
@@ -41,8 +53,9 @@
|
||||
})
|
||||
|
||||
let initValue = outputs?.result.peak()
|
||||
let value: number | undefined =
|
||||
let value: number | undefined = $state(
|
||||
!iterContext && initValue != undefined ? initValue : resolvedConfig.defaultValue
|
||||
)
|
||||
|
||||
$componentControl[id] = {
|
||||
setValue(nvalue: number | undefined) {
|
||||
@@ -52,10 +65,6 @@
|
||||
}
|
||||
let initialHandleDefault = true
|
||||
|
||||
$: handleDefault(resolvedConfig.defaultValue)
|
||||
|
||||
$: value, onChangeValue()
|
||||
|
||||
function onChangeValue() {
|
||||
outputs?.result.set(value ?? undefined)
|
||||
if (iterContext && listInputs) {
|
||||
@@ -80,7 +89,15 @@
|
||||
value = defaultValue
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.numberinputcomponent, customCss)
|
||||
let css = $state(initCss($app.css?.numberinputcomponent, customCss))
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.defaultValue
|
||||
untrack(() => handleDefault(resolvedConfig.defaultValue))
|
||||
})
|
||||
$effect.pre(() => {
|
||||
value
|
||||
untrack(() => onChangeValue())
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['numberinputcomponent'].initialData.configuration) as key (key)}
|
||||
@@ -106,8 +123,8 @@
|
||||
|
||||
<AlignWrapper {render} {verticalAlignment}>
|
||||
<input
|
||||
on:pointerdown|stopPropagation={() => ($selectedComponent = [id])}
|
||||
on:focus={() => ($selectedComponent = [id])}
|
||||
onpointerdown={stopPropagation(() => ($selectedComponent = [id]))}
|
||||
onfocus={() => ($selectedComponent = [id])}
|
||||
class={twMerge(
|
||||
'windmillapp w-full py-1.5 px-2 text-sm app-editor-input',
|
||||
css?.input?.class ?? '',
|
||||
|
||||
@@ -1,43 +1,45 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
import type { AppViewerContext, RichConfigurations } from '../../types'
|
||||
import 'quill/dist/quill.snow.css'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import InitializeComponent from '../helpers/InitializeComponent.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let render: boolean
|
||||
let editor = $state()
|
||||
let quill: any = $state()
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
render: boolean
|
||||
toolbarOptions?: any
|
||||
}
|
||||
|
||||
let editor
|
||||
let quill: any
|
||||
export let toolbarOptions = [
|
||||
[{ header: 1 }, { header: 2 }, 'blockquote', 'link', 'image', 'video'],
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{ list: 'ordered' }, { list: 'ordered' }],
|
||||
[{ align: [] }],
|
||||
['clean']
|
||||
]
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
render,
|
||||
toolbarOptions = [
|
||||
[{ header: 1 }, { header: 2 }, 'blockquote', 'link', 'image', 'video'],
|
||||
['bold', 'italic', 'underline', 'strike'],
|
||||
[{ list: 'ordered' }, { list: 'ordered' }],
|
||||
[{ align: [] }],
|
||||
['clean']
|
||||
]
|
||||
}: Props = $props()
|
||||
|
||||
const { worldStore, componentControl, selectedComponent, connectingInput } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let placeholder: string | undefined = undefined
|
||||
let defaultValue: string | undefined = undefined
|
||||
let placeholder: string | undefined = $state(undefined)
|
||||
let defaultValue: string | undefined = $state(undefined)
|
||||
|
||||
let outputs = initOutput($worldStore, id, {
|
||||
result: ''
|
||||
})
|
||||
|
||||
$: if (!render) {
|
||||
quill = undefined
|
||||
}
|
||||
|
||||
$: if (!quill && render) {
|
||||
loadQuill()
|
||||
}
|
||||
|
||||
async function loadQuill() {
|
||||
const { default: Quill } = await import('quill')
|
||||
|
||||
@@ -73,14 +75,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: handleDefault(defaultValue)
|
||||
|
||||
function handleDefault(defaultValue: string | undefined) {
|
||||
if (quill) {
|
||||
quill.root.innerHTML = defaultValue
|
||||
setOutput()
|
||||
}
|
||||
}
|
||||
$effect.pre(() => {
|
||||
if (!render) {
|
||||
quill = undefined
|
||||
}
|
||||
})
|
||||
$effect.pre(() => {
|
||||
if (!quill && render) {
|
||||
untrack(() => loadQuill())
|
||||
}
|
||||
})
|
||||
$effect.pre(() => {
|
||||
;[defaultValue]
|
||||
untrack(() => handleDefault(defaultValue))
|
||||
})
|
||||
</script>
|
||||
|
||||
<InputValue key="placeholder" {id} input={configuration.placeholder} bind:value={placeholder} />
|
||||
@@ -90,11 +104,11 @@
|
||||
{#if render}
|
||||
<div
|
||||
class="editor-wrapper h-full flex-col flex max-h-full overflow-hidden"
|
||||
on:pointerdown|stopPropagation={() => {
|
||||
onpointerdown={stopPropagation(() => {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
}
|
||||
}}
|
||||
})}
|
||||
>
|
||||
<div bind:this={editor}></div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onDestroy } from 'svelte'
|
||||
import { createBubbler, stopPropagation } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { getContext, onDestroy, untrack } from 'svelte'
|
||||
import RangeSlider from 'svelte-range-slider-pips'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
@@ -17,31 +20,37 @@
|
||||
import { components } from '../../editor/component'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'rangecomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
customCss?: ComponentCustomCSS<'rangecomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore, componentControl } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const iterContext = getContext<ListContext>('ListWrapperContext')
|
||||
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['rangecomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['rangecomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
let values: [number, number] = [0, 1]
|
||||
|
||||
$: (resolvedConfig.defaultLow != undefined || resolvedConfig.defaultHigh != undefined) &&
|
||||
handleDefault()
|
||||
let values: [number, number] = $state([0, 1])
|
||||
|
||||
function handleDefault() {
|
||||
values = [resolvedConfig?.defaultLow ?? 0, resolvedConfig?.defaultHigh ?? 1]
|
||||
}
|
||||
|
||||
let slider: HTMLElement
|
||||
let slider: HTMLElement | undefined = $state()
|
||||
|
||||
let outputs = initOutput($worldStore, id, {
|
||||
result: null as [number, number] | null
|
||||
@@ -57,27 +66,33 @@
|
||||
listInputs?.remove(id)
|
||||
})
|
||||
|
||||
$: {
|
||||
outputs?.result.set(values)
|
||||
if (iterContext && listInputs) {
|
||||
listInputs.set(id, values)
|
||||
}
|
||||
}
|
||||
let css = $state(initCss($app.css?.rangecomponent, customCss))
|
||||
|
||||
let css = initCss($app.css?.rangecomponent, customCss)
|
||||
|
||||
let lastStyle: string | undefined = undefined
|
||||
$: if (css && slider && lastStyle !== css?.handles?.style) {
|
||||
const handles = slider.querySelectorAll<HTMLSpanElement>('.rangeNub')
|
||||
if (handles) {
|
||||
lastStyle = css?.handles?.style
|
||||
handles.forEach((handle) => (handle.style.cssText = css?.handles?.style ?? ''))
|
||||
}
|
||||
}
|
||||
let lastStyle: string | undefined = $state(undefined)
|
||||
|
||||
const format = (v, i, p) => {
|
||||
return `${v}`
|
||||
}
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.defaultLow != undefined || resolvedConfig.defaultHigh != undefined
|
||||
untrack(() => handleDefault())
|
||||
})
|
||||
$effect.pre(() => {
|
||||
;[values[0], values[1]]
|
||||
outputs?.result.set(values)
|
||||
if (iterContext && listInputs) {
|
||||
listInputs.set(id, values)
|
||||
}
|
||||
})
|
||||
$effect.pre(() => {
|
||||
if (css && slider && lastStyle !== css?.handles?.style) {
|
||||
const handles = slider.querySelectorAll<HTMLSpanElement>('.rangeNub')
|
||||
if (handles) {
|
||||
lastStyle = css?.handles?.style
|
||||
handles.forEach((handle) => (handle.style.cssText = css?.handles?.style ?? ''))
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['rangecomponent'].initialData.configuration) as key (key)}
|
||||
@@ -108,7 +123,7 @@
|
||||
class={twMerge('grow', 'wm-slider-bar')}
|
||||
style="--range-handle-focus: {'#7e9abd'}; --range-handle: {'#7e9abd'}; {css?.bar?.style ??
|
||||
''}"
|
||||
on:pointerdown|stopPropagation
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
>
|
||||
<RangeSlider
|
||||
id="range-slider"
|
||||
|
||||
@@ -15,16 +15,26 @@
|
||||
import { defaultIfEmptyString } from '$lib/utils'
|
||||
import { userStore } from '$lib/stores'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'s3fileinputcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let extraKey: string | undefined = undefined
|
||||
export let onFileChange: string[] | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
customCss?: ComponentCustomCSS<'s3fileinputcomponent'> | undefined
|
||||
render: boolean
|
||||
extraKey?: string | undefined
|
||||
onFileChange?: string[] | undefined
|
||||
}
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['s3fileinputcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
customCss = undefined,
|
||||
render,
|
||||
extraKey = undefined,
|
||||
onFileChange = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['s3fileinputcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
let fileUploads: Writable<FileUploadData[]> = writable([])
|
||||
@@ -38,16 +48,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
let value: { path: string; filename: string }[] | undefined = undefined
|
||||
let value: { path: string; filename: string }[] | undefined = $state(undefined)
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: value ?? ([] as { path: string; filename: string }[] | undefined),
|
||||
loading: false,
|
||||
jobId: undefined
|
||||
})
|
||||
|
||||
$: resolvedConfigS3 = resolvedConfig.type.configuration.s3
|
||||
let resolvedConfigS3 = $derived(resolvedConfig.type.configuration.s3)
|
||||
|
||||
let css = initCss($app.css?.fileinputcomponent, customCss)
|
||||
let css = $state(initCss($app.css?.fileinputcomponent, customCss))
|
||||
/*
|
||||
|
||||
{#if resolvedConfig.displayDirectLink && fileUpload.progress === 100}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import RangeSlider from 'svelte-range-slider-pips'
|
||||
import { getContext, onDestroy } from 'svelte'
|
||||
import { getContext, onDestroy, untrack } from 'svelte'
|
||||
import type {
|
||||
ListInputs,
|
||||
AppViewerContext,
|
||||
@@ -17,11 +19,21 @@
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'slidercomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
customCss?: ComponentCustomCSS<'slidercomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const iterContext = getContext<ListContext>('ListWrapperContext')
|
||||
const listInputs: ListInputs | undefined = getContext<ListInputs>('ListInputs')
|
||||
@@ -29,24 +41,21 @@
|
||||
const { app, worldStore, selectedComponent, componentControl } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['slidercomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['slidercomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
onDestroy(() => {
|
||||
listInputs?.remove(id)
|
||||
})
|
||||
|
||||
let values: [number] = [resolvedConfig.defaultValue ?? 0]
|
||||
|
||||
$: resolvedConfig.defaultValue != undefined && handleDefault()
|
||||
let values: [number] = $state([resolvedConfig.defaultValue ?? 0])
|
||||
|
||||
function handleDefault() {
|
||||
values = [resolvedConfig?.defaultValue ?? 0]
|
||||
}
|
||||
|
||||
let slider: HTMLElement
|
||||
let slider: HTMLElement | undefined = $state()
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: (0 as number) || null
|
||||
@@ -58,8 +67,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: values && handleValues()
|
||||
|
||||
function handleValues() {
|
||||
// Disallow 'e' character in numbers
|
||||
// if(value && value.toString().includes('e')) {
|
||||
@@ -73,16 +80,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.slidercomponent, customCss)
|
||||
let css = $state(initCss($app.css?.slidercomponent, customCss))
|
||||
|
||||
let lastStyle: string | undefined = undefined
|
||||
$: if (css && slider && lastStyle !== css?.handle?.style) {
|
||||
const handle = slider.querySelector<HTMLSpanElement>('.rangeNub')
|
||||
if (handle) {
|
||||
lastStyle = css?.handle?.style
|
||||
handle.style.cssText = css?.handle?.style ?? ''
|
||||
}
|
||||
}
|
||||
let lastStyle: string | undefined = $state(undefined)
|
||||
|
||||
const spanClass =
|
||||
'text-center text-sm font-medium bg-blue-100 text-blue-800 rounded px-2.5 py-0.5'
|
||||
@@ -101,9 +101,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: if (resolvedConfig.max != undefined && resolvedConfig.step && render) {
|
||||
computeWidth()
|
||||
}
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.defaultValue != undefined && untrack(() => handleDefault())
|
||||
})
|
||||
$effect.pre(() => {
|
||||
values?.[0]
|
||||
values && handleValues()
|
||||
})
|
||||
$effect.pre(() => {
|
||||
if (css && slider && lastStyle !== css?.handle?.style) {
|
||||
const handle = slider.querySelector<HTMLSpanElement>('.rangeNub')
|
||||
if (handle) {
|
||||
lastStyle = css?.handle?.style
|
||||
handle.style.cssText = css?.handle?.style ?? ''
|
||||
}
|
||||
}
|
||||
})
|
||||
$effect.pre(() => {
|
||||
if (resolvedConfig.max != undefined && resolvedConfig.step && render) {
|
||||
untrack(() => computeWidth())
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['slidercomponent'].initialData.configuration) as key (key)}
|
||||
@@ -138,7 +156,7 @@
|
||||
)}
|
||||
style="--range-handle-focus: {'#7e9abd'}; --range-handle: {'#7e9abd'}; {css?.bar?.style ??
|
||||
''}"
|
||||
on:pointerdown|stopPropagation={() => ($selectedComponent = [id])}
|
||||
onpointerdown={stopPropagation(() => ($selectedComponent = [id]))}
|
||||
>
|
||||
<RangeSlider
|
||||
id="slider-input"
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onDestroy } from 'svelte'
|
||||
import { stopPropagation, createBubbler } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { getContext, onDestroy, untrack } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { initConfig, initOutput, selectId } from '../../editor/appUtils'
|
||||
import type {
|
||||
@@ -17,18 +20,31 @@
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
import { loadIcon } from '../icon'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let inputType = 'text'
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'textinputcomponent'> | undefined = undefined
|
||||
export let appCssKey:
|
||||
| 'textinputcomponent'
|
||||
| 'passwordinputcomponent'
|
||||
| 'emailinputcomponent'
|
||||
| 'textareainputcomponent' = 'textinputcomponent'
|
||||
export let render: boolean
|
||||
export let onChange: string[] | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
inputType?: string
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
customCss?: ComponentCustomCSS<'textinputcomponent'> | undefined
|
||||
appCssKey?:
|
||||
| 'textinputcomponent'
|
||||
| 'passwordinputcomponent'
|
||||
| 'emailinputcomponent'
|
||||
| 'textareainputcomponent'
|
||||
render: boolean
|
||||
onChange?: string[] | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
inputType = 'text',
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
appCssKey = 'textinputcomponent',
|
||||
render,
|
||||
onChange = undefined
|
||||
}: Props = $props()
|
||||
|
||||
const {
|
||||
app,
|
||||
@@ -39,9 +55,8 @@
|
||||
runnableComponents
|
||||
} = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['textinputcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['textinputcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
const iterContext = getContext<ListContext>('ListWrapperContext')
|
||||
@@ -52,8 +67,9 @@
|
||||
})
|
||||
|
||||
let initValue = outputs?.result.peak()
|
||||
let value: string | undefined =
|
||||
let value: string | undefined = $state(
|
||||
!iterContext && initValue && initValue != '' ? initValue : resolvedConfig.defaultValue
|
||||
)
|
||||
|
||||
onDestroy(() => {
|
||||
listInputs?.remove(id)
|
||||
@@ -67,9 +83,6 @@
|
||||
}
|
||||
|
||||
let initialHandleDefault = true
|
||||
$: handleDefault(resolvedConfig.defaultValue)
|
||||
|
||||
$: value, onValueChange()
|
||||
|
||||
function onValueChange() {
|
||||
let val = value ?? ''
|
||||
@@ -96,21 +109,10 @@
|
||||
value = defaultValue
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.[appCssKey], customCss)
|
||||
let css = $state(initCss($app.css?.[appCssKey], customCss))
|
||||
|
||||
$: classInput = twMerge(
|
||||
'windmillapp w-full py-1.5 px-2 text-sm',
|
||||
'app-editor-input',
|
||||
css?.input?.class ?? '',
|
||||
'wm-input',
|
||||
'wm-text-input'
|
||||
)
|
||||
|
||||
let beforeIconComponent: any
|
||||
let afterIconComponent: any
|
||||
|
||||
$: resolvedConfig.beforeIcon && beforeIconComponent && handleBeforeIcon()
|
||||
$: resolvedConfig.afterIcon && afterIconComponent && handleAfterIcon()
|
||||
let beforeIconComponent: any = $state()
|
||||
let afterIconComponent: any = $state()
|
||||
|
||||
async function handleBeforeIcon() {
|
||||
if (resolvedConfig.beforeIcon) {
|
||||
@@ -135,6 +137,29 @@
|
||||
)
|
||||
}
|
||||
}
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.defaultValue
|
||||
untrack(() => handleDefault(resolvedConfig.defaultValue))
|
||||
})
|
||||
$effect.pre(() => {
|
||||
value
|
||||
untrack(() => onValueChange())
|
||||
})
|
||||
let classInput = $derived(
|
||||
twMerge(
|
||||
'windmillapp w-full py-1.5 px-2 text-sm',
|
||||
'app-editor-input',
|
||||
css?.input?.class ?? '',
|
||||
'wm-input',
|
||||
'wm-text-input'
|
||||
)
|
||||
)
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.beforeIcon && beforeIconComponent && untrack(() => handleBeforeIcon())
|
||||
})
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.afterIcon && afterIconComponent && untrack(() => handleAfterIcon())
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['textinputcomponent'].initialData.configuration) as key (key)}
|
||||
@@ -169,9 +194,11 @@
|
||||
'h-full'
|
||||
)}
|
||||
style="resize:none; {css?.input?.style ?? ''}"
|
||||
on:pointerdown|stopPropagation={(e) =>
|
||||
!$connectingInput.opened && selectId(e, id, selectedComponent, $app)}
|
||||
on:keydown|stopPropagation
|
||||
onpointerdown={(e) => {
|
||||
e.stopPropagation()
|
||||
!$connectingInput.opened && selectId(e, id, selectedComponent, $app)
|
||||
}}
|
||||
onkeydown={stopPropagation(bubble('keydown'))}
|
||||
bind:value
|
||||
placeholder={resolvedConfig.placeholder}
|
||||
disabled={resolvedConfig.disabled}
|
||||
@@ -195,9 +222,11 @@
|
||||
resolvedConfig.afterIcon ? '!pr-8' : ''
|
||||
)}
|
||||
style={css?.input?.style ?? ''}
|
||||
on:pointerdown|stopPropagation={(e) =>
|
||||
!$connectingInput.opened && selectId(e, id, selectedComponent, $app)}
|
||||
on:keydown|stopPropagation
|
||||
onpointerdown={(e) => {
|
||||
e.stopPropagation()
|
||||
!$connectingInput.opened && selectId(e, id, selectedComponent, $app)
|
||||
}}
|
||||
onkeydown={stopPropagation(bubble('keydown'))}
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
bind:value
|
||||
@@ -212,9 +241,11 @@
|
||||
resolvedConfig.afterIcon ? '!pr-8' : ''
|
||||
)}
|
||||
style={css?.input?.style ?? ''}
|
||||
on:pointerdown|stopPropagation={(e) =>
|
||||
!$connectingInput.opened && selectId(e, id, selectedComponent, $app)}
|
||||
on:keydown|stopPropagation
|
||||
onpointerdown={(e) => {
|
||||
e.stopPropagation()
|
||||
!$connectingInput.opened && selectId(e, id, selectedComponent, $app)
|
||||
}}
|
||||
onkeydown={stopPropagation(bubble('keydown'))}
|
||||
type="text"
|
||||
bind:value
|
||||
placeholder={resolvedConfig.placeholder}
|
||||
@@ -228,9 +259,11 @@
|
||||
resolvedConfig.afterIcon ? '!pr-8' : ''
|
||||
)}
|
||||
style={css?.input?.style ?? ''}
|
||||
on:pointerdown|stopPropagation={(e) =>
|
||||
!$connectingInput.opened && selectId(e, id, selectedComponent, $app)}
|
||||
on:keydown|stopPropagation
|
||||
onpointerdown={(e) => {
|
||||
e.stopPropagation()
|
||||
!$connectingInput.opened && selectId(e, id, selectedComponent, $app)
|
||||
}}
|
||||
onkeydown={stopPropagation(bubble('keydown'))}
|
||||
type="email"
|
||||
bind:value
|
||||
placeholder={resolvedConfig.placeholder}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
@@ -10,22 +12,32 @@
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'timeinputcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let onChange: string[] | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
customCss?: ComponentCustomCSS<'timeinputcomponent'> | undefined
|
||||
render: boolean
|
||||
onChange?: string[] | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
render,
|
||||
onChange = undefined
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore, selectedComponent, componentControl, runnableComponents } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['timeinputcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['timeinputcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
let value: string | undefined = undefined
|
||||
let value: string | undefined = $state(undefined)
|
||||
|
||||
$componentControl[id] = {
|
||||
setValue(nvalue: string) {
|
||||
@@ -38,14 +50,26 @@
|
||||
validity: true as boolean
|
||||
})
|
||||
|
||||
$: !value && handleDefault(resolvedConfig.defaultValue)
|
||||
|
||||
function convertToMinutes(time: string) {
|
||||
const [hours, minutes] = time.split(':').map(Number)
|
||||
return hours * 60 + minutes
|
||||
}
|
||||
|
||||
$: {
|
||||
function fireOnChange() {
|
||||
if (onChange) {
|
||||
onChange.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb()))
|
||||
}
|
||||
}
|
||||
|
||||
function handleDefault(defaultValue: string | undefined) {
|
||||
value = defaultValue
|
||||
}
|
||||
let css = $state(initCss($app.css?.timeinputcomponent, customCss))
|
||||
$effect.pre(() => {
|
||||
resolvedConfig.defaultValue
|
||||
!value && untrack(() => handleDefault(resolvedConfig.defaultValue))
|
||||
})
|
||||
$effect.pre(() => {
|
||||
if (value) {
|
||||
if (!resolvedConfig['24hFormat']) {
|
||||
let time = value.split(':')
|
||||
@@ -80,18 +104,7 @@
|
||||
outputs?.validity.set(isValid)
|
||||
}
|
||||
fireOnChange()
|
||||
}
|
||||
|
||||
function fireOnChange() {
|
||||
if (onChange) {
|
||||
onChange.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb()))
|
||||
}
|
||||
}
|
||||
|
||||
function handleDefault(defaultValue: string | undefined) {
|
||||
value = defaultValue
|
||||
}
|
||||
let css = initCss($app.css?.timeinputcomponent, customCss)
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['timeinputcomponent'].initialData.configuration) as key (key)}
|
||||
@@ -117,8 +130,8 @@
|
||||
|
||||
<AlignWrapper {render} {verticalAlignment}>
|
||||
<input
|
||||
on:focus={() => ($selectedComponent = [id])}
|
||||
on:pointerdown|stopPropagation={() => ($selectedComponent = [id])}
|
||||
onfocus={() => ($selectedComponent = [id])}
|
||||
onpointerdown={stopPropagation(() => ($selectedComponent = [id]))}
|
||||
type="time"
|
||||
bind:value
|
||||
min={resolvedConfig.minTime}
|
||||
|
||||
+31
-16
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import { initConfig, initOutput } from '$lib/components/apps/editor/appUtils'
|
||||
import { getContext, onDestroy } from 'svelte'
|
||||
import { getContext, onDestroy, untrack } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type {
|
||||
AppViewerContext,
|
||||
@@ -17,11 +19,21 @@
|
||||
import { components } from '$lib/components/apps/editor/component'
|
||||
import ResolveStyle from '../../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'currencycomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
customCss?: ComponentCustomCSS<'currencycomponent'> | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore, selectedComponent, componentControl } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
@@ -36,14 +48,14 @@
|
||||
listInputs?.remove(id)
|
||||
})
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['currencycomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['currencycomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
let initValue = outputs?.result.peak()
|
||||
let value: number | undefined =
|
||||
let value: number | undefined = $state(
|
||||
!iterContext && initValue != undefined ? initValue : resolvedConfig.defaultValue
|
||||
)
|
||||
|
||||
$componentControl[id] = {
|
||||
setValue(nvalue: number) {
|
||||
@@ -61,8 +73,6 @@
|
||||
|
||||
let initialHandleDefault = true
|
||||
|
||||
$: handleDefault(resolvedConfig.defaultValue)
|
||||
|
||||
function handleDefault(dflt: number | undefined) {
|
||||
if (initialHandleDefault) {
|
||||
initialHandleDefault = false
|
||||
@@ -74,9 +84,14 @@
|
||||
handleInput()
|
||||
}
|
||||
|
||||
$: value != undefined && handleInput()
|
||||
|
||||
let css = initCss($app.css?.currencycomponent, customCss)
|
||||
let css = $state(initCss($app.css?.currencycomponent, customCss))
|
||||
$effect(() => {
|
||||
resolvedConfig.defaultValue
|
||||
untrack(() => handleDefault(resolvedConfig.defaultValue))
|
||||
})
|
||||
$effect(() => {
|
||||
value != undefined && untrack(() => handleInput())
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['currencycomponent'].initialData.configuration) as key (key)}
|
||||
@@ -104,7 +119,7 @@
|
||||
{#key resolvedConfig.isNegativeAllowed}
|
||||
{#key resolvedConfig.locale}
|
||||
{#key resolvedConfig.currency}
|
||||
<div class="w-full" on:pointerdown|stopPropagation={() => ($selectedComponent = [id])}>
|
||||
<div class="w-full" onpointerdown={stopPropagation(() => ($selectedComponent = [id]))}>
|
||||
<CurrencyInput
|
||||
inputClasses={{
|
||||
formatted: twMerge(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import DarkModeObserver from '$lib/components/DarkModeObserver.svelte'
|
||||
import { untrack } from 'svelte'
|
||||
|
||||
/* Forked from MIT LICENSE
|
||||
https://raw.githubusercontent.com/Canutin/svelte-currency-input/main/src/lib/CurrencyInput.svelte
|
||||
@@ -27,18 +28,35 @@
|
||||
formattedZero?: string
|
||||
}
|
||||
|
||||
export let value: number = DEFAULT_VALUE
|
||||
export let locale: string = DEFAULT_LOCALE
|
||||
export let currency: string = DEFAULT_CURRENCY
|
||||
export let name: string = DEFAULT_NAME
|
||||
export let required: boolean = false
|
||||
export let disabled: boolean = false
|
||||
export let placeholder: number | null = DEFAULT_VALUE
|
||||
export let isNegativeAllowed: boolean = true
|
||||
export let fractionDigits: number = DEFAULT_FRACTION_DIGITS
|
||||
export let inputClasses: InputClasses | null = null
|
||||
export let noColor: boolean = false
|
||||
export let style: string = ''
|
||||
interface Props {
|
||||
value?: number
|
||||
locale?: string
|
||||
currency?: string
|
||||
name?: string
|
||||
required?: boolean
|
||||
disabled?: boolean
|
||||
placeholder?: number | null
|
||||
isNegativeAllowed?: boolean
|
||||
fractionDigits?: number
|
||||
inputClasses?: InputClasses | null
|
||||
noColor?: boolean
|
||||
style?: string
|
||||
}
|
||||
|
||||
let {
|
||||
value = $bindable(DEFAULT_VALUE),
|
||||
locale = DEFAULT_LOCALE,
|
||||
currency = DEFAULT_CURRENCY,
|
||||
name = DEFAULT_NAME,
|
||||
required = false,
|
||||
disabled = false,
|
||||
placeholder = DEFAULT_VALUE,
|
||||
isNegativeAllowed = true,
|
||||
fractionDigits = DEFAULT_FRACTION_DIGITS,
|
||||
inputClasses = null,
|
||||
noColor = false,
|
||||
style = ''
|
||||
}: Props = $props()
|
||||
|
||||
// Formats value as: e.g. $1,523.00 | -$1,523.00
|
||||
const formatCurrency = (
|
||||
@@ -158,14 +176,19 @@
|
||||
}, 0.1)
|
||||
}
|
||||
|
||||
let formattedValue = ''
|
||||
let formattedValue = $state('')
|
||||
let formattedPlaceholder =
|
||||
placeholder !== null ? formatCurrency(placeholder, fractionDigits, fractionDigits) : ''
|
||||
$: isZero = value === 0
|
||||
$: isNegative = value < 0
|
||||
$: value, setFormattedValue()
|
||||
let isZero = $derived(value === 0)
|
||||
let isNegative = $derived(value < 0)
|
||||
$effect(() => {
|
||||
value
|
||||
untrack(() => {
|
||||
setFormattedValue()
|
||||
})
|
||||
})
|
||||
|
||||
let darkMode: boolean = false
|
||||
let darkMode: boolean = $state(false)
|
||||
</script>
|
||||
|
||||
<DarkModeObserver bind:darkMode />
|
||||
@@ -182,11 +205,11 @@
|
||||
class="
|
||||
{inputClasses?.formatted ?? DEFAULT_CLASS_FORMATTED}
|
||||
{isNegativeAllowed && !isZero && !isNegative
|
||||
? inputClasses?.formattedPositive ?? DEFAULT_CLASS_FORMATTED_POSITIVE
|
||||
? (inputClasses?.formattedPositive ?? DEFAULT_CLASS_FORMATTED_POSITIVE)
|
||||
: ''}
|
||||
{isZero ? inputClasses?.formattedZero ?? DEFAULT_CLASS_FORMATTED_ZERO : ''}
|
||||
{isZero ? (inputClasses?.formattedZero ?? DEFAULT_CLASS_FORMATTED_ZERO) : ''}
|
||||
{isNegativeAllowed && isNegative
|
||||
? inputClasses?.formattedNegative ?? DEFAULT_CLASS_FORMATTED_NEGATIVE
|
||||
? (inputClasses?.formattedNegative ?? DEFAULT_CLASS_FORMATTED_NEGATIVE)
|
||||
: ''}
|
||||
"
|
||||
style={style ? style : noColor ? (darkMode ? 'color: white;' : 'color: black;') : ''}
|
||||
@@ -197,8 +220,8 @@
|
||||
placeholder={formattedPlaceholder}
|
||||
{disabled}
|
||||
bind:value={formattedValue}
|
||||
on:keydown={handleKeyDown}
|
||||
on:keyup={setUnformattedValue}
|
||||
onkeydown={handleKeyDown}
|
||||
onkeyup={setUnformattedValue}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -15,21 +15,33 @@
|
||||
import InitializeComponent from '../helpers/InitializeComponent.svelte'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let horizontalAlignment: HorizontalAlignment | undefined = undefined
|
||||
export let verticalAlignment: VerticalAlignment | undefined = undefined
|
||||
export let customCss:
|
||||
| ComponentCustomCSS<'verticaldividercomponent' | 'horizontaldividercomponent'>
|
||||
| undefined = undefined
|
||||
export let position: 'horizontal' | 'vertical'
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
horizontalAlignment?: HorizontalAlignment | undefined
|
||||
verticalAlignment?: VerticalAlignment | undefined
|
||||
customCss?:
|
||||
| ComponentCustomCSS<'verticaldividercomponent' | 'horizontaldividercomponent'>
|
||||
| undefined
|
||||
position: 'horizontal' | 'vertical'
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
configuration,
|
||||
horizontalAlignment = undefined,
|
||||
verticalAlignment = undefined,
|
||||
customCss = undefined,
|
||||
position,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
let size = 2
|
||||
let color = '#00000060'
|
||||
let size = $state(2)
|
||||
let color = $state('#00000060')
|
||||
|
||||
let css = initCss($app.css?.[position + 'dividercomponent'], customCss)
|
||||
let css = $state(initCss($app.css?.[position + 'dividercomponent'], customCss))
|
||||
|
||||
//used so that we can count number of outputs setup for first refresh
|
||||
initOutput($worldStore, id, {})
|
||||
|
||||
@@ -3,14 +3,28 @@
|
||||
import type { ListInputs, ListContext } from '../../types'
|
||||
import { writable } from 'svelte/store'
|
||||
|
||||
export let index: number
|
||||
export let value: any
|
||||
export let disabled = false
|
||||
export let onSet: ((id: string, value: any) => void) | undefined = undefined
|
||||
export let onRemove: ((id: string) => void) | undefined = undefined
|
||||
interface Props {
|
||||
index: number
|
||||
value: any
|
||||
disabled?: boolean
|
||||
onSet?: ((id: string, value: any) => void) | undefined
|
||||
onRemove?: ((id: string) => void) | undefined
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let {
|
||||
index,
|
||||
value,
|
||||
disabled = false,
|
||||
onSet = undefined,
|
||||
onRemove = undefined,
|
||||
children
|
||||
}: Props = $props()
|
||||
const ctx = writable({ index, value, disabled })
|
||||
|
||||
$: $ctx = { index, value, disabled }
|
||||
$effect(() => {
|
||||
$ctx = { index, value, disabled }
|
||||
})
|
||||
setContext<ListContext>('ListWrapperContext', ctx)
|
||||
setContext<ListInputs>('ListInputs', {
|
||||
set: (id: string, value: any) => {
|
||||
@@ -22,4 +36,4 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
|
||||
@@ -3,15 +3,22 @@
|
||||
import type { ListInputs, ListContext } from '../../types'
|
||||
import { writable } from 'svelte/store'
|
||||
|
||||
export let index: number
|
||||
export let value: any
|
||||
export let disabled = false
|
||||
export let onSet: (id: string, value: any) => void
|
||||
export let onRemove: (id: string) => void
|
||||
interface Props {
|
||||
index: number
|
||||
value: any
|
||||
disabled?: boolean
|
||||
onSet: (id: string, value: any) => void
|
||||
onRemove: (id: string) => void
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { index, value, disabled = false, onSet, onRemove, children }: Props = $props()
|
||||
|
||||
const ctx = writable({ index, value, disabled })
|
||||
|
||||
$: $ctx = { index, value, disabled }
|
||||
$effect(() => {
|
||||
$ctx = { index, value, disabled }
|
||||
})
|
||||
|
||||
setContext<ListContext>('RowWrapperContext', ctx)
|
||||
setContext<ListInputs>('RowInputs', {
|
||||
@@ -24,4 +31,4 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
import { components, type AppComponent } from './component'
|
||||
import InputsSpecsEditor from './settingsPanel/InputsSpecsEditor.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let resourceOnly = false
|
||||
interface Props {
|
||||
component: AppComponent
|
||||
resourceOnly?: boolean
|
||||
}
|
||||
|
||||
let { component = $bindable(), resourceOnly = false }: Props = $props()
|
||||
</script>
|
||||
|
||||
{#if component?.componentInput?.type === 'runnable' && Object.keys(component?.componentInput?.fields ?? {}).length > 0}
|
||||
|
||||
@@ -5,8 +5,12 @@
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import DeploymentHistory from './DeploymentHistory.svelte'
|
||||
|
||||
export let appPath: string | undefined = undefined
|
||||
let historyBrowserDrawerOpen = false
|
||||
interface Props {
|
||||
appPath?: string | undefined
|
||||
}
|
||||
|
||||
let { appPath = undefined }: Props = $props()
|
||||
let historyBrowserDrawerOpen = $state(false)
|
||||
|
||||
export function open() {
|
||||
historyBrowserDrawerOpen = true
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
<script lang="ts">
|
||||
import { createBubbler } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import InlineScriptsPanel from './inlineScriptsPanel/InlineScriptsPanel.svelte'
|
||||
import RunnableJobPanel from './RunnableJobPanel.svelte'
|
||||
|
||||
export let rightPanelSize: number = 0
|
||||
export let centerPanelWidth: number = 0
|
||||
export let runnablePanelSize: number = 0
|
||||
interface Props {
|
||||
rightPanelSize?: number
|
||||
centerPanelWidth?: number
|
||||
runnablePanelSize?: number
|
||||
}
|
||||
|
||||
let { rightPanelSize = 0, centerPanelWidth = 0, runnablePanelSize = 0 }: Props = $props()
|
||||
</script>
|
||||
|
||||
{#if rightPanelSize !== 0}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="relative h-full w-full overflow-x-visible" on:mouseenter on:mouseleave>
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="relative h-full w-full overflow-x-visible"
|
||||
onmouseenter={bubble('mouseenter')}
|
||||
onmouseleave={bubble('mouseleave')}
|
||||
>
|
||||
<InlineScriptsPanel on:hidePanel />
|
||||
<RunnableJobPanel hidden={runnablePanelSize === 0} />
|
||||
</div>
|
||||
|
||||
@@ -20,30 +20,47 @@
|
||||
import TestJobLoader from '$lib/components/TestJobLoader.svelte'
|
||||
import type { Job } from '$lib/gen'
|
||||
import type { JobById } from '../types'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
|
||||
export let open = false
|
||||
export let jobs: string[]
|
||||
export let jobsById: Record<string, JobById>
|
||||
interface Props {
|
||||
open?: boolean
|
||||
jobs: string[]
|
||||
jobsById: Record<string, JobById>
|
||||
hasErrors?: boolean
|
||||
selectedJobId?: string | undefined
|
||||
refreshComponents?: (() => void) | undefined
|
||||
errorByComponent?: Record<string, { id?: string; error: string }>
|
||||
}
|
||||
|
||||
export let hasErrors: boolean = false
|
||||
export let selectedJobId: string | undefined = undefined
|
||||
export let refreshComponents: (() => void) | undefined = undefined
|
||||
export let errorByComponent: Record<string, { id?: string; error: string }> = {}
|
||||
let {
|
||||
open = $bindable(false),
|
||||
jobs,
|
||||
jobsById,
|
||||
hasErrors = false,
|
||||
selectedJobId = $bindable(undefined),
|
||||
refreshComponents = undefined,
|
||||
errorByComponent = {}
|
||||
}: Props = $props()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let testJobLoader: TestJobLoader
|
||||
let job: Job | undefined = undefined
|
||||
let testIsLoading = false
|
||||
let testJobLoader: TestJobLoader | undefined = $state()
|
||||
let job: Job | undefined = $state(undefined)
|
||||
let testIsLoading = $state(false)
|
||||
|
||||
let rightColumnSelect: 'timeline' | 'detail' = 'timeline'
|
||||
let rightColumnSelect: 'timeline' | 'detail' = $state('timeline')
|
||||
|
||||
$: selectedJobId && !selectedJobId?.includes('Frontend') && testJobLoader?.watchJob(selectedJobId)
|
||||
$effect(() => {
|
||||
selectedJobId &&
|
||||
!selectedJobId?.includes('Frontend') &&
|
||||
untrack(() => selectedJobId && testJobLoader?.watchJob(selectedJobId))
|
||||
})
|
||||
|
||||
$: if (selectedJobId?.includes('Frontend') && selectedJobId) {
|
||||
job = undefined
|
||||
}
|
||||
$effect(() => {
|
||||
if (selectedJobId?.includes('Frontend') && selectedJobId) {
|
||||
job = undefined
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<TestJobLoader bind:this={testJobLoader} bind:isLoading={testIsLoading} bind:job />
|
||||
@@ -67,8 +84,8 @@
|
||||
{#each jobs ?? [] as id}
|
||||
{@const selectedJob = jobsById[id]}
|
||||
{#if selectedJob}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class={classNames(
|
||||
'border flex gap-1 truncate justify-between flex-row w-full items-center p-2 rounded-md cursor-pointer hover:bg-surface-secondary hover:text-blue-400',
|
||||
@@ -81,7 +98,7 @@
|
||||
? 'text-blue-600'
|
||||
: ''
|
||||
)}
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
selectedJobId = id
|
||||
rightColumnSelect = 'detail'
|
||||
}}
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
import { Drawer } from '$lib/components/common'
|
||||
|
||||
import AppReportsDrawerInner from './AppReportsDrawerInner.svelte'
|
||||
export let appPath: string
|
||||
export let open = false
|
||||
interface Props {
|
||||
appPath: string
|
||||
open?: boolean
|
||||
}
|
||||
|
||||
let { appPath, open = $bindable(false) }: Props = $props()
|
||||
</script>
|
||||
|
||||
<Drawer bind:open size="800px">
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
<script lang="ts">
|
||||
import { debounce } from '$lib/utils'
|
||||
import { onDestroy } from 'svelte'
|
||||
import { onDestroy, untrack } from 'svelte'
|
||||
|
||||
import TimelineBar from '$lib/components/TimelineBar.svelte'
|
||||
import type { JobById } from '../types'
|
||||
|
||||
export let jobs: string[]
|
||||
export let jobsById: Record<string, JobById>
|
||||
interface Props {
|
||||
jobs: string[]
|
||||
jobsById: Record<string, JobById>
|
||||
}
|
||||
|
||||
let min: undefined | number = undefined
|
||||
let { jobs, jobsById }: Props = $props()
|
||||
|
||||
let min: undefined | number = $state(undefined)
|
||||
let max: undefined | number = undefined
|
||||
let total: number | undefined = undefined
|
||||
let total: number | undefined = $state(undefined)
|
||||
|
||||
let { debounced, clearDebounce } = debounce(() => computeItems(jobs), 30)
|
||||
$: jobs && jobsById && debounced()
|
||||
$effect(() => {
|
||||
jobs && jobsById && untrack(() => debounced())
|
||||
})
|
||||
|
||||
let items: Record<
|
||||
string,
|
||||
{ created_at?: number; started_at?: number; duration_ms?: number; id: string }[]
|
||||
> = {}
|
||||
> = $state({})
|
||||
|
||||
export function reset() {
|
||||
min = undefined
|
||||
@@ -88,7 +94,7 @@
|
||||
items = nitems
|
||||
}
|
||||
|
||||
let now = Date.now()
|
||||
let now = $state(Date.now())
|
||||
|
||||
let interval = setInterval((x) => {
|
||||
if (!max) {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation, createBubbler } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { classNames } from '$lib/utils'
|
||||
import type { AppViewerContext } from '../types'
|
||||
import { Anchor, ArrowDownFromLine, Bug, Expand, Network, Pen, Plug } from 'lucide-svelte'
|
||||
@@ -14,29 +17,45 @@
|
||||
import DecisionTreeDebug from './DecisionTreeDebug.svelte'
|
||||
import AnimatedButton from '$lib/components/common/button/AnimatedButton.svelte'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
export let locked: boolean = false
|
||||
export let hover: boolean = false
|
||||
export let connecting: boolean = false
|
||||
export let hasInlineEditor: boolean = false
|
||||
export let inlineEditorOpened: boolean = false
|
||||
export let errorHandledByComponent: boolean = false
|
||||
export let fullHeight: boolean = false
|
||||
export let componentContainerWidth: number
|
||||
//export let willNotDisplay: boolean = false
|
||||
interface Props {
|
||||
component: AppComponent
|
||||
selected: boolean
|
||||
locked?: boolean
|
||||
hover?: boolean
|
||||
connecting?: boolean
|
||||
hasInlineEditor?: boolean
|
||||
inlineEditorOpened?: boolean
|
||||
errorHandledByComponent?: boolean
|
||||
fullHeight?: boolean
|
||||
componentContainerWidth: number
|
||||
}
|
||||
|
||||
let {
|
||||
component,
|
||||
selected,
|
||||
locked = false,
|
||||
hover = false,
|
||||
connecting = false,
|
||||
hasInlineEditor = false,
|
||||
inlineEditorOpened = false,
|
||||
errorHandledByComponent = false,
|
||||
fullHeight = false,
|
||||
componentContainerWidth
|
||||
}: Props = $props()
|
||||
|
||||
const DECISION_TREE_THRESHOLD = 300
|
||||
const STEPPER_THRESHOLD = 180
|
||||
const CONDITIONAL_WRAPPER_THRESHOLD = 200
|
||||
const MINIMUM_WIDTH = 20
|
||||
|
||||
let maxWidth = 10
|
||||
let isManuallySelected = false
|
||||
let componentIsDebugging = false
|
||||
let id_width = 0
|
||||
let maxWidth = $state(10)
|
||||
let isManuallySelected = $state(false)
|
||||
let componentIsDebugging = $state(false)
|
||||
let id_width = $state(0)
|
||||
|
||||
$: maxWidth = Math.max(Math.round(0.2 * componentContainerWidth), MINIMUM_WIDTH)
|
||||
$effect(() => {
|
||||
maxWidth = Math.max(Math.round(0.2 * componentContainerWidth), MINIMUM_WIDTH)
|
||||
})
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -59,12 +78,12 @@
|
||||
return Object.values(componentOptions).some((value) => value)
|
||||
}
|
||||
|
||||
let hoverHeader = false
|
||||
let hoverHeader = $state(false)
|
||||
</script>
|
||||
|
||||
{#if connecting}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
||||
<div
|
||||
class="absolute z-50 overflow-auto -top-[18px]"
|
||||
style="left: {id_width}px;"
|
||||
@@ -75,7 +94,7 @@
|
||||
closeOnOtherPopoverOpen
|
||||
contentClasses="p-4"
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
{#snippet trigger()}
|
||||
<AnimatedButton
|
||||
animate={true}
|
||||
baseRadius="9999px"
|
||||
@@ -90,32 +109,32 @@
|
||||
aria-label="Open output"><Plug size={12} /></div
|
||||
>
|
||||
</AnimatedButton>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
<ComponentOutputViewer
|
||||
suffix="connect"
|
||||
on:select={({ detail }) =>
|
||||
connectOutput(connectingInput, component.type, component.id, detail)}
|
||||
componentId={component.id}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if selected || hover}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
||||
<div class="-top-[18px] -left-[8px] flex flex-row flex-nowrap w-fit h-fit absolute gap-0.5">
|
||||
<div
|
||||
on:mouseover|stopPropagation={() => {
|
||||
onmouseover={stopPropagation(() => {
|
||||
hoverHeader = true
|
||||
dispatch('mouseover')
|
||||
}}
|
||||
on:mouseleave|stopPropagation={() => {
|
||||
})}
|
||||
onmouseleave={stopPropagation(() => {
|
||||
hoverHeader = false
|
||||
}}
|
||||
on:mousedown|stopPropagation|capture
|
||||
})}
|
||||
onmousedowncapture={stopPropagation(bubble('mousedown'))}
|
||||
draggable="false"
|
||||
title={`Id: ${component.id}`}
|
||||
class={twMerge(
|
||||
@@ -144,8 +163,8 @@
|
||||
? 'bg-blue-300 text-blue-800'
|
||||
: 'text-white hover:bg-blue-400 hover:text-white'
|
||||
)}
|
||||
on:click={() => dispatch('fillHeight')}
|
||||
on:pointerdown|stopPropagation
|
||||
onclick={() => dispatch('fillHeight')}
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
>
|
||||
<ArrowDownFromLine aria-label="Full height" size={11} />
|
||||
</button>
|
||||
@@ -156,8 +175,8 @@
|
||||
'px-1 py-0.5 text-2xs font-bold rounded cursor-pointer w-fit h-full',
|
||||
locked ? 'bg-blue-300 text-blue-800' : 'text-white hover:bg-blue-400 hover:text-white'
|
||||
)}
|
||||
on:click={() => dispatch('lock')}
|
||||
on:pointerdown|stopPropagation
|
||||
onclick={() => dispatch('lock')}
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
>
|
||||
{#if locked}
|
||||
<Anchor aria-label="Unlock position" size={11} />
|
||||
@@ -171,8 +190,8 @@
|
||||
class={twMerge(
|
||||
'px-1 py-0.5 text-2xs font-bold rounded cursor-pointer w-fit h-full text-white hover:bg-blue-400 hover:text-white'
|
||||
)}
|
||||
on:click={() => dispatch('expand')}
|
||||
on:pointerdown|stopPropagation
|
||||
onclick={() => dispatch('expand')}
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
>
|
||||
<Expand aria-label="Expand" size={11} />
|
||||
</button>
|
||||
@@ -198,8 +217,8 @@
|
||||
? 'bg-blue-300 text-blue-800'
|
||||
: 'text-blue-600 hover:bg-blue-300 hover:text-blue-800'
|
||||
)}
|
||||
on:click={() => dispatch('triggerInlineEditor')}
|
||||
on:pointerdown|stopPropagation
|
||||
onclick={() => dispatch('triggerInlineEditor')}
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
>
|
||||
<Pen aria-label="Edit" size={11} />
|
||||
</button>
|
||||
@@ -228,13 +247,13 @@
|
||||
? 'text-red-600 hover:bg-red-300 hover:text-red-800'
|
||||
: 'text-blue-600 hover:bg-blue-300 hover:text-blue-800'
|
||||
)}
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
const element = document.getElementById(`decision-tree-graph-editor`)
|
||||
if (element) {
|
||||
element.click()
|
||||
}
|
||||
}}
|
||||
on:pointerdown|stopPropagation
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
>
|
||||
<Network size={11} />
|
||||
</button>
|
||||
@@ -264,7 +283,7 @@
|
||||
</Popover>
|
||||
{/if} -->
|
||||
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -279,14 +298,14 @@
|
||||
)}
|
||||
>
|
||||
<Popover notClickable placement="bottom" contentClasses="!bg-surface border w-96 p-4">
|
||||
<svelte:fragment slot="trigger">
|
||||
{#snippet trigger()}
|
||||
<Bug size={14} />
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
<div class="bg-surface">
|
||||
<pre class="whitespace-pre-wrap text-red-600 bg-surface border w-full p-4 text-xs mb-2"
|
||||
>{error ?? ''}
|
||||
</pre>
|
||||
</pre>
|
||||
</div>
|
||||
<Button
|
||||
color="red"
|
||||
@@ -294,7 +313,7 @@
|
||||
on:click={() => $openDebugRun?.($errorByComponent[component.id]?.id ?? '')}
|
||||
>Open Debug Runs</Button
|
||||
>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation, createBubbler } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import PanelSection from './settingsPanel/common/PanelSection.svelte'
|
||||
import { classNames, displayDate, emptyString } from '$lib/utils'
|
||||
@@ -6,21 +9,23 @@
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Skeleton } from '$lib/components/common'
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import { Pencil, ArrowRight, X, Loader2 } from 'lucide-svelte'
|
||||
|
||||
export let appPath: string | undefined
|
||||
let loading: boolean = false
|
||||
interface Props {
|
||||
appPath: string | undefined
|
||||
}
|
||||
|
||||
let versions: AppHistory[] = []
|
||||
let { appPath }: Props = $props()
|
||||
let loading: boolean = $state(false)
|
||||
|
||||
let selectedVersion: AppHistory | undefined = undefined
|
||||
let selected: (AppWithLastVersion & { value: any }) | undefined = undefined
|
||||
let versions: AppHistory[] = $state([])
|
||||
|
||||
let deploymentMsgUpdateMode = false
|
||||
let deploymentMsgUpdate: string | undefined = undefined
|
||||
let selectedVersion: AppHistory | undefined = $state(undefined)
|
||||
let selected: (AppWithLastVersion & { value: any }) | undefined = $state(undefined)
|
||||
|
||||
$: selectedVersion !== undefined && loadValue(selectedVersion.version)
|
||||
let deploymentMsgUpdateMode = $state(false)
|
||||
let deploymentMsgUpdate: string | undefined = $state(undefined)
|
||||
|
||||
async function loadVersions() {
|
||||
if (appPath === undefined) {
|
||||
@@ -65,6 +70,12 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
loadVersions()
|
||||
$effect(() => {
|
||||
selectedVersion?.version !== undefined &&
|
||||
untrack(() => {
|
||||
selectedVersion && loadValue(selectedVersion.version!)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<Splitpanes class="!overflow-visible">
|
||||
@@ -75,14 +86,14 @@
|
||||
{#if versions.length > 0}
|
||||
<div class="flex gap-2 flex-col">
|
||||
{#each versions ?? [] as version}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class={classNames(
|
||||
'border flex gap-1 truncate justify-between flex-row w-full items-center p-2 rounded-md cursor-pointer hover:bg-blue-50 hover:text-blue-400',
|
||||
selectedVersion?.version == version.version ? 'bg-blue-100 text-blue-600' : ''
|
||||
)}
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
selectedVersion = version
|
||||
deploymentMsgUpdateMode = false
|
||||
deploymentMsgUpdate = undefined
|
||||
@@ -115,10 +126,11 @@
|
||||
type="text"
|
||||
bind:value={deploymentMsgUpdate}
|
||||
class="!w-auto grow"
|
||||
on:click|stopPropagation={() => {}}
|
||||
on:keydown|stopPropagation
|
||||
on:keypress|stopPropagation={({ key }) => {
|
||||
if (key === 'Enter')
|
||||
onclick={stopPropagation(() => {})}
|
||||
onkeydown={stopPropagation(bubble('keydown'))}
|
||||
onkeypress={(e) => {
|
||||
e.stopPropagation()
|
||||
if (e.key === 'Enter')
|
||||
updateDeploymentMsg(selected?.id, selectedVersion?.version)
|
||||
}}
|
||||
/>
|
||||
@@ -155,7 +167,7 @@
|
||||
Deployed {displayDate(selected.created_at)} by {selected.created_by}
|
||||
{/if}
|
||||
<button
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
deploymentMsgUpdate = selectedVersion?.deployment_msg
|
||||
deploymentMsgUpdateMode = true
|
||||
}}
|
||||
|
||||
@@ -231,7 +231,7 @@
|
||||
}}
|
||||
disableMove={!!$connectingInput.opened}
|
||||
>
|
||||
{#snippet children({ dataItem, overlapped, moveMode, componentDraggedId })}
|
||||
{#snippet children({ dataItem, overlapped, componentDraggedId })}
|
||||
<ComponentWrapper
|
||||
id={dataItem.id}
|
||||
type={dataItem.data.type}
|
||||
@@ -276,7 +276,6 @@
|
||||
$app = $app
|
||||
}}
|
||||
{overlapped}
|
||||
{moveMode}
|
||||
{componentDraggedId}
|
||||
/>
|
||||
</GridEditorMenu>
|
||||
|
||||
@@ -18,34 +18,49 @@
|
||||
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
export let items: FilledItem<T>[]
|
||||
export let rowHeight: number = ROW_HEIGHT
|
||||
export let gap = [ROW_GAP_X, ROW_GAP_Y]
|
||||
export let throttleUpdate = 100
|
||||
export let maxRow: number
|
||||
export let breakpoint: EditorBreakpoint
|
||||
interface Props {
|
||||
items: FilledItem<T>[]
|
||||
rowHeight?: number
|
||||
gap?: any
|
||||
throttleUpdate?: number
|
||||
maxRow: number
|
||||
breakpoint: EditorBreakpoint
|
||||
allIdsInPath?: string[] | undefined
|
||||
containerWidth?: number | undefined
|
||||
parentWidth?: number | undefined
|
||||
children?: import('svelte').Snippet<[any]>
|
||||
}
|
||||
|
||||
export let allIdsInPath: string[] | undefined = undefined
|
||||
export let containerWidth: number | undefined = undefined
|
||||
|
||||
export let parentWidth: number | undefined = undefined
|
||||
let {
|
||||
items = $bindable(),
|
||||
rowHeight = ROW_HEIGHT,
|
||||
gap = [ROW_GAP_X, ROW_GAP_Y],
|
||||
throttleUpdate = 100,
|
||||
maxRow,
|
||||
breakpoint,
|
||||
allIdsInPath = undefined,
|
||||
containerWidth = $bindable(undefined),
|
||||
parentWidth = undefined,
|
||||
children
|
||||
}: Props = $props()
|
||||
|
||||
const cols = columnConfiguration
|
||||
|
||||
let showSkeleton = false
|
||||
let showSkeleton = $state(false)
|
||||
|
||||
let getComputedCols: 3 | 12 | undefined =
|
||||
let getComputedCols: 3 | 12 | undefined = $state(
|
||||
$app.mobileViewOnSmallerScreens == false ? WIDE_GRID_COLUMNS : undefined
|
||||
)
|
||||
|
||||
let container
|
||||
let container = $state()
|
||||
|
||||
$: [gapX, gapY] = gap
|
||||
let [gapX, gapY] = $derived(gap)
|
||||
|
||||
let xPerPx = 0
|
||||
let xPerPx = $state(0)
|
||||
|
||||
let yPerPx = rowHeight
|
||||
|
||||
$: containerHeight = getContainerHeight(items, yPerPx, getComputedCols)
|
||||
let containerHeight = $derived(getContainerHeight(items, yPerPx, getComputedCols))
|
||||
|
||||
const onResize = throttle(() => {
|
||||
if (!getComputedCols) return
|
||||
@@ -92,7 +107,7 @@
|
||||
})
|
||||
})
|
||||
|
||||
sizeObserver.observe(container)
|
||||
sizeObserver.observe(container as Element)
|
||||
|
||||
return () => sizeObserver.disconnect()
|
||||
})
|
||||
@@ -121,7 +136,7 @@
|
||||
: ''} top: {top}px; left: {left}px;"
|
||||
>
|
||||
{#if item[getComputedCols]}
|
||||
<slot dataItem={item} item={item[getComputedCols]} />
|
||||
{@render children?.({ dataItem: item, item: item[getComputedCols] })}
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import TestJobLoader from '$lib/components/TestJobLoader.svelte'
|
||||
import type { Job } from '$lib/gen'
|
||||
import RunnableJobPanelInner from './RunnableJobPanelInner.svelte'
|
||||
|
||||
export let float: boolean = true
|
||||
export let hidden: boolean = false
|
||||
export let testJob: Job | undefined = undefined
|
||||
export let jobToWatch: { componentId: string; job: string } | undefined = undefined
|
||||
export let width: number | undefined = undefined
|
||||
interface Props {
|
||||
float?: boolean
|
||||
hidden?: boolean
|
||||
testJob?: Job | undefined
|
||||
jobToWatch?: { componentId: string; job: string } | undefined
|
||||
width?: number | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
float = true,
|
||||
hidden = false,
|
||||
testJob = $bindable(undefined),
|
||||
jobToWatch = $bindable(undefined),
|
||||
width = undefined
|
||||
}: Props = $props()
|
||||
|
||||
const { runnableJobEditorPanel, selectedComponentInEditor } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
let testIsLoading = false
|
||||
let testIsLoading = $state(false)
|
||||
|
||||
let testJobLoader: TestJobLoader
|
||||
|
||||
$: ($runnableJobEditorPanel.focused || !float) &&
|
||||
$selectedComponentInEditor &&
|
||||
$runnableJobEditorPanel.jobs &&
|
||||
updateSelectedJob()
|
||||
let testJobLoader: TestJobLoader | undefined = $state()
|
||||
|
||||
function updateSelectedJob() {
|
||||
const selectedComponent = $selectedComponentInEditor
|
||||
@@ -45,13 +50,21 @@
|
||||
|
||||
let logDrawerOpen = false
|
||||
let resultDrawerOpen = false
|
||||
$effect(() => {
|
||||
;($runnableJobEditorPanel.focused || !float) &&
|
||||
$selectedComponentInEditor &&
|
||||
$runnableJobEditorPanel.jobs &&
|
||||
untrack(() => {
|
||||
updateSelectedJob()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<TestJobLoader bind:this={testJobLoader} bind:isLoading={testIsLoading} bind:job={testJob} />
|
||||
|
||||
{#if ($runnableJobEditorPanel.focused && $selectedComponentInEditor) || logDrawerOpen || resultDrawerOpen || !float}
|
||||
{@const frontendJob = $runnableJobEditorPanel?.frontendJobs[$selectedComponentInEditor ?? '']}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
{#if float}
|
||||
<div
|
||||
class="absolute z-[100] top-0 right-0 border-t h-full"
|
||||
|
||||
@@ -5,12 +5,16 @@
|
||||
import type { Job } from '$lib/gen'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
|
||||
export let frontendJob: boolean | any = false
|
||||
export let testJob: Job | any = undefined
|
||||
export let testIsLoading = false
|
||||
interface Props {
|
||||
frontendJob?: boolean | any
|
||||
testJob?: Job | any
|
||||
testIsLoading?: boolean
|
||||
}
|
||||
|
||||
let logDrawerOpen = false
|
||||
let resultDrawerOpen = false
|
||||
let { frontendJob = false, testJob = undefined, testIsLoading = false }: Props = $props()
|
||||
|
||||
let logDrawerOpen = $state(false)
|
||||
let resultDrawerOpen = $state(false)
|
||||
</script>
|
||||
|
||||
<Splitpanes horizontal>
|
||||
|
||||
@@ -109,58 +109,37 @@
|
||||
</script>
|
||||
|
||||
{#if gridItemWithLocation}
|
||||
{#key gridItemWithLocation.item.id}
|
||||
<ComponentPanel
|
||||
bind:componentSettings={
|
||||
() => gridItemWithLocation,
|
||||
(cs) => {
|
||||
if (gridItemWithLocation?.location.type === 'grid') {
|
||||
$app.grid[gridItemWithLocation.location.gridItemIndex] = cs.item
|
||||
} else if (
|
||||
gridItemWithLocation?.location.type === 'subgrid' &&
|
||||
Array.isArray($app.subgrids?.[gridItemWithLocation.location.subgridKey])
|
||||
) {
|
||||
if (
|
||||
$app.subgrids[gridItemWithLocation.location.subgridKey][
|
||||
gridItemWithLocation.location.subgridItemIndex
|
||||
]
|
||||
) {
|
||||
$app.subgrids[gridItemWithLocation.location.subgridKey][
|
||||
gridItemWithLocation.location.subgridItemIndex
|
||||
] = cs.item
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onDelete={() => {
|
||||
dispatch('delete')
|
||||
}}
|
||||
/>
|
||||
{/key}
|
||||
{#if gridItemWithLocation.location.type === 'grid'}
|
||||
{#each $app.grid as gridItem, gridItemIndex}
|
||||
{#if gridItem.data.id === gridItemWithLocation.item.id}
|
||||
<ComponentPanel
|
||||
bind:item={$app.grid[gridItemIndex]}
|
||||
parent={gridItemWithLocation.parent}
|
||||
onDelete={() => {
|
||||
dispatch('delete')
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{:else if gridItemWithLocation.location.type === 'subgrid' && $app.subgrids}
|
||||
{#each $app.subgrids[gridItemWithLocation.location.subgridKey] as subgridItem, subgridItemIndex}
|
||||
{#if subgridItem.data.id === gridItemWithLocation.item.id}
|
||||
<ComponentPanel
|
||||
bind:item={$app.subgrids[gridItemWithLocation.location.subgridKey][subgridItemIndex]}
|
||||
parent={gridItemWithLocation.parent}
|
||||
onDelete={() => {
|
||||
dispatch('delete')
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
{:else if tableActionSettings}
|
||||
{#key tableActionSettings?.item?.data?.id}
|
||||
<ComponentPanel
|
||||
noGrid
|
||||
bind:componentSettings={
|
||||
() => tableActionSettings,
|
||||
(cs) => {
|
||||
if (tableActionSettings) {
|
||||
if (tableActionSettings.gridItemLocation.type === 'grid') {
|
||||
const { gridItemIndex } = tableActionSettings.gridItemLocation
|
||||
const { key, index } = tableActionSettings.location
|
||||
if ($app.grid[gridItemIndex]?.data?.[key]) {
|
||||
$app.grid[gridItemIndex].data[key][index] = cs.item.data
|
||||
}
|
||||
} else if (tableActionSettings.gridItemLocation.type === 'subgrid') {
|
||||
const { subgridKey, subgridItemIndex } = tableActionSettings.gridItemLocation
|
||||
const { key, index } = tableActionSettings.location
|
||||
if ($app.subgrids?.[subgridKey]?.[subgridItemIndex]?.data?.[key]) {
|
||||
$app.subgrids[subgridKey][subgridItemIndex].data[key][index] = cs.item.data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bind:item={tableActionSettings.item}
|
||||
parent={tableActionSettings.parent}
|
||||
duplicateMoveAllowed={false}
|
||||
onDelete={() => {
|
||||
if (tableActionSettings) {
|
||||
@@ -209,24 +188,8 @@
|
||||
{#key menuItemsSettings?.item?.id}
|
||||
<ComponentPanel
|
||||
noGrid
|
||||
bind:componentSettings={
|
||||
() => menuItemsSettings,
|
||||
(cs) => {
|
||||
if (menuItemsSettings) {
|
||||
if (menuItemsSettings.gridItemLocation.type === 'grid') {
|
||||
const { gridItemIndex } = menuItemsSettings.gridItemLocation
|
||||
if ($app.grid[gridItemIndex]?.data?.type === 'menucomponent') {
|
||||
$app.grid[gridItemIndex].data.menuItems[cs.index] = cs.item.data
|
||||
}
|
||||
} else if (menuItemsSettings.gridItemLocation.type === 'subgrid') {
|
||||
const { subgridKey, subgridItemIndex } = menuItemsSettings.gridItemLocation
|
||||
if ($app.subgrids?.[subgridKey]?.[subgridItemIndex]?.data?.type === 'menucomponent') {
|
||||
$app.subgrids[subgridKey][subgridItemIndex].data.menuItems[cs.index] = cs.item.data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bind:item={menuItemsSettings.item}
|
||||
parent={menuItemsSettings.parent}
|
||||
onDelete={() => {
|
||||
if (menuItemsSettings) {
|
||||
const item = findGridItemWithLocation($app, menuItemsSettings.parent)
|
||||
|
||||
@@ -268,7 +268,7 @@
|
||||
}}
|
||||
disableMove={!!$connectingInput.opened}
|
||||
>
|
||||
{#snippet children({ dataItem, overlapped, moveMode, componentDraggedId })}
|
||||
{#snippet children({ dataItem, overlapped, componentDraggedId })}
|
||||
<ComponentWrapper
|
||||
id={dataItem.id}
|
||||
type={dataItem.data.type}
|
||||
@@ -314,7 +314,6 @@
|
||||
}
|
||||
$app = $app
|
||||
}}
|
||||
{moveMode}
|
||||
{componentDraggedId}
|
||||
/>
|
||||
</GridEditorMenu>
|
||||
|
||||
@@ -6,7 +6,8 @@ import type {
|
||||
EditorBreakpoint,
|
||||
FocusedGrid,
|
||||
GeneralAppInput,
|
||||
GridItem
|
||||
GridItem,
|
||||
RichConfiguration
|
||||
} from '../types'
|
||||
import {
|
||||
ccomponents,
|
||||
@@ -38,14 +39,14 @@ import gridHelp from '../svelte-grid/utils/helper'
|
||||
|
||||
type GridItemLocation =
|
||||
| {
|
||||
type: 'grid'
|
||||
gridItemIndex: number
|
||||
}
|
||||
type: 'grid'
|
||||
gridItemIndex: number
|
||||
}
|
||||
| {
|
||||
type: 'subgrid'
|
||||
subgridItemIndex: number
|
||||
subgridKey: string
|
||||
}
|
||||
type: 'subgrid'
|
||||
subgridItemIndex: number
|
||||
subgridKey: string
|
||||
}
|
||||
interface GridItemWithLocation {
|
||||
location: GridItemLocation
|
||||
item: GridItem
|
||||
@@ -186,7 +187,7 @@ export function selectId(
|
||||
selectedComponent: Writable<string[] | undefined>,
|
||||
app: App
|
||||
) {
|
||||
;(document?.activeElement as HTMLElement)?.blur()
|
||||
; (document?.activeElement as HTMLElement)?.blur()
|
||||
if (e.shiftKey) {
|
||||
selectedComponent.update((old) => {
|
||||
if (old && old?.[0]) {
|
||||
@@ -482,10 +483,67 @@ export function appComponentFromType<T extends keyof typeof components>(
|
||||
horizontalAlignment: override?.horizontalAlignment ?? init.horizontalAlignment,
|
||||
verticalAlignment: override?.verticalAlignment ?? init.verticalAlignment,
|
||||
id,
|
||||
datasets:
|
||||
type === 'plotlycomponentv2'
|
||||
? createPlotlyComponentDataset()
|
||||
: type === 'chartjscomponentv2'
|
||||
? createChartjsComponentDataset()
|
||||
: undefined,
|
||||
xData:
|
||||
type === 'plotlycomponentv2' || type === 'chartjscomponentv2'
|
||||
? {
|
||||
type: 'evalv2',
|
||||
fieldType: 'array',
|
||||
expr: '[1, 2, 3, 4]',
|
||||
connections: []
|
||||
}
|
||||
: undefined,
|
||||
...(extra ?? {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createChartjsComponentDataset(): RichConfiguration {
|
||||
return {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'chartjs',
|
||||
value: [
|
||||
{
|
||||
value: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'number',
|
||||
value: [25, 25, 50]
|
||||
},
|
||||
name: 'Dataset 1'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export function createPlotlyComponentDataset(): RichConfiguration {
|
||||
return {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'plotly',
|
||||
value: [
|
||||
{
|
||||
value: {
|
||||
type: 'static',
|
||||
fieldType: 'array',
|
||||
subFieldType: 'number',
|
||||
value: [1, 2, 3, 4]
|
||||
},
|
||||
name: 'Dataset 1',
|
||||
aggregation_method: 'sum',
|
||||
type: 'bar',
|
||||
tooltip: '',
|
||||
color: '#C8A2C8'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
export function insertNewGridItem(
|
||||
app: App,
|
||||
builddata: (id: string) => AppComponent,
|
||||
@@ -845,33 +903,33 @@ export type InitConfig<
|
||||
| EvalAppInput
|
||||
| EvalV2AppInput
|
||||
| {
|
||||
type: 'oneOf'
|
||||
selected: string
|
||||
configuration: Record<
|
||||
string,
|
||||
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput>
|
||||
>
|
||||
}
|
||||
type: 'oneOf'
|
||||
selected: string
|
||||
configuration: Record<
|
||||
string,
|
||||
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput>
|
||||
>
|
||||
}
|
||||
>
|
||||
> = {
|
||||
[Property in keyof T]: T[Property] extends StaticAppInput
|
||||
[Property in keyof T]: T[Property] extends StaticAppInput
|
||||
? T[Property]['value'] | undefined
|
||||
: T[Property] extends { type: 'oneOf' }
|
||||
? {
|
||||
type: 'oneOf'
|
||||
selected: keyof T[Property]['configuration']
|
||||
configuration: {
|
||||
[Choice in keyof T[Property]['configuration']]: {
|
||||
[IT in keyof T[Property]['configuration'][Choice]]: T[Property]['configuration'][Choice][IT] extends StaticAppInput
|
||||
? T[Property]['configuration'][Choice][IT] extends StaticAppInputOnDemand
|
||||
? () => Promise<T[Property]['configuration'][Choice][IT]['value'] | undefined>
|
||||
: T[Property]['configuration'][Choice][IT]['value'] | undefined
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
? {
|
||||
type: 'oneOf'
|
||||
selected: keyof T[Property]['configuration']
|
||||
configuration: {
|
||||
[Choice in keyof T[Property]['configuration']]: {
|
||||
[IT in keyof T[Property]['configuration'][Choice]]: T[Property]['configuration'][Choice][IT] extends StaticAppInput
|
||||
? T[Property]['configuration'][Choice][IT] extends StaticAppInputOnDemand
|
||||
? () => Promise<T[Property]['configuration'][Choice][IT]['value'] | undefined>
|
||||
: T[Property]['configuration'][Choice][IT]['value'] | undefined
|
||||
: undefined
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
|
||||
export function initConfig<
|
||||
T extends Record<
|
||||
@@ -880,13 +938,13 @@ export function initConfig<
|
||||
| EvalAppInput
|
||||
| EvalV2AppInput
|
||||
| {
|
||||
type: 'oneOf'
|
||||
selected: string
|
||||
configuration: Record<
|
||||
string,
|
||||
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput>
|
||||
>
|
||||
}
|
||||
type: 'oneOf'
|
||||
selected: string
|
||||
configuration: Record<
|
||||
string,
|
||||
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput>
|
||||
>
|
||||
}
|
||||
>
|
||||
>(
|
||||
r: T,
|
||||
@@ -894,13 +952,13 @@ export function initConfig<
|
||||
string,
|
||||
| StaticAppInput
|
||||
| {
|
||||
type: 'oneOf'
|
||||
selected: string
|
||||
configuration: Record<
|
||||
string,
|
||||
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput | boolean>
|
||||
>
|
||||
}
|
||||
type: 'oneOf'
|
||||
selected: string
|
||||
configuration: Record<
|
||||
string,
|
||||
Record<string, StaticAppInput | EvalAppInput | EvalV2AppInput | boolean>
|
||||
>
|
||||
}
|
||||
| any
|
||||
>
|
||||
): InitConfig<T> {
|
||||
@@ -910,31 +968,31 @@ export function initConfig<
|
||||
Object.entries(r).map(([key, value]) =>
|
||||
value.type == 'static'
|
||||
? [
|
||||
key,
|
||||
configuration?.[key]?.type == 'static' ? configuration?.[key]?.['value'] : undefined
|
||||
]
|
||||
key,
|
||||
configuration?.[key]?.type == 'static' ? configuration?.[key]?.['value'] : undefined
|
||||
]
|
||||
: value.type == 'oneOf'
|
||||
? [
|
||||
key,
|
||||
{
|
||||
selected: value.selected,
|
||||
type: 'oneOf',
|
||||
configuration: Object.fromEntries(
|
||||
Object.entries(value.configuration).map(([choice, config]) => {
|
||||
const conf = initConfig(
|
||||
config,
|
||||
configuration?.[key]?.configuration?.[choice]
|
||||
)
|
||||
Object.entries(config).forEach(([innerKey, innerValue]) => {
|
||||
if (innerValue.type === 'static' && !(innerKey in conf)) {
|
||||
conf[innerKey] = innerValue.value
|
||||
}
|
||||
})
|
||||
return [choice, conf]
|
||||
key,
|
||||
{
|
||||
selected: value.selected,
|
||||
type: 'oneOf',
|
||||
configuration: Object.fromEntries(
|
||||
Object.entries(value.configuration).map(([choice, config]) => {
|
||||
const conf = initConfig(
|
||||
config,
|
||||
configuration?.[key]?.configuration?.[choice]
|
||||
)
|
||||
Object.entries(config).forEach(([innerKey, innerValue]) => {
|
||||
if (innerValue.type === 'static' && !(innerKey in conf)) {
|
||||
conf[innerKey] = innerValue.value
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
]
|
||||
return [choice, conf]
|
||||
})
|
||||
)
|
||||
}
|
||||
]
|
||||
: [key, undefined]
|
||||
)
|
||||
) as any
|
||||
|
||||
@@ -5,19 +5,31 @@
|
||||
import type { AppComponent } from './components'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
export let locked: boolean = false
|
||||
export let render: boolean
|
||||
export let fullHeight: boolean
|
||||
export let overlapped: string | undefined = undefined
|
||||
export let componentDraggedId: string | undefined = undefined
|
||||
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
export let moveMode: string | undefined = undefined
|
||||
let everRender = render
|
||||
interface Props {
|
||||
component: AppComponent
|
||||
selected: boolean
|
||||
locked?: boolean
|
||||
render: boolean
|
||||
fullHeight: boolean
|
||||
overlapped?: string | undefined
|
||||
componentDraggedId?: string | undefined
|
||||
}
|
||||
|
||||
$: render && !everRender && (everRender = true)
|
||||
let {
|
||||
component,
|
||||
selected,
|
||||
locked = false,
|
||||
render,
|
||||
fullHeight,
|
||||
overlapped = undefined,
|
||||
componentDraggedId = undefined
|
||||
}: Props = $props()
|
||||
let everRender = $state(render)
|
||||
|
||||
$effect(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if everRender || $app.eagerRendering}
|
||||
@@ -25,7 +37,6 @@
|
||||
on:expand
|
||||
on:lock
|
||||
on:fillHeight
|
||||
{moveMode}
|
||||
{componentDraggedId}
|
||||
{overlapped}
|
||||
{render}
|
||||
|
||||
@@ -94,7 +94,11 @@
|
||||
}: Props = $props()
|
||||
</script>
|
||||
|
||||
<svelte:boundary>
|
||||
<svelte:boundary
|
||||
onerror={(e) => {
|
||||
console.error(e)
|
||||
}}
|
||||
>
|
||||
{#if component.type === 'displaycomponent'}
|
||||
<AppDisplayComponent
|
||||
id={component.id}
|
||||
@@ -217,8 +221,6 @@
|
||||
customCss={component.customCss}
|
||||
bind:initializing
|
||||
componentInput={component.componentInput}
|
||||
datasets={component.datasets}
|
||||
xData={component.xData}
|
||||
{render}
|
||||
/>
|
||||
{:else if component.type === 'agchartscomponentee'}
|
||||
@@ -228,8 +230,6 @@
|
||||
customCss={component.customCss}
|
||||
bind:initializing
|
||||
componentInput={component.componentInput}
|
||||
datasets={component.datasets}
|
||||
xData={component.xData}
|
||||
license={component.license}
|
||||
ee={true}
|
||||
{render}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts" context="module">
|
||||
<script lang="ts" module>
|
||||
let outTimeout: NodeJS.Timeout | undefined = undefined
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import { getContext, onMount, untrack } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { AppEditorContext, AppViewerContext } from '../../types'
|
||||
import ComponentHeader from '../ComponentHeader.svelte'
|
||||
@@ -12,17 +14,29 @@
|
||||
import { Anchor } from 'lucide-svelte'
|
||||
import { findGridItemParentGrid, isContainer } from '../appUtils'
|
||||
import ComponentInner from './ComponentInner.svelte'
|
||||
import { moveMode } from '../../gridUtils'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
export let locked: boolean = false
|
||||
export let fullHeight: boolean
|
||||
export let overlapped: string | undefined = undefined
|
||||
export let moveMode: string | undefined = undefined
|
||||
export let componentDraggedId: string | undefined = undefined
|
||||
export let render: boolean = false
|
||||
interface Props {
|
||||
component: AppComponent
|
||||
selected: boolean
|
||||
locked?: boolean
|
||||
fullHeight: boolean
|
||||
overlapped?: string | undefined
|
||||
componentDraggedId?: string | undefined
|
||||
render?: boolean
|
||||
}
|
||||
|
||||
let initializing: boolean | undefined
|
||||
let {
|
||||
component,
|
||||
selected,
|
||||
locked = false,
|
||||
fullHeight,
|
||||
overlapped = undefined,
|
||||
componentDraggedId = undefined,
|
||||
render = false
|
||||
}: Props = $props()
|
||||
|
||||
let initializing: boolean | undefined = $state()
|
||||
|
||||
const { mode, app, hoverStore, connectingInput } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
@@ -31,15 +45,16 @@
|
||||
const componentActive = editorContext?.componentActive
|
||||
|
||||
const movingcomponents = editorContext?.movingcomponents
|
||||
$: ismoving =
|
||||
let ismoving = $derived(
|
||||
movingcomponents != undefined && $mode == 'dnd' && $movingcomponents?.includes(component.id)
|
||||
)
|
||||
|
||||
let errorHandledByComponent: boolean = false
|
||||
let componentContainerHeight: number = 0
|
||||
let componentContainerWidth: number = 0
|
||||
let errorHandledByComponent: boolean = $state(false)
|
||||
let componentContainerHeight: number = $state(0)
|
||||
let componentContainerWidth: number = $state(0)
|
||||
|
||||
let inlineEditorOpened: boolean = false
|
||||
let showSkeleton = false
|
||||
let inlineEditorOpened: boolean = $state(false)
|
||||
let showSkeleton = $state(false)
|
||||
|
||||
onMount(() => {
|
||||
setTimeout(() => {
|
||||
@@ -74,8 +89,8 @@
|
||||
)
|
||||
}
|
||||
|
||||
let cachedComponentDraggedIsNotChild: boolean | undefined
|
||||
let cachedAreOnTheSameSubgrid: boolean | undefined
|
||||
let cachedComponentDraggedIsNotChild: boolean | undefined = $state()
|
||||
let cachedAreOnTheSameSubgrid: boolean | undefined = $state()
|
||||
|
||||
function updateCache(componentDraggedId: string | undefined) {
|
||||
if (componentDraggedId) {
|
||||
@@ -90,19 +105,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: updateCache(componentDraggedId)
|
||||
$effect(() => {
|
||||
componentDraggedId
|
||||
untrack(() => {
|
||||
updateCache(componentDraggedId)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
on:mouseover|stopPropagation={() => {
|
||||
onmouseover={stopPropagation(() => {
|
||||
outTimeout && clearTimeout(outTimeout)
|
||||
if (component.id !== $hoverStore) {
|
||||
$hoverStore = component.id
|
||||
}
|
||||
}}
|
||||
on:mouseout|stopPropagation={mouseOut}
|
||||
})}
|
||||
onmouseout={stopPropagation(mouseOut)}
|
||||
class={twMerge(
|
||||
'h-full flex flex-col w-full component relative',
|
||||
initializing ? 'overflow-hidden h-0' : ''
|
||||
@@ -110,7 +130,7 @@
|
||||
data-connection-button
|
||||
>
|
||||
{#if render}
|
||||
{#if locked && componentActive && $componentActive && moveMode === 'move' && componentDraggedId && componentDraggedId !== component.id && cachedAreOnTheSameSubgrid}
|
||||
{#if locked && componentActive && $componentActive && $moveMode === 'move' && componentDraggedId && componentDraggedId !== component.id && cachedAreOnTheSameSubgrid}
|
||||
<div
|
||||
class={twMerge('absolute inset-0 bg-locked center-center flex-col z-50', 'bg-locked-hover')}
|
||||
>
|
||||
@@ -119,7 +139,7 @@
|
||||
<div class="text-xs"> Anchored: The component cannot be moved. </div>
|
||||
</div>
|
||||
</div>
|
||||
{:else if moveMode === 'insert' && isContainer(component.type) && componentDraggedId && componentDraggedId !== component.id && cachedComponentDraggedIsNotChild}
|
||||
{:else if $moveMode === 'insert' && isContainer(component.type) && componentDraggedId && componentDraggedId !== component.id && cachedComponentDraggedIsNotChild}
|
||||
<div
|
||||
class={twMerge(
|
||||
'absolute inset-0 flex-col rounded-md bg-blue-100 dark:bg-gray-800 bg-opacity-50',
|
||||
@@ -162,7 +182,7 @@
|
||||
<div class="absolute -top-8 w-40">
|
||||
<button
|
||||
class="border p-0.5 text-xs"
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
$movingcomponents = undefined
|
||||
}}
|
||||
>
|
||||
@@ -202,19 +222,19 @@
|
||||
</div>
|
||||
</div>
|
||||
{#if initializing && render && showSkeleton}
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
on:mouseover|stopPropagation={() => {
|
||||
onmouseover={stopPropagation(() => {
|
||||
if (component.id !== $hoverStore) {
|
||||
$hoverStore = component.id
|
||||
}
|
||||
}}
|
||||
on:mouseout|stopPropagation={() => {
|
||||
})}
|
||||
onmouseout={stopPropagation(() => {
|
||||
if ($hoverStore !== undefined) {
|
||||
$hoverStore = undefined
|
||||
}
|
||||
}}
|
||||
})}
|
||||
class="absolute inset-0 center-center flex-col border animate-skeleton dark:bg-frost-900/50 [animation-delay:1000ms]"
|
||||
></div>
|
||||
{/if}
|
||||
|
||||
@@ -3,8 +3,14 @@
|
||||
import type { AppViewerContext, ContextPanelContext } from '../../types'
|
||||
import { dfs, selectId } from '../appUtils'
|
||||
|
||||
export let id: string
|
||||
export let type: string
|
||||
interface Props {
|
||||
id: string
|
||||
type: string
|
||||
class: string
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { id, type, class: clazz, children }: Props = $props()
|
||||
|
||||
const { app, connectingInput, selectedComponent } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
@@ -40,34 +46,34 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class={$$props.class}
|
||||
on:pointerover={(e) => {
|
||||
class={clazz}
|
||||
onpointerover={(e) => {
|
||||
if ($connectingInput.opened && $connectingInput.hoveredComponent !== id) {
|
||||
$connectingInput.hoveredComponent = id
|
||||
}
|
||||
e.stopPropagation()
|
||||
}}
|
||||
on:pointerleave={(e) => {
|
||||
onpointerleave={(e) => {
|
||||
if ($connectingInput.opened) {
|
||||
$connectingInput.hoveredComponent = undefined
|
||||
e.stopPropagation()
|
||||
}
|
||||
}}
|
||||
on:focus={(e) => {
|
||||
onfocus={(e) => {
|
||||
if ($connectingInput.opened) {
|
||||
e.stopPropagation()
|
||||
}
|
||||
}}
|
||||
on:pointerdown={onPointerDown}
|
||||
on:click|capture={(event) =>
|
||||
onpointerdown={onPointerDown}
|
||||
onclickcapture={(event) =>
|
||||
preventInteraction(event, type === 'tabscomponent' || type === 'steppercomponent')}
|
||||
on:drag|capture={preventInteraction}
|
||||
on:pointerup|capture={(event) =>
|
||||
ondragcapture={preventInteraction}
|
||||
onpointerupcapture={(event) =>
|
||||
preventInteraction(event, type === 'tabscomponent' || type === 'steppercomponent')}
|
||||
>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
|
||||
@@ -972,7 +972,27 @@ const agchartscomponentconst = {
|
||||
},
|
||||
initialData: {
|
||||
configuration: {},
|
||||
componentInput: undefined
|
||||
componentInput: {
|
||||
type: 'evalv2',
|
||||
noStatic: true,
|
||||
fieldType: 'object',
|
||||
expr: `({
|
||||
data: [
|
||||
{ x: 1, y: 5 },
|
||||
{ x: 2, y: 10 },
|
||||
{ x: 3, y: 2 },
|
||||
{ x: 4, y: 8 }
|
||||
],
|
||||
series: [{
|
||||
type: 'bar',
|
||||
xKey: 'x',
|
||||
yKey: 'y',
|
||||
fill: '#C8A2C8',
|
||||
strokeWidth: 2.5
|
||||
}]
|
||||
})`,
|
||||
connections: [] as InputConnectionEval[]
|
||||
}
|
||||
}
|
||||
} as const
|
||||
|
||||
@@ -1628,8 +1648,8 @@ export const components = {
|
||||
backgroundColor: ['#FF6384', '#4BC0C0', '#FFCE56']
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
chartjscomponentv2: {
|
||||
@@ -1656,7 +1676,20 @@ export const components = {
|
||||
tooltip: 'ChartJs options object https://www.chartjs.org/docs/latest/general/options.html'
|
||||
}
|
||||
},
|
||||
componentInput: undefined
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'object',
|
||||
value: {
|
||||
labels: ['Pie', 'Charts', '<3'],
|
||||
datasets: [
|
||||
{
|
||||
data: [25, 50, 25],
|
||||
backgroundColor: ['#FF6384', '#4BC0C0', '#FFCE56']
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
},
|
||||
}
|
||||
},
|
||||
barchartcomponent: {
|
||||
@@ -1826,7 +1859,8 @@ This is a paragraph.
|
||||
width: 2.5
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
configuration: {
|
||||
layout: {
|
||||
@@ -1846,7 +1880,21 @@ This is a paragraph.
|
||||
dims: '2:8-6:8' as AppComponentDimensions,
|
||||
customCss: {},
|
||||
initialData: {
|
||||
componentInput: undefined,
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'object',
|
||||
value: {
|
||||
type: 'bar',
|
||||
x: [1, 2, 3, 4],
|
||||
y: [5, 10, 2, 8],
|
||||
marker: {
|
||||
color: '#C8A2C8',
|
||||
line: {
|
||||
width: 2.5
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
configuration: {
|
||||
layout: {
|
||||
type: 'static',
|
||||
@@ -1856,7 +1904,8 @@ This is a paragraph.
|
||||
'Layout options for the plot. See https://plotly.com/javascript/reference/layout/ for more information'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
timeseriescomponent: {
|
||||
name: 'Timeseries',
|
||||
|
||||
@@ -3,12 +3,16 @@
|
||||
import type { AppViewerContext, RichConfiguration } from '../../types'
|
||||
import InputsSpecEditor from '../settingsPanel/InputsSpecEditor.svelte'
|
||||
|
||||
export let evalClass: RichConfiguration
|
||||
export let key: string
|
||||
interface Props {
|
||||
evalClass: RichConfiguration
|
||||
key: string
|
||||
}
|
||||
|
||||
let { evalClass = $bindable(), key }: Props = $props()
|
||||
|
||||
const { selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
$: id = Array.isArray($selectedComponent) ? $selectedComponent[0] : $selectedComponent
|
||||
let id = $derived(Array.isArray($selectedComponent) ? $selectedComponent[0] : $selectedComponent)
|
||||
</script>
|
||||
|
||||
{#if evalClass && id}
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div slot="title" class="flex items-center">
|
||||
<div slot="titleSlot" class="flex items-center">
|
||||
<svelte:component this={icon} size={18} />
|
||||
<span class="ml-1">
|
||||
{name}
|
||||
|
||||
@@ -14,15 +14,19 @@
|
||||
import type { AppViewerContext, GridItem } from '../../types'
|
||||
import { getAllSubgridsAndComponentIds } from '../appUtils'
|
||||
|
||||
export let item: GridItem
|
||||
interface Props {
|
||||
item: GridItem
|
||||
}
|
||||
|
||||
let { item }: Props = $props()
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let groups: Array<{
|
||||
name: string
|
||||
path: string
|
||||
}> = []
|
||||
}> = $state([])
|
||||
|
||||
let loading: boolean = false
|
||||
let loading: boolean = $state(false)
|
||||
|
||||
async function getGroups() {
|
||||
loading = true
|
||||
@@ -79,7 +83,7 @@
|
||||
nameField = ''
|
||||
}
|
||||
|
||||
let nameField: string = ''
|
||||
let nameField: string = $state('')
|
||||
|
||||
getGroups()
|
||||
</script>
|
||||
|
||||
+8
-4
@@ -3,17 +3,21 @@
|
||||
import GroupList from './GroupList.svelte'
|
||||
import type { GridItem } from '../../types'
|
||||
|
||||
export let item: GridItem
|
||||
interface Props {
|
||||
item: GridItem
|
||||
}
|
||||
|
||||
let codeDrawer: Drawer
|
||||
let { item }: Props = $props()
|
||||
|
||||
let codeDrawer: Drawer | undefined = $state()
|
||||
|
||||
export async function openDrawer() {
|
||||
codeDrawer.openDrawer()
|
||||
codeDrawer?.openDrawer()
|
||||
}
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={codeDrawer}>
|
||||
<DrawerContent title="Component Groups" on:close={codeDrawer.closeDrawer}>
|
||||
<DrawerContent title="Component Groups" on:close={() => codeDrawer?.closeDrawer()}>
|
||||
<GroupList {item} />
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
@@ -1,29 +1,52 @@
|
||||
<script lang="ts">
|
||||
import { preventDefault } from 'svelte/legacy'
|
||||
|
||||
import { slide } from 'svelte/transition'
|
||||
import { ChevronDown } from 'lucide-svelte'
|
||||
import { isOpenStore } from './store'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
|
||||
|
||||
export let title: string
|
||||
export let prefix: string | undefined = undefined
|
||||
export let openByDefault: boolean = false
|
||||
export let wrapperClasses = ''
|
||||
export let toggleClasses = ''
|
||||
export let contentWrapperClasses = ''
|
||||
export let isOpen = false
|
||||
export let tooltip: string | undefined = undefined
|
||||
export let documentationLink: string | undefined = undefined
|
||||
export let subtitle: string | undefined = undefined
|
||||
interface Props {
|
||||
title: string
|
||||
prefix?: string | undefined
|
||||
openByDefault?: boolean
|
||||
wrapperClasses?: string
|
||||
toggleClasses?: string
|
||||
contentWrapperClasses?: string
|
||||
isOpen?: boolean
|
||||
tooltip?: string | undefined
|
||||
documentationLink?: string | undefined
|
||||
subtitle?: string | undefined
|
||||
titleSlot?: import('svelte').Snippet
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let {
|
||||
title,
|
||||
prefix = undefined,
|
||||
openByDefault = false,
|
||||
wrapperClasses = '',
|
||||
toggleClasses = '',
|
||||
contentWrapperClasses = '',
|
||||
isOpen = $bindable(false),
|
||||
tooltip = undefined,
|
||||
documentationLink = undefined,
|
||||
subtitle = undefined,
|
||||
titleSlot,
|
||||
children
|
||||
}: Props = $props()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const dispatchIfMounted = createDispatcherIfMounted(dispatch)
|
||||
|
||||
$: storeTitle = prefix + title
|
||||
$: isOpen = prefix ? $isOpenStore[storeTitle] : true
|
||||
let storeTitle = $derived(prefix + title)
|
||||
$effect(() => {
|
||||
isOpen = prefix ? $isOpenStore[storeTitle] : true
|
||||
})
|
||||
|
||||
$: dispatchIfMounted('open', isOpen)
|
||||
$effect(() => {
|
||||
dispatch('open', isOpen)
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
if (prefix !== undefined && !(prefix + title in $isOpenStore)) {
|
||||
@@ -35,19 +58,19 @@
|
||||
<section class="pt-1 pb-2 px-1 {wrapperClasses}">
|
||||
{#if prefix !== undefined}
|
||||
<button
|
||||
on:click|preventDefault={() => isOpenStore.toggle(storeTitle)}
|
||||
onclick={preventDefault(() => isOpenStore.toggle(storeTitle))}
|
||||
class="w-full flex justify-between items-center text-secondary px-2 py-1
|
||||
rounded-sm duration-200 hover:bg-surface-hover {toggleClasses}"
|
||||
>
|
||||
<h1 class="text-sm font-semibold text-left">
|
||||
<slot name="title">
|
||||
{#if titleSlot}{@render titleSlot()}{:else}
|
||||
{title}
|
||||
{#if subtitle}
|
||||
<span class="text-2xs text-tertiary ml-1">
|
||||
{subtitle}
|
||||
</span>
|
||||
{/if}
|
||||
</slot>
|
||||
{/if}
|
||||
{#if tooltip}
|
||||
<Tooltip class="ml-1" {documentationLink}>{tooltip}</Tooltip>
|
||||
{/if}
|
||||
@@ -56,25 +79,25 @@
|
||||
</button>
|
||||
{#if isOpen}
|
||||
<div transition:slide|local={{ duration: 300 }} class="px-2 {contentWrapperClasses}">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<h1 class="text-base font-semibold text-left px-2 py-1 text-secondary">
|
||||
<slot name="title">
|
||||
{#if titleSlot}{@render titleSlot()}{:else}
|
||||
{title}
|
||||
{#if subtitle}
|
||||
<span class="text-2xs text-tertiary ml-1">
|
||||
{subtitle}
|
||||
</span>
|
||||
{/if}
|
||||
</slot>
|
||||
{/if}
|
||||
{#if tooltip}
|
||||
<Tooltip class="ml-1" {documentationLink}>{tooltip}</Tooltip>
|
||||
{/if}
|
||||
</h1>
|
||||
<div class="px-2">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
@@ -4,13 +4,17 @@
|
||||
import { Pen } from 'lucide-svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let kind: string
|
||||
export let row: {
|
||||
name: string
|
||||
path: string
|
||||
interface Props {
|
||||
kind: string
|
||||
row: {
|
||||
name: string
|
||||
path: string
|
||||
}
|
||||
}
|
||||
|
||||
let editedName = row.name
|
||||
let { kind, row }: Props = $props()
|
||||
|
||||
let editedName = $state(row.name)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
function onkeydown(e) {
|
||||
@@ -21,18 +25,18 @@
|
||||
</script>
|
||||
|
||||
<Popover floatingConfig={{ strategy: 'absolute', placement: 'bottom-end' }}>
|
||||
<svelte:fragment slot="trigger">
|
||||
{#snippet trigger()}
|
||||
<Button color="light" size="xs2" nonCaptureEvent={true}>
|
||||
<div class="flex flex-row gap-1 items-center">
|
||||
<Pen size={16} />
|
||||
</div>
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content" let:close>
|
||||
{/snippet}
|
||||
{#snippet content({ close })}
|
||||
<div class="flex flex-col w-80 gap-2 p-4">
|
||||
<div class="leading-6 font-semibold text-xs">Edit {kind} name</div>
|
||||
<div class="flex flex-row gap-2">
|
||||
<input on:keydown={onkeydown} bind:value={editedName} />
|
||||
<input {onkeydown} bind:value={editedName} />
|
||||
<Button
|
||||
color="dark"
|
||||
size="xs"
|
||||
@@ -45,5 +49,5 @@
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
{isOpen[prefix] ? '!bg-surface-secondary hover:!bg-surface-hover' : ''}"
|
||||
>
|
||||
<!-- @migration-task: migrate this slot by hand, `title` would shadow a prop on the parent component -->
|
||||
<svelte:fragment slot="title">
|
||||
<svelte:fragment slot="titleSlot">
|
||||
<span class="font-normal text-xs">
|
||||
{group}
|
||||
</span>
|
||||
|
||||
@@ -5,10 +5,15 @@
|
||||
import { onMount } from 'svelte'
|
||||
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
|
||||
export let theme: AppTheme | undefined = undefined
|
||||
interface Props {
|
||||
theme?: AppTheme | undefined
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let code: string | undefined = undefined
|
||||
let cssEditor: SimpleEditor | undefined = undefined
|
||||
let { theme = undefined, children }: Props = $props()
|
||||
|
||||
let code: string | undefined = $state(undefined)
|
||||
let cssEditor: SimpleEditor | undefined = $state(undefined)
|
||||
|
||||
onMount(async () => {
|
||||
code = await resolveTheme(theme, $workspaceStore)
|
||||
@@ -18,7 +23,7 @@
|
||||
|
||||
<div class="relative h-full">
|
||||
<div class="absolute z-[100] left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%]">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
<div class="absolute top-0 left-0 right-0 bottom-0 bg-gray-100 bg-opacity-50 z-50"></div>
|
||||
<SimpleEditor
|
||||
|
||||
@@ -7,13 +7,17 @@
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import HighlightTheme from '$lib/components/HighlightTheme.svelte'
|
||||
|
||||
export let theme: AppTheme
|
||||
interface Props {
|
||||
theme: AppTheme
|
||||
}
|
||||
|
||||
let code: string | undefined = undefined
|
||||
let codeDrawer: Drawer
|
||||
let { theme }: Props = $props()
|
||||
|
||||
let code: string | undefined = $state(undefined)
|
||||
let codeDrawer: Drawer | undefined = $state()
|
||||
|
||||
export async function openDrawer() {
|
||||
codeDrawer.openDrawer()
|
||||
codeDrawer?.openDrawer()
|
||||
code = await resolveTheme(theme, $workspaceStore)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -7,12 +7,16 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
|
||||
export let row: {
|
||||
name: string
|
||||
path: string
|
||||
interface Props {
|
||||
row: {
|
||||
name: string
|
||||
path: string
|
||||
}
|
||||
}
|
||||
|
||||
let editedName = row.name
|
||||
let { row }: Props = $props()
|
||||
|
||||
let editedName = $state(row.name)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
@@ -22,14 +26,14 @@
|
||||
closeOnOtherPopoverOpen
|
||||
contentClasses="flex flex-col w-80 gap-2 p-4"
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
{#snippet trigger()}
|
||||
<Button color="light" size="xs2" nonCaptureEvent={true}>
|
||||
<div class="flex flex-row gap-1 items-center">
|
||||
<Pen size={16} />
|
||||
</div>
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content" let:close>
|
||||
{/snippet}
|
||||
{#snippet content({ close })}
|
||||
<div class="leading-6 font-semibold text-xs">Edit theme name</div>
|
||||
<div class="flex flex-row gap-2">
|
||||
<input bind:value={editedName} />
|
||||
@@ -52,5 +56,5 @@
|
||||
Update
|
||||
</Button>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
|
||||
@@ -11,18 +11,29 @@
|
||||
// @ts-ignore
|
||||
import MenuItemsOutput from './components/MenuItemsOutput.svelte'
|
||||
|
||||
export let gridItem: GridItem
|
||||
export let first: boolean = false
|
||||
export let nested: boolean = false
|
||||
export let expanded: boolean = false
|
||||
export let renderRec: boolean = true
|
||||
interface Props {
|
||||
gridItem: GridItem
|
||||
first?: boolean
|
||||
nested?: boolean
|
||||
expanded?: boolean
|
||||
renderRec?: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
gridItem,
|
||||
first = false,
|
||||
nested = false,
|
||||
expanded = false,
|
||||
renderRec = true
|
||||
}: Props = $props()
|
||||
const { connectingInput } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const name = getComponentNameById(gridItem.id)
|
||||
|
||||
$: nameOverrides =
|
||||
let nameOverrides = $derived(
|
||||
gridItem?.data?.type === 'decisiontreecomponent'
|
||||
? gridItem.data.nodes.map((n, i) => `${n.label} (Tab index ${i})`)
|
||||
: undefined
|
||||
)
|
||||
|
||||
function getComponentNameById(componentId: string) {
|
||||
if (gridItem?.data?.type) {
|
||||
@@ -36,27 +47,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: subGrids = Array.from({ length: gridItem.data?.numberOfSubgrids ?? 0 }).map(
|
||||
(_, i) => `${gridItem.id}-${i}`
|
||||
let subGrids = $derived(
|
||||
Array.from({ length: gridItem.data?.numberOfSubgrids ?? 0 }).map(
|
||||
(_, i) => `${gridItem.id}-${i}`
|
||||
)
|
||||
)
|
||||
</script>
|
||||
|
||||
<OutputHeader
|
||||
render={renderRec}
|
||||
let:render
|
||||
id={gridItem.id}
|
||||
name={getComponentNameById(gridItem.id)}
|
||||
{first}
|
||||
{nested}
|
||||
>
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
componentId={gridItem.id}
|
||||
on:select={({ detail }) => {
|
||||
connectOutput(connectingInput, gridItem?.data?.type, gridItem.data.id, detail)
|
||||
}}
|
||||
/>
|
||||
<SubGridOutput {render} {name} {nameOverrides} {expanded} {subGrids} parentId={gridItem.id} />
|
||||
<TableActionsOutput {render} {gridItem} />
|
||||
<MenuItemsOutput {render} {gridItem} />
|
||||
{#snippet children({ render })}
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
componentId={gridItem.id}
|
||||
on:select={({ detail }) => {
|
||||
connectOutput(connectingInput, gridItem?.data?.type, gridItem.data.id, detail)
|
||||
}}
|
||||
/>
|
||||
<SubGridOutput {render} {name} {nameOverrides} {expanded} {subGrids} parentId={gridItem.id} />
|
||||
<TableActionsOutput {render} {gridItem} />
|
||||
<MenuItemsOutput {render} {gridItem} />
|
||||
{/snippet}
|
||||
</OutputHeader>
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
<script lang="ts">
|
||||
import ObjectViewer from '$lib/components/propertyPicker/ObjectViewer.svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppViewerContext, ContextPanelContext } from '../../types'
|
||||
import { recursivelyFilterKeyInJSON as recursivelyFilterInJSON } from '../appUtils'
|
||||
|
||||
export let componentId: string
|
||||
export let hasContent: boolean = false
|
||||
export let suffix: string = ''
|
||||
export let render: boolean = true
|
||||
interface Props {
|
||||
componentId: string
|
||||
hasContent?: boolean
|
||||
suffix?: string
|
||||
render?: boolean
|
||||
}
|
||||
|
||||
let { componentId, hasContent = $bindable(false), suffix = '', render = true }: Props = $props()
|
||||
const { worldStore, connectingInput } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { search, hasResult } = getContext<ContextPanelContext>('ContextPanel')
|
||||
|
||||
let object = {}
|
||||
let object = $state({})
|
||||
|
||||
function subscribeToAllOutputs(observableOutputs: Record<string, Output<any>> | undefined) {
|
||||
if (observableOutputs) {
|
||||
@@ -34,9 +38,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: subscribeToAllOutputs($worldStore?.outputsById?.[componentId])
|
||||
$: filtered = recursivelyFilterInJSON(object, $search, componentId)
|
||||
$: $hasResult[componentId] = Object.keys(filtered).length > 0
|
||||
$effect(() => {
|
||||
$worldStore?.outputsById?.[componentId]
|
||||
untrack(() => {
|
||||
subscribeToAllOutputs($worldStore?.outputsById?.[componentId])
|
||||
})
|
||||
})
|
||||
let filtered = $derived(recursivelyFilterInJSON(object, $search, componentId))
|
||||
$effect(() => {
|
||||
$hasResult[componentId] = Object.keys(filtered).length > 0
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if render && object != undefined && Object.keys(object).length > 0}
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let hasState: boolean = false
|
||||
let hasState: boolean = $state(false)
|
||||
</script>
|
||||
|
||||
<PanelSection noPadding titlePadding="px-2 pt-2" title="Outputs">
|
||||
<svelte:fragment slot="action">
|
||||
{#snippet action()}
|
||||
<div class="p-0.5">
|
||||
<HideButton
|
||||
on:click={() => {
|
||||
@@ -33,7 +33,7 @@
|
||||
/>
|
||||
<DocLink docLink="https://www.windmill.dev/docs/apps/outputs" />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
<AnimatedButton
|
||||
animate={$connectingInput.opened}
|
||||
baseRadius="0px"
|
||||
@@ -57,39 +57,35 @@
|
||||
<div>
|
||||
<span class="text-xs font-semibold text-secondary p-2">State & Context</span>
|
||||
|
||||
<OutputHeader
|
||||
let:render
|
||||
selectable={false}
|
||||
id={'ctx'}
|
||||
name={'App Context'}
|
||||
first
|
||||
color="blue"
|
||||
>
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
componentId={'ctx'}
|
||||
on:select={({ detail }) => {
|
||||
$connectingInput = connectInput($connectingInput, 'ctx', detail)
|
||||
}}
|
||||
/>
|
||||
<OutputHeader selectable={false} id={'ctx'} name={'App Context'} first color="blue">
|
||||
{#snippet children({ render })}
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
componentId={'ctx'}
|
||||
on:select={({ detail }) => {
|
||||
$connectingInput = connectInput($connectingInput, 'ctx', detail)
|
||||
}}
|
||||
/>
|
||||
{/snippet}
|
||||
</OutputHeader>
|
||||
|
||||
<OutputHeader
|
||||
let:render
|
||||
selectable={false}
|
||||
id={'state'}
|
||||
name={'State'}
|
||||
color="blue"
|
||||
disabled={!hasState}
|
||||
>
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
bind:hasContent={hasState}
|
||||
componentId={'state'}
|
||||
on:select={({ detail }) => {
|
||||
$connectingInput = connectInput($connectingInput, 'state', detail)
|
||||
}}
|
||||
/>
|
||||
{#snippet children({ render })}
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
bind:hasContent={hasState}
|
||||
componentId={'state'}
|
||||
on:select={({ detail }) => {
|
||||
$connectingInput = connectInput($connectingInput, 'state', detail)
|
||||
}}
|
||||
/>
|
||||
{/snippet}
|
||||
</OutputHeader>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,31 +3,28 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
import { connectInput } from '../appUtils'
|
||||
import ComponentOutput from './ComponentOutput.svelte'
|
||||
|
||||
export let name: string | undefined = undefined
|
||||
export let parentId: string
|
||||
export let expanded: boolean = false
|
||||
export let subGrids: string[]
|
||||
export let nameOverrides: string[] | undefined = undefined
|
||||
export let render: boolean
|
||||
const { app, connectingInput, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let selected = 0
|
||||
|
||||
$: outputs = $worldStore?.outputsById[parentId] as {
|
||||
selectedTabIndex: Output<number>
|
||||
interface Props {
|
||||
name?: string | undefined
|
||||
parentId: string
|
||||
expanded?: boolean
|
||||
subGrids: string[]
|
||||
nameOverrides?: string[] | undefined
|
||||
render: boolean
|
||||
}
|
||||
|
||||
$: subgridItems = subGrids.map((k) => ({
|
||||
k,
|
||||
items: $app.subgrids?.[k] ?? []
|
||||
}))
|
||||
let {
|
||||
name = undefined,
|
||||
parentId,
|
||||
expanded = false,
|
||||
subGrids,
|
||||
nameOverrides = undefined,
|
||||
render
|
||||
}: Props = $props()
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
$: if (outputs?.selectedTabIndex) {
|
||||
subscribeToOutput()
|
||||
}
|
||||
let selected = $state(0)
|
||||
|
||||
function subscribeToOutput() {
|
||||
outputs.selectedTabIndex.subscribe(
|
||||
@@ -40,19 +37,35 @@
|
||||
selected
|
||||
)
|
||||
}
|
||||
let outputs = $derived(
|
||||
$worldStore?.outputsById[parentId] as {
|
||||
selectedTabIndex: Output<number>
|
||||
}
|
||||
)
|
||||
let subgridItems = $derived(
|
||||
subGrids.map((k) => ({
|
||||
k,
|
||||
items: $app.subgrids?.[k] ?? []
|
||||
}))
|
||||
)
|
||||
$effect(() => {
|
||||
if (outputs?.selectedTabIndex) {
|
||||
subscribeToOutput()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each subgridItems as { k, items }, index (k)}
|
||||
<div class="ml-2 my-2">
|
||||
{#if subGrids.length > 1 && render}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class={classNames(
|
||||
'px-1 py-0.5 flex justify-between items-center font-semibold text-xs border-l border-y w-full cursor-pointer',
|
||||
selected === index ? 'bg-surface-selected' : 'bg-surface'
|
||||
)}
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
selected = index
|
||||
}}
|
||||
>
|
||||
@@ -78,9 +91,6 @@
|
||||
gridItem={subGridItem}
|
||||
first={index === 0}
|
||||
{expanded}
|
||||
on:select={({ detail }) => {
|
||||
$connectingInput = connectInput($connectingInput, subGridItem.id, detail)
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
{:else}
|
||||
|
||||
+17
-11
@@ -7,17 +7,23 @@
|
||||
|
||||
const { connectingInput } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
export let id: string
|
||||
export let name: string
|
||||
export let first: boolean = false
|
||||
interface Props {
|
||||
id: string;
|
||||
name: string;
|
||||
first?: boolean;
|
||||
}
|
||||
|
||||
let { id, name, first = false }: Props = $props();
|
||||
</script>
|
||||
|
||||
<OutputHeader let:render renamable={false} selectable={true} {id} {name} color="blue" {first}>
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
componentId={id}
|
||||
on:select={({ detail }) => {
|
||||
$connectingInput = connectInput($connectingInput, id, detail)
|
||||
}}
|
||||
/>
|
||||
<OutputHeader renamable={false} selectable={true} {id} {name} color="blue" {first}>
|
||||
{#snippet children({ render })}
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
componentId={id}
|
||||
on:select={({ detail }) => {
|
||||
$connectingInput = connectInput($connectingInput, id, detail)
|
||||
}}
|
||||
/>
|
||||
{/snippet}
|
||||
</OutputHeader>
|
||||
|
||||
@@ -8,11 +8,15 @@
|
||||
|
||||
const { app, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
export let id: string
|
||||
interface Props {
|
||||
id: string
|
||||
}
|
||||
|
||||
let { id }: Props = $props()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: reservedIds = allItems($app.grid, $app.subgrids).map((item) => item.id)
|
||||
let reservedIds = $derived(allItems($app.grid, $app.subgrids).map((item) => item.id))
|
||||
</script>
|
||||
|
||||
<Popover
|
||||
@@ -20,9 +24,9 @@
|
||||
closeOnOtherPopoverOpen
|
||||
contentClasses="p-4"
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
{#snippet trigger()}
|
||||
<button
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
$selectedComponent = [id]
|
||||
}}
|
||||
title="Edit ID"
|
||||
@@ -31,8 +35,8 @@
|
||||
>
|
||||
<Pencil size={14} />
|
||||
</button>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content" let:close>
|
||||
{/snippet}
|
||||
{#snippet content({ close })}
|
||||
<IdEditorInput
|
||||
initialId={id}
|
||||
on:close={() => close()}
|
||||
@@ -42,5 +46,5 @@
|
||||
}}
|
||||
{reservedIds}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
|
||||
+6
-2
@@ -2,8 +2,12 @@
|
||||
import type { GridItem } from '$lib/components/apps/types'
|
||||
import Output from './Output.svelte'
|
||||
|
||||
export let gridItem: GridItem
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
gridItem: GridItem
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let { gridItem, render }: Props = $props()
|
||||
</script>
|
||||
|
||||
<div class="my-1">
|
||||
|
||||
@@ -7,18 +7,24 @@
|
||||
|
||||
const { connectingInput } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
export let id: string
|
||||
export let first: boolean = false
|
||||
export let label: string
|
||||
export let renderRec: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
first?: boolean
|
||||
label: string
|
||||
renderRec: boolean
|
||||
}
|
||||
|
||||
let { id, first = false, label, renderRec }: Props = $props()
|
||||
</script>
|
||||
|
||||
<OutputHeader render={renderRec} let:render renamable={false} {id} name={label} {first}>
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
componentId={id}
|
||||
on:select={({ detail }) => {
|
||||
$connectingInput = connectInput($connectingInput, id, detail)
|
||||
}}
|
||||
/>
|
||||
<OutputHeader render={renderRec} renamable={false} {id} name={label} {first}>
|
||||
{#snippet children({ render })}
|
||||
<ComponentOutputViewer
|
||||
{render}
|
||||
componentId={id}
|
||||
on:select={({ detail }) => {
|
||||
$connectingInput = connectInput($connectingInput, id, detail)
|
||||
}}
|
||||
/>
|
||||
{/snippet}
|
||||
</OutputHeader>
|
||||
|
||||
+48
-28
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import type { AppViewerContext, ContextPanelContext } from '$lib/components/apps/types'
|
||||
import { allItems } from '$lib/components/apps/utils'
|
||||
import { classNames } from '$lib/utils'
|
||||
@@ -10,28 +12,46 @@
|
||||
import type { Runnable } from '$lib/components/apps/inputType'
|
||||
import DocLink from '../../settingsPanel/DocLink.svelte'
|
||||
|
||||
export let id: string
|
||||
export let name: string
|
||||
export let first: boolean = false
|
||||
export let nested: boolean = false
|
||||
export let color: 'blue' | 'indigo' = 'indigo'
|
||||
export let selectable: boolean = true
|
||||
export let renamable: boolean = true
|
||||
export let disabled: boolean = false
|
||||
export let render: boolean = true
|
||||
interface Props {
|
||||
id: string
|
||||
name: string
|
||||
first?: boolean
|
||||
nested?: boolean
|
||||
color?: 'blue' | 'indigo'
|
||||
selectable?: boolean
|
||||
renamable?: boolean
|
||||
disabled?: boolean
|
||||
render?: boolean
|
||||
children?: import('svelte').Snippet<[any]>
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
name,
|
||||
first = false,
|
||||
nested = false,
|
||||
color = 'indigo',
|
||||
selectable = true,
|
||||
renamable = true,
|
||||
disabled = false,
|
||||
render = true,
|
||||
children
|
||||
}: Props = $props()
|
||||
|
||||
const { manuallyOpened, search, hasResult } = getContext<ContextPanelContext>('ContextPanel')
|
||||
|
||||
const { selectedComponent, app, hoverStore, allIdsInPath, connectingInput, worldStore } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
$: subids = $search != '' ? allsubIds($app, id) : []
|
||||
$: inSearch =
|
||||
let subids = $derived($search != '' ? allsubIds($app, id) : [])
|
||||
let inSearch = $derived(
|
||||
$search != '' &&
|
||||
($hasResult[id] ||
|
||||
Object.entries($hasResult).some(([key, value]) => value && subids.includes(key)))
|
||||
$: open =
|
||||
($hasResult[id] ||
|
||||
Object.entries($hasResult).some(([key, value]) => value && subids.includes(key)))
|
||||
)
|
||||
let open = $derived(
|
||||
$allIdsInPath.includes(id) || id == $selectedComponent?.[0] || $manuallyOpened[id] || inSearch
|
||||
)
|
||||
|
||||
const hoverColor = {
|
||||
blue: 'hover:bg-blue-100 hover:text-blue-500 dark:hover:bg-frost-900 dark:hover:text-frost-100',
|
||||
@@ -199,35 +219,35 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<div class={render && ($search == '' || inSearch) ? '' : 'invisible h-0 overflow-hidden'}>
|
||||
{#if render && ($search == '' || inSearch)}
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_mouse_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
on:mouseenter|stopPropagation={() => {
|
||||
onmouseenter={stopPropagation(() => {
|
||||
if (id !== $hoverStore) {
|
||||
$hoverStore = id
|
||||
}
|
||||
}}
|
||||
on:mouseleave|stopPropagation={() => {
|
||||
})}
|
||||
onmouseleave={stopPropagation(() => {
|
||||
if ($hoverStore !== undefined) {
|
||||
$hoverStore = undefined
|
||||
}
|
||||
}}
|
||||
})}
|
||||
class={classNames(
|
||||
'flex items-center justify-between p-1 cursor-pointer gap-1 truncate',
|
||||
hoverColor[color],
|
||||
$selectedComponent?.includes(id)
|
||||
? openBackground[color]
|
||||
: $connectingInput.hoveredComponent === id
|
||||
? 'bg-[#fab157]'
|
||||
: 'bg-surface-secondary',
|
||||
? 'bg-[#fab157]'
|
||||
: 'bg-surface-secondary',
|
||||
first ? 'border-t' : '',
|
||||
nested ? 'border-l' : '',
|
||||
'transition-all'
|
||||
)}
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
if (!disabled) {
|
||||
$manuallyOpened[id] = $manuallyOpened[id] != undefined ? !$manuallyOpened[id] : true
|
||||
}
|
||||
@@ -238,7 +258,7 @@
|
||||
<button
|
||||
disabled={!(selectable && !$selectedComponent?.includes(id)) || $connectingInput?.opened}
|
||||
title="Select component"
|
||||
on:click|stopPropagation={() => ($selectedComponent = [id])}
|
||||
onclick={stopPropagation(() => ($selectedComponent = [id]))}
|
||||
class="flex items-center ml-0.5 rounded-sm bg-surface-selected hover:text-primary text-tertiary"
|
||||
>
|
||||
<div
|
||||
@@ -271,8 +291,8 @@
|
||||
docLink={id === 'state'
|
||||
? 'https://www.windmill.dev/docs/apps/outputs#state'
|
||||
: id === 'ctx'
|
||||
? 'https://www.windmill.dev/docs/apps/outputs#app-context'
|
||||
: ''}
|
||||
? 'https://www.windmill.dev/docs/apps/outputs#app-context'
|
||||
: ''}
|
||||
size="xs2"
|
||||
/>
|
||||
{/if}
|
||||
@@ -299,7 +319,7 @@
|
||||
: ''}"
|
||||
>
|
||||
<div class={classNames(nested ? 'border-l ml-2' : '', open ? 'border-t' : '')}>
|
||||
<slot render={open && render} />
|
||||
{@render children?.({ render: open && render })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+6
-2
@@ -2,8 +2,12 @@
|
||||
import type { GridItem } from '$lib/components/apps/types'
|
||||
import Output from './Output.svelte'
|
||||
|
||||
export let gridItem: GridItem
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
gridItem: GridItem
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let { gridItem, render }: Props = $props()
|
||||
</script>
|
||||
|
||||
<div class="my-1">
|
||||
|
||||
@@ -9,10 +9,19 @@
|
||||
|
||||
import RunButtonInner from '$lib/components/RunButton.svelte'
|
||||
|
||||
export let id: string
|
||||
export let inlineScript: InlineScript | undefined = undefined
|
||||
export let runLoading = false
|
||||
export let hideShortcut = false
|
||||
interface Props {
|
||||
id: string
|
||||
inlineScript?: InlineScript | undefined
|
||||
runLoading?: boolean
|
||||
hideShortcut?: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
inlineScript = undefined,
|
||||
runLoading = $bindable(false),
|
||||
hideShortcut = false
|
||||
}: Props = $props()
|
||||
|
||||
const { runnableComponents } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { runnableJobEditorPanel } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
import Popover from '$lib/components/meltComponents/Popover.svelte'
|
||||
import { autoPlacement } from '@floating-ui/core'
|
||||
|
||||
export let cache_ttl: number | undefined
|
||||
interface Props {
|
||||
cache_ttl: number | undefined
|
||||
}
|
||||
|
||||
let { cache_ttl = $bindable() }: Props = $props()
|
||||
</script>
|
||||
|
||||
<Popover
|
||||
@@ -19,7 +23,7 @@
|
||||
closeButton
|
||||
contentClasses="block text-primary p-4"
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
{#snippet trigger()}
|
||||
<Button
|
||||
nonCaptureEvent={true}
|
||||
btnClasses={Boolean(cache_ttl)
|
||||
@@ -32,8 +36,8 @@
|
||||
startIcon={{ icon: Database }}
|
||||
title="Cache settings"
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
<Toggle
|
||||
checked={Boolean(cache_ttl)}
|
||||
on:change={() => {
|
||||
@@ -56,5 +60,5 @@
|
||||
<SecondsInput disabled />
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
|
||||
+25
-14
@@ -20,14 +20,23 @@
|
||||
import type { Preview } from '$lib/gen'
|
||||
import type { InlineScript } from '../../types'
|
||||
|
||||
export let componentType: string | undefined = undefined
|
||||
export let showScriptPicker = false
|
||||
export let rawApps = false
|
||||
export let unusedInlineScripts: { name: string; inlineScript: InlineScript }[]
|
||||
interface Props {
|
||||
componentType?: string | undefined
|
||||
showScriptPicker?: boolean
|
||||
rawApps?: boolean
|
||||
unusedInlineScripts: { name: string; inlineScript: InlineScript }[]
|
||||
}
|
||||
|
||||
let tab = 'workspacescripts'
|
||||
let filter: string = ''
|
||||
let picker: Drawer
|
||||
let {
|
||||
componentType = undefined,
|
||||
showScriptPicker = false,
|
||||
rawApps = false,
|
||||
unusedInlineScripts
|
||||
}: Props = $props()
|
||||
|
||||
let tab = $state('workspacescripts')
|
||||
let filter: string = $state('')
|
||||
let picker: Drawer | undefined = $state(undefined)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -78,13 +87,15 @@
|
||||
newInlineScript(script.content, script.language)
|
||||
}
|
||||
|
||||
$: langs = processLangs(undefined, $defaultScripts?.order ?? Object.keys(defaultScriptLanguages))
|
||||
.map((l) => [defaultScriptLanguages[l], l])
|
||||
.filter(
|
||||
(x) =>
|
||||
x[1] != 'docker' &&
|
||||
($defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x[1]))
|
||||
) as [string, Preview['language']][]
|
||||
let langs = $derived(
|
||||
processLangs(undefined, $defaultScripts?.order ?? Object.keys(defaultScriptLanguages))
|
||||
.map((l) => [defaultScriptLanguages[l], l])
|
||||
.filter(
|
||||
(x) =>
|
||||
x[1] != 'docker' &&
|
||||
($defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x[1]))
|
||||
) as [string, Preview['language']][]
|
||||
)
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={picker} size="1000px">
|
||||
|
||||
+15
-5
@@ -8,11 +8,21 @@
|
||||
import type { AppViewerContext } from '../../types'
|
||||
import InlineScriptRunnableByPath from './InlineScriptRunnableByPath.svelte'
|
||||
|
||||
export let componentInput: AppInput | undefined
|
||||
export let defaultUserInput = false
|
||||
export let componentType: string
|
||||
export let id: string
|
||||
export let transformer: boolean
|
||||
interface Props {
|
||||
componentInput: AppInput | undefined
|
||||
defaultUserInput?: boolean
|
||||
componentType: string
|
||||
id: string
|
||||
transformer: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
componentInput = $bindable(),
|
||||
defaultUserInput = false,
|
||||
componentType,
|
||||
id,
|
||||
transformer
|
||||
}: Props = $props()
|
||||
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
|
||||
+7
-3
@@ -6,9 +6,13 @@
|
||||
import type { Runnable, StaticAppInput } from '../../inputType'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
|
||||
export let runnable: HiddenRunnable
|
||||
export let id: string
|
||||
export let transformer: boolean
|
||||
interface Props {
|
||||
runnable: HiddenRunnable
|
||||
id: string
|
||||
transformer: boolean
|
||||
}
|
||||
|
||||
let { runnable = $bindable(), id, transformer }: Props = $props()
|
||||
|
||||
const { runnableComponents, app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
async function fork(nrunnable: Runnable) {
|
||||
|
||||
+40
-20
@@ -1,10 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { createBubbler, stopPropagation } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { Button, Drawer, DrawerContent } from '$lib/components/common'
|
||||
import { base } from '$lib/base'
|
||||
import FlowModuleScript from '$lib/components/flows/content/FlowModuleScript.svelte'
|
||||
import FlowPathViewer from '$lib/components/flows/content/FlowPathViewer.svelte'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import { getContext, tick } from 'svelte'
|
||||
import { getContext, tick, untrack } from 'svelte'
|
||||
import type {
|
||||
ConnectedAppInput,
|
||||
RowAppInput,
|
||||
@@ -27,21 +30,33 @@
|
||||
import RunButton from '$lib/components/RunButton.svelte'
|
||||
import Popover from '$lib/components/meltComponents/Popover.svelte'
|
||||
|
||||
export let runnable: RunnableByPath
|
||||
export let fields:
|
||||
| Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
| undefined
|
||||
export let id: string
|
||||
export let rawApps = false
|
||||
export let isLoading = false
|
||||
export let onRun = async () => {}
|
||||
export let onCancel = async () => {}
|
||||
interface Props {
|
||||
runnable: RunnableByPath
|
||||
fields:
|
||||
| Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
| undefined
|
||||
id: string
|
||||
rawApps?: boolean
|
||||
isLoading?: boolean
|
||||
onRun?: any
|
||||
onCancel?: any
|
||||
}
|
||||
|
||||
let {
|
||||
runnable = $bindable(),
|
||||
fields = $bindable(),
|
||||
id,
|
||||
rawApps = false,
|
||||
isLoading = false,
|
||||
onRun = async () => {},
|
||||
onCancel = async () => {}
|
||||
}: Props = $props()
|
||||
|
||||
const viewerContext = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let drawerFlowViewer: Drawer
|
||||
let flowPath: string = ''
|
||||
let notFound = false
|
||||
let drawerFlowViewer: Drawer | undefined = $state(undefined)
|
||||
let flowPath: string = $state('')
|
||||
let notFound = $state(false)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -110,7 +125,12 @@
|
||||
}
|
||||
lastRunnable = runnable
|
||||
}
|
||||
$: refresh(runnable)
|
||||
$effect(() => {
|
||||
runnable.path
|
||||
untrack(() => {
|
||||
refresh(runnable)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={drawerFlowViewer} size="1200px">
|
||||
@@ -160,7 +180,7 @@
|
||||
startIcon={{ icon: Eye }}
|
||||
on:click={() => {
|
||||
flowPath = runnable.path
|
||||
drawerFlowViewer.openDrawer()
|
||||
drawerFlowViewer?.openDrawer()
|
||||
}}
|
||||
>
|
||||
Expand
|
||||
@@ -215,7 +235,7 @@
|
||||
closeButton
|
||||
contentClasses="block text-primary text-xs p-4 w-[20vh]"
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
{#snippet trigger()}
|
||||
<Button
|
||||
nonCaptureEvent={true}
|
||||
btnClasses={'bg-surface text-primay hover:bg-hover'}
|
||||
@@ -223,16 +243,16 @@
|
||||
variant="border"
|
||||
size="xs">Cache</Button
|
||||
>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
Since this is a reference to a workspace {runnable.runType}, set the cache in the {runnable.runType}
|
||||
settings directly by editing it. The cache will be shared by any app or flow that uses this
|
||||
{runnable.runType}.
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
|
||||
<input
|
||||
on:keydown|stopPropagation
|
||||
onkeydown={stopPropagation(bubble('keydown'))}
|
||||
bind:value={runnable.name}
|
||||
placeholder="Background runnable name"
|
||||
class="!text-xs !rounded-xs"
|
||||
|
||||
+22
-13
@@ -40,24 +40,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: gridItem =
|
||||
let gridItem = $derived(
|
||||
$selectedComponentInEditor && !$selectedComponentInEditor.startsWith(BG_PREFIX)
|
||||
? findGridItem($app, $selectedComponentInEditor?.split('_')?.[0])
|
||||
: undefined
|
||||
|
||||
$: hiddenInlineScript = $app?.hiddenInlineScripts?.findIndex((k_, index) => {
|
||||
const [prefix, id] = $selectedComponentInEditor?.split('_') || []
|
||||
|
||||
if (prefix !== 'bg') return false
|
||||
|
||||
return Number(id) === index
|
||||
})
|
||||
|
||||
$: unusedInlineScript = $app?.unusedInlineScripts?.findIndex(
|
||||
(k_, index) => `unused-${index}` === $selectedComponentInEditor
|
||||
)
|
||||
|
||||
export let width: number | undefined = undefined
|
||||
let hiddenInlineScript = $derived(
|
||||
$app?.hiddenInlineScripts?.findIndex((k_, index) => {
|
||||
const [prefix, id] = $selectedComponentInEditor?.split('_') || []
|
||||
|
||||
if (prefix !== 'bg') return false
|
||||
|
||||
return Number(id) === index
|
||||
})
|
||||
)
|
||||
|
||||
let unusedInlineScript = $derived(
|
||||
$app?.unusedInlineScripts?.findIndex(
|
||||
(k_, index) => `unused-${index}` === $selectedComponentInEditor
|
||||
)
|
||||
)
|
||||
|
||||
interface Props {
|
||||
width?: number | undefined
|
||||
}
|
||||
|
||||
let { width = undefined }: Props = $props()
|
||||
</script>
|
||||
|
||||
<Splitpanes
|
||||
|
||||
+16
-16
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Badge, Button } from '$lib/components/common'
|
||||
import { Plus } from 'lucide-svelte'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import { createEventDispatcher, getContext, untrack } from 'svelte'
|
||||
import Tooltip from '../../../Tooltip.svelte'
|
||||
import type { AppEditorContext, AppViewerContext } from '../../types'
|
||||
import { BG_PREFIX, getAllScriptNames } from '../../utils'
|
||||
@@ -26,11 +26,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: runnables = getAppScripts($app.grid, $app.subgrids)
|
||||
|
||||
// When selected component changes, update selectedScriptComponentId
|
||||
$: selectedComponent && handleSelectedComponent($selectedComponent)
|
||||
|
||||
function handleSelectedComponent(selectedComponent: string[] | undefined) {
|
||||
if (
|
||||
selectedComponent != $selectedComponentInEditor &&
|
||||
@@ -79,12 +74,17 @@
|
||||
selectScript(`${BG_PREFIX}${$app.hiddenInlineScripts.length - 1}`)
|
||||
}
|
||||
|
||||
let appTutorials: AppTutorials | undefined = undefined
|
||||
let appTutorials: AppTutorials | undefined = $state(undefined)
|
||||
const dispatch = createEventDispatcher()
|
||||
let runnables = $derived(getAppScripts($app.grid, $app.subgrids))
|
||||
// When selected component changes, update selectedScriptComponentId
|
||||
$effect(() => {
|
||||
$selectedComponent && untrack(() => handleSelectedComponent($selectedComponent))
|
||||
})
|
||||
</script>
|
||||
|
||||
<PanelSection title="Runnables" id="app-editor-runnable-panel">
|
||||
<svelte:fragment slot="action">
|
||||
{#snippet action()}
|
||||
<div class="flex flex-row gap-1">
|
||||
<HideButton
|
||||
direction="bottom"
|
||||
@@ -96,7 +96,7 @@
|
||||
docLink="https://www.windmill.dev/docs/apps/app-runnable-panel#creating-a-runnable"
|
||||
/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
<div class="w-full flex flex-col gap-6 py-1">
|
||||
<div>
|
||||
<div class="flex flex-col gap-2 w-full">
|
||||
@@ -109,7 +109,7 @@
|
||||
{$selectedComponentInEditor === id
|
||||
? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50'
|
||||
: 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}"
|
||||
on:click={() => selectScript(id)}
|
||||
onclick={() => selectScript(id)}
|
||||
>
|
||||
<span class="text-2xs truncate">{name}</span>
|
||||
<div>
|
||||
@@ -124,7 +124,7 @@
|
||||
{$selectedComponentInEditor === id + '_transformer'
|
||||
? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50'
|
||||
: 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}"
|
||||
on:click={() => selectScript(id + '_transformer')}
|
||||
onclick={() => selectScript(id + '_transformer')}
|
||||
>
|
||||
<span class="text-2xs truncate">Transformer</span>
|
||||
</button>
|
||||
@@ -140,7 +140,7 @@
|
||||
{$selectedComponentInEditor === id
|
||||
? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50'
|
||||
: 'hover:bg-blue-50'}"
|
||||
on:click={() => selectScript(id)}
|
||||
onclick={() => selectScript(id)}
|
||||
>
|
||||
<span class="text-2xs truncate">{name}</span>
|
||||
<Badge color="indigo">{id}</Badge>
|
||||
@@ -153,7 +153,7 @@
|
||||
{$selectedComponentInEditor === id + '_transformer'
|
||||
? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50'
|
||||
: 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}"
|
||||
on:click={() => selectScript(id + '_transformer')}
|
||||
onclick={() => selectScript(id + '_transformer')}
|
||||
>
|
||||
<span class="text-2xs truncate">Transformer</span>
|
||||
</button>
|
||||
@@ -171,7 +171,7 @@
|
||||
{$selectedComponentInEditor === id
|
||||
? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50'
|
||||
: 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}"
|
||||
on:click={() => selectScript(id)}
|
||||
onclick={() => selectScript(id)}
|
||||
>
|
||||
<span class="text-2xs truncate">{unusedInlineScript.name}</span>
|
||||
<Badge color="red">Detached</Badge>
|
||||
@@ -220,7 +220,7 @@
|
||||
{$selectedComponentInEditor === id
|
||||
? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50'
|
||||
: 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}"
|
||||
on:click={() => selectScript(id)}
|
||||
onclick={() => selectScript(id)}
|
||||
>
|
||||
<span class="text-2xs truncate">{name}</span>
|
||||
<Badge color="indigo">{id}</Badge>
|
||||
@@ -233,7 +233,7 @@
|
||||
{$selectedComponentInEditor === id + '_transformer'
|
||||
? 'border-blue-500 bg-blue-100 dark:bg-frost-900/50'
|
||||
: 'hover:bg-blue-50 dark:hover:bg-frost-900/50'}"
|
||||
on:click={() => selectScript(id + '_transformer')}
|
||||
onclick={() => selectScript(id + '_transformer')}
|
||||
>
|
||||
<span class="text-2xs truncate">Transformer</span>
|
||||
</button>
|
||||
|
||||
+5
-1
@@ -5,7 +5,11 @@
|
||||
|
||||
const { selectedComponentInEditor } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
export let gridItem: GridItem
|
||||
interface Props {
|
||||
gridItem: GridItem
|
||||
}
|
||||
|
||||
let { gridItem = $bindable() }: Props = $props()
|
||||
</script>
|
||||
|
||||
{#if gridItem?.data?.id === $selectedComponentInEditor || gridItem?.data?.id + '_transformer' === $selectedComponentInEditor}
|
||||
|
||||
@@ -9,14 +9,23 @@
|
||||
import { Button } from '$lib/components/common'
|
||||
import { CornerDownLeft, Loader2 } from 'lucide-svelte'
|
||||
|
||||
export let id: string
|
||||
export let inlineScript: InlineScript | undefined = undefined
|
||||
export let runLoading = false
|
||||
export let hideShortcut = false
|
||||
interface Props {
|
||||
id: string
|
||||
inlineScript?: InlineScript | undefined
|
||||
runLoading?: boolean
|
||||
hideShortcut?: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
inlineScript = undefined,
|
||||
runLoading = $bindable(false),
|
||||
hideShortcut = false
|
||||
}: Props = $props()
|
||||
|
||||
const { runnableComponents } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { runnableJobEditorPanel } = getContext<AppEditorContext>('AppEditorContext')
|
||||
let cancelable: CancelablePromise<void>[] | undefined = undefined
|
||||
let cancelable: CancelablePromise<void>[] | undefined = $state(undefined)
|
||||
</script>
|
||||
|
||||
{#if $runnableComponents[id] != undefined}
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
import InputsSpecEditor from './InputsSpecEditor.svelte'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
|
||||
export let datasets: RichConfiguration | undefined = undefined
|
||||
export let xData: RichConfiguration | undefined = undefined
|
||||
export let id: string
|
||||
interface Props {
|
||||
datasets?: RichConfiguration | undefined
|
||||
xData?: RichConfiguration | undefined
|
||||
id: string
|
||||
}
|
||||
|
||||
let { datasets = $bindable(undefined), xData = $bindable(undefined), id }: Props = $props()
|
||||
</script>
|
||||
|
||||
<PanelSection
|
||||
|
||||
@@ -180,6 +180,7 @@
|
||||
})
|
||||
}
|
||||
}
|
||||
componentInput.value = $state.snapshot(componentInput.value)
|
||||
componentInput = componentInput
|
||||
items = getItems(componentInput)
|
||||
}
|
||||
|
||||
@@ -16,14 +16,18 @@
|
||||
import CloseButton from '$lib/components/common/CloseButton.svelte'
|
||||
import HighlightTheme from '$lib/components/HighlightTheme.svelte'
|
||||
import Portal from '$lib/components/Portal.svelte'
|
||||
export let component: AppComponent | undefined
|
||||
interface Props {
|
||||
component: AppComponent | undefined
|
||||
}
|
||||
|
||||
let { component = $bindable() }: Props = $props()
|
||||
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
function fadeFast(node: HTMLElement) {
|
||||
return fade(node, { duration: 100 })
|
||||
}
|
||||
let migrationModalOpen: boolean = false
|
||||
let migrationModalOpen: boolean = $state(false)
|
||||
|
||||
export function open() {
|
||||
migrationModalOpen = true
|
||||
@@ -38,9 +42,6 @@
|
||||
return code
|
||||
}
|
||||
|
||||
$: generatedCode = generateCodeFromMigrations(migrations)
|
||||
$: migrations = new Map<string, string[]>()
|
||||
|
||||
function getSelector(key: string) {
|
||||
return customisationByComponent
|
||||
.find((c) => c.components.includes(component?.type ?? ''))
|
||||
@@ -126,6 +127,8 @@
|
||||
}
|
||||
|
||||
let type: string | undefined = component?.type
|
||||
let migrations = $derived(new Map<string, string[]>())
|
||||
let generatedCode = $derived(generateCodeFromMigrations(migrations))
|
||||
</script>
|
||||
|
||||
<HighlightTheme />
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
import InputsSpecEditor from './InputsSpecEditor.svelte'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
|
||||
export let datasets: RichConfiguration | undefined = undefined
|
||||
export let xData: RichConfiguration | undefined = undefined
|
||||
export let id: string
|
||||
interface Props {
|
||||
datasets?: RichConfiguration | undefined
|
||||
xData?: RichConfiguration | undefined
|
||||
id: string
|
||||
}
|
||||
|
||||
let { datasets = $bindable(undefined), xData = $bindable(undefined), id }: Props = $props()
|
||||
</script>
|
||||
|
||||
<PanelSection
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user