Compare commits

...

8 Commits

Author SHA1 Message Date
Guilhem
868fe2af5d fix minor issue 2024-10-02 08:46:42 +02:00
Guilhem
3cef291327 fix minor issue 2024-10-01 18:53:52 +02:00
Guilhem
cf73f67079 Add bage for advanced options 2024-10-01 17:38:25 +02:00
Guilhem
f07b630f82 Add nord theme colors 2024-10-01 17:37:45 +02:00
Guilhem
e50428a3aa Add advanced settings badge 2024-10-01 15:30:02 +02:00
Guilhem
a9e67c601f changing mute toggle 2024-10-01 11:40:51 +02:00
Guilhem
ea6ccae19e improve scroll 2024-10-01 08:51:42 +02:00
Guilhem
13b74fa923 fat(frontend): simplify flow settings menu 2024-09-30 21:10:49 +02:00
8 changed files with 756 additions and 582 deletions

View File

@@ -13,7 +13,7 @@
containerClasses="border rounded-lg shadow-lg p-4 bg-surface"
>
<svelte:fragment slot="button">
<Button color="dark" size="xs" nonCaptureEvent={true}>
<Button color="nord" size="xs" nonCaptureEvent={true}>
<div class="flex flex-row gap-1 items-center"
><Pen size={14} /> Custom Tags&nbsp;<Tooltip light
>Tags are assigned to scripts and flows. Workers only accept jobs that correspond to their

View File

@@ -24,8 +24,6 @@
import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte'
import FolderEditor from './FolderEditor.svelte'
import { random_adj } from './random_positive_adjetive'
import Required from './Required.svelte'
import Tooltip from './Tooltip.svelte'
import { Eye, Folder, Plus, SearchCode, User } from 'lucide-svelte'
type PathKind =
@@ -292,6 +290,7 @@
)
</script>
<!-- Drawers -->
<Drawer bind:this={newFolder}>
<DrawerContent
title="New Folder"
@@ -319,121 +318,150 @@
</DrawerContent>
</Drawer>
<div>
<div class="flex flex-col sm:flex-row sm:items-center gap-2 sm:gap-4 pb-0 mb-1">
<div class="flex flex-col gap-2">
<!-- full path -->
<div class="flex grow flex-col w-full">
<div class="flex justify-start w-full grow">
<Badge
color="gray"
class="center-center !bg-surface-secondary !text-tertiary !font-normal !w-[70px] !h-[24px] rounded-r-none border border-r-0"
>
Full path
</Badge>
<input
type="text"
readonly
value={path}
size={path?.length || 50}
class="font-mono !text-xs max-w-[calc(100%-70px)] !text-tertiary !w-auto !h-[24px] !py-0 !border-l-0 !rounded-l-none grow"
on:focus={({ currentTarget }) => {
currentTarget.select()
}}
/>
<!-- <span class="font-mono text-sm break-all">{path}</span> -->
</div>
<div class="text-red-600 dark:text-red-400 text-2xs">{error}</div>
</div>
<!-- path selector-->
<div class="flex flex-row items-center gap-4">
<!-- new folder picker -->
{#if meta != undefined}
<div class="flex gap-x-4 shrink">
<!-- svelte-ignore a11y-label-has-associated-control -->
{#if !hideUser}
<div class="block">
<span class="text-secondary text-sm whitespace-nowrap">&nbsp;</span>
<ToggleButtonGroup
class="mt-0.5"
bind:selected={meta.ownerKind}
on:selected={(e) => {
setDirty()
const kind = e.detail
if (meta) {
if (kind === 'folder') {
meta.owner = folders?.[0]?.name ?? ''
} else if (kind === 'group') {
meta.owner = 'all'
} else {
meta.owner = $userStore?.username?.split('@')[0] ?? ''
}
<!-- svelte-ignore a11y-label-has-associated-control -->
{#if !hideUser}
<!-- Toggle User/Folder -->
<div class="block">
<ToggleButtonGroup
class="items-center"
bind:selected={meta.ownerKind}
on:selected={(e) => {
setDirty()
const kind = e.detail
if (meta) {
if (kind === 'folder') {
meta.owner = folders?.[0]?.name ?? ''
} else if (kind === 'group') {
meta.owner = 'all'
} else {
meta.owner = $userStore?.username?.split('@')[0] ?? ''
}
}}
>
<ToggleButton
icon={User}
{disabled}
light
size="xs"
value="user"
position="left"
label="User"
/>
<!-- <ToggleButton light size="xs" value="group" position="center">Group</ToggleButton> -->
<ToggleButton
icon={Folder}
{disabled}
light
size="xs"
value="folder"
position="right"
label="Folder"
/>
</ToggleButtonGroup>
</div>
{/if}
{#if meta.ownerKind === 'user'}
<label class="block shrink min-w-0">
<span class="text-secondary text-sm">User</span>
<input
class="!w-36"
type="text"
bind:value={meta.owner}
placeholder={$userStore?.username ?? ''}
disabled={disabled || !($superadmin || ($userStore?.is_admin ?? false))}
on:keydown={setDirty}
}
}}
>
<ToggleButton
icon={User}
{disabled}
light
size="xs"
value="user"
position="left"
label="User"
/>
</label>
{:else if meta.ownerKind === 'folder'}
<label class="block grow w-48">
<span class="text-secondary text-sm">
Folder
<Tooltip
documentationLink="https://www.windmill.dev/docs/core_concepts/groups_and_folders"
>
Read and write permissions are given to groups and users at the folder level and
shared by all items inside the folder.
</Tooltip>
</span>
<div class="flex flex-row items-center gap-1 w-full">
<select class="grow w-full" {disabled} bind:value={meta.owner}>
{#if folders?.length == 0}
<option disabled>No folders</option>
{/if}
{#each folders as { name, write }}
<option disabled={!write}>{name}{write ? '' : ' (read-only)'}</option>
{/each}
</select>
<Button
title="View folder"
btnClasses="!p-1.5"
variant="border"
color="light"
size="xs"
disabled={!meta.owner || meta.owner == ''}
on:click={viewFolder.openDrawer}
iconOnly
startIcon={{ icon: Eye }}
/>
<Button
title="New folder"
btnClasses="!p-1.5"
variant="border"
color="light"
size="xs"
{disabled}
on:click={newFolder.openDrawer}
iconOnly
startIcon={{ icon: Plus }}
/>
</div>
</label>
{/if}
</div>
<label class="block grow w-full max-w-md">
<div class="text-secondary text-sm flex items-center gap-1 w-full justify-between">
<div>
Name
<Required required={true} />
</div>
<div class="text-2xs text-tertiary"> '/' for subfolders </div>
<!-- <ToggleButton light size="xs" value="group" position="center">Group</ToggleButton> -->
<ToggleButton
icon={Folder}
{disabled}
light
size="xs"
value="folder"
position="right"
label="Folder"
/>
</ToggleButtonGroup>
</div>
{/if}
<div class="text-secondary text-sm">/</div>
{#if meta.ownerKind === 'user'}
<label class="block grow shrink min-w-36">
<input
class="w-full"
type="text"
bind:value={meta.owner}
placeholder={$userStore?.username ?? ''}
disabled={disabled || !($superadmin || ($userStore?.is_admin ?? false))}
on:keydown={setDirty}
/>
</label>
{:else if meta.ownerKind === 'folder'}
<label class="block grow min-w-48">
<!-- <span class="text-secondary text-sm">
Folder
<Tooltip
documentationLink="https://www.windmill.dev/docs/core_concepts/groups_and_folders"
>
Read and write permissions are given to groups and users at the folder level and
shared by all items inside the folder.
</Tooltip>
</span> -->
<div class="flex flex-row items-center gap-1 w-full">
<select class="grow w-full" {disabled} bind:value={meta.owner}>
{#if folders?.length == 0}
<option disabled>No folders</option>
{/if}
{#each folders as { name, write }}
<option disabled={!write}>{name}{write ? '' : ' (read-only)'}</option>
{/each}
</select>
<Button
title="View folder"
btnClasses="!p-1.5"
variant="border"
color="light"
size="xs"
disabled={!meta.owner || meta.owner == ''}
on:click={viewFolder.openDrawer}
iconOnly
startIcon={{ icon: Eye }}
/>
<Button
title="New folder"
btnClasses="!p-1.5"
variant="border"
color="light"
size="xs"
{disabled}
on:click={newFolder.openDrawer}
iconOnly
startIcon={{ icon: Plus }}
/>
</div>
</label>
{/if}
<div class="text-secondary text-sm">/</div>
<!-- The name -->
<label class="block grow w-full max-w-md">
<!-- <div class="text-secondary text-sm flex items-center gap-1 w-full justify-between">
<div>
Name
<Required required={true} />
</div>
<div class="text-2xs text-tertiary"> '/' for subfolders </div>
</div> -->
<!-- svelte-ignore a11y-autofocus -->
<input
{disabled}
@@ -453,29 +481,6 @@
{/if}
</div>
<div class="flex flex-col w-full mt-4">
<div class="flex justify-start w-full">
<Badge
color="gray"
class="center-center !bg-surface-secondary !text-tertiary !w-[70px] !h-[24px] rounded-r-none border"
>
Full path
</Badge>
<input
type="text"
readonly
value={path}
size={path?.length || 50}
class="font-mono !text-xs max-w-[calc(100%-70px)] !w-auto !h-[24px] !py-0 !border-l-0 !rounded-l-none"
on:focus={({ currentTarget }) => {
currentTarget.select()
}}
/>
<!-- <span class="font-mono text-sm break-all">{path}</span> -->
</div>
<div class="text-red-600 dark:text-red-400 text-2xs">{error}</div>
</div>
{#if kind != 'app' && kind != 'schedule' && kind != 'http_trigger' && initialPath != '' && initialPath != undefined && initialPath != path}
<Alert type="warning" class="mt-4" title="Moving may break other items relying on it">
You are renaming an item that may be depended upon by other items. This may break apps, flows

View File

@@ -9,18 +9,23 @@
export let eeOnly = false
export let small: boolean = false
export let subsection: boolean = false
export let collapsable: boolean = false
let collapsed: boolean = true
</script>
<div class="w-full">
<div class="flex flex-row justify-between items-center mb-2">
<div class="flex flex-row justify-between items-start mb-2">
<h2
class={twMerge(
'font-semibold flex flex-row items-center gap-1',
subsection ? 'font-normal' : 'font-semibold',
subsection ? 'text-secondary' : 'text-primary',
'flex flex-row items-center gap-1',
small ? 'text-sm' : 'text-base'
)}
>
{label}
{#if collapsable}
<button class="flex items-center gap-1" on:click={() => (collapsed = !collapsed)}>
{#if collapsed}
@@ -28,10 +33,7 @@
{:else}
<ChevronDown size={16} />
{/if}
{label}
</button>
{:else}
{label}
{/if}
<slot name="header" />
@@ -48,7 +50,11 @@
{/if}
</h2>
<slot name="action" />
{#if collapsable && collapsed}
<slot name="badge" />
{/if}
</div>
<div class={collapsable && collapsed ? `hidden ${$$props.class}` : `${$$props.class}`}>
<slot />
</div>

View File

@@ -14,14 +14,18 @@
export let disabled = false
export let textClass = ''
export let textStyle = ''
export let color: 'blue' | 'red' = 'blue'
export let color: 'blue' | 'red' | 'nord' = 'blue'
export let id = (Math.random() + 1).toString(36).substring(10)
export let lightMode: boolean = false
export let size: 'sm' | 'xs' = 'sm'
export let lightToogle = false
const dispatch = createEventDispatcher()
const bothOptions = Boolean(options.left) && Boolean(options.right)
export let textDisabled = false
</script>
<label
@@ -34,7 +38,7 @@
<span
class={twMerge(
'mr-2 font-medium duration-50 select-none',
bothOptions ? (checked ? 'text-disabled' : 'text-primary') : 'text-primary',
bothOptions || textDisabled ? (checked ? 'text-disabled' : 'text-primary') : 'text-primary',
size === 'xs' ? 'text-xs' : 'text-sm',
textClass
)}
@@ -67,8 +71,12 @@
"transition-all bg-surface-selected rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:bg-surface after:border-white after:border after:rounded-full after:transition-all ",
color == 'red'
? 'peer-checked:bg-red-600'
: 'peer-checked:bg-blue-600 dark:peer-checked:bg-blue-500',
size === 'sm'
: color == 'blue'
? 'peer-checked:bg-blue-600 dark:peer-checked:bg-blue-500'
: 'peer-checked:bg-nord-300 dark:peer-checked:bg-nord-500',
lightToogle
? 'w-9 h-5 after:top-0.5 after:left-[2px] after:h-4 after:w-4'
: size === 'sm'
? 'w-11 h-6 after:top-0.5 after:left-[2px] after:h-5 after:w-5'
: 'w-7 h-4 after:top-0.5 after:left-[2px] after:h-3 after:w-3'
)}
@@ -78,7 +86,7 @@
<span
class={twMerge(
'ml-2 font-medium duration-50 select-none',
bothOptions ? (checked ? 'text-primary' : 'text-disabled') : 'text-primary',
bothOptions || textDisabled ? (checked ? 'text-primary' : 'text-disabled') : 'text-primary',
size === 'xs' ? 'text-xs' : 'text-sm',
textClass
)}
@@ -86,7 +94,7 @@
>
{options?.right}
{#if options?.rightTooltip}
<Tooltip light={lightMode}>{options?.rightTooltip}</Tooltip>
<Tooltip light={lightMode} wrapperClass="text-disabled">{options?.rightTooltip}</Tooltip>
{/if}
</span>
{/if}

View File

@@ -114,6 +114,13 @@
contained:
'bg-surface border-transparent hover:bg-surface-hover focus-visible:bg-surface-hover text-primary focus-visible:ring-surface-selected',
divider: 'divide-x divide-gray-200 dark:divide-gray-700'
},
nord: {
border:
'border-nord-200 bg-surface hover:bg-surface-hover focus-visible:bg-surface-hover text-primary hover:text-secondary focus-visible:text-secondary focus-visible:ring-surface-selected-inverse dark:border-nord-200',
contained:
'bg-nord-300 hover:bg-nord-0 focus-visible:bg-surface-hover-inverse text-primary-inverse focus-visible:ring-surface-selected-inverse dark:bg-nord-400 dark:hover:bg-nord-600 dark:text-primary-inverse',
divider: 'divide-x divide-gray-800 dark:divide-gray-200'
}
}

View File

@@ -0,0 +1,69 @@
<script lang="ts">
import Toggle from '$lib/components/Toggle.svelte'
import { FlowService, ScriptService } from '$lib/gen'
import { sendUserToast } from '$lib/toast'
import { workspaceStore } from '$lib/stores'
export let kind: 'script' | 'flow'
export let scriptOrFlowPath: string
export let errorHandlerMuted: boolean | undefined
export let textDisabled = false
let toggleState = errorHandlerMuted
export let color: 'nord' | 'red' | 'blue' = 'nord'
async function toggleErrorHandler(): Promise<void> {
toggleState = !toggleState
if ($workspaceStore !== undefined) {
try {
if (kind === 'flow') {
await FlowService.toggleWorkspaceErrorHandlerForFlow({
workspace: $workspaceStore,
path: scriptOrFlowPath,
requestBody: {
muted: !errorHandlerMuted
}
})
} else {
await ScriptService.toggleWorkspaceErrorHandlerForScript({
workspace: $workspaceStore,
path: scriptOrFlowPath,
requestBody: {
muted: !errorHandlerMuted
}
})
}
} catch (error) {
sendUserToast(
`Error while toggling Workspace Error Handler: ${error.body || error.message}`,
true
)
toggleState = false
return
}
errorHandlerMuted = !errorHandlerMuted
toggleState = errorHandlerMuted
sendUserToast(
errorHandlerMuted ? 'Workspace error handler muted' : 'Workspace error handler active',
false
)
}
toggleState = false
}
$: console.log('toggleState', toggleState)
</script>
<Toggle
{color}
lightToogle={true}
size="sm"
checked={toggleState}
on:change={toggleErrorHandler}
options={{
right: 'Mute',
rightTooltip: 'Disable workspace error handler, EE only'
}}
{textDisabled}
/>

File diff suppressed because it is too large Load Diff

View File

@@ -384,6 +384,20 @@ const config = {
400: '#394A6D',
500: '#323F5B'
},
nord: {
0: '#2E3440',
100: '#3B4252',
200: '#434C5E',
300: '#4C566A',
400: '#D8DEE9',
500: '#E5E9F0',
600: '#ECEFF4',
700: '#8FBCBB',
800: '#88C0D0',
900: '#81A1C1',
950: '#5E81AC'
},
surface: 'rgb(var(--color-surface) / <alpha-value>)',
'surface-secondary': 'rgb(var(--color-surface-secondary) / <alpha-value>)',
'surface-hover': 'rgb(var(--color-surface-hover) / <alpha-value>)',