mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-27 00:02:35 +00:00
Svelte 5 migration tool + claude code @migration-task fixes
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Button, Drawer } from './common'
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
@@ -6,24 +8,27 @@
|
||||
import AppConnectInner from './AppConnectInner.svelte'
|
||||
import DarkModeObserver from './DarkModeObserver.svelte'
|
||||
|
||||
export let expressOAuthSetup = false
|
||||
interface Props {
|
||||
expressOAuthSetup?: boolean;
|
||||
}
|
||||
|
||||
let drawer: Drawer
|
||||
let resourceType = ''
|
||||
let step = 1
|
||||
let disabled = false
|
||||
let isGoogleSignin = false
|
||||
let manual = true
|
||||
let { expressOAuthSetup = false }: Props = $props();
|
||||
|
||||
let appConnectInner: AppConnectInner | undefined = undefined
|
||||
let drawer: Drawer = $state()
|
||||
let resourceType = $state('')
|
||||
let step = $state(1)
|
||||
let disabled = $state(false)
|
||||
let isGoogleSignin = $state(false)
|
||||
let manual = $state(true)
|
||||
|
||||
let rtToLoad: string | undefined = ''
|
||||
let appConnectInner: AppConnectInner | undefined = $state(undefined)
|
||||
|
||||
let rtToLoad: string | undefined = $state('')
|
||||
export async function open(rt?: string) {
|
||||
rtToLoad = rt
|
||||
drawer.openDrawer?.()
|
||||
}
|
||||
|
||||
$: appConnectInner && onRtToLoadChange(rtToLoad)
|
||||
|
||||
function onRtToLoadChange(rtToLoad: string | undefined) {
|
||||
appConnectInner?.open(rtToLoad)
|
||||
@@ -31,7 +36,10 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let darkMode: boolean = false
|
||||
let darkMode: boolean = $state(false)
|
||||
run(() => {
|
||||
appConnectInner && onRtToLoadChange(rtToLoad)
|
||||
});
|
||||
</script>
|
||||
|
||||
<DarkModeObserver bind:darkMode />
|
||||
@@ -68,7 +76,7 @@
|
||||
<Button variant="default" on:click={appConnectInner?.back ?? (() => {})}>Back</Button>
|
||||
{/if}
|
||||
{#if isGoogleSignin}
|
||||
<button {disabled} on:click={appConnectInner?.next}>
|
||||
<button {disabled} onclick={appConnectInner?.next}>
|
||||
<img
|
||||
class="h-10 w-auto object-contain"
|
||||
src={darkMode ? '/google_signin_dark.png' : '/google_signin_light.png'}
|
||||
|
||||
@@ -892,8 +892,8 @@
|
||||
{:else if itemsType?.type == 'string' && itemsType?.contentEncoding == 'base64'}
|
||||
<FileInput
|
||||
class="w-full"
|
||||
on:change={(x) =>
|
||||
fileChangedInner(x.detail?.[0], (val) => (value[i] = val))}
|
||||
onChange={(x) =>
|
||||
fileChangedInner(x?.[0], (val) => (value[i] = val))}
|
||||
multiple={false}
|
||||
/>
|
||||
{@render deleteItemBtn()}
|
||||
@@ -1390,7 +1390,7 @@
|
||||
{:else if inputCat == 'base64'}
|
||||
<div class="flex flex-col w-full">
|
||||
<FileInput
|
||||
on:change={(x) => fileChangedInner(x.detail?.[0], (val) => (value = val))}
|
||||
onChange={(x) => fileChangedInner(x?.[0], (val) => (value = val))}
|
||||
multiple={false}
|
||||
/>
|
||||
{#if value?.length}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
import SettingCard from './instanceSettings/SettingCard.svelte'
|
||||
|
||||
export let value: any
|
||||
interface Props {
|
||||
value: any;
|
||||
}
|
||||
|
||||
$: enabled = value != undefined
|
||||
let { value = $bindable() }: Props = $props();
|
||||
|
||||
let org = ''
|
||||
|
||||
$: changeOrg(org)
|
||||
let org = $state('')
|
||||
|
||||
|
||||
function changeOrg(org) {
|
||||
if (value) {
|
||||
@@ -30,10 +34,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
let enabled = $derived(value != undefined)
|
||||
run(() => {
|
||||
changeOrg(org)
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="text-xs font-semibold text-emphasis flex gap-4 items-center"
|
||||
><div class="w-[120px]"><IconedResourceType name={'authelia'} after={true} /></div><Toggle
|
||||
checked={enabled}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
import SettingCard from './instanceSettings/SettingCard.svelte'
|
||||
|
||||
export let value: any
|
||||
interface Props {
|
||||
value: any;
|
||||
}
|
||||
|
||||
let { value = $bindable() }: Props = $props();
|
||||
|
||||
$: enabled = value != undefined
|
||||
|
||||
// Initialize org from existing auth_url
|
||||
$: org = value?.connect_config?.auth_url?.replace('/application/o/authorize/', '') ?? ''
|
||||
|
||||
$: changeOrg(org)
|
||||
|
||||
function changeOrg(org) {
|
||||
if (value && org) {
|
||||
@@ -30,10 +32,16 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
let enabled = $derived(value != undefined)
|
||||
// Initialize org from existing auth_url
|
||||
let org = $derived(value?.connect_config?.auth_url?.replace('/application/o/authorize/', '') ?? '')
|
||||
run(() => {
|
||||
changeOrg(org)
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="text-xs font-semibold text-emphasis flex gap-4 items-center"
|
||||
><div class="w-[120px]"><IconedResourceType name={'authentik'} after={true} /></div><Toggle
|
||||
checked={enabled}
|
||||
|
||||
@@ -1,38 +1,48 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { ExternalLink } from 'lucide-svelte'
|
||||
import OauthScopes from './OauthScopes.svelte'
|
||||
|
||||
export let connect_config: {
|
||||
interface Props {
|
||||
connect_config?: {
|
||||
scopes: string[]
|
||||
auth_url: string
|
||||
token_url: string
|
||||
req_body_auth: boolean
|
||||
extra_params: { tenant_id: string }
|
||||
extra_params_callback: Record<string, any>
|
||||
} = {
|
||||
};
|
||||
}
|
||||
|
||||
let { connect_config = $bindable({
|
||||
scopes: ['offline_access'],
|
||||
auth_url: '',
|
||||
token_url: '',
|
||||
req_body_auth: true,
|
||||
extra_params: { tenant_id: '' },
|
||||
extra_params_callback: {}
|
||||
}
|
||||
}) }: Props = $props();
|
||||
|
||||
$: if (!connect_config) {
|
||||
connect_config = {
|
||||
scopes: ['offline_access'],
|
||||
auth_url: '',
|
||||
token_url: '',
|
||||
req_body_auth: true,
|
||||
extra_params: { tenant_id: '' },
|
||||
extra_params_callback: {}
|
||||
run(() => {
|
||||
if (!connect_config) {
|
||||
connect_config = {
|
||||
scopes: ['offline_access'],
|
||||
auth_url: '',
|
||||
token_url: '',
|
||||
req_body_auth: true,
|
||||
extra_params: { tenant_id: '' },
|
||||
extra_params_callback: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$: if (connect_config.extra_params.tenant_id) {
|
||||
connect_config.auth_url = `https://login.microsoftonline.com/${connect_config.extra_params.tenant_id}/oauth2/v2.0/authorize`
|
||||
connect_config.token_url = `https://login.microsoftonline.com/${connect_config.extra_params.tenant_id}/oauth2/v2.0/token`
|
||||
}
|
||||
run(() => {
|
||||
if (connect_config.extra_params.tenant_id) {
|
||||
connect_config.auth_url = `https://login.microsoftonline.com/${connect_config.extra_params.tenant_id}/oauth2/v2.0/authorize`
|
||||
connect_config.token_url = `https://login.microsoftonline.com/${connect_config.extra_params.tenant_id}/oauth2/v2.0/token`
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<label class="flex flex-col gap-1" for="tenant-id">
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
<script lang="ts">
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
export let twBgColor = 'bg-blue-200'
|
||||
export let twTextColor = 'text-secondary'
|
||||
export let tooltip: string | undefined = undefined
|
||||
interface Props {
|
||||
twBgColor?: string;
|
||||
twTextColor?: string;
|
||||
tooltip?: string | undefined;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
twBgColor = 'bg-blue-200',
|
||||
twTextColor = 'text-secondary',
|
||||
tooltip = undefined,
|
||||
children
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<span class="{twBgColor} {twTextColor} text-2xs rounded px-1 whitespace-nowrap">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
{#if tooltip && tooltip != ''}
|
||||
<Tooltip>{tooltip}</Tooltip>
|
||||
{/if}
|
||||
|
||||
@@ -5,12 +5,21 @@
|
||||
import Alert from './common/alert/Alert.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let email: string
|
||||
export let username: string
|
||||
export let isConflict = false
|
||||
export let noPadding = false
|
||||
interface Props {
|
||||
email: string;
|
||||
username: string;
|
||||
isConflict?: boolean;
|
||||
noPadding?: boolean;
|
||||
}
|
||||
|
||||
let loading = false
|
||||
let {
|
||||
email,
|
||||
username = $bindable(),
|
||||
isConflict = false,
|
||||
noPadding = false
|
||||
}: Props = $props();
|
||||
|
||||
let loading = $state(false)
|
||||
|
||||
let usernameInfo:
|
||||
| {
|
||||
@@ -20,7 +29,7 @@
|
||||
username: string
|
||||
}[]
|
||||
}
|
||||
| undefined = undefined
|
||||
| undefined = $state(undefined)
|
||||
|
||||
function handleKeyUp(event: KeyboardEvent) {
|
||||
const key = event.key
|
||||
@@ -83,7 +92,7 @@
|
||||
<input
|
||||
type="text"
|
||||
class="mb-4"
|
||||
on:keyup={handleKeyUp}
|
||||
onkeyup={handleKeyUp}
|
||||
bind:value={username}
|
||||
disabled={isConflict}
|
||||
/>
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let edit: boolean = false
|
||||
let name: string = ''
|
||||
let value: string = ''
|
||||
let edit: boolean = $state(false)
|
||||
let name: string = $state('')
|
||||
let value: string = $state('')
|
||||
|
||||
export function initNew(): void {
|
||||
edit = false
|
||||
@@ -31,7 +31,7 @@
|
||||
drawer.openDrawer()
|
||||
}
|
||||
|
||||
let drawer: Drawer
|
||||
let drawer: Drawer = $state()
|
||||
|
||||
async function updateVariable(): Promise<void> {
|
||||
await WorkspaceService.setEnvironmentVariable({
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import OauthExtraParams from './OauthExtraParams.svelte'
|
||||
import OauthScopes from './OauthScopes.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
|
||||
export let connect_config = {
|
||||
let { connect_config = $bindable({
|
||||
scopes: [],
|
||||
auth_url: '',
|
||||
token_url: '',
|
||||
req_body_auth: false,
|
||||
extra_params: {},
|
||||
extra_params_callback: {}
|
||||
}
|
||||
}) } = $props();
|
||||
|
||||
$: if (!connect_config) {
|
||||
connect_config = {
|
||||
scopes: [],
|
||||
auth_url: '',
|
||||
token_url: '',
|
||||
req_body_auth: false,
|
||||
extra_params: {},
|
||||
extra_params_callback: {}
|
||||
run(() => {
|
||||
if (!connect_config) {
|
||||
connect_config = {
|
||||
scopes: [],
|
||||
auth_url: '',
|
||||
token_url: '',
|
||||
req_body_auth: false,
|
||||
extra_params: {},
|
||||
extra_params_callback: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-6">
|
||||
@@ -42,12 +46,12 @@
|
||||
bind:value={connect_config.token_url}
|
||||
/>
|
||||
</label>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="flex flex-col gap-1">
|
||||
<span class="text-emphasis font-semibold text-xs">Scopes</span>
|
||||
<OauthScopes bind:scopes={connect_config.scopes} />
|
||||
</label>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="flex flex-col gap-1">
|
||||
<span class="text-emphasis font-semibold text-xs"
|
||||
>Extra Query Args for Authorize Request <Tooltip
|
||||
@@ -57,14 +61,14 @@
|
||||
>
|
||||
<OauthExtraParams bind:extra_params={connect_config.extra_params} />
|
||||
</label>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="flex flex-col gap-1">
|
||||
<span class="text-emphasis font-semibold text-xs"
|
||||
>Extra Query Args for Token request <Tooltip>Not needed in most cases</Tooltip></span
|
||||
>
|
||||
<OauthExtraParams bind:extra_params={connect_config.extra_params_callback} />
|
||||
</label>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="flex flex-col gap-1">
|
||||
<span class="text-emphasis font-semibold text-xs"
|
||||
>Payload <Tooltip
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import OauthExtraParams from './OauthExtraParams.svelte'
|
||||
import OauthScopes from './OauthScopes.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
|
||||
export let login_config = {
|
||||
let { login_config = $bindable({
|
||||
scopes: [],
|
||||
auth_url: '',
|
||||
token_url: '',
|
||||
@@ -12,19 +14,21 @@
|
||||
req_body_auth: false,
|
||||
extra_params: {},
|
||||
extra_params_callback: {}
|
||||
}
|
||||
}) } = $props();
|
||||
|
||||
$: if (!login_config) {
|
||||
login_config = {
|
||||
scopes: [],
|
||||
auth_url: '',
|
||||
token_url: '',
|
||||
userinfo_url: '',
|
||||
req_body_auth: false,
|
||||
extra_params: {},
|
||||
extra_params_callback: {}
|
||||
run(() => {
|
||||
if (!login_config) {
|
||||
login_config = {
|
||||
scopes: [],
|
||||
auth_url: '',
|
||||
token_url: '',
|
||||
userinfo_url: '',
|
||||
req_body_auth: false,
|
||||
extra_params: {},
|
||||
extra_params_callback: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<label class="block pb-6">
|
||||
@@ -51,12 +55,12 @@
|
||||
bind:value={login_config.userinfo_url}
|
||||
/>
|
||||
</label>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="block pb-6">
|
||||
<span class="text-primary font-semibold text-xs">Scopes</span>
|
||||
<OauthScopes bind:scopes={login_config.scopes} />
|
||||
</label>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="block pb-6">
|
||||
<span class="text-primary font-semibold text-xs"
|
||||
>Extra Query Args for Authorize Request <Tooltip
|
||||
@@ -66,14 +70,14 @@
|
||||
>
|
||||
<OauthExtraParams bind:extra_params={login_config.extra_params} />
|
||||
</label>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="block pb-6">
|
||||
<span class="text-primary font-semibold text-xs"
|
||||
>Extra Query Args for Token request <Tooltip>Not needed in most cases</Tooltip></span
|
||||
>
|
||||
<OauthExtraParams bind:extra_params={login_config.extra_params_callback} />
|
||||
</label>
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="block pb-6">
|
||||
<span class="text-primary font-semibold text-xs"
|
||||
>Payload <Tooltip
|
||||
|
||||
@@ -6,11 +6,15 @@
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import DefaultScriptsInner from './DefaultScriptsInner.svelte'
|
||||
|
||||
let drawer: Drawer
|
||||
export let placement: 'left' | 'right' = 'left'
|
||||
let drawer: Drawer = $state()
|
||||
|
||||
export let size: 'xs3' | 'xs2' = 'xs2'
|
||||
export let noText = false
|
||||
interface Props {
|
||||
placement?: 'left' | 'right';
|
||||
size?: 'xs3' | 'xs2';
|
||||
noText?: boolean;
|
||||
}
|
||||
|
||||
let { placement = 'left', size = 'xs2', noText = false }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if $userStore?.is_admin || $userStore?.is_super_admin}
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
import { defaultScriptLanguages } from '$lib/scripts'
|
||||
import Alert from './common/alert/Alert.svelte'
|
||||
|
||||
export let small = false
|
||||
$: langs = computeLangs($defaultScripts)
|
||||
interface Props {
|
||||
small?: boolean;
|
||||
}
|
||||
|
||||
let { small = false }: Props = $props();
|
||||
|
||||
function computeLangs(defaultScripts: WorkspaceDefaultScripts | undefined): Script['language'][] {
|
||||
const allLangs = Object.keys(defaultScriptLanguages) as Script['language'][]
|
||||
@@ -30,6 +33,7 @@
|
||||
requestBody: $defaultScripts
|
||||
})
|
||||
}
|
||||
let langs = $derived(computeLangs($defaultScripts))
|
||||
</script>
|
||||
|
||||
<Alert title="Global to workspace" type="info" class="mb-4" size={small ? 'xs' : 'sm'}>
|
||||
@@ -47,7 +51,7 @@
|
||||
<div>
|
||||
{#if i > 0}
|
||||
<button
|
||||
on:click={() => changePosition(i ?? 0, true)}
|
||||
onclick={() => changePosition(i ?? 0, true)}
|
||||
class={small ? 'mr-2 text-secondary text-sm' : 'text-lg mr-2'}
|
||||
title="Move up"
|
||||
>
|
||||
@@ -56,7 +60,7 @@
|
||||
{/if}
|
||||
{#if i < langs.length - 1}
|
||||
<button
|
||||
on:click={() => changePosition(i ?? 0, false)}
|
||||
onclick={() => changePosition(i ?? 0, false)}
|
||||
class={small ? 'mr-2 text-secondary text-sm' : 'text-lg mr-2'}
|
||||
title="Move down">↓</button
|
||||
>
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
import { ExternalLink } from 'lucide-svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let link: string | undefined = undefined
|
||||
interface Props {
|
||||
link?: string | undefined
|
||||
class?: string
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
let { link = undefined, class: c = '', children }: Props = $props()
|
||||
</script>
|
||||
|
||||
<div class={twMerge('text-xs text-primary font-normal', $$props.class)}>
|
||||
<slot />
|
||||
<div class={twMerge('text-xs text-primary font-normal', c)}>
|
||||
{@render children?.()}
|
||||
{#if link}
|
||||
<a href={link} target="_blank" class="whitespace-nowrap"
|
||||
>Learn more <ExternalLink size={12} class="inline-block" /></a
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { onDestroy, onMount, setContext, untrack } from 'svelte'
|
||||
import DarkModeToggle from '$lib/components/sidebar/DarkModeToggle.svelte'
|
||||
import { page } from '$app/stores'
|
||||
import { page } from '$app/state'
|
||||
import { getUserExt } from '$lib/user'
|
||||
import FlowPreviewButtons from './flows/header/FlowPreviewButtons.svelte'
|
||||
import FlowModuleSchemaMap from './flows/map/FlowModuleSchemaMap.svelte'
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
buttonReplacement?: import('svelte').Snippet
|
||||
menu?: import('svelte').Snippet
|
||||
maxHeight?: string | undefined
|
||||
onOpen?: () => void
|
||||
onClose?: () => void
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -64,7 +66,9 @@
|
||||
btnId = undefined,
|
||||
buttonReplacement,
|
||||
menu,
|
||||
maxHeight = undefined
|
||||
maxHeight = undefined,
|
||||
onOpen: onOpenProp = undefined,
|
||||
onClose: onCloseProp = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let buttonEl: HTMLButtonElement | undefined = $state(undefined)
|
||||
@@ -121,7 +125,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<ResolveOpen {open} on:open on:close />
|
||||
<ResolveOpen {open} onOpen={onOpenProp} onClose={onCloseProp} />
|
||||
|
||||
<button
|
||||
bind:this={buttonEl}
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
import { Hourglass } from 'lucide-svelte'
|
||||
import WaitTimeWarning from './common/waitTimeWarning/WaitTimeWarning.svelte'
|
||||
|
||||
export let duration_ms: number
|
||||
export let self_wait_time_ms: number | undefined = undefined
|
||||
export let aggregate_wait_time_ms: number | undefined = undefined
|
||||
interface Props {
|
||||
duration_ms: number;
|
||||
self_wait_time_ms?: number | undefined;
|
||||
aggregate_wait_time_ms?: number | undefined;
|
||||
}
|
||||
|
||||
let { duration_ms, self_wait_time_ms = undefined, aggregate_wait_time_ms = undefined }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -592,7 +592,7 @@
|
||||
{argName}
|
||||
{#if !uiOnly}
|
||||
<div onclick={stopPropagation(preventDefault(bubble('click')))}>
|
||||
<Popover placement="bottom-end" containerClasses="p-4" closeButton>
|
||||
<Popover placement="bottom-end" contentClasses="p-4" closeButton>
|
||||
{#snippet trigger()}
|
||||
<Button
|
||||
variant="subtle"
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { type Job } from '$lib/gen'
|
||||
import { isScriptPreview } from '$lib/utils'
|
||||
import { onDestroy } from 'svelte'
|
||||
|
||||
export let job: Job | undefined = undefined
|
||||
/** Execution duration of current active job (in ms) */
|
||||
export let executionDuration: number = 0
|
||||
/** Is current job running more than specified value in `longDefinition` seconds */
|
||||
export let longRunning: boolean = false
|
||||
/** What do we count as "long" (in ms)*/
|
||||
export let longDefinition: number = 30_000
|
||||
/** How often component updates execution duration (in ms)
|
||||
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
job?: Job | undefined;
|
||||
/** Execution duration of current active job (in ms) */
|
||||
executionDuration?: number;
|
||||
/** Is current job running more than specified value in `longDefinition` seconds */
|
||||
longRunning?: boolean;
|
||||
/** What do we count as "long" (in ms)*/
|
||||
longDefinition?: number;
|
||||
/** How often component updates execution duration (in ms)
|
||||
* Higher value -> more efficient component is, less accuracy it has
|
||||
* Lower value -> less efficient component is, more accuracy it has
|
||||
*/
|
||||
export let updateResolution: number = 5_000
|
||||
updateResolution?: number;
|
||||
}
|
||||
|
||||
let {
|
||||
job = $bindable(undefined),
|
||||
executionDuration = $bindable(0),
|
||||
longRunning = $bindable(false),
|
||||
longDefinition = 30_000,
|
||||
updateResolution = 5_000
|
||||
}: Props = $props();
|
||||
|
||||
let startedAt: number | undefined = undefined
|
||||
let busy: boolean = false
|
||||
let busy: boolean = $state(false)
|
||||
let interval: number | undefined
|
||||
// Detect when execution of job started
|
||||
$: if (
|
||||
!busy &&
|
||||
job &&
|
||||
'running' in job &&
|
||||
(job.job_kind == 'script' || isScriptPreview(job?.job_kind))
|
||||
)
|
||||
start(job)
|
||||
|
||||
function start(job: Job) {
|
||||
busy = true
|
||||
@@ -50,4 +58,14 @@
|
||||
// Clear the interval when the component is destroyed
|
||||
clearInterval(interval)
|
||||
})
|
||||
// Detect when execution of job started
|
||||
run(() => {
|
||||
if (
|
||||
!busy &&
|
||||
job &&
|
||||
'running' in job &&
|
||||
(job.job_kind == 'script' || isScriptPreview(job?.job_kind))
|
||||
)
|
||||
start(job)
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -5,19 +5,37 @@
|
||||
import Tooltip from './meltComponents/Tooltip.svelte'
|
||||
import { InfoIcon } from 'lucide-svelte'
|
||||
|
||||
export let label: string
|
||||
export let format: string = ''
|
||||
export let contentEncoding = ''
|
||||
export let type: string | undefined = undefined
|
||||
export let disabled: boolean = false
|
||||
export let required = false
|
||||
export let displayType: boolean = true
|
||||
export let labelClass: string = ''
|
||||
export let prettify = false
|
||||
export let simpleTooltip: string | undefined = undefined
|
||||
export let lightHeader = false
|
||||
export let SimpleTooltipIcon = InfoIcon
|
||||
export let simpleTooltipIconClass = ''
|
||||
interface Props {
|
||||
label: string;
|
||||
format?: string;
|
||||
contentEncoding?: string;
|
||||
type?: string | undefined;
|
||||
disabled?: boolean;
|
||||
required?: boolean;
|
||||
displayType?: boolean;
|
||||
labelClass?: string;
|
||||
prettify?: boolean;
|
||||
simpleTooltip?: string | undefined;
|
||||
lightHeader?: boolean;
|
||||
SimpleTooltipIcon?: any;
|
||||
simpleTooltipIconClass?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
label,
|
||||
format = '',
|
||||
contentEncoding = '',
|
||||
type = undefined,
|
||||
disabled = false,
|
||||
required = false,
|
||||
displayType = true,
|
||||
labelClass = '',
|
||||
prettify = false,
|
||||
simpleTooltip = undefined,
|
||||
lightHeader = false,
|
||||
SimpleTooltipIcon = InfoIcon,
|
||||
simpleTooltipIconClass = ''
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="inline-flex flex-row items-baseline truncated">
|
||||
@@ -54,9 +72,11 @@
|
||||
{#if !emptyString(simpleTooltip)}
|
||||
<Tooltip class="ml-2" placement="bottom">
|
||||
<SimpleTooltipIcon size="14" class={'-mb-0.5 ' + simpleTooltipIconClass} />
|
||||
<span class="text-xs" slot="text">
|
||||
{simpleTooltip}
|
||||
</span>
|
||||
{#snippet text()}
|
||||
<span class="text-xs" >
|
||||
{simpleTooltip}
|
||||
</span>
|
||||
{/snippet}
|
||||
</Tooltip>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -9,23 +9,38 @@
|
||||
import { dfs } from './flows/dfs'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
|
||||
export let flow: {
|
||||
|
||||
interface Props {
|
||||
flow: {
|
||||
summary: string
|
||||
description?: string
|
||||
value: FlowValue
|
||||
schema?: any
|
||||
path?: string
|
||||
};
|
||||
overflowAuto?: boolean;
|
||||
noSide?: boolean;
|
||||
download?: boolean;
|
||||
noGraph?: boolean;
|
||||
triggerNode?: boolean;
|
||||
stepDetail?: FlowModule | string | undefined;
|
||||
workspace?: string | undefined;
|
||||
minHeight?: number;
|
||||
noBorder?: boolean;
|
||||
}
|
||||
|
||||
export let overflowAuto = false
|
||||
export let noSide = false
|
||||
export let download = false
|
||||
export let noGraph = false
|
||||
export let triggerNode = false
|
||||
export let stepDetail: FlowModule | string | undefined = undefined
|
||||
export let workspace: string | undefined = $workspaceStore
|
||||
export let minHeight = 400
|
||||
export let noBorder = false
|
||||
let {
|
||||
flow,
|
||||
overflowAuto = false,
|
||||
noSide = false,
|
||||
download = false,
|
||||
noGraph = false,
|
||||
triggerNode = false,
|
||||
stepDetail = $bindable(undefined),
|
||||
workspace = $workspaceStore,
|
||||
minHeight = 400,
|
||||
noBorder = false
|
||||
}: Props = $props();
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
@@ -19,11 +19,15 @@
|
||||
import HighlightTheme from './HighlightTheme.svelte'
|
||||
import LanguageIcon from './common/languageIcons/LanguageIcon.svelte'
|
||||
|
||||
export let schema: any | undefined = undefined
|
||||
|
||||
export let stepDetail: FlowModule | string | undefined = undefined
|
||||
export let jobScriptHash: string | undefined = undefined
|
||||
let codeViewer: Drawer
|
||||
interface Props {
|
||||
schema?: any | undefined;
|
||||
stepDetail?: FlowModule | string | undefined;
|
||||
jobScriptHash?: string | undefined;
|
||||
}
|
||||
|
||||
let { schema = undefined, stepDetail = undefined, jobScriptHash = undefined }: Props = $props();
|
||||
let codeViewer: Drawer = $state()
|
||||
</script>
|
||||
|
||||
<HighlightTheme />
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
|
||||
import FieldHeader from './FieldHeader.svelte'
|
||||
|
||||
export let schema: Schema | { [key: string]: unknown } | undefined
|
||||
interface Props {
|
||||
schema: Schema | { [key: string]: unknown } | undefined;
|
||||
}
|
||||
|
||||
let { schema }: Props = $props();
|
||||
</script>
|
||||
|
||||
<ul class="my-2">
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
import AnimatedButton from './common/button/AnimatedButton.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let connecting: boolean
|
||||
export let id: undefined | string = undefined
|
||||
export let wrapperClasses = ''
|
||||
interface Props {
|
||||
connecting: boolean;
|
||||
id?: undefined | string;
|
||||
wrapperClasses?: string;
|
||||
}
|
||||
|
||||
let { connecting, id = undefined, wrapperClasses = '' }: Props = $props();
|
||||
</script>
|
||||
|
||||
<AnimatedButton animate={connecting} baseRadius="6px" animationDuration="2s" marginWidth="2px">
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
<Popover
|
||||
floatingConfig={{ strategy: 'absolute', placement: 'bottom-start' }}
|
||||
disablePopup={!flowPath}
|
||||
on:openChange={(e) => { if (e.detail) loadFlowVersions() }}
|
||||
onOpenChange={(isOpen) => { if (isOpen) loadFlowVersions() }}
|
||||
>
|
||||
{#snippet trigger()}
|
||||
{@render singleRestartButton()}
|
||||
@@ -178,7 +178,7 @@
|
||||
{:else}
|
||||
<Popover
|
||||
floatingConfig={{ strategy: 'absolute', placement: 'bottom-start' }}
|
||||
on:openChange={(e) => { if (e.detail) loadFlowVersions() }}
|
||||
onOpenChange={(isOpen) => { if (isOpen) loadFlowVersions() }}
|
||||
>
|
||||
{#snippet trigger()}
|
||||
<Button
|
||||
|
||||
@@ -270,12 +270,13 @@
|
||||
{/if}
|
||||
{#if perms}
|
||||
<TableCustom>
|
||||
<!-- @migration-task: migrate this slot by hand, `header-row` is an invalid identifier -->
|
||||
<tr slot="header-row">
|
||||
<th>user/group</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{#snippet header_row()}
|
||||
<tr>
|
||||
<th>user/group</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{/snippet}
|
||||
{#snippet body()}
|
||||
<tbody>
|
||||
{#each perms ?? [] as { owner_name, role }}<tr>
|
||||
@@ -407,10 +408,12 @@
|
||||
<p class="text-primary text-sm">No folder is managing this folder</p>
|
||||
{:else}
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
{#snippet header_row()}
|
||||
<tr>
|
||||
<th>folder</th>
|
||||
<th />
|
||||
</tr>
|
||||
{/snippet}
|
||||
<tbody slot="body">
|
||||
{#each managing_folders as managing_folder}<tr>
|
||||
<td>{managing_folder.split('/')[1]}</td>
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { FolderService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import Cell from './table/Cell.svelte'
|
||||
|
||||
export let name: string
|
||||
export let tabular = false
|
||||
export let order = ['scripts', 'flows', 'apps', 'schedules', 'variables', 'resources']
|
||||
interface Props {
|
||||
name: string;
|
||||
tabular?: boolean;
|
||||
order?: any;
|
||||
}
|
||||
|
||||
$: $workspaceStore && loadUsage()
|
||||
let { name, tabular = false, order = ['scripts', 'flows', 'apps', 'schedules', 'variables', 'resources'] }: Props = $props();
|
||||
|
||||
let usage: Record<string, number> = {}
|
||||
|
||||
let usage: Record<string, number> = $state({})
|
||||
|
||||
async function loadUsage() {
|
||||
usage = await FolderService.getFolderUsage({ workspace: $workspaceStore!, name })
|
||||
}
|
||||
run(() => {
|
||||
$workspaceStore && loadUsage()
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if tabular}
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
let divEl: HTMLDivElement | null = null
|
||||
let editor: meditor.IStandaloneCodeEditor
|
||||
|
||||
export let code: string = ''
|
||||
interface Props {
|
||||
code?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
let { code = '', class: c = '' }: Props = $props()
|
||||
|
||||
async function loadMonaco() {
|
||||
editor = meditor.create(divEl as HTMLDivElement, {
|
||||
@@ -43,4 +48,4 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<div bind:this={divEl} class="{$$props.class ?? ''} editor"></div>
|
||||
<div bind:this={divEl} class="{c ?? ''} editor"></div>
|
||||
|
||||
@@ -159,12 +159,13 @@
|
||||
{/if}
|
||||
{#if members}
|
||||
<TableCustom>
|
||||
<!-- @migration-task: migrate this slot by hand, `header-row` is an invalid identifier -->
|
||||
<tr slot="header-row">
|
||||
<th>user</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{#snippet header_row()}
|
||||
<tr>
|
||||
<th>user</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{/snippet}
|
||||
{#snippet body()}
|
||||
<tbody>
|
||||
{#each members ?? [] as { member_name, role }}<tr>
|
||||
@@ -301,10 +302,11 @@
|
||||
{#if instance_group?.emails}
|
||||
<h2 class="mt-6 text-emphasis text-xs font-semibold">Members from the instance group</h2>
|
||||
<TableCustom>
|
||||
<!-- @migration-task: migrate this slot by hand, `header-row` is an invalid identifier -->
|
||||
<tr slot="header-row">
|
||||
<th>user</th>
|
||||
</tr>
|
||||
{#snippet header_row()}
|
||||
<tr>
|
||||
<th>user</th>
|
||||
</tr>
|
||||
{/snippet}
|
||||
{#snippet body()}
|
||||
<tbody>
|
||||
{#each instance_group?.emails ?? [] as email}<tr>
|
||||
|
||||
@@ -134,9 +134,11 @@
|
||||
{#if !lines}
|
||||
<Highlight class="nowrap {className}" language={lang} {code} />
|
||||
{:else}
|
||||
<Highlight class="nowrap {className}" language={lang} {code} let:highlighted>
|
||||
<LineNumbers {highlighted} />
|
||||
</Highlight>
|
||||
<Highlight class="nowrap {className}" language={lang} {code} >
|
||||
{#snippet children({ highlighted })}
|
||||
<LineNumbers {highlighted} />
|
||||
{/snippet}
|
||||
</Highlight>
|
||||
{/if}
|
||||
{:else}
|
||||
<pre class="overflow-auto max-h-screen text-xs {className}"
|
||||
|
||||
@@ -134,8 +134,8 @@
|
||||
{showAuthor}
|
||||
{placement}
|
||||
{viewerOpen}
|
||||
on:openChange={({ detail }) => {
|
||||
updateViewerOpenState(item.id, detail)
|
||||
onOpenChange={(isOpen) => {
|
||||
updateViewerOpenState(item.id, isOpen)
|
||||
}}
|
||||
{limitPayloadSize}
|
||||
/>
|
||||
|
||||
@@ -178,13 +178,13 @@
|
||||
<tbody class="h-full w-full">
|
||||
{#if extra_row}
|
||||
<Row
|
||||
on:click={() => dispatch('select', 'extraRow')}
|
||||
onclick={() => dispatch('select', 'extraRow')}
|
||||
class={twMerge(
|
||||
extraRowClasses.class,
|
||||
selectedItemId === 'extraRow' ? extraRowClasses.bgSelected : extraRowClasses.bgHover,
|
||||
'cursor-pointer rounded-md'
|
||||
)}
|
||||
on:hover={(e) => (hovered = e.detail ? 'extraRow' : undefined)}
|
||||
onHover={(h) => (hovered = h ? 'extraRow' : undefined)}
|
||||
>
|
||||
{@render extra_row?.({ hover: hovered === 'extraRow' })}
|
||||
</Row>
|
||||
@@ -195,13 +195,13 @@
|
||||
{@render customRow?.({ item, hover })}
|
||||
{:else}
|
||||
<Row
|
||||
on:click={() => dispatch('select', item)}
|
||||
onclick={() => dispatch('select', item)}
|
||||
class={twMerge(
|
||||
selectedItemId === item.id ? 'bg-surface-selected' : 'hover:bg-surface-hover',
|
||||
'cursor-pointer rounded-md',
|
||||
item.isNew && index === 0 ? 'animate-slideIn' : 'group'
|
||||
)}
|
||||
on:hover={(e) => (hovered = e.detail ? item.id : undefined)}
|
||||
onHover={(h) => (hovered = h ? item.id : undefined)}
|
||||
>
|
||||
{@render children?.({ item, hover })}
|
||||
</Row>
|
||||
|
||||
@@ -7,8 +7,12 @@
|
||||
import Cell from './table/Cell.svelte'
|
||||
import Row from './table/Row.svelte'
|
||||
|
||||
export let inputTransforms: Record<string, InputTransform>
|
||||
$: entries = Object.entries(inputTransforms)
|
||||
interface Props {
|
||||
inputTransforms: Record<string, InputTransform>;
|
||||
}
|
||||
|
||||
let { inputTransforms }: Props = $props();
|
||||
let entries = $derived(Object.entries(inputTransforms))
|
||||
</script>
|
||||
|
||||
{#if entries.length}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { GroupService, type InstanceGroup } from '$lib/gen'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import autosize from '$lib/autosize'
|
||||
@@ -8,17 +10,18 @@
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
|
||||
export let name: string
|
||||
interface Props {
|
||||
name: string;
|
||||
}
|
||||
|
||||
let email = ''
|
||||
let instance_group: InstanceGroup | undefined
|
||||
let members: { member_email: string }[] | undefined = undefined
|
||||
let { name }: Props = $props();
|
||||
|
||||
let email = $state('')
|
||||
let instance_group: InstanceGroup | undefined = $state()
|
||||
let members: { member_email: string }[] | undefined = $state(undefined)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: {
|
||||
load()
|
||||
}
|
||||
|
||||
async function load() {
|
||||
return Promise.all([loadInstanceGroup()])
|
||||
@@ -32,6 +35,9 @@
|
||||
})
|
||||
: []
|
||||
}
|
||||
run(() => {
|
||||
load()
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-6">
|
||||
@@ -85,17 +91,20 @@
|
||||
</div>
|
||||
{#if members}
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
<th>user</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tbody slot="body">
|
||||
{#each members as { member_email }}<tr>
|
||||
<td>{member_email}</td>
|
||||
<td>
|
||||
<button
|
||||
class="ml-2 text-red-500"
|
||||
on:click={async () => {
|
||||
{#snippet header_row()}
|
||||
<tr>
|
||||
<th>user</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{/snippet}
|
||||
{#snippet body()}
|
||||
<tbody >
|
||||
{#each members as { member_email }}<tr>
|
||||
<td>{member_email}</td>
|
||||
<td>
|
||||
<button
|
||||
class="ml-2 text-red-500"
|
||||
onclick={async () => {
|
||||
await GroupService.removeUserFromInstanceGroup({
|
||||
name,
|
||||
requestBody: { email: member_email }
|
||||
@@ -104,10 +113,11 @@
|
||||
sendUserToast('User removed')
|
||||
loadInstanceGroup()
|
||||
}}>remove</button
|
||||
>
|
||||
</td>
|
||||
</tr>{/each}
|
||||
</tbody>
|
||||
>
|
||||
</td>
|
||||
</tr>{/each}
|
||||
</tbody>
|
||||
{/snippet}
|
||||
</TableCustom>
|
||||
{:else}
|
||||
<div class="flex flex-col">
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation, createBubbler } from 'svelte/legacy';
|
||||
|
||||
const bubble = createBubbler();
|
||||
import { Pencil } from 'lucide-svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Button from './common/button/Button.svelte'
|
||||
@@ -9,13 +12,23 @@
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
|
||||
export let value: string | undefined
|
||||
export let email: string
|
||||
export let username: string | undefined = undefined
|
||||
export let automateUsernameCreation: boolean = false
|
||||
export let login_type: string
|
||||
interface Props {
|
||||
value: string | undefined;
|
||||
email: string;
|
||||
username?: string | undefined;
|
||||
automateUsernameCreation?: boolean;
|
||||
login_type: string;
|
||||
}
|
||||
|
||||
let password: string = ''
|
||||
let {
|
||||
value = $bindable(),
|
||||
email,
|
||||
username = undefined,
|
||||
automateUsernameCreation = false,
|
||||
login_type = $bindable()
|
||||
}: Props = $props();
|
||||
|
||||
let password: string = $state('')
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -46,112 +59,116 @@
|
||||
}}
|
||||
closeButton
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
<Button unifiedSize="sm" nonCaptureEvent={true} variant="subtle" startIcon={{ icon: Pencil }}
|
||||
>Edit</Button
|
||||
>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
<div class="flex flex-col gap-8 max-w-sm p-4">
|
||||
{#if automateUsernameCreation && username}
|
||||
<ChangeInstanceUsernameInner {email} {username} on:renamed noPadding />
|
||||
{/if}
|
||||
<label class="block text-primary">
|
||||
<div class="pb-1 text-xs font-semibold text-emphasis">Name</div>
|
||||
<div class="flex w-full">
|
||||
<TextInput
|
||||
inputProps={{
|
||||
onclick: (e) => {
|
||||
e.stopPropagation()
|
||||
},
|
||||
onkeydown: (e) => {
|
||||
e.stopPropagation()
|
||||
},
|
||||
onkeypress: ({ key }) => {
|
||||
if (key === 'Enter') {
|
||||
saveName()
|
||||
{#snippet trigger()}
|
||||
|
||||
<Button unifiedSize="sm" nonCaptureEvent={true} variant="subtle" startIcon={{ icon: Pencil }}
|
||||
>Edit</Button
|
||||
>
|
||||
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
|
||||
<div class="flex flex-col gap-8 max-w-sm p-4">
|
||||
{#if automateUsernameCreation && username}
|
||||
<ChangeInstanceUsernameInner {email} {username} on:renamed noPadding />
|
||||
{/if}
|
||||
<label class="block text-primary">
|
||||
<div class="pb-1 text-xs font-semibold text-emphasis">Name</div>
|
||||
<div class="flex w-full">
|
||||
<TextInput
|
||||
inputProps={{
|
||||
onclick: (e) => {
|
||||
e.stopPropagation()
|
||||
},
|
||||
onkeydown: (e) => {
|
||||
e.stopPropagation()
|
||||
},
|
||||
onkeypress: ({ key }) => {
|
||||
if (key === 'Enter') {
|
||||
saveName()
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
bind:value
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
unifiedSize="md"
|
||||
variant="default"
|
||||
buttonType="button"
|
||||
btnClasses="mt-2 "
|
||||
aria-label="Save ID"
|
||||
onclick={() => {
|
||||
saveName()
|
||||
}}
|
||||
bind:value
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
unifiedSize="md"
|
||||
variant="default"
|
||||
buttonType="button"
|
||||
btnClasses="mt-2 "
|
||||
aria-label="Save ID"
|
||||
onclick={() => {
|
||||
saveName()
|
||||
}}
|
||||
>
|
||||
Update name
|
||||
</Button>
|
||||
</label>
|
||||
<label class="block text-primary">
|
||||
<div class="pb-1 text-xs font-semibold text-emphasis">Password</div>
|
||||
<div class="flex w-full">
|
||||
<input
|
||||
type="password"
|
||||
bind:value={password}
|
||||
class="!w-auto grow"
|
||||
on:click|stopPropagation={() => {}}
|
||||
on:keydown|stopPropagation
|
||||
on:keypress|stopPropagation={({ key }) => {
|
||||
>
|
||||
Update name
|
||||
</Button>
|
||||
</label>
|
||||
<label class="block text-primary">
|
||||
<div class="pb-1 text-xs font-semibold text-emphasis">Password</div>
|
||||
<div class="flex w-full">
|
||||
<input
|
||||
type="password"
|
||||
bind:value={password}
|
||||
class="!w-auto grow"
|
||||
onclick={stopPropagation(() => {})}
|
||||
onkeydown={stopPropagation(bubble('keydown'))}
|
||||
onkeypress={stopPropagation(({ key }) => {
|
||||
if (key === 'Enter') {
|
||||
savePassword()
|
||||
}
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
unifiedSize="md"
|
||||
variant="default"
|
||||
buttonType="button"
|
||||
btnClasses="mt-2 "
|
||||
aria-label="Save ID"
|
||||
on:click={() => {
|
||||
savePassword()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
unifiedSize="md"
|
||||
variant="default"
|
||||
buttonType="button"
|
||||
btnClasses="mt-2 "
|
||||
aria-label="Save ID"
|
||||
on:click={() => {
|
||||
savePassword()
|
||||
}}
|
||||
>
|
||||
Update password
|
||||
</Button>
|
||||
</label>
|
||||
<label class="block text-primary">
|
||||
<div class="mb-1 text-xs font-semibold text-emphasis">Login type</div>
|
||||
>
|
||||
Update password
|
||||
</Button>
|
||||
</label>
|
||||
<label class="block text-primary">
|
||||
<div class="mb-1 text-xs font-semibold text-emphasis">Login type</div>
|
||||
|
||||
<div class="flex w-full">
|
||||
<input
|
||||
type="text"
|
||||
bind:value={login_type}
|
||||
class="!w-auto grow"
|
||||
on:click|stopPropagation={() => {}}
|
||||
on:keydown|stopPropagation
|
||||
on:keypress|stopPropagation={({ key }) => {
|
||||
<div class="flex w-full">
|
||||
<input
|
||||
type="text"
|
||||
bind:value={login_type}
|
||||
class="!w-auto grow"
|
||||
onclick={stopPropagation(() => {})}
|
||||
onkeydown={stopPropagation(bubble('keydown'))}
|
||||
onkeypress={stopPropagation(({ key }) => {
|
||||
if (key === 'Enter') {
|
||||
saveLoginType()
|
||||
}
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div class="text-2xs text-secondary mb-1">
|
||||
Must match exact SSO name, "password" or "saml". Examples: password, google, saml,
|
||||
microsoft
|
||||
</div>
|
||||
<Button
|
||||
unifiedSize="md"
|
||||
variant="default"
|
||||
buttonType="button"
|
||||
btnClasses="mt-2 "
|
||||
aria-label="Save login type"
|
||||
on:click={() => {
|
||||
saveLoginType()
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="text-2xs text-secondary mb-1">
|
||||
Must match exact SSO name, "password" or "saml". Examples: password, google, saml,
|
||||
microsoft
|
||||
</div>
|
||||
<Button
|
||||
unifiedSize="md"
|
||||
variant="default"
|
||||
buttonType="button"
|
||||
btnClasses="mt-2 "
|
||||
aria-label="Save login type"
|
||||
on:click={() => {
|
||||
saveLoginType()
|
||||
}}
|
||||
>
|
||||
Update login type
|
||||
</Button>
|
||||
</label>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
>
|
||||
Update login type
|
||||
</Button>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/snippet}
|
||||
</Popover>
|
||||
|
||||
@@ -8,13 +8,17 @@
|
||||
import { generateRandomString } from '$lib/utils'
|
||||
import { globalEmailInvite } from '$lib/stores'
|
||||
|
||||
export let close: (() => void) | undefined = undefined
|
||||
interface Props {
|
||||
close?: (() => void) | undefined;
|
||||
}
|
||||
|
||||
let { close = undefined }: Props = $props();
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let is_super_admin = false
|
||||
let password: string = generateRandomString(10)
|
||||
let name: string | undefined
|
||||
let is_super_admin = $state(false)
|
||||
let password: string = $state(generateRandomString(10))
|
||||
let name: string | undefined = $state()
|
||||
let company: string | undefined
|
||||
|
||||
async function addUser() {
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
import SettingCard from './instanceSettings/SettingCard.svelte'
|
||||
|
||||
export let value: any
|
||||
interface Props {
|
||||
value: any;
|
||||
}
|
||||
|
||||
let { value = $bindable() }: Props = $props();
|
||||
|
||||
const AUTH_URL_SUFFIX = '/ui/oauth2'
|
||||
|
||||
$: enabled = value != undefined
|
||||
|
||||
// If `baseUrl` is not already set in the form, try to parse it from the `auth_url` value
|
||||
//
|
||||
// The binding dance here allows us to avoid rendering the string 'undefined' in the input, and
|
||||
// also allow lazy/async binding of the `value` prop.
|
||||
$: derivedBaseUrl = value?.connect_config?.auth_url?.replace(AUTH_URL_SUFFIX, '')
|
||||
let proxyUrlValue = undefined
|
||||
$: baseUrl = proxyUrlValue ?? derivedBaseUrl ?? ''
|
||||
let proxyUrlValue = $state(undefined)
|
||||
|
||||
$: changeValues({ baseUrl, id: value?.id ?? '' })
|
||||
|
||||
function changeValues({ baseUrl, id }) {
|
||||
if (value) {
|
||||
@@ -40,10 +38,20 @@
|
||||
proxyUrlValue = baseUrl
|
||||
}
|
||||
}
|
||||
let enabled = $derived(value != undefined)
|
||||
// If `baseUrl` is not already set in the form, try to parse it from the `auth_url` value
|
||||
//
|
||||
// The binding dance here allows us to avoid rendering the string 'undefined' in the input, and
|
||||
// also allow lazy/async binding of the `value` prop.
|
||||
let derivedBaseUrl = $derived(value?.connect_config?.auth_url?.replace(AUTH_URL_SUFFIX, ''))
|
||||
let baseUrl = $derived(proxyUrlValue ?? derivedBaseUrl ?? '')
|
||||
run(() => {
|
||||
changeValues({ baseUrl, id: value?.id ?? '' })
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="text-xs font-semibold text-emphasis flex gap-4 items-center"
|
||||
><div class="w-[120px]"><IconedResourceType name={'kanidm'} after={true} /></div><Toggle
|
||||
checked={enabled}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
import SettingCard from './instanceSettings/SettingCard.svelte'
|
||||
|
||||
export let value: any
|
||||
interface Props {
|
||||
value: any;
|
||||
}
|
||||
|
||||
$: enabled = value != undefined
|
||||
let { value = $bindable() }: Props = $props();
|
||||
|
||||
let org = ''
|
||||
|
||||
$: changeOrg(org)
|
||||
let org = $state('')
|
||||
|
||||
|
||||
function changeOrg(org) {
|
||||
if (value) {
|
||||
@@ -30,10 +34,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
let enabled = $derived(value != undefined)
|
||||
run(() => {
|
||||
changeOrg(org)
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="text-xs font-semibold text-emphasis flex gap-4 items-center"
|
||||
><div class="w-[120px]"><IconedResourceType name={'keycloak'} after={true} /></div><Toggle
|
||||
checked={enabled}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
<script lang="ts">
|
||||
export let id: string
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
$: id && console.log('updateJobId')
|
||||
interface Props {
|
||||
id: string;
|
||||
}
|
||||
|
||||
let { id }: Props = $props();
|
||||
|
||||
run(() => {
|
||||
id && console.log('updateJobId')
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { AnsiUp } from 'ansi_up'
|
||||
|
||||
export let content: string
|
||||
export let highlighted: any[]
|
||||
interface Props {
|
||||
content: string;
|
||||
highlighted: any[];
|
||||
onclick?: () => void;
|
||||
}
|
||||
|
||||
let { content, highlighted, onclick: onclickProp = undefined }: Props = $props();
|
||||
|
||||
const ansi_up = new AnsiUp()
|
||||
ansi_up.use_classes = true
|
||||
@@ -30,7 +35,7 @@
|
||||
let html = highlightSnippet(content)
|
||||
</script>
|
||||
|
||||
<button on:click class="font-light !m-0 !p-0">
|
||||
<button onclick={() => onclickProp?.()} class="font-light !m-0 !p-0">
|
||||
<pre
|
||||
class="bg-surface-secondary hover:bg-surface px-2 py-1 text-secondary text-xs w-[100%] whitespace-pre border min-w-full text-start">
|
||||
{@html html}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { Map, View, Feature } from 'ol'
|
||||
import { Fill, Stroke, Style, Text } from 'ol/style.js'
|
||||
import { useGeographic } from 'ol/proj.js'
|
||||
@@ -18,17 +20,26 @@
|
||||
strokeColor?: string
|
||||
}
|
||||
|
||||
export let lon: number | undefined = undefined
|
||||
export let lat: number | undefined = undefined
|
||||
export let zoom: number | undefined = undefined
|
||||
export let markers: Marker[] | string | undefined = undefined
|
||||
interface Props {
|
||||
lon?: number | undefined;
|
||||
lat?: number | undefined;
|
||||
zoom?: number | undefined;
|
||||
markers?: Marker[] | string | undefined;
|
||||
}
|
||||
|
||||
let {
|
||||
lon = undefined,
|
||||
lat = undefined,
|
||||
zoom = undefined,
|
||||
markers = undefined
|
||||
}: Props = $props();
|
||||
|
||||
const LAYER_NAME = {
|
||||
MARKER: 'Marker'
|
||||
} as const
|
||||
|
||||
let map: Map | undefined = undefined
|
||||
let mapElement: HTMLDivElement | undefined = undefined
|
||||
let map: Map | undefined = $state(undefined)
|
||||
let mapElement: HTMLDivElement | undefined = $state(undefined)
|
||||
|
||||
function getLayersByName(name: keyof typeof LAYER_NAME) {
|
||||
return map
|
||||
@@ -100,36 +111,38 @@
|
||||
createMarkerLayers()?.forEach((l) => map?.addLayer(l))
|
||||
}
|
||||
|
||||
$: if (!map && mapElement) {
|
||||
useGeographic()
|
||||
map = new Map({
|
||||
target: mapElement,
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new OSM()
|
||||
run(() => {
|
||||
if (!map && mapElement) {
|
||||
useGeographic()
|
||||
map = new Map({
|
||||
target: mapElement,
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new OSM()
|
||||
}),
|
||||
...(createMarkerLayers() || [])
|
||||
],
|
||||
view: new View({
|
||||
center: [lon ?? 0, lat ?? 0],
|
||||
zoom: zoom ?? 2
|
||||
}),
|
||||
...(createMarkerLayers() || [])
|
||||
],
|
||||
view: new View({
|
||||
center: [lon ?? 0, lat ?? 0],
|
||||
zoom: zoom ?? 2
|
||||
}),
|
||||
controls: defaultControls({
|
||||
attribution: false
|
||||
controls: defaultControls({
|
||||
attribution: false
|
||||
})
|
||||
})
|
||||
})
|
||||
if (lat && lon) {
|
||||
map.getView().setCenter([lon, lat])
|
||||
}
|
||||
if (lat && lon) {
|
||||
map.getView().setCenter([lon, lat])
|
||||
}
|
||||
|
||||
if (map && zoom) {
|
||||
map.getView().setZoom(zoom)
|
||||
}
|
||||
if (map && zoom) {
|
||||
map.getView().setZoom(zoom)
|
||||
}
|
||||
|
||||
if (map && markers) {
|
||||
updateMarkers()
|
||||
if (map && markers) {
|
||||
updateMarkers()
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div bind:this={mapElement} class="w-full h-[300px]"></div>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { type MetricDataPoint, MetricsService } from '$lib/gen'
|
||||
import { displayTime } from '$lib/utils'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
@@ -17,16 +19,20 @@
|
||||
|
||||
ChartJS.register(Title, Tooltip, Legend, LineElement, LinearScale, PointElement, CategoryScale)
|
||||
|
||||
export let jobId: string
|
||||
export let jobUpdateLastFetch: Date | undefined
|
||||
interface Props {
|
||||
jobId: string;
|
||||
jobUpdateLastFetch: Date | undefined;
|
||||
}
|
||||
|
||||
let { jobId, jobUpdateLastFetch = $bindable() }: Props = $props();
|
||||
|
||||
let jobMetricsLastFetch: Date | undefined = undefined
|
||||
let jobMemoryStats: MetricDataPoint[] | undefined = undefined
|
||||
let jobMemoryStats: MetricDataPoint[] | undefined = $state(undefined)
|
||||
|
||||
let data: {
|
||||
x: number
|
||||
y: number
|
||||
}[] = []
|
||||
}[] = $state([])
|
||||
let labels: string[] = []
|
||||
|
||||
async function loadMetricsData() {
|
||||
@@ -66,7 +72,9 @@
|
||||
data = [...data]
|
||||
}
|
||||
|
||||
$: jobUpdateLastFetch && loadMetricsData()
|
||||
run(() => {
|
||||
jobUpdateLastFetch && loadMetricsData()
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="relative max-h-100">
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
import { displayDate } from '$lib/utils'
|
||||
import { Hourglass } from 'lucide-svelte'
|
||||
|
||||
export let type: FlowStatusModule['type']
|
||||
export let scheduled_for: Date | undefined
|
||||
export let skipped: boolean = false
|
||||
interface Props {
|
||||
type: FlowStatusModule['type'];
|
||||
scheduled_for: Date | undefined;
|
||||
skipped?: boolean;
|
||||
}
|
||||
|
||||
let { type, scheduled_for, skipped = false }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if type == 'WaitingForEvents'}
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
import { Button } from './common'
|
||||
import { X, Plus } from 'lucide-svelte'
|
||||
|
||||
export let extra_params: Record<string, string> = {}
|
||||
interface Props {
|
||||
extra_params?: Record<string, string>;
|
||||
}
|
||||
|
||||
let extra_params_vec: [string, string][] = Object.entries(extra_params)
|
||||
let { extra_params = $bindable({}) }: Props = $props();
|
||||
|
||||
let extra_params_vec: [string, string][] = $state(Object.entries(extra_params))
|
||||
|
||||
function sync() {
|
||||
extra_params = Object.fromEntries(extra_params_vec)
|
||||
@@ -13,8 +17,8 @@
|
||||
|
||||
{#each extra_params_vec as o}
|
||||
<div class="flex flex-row max-w-md mb-2 gap-2">
|
||||
<input type="text" on:keyup={sync} bind:value={o[0]} />
|
||||
<input type="text" on:keyup={sync} bind:value={o[1]} />
|
||||
<input type="text" onkeyup={sync} bind:value={o[0]} />
|
||||
<input type="text" onkeyup={sync} bind:value={o[1]} />
|
||||
<Button
|
||||
variant="subtle"
|
||||
destructive
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
import { Button } from './common'
|
||||
import { Minus, Plus } from 'lucide-svelte'
|
||||
|
||||
export let scopes: string[] = []
|
||||
interface Props {
|
||||
scopes?: string[];
|
||||
}
|
||||
|
||||
let { scopes = $bindable([]) }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if scopes && Array.isArray(scopes)}
|
||||
|
||||
@@ -51,44 +51,48 @@
|
||||
</script>
|
||||
|
||||
<MeltPopover placement="bottom">
|
||||
<svelte:fragment slot="trigger">
|
||||
<UserCog class="w-4 h-4 {selected ? 'text-green-500' : 'text-yellow-500'}" />
|
||||
</svelte:fragment>
|
||||
<div slot="content" class="p-3 flex flex-col gap-2 min-w-48">
|
||||
<div class="text-xs font-medium text-secondary mb-1">{label}</div>
|
||||
<button
|
||||
class="flex items-center gap-2 px-2 py-1.5 rounded text-left text-xs hover:bg-surface-hover {!canPreserve
|
||||
? 'opacity-50 cursor-not-allowed'
|
||||
: ''}"
|
||||
disabled={!canPreserve}
|
||||
onclick={() => onSelect('source')}
|
||||
>
|
||||
<Check class="w-3 h-3 {selected === 'source' ? 'opacity-100' : 'opacity-0'}" />
|
||||
<span class="truncate max-w-40">{sourceEmail}</span>
|
||||
<span class="text-xs text-tertiary">(source)</span>
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-2 px-2 py-1.5 rounded text-left text-xs hover:bg-surface-hover {!canPreserve || !targetEmail
|
||||
? 'opacity-50 cursor-not-allowed'
|
||||
: ''}"
|
||||
disabled={!canPreserve || !targetEmail}
|
||||
onclick={() => onSelect('target')}
|
||||
>
|
||||
<Check class="w-3 h-3 {selected === 'target' ? 'opacity-100' : 'opacity-0'}" />
|
||||
<span class="truncate max-w-40 {!targetEmail ? 'italic text-tertiary' : ''}"
|
||||
>{targetEmail ?? 'unknown'}</span
|
||||
{#snippet trigger()}
|
||||
|
||||
<UserCog class="w-4 h-4 {selected ? 'text-green-500' : 'text-yellow-500'}" />
|
||||
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
<div class="p-3 flex flex-col gap-2 min-w-48">
|
||||
<div class="text-xs font-medium text-secondary mb-1">{label}</div>
|
||||
<button
|
||||
class="flex items-center gap-2 px-2 py-1.5 rounded text-left text-xs hover:bg-surface-hover {!canPreserve
|
||||
? 'opacity-50 cursor-not-allowed'
|
||||
: ''}"
|
||||
disabled={!canPreserve}
|
||||
onclick={() => onSelect('source')}
|
||||
>
|
||||
<span class="text-xs text-tertiary">(target)</span>
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-2 px-2 py-1.5 rounded text-left text-xs hover:bg-surface-hover"
|
||||
onclick={() => onSelect('me')}
|
||||
>
|
||||
<Check class="w-3 h-3 {selected === 'me' ? 'opacity-100' : 'opacity-0'}" />
|
||||
<span class="truncate max-w-40"
|
||||
>{kind === 'trigger' ? $userStore?.username : $userStore?.email}</span
|
||||
<Check class="w-3 h-3 {selected === 'source' ? 'opacity-100' : 'opacity-0'}" />
|
||||
<span class="truncate max-w-40">{sourceEmail}</span>
|
||||
<span class="text-xs text-tertiary">(source)</span>
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-2 px-2 py-1.5 rounded text-left text-xs hover:bg-surface-hover {!canPreserve || !targetEmail
|
||||
? 'opacity-50 cursor-not-allowed'
|
||||
: ''}"
|
||||
disabled={!canPreserve || !targetEmail}
|
||||
onclick={() => onSelect('target')}
|
||||
>
|
||||
<span class="text-xs text-tertiary">(me)</span>
|
||||
</button>
|
||||
</div>
|
||||
<Check class="w-3 h-3 {selected === 'target' ? 'opacity-100' : 'opacity-0'}" />
|
||||
<span class="truncate max-w-40 {!targetEmail ? 'italic text-tertiary' : ''}"
|
||||
>{targetEmail ?? 'unknown'}</span
|
||||
>
|
||||
<span class="text-xs text-tertiary">(target)</span>
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-2 px-2 py-1.5 rounded text-left text-xs hover:bg-surface-hover"
|
||||
onclick={() => onSelect('me')}
|
||||
>
|
||||
<Check class="w-3 h-3 {selected === 'me' ? 'opacity-100' : 'opacity-0'}" />
|
||||
<span class="truncate max-w-40"
|
||||
>{kind === 'trigger' ? $userStore?.username : $userStore?.email}</span
|
||||
>
|
||||
<span class="text-xs text-tertiary">(me)</span>
|
||||
</button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</MeltPopover>
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
<script lang="ts">
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
|
||||
export let title: string
|
||||
export let tooltip: string = ''
|
||||
export let documentationLink: string | undefined = undefined
|
||||
export let primary: boolean = true
|
||||
export let childrenWrapperDivClasses: string = ''
|
||||
interface Props {
|
||||
title: string;
|
||||
tooltip?: string;
|
||||
documentationLink?: string | undefined;
|
||||
primary?: boolean;
|
||||
childrenWrapperDivClasses?: string;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
title,
|
||||
tooltip = '',
|
||||
documentationLink = undefined,
|
||||
primary = true,
|
||||
childrenWrapperDivClasses = '',
|
||||
children
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row flex-wrap justify-between items-center pb-2 my-4 mr-2 min-h-16">
|
||||
@@ -31,9 +43,9 @@
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
{#if $$slots.default}
|
||||
{#if children}
|
||||
<div class="my-2 {childrenWrapperDivClasses}">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { type GridApi, createGrid, type IDatasource } from 'ag-grid-community'
|
||||
|
||||
import 'ag-grid-community/styles/ag-grid.css'
|
||||
@@ -14,15 +16,24 @@
|
||||
// import 'ag-grid-community/dist/styles/ag-theme-alpine-dark.css'
|
||||
|
||||
let selectedRowIndex = -1
|
||||
export let s3resource: string
|
||||
export let storage: string | undefined
|
||||
export let workspaceId: string | undefined
|
||||
export let disable_download: boolean = false
|
||||
interface Props {
|
||||
s3resource: string;
|
||||
storage: string | undefined;
|
||||
workspaceId: string | undefined;
|
||||
disable_download?: boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
s3resource,
|
||||
storage,
|
||||
workspaceId,
|
||||
disable_download = false
|
||||
}: Props = $props();
|
||||
|
||||
let lastSearch: string | undefined = undefined
|
||||
|
||||
let nbRows: number | undefined = undefined
|
||||
let csvSeparatorChar: string = ','
|
||||
let nbRows: number | undefined = $state(undefined)
|
||||
let csvSeparatorChar: string = $state(',')
|
||||
let datasource: IDatasource = {
|
||||
rowCount: 0,
|
||||
getRows: async function (params) {
|
||||
@@ -95,11 +106,10 @@
|
||||
toggleRow(rows[0])
|
||||
}
|
||||
|
||||
let eGui: HTMLDivElement
|
||||
let eGui: HTMLDivElement = $state()
|
||||
|
||||
$: eGui && mountGrid()
|
||||
|
||||
let error: string | undefined = undefined
|
||||
let error: string | undefined = $state(undefined)
|
||||
async function mountGrid() {
|
||||
if (eGui) {
|
||||
try {
|
||||
@@ -170,7 +180,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
let darkMode: boolean = false
|
||||
let darkMode: boolean = $state(false)
|
||||
run(() => {
|
||||
eGui && mountGrid()
|
||||
});
|
||||
</script>
|
||||
|
||||
<DarkModeObserver bind:darkMode />
|
||||
@@ -182,7 +195,7 @@
|
||||
<label for="csvSeparatorChar" class="text-2xs text-secondary">Separator</label>
|
||||
|
||||
<div class="w-12 ml-2 mr-2">
|
||||
<select class="h-8" bind:value={csvSeparatorChar} on:change={(e) => mountGrid()}>
|
||||
<select class="h-8" bind:value={csvSeparatorChar} onchange={(e) => mountGrid()}>
|
||||
<option value=",">,</option>
|
||||
<option value=";">;</option>
|
||||
<option value="\t">\t</option>
|
||||
|
||||
@@ -79,12 +79,14 @@
|
||||
<p class="text-primary text-sm">No permission changes recorded yet</p>
|
||||
{:else}
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
<th>Changed By</th>
|
||||
<th>Change Type</th>
|
||||
<th>Affected</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
{#snippet header_row()}
|
||||
<tr>
|
||||
<th>Changed By</th>
|
||||
<th>Change Type</th>
|
||||
<th>Affected</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
{/snippet}
|
||||
{#snippet body()}
|
||||
<tbody>
|
||||
{#each history as change}
|
||||
|
||||
@@ -10,19 +10,19 @@
|
||||
import { Hourglass, Loader2, Play, RefreshCw } from 'lucide-svelte'
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
let drawer: Drawer
|
||||
let drawer: Drawer = $state()
|
||||
|
||||
let script: Script
|
||||
let loadQueuedJobs = true
|
||||
let queuedJobsLoading = false
|
||||
let script: Script = $state()
|
||||
let loadQueuedJobs = $state(true)
|
||||
let queuedJobsLoading = $state(false)
|
||||
let queuedJobs: {
|
||||
status: 'running' | 'queued'
|
||||
jobId: string
|
||||
scheduledFor: string
|
||||
scriptHash: string
|
||||
}[] = []
|
||||
}[] = $state([])
|
||||
|
||||
let cancellingInProgress = false
|
||||
let cancellingInProgress = $state(false)
|
||||
|
||||
async function continuouslyLoadQueuedJobs() {
|
||||
while (loadQueuedJobs) {
|
||||
@@ -124,44 +124,48 @@
|
||||
</Button>
|
||||
</div>
|
||||
<TableCustom>
|
||||
<tr slot="header-row">
|
||||
<th class="text-xs">Script Hash</th>
|
||||
<th class="text-xs">Job ID</th>
|
||||
<th class="text-xs">Status</th>
|
||||
<th class="text-xs">Scheduled For</th>
|
||||
</tr>
|
||||
<tbody slot="body">
|
||||
{#each queuedJobs as { jobId, status, scriptHash, scheduledFor }}
|
||||
<tr class="">
|
||||
<td class="text-xs">
|
||||
<a
|
||||
class="pr-3"
|
||||
href="{base}/scripts/get/{scriptHash}?workspace={$workspaceStore}"
|
||||
target="_blank"
|
||||
>
|
||||
{scriptHash}
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-xs">
|
||||
<a class="pr-3" href="{base}/run/{jobId}?workspace={$workspaceStore}" target="_blank"
|
||||
>{jobId.substring(24)}</a
|
||||
>
|
||||
</td>
|
||||
<td class="text-xs">
|
||||
{#if status === 'running'}
|
||||
<Badge color="yellow" baseClass="!px-1.5">
|
||||
<Play size={14} />
|
||||
</Badge>
|
||||
{:else}
|
||||
<Badge baseClass="!px-1.5">
|
||||
<Hourglass size={14} />
|
||||
</Badge>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="text-xs">{scheduledFor}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
{#snippet header_row()}
|
||||
<tr>
|
||||
<th class="text-xs">Script Hash</th>
|
||||
<th class="text-xs">Job ID</th>
|
||||
<th class="text-xs">Status</th>
|
||||
<th class="text-xs">Scheduled For</th>
|
||||
</tr>
|
||||
{/snippet}
|
||||
{#snippet body()}
|
||||
<tbody >
|
||||
{#each queuedJobs as { jobId, status, scriptHash, scheduledFor }}
|
||||
<tr class="">
|
||||
<td class="text-xs">
|
||||
<a
|
||||
class="pr-3"
|
||||
href="{base}/scripts/get/{scriptHash}?workspace={$workspaceStore}"
|
||||
target="_blank"
|
||||
>
|
||||
{scriptHash}
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-xs">
|
||||
<a class="pr-3" href="{base}/run/{jobId}?workspace={$workspaceStore}" target="_blank"
|
||||
>{jobId.substring(24)}</a
|
||||
>
|
||||
</td>
|
||||
<td class="text-xs">
|
||||
{#if status === 'running'}
|
||||
<Badge color="yellow" baseClass="!px-1.5">
|
||||
<Play size={14} />
|
||||
</Badge>
|
||||
{:else}
|
||||
<Badge baseClass="!px-1.5">
|
||||
<Hourglass size={14} />
|
||||
</Badge>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="text-xs">{scheduledFor}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
{/snippet}
|
||||
</TableCustom>
|
||||
|
||||
{#snippet actions()}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import QueueMetricsDrawerInner from './QueueMetricsDrawerInner.svelte'
|
||||
import QueueAlerts from './QueueAlerts.svelte'
|
||||
|
||||
let drawer: Drawer
|
||||
let drawer: Drawer = $state()
|
||||
export function openDrawer() {
|
||||
drawer?.openDrawer()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import 'chartjs-adapter-date-fns'
|
||||
import { Line } from '$lib/components/chartjs-wrappers/chartJs'
|
||||
|
||||
@@ -22,7 +24,7 @@
|
||||
import Alert from './common/alert/Alert.svelte'
|
||||
import { Section } from './common'
|
||||
|
||||
let loading: boolean = true
|
||||
let loading: boolean = $state(true)
|
||||
|
||||
const colorTuples = [
|
||||
['#7EB26D', 'rgba(126, 178, 109, 0.2)'],
|
||||
@@ -64,12 +66,12 @@
|
||||
LogarithmicScale
|
||||
)
|
||||
|
||||
let countData: ChartData<'line', Point[], undefined> | undefined = undefined
|
||||
let delayData: ChartData<'line', Point[], undefined> | undefined = undefined
|
||||
let countData: ChartData<'line', Point[], undefined> | undefined = $state(undefined)
|
||||
let delayData: ChartData<'line', Point[], undefined> | undefined = $state(undefined)
|
||||
|
||||
let minDate = new Date()
|
||||
let minDate = $state(new Date())
|
||||
|
||||
let noMetrics = false
|
||||
let noMetrics = $state(false)
|
||||
|
||||
function fillData(
|
||||
data: {
|
||||
@@ -179,10 +181,14 @@
|
||||
|
||||
loadMetrics()
|
||||
|
||||
let darkMode = false
|
||||
let darkMode = $state(false)
|
||||
|
||||
$: ChartJS.defaults.color = darkMode ? '#ccc' : '#666'
|
||||
$: ChartJS.defaults.borderColor = darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'
|
||||
run(() => {
|
||||
ChartJS.defaults.color = darkMode ? '#ccc' : '#666'
|
||||
});
|
||||
run(() => {
|
||||
ChartJS.defaults.borderColor = darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'
|
||||
});
|
||||
</script>
|
||||
|
||||
<DarkModeObserver bind:darkMode />
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
<script lang="ts">
|
||||
export let label = ''
|
||||
export let options: [string | { title: string; desc: string }, any][]
|
||||
export let value: any
|
||||
export let disabled = false
|
||||
export let labelClass = ''
|
||||
export let inputClass = ''
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
interface Props {
|
||||
label?: string;
|
||||
options: [string | { title: string; desc: string }, any][];
|
||||
value: any;
|
||||
disabled?: boolean;
|
||||
labelClass?: string;
|
||||
inputClass?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
label = '',
|
||||
options,
|
||||
value = $bindable(),
|
||||
disabled = false,
|
||||
labelClass = '',
|
||||
inputClass = ''
|
||||
}: Props = $props();
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
</script>
|
||||
@@ -28,7 +39,7 @@
|
||||
class="sr-only"
|
||||
bind:group={value}
|
||||
aria-labelledby="memory-option-0-label"
|
||||
on:click={() => dispatch('change', val)}
|
||||
onclick={() => dispatch('change', val)}
|
||||
/>
|
||||
<p>
|
||||
{#if typeof label !== 'string'}
|
||||
|
||||
@@ -1,29 +1,47 @@
|
||||
<script lang="ts">
|
||||
import { run, createBubbler, stopPropagation } from 'svelte/legacy';
|
||||
|
||||
const bubble = createBubbler();
|
||||
import RangeSlider from 'svelte-range-slider-pips'
|
||||
|
||||
export let min = 0
|
||||
export let max = 100
|
||||
export let initialValue = 0
|
||||
export let value = typeof initialValue === 'string' ? parseInt(initialValue) : initialValue
|
||||
export let disabled: boolean = false
|
||||
export let defaultValue: number | undefined = undefined
|
||||
export let format: (value: number) => string = (v) => `${v}`
|
||||
export let hideInput: boolean = false
|
||||
interface Props {
|
||||
min?: number;
|
||||
max?: number;
|
||||
initialValue?: number;
|
||||
value?: any;
|
||||
disabled?: boolean;
|
||||
defaultValue?: number | undefined;
|
||||
format?: (value: number) => string;
|
||||
hideInput?: boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
min = 0,
|
||||
max = 100,
|
||||
initialValue = 0,
|
||||
value = $bindable(typeof initialValue === 'string' ? parseInt(initialValue) : initialValue),
|
||||
disabled = false,
|
||||
defaultValue = undefined,
|
||||
format = (v) => `${v}`,
|
||||
hideInput = false
|
||||
}: Props = $props();
|
||||
|
||||
let step: number = 1
|
||||
|
||||
let slider: HTMLElement
|
||||
let slider: HTMLElement = $state()
|
||||
|
||||
function calculateAxisStep(min: number, max: number): number {
|
||||
const range = max - min
|
||||
return range < 100 ? 1 : range / 20
|
||||
}
|
||||
|
||||
$: if (value === null) {
|
||||
value = 0
|
||||
}
|
||||
run(() => {
|
||||
if (value === null) {
|
||||
value = 0
|
||||
}
|
||||
});
|
||||
|
||||
$: axisStep = calculateAxisStep(min, max)
|
||||
let axisStep = $derived(calculateAxisStep(min, max))
|
||||
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
if (disabled) return
|
||||
@@ -44,17 +62,17 @@
|
||||
}
|
||||
|
||||
// Calculate the handle width based on the length of the max value
|
||||
$: handleWidth = `${Math.max(max.toString().length ?? 2, 2)}em`
|
||||
let handleWidth = $derived(`${Math.max(max.toString().length ?? 2, 2)}em`)
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row w-full mx-2 items-center gap-8">
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
|
||||
<div
|
||||
class={'grow'}
|
||||
style="--range-handle-focus: {'#7e9abd'}; --range-handle: {'#7e9abd'}; --handle-width: {handleWidth}; --handle-border: 4px;"
|
||||
on:pointerdown|stopPropagation
|
||||
on:keydown={handleKeyDown}
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
onkeydown={handleKeyDown}
|
||||
>{#if max <= min}
|
||||
<div class="text-secondary text-sm"
|
||||
>Impossible to display range: {`max (${max}) <= min (${min})`}</div
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
<script lang="ts">
|
||||
export let required: boolean
|
||||
export let detail = ''
|
||||
interface Props {
|
||||
required: boolean
|
||||
detail?: string
|
||||
class?: string
|
||||
}
|
||||
|
||||
let { required, detail = '', class: c = '' }: Props = $props()
|
||||
</script>
|
||||
|
||||
{#if required}
|
||||
<span class="text-red-500 dark:text-red-400 text-sm font-normal {$$props.class}">*</span>
|
||||
<span class="text-red-500 dark:text-red-400 text-sm font-normal {c}">*</span>
|
||||
{:else if detail || detail != ''}
|
||||
<span class="text-sm text-primary ml-2 font-normal {$$props.class}"
|
||||
<span class="text-sm text-primary ml-2 font-normal {c}"
|
||||
>({detail != '' ? `${detail}` : ''})</span
|
||||
>
|
||||
{/if}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { Button, Drawer } from './common'
|
||||
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
|
||||
import { Loader2, Save } from 'lucide-svelte'
|
||||
|
||||
let drawer: Drawer
|
||||
let canSave = true
|
||||
let resource_type: string | undefined = undefined
|
||||
let defaultValues: Record<string, any> | undefined = undefined
|
||||
let drawer: Drawer = $state()
|
||||
let canSave = $state(true)
|
||||
let resource_type: string | undefined = $state(undefined)
|
||||
let defaultValues: Record<string, any> | undefined = $state(undefined)
|
||||
|
||||
let resourceEditor: { editResource: () => void; createResource: () => void } | undefined =
|
||||
undefined
|
||||
$state(undefined)
|
||||
|
||||
let path: string | undefined = undefined
|
||||
let path: string | undefined = $state(undefined)
|
||||
|
||||
let newResource = false
|
||||
let newResource = $state(false)
|
||||
export async function initEdit(p: string): Promise<void> {
|
||||
resource_type = undefined
|
||||
newResource = false
|
||||
@@ -34,9 +36,11 @@
|
||||
drawer.openDrawer?.()
|
||||
}
|
||||
|
||||
let mode: 'edit' | 'new' = newResource ? 'new' : 'edit'
|
||||
let mode: 'edit' | 'new' = $state(newResource ? 'new' : 'edit')
|
||||
|
||||
$: path ? (mode = 'edit') : (mode = 'new')
|
||||
run(() => {
|
||||
path ? (mode = 'edit') : (mode = 'new')
|
||||
});
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={drawer} size="800px">
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import Popover from './meltComponents/Popover.svelte'
|
||||
import { Calendar, Check, CornerDownLeft } from 'lucide-svelte'
|
||||
import RunFormAdvancedPopup from './RunFormAdvancedPopup.svelte'
|
||||
import { page } from '$app/stores'
|
||||
import { page } from '$app/state'
|
||||
import { replaceState } from '$app/navigation'
|
||||
import JsonInputs from '$lib/components/JsonInputs.svelte'
|
||||
import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte'
|
||||
@@ -108,7 +108,7 @@
|
||||
nurl.hash = computeSharableHash(args)
|
||||
|
||||
try {
|
||||
replaceState(nurl.toString(), $page.state)
|
||||
replaceState(nurl.toString(), page.state)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
import { WorkerService } from '$lib/gen'
|
||||
import DateTimeInput from './DateTimeInput.svelte'
|
||||
|
||||
export let runnable:
|
||||
|
||||
interface Props {
|
||||
runnable:
|
||||
| {
|
||||
summary?: string
|
||||
description?: string
|
||||
@@ -21,11 +23,18 @@
|
||||
created_by?: string
|
||||
extra_perms?: Record<string, boolean>
|
||||
}
|
||||
| undefined
|
||||
| undefined;
|
||||
scheduledForStr: string | undefined;
|
||||
invisible_to_owner: boolean | undefined;
|
||||
overrideTag: string | undefined;
|
||||
}
|
||||
|
||||
export let scheduledForStr: string | undefined
|
||||
export let invisible_to_owner: boolean | undefined
|
||||
export let overrideTag: string | undefined
|
||||
let {
|
||||
runnable,
|
||||
scheduledForStr = $bindable(),
|
||||
invisible_to_owner = $bindable(),
|
||||
overrideTag = $bindable()
|
||||
}: Props = $props();
|
||||
loadWorkerGroups()
|
||||
|
||||
async function loadWorkerGroups() {
|
||||
|
||||
@@ -11,15 +11,19 @@
|
||||
import S3FilePicker from './S3FilePicker.svelte'
|
||||
import FileUpload from './common/fileUpload/FileUpload.svelte'
|
||||
|
||||
export let value: any
|
||||
export let editor: SimpleEditor | undefined = undefined
|
||||
interface Props {
|
||||
value: any;
|
||||
editor?: SimpleEditor | undefined;
|
||||
}
|
||||
|
||||
let { value = $bindable(), editor = $bindable(undefined) }: Props = $props();
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let s3FilePicker: S3FilePicker
|
||||
let s3FileUploadRawMode: false
|
||||
let s3FilePicker: S3FilePicker = $state()
|
||||
let s3FileUploadRawMode: false = $state()
|
||||
let el: HTMLTextAreaElement | undefined = undefined
|
||||
let rawValue: string | undefined = undefined
|
||||
let rawValue: string | undefined = $state(undefined)
|
||||
|
||||
function evalValueToRaw() {
|
||||
rawValue = JSON.stringify(value, null, 2)
|
||||
|
||||
@@ -10,14 +10,25 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let runnableId: string | undefined
|
||||
export let runnableType: RunnableType | undefined
|
||||
export let args: object
|
||||
export let disabled: boolean = false
|
||||
export let small: boolean | undefined = undefined
|
||||
export let showTooltip: boolean | undefined = undefined
|
||||
interface Props {
|
||||
runnableId: string | undefined;
|
||||
runnableType: RunnableType | undefined;
|
||||
args: object;
|
||||
disabled?: boolean;
|
||||
small?: boolean | undefined;
|
||||
showTooltip?: boolean | undefined;
|
||||
}
|
||||
|
||||
let savingInputs = false
|
||||
let {
|
||||
runnableId,
|
||||
runnableType,
|
||||
args,
|
||||
disabled = false,
|
||||
small = undefined,
|
||||
showTooltip = undefined
|
||||
}: Props = $props();
|
||||
|
||||
let savingInputs = $state(false)
|
||||
|
||||
async function saveInput(args: object) {
|
||||
savingInputs = true
|
||||
|
||||
@@ -285,8 +285,8 @@
|
||||
{limitPayloadSize}
|
||||
{hover}
|
||||
{viewerOpen}
|
||||
on:openChange={(e) => {
|
||||
updateViewerOpenState(item.id, e.detail)
|
||||
onOpenChange={(isOpen) => {
|
||||
updateViewerOpenState(item.id, isOpen)
|
||||
}}
|
||||
maxWidth={clientWidth}
|
||||
{editOptions}
|
||||
|
||||
@@ -4,16 +4,25 @@
|
||||
import ObjectViewerWrapper from '$lib/components/propertyPicker/ObjectViewerWrapper.svelte'
|
||||
import { copyToClipboard, isObjectTooBig } from '$lib/utils'
|
||||
import { Eye, CopyIcon, Loader2 } from 'lucide-svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
interface Props {
|
||||
payloadData: any;
|
||||
limitPayloadSize?: boolean;
|
||||
hover?: boolean;
|
||||
viewerOpen?: boolean;
|
||||
maxWidth?: number | undefined;
|
||||
editOptions?: boolean;
|
||||
onOpenChange?: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
export let payloadData: any
|
||||
export let limitPayloadSize: boolean = false
|
||||
export let hover: boolean = false
|
||||
export let viewerOpen: boolean = false
|
||||
export let maxWidth: number | undefined = undefined
|
||||
export let editOptions: boolean = true
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let {
|
||||
payloadData,
|
||||
limitPayloadSize = false,
|
||||
hover = false,
|
||||
viewerOpen = false,
|
||||
maxWidth = undefined,
|
||||
editOptions = true,
|
||||
onOpenChange = undefined
|
||||
}: Props = $props();
|
||||
const payloadTooBigForPreview = payloadData != 'WINDMILL_TOO_BIG' && isObjectTooBig(payloadData)
|
||||
const buttonWidth = 34
|
||||
const floatingConfig = {
|
||||
@@ -32,14 +41,13 @@
|
||||
}
|
||||
const xOffset = editOptions ? 218 : 168 // width of the optional buttons on the right
|
||||
|
||||
let popover: Popover | undefined
|
||||
let popover: Popover | undefined = $state()
|
||||
let popoverOpen = false
|
||||
let hoverTimeout: ReturnType<typeof setTimeout> | undefined
|
||||
let objectViewerLoaded = false
|
||||
let popoverFullyOpened = false
|
||||
let objectViewerLoaded = $state(false)
|
||||
let popoverFullyOpened = $state(false)
|
||||
|
||||
function handlePopoverChange(event: CustomEvent<boolean>) {
|
||||
const isOpen = event.detail
|
||||
function handlePopoverChange(isOpen: boolean) {
|
||||
popoverOpen = isOpen
|
||||
|
||||
if (!isOpen) {
|
||||
@@ -53,7 +61,7 @@
|
||||
}, 50)
|
||||
}
|
||||
|
||||
dispatch('openChange', isOpen)
|
||||
onOpenChange?.(isOpen)
|
||||
}
|
||||
|
||||
function handleHoverChange(isHovering: boolean) {
|
||||
@@ -73,90 +81,101 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: handleHoverChange(hover)
|
||||
$: ajustedWidth = maxWidth ? Math.abs(maxWidth - xOffset) : undefined
|
||||
$effect(() => {
|
||||
handleHoverChange(hover)
|
||||
});
|
||||
let ajustedWidth = $derived(maxWidth ? Math.abs(maxWidth - xOffset) : undefined)
|
||||
</script>
|
||||
|
||||
<Popover
|
||||
bind:this={popover}
|
||||
{floatingConfig}
|
||||
on:openChange={handlePopoverChange}
|
||||
on:click={(e) => {
|
||||
onOpenChange={handlePopoverChange}
|
||||
onclick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
closeOnOtherPopoverOpen
|
||||
closeOnClickOutside={false}
|
||||
usePointerDownOutside
|
||||
>
|
||||
<svelte:fragment slot="trigger" let:isOpen>
|
||||
<Button
|
||||
variant="subtle"
|
||||
unifiedSize="sm"
|
||||
btnClasses={hover || isOpen ? 'block -my-2 bg-transparent' : 'hidden'}
|
||||
wrapperClasses="p-0"
|
||||
iconOnly
|
||||
nonCaptureEvent
|
||||
startIcon={{ icon: Eye }}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
<div
|
||||
class="p-2 overflow-auto"
|
||||
style="width: {ajustedWidth ? ajustedWidth + 'px' : '50vh'}; max-height: 50vh"
|
||||
>
|
||||
{#if payloadData === 'WINDMILL_TOO_BIG'}
|
||||
<div class="text-center text-primary text-xs">
|
||||
{#if limitPayloadSize}
|
||||
Payload too big to be used
|
||||
{:else}
|
||||
Payload too big to preview but can still be loaded
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="relative p-2"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="Copy JSON payload to clipboard"
|
||||
on:click={() => {
|
||||
{#snippet trigger({ isOpen })}
|
||||
|
||||
<Button
|
||||
variant="subtle"
|
||||
unifiedSize="sm"
|
||||
btnClasses={hover || isOpen ? 'block -my-2 bg-transparent' : 'hidden'}
|
||||
wrapperClasses="p-0"
|
||||
iconOnly
|
||||
nonCaptureEvent
|
||||
startIcon={{ icon: Eye }}
|
||||
/>
|
||||
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
|
||||
<div
|
||||
class="p-2 overflow-auto"
|
||||
style="width: {ajustedWidth ? ajustedWidth + 'px' : '50vh'}; max-height: 50vh"
|
||||
>
|
||||
{#if payloadData === 'WINDMILL_TOO_BIG'}
|
||||
<div class="text-center text-primary text-xs">
|
||||
{#if limitPayloadSize}
|
||||
Payload too big to be used
|
||||
{:else}
|
||||
Payload too big to preview but can still be loaded
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="relative p-2"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="Copy JSON payload to clipboard"
|
||||
onclick={() => {
|
||||
copyToClipboard(JSON.stringify(payloadData))
|
||||
}}
|
||||
on:keydown
|
||||
>
|
||||
{#if !objectViewerLoaded && payloadTooBigForPreview}
|
||||
<div class="flex justify-center items-center py-4">
|
||||
<Loader2 size={20} class="animate-spin text-primary" />
|
||||
<span class="ml-2 text-xs text-primary">Loading data...</span>
|
||||
</div>
|
||||
{/if}
|
||||
onkeydown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault()
|
||||
copyToClipboard(JSON.stringify(payloadData))
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if !objectViewerLoaded && payloadTooBigForPreview}
|
||||
<div class="flex justify-center items-center py-4">
|
||||
<Loader2 size={20} class="animate-spin text-primary" />
|
||||
<span class="ml-2 text-xs text-primary">Loading data...</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if popoverFullyOpened || !payloadTooBigForPreview}
|
||||
<div
|
||||
class={!objectViewerLoaded && payloadTooBigForPreview
|
||||
? 'invisible h-0 overflow-hidden'
|
||||
: ''}
|
||||
>
|
||||
<ObjectViewerWrapper
|
||||
json={payloadData}
|
||||
allowCopy
|
||||
pureViewer
|
||||
on:mounted={() => (objectViewerLoaded = true)}
|
||||
{#if popoverFullyOpened || !payloadTooBigForPreview}
|
||||
<div
|
||||
class={!objectViewerLoaded && payloadTooBigForPreview
|
||||
? 'invisible h-0 overflow-hidden'
|
||||
: ''}
|
||||
>
|
||||
<ObjectViewerWrapper
|
||||
json={payloadData}
|
||||
allowCopy
|
||||
pureViewer
|
||||
onmounted={() => (objectViewerLoaded = true)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="absolute top-2 right-2 w-full h-full">
|
||||
<Button
|
||||
variant="subtle"
|
||||
unifiedSize="sm"
|
||||
class="absolute top-0 right-0"
|
||||
iconOnly
|
||||
startIcon={{ icon: CopyIcon }}
|
||||
nonCaptureEvent
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="absolute top-2 right-2 w-full h-full">
|
||||
<Button
|
||||
variant="subtle"
|
||||
unifiedSize="sm"
|
||||
class="absolute top-0 right-0"
|
||||
iconOnly
|
||||
startIcon={{ icon: CopyIcon }}
|
||||
nonCaptureEvent
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{/snippet}
|
||||
</Popover>
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
class="w-fit"
|
||||
usePointerDownOutside
|
||||
closeOnOtherPopoverOpen
|
||||
on:click={(e) => {
|
||||
onclick={(e) => {
|
||||
e.stopPropagation()
|
||||
}}
|
||||
floatingConfig={{ placement: 'top-end' }}
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
import type { SchemaProperty } from '$lib/common'
|
||||
import Badge from './common/badge/Badge.svelte'
|
||||
|
||||
export let property: SchemaProperty
|
||||
interface Props {
|
||||
property: SchemaProperty;
|
||||
}
|
||||
|
||||
let { property }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row flex-wrap gap-1">
|
||||
|
||||
@@ -1230,7 +1230,10 @@
|
||||
{#if script.schema && !disableAi && !customUi?.settingsPanel?.metadata?.disableAiFilling}
|
||||
<div class="mt-3">
|
||||
<AIFormSettings
|
||||
bind:prompt={script.schema.prompt_for_ai as string | undefined}
|
||||
bind:prompt={
|
||||
() => script.schema!.prompt_for_ai as string | undefined,
|
||||
(v) => (script.schema!.prompt_for_ai = v)
|
||||
}
|
||||
type="script"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -2,14 +2,24 @@
|
||||
import { onMount, onDestroy } from 'svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
let isAtBottom: boolean = false
|
||||
let isScrollable = false
|
||||
let isAtBottom: boolean = $state(false)
|
||||
let isScrollable = $state(false)
|
||||
|
||||
export let id: string | null | undefined = undefined
|
||||
export let scrollableClass: string = ''
|
||||
export let shiftedShadow: boolean = false
|
||||
interface Props {
|
||||
id?: string | null | undefined;
|
||||
scrollableClass?: string;
|
||||
shiftedShadow?: boolean;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
id = undefined,
|
||||
scrollableClass = '',
|
||||
shiftedShadow = false,
|
||||
children
|
||||
}: Props = $props();
|
||||
let mutationObserver: MutationObserver
|
||||
let el: HTMLDivElement
|
||||
let el: HTMLDivElement = $state()
|
||||
|
||||
function handleScroll(event) {
|
||||
const scrollableElement = event.target
|
||||
@@ -45,8 +55,8 @@
|
||||
</script>
|
||||
|
||||
<div {id} class={twMerge('relative pb-1', scrollableClass)}>
|
||||
<div bind:this={el} on:scroll={handleScroll} class="w-full h-full overflow-y-auto">
|
||||
<slot />
|
||||
<div bind:this={el} onscroll={handleScroll} class="w-full h-full overflow-y-auto">
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{#if !isAtBottom && isScrollable}
|
||||
<div
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
import SplitPanesOrColumnOnMobile from './splitPanes/SplitPanesOrColumnOnMobile.svelte'
|
||||
import Select from './select/Select.svelte'
|
||||
import { goto } from '$lib/navigation'
|
||||
import { page } from '$app/stores'
|
||||
import { page } from '$app/state'
|
||||
import { watch } from 'runed'
|
||||
|
||||
interface Props {
|
||||
@@ -169,13 +169,13 @@
|
||||
|
||||
type Selected = { mode: string; workerGroup: string; hostname: string }
|
||||
let initialSelected =
|
||||
$page.url.searchParams.get('mode') &&
|
||||
$page.url.searchParams.get('workerGroup') &&
|
||||
$page.url.searchParams.get('hostname')
|
||||
page.url.searchParams.get('mode') &&
|
||||
page.url.searchParams.get('workerGroup') &&
|
||||
page.url.searchParams.get('hostname')
|
||||
? {
|
||||
mode: $page.url.searchParams.get('mode')!,
|
||||
workerGroup: $page.url.searchParams.get('workerGroup')!,
|
||||
hostname: $page.url.searchParams.get('hostname')!
|
||||
mode: page.url.searchParams.get('mode')!,
|
||||
workerGroup: page.url.searchParams.get('workerGroup')!,
|
||||
hostname: page.url.searchParams.get('hostname')!
|
||||
}
|
||||
: undefined
|
||||
let selected: Selected | undefined = $state(initialSelected)
|
||||
@@ -663,7 +663,7 @@
|
||||
<LogSnippetViewer
|
||||
content={snippet_fragment || document.logs[0]}
|
||||
highlighted={snippet_highlighted}
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
let logLineNumber = document.line_number[0]
|
||||
let logFile = document.file_name[0]
|
||||
let host = document.host[0]
|
||||
|
||||
@@ -154,12 +154,13 @@
|
||||
{/if}
|
||||
{#if acls?.length > 0}
|
||||
<TableCustom>
|
||||
<!-- @migration-task: migrate this slot by hand, `header-row` is an invalid identifier -->
|
||||
<tr slot="header-row">
|
||||
<th>owner</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{#snippet header_row()}
|
||||
<tr>
|
||||
<th>owner</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{/snippet}
|
||||
{#snippet body()}
|
||||
<tbody>
|
||||
{#each acls as [owner, write]}
|
||||
|
||||
@@ -5,10 +5,21 @@
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let text: string
|
||||
export let tooltip: string | undefined = undefined
|
||||
export let view = false
|
||||
export let size: 'xs' | 'sm' | 'md' | 'lg' = 'md'
|
||||
interface Props {
|
||||
text: string;
|
||||
tooltip?: string | undefined;
|
||||
view?: boolean;
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg';
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
text,
|
||||
tooltip = undefined,
|
||||
view = $bindable(false),
|
||||
size = 'md',
|
||||
children
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<Button
|
||||
@@ -26,5 +37,5 @@
|
||||
{/if}
|
||||
</Button>
|
||||
{#if view}
|
||||
<div class="my-4 px-2" transition:slide|local><slot /></div>
|
||||
<div class="my-4 px-2" transition:slide|local>{@render children?.()}</div>
|
||||
{/if}
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
import { Pen } from 'lucide-svelte'
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
|
||||
export let value: string
|
||||
export let disabled = false
|
||||
interface Props {
|
||||
value: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
let { value = $bindable(), disabled = false }: Props = $props();
|
||||
|
||||
function blur(e: KeyboardEvent) {
|
||||
e.key === 'Enter' && (e?.target as any)?.blur()
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { Loader2, RotateCwIcon } from 'lucide-svelte'
|
||||
|
||||
import { Button, DrawerContent } from './common'
|
||||
@@ -15,8 +17,8 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import HighlightTheme from './HighlightTheme.svelte'
|
||||
|
||||
let drawer: Drawer
|
||||
let token: undefined | string = undefined
|
||||
let drawer: Drawer = $state()
|
||||
let token: undefined | string = $state(undefined)
|
||||
export async function open() {
|
||||
token = $oauthStore?.access_token ?? ''
|
||||
drawer.openDrawer?.()
|
||||
@@ -24,7 +26,7 @@
|
||||
description = ''
|
||||
}
|
||||
|
||||
let step: 'init' | 'resource' = 'init'
|
||||
let step: 'init' | 'resource' = $state('init')
|
||||
|
||||
async function listDatabases() {
|
||||
if (!token) return
|
||||
@@ -44,31 +46,33 @@
|
||||
region: string
|
||||
id: string
|
||||
}
|
||||
let databases: undefined | Database[] = undefined
|
||||
let databases: undefined | Database[] = $state(undefined)
|
||||
|
||||
$: token != undefined && listDatabases()
|
||||
run(() => {
|
||||
token != undefined && listDatabases()
|
||||
});
|
||||
|
||||
let selectedDatabase: undefined | Database = undefined
|
||||
let selectedDatabase: undefined | Database = $state(undefined)
|
||||
|
||||
let description = ''
|
||||
let pathError = ''
|
||||
let password = ''
|
||||
let path: string | undefined = undefined
|
||||
let description = $state('')
|
||||
let pathError = $state('')
|
||||
let password = $state('')
|
||||
let path: string | undefined = $state(undefined)
|
||||
|
||||
/**
|
||||
* https://github.com/orgs/supabase/discussions/17817
|
||||
* host is in the format of `aws-0-${region}.pooler.supabase.com`
|
||||
* user is in the format of `postgres.${id}`
|
||||
*/
|
||||
$: resourceValue = {
|
||||
let resourceValue = $derived({
|
||||
host: `aws-0-${selectedDatabase?.region}.pooler.supabase.com`,
|
||||
user: `postgres.${selectedDatabase?.id}`,
|
||||
port: 5432,
|
||||
dbname: 'postgres',
|
||||
sslmode: 'prefer',
|
||||
password: `$var:${path}`
|
||||
}
|
||||
$: disabled = path == undefined || pathError != '' || path == ''
|
||||
})
|
||||
let disabled = $derived(path == undefined || pathError != '' || path == '')
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
async function save() {
|
||||
@@ -120,7 +124,7 @@
|
||||
{#each databases as database}
|
||||
<button
|
||||
class="btn btn-outline-primary mt-2 border p-2 w-full border-secondary-inverse hover:border-secondary rounded"
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
selectedDatabase = database
|
||||
|
||||
step = 'resource'
|
||||
|
||||
@@ -98,15 +98,17 @@
|
||||
<span class="text-accent">→ {uptodateVersion}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<svelte:fragment slot="text">
|
||||
{#if isCloudHosted()}
|
||||
The cloud version is updated daily.
|
||||
{:else}
|
||||
How to update?<br />
|
||||
- docker: <code>docker compose up -d</code><br />
|
||||
- <a href="https://github.com/windmill-labs/windmill-helm-charts#install">helm</a>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
{#snippet text()}
|
||||
|
||||
{#if isCloudHosted()}
|
||||
The cloud version is updated daily.
|
||||
{:else}
|
||||
How to update?<br />
|
||||
- docker: <code>docker compose up -d</code><br />
|
||||
- <a href="https://github.com/windmill-labs/windmill-helm-charts#install">helm</a>
|
||||
{/if}
|
||||
|
||||
{/snippet}
|
||||
</MeltTooltip>
|
||||
{/snippet}
|
||||
{#snippet actions()}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { base } from '$lib/base'
|
||||
import SearchItems from './SearchItems.svelte'
|
||||
import { page } from '$app/stores'
|
||||
import { page } from '$app/state'
|
||||
import { goto as gotoUrl } from '$app/navigation'
|
||||
import Version from './Version.svelte'
|
||||
import Uptodate from './Uptodate.svelte'
|
||||
@@ -50,9 +50,9 @@
|
||||
} = $props()
|
||||
|
||||
function removeHash() {
|
||||
const index = $page.url.href.lastIndexOf('#')
|
||||
const index = page.url.href.lastIndexOf('#')
|
||||
if (index === -1) return
|
||||
const hashRemoved = $page.url.href.slice(0, index)
|
||||
const hashRemoved = page.url.href.slice(0, index)
|
||||
gotoUrl(hashRemoved)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,51 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
interface Props {
|
||||
paginated?: boolean
|
||||
currentPage?: number
|
||||
showNext?: boolean
|
||||
class?: string
|
||||
header_row?: import('svelte').Snippet
|
||||
body?: import('svelte').Snippet
|
||||
onNext?: () => void
|
||||
onPrevious?: () => void
|
||||
}
|
||||
|
||||
export let paginated = false
|
||||
export let currentPage = 1
|
||||
export let showNext = true
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
let {
|
||||
paginated = false,
|
||||
currentPage = 1,
|
||||
showNext = true,
|
||||
class: className = '',
|
||||
header_row,
|
||||
body,
|
||||
onNext,
|
||||
onPrevious
|
||||
}: Props = $props()
|
||||
</script>
|
||||
|
||||
<!-- A custom table
|
||||
<!-- A custom table
|
||||
- the first slot should be a <tr>, containing th elements
|
||||
- the second slot should be a <tbody>, containing th elements
|
||||
-->
|
||||
<div class="flex flex-col {$$props.class} min-w-full">
|
||||
<div class="flex flex-col {className} min-w-full">
|
||||
<div class="inline-block min-w-full py-2 align-middle">
|
||||
<table class="table-custom min-w-full table-auto divide-y">
|
||||
<thead>
|
||||
<slot name="header-row" />
|
||||
{@render header_row?.()}
|
||||
</thead>
|
||||
<slot name="body" />
|
||||
{@render body?.()}
|
||||
</table>
|
||||
</div>
|
||||
{#if paginated}
|
||||
<div class="sticky flex flex-row-reverse text-primary mb-6">
|
||||
<button
|
||||
class="ml-2 drop-shadow-md {showNext ? 'visible' : 'invisible'}"
|
||||
on:click={() => dispatch('next')}
|
||||
onclick={() => onNext?.()}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
<button
|
||||
class="mx-2 drop-shadow-md {currentPage === 1 ? 'hidden' : ''}"
|
||||
on:click={() => dispatch('previous')}
|
||||
onclick={() => onPrevious?.()}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
|
||||
@@ -7,10 +7,19 @@
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { tryEvery } from '$lib/utils'
|
||||
|
||||
export let workspaceOverride: string | undefined = undefined
|
||||
export let resourceType: string | undefined
|
||||
export let args: Record<string, any> | any = {}
|
||||
export let buttonTextOverride: string | undefined = undefined
|
||||
interface Props {
|
||||
workspaceOverride?: string | undefined;
|
||||
resourceType: string | undefined;
|
||||
args?: Record<string, any> | any;
|
||||
buttonTextOverride?: string | undefined;
|
||||
}
|
||||
|
||||
let {
|
||||
workspaceOverride = undefined,
|
||||
resourceType,
|
||||
args = {},
|
||||
buttonTextOverride = undefined
|
||||
}: Props = $props();
|
||||
|
||||
const scripts: {
|
||||
[key: string]: {
|
||||
@@ -166,7 +175,7 @@ export async function main(bucket: any) {
|
||||
}
|
||||
}
|
||||
|
||||
let loading = false
|
||||
let loading = $state(false)
|
||||
async function testConnection() {
|
||||
if (!resourceType) return
|
||||
loading = true
|
||||
|
||||
@@ -4,9 +4,19 @@
|
||||
import { gfmPlugin } from 'svelte-exmarkdown/gfm'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let documentationLink: string | undefined = undefined
|
||||
export let markdownTooltip: string | undefined = undefined
|
||||
export let customBgClass: string | undefined = undefined
|
||||
interface Props {
|
||||
documentationLink?: string | undefined;
|
||||
markdownTooltip?: string | undefined;
|
||||
customBgClass?: string | undefined;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
documentationLink = undefined,
|
||||
markdownTooltip = undefined,
|
||||
customBgClass = undefined,
|
||||
children
|
||||
}: Props = $props();
|
||||
const plugins = [gfmPlugin()]
|
||||
</script>
|
||||
|
||||
@@ -21,7 +31,7 @@
|
||||
<Markdown md={markdownTooltip} {plugins} />
|
||||
</div>
|
||||
{:else}
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
{/if}
|
||||
|
||||
{#if documentationLink}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
|
||||
let uptodate: string | undefined = undefined
|
||||
let uptodate: string | undefined = $state(undefined)
|
||||
|
||||
async function loadVersion() {
|
||||
try {
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { urlize } from '$lib/utils'
|
||||
|
||||
export let text: string
|
||||
$: parsed = text ? urlize(text, 'html') : ''
|
||||
interface Props {
|
||||
text: string;
|
||||
}
|
||||
|
||||
let { text }: Props = $props();
|
||||
let parsed = $derived(text ? urlize(text, 'html') : '')
|
||||
</script>
|
||||
|
||||
{@html parsed}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { SettingsService } from '$lib/gen'
|
||||
|
||||
let version = ''
|
||||
let version = $state('')
|
||||
|
||||
loadVersion()
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { WorkerService } from '$lib/gen'
|
||||
import { Alert } from './common'
|
||||
|
||||
let ips: string[] | undefined = undefined
|
||||
let ips: string[] | undefined = $state(undefined)
|
||||
|
||||
WorkerService.listWorkers({ pingSince: 300 }).then((workers) => {
|
||||
ips = [
|
||||
|
||||
@@ -7,23 +7,15 @@
|
||||
import TimelineBar from './TimelineBar.svelte'
|
||||
import type { WorkflowStatus } from '$lib/gen'
|
||||
|
||||
export let flow_status: Record<string, WorkflowStatus>
|
||||
export let flowDone = false
|
||||
interface Props {
|
||||
flow_status: Record<string, WorkflowStatus>;
|
||||
flowDone?: boolean;
|
||||
}
|
||||
|
||||
$: min = Object.values(flow_status).reduce(
|
||||
(a, b) => Math.min(a, b.scheduled_for ? new Date(b.scheduled_for).getTime() : Infinity),
|
||||
Infinity
|
||||
)
|
||||
$: max = flowDone
|
||||
? Object.values(flow_status).reduce(
|
||||
(a, b) =>
|
||||
Math.max(a, b.started_at ? new Date(b.started_at).getTime() + (b.duration_ms ?? 0) : 0),
|
||||
0
|
||||
)
|
||||
: undefined
|
||||
$: total = flowDone && max ? max - min : now - min
|
||||
let { flow_status, flowDone = false }: Props = $props();
|
||||
|
||||
let now = getDbClockNow().getTime()
|
||||
|
||||
let now = $state(getDbClockNow().getTime())
|
||||
|
||||
let interval = setInterval((x) => {
|
||||
if (!max) {
|
||||
@@ -37,6 +29,18 @@
|
||||
onDestroy(() => {
|
||||
interval && clearInterval(interval)
|
||||
})
|
||||
let min = $derived(Object.values(flow_status).reduce(
|
||||
(a, b) => Math.min(a, b.scheduled_for ? new Date(b.scheduled_for).getTime() : Infinity),
|
||||
Infinity
|
||||
))
|
||||
let max = $derived(flowDone
|
||||
? Object.values(flow_status).reduce(
|
||||
(a, b) =>
|
||||
Math.max(a, b.started_at ? new Date(b.started_at).getTime() + (b.duration_ms ?? 0) : 0),
|
||||
0
|
||||
)
|
||||
: undefined)
|
||||
let total = $derived(flowDone && max ? max - min : now - min)
|
||||
</script>
|
||||
|
||||
{#if flow_status}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
import SettingCard from './instanceSettings/SettingCard.svelte'
|
||||
|
||||
export let value: any
|
||||
interface Props {
|
||||
value: any;
|
||||
}
|
||||
|
||||
$: enabled = value != undefined
|
||||
let { value = $bindable() }: Props = $props();
|
||||
|
||||
let org = ''
|
||||
|
||||
$: changeOrg(org)
|
||||
let org = $state('')
|
||||
|
||||
|
||||
function changeOrg(org) {
|
||||
if (value) {
|
||||
@@ -30,10 +34,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
let enabled = $derived(value != undefined)
|
||||
run(() => {
|
||||
changeOrg(org)
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<!-- svelte-ignore a11y-label-has-associated-control -->
|
||||
<!-- svelte-ignore a11y_label_has_associated_control -->
|
||||
<label class="text-xs font-semibold text-emphasis flex gap-4 items-center"
|
||||
><div class="w-[120px]"><IconedResourceType name={'zitadel'} after={true} /></div><Toggle
|
||||
checked={enabled}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
on:keydown={(e) => {
|
||||
onkeydown={(e) => {
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
|
||||
onConfirm()
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
multiple={resolvedConfig?.allowMultiple}
|
||||
convertTo="base64"
|
||||
returnFileNames
|
||||
on:change={({ detail }) => {
|
||||
onChange={(detail) => {
|
||||
handleChange(detail)
|
||||
}}
|
||||
class={twMerge('w-full h-full', css?.container?.class, 'wm-file-input')}
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
import Tab from '$lib/components/common/tabs/Tab.svelte'
|
||||
import HighlightTheme from '$lib/components/HighlightTheme.svelte'
|
||||
|
||||
let jsonViewerDrawer: Drawer
|
||||
let jsonViewerDrawer: Drawer = $state()
|
||||
|
||||
let app: any | undefined = undefined
|
||||
let app: any | undefined = $state(undefined)
|
||||
|
||||
let rawType: 'json' | 'yaml' = 'yaml'
|
||||
let rawType: 'json' | 'yaml' = $state('yaml')
|
||||
|
||||
export function open(app_l: any) {
|
||||
app = app_l
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let resourceOnly: boolean = true
|
||||
let resourceOnly: boolean = $state(true)
|
||||
</script>
|
||||
|
||||
<Alert type="info" title="Configurations">
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Globe, Loader2, Save } from 'lucide-svelte'
|
||||
|
||||
let jsonViewerDrawer: Drawer
|
||||
let jsonViewerDrawer: Drawer = $state()
|
||||
|
||||
let code: string = ''
|
||||
let code: string = $state('')
|
||||
let path: string = ''
|
||||
let useDraft: boolean = false
|
||||
let loading = true
|
||||
let useDraft: boolean = $state(false)
|
||||
let loading = $state(true)
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let app: any | undefined = undefined
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import type { App, AppEditorContext, AppViewerContext } from '../types'
|
||||
import RecomputeAllButton from './RecomputeAllButton.svelte'
|
||||
@@ -10,12 +12,9 @@
|
||||
|
||||
let timeout: number | undefined = undefined
|
||||
let shouldRefresh = false
|
||||
let firstLoad = false
|
||||
let firstLoad = $state(false)
|
||||
let progressTimer: number | undefined = undefined
|
||||
|
||||
$: !firstLoad &&
|
||||
canInitializeAll($initialized?.initializedComponents, $app) &&
|
||||
refresh('all initialized')
|
||||
|
||||
// $: console.log('canInitializeAll', firstLoad, $initialized?.initializedComponents)
|
||||
function canInitializeAll(initialized: string[] | undefined, app: App) {
|
||||
@@ -53,8 +52,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: $recomputeAllContext.componentNumber =
|
||||
Object.values($runnableComponents).filter((x) => x.autoRefresh).length ?? 0
|
||||
|
||||
onMount(() => {
|
||||
if (appEditorContext) {
|
||||
@@ -112,7 +109,7 @@
|
||||
onRefresh(!inter, 'setInter ' + source)
|
||||
}
|
||||
|
||||
let refreshing: string[] = []
|
||||
let refreshing: string[] = $state([])
|
||||
function refresh(reason: string, excludeId: string | undefined = undefined) {
|
||||
let isFirstLoad = false
|
||||
if (!firstLoad && reason == 'all initialized') {
|
||||
@@ -182,6 +179,15 @@
|
||||
setInter: (n) => setInter(n, 'all context')
|
||||
}
|
||||
})
|
||||
run(() => {
|
||||
!firstLoad &&
|
||||
canInitializeAll($initialized?.initializedComponents, $app) &&
|
||||
refresh('all initialized')
|
||||
});
|
||||
run(() => {
|
||||
$recomputeAllContext.componentNumber =
|
||||
Object.values($runnableComponents).filter((x) => x.autoRefresh).length ?? 0
|
||||
});
|
||||
</script>
|
||||
|
||||
<RecomputeAllButton
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
|
||||
entries.sort((a, b) => (b.order ?? 0) - (a.order ?? 0) + a.name.localeCompare(b.name))
|
||||
|
||||
let search = ''
|
||||
let search = $state('')
|
||||
</script>
|
||||
|
||||
<div class="p-2">
|
||||
@@ -98,12 +98,15 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div slot="titleSlot" class="flex items-center">
|
||||
<svelte:component this={icon} size={18} />
|
||||
<span class="ml-1">
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
{#snippet titleSlot()}
|
||||
{@const SvelteComponent = icon}
|
||||
<div class="flex items-center">
|
||||
<SvelteComponent size={18} />
|
||||
<span class="ml-1">
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#if description}
|
||||
<div class="py-2 text-xs text-gray-500">{description}</div>
|
||||
{/if}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
let customcomponents: Array<{
|
||||
name: string
|
||||
path: string
|
||||
}> = []
|
||||
}> = $state([])
|
||||
|
||||
let loading: boolean = false
|
||||
let loading: boolean = $state(false)
|
||||
|
||||
async function getCustomComponents() {
|
||||
loading = true
|
||||
@@ -61,10 +61,10 @@
|
||||
nameField = ''
|
||||
}
|
||||
|
||||
let nameField: string = ''
|
||||
let reactVersion: string = '18.2.0'
|
||||
let files: FileList
|
||||
let useReact = true
|
||||
let nameField: string = $state('')
|
||||
let reactVersion: string = $state('18.2.0')
|
||||
let files: FileList = $state()
|
||||
let useReact = $state(true)
|
||||
|
||||
getCustomComponents()
|
||||
</script>
|
||||
|
||||
@@ -210,12 +210,13 @@
|
||||
toggleClasses=" !rounded-b-none !py-0
|
||||
{isOpen[prefix] ? '!bg-surface-secondary hover:!bg-surface-hover' : ''}"
|
||||
>
|
||||
<!-- @migration-task: migrate this slot by hand, `title` would shadow a prop on the parent component -->
|
||||
<svelte:fragment slot="titleSlot">
|
||||
<span class="font-normal text-xs">
|
||||
{group}
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
{#snippet titleSlot()}
|
||||
|
||||
<span class="font-normal text-xs">
|
||||
{group}
|
||||
</span>
|
||||
|
||||
{/snippet}
|
||||
<div class="flex justify-start items-center flex-wrap gap-x-4 gap-y-1 pt-3">
|
||||
{#each property[group] as p}
|
||||
{@const {
|
||||
|
||||
@@ -19,14 +19,14 @@
|
||||
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)
|
||||
|
||||
let themes: Array<{
|
||||
name: string
|
||||
path: string
|
||||
}> = []
|
||||
}> = $state([])
|
||||
|
||||
let loading: boolean = false
|
||||
let loading: boolean = $state(false)
|
||||
|
||||
async function getThemes() {
|
||||
loading = true
|
||||
@@ -62,8 +62,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
let nameField: string = ''
|
||||
let previewThemePath: string | undefined = undefined
|
||||
let nameField: string = $state('')
|
||||
let previewThemePath: string | undefined = $state(undefined)
|
||||
|
||||
onMount(() => {
|
||||
getThemes()
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
|
||||
const { app, initialized } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
$: unintitializedComponents = allItems($app.grid, $app.subgrids)
|
||||
let unintitializedComponents = $derived(allItems($app.grid, $app.subgrids)
|
||||
.map((x) => x.id)
|
||||
.filter((x) => !$initialized.initializedComponents?.includes(x))
|
||||
.sort()
|
||||
.sort())
|
||||
|
||||
$: subgridsErrors = Object.keys($app.subgrids ?? {})
|
||||
let subgridsErrors = $derived(Object.keys($app.subgrids ?? {})
|
||||
.map((x) => {
|
||||
const parentId = x.split('-')[0]
|
||||
const parent = findGridItem($app, parentId)
|
||||
@@ -39,7 +39,7 @@
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
.filter(Boolean))
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-8" style="all:none;">
|
||||
|
||||
+3
-4
@@ -66,7 +66,7 @@
|
||||
convertTo={hasConvertTo(fileUpload) ? fileUpload.convertTo : undefined}
|
||||
iconSize={24}
|
||||
class="text-sm py-4"
|
||||
on:change={({ detail }) => {
|
||||
onChange={(detail) => {
|
||||
componentInput = {
|
||||
...componentInput,
|
||||
type: 'static',
|
||||
@@ -74,10 +74,9 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<!-- @migration-task: migrate this slot by hand, `selected-title` is an invalid identifier -->
|
||||
<svelte:fragment slot="selected-title">
|
||||
{#snippet selected_title()}
|
||||
<!-- Removing the title when there is a selected file -->
|
||||
<span></span>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</FileInput>
|
||||
{/if}
|
||||
|
||||
@@ -43,29 +43,33 @@
|
||||
{/if}
|
||||
{#if (asset.kind === 'resource' && resourceDataCacheValue === undefined) || ducklakeNotFound || datatableNotFound}
|
||||
<Popover contentClasses="px-3 py-2">
|
||||
<svelte:fragment slot="trigger">
|
||||
<Button
|
||||
startIcon={{ icon: AlertTriangle }}
|
||||
variant="default"
|
||||
unifiedSize="md"
|
||||
btnClasses="text-red-500"
|
||||
iconOnly
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
<span class="text-sm">Not found</span>
|
||||
{#if ducklakeNotFound}
|
||||
<Button wrapperClasses="mt-1" href="/workspace_settings?tab=windmill_lfs">
|
||||
Go to Ducklake settings
|
||||
</Button>
|
||||
{:else if datatableNotFound}
|
||||
<Button wrapperClasses="mt-1" href="/workspace_settings?tab=windmill_data_tables">
|
||||
Go to Data Table settings
|
||||
</Button>
|
||||
{:else if asset.kind === 'resource' && resourceDataCacheValue === undefined}
|
||||
<Button wrapperClasses="mt-1" href="/resources">Go to Resources</Button>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
{#snippet trigger()}
|
||||
|
||||
<Button
|
||||
startIcon={{ icon: AlertTriangle }}
|
||||
variant="default"
|
||||
unifiedSize="md"
|
||||
btnClasses="text-red-500"
|
||||
iconOnly
|
||||
/>
|
||||
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
|
||||
<span class="text-sm">Not found</span>
|
||||
{#if ducklakeNotFound}
|
||||
<Button wrapperClasses="mt-1" href="/workspace_settings?tab=windmill_lfs">
|
||||
Go to Ducklake settings
|
||||
</Button>
|
||||
{:else if datatableNotFound}
|
||||
<Button wrapperClasses="mt-1" href="/workspace_settings?tab=windmill_data_tables">
|
||||
Go to Data Table settings
|
||||
</Button>
|
||||
{:else if asset.kind === 'resource' && resourceDataCacheValue === undefined}
|
||||
<Button wrapperClasses="mt-1" href="/resources">Go to Resources</Button>
|
||||
{/if}
|
||||
|
||||
{/snippet}
|
||||
</Popover>
|
||||
{:else if assetCanBeExplored(asset, { resource_type: resourceDataCacheValue })}
|
||||
<ExploreAssetButton
|
||||
|
||||
@@ -34,9 +34,11 @@
|
||||
{:else}
|
||||
<Tooltip>
|
||||
{@render badge()}
|
||||
<svelte:fragment slot="text">
|
||||
{accessType2} access to column "{columnName}"
|
||||
</svelte:fragment>
|
||||
{#snippet text()}
|
||||
|
||||
{accessType2} access to column "{columnName}"
|
||||
|
||||
{/snippet}
|
||||
</Tooltip>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -103,122 +103,132 @@
|
||||
bind:isOpen
|
||||
escapeBehavior="ignore"
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
<div
|
||||
class={twMerge(
|
||||
size === '3xs' ? 'h-[1.6rem]' : 'py-1.5',
|
||||
'text-xs flex items-center gap-1.5 px-2 rounded-md relative',
|
||||
'border',
|
||||
'bg-surface hover:bg-surface-hover active:bg-surface',
|
||||
'transition-all hover:text-primary backdrop-blur-md cursor-pointer'
|
||||
)}
|
||||
>
|
||||
{#snippet trigger()}
|
||||
|
||||
<div
|
||||
bind:this={blueBgDiv}
|
||||
class="absolute pointer-events-none bg-slate-300 dark:bg-[#576278] inset-0 rounded-md opacity-0"
|
||||
></div>
|
||||
<Pyramid size={size === '3xs' ? 13 : 16} class="z-10" />
|
||||
<span
|
||||
class={twMerge('z-10 font-normal', size === '3xs' ? 'text-3xs mt-[0.08rem]' : 'text-xs')}
|
||||
class={twMerge(
|
||||
size === '3xs' ? 'h-[1.6rem]' : 'py-1.5',
|
||||
'text-xs flex items-center gap-1.5 px-2 rounded-md relative',
|
||||
'border',
|
||||
'bg-surface hover:bg-surface-hover active:bg-surface',
|
||||
'transition-all hover:text-primary backdrop-blur-md cursor-pointer'
|
||||
)}
|
||||
>
|
||||
{noBtnText ? assets.length : pluralize(assets.length, 'asset')}
|
||||
</span>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
<ul class="divide-y rounded-md">
|
||||
{#each assets as asset}
|
||||
{@const ducklakeNotFound =
|
||||
asset.kind === 'ducklake' &&
|
||||
ducklakes.current &&
|
||||
!ducklakes.current.find((name) => name === asset.path.split('/')[0])}
|
||||
{@const datatableNotFound =
|
||||
asset.kind === 'datatable' &&
|
||||
datatables.current &&
|
||||
!datatables.current.find((name) => name === asset.path.split('/')[0])}
|
||||
<li
|
||||
class="text-sm px-3 h-12 flex gap-3 items-center"
|
||||
onmouseenter={() => onHoverLi?.(asset, 'enter')}
|
||||
onmouseleave={() => onHoverLi?.(asset, 'leave')}
|
||||
<div
|
||||
bind:this={blueBgDiv}
|
||||
class="absolute pointer-events-none bg-slate-300 dark:bg-[#576278] inset-0 rounded-md opacity-0"
|
||||
></div>
|
||||
<Pyramid size={size === '3xs' ? 13 : 16} class="z-10" />
|
||||
<span
|
||||
class={twMerge('z-10 font-normal', size === '3xs' ? 'text-3xs mt-[0.08rem]' : 'text-xs')}
|
||||
>
|
||||
<Popover
|
||||
contentClasses="py-2 px-4 flex flex-col gap-2"
|
||||
disablePopup={!!asset.access_type}
|
||||
{noBtnText ? assets.length : pluralize(assets.length, 'asset')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
|
||||
<ul class="divide-y rounded-md">
|
||||
{#each assets as asset}
|
||||
{@const ducklakeNotFound =
|
||||
asset.kind === 'ducklake' &&
|
||||
ducklakes.current &&
|
||||
!ducklakes.current.find((name) => name === asset.path.split('/')[0])}
|
||||
{@const datatableNotFound =
|
||||
asset.kind === 'datatable' &&
|
||||
datatables.current &&
|
||||
!datatables.current.find((name) => name === asset.path.split('/')[0])}
|
||||
<li
|
||||
class="text-sm px-3 h-12 flex gap-3 items-center"
|
||||
onmouseenter={() => onHoverLi?.(asset, 'enter')}
|
||||
onmouseleave={() => onHoverLi?.(asset, 'leave')}
|
||||
>
|
||||
<svelte:fragment slot="trigger">
|
||||
<div
|
||||
class={twMerge(
|
||||
'text-xs font-normal border text-primary w-10 p-1 text-center rounded-md',
|
||||
!asset.access_type ? 'text-orange-600 !border-orange-600' : '',
|
||||
!asset.access_type ? 'hover:bg-surface active:opacity-80' : ''
|
||||
)}
|
||||
>
|
||||
{formatAssetAccessType(getAccessType(asset)) ?? '?'}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
{#if !asset.access_type}
|
||||
<span class="text-sm text-primary leading-4">
|
||||
Could not infer automatically <br />
|
||||
<span class="text-xs">Please select manually </span>
|
||||
</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<ToggleButtonGroup
|
||||
allowEmpty
|
||||
bind:selected={asset.alt_access_type}
|
||||
class="max-w-fit"
|
||||
<Popover
|
||||
contentClasses="py-2 px-4 flex flex-col gap-2"
|
||||
disablePopup={!!asset.access_type}
|
||||
>
|
||||
{#snippet trigger()}
|
||||
|
||||
<div
|
||||
class={twMerge(
|
||||
'text-xs font-normal border text-primary w-10 p-1 text-center rounded-md',
|
||||
!asset.access_type ? 'text-orange-600 !border-orange-600' : '',
|
||||
!asset.access_type ? 'hover:bg-surface active:opacity-80' : ''
|
||||
)}
|
||||
>
|
||||
{#snippet children({ item })}
|
||||
<ToggleButton value="r" label="Read" {item} />
|
||||
<ToggleButton value="w" label="Write" {item} />
|
||||
<ToggleButton value="rw" label="Read/Write" {item} />
|
||||
{/snippet}
|
||||
</ToggleButtonGroup>
|
||||
{formatAssetAccessType(getAccessType(asset)) ?? '?'}
|
||||
</div>
|
||||
|
||||
{/snippet}
|
||||
{#snippet content()}
|
||||
|
||||
{#if !asset.access_type}
|
||||
<span class="text-sm text-primary leading-4">
|
||||
Could not infer automatically <br />
|
||||
<span class="text-xs">Please select manually </span>
|
||||
</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<ToggleButtonGroup
|
||||
allowEmpty
|
||||
bind:selected={asset.alt_access_type}
|
||||
class="max-w-fit"
|
||||
>
|
||||
{#snippet children({ item })}
|
||||
<ToggleButton value="r" label="Read" {item} />
|
||||
<ToggleButton value="w" label="Write" {item} />
|
||||
<ToggleButton value="rw" label="Read/Write" {item} />
|
||||
{/snippet}
|
||||
</ToggleButtonGroup>
|
||||
|
||||
<Tooltip2>
|
||||
This is used to determine if the asset should be displayed as an input or an
|
||||
output node in the flow editor
|
||||
</Tooltip2>
|
||||
</div>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
<div class="flex flex-col flex-1">
|
||||
<Tooltip class="select-none w-48 truncate" disablePopup={disableLiTooltip}>
|
||||
{asset.path}
|
||||
<svelte:fragment slot="text">
|
||||
<Tooltip2>
|
||||
This is used to determine if the asset should be displayed as an input or an
|
||||
output node in the flow editor
|
||||
</Tooltip2>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{/snippet}
|
||||
</Popover>
|
||||
<div class="flex flex-col flex-1">
|
||||
<Tooltip class="select-none w-48 truncate" disablePopup={disableLiTooltip}>
|
||||
{asset.path}
|
||||
</svelte:fragment>
|
||||
</Tooltip>
|
||||
<span class="text-xs text-primary select-none">
|
||||
{liSubtitle?.(asset) ??
|
||||
formatAssetKind({
|
||||
...asset,
|
||||
...(asset.kind === 'resource'
|
||||
? {
|
||||
metadata: {
|
||||
resource_type: resourceDataCache[asset.path.split('?table=')[0]]
|
||||
{#snippet text()}
|
||||
|
||||
{asset.path}
|
||||
|
||||
{/snippet}
|
||||
</Tooltip>
|
||||
<span class="text-xs text-primary select-none">
|
||||
{liSubtitle?.(asset) ??
|
||||
formatAssetKind({
|
||||
...asset,
|
||||
...(asset.kind === 'resource'
|
||||
? {
|
||||
metadata: {
|
||||
resource_type: resourceDataCache[asset.path.split('?table=')[0]]
|
||||
}
|
||||
}
|
||||
}
|
||||
: {})
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
: {})
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<AssetButtons
|
||||
onClick={() => (isOpen = false)}
|
||||
{asset}
|
||||
{resourceDataCache}
|
||||
{dbManagerDrawer}
|
||||
{resourceEditorDrawer}
|
||||
{s3FilePicker}
|
||||
{ducklakeNotFound}
|
||||
{datatableNotFound}
|
||||
/>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</svelte:fragment>
|
||||
<AssetButtons
|
||||
onClick={() => (isOpen = false)}
|
||||
{asset}
|
||||
{resourceDataCache}
|
||||
{dbManagerDrawer}
|
||||
{resourceEditorDrawer}
|
||||
{s3FilePicker}
|
||||
{ducklakeNotFound}
|
||||
{datatableNotFound}
|
||||
/>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
{/snippet}
|
||||
</Popover>
|
||||
<S3FilePicker bind:this={s3FilePicker} readOnlyMode />
|
||||
<ResourceEditorDrawer bind:this={resourceEditorDrawer} />
|
||||
|
||||
@@ -71,11 +71,13 @@
|
||||
<div class={twMerge('text-xs font-normal text-primary min-w-12 p-1 text-center rounded-md')}>
|
||||
{text}
|
||||
</div>
|
||||
<svelte:fragment slot="text">
|
||||
{#if tooltip}
|
||||
{tooltip}
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
{#snippet text()}
|
||||
|
||||
{#if tooltip}
|
||||
{tooltip}
|
||||
{/if}
|
||||
|
||||
{/snippet}
|
||||
</Tooltip>
|
||||
{/if}
|
||||
{/snippet}
|
||||
|
||||
@@ -323,7 +323,7 @@
|
||||
<span class="text-xs absolute font-semibold text-emphasis -top-4">Scope</span>
|
||||
<ToggleButtonGroup
|
||||
selected={scope ?? 'admins'}
|
||||
on:selected={({ detail }) => {
|
||||
onSelected={(detail) => {
|
||||
scope = detail === 'admins' ? undefined : detail
|
||||
}}
|
||||
>
|
||||
@@ -358,10 +358,10 @@
|
||||
date={after}
|
||||
placement="bottom-end"
|
||||
label="From"
|
||||
on:change={({ detail }) => {
|
||||
after = new Date(detail).toISOString()
|
||||
onchange={(value) => {
|
||||
after = new Date(value).toISOString()
|
||||
}}
|
||||
on:clear={() => {
|
||||
onclear={() => {
|
||||
after = undefined
|
||||
}}
|
||||
/>
|
||||
@@ -374,10 +374,10 @@
|
||||
bind:date={before}
|
||||
label="To"
|
||||
placement="bottom-end"
|
||||
on:change={({ detail }) => {
|
||||
before = new Date(detail).toISOString()
|
||||
onchange={(value) => {
|
||||
before = new Date(value).toISOString()
|
||||
}}
|
||||
on:clear={() => {
|
||||
onclear={() => {
|
||||
before = undefined
|
||||
}}
|
||||
/>
|
||||
@@ -445,7 +445,7 @@
|
||||
<div class="flex flex-row">
|
||||
<Button
|
||||
variant="subtle"
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
after = undefined
|
||||
before = undefined
|
||||
username = 'all'
|
||||
@@ -462,7 +462,7 @@
|
||||
</Button>
|
||||
<Button
|
||||
variant="subtle"
|
||||
on:click={downloadAuditLogsAsJson}
|
||||
onclick={downloadAuditLogsAsJson}
|
||||
unifiedSize="md"
|
||||
title="Downloads currently displayed logs only (up to {perPage} entries)"
|
||||
>
|
||||
@@ -473,7 +473,7 @@
|
||||
</Button>
|
||||
<Button
|
||||
variant="accent"
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
refresh++
|
||||
}}
|
||||
unifiedSize="md"
|
||||
|
||||
@@ -1,23 +1,37 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
import { tweened } from 'svelte/motion'
|
||||
import { cubicOut } from 'svelte/easing'
|
||||
|
||||
export let color = 'blue'
|
||||
export let progress = 0
|
||||
export let ended: boolean = false
|
||||
interface Props {
|
||||
color?: string;
|
||||
progress?: number;
|
||||
ended?: boolean;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
color = 'blue',
|
||||
progress = 0,
|
||||
ended = false,
|
||||
children
|
||||
}: Props = $props();
|
||||
|
||||
const tweenedProgress = tweened(progress, {
|
||||
duration: 400,
|
||||
easing: cubicOut
|
||||
})
|
||||
|
||||
$: tweenedProgress.set(progress)
|
||||
run(() => {
|
||||
tweenedProgress.set(progress)
|
||||
});
|
||||
</script>
|
||||
|
||||
{#key color}
|
||||
<div class="flex flex-row gap-1 items-center justify-between w-full">
|
||||
{#if ended}
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
{:else}
|
||||
<div class="progress-bar">
|
||||
<div
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<script lang="ts">
|
||||
export let notificationCount = 0
|
||||
export let notificationLimit: number | undefined = undefined
|
||||
interface Props {
|
||||
notificationCount?: number;
|
||||
notificationLimit?: number | undefined;
|
||||
}
|
||||
|
||||
let { notificationCount = 0, notificationLimit = undefined }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if notificationCount > 0}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user