mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 16:02:14 +00:00
fix(frontend): Fix AppTable error display + clear errors when removing a component + properly detect that latest component run had an error (#1322)
This commit is contained in:
@@ -355,11 +355,13 @@
|
||||
/>
|
||||
</div>
|
||||
{:else if result != undefined}
|
||||
<Alert title="Parsing issues" type="error" size="xs">
|
||||
The result should be an array of objects. Received:
|
||||
<pre class="overflow-auto">
|
||||
{JSON.stringify(result)}
|
||||
</pre>
|
||||
</Alert>
|
||||
<div class="flex flex-col h-full w-full overflow-auto">
|
||||
<Alert title="Parsing issues" type="error" size="xs" class="h-full w-full ">
|
||||
The result should be an array of objects. Received:
|
||||
<pre class="w-full bg-white p-2 rounded-md">
|
||||
{JSON.stringify(result, null, 4)}
|
||||
</pre>
|
||||
</Alert>
|
||||
</div>
|
||||
{/if}
|
||||
</RunnableWrapper>
|
||||
|
||||
@@ -244,6 +244,8 @@
|
||||
}
|
||||
|
||||
async function setResult(res: any) {
|
||||
const hasRes = res !== undefined && res !== null
|
||||
|
||||
if (transformer) {
|
||||
$worldStore.newOutput(id, 'raw', res)
|
||||
res = await eval_like(
|
||||
@@ -255,7 +257,18 @@
|
||||
$componentControl,
|
||||
$worldStore
|
||||
)
|
||||
|
||||
if (hasRes && res === undefined) {
|
||||
res = {
|
||||
error: {
|
||||
name: 'TransformerError',
|
||||
message: 'An error occured in the transformer',
|
||||
stack: 'Transformer returned undefined'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputs.result?.set(res)
|
||||
|
||||
result = res
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
import DisplayResult from '$lib/components/DisplayResult.svelte'
|
||||
import Dropdown from '$lib/components/Dropdown.svelte'
|
||||
import FlowProgressBar from '$lib/components/flows/FlowProgressBar.svelte'
|
||||
import { idMutex } from '$lib/components/flows/flowStateUtils'
|
||||
import FlowStatusViewer from '$lib/components/FlowStatusViewer.svelte'
|
||||
import JobArgs from '$lib/components/JobArgs.svelte'
|
||||
import LogViewer from '$lib/components/LogViewer.svelte'
|
||||
@@ -43,12 +42,9 @@
|
||||
Eye,
|
||||
Laptop2,
|
||||
Loader2,
|
||||
MoreVertical,
|
||||
Pencil,
|
||||
Redo,
|
||||
SlidersHorizontal,
|
||||
Smartphone,
|
||||
Undo,
|
||||
X
|
||||
} from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { Alert, Button } from '$lib/components/common'
|
||||
import type { AppComponent } from './component'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { getErrorFromLatestResult } from './appUtils'
|
||||
|
||||
export let component: AppComponent
|
||||
export let selected: boolean
|
||||
@@ -15,9 +16,9 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const { errorByComponent, openDebugRun } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { errorByComponent, openDebugRun, jobs } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
$: error = Object.values($errorByComponent).find((e) => e.componentId === component.id)
|
||||
$: error = getErrorFromLatestResult(component.id, $errorByComponent, $jobs)
|
||||
|
||||
function openDebugRuns() {
|
||||
if ($openDebugRun) {
|
||||
@@ -84,7 +85,7 @@
|
||||
{/if}
|
||||
|
||||
{#if error}
|
||||
{@const json = JSON.parse(JSON.stringify(error.error))}
|
||||
{@const json = JSON.parse(JSON.stringify(error))}
|
||||
<span
|
||||
title="Error"
|
||||
class={classNames(
|
||||
@@ -99,9 +100,9 @@
|
||||
<Alert type="error" title={`${json?.name}: ${json?.message}`}>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div>
|
||||
<pre class=" whitespace-pre-wrap text-gray-900 bg-white border w-full p-4 text-xs"
|
||||
>{json?.stack ?? ''}
|
||||
</pre>
|
||||
<pre class=" whitespace-pre-wrap text-gray-900 bg-white border w-full p-4 text-xs">
|
||||
{json?.stack ?? ''}
|
||||
</pre>
|
||||
</div>
|
||||
<Button color="red" variant="border" on:click={openDebugRuns}>Open Debug Runs</Button>
|
||||
</div>
|
||||
|
||||
@@ -568,3 +568,56 @@ export function recursivelyFilterKeyInJSON(
|
||||
})
|
||||
return filteredJSON
|
||||
}
|
||||
|
||||
export function clearErrorByComponentId(
|
||||
id: string,
|
||||
errorByComponent: Record<
|
||||
string,
|
||||
{
|
||||
error: string
|
||||
componentId: string
|
||||
}
|
||||
>
|
||||
) {
|
||||
return Object.entries(errorByComponent).reduce((acc, [key, value]) => {
|
||||
if (value.componentId !== id) {
|
||||
acc[key] = value
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
export function clearJobsByComponentId(
|
||||
id: string,
|
||||
jobs: {
|
||||
job: string
|
||||
component: string
|
||||
}[]
|
||||
) {
|
||||
return jobs.filter((job) => job.component !== id)
|
||||
}
|
||||
|
||||
// Returns the error message for the latest job for a component if an error occurred, otherwise undefined
|
||||
export function getErrorFromLatestResult(
|
||||
id: string,
|
||||
errorByComponent: Record<
|
||||
string, // job id
|
||||
{
|
||||
error: string
|
||||
componentId: string
|
||||
}
|
||||
>,
|
||||
jobs: {
|
||||
job: string
|
||||
component: string
|
||||
}[]
|
||||
) {
|
||||
// find last jobId for component id
|
||||
const lastJob = jobs.find((job) => job.component === id)
|
||||
|
||||
if (lastJob?.job && errorByComponent[lastJob.job]) {
|
||||
return errorByComponent[lastJob.job].error
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
import AlignmentEditor from './AlignmentEditor.svelte'
|
||||
import RunnableInputEditor from './inputEditor/RunnableInputEditor.svelte'
|
||||
import TemplateEditor from '$lib/components/TemplateEditor.svelte'
|
||||
import { ccomponents, components, type AppComponent } from '../component'
|
||||
import { ccomponents, type AppComponent } from '../component'
|
||||
import CssProperty from '../componentsPanel/CssProperty.svelte'
|
||||
import GridTab from './GridTab.svelte'
|
||||
import { deleteGridItem } from '../appUtils'
|
||||
import { clearErrorByComponentId, clearJobsByComponentId, deleteGridItem } from '../appUtils'
|
||||
import GridPane from './GridPane.svelte'
|
||||
import { slide } from 'svelte/transition'
|
||||
import { push } from '$lib/history'
|
||||
@@ -35,8 +35,17 @@
|
||||
|
||||
let editor: TemplateEditor | undefined = undefined
|
||||
|
||||
const { app, runnableComponents, selectedComponent, worldStore, focusedGrid, stateId, state } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
const {
|
||||
app,
|
||||
runnableComponents,
|
||||
selectedComponent,
|
||||
worldStore,
|
||||
focusedGrid,
|
||||
stateId,
|
||||
state,
|
||||
errorByComponent,
|
||||
jobs
|
||||
} = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
const { history, ontextfocus } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
@@ -44,6 +53,10 @@
|
||||
|
||||
function removeGridElement() {
|
||||
push(history, $app)
|
||||
|
||||
$errorByComponent = clearErrorByComponentId(component.id, $errorByComponent)
|
||||
$jobs = clearJobsByComponentId(component.id, $jobs)
|
||||
|
||||
$selectedComponent = undefined
|
||||
$focusedGrid = undefined
|
||||
if (componentSettings?.item && !noGrid) {
|
||||
|
||||
@@ -7,7 +7,11 @@
|
||||
import { getContext } from 'svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import type { AppViewerContext, BaseAppComponent } from '../../types'
|
||||
import { appComponentFromType } from '../appUtils'
|
||||
import {
|
||||
appComponentFromType,
|
||||
clearErrorByComponentId,
|
||||
clearJobsByComponentId
|
||||
} from '../appUtils'
|
||||
import type { ButtonComponent } from '../component'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
import TableActionLabel from './TableActionLabel.svelte'
|
||||
@@ -15,7 +19,8 @@
|
||||
export let components: (BaseAppComponent & ButtonComponent)[]
|
||||
export let id: string
|
||||
|
||||
const { selectedComponent, app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { selectedComponent, app, errorByComponent, jobs } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
function addComponent() {
|
||||
const actionId = getNextId(components.map((x) => x.id.split('_')[1]))
|
||||
@@ -30,6 +35,10 @@
|
||||
|
||||
function deleteComponent(cid: string) {
|
||||
components = components.filter((x) => x.id !== cid)
|
||||
|
||||
$errorByComponent = clearErrorByComponentId(cid, $errorByComponent)
|
||||
$jobs = clearJobsByComponentId(cid, $jobs)
|
||||
|
||||
$selectedComponent = id
|
||||
$app = $app
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user