mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-07 00:01:49 +00:00
* feat: add explore button for object storage resources in resource list Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * fix: make s3 drawer tooltip reflect explored resource Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * fix: honor workspace prop in global s3 explorer and add resource connection error state Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * fix: use picker's effective workspace in S3FilePreview requests Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * fix: pass acting workspace to explore button in ResourcePicker Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015FhmfSxPuTck3yAhDpkfcA * chore: update ee-repo-ref to f78df23339e3136e8b6e9148a509508633448dd2 This commit updates the EE repository reference after PR #686 was merged in windmill-ee-private. Previous ee-repo-ref: efb5e014fec34fc580b9dbb1b260494dd76c5462 New ee-repo-ref: f78df23339e3136e8b6e9148a509508633448dd2 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
173 lines
5.0 KiB
Svelte
173 lines
5.0 KiB
Svelte
<script lang="ts">
|
|
import { emptyString, type S3Object } from '$lib/utils'
|
|
import { Button, Drawer } from './common'
|
|
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
|
import { tick } from 'svelte'
|
|
import S3FilePickerInner from './S3FilePickerInner.svelte'
|
|
import Select from './select/Select.svelte'
|
|
import { FileUp } from 'lucide-svelte'
|
|
import { SettingService } from '$lib/gen'
|
|
import { workspaceStore } from '$lib/stores'
|
|
import { resource } from 'runed'
|
|
|
|
interface Props {
|
|
fromWorkspaceSettings?: boolean
|
|
readOnlyMode: boolean
|
|
allowDelete?: boolean
|
|
initialFileKey?: { s3: string; storage?: string } | undefined
|
|
selectedFileKey?: { s3: string; storage?: string } | undefined
|
|
folderOnly?: boolean
|
|
regexFilter?: RegExp | undefined
|
|
/** Workspace to browse S3 storage in — the acting workspace of the editor that
|
|
* opened the picker, else the nav workspace. */
|
|
workspace?: string | undefined
|
|
onClose?: () => void
|
|
onSelectAndClose?: (selected: { s3: string; storage: string | undefined }) => void
|
|
}
|
|
|
|
let {
|
|
fromWorkspaceSettings = false,
|
|
readOnlyMode,
|
|
allowDelete = false,
|
|
initialFileKey = $bindable(undefined),
|
|
selectedFileKey = $bindable(undefined),
|
|
folderOnly = false,
|
|
regexFilter = undefined,
|
|
workspace = undefined,
|
|
onClose,
|
|
onSelectAndClose
|
|
}: Props = $props()
|
|
|
|
let drawer: Drawer | undefined = $state()
|
|
let s3FilePickerInner: S3FilePickerInner | undefined = $state()
|
|
|
|
let workspaceSettingsInitialized = $state(true)
|
|
let storage: string | undefined = $state(undefined)
|
|
let s3ResourcePath: string | undefined = $state(undefined)
|
|
/** Per-open workspace override, for callers (e.g. the global explorer) whose
|
|
* asset lives in a different workspace than this picker was mounted for. */
|
|
let workspaceOverride: string | undefined = $state(undefined)
|
|
let effectiveWorkspace = $derived(workspaceOverride ?? workspace)
|
|
let ws = $derived(effectiveWorkspace ?? $workspaceStore)
|
|
let uploadModalOpen = $state(false)
|
|
|
|
let allFilesByKey: Record<
|
|
string,
|
|
{
|
|
type: 'folder' | 'leaf'
|
|
full_key: string
|
|
display_name: string
|
|
collapsed: boolean
|
|
parentPath: string | undefined
|
|
nestingLevel: number
|
|
count: number
|
|
}
|
|
> = $state({})
|
|
|
|
let secondaryStorageNames = resource(
|
|
() => ws,
|
|
() => SettingService.getSecondaryStorageNames({ workspace: ws! }),
|
|
{ lazy: true }
|
|
)
|
|
|
|
export async function open(
|
|
_preSelectedFileKey: S3Object | undefined = undefined,
|
|
opts: { s3ResourcePath?: string; workspace?: string } = {}
|
|
) {
|
|
s3ResourcePath = opts.s3ResourcePath
|
|
workspaceOverride = opts.workspace
|
|
if (!s3ResourcePath) {
|
|
secondaryStorageNames.refetch()
|
|
}
|
|
drawer?.openDrawer?.()
|
|
|
|
await tick()
|
|
s3FilePickerInner?.open?.(_preSelectedFileKey)
|
|
}
|
|
</script>
|
|
|
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
<Drawer
|
|
bind:this={drawer}
|
|
on:close={() => {
|
|
onClose?.()
|
|
s3FilePickerInner?.close?.()
|
|
}}
|
|
size="1200px"
|
|
>
|
|
<DrawerContent
|
|
title={s3ResourcePath ? `Exploring ${s3ResourcePath}` : 'S3 file browser'}
|
|
on:close={() => {
|
|
s3FilePickerInner?.exit?.()
|
|
drawer?.closeDrawer?.()
|
|
}}
|
|
tooltip={s3ResourcePath
|
|
? `Files present in the bucket of the ${s3ResourcePath} resource.`
|
|
: 'Files present in the Workspace S3 bucket. You can set the workspace S3 bucket in the settings.'}
|
|
documentationLink="https://www.windmill.dev/docs/integrations/s3"
|
|
>
|
|
<S3FilePickerInner
|
|
bind:this={s3FilePickerInner}
|
|
on:selectAndClose={(e) => {
|
|
onSelectAndClose?.(e.detail)
|
|
drawer?.closeDrawer?.()
|
|
}}
|
|
{fromWorkspaceSettings}
|
|
{readOnlyMode}
|
|
{allowDelete}
|
|
bind:initialFileKey
|
|
bind:selectedFileKey
|
|
bind:workspaceSettingsInitialized
|
|
bind:storage
|
|
bind:allFilesByKey
|
|
bind:uploadModalOpen
|
|
{s3ResourcePath}
|
|
{folderOnly}
|
|
{regexFilter}
|
|
workspace={effectiveWorkspace}
|
|
/>
|
|
{#snippet actions()}
|
|
<div class="flex gap-1">
|
|
{#if !s3ResourcePath && secondaryStorageNames.current?.length}
|
|
<Select
|
|
inputClass="h-10 min-w-44 !placeholder-secondary"
|
|
items={[
|
|
{ value: undefined, label: 'Default storage' },
|
|
...secondaryStorageNames.current.map((value) => ({ value }))
|
|
]}
|
|
placeholder="Default storage"
|
|
bind:value={
|
|
() => storage,
|
|
(v) => {
|
|
if (v === storage) return
|
|
storage = v
|
|
s3FilePickerInner?.reloadContent?.()
|
|
}
|
|
}
|
|
/>
|
|
{/if}
|
|
{#if !readOnlyMode}
|
|
<Button
|
|
variant="border"
|
|
color="light"
|
|
disabled={workspaceSettingsInitialized === false}
|
|
startIcon={{ icon: FileUp }}
|
|
on:click={() => {
|
|
uploadModalOpen = true
|
|
}}>Upload File</Button
|
|
>
|
|
{#if !fromWorkspaceSettings && s3FilePickerInner}
|
|
<Button
|
|
disabled={selectedFileKey === undefined ||
|
|
emptyString(selectedFileKey.s3) ||
|
|
(folderOnly && allFilesByKey[selectedFileKey.s3]?.type !== 'folder')}
|
|
on:click={s3FilePickerInner.selectAndClose}>Select</Button
|
|
>
|
|
{/if}
|
|
{/if}
|
|
</div>
|
|
{/snippet}
|
|
</DrawerContent>
|
|
</Drawer>
|