fix(frontend): fix treeview (#2552)

* fix(frontend): fix wip

* fix(frontend): improving home performance

* slice number of items to show

---------

Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
This commit is contained in:
Faton Ramadani
2023-11-04 09:37:30 +01:00
committed by GitHub
co-authored by Ruben Fiszel
parent 1f9455a3d3
commit ce34017467
9 changed files with 261 additions and 174 deletions
+1 -1
View File
@@ -27,7 +27,7 @@
}
</script>
<Menu {placement} let:close>
<Menu {placement} let:close on:dropdownOpen on:dropdownClose>
<Button
nonCaptureEvent
color="light"
@@ -4,7 +4,7 @@
<script lang="ts">
import { classNames } from '$lib/utils'
import { onMount } from 'svelte'
import { createEventDispatcher, onMount } from 'svelte'
import { fade } from 'svelte/transition'
export let noMinW = false
@@ -56,10 +56,12 @@
'top-start': 'origin-bottom-left left-0 bottom-0',
'top-end': 'origin-bottom-right right-0 bottom-0'
}
const dispatch = createEventDispatcher()
</script>
<div class="relative {wrapperClasses}" bind:this={menu}>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div
on:click={() => {
if (!pointerDown) {
@@ -68,6 +70,11 @@
current = close
}
show = !show
if (show) {
dispatch('dropdownOpen')
} else {
dispatch('dropdownClose')
}
}
}}
on:pointerdown={() => {
@@ -35,6 +35,7 @@
export let deploymentDrawer: DeployWorkspaceDrawer
export let deleteConfirmedCallback: (() => void) | undefined
export let depth: number = 0
export let menuOpen: boolean = false
let {
summary,
@@ -66,8 +67,11 @@
}
</script>
<AppJsonEditor on:change bind:this={appExport} />
<AppDeploymentHistory bind:this={appDeploymentHistory} />
{#if menuOpen}
<AppJsonEditor on:change bind:this={appExport} />
<AppDeploymentHistory bind:this={appDeploymentHistory} />
{/if}
<Row
href={`/apps/get/${path}`}
kind="app"
@@ -250,6 +254,12 @@
}
]
}}
on:dropdownOpen={() => {
menuOpen = true
}}
on:dropdownClose={() => {
menuOpen = false
}}
/>
</svelte:fragment>
</Row>
@@ -36,6 +36,7 @@
export let deploymentDrawer: DeployWorkspaceDrawer
export let errorHandlerMuted: boolean
export let depth: number = 0
export let menuOpen: boolean = false
let { summary, path, extra_perms, canWrite, workspace_id, archived, draft_only, has_draft } = flow
@@ -67,7 +68,9 @@
let scheduleEditor: ScheduleEditor
</script>
<ScheduleEditor on:update={() => goto('/schedules')} bind:this={scheduleEditor} />
{#if menuOpen}
<ScheduleEditor on:update={() => goto('/schedules')} bind:this={scheduleEditor} />
{/if}
<Row
href="/flows/get/{path}?workspace={$workspaceStore}"
kind="flow"
@@ -236,6 +239,12 @@
}
]
}}
on:dropdownOpen={() => {
menuOpen = true
}}
on:dropdownClose={() => {
menuOpen = false
}}
/>
</svelte:fragment>
</Row>
@@ -23,6 +23,7 @@
export let deleteConfirmedCallback: (() => void) | undefined
export let deploymentDrawer: DeployWorkspaceDrawer
export let depth: number = 0
export let menuOpen: boolean = false
let updateAppDrawer: Drawer
@@ -31,26 +32,27 @@
const dispatch = createEventDispatcher()
</script>
<Drawer bind:this={updateAppDrawer} size="800px">
<DrawerContent title="Update app" on:close={() => updateAppDrawer?.toggleDrawer?.()}>
<FileInput
accept={'.js'}
multiple={false}
convertTo={'text'}
iconSize={24}
class="text-sm py-4"
on:change={async ({ detail }) => {
await RawAppService.updateRawApp({
workspace: $workspaceStore ?? '',
path,
requestBody: { value: detail?.[0] }
})
goto(`/apps/get_raw/${version + 1}/${path}`)
}}
/>
</DrawerContent>
</Drawer>
{#if menuOpen}
<Drawer bind:this={updateAppDrawer} size="800px">
<DrawerContent title="Update app" on:close={() => updateAppDrawer?.toggleDrawer?.()}>
<FileInput
accept={'.js'}
multiple={false}
convertTo={'text'}
iconSize={24}
class="text-sm py-4"
on:change={async ({ detail }) => {
await RawAppService.updateRawApp({
workspace: $workspaceStore ?? '',
path,
requestBody: { value: detail?.[0] }
})
goto(`/apps/get_raw/${version + 1}/${path}`)
}}
/>
</DrawerContent>
</Drawer>
{/if}
<Row
href="/apps/get_raw/{version}/{path}"
kind="raw_app"
@@ -137,6 +139,12 @@
}
]
}}
on:dropdownOpen={() => {
menuOpen = true
}}
on:dropdownClose={() => {
menuOpen = false
}}
/>
</svelte:fragment>
</Row>
@@ -40,6 +40,7 @@
export let errorHandlerMuted: boolean
export let showCode: (path: string, summary: string) => void
export let depth: number = 0
export let menuOpen: boolean = false
let {
summary,
@@ -86,7 +87,9 @@
const dlt: 'delete' = 'delete'
</script>
<ScheduleEditor on:update={() => goto('/schedules')} bind:this={scheduleEditor} />
{#if menuOpen}
<ScheduleEditor on:update={() => goto('/schedules')} bind:this={scheduleEditor} />
{/if}
<Row
href="/scripts/get/{hash}?workspace={$workspaceStore}"
@@ -283,6 +286,12 @@
: [])
]
}}
on:dropdownOpen={() => {
menuOpen = true
}}
on:dropdownClose={() => {
menuOpen = false
}}
/>
</svelte:fragment>
</Row>
+46 -38
View File
@@ -19,6 +19,8 @@
let shareModal: ShareModal
let moveDrawer: MoveDrawer
let deploymentDrawer: DeployWorkspaceDrawer
let menuOpen: boolean = false
export let showCode: (path: string, summary: string) => void
</script>
@@ -40,6 +42,7 @@
{moveDrawer}
{deploymentDrawer}
{depth}
bind:menuOpen
{showCode}
/>
{:else if item.type == 'flow'}
@@ -57,6 +60,7 @@
{moveDrawer}
{deploymentDrawer}
{depth}
bind:menuOpen
/>
{:else if item.type == 'app'}
<AppRow
@@ -69,6 +73,7 @@
{shareModal}
{deploymentDrawer}
{depth}
bind:menuOpen
/>
{:else if item.type == 'raw_app'}
<RawAppRow
@@ -81,49 +86,52 @@
{shareModal}
{deploymentDrawer}
{depth}
bind:menuOpen
/>
{/if}
{/key}
{/key}
{/key}
<ConfirmationModal
open={Boolean(deleteConfirmedCallback)}
title="Remove"
confirmationText="Remove"
on:canceled={() => {
deleteConfirmedCallback = undefined
}}
on:confirmed={() => {
if (deleteConfirmedCallback) {
deleteConfirmedCallback()
}
deleteConfirmedCallback = undefined
}}
>
<div class="flex flex-col w-full space-y-4">
<span>Are you sure you want to remove it?</span>
<Alert type="info" title="Bypass confirmation">
<div>
You can press
<Badge color="dark-gray">SHIFT</Badge>
while removing to bypass confirmation.
</div>
</Alert>
</div>
</ConfirmationModal>
{#if menuOpen}
<ConfirmationModal
open={Boolean(deleteConfirmedCallback)}
title="Remove"
confirmationText="Remove"
on:canceled={() => {
deleteConfirmedCallback = undefined
}}
on:confirmed={() => {
if (deleteConfirmedCallback) {
deleteConfirmedCallback()
}
deleteConfirmedCallback = undefined
}}
>
<div class="flex flex-col w-full space-y-4">
<span>Are you sure you want to remove it?</span>
<Alert type="info" title="Bypass confirmation">
<div>
You can press
<Badge color="dark-gray">SHIFT</Badge>
while removing to bypass confirmation.
</div>
</Alert>
</div>
</ConfirmationModal>
<ShareModal
bind:this={shareModal}
on:change={() => {
dispatch('reload')
}}
/>
<ShareModal
bind:this={shareModal}
on:change={() => {
dispatch('reload')
}}
/>
<DeployWorkspaceDrawer bind:this={deploymentDrawer} />
<MoveDrawer
bind:this={moveDrawer}
on:update={() => {
dispatch('reload')
}}
/>
<DeployWorkspaceDrawer bind:this={deploymentDrawer} />
<MoveDrawer
bind:this={moveDrawer}
on:update={() => {
dispatch('reload')
}}
/>
{/if}
@@ -390,21 +390,23 @@
{:else}
<div class="border rounded-md">
{#if treeView}
{#each (groupItems(items) ?? []).slice(0, nbDisplayed) as item}
<TreeView
{item}
on:scriptChanged={loadScripts}
on:flowChanged={loadFlows}
on:appChanged={loadApps}
on:rawAppChanged={loadRawApps}
on:reload={() => {
loadScripts()
loadFlows()
loadApps()
loadRawApps()
}}
{showCode}
/>
{#each (groupItems(items) ?? []).slice(0, nbDisplayed) as item (item['folderName'] ?? 'user__' + item['username'])}
{#if item}
<TreeView
{item}
on:scriptChanged={loadScripts}
on:flowChanged={loadFlows}
on:appChanged={loadApps}
on:rawAppChanged={loadRawApps}
on:reload={() => {
loadScripts()
loadFlows()
loadApps()
loadRawApps()
}}
{showCode}
/>
{/if}
{/each}
{:else}
{#each (items ?? []).slice(0, nbDisplayed) as item (item.type + '/' + item.path)}
@@ -425,7 +427,7 @@
{/each}
{/if}
</div>
{#if items && items?.length > 30}
{#if items && items?.length > 30 && !treeView && nbDisplayed < items.length}
<span class="text-xs"
>{nbDisplayed} items out of {items.length}
<button class="ml-4" on:click={() => (nbDisplayed += 30)}>load 30 more</button></span
+128 -94
View File
@@ -1,3 +1,5 @@
<svelte:options immutable={true} />
<script lang="ts">
import { ChevronDown, ChevronUp, Folder, FolderTree, User } from 'lucide-svelte'
import Item from './Item.svelte'
@@ -6,7 +8,7 @@
import { slide } from 'svelte/transition'
import { pluralize } from '$lib/utils'
export let item: ItemType | FolderItem | UserItem | undefined
export let item: ItemType | FolderItem | UserItem
export let depth: number = 0
@@ -15,111 +17,143 @@
let opened: boolean = true
export let showCode: (path: string, summary: string) => void
let showMax = 30
</script>
{#if item}
{#if isFolder(item)}
<div>
<div class={twMerge('px-4 py-2 border-b w-full flex flex-row items-center justify-between')}>
{#if isFolder(item)}
<div>
<div
class={twMerge(
'px-4 py-2 border-b border-t w-full flex flex-row items-center justify-between'
)}
>
<div
class={twMerge('flex flex-row items-center gap-4 text-sm font-semibold')}
style={depth > 0 ? `padding-left: ${depth * 16}px;` : ''}
>
<div
class={twMerge('flex flex-row items-center gap-4 text-sm font-semibold')}
style={depth > 0 ? `padding-left: ${depth * 16}px;` : ''}
class=" rounded-md p-1 flex justify-center items-center border bg-gray-50 border-gray-200 dark:bg-transparent dark:border-gray-900"
>
<div
class=" rounded-md p-1 flex justify-center items-center border bg-gray-50 border-gray-200 dark:bg-transparent dark:border-gray-900"
>
{#if depth === 0}
<Folder size={20} color="#aaa" />
{:else}
<FolderTree size={20} color="#aaa" />
{/if}
</div>
<div>
{#if depth === 0}f/{/if}{item.folderName}
<div class="text-2xs font-normal text-secondary">
({pluralize(item.items.length, ' item')})
</div>
</div>
</div>
<button on:click={() => (opened = !opened)}>
{#if opened}
<ChevronUp size={20} />
{#if depth === 0}
<Folder size={20} color="#aaa" />
{:else}
<ChevronDown size={20} />
<FolderTree size={20} color="#aaa" />
{/if}
</button>
</div>
{#if opened}
<div transition:slide>
{#each item.items as subItem}
<svelte:self
item={subItem}
on:scriptChanged
on:flowChanged
on:appChanged
on:rawAppChanged
on:reload
depth={depth + 1}
/>
{/each}
</div>
{/if}
<div>
{#if depth === 0}f/{/if}{item.folderName}
<div class="text-2xs font-normal text-secondary">
({pluralize(item.items.length, ' item')})
</div>
</div>
</div>
<button on:click={() => (opened = !opened)}>
{#if opened}
<ChevronUp size={20} />
{:else}
<ChevronDown size={20} />
{/if}
</button>
</div>
{:else if isUser(item)}
<div>
<div class={twMerge('px-4 py-2 border-b w-full flex flex-row items-center justify-between')}>
{#if opened}
<div transition:slide>
{#each item.items.slice(0, showMax) as subItem (subItem['path'] ?? 'folder__' + subItem['folderName'])}
<svelte:self
item={subItem}
on:scriptChanged
on:flowChanged
on:appChanged
on:rawAppChanged
on:reload
depth={depth + 1}
/>
{/each}
{#if showMax < item.items.length}
<div
class="text-center text-sm text-secondary cursor-pointer hover:text-primary"
on:click={() => {
if (isFolder(item)) {
showMax += Math.min(30, item.items.length - showMax)
showMax = showMax
console.log(showMax)
}
}}
>
Show more ({showMax}/{item.items.length})
</div>
{/if}
</div>
{/if}
</div>
{:else if isUser(item)}
<div>
<div class={twMerge('px-4 py-2 border-b w-full flex flex-row items-center justify-between')}>
<div
class={twMerge('flex flex-row items-center gap-4 text-sm font-semibold')}
style={depth > 0 ? `padding-left: ${depth * 16}px;` : ''}
>
<div
class={twMerge('flex flex-row items-center gap-4 text-sm font-semibold')}
style={depth > 0 ? `padding-left: ${depth * 16}px;` : ''}
class=" rounded-md p-1 flex justify-center items-center border bg-gray-50 border-gray-200 dark:bg-transparent dark:border-gray-900"
>
<div
class=" rounded-md p-1 flex justify-center items-center border bg-gray-50 border-gray-200 dark:bg-transparent dark:border-gray-900"
>
<User size={20} color="#aaa" />
</div>
<User size={20} color="#aaa" />
</div>
<div>
u/{item.username}
<div class="text-2xs font-normal text-secondary"
>({pluralize(item.items.length, ' item')})</div
>
</div>
<div>
u/{item.username}
<div class="text-2xs font-normal text-secondary"
>({pluralize(item.items.length, ' item')})</div
>
</div>
<button on:click={() => (opened = !opened)}>
{#if opened}
<ChevronUp size={20} />
{:else}
<ChevronDown size={20} />
{/if}
</button>
</div>
{#if opened}
<div transition:slide>
{#each item.items as subItem}
<svelte:self
item={subItem}
on:scriptChanged
on:flowChanged
on:appChanged
on:rawAppChanged
on:reload
depth={depth + 1}
/>
{/each}
</div>
{/if}
<button on:click={() => (opened = !opened)}>
{#if opened}
<ChevronUp size={20} />
{:else}
<ChevronDown size={20} />
{/if}
</button>
</div>
{:else}
<Item
{item}
on:scriptChanged
on:flowChanged
on:appChanged
on:rawAppChanged
on:reload
{depth}
{showCode}
/>
{/if}
{#if opened}
<div transition:slide>
{#each item.items.slice(0, showMax) as subItem (subItem['path'] ?? 'folder__' + subItem['folderName'])}
<svelte:self
item={subItem}
on:scriptChanged
on:flowChanged
on:appChanged
on:rawAppChanged
on:reload
depth={depth + 1}
/>
{/each}
{#if showMax < item.items.length}
<!-- 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={() => {
if (isUser(item)) {
showMax += Math.min(30, item.items.length - showMax)
}
}}
>
Show more ({showMax}/{item.items.length})
</div>
{/if}
</div>
{/if}
</div>
{:else}
<Item
{item}
{showCode}
on:scriptChanged
on:flowChanged
on:appChanged
on:rawAppChanged
on:reload
{depth}
/>
{/if}