nits svelte 5 migration

This commit is contained in:
Ruben Fiszel
2025-06-28 20:13:55 +02:00
parent ca368aba7a
commit e6a9f2d593
35 changed files with 701 additions and 452 deletions
+57 -27
View File
@@ -1,4 +1,4 @@
<script context="module" lang="ts">
<script module lang="ts">
import { writable } from 'svelte/store'
const activeDropdown = writable<{ id: string | null; close: (() => void) | null }>({
id: null,
@@ -17,24 +17,49 @@
import Button from '$lib/components/common/button/Button.svelte'
import { twMerge } from 'tailwind-merge'
import { triggerableByAI } from '$lib/actions/triggerableByAI'
import { _ } from 'ag-grid-community'
import { untrack } from 'svelte'
export let aiId: string | undefined = undefined
export let aiDescription: string | undefined = undefined
export let items: Item[] | (() => Item[]) | (() => Promise<Item[]>) = []
export let disabled = false
export let placement: Placement = 'bottom-end'
export let usePointerDownOutside = false
export let closeOnOtherDropdownOpen = true
export let fixedHeight = true
export let hidePopup = false
export let open = false
export let customWidth: number | undefined = undefined
export let customMenu = false
interface Props {
aiId?: string | undefined
aiDescription?: string | undefined
items?: Item[] | (() => Item[]) | (() => Promise<Item[]>)
disabled?: boolean
placement?: Placement
usePointerDownOutside?: boolean
closeOnOtherDropdownOpen?: boolean
fixedHeight?: boolean
hidePopup?: boolean
open?: boolean
customWidth?: number | undefined
customMenu?: boolean
class?: string | undefined
buttonReplacement?: import('svelte').Snippet
menu?: import('svelte').Snippet
}
let buttonEl: HTMLButtonElement | undefined = undefined
let {
aiId = undefined,
aiDescription = undefined,
items = [],
disabled = false,
placement = 'bottom-end',
usePointerDownOutside = false,
closeOnOtherDropdownOpen = true,
fixedHeight = true,
hidePopup = false,
open = $bindable(false),
customWidth = undefined,
customMenu = false,
class: classNames = undefined,
buttonReplacement,
menu
}: Props = $props()
let buttonEl: HTMLButtonElement | undefined = $state(undefined)
const {
elements: { menu, item, trigger },
elements: { menu: menuEl, item, trigger },
states,
ids: { menu: dropdownId }
} = createDropdownMenu({
@@ -60,7 +85,12 @@
})
const sync = createSync(states)
$: sync.open(open, (v) => (open = Boolean(v)))
$effect(() => {
open
untrack(() => {
sync.open(open, (v) => (open = Boolean(v)))
})
})
export function close() {
open = false
@@ -88,25 +118,25 @@
description: aiDescription,
callback: () => buttonEl?.click()
}}
class={twMerge('w-full flex items-center justify-end', fixedHeight && 'h-8', $$props.class)}
class={twMerge('w-full flex items-center justify-end', fixedHeight && 'h-8', classNames)}
use:melt={$trigger}
{disabled}
on:click={(e) => e.stopPropagation()}
onclick={(e) => e.stopPropagation()}
use:pointerDownOutside={{
capture: true,
stopPropagation: false,
exclude: getMenuElements,
customEventName: 'pointerdown_menu'
}}
on:pointerdown_outside={() => {
if (usePointerDownOutside) {
close()
customEventName: 'pointerdown_menu',
onClickOutside: () => {
if (usePointerDownOutside) {
close()
}
}
}}
data-menu
>
{#if $$slots.buttonReplacement}
<slot name="buttonReplacement" />
{#if buttonReplacement}
{@render buttonReplacement?.()}
{:else}
<Button
nonCaptureEvent
@@ -119,9 +149,9 @@
</button>
{#if open && !hidePopup}
<div use:melt={$menu} data-menu class="z-[6000] transition-all duration-100">
<div use:melt={$menuEl} data-menu class="z-[6000] transition-all duration-100">
{#if customMenu}
<slot name="menu" />
{@render menu?.()}
{:else}
<div
class="bg-surface border w-56 origin-top-right rounded-md shadow-md focus:outline-none overflow-y-auto py-1 max-h-[50vh]"
@@ -29,8 +29,9 @@
<div class="flex flex-col">
{#each computedItems ?? [] as item}
<MenuItem
on:click={(e) => item?.action?.(e)}
onClick={(e) => item?.action?.(e)}
href={item?.href}
target={item?.hrefTarget}
disabled={item?.disabled}
class={twMerge(
'px-4 py-2 text-primary font-semibold hover:bg-surface-hover cursor-pointer text-xs transition-all w-full',
@@ -7,8 +7,8 @@
import FlowTutorials from './FlowTutorials.svelte'
import { tutorialsToDo } from '$lib/stores'
let targetTutorial: string | undefined = undefined
let flowTutorials: FlowTutorials | undefined = undefined
let targetTutorial: string | undefined = $state(undefined)
let flowTutorials: FlowTutorials | undefined = $state(undefined)
async function getTutorialItems() {
const tutorials = [
@@ -42,7 +42,7 @@
{#key $tutorialsToDo}
<Dropdown items={getTutorialItems} class="w-fit">
<svelte:fragment slot="buttonReplacement">
{#snippet buttonReplacement()}
<Button
nonCaptureEvent
size="xs"
@@ -51,7 +51,7 @@
id="tutorials-button"
startIcon={{ icon: BookOpen }}
/>
</svelte:fragment>
{/snippet}
</Dropdown>
{/key}
@@ -6,11 +6,12 @@
import FlowBuilderTutorialForLoop from './tutorials/FlowBuilderTutorialForLoop.svelte'
import FlowBuilderTutorialErrorHandler from './tutorials/FlowBuilderTutorialErrorHandler.svelte'
let flowBuilderTutorialSimpleFlow: FlowBuilderTutorialSimpleFlow | undefined = undefined
let flowBuilderTutorialForLoop: FlowBuilderTutorialForLoop | undefined = undefined
let flowBuilderTutorialBranchOne: FlowBuilderTutorialBranchOne | undefined = undefined
let flowBuilderTutorialBranchAll: FlowBuilderTutorialBranchAll | undefined = undefined
let flowBuilderTutorialErrorHandler: FlowBuilderTutorialErrorHandler | undefined = undefined
let flowBuilderTutorialSimpleFlow: FlowBuilderTutorialSimpleFlow | undefined = $state(undefined)
let flowBuilderTutorialForLoop: FlowBuilderTutorialForLoop | undefined = $state(undefined)
let flowBuilderTutorialBranchOne: FlowBuilderTutorialBranchOne | undefined = $state(undefined)
let flowBuilderTutorialBranchAll: FlowBuilderTutorialBranchAll | undefined = $state(undefined)
let flowBuilderTutorialErrorHandler: FlowBuilderTutorialErrorHandler | undefined =
$state(undefined)
export function runTutorialById(id: string, indexToInsertAt?: number | undefined) {
if (id === 'forloop') {
@@ -4,12 +4,15 @@
import DataTable from './table/DataTable.svelte'
import Head from './table/Head.svelte'
export let headers: string[] | undefined
export let data: any[] | undefined // Object containing the data
export let keys: string[]
export let size: 'sm' | 'md' | 'lg' = 'md'
interface Props {
headers: string[] | undefined
data: any[] | undefined // Object containing the data
keys: string[]
size?: 'sm' | 'md' | 'lg'
getRowActions?: ((row: any) => any[]) | undefined
}
export let getRowActions: ((row: any) => any[]) | undefined = undefined
let { headers, data, keys, size = 'md', getRowActions = undefined }: Props = $props()
</script>
<div class="mt-2 w-full">
@@ -222,7 +222,7 @@
function onTemplateChange(previousValueKey: string) {
return (newValue) => {
console.log('onTemplateChange', previousValueKey, newValue, id)
// console.log('onTemplateChange', previousValueKey, newValue, id)
previousConnectedValues[previousValueKey] = newValue
debounceTemplate()
}
@@ -801,7 +801,8 @@
displayName: 'Public URL',
icon: Globe,
disabled: !secretUrlHref,
href: secretUrlHref
href: secretUrlHref,
hrefTarget: '_blank'
},
// {
// displayName: 'Publish to Hub',
@@ -876,7 +877,7 @@
appExport?.open(toStatic($app, $staticExporter, $summary).app)
}
}
])
]) as Item[]
let appEditorTutorial: AppEditorTutorial | undefined = $state(undefined)
@@ -11,8 +11,8 @@
import ConfirmationModal from '$lib/components/common/confirmationModal/ConfirmationModal.svelte'
import { isAppTainted } from '$lib/components/tutorials/utils'
let appTutorials: AppTutorials | undefined = undefined
let targetTutorial: string | undefined = undefined
let appTutorials: AppTutorials | undefined = $state(undefined)
let targetTutorial: string | undefined = $state(undefined)
const { app } = getContext<AppViewerContext>('AppViewerContext')
@@ -81,7 +81,7 @@
{#key $tutorialsToDo}
<Dropdown items={getTutorialItems}>
<svelte:fragment slot="buttonReplacement">
{#snippet buttonReplacement()}
<Button
nonCaptureEvent
size="xs"
@@ -92,7 +92,7 @@
icon: BookOpen
}}
/>
</svelte:fragment>
{/snippet}
</Dropdown>
{/key}
@@ -6,11 +6,21 @@
import Badge from '$lib/components/common/badge/Badge.svelte'
import { createEventDispatcher } from 'svelte'
export let componentNumber: number = 0
export let interval: number | undefined = undefined
export let refreshing: string[] = []
export let progress: number = 100
export let loading: boolean | undefined = false
interface Props {
componentNumber?: number
interval?: number | undefined
refreshing?: string[]
progress?: number
loading?: boolean | undefined
}
let {
componentNumber = 0,
interval = undefined,
refreshing = [],
progress = 100,
loading = false
}: Props = $props()
const dispatch = createEventDispatcher()
@@ -53,7 +63,7 @@
</Button>
<Dropdown {items} class="w-fit h-auto">
<svelte:fragment slot="buttonReplacement">
{#snippet buttonReplacement()}
<div
class="flex flex-row gap-2 text-xs bg-surface hover:bg-surface-hover px-2 items-center h-7"
>
@@ -66,7 +76,7 @@
<TimerReset size={14} />
</div>
</div>
</svelte:fragment>
{/snippet}
</Dropdown>
</div>
{#if interval}
@@ -1,21 +1,32 @@
<script lang="ts">
import { createBubbler, stopPropagation } from 'svelte/legacy'
const bubble = createBubbler()
import Dropdown from '$lib/components/DropdownV2.svelte'
import { classNames } from '$lib/utils'
import { createEventDispatcher, getContext } from 'svelte'
import type { AppViewerContext } from '../types'
import { Bug } from 'lucide-svelte'
export let tabs: any[] = []
export let id: string
export let isConditionalDebugMode: boolean = false
export let isSmall = false
const { componentControl } = getContext<AppViewerContext>('AppViewerContext')
const dispatch = createEventDispatcher()
export let isManuallySelected: boolean = false
let selected: number | null = null
interface Props {
tabs?: any[]
id: string
isConditionalDebugMode?: boolean
isSmall?: boolean
isManuallySelected?: boolean
}
let {
tabs = [],
id,
isConditionalDebugMode = false,
isSmall = false,
isManuallySelected = $bindable(false)
}: Props = $props()
let selected: number | null = $state(null)
async function getItems() {
return [
@@ -48,7 +59,7 @@
{#key tabs}
<Dropdown items={getItems} class="w-fit h-auto" usePointerDownOutside>
<svelte:fragment slot="buttonReplacement">
{#snippet buttonReplacement()}
<button
title={isConditionalDebugMode ? 'Debug conditions' : 'Debug tabs'}
class={classNames(
@@ -57,8 +68,8 @@
? 'hover:bg-red-200 hover:text-red-800'
: 'text-blue-600 hover:bg-blue-300 hover:text-blue-800'
)}
on:click={() => dispatch('triggerInlineEditor')}
on:pointerdown|stopPropagation
onclick={() => dispatch('triggerInlineEditor')}
onpointerdown={stopPropagation(bubble('pointerdown'))}
>
{#if isManuallySelected}
<div class="whitespace-nowrap">
@@ -79,6 +90,6 @@
{isConditionalDebugMode ? `Debug conditions` : `Debug tabs`}
{/if}
</button>
</svelte:fragment>
{/snippet}
</Dropdown>
{/key}
@@ -9,11 +9,15 @@
import Dropdown from '$lib/components/DropdownV2.svelte'
import { ResourceService } from '$lib/gen'
export let row: {
name: string
path: string
interface Props {
row: {
name: string
path: string
}
}
let { row }: Props = $props()
const dispatch = createEventDispatcher()
async function toggleDelete() {
@@ -8,11 +8,15 @@
import { createEventDispatcher } from 'svelte'
import GroupNameEditor from './NameEditor.svelte'
export let row: {
name: string
path: string
interface Props {
row: {
name: string
path: string
}
}
let { row }: Props = $props()
const dispatch = createEventDispatcher()
async function toggleDelete() {
@@ -16,17 +16,20 @@
import ThemeDrawer from './ThemeDrawer.svelte'
import Dropdown from '$lib/components/DropdownV2.svelte'
export let previewThemePath: string | undefined = undefined
export let row: {
name: string
path: string
interface Props {
previewThemePath?: string | undefined
row: {
name: string
path: string
}
}
let { previewThemePath = $bindable(undefined), row }: Props = $props()
const { previewTheme, app } = getContext<AppViewerContext>('AppViewerContext')
let cssString: string | undefined = $app?.theme?.type === 'inlined' ? $app.theme.css : undefined
$: type = $app?.theme?.type
let type = $derived($app?.theme?.type)
const dispatch = createEventDispatcher()
@@ -162,7 +165,7 @@
}
]
}
let themeDrawer: ThemeDrawer
let themeDrawer: ThemeDrawer | undefined = $state()
</script>
<tr class={twMerge(previewThemePath === row.path ? 'bg-blue-200' : '', 'transition-all')}>
@@ -1,4 +1,7 @@
<script lang="ts">
import { run, createBubbler } from 'svelte/legacy'
const bubble = createBubbler()
import { createEventDispatcher } from 'svelte'
import { ButtonType } from './model'
import { twMerge } from 'tailwind-merge'
@@ -11,46 +14,6 @@
import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted'
import { triggerableByAI } from '$lib/actions/triggerableByAI'
export let id: string = ''
export let aiId: string | undefined = undefined
export let aiDescription: string | undefined = undefined
export let size: ButtonType.Size = 'md'
export let spacingSize: ButtonType.Size = size
export let color: ButtonType.Color | string = 'blue'
export let variant: ButtonType.Variant = 'contained'
export let btnClasses: string = ''
export let wrapperClasses: string = ''
export let wrapperStyle: string = ''
export let disabled: boolean = false
export let href: string | undefined = undefined
export let target: '_self' | '_blank' | undefined = undefined
export let iconOnly: boolean = false
export let loadUntilNav: boolean = false
export let clickableWhileLoading = false
export let element: ButtonType.Element | undefined = undefined
export let nonCaptureEvent: boolean = false
export let propagateEvent: boolean = false
export let loading = false
export let title: string | undefined = undefined
export let style: string = ''
export let download: string | undefined = undefined
export let startIcon: ButtonType.Icon | undefined = undefined
export let endIcon: ButtonType.Icon | undefined = undefined
export let shortCut:
| { key?: string; hide?: boolean; Icon?: any; withoutModifier?: boolean }
| undefined = undefined
export let tooltipPopover:
| {
placement?: Placement
openDelay?: number
closeDelay?: number
portal?: string
}
| undefined = undefined
export let dropdownBtnClasses: string = ''
type MenuItem = {
label: string
onClick?: (e?: Event) => void
@@ -58,8 +21,84 @@
icon?: any
disabled?: boolean
}
export let dropdownItems: MenuItem[] | (() => MenuItem[]) | undefined = undefined
export let hideDropdown: boolean = false
interface Props {
id?: string
aiId?: string | undefined
aiDescription?: string | undefined
size?: ButtonType.Size
spacingSize?: ButtonType.Size
color?: ButtonType.Color | string
variant?: ButtonType.Variant
btnClasses?: string
wrapperClasses?: string
wrapperStyle?: string
disabled?: boolean
href?: string | undefined
target?: '_self' | '_blank' | undefined
iconOnly?: boolean
loadUntilNav?: boolean
clickableWhileLoading?: boolean
element?: ButtonType.Element | undefined
nonCaptureEvent?: boolean
propagateEvent?: boolean
loading?: boolean
title?: string | undefined
style?: string
download?: string | undefined
startIcon?: ButtonType.Icon | undefined
endIcon?: ButtonType.Icon | undefined
shortCut?: { key?: string; hide?: boolean; Icon?: any; withoutModifier?: boolean } | undefined
tooltipPopover?:
| {
placement?: Placement
openDelay?: number
closeDelay?: number
portal?: string
}
| undefined
dropdownBtnClasses?: string
dropdownItems?: MenuItem[] | (() => MenuItem[]) | undefined
hideDropdown?: boolean
children?: import('svelte').Snippet
tooltip?: import('svelte').Snippet
[key: string]: any
}
let {
id = '',
aiId = undefined,
aiDescription = undefined,
size = 'md',
spacingSize = size,
color = 'blue',
variant = 'contained',
btnClasses = '',
wrapperClasses = '',
wrapperStyle = '',
disabled = false,
href = undefined,
target = undefined,
iconOnly = false,
loadUntilNav = false,
clickableWhileLoading = false,
element = $bindable(undefined),
nonCaptureEvent = false,
propagateEvent = false,
loading = $bindable(false),
title = undefined,
style = '',
download = undefined,
startIcon = undefined,
endIcon = undefined,
shortCut = undefined,
tooltipPopover = undefined,
dropdownBtnClasses = '',
dropdownItems = undefined,
hideDropdown = false,
children,
tooltip,
...rest
}: Props = $props()
function computeDropdowns(menuItems: MenuItem[] | (() => MenuItem[])): Item[] {
const items = typeof menuItems === 'function' ? menuItems() : menuItems
@@ -103,19 +142,21 @@
}
}
$: buttonClass = twMerge(
'w-full',
getColorClass(color, variant),
variant === 'border' ? 'border' : '',
ButtonType.FontSizeClasses[size],
ButtonType.SpacingClasses[spacingSize][variant],
'focus-visible:ring-2 font-semibold',
dropdownItems && dropdownItems.length > 0 ? 'rounded-l-md h-full' : 'rounded-md',
'justify-center items-center text-center whitespace-nowrap inline-flex gap-2',
btnClasses,
'active:opacity-80 transition-all',
disabled ? '!bg-surface-disabled !text-tertiary cursor-not-allowed' : '',
loading ? 'cursor-wait' : ''
let buttonClass = $derived(
twMerge(
'w-full',
getColorClass(color, variant),
variant === 'border' ? 'border' : '',
ButtonType.FontSizeClasses[size],
ButtonType.SpacingClasses[spacingSize][variant],
'focus-visible:ring-2 font-semibold',
dropdownItems && dropdownItems.length > 0 ? 'rounded-l-md h-full' : 'rounded-md',
'justify-center items-center text-center whitespace-nowrap inline-flex gap-2',
btnClasses,
'active:opacity-80 transition-all',
disabled ? '!bg-surface-disabled !text-tertiary cursor-not-allowed' : '',
loading ? 'cursor-wait' : ''
)
)
const iconMap = {
@@ -138,7 +179,7 @@
xl: 'm-[5px] qhd:m-[5.625px]'
}
$: lucideIconSize = (iconMap[size] ?? 12) * 1
let lucideIconSize = $derived((iconMap[size] ?? 12) * 1)
const {
elements: { trigger, content },
@@ -158,9 +199,13 @@
states: { open: undefined },
options: { openDelay: undefined }
}
$: tooltipPopover && openDelay !== undefined && ($openDelay = tooltipPopover?.openDelay) //This option is reactive
run(() => {
tooltipPopover && openDelay !== undefined && ($openDelay = tooltipPopover?.openDelay)
}) //This option is reactive
$: $open !== undefined && dispatchIfMounted('tooltipOpen', $open)
run(() => {
$open !== undefined && dispatchIfMounted('tooltipOpen', $open)
})
</script>
<div
@@ -182,141 +227,137 @@
}
}}
>
{#if href && !disabled}
<a
bind:this={element}
on:pointerdown
on:focus
on:blur
on:mouseenter
on:mouseleave
on:click={() => {
loading = true
dispatch('click', event)
if (!loadUntilNav) {
loading = false
}
}}
{href}
{download}
class={buttonClass}
{id}
{target}
tabindex={disabled ? -1 : 0}
{...$$restProps}
{style}
>
{#if loading}
<Loader2 class={twMerge('animate-spin', iconOnlyPadding[size])} size={lucideIconSize} />
{:else if startIcon?.icon}
<svelte:component
this={startIcon.icon}
class={twMerge(startIcon?.classes, iconOnlyPadding[size])}
size={lucideIconSize}
{...startIcon.props}
/>
{/if}
{#if href && !disabled}
<a
bind:this={element}
onpointerdown={bubble('pointerdown')}
onfocus={bubble('focus')}
onblur={bubble('blur')}
onmouseenter={bubble('mouseenter')}
onmouseleave={bubble('mouseleave')}
onclick={() => {
loading = true
dispatch('click', event)
if (!loadUntilNav) {
loading = false
}
}}
{href}
{download}
class={buttonClass}
{id}
{target}
tabindex={disabled ? -1 : 0}
{...rest}
{style}
>
{#if loading}
<Loader2 class={twMerge('animate-spin', iconOnlyPadding[size])} size={lucideIconSize} />
{:else if startIcon?.icon}
<startIcon.icon
class={twMerge(startIcon?.classes, iconOnlyPadding[size])}
size={lucideIconSize}
{...startIcon.props}
/>
{/if}
{#if !iconOnly}
<slot />
{/if}
{#if endIcon?.icon}
<svelte:component
this={endIcon.icon}
class={twMerge(endIcon?.classes, iconOnlyPadding[size])}
size={lucideIconSize}
/>
{/if}
{#if shortCut && !shortCut.hide}
<div class="flex flex-row items-center !text-md opacity-60 gap-0 font-normal">
{#if shortCut.withoutModifier !== true}{getModifierKey()}{/if}{#if shortCut.Icon}<shortCut.Icon
class="w-4 h-4"
size={lucideIconSize}
/>{:else}{shortCut.key}{/if}
</div>
{/if}
</a>
{:else}
<button
bind:this={element}
on:pointerdown
on:click={onClick}
on:focus
on:blur
on:mouseenter
on:mouseleave
class={buttonClass}
{id}
tabindex={disabled ? -1 : 0}
{title}
{...$$restProps}
disabled={disabled || (loading && !clickableWhileLoading)}
{style}
use:conditionalMelt={trigger}
{...$trigger}
>
{#if loading}
<Loader2 class={twMerge('animate-spin', iconOnlyPadding[size])} size={lucideIconSize} />
{:else if startIcon?.icon}
<svelte:component
this={startIcon.icon}
class={twMerge(startIcon?.classes, iconOnlyPadding[size])}
size={lucideIconSize}
{...startIcon.props}
/>
{/if}
{#if !iconOnly}
<slot />
{/if}
{#if endIcon?.icon}
<svelte:component
this={endIcon.icon}
class={twMerge(endIcon?.classes, iconOnlyPadding[size])}
size={lucideIconSize}
/>
{/if}
{#if shortCut && !shortCut.hide}
{@const Icon = shortCut.Icon}
<div class="flex flex-row items-center !text-md opacity-60 gap-0 font-normal">
{#if shortCut.withoutModifier !== true}{getModifierKey()}{/if}{#if shortCut.Icon}<Icon
size={lucideIconSize}
/>{:else}{shortCut.key}{/if}
</div>
{/if}
</button>
{#if tooltipPopover && $open}
<div use:conditionalMelt={content} {...$content} class="z-[20000]">
<slot name="tooltip" />
{#if !iconOnly}
{@render children?.()}
{/if}
{#if endIcon?.icon}
<endIcon.icon
class={twMerge(endIcon?.classes, iconOnlyPadding[size])}
size={lucideIconSize}
/>
{/if}
{#if shortCut && !shortCut.hide}
<div class="flex flex-row items-center !text-md opacity-60 gap-0 font-normal">
{#if shortCut.withoutModifier !== true}{getModifierKey()}{/if}{#if shortCut.Icon}<shortCut.Icon
class="w-4 h-4"
size={lucideIconSize}
/>{:else}{shortCut.key}{/if}
</div>
{/if}
{/if}
</a>
{:else}
<button
bind:this={element}
onpointerdown={bubble('pointerdown')}
onclick={onClick}
onfocus={bubble('focus')}
onblur={bubble('blur')}
onmouseenter={bubble('mouseenter')}
onmouseleave={bubble('mouseleave')}
class={buttonClass}
{id}
tabindex={disabled ? -1 : 0}
{title}
{...rest}
disabled={disabled || (loading && !clickableWhileLoading)}
{style}
use:conditionalMelt={trigger}
{...$trigger}
>
{#if loading}
<Loader2 class={twMerge('animate-spin', iconOnlyPadding[size])} size={lucideIconSize} />
{:else if startIcon?.icon}
<startIcon.icon
class={twMerge(startIcon?.classes, iconOnlyPadding[size])}
size={lucideIconSize}
{...startIcon.props}
/>
{/if}
{#if dropdownItems && dropdownItems.length > 0}
<Dropdown
aiId={aiId ? `${aiId}-dropdown` : undefined}
aiDescription={aiDescription ? `${aiDescription} dropdown` : undefined}
items={computeDropdowns(dropdownItems)}
class="h-auto w-fit"
hidePopup={hideDropdown}
usePointerDownOutside
on:open={() => dispatch('dropdownOpen', true)}
on:close={() => dispatch('dropdownOpen', false)}
>
<svelte:fragment slot="buttonReplacement">
<div
class={twMerge(
buttonClass,
'rounded-md m-0 p-0 center-center h-full',
variant === 'border' ? 'border-0 border-r border-y ' : 'border-0',
'rounded-r-md !rounded-l-none',
size === 'xs2' || size === 'xs' ? '!w-8' : '!w-10',
dropdownBtnClasses
)}
>
<ChevronDown size={lucideIconSize} />
</div>
</svelte:fragment>
</Dropdown>
{#if !iconOnly}
{@render children?.()}
{/if}
{#if endIcon?.icon}
<endIcon.icon
class={twMerge(endIcon?.classes, iconOnlyPadding[size])}
size={lucideIconSize}
/>
{/if}
{#if shortCut && !shortCut.hide}
{@const Icon = shortCut.Icon}
<div class="flex flex-row items-center !text-md opacity-60 gap-0 font-normal">
{#if shortCut.withoutModifier !== true}{getModifierKey()}{/if}{#if shortCut.Icon}<Icon
size={lucideIconSize}
/>{:else}{shortCut.key}{/if}
</div>
{/if}
</button>
{#if tooltipPopover && $open}
<div use:conditionalMelt={content} {...$content} class="z-[20000]">
{@render tooltip?.()}
</div>
{/if}
{/if}
{#if dropdownItems && dropdownItems.length > 0}
<Dropdown
aiId={aiId ? `${aiId}-dropdown` : undefined}
aiDescription={aiDescription ? `${aiDescription} dropdown` : undefined}
items={computeDropdowns(dropdownItems)}
class="h-auto w-fit"
hidePopup={hideDropdown}
usePointerDownOutside
on:open={() => dispatch('dropdownOpen', true)}
on:close={() => dispatch('dropdownOpen', false)}
>
{#snippet buttonReplacement()}
<div
class={twMerge(
buttonClass,
'rounded-md m-0 p-0 center-center h-full',
variant === 'border' ? 'border-0 border-r border-y ' : 'border-0',
'rounded-r-md !rounded-l-none',
size === 'xs2' || size === 'xs' ? '!w-8' : '!w-10',
dropdownBtnClasses
)}
>
<ChevronDown size={lucideIconSize} />
</div>
{/snippet}
</Dropdown>
{/if}
</div>
@@ -33,20 +33,34 @@
import { isDeployable } from '$lib/utils_deployable'
import { getDeployUiSettings } from '$lib/components/home/deploy_ui'
export let app: ListableApp & { has_draft?: boolean; draft_only?: boolean; canWrite: boolean }
export let marked: string | undefined
export let starred: boolean
export let shareModal: ShareModal
export let moveDrawer: MoveDrawer
export let deploymentDrawer: DeployWorkspaceDrawer
export let deleteConfirmedCallback: (() => void) | undefined
export let depth: number = 0
export let menuOpen: boolean = false
interface Props {
app: ListableApp & { has_draft?: boolean; draft_only?: boolean; canWrite: boolean }
marked: string | undefined
starred: boolean
shareModal: ShareModal
moveDrawer: MoveDrawer
deploymentDrawer: DeployWorkspaceDrawer
deleteConfirmedCallback: (() => void) | undefined
depth?: number
menuOpen?: boolean
}
let {
app,
marked,
starred,
shareModal,
moveDrawer,
deploymentDrawer,
deleteConfirmedCallback = $bindable(),
depth = 0,
menuOpen = $bindable(false)
}: Props = $props()
const dispatch = createEventDispatcher()
let appExport: { open: (path: string) => void } | undefined = undefined
let appDeploymentHistory: AppDeploymentHistory | undefined = undefined
let appExport: { open: (path: string) => void } | undefined = $state(undefined)
let appDeploymentHistory: AppDeploymentHistory | undefined = $state(undefined)
async function loadAppJson() {
appExport?.open(app.path)
@@ -72,7 +86,7 @@
canFavorite={!app.draft_only}
{depth}
>
<svelte:fragment slot="badges">
{#snippet badges()}
{#if app.execution_mode == 'anonymous'}
<Badge small>
<div class="flex gap-1 items-center">
@@ -92,8 +106,8 @@
<SharedBadge canWrite={app.canWrite} extraPerms={app.extra_perms} />
<DraftBadge has_draft={app.has_draft} draft_only={app.draft_only} />
<div class="w-8 center-center"></div>
</svelte:fragment>
<svelte:fragment slot="actions">
{/snippet}
{#snippet actions()}
<span class="hidden md:inline-flex gap-x-1">
{#if !$userStore?.operator}
{#if app.canWrite}
@@ -284,5 +298,5 @@
menuOpen = true
}}
/>
</svelte:fragment>
{/snippet}
</Row>
@@ -35,16 +35,31 @@
import FlowHistory from '$lib/components/flows/FlowHistory.svelte'
import { getDeployUiSettings } from '$lib/components/home/deploy_ui'
export let flow: Flow & { has_draft?: boolean; draft_only?: boolean; canWrite: boolean }
export let marked: string | undefined
export let starred: boolean
export let shareModal: ShareModal
export let moveDrawer: MoveDrawer
export let deleteConfirmedCallback: (() => void) | undefined
export let deploymentDrawer: DeployWorkspaceDrawer
export let errorHandlerMuted: boolean
export let depth: number = 0
export let menuOpen: boolean = false
interface Props {
flow: Flow & { has_draft?: boolean; draft_only?: boolean; canWrite: boolean }
marked: string | undefined
starred: boolean
shareModal: ShareModal
moveDrawer: MoveDrawer
deleteConfirmedCallback: (() => void) | undefined
deploymentDrawer: DeployWorkspaceDrawer
errorHandlerMuted: boolean
depth?: number
menuOpen?: boolean
}
let {
flow,
marked,
starred,
shareModal,
moveDrawer,
deleteConfirmedCallback = $bindable(),
deploymentDrawer,
errorHandlerMuted,
depth = 0,
menuOpen = $bindable(false)
}: Props = $props()
const dispatch = createEventDispatcher()
@@ -71,8 +86,8 @@
sendUserToast(`Could not delete this flow ${err.body}`, true)
}
}
let scheduleEditor: ScheduleEditor
let flowHistory: FlowHistory
let scheduleEditor: ScheduleEditor | undefined = $state(undefined)
let flowHistory: FlowHistory | undefined = $state(undefined)
</script>
{#if menuOpen}
@@ -97,15 +112,15 @@
canFavorite={!flow.draft_only}
{depth}
>
<svelte:fragment slot="badges">
{#snippet badges()}
{#if flow.archived}
<Badge color="red" baseClass="border">archived</Badge>
{/if}
<SharedBadge canWrite={flow.canWrite} extraPerms={flow.extra_perms} />
<DraftBadge has_draft={flow.has_draft} draft_only={flow.draft_only} />
<div class="w-8 center-center"></div>
</svelte:fragment>
<svelte:fragment slot="actions">
{/snippet}
{#snippet actions()}
<span class="hidden md:inline-flex gap-x-1">
{#if !$userStore?.operator}
{#if flow.canWrite && !flow.archived}
@@ -218,7 +233,7 @@
displayName: 'Deployments',
icon: HistoryIcon,
action: () => {
flowHistory.open()
flowHistory?.open()
},
hide: $userStore?.operator
},
@@ -291,5 +306,5 @@
menuOpen = true
}}
/>
</svelte:fragment>
{/snippet}
</Row>
@@ -18,17 +18,31 @@
import { isDeployable } from '$lib/utils_deployable'
import { getDeployUiSettings } from '$lib/components/home/deploy_ui'
export let app: ListableRawApp & { canWrite: boolean }
export let marked: string | undefined
export let starred: boolean
export let shareModal: ShareModal
export let moveDrawer: MoveDrawer
export let deleteConfirmedCallback: (() => void) | undefined
export let deploymentDrawer: DeployWorkspaceDrawer
export let depth: number = 0
export let menuOpen: boolean = false
interface Props {
app: ListableRawApp & { canWrite: boolean }
marked: string | undefined
starred: boolean
shareModal: ShareModal
moveDrawer: MoveDrawer
deleteConfirmedCallback: (() => void) | undefined
deploymentDrawer: DeployWorkspaceDrawer
depth?: number
menuOpen?: boolean
}
let updateAppDrawer: Drawer
let {
app,
marked,
starred,
shareModal,
moveDrawer,
deleteConfirmedCallback = $bindable(),
deploymentDrawer,
depth = 0,
menuOpen = $bindable(false)
}: Props = $props()
let updateAppDrawer: Drawer | undefined = $state(undefined)
const dispatch = createEventDispatcher()
</script>
@@ -66,10 +80,10 @@
canFavorite={true}
{depth}
>
<svelte:fragment slot="badges">
{#snippet badges()}
<SharedBadge canWrite={app.canWrite} extraPerms={app.extra_perms} />
</svelte:fragment>
<svelte:fragment slot="actions">
{/snippet}
{#snippet actions()}
<span class="hidden md:inline-flex gap-x-1">
{#if !$userStore?.operator}
{#if app.canWrite}
@@ -143,5 +157,5 @@
menuOpen = true
}}
/>
</svelte:fragment>
{/snippet}
</Row>
@@ -7,26 +7,55 @@
import { goto } from '$lib/navigation'
import { triggerableByAI } from '$lib/actions/triggerableByAI'
export let marked: string | undefined
export let starred: boolean
export let canFavorite: boolean = true
export let errorHandlerMuted: boolean = false
const dispatch = createEventDispatcher()
export let aiId: string | undefined = undefined
export let aiDescription: string | undefined = undefined
export let kind: 'script' | 'flow' | 'app' | 'raw_app' = 'script'
export let summary: string | undefined = undefined
export let path: string
export let href: string
export let workspaceId: string
export let depth: number = 0
interface Props {
marked: string | undefined
starred: boolean
canFavorite?: boolean
errorHandlerMuted?: boolean
aiId?: string | undefined
aiDescription?: string | undefined
kind?: 'script' | 'flow' | 'app' | 'raw_app'
summary?: string | undefined
path: string
href: string
workspaceId: string
depth?: number
badges?: import('svelte').Snippet
actions?: import('svelte').Snippet
}
let {
marked,
starred,
canFavorite = true,
errorHandlerMuted = false,
aiId = undefined,
aiDescription = undefined,
kind = 'script',
summary = undefined,
path,
href,
workspaceId,
depth = 0,
badges,
actions
}: Props = $props()
let displayPath: string = (depth === 0 ? path : path?.split('/')?.slice(-1)?.[0]) ?? ''
</script>
<div style="display: none" use:triggerableByAI={{id: aiId, description: aiDescription, callback: () => { goto(href) }}}></div>
<div
style="display: none"
use:triggerableByAI={{
id: aiId,
description: aiDescription,
callback: () => {
goto(href)
}
}}
></div>
<div
class={twMerge(
'hover:bg-surface-hover w-full inline-flex items-center gap-4 first-of-type:!border-t-0 first-of-type:rounded-t-md last-of-type:rounded-b-md [*:not(:last-child)]:border-b px-4 py-2.5 border-b last:border-b-0',
@@ -56,9 +85,9 @@
<BellOff class="w-8 opacity-60" size={12} fill="currentcolor" />
{/if}
{#if $$slots.badges}
{#if badges}
<div class="hidden lg:flex flex-row gap-4 items-center">
<slot name="badges" />
{@render badges?.()}
</div>
{/if}
@@ -79,6 +108,6 @@
{/if}
<div class="flex gap-1 items-center justify-end pr-2">
<slot name="actions" />
{@render actions?.()}
</div>
</div>
@@ -42,17 +42,33 @@
import Tooltip from '$lib/components/Tooltip.svelte'
import { getDeployUiSettings } from '$lib/components/home/deploy_ui'
export let script: Script & { canWrite: boolean; use_codebase: boolean }
export let marked: string | undefined
export let starred: boolean
export let shareModal: ShareModal
export let moveDrawer: MoveDrawer
export let deploymentDrawer: DeployWorkspaceDrawer
export let deleteConfirmedCallback: (() => void) | undefined
export let errorHandlerMuted: boolean
export let showCode: (path: string, summary: string) => void
export let depth: number = 0
export let menuOpen: boolean = false
interface Props {
script: Script & { canWrite: boolean; use_codebase: boolean }
marked: string | undefined
starred: boolean
shareModal: ShareModal
moveDrawer: MoveDrawer
deploymentDrawer: DeployWorkspaceDrawer
deleteConfirmedCallback: (() => void) | undefined
errorHandlerMuted: boolean
showCode: (path: string, summary: string) => void
depth?: number
menuOpen?: boolean
}
let {
script,
marked,
starred,
shareModal,
moveDrawer,
deploymentDrawer,
deleteConfirmedCallback = $bindable(),
errorHandlerMuted,
showCode,
depth = 0,
menuOpen = $bindable(false)
}: Props = $props()
const dispatch = createEventDispatcher()
@@ -81,10 +97,10 @@
dispatch('change')
sendUserToast(`Deleted script ${path}`)
}
let scheduleEditor: ScheduleEditor
let scheduleEditor: ScheduleEditor | undefined = $state(undefined)
const dlt: 'delete' = 'delete'
let versionsDrawerOpen: boolean = false
let versionsDrawerOpen: boolean = $state(false)
</script>
{#if menuOpen}
@@ -108,7 +124,7 @@
canFavorite={!script.draft_only}
{depth}
>
<svelte:fragment slot="badges">
{#snippet badges()}
{#if script.lock_error_logs}
<Badge color="red" baseClass="border border-red-200">Deployment failed</Badge>
{/if}
@@ -128,9 +144,9 @@
<div class="w-8 center-center">
<LanguageIcon lang={script.language} width={12} height={12} />
</div>
</svelte:fragment>
{/snippet}
<svelte:fragment slot="actions">
{#snippet actions()}
<span class="hidden md:inline-flex gap-x-1">
{#if !$userStore?.operator}
{#if script.use_codebase}
@@ -261,7 +277,7 @@
displayName: 'Schedule',
icon: Calendar,
action: () => {
scheduleEditor.openNew(false, script.path)
scheduleEditor?.openNew(false, script.path)
},
disabled: script.archived,
hide: $userStore?.operator
@@ -340,7 +356,7 @@
menuOpen = true
}}
/>
</svelte:fragment>
{/snippet}
</Row>
{#if script}
@@ -4,18 +4,30 @@
import DropdownV2 from '$lib/components/DropdownV2.svelte'
import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte'
export let disabled: boolean = false
export let small = false
export let light = false
export let id: string | undefined = undefined
export let item: any | undefined = undefined
export let selected: string | undefined = undefined
type TogglableItem = {
label: string
value: string
}
export let togglableItems: TogglableItem[]
interface Props {
disabled?: boolean
small?: boolean
light?: boolean
id?: string | undefined
item?: any | undefined
selected?: string | undefined
togglableItems: TogglableItem[]
}
let {
disabled = false,
small = false,
light = false,
id = undefined,
item = undefined,
selected = $bindable(undefined),
togglableItems
}: Props = $props()
function select(v: string) {
selected = v
@@ -23,16 +23,31 @@
color?: 'red'
}
const { triggersCount, triggersState } = getContext<TriggerContext>('TriggerContext')
const { triggersCount, triggersState } = $state(getContext<TriggerContext>('TriggerContext'))
export let mainButtons: MainButton[] = []
export let menuItems: MenuItemButton[] = []
export let title: string
export let tag: string | undefined
interface Props {
mainButtons?: MainButton[]
menuItems?: MenuItemButton[]
title: string
tag: string | undefined
errorHandlerKind: 'flow' | 'script'
scriptOrFlowPath: string
errorHandlerMuted: boolean | undefined
children?: import('svelte').Snippet
trigger_badges?: import('svelte').Snippet
}
export let errorHandlerKind: 'flow' | 'script'
export let scriptOrFlowPath: string
export let errorHandlerMuted: boolean | undefined
let {
mainButtons = [],
menuItems = [],
title,
tag,
errorHandlerKind,
scriptOrFlowPath,
errorHandlerMuted = $bindable(),
children,
trigger_badges
}: Props = $props()
const dispatch = createEventDispatcher()
</script>
@@ -51,7 +66,7 @@
</div>{#if tag}
<Badge>tag: {tag}</Badge>
{/if}
<slot />
{@render children?.()}
{#if triggersState?.triggers?.some((t) => t.isPrimary && !t.isDraft)}
{@const primarySchedule = triggersState.triggers.findIndex(
(t) => t.isPrimary && !t.isDraft
@@ -71,7 +86,7 @@
{$triggersCount?.primary_schedule?.schedule ?? ''}
</Button>
{/if}
<slot name="trigger-badges" />
{@render trigger_badges?.()}
</div>
<div class="flex gap-1 md:gap-2 items-center">
{#if menuItems.length > 0}
@@ -10,12 +10,13 @@
import { Loader2, Plus } from 'lucide-svelte'
import YAML from 'yaml'
let drawer: Drawer | undefined = undefined
let pendingRaw: string
let importType: 'yaml' | 'json' = 'yaml'
let drawer: Drawer | undefined = $state(undefined)
let pendingRaw: string | undefined = $state(undefined)
let importType: 'yaml' | 'json' = $state('yaml')
async function importRaw() {
$importFlowStore = importType === 'yaml' ? YAML.parse(pendingRaw) : JSON.parse(pendingRaw)
$importFlowStore =
importType === 'yaml' ? YAML.parse(pendingRaw ?? '') : JSON.parse(pendingRaw ?? '')
await goto('/flows/add')
drawer?.closeDrawer?.()
}
@@ -148,7 +148,7 @@
items[idx].success == false ? 'text-red-400' : '',
'data-[highlighted]:bg-surface-hover'
)}
on:click={() => {
onClick={() => {
onSelectedIteration({
moduleId: moduleId,
index: items[idx].index,
@@ -295,7 +295,7 @@
<MenuItem
{item}
class={itemClass}
on:click={() => {
onClick={() => {
onSelect?.(triggerIndex)
}}
>
@@ -3,15 +3,36 @@
import type { MenubarMenuElements } from '@melt-ui/svelte'
import { triggerableByAI } from '$lib/actions/triggerableByAI'
export let aiId: string | undefined = undefined
export let aiDescription: string | undefined = undefined
export let href: string | undefined = undefined
export let disabled: boolean = false
export let target: string | undefined = undefined
export let item: MenubarMenuElements['item']
interface Props {
aiId?: string | undefined
aiDescription?: string | undefined
href?: string | undefined
disabled?: boolean
target?: string | undefined
item: MenubarMenuElements['item']
class?: string | undefined
onClick?: (event: MouseEvent) => void
children?: import('svelte').Snippet
onFocusIn?: (event: FocusEvent) => void
onFocusOut?: (event: FocusEvent) => void
}
let aRef: HTMLAnchorElement | undefined = undefined
let buttonRef: HTMLButtonElement | undefined = undefined
let {
aiId = undefined,
aiDescription = undefined,
href = undefined,
disabled = false,
target = undefined,
item,
class: classNames = undefined,
children,
onClick,
onFocusIn,
onFocusOut
}: Props = $props()
let aRef: HTMLAnchorElement | undefined = $state(undefined)
let buttonRef: HTMLButtonElement | undefined = $state(undefined)
</script>
{#if href}
@@ -26,20 +47,20 @@
}
}}
{href}
class={$$props.class}
class={classNames}
role="menuitem"
aria-disabled={disabled}
tabindex={disabled ? -1 : undefined}
{target}
on:m-focusin
on:m-focusout
onfocusin={onFocusIn}
onfocusout={onFocusOut}
>
<slot />
{@render children?.()}
</a>
{:else}
<button
bind:this={buttonRef}
on:click
onclick={onClick}
use:melt={$item}
use:triggerableByAI={{
id: aiId,
@@ -49,11 +70,11 @@
}
}}
{disabled}
class={$$props.class}
class={classNames}
role="menuitem"
on:m-focusin
on:m-focusout
onfocusin={onFocusIn}
onfocusout={onFocusOut}
>
<slot />
{@render children?.()}
</button>
{/if}
@@ -219,7 +219,7 @@
<div role="none">
<MenuItem
on:click={() => {
onClick={() => {
if (!document.documentElement.classList.contains('dark')) {
document.documentElement.classList.add('dark')
window.localStorage.setItem('dark-mode', 'dark')
@@ -244,7 +244,7 @@
</MenuItem>
<MenuItem
href="{base}/user/workspaces"
on:click={() => {
onClick={() => {
localStorage.removeItem('workspace')
}}
class={twMerge(
@@ -274,7 +274,7 @@
{/if}
<MenuItem
on:click={() => logout()}
onClick={() => logout()}
class={twMerge(
'flex flex-row gap-3.5 items-center px-2 py-2 w-full',
'text-secondary text-xs',
@@ -293,8 +293,8 @@
role="none"
>
<MenuItem
on:m-focusin={() => debouncedSetMoreOpen(true)}
on:m-focusout={() => debouncedSetMoreOpen(false)}
onFocusIn={() => debouncedSetMoreOpen(true)}
onFocusOut={() => debouncedSetMoreOpen(false)}
{item}
>
{#if !moreOpen || secondMenuLinks.length === 0}
@@ -311,8 +311,8 @@
'data-[highlighted]:bg-surface-hover data-[highlighted]:text-primary'
)}
{item}
on:m-focusin={() => debouncedSetMoreOpen(true)}
on:m-focusout={() => debouncedSetMoreOpen(false)}
onFocusIn={() => debouncedSetMoreOpen(true)}
onFocusOut={() => debouncedSetMoreOpen(false)}
>
{menuLink.label}
</MenuItem>
@@ -510,7 +510,7 @@
class={itemClass}
href={subItem.href}
{item}
on:click={() => {
onClick={() => {
subItem?.['action']?.()
}}
aiId={subItem.aiId}
@@ -66,7 +66,7 @@
</MenuItem>
<MenuItem
on:click={() => {
onClick={() => {
if (!document.documentElement.classList.contains('dark')) {
document.documentElement.classList.add('dark')
window.localStorage.setItem('dark-mode', 'dark')
@@ -87,7 +87,7 @@
</MenuItem>
<MenuItem
on:click={() => logout()}
onClick={() => logout()}
class={twMerge(itemClass, 'text-primary font-semibold')}
{item}
>
@@ -124,7 +124,7 @@
{#if $userStore?.is_admin}
<MenuItem
class={twMerge(itemClass, 'py-2')}
on:click={() => {
onClick={() => {
goto('/workspace_settings?tab=premium')
}}
{item}
@@ -135,7 +135,7 @@
{:else}
<MenuItem
class={twMerge(itemClass, 'py-2')}
on:click={() => {
onClick={() => {
goto('/workspace_settings?tab=premium')
}}
{item}
@@ -81,7 +81,7 @@
? 'cursor-default bg-surface-selected'
: 'cursor-pointer hover:bg-surface-hover data-[highlighted]:bg-surface-hover'
)}
on:click={async () => {
onClick={async () => {
await toggleSwitchWorkspace(workspace.id)
}}
{item}
@@ -123,7 +123,7 @@
<div class="py-1" role="none">
<MenuItem
href="{base}/user/workspaces"
on:click={() => {
onClick={() => {
localStorage.removeItem('workspace')
}}
class={twMerge(
@@ -169,7 +169,7 @@
'text-secondary block font-normal w-full text-left px-4 py-2 text-sm hover:bg-gray-100 hover:text-gray-900',
'data-[highlighted]:bg-gray-100 data-[highlighted]:text-gray-900'
)}
on:click={() => {
onClick={() => {
goto('/workspace_settings?tab=premium')
}}
{item}
@@ -975,7 +975,6 @@
{/snippet}
{#snippet action()}
<div class="flex flex-row items-center gap-1 text-2xs text-tertiary">
defaults
<Dropdown
disabled={!can_write}
items={[
@@ -990,7 +989,7 @@
}
]}
>
{#snippet children()}
{#snippet buttonReplacement()}
<Save size={12} class="mr-1" />
Set as default
{/snippet}
@@ -1091,7 +1090,7 @@
}
]}
>
{#snippet children()}
{#snippet buttonReplacement()}
<Save size={12} class="mr-1" />
Set as default
{/snippet}
@@ -1182,7 +1181,7 @@
}
]}
>
{#snippet children()}
{#snippet buttonReplacement()}
<Save size={12} class="mr-1" />
Set as default
{/snippet}
+1
View File
@@ -1250,6 +1250,7 @@ export type Item = {
icon?: any
iconColor?: string
href?: string
hrefTarget?: '_blank' | '_self' | '_parent' | '_top'
disabled?: boolean
type?: 'action' | 'delete'
hide?: boolean | undefined
@@ -446,7 +446,7 @@
tag={flow.tag}
>
<!-- @migration-task: migrate this slot by hand, `trigger-badges` is an invalid identifier -->
<svelte:fragment slot="trigger-badges">
{#snippet trigger_badges()}
<TriggersBadge
showOnlyWithCount={true}
showDraft={false}
@@ -461,7 +461,7 @@
}}
small={false}
/>
</svelte:fragment>
{/snippet}
{#if $workspaceStore}
<Star
kind="flow"
@@ -19,13 +19,14 @@
import Head from '$lib/components/table/Head.svelte'
import Cell from '$lib/components/table/Cell.svelte'
import Row from '$lib/components/table/Row.svelte'
import { untrack } from 'svelte'
type GroupW = Group & { canWrite: boolean }
let newGroupName: string = ''
let groups: GroupW[] | undefined = undefined
let instanceGroups: InstanceGroup[] | undefined = undefined
let groupDrawer: Drawer
let newGroupName: string = $state('')
let groups: GroupW[] | undefined = $state(undefined)
let instanceGroups: InstanceGroup[] | undefined = $state(undefined)
let groupDrawer: Drawer | undefined = $state()
async function loadGroups(): Promise<void> {
groups = (await GroupService.listGroups({ workspace: $workspaceStore! })).map((x) => {
@@ -56,17 +57,17 @@
})
loadGroups()
editGroupName = newGroupName
groupDrawer.openDrawer()
groupDrawer?.openDrawer()
}
$: {
loadInstanceGroups()
$effect(() => {
untrack(() => loadInstanceGroups())
if ($workspaceStore && $userStore) {
loadGroups()
untrack(() => loadGroups())
}
}
})
let editGroupName: string = ''
let editGroupName: string = $state('')
</script>
<Drawer bind:this={groupDrawer}>
@@ -93,14 +94,14 @@
floatingConfig={{ strategy: 'absolute', placement: 'bottom-end' }}
containerClasses="border rounded-lg shadow-lg p-4 bg-surface"
>
<svelte:fragment slot="trigger">
{#snippet trigger()}
<Button size="md" startIcon={{ icon: Plus }} nonCaptureEvent>New&nbsp;group</Button>
</svelte:fragment>
<svelte:fragment slot="content" let:close>
{/snippet}
{#snippet content({ close })}
<div class="flex-col flex gap-2 p-4">
<input
class="mr-2"
on:keyup={(e) => handleKeyUp(e, close)}
onkeyup={(e) => handleKeyUp(e, close)}
placeholder="New group name"
bind:value={newGroupName}
/>
@@ -116,7 +117,7 @@
Create
</Button>
</div>
</svelte:fragment>
{/snippet}
</Popover>
</div>
</div>
@@ -146,7 +147,7 @@
hoverable
on:click={() => {
editGroupName = name
groupDrawer.openDrawer()
groupDrawer?.openDrawer()
}}
>
<Cell first>
@@ -174,7 +175,7 @@
action: (e) => {
e?.stopPropagation()
editGroupName = name
groupDrawer.openDrawer()
groupDrawer?.openDrawer()
}
},
{
@@ -206,27 +207,30 @@
/>
<div class="relative mb-20 pt-8">
<TableCustom>
<!-- @migration-task: migrate this slot by hand, `header-row` is an invalid identifier -->
<tr slot="header-row">
<th>Name</th>
<th>Members</th>
</tr>
<tbody slot="body">
{#each instanceGroups as { name, emails }}
<tr>
<td>
<a
href="#{name}"
on:click={() => {
editGroupName = name
groupDrawer.openDrawer()
}}
>{name}
</a>
</td>
<td>{emails?.length ?? 0} members</td>
</tr>
{/each}
</tbody>
{#snippet body()}
<tbody>
{#each instanceGroups ?? [] as { name, emails }}
<tr>
<td>
<a
href="#{name}"
onclick={() => {
editGroupName = name
groupDrawer?.openDrawer()
}}
>{name}
</a>
</td>
<td>{emails?.length ?? 0} members</td>
</tr>
{/each}
</tbody>
{/snippet}
</TableCustom>
</div>
{/if}
@@ -564,12 +564,11 @@
rightPaneSelected = 'triggers'
}}
>
<!-- @migration-task: migrate this slot by hand, `trigger-badges` is an invalid identifier -->
<svelte:fragment slot="trigger-badges">
{#snippet trigger_badges()}
<TriggersBadge
showOnlyWithCount={true}
showDraft={false}
path={script.path}
path={script?.path ?? ''}
newItem={false}
isFlow={false}
selected={rightPaneSelected === 'triggers'}
@@ -581,7 +580,7 @@
triggersState.selectedTriggerIndex = triggerIndex
}}
/>
</svelte:fragment>
{/snippet}
{#if $workspaceStore}
<Star
kind="script"
@@ -6,7 +6,7 @@
import DarkModeToggle from '$lib/components/sidebar/DarkModeToggle.svelte'
import { Globe } from 'lucide-svelte'
let tab = 'button'
let tab = $state('button')
let dropdownItems = [
{
label: 'Lorem ipsum',