fix(frontend): App form component (#1087)
* fix(frontend): Make app form usage more clear * fix(frontend): Form orientation * fix(frontend): Form message format Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
export let placement: `${typeof SIDE[number]}` | `${typeof SIDE[number]}-${typeof ALIGN[number]}` = 'auto'
|
||||
export let notClickable = false
|
||||
export let popupClass = ''
|
||||
export let disapperTimoout = 100
|
||||
|
||||
const [popperRef, popperContent] = createPopperActions({ placement })
|
||||
const betterPreventOverflow = (options) => ({
|
||||
@@ -39,20 +40,30 @@
|
||||
showTooltip = true
|
||||
}
|
||||
function close() {
|
||||
timeout = setTimeout(() => (showTooltip = false), 100)
|
||||
timeout = setTimeout(() => (showTooltip = false), disapperTimoout)
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
class:cursor-default={notClickable}
|
||||
use:popperRef
|
||||
on:mouseenter={open}
|
||||
on:mouseleave={close}
|
||||
on:click
|
||||
class={$$props.class}
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
{#if notClickable}
|
||||
<span
|
||||
use:popperRef
|
||||
on:mouseenter={open}
|
||||
on:mouseleave={close}
|
||||
class={$$props.class}
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
{:else}
|
||||
<button
|
||||
use:popperRef
|
||||
on:mouseenter={open}
|
||||
on:mouseleave={close}
|
||||
on:click
|
||||
class={$$props.class}
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
{/if}
|
||||
{#if showTooltip}
|
||||
<div
|
||||
use:popperContent={extraOpts}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { Button, type ButtonType } from '$lib/components/common'
|
||||
import { faUser } from '@fortawesome/free-solid-svg-icons'
|
||||
import { getContext } from 'svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
@@ -27,6 +29,8 @@
|
||||
|
||||
let isLoading: boolean = false
|
||||
|
||||
$: noInputs = componentInput?.type != 'runnable' || Object.values(componentInput?.fields ?? {}).filter((x) => x.type == 'user').length == 0
|
||||
|
||||
$: outputs = $worldStore?.outputsById[id] as {
|
||||
result: Output<Array<any>>
|
||||
loading: Output<boolean>
|
||||
@@ -56,39 +60,47 @@
|
||||
{extraQueryParams}
|
||||
autoRefresh={false}
|
||||
forceSchemaDisplay={true}
|
||||
runnableClass="!flex-col"
|
||||
>
|
||||
<AlignWrapper {horizontalAlignment}>
|
||||
<div class="flex flex-col gap-2 px-4 w-full ">
|
||||
<div>
|
||||
{#if componentInput?.type != 'runnable' || Object.values(componentInput?.fields ?? {}).filter((x) => x.type == 'user').length == 0}
|
||||
<span class="text-gray-600 italic text-sm py-2">
|
||||
Run forms are associated with a runnable that has user inputs. Once a runnable is
|
||||
chosen, set some 'Runnable Inputs' to 'User Input'
|
||||
</span>
|
||||
{#if noInputs}
|
||||
<div class="text-gray-600 italic text-sm my-4">
|
||||
Run forms are associated with a runnable that has user inputs.
|
||||
<br>
|
||||
Once a script or flow is chosen, set some <strong>Runnable Inputs</strong> to
|
||||
<strong>
|
||||
User Input
|
||||
<Icon data={faUser} scale={1.3} class="rounded-sm bg-gray-200 p-1 ml-0.5" />
|
||||
</strong>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<Button
|
||||
loading={isLoading}
|
||||
btnClasses="my-1"
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
window.dispatchEvent(new Event('pointerup'))
|
||||
}}
|
||||
on:click={() => {
|
||||
runnableComponent?.runComponent()
|
||||
{#if !noInputs}
|
||||
<Button
|
||||
loading={isLoading}
|
||||
btnClasses="my-1"
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
window.dispatchEvent(new Event('pointerup'))
|
||||
}}
|
||||
on:click={() => {
|
||||
runnableComponent?.runComponent()
|
||||
|
||||
if (recomputeIds) {
|
||||
recomputeIds.forEach((id) => {
|
||||
$runnableComponents[id]?.()
|
||||
})
|
||||
}
|
||||
}}
|
||||
{size}
|
||||
{color}
|
||||
>
|
||||
{labelValue}
|
||||
</Button>
|
||||
if (recomputeIds) {
|
||||
recomputeIds.forEach((id) => {
|
||||
$runnableComponents[id]?.()
|
||||
})
|
||||
}
|
||||
}}
|
||||
{size}
|
||||
{color}
|
||||
>
|
||||
{labelValue}
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</AlignWrapper>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
export let noMinH = false
|
||||
export let defaultUserInput = false
|
||||
export let flexWrap = false
|
||||
export let wrapperClass = ''
|
||||
|
||||
const { worldStore, runnableComponents, workspace, appPath, isEditor, jobs, noBackend } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
@@ -271,7 +272,7 @@
|
||||
bind:this={testJobLoader}
|
||||
/>
|
||||
|
||||
<div class="h-full flex relative flex-row flex-wrap">
|
||||
<div class="h-full flex relative flex-row flex-wrap {wrapperClass}">
|
||||
{#if autoRefresh === true}
|
||||
<div class="flex absolute top-1 right-1">
|
||||
<RefreshButton componentId={id} />
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
export let forceSchemaDisplay: boolean = false
|
||||
export let defaultUserInput = false
|
||||
export let flexWrap = false
|
||||
export let runnableClass = ''
|
||||
|
||||
const { staticExporter, noBackend } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
@@ -47,6 +48,7 @@
|
||||
{extraQueryParams}
|
||||
{forceSchemaDisplay}
|
||||
{noMinH}
|
||||
wrapperClass={runnableClass}
|
||||
>
|
||||
<slot />
|
||||
</RunnableComponent>
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import Popup from '../../../common/popup/Popup.svelte'
|
||||
import Popover from '../../../Popover.svelte'
|
||||
|
||||
export let inputSpecs: Record<
|
||||
string,
|
||||
@@ -36,7 +38,7 @@
|
||||
{shouldCapitalize ? capitalize(inputSpecKey) : inputSpecKey}
|
||||
</span>
|
||||
|
||||
<div class="flex gap-2 flex-wrap items-center">
|
||||
<div class="flex gap-x-2 gap-y-1 flex-wrap justify-end items-center">
|
||||
<Badge color="blue">
|
||||
{input.fieldType === 'array' && input.subFieldType
|
||||
? `${capitalize(fieldTypeToTsType(input.subFieldType))}[]`
|
||||
@@ -57,47 +59,64 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ToggleButton
|
||||
title="Static"
|
||||
position="left"
|
||||
value="static"
|
||||
startIcon={{ icon: faPen }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
/>
|
||||
{#if rowColumns}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
title="Column"
|
||||
position="center"
|
||||
value="row"
|
||||
startIcon={{ icon: faTableCells }}
|
||||
position="left"
|
||||
value="static"
|
||||
startIcon={{ icon: faPen }}
|
||||
size="xs"
|
||||
disabled={staticOnly}
|
||||
><Tooltip
|
||||
>Use the column name to have the value of the cell be passed to the action</Tooltip
|
||||
></ToggleButton
|
||||
>
|
||||
iconOnly
|
||||
/>
|
||||
<svelte:fragment slot="text">
|
||||
Static
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
{#if rowColumns}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="center"
|
||||
value="row"
|
||||
startIcon={{ icon: faTableCells }}
|
||||
size="xs"
|
||||
disabled={staticOnly}
|
||||
>
|
||||
<Tooltip>
|
||||
Use the column name to have the value of the cell be passed to the action
|
||||
</Tooltip>
|
||||
</ToggleButton>
|
||||
<svelte:fragment slot="text">
|
||||
Column
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
{#if userInputEnabled && !input.format?.startsWith('resource-')}
|
||||
{#if userInputEnabled && (!input.format?.startsWith('resource-'))}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="center"
|
||||
value="user"
|
||||
startIcon={{ icon: faUser }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
disabled={staticOnly}
|
||||
/>
|
||||
<svelte:fragment slot="text">
|
||||
User Input
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
title="User Input"
|
||||
position="center"
|
||||
value="user"
|
||||
startIcon={{ icon: faUser }}
|
||||
position="right"
|
||||
value="connected"
|
||||
startIcon={{ icon: faArrowRight }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
disabled={staticOnly}
|
||||
/>
|
||||
{/if}
|
||||
<ToggleButton
|
||||
title="Connect"
|
||||
position="right"
|
||||
value="connected"
|
||||
startIcon={{ icon: faArrowRight }}
|
||||
size="xs"
|
||||
iconOnly
|
||||
disabled={staticOnly}
|
||||
/>
|
||||
<svelte:fragment slot="text">
|
||||
Connect
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
</ToggleButtonGroup>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user