further apps improvements

This commit is contained in:
Ruben Fiszel
2022-12-30 11:48:03 +01:00
parent aedd02bc2a
commit e8fc94d7ef
16 changed files with 100 additions and 103 deletions
+1
View File
@@ -57,6 +57,7 @@ pub struct ListableApp {
pub extra_perms: serde_json::Value,
pub execution_mode: String,
pub starred: bool,
pub edited_at: chrono::DateTime<chrono::Utc>,
}
#[derive(FromRow, Serialize, Deserialize)]
@@ -21,6 +21,8 @@
let intervalId: SetIntervalAsyncTimer<unknown[]> | undefined = undefined
let syncIteration: number = 0
let errorIteration = 0
let ITERATIONS_BEFORE_SLOW_REFRESH = 10
let ITERATIONS_BEFORE_SUPER_SLOW_REFRESH = 100
@@ -119,6 +121,8 @@
}
export async function watchJob(testId: string) {
syncIteration = 0
errorIteration = 0
const isCompleted = await loadTestJob(testId)
if (!isCompleted) {
isLoading = true
@@ -161,10 +165,10 @@
}
notfound = false
} catch (err) {
intervalId && clearIntervalAsync(intervalId!)
clearCurrentJob()
if (err.status === 404) {
errorIteration += 1
if (errorIteration == 5) {
notfound = true
await clearCurrentJob()
}
console.warn(err)
}
@@ -1,25 +1,31 @@
<script lang="ts">
import Button from '$lib/components/common/button/Button.svelte'
import { faRefresh } from '@fortawesome/free-solid-svg-icons'
import { RefreshCcw, RefreshCw } from 'lucide-svelte'
import { getContext } from 'svelte'
import type { AppEditorContext } from '../../types'
export let componentId: string
const { runnableComponents } = getContext<AppEditorContext>('AppEditorContext')
const { runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
let loading = false
async function refresh() {
loading = true
window.dispatchEvent(new Event('pointerup'))
await $runnableComponents[componentId]?.()
loading = false
}
let loading = false
$: $worldStore?.outputsById[componentId]?.['loading']?.subscribe({
next: (value) => {
loading = value
}
})
</script>
<Button
iconOnly
startIcon={{ icon: faRefresh, classes: loading ? 'animate-spin' : '' }}
color="dark"
size="xs"
on:click={refresh}
/>
<button
on:pointerdown|preventDefault|stopPropagation
on:click|preventDefault|stopPropagation={refresh}
class="center-center p-1 rounded border bg-white/60 z-40"
>
<RefreshCw class={loading ? 'animate-spin' : ''} size={16} />
</button>
@@ -14,6 +14,7 @@
import { fieldTypeToTsType, loadSchema, schemaToInputsSpec } from '../../utils'
import InputValue from './InputValue.svelte'
import MissingConnectionWarning from './MissingConnectionWarning.svelte'
import RefreshButton from './RefreshButton.svelte'
// Component props
export let id: string
@@ -78,10 +79,9 @@
return areAllArgsValid
}
$: isValid = argMergedArgsValid(
{ ...extraQueryParams, ...runnableInputValues, ...args },
testJobLoader
)
$: isValid =
Object.keys(fields ?? {}).length == 0 ||
argMergedArgsValid({ ...extraQueryParams, ...runnableInputValues, ...args }, testJobLoader)
// Test job internal state
let testJob: CompletedJob | undefined = undefined
@@ -297,14 +297,18 @@
{/if}
{#if !runnable && autoRefresh}
<Alert type="warning" size="xs" class="mt-2" title="Missing runnable">
<Alert type="warning" size="xs" class="mt-2 px-1" title="Missing runnable">
Please select a runnable
</Alert>
{:else if autoRefresh === true}
<div class="flex absolute top-1 right-1">
<RefreshButton componentId={id} />
</div>
{#if isValid}
<slot />
{:else}
<Alert type="info" size="xs" class="mt-2" title="Missing inputs">
<Alert type="info" size="xs" class="mt-2 px-1" title="Missing inputs">
Please fill in all the inputs
{#each Object.keys(fields ?? {}) as key}
@@ -26,7 +26,7 @@
$: result = [] as Array<Record<string, any>>
let search: 'Runnable' | 'Component' | 'Disabled' = 'Disabled'
let search: 'Runnable' | 'Component' | 'Disabled' | undefined = undefined
let searchValue = ''
let pagination: boolean | undefined = undefined
@@ -114,16 +114,16 @@
<RunnableWrapper bind:componentInput {id} bind:result {extraQueryParams}>
{#if Array.isArray(result) && result.every(isObject)}
<div class="border border-gray-300 shadow-sm divide-y divide-gray-300 flex flex-col h-full">
<div class="py-2 px-4">
<div class="flex justify-between items-center">
<RefreshButton componentId={id} />
{#if search !== 'Disabled'}
{#if search !== 'Disabled'}
<div class="px-4 py-2">
<div class="flex items-center">
<div>
<DebouncedInput placeholder="Search..." bind:value={searchValue} />
</div>
{/if}
</div>
</div>
</div>
{/if}
<div class="overflow-auto flex-1 w-full">
<table class="divide-y divide-gray-300 w-full border-b border-b-gray-200">
<thead class="bg-gray-50 text-left">
@@ -32,10 +32,12 @@
import { grid } from 'd3-dag'
import SettingsPanel from './SettingsPanel.svelte'
import { fly } from 'svelte/transition'
import type { Policy } from '$lib/gen'
export let app: App
export let path: string
export let initialMode: EditorMode = 'dnd'
export let policy: Policy
const appStore = writable<App>(app)
const worldStore = writable<World | undefined>(undefined)
@@ -49,7 +51,7 @@
input: undefined
})
const runnableComponents = writable<Record<string, () => void>>({})
const runnableComponents = writable<Record<string, () => Promise<void>>>({})
setContext<AppEditorContext>('AppEditorContext', {
worldStore,
@@ -88,20 +90,20 @@
{/if}
{#if previewing}
<AppPreview app={$appStore} appPath={path} {breakpoint} />
<AppPreview app={$appStore} appPath={path} {breakpoint} {policy} />
{:else}
<SplitPanesWrapper class="max-w-full overflow-hidden">
<Pane size={20}>
<Pane size={15}>
<ContextPanel />
</Pane>
<Pane size={55}>
<Pane size={65}>
<SplitPanesWrapper horizontal>
<Pane size={70}>
<div class="bg-gray-100 w-full p-4 h-full overflow-auto">
<div class={classNames('bg-gray-100 mx-auto relative min-h-full', width)}>
{#if $appStore.grid}
<div class={classNames('w-full p-2 h-full bg-white', width)}>
<GridEditor />
<div class={classNames('w-full px-2 pb-2 h-full bg-white', width)}>
<GridEditor {policy} />
</div>
{/if}
{#if $connectingInput.opened}
@@ -124,7 +126,7 @@
</Pane>
</SplitPanesWrapper>
</Pane>
<Pane size={25} minSize={20} maxSize={33}>
<Pane size={20} minSize={15} maxSize={33}>
<div class="relative">
<Tabs bind:selected={selectedTab}>
<Tab value="insert" size="xs">
@@ -13,10 +13,12 @@
import GridEditor from './GridEditor.svelte'
import { classNames } from '$lib/utils'
import type { Policy } from '$lib/gen'
export let app: App
export let appPath: string
export let breakpoint: Writable<EditorBreakpoint>
export let policy: Policy
const appStore = writable<App>(app)
const worldStore = writable<World | undefined>(undefined)
@@ -29,7 +31,7 @@
input: undefined
})
const runnableComponents = writable<Record<string, () => void>>({})
const runnableComponents = writable<Record<string, () => Promise<void>>>({})
setContext<AppEditorContext>('AppEditorContext', {
worldStore,
@@ -57,7 +59,7 @@
<div class="h-full w-5/6 mx-auto">
{#if $appStore.grid}
<div class={classNames('mx-auto h-full', width)}>
<GridEditor />
<GridEditor {policy} />
</div>
{/if}
</div>
@@ -15,7 +15,7 @@
<span
class={classNames(
'px-2 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute z-50',
selected ? 'bg-indigo-500 text-white' : 'bg-gray-200/60 text-gray-500'
selected ? 'bg-indigo-500/90 text-white' : 'bg-gray-200/60 text-gray-500'
)}
>
{component.id}
@@ -24,7 +24,7 @@
{#if pointerdown || selected}
<button
class={classNames(
'text-white px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute right-8 z-50 cursor-pointer',
'text-white px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute right-10 z-50 cursor-pointer',
' hover:bg-gray-800',
selected ? 'bg-gray-600/90' : 'bg-gray-600/80'
)}
@@ -44,19 +44,8 @@
<span
on:mousedown|stopPropagation|capture
class={classNames(
'text-white px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute right-16 z-50 cursor-move',
'text-white px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute right-20 z-50 cursor-move',
'bg-gray-600/80'
)}><Move size={16} /></span
>
<button
class={classNames(
'text-white px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute right-0 z-50 cursor-pointer',
'bg-gray-600/80 hover:bg-gray-800'
)}
on:click={() => {
dispatch('delete')
}}
>
<X size={16} />
</button>
{/if}
@@ -5,9 +5,11 @@
import ComponentEditor from './ComponentEditor.svelte'
import { classNames } from '$lib/utils'
import { columnConfiguration, disableDrag, enableDrag, isFixed, toggleFixed } from '../gridUtils'
import { fly } from 'svelte/transition'
import RecomputeAllComponents from './RecomputeAllComponents.svelte'
import type { Policy } from '$lib/gen'
export let policy: Policy
const {
selectedComponent,
@@ -104,7 +106,15 @@
on:pointerup={onpointerup}
class="bg-white h-full relative"
>
<RecomputeAllComponents />
<div class="w-full flex justify-between border-b p-1 m-1 items-center gap-4">
<h2>{$app.title}</h2>
<RecomputeAllComponents />
<div class="text-2xs text-gray-600"
>{policy.execution_mode} mode {policy.on_behalf_of
? `on behalf of ${policy.on_behalf_of}`
: ''}</div
>
</div>
<Grid
bind:items={$app.grid}
let:dataItem
@@ -1,7 +1,5 @@
<script lang="ts">
import Button from '$lib/components/common/button/Button.svelte'
import { classNames } from '$lib/utils'
import { faRefresh } from '@fortawesome/free-solid-svg-icons'
import { RefreshCw } from 'lucide-svelte'
import { getContext } from 'svelte'
import type { AppEditorContext } from '../types'
@@ -20,12 +18,10 @@
}
</script>
<Button
size="xs"
btnClasses="m-2 mb-6"
startIcon={{ icon: faRefresh, classes: classNames(loading ? 'animate-spin' : '', 'mr-2') }}
color="dark"
on:click={onRefresh}
<button
on:click|preventDefault|stopPropagation={onRefresh}
class="center-center p-1 rounded border bg-white/60 inline-flex gap-2"
>
Recompute all ({Object.keys($runnableComponents).length})
</Button>
<RefreshCw class={loading ? 'animate-spin' : ''} size={20} /> ({Object.keys($runnableComponents)
.length})
</button>
@@ -8,7 +8,7 @@ const Breakpoints = {
}
const columnConfiguration: ColumnConfiguration = [
[Breakpoints.lg, 12],
[Breakpoints.lg, 9],
[Breakpoints.sm, 3]
]
+1 -1
View File
@@ -133,7 +133,7 @@ export type AppEditorContext = {
mode: Writable<EditorMode>
connectingInput: Writable<ConnectingInput>
breakpoint: Writable<EditorBreakpoint>
runnableComponents: Writable<Record<string, () => void>>
runnableComponents: Writable<Record<string, () => Promise<void>>>
appPath: string
}
@@ -53,18 +53,18 @@
<nav class="grow flex md:justify-between flex-col overflow-x-hidden scrollbar-hidden px-2 md:pb-4">
<div class="space-y-1 pt-4 mb-6 md:mb-10">
{#each mainMenuLinks as menuLink (menuLink.href)}
<MenuLink class="text-md" {...menuLink} {isCollapsed} />
<MenuLink class="!text-md" {...menuLink} {isCollapsed} />
{/each}
</div>
<div>
<div class="space-y-1 mb-6 md:mb-10">
<div class="mb-6 md:mb-10">
{#each secondaryMenuLinks as menuLink (menuLink.href)}
<MenuLink class="text-xs" {...menuLink} {isCollapsed} />
<MenuLink class="!text-xs" {...menuLink} {isCollapsed} />
{/each}
</div>
<div>
{#each thirdMenuLinks as menuLink (menuLink.href)}
<MenuLink class="text-xs" {...menuLink} {isCollapsed} />
<MenuLink class="!text-xs" {...menuLink} {isCollapsed} />
{/each}
</div>
</div>
@@ -11,7 +11,7 @@
import SidebarContent from '$lib/components/sidebar/SidebarContent.svelte'
import { starStore, superadmin, usageStore, userStore, workspaceStore } from '$lib/stores'
import CenteredModal from '$lib/components/CenteredModal.svelte'
import { beforeNavigate, goto } from '$app/navigation'
import { afterNavigate, beforeNavigate, goto } from '$app/navigation'
import UserSettings from '$lib/components/UserSettings.svelte'
import SuperadminSettings from '$lib/components/SuperadminSettings.svelte'
import WindmillIcon from '$lib/components/icons/WindmillIcon.svelte'
@@ -81,16 +81,15 @@
]
}
$: onAppEditor = $page.url.pathname?.includes('apps')
$: if (onAppEditor) {
isCollapsed = true
} else {
if (innerWidth < 1248 && innerWidth >= 768) {
afterNavigate((n) => {
if (n.to?.url.pathname.startsWith('/apps')) {
isCollapsed = true
} else if (innerWidth >= 1248 || innerWidth < 768) {
isCollapsed = false
}
})
$: if (innerWidth < 1248 && innerWidth >= 768) {
isCollapsed = true
} else if (innerWidth >= 1248 || innerWidth < 768) {
isCollapsed = false
}
</script>
@@ -199,9 +198,7 @@
<WindmillIcon white={true} height="20px" width="20px" />
</div>
{#if !isCollapsed}
<span>
Windmill
</span>
<span> Windmill </span>
{/if}
</div>
</button>
@@ -221,7 +218,6 @@
on:click={() => {
isCollapsed = !isCollapsed
}}
disabled={onAppEditor}
>
<Icon
data={faArrowLeft}
@@ -23,6 +23,6 @@
{#if app}
<div class="h-screen">
<AppEditor app={app.value} path={app.path} />
<AppEditor app={app.value} path={app.path} policy={app.policy} />
</div>
{/if}
@@ -3,12 +3,9 @@
import AppPreview from '$lib/components/apps/editor/AppPreview.svelte'
import type { EditorBreakpoint } from '$lib/components/apps/types'
import CenteredPage from '$lib/components/CenteredPage.svelte'
import { Skeleton } from '$lib/components/common'
import Button from '$lib/components/common/button/Button.svelte'
import { AppService, AppWithLastVersion } from '$lib/gen'
import { workspaceStore } from '$lib/stores'
import { faPen } from '@fortawesome/free-solid-svg-icons'
import { writable } from 'svelte/store'
let app: AppWithLastVersion | undefined = undefined
@@ -24,20 +21,10 @@
const breakpoint = writable<EditorBreakpoint>('lg')
</script>
<Skeleton loading={app == undefined} layout={[10]} />
<CenteredPage>
{#if app}
<div class="flex justify-between items-center py-4">
<h2>{app.value.title}</h2>
<Button size="xs" href="/apps/edit/{$page.params.path}" startIcon={{ icon: faPen }}>
Edit
</Button>
</div>
<div class="border rounded-md p-2">
<AppPreview app={app.value} appPath={app.path} {breakpoint} />
</div>
{/if}
</CenteredPage>
{#if app}
<div class="border rounded-md p-2 w-full">
<AppPreview app={app.value} appPath={app.path} {breakpoint} policy={app.policy} />
</div>
{:else}
<Skeleton layout={[10]} />
{/if}