migrate ToggleButtonGroup to melt

This commit is contained in:
Guilhem
2025-02-18 13:01:55 +00:00
parent 4c0177c255
commit 5f696f12f9
69 changed files with 810 additions and 578 deletions
+4 -1
View File
@@ -92,12 +92,13 @@
{/if}
<span class="text-xs mb-1 pt-2 leading-6">Role</span>
<ToggleButtonGroup bind:selected class="mb-4">
<ToggleButtonGroup bind:selected class="mb-4" let:item>
<ToggleButton
value="operator"
size="sm"
label="Operator"
tooltip="An operator can only execute and view scripts/flows/apps from your workspace, and only those that he has visibility on."
{item}
/>
<ToggleButton
position="center"
@@ -105,6 +106,7 @@
size="sm"
label="Developer"
tooltip="A Developer can execute and view scripts/flows/apps, but they can also create new ones and edit those they are allowed to by their path (either u/ or Writer or Admin of their folder found at /f)."
{item}
/>
<ToggleButton
position="right"
@@ -112,6 +114,7 @@
size="sm"
label="Admin"
tooltip="An admin has full control over a specific Windmill workspace, including the ability to manage users, edit entities, and control permissions within the workspace."
{item}
/>
</ToggleButtonGroup>
<Button
+2 -1
View File
@@ -759,9 +759,10 @@
value = { label: oneOfSelected }
redraw += 1
}}
let:item
>
{#each oneOf as obj}
<ToggleButton value={obj.title} label={obj.title} />
<ToggleButton value={obj.title} label={obj.title} {item} />
{/each}
</ToggleButtonGroup>
{#if oneOfSelected}
@@ -52,9 +52,15 @@
<label class="block pb-2">
<div class="flex gap-2 items-end">
<div>
<ToggleButtonGroup bind:selected={value['custom']}>
<ToggleButton value={false} label={'Org'} />
<ToggleButton value={true} label="Custom" />
<ToggleButtonGroup
selected={value['custom'] ? 'custom' : 'org'}
on:selected={({ detail }) => {
value['custom'] = detail === 'custom'
}}
let:item
>
<ToggleButton value="org" label={'Org'} {item} />
<ToggleButton value="custom" label="Custom" {item} />
</ToggleButtonGroup>
</div>
<div class="grow">
@@ -264,28 +264,23 @@
on:selected={(e) => dispatch('dirty')}
bind:selected={config.integration.type}
class="mb-4 mt-2"
let:item
>
<ToggleButton
value="dryrun"
size="sm"
label="Dry run"
tooltip="See autoscaling events but not actual scaling actions will be performed"
{item}
/>
<ToggleButton
value="script"
size="sm"
label="Custom script"
tooltip="Run a custom script to scale your worker group"
{item}
/>
<ToggleButton position="center" disabled value="ecs" size="sm" label="ECS (soon)" />
<ToggleButton position="right" disabled value="nomad" size="sm" label="Nomad (soon)" />
<ToggleButton
position="right"
disabled
value="kubernetes"
size="sm"
label="Kubernetes (soon)"
/>
<ToggleButton disabled value="ecs" label="ECS (soon)" {item} />
<ToggleButton disabled value="nomad" label="Nomad (soon)" {item} />
<ToggleButton disabled value="kubernetes" label="Kubernetes (soon)" {item} />
</ToggleButtonGroup>
{#if config.integration.type === 'script'}
@@ -347,12 +342,12 @@
</div>
{/if}
{:else}
<ToggleButtonGroup selected={'script'} disabled class="mb-4 mt-2">
<ToggleButton value="dryrun" size="sm" label="Dry run" />
<ToggleButton value="script" size="sm" label="Custom script" />
<ToggleButton position="center" value="ecs" size="sm" label="ECS (soon)" />
<ToggleButton position="right" value="nomad" size="sm" label="Nomad (soon)" />
<ToggleButton position="right" value="kubernetes" size="sm" label="Kubernetes (soon)" />
<ToggleButtonGroup selected={'script'} disabled class="mb-4 mt-2" let:item>
<ToggleButton value="dryrun" label="Dry run" {item} />
<ToggleButton value="script" label="Custom script" {item} />
<ToggleButton value="ecs" label="ECS (soon)" {item} />
<ToggleButton value="nomad" label="Nomad (soon)" {item} />
<ToggleButton value="kubernetes" label="Kubernetes (soon)" {item} />
</ToggleButtonGroup>
<label>
@@ -157,15 +157,23 @@
<div class="flex flex-col gap-2">
<div class="flex gap-2 flex-wrap sticky top-0 left-0 right-0 bg-surface">
<div class="p-2">
<ToggleButtonGroup bind:selected={searchKind} class="h-10 ">
<ToggleButton small light value="all" label={'All' + counts.all} />
<ToggleButton small light value="scripts" icon={Code2} label={'Scripts' + counts.scripts} />
<ToggleButtonGroup bind:selected={searchKind} class="h-10 " let:item>
<ToggleButton small light value="all" label={'All' + counts.all} {item} />
<ToggleButton
small
light
value="scripts"
icon={Code2}
label={'Scripts' + counts.scripts}
{item}
/>
<ToggleButton
small
light
value="resources"
icon={Boxes}
label={'Resources' + counts.resources}
{item}
/>
<ToggleButton
small
@@ -174,6 +182,7 @@
label={'Flows' + counts.flows}
icon={FlowIcon}
selectedColor="#14b8a6"
{item}
/>
<ToggleButton
small
@@ -182,6 +191,7 @@
label={'Apps' + counts.apps}
icon={LayoutDashboard}
selectedColor="#fb923c"
{item}
/>
</ToggleButtonGroup>
</div>
@@ -86,9 +86,16 @@
</Button>
</svelte:fragment>
{#if dbSchema.lang !== 'graphql' && (dbSchema.schema?.public || dbSchema.schema?.PUBLIC || dbSchema.schema?.dbo)}
<ToggleButtonGroup class="mb-4" bind:selected={dbSchema.publicOnly}>
<ToggleButton value={true} label={dbSchema.schema.dbo ? 'Dbo' : 'Public'} />
<ToggleButton value={false} label="All" />
<ToggleButtonGroup
class="mb-4"
selected={dbSchema.publicOnly ? 'dbo' : 'all'}
on:selected={({ detail }) => {
dbSchema.publicOnly = detail === 'dbo'
}}
let:item
>
<ToggleButton value="dbo" label={dbSchema.schema.dbo ? 'Dbo' : 'Public'} {item} />
<ToggleButton value="all" label="All" {item} />
</ToggleButtonGroup>
{/if}
{#if dbSchema.lang === 'graphql'}
@@ -146,9 +146,9 @@
</Button>
{/if}
<!-- <div>
<ToggleButtonGroup bind:selected={format}>
<ToggleButton light small value={'local'} label="local" />
<ToggleButton light small value={'utc'} label="utc" />
<ToggleButtonGroup bind:selected={format} let:item>
<ToggleButton light small value={'local'} label="local" {item} />
<ToggleButton light small value={'utc'} label="utc" {item} />
</ToggleButtonGroup>
</div> -->
</div>
@@ -379,10 +379,11 @@
on:selected={(ev) => {
globalForceJson = ev.detail === 'json'
}}
let:item
>
<ToggleButton class="px-1.5" value="pretty" label="Pretty" icon={Highlighter} />
<ToggleButton class="px-1.5" value="pretty" label="Pretty" icon={Highlighter} {item} />
<ToggleButton class="px-1.5" value="json" label="JSON" icon={Braces} />
<ToggleButton class="px-1.5" value="json" label="JSON" icon={Braces} {item} />
</ToggleButtonGroup>
</div>
{/if}
@@ -412,16 +413,23 @@
{#if !hideAsJson && !['json', 's3object'].includes(resultKind ?? '') && typeof result === 'object'}<ToggleButtonGroup
class="h-6"
selected={forceJson ? 'json' : resultKind?.startsWith('table-') ? 'table' : 'pretty'}
let:item
on:selected={(ev) => {
forceJson = ev.detail === 'json'
}}
>
{#if ['table-col', 'table-row', 'table-row-object'].includes(resultKind ?? '')}
<ToggleButton class="px-1.5" value="table" label="Table" icon={Table2} />
<ToggleButton class="px-1.5" value="table" label="Table" icon={Table2} {item} />
{:else}
<ToggleButton class="px-1.5" value="pretty" label="Pretty" icon={Highlighter} />
<ToggleButton
class="px-1.5"
value="pretty"
label="Pretty"
icon={Highlighter}
{item}
/>
{/if}
<ToggleButton class="px-1.5" value="json" label="JSON" icon={Braces} />
<ToggleButton class="px-1.5" value="json" label="JSON" icon={Braces} {item} />
</ToggleButtonGroup>
{/if}
</div>
@@ -468,6 +468,7 @@
<ToggleButtonGroup
tabListClass="flex-wrap"
class="h-auto"
let:item
bind:selected
on:selected={(e) => {
const isS3 = e.detail == 'S3'
@@ -548,7 +549,7 @@
}}
>
{#each [['String', 'string'], ['Number', 'number'], ['Integer', 'integer'], ['Object', 'object'], ['OneOf', 'oneOf'], ['Array', 'array'], ['Boolean', 'boolean'], ['S3 Object', 'S3']] as x}
<ToggleButton value={x[1]} label={x[0]} />
<ToggleButton value={x[1]} label={x[0]} {item} />
{/each}
</ToggleButtonGroup>
</Label>
@@ -184,9 +184,13 @@
</Alert>
<div class="flex items-center gap-1">
<div>
<ToggleButtonGroup bind:selected={ownerKind} on:selected={() => (ownerItem = '')}>
<ToggleButton value="user" size="xs" label="User" />
<ToggleButton value="group" size="xs" label="Group" />
<ToggleButtonGroup
bind:selected={ownerKind}
on:selected={() => (ownerItem = '')}
let:item
>
<ToggleButton value="user" size="xs" label="User" {item} />
<ToggleButton value="group" size="xs" label="Group" {item} />
</ToggleButtonGroup>
</div>
@@ -150,6 +150,7 @@
<div>
<ToggleButtonGroup
selected={role}
let:item
on:selected={async (e) => {
const role = e.detail
// const wasInGroup = (group?.members ?? []).includes(group)
@@ -215,6 +216,7 @@
size="xs"
label="Member"
tooltip="A Member of a group can see everything the group can see, write to everything the group can write, and generally act on behalf of the group"
{item}
/>
<ToggleButton
position="right"
@@ -222,6 +224,7 @@
size="xs"
label="Admin"
tooltip="An admin of a group is a member of a group that can also add and remove members to the group, or make them admin."
{item}
/>
{#if role === 'manager'}
<ToggleButton
@@ -230,6 +233,7 @@
label="Manager"
tooltip="A manager of a group can manage the group, adding and removing users and
change their roles. Being a manager does not make you a member"
{item}
/>
{/if}
</ToggleButtonGroup>
@@ -358,6 +358,7 @@
<div>
<ToggleButtonGroup
selected={propertyType}
let:item
on:selected={(e) => {
if (e.detail == propertyType) return
const staticTemplate = isStaticTemplate(inputCat)
@@ -417,9 +418,10 @@
value="static"
size="xs2"
label={'${}'}
{item}
/>
{:else}
<ToggleButton small label="Static" value="static" />
<ToggleButton small label="Static" value="static" {item} />
{/if}
{#if codeInjectionDetected && propertyType == 'static'}
@@ -441,6 +443,7 @@
tooltip="JavaScript expression ('flow_input' or 'results')."
value="javascript"
icon={FunctionSquare}
{item}
/>
{/if}
</ToggleButtonGroup>
@@ -183,12 +183,13 @@
</span>
{/if}
</label>
<ToggleButtonGroup bind:selected={$values[setting.key]}>
<ToggleButtonGroup bind:selected={$values[setting.key]} let:item={toggleButton}>
{#each setting.select_items ?? [] as item}
<ToggleButton
value={item.value ?? item.label}
label={item.label}
tooltip={item.tooltip}
item={toggleButton}
/>
{/each}
</ToggleButtonGroup>
@@ -80,12 +80,13 @@
bind:value={email}
class="mr-4"
/>
<ToggleButtonGroup bind:selected>
<ToggleButtonGroup bind:selected let:item>
<ToggleButton
value="operator"
size="sm"
label="Operator"
tooltip="An operator can only execute and view scripts/flows/apps from your workspace, and only those that he has visibility on."
{item}
/>
<ToggleButton
@@ -94,6 +95,7 @@
size="sm"
label="Developer"
tooltip="A Developer can execute and view scripts/flows/apps, but they can also create new ones and edit those they are allowed to by their path (either u/ or Writer or Admin of their folder found at /f)."
{item}
/>
<ToggleButton
@@ -102,6 +104,7 @@
size="sm"
label="Admin"
tooltip="An admin has full control over a specific Windmill workspace, including the ability to manage users, edit entities, and control permissions within the workspace."
{item}
/>
</ToggleButtonGroup>
<Button
@@ -52,9 +52,15 @@
<label class="block pb-2">
<div class="flex gap-2 items-end">
<div>
<ToggleButtonGroup bind:selected={value['custom']}>
<ToggleButton value={false} label={'Org'} />
<ToggleButton value={true} label="Custom" />
<ToggleButtonGroup
selected={value['custom'] ? 'custom' : 'org'}
on:selected={({ detail }) => {
value['custom'] = detail === 'custom'
}}
let:item
>
<ToggleButton value="org" label={'Org'} {item} />
<ToggleButton value="custom" label="Custom" {item} />
</ToggleButtonGroup>
</div>
<div class="grow">
+3
View File
@@ -367,6 +367,7 @@
}
}
}}
let:item
>
<ToggleButton
icon={User}
@@ -376,6 +377,7 @@
value="user"
position="left"
label="User"
{item}
/>
<!-- <ToggleButton light size="xs" value="group" position="center">Group</ToggleButton> -->
<ToggleButton
@@ -386,6 +388,7 @@
value="folder"
position="right"
label="Folder"
{item}
/>
</ToggleButtonGroup>
</div>
@@ -335,27 +335,30 @@
{#if linkedSecretCandidates?.includes(argName)}
<div>
<ToggleButtonGroup
selected={linkedSecret == argName}
selected={linkedSecret == argName ? 'secret' : 'inlined'}
on:selected={(e) => {
if (e.detail) {
if (e.detail === 'secret') {
linkedSecret = argName
} else if (linkedSecret == argName) {
linkedSecret = undefined
}
}}
let:item
>
<ToggleButton
value={false}
value="inlined"
size="sm"
label="Inlined"
tooltip="The value is inlined in the resource and thus has no special treatment."
{item}
/>
<ToggleButton
position="right"
value={true}
value="secret"
size="sm"
label="Secret"
tooltip="The value will be stored in a newly created linked secret variable at the same path. That variable can be permissioned differently, will be treated as a secret the UI, operators will not be able to load it and every access will generate a corresponding audit log."
{item}
/>
</ToggleButtonGroup>
</div>{/if}</svelte:fragment
@@ -902,6 +902,7 @@
script.kind = detail
initContent(script.language, detail, template)
}}
let:item
>
{#each scriptKindOptions as { value, title, desc, documentationLink, Icon }}
<ToggleButton
@@ -911,6 +912,7 @@
{documentationLink}
icon={Icon}
showTooltipIcon={Boolean(desc)}
{item}
/>
{/each}
</ToggleButtonGroup>
@@ -50,7 +50,7 @@
items = (
await ScriptService.listScripts({
workspace: $workspaceStore!,
kinds: kinds.join(','),
kinds: kinds.join(',')
})
).map((script) => ({
value: script.path,
@@ -85,9 +85,9 @@
<div class="flex flex-row items-center gap-4 w-full mt-2">
{#if options.length > 1}
<div>
<ToggleButtonGroup bind:selected={itemKind}>
<ToggleButtonGroup bind:selected={itemKind} let:item>
{#each options as [label, value, icon, selectedColor]}
<ToggleButton {icon} {disabled} {value} {label} {selectedColor} />
<ToggleButton {icon} {disabled} {value} {label} {selectedColor} {item} />
{/each}
</ToggleButtonGroup>
</div>
@@ -190,9 +190,15 @@
{#if selectedVersionIndex !== undefined && versions?.slice(selectedVersionIndex + 1).length}
<div class="p-2 flex flex-row items-center gap-2 h-8">
<div class="w-min">
<ToggleButtonGroup bind:selected={showDiff}>
<ToggleButton light small value={false} label="Code" icon={Code} />
<ToggleButton light small value={true} label="Diff" icon={Diff} />
<ToggleButtonGroup
selected={showDiff ? 'diff' : 'code'}
let:item
on:selected={({ detail }) => {
showDiff = detail === 'diff'
}}
>
<ToggleButton light small value="code" label="Code" icon={Code} {item} />
<ToggleButton light small value="diff" label="Diff" icon={Diff} {item} />
</ToggleButtonGroup>
</div>
+10 -5
View File
@@ -122,9 +122,13 @@
{#if own}
<div class="flex flex-row flex-wrap gap-2 items-center">
<div>
<ToggleButtonGroup bind:selected={ownerKind} on:selected={() => (owner = '')}>
<ToggleButton value="user" size="xs" label="User" />
<ToggleButton value="group" size="xs" label="Group" />
<ToggleButtonGroup
bind:selected={ownerKind}
on:selected={() => (owner = '')}
let:item
>
<ToggleButton value="user" size="xs" label="User" {item} />
<ToggleButton value="group" size="xs" label="Group" {item} />
</ToggleButtonGroup>
</div>
{#key ownerKind}
@@ -162,9 +166,10 @@
}
loadAcls()
}}
let:item
>
<ToggleButton value="viewer" size="xs" label="Viewer" />
<ToggleButton value="writer" size="xs" label="Writer" />
<ToggleButton value="viewer" size="xs" label="Viewer" {item} />
<ToggleButton value="writer" size="xs" label="Writer" {item} />
</ToggleButtonGroup>
</div>
{:else}{write}{/if}</td
@@ -133,9 +133,16 @@
disableVariablePicker = undefined
}
}}
let:item
>
{#each FIELD_SETTINGS as x}
<ToggleButton value={x[1]} label={x[0]} tooltip={x[2]} showTooltipIcon={Boolean(x[2])} />
<ToggleButton
value={x[1]}
label={x[0]}
tooltip={x[2]}
showTooltipIcon={Boolean(x[2])}
{item}
/>
{/each}
</ToggleButtonGroup>
{/if}
@@ -292,15 +292,22 @@
sendUserToast('User updated')
listUsers(activeOnly)
}}
let:item
>
<ToggleButton value={'user'} size="xs" label="User" />
<ToggleButton value={'user'} size="xs" label="User" {item} />
<ToggleButton
value={'devops'}
size="xs"
label="Devops"
tooltip="Devops is a role that grants visibilty similar to that of a super admin, but without giving all rights. For example devops users can see service logs and crtical alerts. You can think of it as a 'readonly' super admin"
{item}
/>
<ToggleButton
value={'super_admin'}
size="xs"
label="Superadmin"
{item}
/>
<ToggleButton value={'super_admin'} size="xs" label="Superadmin" />
</ToggleButtonGroup>
</td>
<td>
@@ -7,8 +7,8 @@
</script>
<div class="max-w-min">
<ToggleButtonGroup bind:selected>
<ToggleButton value="hub" icon={WindmillIcon} label="Hub" />
<ToggleButton value="workspace" icon={Building} label="Workspace" />
<ToggleButtonGroup bind:selected let:item>
<ToggleButton value="hub" icon={WindmillIcon} label="Hub" {item} />
<ToggleButton value="workspace" icon={Building} label="Workspace" {item} />
</ToggleButtonGroup>
</div>
@@ -7,9 +7,9 @@
</script>
<div class="max-w-min">
<ToggleButtonGroup id="flow-editor-flow-providers" bind:selected>
<ToggleButton value="all" label="All" light small />
<ToggleButton value="hub" icon={WindmillIcon2} label="Hub" light small />
<ToggleButton value="workspace" icon={Building} label="Workspace" light small />
<ToggleButtonGroup id="flow-editor-flow-providers" bind:selected let:item>
<ToggleButton value="all" label="All" light small {item} />
<ToggleButton value="hub" icon={WindmillIcon2} label="Hub" light small {item} />
<ToggleButton value="workspace" icon={Building} label="Workspace" light small {item} />
</ToggleButtonGroup>
</div>
@@ -183,10 +183,10 @@
>{/if}{/if}
</div>
<div class="flex flex-col gap-2">
<ToggleButtonGroup bind:selected={editorKind}>
<ToggleButton value="plain" label="Plain" />
<ToggleButton value="json" label="Json" />
<ToggleButton value="yaml" label="YAML" />
<ToggleButtonGroup bind:selected={editorKind} let:item>
<ToggleButton value="plain" label="Plain" {item} />
<ToggleButton value="json" label="Json" {item} />
<ToggleButton value="yaml" label="YAML" {item} />
</ToggleButtonGroup>
{#if editorKind == 'plain'}
<textarea
@@ -263,13 +263,21 @@
}
}}
class="mb-4"
let:item
>
<ToggleButton position="left" value="normal" size="sm" label="Any jobs within worker tags" />
<ToggleButton
position="left"
value="normal"
size="sm"
label="Any jobs within worker tags"
{item}
/>
<ToggleButton
position="dedicated"
value="dedicated"
size="sm"
label="Dedicated to a script/flow"
{item}
/>
</ToggleButtonGroup>
{#if selected == 'normal'}
@@ -85,7 +85,6 @@
import { getDeleteInput } from '../components/display/dbtable/queries/delete'
import { collectOneOfFields } from './appUtils'
import Summary from '$lib/components/Summary.svelte'
import ToggleEnable from '$lib/components/common/toggleButton-v2/ToggleEnable.svelte'
import HideButton from './settingsPanel/HideButton.svelte'
import DeployOverrideConfirmationModal from '$lib/components/common/confirmationModal/DeployOverrideConfirmationModal.svelte'
import { computeS3FileInputPolicy, computeWorkspaceS3FileInputPolicy } from './appUtilsS3'
@@ -1547,70 +1546,92 @@
/>
{#if $app}
<ToggleButtonGroup class="h-[30px]" bind:selected={$app.fullscreen}>
<ToggleButtonGroup
class="h-[30px]"
selected={$app.fullscreen ? 'true' : 'false'}
on:selected={({ detail }) => {
$app.fullscreen = detail === 'true'
}}
let:item
>
<ToggleButton
icon={AlignHorizontalSpaceAround}
value={false}
value={'false'}
tooltip="The max width is 1168px and the content stay centered instead of taking the full page width"
iconProps={{ size: 16 }}
{item}
/>
<ToggleButton
tooltip="The width is of the app if the full width of its container"
icon={Expand}
value={true}
value={'true'}
iconProps={{ size: 16 }}
{item}
/>
</ToggleButtonGroup>
{/if}
{#if $app}
<ToggleButtonGroup
class="h-[30px]"
on:selected={(e) => {
setTheme(e.detail)
on:selected={({ detail }) => {
console.log('dbg detail', detail)
const theme = detail === 'dark' ? true : detail === 'sun' ? false : undefined
console.log('dbg settheme', theme)
setTheme(theme)
}}
bind:selected={$app.darkMode}
selected={$app.darkMode === undefined ? 'auto' : $app.darkMode ? 'dark' : 'sun'}
let:item
>
<ToggleButton
icon={SunMoon}
value={undefined}
value={'auto'}
tooltip="The app mode between dark/light is automatic"
iconProps={{ size: 16 }}
{item}
/>
<ToggleButton
icon={Sun}
value={false}
value={'sun'}
tooltip="Force light mode"
iconProps={{ size: 16 }}
{item}
/>
<ToggleButton
tooltip="Force dark mode"
icon={Moon}
value={true}
value={'dark'}
iconProps={{ size: 16 }}
{item}
/>
</ToggleButtonGroup>
{/if}
<div class="flex flex-row gap-2">
<ToggleButtonGroup class="h-[30px]" bind:selected={$breakpoint}>
<ToggleButtonGroup class="h-[30px]" bind:selected={$breakpoint} let:item>
<ToggleButton
tooltip="Computer View"
icon={Laptop2}
value={'lg'}
iconProps={{ size: 16 }}
{item}
/>
<ToggleButton
tooltip="Mobile View"
icon={Smartphone}
value={'sm'}
iconProps={{ size: 16 }}
{item}
/>
{#if $breakpoint === 'sm'}
<ToggleEnable
tooltip="Desktop view is enabled by default. Enable this to customize the layout of the components for the mobile view"
label="Enable mobile view for smaller screens"
<Toggle
size="xs"
options={{
right: 'Enable mobile view for smaller screens',
rightTooltip:
'Desktop view is enabled by default. Enable this to customize the layout of the components for the mobile view'
}}
textClass="text-2xs whitespace-nowrap white !w-full"
bind:checked={$app.mobileViewOnSmallerScreens}
iconProps={{ size: 16 }}
iconOnly={false}
class="flex flex-row px-2 items-center"
/>
{/if}
</ToggleButtonGroup>
@@ -18,6 +18,7 @@
jobsById.set({})
jobs.set([])
}}
let:item
>
<ToggleButton
label="Editor"
@@ -26,6 +27,7 @@
disabled={loading}
iconProps={{ size: 16 }}
class="gap-2"
{item}
/>
<ToggleButton
label="Preview"
@@ -36,5 +38,6 @@
id="app-editor-preview-toggle"
iconProps={{ size: 16 }}
class="gap-2"
{item}
/>
</ToggleButtonGroup>
@@ -124,27 +124,31 @@
{/if}
{#if quickStyleProperties?.length}
<ToggleButtonGroup
bind:selected={richEditorOpen}
on:selected={() => {
selected={richEditorOpen ? 'true' : 'false'}
on:selected={({ detail }) => {
richEditorOpen = detail === 'true'
if (richEditorOpen !== isQuickMenuOpen) {
toggleQuickMenu()
richEditorOpen = isQuickMenuOpen
}
}}
let:item
>
<ToggleButton
small
light
value={false}
value={'false'}
icon={Code}
tooltip="Edit the CSS directly"
{item}
/>
<ToggleButton
small
light
value={true}
value={'true'}
icon={Paintbrush2}
tooltip="Open the rich editor to style the component with a visual interface"
{item}
/>
</ToggleButtonGroup>
{/if}
@@ -26,10 +26,11 @@
noWFull
on:selected={() => ($app = $app)}
bind:selected={component.horizontalAlignment}
let:item
>
<ToggleButton value="left" icon={AlignStartVertical} />
<ToggleButton value="center" icon={AlignCenterVertical} />
<ToggleButton value="right" icon={AlignEndVertical} />
<ToggleButton value="left" icon={AlignStartVertical} {item} />
<ToggleButton value="center" icon={AlignCenterVertical} {item} />
<ToggleButton value="right" icon={AlignEndVertical} {item} />
</ToggleButtonGroup>
{/if}
{#if component.type !== 'formcomponent' && component.verticalAlignment}
@@ -37,10 +38,11 @@
noWFull
on:selected={() => ($app = $app)}
bind:selected={component.verticalAlignment}
let:item
>
<ToggleButton value="top" icon={AlignStartHorizontal} />
<ToggleButton value="center" icon={AlignCenterHorizontal} />
<ToggleButton value="bottom" icon={AlignEndHorizontal} />
<ToggleButton value="top" icon={AlignStartHorizontal} {item} />
<ToggleButton value="center" icon={AlignCenterHorizontal} {item} />
<ToggleButton value="bottom" icon={AlignEndHorizontal} {item} />
</ToggleButtonGroup>
{/if}
</div>
@@ -56,6 +56,7 @@
}}
noWFull
bind:selected={componentInput.type}
let:item
>
{#if componentInput.fieldType === 'template'}
{#if componentInput.type == 'template'}
@@ -65,6 +66,7 @@
disabled={disableStatic}
icon={CurlyBraces}
label="Template"
{item}
/>
{:else}
<ToggleButton
@@ -73,6 +75,7 @@
disabled={disableStatic}
icon={CurlyBraces}
label="Template"
{item}
/>
{/if}
{:else if componentInput.noStatic !== true}
@@ -82,6 +85,7 @@
disabled={disableStatic}
iconOnly={clientWidth < iconOnlyThreshold}
icon={Pen}
{item}
/>
{/if}
{#if componentInput.type == 'connected'}
@@ -90,6 +94,7 @@
icon={Plug2}
iconOnly={clientWidth < iconOnlyThreshold}
label="Connect"
{item}
/>
{/if}
<ToggleButton
@@ -97,6 +102,7 @@
icon={FunctionSquare}
iconOnly={clientWidth < iconOnlyThreshold}
label="Eval"
{item}
/>
<ToggleButton
@@ -104,6 +110,7 @@
icon={Code}
iconOnly={clientWidth < iconOnlyThreshold}
label="Compute"
{item}
id="data-source-compute"
/>
</ToggleButtonGroup>
@@ -397,16 +397,19 @@
on:selected={() => {
handleSelected(selected)
}}
let:item
>
<ToggleButton
value="ui-editor"
label="UI Editor"
tooltip="Use the UI editor to quickly create a plotly chart."
{item}
/>
<ToggleButton
value="json"
label="JSON"
tooltip="Switch to JSON mode for complete customization of Plotly settings."
{item}
/>
</ToggleButtonGroup>
</div>
@@ -137,21 +137,28 @@
componentInput['expr'] = JSON.stringify(JSON.parse(componentInput['expr']), null, 4)
}
}}
let:item
>
<ToggleButton value="static" icon={Pen} iconOnly tooltip="Static" />
<ToggleButton value="static" icon={Pen} iconOnly tooltip="Static" {item} />
{#if userInputEnabled}
<ToggleButton value="user" icon={User} iconOnly tooltip="User Input" />
<ToggleButton value="user" icon={User} iconOnly tooltip="User Input" {item} />
{/if}
{#if fileUpload}
<ToggleButton value="upload" icon={Upload} iconOnly tooltip="Upload" />
<ToggleButton value="upload" icon={Upload} iconOnly tooltip="Upload" {item} />
{/if}
{#if componentInput?.type === 'connected'}
<ToggleButton value="connected" icon={Plug2} iconOnly tooltip="Connect" />
<ToggleButton value="connected" icon={Plug2} iconOnly tooltip="Connect" {item} />
{/if}
{#if componentInput?.type === 'eval'}
<ToggleButton value="eval" icon={FunctionSquare} iconOnly tooltip="Eval Legacy" />
<ToggleButton
value="eval"
icon={FunctionSquare}
iconOnly
tooltip="Eval Legacy"
{item}
/>
{/if}
<ToggleButton value="evalv2" icon={FunctionSquare} iconOnly tooltip="Eval" />
<ToggleButton value="evalv2" icon={FunctionSquare} iconOnly tooltip="Eval" {item} />
</ToggleButtonGroup>
<ConnectionButton {closeConnection} {openConnection} isOpen={!!$connectingInput.opened} />
{/if}
@@ -1,13 +1,10 @@
<script lang="ts">
import { getContext } from 'svelte'
import { Tab } from '@rgossiaux/svelte-headlessui'
import type { ToggleButtonContext } from './ToggleButtonGroup.svelte'
import { twMerge } from 'tailwind-merge'
import Tooltip from '$lib/components/meltComponents/Tooltip.svelte'
import { melt } from '@melt-ui/svelte'
import { Info } from 'lucide-svelte'
export let value: any
export let value: string | undefined = undefined
export let label: string | undefined = undefined
export let iconOnly: boolean = false
export let tooltip: string | undefined = undefined
@@ -20,36 +17,40 @@
export let showTooltipIcon: boolean = false
export let documentationLink: string | undefined = undefined
export let id: string | undefined = undefined
const { select, selected } = getContext<ToggleButtonContext>('ToggleButtonGroup')
export let item: any | undefined = undefined
</script>
<Tooltip
class={twMerge('flex', disabled ? 'cursor-not-allowed' : 'cursor-pointer')}
disablePopup={tooltip === undefined}
disappearTimeout={0}
{documentationLink}
>
<div {id} class="flex">
<Tab
{#if item}
<Tooltip
class={twMerge('flex', disabled ? 'cursor-not-allowed' : 'cursor-pointer')}
disablePopup={tooltip === undefined}
disappearTimeout={0}
{documentationLink}
>
<button
{id}
{disabled}
class={twMerge(
' rounded-md transition-all text-xs flex gap-1 flex-row items-center',
'group rounded-md transition-all text-xs flex gap-1 flex-row items-center',
small ? 'px-1.5 py-0.5 text-2xs' : 'px-2 py-1',
light ? 'font-medium' : '',
$selected === value
? 'bg-surface shadow-md'
: 'bg-surface-secondary hover:bg-surface-hover',
'data-[state=on]:bg-surface data-[state=on]:shadow-md',
'bg-surface-secondary hover:bg-surface-hover',
$$props.class
)}
on:click={() => select(value)}
use:melt={$item(value)}
style={`--selected-color: ${selectedColor}`}
>
{#if icon}
<svelte:component
this={icon}
size={small ? 12 : 14}
color={$selected === value ? selectedColor : '#9CA3AF'}
{...iconProps}
class={twMerge(
'text-gray-400',
'group-data-[state=on]:text-[var(--selected-color)]',
iconProps.class
)}
/>
{/if}
{#if label && !iconOnly}
@@ -58,9 +59,10 @@
{#if showTooltipIcon}
<Info size={14} class="text-gray-400" />
{/if}
</Tab>
</div>
<svelte:fragment slot="text">
{tooltip}
</svelte:fragment>
</Tooltip>
</button>
<svelte:fragment slot="text">
{tooltip}
</svelte:fragment>
</Tooltip>
{/if}
@@ -1,53 +1,51 @@
<script context="module" lang="ts">
export type ToggleButtonContext = {
selected: Writable<any>
select: (value: any) => void
}
</script>
<script lang="ts">
import { createEventDispatcher, setContext } from 'svelte'
import { writable, type Writable } from 'svelte/store'
import { TabGroup, TabList } from '@rgossiaux/svelte-headlessui'
import { createEventDispatcher } from 'svelte'
import { twMerge } from 'tailwind-merge'
import { createSync } from '@melt-ui/svelte'
export let id: string | null | undefined = undefined
export let selected: any
export let selected: string | string[] | undefined = undefined
export let noWFull: boolean = false
export let disabled: boolean = false
export let tabListClass: string = ''
export let allowEmpty: boolean = false
const dispatch = createEventDispatcher()
const selectedContent = writable(selected)
function setSelected(selected: any) {
if ($selectedContent != selected) {
selectedContent.set(selected)
}
}
import { createToggleGroup, melt } from '@melt-ui/svelte'
$: setSelected(selected)
setContext<ToggleButtonContext>('ToggleButtonGroup', {
selected: selectedContent,
select: (value: any) => {
selectedContent.set(value)
selected = value
dispatch('selected', value)
const {
elements: { root, item },
options: { disabled: disabledOption },
states
} = createToggleGroup({
type: 'multiple',
onValueChange: ({ curr, next }) => {
if (next === undefined && !allowEmpty) {
return curr
}
dispatch('selected', next)
return next
}
})
$: $disabledOption = disabled
const sync = createSync(states)
$: sync.value(selected, (v) => (selected = v))
</script>
<TabGroup
{id}
<div
use:melt={$root}
class={twMerge(
`h-8 flex ${noWFull ? '' : 'w-full'} ${disabled ? 'disabled' : ''}`,
$$props.class
$$props.class,
'flex items-center data-[orientation="vertical"]:flex-col'
)}
aria-label="Text alignment"
{id}
>
<TabList
class={twMerge('flex bg-surface-secondary rounded-md p-0.5 gap-1 h-full ', tabListClass)}
>
<slot />
</TabList>
</TabGroup>
<div class={twMerge('flex bg-surface-secondary rounded-md p-0.5 gap-1 h-full ', tabListClass)}>
<slot {item} />
</div>
</div>
@@ -1,16 +1,15 @@
<script lang="ts">
import { getContext } from 'svelte'
import { Tab } from '@rgossiaux/svelte-headlessui'
import type { ToggleButtonContext } from './ToggleButtonGroup.svelte'
import { twMerge } from 'tailwind-merge'
import Popover from '$lib/components/Popover.svelte'
import DropdownV2 from '$lib/components/DropdownV2.svelte'
import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte'
export let disabled: boolean = false
export let small = false
export let light = false
export let id: string | undefined = undefined
export let item: any | undefined = undefined
export let selected: string | undefined = undefined
type TogglableItem = {
label: string
value: string
@@ -18,11 +17,14 @@
export let togglableItems: TogglableItem[]
const { select, selected } = getContext<ToggleButtonContext>('ToggleButtonGroup')
function select(v: string) {
console.log('dbg select', v)
selected = v
}
let items = togglableItems.map((i) => ({ displayName: i.label, action: () => select(i.value) }))
function isAnOptionSelected(selected: string) {
function isAnOptionSelected(selected: string | undefined) {
return togglableItems.some((i) => i.value === selected)
}
</script>
@@ -34,21 +36,16 @@
disappearTimeout={0}
>
<div {id} class="flex">
{#if isAnOptionSelected($selected)}
<Tab
{#if isAnOptionSelected(selected)}
<ToggleButton
{disabled}
class={twMerge(
' rounded-md transition-all text-xs flex gap-1 flex-row items-center',
small ? 'px-1.5 py-0.5 text-2xs' : 'px-2 py-1',
light ? 'font-medium' : '',
isAnOptionSelected($selected)
? 'bg-surface shadow-md'
: 'bg-surface-secondary hover:bg-surface-hover',
$$props.class
)}
>
{togglableItems.find((i) => i.value === $selected)?.label}
</Tab>
value={selected}
{item}
{small}
{light}
{id}
label={togglableItems.find((i) => i.value === selected)?.label}
/>
{/if}
<div class="flex items-center">
<DropdownV2 {items} />
@@ -1,37 +0,0 @@
<script lang="ts">
import { Tab } from '@rgossiaux/svelte-headlessui'
import { twMerge } from 'tailwind-merge'
import Toggle from '$lib/components/Toggle.svelte'
export let label: string | undefined = undefined
export let tooltip: string | undefined = undefined
export let disabled: boolean = false
export let small = false
export let light = false
export let checked: boolean = false
export let id: string | undefined = undefined
</script>
<div {id} class="flex">
<Tab
{disabled}
class={twMerge(
' rounded-md transition-all text-xs flex gap-1 flex-row items-center',
small ? 'px-1.5 py-0.5 text-2xs' : 'px-2 py-1',
light ? 'font-medium' : '',
'bg-surface-secondary ',
$$props.class
)}
>
<Toggle
size="xs"
options={{
right: label,
rightTooltip: tooltip
}}
textClass="text-2xs whitespace-nowrap white !w-full"
bind:checked
/>
</Tab>
</div>
@@ -249,6 +249,11 @@
}
$: $copilotInfo && checkForInvalidModel()
function handlePublicOnlySelected({ detail }: { detail: string }) {
if (!dbSchema) return
;(dbSchema as any).publicOnly = detail === 'true'
}
onDestroy(() => {
abortController?.abort()
})
@@ -401,9 +406,15 @@
{:else if $copilotInfo.exists_ai_resource}
<div class="flex flex-col gap-4">
<div class="flex flex-row justify-between items-center w-96 gap-2">
<ToggleButtonGroup class="w-auto shrink-0 h-auto" bind:selected={mode}>
<ToggleButton value={'gen'} label="Generate from scratch" light class="px-2" />
<ToggleButton value={'edit'} label="Edit existing code" light class="px-2" />
<ToggleButtonGroup class="w-auto shrink-0 h-auto" bind:selected={mode} let:item>
<ToggleButton
value={'gen'}
label="Generate from scratch"
light
class="px-2"
{item}
/>
<ToggleButton value={'edit'} label="Edit existing code" light class="px-2" {item} />
</ToggleButtonGroup>
<div class="min-w-0">
@@ -502,14 +513,20 @@
{/if}
</div>
{#if dbSchema && dbSchema.lang !== 'graphql' && (dbSchema.schema?.public || dbSchema.schema?.PUBLIC || dbSchema.schema?.dbo)}
<ToggleButtonGroup class="w-auto shrink-0" bind:selected={dbSchema.publicOnly}>
<ToggleButtonGroup
class="w-auto shrink-0"
selected={dbSchema?.publicOnly ? 'true' : 'false'}
on:selected={handlePublicOnlySelected}
let:item
>
<ToggleButton
value={true}
value={'true'}
label={(dbSchema.schema?.dbo ? 'Dbo' : 'Public') + ' schema'}
small
light
{item}
/>
<ToggleButton value={false} label="All schemas" small light />
<ToggleButton value={'false'} label="All schemas" small light {item} />
</ToggleButtonGroup>
{/if}
</div>
@@ -8,9 +8,7 @@
Webhook,
Unplug,
PlugZap,
Database
} from 'lucide-svelte'
import HighlightTheme from '../HighlightTheme.svelte'
@@ -111,9 +109,9 @@
<slot name="postgres" />
{:else if triggerSelected === 'kafka' || triggerSelected === 'nats'}
<div class="m-1.5">
<ToggleButtonGroup bind:selected={eventStreamType}>
<ToggleButton value="kafka" label="Kafka" icon={KafkaIcon} />
<ToggleButton value="nats" label="NATS" icon={NatsIcon} />
<ToggleButtonGroup bind:selected={eventStreamType} let:item>
<ToggleButton value="kafka" label="Kafka" icon={KafkaIcon} {item} />
<ToggleButton value="nats" label="NATS" icon={NatsIcon} {item} />
</ToggleButtonGroup>
</div>
{#if eventStreamType === 'kafka'}
@@ -110,9 +110,9 @@
<div class="flex flex-col gap-2">
<div class="flex flex-row justify-between">
<div class="text-xs font-semibold flex flex-row items-center">Call method</div>
<ToggleButtonGroup class="h-[30px] w-auto" bind:selected={requestType}>
<ToggleButton label="By path" value="path" />
<ToggleButton label="By hash" value="hash" />
<ToggleButtonGroup class="h-[30px] w-auto" bind:selected={requestType} let:item>
<ToggleButton label="By path" value="path" {item} />
<ToggleButton label="By hash" value="hash" {item} />
</ToggleButtonGroup>
</div>
</div>
@@ -68,12 +68,13 @@
{:else}{#if !failureModule && !preprocessorModule}
<div class="center-center">
<div class="max-w-min">
<ToggleButtonGroup bind:selected={kind}>
<ToggleButtonGroup bind:selected={kind} let:item>
<ToggleButton
value="script"
icon={Code}
label="Action"
tooltip="An action script is simply a script that is neither a trigger nor an approval script. Those are the majority of the scripts."
{item}
/>
{#if !shouldDisableTriggerScripts}
<ToggleButton
@@ -81,6 +82,7 @@
icon={Zap}
label="Trigger"
tooltip="Used as a first step most commonly with a state and a schedule to watch for changes on an external system, compute the diff since last time and set the new state. The diffs are then treated one by one with a for-loop."
{item}
/>
{/if}
<ToggleButton
@@ -88,6 +90,7 @@
icon={Check}
label="Approval"
tooltip="An approval step will suspend the execution of a flow until it has been approved through the resume endpoints or the approval page by and solely by the recipients of those secret urls."
{item}
/>
</ToggleButtonGroup>
</div>
@@ -629,13 +629,18 @@
</div>
<div class="flex gap-2 justify-between mb-4 items-center">
<div class="flex gap-2">
<ToggleButtonGroup bind:selected={s3Kind} class="w-auto">
<ToggleButtonGroup bind:selected={s3Kind} class="w-auto" let:item>
{#if flowModule.value['language'] === 'deno'}
<ToggleButton value="s3_client" size="sm" label="S3 lite client" />
<ToggleButton
value="s3_client"
size="sm"
label="S3 lite client"
{item}
/>
{:else}
<ToggleButton value="s3_client" size="sm" label="Boto3" />
<ToggleButton value="polars" size="sm" label="Polars" />
<ToggleButton value="duckdb" size="sm" label="DuckDB" />
<ToggleButton value="s3_client" size="sm" label="Boto3" {item} />
<ToggleButton value="polars" size="sm" label="Polars" {item} />
<ToggleButton value="duckdb" size="sm" label="DuckDB" {item} />
{/if}
</ToggleButtonGroup>
</div>
@@ -68,10 +68,11 @@
setExponentialRetries()
}
}}
let:item
>
<ToggleButton light value="disabled" label="Disabled" />
<ToggleButton light value="constant" label="Constant" />
<ToggleButton light value="exponential" label="Exponential" />
<ToggleButton light value="disabled" label="Disabled" {item} />
<ToggleButton light value="constant" label="Constant" {item} />
<ToggleButton light value="exponential" label="Exponential" {item} />
</ToggleButtonGroup>
<div class="flex h-[calc(100%-22px)]">
<div class="w-1/2 h-full overflow-auto pr-2">
@@ -344,9 +344,16 @@
setQuery($page.url, 'kind', itemKind)
}}
class="h-10"
let:item
>
<ToggleButton value="all" label="All" class="text-sm px-4 py-2" />
<ToggleButton value="script" icon={Code2} label="Scripts" class="text-sm px-4 py-2" />
<ToggleButton value="all" label="All" class="text-sm px-4 py-2" {item} />
<ToggleButton
value="script"
icon={Code2}
label="Scripts"
class="text-sm px-4 py-2"
{item}
/>
{#if HOME_SEARCH_SHOW_FLOW}
<ToggleButton
value="flow"
@@ -354,6 +361,7 @@
icon={FlowIcon}
class="text-sm px-4 py-2"
selectedColor="#14b8a6"
{item}
/>
{/if}
<ToggleButton
@@ -362,6 +370,7 @@
icon={LayoutDashboard}
class="text-sm px-4 py-2"
selectedColor="#fb923c"
{item}
/>
</ToggleButtonGroup>
</div>
@@ -103,6 +103,8 @@
let labelTimeout: NodeJS.Timeout | undefined = undefined
let concurrencyKeyTimeout: NodeJS.Timeout | undefined = undefined
let tagTimeout: NodeJS.Timeout | undefined = undefined
let allWorkspacesValue = allWorkspaces ? 'all' : 'admins'
</script>
<div class="flex gap-4">
@@ -111,9 +113,13 @@
{#if $workspaceStore == 'admins'}
<div class="relative">
<span class="text-xs absolute -top-4">Workspaces</span>
<ToggleButtonGroup bind:selected={allWorkspaces}>
<ToggleButton value={false} label="Admins" />
<ToggleButton value={true} label="All" />
<ToggleButtonGroup
bind:selected={allWorkspacesValue}
on:selected={({ detail }) => (allWorkspaces = detail === 'all')}
let:item
>
<ToggleButton value={'admins'} label="Admins" {item} />
<ToggleButton value={'all'} label="All" {item} />
</ToggleButtonGroup>
</div>
{/if}
@@ -135,10 +141,11 @@
autoSet = false
}
}}
let:item
>
<ToggleButton value="path" label="Path" />
<ToggleButton value="user" label="User" />
<ToggleButton value="folder" label="Folder" />
<ToggleButton value="path" label="Path" {item} />
<ToggleButton value="user" label="User" {item} />
<ToggleButton value="folder" label="Folder" {item} />
<ToggleButtonMore
togglableItems={[
{ label: 'Schedule path', value: 'schedulePath' },
@@ -146,6 +153,8 @@
{ label: 'Label', value: 'label' },
{ label: 'Tag', value: 'tag' }
]}
{item}
bind:selected={filterBy}
/>
</ToggleButtonGroup>
</div>
@@ -410,47 +419,53 @@
</div>
<div class="relative">
<span class="text-xs absolute -top-4">Kind</span>
<ToggleButtonGroup bind:selected={jobKindsCat}>
<ToggleButton value="all" label="All" />
<ToggleButtonGroup bind:selected={jobKindsCat} let:item>
<ToggleButton value="all" label="All" {item} />
<ToggleButton
value="runs"
label="Runs"
showTooltipIcon
tooltip="Runs are jobs that have no parent jobs (flows are jobs that are parent of the jobs they start), they have been triggered through the UI, a schedule or webhook"
{item}
/>
<ToggleButton
value="previews"
label="Previews"
showTooltipIcon
tooltip="Previews are jobs that have been started in the editor as 'Tests'"
{item}
/>
<ToggleButton
value="dependencies"
label="Deps"
showTooltipIcon
tooltip="Deploying a script, flow or an app launch a dependency job that create and then attach the lockfile to the deployed item. This mechanism ensure that logic is always executed with the exact same direct and indirect dependencies."
{item}
/>
<ToggleButton
value="deploymentcallbacks"
label="Sync"
showTooltipIcon
tooltip="Sync jobs that are triggered on every script deployment to sync the workspace with the Git repository configured in the the workspace settings"
{item}
/>
</ToggleButtonGroup>
</div>
<div class="relative">
<span class="text-xs absolute -top-4">Status</span>
<ToggleButtonGroup
allowEmpty
bind:selected={success}
on:selected={() => dispatch('successChange', success)}
let:item
>
<ToggleButton value={undefined} label="All" />
<ToggleButton
value={'running'}
tooltip="Running"
class="whitespace-nowrap"
icon={PlayCircle}
iconProps={{ color: success === 'running' ? 'blue' : 'gray' }}
{item}
/>
<ToggleButton
value={'success'}
@@ -458,6 +473,7 @@
class="whitespace-nowrap"
icon={CheckCircle2}
iconProps={{ color: success === 'success' ? 'green' : 'gray' }}
{item}
/>
<ToggleButton
value={'failure'}
@@ -465,6 +481,7 @@
class="whitespace-nowrap"
icon={AlertCircle}
iconProps={{ color: success === 'failure' ? 'red' : 'gray' }}
{item}
/>
{#if success == 'waiting'}
<ToggleButton
@@ -473,6 +490,7 @@
class="whitespace-nowrap"
icon={Hourglass}
iconProps={{ color: 'blue' }}
{item}
/>
{:else if success == 'suspended'}
<ToggleButton
@@ -481,6 +499,7 @@
class="whitespace-nowrap"
icon={Hourglass}
iconProps={{ color: 'blue' }}
{item}
/>
{/if}
</ToggleButtonGroup>
@@ -501,9 +520,10 @@
<svelte:fragment slot="content">
<Section label="Filters">
<div class="w-102 flex flex-col gap-4">
{#if mobile}
{#if mobile || true}
<Label label="Filter by">
<ToggleButtonGroup
let:item
bind:selected={filterBy}
on:selected={() => {
if (!autoSet) {
@@ -519,13 +539,13 @@
}
}}
>
<ToggleButton value="path" label="Path" />
<ToggleButton value="user" label="User" />
<ToggleButton value="folder" label="Folder" />
<ToggleButton value="schedulePath" label="Schedule" />
<ToggleButton value="concurrencyKey" label="Concurrency" />
<ToggleButton value="tag" label="Tag" />
<ToggleButton value="label" label="Label" />
<ToggleButton value="path" label="Path" {item} />
<ToggleButton value="user" label="User" {item} />
<ToggleButton value="folder" label="Folder" {item} />
<ToggleButton value="schedulePath" label="Schedule" {item} />
<ToggleButton value="concurrencyKey" label="Concurrency" {item} />
<ToggleButton value="tag" label="Tag" {item} />
<ToggleButton value="label" label="Label" {item} />
</ToggleButtonGroup>
</Label>
@@ -725,41 +745,44 @@
{/if}
<Label label="Kind">
<ToggleButtonGroup bind:selected={jobKindsCat}>
<ToggleButton value="all" label="All" />
<ToggleButtonGroup bind:selected={jobKindsCat} let:item>
<ToggleButton value="all" label="All" {item} />
<ToggleButton
value="runs"
label="Runs"
showTooltipIcon
tooltip="Runs are jobs that have no parent jobs (flows are jobs that are parent of the jobs they start), they have been triggered through the UI, a schedule or webhook"
{item}
/>
<ToggleButton
value="previews"
label="Previews"
showTooltipIcon
tooltip="Previews are jobs that have been started in the editor as 'Tests'"
{item}
/>
<ToggleButton
value="dependencies"
label="Deps"
showTooltipIcon
tooltip="Deploying a script, flow or an app launch a dependency job that create and then attach the lockfile to the deployed item. This mechanism ensure that logic is always executed with the exact same direct and indirect dependencies."
{item}
/>
<ToggleButton
value="deploymentcallbacks"
label="Sync"
showTooltipIcon
tooltip="Sync jobs that are triggered on every script deployment to sync the workspace with the Git repository configured in the the workspace settings"
{item}
/>
</ToggleButtonGroup>
</Label>
<Label label="Status">
<ToggleButtonGroup bind:selected={success}>
<ToggleButton value={undefined} label="All" />
<ToggleButton value={'running'} label="Running" class="whitespace-nowrap" />
<ToggleButton value={'success'} label="Success" class="whitespace-nowrap" />
<ToggleButton value={'failure'} label="Failure" class="whitespace-nowrap" />
<ToggleButtonGroup bind:selected={success} let:item allowEmpty>
<ToggleButton value={'running'} label="Running" class="whitespace-nowrap" {item} />
<ToggleButton value={'success'} label="Success" class="whitespace-nowrap" {item} />
<ToggleButton value={'failure'} label="Failure" class="whitespace-nowrap" {item} />
</ToggleButtonGroup>
</Label>
{/if}
@@ -181,9 +181,14 @@
<div class="flex flex-col gap-2">
{#if type === 'object' && schema.oneOf && schema.oneOf.length >= 2}
<div class="flex flex-row gap-1 items-center justify-start">
<ToggleButtonGroup bind:selected={oneOfSelected} class="h-auto" tabListClass="flex-wrap">
<ToggleButtonGroup
bind:selected={oneOfSelected}
class="h-auto"
tabListClass="flex-wrap"
let:item
>
{#each schema.oneOf as obj}
<ToggleButton value={obj.title} label={obj.title} />
<ToggleButton value={obj.title} label={obj.title} {item} />
{/each}
</ToggleButtonGroup>
@@ -193,9 +193,9 @@
bind:currencyLocale={extra['currencyLocale']}
/>
{:else if type == 'object' && oneOf && oneOf.length >= 2 && !isFlowInput && !isAppInput}
<ToggleButtonGroup bind:selected={oneOfSelected} class="mb-2">
<ToggleButtonGroup bind:selected={oneOfSelected} class="mb-2" let:item>
{#each oneOf as obj}
<ToggleButton value={obj.title} label={obj.title} />
<ToggleButton value={obj.title} label={obj.title} {item} />
{/each}
</ToggleButtonGroup>
{#if oneOfSelected && oneOfSchemas}
@@ -71,9 +71,9 @@
$: enableAllState = (() => {
const values = Object.values(operatorWorkspaceSettings)
if (values.every((v) => v === true)) return true
if (values.every((v) => v === false)) return false
return null
if (values.every((v) => v === true)) return 'true'
if (values.every((v) => v === false)) return 'false'
return undefined
})()
function toggleAllSettings(event) {
@@ -111,9 +111,25 @@
<Cell head first>Section</Cell>
<Cell head>Description</Cell>
<Cell head last>
<ToggleButtonGroup bind:selected={enableAllState} on:selected={toggleAllSettings}>
<ToggleButton icon={EyeIcon} small={true} value={true} label="Enable All" />
<ToggleButton icon={EyeOffIcon} small={true} value={false} label="Disable All" />
<ToggleButtonGroup
bind:selected={enableAllState}
on:selected={toggleAllSettings}
let:item
>
<ToggleButton
icon={EyeIcon}
small={true}
value={'true'}
label="Enable All"
{item}
/>
<ToggleButton
icon={EyeOffIcon}
small={true}
value={'false'}
label="Disable All"
{item}
/>
</ToggleButtonGroup>
</Cell>
</tr>
@@ -124,9 +140,13 @@
<Cell first>{title}</Cell>
<Cell>{description}</Cell>
<Cell last class="pl-8">
<ToggleButtonGroup bind:selected={operatorWorkspaceSettings[key]}>
<ToggleButton icon={EyeIcon} small={true} value={true} label="On" />
<ToggleButton icon={EyeOffIcon} small={true} value={false} label="Off" />
<ToggleButtonGroup
selected={operatorWorkspaceSettings[key] ? 'on' : 'off'}
on:selected={({ detail }) => (operatorWorkspaceSettings[key] = detail === 'on')}
let:item
>
<ToggleButton icon={EyeIcon} small={true} value={'on'} label="On" {item} />
<ToggleButton icon={EyeOffIcon} small={true} value={'off'} label="Off" {item} />
</ToggleButtonGroup>
</Cell>
</tr>
@@ -204,9 +204,10 @@
autoAdd = e.detail === 'add'
}
}}
let:item
>
<ToggleButton value="invite" size="xs" label="Auto-invite" />
<ToggleButton value="add" size="xs" label="Auto-add" />
<ToggleButton value="invite" size="xs" label="Auto-invite" {item} />
<ToggleButton value="add" size="xs" label="Auto-add" {item} />
</ToggleButtonGroup>
{/if}
@@ -233,18 +234,21 @@
operatorOnly = e.detail === 'operator'
}
}}
let:item
>
<ToggleButton
value="operator"
size="xs"
label="Operator"
tooltip="An operator can only execute and view scripts/flows/apps from your workspace, and only those that he has visibility on."
{item}
/>
<ToggleButton
value="developer"
size="xs"
label="Developer"
tooltip="A Developer can execute and view scripts/flows/apps, but they can also create new ones and edit those they are allowed to by their path (either u/ or Writer or Admin of their folder found at /f)."
{item}
/>
</ToggleButtonGroup>
<div class="pt-2">
@@ -363,12 +367,14 @@
})
listUsers()
}}
let:item
>
<ToggleButton
value="operator"
size="xs"
label="Operator"
tooltip="An operator can only execute and view scripts/flows/apps from your workspace, and only those that he has visibility on."
{item}
/>
<ToggleButton
@@ -376,6 +382,7 @@
size="xs"
label="Developer"
tooltip="A Developer can execute and view scripts/flows/apps, but they can also create new ones and edit those they are allowed to by their path (either u/ or Writer or Admin of their folder found at /f)."
{item}
/>
<ToggleButton
@@ -383,6 +390,7 @@
size="xs"
label="Admin"
tooltip="An admin has full control over a specific Windmill workspace, including the ability to manage users, edit entities, and control permissions within the workspace."
{item}
/>
</ToggleButtonGroup>
</div>
@@ -492,12 +500,14 @@
})
listUsers()
}}
let:item
>
<ToggleButton
value="operator"
size="xs"
label="Operator"
tooltip="An operator can only execute and view scripts/flows/apps from your workspace, and only those that he has visibility on."
{item}
/>
<ToggleButton
@@ -505,6 +515,7 @@
size="xs"
label="Developer"
tooltip="A Developer can execute and view scripts/flows/apps, but they can also create new ones and edit those they are allowed to by their path (either u/ or Writer or Admin of their folder found at /f)."
{item}
/>
<ToggleButton
@@ -512,6 +523,7 @@
size="xs"
label="Admin"
tooltip="An admin has full control over a specific Windmill workspace, including the ability to manage users, edit entities, and control permissions within the workspace."
{item}
/>
</ToggleButtonGroup>
</div>
@@ -208,13 +208,15 @@
on:selected={(e) => {
initLoadCaptures(e.detail)
}}
let:item
>
<ToggleButton value="main" label={isFlow ? 'Flow' : 'Main'} small />
<ToggleButton value="main" label={isFlow ? 'Flow' : 'Main'} small {item} />
<ToggleButton
value="preprocessor"
label="Preprocessor"
small
tooltip="When the runnable has a preprocessor, it receives additional information about the request"
{item}
/>
</ToggleButtonGroup>
</div>
@@ -155,9 +155,9 @@
</div>
{:else if $selectedTrigger === 'kafka' || $selectedTrigger === 'nats'}
<div class="p-4 flex flex-col gap-2">
<ToggleButtonGroup bind:selected={eventStreamType}>
<ToggleButton value="kafka" label="Kafka" icon={KafkaIcon} />
<ToggleButton value="nats" label="NATS" icon={NatsIcon} />
<ToggleButtonGroup bind:selected={eventStreamType} let:item>
<ToggleButton value="kafka" label="Kafka" icon={KafkaIcon} {item} />
<ToggleButton value="nats" label="NATS" icon={NatsIcon} {item} />
</ToggleButtonGroup>
{#if eventStreamType === 'kafka'}
<KafkaTriggersPanel
@@ -148,12 +148,13 @@
disabled={!($userStore?.is_admin || $userStore?.is_super_admin) ||
!can_write ||
!!static_asset_config}
let:item
>
<ToggleButton label="GET" value="get" />
<ToggleButton label="POST" value="post" />
<ToggleButton label="PUT" value="put" />
<ToggleButton label="PATCH" value="patch" />
<ToggleButton label="DELETE" value="delete" />
<ToggleButton label="GET" value="get" {item} />
<ToggleButton label="POST" value="post" {item} />
<ToggleButton label="PUT" value="put" {item} />
<ToggleButton label="PATCH" value="patch" {item} />
<ToggleButton label="DELETE" value="delete" {item} />
</ToggleButtonGroup>
<div class="flex flex-col w-full mt-2">
<div class="flex justify-start w-full">
@@ -262,10 +262,11 @@
static_asset_config = undefined
}
}}
let:item
>
<ToggleButton label="Runnable" value="runnable" />
<ToggleButton label="Static asset" value="static_asset" />
<ToggleButton label="Static website" value="static_website" />
<ToggleButton label="Runnable" value="runnable" {item} />
<ToggleButton label="Static asset" value="static_asset" {item} />
<ToggleButton label="Static website" value="static_website" {item} />
</ToggleButtonGroup>
{/if}
@@ -385,18 +386,24 @@
<svelte:fragment slot="action">
<ToggleButtonGroup
class="w-auto h-full"
bind:selected={is_async}
selected={is_async ? 'async' : 'sync'}
on:selected={({ detail }) => {
is_async = detail === 'async'
}}
disabled={!can_write || !!static_asset_config}
let:item
>
<ToggleButton
label="Async"
value={true}
value="async"
tooltip="The returning value is the uuid of the job assigned to execute the job."
{item}
/>
<ToggleButton
label="Sync"
value={false}
value="sync"
tooltip="Triggers the execution, wait for the job to complete and return it as a response."
{item}
/>
</ToggleButtonGroup>
</svelte:fragment>
@@ -407,14 +414,19 @@
<svelte:fragment slot="action">
<ToggleButtonGroup
class="w-auto h-full"
bind:selected={requires_auth}
selected={requires_auth ? 'required' : 'none'}
on:selected={({ detail }) => {
requires_auth = detail === 'required'
}}
disabled={!can_write}
let:item
>
<ToggleButton label="None" value={false} />
<ToggleButton label="None" value="none" {item} />
<ToggleButton
label="Required"
value={true}
value="required"
tooltip="Requires authentication with read access on the route"
{item}
/>
</ToggleButtonGroup>
</svelte:fragment>
@@ -200,9 +200,10 @@
delete args.security
}
}}
let:item
>
<ToggleButton value="static" label="Static" small={true} />
<ToggleButton value="resource" label="Resource" icon={Boxes} small={true} />
<ToggleButton value="static" label="Static" small={true} {item} />
<ToggleButton value="resource" label="Resource" icon={Boxes} small={true} {item} />
</ToggleButtonGroup>
{/if}
</svelte:fragment>
@@ -251,9 +251,10 @@
delete args.require_tls
}
}}
let:item
>
<ToggleButton value="static" label="Static" small={true} />
<ToggleButton value="resource" label="Resource" icon={Boxes} small={true} />
<ToggleButton value="static" label="Static" small={true} {item} />
<ToggleButton value="resource" label="Resource" icon={Boxes} small={true} {item} />
</ToggleButtonGroup>
{/if}
</svelte:fragment>
@@ -488,9 +488,10 @@
replication_slot_name = ''
}}
disabled={!can_write}
let:item
>
<ToggleButton value="create" label="Create Slot" />
<ToggleButton value="get" label="Get Slot" />
<ToggleButton value="create" label="Create Slot" {item} />
<ToggleButton value="get" label="Get Slot" {item} />
</ToggleButtonGroup>
{#if selectedSlotAction === 'create'}
<div class="flex gap-3">
@@ -45,9 +45,10 @@
}
}}
bind:selected={selectedTable}
let:item
>
<ToggleButton value="all" label="All Tables" />
<ToggleButton value="specific" label="Specific Tables" />
<ToggleButton value="all" label="All Tables" light {item} />
<ToggleButton value="specific" label="Specific Tables" light {item} />
</ToggleButtonGroup>
</div>
</div>
@@ -308,26 +308,29 @@ done`
<div class="flex flex-row justify-between">
<div class="text-sm font-normal text-secondary flex flex-row items-center">Request type</div
>
<ToggleButtonGroup class="h-[30px] w-auto" bind:selected={webhookType}>
<ToggleButtonGroup class="h-[30px] w-auto" bind:selected={webhookType} let:item>
<ToggleButton
label="Async"
value="async"
tooltip="The returning value is the uuid of the job assigned to execute the job."
{item}
/>
<ToggleButton
label="Sync"
value="sync"
tooltip="Triggers the execution, wait for the job to complete and return it as a response."
{item}
/>
</ToggleButtonGroup>
</div>
<div class="flex flex-row justify-between">
<div class="text-sm font-normal text-secondary flex flex-row items-center">Call method</div>
<ToggleButtonGroup class="h-[30px] w-auto" bind:selected={requestType}>
<ToggleButtonGroup class="h-[30px] w-auto" bind:selected={requestType} let:item>
<ToggleButton
label="POST by path"
value="path"
icon={ArrowUpRight}
{item}
selectedColor="#fb923c"
/>
{#if !isFlow}
@@ -337,6 +340,7 @@ done`
icon={ArrowUpRight}
selectedColor="#fb923c"
disabled={!hash}
{item}
/>
{/if}
@@ -345,6 +349,7 @@ done`
value="get_path"
icon={ArrowDownRight}
disabled={webhookType !== 'sync'}
{item}
selectedColor="#14b8a6"
/>
</ToggleButtonGroup>
@@ -353,9 +358,9 @@ done`
<div class="text-sm font-normal text-secondary flex flex-row items-center"
>Token configuration</div
>
<ToggleButtonGroup class="h-[30px] w-auto" bind:selected={tokenType}>
<ToggleButton label="Token in Headers" value="headers" />
<ToggleButton label="Token in Query" value="query" />
<ToggleButtonGroup class="h-[30px] w-auto" bind:selected={tokenType} let:item>
<ToggleButton label="Token in Headers" value="headers" {item} />
<ToggleButton label="Token in Query" value="query" {item} />
</ToggleButtonGroup>
</div>
</div>
@@ -102,9 +102,10 @@
url = ev.detail === 'runnable' ? '$script:' : ''
url_runnable_args = {}
}}
let:item
>
<ToggleButton value="static" label="Static URL" />
<ToggleButton value="runnable" label="Runnable result as URL" />
<ToggleButton value="static" label="Static URL" {item} />
<ToggleButton value="runnable" label="Runnable result as URL" {item} />
</ToggleButtonGroup>
</div>
{#if url?.startsWith('$')}
@@ -244,9 +244,9 @@
/>
<div class="flex flex-row items-center gap-2 mt-6">
<div class="text-sm shrink-0"> Filter by path of </div>
<ToggleButtonGroup bind:selected={selectedFilterKind}>
<ToggleButton small value="trigger" label="Kafka trigger" icon={KafkaIcon} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} />
<ToggleButtonGroup bind:selected={selectedFilterKind} let:item>
<ToggleButton small value="trigger" label="Kafka trigger" icon={KafkaIcon} {item} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} {item} />
</ToggleButtonGroup>
</div>
<ListFilters syncQuery bind:selectedFilter={ownerFilter} filters={owners} />
@@ -208,223 +208,230 @@
f={(x) => (x.summary ?? '') + ' ' + x.path + ' (' + x.script_path + ')'}
/>
{#if $userStore?.operator && $workspaceStore && !$userWorkspaces.find(_ => _.id === $workspaceStore)?.operator_settings?.triggers}
<div class="bg-red-100 border-l-4 border-red-600 text-orange-700 p-4 m-4 mt-12" role="alert">
<p class="font-bold">Unauthorized</p>
<p>Page not available for operators</p>
</div>
{#if $userStore?.operator && $workspaceStore && !$userWorkspaces.find((_) => _.id === $workspaceStore)?.operator_settings?.triggers}
<div class="bg-red-100 border-l-4 border-red-600 text-orange-700 p-4 m-4 mt-12" role="alert">
<p class="font-bold">Unauthorized</p>
<p>Page not available for operators</p>
</div>
{:else}
<CenteredPage>
<PageHeader
title="NATS triggers"
tooltip="Windmill can consume NATS events and trigger scripts or flows based on them."
>
<Button size="md" startIcon={{ icon: Plus }} on:click={() => natsTriggerEditor.openNew(false)}>
New&nbsp;NATS trigger
</Button>
</PageHeader>
<CenteredPage>
<PageHeader
title="NATS triggers"
tooltip="Windmill can consume NATS events and trigger scripts or flows based on them."
>
<Button
size="md"
startIcon={{ icon: Plus }}
on:click={() => natsTriggerEditor.openNew(false)}
>
New&nbsp;NATS trigger
</Button>
</PageHeader>
{#if isCloudHosted()}
<Alert title="Not compatible with multi-tenant cloud" type="warning">
NATS triggers are disabled in the multi-tenant cloud.
</Alert>
<div class="py-4" />
{/if}
<div class="w-full h-full flex flex-col">
<div class="w-full pb-4 pt-6">
<input
type="text"
placeholder="Search NATS triggers"
bind:value={filter}
class="search-item"
/>
<div class="flex flex-row items-center gap-2 mt-6">
<div class="text-sm shrink-0"> Filter by path of </div>
<ToggleButtonGroup bind:selected={selectedFilterKind}>
<ToggleButton small value="trigger" label="NATS trigger" icon={NatsIcon} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} />
</ToggleButtonGroup>
{#if isCloudHosted()}
<Alert title="Not compatible with multi-tenant cloud" type="warning">
NATS triggers are disabled in the multi-tenant cloud.
</Alert>
<div class="py-4" />
{/if}
<div class="w-full h-full flex flex-col">
<div class="w-full pb-4 pt-6">
<input
type="text"
placeholder="Search NATS triggers"
bind:value={filter}
class="search-item"
/>
<div class="flex flex-row items-center gap-2 mt-6">
<div class="text-sm shrink-0"> Filter by path of </div>
<ToggleButtonGroup bind:selected={selectedFilterKind} let:item>
<ToggleButton small value="trigger" label="NATS trigger" icon={NatsIcon} {item} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} {item} />
</ToggleButtonGroup>
</div>
<ListFilters syncQuery bind:selectedFilter={ownerFilter} filters={owners} />
<div class="flex flex-row items-center justify-end gap-4">
{#if $userStore?.is_super_admin && $userStore.username.includes('@')}
<Toggle size="xs" bind:checked={filterUserFolders} options={{ right: 'Only f/*' }} />
{:else if $userStore?.is_admin || $userStore?.is_super_admin}
<Toggle
size="xs"
bind:checked={filterUserFolders}
options={{ right: `Only u/${$userStore.username} and f/*` }}
/>
{/if}
</div>
</div>
<ListFilters syncQuery bind:selectedFilter={ownerFilter} filters={owners} />
{#if loading}
{#each new Array(6) as _}
<Skeleton layout={[[6], 0.4]} />
{/each}
{:else if !triggers?.length}
<div class="text-center text-sm text-tertiary mt-2"> No NATS triggers </div>
{:else if items?.length}
<div class="border rounded-md divide-y">
{#each items.slice(0, nbDisplayed) as { path, edited_by, edited_at, script_path, is_flow, nats_resource_path, subjects, extra_perms, canWrite, marked, server_id, error, last_server_ping, enabled } (path)}
{@const href = `${is_flow ? '/flows/get' : '/scripts/get'}/${script_path}`}
{@const ping = last_server_ping ? new Date(last_server_ping) : undefined}
{@const pinging = ping && ping.getTime() > new Date().getTime() - 15 * 1000}
<div class="flex flex-row items-center justify-end gap-4">
{#if $userStore?.is_super_admin && $userStore.username.includes('@')}
<Toggle size="xs" bind:checked={filterUserFolders} options={{ right: 'Only f/*' }} />
{:else if $userStore?.is_admin || $userStore?.is_super_admin}
<Toggle
size="xs"
bind:checked={filterUserFolders}
options={{ right: `Only u/${$userStore.username} and f/*` }}
/>
{/if}
</div>
</div>
{#if loading}
{#each new Array(6) as _}
<Skeleton layout={[[6], 0.4]} />
{/each}
{:else if !triggers?.length}
<div class="text-center text-sm text-tertiary mt-2"> No NATS triggers </div>
{:else if items?.length}
<div class="border rounded-md divide-y">
{#each items.slice(0, nbDisplayed) as { path, edited_by, edited_at, script_path, is_flow, nats_resource_path, subjects, extra_perms, canWrite, marked, server_id, error, last_server_ping, enabled } (path)}
{@const href = `${is_flow ? '/flows/get' : '/scripts/get'}/${script_path}`}
{@const ping = last_server_ping ? new Date(last_server_ping) : undefined}
{@const pinging = ping && ping.getTime() > new Date().getTime() - 15 * 1000}
<div
class="hover:bg-surface-hover w-full items-center px-4 py-2 gap-4 first-of-type:!border-t-0
<div
class="hover:bg-surface-hover w-full items-center px-4 py-2 gap-4 first-of-type:!border-t-0
first-of-type:rounded-t-md last-of-type:rounded-b-md flex flex-col"
>
<div class="w-full flex gap-5 items-center">
<RowIcon kind={is_flow ? 'flow' : 'script'} />
>
<div class="w-full flex gap-5 items-center">
<RowIcon kind={is_flow ? 'flow' : 'script'} />
<a
href="#{path}"
on:click={() => natsTriggerEditor?.openEdit(path, is_flow)}
class="min-w-0 grow hover:underline decoration-gray-400"
>
<div class="text-primary flex-wrap text-left text-md font-semibold mb-1 truncate">
{#if marked}
<span class="text-xs">
{@html marked}
</span>
{:else}
{nats_resource_path} - {subjects.join(', ')}
<a
href="#{path}"
on:click={() => natsTriggerEditor?.openEdit(path, is_flow)}
class="min-w-0 grow hover:underline decoration-gray-400"
>
<div class="text-primary flex-wrap text-left text-md font-semibold mb-1 truncate">
{#if marked}
<span class="text-xs">
{@html marked}
</span>
{:else}
{nats_resource_path} - {subjects.join(', ')}
{/if}
</div>
<div class="text-secondary text-xs truncate text-left font-light">
{path}
</div>
<div class="text-secondary text-xs truncate text-left font-light">
runnable: {script_path}
</div>
</a>
<div class="hidden lg:flex flex-row gap-1 items-center">
<SharedBadge {canWrite} extraPerms={extra_perms} />
</div>
<div class="w-10">
{#if (enabled && (!pinging || error)) || (!enabled && error) || (enabled && !server_id)}
<Popover notClickable>
<span class="flex h-4 w-4">
<Circle
class="text-red-600 animate-ping absolute inline-flex fill-current"
size={12}
/>
<Circle class="text-red-600 relative inline-flex fill-current" size={12} />
</span>
<div slot="text">
{#if enabled}
{#if !server_id}
Consumer is starting...
{:else}
Consumer is not connected{error ? ': ' + error : ''}
{/if}
{:else}
Consumer was disabled because of an error: {error}
{/if}
</div>
</Popover>
{:else if enabled}
<Popover notClickable>
<span class="flex h-4 w-4">
<Circle
class="text-green-600 relative inline-flex fill-current"
size={12}
/>
</span>
<div slot="text"> Consumer is connected </div>
</Popover>
{/if}
</div>
<div class="text-secondary text-xs truncate text-left font-light">
{path}
</div>
<div class="text-secondary text-xs truncate text-left font-light">
runnable: {script_path}
</div>
</a>
<div class="hidden lg:flex flex-row gap-1 items-center">
<SharedBadge {canWrite} extraPerms={extra_perms} />
</div>
<div class="w-10">
{#if (enabled && (!pinging || error)) || (!enabled && error) || (enabled && !server_id)}
<Popover notClickable>
<span class="flex h-4 w-4">
<Circle
class="text-red-600 animate-ping absolute inline-flex fill-current"
size={12}
/>
<Circle class="text-red-600 relative inline-flex fill-current" size={12} />
</span>
<div slot="text">
{#if enabled}
{#if !server_id}
Consumer is starting...
{:else}
Consumer is not connected{error ? ': ' + error : ''}
{/if}
{:else}
Consumer was disabled because of an error: {error}
{/if}
</div>
</Popover>
{:else if enabled}
<Popover notClickable>
<span class="flex h-4 w-4">
<Circle class="text-green-600 relative inline-flex fill-current" size={12} />
</span>
<div slot="text"> Consumer is connected </div>
</Popover>
{/if}
</div>
<Toggle
checked={enabled}
disabled={!canWrite}
on:change={(e) => {
setTriggerEnabled(path, e.detail)
}}
/>
<div class="flex gap-2 items-center justify-end">
<Button
on:click={() => natsTriggerEditor?.openEdit(path, is_flow)}
size="xs"
startIcon={canWrite
? { icon: Pen }
: {
icon: Eye
}}
color="dark"
>
{canWrite ? 'Edit' : 'View'}
</Button>
<Dropdown
items={[
{
displayName: `View ${is_flow ? 'Flow' : 'Script'}`,
icon: Eye,
action: () => {
goto(href)
}
},
{
displayName: 'Delete',
type: 'delete',
icon: Trash,
disabled: !canWrite,
action: async () => {
await NatsTriggerService.deleteNatsTrigger({
workspace: $workspaceStore ?? '',
path
})
loadTriggers()
}
},
{
displayName: canWrite ? 'Edit' : 'View',
icon: canWrite ? Pen : Eye,
action: () => {
natsTriggerEditor?.openEdit(path, is_flow)
}
},
{
displayName: 'Audit logs',
icon: Eye,
href: `${base}/audit_logs?resource=${path}`
},
{
displayName: canWrite ? 'Share' : 'See Permissions',
icon: Share,
action: () => {
shareModal.openDrawer(path, 'nats_trigger')
}
}
]}
<Toggle
checked={enabled}
disabled={!canWrite}
on:change={(e) => {
setTriggerEnabled(path, e.detail)
}}
/>
<div class="flex gap-2 items-center justify-end">
<Button
on:click={() => natsTriggerEditor?.openEdit(path, is_flow)}
size="xs"
startIcon={canWrite
? { icon: Pen }
: {
icon: Eye
}}
color="dark"
>
{canWrite ? 'Edit' : 'View'}
</Button>
<Dropdown
items={[
{
displayName: `View ${is_flow ? 'Flow' : 'Script'}`,
icon: Eye,
action: () => {
goto(href)
}
},
{
displayName: 'Delete',
type: 'delete',
icon: Trash,
disabled: !canWrite,
action: async () => {
await NatsTriggerService.deleteNatsTrigger({
workspace: $workspaceStore ?? '',
path
})
loadTriggers()
}
},
{
displayName: canWrite ? 'Edit' : 'View',
icon: canWrite ? Pen : Eye,
action: () => {
natsTriggerEditor?.openEdit(path, is_flow)
}
},
{
displayName: 'Audit logs',
icon: Eye,
href: `${base}/audit_logs?resource=${path}`
},
{
displayName: canWrite ? 'Share' : 'See Permissions',
icon: Share,
action: () => {
shareModal.openDrawer(path, 'nats_trigger')
}
}
]}
/>
</div>
</div>
</div>
<div class="w-full flex justify-between items-baseline">
<div
class="flex flex-wrap text-[0.7em] text-tertiary gap-1 items-center justify-end truncate pr-2"
><div class="truncate">edited by {edited_by}</div><div class="truncate"
>the {displayDate(edited_at)}</div
<div class="w-full flex justify-between items-baseline">
<div
class="flex flex-wrap text-[0.7em] text-tertiary gap-1 items-center justify-end truncate pr-2"
><div class="truncate">edited by {edited_by}</div><div class="truncate"
>the {displayDate(edited_at)}</div
></div
></div
></div
>
</div>
{/each}
</div>
{:else}
<NoItemFound />
>
</div>
{/each}
</div>
{:else}
<NoItemFound />
{/if}
</div>
{#if items && items?.length > 15 && nbDisplayed < items.length}
<span class="text-xs"
>{nbDisplayed} items out of {items.length}
<button class="ml-4" on:click={() => (nbDisplayed += 30)}>load 30 more</button></span
>
{/if}
</div>
{#if items && items?.length > 15 && nbDisplayed < items.length}
<span class="text-xs"
>{nbDisplayed} items out of {items.length}
<button class="ml-4" on:click={() => (nbDisplayed += 30)}>load 30 more</button></span
>
{/if}
</CenteredPage>
</CenteredPage>
{/if}
<ShareModal
@@ -237,9 +237,9 @@
/>
<div class="flex flex-row items-center gap-2 mt-6">
<div class="text-sm shrink-0"> Filter by path of </div>
<ToggleButtonGroup bind:selected={selectedFilterKind}>
<ToggleButton small value="trigger" label="Postgres trigger" icon={Database} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} />
<ToggleButtonGroup bind:selected={selectedFilterKind} let:item>
<ToggleButton small value="trigger" label="Postgres trigger" icon={Database} {item} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} {item} />
</ToggleButtonGroup>
</div>
<ListFilters syncQuery bind:selectedFilter={ownerFilter} filters={owners} />
@@ -183,9 +183,9 @@
<input type="text" placeholder="Search routes" bind:value={filter} class="search-item" />
<div class="flex flex-row items-center gap-2 mt-6">
<div class="text-sm shrink-0"> Filter by path of </div>
<ToggleButtonGroup bind:selected={selectedFilterKind}>
<ToggleButton small value="trigger" label="Route" icon={Route} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} />
<ToggleButtonGroup bind:selected={selectedFilterKind} let:item>
<ToggleButton small value="trigger" label="Route" icon={Route} {item} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} {item} />
</ToggleButtonGroup>
</div>
<ListFilters syncQuery bind:selectedFilter={ownerFilter} filters={owners} />
@@ -89,7 +89,7 @@
let maxTs = $page.url.searchParams.get('max_ts') ?? undefined
let schedulePath = $page.url.searchParams.get('schedule_path') ?? undefined
let jobKindsCat = $page.url.searchParams.get('job_kinds') ?? 'runs'
let allWorkspaces = $page.url.searchParams.get('all_workspaces') == 'true' ?? false
let allWorkspaces = $page.url.searchParams.get('all_workspaces') == 'true'
let lastFetchWentToEnd = false
function loadFromQuery() {
@@ -135,7 +135,7 @@
maxTs = $page.url.searchParams.get('max_ts') ?? undefined
schedulePath = $page.url.searchParams.get('schedule_path') ?? undefined
jobKindsCat = $page.url.searchParams.get('job_kinds') ?? 'runs'
allWorkspaces = $page.url.searchParams.get('all_workspaces') == 'true' ?? false
allWorkspaces = $page.url.searchParams.get('all_workspaces') == 'true'
}
let queue_count: Tweened<number> | undefined = undefined
@@ -639,13 +639,12 @@
}}
/>
{#if $userStore?.operator && $workspaceStore && !$userWorkspaces.find(_ => _.id === $workspaceStore)?.operator_settings?.runs}
<div class="bg-red-100 border-l-4 border-red-600 text-orange-700 p-4 m-4 mt-12" role="alert">
<p class="font-bold">Unauthorized</p>
<p>Page not available for operators</p>
</div>
{:else}
{#if innerWidth > 900}
{#if $userStore?.operator && $workspaceStore && !$userWorkspaces.find((_) => _.id === $workspaceStore)?.operator_settings?.runs}
<div class="bg-red-100 border-l-4 border-red-600 text-orange-700 p-4 m-4 mt-12" role="alert">
<p class="font-bold">Unauthorized</p>
<p>Page not available for operators</p>
</div>
{:else if innerWidth > 900}
<div class="w-full h-screen">
<div class="px-2">
<div class="flex items-center space-x-2 flex-row justify-between">
@@ -706,9 +705,11 @@
on:selected={() => {
graphIsRunsChart = graph === 'RunChart'
}}
let:item
>
<ToggleButton value="RunChart" label="Duration" />
<ToggleButton value="RunChart" label="Durations" {item} />
<ToggleButton
{item}
value="ConcurrencyChart"
label="Concurrency"
icon={warnJobLimit ? AlertTriangle : undefined}
@@ -1083,9 +1084,10 @@
on:selected={() => {
graphIsRunsChart = graph == 'RunChart'
}}
let:item
>
<ToggleButton value="RunChart" label="Duration" />
<ToggleButton value="ConcurrencyChart" label="Concurrency" />
<ToggleButton value="RunChart" label="Duration" {item} />
<ToggleButton value="ConcurrencyChart" label="Concurrency" {item} />
</ToggleButtonGroup>
{#if !graphIsRunsChart}
<DropdownV2
@@ -1377,4 +1379,3 @@
</div>
</div>
{/if}
{/if}
@@ -268,18 +268,18 @@
<input type="text" placeholder="Search schedule" bind:value={filter} class="search-item" />
<div class="flex flex-row items-center gap-2 mt-6">
<div class="text-sm shrink-0"> Filter by path of </div>
<ToggleButtonGroup bind:selected={selectedFilterKind}>
<ToggleButton small value="schedule" label="Schedule" icon={Calendar} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} />
<ToggleButtonGroup bind:selected={selectedFilterKind} let:item>
<ToggleButton small value="schedule" label="Schedule" icon={Calendar} {item} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} {item} />
</ToggleButtonGroup>
</div>
<ListFilters syncQuery bind:selectedFilter={ownerFilter} filters={owners} />
<div class="flex flex-row items-center justify-end gap-4">
<ToggleButtonGroup class="h-6 w-auto" bind:selected={filterEnabledDisabled}>
<ToggleButton small value="all" label="All" />
<ToggleButton small value="enabled" label="Enabled" />
<ToggleButton small value="disabled" label="Disabled" />
<ToggleButtonGroup class="h-6 w-auto" bind:selected={filterEnabledDisabled} let:item>
<ToggleButton small value="all" label="All" {item} />
<ToggleButton small value="enabled" label="Enabled" {item} />
<ToggleButton small value="disabled" label="Disabled" {item} />
</ToggleButtonGroup>
{#if $userStore?.is_super_admin && $userStore.username.includes('@')}
<Toggle size="xs" bind:checked={filterUserFolders} options={{ right: 'Only f/*' }} />
@@ -233,8 +233,8 @@
{/if}
</label>
{/if}
<label class="block pb-4">
<div class="flex flex-col gap-1">
<div class="block pb-4">
<label for="ai-key" class="flex flex-col gap-1">
<span class="text-secondary text-sm">
AI key for Windmill AI
<Tooltip>
@@ -246,19 +246,22 @@
</Tooltip>
<span class="text-2xs text-tertiary ml-2">(optional but recommended)</span>
</span>
<div class="pb-2">
<ToggleButtonGroup bind:selected>
<ToggleButton value="openai" label="OpenAI" />
<ToggleButton value="anthropic" label="Anthropic" />
<ToggleButton value="mistral" label="Mistral" />
<ToggleButton value="deepseek" label="DeepSeek" />
<ToggleButton value="groq" label="Groq" />
<ToggleButton value="openrouter" label="OpenRouter" />
<ToggleButtonGroup bind:selected let:item>
<ToggleButton value="openai" label="OpenAI" {item} />
<ToggleButton value="anthropic" label="Anthropic" {item} />
<ToggleButton value="mistral" label="Mistral" {item} />
<ToggleButton value="deepseek" label="DeepSeek" {item} />
<ToggleButton value="groq" label="Groq" {item} />
<ToggleButton value="openrouter" label="OpenRouter" {item} />
</ToggleButtonGroup>
</div>
</div>
</label>
<div class="flex flex-row gap-1 pb-4">
<input
id="ai-key"
type="password"
autocomplete="new-password"
bind:value={aiKey}
@@ -278,7 +281,7 @@
options={{ right: 'Enable code completion' }}
/>
{/if}
</label>
</div>
<Toggle
disabled={isCloudHosted() && !isDomainAllowed}
bind:checked={auto_invite}
@@ -304,9 +307,10 @@
on:selected={(e) => {
operatorOnly = e.detail == 'operator'
}}
let:item
>
<ToggleButton value="operator" size="xs" label="Operator" />
<ToggleButton value="developer" size="xs" label="Developer" />
<ToggleButton value="operator" size="xs" label="Operator" {item} />
<ToggleButton value="developer" size="xs" label="Developer" {item} />
</ToggleButtonGroup>
</div>
<div class="flex flex-wrap flex-row justify-between pt-10 gap-1">
@@ -232,9 +232,9 @@
<input type="text" placeholder="Search WS triggers" bind:value={filter} class="search-item" />
<div class="flex flex-row items-center gap-2 mt-6">
<div class="text-sm shrink-0"> Filter by path of </div>
<ToggleButtonGroup bind:selected={selectedFilterKind}>
<ToggleButton small value="trigger" label="WS trigger" icon={Unplug} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} />
<ToggleButtonGroup bind:selected={selectedFilterKind} let:item>
<ToggleButton small value="trigger" label="WS trigger" icon={Unplug} {item} />
<ToggleButton small value="script_flow" label="Script/Flow" icon={Code} {item} />
</ToggleButtonGroup>
</div>
<ListFilters syncQuery bind:selectedFilter={ownerFilter} filters={owners} />
@@ -1071,19 +1071,21 @@
aiModels = []
codeCompletionModel = undefined
}}
let:item
>
<ToggleButton value="openai" label="OpenAI" />
<ToggleButton value="anthropic" label="Anthropic" />
<ToggleButton value="mistral" label="Mistral" />
<ToggleButton value="deepseek" label="DeepSeek" />
<ToggleButton value="groq" label="Groq" />
<ToggleButton value="openrouter" label="OpenRouter" />
<ToggleButton value="openai" label="OpenAI" {item} />
<ToggleButton value="anthropic" label="Anthropic" {item} />
<ToggleButton value="mistral" label="Mistral" {item} />
<ToggleButton value="deepseek" label="DeepSeek" {item} />
<ToggleButton value="groq" label="Groq" {item} />
<ToggleButton value="openrouter" label="OpenRouter" {item} />
<ToggleButton
value="customai"
label={'Custom AI' + ($enterpriseLicense ? '' : ' (EE)')}
disabled={!$enterpriseLicense}
tooltip="Configure a custom AI provider that is OpenAI API compatible"
showTooltipIcon
{item}
/>
</ToggleButtonGroup>
<div class="flex gap-1">