mirror of
https://github.com/LogicLabs-OU/OpenArchiver.git
synced 2026-04-06 00:31:57 +02:00
frontend: Responsive design for menu bar, pagination
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "open-archiver-enterprise-app",
|
||||
"version": "1.0.0",
|
||||
"version": "1.4.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "ts-node-dev -r tsconfig-paths/register --project tsconfig.json --respawn --transpile-only index.ts",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "open-archiver",
|
||||
"version": "0.3.4",
|
||||
"version": "0.4.0",
|
||||
"private": true,
|
||||
"license": "SEE LICENSE IN LICENSE-AGPL.txt",
|
||||
"license": "SEE LICENSE IN LICENSE file",
|
||||
"scripts": {
|
||||
"build:oss": "pnpm --filter \"./packages/*\" --filter \"!./packages/enterprise\" --filter \"./apps/open-archiver\" build",
|
||||
"build:enterprise": "cross-env VITE_ENTERPRISE_MODE=true pnpm build",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@open-archiver/enterprise",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"license": "SEE LICENSE IN LICENSE.txt",
|
||||
"license": "SEE LICENSE IN LICENSE-BSL.txt",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"@iconify/svelte": "^5.0.1",
|
||||
"@open-archiver/types": "workspace:*",
|
||||
"@sveltejs/kit": "^2.38.1",
|
||||
"bits-ui": "^2.8.10",
|
||||
"clsx": "^2.1.1",
|
||||
"d3-shape": "^3.2.0",
|
||||
"html-entities": "^2.6.0",
|
||||
@@ -32,13 +31,14 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@internationalized/date": "^3.8.2",
|
||||
"@lucide/svelte": "^0.515.0",
|
||||
"@lucide/svelte": "^0.544.0",
|
||||
"@sveltejs/adapter-auto": "^6.0.0",
|
||||
"@sveltejs/adapter-node": "^5.2.13",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"@types/d3-shape": "^3.1.7",
|
||||
"@types/semver": "^7.7.1",
|
||||
"bits-ui": "^2.12.0",
|
||||
"dotenv": "^17.2.0",
|
||||
"layerchart": "2.0.0-next.27",
|
||||
"mode-watcher": "^1.1.0",
|
||||
|
||||
25
packages/frontend/src/lib/components/ui/pagination/index.ts
Normal file
25
packages/frontend/src/lib/components/ui/pagination/index.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import Root from "./pagination.svelte";
|
||||
import Content from "./pagination-content.svelte";
|
||||
import Item from "./pagination-item.svelte";
|
||||
import Link from "./pagination-link.svelte";
|
||||
import PrevButton from "./pagination-prev-button.svelte";
|
||||
import NextButton from "./pagination-next-button.svelte";
|
||||
import Ellipsis from "./pagination-ellipsis.svelte";
|
||||
|
||||
export {
|
||||
Root,
|
||||
Content,
|
||||
Item,
|
||||
Link,
|
||||
PrevButton,
|
||||
NextButton,
|
||||
Ellipsis,
|
||||
//
|
||||
Root as Pagination,
|
||||
Content as PaginationContent,
|
||||
Item as PaginationItem,
|
||||
Link as PaginationLink,
|
||||
PrevButton as PaginationPrevButton,
|
||||
NextButton as PaginationNextButton,
|
||||
Ellipsis as PaginationEllipsis,
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLAttributes<HTMLUListElement>> = $props();
|
||||
</script>
|
||||
|
||||
<ul
|
||||
bind:this={ref}
|
||||
data-slot="pagination-content"
|
||||
class={cn("flex flex-row items-center gap-1", className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
</ul>
|
||||
@@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
import EllipsisIcon from "@lucide/svelte/icons/ellipsis";
|
||||
import { cn, type WithElementRef, type WithoutChildren } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
...restProps
|
||||
}: WithoutChildren<WithElementRef<HTMLAttributes<HTMLSpanElement>>> = $props();
|
||||
</script>
|
||||
|
||||
<span
|
||||
bind:this={ref}
|
||||
aria-hidden="true"
|
||||
data-slot="pagination-ellipsis"
|
||||
class={cn("flex size-9 items-center justify-center", className)}
|
||||
{...restProps}
|
||||
>
|
||||
<EllipsisIcon class="size-4" />
|
||||
<span class="sr-only">More pages</span>
|
||||
</span>
|
||||
@@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
import type { HTMLLiAttributes } from "svelte/elements";
|
||||
import type { WithElementRef } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
children,
|
||||
...restProps
|
||||
}: WithElementRef<HTMLLiAttributes> = $props();
|
||||
</script>
|
||||
|
||||
<li bind:this={ref} data-slot="pagination-item" {...restProps}>
|
||||
{@render children?.()}
|
||||
</li>
|
||||
@@ -0,0 +1,39 @@
|
||||
<script lang="ts">
|
||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import { type Props, buttonVariants } from "$lib/components/ui/button/index.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
size = "icon",
|
||||
isActive,
|
||||
page,
|
||||
children,
|
||||
...restProps
|
||||
}: PaginationPrimitive.PageProps &
|
||||
Props & {
|
||||
isActive: boolean;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
{#snippet Fallback()}
|
||||
{page.value}
|
||||
{/snippet}
|
||||
|
||||
<PaginationPrimitive.Page
|
||||
bind:ref
|
||||
{page}
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
data-slot="pagination-link"
|
||||
data-active={isActive}
|
||||
class={cn(
|
||||
buttonVariants({
|
||||
variant: isActive ? "outline" : "ghost",
|
||||
size,
|
||||
}),
|
||||
className
|
||||
)}
|
||||
children={children || Fallback}
|
||||
{...restProps}
|
||||
/>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script lang="ts">
|
||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||
import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
|
||||
import { buttonVariants } from "$lib/components/ui/button/index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: PaginationPrimitive.NextButtonProps = $props();
|
||||
</script>
|
||||
|
||||
{#snippet Fallback()}
|
||||
<span>Next</span>
|
||||
<ChevronRightIcon class="size-4" />
|
||||
{/snippet}
|
||||
|
||||
<PaginationPrimitive.NextButton
|
||||
bind:ref
|
||||
aria-label="Go to next page"
|
||||
class={cn(
|
||||
buttonVariants({
|
||||
size: "default",
|
||||
variant: "ghost",
|
||||
class: "gap-1 px-2.5 sm:pr-2.5",
|
||||
}),
|
||||
className
|
||||
)}
|
||||
children={children || Fallback}
|
||||
{...restProps}
|
||||
/>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script lang="ts">
|
||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||
import ChevronLeftIcon from "@lucide/svelte/icons/chevron-left";
|
||||
import { buttonVariants } from "$lib/components/ui/button/index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
children,
|
||||
...restProps
|
||||
}: PaginationPrimitive.PrevButtonProps = $props();
|
||||
</script>
|
||||
|
||||
{#snippet Fallback()}
|
||||
<ChevronLeftIcon class="size-4" />
|
||||
<span>Previous</span>
|
||||
{/snippet}
|
||||
|
||||
<PaginationPrimitive.PrevButton
|
||||
bind:ref
|
||||
aria-label="Go to previous page"
|
||||
class={cn(
|
||||
buttonVariants({
|
||||
size: "default",
|
||||
variant: "ghost",
|
||||
class: "gap-1 px-2.5 sm:pl-2.5",
|
||||
}),
|
||||
className
|
||||
)}
|
||||
children={children || Fallback}
|
||||
{...restProps}
|
||||
/>
|
||||
@@ -0,0 +1,28 @@
|
||||
<script lang="ts">
|
||||
import { Pagination as PaginationPrimitive } from "bits-ui";
|
||||
|
||||
import { cn } from "$lib/utils.js";
|
||||
|
||||
let {
|
||||
ref = $bindable(null),
|
||||
class: className,
|
||||
count = 0,
|
||||
perPage = 10,
|
||||
page = $bindable(1),
|
||||
siblingCount = 1,
|
||||
...restProps
|
||||
}: PaginationPrimitive.RootProps = $props();
|
||||
</script>
|
||||
|
||||
<PaginationPrimitive.Root
|
||||
bind:ref
|
||||
bind:page
|
||||
role="navigation"
|
||||
aria-label="pagination"
|
||||
data-slot="pagination"
|
||||
class={cn("mx-auto flex w-full justify-center", className)}
|
||||
{count}
|
||||
{perPage}
|
||||
{siblingCount}
|
||||
{...restProps}
|
||||
/>
|
||||
@@ -1,7 +1,9 @@
|
||||
<script lang="ts">
|
||||
import * as NavigationMenu from '$lib/components/ui/navigation-menu/index.js';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu/index.js';
|
||||
import Button from '$lib/components/ui/button/button.svelte';
|
||||
import { authStore } from '$lib/stores/auth.store';
|
||||
import { Menu } from 'lucide-svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
import ThemeSwitcher from '$lib/components/custom/ThemeSwitcher.svelte';
|
||||
@@ -20,13 +22,19 @@
|
||||
|
||||
const baseNavItems: NavItem[] = [
|
||||
{ href: '/dashboard', label: $t('app.layout.dashboard'), position: 0 },
|
||||
{ href: '/dashboard/ingestions', label: $t('app.layout.ingestions'), position: 1 },
|
||||
{
|
||||
href: '/dashboard/archived-emails',
|
||||
label: $t('app.layout.archived_emails'),
|
||||
position: 2,
|
||||
label: $t('app.archive.title'),
|
||||
subMenu: [
|
||||
{ href: '/dashboard/ingestions', label: $t('app.layout.ingestions') },
|
||||
{
|
||||
href: '/dashboard/archived-emails',
|
||||
label: $t('app.layout.archived_emails'),
|
||||
},
|
||||
],
|
||||
position: 1,
|
||||
},
|
||||
{ href: '/dashboard/search', label: $t('app.layout.search'), position: 3 },
|
||||
|
||||
{ href: '/dashboard/search', label: $t('app.layout.search'), position: 2 },
|
||||
{
|
||||
label: $t('app.layout.admin'),
|
||||
subMenu: [
|
||||
@@ -43,7 +51,7 @@
|
||||
label: $t('app.layout.roles'),
|
||||
},
|
||||
],
|
||||
position: 5,
|
||||
position: 4,
|
||||
},
|
||||
{
|
||||
label: $t('app.layout.settings'),
|
||||
@@ -57,7 +65,7 @@
|
||||
label: $t('app.layout.api_keys'),
|
||||
},
|
||||
],
|
||||
position: 6,
|
||||
position: 5,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -65,13 +73,42 @@
|
||||
{
|
||||
label: 'Compliance',
|
||||
subMenu: [{ href: '/dashboard/compliance/audit-log', label: 'Audit Log' }],
|
||||
position: 4,
|
||||
position: 3,
|
||||
},
|
||||
];
|
||||
|
||||
function mergeNavItems(baseItems: NavItem[], enterpriseItems: NavItem[]): NavItem[] {
|
||||
const mergedItemsMap = new Map<number, NavItem>();
|
||||
|
||||
for (const item of baseItems) {
|
||||
mergedItemsMap.set(item.position, {
|
||||
...item,
|
||||
subMenu: item.subMenu ? [...item.subMenu] : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
for (const enterpriseItem of enterpriseItems) {
|
||||
const existingItem = mergedItemsMap.get(enterpriseItem.position);
|
||||
|
||||
if (existingItem) {
|
||||
if (existingItem.subMenu && enterpriseItem.subMenu) {
|
||||
existingItem.subMenu = [...existingItem.subMenu, ...enterpriseItem.subMenu];
|
||||
}
|
||||
} else {
|
||||
mergedItemsMap.set(enterpriseItem.position, {
|
||||
...enterpriseItem,
|
||||
subMenu: enterpriseItem.subMenu ? [...enterpriseItem.subMenu] : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const mergedItems = Array.from(mergedItemsMap.values());
|
||||
return mergedItems.sort((a, b) => a.position - b.position);
|
||||
}
|
||||
|
||||
let navItems: NavItem[] = $state(baseNavItems);
|
||||
if (data.enterpriseMode) {
|
||||
navItems = [...baseNavItems, ...enterpriseNavItems].sort((a, b) => a.position - b.position);
|
||||
navItems = mergeNavItems(baseNavItems, enterpriseNavItems);
|
||||
}
|
||||
function handleLogout() {
|
||||
authStore.logout();
|
||||
@@ -79,59 +116,100 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<header class="bg-background sticky top-0 z-40 border-b">
|
||||
<header class="bg-background sticky top-0 z-40 border-b px-4 md:px-0">
|
||||
<div class="container mx-auto flex h-16 flex-row items-center justify-between">
|
||||
<a href="/dashboard" class="flex flex-row items-center gap-2 font-bold">
|
||||
<img src="/logos/logo-sq.svg" alt="OpenArchiver Logo" class="h-8 w-8" />
|
||||
<span>Open Archiver</span>
|
||||
<span class="hidden sm:inline-block">Open Archiver</span>
|
||||
</a>
|
||||
<NavigationMenu.Root viewport={false}>
|
||||
<NavigationMenu.List class="flex items-center space-x-4">
|
||||
{#each navItems as item}
|
||||
{#if item.subMenu && item.subMenu.length > 0}
|
||||
<NavigationMenu.Item
|
||||
class={item.subMenu.some((sub) =>
|
||||
page.url.pathname.startsWith(
|
||||
sub.href.substring(0, sub.href.lastIndexOf('/'))
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
<div class="hidden lg:flex">
|
||||
<NavigationMenu.Root viewport={false}>
|
||||
<NavigationMenu.List class="flex items-center space-x-4">
|
||||
{#each navItems as item}
|
||||
{#if item.subMenu && item.subMenu.length > 0}
|
||||
<NavigationMenu.Item
|
||||
class={item.subMenu.some((sub) =>
|
||||
page.url.pathname.startsWith(
|
||||
sub.href.substring(0, sub.href.lastIndexOf('/'))
|
||||
)
|
||||
)
|
||||
)
|
||||
? 'bg-accent rounded-md'
|
||||
: ''}
|
||||
>
|
||||
<NavigationMenu.Trigger class="cursor-pointer font-normal">
|
||||
{item.label}
|
||||
</NavigationMenu.Trigger>
|
||||
<NavigationMenu.Content>
|
||||
<ul class="grid w-fit min-w-28 gap-1 p-1">
|
||||
{#each item.subMenu as subItem}
|
||||
<li>
|
||||
<NavigationMenu.Link href={subItem.href}>
|
||||
{subItem.label}
|
||||
</NavigationMenu.Link>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</NavigationMenu.Content>
|
||||
</NavigationMenu.Item>
|
||||
{:else if item.href}
|
||||
<NavigationMenu.Item
|
||||
class={page.url.pathname === item.href ? 'bg-accent rounded-md' : ''}
|
||||
>
|
||||
<NavigationMenu.Link href={item.href}>
|
||||
{item.label}
|
||||
</NavigationMenu.Link>
|
||||
</NavigationMenu.Item>
|
||||
{/if}
|
||||
{/each}
|
||||
</NavigationMenu.List>
|
||||
</NavigationMenu.Root>
|
||||
? 'bg-accent rounded-md'
|
||||
: ''}
|
||||
>
|
||||
<NavigationMenu.Trigger class="cursor-pointer font-normal">
|
||||
{item.label}
|
||||
</NavigationMenu.Trigger>
|
||||
<NavigationMenu.Content>
|
||||
<ul class="grid w-fit min-w-32 gap-1 p-1">
|
||||
{#each item.subMenu as subItem}
|
||||
<li>
|
||||
<NavigationMenu.Link href={subItem.href}>
|
||||
{subItem.label}
|
||||
</NavigationMenu.Link>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</NavigationMenu.Content>
|
||||
</NavigationMenu.Item>
|
||||
{:else if item.href}
|
||||
<NavigationMenu.Item
|
||||
class={page.url.pathname === item.href
|
||||
? 'bg-accent rounded-md'
|
||||
: ''}
|
||||
>
|
||||
<NavigationMenu.Link href={item.href}>
|
||||
{item.label}
|
||||
</NavigationMenu.Link>
|
||||
</NavigationMenu.Item>
|
||||
{/if}
|
||||
{/each}
|
||||
</NavigationMenu.List>
|
||||
</NavigationMenu.Root>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<!-- Mobile Navigation -->
|
||||
<div class="lg:hidden">
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
{#snippet child({ props })}
|
||||
<Button {...props} variant="ghost" size="icon">
|
||||
<Menu class="h-6 w-6" />
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content class="w-56" align="end">
|
||||
{#each navItems as item}
|
||||
{#if item.subMenu && item.subMenu.length > 0}
|
||||
<DropdownMenu.Sub>
|
||||
<DropdownMenu.SubTrigger>{item.label}</DropdownMenu.SubTrigger>
|
||||
<DropdownMenu.SubContent>
|
||||
{#each item.subMenu as subItem}
|
||||
<a href={subItem.href}>
|
||||
<DropdownMenu.Item
|
||||
>{subItem.label}</DropdownMenu.Item
|
||||
>
|
||||
</a>
|
||||
{/each}
|
||||
</DropdownMenu.SubContent>
|
||||
</DropdownMenu.Sub>
|
||||
{:else if item.href}
|
||||
<a href={item.href}>
|
||||
<DropdownMenu.Item>{item.label}</DropdownMenu.Item>
|
||||
</a>
|
||||
{/if}
|
||||
{/each}
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<ThemeSwitcher />
|
||||
<Button onclick={handleLogout} variant="outline">{$t('app.layout.logout')}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container mx-auto my-10">
|
||||
<main class="container mx-auto my-10 px-4 md:px-0">
|
||||
{@render children()}
|
||||
</main>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{#each queues as queue}
|
||||
<a href={`/dashboard/admin/jobs/${queue.name}`} class="block">
|
||||
<Card.Root class="hover:border-primary">
|
||||
<Card.Root class=" hover:shadow-md">
|
||||
<Card.Header>
|
||||
<Card.Title class="capitalize">{queue.name.split('_').join(' ')}</Card.Title
|
||||
>
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
import type { PageData } from './$types';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { t } from '$lib/translations';
|
||||
import { Badge } from '$lib/components/ui/badge';
|
||||
import * as Table from '$lib/components/ui/table';
|
||||
import { Button, buttonVariants } from '$lib/components/ui/button';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { goto } from '$app/navigation';
|
||||
import type { JobStatus } from '@open-archiver/types';
|
||||
import * as Pagination from '$lib/components/ui/pagination/index.js';
|
||||
import ChevronLeft from 'lucide-svelte/icons/chevron-left';
|
||||
import ChevronRight from 'lucide-svelte/icons/chevron-right';
|
||||
import { onMount } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
let { data }: { data: PageData } = $props();
|
||||
let queue = $derived(data.queue);
|
||||
@@ -22,6 +26,16 @@
|
||||
|
||||
let selectedStatus: JobStatus | undefined = $state('failed');
|
||||
|
||||
onMount(() => {
|
||||
if (browser) {
|
||||
const url = new URL(window.location.href);
|
||||
const status = url.searchParams.get('status') as JobStatus;
|
||||
if (status) {
|
||||
selectedStatus = status;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function handleStatusChange(status: JobStatus) {
|
||||
selectedStatus = status;
|
||||
const url = new URL(window.location.href);
|
||||
@@ -29,12 +43,6 @@
|
||||
url.searchParams.set('page', '1');
|
||||
goto(url.toString(), { invalidateAll: true });
|
||||
}
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.set('page', page.toString());
|
||||
goto(url.toString(), { invalidateAll: true });
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -132,32 +140,72 @@
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</Card.Content>
|
||||
<Card.Footer class="flex justify-between">
|
||||
<div>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
{$t('app.jobs.showing')}
|
||||
{queue.jobs.length}
|
||||
{$t('app.jobs.of')}
|
||||
{queue.pagination.totalJobs}
|
||||
{$t('app.jobs.jobs')}
|
||||
</p>
|
||||
<Card.Footer class="flex flex-col items-center justify-between gap-4 sm:flex-row">
|
||||
<div class="text-muted-foreground text-nowrap text-sm">
|
||||
{$t('app.jobs.showing')}
|
||||
{queue.jobs.length}
|
||||
{$t('app.jobs.of')}
|
||||
{queue.pagination.totalJobs}
|
||||
{$t('app.jobs.jobs')}
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
disabled={queue.pagination.currentPage <= 1}
|
||||
onclick={() => handlePageChange(queue.pagination.currentPage - 1)}
|
||||
{#if queue.pagination.totalJobs > queue.pagination.limit}
|
||||
<Pagination.Root
|
||||
count={queue.pagination.totalJobs}
|
||||
perPage={queue.pagination.limit}
|
||||
page={queue.pagination.currentPage}
|
||||
>
|
||||
{$t('app.jobs.previous')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
disabled={queue.pagination.currentPage >= queue.pagination.totalPages}
|
||||
onclick={() => handlePageChange(queue.pagination.currentPage + 1)}
|
||||
>
|
||||
{$t('app.jobs.next')}
|
||||
</Button>
|
||||
</div>
|
||||
{#snippet children({ pages, currentPage })}
|
||||
<Pagination.Content>
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/admin/jobs/${queue.name}?status=${selectedStatus}&page=${
|
||||
currentPage - 1
|
||||
}`}
|
||||
>
|
||||
<Pagination.PrevButton>
|
||||
<ChevronLeft class="h-4 w-4" />
|
||||
<span class="hidden sm:block"
|
||||
>{$t('app.jobs.previous')}</span
|
||||
>
|
||||
</Pagination.PrevButton>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
{#each pages as page (page.key)}
|
||||
{#if page.type === 'ellipsis'}
|
||||
<Pagination.Item>
|
||||
<Pagination.Ellipsis />
|
||||
</Pagination.Item>
|
||||
{:else}
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/admin/jobs/${queue.name}?status=${selectedStatus}&page=${page.value}`}
|
||||
>
|
||||
<Pagination.Link
|
||||
{page}
|
||||
isActive={currentPage === page.value}
|
||||
>
|
||||
{page.value}
|
||||
</Pagination.Link>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
{/if}
|
||||
{/each}
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/admin/jobs/${queue.name}?status=${selectedStatus}&page=${
|
||||
currentPage + 1
|
||||
}`}
|
||||
>
|
||||
<Pagination.NextButton>
|
||||
<span class="hidden sm:block">{$t('app.jobs.next')}</span>
|
||||
<ChevronRight class="h-4 w-4" />
|
||||
</Pagination.NextButton>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
</Pagination.Content>
|
||||
{/snippet}
|
||||
</Pagination.Root>
|
||||
{/if}
|
||||
</Card.Footer>
|
||||
</Card.Root>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import { goto } from '$app/navigation';
|
||||
import { t } from '$lib/translations';
|
||||
import * as Pagination from '$lib/components/ui/pagination/index.js';
|
||||
import ChevronLeft from 'lucide-svelte/icons/chevron-left';
|
||||
import ChevronRight from 'lucide-svelte/icons/chevron-right';
|
||||
|
||||
let { data }: { data: PageData } = $props();
|
||||
|
||||
@@ -17,55 +20,6 @@
|
||||
goto(`/dashboard/archived-emails?ingestionSourceId=${value}`);
|
||||
}
|
||||
};
|
||||
|
||||
const getPaginationItems = (currentPage: number, totalPages: number, siblingCount = 1) => {
|
||||
const totalPageNumbers = siblingCount + 5;
|
||||
|
||||
if (totalPages <= totalPageNumbers) {
|
||||
return Array.from({ length: totalPages }, (_, i) => i + 1);
|
||||
}
|
||||
|
||||
const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
|
||||
const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages);
|
||||
|
||||
const shouldShowLeftDots = leftSiblingIndex > 2;
|
||||
const shouldShowRightDots = rightSiblingIndex < totalPages - 2;
|
||||
|
||||
const firstPageIndex = 1;
|
||||
const lastPageIndex = totalPages;
|
||||
|
||||
if (!shouldShowLeftDots && shouldShowRightDots) {
|
||||
let leftItemCount = 3 + 2 * siblingCount;
|
||||
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
||||
return [...leftRange, '...', totalPages];
|
||||
}
|
||||
|
||||
if (shouldShowLeftDots && !shouldShowRightDots) {
|
||||
let rightItemCount = 3 + 2 * siblingCount;
|
||||
let rightRange = Array.from(
|
||||
{ length: rightItemCount },
|
||||
(_, i) => totalPages - rightItemCount + i + 1
|
||||
);
|
||||
return [firstPageIndex, '...', ...rightRange];
|
||||
}
|
||||
|
||||
if (shouldShowLeftDots && shouldShowRightDots) {
|
||||
let middleRange = Array.from(
|
||||
{ length: rightSiblingIndex - leftSiblingIndex + 1 },
|
||||
(_, i) => leftSiblingIndex + i
|
||||
);
|
||||
return [firstPageIndex, '...', ...middleRange, '...', lastPageIndex];
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
let paginationItems = $derived(
|
||||
getPaginationItems(
|
||||
archivedEmails.page,
|
||||
Math.ceil(archivedEmails.total / archivedEmails.limit)
|
||||
)
|
||||
);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -155,46 +109,61 @@
|
||||
</div>
|
||||
|
||||
{#if archivedEmails.total > archivedEmails.limit}
|
||||
<div class="mt-8 flex flex-row items-center justify-center space-x-2">
|
||||
<a
|
||||
href={`/dashboard/archived-emails?ingestionSourceId=${selectedIngestionSourceId}&page=${
|
||||
archivedEmails.page - 1
|
||||
}&limit=${archivedEmails.limit}`}
|
||||
class={archivedEmails.page === 1 ? 'pointer-events-none' : ''}
|
||||
<div class="mt-8">
|
||||
<Pagination.Root
|
||||
count={archivedEmails.total}
|
||||
perPage={archivedEmails.limit}
|
||||
page={archivedEmails.page}
|
||||
>
|
||||
<Button variant="outline" disabled={archivedEmails.page === 1}
|
||||
>{$t('app.archived_emails_page.prev')}</Button
|
||||
>
|
||||
</a>
|
||||
|
||||
{#each paginationItems as item}
|
||||
{#if typeof item === 'number'}
|
||||
<a
|
||||
href={`/dashboard/archived-emails?ingestionSourceId=${selectedIngestionSourceId}&page=${item}&limit=${archivedEmails.limit}`}
|
||||
>
|
||||
<Button variant={item === archivedEmails.page ? 'default' : 'outline'}
|
||||
>{item}</Button
|
||||
>
|
||||
</a>
|
||||
{:else}
|
||||
<span class="px-4 py-2">...</span>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
<a
|
||||
href={`/dashboard/archived-emails?ingestionSourceId=${selectedIngestionSourceId}&page=${
|
||||
archivedEmails.page + 1
|
||||
}&limit=${archivedEmails.limit}`}
|
||||
class={archivedEmails.page === Math.ceil(archivedEmails.total / archivedEmails.limit)
|
||||
? 'pointer-events-none'
|
||||
: ''}
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
disabled={archivedEmails.page ===
|
||||
Math.ceil(archivedEmails.total / archivedEmails.limit)}
|
||||
>{$t('app.archived_emails_page.next')}</Button
|
||||
>
|
||||
</a>
|
||||
{#snippet children({ pages, currentPage })}
|
||||
<Pagination.Content>
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/archived-emails?ingestionSourceId=${selectedIngestionSourceId}&page=${
|
||||
currentPage - 1
|
||||
}&limit=${archivedEmails.limit}`}
|
||||
>
|
||||
<Pagination.PrevButton>
|
||||
<ChevronLeft class="h-4 w-4" />
|
||||
<span class="hidden sm:block"
|
||||
>{$t('app.archived_emails_page.prev')}</span
|
||||
>
|
||||
</Pagination.PrevButton>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
{#each pages as page (page.key)}
|
||||
{#if page.type === 'ellipsis'}
|
||||
<Pagination.Item>
|
||||
<Pagination.Ellipsis />
|
||||
</Pagination.Item>
|
||||
{:else}
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/archived-emails?ingestionSourceId=${selectedIngestionSourceId}&page=${page.value}&limit=${archivedEmails.limit}`}
|
||||
>
|
||||
<Pagination.Link {page} isActive={currentPage === page.value}>
|
||||
{page.value}
|
||||
</Pagination.Link>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
{/if}
|
||||
{/each}
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/archived-emails?ingestionSourceId=${selectedIngestionSourceId}&page=${
|
||||
currentPage + 1
|
||||
}&limit=${archivedEmails.limit}`}
|
||||
>
|
||||
<Pagination.NextButton>
|
||||
<span class="hidden sm:block"
|
||||
>{$t('app.archived_emails_page.next')}</span
|
||||
>
|
||||
<ChevronRight class="h-4 w-4" />
|
||||
</Pagination.NextButton>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
</Pagination.Content>
|
||||
{/snippet}
|
||||
</Pagination.Root>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -14,58 +14,15 @@
|
||||
import type { AuditLogAction, AuditLogEntry } from '@open-archiver/types';
|
||||
import * as Dialog from '$lib/components/ui/dialog/index.js';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import * as Pagination from '$lib/components/ui/pagination/index.js';
|
||||
import ChevronLeft from 'lucide-svelte/icons/chevron-left';
|
||||
import ChevronRight from 'lucide-svelte/icons/chevron-right';
|
||||
|
||||
let { data }: { data: PageData } = $props();
|
||||
|
||||
let logs = $derived(data.logs);
|
||||
let meta = $derived(data.meta);
|
||||
|
||||
const getPaginationItems = (currentPage: number, totalPages: number, siblingCount = 1) => {
|
||||
const totalPageNumbers = siblingCount + 5;
|
||||
|
||||
if (totalPages <= totalPageNumbers) {
|
||||
return Array.from({ length: totalPages }, (_, i) => i + 1);
|
||||
}
|
||||
|
||||
const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
|
||||
const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages);
|
||||
|
||||
const shouldShowLeftDots = leftSiblingIndex > 2;
|
||||
const shouldShowRightDots = rightSiblingIndex < totalPages - 2;
|
||||
|
||||
const firstPageIndex = 1;
|
||||
const lastPageIndex = totalPages;
|
||||
|
||||
if (!shouldShowLeftDots && shouldShowRightDots) {
|
||||
let leftItemCount = 3 + 2 * siblingCount;
|
||||
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
||||
return [...leftRange, '...', totalPages];
|
||||
}
|
||||
|
||||
if (shouldShowLeftDots && !shouldShowRightDots) {
|
||||
let rightItemCount = 3 + 2 * siblingCount;
|
||||
let rightRange = Array.from(
|
||||
{ length: rightItemCount },
|
||||
(_, i) => totalPages - rightItemCount + i + 1
|
||||
);
|
||||
return [firstPageIndex, '...', ...rightRange];
|
||||
}
|
||||
|
||||
if (shouldShowLeftDots && shouldShowRightDots) {
|
||||
let middleRange = Array.from(
|
||||
{ length: rightSiblingIndex - leftSiblingIndex + 1 },
|
||||
(_, i) => leftSiblingIndex + i
|
||||
);
|
||||
return [firstPageIndex, '...', ...middleRange, '...', lastPageIndex];
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
let paginationItems = $derived(
|
||||
getPaginationItems(meta.page, Math.ceil(meta.total / meta.limit))
|
||||
);
|
||||
|
||||
let isDetailViewOpen = $state(false);
|
||||
let selectedLog = $state<AuditLogEntry | null>(null);
|
||||
|
||||
@@ -228,32 +185,54 @@
|
||||
</div>
|
||||
|
||||
{#if meta.total > meta.limit}
|
||||
<div class="mt-8 flex flex-row items-center justify-center space-x-2">
|
||||
<a
|
||||
href={`/dashboard/compliance/audit-log?page=${meta.page - 1}&limit=${meta.limit}`}
|
||||
class={meta.page === 1 ? 'pointer-events-none' : ''}
|
||||
>
|
||||
<Button variant="outline" disabled={meta.page === 1}>{$t('app.audit_log.prev')}</Button>
|
||||
</a>
|
||||
|
||||
{#each paginationItems as item}
|
||||
{#if typeof item === 'number'}
|
||||
<a href={`/dashboard/compliance/audit-log?page=${item}&limit=${meta.limit}`}>
|
||||
<Button variant={item === meta.page ? 'default' : 'outline'}>{item}</Button>
|
||||
</a>
|
||||
{:else}
|
||||
<span class="px-4 py-2">...</span>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
<a
|
||||
href={`/dashboard/compliance/audit-log?page=${meta.page + 1}&limit=${meta.limit}`}
|
||||
class={meta.page === Math.ceil(meta.total / meta.limit) ? 'pointer-events-none' : ''}
|
||||
>
|
||||
<Button variant="outline" disabled={meta.page === Math.ceil(meta.total / meta.limit)}
|
||||
>{$t('app.audit_log.next')}</Button
|
||||
>
|
||||
</a>
|
||||
<div class="mt-8">
|
||||
<Pagination.Root count={meta.total} perPage={meta.limit} page={meta.page}>
|
||||
{#snippet children({ pages, currentPage })}
|
||||
<Pagination.Content>
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/compliance/audit-log?page=${
|
||||
currentPage - 1
|
||||
}&limit=${meta.limit}`}
|
||||
>
|
||||
<Pagination.PrevButton>
|
||||
<ChevronLeft class="h-4 w-4" />
|
||||
<span class="hidden sm:block">{$t('app.audit_log.prev')}</span>
|
||||
</Pagination.PrevButton>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
{#each pages as page (page.key)}
|
||||
{#if page.type === 'ellipsis'}
|
||||
<Pagination.Item>
|
||||
<Pagination.Ellipsis />
|
||||
</Pagination.Item>
|
||||
{:else}
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/compliance/audit-log?page=${page.value}&limit=${meta.limit}`}
|
||||
>
|
||||
<Pagination.Link {page} isActive={currentPage === page.value}>
|
||||
{page.value}
|
||||
</Pagination.Link>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
{/if}
|
||||
{/each}
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/compliance/audit-log?page=${
|
||||
currentPage + 1
|
||||
}&limit=${meta.limit}`}
|
||||
>
|
||||
<Pagination.NextButton>
|
||||
<span class="hidden sm:block">{$t('app.audit_log.next')}</span>
|
||||
<ChevronRight class="h-4 w-4" />
|
||||
</Pagination.NextButton>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
</Pagination.Content>
|
||||
{/snippet}
|
||||
</Pagination.Root>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
import CircleAlertIcon from '@lucide/svelte/icons/circle-alert';
|
||||
import * as Alert from '$lib/components/ui/alert/index.js';
|
||||
import { t } from '$lib/translations';
|
||||
import * as Pagination from '$lib/components/ui/pagination/index.js';
|
||||
import ChevronLeft from 'lucide-svelte/icons/chevron-left';
|
||||
import ChevronRight from 'lucide-svelte/icons/chevron-right';
|
||||
|
||||
let { data }: { data: PageData } = $props();
|
||||
let searchResult = $derived(data.searchResult);
|
||||
@@ -121,55 +124,6 @@
|
||||
|
||||
return snippets;
|
||||
}
|
||||
|
||||
const getPaginationItems = (currentPage: number, totalPages: number, siblingCount = 1) => {
|
||||
const totalPageNumbers = siblingCount + 5;
|
||||
|
||||
if (totalPages <= totalPageNumbers) {
|
||||
return Array.from({ length: totalPages }, (_, i) => i + 1);
|
||||
}
|
||||
|
||||
const leftSiblingIndex = Math.max(currentPage - siblingCount, 1);
|
||||
const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages);
|
||||
|
||||
const shouldShowLeftDots = leftSiblingIndex > 2;
|
||||
const shouldShowRightDots = rightSiblingIndex < totalPages - 2;
|
||||
|
||||
const firstPageIndex = 1;
|
||||
const lastPageIndex = totalPages;
|
||||
|
||||
if (!shouldShowLeftDots && shouldShowRightDots) {
|
||||
let leftItemCount = 3 + 2 * siblingCount;
|
||||
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
||||
return [...leftRange, '...', totalPages];
|
||||
}
|
||||
|
||||
if (shouldShowLeftDots && !shouldShowRightDots) {
|
||||
let rightItemCount = 3 + 2 * siblingCount;
|
||||
let rightRange = Array.from(
|
||||
{ length: rightItemCount },
|
||||
(_, i) => totalPages - rightItemCount + i + 1
|
||||
);
|
||||
return [firstPageIndex, '...', ...rightRange];
|
||||
}
|
||||
|
||||
if (shouldShowLeftDots && shouldShowRightDots) {
|
||||
let middleRange = Array.from(
|
||||
{ length: rightSiblingIndex - leftSiblingIndex + 1 },
|
||||
(_, i) => leftSiblingIndex + i
|
||||
);
|
||||
return [firstPageIndex, '...', ...middleRange, '...', lastPageIndex];
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
let paginationItems = $derived(
|
||||
getPaginationItems(
|
||||
page,
|
||||
Math.ceil((searchResult?.total || 0) / (searchResult?.limit || 10))
|
||||
)
|
||||
);
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -336,42 +290,57 @@
|
||||
</div>
|
||||
|
||||
{#if searchResult.total > searchResult.limit}
|
||||
<div class="mt-8 flex flex-row items-center justify-center space-x-2">
|
||||
<a
|
||||
href={`/dashboard/search?keywords=${keywords}&page=${
|
||||
page - 1
|
||||
}&matchingStrategy=${matchingStrategy}`}
|
||||
class={page === 1 ? 'pointer-events-none' : ''}
|
||||
>
|
||||
<Button variant="outline" disabled={page === 1}>{$t('app.search.prev')}</Button>
|
||||
</a>
|
||||
|
||||
{#each paginationItems as item}
|
||||
{#if typeof item === 'number'}
|
||||
<a
|
||||
href={`/dashboard/search?keywords=${keywords}&page=${item}&matchingStrategy=${matchingStrategy}`}
|
||||
>
|
||||
<Button variant={item === page ? 'default' : 'outline'}>{item}</Button>
|
||||
</a>
|
||||
{:else}
|
||||
<span class="px-4 py-2">...</span>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
<a
|
||||
href={`/dashboard/search?keywords=${keywords}&page=${
|
||||
page + 1
|
||||
}&matchingStrategy=${matchingStrategy}`}
|
||||
class={page === Math.ceil(searchResult.total / searchResult.limit)
|
||||
? 'pointer-events-none'
|
||||
: ''}
|
||||
>
|
||||
<Button
|
||||
variant="outline"
|
||||
disabled={page === Math.ceil(searchResult.total / searchResult.limit)}
|
||||
>{$t('app.search.next')}</Button
|
||||
>
|
||||
</a>
|
||||
<div class="mt-8">
|
||||
<Pagination.Root count={searchResult.total} perPage={searchResult.limit} {page}>
|
||||
{#snippet children({ pages, currentPage })}
|
||||
<Pagination.Content>
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/search?keywords=${keywords}&page=${
|
||||
currentPage - 1
|
||||
}&matchingStrategy=${matchingStrategy}`}
|
||||
>
|
||||
<Pagination.PrevButton>
|
||||
<ChevronLeft class="h-4 w-4" />
|
||||
<span class="hidden sm:block">{$t('app.search.prev')}</span>
|
||||
</Pagination.PrevButton>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
{#each pages as page (page.key)}
|
||||
{#if page.type === 'ellipsis'}
|
||||
<Pagination.Item>
|
||||
<Pagination.Ellipsis />
|
||||
</Pagination.Item>
|
||||
{:else}
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/search?keywords=${keywords}&page=${page.value}&matchingStrategy=${matchingStrategy}`}
|
||||
>
|
||||
<Pagination.Link
|
||||
{page}
|
||||
isActive={currentPage === page.value}
|
||||
>
|
||||
{page.value}
|
||||
</Pagination.Link>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
{/if}
|
||||
{/each}
|
||||
<Pagination.Item>
|
||||
<a
|
||||
href={`/dashboard/search?keywords=${keywords}&page=${
|
||||
currentPage + 1
|
||||
}&matchingStrategy=${matchingStrategy}`}
|
||||
>
|
||||
<Pagination.NextButton>
|
||||
<span class="hidden sm:block">{$t('app.search.next')}</span>
|
||||
<ChevronRight class="h-4 w-4" />
|
||||
</Pagination.NextButton>
|
||||
</a>
|
||||
</Pagination.Item>
|
||||
</Pagination.Content>
|
||||
{/snippet}
|
||||
</Pagination.Root>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
146
pnpm-lock.yaml
generated
146
pnpm-lock.yaml
generated
@@ -83,12 +83,6 @@ importers:
|
||||
'@azure/msal-node':
|
||||
specifier: ^3.6.3
|
||||
version: 3.6.3
|
||||
'@bull-board/api':
|
||||
specifier: ^6.13.0
|
||||
version: 6.13.0(@bull-board/ui@6.13.0)
|
||||
'@bull-board/express':
|
||||
specifier: ^6.13.0
|
||||
version: 6.13.0
|
||||
'@casl/ability':
|
||||
specifier: ^6.7.3
|
||||
version: 6.7.3
|
||||
@@ -283,9 +277,6 @@ importers:
|
||||
'@sveltejs/kit':
|
||||
specifier: ^2.38.1
|
||||
version: 2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1))
|
||||
bits-ui:
|
||||
specifier: ^2.8.10
|
||||
version: 2.8.10(@internationalized/date@3.8.2)(svelte@5.35.5)
|
||||
clsx:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
@@ -324,8 +315,8 @@ importers:
|
||||
specifier: ^3.8.2
|
||||
version: 3.8.2
|
||||
'@lucide/svelte':
|
||||
specifier: ^0.515.0
|
||||
version: 0.515.0(svelte@5.35.5)
|
||||
specifier: ^0.544.0
|
||||
version: 0.544.0(svelte@5.35.5)
|
||||
'@sveltejs/adapter-auto':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.1(@sveltejs/kit@2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))
|
||||
@@ -344,6 +335,9 @@ importers:
|
||||
'@types/semver':
|
||||
specifier: ^7.7.1
|
||||
version: 7.7.1
|
||||
bits-ui:
|
||||
specifier: ^2.12.0
|
||||
version: 2.12.0(@internationalized/date@3.8.2)(@sveltejs/kit@2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)
|
||||
dotenv:
|
||||
specifier: ^17.2.0
|
||||
version: 17.2.0
|
||||
@@ -652,17 +646,6 @@ packages:
|
||||
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@bull-board/api@6.13.0':
|
||||
resolution: {integrity: sha512-GZ0On0VeL5uZVS1x7UdU90F9GV1kdmHa1955hW3Ow1PmslCY/2YwmvnapVdbvCUSVBqluTfbVZsE9X3h79r1kw==}
|
||||
peerDependencies:
|
||||
'@bull-board/ui': 6.13.0
|
||||
|
||||
'@bull-board/express@6.13.0':
|
||||
resolution: {integrity: sha512-PAbzD3dplV2NtN8ETs00bp++pBOD+cVb1BEYltXrjyViA2WluDBVKdlh/2wM+sHbYO2TAMNg8bUtKxGNCmxG7w==}
|
||||
|
||||
'@bull-board/ui@6.13.0':
|
||||
resolution: {integrity: sha512-63I6b3nZnKWI5ok6mw/Tk2rIObuzMTY/tLGyO51p0GW4rAImdXxrK6mT7j4SgEuP2B+tt/8L1jU7sLu8MMcCNw==}
|
||||
|
||||
'@casl/ability@6.7.3':
|
||||
resolution: {integrity: sha512-A4L28Ko+phJAsTDhRjzCOZWECQWN2jzZnJPnROWWHjJpyMq1h7h9ZqjwS2WbIUa3Z474X1ZPSgW0f1PboZGC0A==}
|
||||
|
||||
@@ -1205,8 +1188,8 @@ packages:
|
||||
'@layerstack/utils@2.0.0-next.12':
|
||||
resolution: {integrity: sha512-fhGZUlSr3N+D44BYm37WKMGSEFyZBW+dwIqtGU8Cl54mR4TLQ/UwyGhdpgIHyH/x/8q1abE0fP0Dn6ZsrDE3BA==}
|
||||
|
||||
'@lucide/svelte@0.515.0':
|
||||
resolution: {integrity: sha512-CEAyqcZmNBfYzVgaRmK2RFJP5tnbXxekRyDk0XX/eZQRfsJmkDvmQwXNX8C869BgNeryzmrRyjHhUL6g9ZOHNA==}
|
||||
'@lucide/svelte@0.544.0':
|
||||
resolution: {integrity: sha512-9f9O6uxng2pLB01sxNySHduJN3HTl5p0HDu4H26VR51vhZfiMzyOMe9Mhof3XAk4l813eTtl+/DYRvGyoRR+yw==}
|
||||
peerDependencies:
|
||||
svelte: ^5
|
||||
|
||||
@@ -2176,8 +2159,8 @@ packages:
|
||||
birpc@2.5.0:
|
||||
resolution: {integrity: sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==}
|
||||
|
||||
bits-ui@2.8.10:
|
||||
resolution: {integrity: sha512-MOobkqapDZNrpcNmeL2g664xFmH4tZBOKBTxFmsQYMZQuybSZHQnPXy+AjM5XZEXRmCFx5+XRmo6+fC3vHh1hQ==}
|
||||
bits-ui@2.12.0:
|
||||
resolution: {integrity: sha512-8NF4ILNyAJlIxDXpl/akGXGBV5QmZAe+8gTfPttM5P6/+LrijumcSfFXY5cr4QkXwTmLA7H5stYpbgJf2XFJvg==}
|
||||
engines: {node: '>=20'}
|
||||
peerDependencies:
|
||||
'@internationalized/date': ^3.8.1
|
||||
@@ -2726,11 +2709,6 @@ packages:
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
ejs@3.1.10:
|
||||
resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
hasBin: true
|
||||
|
||||
emoji-regex-xs@1.0.0:
|
||||
resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==}
|
||||
|
||||
@@ -2886,9 +2864,6 @@ packages:
|
||||
file-uri-to-path@1.0.0:
|
||||
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
|
||||
|
||||
filelist@1.0.4:
|
||||
resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
|
||||
|
||||
fill-range@7.1.1:
|
||||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -3217,11 +3192,6 @@ packages:
|
||||
jackspeak@3.4.3:
|
||||
resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
|
||||
|
||||
jake@10.9.2:
|
||||
resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
jiti@2.4.2:
|
||||
resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
|
||||
hasBin: true
|
||||
@@ -3416,6 +3386,10 @@ packages:
|
||||
resolution: {integrity: sha512-RkRWjA926cTvz5rAb1BqyWkKbbjzCGchDUIKMCUvNi17j6f6j8uHGDV82Aqcqtzd+icoYpELmG3ksgGiFNNcNg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
lz-string@1.5.0:
|
||||
resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
|
||||
hasBin: true
|
||||
|
||||
magic-string@0.30.17:
|
||||
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
||||
|
||||
@@ -4017,9 +3991,6 @@ packages:
|
||||
resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
redis-info@3.1.0:
|
||||
resolution: {integrity: sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==}
|
||||
|
||||
redis-parser@3.0.0:
|
||||
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -4092,10 +4063,14 @@ packages:
|
||||
peerDependencies:
|
||||
svelte: ^5.7.0
|
||||
|
||||
runed@0.29.2:
|
||||
resolution: {integrity: sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA==}
|
||||
runed@0.35.1:
|
||||
resolution: {integrity: sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q==}
|
||||
peerDependencies:
|
||||
'@sveltejs/kit': ^2.21.0
|
||||
svelte: ^5.7.0
|
||||
peerDependenciesMeta:
|
||||
'@sveltejs/kit':
|
||||
optional: true
|
||||
|
||||
rw@1.3.3:
|
||||
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
|
||||
@@ -4351,18 +4326,18 @@ packages:
|
||||
peerDependencies:
|
||||
svelte: ^5.0.0
|
||||
|
||||
svelte-toolbelt@0.10.6:
|
||||
resolution: {integrity: sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ==}
|
||||
engines: {node: '>=18', pnpm: '>=8.7.0'}
|
||||
peerDependencies:
|
||||
svelte: ^5.30.2
|
||||
|
||||
svelte-toolbelt@0.7.1:
|
||||
resolution: {integrity: sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==}
|
||||
engines: {node: '>=18', pnpm: '>=8.7.0'}
|
||||
peerDependencies:
|
||||
svelte: ^5.0.0
|
||||
|
||||
svelte-toolbelt@0.9.3:
|
||||
resolution: {integrity: sha512-HCSWxCtVmv+c6g1ACb8LTwHVbDqLKJvHpo6J8TaqwUme2hj9ATJCpjCPNISR1OCq2Q4U1KT41if9ON0isINQZw==}
|
||||
engines: {node: '>=18', pnpm: '>=8.7.0'}
|
||||
peerDependencies:
|
||||
svelte: ^5.30.2
|
||||
|
||||
svelte@5.35.5:
|
||||
resolution: {integrity: sha512-KuRvI82rhh0RMz1EKsUJD96gZyHJ+h2+8zrwO8iqE/p/CmcNKvIItDUAeUePhuCDgtegDJmF8IKThbHIfmTgTA==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -5367,24 +5342,6 @@ snapshots:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.27.1
|
||||
|
||||
'@bull-board/api@6.13.0(@bull-board/ui@6.13.0)':
|
||||
dependencies:
|
||||
'@bull-board/ui': 6.13.0
|
||||
redis-info: 3.1.0
|
||||
|
||||
'@bull-board/express@6.13.0':
|
||||
dependencies:
|
||||
'@bull-board/api': 6.13.0(@bull-board/ui@6.13.0)
|
||||
'@bull-board/ui': 6.13.0
|
||||
ejs: 3.1.10
|
||||
express: 5.1.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@bull-board/ui@6.13.0':
|
||||
dependencies:
|
||||
'@bull-board/api': 6.13.0(@bull-board/ui@6.13.0)
|
||||
|
||||
'@casl/ability@6.7.3':
|
||||
dependencies:
|
||||
'@ucast/mongo2js': 1.4.0
|
||||
@@ -5738,7 +5695,7 @@ snapshots:
|
||||
d3-time-format: 4.1.0
|
||||
lodash-es: 4.17.21
|
||||
|
||||
'@lucide/svelte@0.515.0(svelte@5.35.5)':
|
||||
'@lucide/svelte@0.544.0(svelte@5.35.5)':
|
||||
dependencies:
|
||||
svelte: 5.35.5
|
||||
|
||||
@@ -6805,16 +6762,18 @@ snapshots:
|
||||
|
||||
birpc@2.5.0: {}
|
||||
|
||||
bits-ui@2.8.10(@internationalized/date@3.8.2)(svelte@5.35.5):
|
||||
bits-ui@2.12.0(@internationalized/date@3.8.2)(@sveltejs/kit@2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5):
|
||||
dependencies:
|
||||
'@floating-ui/core': 1.7.2
|
||||
'@floating-ui/dom': 1.7.2
|
||||
'@internationalized/date': 3.8.2
|
||||
esm-env: 1.2.2
|
||||
runed: 0.29.2(svelte@5.35.5)
|
||||
runed: 0.35.1(@sveltejs/kit@2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)
|
||||
svelte: 5.35.5
|
||||
svelte-toolbelt: 0.9.3(svelte@5.35.5)
|
||||
svelte-toolbelt: 0.10.6(@sveltejs/kit@2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)
|
||||
tabbable: 6.2.0
|
||||
transitivePeerDependencies:
|
||||
- '@sveltejs/kit'
|
||||
|
||||
bl@4.1.0:
|
||||
dependencies:
|
||||
@@ -7293,10 +7252,6 @@ snapshots:
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
ejs@3.1.10:
|
||||
dependencies:
|
||||
jake: 10.9.2
|
||||
|
||||
emoji-regex-xs@1.0.0: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
@@ -7518,10 +7473,6 @@ snapshots:
|
||||
|
||||
file-uri-to-path@1.0.0: {}
|
||||
|
||||
filelist@1.0.4:
|
||||
dependencies:
|
||||
minimatch: 5.1.6
|
||||
|
||||
fill-range@7.1.1:
|
||||
dependencies:
|
||||
to-regex-range: 5.0.1
|
||||
@@ -7917,13 +7868,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@pkgjs/parseargs': 0.11.0
|
||||
|
||||
jake@10.9.2:
|
||||
dependencies:
|
||||
async: 3.2.6
|
||||
chalk: 4.1.2
|
||||
filelist: 1.0.4
|
||||
minimatch: 3.1.2
|
||||
|
||||
jiti@2.4.2: {}
|
||||
|
||||
jose@6.0.11: {}
|
||||
@@ -8128,6 +8072,8 @@ snapshots:
|
||||
|
||||
luxon@3.7.1: {}
|
||||
|
||||
lz-string@1.5.0: {}
|
||||
|
||||
magic-string@0.30.17:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.4
|
||||
@@ -8717,10 +8663,6 @@ snapshots:
|
||||
|
||||
redis-errors@1.2.0: {}
|
||||
|
||||
redis-info@3.1.0:
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
|
||||
redis-parser@3.0.0:
|
||||
dependencies:
|
||||
redis-errors: 1.2.0
|
||||
@@ -8814,10 +8756,14 @@ snapshots:
|
||||
esm-env: 1.2.2
|
||||
svelte: 5.35.5
|
||||
|
||||
runed@0.29.2(svelte@5.35.5):
|
||||
runed@0.35.1(@sveltejs/kit@2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5):
|
||||
dependencies:
|
||||
dequal: 2.0.3
|
||||
esm-env: 1.2.2
|
||||
lz-string: 1.5.0
|
||||
svelte: 5.35.5
|
||||
optionalDependencies:
|
||||
'@sveltejs/kit': 2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1))
|
||||
|
||||
rw@1.3.3: {}
|
||||
|
||||
@@ -9103,6 +9049,15 @@ snapshots:
|
||||
runed: 0.28.0(svelte@5.35.5)
|
||||
svelte: 5.35.5
|
||||
|
||||
svelte-toolbelt@0.10.6(@sveltejs/kit@2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5):
|
||||
dependencies:
|
||||
clsx: 2.1.1
|
||||
runed: 0.35.1(@sveltejs/kit@2.38.1(@sveltejs/vite-plugin-svelte@5.1.0(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)(vite@6.3.5(@types/node@24.0.13)(jiti@2.4.2)(lightningcss@1.30.1)))(svelte@5.35.5)
|
||||
style-to-object: 1.0.9
|
||||
svelte: 5.35.5
|
||||
transitivePeerDependencies:
|
||||
- '@sveltejs/kit'
|
||||
|
||||
svelte-toolbelt@0.7.1(svelte@5.35.5):
|
||||
dependencies:
|
||||
clsx: 2.1.1
|
||||
@@ -9110,13 +9065,6 @@ snapshots:
|
||||
style-to-object: 1.0.9
|
||||
svelte: 5.35.5
|
||||
|
||||
svelte-toolbelt@0.9.3(svelte@5.35.5):
|
||||
dependencies:
|
||||
clsx: 2.1.1
|
||||
runed: 0.29.2(svelte@5.35.5)
|
||||
style-to-object: 1.0.9
|
||||
svelte: 5.35.5
|
||||
|
||||
svelte@5.35.5:
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.3.0
|
||||
|
||||
Reference in New Issue
Block a user