mirror of
https://github.com/pockethost/pockethost.git
synced 2025-03-30 15:08:30 +00:00
enh: overhaul dashboard nav and state management
This commit is contained in:
parent
a4ca2985f6
commit
c2fc64d66e
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<div class="drawer-content">
|
<div class="drawer-content">
|
||||||
<div class="flex items-center justify-between px-8 pt-1">
|
<div class="flex items-center justify-between px-8 pt-1">
|
||||||
<a href="/dashboard" class="flex gap-2 items-center justify-center">
|
<a href="/" class="flex gap-2 items-center justify-center">
|
||||||
<Logo hideLogoText={true} logoWidth="w-16" />
|
<Logo hideLogoText={true} logoWidth="w-16" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
import Logo from '$components/Logo.svelte'
|
import Logo from '$components/Logo.svelte'
|
||||||
import MediaQuery from '$components/MediaQuery.svelte'
|
import MediaQuery from '$components/MediaQuery.svelte'
|
||||||
import { DOCS_URL } from '$src/env'
|
import { DOCS_URL } from '$src/env'
|
||||||
|
import InstancesGuard from '$src/routes/InstancesGuard.svelte'
|
||||||
import { handleLogoutAndRedirect } from '$util/database'
|
import { handleLogoutAndRedirect } from '$util/database'
|
||||||
import { globalInstancesStore } from '$util/stores'
|
import { globalInstancesStore } from '$util/stores'
|
||||||
import { values } from '@s-libs/micro-dash'
|
import { values } from '@s-libs/micro-dash'
|
||||||
|
import UserLoggedIn from './helpers/UserLoggedIn.svelte'
|
||||||
|
|
||||||
const linkClasses =
|
const linkClasses =
|
||||||
'font-medium text-xl text-base-content btn btn-ghost capitalize justify-start'
|
'font-medium text-xl text-base-content btn btn-ghost capitalize justify-start'
|
||||||
@ -22,20 +24,21 @@
|
|||||||
<aside class="p-4 min-w-[250px] flex flex-col h-screen">
|
<aside class="p-4 min-w-[250px] flex flex-col h-screen">
|
||||||
<MediaQuery query="(min-width: 1280px)" let:matches>
|
<MediaQuery query="(min-width: 1280px)" let:matches>
|
||||||
{#if matches}
|
{#if matches}
|
||||||
<a href="/dashboard" class="flex gap-2 items-center justify-center">
|
<a href="/" class="flex gap-2 items-center justify-center">
|
||||||
<Logo hideLogoText={true} logoWidth="w-20" />
|
<Logo hideLogoText={true} logoWidth="w-20" />
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
</MediaQuery>
|
</MediaQuery>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2 mb-auto">
|
<div class="flex flex-col gap-2 mb-auto">
|
||||||
<a on:click={handleClick} href="/dashboard" class={linkClasses}>
|
<a on:click={handleClick} href="/" class={linkClasses}>
|
||||||
<i
|
<i
|
||||||
class="fa-regular fa-table-columns {$page.url.pathname ===
|
class="fa-regular fa-table-columns {$page.url.pathname === '/' &&
|
||||||
'/dashboard' && 'text-primary'}"
|
'text-primary'}"
|
||||||
></i> Dashboard
|
></i> Dashboard
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<InstancesGuard>
|
||||||
<div class="pl-8 flex flex-col gap-4 mb-4">
|
<div class="pl-8 flex flex-col gap-4 mb-4">
|
||||||
{#each values($globalInstancesStore) as app}
|
{#each values($globalInstancesStore) as app}
|
||||||
<a
|
<a
|
||||||
@ -55,7 +58,6 @@
|
|||||||
{app.subdomain}
|
{app.subdomain}
|
||||||
</a>
|
</a>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<a href="/app/new" on:click={handleClick} class={addNewAppClasses}>
|
<a href="/app/new" on:click={handleClick} class={addNewAppClasses}>
|
||||||
<i
|
<i
|
||||||
class="fa-regular fa-plus {$page.url.pathname === `/app/new` &&
|
class="fa-regular fa-plus {$page.url.pathname === `/app/new` &&
|
||||||
@ -63,6 +65,7 @@
|
|||||||
></i> Create A New App
|
></i> Create A New App
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
</InstancesGuard>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="https://discord.gg/nVTxCMEcGT"
|
href="https://discord.gg/nVTxCMEcGT"
|
||||||
@ -99,8 +102,13 @@
|
|||||||
></i></a
|
></i></a
|
||||||
>
|
>
|
||||||
|
|
||||||
<button type="button" class={linkClasses} on:click={handleLogoutAndRedirect}
|
<UserLoggedIn>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class={linkClasses}
|
||||||
|
on:click={handleLogoutAndRedirect}
|
||||||
><i class="fa-regular fa-arrow-up-left-from-circle"></i> Logout</button
|
><i class="fa-regular fa-arrow-up-left-from-circle"></i> Logout</button
|
||||||
>
|
>
|
||||||
|
</UserLoggedIn>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { browser } from '$app/environment'
|
|
||||||
import { MOTHERSHIP_URL } from '$src/env'
|
import { MOTHERSHIP_URL } from '$src/env'
|
||||||
import { LoggerService } from '@pockethost/common'
|
import { LoggerService } from '@pockethost/common'
|
||||||
import {
|
import {
|
||||||
@ -9,7 +8,6 @@ import {
|
|||||||
export const client = (() => {
|
export const client = (() => {
|
||||||
let clientInstance: PocketbaseClient | undefined
|
let clientInstance: PocketbaseClient | undefined
|
||||||
return () => {
|
return () => {
|
||||||
if (!browser) throw new Error(`PocketBase client not supported in SSR`)
|
|
||||||
if (clientInstance) return clientInstance
|
if (clientInstance) return clientInstance
|
||||||
const { info } = LoggerService()
|
const { info } = LoggerService()
|
||||||
info(`Initializing pocketbase client`)
|
info(`Initializing pocketbase client`)
|
||||||
|
@ -2,21 +2,18 @@
|
|||||||
import MediaQuery from '$components/MediaQuery.svelte'
|
import MediaQuery from '$components/MediaQuery.svelte'
|
||||||
import MobileNavDrawer from '$components/MobileNavDrawer.svelte'
|
import MobileNavDrawer from '$components/MobileNavDrawer.svelte'
|
||||||
import Navbar from '$components/Navbar.svelte'
|
import Navbar from '$components/Navbar.svelte'
|
||||||
|
import AuthStateGuard from '$components/helpers/AuthStateGuard.svelte'
|
||||||
import Meta from '$components/helpers/Meta.svelte'
|
import Meta from '$components/helpers/Meta.svelte'
|
||||||
import Protect from '$components/helpers/Protect.svelte'
|
import UserLoggedIn from '$components/helpers/UserLoggedIn.svelte'
|
||||||
import '../app.css'
|
import '../app.css'
|
||||||
import '../services'
|
import '../services'
|
||||||
|
|
||||||
import { getInstances } from '$util/getInstances'
|
|
||||||
import { isUserLoggedIn } from '$util/stores'
|
|
||||||
|
|
||||||
getInstances()
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Meta />
|
<Meta />
|
||||||
|
|
||||||
{#if $isUserLoggedIn}
|
<AuthStateGuard>
|
||||||
<div class="layout xl:flex">
|
<div class="layout xl:flex">
|
||||||
|
<UserLoggedIn>
|
||||||
<MediaQuery query="(min-width: 1280px)" let:matches>
|
<MediaQuery query="(min-width: 1280px)" let:matches>
|
||||||
{#if matches}
|
{#if matches}
|
||||||
<Navbar />
|
<Navbar />
|
||||||
@ -26,6 +23,7 @@
|
|||||||
</MobileNavDrawer>
|
</MobileNavDrawer>
|
||||||
{/if}
|
{/if}
|
||||||
</MediaQuery>
|
</MediaQuery>
|
||||||
|
</UserLoggedIn>
|
||||||
|
|
||||||
<div class="lg:p-4 lg:pt-0 xl:pt-4 min-h-screen grow">
|
<div class="lg:p-4 lg:pt-0 xl:pt-4 min-h-screen grow">
|
||||||
<div
|
<div
|
||||||
@ -35,10 +33,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
</AuthStateGuard>
|
||||||
|
|
||||||
{#if !$isUserLoggedIn}
|
|
||||||
<div>
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
2
packages/dashboard/src/routes/+layout.ts
Normal file
2
packages/dashboard/src/routes/+layout.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
const ssr = false
|
||||||
|
export { ssr }
|
@ -1,30 +1,26 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Logo from '$components/Logo.svelte'
|
import Logo from '$components/Logo.svelte'
|
||||||
import AuthStateGuard from '$components/helpers/AuthStateGuard.svelte'
|
import UserLoggedIn from '$components/helpers/UserLoggedIn.svelte'
|
||||||
|
import UserLoggedOut from '$components/helpers/UserLoggedOut.svelte'
|
||||||
import InstanceGeneratorWidget from '$components/login-register/InstanceGeneratorWidget.svelte'
|
import InstanceGeneratorWidget from '$components/login-register/InstanceGeneratorWidget.svelte'
|
||||||
import { isUserLoggedIn } from '$util/stores'
|
import Dashboard from './dashboard/Dashboard.svelte'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>Home - PocketHost</title>
|
<title>Home - PocketHost</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<UserLoggedIn>
|
||||||
|
<Dashboard />
|
||||||
|
</UserLoggedIn>
|
||||||
|
|
||||||
|
<UserLoggedOut>
|
||||||
<div class="min-h-screen flex items-center justify-center">
|
<div class="min-h-screen flex items-center justify-center">
|
||||||
<div>
|
<div>
|
||||||
<AuthStateGuard>
|
|
||||||
<Logo />
|
<Logo />
|
||||||
|
|
||||||
{#if $isUserLoggedIn}
|
|
||||||
<div class="">
|
|
||||||
<a href="/dashboard" class="btn btn-primary"
|
|
||||||
>Go to Your Dashboard <i class="bi bi-arrow-right-short" /></a
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if !$isUserLoggedIn}
|
|
||||||
<InstanceGeneratorWidget />
|
<InstanceGeneratorWidget />
|
||||||
{/if}
|
|
||||||
</AuthStateGuard>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</UserLoggedOut>
|
||||||
|
</div>
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
<script lang="ts">
|
<script>
|
||||||
import { page } from '$app/stores'
|
import { page } from '$app/stores'
|
||||||
import AuthStateGuard from '$components/helpers/AuthStateGuard.svelte'
|
import { globalInstancesStore } from '$util/stores'
|
||||||
import { getSingleInstance } from '$util/getInstances'
|
import { assert } from '@pockethost/common'
|
||||||
import { assertTruthy } from '@pockethost/common'
|
|
||||||
import { instance } from './store'
|
import { instance } from './store'
|
||||||
|
|
||||||
// Run anytime the page params changes
|
let isReady = false
|
||||||
$: {
|
$: {
|
||||||
const { instanceId } = $page.params
|
const { instanceId } = $page.params
|
||||||
assertTruthy(instanceId)
|
assert(instanceId)
|
||||||
getSingleInstance(instanceId)
|
const _instance = $globalInstancesStore[instanceId]
|
||||||
|
if (_instance) {
|
||||||
|
instance.set(_instance)
|
||||||
|
}
|
||||||
|
isReady = !!_instance
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<AuthStateGuard>
|
{#if isReady}
|
||||||
{#if $instance}
|
|
||||||
<slot />
|
<slot />
|
||||||
|
{:else}
|
||||||
|
<div>Instance not found</div>
|
||||||
{/if}
|
{/if}
|
||||||
</AuthStateGuard>
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { page } from '$app/stores'
|
||||||
import { INSTANCE_ADMIN_URL } from '$src/env'
|
import { INSTANCE_ADMIN_URL } from '$src/env'
|
||||||
import { assertExists } from '@pockethost/common'
|
import { assertExists } from '@pockethost/common'
|
||||||
import { slide } from 'svelte/transition'
|
import { slide } from 'svelte/transition'
|
||||||
@ -13,6 +14,11 @@
|
|||||||
import UsageChart from './UsageChart.svelte'
|
import UsageChart from './UsageChart.svelte'
|
||||||
import { instance } from './store'
|
import { instance } from './store'
|
||||||
|
|
||||||
|
const { instanceId } = $page.params
|
||||||
|
|
||||||
|
console.log(instanceId)
|
||||||
|
let isReady = false
|
||||||
|
|
||||||
$: ({ status, version, secondsThisMonth } = $instance)
|
$: ({ status, version, secondsThisMonth } = $instance)
|
||||||
|
|
||||||
assertExists($instance, `Expected instance here`)
|
assertExists($instance, `Expected instance here`)
|
||||||
|
@ -2,15 +2,16 @@
|
|||||||
import Card from '$components/cards/Card.svelte'
|
import Card from '$components/cards/Card.svelte'
|
||||||
import CardHeader from '$components/cards/CardHeader.svelte'
|
import CardHeader from '$components/cards/CardHeader.svelte'
|
||||||
import { client } from '$src/pocketbase'
|
import { client } from '$src/pocketbase'
|
||||||
|
import { mkCleanup } from '$util/componentCleanup'
|
||||||
import {
|
import {
|
||||||
LoggerService,
|
LoggerService,
|
||||||
createCleanupManager,
|
Unsubscribe,
|
||||||
type InstanceLogFields,
|
type InstanceLogFields,
|
||||||
type RecordId,
|
type RecordId,
|
||||||
} from '@pockethost/common'
|
} from '@pockethost/common'
|
||||||
import { values } from '@s-libs/micro-dash'
|
import { values } from '@s-libs/micro-dash'
|
||||||
import { onDestroy, onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { writable } from 'svelte/store'
|
import { derived, writable } from 'svelte/store'
|
||||||
import { instance } from './store'
|
import { instance } from './store'
|
||||||
|
|
||||||
const { dbg, trace } = LoggerService().create(`Logging.svelte`)
|
const { dbg, trace } = LoggerService().create(`Logging.svelte`)
|
||||||
@ -46,12 +47,17 @@
|
|||||||
const logs = writable<{ [_: RecordId]: InstanceLogFields }>({})
|
const logs = writable<{ [_: RecordId]: InstanceLogFields }>({})
|
||||||
let logsArray: InstanceLogFields[] = []
|
let logsArray: InstanceLogFields[] = []
|
||||||
|
|
||||||
const cm = createCleanupManager()
|
const onDestroy = mkCleanup()
|
||||||
|
|
||||||
|
const instanceId = derived(instance, (instance) => instance.id)
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
dbg(`Watching instance log`)
|
let unwatch: Unsubscribe | undefined
|
||||||
|
const unsub = instanceId.subscribe((id) => {
|
||||||
const unsub = client().watchInstanceLog(id, (newLog) => {
|
dbg(`Watching instance log ${id}`)
|
||||||
|
unwatch?.()
|
||||||
|
logs.set({})
|
||||||
|
unwatch = client().watchInstanceLog(id, (newLog) => {
|
||||||
trace(`Got new log`, newLog)
|
trace(`Got new log`, newLog)
|
||||||
|
|
||||||
logs.update((currentLogs) => {
|
logs.update((currentLogs) => {
|
||||||
@ -63,11 +69,10 @@
|
|||||||
.slice(0, 1000)
|
.slice(0, 1000)
|
||||||
.reverse()
|
.reverse()
|
||||||
})
|
})
|
||||||
|
|
||||||
cm.add(unsub)
|
|
||||||
})
|
})
|
||||||
|
onDestroy(unsub)
|
||||||
onDestroy(cm.shutdown)
|
onDestroy(() => unwatch?.())
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { SECRET_KEY_REGEX } from '@pockethost/common'
|
import { client } from '$src/pocketbase/index.js'
|
||||||
import { items } from './stores.js'
|
import { SECRET_KEY_REGEX, SaveSecretsPayload } from '@pockethost/common'
|
||||||
|
import { reduce } from '@s-libs/micro-dash'
|
||||||
import { slide } from 'svelte/transition'
|
import { slide } from 'svelte/transition'
|
||||||
|
import { instance } from '../store.js'
|
||||||
|
import { items } from './stores.js'
|
||||||
|
|
||||||
// Keep track of the new key and value to be added
|
// Keep track of the new key and value to be added
|
||||||
let secretKey: string = ''
|
let secretKey: string = ''
|
||||||
@ -40,6 +43,18 @@
|
|||||||
|
|
||||||
// Save to the database
|
// Save to the database
|
||||||
items.upsert({ name: secretKey, value: secretValue })
|
items.upsert({ name: secretKey, value: secretValue })
|
||||||
|
await client().saveSecrets({
|
||||||
|
instanceId: $instance.id,
|
||||||
|
secrets: reduce(
|
||||||
|
$items,
|
||||||
|
(c, v) => {
|
||||||
|
const { name, value } = v
|
||||||
|
c[name] = value
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
{} as SaveSecretsPayload['secrets'],
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
// Reset the values when the POST is done
|
// Reset the values when the POST is done
|
||||||
secretKey = ''
|
secretKey = ''
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import CodeSample from '$components/CodeSample.svelte'
|
||||||
import Card from '$components/cards/Card.svelte'
|
import Card from '$components/cards/Card.svelte'
|
||||||
import CardHeader from '$components/cards/CardHeader.svelte'
|
import CardHeader from '$components/cards/CardHeader.svelte'
|
||||||
import CodeSample from '$components/CodeSample.svelte'
|
import { LoggerService } from '@pockethost/common'
|
||||||
import { client } from '$src/pocketbase'
|
import { forEach } from '@s-libs/micro-dash'
|
||||||
import {
|
|
||||||
createCleanupManager,
|
|
||||||
LoggerService,
|
|
||||||
type SaveSecretsPayload,
|
|
||||||
} from '@pockethost/common'
|
|
||||||
import { forEach, reduce } from '@s-libs/micro-dash'
|
|
||||||
import { onDestroy, onMount } from 'svelte'
|
|
||||||
import { instance } from '../store'
|
import { instance } from '../store'
|
||||||
import Form from './Form.svelte'
|
import Form from './Form.svelte'
|
||||||
import List from './List.svelte'
|
import List from './List.svelte'
|
||||||
@ -17,7 +11,14 @@
|
|||||||
|
|
||||||
// TODO: Hot Reload is causing an infinite loop in the network tab for some reason. Wasn't able to figure out why
|
// TODO: Hot Reload is causing an infinite loop in the network tab for some reason. Wasn't able to figure out why
|
||||||
|
|
||||||
$: ({ id, secrets } = $instance)
|
$: {
|
||||||
|
const { id, secrets } = $instance
|
||||||
|
items.clear()
|
||||||
|
|
||||||
|
forEach(secrets || {}, (value, name) => {
|
||||||
|
items.upsert({ name, value })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Keep track of which tab the user has selected
|
// Keep track of which tab the user has selected
|
||||||
let activeTab = 0
|
let activeTab = 0
|
||||||
@ -28,44 +29,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { dbg } = LoggerService().create(`Secrets.svelte`)
|
const { dbg } = LoggerService().create(`Secrets.svelte`)
|
||||||
|
|
||||||
const cm = createCleanupManager()
|
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
items.clear()
|
|
||||||
|
|
||||||
forEach(secrets || {}, (value, name) => {
|
|
||||||
items.upsert({ name, value })
|
|
||||||
})
|
|
||||||
|
|
||||||
let initial = false
|
|
||||||
|
|
||||||
const unsub = items.subscribe(async (secrets) => {
|
|
||||||
if (!initial) {
|
|
||||||
initial = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg(`Got change`, secrets)
|
|
||||||
|
|
||||||
await client().saveSecrets({
|
|
||||||
instanceId: id,
|
|
||||||
secrets: reduce(
|
|
||||||
secrets,
|
|
||||||
(c, v) => {
|
|
||||||
const { name, value } = v
|
|
||||||
c[name] = value
|
|
||||||
return c
|
|
||||||
},
|
|
||||||
{} as SaveSecretsPayload['secrets'],
|
|
||||||
),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
cm.add(unsub)
|
|
||||||
})
|
|
||||||
|
|
||||||
onDestroy(cm.shutdown)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
|
@ -75,7 +75,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="flex items-center justify-center gap-4">
|
<div class="flex items-center justify-center gap-4">
|
||||||
<a href="/dashboard" class="btn">Cancel</a>
|
<a href="/" class="btn">Cancel</a>
|
||||||
|
|
||||||
<button class="btn btn-primary" disabled={isFormButtonDisabled}>
|
<button class="btn btn-primary" disabled={isFormButtonDisabled}>
|
||||||
Create <i class="bi bi-arrow-right-short" />
|
Create <i class="bi bi-arrow-right-short" />
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { browser } from '$app/environment'
|
|
||||||
import { page } from '$app/stores'
|
import { page } from '$app/stores'
|
||||||
import AlertBar from '$components/AlertBar.svelte'
|
import AlertBar from '$components/AlertBar.svelte'
|
||||||
import { handleAccountConfirmation } from '$util/database'
|
import { handleAccountConfirmation } from '$util/database'
|
||||||
@ -9,7 +8,6 @@
|
|||||||
|
|
||||||
// Check for a token in the URL
|
// Check for a token in the URL
|
||||||
$: {
|
$: {
|
||||||
if (browser) {
|
|
||||||
token = $page?.url?.searchParams?.get('token')
|
token = $page?.url?.searchParams?.get('token')
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
@ -19,7 +17,6 @@
|
|||||||
formError = 'Invalid link'
|
formError = 'Invalid link'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const handleLoad = async () => {
|
const handleLoad = async () => {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
|
@ -38,7 +38,7 @@ export const handleLogin = async (
|
|||||||
await authViaEmail(email, password)
|
await authViaEmail(email, password)
|
||||||
|
|
||||||
if (shouldRedirect) {
|
if (shouldRedirect) {
|
||||||
await goto('/dashboard')
|
await goto('/')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!(error instanceof Error)) {
|
if (!(error instanceof Error)) {
|
||||||
@ -88,7 +88,7 @@ export const handleAccountConfirmation = async (
|
|||||||
try {
|
try {
|
||||||
await confirmVerification(token)
|
await confirmVerification(token)
|
||||||
|
|
||||||
window.location.href = '/dashboard'
|
window.location.href = '/'
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
handleFormError(error, setError)
|
handleFormError(error, setError)
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ export const handleUnauthenticatedPasswordResetConfirm = async (
|
|||||||
try {
|
try {
|
||||||
await requestPasswordResetConfirm(token, password)
|
await requestPasswordResetConfirm(token, password)
|
||||||
|
|
||||||
await goto('/dashboard')
|
await goto('/')
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
handleFormError(error, setError)
|
handleFormError(error, setError)
|
||||||
}
|
}
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
import { browser } from '$app/environment'
|
|
||||||
import { client } from '$src/pocketbase'
|
|
||||||
import { instance } from '$src/routes/app/instances/[instanceId]/store'
|
|
||||||
import { globalInstancesStore, isUserLoggedIn } from '$util/stores'
|
|
||||||
import {
|
|
||||||
LoggerService,
|
|
||||||
assertExists,
|
|
||||||
createCleanupManager,
|
|
||||||
type InstanceFields,
|
|
||||||
} from '@pockethost/common'
|
|
||||||
import { onDestroy, onMount } from 'svelte'
|
|
||||||
|
|
||||||
export const getInstances = async () => {
|
|
||||||
const { error } = LoggerService()
|
|
||||||
|
|
||||||
const cm = createCleanupManager()
|
|
||||||
onMount(async () => {
|
|
||||||
const unsub = isUserLoggedIn.subscribe(async (isLoggedIn) => {
|
|
||||||
if (!isLoggedIn) return
|
|
||||||
const { getAllInstancesById } = client()
|
|
||||||
|
|
||||||
const instances = await getAllInstancesById()
|
|
||||||
|
|
||||||
globalInstancesStore.set(instances)
|
|
||||||
|
|
||||||
const unsub = await client()
|
|
||||||
.client.collection('instances')
|
|
||||||
.subscribe<InstanceFields>('*', (data) => {
|
|
||||||
globalInstancesStore.update((instances) => {
|
|
||||||
instances[data.record.id] = data.record
|
|
||||||
return instances
|
|
||||||
})
|
|
||||||
})
|
|
||||||
cm.add(unsub)
|
|
||||||
})
|
|
||||||
cm.add(unsub)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Stop listening to the db if this component unmounts
|
|
||||||
onDestroy(() => {
|
|
||||||
cm.shutdown().catch(console.error)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getSingleInstance = async (instanceId: string) => {
|
|
||||||
const cm = createCleanupManager()
|
|
||||||
// Only run this on the browser
|
|
||||||
if (browser) {
|
|
||||||
const { dbg, error } = LoggerService().create(`layout.svelte`)
|
|
||||||
|
|
||||||
const { watchInstanceById } = client()
|
|
||||||
|
|
||||||
watchInstanceById(instanceId, (r) => {
|
|
||||||
dbg(`Handling instance update`, r)
|
|
||||||
const { action, record } = r
|
|
||||||
assertExists(record, `Expected instance here`)
|
|
||||||
|
|
||||||
// Update the page state with the instance information
|
|
||||||
instance.set(record)
|
|
||||||
})
|
|
||||||
.then(cm.add)
|
|
||||||
.catch(error)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +1,17 @@
|
|||||||
import { browser } from '$app/environment'
|
|
||||||
import { client } from '$src/pocketbase'
|
import { client } from '$src/pocketbase'
|
||||||
import type { AuthStoreProps } from '$src/pocketbase/PocketbaseClient'
|
|
||||||
import {
|
import {
|
||||||
LoggerService,
|
LoggerService,
|
||||||
type InstanceFields,
|
type InstanceFields,
|
||||||
type InstanceId,
|
type InstanceId,
|
||||||
} from '@pockethost/common'
|
} from '@pockethost/common'
|
||||||
|
import { UnsubscribeFunc } from 'pocketbase'
|
||||||
import { writable } from 'svelte/store'
|
import { writable } from 'svelte/store'
|
||||||
import '../services'
|
import '../services'
|
||||||
|
|
||||||
export const authStoreState = writable<AuthStoreProps>({
|
|
||||||
isValid: false,
|
|
||||||
model: null,
|
|
||||||
token: '',
|
|
||||||
})
|
|
||||||
|
|
||||||
export const isUserLoggedIn = writable(false)
|
export const isUserLoggedIn = writable(false)
|
||||||
export const isUserVerified = writable(false)
|
export const isUserVerified = writable(false)
|
||||||
export const isAuthStateInitialized = writable(false)
|
export const isAuthStateInitialized = writable(false)
|
||||||
|
|
||||||
if (browser) {
|
|
||||||
const { onAuthChange } = client()
|
const { onAuthChange } = client()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,20 +20,48 @@ if (browser) {
|
|||||||
onAuthChange((authStoreProps) => {
|
onAuthChange((authStoreProps) => {
|
||||||
const { dbg } = LoggerService()
|
const { dbg } = LoggerService()
|
||||||
dbg(`onAuthChange in store`, { ...authStoreProps })
|
dbg(`onAuthChange in store`, { ...authStoreProps })
|
||||||
authStoreState.set(authStoreProps)
|
|
||||||
isAuthStateInitialized.set(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Update derived stores when authStore changes
|
|
||||||
authStoreState.subscribe((authStoreProps) => {
|
|
||||||
const { dbg } = LoggerService()
|
|
||||||
dbg(`subscriber change`, authStoreProps)
|
|
||||||
isUserLoggedIn.set(authStoreProps.isValid)
|
isUserLoggedIn.set(authStoreProps.isValid)
|
||||||
isUserVerified.set(!!authStoreProps.model?.verified)
|
isUserVerified.set(!!authStoreProps.model?.verified)
|
||||||
|
isAuthStateInitialized.set(true)
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// This holds an array of all the user's instances and their data
|
// This holds an array of all the user's instances and their data
|
||||||
export const globalInstancesStore = writable<{
|
export const globalInstancesStore = writable<{
|
||||||
[_: InstanceId]: InstanceFields
|
[_: InstanceId]: InstanceFields
|
||||||
}>({})
|
}>({})
|
||||||
|
|
||||||
|
export const globalInstancesStoreReady = writable(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for instances
|
||||||
|
*/
|
||||||
|
isUserLoggedIn.subscribe(async (isLoggedIn) => {
|
||||||
|
let unsub: UnsubscribeFunc | undefined
|
||||||
|
if (!isLoggedIn) {
|
||||||
|
globalInstancesStore.set({})
|
||||||
|
globalInstancesStoreReady.set(false)
|
||||||
|
unsub?.()
|
||||||
|
.then(() => {
|
||||||
|
unsub = undefined
|
||||||
|
})
|
||||||
|
.catch(console.error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { getAllInstancesById } = client()
|
||||||
|
|
||||||
|
const instances = await getAllInstancesById()
|
||||||
|
|
||||||
|
globalInstancesStore.set(instances)
|
||||||
|
globalInstancesStoreReady.set(true)
|
||||||
|
|
||||||
|
client()
|
||||||
|
.client.collection('instances')
|
||||||
|
.subscribe<InstanceFields>('*', (data) => {
|
||||||
|
globalInstancesStore.update((instances) => {
|
||||||
|
instances[data.record.id] = data.record
|
||||||
|
return instances
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then((u) => (unsub = u))
|
||||||
|
.catch(console.error)
|
||||||
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user