mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 00:02:13 +00:00
fix(frontend): schedule operator perms + add instance settings in operator menu (#4912)
* fix(frontend): schedule operator perms + add instance settings in operator menu * fix npm timeout * forgot
This commit is contained in:
@@ -15,7 +15,6 @@ jobs:
|
||||
with:
|
||||
node-version: 18
|
||||
- name: "npm check"
|
||||
timeout-minutes: 2
|
||||
run:
|
||||
cd frontend && npm ci && npm run generate-backend-client && npm run
|
||||
timeout-minutes: 5
|
||||
run: cd frontend && npm ci && npm run generate-backend-client && npm run
|
||||
check
|
||||
|
||||
@@ -7,14 +7,16 @@
|
||||
|
||||
export let placement: 'bottom-end' | 'top-end' = 'bottom-end'
|
||||
export let color: 'nord' | 'dark' = 'dark'
|
||||
export let disabled = false
|
||||
</script>
|
||||
|
||||
<Popup
|
||||
floatingConfig={{ strategy: 'absolute', placement: placement }}
|
||||
containerClasses="border rounded-lg shadow-lg p-4 bg-surface"
|
||||
{disabled}
|
||||
>
|
||||
<svelte:fragment slot="button">
|
||||
<Button {color} size="xs" nonCaptureEvent={true}>
|
||||
<Button {color} size="xs" nonCaptureEvent={true} {disabled}>
|
||||
<div class="flex flex-row gap-1 items-center"
|
||||
><Pen size={14} /> Custom tags <Tooltip light
|
||||
>Tags are assigned to scripts and flows. Workers only accept jobs that correspond to their
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
export let items: Item[] | (() => Item[]) | (() => Promise<Item[]>) = []
|
||||
export let justifyEnd: boolean = true
|
||||
export let disabled = false
|
||||
|
||||
async function computeItems(): Promise<Item[]> {
|
||||
if (typeof items === 'function') {
|
||||
@@ -26,7 +27,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<Menu placement="bottom-end" {justifyEnd} on:close on:open>
|
||||
<Menu placement="bottom-end" {justifyEnd} on:close on:open {disabled}>
|
||||
<div slot="trigger">
|
||||
{#if $$slots.buttonReplacement}
|
||||
<slot name="buttonReplacement" />
|
||||
|
||||
@@ -1105,6 +1105,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
let timeoutModel: NodeJS.Timeout | undefined = undefined
|
||||
async function loadMonaco() {
|
||||
try {
|
||||
console.log("Loading Monaco's language client")
|
||||
@@ -1143,7 +1144,6 @@
|
||||
|
||||
// updateEditorKeybindingsMode(editor, 'vim', undefined)
|
||||
|
||||
let timeoutModel: NodeJS.Timeout | undefined = undefined
|
||||
let ataModel: NodeJS.Timeout | undefined = undefined
|
||||
|
||||
editor?.onDidChangeModelContent((event) => {
|
||||
@@ -1316,6 +1316,7 @@
|
||||
sqlSchemaCompletor && sqlSchemaCompletor.dispose()
|
||||
copilotCompletor && copilotCompletor.dispose()
|
||||
sqlTypeCompletor && sqlTypeCompletor.dispose()
|
||||
timeoutModel && clearTimeout(timeoutModel)
|
||||
})
|
||||
|
||||
async function genRoot(hostname: string) {
|
||||
|
||||
@@ -191,8 +191,8 @@
|
||||
|
||||
<div>
|
||||
<Tabs bind:selected={handlerSelected} class="mt-2 mb-4">
|
||||
<Tab value="slack">Slack</Tab>
|
||||
<Tab value="custom">
|
||||
<Tab value="slack" disabled={!isEditable}>Slack</Tab>
|
||||
<Tab value="custom" disabled={!isEditable}>
|
||||
Custom
|
||||
<slot name="custom-tab-tooltip" />
|
||||
</Tab>
|
||||
@@ -208,7 +208,7 @@
|
||||
allowFlow={true}
|
||||
bind:scriptPath={handlerPath}
|
||||
bind:itemKind={customHandlerKind}
|
||||
allowRefresh
|
||||
allowRefresh={isEditable}
|
||||
/>
|
||||
|
||||
{#if handlerPath === undefined}
|
||||
@@ -217,6 +217,7 @@
|
||||
color="dark"
|
||||
size="xs"
|
||||
href={customScriptTemplate}
|
||||
disabled={!isEditable}
|
||||
target="_blank">Create from template</Button
|
||||
>
|
||||
{/if}
|
||||
|
||||
@@ -218,11 +218,13 @@
|
||||
async function loadScript(p: string | undefined): Promise<void> {
|
||||
if (p) {
|
||||
runnable = undefined
|
||||
if (is_flow) {
|
||||
runnable = await FlowService.getFlowByPath({ workspace: $workspaceStore!, path: p })
|
||||
} else {
|
||||
runnable = await ScriptService.getScriptByPath({ workspace: $workspaceStore!, path: p })
|
||||
}
|
||||
try {
|
||||
if (is_flow) {
|
||||
runnable = await FlowService.getFlowByPath({ workspace: $workspaceStore!, path: p })
|
||||
} else {
|
||||
runnable = await ScriptService.getScriptByPath({ workspace: $workspaceStore!, path: p })
|
||||
}
|
||||
} catch (err) {}
|
||||
} else {
|
||||
runnable = undefined
|
||||
}
|
||||
@@ -524,7 +526,11 @@
|
||||
|
||||
<Drawer size="900px" bind:this={drawer}>
|
||||
<DrawerContent
|
||||
title={edit ? `Edit schedule ${initialPath}` : 'New schedule'}
|
||||
title={edit
|
||||
? can_write
|
||||
? `Edit schedule ${initialPath}`
|
||||
: `View schedule ${initialPath}`
|
||||
: 'New schedule'}
|
||||
on:close={drawer.closeDrawer}
|
||||
>
|
||||
<svelte:fragment slot="actions">
|
||||
@@ -541,22 +547,24 @@
|
||||
View runs
|
||||
</Button>
|
||||
</div>
|
||||
<div class="mr-8 center-center -mt-1">
|
||||
<Toggle
|
||||
disabled={!can_write}
|
||||
checked={enabled}
|
||||
options={{ right: 'Enabled' }}
|
||||
on:change={async (e) => {
|
||||
await ScheduleService.setScheduleEnabled({
|
||||
path: initialPath,
|
||||
workspace: $workspaceStore ?? '',
|
||||
requestBody: { enabled: e.detail }
|
||||
})
|
||||
dispatch('update')
|
||||
sendUserToast(`${e.detail ? 'enabled' : 'disabled'} schedule ${initialPath}`)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{#if can_write}
|
||||
<div class="mr-8 center-center -mt-1">
|
||||
<Toggle
|
||||
disabled={!can_write}
|
||||
checked={enabled}
|
||||
options={{ right: 'Enabled' }}
|
||||
on:change={async (e) => {
|
||||
await ScheduleService.setScheduleEnabled({
|
||||
path: initialPath,
|
||||
workspace: $workspaceStore ?? '',
|
||||
requestBody: { enabled: e.detail }
|
||||
})
|
||||
dispatch('update')
|
||||
sendUserToast(`${e.detail ? 'enabled' : 'disabled'} schedule ${initialPath}`)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
<Button
|
||||
startIcon={{ icon: Save }}
|
||||
@@ -565,7 +573,8 @@
|
||||
emptyString(script_path) ||
|
||||
(errorHandlerSelected == 'slack' &&
|
||||
!emptyString(errorHandlerPath) &&
|
||||
emptyString(errorHandlerExtraArgs['channel']))}
|
||||
emptyString(errorHandlerExtraArgs['channel'])) ||
|
||||
!can_write}
|
||||
on:click={scheduleScript}
|
||||
>
|
||||
{edit ? 'Save' : 'Schedule'}
|
||||
@@ -575,6 +584,7 @@
|
||||
{#if drawerLoading}
|
||||
<Loader2 class="animate-spin" />
|
||||
{:else}
|
||||
{can_write}
|
||||
<div class="flex flex-col gap-12">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
@@ -587,6 +597,7 @@
|
||||
placeholder="Short summary to be displayed when listed"
|
||||
class="text-sm w-full"
|
||||
bind:value={summary}
|
||||
disabled={!can_write}
|
||||
on:keyup={() => {
|
||||
if (!edit && summary?.length > 0 && !dirtyPath) {
|
||||
pathC?.setName(
|
||||
@@ -664,6 +675,7 @@
|
||||
size="xs"
|
||||
bind:checked={isLatestCron}
|
||||
on:change={onVersionChange}
|
||||
disabled={!can_write}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -682,6 +694,7 @@
|
||||
}}
|
||||
bind:checked={showPauseUntil}
|
||||
size="xs"
|
||||
disabled={!can_write}
|
||||
/>
|
||||
{#if showPauseUntil}
|
||||
<DateTimeInput bind:value={paused_until} />
|
||||
@@ -715,6 +728,8 @@
|
||||
scriptPath={script_path}
|
||||
allowFlow={true}
|
||||
{itemKind}
|
||||
allowView={script_path != '' && !!runnable}
|
||||
allowEdit={script_path != '' && !!runnable && !$userStore?.operator}
|
||||
/>
|
||||
{/if}
|
||||
{#if itemKind == 'flow'}
|
||||
@@ -752,6 +767,11 @@
|
||||
This {is_flow ? 'flow' : 'script'} takes no argument
|
||||
</div>
|
||||
{/if}
|
||||
{:else if script_path != ''}
|
||||
<div class="text-xs texg-gray-700 my-2">
|
||||
You cannot see the the {is_flow ? 'flow' : 'script'} input form as you do not have
|
||||
access to it.
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-xs texg-gray-700 my-2">
|
||||
Pick a {is_flow ? 'flow' : 'script'} and fill its argument here
|
||||
@@ -787,6 +807,7 @@
|
||||
<div class="flex flex-row items-center gap-1 text-2xs text-tertiary">
|
||||
defaults
|
||||
<Dropdown
|
||||
disabled={!can_write}
|
||||
items={[
|
||||
{
|
||||
displayName: `Override future schedules only`,
|
||||
@@ -879,6 +900,7 @@
|
||||
</div>
|
||||
</Section>
|
||||
{:else if optionTabSelected === 'recovery_handler'}
|
||||
{@const disabled = !can_write || emptyString($enterpriseLicense)}
|
||||
<Section label="Recovery handler">
|
||||
<svelte:fragment slot="header">
|
||||
<div class="flex flex-row gap-2">
|
||||
@@ -890,6 +912,7 @@
|
||||
<div class="flex flex-row items-center text-tertiary text-2xs gap-2">
|
||||
defaults
|
||||
<Dropdown
|
||||
{disabled}
|
||||
items={[
|
||||
{
|
||||
displayName: `Override future schedules only`,
|
||||
@@ -910,7 +933,7 @@
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<ErrorOrRecoveryHandler
|
||||
isEditable={can_write && !emptyString($enterpriseLicense)}
|
||||
isEditable={!disabled}
|
||||
errorOrRecovery="recovery"
|
||||
bind:handlerSelected={recoveryHandlerSelected}
|
||||
bind:handlerPath={recoveryHandlerPath}
|
||||
@@ -963,12 +986,14 @@
|
||||
class="!w-14 mx-2 text-center"
|
||||
bind:value={recoveredTimes}
|
||||
min="1"
|
||||
{disabled}
|
||||
/>
|
||||
<p>time{recoveredTimes > 1 ? 's in a row' : ''}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
{:else if optionTabSelected === 'success_handler'}
|
||||
{@const disabled = !can_write || emptyString($enterpriseLicense)}
|
||||
<Section label="Success handler">
|
||||
<svelte:fragment slot="header">
|
||||
<div class="flex flex-row gap-2">
|
||||
@@ -980,6 +1005,7 @@
|
||||
<div class="flex flex-row items-center text-tertiary text-2xs gap-2">
|
||||
defaults
|
||||
<Dropdown
|
||||
{disabled}
|
||||
items={[
|
||||
{
|
||||
displayName: `Override future schedules only`,
|
||||
@@ -1000,7 +1026,7 @@
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<ErrorOrRecoveryHandler
|
||||
isEditable={can_write && !emptyString($enterpriseLicense)}
|
||||
isEditable={!disabled}
|
||||
errorOrRecovery="success"
|
||||
bind:handlerSelected={successHandlerSelected}
|
||||
bind:handlerPath={successHandlerPath}
|
||||
@@ -1031,6 +1057,7 @@
|
||||
</ErrorOrRecoveryHandler>
|
||||
</Section>
|
||||
{:else if optionTabSelected === 'retries'}
|
||||
{@const disabled = !can_write || emptyString($enterpriseLicense)}
|
||||
<Section label="Retries">
|
||||
<svelte:fragment slot="header">
|
||||
<div class="flex flex-row gap-2">
|
||||
@@ -1045,14 +1072,17 @@
|
||||
flow step in the flow editor.
|
||||
</Tooltip>
|
||||
</svelte:fragment>
|
||||
<FlowRetries bind:flowModuleRetry={retry} disabled={itemKind !== 'script'} />
|
||||
<FlowRetries
|
||||
bind:flowModuleRetry={retry}
|
||||
disabled={itemKind !== 'script' || disabled}
|
||||
/>
|
||||
</Section>
|
||||
{:else if optionTabSelected === 'tag'}
|
||||
<Section
|
||||
label="Custom script tag"
|
||||
tooltip="When set, the script tag will be overridden by this tag"
|
||||
>
|
||||
<WorkerTagPicker bind:tag popupPlacement="top-end" />
|
||||
<WorkerTagPicker bind:tag popupPlacement="top-end" disabled={!can_write} />
|
||||
</Section>
|
||||
{/if}
|
||||
{:else}
|
||||
|
||||
@@ -220,8 +220,8 @@
|
||||
) {
|
||||
scriptEditor?.disableCollaboration()
|
||||
script.content = initialCode(language, kind, template)
|
||||
scriptEditor?.inferSchema(script.content, language)
|
||||
if (script.content != editor?.getCode() && editor?.getScriptLang() == language) {
|
||||
scriptEditor?.inferSchema(script.content, language, true)
|
||||
if (script.content != editor?.getCode()) {
|
||||
setCode(script.content)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
let hasPreprocessor = false
|
||||
|
||||
export async function inferSchema(code: string, nlang?: SupportedLanguage) {
|
||||
export async function inferSchema(code: string, nlang?: SupportedLanguage, resetArgs = false) {
|
||||
let nschema = schema ?? emptySchema()
|
||||
|
||||
try {
|
||||
@@ -142,6 +142,9 @@
|
||||
(selectedTab === 'preprocessor' ? !result?.no_main_func : result?.has_preprocessor) ?? false
|
||||
|
||||
validCode = true
|
||||
if (resetArgs) {
|
||||
args = {}
|
||||
}
|
||||
schema = nschema
|
||||
} catch (e) {
|
||||
validCode = false
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
export let disabled = false
|
||||
export let allowRefresh = false
|
||||
export let allowEdit = true
|
||||
export let allowView = true
|
||||
|
||||
let items: { value: string; label: string }[] = []
|
||||
let drawerViewer: Drawer
|
||||
@@ -138,16 +139,18 @@
|
||||
href="{base}/flows/edit/{scriptPath}">Edit</Button
|
||||
>
|
||||
{/if}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
variant="border"
|
||||
on:click={async () => {
|
||||
drawerFlowViewer.openDrawer()
|
||||
}}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
{#if allowView}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
variant="border"
|
||||
on:click={async () => {
|
||||
drawerFlowViewer.openDrawer()
|
||||
}}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if itemKind == 'app'}
|
||||
<div class="flex gap-2">
|
||||
@@ -163,16 +166,18 @@
|
||||
Edit
|
||||
</Button>
|
||||
{/if}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
variant="border"
|
||||
target="_blank"
|
||||
startIcon={{ icon: Code }}
|
||||
href="{base}/apps/get/{scriptPath}"
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
{#if allowView}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
variant="border"
|
||||
target="_blank"
|
||||
startIcon={{ icon: Code }}
|
||||
href="{base}/apps/get/{scriptPath}"
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex gap-2">
|
||||
@@ -188,20 +193,22 @@
|
||||
Edit
|
||||
</Button>
|
||||
{/if}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
variant="border"
|
||||
startIcon={{ icon: Code }}
|
||||
on:click={async () => {
|
||||
const { language, content } = await getScriptByPath(scriptPath ?? '')
|
||||
code = content
|
||||
lang = language
|
||||
drawerViewer.openDrawer()
|
||||
}}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
{#if allowView}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
variant="border"
|
||||
startIcon={{ icon: Code }}
|
||||
on:click={async () => {
|
||||
const { language, content } = await getScriptByPath(scriptPath ?? '')
|
||||
code = content
|
||||
lang = language
|
||||
drawerViewer.openDrawer()
|
||||
}}
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
export let tag: string | undefined
|
||||
export let popupPlacement: 'bottom-end' | 'top-end' = 'bottom-end'
|
||||
export let disabled = false
|
||||
|
||||
loadWorkerGroups()
|
||||
async function loadWorkerGroups() {
|
||||
@@ -21,7 +22,7 @@
|
||||
<div class="max-w-sm grow">
|
||||
{#if $workerTags}
|
||||
{#if $workerTags?.length ?? 0 > 0}
|
||||
<WorkerTagSelect noLabel bind:tag />
|
||||
<WorkerTagSelect noLabel bind:tag {disabled} />
|
||||
{:else}
|
||||
<div class="text-sm text-secondary flex flex-row gap-2">
|
||||
No custom worker group tag defined on this instance in "Workers {'->'} Custom tags"
|
||||
@@ -50,6 +51,7 @@
|
||||
loadWorkerGroups()
|
||||
}}
|
||||
startIcon={{ icon: RotateCw }}
|
||||
{disabled}
|
||||
/>
|
||||
<AssignableTags placement={popupPlacement} color="nord" />
|
||||
<AssignableTags placement={popupPlacement} color="nord" {disabled} />
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
export let tag: string | undefined
|
||||
export let noLabel: boolean = false
|
||||
export let nullTag: string | undefined = undefined
|
||||
export let disabled = false
|
||||
|
||||
loadWorkerGroups()
|
||||
|
||||
@@ -28,6 +29,7 @@
|
||||
tag = undefined
|
||||
}
|
||||
}}
|
||||
{disabled}
|
||||
>
|
||||
{#if tag}
|
||||
<option value="">reset to default</option>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
export let justifyEnd: boolean = false
|
||||
export let lightMode: boolean = false
|
||||
export let maxHeight: number = 900
|
||||
export let disabled = false
|
||||
const [floatingRef, floatingContent] = createFloatingActions({
|
||||
strategy: 'fixed',
|
||||
middleware: [offset(), flip(), shift()],
|
||||
@@ -18,10 +19,10 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<Menu let:open as="div" class="relative hover:z-50 flex w-full h-8">
|
||||
<Menu let:open as="div" class="relative hover:z-50 flex w-full h-8">
|
||||
<ResolveOpen {open} on:open on:close />
|
||||
<div use:floatingRef class="w-full">
|
||||
<MenuButton class={twMerge('w-full', justifyEnd ? 'flex justify-end' : '')}>
|
||||
<MenuButton class={twMerge('w-full', justifyEnd ? 'flex justify-end' : '')} disabled={disabled}>
|
||||
<slot name="trigger" />
|
||||
</MenuButton>
|
||||
</div>
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
export let noTransition = false
|
||||
export let popupHover = false
|
||||
export let preventPopupClosingOnClickInside = false
|
||||
export let disabled = false
|
||||
</script>
|
||||
|
||||
<Popover on:close class="leading-none">
|
||||
<PopoverButton let:open>
|
||||
<PopoverButton let:open {disabled}>
|
||||
<div use:floatingRef>
|
||||
<slot name="button" {open} />
|
||||
</div>
|
||||
|
||||
@@ -10,14 +10,15 @@
|
||||
Code2,
|
||||
LayoutDashboard,
|
||||
Building,
|
||||
Calendar
|
||||
Calendar,
|
||||
ServerCog
|
||||
} from 'lucide-svelte'
|
||||
import { base } from '$lib/base'
|
||||
|
||||
import Menu from '../common/menu/MenuV2.svelte'
|
||||
|
||||
import MultiplayerMenu from './MultiplayerMenu.svelte'
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import { enterpriseLicense, superadmin } from '$lib/stores'
|
||||
import MenuButton from './MenuButton.svelte'
|
||||
import { MenuItem } from '@rgossiaux/svelte-headlessui'
|
||||
import MenuLink from './MenuLink.svelte'
|
||||
@@ -43,10 +44,6 @@
|
||||
]
|
||||
|
||||
let secondMenuLinks = [
|
||||
{
|
||||
label: 'Schedules',
|
||||
href: `${base}/schedules`
|
||||
},
|
||||
{
|
||||
label: 'Resources',
|
||||
href: `${base}/resources`
|
||||
@@ -55,6 +52,18 @@
|
||||
label: 'Variables',
|
||||
href: `${base}/variables`
|
||||
},
|
||||
{
|
||||
label: 'Custom HTTP Routes',
|
||||
href: `${base}/routes`
|
||||
},
|
||||
{
|
||||
label: 'Websocket Triggers',
|
||||
href: `${base}/websockets`
|
||||
},
|
||||
{
|
||||
label: 'Kafka Triggers',
|
||||
href: `${base}/kafka`
|
||||
},
|
||||
{
|
||||
label: 'Audit Logs',
|
||||
href: `${base}/audit_logs`
|
||||
@@ -158,6 +167,20 @@
|
||||
All Workspaces
|
||||
</a>
|
||||
|
||||
{#if $superadmin}
|
||||
<MenuItem
|
||||
href="#superadmin-settings"
|
||||
class={twMerge(
|
||||
'flex flex-row gap-3.5 items-center px-2 py-2 ',
|
||||
'text-secondary text-xs',
|
||||
'hover:bg-surface-hover hover:text-primary cursor-pointer'
|
||||
)}
|
||||
>
|
||||
<ServerCog size={14} />
|
||||
Instance settings
|
||||
</MenuItem>
|
||||
{/if}
|
||||
|
||||
<MenuItem
|
||||
href="#"
|
||||
on:click={() => logout()}
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
on:close={drawer.closeDrawer}
|
||||
>
|
||||
<svelte:fragment slot="actions">
|
||||
{#if !drawerLoading && can_write}
|
||||
{#if !drawerLoading}
|
||||
{#if edit}
|
||||
<div class="mr-8 center-center -mt-1">
|
||||
<Toggle
|
||||
@@ -169,21 +169,23 @@
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<Button
|
||||
startIcon={{ icon: Save }}
|
||||
disabled={pathError != '' ||
|
||||
emptyString(script_path) ||
|
||||
emptyString(kafka_resource_path) ||
|
||||
topics.length < 1 ||
|
||||
topics.some((t) => emptyString(t)) ||
|
||||
topicsError != '' ||
|
||||
emptyString(group_id) ||
|
||||
groupIdError != '' ||
|
||||
!can_write}
|
||||
on:click={updateTrigger}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
{#if can_write}
|
||||
<Button
|
||||
startIcon={{ icon: Save }}
|
||||
disabled={pathError != '' ||
|
||||
emptyString(script_path) ||
|
||||
emptyString(kafka_resource_path) ||
|
||||
topics.length < 1 ||
|
||||
topics.some((t) => emptyString(t)) ||
|
||||
topicsError != '' ||
|
||||
emptyString(group_id) ||
|
||||
groupIdError != '' ||
|
||||
!can_write}
|
||||
on:click={updateTrigger}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
{/if}
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
{#if drawerLoading}
|
||||
@@ -300,7 +302,8 @@
|
||||
allowFlow={true}
|
||||
bind:itemKind
|
||||
bind:scriptPath={script_path}
|
||||
allowRefresh
|
||||
allowRefresh={can_write}
|
||||
allowEdit={!$userStore?.operator}
|
||||
/>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
import JsonEditor from '../apps/editor/settingsPanel/inputEditor/JsonEditor.svelte'
|
||||
import FileUpload from '../common/fileUpload/FileUpload.svelte'
|
||||
import SimpleEditor from '../SimpleEditor.svelte'
|
||||
import { json } from 'svelte-highlight/languages'
|
||||
import { Highlight } from 'svelte-highlight'
|
||||
|
||||
let is_flow: boolean = false
|
||||
let initialPath = ''
|
||||
@@ -341,36 +343,48 @@
|
||||
|
||||
{#if static_asset_config}
|
||||
<div class="flex flex-col w-full gap-1">
|
||||
<Toggle
|
||||
class="flex justify-end"
|
||||
bind:checked={s3FileUploadRawMode}
|
||||
size="xs"
|
||||
options={{ left: 'Existing file' }}
|
||||
/>
|
||||
{#if s3FileUploadRawMode}
|
||||
<JsonEditor
|
||||
bind:editor={s3Editor}
|
||||
on:focus={(e) => {
|
||||
dispatch('focus')
|
||||
}}
|
||||
on:blur={(e) => {
|
||||
dispatch('blur')
|
||||
}}
|
||||
code={JSON.stringify(static_asset_config ?? { s3: '' }, null, 2)}
|
||||
bind:value={static_asset_config}
|
||||
/>
|
||||
<Button
|
||||
variant="border"
|
||||
color="light"
|
||||
{#if can_write}
|
||||
<Toggle
|
||||
class="flex justify-end"
|
||||
bind:checked={s3FileUploadRawMode}
|
||||
size="xs"
|
||||
btnClasses="mt-1"
|
||||
on:click={() => {
|
||||
s3FilePicker?.open?.(static_asset_config)
|
||||
}}
|
||||
startIcon={{ icon: Pipette }}
|
||||
>
|
||||
Choose an object from the catalog
|
||||
</Button>
|
||||
options={{ left: 'Existing file' }}
|
||||
disabled={!can_write}
|
||||
/>
|
||||
{/if}
|
||||
{#if s3FileUploadRawMode}
|
||||
{#if can_write}
|
||||
<JsonEditor
|
||||
bind:editor={s3Editor}
|
||||
on:focus={(e) => {
|
||||
dispatch('focus')
|
||||
}}
|
||||
on:blur={(e) => {
|
||||
dispatch('blur')
|
||||
}}
|
||||
code={JSON.stringify(static_asset_config ?? { s3: '' }, null, 2)}
|
||||
bind:value={static_asset_config}
|
||||
/>
|
||||
{:else}
|
||||
<Highlight
|
||||
language={json}
|
||||
code={JSON.stringify(static_asset_config ?? { s3: '' }, null, 2)}
|
||||
/>
|
||||
{/if}
|
||||
{#if can_write}
|
||||
<Button
|
||||
variant="border"
|
||||
color="light"
|
||||
size="xs"
|
||||
btnClasses="mt-1"
|
||||
on:click={() => {
|
||||
s3FilePicker?.open?.(static_asset_config)
|
||||
}}
|
||||
startIcon={{ icon: Pipette }}
|
||||
>
|
||||
Choose an object from the catalog
|
||||
</Button>
|
||||
{/if}
|
||||
{:else}
|
||||
<FileUpload
|
||||
allowMultiple={false}
|
||||
@@ -403,7 +417,8 @@
|
||||
allowFlow={true}
|
||||
bind:itemKind
|
||||
bind:scriptPath={script_path}
|
||||
allowRefresh
|
||||
allowRefresh={can_write}
|
||||
allowEdit={!$userStore?.operator}
|
||||
/>
|
||||
|
||||
{#if script_path === undefined}
|
||||
|
||||
@@ -253,7 +253,7 @@
|
||||
on:close={drawer.closeDrawer}
|
||||
>
|
||||
<svelte:fragment slot="actions">
|
||||
{#if !drawerLoading && can_write}
|
||||
{#if !drawerLoading}
|
||||
{#if edit}
|
||||
<div class="mr-8 center-center -mt-1">
|
||||
<Toggle
|
||||
@@ -273,17 +273,19 @@
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<Button
|
||||
startIcon={{ icon: Save }}
|
||||
disabled={pathError != '' ||
|
||||
urlError != '' ||
|
||||
invalidInitialMessages ||
|
||||
emptyString(script_path) ||
|
||||
!can_write}
|
||||
on:click={updateTrigger}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
{#if can_write}
|
||||
<Button
|
||||
startIcon={{ icon: Save }}
|
||||
disabled={pathError != '' ||
|
||||
urlError != '' ||
|
||||
invalidInitialMessages ||
|
||||
emptyString(script_path) ||
|
||||
!can_write}
|
||||
on:click={updateTrigger}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
{/if}
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
{#if drawerLoading}
|
||||
@@ -411,7 +413,8 @@
|
||||
allowFlow={true}
|
||||
bind:itemKind
|
||||
bind:scriptPath={script_path}
|
||||
allowRefresh
|
||||
allowRefresh={can_write}
|
||||
allowEdit={!$userStore?.operator}
|
||||
/>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
@@ -384,10 +384,10 @@
|
||||
<Button
|
||||
on:click={() => scheduleEditor?.openEdit(path, is_flow)}
|
||||
size="xs"
|
||||
startIcon={{ icon: Pen }}
|
||||
startIcon={{ icon: canWrite ? Pen : Eye }}
|
||||
color="dark"
|
||||
>
|
||||
Edit
|
||||
{canWrite ? 'Edit' : 'View'}
|
||||
</Button>
|
||||
<Dropdown
|
||||
items={[
|
||||
@@ -412,9 +412,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: 'Edit',
|
||||
icon: Pen,
|
||||
disabled: !canWrite,
|
||||
displayName: canWrite ? 'Edit' : 'View',
|
||||
icon: canWrite ? Pen : Eye,
|
||||
action: () => {
|
||||
scheduleEditor?.openEdit(path, is_flow)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user