mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 00:02:19 +00:00
188 lines
5.8 KiB
Svelte
188 lines
5.8 KiB
Svelte
<script lang="ts">
|
|
import { CompletedJob, Job, JobService, Preview } from '$lib/gen'
|
|
import { workspaceStore } from '$lib/stores'
|
|
import { displayDate } from '$lib/utils'
|
|
import { faTimes } from '@fortawesome/free-solid-svg-icons'
|
|
import Icon from 'svelte-awesome'
|
|
import { check } from 'svelte-awesome/icons'
|
|
import Tabs from '../common/tabs/Tabs.svelte'
|
|
import Tab from '../common/tabs/Tab.svelte'
|
|
import TabContent from '../common/tabs/TabContent.svelte'
|
|
import DisplayResult from '../DisplayResult.svelte'
|
|
import TableCustom from '../TableCustom.svelte'
|
|
import Drawer from '../common/drawer/Drawer.svelte'
|
|
import { Highlight } from 'svelte-highlight'
|
|
import { json } from 'svelte-highlight/languages'
|
|
import DrawerContent from '../common/drawer/DrawerContent.svelte'
|
|
import HighlightCode from '../HighlightCode.svelte'
|
|
import LogViewer from '../LogViewer.svelte'
|
|
import { Pane } from 'svelte-splitpanes'
|
|
import SplitPanesWrapper from '../splitPanes/SplitPanesWrapper.svelte'
|
|
|
|
export let path: string | undefined
|
|
export let lang: Preview.language
|
|
export let previewIsLoading = false
|
|
export let previewJob: Job | undefined
|
|
export let pastPreviews: CompletedJob[] = []
|
|
export let lastSave: string | null
|
|
|
|
type DrawerContent = {
|
|
mode: 'json' | Preview.language | 'plain'
|
|
title: string
|
|
content: string
|
|
}
|
|
|
|
let selectedTab = 'logs'
|
|
let drawerOpen: boolean = false
|
|
let drawerContent: DrawerContent | undefined = undefined
|
|
|
|
export function setFocusToLogs() {
|
|
selectedTab = 'logs'
|
|
}
|
|
|
|
function openDrawer(newContent: DrawerContent) {
|
|
drawerContent = newContent
|
|
drawerOpen = true
|
|
}
|
|
|
|
function closeDrawer() {
|
|
drawerOpen = false
|
|
}
|
|
</script>
|
|
|
|
<Drawer bind:open={drawerOpen} size="800px">
|
|
<DrawerContent title={drawerContent?.title} on:close={() => closeDrawer()}>
|
|
{#if drawerContent?.mode === 'json'}
|
|
<Highlight language={json} code={JSON.stringify(drawerContent.content, null, 4)} />
|
|
{:else if drawerContent?.mode === 'plain'}
|
|
<pre
|
|
class="overflow-x-auto break-words relative h-full m-2 text-xs bg-white shadow-inner p-2">
|
|
{drawerContent?.content}
|
|
</pre>
|
|
{:else if drawerContent?.mode === 'deno' || drawerContent?.mode === 'python3' || drawerContent?.mode === 'go' || drawerContent?.mode === 'bash'}
|
|
<HighlightCode language={drawerContent?.mode} code={drawerContent?.content} />
|
|
{/if}
|
|
</DrawerContent>
|
|
</Drawer>
|
|
|
|
<Tabs bind:selected={selectedTab} class="mt-1">
|
|
<Tab value="logs" size="xs">Logs/Result</Tab>
|
|
<Tab value="history" size="xs">History</Tab>
|
|
<Tab value="last_save" size="xs">Last save</Tab>
|
|
|
|
<svelte:fragment slot="content">
|
|
<!--
|
|
TabContent would wrap it in an extra div which is undesirable in this situation
|
|
because SplitPanesWrapper uses the parent element as a reference point.
|
|
-->
|
|
{#if selectedTab === 'logs'}
|
|
<SplitPanesWrapper horizontal>
|
|
<Pane class="!duration-[0ms] relative">
|
|
<LogViewer
|
|
duration={previewJob?.['duration_ms']}
|
|
content={previewJob?.logs}
|
|
isLoading={previewIsLoading}
|
|
/>
|
|
</Pane>
|
|
<Pane class="!duration-[0ms]">
|
|
{#if previewJob != undefined && 'result' in previewJob && previewJob.result != undefined}
|
|
<pre class="overflow-x-auto break-words relative h-full p-2"
|
|
><DisplayResult result={previewJob.result} />
|
|
</pre>
|
|
{:else}
|
|
<div class="text-sm text-gray-600 p-2">
|
|
{previewIsLoading ? 'Waiting for result...' : 'Test to see the result here'}
|
|
</div>
|
|
{/if}
|
|
</Pane>
|
|
</SplitPanesWrapper>
|
|
{/if}
|
|
<TabContent value="history" class="p-2">
|
|
<TableCustom>
|
|
<tr slot="header-row">
|
|
<th class="text-xs">Id</th>
|
|
<th class="text-xs">Created at</th>
|
|
<th class="text-xs">Success</th>
|
|
<th class="text-xs">Result</th>
|
|
<th class="text-xs">Code</th>
|
|
<th class="text-xs">Logs</th>
|
|
</tr>
|
|
<tbody slot="body">
|
|
{#each pastPreviews as { id, created_at, success, result }}
|
|
<tr class="">
|
|
<td class="text-xs">
|
|
<a class="pr-3" href="/run/{id}" target="_blank">{id.substring(30)}</a>
|
|
</td>
|
|
<td class="text-xs">{displayDate(created_at)}</td>
|
|
<td class="text-xs">
|
|
{#if success}
|
|
<Icon class="text-green-600" data={check} scale={0.6} />
|
|
{:else}
|
|
<Icon class="text-red-700" data={faTimes} scale={0.6} />
|
|
{/if}
|
|
</td>
|
|
<td class="text-xs">
|
|
<a
|
|
href="#result"
|
|
class="text-xs"
|
|
on:click={() => {
|
|
openDrawer({ mode: 'json', content: result, title: 'Result' })
|
|
}}
|
|
>
|
|
{JSON.stringify(result).substring(0, 30)}...
|
|
</a>
|
|
</td>
|
|
<td class="text-xs">
|
|
<a
|
|
href="#code"
|
|
class="text-xs"
|
|
on:click={async () => {
|
|
const code = (
|
|
await JobService.getCompletedJob({
|
|
workspace: $workspaceStore ?? 'NO_W',
|
|
id
|
|
})
|
|
).raw_code
|
|
|
|
openDrawer({ mode: lang, content: String(code), title: `Code ${lang}` })
|
|
}}
|
|
>
|
|
View code
|
|
</a>
|
|
</td>
|
|
<td>
|
|
<a
|
|
href="#logs"
|
|
class="text-xs"
|
|
on:click={async () => {
|
|
const logs = (
|
|
await JobService.getCompletedJob({
|
|
workspace: $workspaceStore ?? 'NO_W',
|
|
id
|
|
})
|
|
).logs
|
|
openDrawer({ mode: 'plain', content: String(logs), title: `Code ${lang}` })
|
|
}}
|
|
>
|
|
View logs
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{/each}
|
|
</tbody>
|
|
</TableCustom>
|
|
</TabContent>
|
|
<TabContent value="last_save" class="p-2">
|
|
{#if lastSave}
|
|
<div class="text-sm font-bold text-gray-600">
|
|
Last local save for path
|
|
<span class="italic">{path}</span>
|
|
</div>
|
|
<HighlightCode language={lang} code={lastSave} />
|
|
{:else}
|
|
No local save
|
|
{/if}
|
|
</TabContent>
|
|
</svelte:fragment>
|
|
</Tabs>
|