mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-26 08:01:38 +00:00
feat(app): Add progress bar app component (#7242)
* Add progress bar app component - Create AppJobProgressBar component for displaying job progress - Register jobprogressbarcomponent in component system - Add component rendering in ComponentInner - Component accepts jobId configuration parameter - Similar to jobidlogcomponent and jobidflowstatuscomponent Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> * feat(app): Add job progress bar to component picker Add jobprogressbarcomponent to the display component set so it appears in the component picker UI alongside other job-related components. Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com> * Add jobprogressbarcomponent to quickStyleProperties Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com> --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> Co-authored-by: Ruben Fiszel <rubenfiszel@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
<script lang="ts">
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import { initCss } from '../../utils'
|
||||
import JobLoader from '$lib/components/JobLoader.svelte'
|
||||
import JobProgressBar from '$lib/components/jobs/JobProgressBar.svelte'
|
||||
import type { Job } from '$lib/gen'
|
||||
import { components } from '../../editor/component'
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
import InitializeComponent from '../helpers/InitializeComponent.svelte'
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
initializing?: boolean | undefined
|
||||
customCss?: ComponentCustomCSS<'jobprogressbarcomponent'> | undefined
|
||||
configuration: RichConfigurations
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
initializing = $bindable(undefined),
|
||||
customCss = undefined,
|
||||
configuration,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
$effect.pre(() => {
|
||||
if (initializing) {
|
||||
initializing = false
|
||||
}
|
||||
})
|
||||
|
||||
const { app, worldStore, workspace } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['jobprogressbarcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: undefined,
|
||||
loading: false,
|
||||
jobId: undefined
|
||||
})
|
||||
|
||||
initializing = false
|
||||
|
||||
let css = $state(initCss($app.css?.jobprogressbarcomponent, customCss))
|
||||
|
||||
let jobLoader: JobLoader | undefined = $state(undefined)
|
||||
let testIsLoading: boolean = $state(false)
|
||||
let testJob: Job | undefined = $state(undefined)
|
||||
let scriptProgress: number | undefined = $state(undefined)
|
||||
|
||||
$effect(() => {
|
||||
if (resolvedConfig.jobId) {
|
||||
untrack(() => {
|
||||
outputs.loading.set(true)
|
||||
const jobId = resolvedConfig?.['jobId']
|
||||
if (jobId) {
|
||||
let callbacks = {
|
||||
done(x) {
|
||||
outputs.loading.set(false)
|
||||
outputs.jobId.set(x.id)
|
||||
outputs.result.set(x.result)
|
||||
}
|
||||
}
|
||||
jobLoader?.watchJob(jobId, callbacks)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['jobprogressbarcomponent'].initialData.configuration) as key (key)}
|
||||
<ResolveConfig
|
||||
{id}
|
||||
{key}
|
||||
bind:resolvedConfig={resolvedConfig[key]}
|
||||
configuration={configuration[key]}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
{#each Object.keys(css ?? {}) as key (key)}
|
||||
<ResolveStyle
|
||||
{id}
|
||||
{customCss}
|
||||
{key}
|
||||
bind:css={css[key]}
|
||||
componentStyle={$app.css?.jobprogressbarcomponent}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
<JobLoader
|
||||
noCode={true}
|
||||
workspaceOverride={workspace}
|
||||
bind:this={jobLoader}
|
||||
bind:isLoading={testIsLoading}
|
||||
bind:job={testJob}
|
||||
/>
|
||||
|
||||
<InitializeComponent {id} />
|
||||
|
||||
{#if render}
|
||||
<div class="flex flex-col w-full h-full component-wrapper">
|
||||
<div
|
||||
class={twMerge(
|
||||
'w-full border-b p-2 text-xs font-semibold text-primary bg-surface-secondary',
|
||||
css?.header?.class
|
||||
)}
|
||||
style={css?.header?.style}
|
||||
>
|
||||
Progress
|
||||
</div>
|
||||
<div
|
||||
style={css?.container?.style}
|
||||
class={twMerge('p-2 grow overflow-auto', css?.container?.class)}
|
||||
>
|
||||
{#if testJob}
|
||||
<JobProgressBar job={testJob} {scriptProgress} />
|
||||
{:else}
|
||||
<span class="text-secondary text-xs">No job</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -16,6 +16,7 @@
|
||||
import AppList from '../../components/layout/AppList.svelte'
|
||||
import AppJobIdLogComponent from '../../components/display/AppJobIdLogComponent.svelte'
|
||||
import AppJobIdFlowStatus from '../../components/display/AppJobIdFlowStatus.svelte'
|
||||
import AppJobProgressBar from '../../components/display/AppJobProgressBar.svelte'
|
||||
import AppCarouselList from '../../components/display/AppCarouselList.svelte'
|
||||
import AppAccordionList from '../../components/display/AppAccordionList.svelte'
|
||||
import AppAggridTableEe from '../../components/display/table/AppAggridTableEe.svelte'
|
||||
@@ -146,6 +147,7 @@
|
||||
])
|
||||
const chunk5Components = new Set([
|
||||
'jobidlogcomponent',
|
||||
'jobprogressbarcomponent',
|
||||
'listcomponent',
|
||||
'logcomponent',
|
||||
'mapcomponent',
|
||||
@@ -605,6 +607,14 @@
|
||||
configuration={component.configuration}
|
||||
{render}
|
||||
/>
|
||||
{:else if component.type === 'jobprogressbarcomponent'}
|
||||
<AppJobProgressBar
|
||||
id={component.id}
|
||||
customCss={component.customCss}
|
||||
bind:initializing
|
||||
configuration={component.configuration}
|
||||
{render}
|
||||
/>
|
||||
{:else if component.type === 'listcomponent'}
|
||||
<AppList
|
||||
id={component.id}
|
||||
|
||||
@@ -215,6 +215,7 @@ export type LogComponent = BaseComponent<'logcomponent'>
|
||||
export type JobIdLogComponent = BaseComponent<'jobidlogcomponent'>
|
||||
export type FlowStatusComponent = BaseComponent<'flowstatuscomponent'>
|
||||
export type JobIdFlowStatusComponent = BaseComponent<'jobidflowstatuscomponent'>
|
||||
export type JobProgressBarComponent = BaseComponent<'jobprogressbarcomponent'>
|
||||
export type ImageComponent = BaseComponent<'imagecomponent'>
|
||||
export type InputComponent = BaseComponent<'inputcomponent'>
|
||||
export type SelectComponent = BaseComponent<'selectcomponent'> &
|
||||
@@ -345,6 +346,7 @@ export type TypedComponent =
|
||||
| JobIdLogComponent
|
||||
| FlowStatusComponent
|
||||
| JobIdFlowStatusComponent
|
||||
| JobProgressBarComponent
|
||||
| TextInputComponent
|
||||
| QuillComponent
|
||||
| CodeInputComponent
|
||||
@@ -1276,6 +1278,26 @@ export const components = {
|
||||
}
|
||||
}
|
||||
},
|
||||
jobprogressbarcomponent: {
|
||||
name: 'Progress Bar by Job Id',
|
||||
icon: Clock,
|
||||
documentationLink: `${documentationBaseUrl}/progress_bar`,
|
||||
dims: '2:2-6:2' as AppComponentDimensions,
|
||||
customCss: {
|
||||
header: { class: '', style: '' },
|
||||
container: { class: '', style: '' }
|
||||
},
|
||||
initialData: {
|
||||
configuration: {
|
||||
jobId: {
|
||||
type: 'static',
|
||||
fieldType: 'text',
|
||||
value: '',
|
||||
tooltip: 'Job id to display progress from'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
containercomponent: {
|
||||
name: 'Container',
|
||||
icon: BoxSelect,
|
||||
|
||||
@@ -76,6 +76,7 @@ const display: ComponentSet = {
|
||||
'chatcomponent',
|
||||
'displaycomponent',
|
||||
'jobidlogcomponent',
|
||||
'jobprogressbarcomponent',
|
||||
'jobidflowstatuscomponent',
|
||||
'jobiddisplaycomponent',
|
||||
'statcomponent',
|
||||
|
||||
@@ -665,6 +665,10 @@ export const quickStyleProperties: Record<
|
||||
header: [...containerDefaultProps, typographyGrouping],
|
||||
container: containerDefaultProps
|
||||
},
|
||||
jobprogressbarcomponent: {
|
||||
header: [...containerDefaultProps, typographyGrouping],
|
||||
container: containerDefaultProps
|
||||
},
|
||||
accordionlistcomponent: {
|
||||
container: containerDefaultProps
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user