mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
feat: add move to drawer for script and flows
This commit is contained in:
@@ -4275,6 +4275,7 @@ components:
|
||||
- hash
|
||||
- path
|
||||
- summary
|
||||
- description
|
||||
- content
|
||||
- created_by
|
||||
- created_at
|
||||
|
||||
@@ -36,16 +36,17 @@
|
||||
dispatch('click', { item: item?.eventName })
|
||||
}
|
||||
}}
|
||||
class="block w-full whitespace-nowrap hover:drop-shadow-sm hover:bg-gray-50 hover:bg-opacity-30 px-4 py-2 text-sm text-gray-700 text-left {item.separatorTop
|
||||
? 'border-t'
|
||||
: ''} {item.separatorBottom ? 'border-b' : ''} {item.type == 'delete'
|
||||
class="block w-full whitespace-nowrap hover:drop-shadow-sm hover:bg-gray-50 hover:bg-opacity-30
|
||||
px-4 py-2 text-sm text-gray-700 text-left
|
||||
{item.disabled ? 'bg-gray-100' : ''}
|
||||
{item.separatorTop ? 'border-t' : ''} {item.separatorBottom ? 'border-b' : ''} {item.type ==
|
||||
'delete'
|
||||
? 'text-red-500'
|
||||
: ''}"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
id="user-menu-item-{name}-{i}}"
|
||||
disabled={item.disabled}
|
||||
class:disabled={item.disabled}
|
||||
>
|
||||
{#if item.icon}
|
||||
<Icon
|
||||
@@ -66,7 +67,7 @@
|
||||
e.preventDefault()
|
||||
}
|
||||
}}
|
||||
class="block w-full px-4 py-2 text-sm text-gray-700 hover:drop-shadow-sm hover:bg-gray-50 hover:bg-opacity-30"
|
||||
class="block w-full px-4 font-semibold py-2 text-sm text-gray-700 hover:drop-shadow-sm hover:bg-gray-50 hover:bg-opacity-30"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
id="user-menu-item-{name}-{i}}"
|
||||
|
||||
@@ -64,7 +64,8 @@
|
||||
|
||||
async function loadFolder(): Promise<void> {
|
||||
folder = await FolderService.getFolder({ workspace: $workspaceStore!, name })
|
||||
can_write = folder.owners.includes('u/' + $userStore?.username)
|
||||
can_write =
|
||||
folder.owners.includes('u/' + $userStore?.username) || ($userStore?.is_admin ?? false)
|
||||
perms = Array.from(
|
||||
new Set(
|
||||
Object.entries(folder?.extra_perms ?? {})
|
||||
@@ -216,7 +217,7 @@
|
||||
(scripts/flows/apps/schedules/resources/variables) inside the folder</Tooltip
|
||||
></ToggleButton
|
||||
>
|
||||
<ToggleButton position="right" value="owner" size="xs"
|
||||
<ToggleButton position="right" value="admin" size="xs"
|
||||
>Admin <Tooltip
|
||||
>An admin of a folder has read AND write access to all the elements inside
|
||||
the folders and can manage the permissions as well as add new admins</Tooltip
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<script lang="ts">
|
||||
import { isOwner } from '$lib/utils'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { Alert, Button, Drawer } from './common'
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import Path from './Path.svelte'
|
||||
import { FlowService, ScriptService } from '$lib/gen'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
type Kind = 'script' | 'resource' | 'schedule' | 'variable' | 'flow' | 'app'
|
||||
|
||||
let kind: Kind
|
||||
let initialPath: string = ''
|
||||
let path: string = ''
|
||||
|
||||
let drawer: Drawer
|
||||
|
||||
let own = false
|
||||
export async function openDrawer(initialPath_l: string, kind_l: Kind) {
|
||||
kind = kind_l
|
||||
initialPath = initialPath_l
|
||||
drawer.openDrawer()
|
||||
}
|
||||
|
||||
$: $userStore && $workspaceStore && loadOwner()
|
||||
|
||||
async function loadOwner() {
|
||||
own = await isOwner(path, $userStore!, $workspaceStore!)
|
||||
}
|
||||
|
||||
async function updatePath() {
|
||||
if (kind == 'flow') {
|
||||
const flow = await FlowService.getFlowByPath({
|
||||
workspace: $workspaceStore!,
|
||||
path: initialPath
|
||||
})
|
||||
await FlowService.updateFlow({
|
||||
workspace: $workspaceStore!,
|
||||
path: initialPath,
|
||||
requestBody: {
|
||||
path,
|
||||
summary: flow.summary,
|
||||
description: flow.description,
|
||||
value: flow.value
|
||||
}
|
||||
})
|
||||
} else if (kind == 'script') {
|
||||
const script = await ScriptService.getScriptByPath({
|
||||
workspace: $workspaceStore!,
|
||||
path: initialPath
|
||||
})
|
||||
await ScriptService.createScript({
|
||||
workspace: $workspaceStore!,
|
||||
requestBody: {
|
||||
...script,
|
||||
description: script.description ?? '',
|
||||
lock: script.lock?.split('\n'),
|
||||
parent_hash: script.hash,
|
||||
path
|
||||
}
|
||||
})
|
||||
}
|
||||
dispatch('update', path)
|
||||
drawer.closeDrawer()
|
||||
}
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={drawer}>
|
||||
<DrawerContent title="Move {initialPath}" on:close={drawer.closeDrawer}>
|
||||
<div class="flex flex-col gap-6">
|
||||
<h1>Move {initialPath} to</h1>
|
||||
{#if !own}
|
||||
<Alert type="warning" title="Not owner"
|
||||
>Since you do not own this item, you cannot move this item(you can however fork it!)</Alert
|
||||
>
|
||||
{/if}
|
||||
<Path disabled={!own} {kind} {initialPath} bind:path />
|
||||
<Button disabled={!own} on:click={updatePath}>Move</Button>
|
||||
<div />
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
@@ -350,7 +350,7 @@
|
||||
></span
|
||||
>
|
||||
|
||||
<div class="flex flex-row gap-1 w-full">
|
||||
<div class="flex flex-row gap-1">
|
||||
<select class="grow w-full" {disabled} bind:value={meta.owner}>
|
||||
{#each groups as g}
|
||||
<option>{g}</option>
|
||||
@@ -366,7 +366,7 @@
|
||||
</label>
|
||||
{/if}
|
||||
</div>
|
||||
<label class="block grow">
|
||||
<label class="block grow w-full max-w-md">
|
||||
<span class="text-gray-700 text-sm">
|
||||
Name
|
||||
<Required required={true} />
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let kind: 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow'
|
||||
export let path: string = ''
|
||||
type Kind = 'script' | 'group_' | 'resource' | 'schedule' | 'variable' | 'flow'
|
||||
let kind: Kind
|
||||
|
||||
let path: string = ''
|
||||
|
||||
let ownerKind: 'user' | 'group' = 'user'
|
||||
let owner: string = ''
|
||||
@@ -30,8 +32,9 @@
|
||||
$: newOwner = [ownerKind === 'group' ? 'g' : 'u', owner].join('/')
|
||||
|
||||
let own = false
|
||||
export async function openDrawer(newPath: string) {
|
||||
export async function openDrawer(newPath: string, kind_l: Kind) {
|
||||
path = newPath
|
||||
kind = kind_l
|
||||
loadAcls()
|
||||
loadGroups()
|
||||
loadUsernames()
|
||||
@@ -66,7 +69,7 @@
|
||||
requestBody: { owner }
|
||||
})
|
||||
loadAcls()
|
||||
dispatch('change')
|
||||
dispatch('change', { path, kind })
|
||||
} catch (err) {
|
||||
sendUserToast(err.toString(), true)
|
||||
}
|
||||
@@ -80,7 +83,7 @@
|
||||
requestBody: { owner, write }
|
||||
})
|
||||
loadAcls()
|
||||
dispatch('change')
|
||||
dispatch('change', { path, kind })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation'
|
||||
import Dropdown from '$lib/components/Dropdown.svelte'
|
||||
import type MoveDrawer from '$lib/components/MoveDrawer.svelte'
|
||||
import ScheduleEditor from '$lib/components/ScheduleEditor.svelte'
|
||||
import SharedBadge from '$lib/components/SharedBadge.svelte'
|
||||
import type ShareModal from '$lib/components/ShareModal.svelte'
|
||||
@@ -14,6 +15,7 @@
|
||||
faCodeFork,
|
||||
faEdit,
|
||||
faEye,
|
||||
faFileExport,
|
||||
faList,
|
||||
faPlay,
|
||||
faShare
|
||||
@@ -27,6 +29,7 @@
|
||||
export let marked: string | undefined
|
||||
export let starred: boolean
|
||||
export let shareModal: ShareModal
|
||||
export let moveDrawer: MoveDrawer
|
||||
|
||||
let { summary, path, extra_perms, canWrite, workspace_id } = flow
|
||||
|
||||
@@ -133,6 +136,13 @@
|
||||
icon: faList,
|
||||
href: `/runs/${path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Move',
|
||||
icon: faFileExport,
|
||||
action: () => {
|
||||
moveDrawer.openDrawer(path, 'flow')
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: 'Schedule',
|
||||
icon: faCalendarAlt,
|
||||
@@ -141,10 +151,10 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: 'Share',
|
||||
displayName: canWrite ? 'Share' : 'See Permissions',
|
||||
icon: faShare,
|
||||
action: () => {
|
||||
shareModal.openDrawer && shareModal.openDrawer(path)
|
||||
shareModal.openDrawer && shareModal.openDrawer(path, 'flow')
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation'
|
||||
import Dropdown from '$lib/components/Dropdown.svelte'
|
||||
import type MoveDrawer from '$lib/components/MoveDrawer.svelte'
|
||||
import ScheduleEditor from '$lib/components/ScheduleEditor.svelte'
|
||||
import SharedBadge from '$lib/components/SharedBadge.svelte'
|
||||
import type ShareModal from '$lib/components/ShareModal.svelte'
|
||||
@@ -14,6 +15,7 @@
|
||||
faCodeFork,
|
||||
faEdit,
|
||||
faEye,
|
||||
faFileExport,
|
||||
faList,
|
||||
faPlay,
|
||||
faShare
|
||||
@@ -28,6 +30,7 @@
|
||||
export let marked: string | undefined
|
||||
export let starred: boolean
|
||||
export let shareModal: ShareModal
|
||||
export let moveDrawer: MoveDrawer
|
||||
|
||||
let {
|
||||
summary,
|
||||
@@ -153,6 +156,13 @@
|
||||
icon: faCodeFork,
|
||||
href: `/scripts/add?template=${path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Move',
|
||||
icon: faFileExport,
|
||||
action: () => {
|
||||
moveDrawer.openDrawer(path, 'script')
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: 'View runs',
|
||||
icon: faList,
|
||||
@@ -166,10 +176,10 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: 'Share',
|
||||
displayName: canWrite ? 'Share' : 'See Permissions',
|
||||
icon: faShare,
|
||||
action: () => {
|
||||
shareModal.openDrawer && shareModal.openDrawer(path)
|
||||
shareModal.openDrawer && shareModal.openDrawer(path, 'script')
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -139,7 +139,7 @@ export function buildExtraLib(flowInput: Record<string, any>, results: Record<st
|
||||
return `
|
||||
/**
|
||||
* get variable (including secret) at path
|
||||
* @param {string} path - path of the variable (e.g: g/all/pretty_secret)
|
||||
* @param {string} path - path of the variable (e.g: f/examples/secret)
|
||||
*/
|
||||
declare function variable(path: string): string;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import SearchItems from '../SearchItems.svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import { faBarsStaggered } from '@fortawesome/free-solid-svg-icons'
|
||||
import MoveDrawer from '../MoveDrawer.svelte'
|
||||
|
||||
type TableItem<T, U extends 'script' | 'flow' | 'app'> = T & {
|
||||
canWrite: boolean
|
||||
@@ -40,8 +41,8 @@
|
||||
|
||||
let itemKind: 'script' | 'flow' | 'app' | 'all' = 'all'
|
||||
|
||||
let shareModalScripts: ShareModal
|
||||
let shareModalFlows: ShareModal
|
||||
let shareModal: ShareModal
|
||||
let moveDrawer: MoveDrawer
|
||||
|
||||
let loading = true
|
||||
|
||||
@@ -208,17 +209,19 @@
|
||||
/>
|
||||
|
||||
<ShareModal
|
||||
bind:this={shareModalScripts}
|
||||
kind="script"
|
||||
bind:this={shareModal}
|
||||
on:change={() => {
|
||||
loadScripts()
|
||||
loadApps()
|
||||
loadFlows()
|
||||
}}
|
||||
/>
|
||||
|
||||
<ShareModal
|
||||
bind:this={shareModalFlows}
|
||||
kind="flow"
|
||||
on:change={() => {
|
||||
<MoveDrawer
|
||||
bind:this={moveDrawer}
|
||||
on:update={() => {
|
||||
loadScripts()
|
||||
loadApps()
|
||||
loadFlows()
|
||||
}}
|
||||
/>
|
||||
@@ -300,7 +303,8 @@
|
||||
marked={item.marked}
|
||||
on:change={loadScripts}
|
||||
script={item}
|
||||
shareModal={shareModalScripts}
|
||||
{shareModal}
|
||||
{moveDrawer}
|
||||
/>
|
||||
{:else if item.type == 'flow'}
|
||||
<FlowRow
|
||||
@@ -308,7 +312,8 @@
|
||||
marked={item.marked}
|
||||
on:change={loadFlows}
|
||||
flow={item}
|
||||
shareModal={shareModalFlows}
|
||||
{shareModal}
|
||||
{moveDrawer}
|
||||
/>
|
||||
{:else if item.type == 'app'}
|
||||
<AppRow
|
||||
|
||||
@@ -25,11 +25,11 @@ def main(no_default: str,
|
||||
# secret fetching is audited by windmill.
|
||||
|
||||
try:
|
||||
secret = wmill.get_variable("g/all/pretty_secret")
|
||||
secret = wmill.get_variable("f/examples/secret")
|
||||
except:
|
||||
secret = "No secret yet at g/all/pretty_secret!"
|
||||
secret = "No secret yet at f/examples/secret !"
|
||||
|
||||
print(f"The variable at \`g/all/pretty_secret\`: {secret}")
|
||||
print(f"The variable at \`f/examples/secret\`: {secret}")
|
||||
|
||||
# Get last state of this script execution by the same trigger/user
|
||||
last_state = wmill.get_state()
|
||||
@@ -73,7 +73,7 @@ func main(x string, nested struct{ Foo string \`json:"foo"\` }) (interface{}, er
|
||||
fmt.Println("Hello, World")
|
||||
fmt.Println(nested.Foo)
|
||||
fmt.Println(quote.Opt())
|
||||
// v, _ := wmill.GetVariable("g/all/pretty_secret")
|
||||
// v, _ := wmill.GetVariable("f/examples/secret")
|
||||
return x, nil
|
||||
}
|
||||
`
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
Schedule
|
||||
</Button>
|
||||
<Button
|
||||
on:click={() => shareModal.openDrawer(flow?.path ?? '')}
|
||||
on:click={() => shareModal.openDrawer(flow?.path ?? '', 'flow')}
|
||||
variant="border"
|
||||
color="light"
|
||||
size="xs"
|
||||
@@ -218,7 +218,7 @@
|
||||
<h2 class="font-bold pb-4">{flow.path}</h2>
|
||||
{/if}
|
||||
{/if}
|
||||
<ShareModal bind:this={shareModal} kind="flow" path={flow?.path ?? ''} />
|
||||
<ShareModal bind:this={shareModal} />
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 max-w-7xl pb-6">
|
||||
<Skeleton
|
||||
|
||||
@@ -103,7 +103,11 @@
|
||||
<tbody slot="body">
|
||||
{#if folders === undefined}
|
||||
{#each new Array(6) as _}
|
||||
<Skeleton layout={[0.25, [2], 0.25]} />
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<Skeleton layout={[[2]]} />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
{:else}
|
||||
{#if folders.length === 0}
|
||||
|
||||
@@ -94,9 +94,11 @@
|
||||
</tr>
|
||||
<tbody slot="body">
|
||||
{#if groups === undefined}
|
||||
{#each new Array(6) as _}
|
||||
<Skeleton layout={[0.25, [2], 0.25]} />
|
||||
{/each}
|
||||
<tr>
|
||||
<td colspan="4">
|
||||
<Skeleton layout={[[2]]} />
|
||||
</td>
|
||||
</tr>
|
||||
{:else}
|
||||
{#each groups as { name, summary, extra_perms, canWrite }}
|
||||
<tr>
|
||||
|
||||
@@ -459,10 +459,10 @@
|
||||
placement="bottom-end"
|
||||
dropdownItems={[
|
||||
{
|
||||
displayName: 'Share',
|
||||
displayName: !canWrite ? 'View Permissions' : 'Share',
|
||||
icon: faShare,
|
||||
action: () => {
|
||||
shareModal.openDrawer?.(path)
|
||||
shareModal.openDrawer?.(path, 'resource')
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -604,7 +604,6 @@
|
||||
|
||||
<ShareModal
|
||||
bind:this={shareModal}
|
||||
kind="resource"
|
||||
on:change={() => {
|
||||
loadResources()
|
||||
}}
|
||||
|
||||
@@ -185,10 +185,10 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
displayName: 'Share',
|
||||
displayName: canWrite ? 'Share' : 'See Permissions',
|
||||
icon: faShare,
|
||||
action: () => {
|
||||
shareModal.openDrawer(path)
|
||||
shareModal.openDrawer(path, 'schedule')
|
||||
}
|
||||
}
|
||||
]}
|
||||
@@ -204,7 +204,6 @@
|
||||
|
||||
<ShareModal
|
||||
bind:this={shareModal}
|
||||
kind="schedule"
|
||||
on:change={() => {
|
||||
loadSchedules()
|
||||
}}
|
||||
|
||||
@@ -272,7 +272,7 @@
|
||||
Publish to Hub
|
||||
</Button>
|
||||
<Button
|
||||
on:click={() => shareModal.openDrawer(script?.path ?? '')}
|
||||
on:click={() => shareModal.openDrawer(script?.path ?? '', 'script')}
|
||||
variant="border"
|
||||
color="light"
|
||||
size="xs"
|
||||
@@ -487,4 +487,4 @@
|
||||
|
||||
<UserSettings bind:this={userSettings} />
|
||||
|
||||
<ShareModal bind:this={shareModal} kind="script" path={script?.path ?? ''} />
|
||||
<ShareModal bind:this={shareModal} />
|
||||
|
||||
@@ -124,7 +124,6 @@
|
||||
<VariableEditor bind:this={variableEditor} on:create={loadVariables} />
|
||||
<ShareModal
|
||||
bind:this={shareModal}
|
||||
kind="variable"
|
||||
on:change={() => {
|
||||
loadVariables()
|
||||
}}
|
||||
@@ -308,9 +307,9 @@
|
||||
disabled: !canWrite
|
||||
},
|
||||
{
|
||||
displayName: 'Share',
|
||||
displayName: canWrite ? 'Share' : 'See Permissions',
|
||||
action: () => {
|
||||
shareModal.openDrawer(path)
|
||||
shareModal.openDrawer(path, 'variable')
|
||||
},
|
||||
icon: faShare
|
||||
},
|
||||
|
||||
@@ -40,3 +40,4 @@ rsa = "*"
|
||||
cryptography = "*"
|
||||
pyparsing = "*"
|
||||
jmespath = "*"
|
||||
boto3 = "*"
|
||||
@@ -4,6 +4,7 @@ from typing import Generic, TypeVar, TypeAlias
|
||||
import os
|
||||
|
||||
from time import sleep
|
||||
from windmill_api.models.whoami_response_200 import WhoamiResponse200
|
||||
|
||||
from windmill_api.client import AuthenticatedClient
|
||||
|
||||
@@ -179,6 +180,15 @@ def get_resource(path: str | None = None, none_if_undefined: bool = False) -> An
|
||||
return _transform_leaf(raw)
|
||||
|
||||
|
||||
def whoami() -> WhoamiResponse200 | None:
|
||||
"""
|
||||
Returns the current user
|
||||
"""
|
||||
from windmill_api.api.user import whoami
|
||||
|
||||
return whoami.sync(client=create_client(), workspace=get_workspace())
|
||||
|
||||
|
||||
def get_state() -> Any:
|
||||
"""
|
||||
Get the state
|
||||
|
||||
Reference in New Issue
Block a user