mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
Fix u/* filter and refactored TreeView (#6563)
* fix only f/* filter * migrate treeview to svelte 5
This commit is contained in:
@@ -146,14 +146,14 @@
|
||||
|
||||
function filterItemsPathsBaseOnUserFilters(
|
||||
item: TableScript | TableFlow | TableApp | TableRawApp,
|
||||
filterUserFolders: boolean
|
||||
filterUserFolders: boolean,
|
||||
filterUserFoldersType: 'only f/*' | 'u/username and f/*' | undefined
|
||||
) {
|
||||
if ($workspaceStore == 'admins') return true
|
||||
if (filterUserFolders) {
|
||||
return !item.path.startsWith('u/') || item.path.startsWith('u/' + $userStore?.username + '/')
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
if (!filterUserFoldersType || !filterUserFolders) return true
|
||||
if (filterUserFoldersType === 'only f/*') return item.path.startsWith('f/')
|
||||
if (filterUserFoldersType === 'u/username and f/*')
|
||||
return item.path.startsWith('f/') || item.path.startsWith(`u/${$userStore?.username}/`)
|
||||
return true // should not happen
|
||||
}
|
||||
|
||||
let ownerFilter: string | undefined = $state(undefined)
|
||||
@@ -217,6 +217,13 @@
|
||||
const FILTER_USER_FOLDER_SETTING_NAME = 'filterUserFolders'
|
||||
const INCLUDE_WITHOUT_MAIN_SETTING_NAME = 'includeWithoutMain'
|
||||
let treeView = $state(getLocalSetting(TREE_VIEW_SETTING_NAME) == 'true')
|
||||
let filterUserFoldersType: 'only f/*' | 'u/username and f/*' | undefined = $derived(
|
||||
$userStore?.is_super_admin && $userStore.username.includes('@')
|
||||
? 'only f/*'
|
||||
: $userStore?.is_admin || $userStore?.is_super_admin
|
||||
? 'u/username and f/*'
|
||||
: undefined
|
||||
)
|
||||
let filterUserFolders = $state(getLocalSetting(FILTER_USER_FOLDER_SETTING_NAME) == 'true')
|
||||
let includeWithoutMain = $state(
|
||||
getLocalSetting(INCLUDE_WITHOUT_MAIN_SETTING_NAME)
|
||||
@@ -302,12 +309,12 @@
|
||||
(x) =>
|
||||
x.path.startsWith(ownerFilter + '/') &&
|
||||
(x.type == itemKind || itemKind == 'all') &&
|
||||
filterItemsPathsBaseOnUserFilters(x, filterUserFolders)
|
||||
filterItemsPathsBaseOnUserFilters(x, filterUserFolders, filterUserFoldersType)
|
||||
)
|
||||
: combinedItems?.filter(
|
||||
(x) =>
|
||||
(x.type == itemKind || itemKind == 'all') &&
|
||||
filterItemsPathsBaseOnUserFilters(x, filterUserFolders)
|
||||
filterItemsPathsBaseOnUserFilters(x, filterUserFolders, filterUserFoldersType)
|
||||
)
|
||||
)
|
||||
let items = $derived(filter !== '' ? filteredItems : preFilteredItems)
|
||||
@@ -486,13 +493,13 @@
|
||||
</div>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
{#if $userStore?.is_super_admin && $userStore.username.includes('@')}
|
||||
{#if filterUserFoldersType === 'only f/*'}
|
||||
<Toggle size="xs" bind:checked={filterUserFolders} options={{ right: 'Only f/*' }} />
|
||||
{:else if $userStore?.is_admin || $userStore?.is_super_admin}
|
||||
{:else if filterUserFoldersType === 'u/username and f/*'}
|
||||
<Toggle
|
||||
size="xs"
|
||||
bind:checked={filterUserFolders}
|
||||
options={{ right: `Only u/${$userStore.username} and f/*` }}
|
||||
options={{ right: `Only u/${$userStore?.username} and f/*` }}
|
||||
/>
|
||||
{/if}
|
||||
<Toggle size="xs" bind:checked={treeView} options={{ right: 'Tree view' }} />
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
<svelte:options immutable={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import TreeView from './TreeView.svelte'
|
||||
|
||||
import { ChevronDown, ChevronUp, Folder, FolderTree, User } from 'lucide-svelte'
|
||||
import Item from './Item.svelte'
|
||||
import type { FolderItem, ItemType, UserItem } from './treeViewUtils'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { pluralize } from '$lib/utils'
|
||||
|
||||
export let item: ItemType | FolderItem | UserItem
|
||||
|
||||
export let collapseAll: boolean
|
||||
export let depth: number = 0
|
||||
export let showCode: (path: string, summary: string) => void
|
||||
export let isSearching: boolean = false
|
||||
|
||||
const isFolder = (i: any): i is FolderItem => i && 'folderName' in i
|
||||
const isUser = (i: any): i is UserItem => i && 'username' in i
|
||||
|
||||
let opened: boolean = true
|
||||
|
||||
$: toggleOpened(collapseAll)
|
||||
|
||||
function toggleOpened(collapseAll: boolean) {
|
||||
opened = !collapseAll
|
||||
interface Props {
|
||||
item: ItemType | FolderItem | UserItem
|
||||
collapseAll: boolean
|
||||
depth?: number
|
||||
showCode: (path: string, summary: string) => void
|
||||
isSearching?: boolean
|
||||
}
|
||||
|
||||
let showMax = 15
|
||||
let { item, collapseAll, depth = 0, showCode, isSearching = false }: Props = $props()
|
||||
|
||||
const isFolder = (i: typeof item): i is FolderItem => i && 'folderName' in i
|
||||
const isUser = (i: typeof item): i is UserItem => i && 'username' in i
|
||||
|
||||
let opened: boolean = $state(true)
|
||||
|
||||
let showMax = $state(15)
|
||||
$effect(() => {
|
||||
opened = !collapseAll
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if isFolder(item)}
|
||||
<div>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
on:click={() => (opened = !opened)}
|
||||
onclick={() => (opened = !opened)}
|
||||
class="px-4 py-2 border-b w-full flex flex-row items-center justify-between cursor-pointer"
|
||||
>
|
||||
<div
|
||||
@@ -70,7 +70,7 @@
|
||||
{#if opened || isSearching}
|
||||
<div>
|
||||
{#each item.items.slice(0, showMax) as subItem ((subItem['path'] ? subItem['type'] + '__' + subItem['path'] : undefined) ?? 'folder__' + subItem['folderName'])}
|
||||
<svelte:self
|
||||
<TreeView
|
||||
{isSearching}
|
||||
{collapseAll}
|
||||
item={subItem}
|
||||
@@ -84,11 +84,11 @@
|
||||
/>
|
||||
{/each}
|
||||
{#if showMax < item.items.length}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="text-center text-sm text-secondary cursor-pointer hover:text-primary"
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
if (isFolder(item)) {
|
||||
showMax += Math.min(30, item.items.length - showMax)
|
||||
showMax = showMax
|
||||
@@ -103,10 +103,10 @@
|
||||
</div>
|
||||
{:else if isUser(item)}
|
||||
<div>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
on:click={() => (opened = !opened)}
|
||||
onclick={() => (opened = !opened)}
|
||||
class="px-4 py-2 border-b w-full flex flex-row items-center justify-between cursor-pointer"
|
||||
>
|
||||
<div
|
||||
@@ -137,7 +137,7 @@
|
||||
{#if opened || isSearching}
|
||||
<div>
|
||||
{#each item.items.slice(0, showMax) as subItem ((subItem['path'] ? subItem['type'] + '__' + subItem['path'] : undefined) ?? 'folder__' + subItem['folderName'])}
|
||||
<svelte:self
|
||||
<TreeView
|
||||
{collapseAll}
|
||||
item={subItem}
|
||||
on:scriptChanged
|
||||
@@ -150,11 +150,11 @@
|
||||
/>
|
||||
{/each}
|
||||
{#if showMax < item.items.length}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="text-center text-sm text-secondary cursor-pointer py-2 hover:text-primary"
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
if (isUser(item)) {
|
||||
showMax += Math.min(30, item.items.length - showMax)
|
||||
}
|
||||
|
||||
@@ -1,32 +1,34 @@
|
||||
<script lang="ts">
|
||||
import { untrack } from 'svelte'
|
||||
import TreeView from './TreeView.svelte'
|
||||
import { groupItems } from './treeViewUtils'
|
||||
import { groupItems, type ItemType } from './treeViewUtils'
|
||||
|
||||
export let collapseAll: boolean
|
||||
export let showCode: (path: string, summary: string) => void
|
||||
export let nbDisplayed: number
|
||||
export let items: any[] | undefined
|
||||
export let isSearching: boolean = false
|
||||
|
||||
let treeLoading = false
|
||||
|
||||
$: groupedItems = grpItems(items)
|
||||
function grpItems(items: any[] | undefined): any[] {
|
||||
treeLoading = true
|
||||
let r
|
||||
try {
|
||||
r = groupItems(items)
|
||||
} finally {
|
||||
treeLoading = false
|
||||
}
|
||||
return r
|
||||
interface Props {
|
||||
collapseAll: boolean
|
||||
showCode: (path: string, summary: string) => void
|
||||
nbDisplayed: number
|
||||
items: ItemType[] | undefined
|
||||
isSearching?: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
collapseAll,
|
||||
showCode,
|
||||
nbDisplayed = $bindable(),
|
||||
items,
|
||||
isSearching = false
|
||||
}: Props = $props()
|
||||
|
||||
let groupedItems: ReturnType<typeof groupItems> | 'loading' = $state('loading')
|
||||
$effect(() => {
|
||||
items
|
||||
untrack(() => (groupedItems = groupItems(items)))
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if treeLoading}
|
||||
{#if groupedItems === 'loading'}
|
||||
<div class="flex flex-row items-center justify-center">
|
||||
<div
|
||||
class="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900 dark:border-gray-100"
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900 dark:border-gray-100"
|
||||
></div>
|
||||
</div>
|
||||
{:else if groupedItems.length === 0}
|
||||
@@ -54,7 +56,7 @@
|
||||
{#if groupedItems.length > 15 && nbDisplayed < groupedItems.length}
|
||||
<span class="text-xs"
|
||||
>{nbDisplayed} root nodes out of {groupedItems.length}
|
||||
<button class="ml-4" on:click={() => (nbDisplayed += 30)}>load 30 more</button></span
|
||||
<button class="ml-4" onclick={() => (nbDisplayed += 30)}>load 30 more</button></span
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user