Files
windmill/frontend/src/lib/components/apps/components/buttons/AppButton.svelte
T
Faton Ramadani 48413a78c5 feat(frontend): App set tab (#1307)
* feat(frontend): Set tab

* feat(frontend): Set tab

* feat(frontend): fix styling

* feat(frontend): update how set Tab is stored

* feat(frontend): clean up

* feat(frontend): update setTab to an array structure

* feat(frontend): revert

* feat(frontend): support all components

* feat(frontend): fix typing

* feat(frontend): group success side effects

* feat(frontend): add missing tooltip + remove duplicate code
2023-03-20 19:09:56 +01:00

168 lines
4.8 KiB
Svelte

<script lang="ts">
import { Button } from '$lib/components/common'
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import type RunnableComponent from '../helpers/RunnableComponent.svelte'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import { loadIcon } from '../icon'
import { twMerge } from 'tailwind-merge'
import { initConfig, initOutput } from '../../editor/appUtils'
import { components, configurationKeys } from '../../editor/component'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: RichConfigurations
export let recomputeIds: string[] | undefined = undefined
export let extraQueryParams: Record<string, any> = {}
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let noWFull = false
export let preclickAction: (() => Promise<void>) | undefined = undefined
export let customCss: ComponentCustomCSS<'buttoncomponent'> | undefined = undefined
export let render: boolean
export let initializing: boolean | undefined = true
export let extraKey: string | undefined = undefined
export let controls: { left: () => boolean; right: () => boolean | string } | undefined =
undefined
const { worldStore, app, componentControl, selectedComponent } =
getContext<AppViewerContext>('AppViewerContext')
let outputs = initOutput($worldStore, id, {
result: undefined,
loading: false
})
if (controls) {
$componentControl[id] = controls
}
let runnableComponent: RunnableComponent
let isLoading: boolean = false
let ownClick: boolean = false
let resolvedConfig = initConfig(components['buttoncomponent'].initialData.configuration)
$: initializing = resolvedConfig?.label == undefined
let beforeIconComponent: any
let afterIconComponent: any
$: resolvedConfig.beforeIcon && handleBeforeIcon()
$: resolvedConfig.afterIcon && handleAfterIcon()
async function handleBeforeIcon() {
if (resolvedConfig.beforeIcon) {
beforeIconComponent = await loadIcon(resolvedConfig.beforeIcon)
}
}
async function handleAfterIcon() {
if (resolvedConfig.afterIcon) {
afterIconComponent = await loadIcon(resolvedConfig.afterIcon)
}
}
$: resolvedConfig?.triggerOnAppLoad && runnableComponent?.runComponent()
$: if (outputs?.loading != undefined) {
outputs.loading.set(false, true)
}
$: outputs?.loading.subscribe({
id: 'loading-' + id,
next: (value) => {
isLoading = value
if (ownClick && !value) {
ownClick = false
}
}
})
$: loading = isLoading && ownClick
let errors: Record<string, string> = {}
$: errorsMessage = Object.values(errors)
.filter((x) => x != '')
.join('\n')
let runnableWrapper: RunnableWrapper
async function handleClick(event: CustomEvent) {
event?.stopPropagation()
event?.preventDefault()
$selectedComponent = id
if (preclickAction) {
await preclickAction()
}
ownClick = true
if (!runnableComponent) {
runnableWrapper.onSuccess()
} else {
await runnableComponent?.runComponent()
}
}
</script>
{#each configurationKeys['buttoncomponent'] as key (key)}
<InputValue
key={key + extraKey}
{id}
input={configuration[key]}
bind:value={resolvedConfig[key]}
/>
{/each}
<RunnableWrapper
bind:this={runnableWrapper}
{recomputeIds}
bind:runnableComponent
{componentInput}
{id}
{extraQueryParams}
autoRefresh={false}
gotoUrl={resolvedConfig.goto}
gotoNewTab={resolvedConfig.gotoNewTab}
setTab={resolvedConfig.setTab}
{render}
{outputs}
{extraKey}
>
<AlignWrapper {noWFull} {horizontalAlignment} {verticalAlignment}>
{#if errorsMessage}
<div class="text-red-500 text-xs">{errorsMessage}</div>
{/if}
<Button
on:pointerdown={(e) => e.stopPropagation()}
btnClasses={twMerge(
$app.css?.['buttoncomponent']?.['button']?.class,
customCss?.button?.class,
resolvedConfig.fillContainer ? 'w-full h-full' : ''
)}
style={[$app.css?.['buttoncomponent']?.['button']?.style, customCss?.button?.style].join(';')}
disabled={resolvedConfig.disabled}
on:click={handleClick}
size={resolvedConfig.size}
color={resolvedConfig.color}
{loading}
>
<span class="truncate inline-flex gap-2 items-center">
{#if resolvedConfig.beforeIcon && beforeIconComponent}
<svelte:component this={beforeIconComponent} size={14} />
{/if}
<div>{resolvedConfig.label}</div>
{#if resolvedConfig.afterIcon && afterIconComponent}
<svelte:component this={afterIconComponent} size={14} />
{/if}
</span>
</Button>
</AlignWrapper>
</RunnableWrapper>