whitelabel custom settings

This commit is contained in:
Ruben Fiszel
2024-08-02 13:42:14 +02:00
parent 91e364bde5
commit c55d15c0a9
12 changed files with 228 additions and 137 deletions

View File

@@ -219,6 +219,11 @@
"svelte": "./package/components/FlowViewer.svelte",
"default": "./package/components/FlowViewer.svelte"
},
"./components/FlowStatusViewer.svelte": {
"types": "./package/components/FlowStatusViewer.svelte.d.ts",
"svelte": "./package/components/FlowStatusViewer.svelte",
"default": "./package/components/FlowStatusViewer.svelte"
},
"./components/FlowBuilder.svelte": {
"types": "./package/components/FlowBuilder.svelte.d.ts",
"svelte": "./package/components/FlowBuilder.svelte",
@@ -379,6 +384,9 @@
"components/FlowViewer.svelte": [
"./package/components/FlowViewer.svelte.d.ts"
],
"components/FlowStatusViewer.svelte": [
"./package/components/FlowStatusViewer.svelte.d.ts"
],
"components/FlowBuilder.svelte": [
"./package/components/FlowBuilder.svelte.d.ts"
],

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { WorkspaceService, type WorkspaceDefaultScripts } from '$lib/gen'
import { WorkspaceService, type Script, type WorkspaceDefaultScripts } from '$lib/gen'
import { defaultScripts, workspaceStore } from '$lib/stores'
import { flip } from 'svelte/animate'
import Toggle from './Toggle.svelte'
@@ -8,12 +8,12 @@
$: langs = computeLangs($defaultScripts)
function computeLangs(defaultScripts: WorkspaceDefaultScripts | undefined) {
const allLangs = Object.keys(defaultScriptLanguages)
function computeLangs(defaultScripts: WorkspaceDefaultScripts | undefined): Script['language'][] {
const allLangs = Object.keys(defaultScriptLanguages) as Script['language'][]
if (!defaultScripts || defaultScripts.order == undefined) return allLangs
return defaultScripts.order
?.concat(allLangs.filter((l) => !defaultScripts.order?.includes(l)))
.filter((x) => x != 'nativets')
.filter((x) => x != 'nativets') as Script['language'][]
}
async function changePosition(i: number, up: boolean) {
@@ -62,7 +62,10 @@
on:change={(e) => {
let toggled = e.detail
if (toggled) {
defaultScripts.update((s) => ({ ...(s ?? {}), hidden: [...(s?.hidden ?? []), lang] }))
defaultScripts.update((s) => ({
...(s ?? {}),
hidden: [...(s?.hidden ?? []), lang]
}))
} else {
defaultScripts.update((s) => ({
...(s ?? {}),

View File

@@ -471,6 +471,7 @@
} else {
schema.required = schema.required?.filter((x) => x !== argName)
}
dispatch('change', schema)
}}
on:schemaChange={(e) => {
schema = schema

View File

@@ -80,6 +80,7 @@
import { twMerge } from 'tailwind-merge'
import CustomPopover from './CustomPopover.svelte'
import Summary from './Summary.svelte'
import type { WhitelabelCustomUi } from './custom_ui'
export let initialPath: string = ''
export let pathStoreInit: string | undefined = undefined
@@ -95,6 +96,9 @@
})
| undefined = undefined
export let diffDrawer: DiffDrawer | undefined = undefined
export let customUi: WhitelabelCustomUi = {}
$: setContext('customUi', customUi)
const dispatch = createEventDispatcher()
@@ -1010,26 +1014,40 @@
}
}
const moreItems: {
let moreItems: {
displayName: string
icon: ComponentType<Icon>
action: () => void
disabled?: boolean
}[] = [
{
displayName: 'Deployment History',
icon: HistoryIcon,
action: () => {
flowHistory?.open()
},
disabled: newFlow
},
{
displayName: 'Export',
icon: FileJson,
action: () => jsonViewerDrawer?.openDrawer()
}
]
}[] = []
$: onCustomUiChange(customUi)
function onCustomUiChange(customUi: WhitelabelCustomUi | undefined) {
moreItems = [
...(customUi?.topBar?.history != false
? [
{
displayName: 'Deployment History',
icon: HistoryIcon,
action: () => {
flowHistory?.open()
},
disabled: newFlow
}
]
: []),
...(customUi?.topBar?.history != false
? [
{
displayName: 'Export',
icon: FileJson,
action: () => jsonViewerDrawer?.openDrawer()
}
]
: [])
]
}
let deploymentMsg = ''
let msgInput: HTMLInputElement | undefined = undefined
@@ -1117,104 +1135,112 @@
{$scheduleStore.cron ?? ''}
</Button>
{/if}
<div class="flex justify-start w-full">
<div>
<button
on:click={async () => {
select('settings-metadata')
document.getElementById('path')?.focus()
}}
>
<Badge
color="gray"
class="center-center !bg-gray-300 !text-tertiary dark:!bg-gray-700 dark:!text-gray-300 !h-[28px] !w-[70px] rounded-r-none"
{#if customUi?.topBar?.path != false}
<div class="flex justify-start w-full">
<div>
<button
on:click={async () => {
select('settings-metadata')
document.getElementById('path')?.focus()
}}
>
<Pen size={12} class="mr-2" /> Path
</Badge>
</button>
<Badge
color="gray"
class="center-center !bg-gray-300 !text-tertiary dark:!bg-gray-700 dark:!text-gray-300 !h-[28px] !w-[70px] rounded-r-none"
>
<Pen size={12} class="mr-2" /> Path
</Badge>
</button>
</div>
<input
type="text"
readonly
value={$pathStore && $pathStore != '' ? $pathStore : 'Choose a path'}
class="font-mono !text-xs !min-w-[96px] !max-w-[300px] !w-full !h-[28px] !my-0 !py-0 !border-l-0 !rounded-l-none"
on:focus={({ currentTarget }) => {
currentTarget.select()
}}
/>
</div>
<input
type="text"
readonly
value={$pathStore && $pathStore != '' ? $pathStore : 'Choose a path'}
class="font-mono !text-xs !min-w-[96px] !max-w-[300px] !w-full !h-[28px] !my-0 !py-0 !border-l-0 !rounded-l-none"
on:focus={({ currentTarget }) => {
currentTarget.select()
}}
/>
</div>
{/if}
</div>
<div class="flex flex-row gap-2 items-center">
{#if $enterpriseLicense && !newFlow}
<Awareness />
{/if}
<div>
<ButtonDropdown hasPadding={false}>
<svelte:fragment slot="buttonReplacement">
<Button nonCaptureEvent size="xs" color="light">
<div class="flex flex-row items-center">
<MoreVertical size={14} />
</div>
</Button>
</svelte:fragment>
<svelte:fragment slot="items">
{#each moreItems as item}
<MenuItem
on:click={item.action}
disabled={item.disabled}
class={item.disabled ? 'opacity-50' : ''}
>
<div
class={twMerge(
'text-primary flex flex-row items-center text-left px-4 py-2 gap-2 cursor-pointer hover:bg-surface-hover !text-xs font-semibold'
)}
>
<svelte:component this={item.icon} size={14} />
{item.displayName}
{#if moreItems?.length > 0}
<ButtonDropdown hasPadding={false}>
<svelte:fragment slot="buttonReplacement">
<Button nonCaptureEvent size="xs" color="light">
<div class="flex flex-row items-center">
<MoreVertical size={14} />
</div>
</MenuItem>
{/each}
</svelte:fragment>
</ButtonDropdown>
</Button>
</svelte:fragment>
<svelte:fragment slot="items">
{#each moreItems as item}
<MenuItem
on:click={item.action}
disabled={item.disabled}
class={item.disabled ? 'opacity-50' : ''}
>
<div
class={twMerge(
'text-primary flex flex-row items-center text-left px-4 py-2 gap-2 cursor-pointer hover:bg-surface-hover !text-xs font-semibold'
)}
>
<svelte:component this={item.icon} size={14} />
{item.displayName}
</div>
</MenuItem>
{/each}
</svelte:fragment>
</ButtonDropdown>
{/if}
</div>
<FlowBuilderTutorials
on:reload={() => {
renderCount += 1
}}
/>
<Button
color="light"
variant="border"
size="xs"
on:click={() => {
if (!savedFlow) {
return
}
diffDrawer?.openDrawer()
diffDrawer?.setDiff({
mode: 'normal',
deployed: savedFlow,
draft: savedFlow['draft'],
current: { ...$flowStore, path: $pathStore }
})
}}
disabled={!savedFlow}
>
<div class="flex flex-row gap-2 items-center">
<DiffIcon size={14} />
Diff
</div>
</Button>
<FlowCopilotStatus
{copilotLoading}
bind:copilotStatus
{genFlow}
{finishCopilotFlowBuilder}
{abortController}
/>
{#if customUi?.topBar?.tutorials != false}
<FlowBuilderTutorials
on:reload={() => {
renderCount += 1
}}
/>
{/if}
{#if customUi?.topBar?.diff != false}
<Button
color="light"
variant="border"
size="xs"
on:click={() => {
if (!savedFlow) {
return
}
diffDrawer?.openDrawer()
diffDrawer?.setDiff({
mode: 'normal',
deployed: savedFlow,
draft: savedFlow['draft'],
current: { ...$flowStore, path: $pathStore }
})
}}
disabled={!savedFlow}
>
<div class="flex flex-row gap-2 items-center">
<DiffIcon size={14} />
Diff
</div>
</Button>
{/if}
{#if customUi?.topBar?.aiBuilder != false}
<FlowCopilotStatus
{copilotLoading}
bind:copilotStatus
{genFlow}
{finishCopilotFlowBuilder}
{abortController}
/>
{/if}
<FlowPreviewButtons />
<Button
loading={loadingDraft}
@@ -1270,6 +1296,8 @@
<!-- metadata -->
{#if $flowStateStore}
<FlowEditor
enableAi={customUi?.stepInputs?.ai != false}
disableSettings={customUi?.settingsPanel === false}
{loading}
on:reload={() => {
renderCount += 1

View File

@@ -73,7 +73,7 @@
on:close
>
<aside
class="drawer {$$props.class ?? ''} {$$props.positionClass ?? ''}"
class="drawer windmill-drawer {$$props.class ?? ''} {$$props.positionClass ?? ''}"
class:open
class:close={!open && timeout}
style={`${style}; --zIndex: ${zIndex};`}

View File

@@ -0,0 +1,21 @@
import type { SupportedLanguage } from '$lib/common'
export type WhitelabelCustomUi = {
topBar?: {
path?: boolean
export?: boolean
history?: boolean
aiBuilder?: boolean
tutorials?: boolean
diff?: boolean
}
settingsPanel?: boolean
triggers?: boolean
flowNode?: boolean
hub?: boolean
graph?: { aiBuilder?: boolean; dataflow?: boolean }
stepInputs?: { ai?: boolean }
stepAdvancedSettings?: boolean
languages?: (SupportedLanguage | 'docker' | 'bunnative')[]
scriptFork?: boolean
}

View File

@@ -12,6 +12,12 @@
const { flowStore } = getContext<FlowEditorContext>('FlowEditorContext')
export let loading: boolean
export let disableStaticInputs = false
export let disableTutorials = false
export let disableAi = false
export let disableSettings = false
export let smallErrorHandler = false
export let enableAi = true
let size = 40
@@ -35,7 +41,15 @@
{/each}
</div>
{:else if $flowStore.value.modules}
<FlowModuleSchemaMap bind:modules={$flowStore.value.modules} on:reload />
<FlowModuleSchemaMap
{disableStaticInputs}
{disableTutorials}
{disableAi}
{disableSettings}
{smallErrorHandler}
bind:modules={$flowStore.value.modules}
on:reload
/>
{/if}
</div>
</Pane>
@@ -47,7 +61,7 @@
</div>
</div>
{:else}
<FlowEditorPanel enableAi />
<FlowEditorPanel {enableAi} />
{/if}
</Pane>
</Splitpanes>

View File

@@ -3,7 +3,7 @@
import ToggleHubWorkspace from '$lib/components/ToggleHubWorkspace.svelte'
import Tooltip from '$lib/components/Tooltip.svelte'
import { createEventDispatcher } from 'svelte'
import { createEventDispatcher, getContext } from 'svelte'
import FlowScriptPicker from '../pickers/FlowScriptPicker.svelte'
import PickHubScript from '../pickers/PickHubScript.svelte'
import WorkspaceScriptPicker from '../pickers/WorkspaceScriptPicker.svelte'
@@ -17,6 +17,7 @@
import { defaultScriptLanguages, processLangs } from '$lib/scripts'
import type { SupportedLanguage } from '$lib/common'
import DefaultScripts from '$lib/components/DefaultScripts.svelte'
import type { WhitelabelCustomUi } from '$lib/components/custom_ui'
export let failureModule: boolean
export let shouldDisableTriggerScripts: boolean = false
@@ -53,6 +54,8 @@
}
return kind == 'script' && !failureModule
}
let customUi: undefined | WhitelabelCustomUi = getContext('customUi')
</script>
<div class="p-4 h-full flex flex-col" id="flow-editor-flow-inputs">
@@ -193,7 +196,7 @@
<div class="pb-2" />
{/if}
<div class="flex flex-row flex-wrap gap-2" id="flow-editor-action-script">
{#each langs as [label, lang] (lang)}
{#each langs.filter((lang) => customUi?.languages == undefined || customUi?.languages?.includes(lang?.[1])) as [label, lang] (lang)}
{#if displayLang(lang, kind)}
<FlowScriptPicker
id={`flow-editor-action-script-${lang}`}

View File

@@ -19,12 +19,14 @@
import { sendUserToast } from '$lib/utils'
import { workerTags } from '$lib/stores'
import { getLatestHashForScript } from '$lib/scripts'
import type { WhitelabelCustomUi } from '$lib/components/custom_ui'
export let module: FlowModule
const { scriptEditorDrawer, flowStore, selectedId } =
getContext<FlowEditorContext>('FlowEditorContext')
const dispatch = createEventDispatcher()
let customUi: undefined | WhitelabelCustomUi = getContext('customUi')
loadWorkerGroups()
@@ -132,15 +134,17 @@
Edit {#if module.value.hash != undefined} (locked hash){/if}
</Button>
{/if}
<Button
size="xs"
color="light"
on:click={() => dispatch('fork')}
startIcon={{ icon: GitFork }}
iconOnly={false}
>
Fork
</Button>
{#if customUi?.scriptFork != false}
<Button
size="xs"
color="light"
on:click={() => dispatch('fork')}
startIcon={{ icon: GitFork }}
iconOnly={false}
>
Fork
</Button>
{/if}
{/if}
<div class="px-0.5" />
{#if module.value.type === 'rawscript'}

View File

@@ -35,6 +35,8 @@
export let disableStaticInputs = false
export let disableTutorials = false
export let disableAi = false
export let disableSettings = false
export let smallErrorHandler = false
let flowTutorials: FlowTutorials | undefined = undefined
@@ -240,7 +242,9 @@
{#if $copilotCurrentStepStore !== undefined}
<div transition:fade class="absolute inset-0 bg-gray-500 bg-opacity-75 z-[900] !m-0" />
{/if}
<FlowSettingsItem />
{#if !disableSettings}
<FlowSettingsItem />
{/if}
{#if !disableStaticInputs}
<FlowConstantsItem />
{/if}

View File

@@ -1,10 +1,11 @@
<script lang="ts">
import { Menu } from '$lib/components/common'
import { createEventDispatcher } from 'svelte'
import { createEventDispatcher, getContext } from 'svelte'
import { CheckCircle2, Code, Cross, GitBranch, Repeat, Square, Zap } from 'lucide-svelte'
import StepGen from '$lib/components/copilot/StepGen.svelte'
import type { FlowModule } from '$lib/gen'
import BarsStaggered from '$lib/components/icons/BarsStaggered.svelte'
import type { WhitelabelCustomUi } from '$lib/components/custom_ui'
const dispatch = createEventDispatcher()
export let trigger = false
@@ -16,6 +17,7 @@
export let disableAi = false
$: !open && (funcDesc = '')
let customUi: undefined | WhitelabelCustomUi = getContext('customUi')
</script>
<Menu
@@ -52,7 +54,7 @@
<Code size={14} />
Action
</button>
{#if trigger}
{#if customUi?.triggers != false && trigger}
<button
class="w-full text-left py-2 px-3 hover:bg-surface-hover whitespace-nowrap flex flex-row gap-2 items-center"
on:pointerdown={() => {
@@ -128,17 +130,19 @@
Branch to all
</button>
<button
class="w-full text-left py-2 px-3 hover:bg-surface-hover rounded-none whitespace-nowrap flex flex-row gap-2 items-center"
on:pointerdown={() => {
close()
dispatch('new', 'flow')
}}
role="menuitem"
>
<BarsStaggered size={14} />
Flow
</button>
{#if customUi?.flowNode != false}
<button
class="w-full text-left py-2 px-3 hover:bg-surface-hover rounded-none whitespace-nowrap flex flex-row gap-2 items-center"
on:pointerdown={() => {
close()
dispatch('new', 'flow')
}}
role="menuitem"
>
<BarsStaggered size={14} />
Flow
</button>
{/if}
{#if stop}
<button
class="w-full text-left py-2 px-3 hover:bg-surface-hover inline-flex gap-2.5"

View File

@@ -71,6 +71,7 @@
!$selectedId.startsWith('settings') &&
$selectedId !== 'failure' &&
$selectedId !== 'Result'
let dataflow = false
let dispatch = createEventDispatcher()