feat(frontend): hide/show app editor panels (#4266)
* feat(frontend): wip * feat(frontend): wip * feat(frontend): wip * feat(frontend): wip * feat(frontend): add all shortcuts * feat(frontend): improve the shorcuts * feat(frontend): improve the shorcuts * feat(frontend): hide the buttons in preview mode * feat(frontend): improve the shorcuts * feat(frontend): fix shortcuts * feat(frontend): fix shared state between log panels
This commit is contained in:
@@ -28,12 +28,10 @@
|
||||
import ComponentList from './componentsPanel/ComponentList.svelte'
|
||||
import ContextPanel from './contextPanel/ContextPanel.svelte'
|
||||
|
||||
import InlineScriptsPanel from './inlineScriptsPanel/InlineScriptsPanel.svelte'
|
||||
|
||||
import { page } from '$app/stores'
|
||||
import ItemPicker from '$lib/components/ItemPicker.svelte'
|
||||
import VariableEditor from '$lib/components/VariableEditor.svelte'
|
||||
import { VariableService, type Policy } from '$lib/gen'
|
||||
import { VariableService, type Job, type Policy } from '$lib/gen'
|
||||
import { initHistory } from '$lib/history'
|
||||
import { Component, Minus, Paintbrush, Plus, Smartphone } from 'lucide-svelte'
|
||||
import { findGridItem, findGridItemParentGrid } from './appUtils'
|
||||
@@ -56,6 +54,8 @@
|
||||
import type DiffDrawer from '$lib/components/DiffDrawer.svelte'
|
||||
import RunnableJobPanel from './RunnableJobPanel.svelte'
|
||||
import { goto, replaceState } from '$app/navigation'
|
||||
import HideButton from './settingsPanel/HideButton.svelte'
|
||||
import AppEditorBottomPanel from './AppEditorBottomPanel.svelte'
|
||||
|
||||
export let app: App
|
||||
export let path: string
|
||||
@@ -311,7 +311,7 @@
|
||||
let gridPanelSize = 70
|
||||
|
||||
let leftPanelSize = 22
|
||||
let centerPanelSize = 63
|
||||
let centerPanelSize = 56
|
||||
let rightPanelSize = 22
|
||||
|
||||
let tmpRunnablePanelSize = -1
|
||||
@@ -540,11 +540,105 @@
|
||||
|
||||
let runnableJobEnterTimeout: NodeJS.Timeout | undefined = undefined
|
||||
let stillInJobEnter = false
|
||||
let storedLeftPanelSize = 0
|
||||
let storedRightPanelSize = 0
|
||||
let storedBottomPanelSize = 0
|
||||
|
||||
let centerPanelWidth = 0
|
||||
|
||||
function hideLeftPanel() {
|
||||
storedLeftPanelSize = leftPanelSize
|
||||
leftPanelSize = 0
|
||||
centerPanelSize = centerPanelSize + storedLeftPanelSize
|
||||
}
|
||||
|
||||
function hideRightPanel() {
|
||||
storedRightPanelSize = rightPanelSize
|
||||
rightPanelSize = 0
|
||||
centerPanelSize = centerPanelSize + storedRightPanelSize
|
||||
}
|
||||
|
||||
function hideBottomPanel() {
|
||||
storedBottomPanelSize = runnablePanelSize
|
||||
gridPanelSize = 99
|
||||
runnablePanelSize = 0
|
||||
}
|
||||
|
||||
function showLeftPanel() {
|
||||
leftPanelSize = storedLeftPanelSize
|
||||
centerPanelSize = centerPanelSize - storedLeftPanelSize
|
||||
storedLeftPanelSize = 0
|
||||
}
|
||||
|
||||
function showRightPanel() {
|
||||
rightPanelSize = storedRightPanelSize
|
||||
centerPanelSize = centerPanelSize - storedRightPanelSize
|
||||
storedRightPanelSize = 0
|
||||
}
|
||||
|
||||
function showBottomPanel() {
|
||||
runnablePanelSize = storedBottomPanelSize
|
||||
gridPanelSize = gridPanelSize - storedBottomPanelSize
|
||||
storedBottomPanelSize = 0
|
||||
}
|
||||
|
||||
function keydown(event: KeyboardEvent) {
|
||||
let classes = event.target?.['className']
|
||||
if (
|
||||
(typeof classes === 'string' && classes.includes('inputarea')) ||
|
||||
['INPUT', 'TEXTAREA'].includes(document.activeElement?.tagName!)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case 'b': {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
event.preventDefault()
|
||||
|
||||
if (leftPanelSize !== 0) {
|
||||
hideLeftPanel()
|
||||
} else {
|
||||
showLeftPanel()
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'u': {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
event.preventDefault()
|
||||
|
||||
if (rightPanelSize !== 0) {
|
||||
hideRightPanel()
|
||||
} else {
|
||||
showRightPanel()
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'l': {
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
event.preventDefault()
|
||||
|
||||
if (runnablePanelSize !== 0) {
|
||||
hideBottomPanel()
|
||||
} else {
|
||||
showBottomPanel()
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
let testJob: Job | undefined = undefined
|
||||
let jobToWatch: { componentId: string; job: string } | undefined = undefined
|
||||
</script>
|
||||
|
||||
<DarkModeObserver on:change={onThemeChange} />
|
||||
|
||||
<svelte:window on:hashchange={hashchange} />
|
||||
<svelte:window on:hashchange={hashchange} on:keydown={keydown} />
|
||||
|
||||
{#if !$userStore?.operator}
|
||||
{#if $appStore}
|
||||
@@ -556,6 +650,15 @@
|
||||
{diffDrawer}
|
||||
bind:savedApp
|
||||
{version}
|
||||
leftPanelHidden={leftPanelSize === 0}
|
||||
rightPanelHidden={rightPanelSize === 0}
|
||||
bottomPanelHidden={runnablePanelSize === 0}
|
||||
on:showLeftPanel={() => showLeftPanel()}
|
||||
on:showRightPanel={() => showRightPanel()}
|
||||
on:hideLeftPanel={() => hideLeftPanel()}
|
||||
on:hideRightPanel={() => hideRightPanel()}
|
||||
on:hideBottomPanel={() => hideBottomPanel()}
|
||||
on:showBottomPanel={() => showBottomPanel()}
|
||||
/>
|
||||
{#if $mode === 'preview'}
|
||||
<SplitPanesWrapper>
|
||||
@@ -601,7 +704,7 @@
|
||||
<!-- {yTop} -->
|
||||
|
||||
<SecondaryMenu right={false} />
|
||||
<ContextPanel />
|
||||
<ContextPanel on:hidePanel={() => hideLeftPanel()} />
|
||||
</div>
|
||||
</Pane>
|
||||
<Pane bind:size={centerPanelSize}>
|
||||
@@ -618,7 +721,39 @@
|
||||
'wm-app-viewer h-full overflow-visible'
|
||||
)}
|
||||
style={$appStore.css?.['app']?.['viewer']?.style}
|
||||
bind:clientWidth={centerPanelWidth}
|
||||
>
|
||||
{#if leftPanelSize === 0}
|
||||
<div class="absolute top-0.5 left-0.5 z-50">
|
||||
<HideButton
|
||||
on:click={() => showLeftPanel()}
|
||||
direction="right"
|
||||
hidden
|
||||
btnClasses="border bg-surface"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if rightPanelSize === 0}
|
||||
<div class="absolute top-0.5 right-0.5 z-50">
|
||||
<HideButton
|
||||
on:click={() => showRightPanel()}
|
||||
direction="left"
|
||||
hidden
|
||||
btnClasses="border bg-surface"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if runnablePanelSize === 0}
|
||||
<div class="absolute bottom-0.5 right-0.5 z-50">
|
||||
<HideButton
|
||||
on:click={() => showBottomPanel()}
|
||||
direction="bottom"
|
||||
hidden
|
||||
btnClasses="border bg-surface"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="absolute bottom-2 left-2 z-50 border bg-surface">
|
||||
<div class="flex flex-row gap-2 text-xs items-center h-8 px-1">
|
||||
<Button
|
||||
@@ -706,9 +841,7 @@
|
||||
</Pane>
|
||||
{#if $connectingInput?.opened == false && !$componentActive}
|
||||
<Pane bind:size={runnablePanelSize}>
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="relative h-full w-full overflow-x-visible"
|
||||
<AppEditorBottomPanel
|
||||
on:mouseenter={() => {
|
||||
runnableJobEnterTimeout && clearTimeout(runnableJobEnterTimeout)
|
||||
stillInJobEnter = true
|
||||
@@ -718,6 +851,7 @@
|
||||
}
|
||||
}, 200)
|
||||
}}
|
||||
on:hidePanel={() => hideBottomPanel()}
|
||||
on:mouseleave={() => {
|
||||
stillInJobEnter = false
|
||||
runnableJobEnterTimeout = setTimeout(
|
||||
@@ -725,98 +859,119 @@
|
||||
200
|
||||
)
|
||||
}}
|
||||
{rightPanelSize}
|
||||
{centerPanelWidth}
|
||||
{runnablePanelSize}
|
||||
>
|
||||
<InlineScriptsPanel />
|
||||
<RunnableJobPanel />
|
||||
</div>
|
||||
<RunnableJobPanel
|
||||
float={rightPanelSize !== 0}
|
||||
hidden={runnablePanelSize === 0}
|
||||
bind:testJob
|
||||
bind:jobToWatch
|
||||
/>
|
||||
</AppEditorBottomPanel>
|
||||
</Pane>
|
||||
{/if}
|
||||
</Splitpanes>
|
||||
</Pane>
|
||||
<Pane bind:size={rightPanelSize} minSize={15} maxSize={33}>
|
||||
<div bind:clientWidth={$runnableJob.width} class="relative flex flex-col h-full">
|
||||
<Tabs bind:selected={selectedTab} wrapperClass="!min-h-[42px]" class="!h-full">
|
||||
<Popover disappearTimeout={0} notClickable placement="bottom">
|
||||
<svelte:fragment slot="text">Component library</svelte:fragment>
|
||||
<Tab
|
||||
value="insert"
|
||||
size="xs"
|
||||
class="h-full"
|
||||
on:pointerdown={() => {
|
||||
if ($cssEditorOpen) {
|
||||
$cssEditorOpen = false
|
||||
selectedTab = 'insert'
|
||||
}
|
||||
}}
|
||||
id="app-editor-component-library-tab"
|
||||
>
|
||||
<div class="m-1 center-center">
|
||||
<Plus size={18} />
|
||||
</div>
|
||||
</Tab>
|
||||
</Popover>
|
||||
<Popover disappearTimeout={0} notClickable placement="bottom">
|
||||
<svelte:fragment slot="text">Component settings</svelte:fragment>
|
||||
<Tab
|
||||
value="settings"
|
||||
size="xs"
|
||||
class="h-full"
|
||||
on:pointerdown={() => {
|
||||
if ($cssEditorOpen) {
|
||||
$cssEditorOpen = false
|
||||
selectedTab = 'settings'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div class="m-1 center-center">
|
||||
<Component size={18} />
|
||||
</div>
|
||||
</Tab>
|
||||
</Popover>
|
||||
<Popover disappearTimeout={0} notClickable placement="bottom">
|
||||
<svelte:fragment slot="text">Global styling</svelte:fragment>
|
||||
<Tab
|
||||
value="css"
|
||||
size="xs"
|
||||
class="h-full"
|
||||
on:pointerdown={() => {
|
||||
if (!$cssEditorOpen) {
|
||||
$cssEditorOpen = true
|
||||
selectedTab = 'css'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div class="m-1 center-center">
|
||||
<Paintbrush size={18} />
|
||||
</div>
|
||||
</Tab>
|
||||
</Popover>
|
||||
<div slot="content" class="h-full overflow-y-auto">
|
||||
<TabContent class="overflow-auto h-full" value="settings">
|
||||
{#if $selectedComponent !== undefined}
|
||||
<SettingsPanel
|
||||
on:delete={() => {
|
||||
befSelected = undefined
|
||||
{#if rightPanelSize === 0}
|
||||
<div class="relative flex flex-col h-full" />
|
||||
{:else}
|
||||
<Pane bind:size={rightPanelSize} minSize={15} maxSize={33}>
|
||||
<div bind:clientWidth={$runnableJob.width} class="relative flex flex-col h-full">
|
||||
<Tabs bind:selected={selectedTab} wrapperClass="!min-h-[42px]" class="!h-full">
|
||||
<Popover disappearTimeout={0} notClickable placement="bottom">
|
||||
<svelte:fragment slot="text">Component library</svelte:fragment>
|
||||
<Tab
|
||||
value="insert"
|
||||
size="xs"
|
||||
class="h-full"
|
||||
on:pointerdown={() => {
|
||||
if ($cssEditorOpen) {
|
||||
$cssEditorOpen = false
|
||||
selectedTab = 'insert'
|
||||
}}
|
||||
/>
|
||||
<SecondaryMenu right />
|
||||
{:else}
|
||||
<div class="min-w-[150px] text-sm !text-secondary text-center py-8 px-2">
|
||||
Select a component to see the settings for it
|
||||
}
|
||||
}}
|
||||
id="app-editor-component-library-tab"
|
||||
>
|
||||
<div class="m-1 center-center">
|
||||
<Plus size={18} />
|
||||
</div>
|
||||
{/if}
|
||||
</TabContent>
|
||||
<TabContent value="insert">
|
||||
<ComponentList />
|
||||
</TabContent>
|
||||
<TabContent value="css" class="h-full">
|
||||
<CssSettings />
|
||||
</TabContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Pane>
|
||||
</Tab>
|
||||
</Popover>
|
||||
<Popover disappearTimeout={0} notClickable placement="bottom">
|
||||
<svelte:fragment slot="text">Component settings</svelte:fragment>
|
||||
<Tab
|
||||
value="settings"
|
||||
size="xs"
|
||||
class="h-full"
|
||||
on:pointerdown={() => {
|
||||
if ($cssEditorOpen) {
|
||||
$cssEditorOpen = false
|
||||
selectedTab = 'settings'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div class="m-1 center-center">
|
||||
<Component size={18} />
|
||||
</div>
|
||||
</Tab>
|
||||
</Popover>
|
||||
<Popover disappearTimeout={0} notClickable placement="bottom">
|
||||
<svelte:fragment slot="text">Global styling</svelte:fragment>
|
||||
<Tab
|
||||
value="css"
|
||||
size="xs"
|
||||
class="h-full"
|
||||
on:pointerdown={() => {
|
||||
if (!$cssEditorOpen) {
|
||||
$cssEditorOpen = true
|
||||
selectedTab = 'css'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div class="m-1 center-center">
|
||||
<Paintbrush size={18} />
|
||||
</div>
|
||||
</Tab>
|
||||
</Popover>
|
||||
<div class="h-full w-full flex justify-end px-1">
|
||||
<HideButton
|
||||
on:click={() => {
|
||||
storedRightPanelSize = rightPanelSize
|
||||
rightPanelSize = 0
|
||||
centerPanelSize = centerPanelSize + storedRightPanelSize
|
||||
}}
|
||||
direction="right"
|
||||
/>
|
||||
</div>
|
||||
<div slot="content" class="h-full overflow-y-auto">
|
||||
<TabContent class="overflow-auto h-full" value="settings">
|
||||
{#if $selectedComponent !== undefined}
|
||||
<SettingsPanel
|
||||
on:delete={() => {
|
||||
befSelected = undefined
|
||||
selectedTab = 'insert'
|
||||
}}
|
||||
/>
|
||||
<SecondaryMenu right />
|
||||
{:else}
|
||||
<div class="min-w-[150px] text-sm !text-secondary text-center py-8 px-2">
|
||||
Select a component to see the settings for it
|
||||
</div>
|
||||
{/if}
|
||||
</TabContent>
|
||||
<TabContent value="insert">
|
||||
<ComponentList />
|
||||
</TabContent>
|
||||
<TabContent value="css" class="h-full">
|
||||
<CssSettings />
|
||||
</TabContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Pane>
|
||||
{/if}
|
||||
</Splitpanes>
|
||||
</SplitPanesWrapper>
|
||||
{/if}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<script lang="ts">
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
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
|
||||
</script>
|
||||
|
||||
{#if rightPanelSize !== 0}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class={twMerge('relative h-full w-full overflow-x-visible')} on:mouseenter on:mouseleave>
|
||||
<InlineScriptsPanel on:hidePanel />
|
||||
<RunnableJobPanel hidden={runnablePanelSize === 0} />
|
||||
<slot />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-row relative w-full h-full">
|
||||
<InlineScriptsPanel width={centerPanelWidth - 400} on:hidePanel />
|
||||
|
||||
<slot />
|
||||
</div>
|
||||
{/if}
|
||||
@@ -33,7 +33,7 @@
|
||||
Smartphone,
|
||||
FileClock
|
||||
} from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import {
|
||||
classNames,
|
||||
@@ -84,6 +84,7 @@
|
||||
import { collectOneOfFields } from './appUtils'
|
||||
import Summary from '$lib/components/Summary.svelte'
|
||||
import ToggleEnable from '$lib/components/common/toggleButton-v2/ToggleEnable.svelte'
|
||||
import HideButton from './settingsPanel/HideButton.svelte'
|
||||
|
||||
async function hash(message) {
|
||||
try {
|
||||
@@ -116,6 +117,9 @@
|
||||
}
|
||||
| undefined = undefined
|
||||
export let version: number | undefined = undefined
|
||||
export let leftPanelHidden: boolean = false
|
||||
export let rightPanelHidden: boolean = false
|
||||
export let bottomPanelHidden: boolean = false
|
||||
|
||||
const {
|
||||
app,
|
||||
@@ -126,7 +130,8 @@
|
||||
jobsById,
|
||||
staticExporter,
|
||||
errorByComponent,
|
||||
openDebugRun
|
||||
openDebugRun,
|
||||
mode
|
||||
} = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
const { history, jobsDrawerOpen, refreshComponents } =
|
||||
@@ -743,6 +748,8 @@
|
||||
export function openTroubleshootPanel() {
|
||||
debugAppDrawerOpen = true
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
@@ -1322,6 +1329,43 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if $mode !== 'preview'}
|
||||
<div class="flex gap-1">
|
||||
<HideButton
|
||||
direction="left"
|
||||
hidden={leftPanelHidden}
|
||||
on:click={() => {
|
||||
if (leftPanelHidden) {
|
||||
dispatch('showLeftPanel')
|
||||
} else {
|
||||
dispatch('hideLeftPanel')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<HideButton
|
||||
hidden={bottomPanelHidden}
|
||||
direction="bottom"
|
||||
on:click={() => {
|
||||
if (bottomPanelHidden) {
|
||||
dispatch('showBottomPanel')
|
||||
} else {
|
||||
dispatch('hideBottomPanel')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<HideButton
|
||||
hidden={rightPanelHidden}
|
||||
direction="right"
|
||||
on:click={() => {
|
||||
if (rightPanelHidden) {
|
||||
dispatch('showRightPanel')
|
||||
} else {
|
||||
dispatch('hideRightPanel')
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if $enterpriseLicense && appPath != ''}
|
||||
<Awareness />
|
||||
{/if}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script lang="ts">
|
||||
import DisplayResult from '$lib/components/DisplayResult.svelte'
|
||||
import LogViewer from '$lib/components/LogViewer.svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { Splitpanes, Pane } from 'svelte-splitpanes'
|
||||
import type { AppEditorContext } from '../types'
|
||||
import TestJobLoader from '$lib/components/TestJobLoader.svelte'
|
||||
import type { Job } from '$lib/gen'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import RunnalbeJobPanelInner from './RunnalbeJobPanelInner.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
|
||||
|
||||
const { runnableJobEditorPanel, selectedComponentInEditor } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
let testJob: Job | undefined = undefined
|
||||
let testIsLoading = false
|
||||
|
||||
let testJobLoader: TestJobLoader
|
||||
|
||||
let jobToWatch: { componentId: string; job: string } | undefined = undefined
|
||||
$: $runnableJobEditorPanel.focused &&
|
||||
$selectedComponentInEditor &&
|
||||
$runnableJobEditorPanel.jobs &&
|
||||
@@ -48,57 +48,25 @@
|
||||
|
||||
<TestJobLoader bind:this={testJobLoader} bind:isLoading={testIsLoading} bind:job={testJob} />
|
||||
|
||||
{#if ($runnableJobEditorPanel.focused && $selectedComponentInEditor) || logDrawerOpen || resultDrawerOpen}
|
||||
{#if ($runnableJobEditorPanel.focused && $selectedComponentInEditor) || logDrawerOpen || resultDrawerOpen || !float}
|
||||
{@const frontendJob = $runnableJobEditorPanel?.frontendJobs[$selectedComponentInEditor ?? '']}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="absolute z-[100] top-0 right-0 border-t h-full"
|
||||
style="width: {$runnableJobEditorPanel.width}px; transform: translateX({$runnableJobEditorPanel.width}px);"
|
||||
>
|
||||
<Splitpanes horizontal>
|
||||
<Pane size={frontendJob ? 30 : 50} minSize={10}>
|
||||
{#if frontendJob}
|
||||
<div class="p-2 bg-surface-secondary h-full w-full">
|
||||
<div class="text-sm text-tertiary pb-4">Frontend Job</div>
|
||||
<div class="text-2xs text-tertiary">Check your browser console to see the logs</div>
|
||||
</div>
|
||||
{:else}
|
||||
<LogViewer
|
||||
bind:drawerOpen={logDrawerOpen}
|
||||
small
|
||||
jobId={testJob?.id}
|
||||
duration={testJob?.['duration_ms']}
|
||||
mem={testJob?.['mem_peak']}
|
||||
content={testJob?.logs}
|
||||
isLoading={testIsLoading && testJob?.['running'] == false}
|
||||
tag={testJob?.tag}
|
||||
/>
|
||||
{/if}
|
||||
</Pane>
|
||||
<Pane size={frontendJob ? 70 : 50} minSize={10} class="text-sm text-tertiary">
|
||||
{#if frontendJob}
|
||||
<div class="break-words relative h-full px-1">
|
||||
<DisplayResult bind:drawerOpen={resultDrawerOpen} result={frontendJob} />
|
||||
</div>
|
||||
{:else if testJob != undefined && 'result' in testJob && testJob.result != undefined}
|
||||
<div class="break-words relative h-full px-1">
|
||||
<DisplayResult
|
||||
bind:drawerOpen={resultDrawerOpen}
|
||||
workspaceId={testJob?.workspace_id}
|
||||
jobId={testJob?.id}
|
||||
result={testJob.result}
|
||||
/></div
|
||||
>
|
||||
{:else}
|
||||
<div class="px-1 pt-1">
|
||||
{#if testIsLoading}
|
||||
<Loader2 class="animate-spin" />
|
||||
{:else}
|
||||
Test to see the result here
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
</div>
|
||||
{#if float}
|
||||
<div
|
||||
class="absolute z-[100] top-0 right-0 border-t h-full"
|
||||
style="width: {$runnableJobEditorPanel.width}px; transform: translateX({$runnableJobEditorPanel.width}px);"
|
||||
>
|
||||
<RunnalbeJobPanelInner {frontendJob} {testJob} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-col w-full">
|
||||
{#if $selectedComponentInEditor}
|
||||
<RunnalbeJobPanelInner {frontendJob} {testJob} />
|
||||
{:else if !hidden}
|
||||
<div class="text-sm text-secondary text-center py-8 px-2 border-l h-full">
|
||||
Logs and results will be displayed here
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<script lang="ts">
|
||||
import DisplayResult from '$lib/components/DisplayResult.svelte'
|
||||
import LogViewer from '$lib/components/LogViewer.svelte'
|
||||
import { Splitpanes, Pane } from 'svelte-splitpanes'
|
||||
import type { Job } from '$lib/gen'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
|
||||
export let frontendJob: boolean | any = false
|
||||
export let testJob: Job | any = undefined
|
||||
|
||||
let testIsLoading = false
|
||||
|
||||
let logDrawerOpen = false
|
||||
let resultDrawerOpen = false
|
||||
</script>
|
||||
|
||||
<Splitpanes horizontal>
|
||||
<Pane size={frontendJob ? 30 : 50} minSize={10}>
|
||||
{#if frontendJob}
|
||||
<div class="p-2 bg-surface-secondary h-full w-full">
|
||||
<div class="text-sm text-tertiary pb-4">Frontend Job</div>
|
||||
<div class="text-2xs text-tertiary">Check your browser console to see the logs</div>
|
||||
</div>
|
||||
{:else}
|
||||
<LogViewer
|
||||
bind:drawerOpen={logDrawerOpen}
|
||||
small
|
||||
jobId={testJob?.id}
|
||||
duration={testJob?.['duration_ms']}
|
||||
mem={testJob?.['mem_peak']}
|
||||
content={testJob?.logs}
|
||||
isLoading={testIsLoading && testJob?.['running'] == false}
|
||||
tag={testJob?.tag}
|
||||
/>
|
||||
{/if}
|
||||
</Pane>
|
||||
<Pane size={frontendJob ? 70 : 50} minSize={10} class="text-sm text-tertiary">
|
||||
{#if frontendJob}
|
||||
<div class="break-words relative h-full px-1">
|
||||
<DisplayResult bind:drawerOpen={resultDrawerOpen} result={frontendJob} />
|
||||
</div>
|
||||
{:else if testJob != undefined && 'result' in testJob && testJob.result != undefined}
|
||||
<div class="break-words relative h-full px-1">
|
||||
<DisplayResult
|
||||
bind:drawerOpen={resultDrawerOpen}
|
||||
workspaceId={testJob?.workspace_id}
|
||||
jobId={testJob?.id}
|
||||
result={testJob.result}
|
||||
/></div
|
||||
>
|
||||
{:else}
|
||||
<div class="px-1 pt-1">
|
||||
{#if testIsLoading}
|
||||
<Loader2 class="animate-spin" />
|
||||
{:else}
|
||||
Test to see the result here
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</Pane>
|
||||
</Splitpanes>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { classNames } from '$lib/utils'
|
||||
import { getContext } from 'svelte'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
|
||||
import type { AppViewerContext, ContextPanelContext } from '../../types'
|
||||
import { connectInput } from '../appUtils'
|
||||
@@ -11,16 +11,25 @@
|
||||
import OutputHeader from './components/OutputHeader.svelte'
|
||||
import { ClearableInput } from '../../../common'
|
||||
import DocLink from '../settingsPanel/DocLink.svelte'
|
||||
import HideButton from '../settingsPanel/HideButton.svelte'
|
||||
|
||||
const { connectingInput, app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { search } = getContext<ContextPanelContext>('ContextPanel')
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let hasState: boolean = false
|
||||
</script>
|
||||
|
||||
<PanelSection noPadding titlePadding="px-2 pt-2" title="Outputs">
|
||||
<svelte:fragment slot="action">
|
||||
<div class="p-0.5">
|
||||
<HideButton
|
||||
on:click={() => {
|
||||
dispatch('hidePanel')
|
||||
}}
|
||||
direction="left"
|
||||
/>
|
||||
<DocLink docLink="https://www.windmill.dev/docs/apps/outputs" />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import { ScriptService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { findNextAvailablePath } from '$lib/path'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
const { app, runnableComponents } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { selectedComponentInEditor } = getContext<AppEditorContext>('AppEditorContext')
|
||||
@@ -100,12 +101,17 @@
|
||||
|
||||
$app = $app
|
||||
}
|
||||
|
||||
export let width: number | undefined = undefined
|
||||
</script>
|
||||
|
||||
<SplitPanesWrapper>
|
||||
<Splitpanes class="!overflow-visible">
|
||||
<Splitpanes
|
||||
class={twMerge('!overflow-visible')}
|
||||
style={width !== undefined ? `width:${width}px;` : ''}
|
||||
>
|
||||
<Pane size={25}>
|
||||
<InlineScriptsPanelList />
|
||||
<InlineScriptsPanelList on:hidePanel />
|
||||
</Pane>
|
||||
<Pane size={75}>
|
||||
{#if !$selectedComponentInEditor}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Badge, Button } from '$lib/components/common'
|
||||
import { Plus } from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import Tooltip from '../../../Tooltip.svelte'
|
||||
import type { AppEditorContext, AppViewerContext } from '../../types'
|
||||
import { BG_PREFIX, getAllScriptNames } from '../../utils'
|
||||
@@ -12,6 +12,7 @@
|
||||
import { ignoredTutorials } from '$lib/components/tutorials/ignoredTutorials'
|
||||
import { tutorialInProgress } from '$lib/tutorialUtils'
|
||||
import DocLink from '../settingsPanel/DocLink.svelte'
|
||||
import HideButton from '../settingsPanel/HideButton.svelte'
|
||||
|
||||
const PREFIX = 'script-selector-' as const
|
||||
|
||||
@@ -79,11 +80,22 @@
|
||||
}
|
||||
|
||||
let appTutorials: AppTutorials | undefined = undefined
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
<PanelSection title="Runnables" id="app-editor-runnable-panel">
|
||||
<svelte:fragment slot="action">
|
||||
<DocLink docLink="https://www.windmill.dev/docs/apps/app-runnable-panel#creating-a-runnable" />
|
||||
<div class="flex flex-row gap-1">
|
||||
<HideButton
|
||||
direction="bottom"
|
||||
on:click={() => {
|
||||
dispatch('hidePanel')
|
||||
}}
|
||||
/>
|
||||
<DocLink
|
||||
docLink="https://www.windmill.dev/docs/apps/app-runnable-panel#creating-a-runnable"
|
||||
/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<div class="w-full flex flex-col gap-6 py-1">
|
||||
<div>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<script lang="ts">
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import { ButtonType } from '$lib/components/common'
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { getModifierKey } from '$lib/utils'
|
||||
import { PanelBottomClose, PanelLeftClose, PanelRightClose } from 'lucide-svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let btnClasses: string | undefined = undefined
|
||||
export let size: ButtonType.Size = 'xs'
|
||||
|
||||
export let direction: 'left' | 'right' | 'bottom' = 'right'
|
||||
export let hidden: boolean = false
|
||||
|
||||
const IconMap = {
|
||||
left: PanelLeftClose,
|
||||
right: PanelRightClose,
|
||||
bottom: PanelBottomClose
|
||||
}
|
||||
|
||||
const shortcuts = {
|
||||
left: 'B',
|
||||
right: 'U',
|
||||
bottom: 'L'
|
||||
}
|
||||
</script>
|
||||
|
||||
<Popover>
|
||||
<svelte:fragment slot="text">
|
||||
<div class="flex flex-row gap-1">
|
||||
{hidden ? 'Show' : 'Hide '} the {direction} panel.
|
||||
|
||||
<div class="flex flex-row items-center !text-md opacity-60 gap-0 font-normal">
|
||||
{getModifierKey()}{shortcuts[direction]}
|
||||
</div>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<Button
|
||||
iconOnly
|
||||
startIcon={{
|
||||
icon: IconMap[direction]
|
||||
}}
|
||||
{size}
|
||||
btnClasses={twMerge(
|
||||
'p-1 text-gray-300 hover:!text-gray-600 dark:text-gray-500 dark:hover:!text-gray-200 bg-transparent',
|
||||
hidden ? 'bg-surface-selected !text-primary' : '',
|
||||
btnClasses
|
||||
)}
|
||||
on:click
|
||||
color="light"
|
||||
/>
|
||||
</Popover>
|
||||
Reference in New Issue
Block a user