Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 30 additions & 16 deletions src/lib/state/breadcrumbs-state.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,39 @@
import type { Pathname } from '$app/types';
import { onMount } from 'svelte';
import { onDestroy } from 'svelte';

export interface BreadCrumbEntry {
text: string;
export interface BreadcrumbEntry {
label: string;
href: Pathname | null;
}

let _state = $state<BreadCrumbEntry[]>([]);
interface BreadcrumbSlot {
id: symbol;
entries: BreadcrumbEntry[];
}

const _slots = $state<BreadcrumbSlot[]>([]);

export const breadcrumbs = {
get state() {
return _state;
get state(): BreadcrumbEntry[] {
return _slots.flatMap((s) => s.entries);
},
push: (text: string, href: Pathname | null = null) => {
onMount(() => {
const entry = { text, href };
_state = [..._state, entry];
return () => {
_state = _state.filter((e) => e.text !== entry.text || e.href !== entry.href);
};
});
},
clear: () => (_state = []),
};

export function registerBreadcrumbs(
entriesFn: () => Array<{ label: string; href?: Pathname | null }>
): void {
const id = Symbol();
_slots.push({ id, entries: [] });

$effect(() => {
const slot = _slots.find((s) => s.id === id);
if (slot) {
slot.entries = entriesFn().map((e) => ({ label: e.label, href: e.href ?? null }));
}
});

onDestroy(() => {
const idx = _slots.findIndex((s) => s.id === id);
if (idx !== -1) _slots.splice(idx, 1);
});
}
3 changes: 3 additions & 0 deletions src/routes/(app)/admin/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
<script lang="ts">
import { resolve } from '$app/paths';
import { Button } from '$lib/components/ui/button';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { userState } from '$lib/state/user-state.svelte';
import type { Snippet } from 'svelte';

registerBreadcrumbs(() => [{ label: 'Admin', href: '/admin/users' }]);

interface Props {
children?: Snippet;
}
Expand Down
3 changes: 3 additions & 0 deletions src/routes/(app)/admin/blacklists/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
} from '$lib/api/internal/v1';
import TextInput from '$lib/components/input/TextInput.svelte';
import { Button } from '$lib/components/ui/button';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { Card, CardContent, CardHeader, CardTitle } from '$lib/components/ui/card';
import { ScrollArea } from '$lib/components/ui/scroll-area';
import * as Select from '$lib/components/ui/select';
Expand All @@ -16,6 +17,8 @@
import type { ValidationResult } from '$lib/types/ValidationResult';
import type { TimeoutHandle } from '$lib/types/WAPI';

registerBreadcrumbs(() => [{ label: 'Blacklists' }]);

// --- state ---
let usernameEntry = $state<string>('');
let matchTypeEntry = $state<MatchTypeEnum>(MatchTypeEnum.Exact);
Expand Down
3 changes: 3 additions & 0 deletions src/routes/(app)/admin/config/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
LocaleDateTimeRenderer,
RenderCell,
} from '$lib/components/Table/ColumnUtils';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import DataTable from '$lib/components/Table/DataTableTemplate.svelte';
import { Button } from '$lib/components/ui/button';
import { CardHeader, CardTitle } from '$lib/components/ui/card';
Expand All @@ -18,6 +19,8 @@
import DataTableActions from './data-table-actions.svelte';
import WebhookAddDialog from './dialog-item-add.svelte';

registerBreadcrumbs(() => [{ label: 'Config' }]);

const columns: ColumnDef<ConfigurationItemDto>[] = [
CreateSortableColumnDef('name', 'Name', RenderCell),
CreateSortableColumnDef('description', 'Description', RenderCell),
Expand Down
3 changes: 3 additions & 0 deletions src/routes/(app)/admin/online-hubs/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
import { handleApiError } from '$lib/errorhandling/apiErrorHandling';
import { SemVer } from 'semver';
import { onMount } from 'svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { type OnlineHub, columns } from './columns';

registerBreadcrumbs(() => [{ label: 'Online Hubs' }]);

let data = $state<OnlineHub[]>([]);
let sorting = $state<SortingState>([]);
let filters = $state<ColumnFiltersState>([]);
Expand Down
3 changes: 3 additions & 0 deletions src/routes/(app)/admin/users/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
RenderRedCell,
} from '$lib/components/Table/ColumnUtils';
import { renderComponent } from '$lib/components/ui/data-table';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import DataTableActions from './data-table-actions.svelte';

registerBreadcrumbs(() => [{ label: 'Users' }]);

const PasswordHashTypeRenderer = (passwordHashType: PasswordHashingAlgorithm) => {
if (passwordHashType !== PasswordHashingAlgorithm.BCrypt)
return RenderOrangeCell(passwordHashType);
Expand Down
6 changes: 6 additions & 0 deletions src/routes/(app)/admin/users/[userId]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@
import { adminApi } from '$lib/api';
import type { AdminUsersView, AdminUsersViewPaginated } from '$lib/api/internal/v1';
import { handleApiError } from '$lib/errorhandling/apiErrorHandling';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';

let user = $state<AdminUsersView | null>(null);

registerBreadcrumbs(() => [
{ label: 'Users', href: '/admin/users' },
{ label: user?.name ?? 'Loading...' },
]);

function handleResponse(page: AdminUsersViewPaginated) {
if (page.data.length === 0) {
user = null;
Expand Down
3 changes: 3 additions & 0 deletions src/routes/(app)/admin/webhooks/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
import { handleApiError } from '$lib/errorhandling/apiErrorHandling';
import { onMount } from 'svelte';
import DataTableActions from './data-table-actions.svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import WebhookAddDialog from './dialog-webhook-add.svelte';

registerBreadcrumbs(() => [{ label: 'Webhooks' }]);

const columns: ColumnDef<WebhookDto>[] = [
CreateSortableColumnDef('name', 'Name', RenderCell),
CreateSortableColumnDef('url', 'Url', RenderCell),
Expand Down
4 changes: 2 additions & 2 deletions src/routes/(app)/home/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import Container from '$lib/components/Container.svelte';
import * as Card from '$lib/components/ui/card';
import { Button } from '$lib/components/ui/button';
import { breadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { userState } from '$lib/state/user-state.svelte';
import { onlineHubs, ownHubs, refreshOwnHubs } from '$lib/state/hubs-state.svelte';
import { onMount } from 'svelte';

breadcrumbs.push('Home', '/home');
registerBreadcrumbs(() => [{ label: 'Home', href: '/home' }]);

let shockerCount = $derived(
Array.from(ownHubs).reduce((sum, [, hub]) => sum + hub.shockers.length, 0)
Expand Down
4 changes: 2 additions & 2 deletions src/routes/(app)/hubs/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as Card from '$lib/components/ui/card';
import * as Table from '$lib/components/ui/table';
import { IsMobile } from '$lib/hooks/is-mobile.svelte';
import { breadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { onlineHubs, ownHubs, refreshOwnHubs } from '$lib/state/hubs-state.svelte';
import { onMount } from 'svelte';
import type { Hub } from './columns';
Expand Down Expand Up @@ -57,7 +57,7 @@
}
}

breadcrumbs.push('Hubs', '/hubs');
registerBreadcrumbs(() => [{ label: 'Hubs', href: '/hubs' }]);
onMount(refreshOwnHubs);
</script>

Expand Down
5 changes: 2 additions & 3 deletions src/routes/(app)/hubs/[hubId=guid]/update/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
import { handleApiError } from '$lib/errorhandling/apiErrorHandling';
import { getConnection } from '$lib/signalr/user.svelte';
import { serializeOtaInstallMessage } from '$lib/signalr/serializers/OtaInstall';
import { breadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import {
HubOnlineState,
onlineHubs,
Expand Down Expand Up @@ -197,8 +197,7 @@

$effect(() => fetchOtaLogs(page.params.hubId));

breadcrumbs.push('Hubs', '/hubs');
breadcrumbs.push('Update');
registerBreadcrumbs(() => [{ label: 'Hubs', href: '/hubs' }, { label: hubName ?? 'Update' }]);

onMount(refreshOwnHubs);
</script>
Expand Down
10 changes: 10 additions & 0 deletions src/routes/(app)/profile/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script lang="ts">
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';

registerBreadcrumbs(() => [{ label: 'Profile' }]);
</script>

<main>
<h1>Profile</h1>
<p>Your profile page is coming soon.</p>
</main>
6 changes: 6 additions & 0 deletions src/routes/(app)/settings/account/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@
import ChangeEmail from './ChangeEmail.svelte';
import ChangePassword from './ChangePassword.svelte';
import ChangeUsername from './ChangeUsername.svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import DangerZone from './DangerZone.svelte';

registerBreadcrumbs(() => [
{ label: 'Settings', href: '/settings/account' },
{ label: 'Account' },
]);

let account = $derived(userState.self);
</script>

Expand Down
5 changes: 5 additions & 0 deletions src/routes/(app)/settings/api-tokens/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@
import { toast } from 'svelte-sonner';
import DataTableActions from './data-table-actions.svelte';
import TokenCreateDialog from './dialog-token-create.svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import TokenCreatedDialog from './dialog-token-created.svelte';

registerBreadcrumbs(() => [
{ label: 'Settings', href: '/settings/account' },
{ label: 'API Tokens' },
]);
let data = $state<TokenResponse[]>([]);
let sorting = $state<SortingState>([]);

Expand Down
7 changes: 7 additions & 0 deletions src/routes/(app)/settings/api-tokens/new/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
import type { QueryParamsType } from './queryParamsType';
import { page } from '$app/state';
import { browser } from '$app/environment';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';

registerBreadcrumbs(() => [
{ label: 'Settings', href: '/settings/account' },
{ label: 'API Tokens', href: '/settings/api-tokens' },
{ label: 'New' },
]);

let windowQueryParams = $state<
| QueryParamsType
Expand Down
6 changes: 6 additions & 0 deletions src/routes/(app)/settings/connections/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@
import { onMount } from 'svelte';
import { toast } from 'svelte-sonner';
import DisconnectDialog from './dialog-oauth-disconnect.svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { backendMetadata } from '$lib/state/backend-metadata-state.svelte';

registerBreadcrumbs(() => [
{ label: 'Settings', href: '/settings/account' },
{ label: 'Connections' },
]);

// ---------- state
let loading = $state(false); // overall refresh button state
let loadingProviders = $state(true);
Expand Down
6 changes: 6 additions & 0 deletions src/routes/(app)/settings/sessions/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@
import { handleApiError } from '$lib/errorhandling/apiErrorHandling';
import { onMount } from 'svelte';
import { toast } from 'svelte-sonner';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import DataTableActions from './data-table-actions.svelte';

registerBreadcrumbs(() => [
{ label: 'Settings', href: '/settings/account' },
{ label: 'Sessions' },
]);

let data = $state<LoginSessionResponse[]>([]);
let sorting = $state<SortingState>([]);

Expand Down
3 changes: 3 additions & 0 deletions src/routes/(app)/shares/public/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
import { handleApiError } from '$lib/errorhandling/apiErrorHandling';
import { onMount } from 'svelte';
import DataTableActions from './data-table-actions.svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import CreatePublicShareDialog from './dialog-publicshare-create.svelte';

registerBreadcrumbs(() => [{ label: 'Public Shares' }]);

const columns: ColumnDef<OwnPublicShareResponse>[] = [
CreateSortableColumnDef('name', 'Name', RenderCell),
CreateSortableColumnDef('createdOn', 'Created at', LocaleDateTimeRenderer),
Expand Down
14 changes: 13 additions & 1 deletion src/routes/(app)/shares/public/[shareId=guid]/edit/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { Plus, Save } from '@lucide/svelte';
import { ExternalLink, Plus, Save } from '@lucide/svelte';
import { resolve } from '$app/paths';
import { page } from '$app/state';
import { publicShockerSharesApi } from '$lib/api';
import type { PublicShareResponse } from '$lib/api/internal/v1';
Expand All @@ -12,6 +13,7 @@
import { onMount } from 'svelte';
import { toast } from 'svelte-sonner';
import SharedDevice from './SharedDevice.svelte';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import DialogAddShocker from './dialog-add-shocker.svelte';

let publicShareRequest = $state<Promise<PublicShareResponse>>(getPublicShare());
Expand All @@ -21,6 +23,12 @@
let isAddingShockers = $state(false);

const shareId = $derived(page.params.shareId);
const publicUrl = $derived(resolve(`/shares/public/${shareId}`));

registerBreadcrumbs(() => [
{ label: 'Public Shares', href: '/shares/public' },
{ label: publicShareData?.name ?? 'Edit' },
]);

onMount(() => {
refreshOwnHubs();
Expand Down Expand Up @@ -105,6 +113,10 @@
<Card.Title class="flex items-center justify-between space-x-2 text-3xl">
Edit Public Share: {publicShareData?.name ?? 'Loading...'}
<div class="flex gap-2">
<Button variant="outline" href={publicUrl}>
<ExternalLink />
View
</Button>
<Button onclick={() => (showAddShockerModal = true)} disabled={isAddingShockers}>
<Plus />
Add Shocker
Expand Down
3 changes: 3 additions & 0 deletions src/routes/(app)/shares/user/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
import DialogShareCodeCreated from './dialog-share-code-created.svelte';
import DialogShareCodeRedeem from './dialog-share-code-redeem.svelte';
import { resolve } from '$app/paths';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';

registerBreadcrumbs(() => [{ label: 'User Shares', href: '/shares/user/outgoing' }]);

let createDialogOpen = $state(false);
let redeemDialogOpen = $state(false);
Expand Down
10 changes: 6 additions & 4 deletions src/routes/(app)/shockers/[shockerId=guid]/edit/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,12 @@
import * as Select from '$lib/components/ui/select';
import PauseToggle from '$lib/components/utils/PauseToggle.svelte';
import { handleApiError } from '$lib/errorhandling/apiErrorHandling';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { refreshOwnHubs } from '$lib/state/hubs-state.svelte';
import { breadcrumbs } from '$lib/state/breadcrumbs-state.svelte';
import { ArrowLeft, LoaderCircle, Trash2 } from '@lucide/svelte';
import { onMount } from 'svelte';
import { toast } from 'svelte-sonner';

breadcrumbs.push('Shockers', '/shockers/own');
breadcrumbs.push('Edit', null);

const modelOptions = [
{ value: ShockerModelType.CaiXianlin, label: 'CaiXianlin' },
{ value: ShockerModelType.PetTrainer, label: 'PetTrainer' },
Expand All @@ -36,6 +33,11 @@
let model = $state<ShockerModelType>(ShockerModelType.CaiXianlin);
let saving = $state(false);

registerBreadcrumbs(() => [
{ label: 'Shockers', href: '/shockers/own' },
{ label: shocker?.name ?? 'Edit Shocker' },
]);

let hasChanges = $derived(
shocker !== null &&
(name.trim() !== shocker.name || rfId !== shocker.rfId || model !== shocker.model)
Expand Down
3 changes: 3 additions & 0 deletions src/routes/(app)/shockers/logs/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
} from '$lib/components/Table/ColumnUtils';
import DataTable from '$lib/components/Table/DataTableTemplate.svelte';
import * as Card from '$lib/components/ui/card';
import { registerBreadcrumbs } from '$lib/state/breadcrumbs-state.svelte';

registerBreadcrumbs(() => [{ label: 'Shocker Logs' }]);

let { data } = $props();

Expand Down
Loading
Loading