Compare commits
12 Commits
v1.368.1
...
app-previe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4140117b6a | ||
|
|
f20ea37eb0 | ||
|
|
87d31ee63b | ||
|
|
fb2d52f99b | ||
|
|
2e3271257f | ||
|
|
b013996585 | ||
|
|
0a76e3533c | ||
|
|
7648b382ff | ||
|
|
e2747e824f | ||
|
|
2060445d20 | ||
|
|
94e30052bf | ||
|
|
68add7932e |
@@ -86,6 +86,33 @@
|
||||
$: errorsMessage = Object.values(errors)
|
||||
.filter((x) => x != '')
|
||||
.join('\n')
|
||||
|
||||
async function handleClick(event: CustomEvent) {
|
||||
event?.stopPropagation()
|
||||
event?.preventDefault()
|
||||
|
||||
if (preclickAction) {
|
||||
await preclickAction()
|
||||
}
|
||||
|
||||
ownClick = true
|
||||
|
||||
if (!runnableComponent) {
|
||||
if (gotoUrl) {
|
||||
if (gotoNewTab) {
|
||||
window.open(gotoUrl, '_blank')
|
||||
} else {
|
||||
goto(gotoUrl)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await runnableComponent?.runComponent()
|
||||
}
|
||||
|
||||
if (recomputeIds) {
|
||||
await Promise.all(recomputeIds.map((id) => $runnableComponents?.[id]?.()))
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<InputValue {id} input={configuration.label} bind:value={labelValue} />
|
||||
@@ -131,32 +158,7 @@
|
||||
e?.stopPropagation()
|
||||
window.dispatchEvent(new Event('pointerup'))
|
||||
}}
|
||||
on:click={async (e) => {
|
||||
if (preclickAction) {
|
||||
await preclickAction()
|
||||
}
|
||||
e?.stopPropagation()
|
||||
e?.preventDefault()
|
||||
ownClick = true
|
||||
|
||||
if (!runnableComponent) {
|
||||
if (gotoUrl) {
|
||||
if (gotoNewTab) {
|
||||
window.open(gotoUrl, '_blank')
|
||||
} else {
|
||||
goto(gotoUrl)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await runnableComponent?.runComponent()
|
||||
}
|
||||
|
||||
if (recomputeIds) {
|
||||
recomputeIds.forEach((id) => {
|
||||
$runnableComponents[id]?.()
|
||||
})
|
||||
}
|
||||
}}
|
||||
on:click={handleClick}
|
||||
{size}
|
||||
{color}
|
||||
{loading}
|
||||
|
||||
@@ -164,7 +164,6 @@
|
||||
|
||||
function handleSyncRegion() {
|
||||
const gridItem = findGridItem($app, id)
|
||||
|
||||
if (!map || !gridItem) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -118,7 +118,6 @@
|
||||
function scrollToPage(page: number) {
|
||||
page = pageNumber = minMax(page, 1, pages.length)
|
||||
const offset = (wrapper?.children.item(page - 1) as HTMLCanvasElement | null)?.offsetTop
|
||||
// debugger
|
||||
if (!offset) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
|
||||
import { getContext } from 'svelte'
|
||||
import ResizeWrapper from '../helpers/ResizeWrapper.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
@@ -26,6 +27,7 @@
|
||||
let result: string | undefined = undefined
|
||||
let style: 'Title' | 'Subtitle' | 'Body' | 'Caption' | 'Label' | undefined = undefined
|
||||
let copyButton: boolean
|
||||
let fitContent = false
|
||||
|
||||
function getComponent() {
|
||||
switch (style) {
|
||||
@@ -63,36 +65,39 @@
|
||||
|
||||
<InputValue {id} input={configuration.style} bind:value={style} />
|
||||
<InputValue {id} input={configuration.copyButton} bind:value={copyButton} />
|
||||
<InputValue {id} input={configuration.fitContent} bind:value={fitContent} />
|
||||
|
||||
<RunnableWrapper flexWrap {componentInput} {id} bind:initializing bind:result>
|
||||
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
|
||||
{#if !result || result === ''}
|
||||
<div class="text-gray-400 bg-gray-100 flex justify-center items-center h-full w-full">
|
||||
No text
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-wrap gap-2 pb-0.5 overflow-x-auto">
|
||||
<svelte:element
|
||||
this={component}
|
||||
class={twMerge(
|
||||
'whitespace-pre-wrap',
|
||||
$app.css?.['textcomponent']?.['text']?.class,
|
||||
customCss?.text?.class,
|
||||
classes
|
||||
)}
|
||||
style={[$app.css?.['textcomponent']?.['text']?.style, customCss?.text?.style].join(';')}
|
||||
>
|
||||
{String(result)}
|
||||
</svelte:element>
|
||||
{#if copyButton && result}
|
||||
<Popover notClickable>
|
||||
<Button size="xs" btnClasses="!px-2" on:click={() => copyToClipboard(result)}>
|
||||
<Clipboard size={14} strokeWidth={2} />
|
||||
</Button>
|
||||
<svelte:fragment slot="text">Copy to clipboard</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</AlignWrapper>
|
||||
<ResizeWrapper {id} shouldWrap={fitContent}>
|
||||
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
|
||||
{#if !result || result === ''}
|
||||
<div class="text-gray-400 bg-gray-100 flex justify-center items-center h-full w-full">
|
||||
No text
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-wrap gap-2 pb-0.5 overflow-x-auto">
|
||||
<svelte:element
|
||||
this={component}
|
||||
class={twMerge(
|
||||
'whitespace-pre-wrap',
|
||||
$app.css?.['textcomponent']?.['text']?.class,
|
||||
customCss?.text?.class,
|
||||
classes
|
||||
)}
|
||||
style={[$app.css?.['textcomponent']?.['text']?.style, customCss?.text?.style].join(';')}
|
||||
>
|
||||
{String(result)}
|
||||
</svelte:element>
|
||||
{#if copyButton && result}
|
||||
<Popover notClickable>
|
||||
<Button size="xs" btnClasses="!px-2" on:click={() => copyToClipboard(result)}>
|
||||
<Clipboard size={14} strokeWidth={2} />
|
||||
</Button>
|
||||
<svelte:fragment slot="text">Copy to clipboard</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</AlignWrapper>
|
||||
</ResizeWrapper>
|
||||
</RunnableWrapper>
|
||||
|
||||
@@ -64,11 +64,11 @@
|
||||
|
||||
let selectedRowIndex = -1
|
||||
|
||||
function toggleRow(row: Record<string, any>, rowIndex: number) {
|
||||
if (selectedRowIndex !== rowIndex) {
|
||||
function toggleRow(row: Record<string, any>, rowIndex: number, force: boolean = false) {
|
||||
if (selectedRowIndex !== rowIndex || force) {
|
||||
selectedRowIndex = rowIndex
|
||||
outputs?.selectedRow.set(row.original)
|
||||
outputs?.selectedRowIndex.set(rowIndex)
|
||||
outputs?.selectedRow.set(row.original, force)
|
||||
outputs?.selectedRowIndex.set(rowIndex, force)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +138,9 @@
|
||||
|
||||
function rerender() {
|
||||
table = createSvelteTable(options)
|
||||
if (result) {
|
||||
toggleRow({ original: result[0] }, 0, true)
|
||||
}
|
||||
}
|
||||
|
||||
$: result && rerender()
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { findGridItem } from '../../editor/appUtils'
|
||||
import type { AppEditorContext } from '../../types'
|
||||
|
||||
export let id: string
|
||||
export let shouldWrap: boolean = false
|
||||
const { app, breakpoint } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
$: gridItem = findGridItem($app, id)
|
||||
|
||||
let wrapper: HTMLElement
|
||||
|
||||
$: {
|
||||
if (wrapper && gridItem && shouldWrap) {
|
||||
const wrapperHeight = wrapper.getBoundingClientRect().height
|
||||
const width = $breakpoint === 'sm' ? 3 : 12
|
||||
gridItem[width].h = Math.ceil(wrapperHeight / 36)
|
||||
gridItem = gridItem
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if shouldWrap}
|
||||
<div bind:this={wrapper}>
|
||||
<slot />
|
||||
</div>
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
@@ -2,10 +2,12 @@
|
||||
import { goto } from '$app/navigation'
|
||||
import type { Schema } from '$lib/common'
|
||||
import Alert from '$lib/components/common/alert/Alert.svelte'
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import SchemaForm from '$lib/components/SchemaForm.svelte'
|
||||
import TestJobLoader from '$lib/components/TestJobLoader.svelte'
|
||||
import { AppService, type CompletedJob } from '$lib/gen'
|
||||
import { defaultIfEmptyString, emptySchema, sendUserToast } from '$lib/utils'
|
||||
import { classNames, defaultIfEmptyString, emptySchema, sendUserToast } from '$lib/utils'
|
||||
import { Bug } from 'lucide-svelte'
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import type { AppInputs, Runnable } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
@@ -104,7 +106,6 @@
|
||||
}
|
||||
|
||||
$: outputs?.loading?.set(testIsLoading)
|
||||
|
||||
$: schemaStripped = stripSchema(fields, $stateId)
|
||||
|
||||
function stripSchema(inputs: AppInputs, s: any): Schema {
|
||||
@@ -276,16 +277,28 @@
|
||||
Please select a runnable
|
||||
</Alert>
|
||||
{:else if result?.error && $mode === 'preview'}
|
||||
<div class="p-2">
|
||||
<Alert type="error" title="Error during execution">
|
||||
<div class="flex flex-col gap-2">
|
||||
An error occured, please contact the app author.
|
||||
<span class="font-semibold">Job id: {testJob?.id}</span>
|
||||
<pre class=" whitespace-pre-wrap text-gray-900 bg-white border w-full p-4 text-xs"
|
||||
>{JSON.stringify(result.error, null, 4)}
|
||||
</pre>
|
||||
</div>
|
||||
</Alert>
|
||||
<div
|
||||
title="Error"
|
||||
class={classNames(
|
||||
'text-red-500 px-1 text-2xs py-0.5 font-bold w-fit absolute border border-red-500 -bottom-2 shadow left-1/2 transform -translate-x-1/2 z-50 cursor-pointer',
|
||||
'bg-red-100/80'
|
||||
)}
|
||||
>
|
||||
<Popover notClickable placement="bottom" popupClass="!bg-white border w-96">
|
||||
<Bug size={14} />
|
||||
<span slot="text">
|
||||
<div class="bg-white">
|
||||
<Alert type="error" title="Error during execution">
|
||||
<div class="flex flex-col gap-2">
|
||||
An error occured, please contact the app author.
|
||||
<span class="font-semibold">Job id: {testJob?.id}</span>
|
||||
</div>
|
||||
</Alert>
|
||||
</div>
|
||||
</span>
|
||||
</Popover>
|
||||
</div>
|
||||
<div class="block grow w-full max-h-full border border-red-300 bg-red-50 relative">
|
||||
<slot />
|
||||
</div>
|
||||
{:else}
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const { errorByComponent, openDebugRun, focusedGrid, worldStore } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
const { errorByComponent, openDebugRun } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
$: error = Object.values($errorByComponent).find((e) => e.componentId === component.id)
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
export let locked: boolean = false
|
||||
export let pointerdown: boolean = false
|
||||
|
||||
const { staticOutputs, mode, connectingInput, app } =
|
||||
const { staticOutputs, mode, connectingInput, app, errorByComponent } =
|
||||
getContext<AppEditorContext>('AppEditorContext')
|
||||
let hover = false
|
||||
let initializing: boolean | undefined = undefined
|
||||
@@ -57,6 +57,9 @@
|
||||
// $: if (!deepEqual(component, pComponent)) {
|
||||
// component = JSON.parse(JSON.stringify(pComponent))
|
||||
// }
|
||||
|
||||
$: componentWithErrors = Object.values($errorByComponent).map((e) => e.componentId)
|
||||
$: hasError = componentWithErrors.includes(component.id)
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -82,7 +85,7 @@
|
||||
selected && $mode !== 'preview' ? 'border border-blue-500' : '',
|
||||
!selected && $mode !== 'preview' && !component.card ? 'border-gray-100' : '',
|
||||
$mode !== 'preview' && !$connectingInput.opened ? 'hover:border-blue-500' : '',
|
||||
component.softWrap ? '' : 'overflow-auto',
|
||||
component.softWrap || hasError ? '' : 'overflow-auto',
|
||||
$mode != 'preview' ? 'cursor-pointer' : '',
|
||||
'relative z-auto',
|
||||
$app.css?.['app']?.['component']?.class
|
||||
@@ -195,6 +198,7 @@
|
||||
customCss={component.customCss}
|
||||
componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
recomputeIds={component.recomputeIds}
|
||||
/>
|
||||
{:else if component.type === 'selectcomponent'}
|
||||
<AppSelect
|
||||
@@ -222,6 +226,7 @@
|
||||
customCss={component.customCss}
|
||||
componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
recomputeIds={component.recomputeIds}
|
||||
/>
|
||||
{:else if component.type === 'formbuttoncomponent'}
|
||||
<AppFormButton
|
||||
@@ -232,6 +237,7 @@
|
||||
customCss={component.customCss}
|
||||
componentInput={component.componentInput}
|
||||
bind:staticOutputs={$staticOutputs[component.id]}
|
||||
recomputeIds={component.recomputeIds}
|
||||
/>
|
||||
{:else if component.type === 'checkboxcomponent'}
|
||||
<AppCheckbox
|
||||
@@ -405,7 +411,7 @@
|
||||
</div>
|
||||
{#if initializing}
|
||||
<div
|
||||
out:fade={{ duration: 200 }}
|
||||
out:fade|local={{ duration: 200 }}
|
||||
class="absolute inset-0 center-center flex-col bg-white text-gray-600 border"
|
||||
>
|
||||
<Loader2 class="animate-spin" size={16} />
|
||||
|
||||
@@ -231,6 +231,12 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
|
||||
value: false,
|
||||
fieldType: 'boolean',
|
||||
onlyStatic: true
|
||||
},
|
||||
fitContent: {
|
||||
type: 'static',
|
||||
value: false,
|
||||
fieldType: 'boolean',
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
customCss: {
|
||||
|
||||
@@ -131,9 +131,8 @@
|
||||
<div class="flex flex-row gap-1 items-center">
|
||||
Format
|
||||
|
||||
<div class="flex flex-row items-center">
|
||||
<div class="flex flex-row items-center gap-1">
|
||||
<Kbd>{isMac ? '⌘' : 'CTRL'}</Kbd>
|
||||
<Plus size={12} />
|
||||
<Kbd>S</Kbd>
|
||||
</div>
|
||||
</div>
|
||||
@@ -154,9 +153,8 @@
|
||||
<div class="flex flex-row gap-1 items-center">
|
||||
Run
|
||||
|
||||
<div class="flex flex-row items-center">
|
||||
<div class="flex flex-row items-center gap-1">
|
||||
<Kbd>{isMac ? '⌘' : 'CTRL'}</Kbd>
|
||||
<Plus size={12} />
|
||||
<Kbd>
|
||||
<div class="h-4 flex items-center justify-center">
|
||||
<CornerDownLeft size={10} />
|
||||
|
||||
@@ -43,14 +43,14 @@ export interface BaseAppComponent extends Partial<Aligned> {
|
||||
configuration: Record<
|
||||
string,
|
||||
GeneralAppInput &
|
||||
(
|
||||
| StaticAppInput
|
||||
| ConnectedAppInput
|
||||
| UserAppInput
|
||||
| RowAppInput
|
||||
| EvalAppInput
|
||||
| UploadAppInput
|
||||
)
|
||||
(
|
||||
| StaticAppInput
|
||||
| ConnectedAppInput
|
||||
| UserAppInput
|
||||
| RowAppInput
|
||||
| EvalAppInput
|
||||
| UploadAppInput
|
||||
)
|
||||
>
|
||||
card: boolean | undefined
|
||||
customCss?: ComponentCustomCSS
|
||||
|
||||
Reference in New Issue
Block a user