mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 16:02:14 +00:00
whitelabel custom settings
This commit is contained in:
@@ -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"
|
||||
],
|
||||
|
||||
@@ -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 ?? {}),
|
||||
|
||||
@@ -471,6 +471,7 @@
|
||||
} else {
|
||||
schema.required = schema.required?.filter((x) => x !== argName)
|
||||
}
|
||||
dispatch('change', schema)
|
||||
}}
|
||||
on:schemaChange={(e) => {
|
||||
schema = schema
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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};`}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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}`}
|
||||
|
||||
@@ -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'}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
!$selectedId.startsWith('settings') &&
|
||||
$selectedId !== 'failure' &&
|
||||
$selectedId !== 'Result'
|
||||
|
||||
let dataflow = false
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
|
||||
Reference in New Issue
Block a user