dashboard UI cosmetic updates

This commit is contained in:
Ben Allfree
2024-10-05 05:23:49 -07:00
parent e7d58b518b
commit ed2761e03e
25 changed files with 512 additions and 590 deletions

View File

@@ -1,3 +1,14 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
.prose :where(pre):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
@apply mb-1 mt-1;
}
.prose :where(code):not(:where([class~='not-prose'] *)) {
@apply bg-transparent;
}
.prose :where(p):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
@apply mt-0 mb-0;
}

View File

@@ -1,10 +1,13 @@
<script>
<script lang="ts">
import { page } from '$app/stores'
import AlertBar from '$components/AlertBar.svelte'
import { INSTANCE_ADMIN_URL } from '$src/env'
import { globalInstancesStore } from '$util/stores'
import { assert } from 'pockethost/common'
import { instance } from './store'
import { client } from '$src/pocketbase-client'
import { InstanceId } from 'pockethost/common'
import Toggle from './Toggle.svelte'
let isReady = false
$: {
@@ -17,7 +20,23 @@
isReady = !!_instance
}
$: ({ status, version, id } = $instance || {})
$: ({ id } = $instance || {})
const { updateInstance } = client()
const handleMaintenanceChange = (id: InstanceId) => (isChecked: boolean) => {
const maintenance = !isChecked
// Update the database with the new value
updateInstance({ id, fields: { maintenance } })
.then(() => 'saved')
.catch((error) => {
error.data.message || error.message
})
}
$: isActive = (path: string) => $page.url.pathname.endsWith(path)
$: activeClass = (path: string) => (isActive(path) ? 'text-primary' : '')
</script>
<svelte:head>
@@ -27,93 +46,100 @@
</svelte:head>
{#if isReady}
<div
class="flex md:flex-row flex-col items-center justify-between mb-6 gap-4"
>
<div class="flex flex-row items-center justify-between mb-6 gap-4">
<div>
<h2
class="text-4xl md:text-left text-center text-base-content font-bold capitalize mb-3 break-words"
class="text-4xl md:text-left text-center text-base-content font-bold mb-3 break-words"
>
{$instance.subdomain}
{$instance.subdomain}<span class="text-xs text-gray-400"
>.pockethost.io</span
>
<span class="text-xs text-gray-400">v{$instance.version}</span>
</h2>
<div class="flex flex-wrap md:justify-start justify-center gap-2">
<div class="badge badge-accent badge-outline">
Status: &nbsp;<span class="capitalize">{status}</span>
</div>
<div class="badge badge-accent badge-outline">Version: {version}</div>
</div>
</div>
<a
href={INSTANCE_ADMIN_URL($instance)}
rel="noreferrer"
target="_blank"
class="btn btn-primary"
>
<img
src="/images/pocketbase-logo.svg"
alt="PocketBase Logo"
class="w-6"
<div>
<Toggle
title="Power"
checked={!$instance.maintenance}
onChange={handleMaintenanceChange($instance.id)}
/>
Admin
</a>
</div>
</div>
{#if $instance.maintenance}
<AlertBar
message="This instance is in Maintenance Mode and will not respond to requests"
message="This instance is turned off and will not respond to requests"
type="warning"
/>
{/if}
<div role="tablist" class="tabs tabs-bordered gap-4 mb-4 p-4">
<a
role="tab"
class="tab h-auto md:h-8 flex gap-2 font-bold {$page.url.pathname.endsWith(
id,
)
? `tab-active`
: ``}"
href="/app/instances/{id}"
><i class="fa-light fa-sparkles"></i> Overview</a
>
<a
role="tab"
class="tab h-auto md:h-8 flex gap-2 font-bold {$page.url.pathname.endsWith(
`logs`,
)
? `tab-active`
: ``}"
href="/app/instances/{id}/logs"
><i class="fa-light fa-terminal"></i> Logs</a
>
<a
role="tab"
class="tab h-auto md:h-8 flex gap-2 font-bold {$page.url.pathname.endsWith(
`secrets`,
)
? `tab-active`
: ``}"
href="/app/instances/{id}/secrets"
><i class="fa-light fa-shield"></i> Secrets</a
>
<a
role="tab"
class="tab h-auto md:h-8 flex gap-2 font-bold {$page.url.pathname.endsWith(
`settings`,
)
? `tab-active`
: ``}"
href="/app/instances/{id}/settings"
><i class="fa-light fa-gear"></i> Settings</a
>
</div>
<div class="flex gap-4">
<div class="w-48">
<ul>
<li>
<a href={`/app/instances/${id}`} class={activeClass(id)}>Overview</a>
</li>
<li>
<a
href={`/app/instances/${id}/secrets`}
class={activeClass(`secrets`)}>Secrets</a
>
</li>
<li>
<a href={`/app/instances/${id}/logs`} class={activeClass(`logs`)}
>Logs</a
>
</li>
<li>
<a href={`/app/instances/${id}/ftp`} class={activeClass(`ftp`)}
>FTP Access</a
>
</li>
<li>
<a
href={INSTANCE_ADMIN_URL($instance)}
rel="noreferrer"
target="_blank"
>
<img
src="/images/pocketbase-logo.svg"
alt="PocketBase Logo"
class="w-6 inline-block"
/>
Admin
<i class="fa-solid fa-external-link-alt text-xs"></i>
</a>
</li>
</ul>
<div class="divider"></div>
<div class="mt-2 mb-2">
<i class="fa-solid fa-siren-on text-error"></i>
<span class=" font-bold text-error">Danger Zone</span>
<i class="fa-solid fa-siren-on text-error"></i>
</div>
<ul>
<li><a href={`/app/instances/${id}/version`}>Change Version</a></li>
<li><a href={`/app/instances/${id}/domain`}>Custom Domain</a></li>
<li><a href={`/app/instances/${id}/admin-sync`}>Admin Sync</a></li>
<li><a href={`/app/instances/${id}/dev`}>Dev Mode</a></li>
<li><a href={`/app/instances/${id}/rename`}>Rename</a></li>
<li>
<a href={`/app/instances/${id}/delete`} class="btn btn-error btn-xs"
>Delete</a
>
</li>
</ul>
</div>
{#key $page.url.pathname}
<slot />
{/key}
<div class="w-full">
{#key $page.url.pathname}
<article class="prose">
<slot />
</article>
{/key}
</div>
</div>
{:else}
<div>Instance not found</div>
{/if}

View File

@@ -1,7 +1,7 @@
<script lang="ts">
import { assertExists } from 'pockethost/common'
import Code from './Code.svelte'
import Ftp from './Ftpx.svelte'
import Ftp from './ftp/+page.svelte'
import { instance } from './store'
$: ({ status, version, id } = $instance)
@@ -10,7 +10,4 @@
const { subdomain } = $instance
</script>
<div class="grid lg:grid-cols-2 grid-cols-1 gap-4 mb-4">
<Code />
<Ftp />
</div>
<Code />

View File

@@ -1,7 +1,5 @@
<script lang="ts">
import CodeSample from '$components/CodeSample.svelte'
import Card from '$components/cards/Card.svelte'
import CardHeader from '$components/cards/CardHeader.svelte'
import { DISCORD_URL, INSTANCE_URL } from '$src/env'
import { instance } from './store'
@@ -19,56 +17,54 @@
});`
</script>
<Card>
<CardHeader>Getting Started</CardHeader>
<h2>Overview</h2>
<div class="mb-4">
<p>Your PocketBase URL is</p>
<CodeSample code={url} />
</div>
<div class="mb-4">
<p>Your PocketBase URL is</p>
<CodeSample code={url} />
</div>
<div class="mb-4">
<p>Installing PocketBase</p>
<CodeSample code={installSnippet} />
</div>
<div class="mb-4">
<p>Installing PocketBase</p>
<CodeSample code={installSnippet} />
</div>
<div class="mb-4">
<p>Connecting to Your Instance</p>
{#if $instance.cname}
{#if $instance.cname_active}
<div class="text-accent">Notice: You are in Custom Domain mode</div>
{:else}
<div class="text-error">
Notice: You are in Custom Domain mode but it is not active and will
not work. Go find <a href={DISCORD_URL} target="_blank" class="link"
>@noaxis on Discord</a
> to get set up.
</div>
{/if}
<div class="mb-4">
<p>Connecting to Your Instance</p>
{#if $instance.cname}
{#if $instance.cname_active}
<div class="text-accent">Notice: You are in Custom Domain mode</div>
{:else}
<div class="text-error">
Notice: You are in Custom Domain mode but it is not active and will not
work. Go find <a href={DISCORD_URL} target="_blank" class="link"
>@noaxis on Discord</a
> to get set up.
</div>
{/if}
<CodeSample code={connectionSnippet} />
</div>
{/if}
<CodeSample code={connectionSnippet} />
</div>
<div class="mb-4">
<p>Making Your First Query</p>
<CodeSample code={firstQuerySnippet} />
</div>
<div class="mb-4">
<p>Making Your First Query</p>
<CodeSample code={firstQuerySnippet} />
</div>
<p>Additional Resources:</p>
<ul class="list-disc pl-4">
<li>
<a
href={`https://pocketbase.io/docs/api-records/`}
target="_blank"
class="link">PocketBase Web APIs</a
>
</li>
<li>
<a
href="https://www.npmjs.com/package/pocketbase"
target="_blank"
class="link">PocketBase NPM Package</a
>
</li>
</ul>
</Card>
<p>Additional Resources:</p>
<ul class="list-disc pl-4">
<li>
<a
href={`https://pocketbase.io/docs/api-records/`}
target="_blank"
class="link">PocketBase Web APIs</a
>
</li>
<li>
<a
href="https://www.npmjs.com/package/pocketbase"
target="_blank"
class="link">PocketBase NPM Package</a
>
</li>
</ul>

View File

@@ -1,63 +0,0 @@
<script lang="ts">
import CodeSample from '$components/CodeSample.svelte'
import Card from '$components/cards/Card.svelte'
import CardHeader from '$components/cards/CardHeader.svelte'
import { DOCS_URL, FTP_URL } from '$src/env'
import { client } from '$src/pocketbase-client'
import { bash } from 'svelte-highlight/languages'
const { user } = client()
const { email } = user() || {}
// This will hide the component if the email was not found
if (!email) {
throw new Error(`Email expected here`)
}
const ftpUrl = FTP_URL(email)
</script>
<Card>
<CardHeader documentation={DOCS_URL(`/usage/ftp`)}>FTP Access</CardHeader>
<p class="mb-8">
Securely access your instance files via FTPS. Use your PocketHost account
login and password.
</p>
<p>Bash:</p>
<div class="mb-12">
<CodeSample code={`ftp ${ftpUrl}`} language={bash} />
</div>
<table class="table">
<thead>
<tr>
<th class="border-b-2 border-neutral">Directory</th>
<th class="border-b-2 border-neutral">Description</th>
</tr>
</thead>
<tbody>
<tr>
<th>pb_data</th>
<td
>The PocketBase data directory, including upload storage and database
backups</td
>
</tr>
<tr>
<th>pb_public</th>
<td>Public files, such as a web frontend</td>
</tr>
<tr>
<th>pb_migrations</th>
<td>The PocketBase migrations directory</td>
</tr>
<tr>
<th>pb_hooks</th>
<td>The PocketBase JS hooks directory</td>
</tr>
</tbody>
</table>
</Card>

View File

@@ -0,0 +1,35 @@
<script lang="ts">
export let checked = false
export let title = ''
export let onClass = 'success'
export let offClass = 'red-500'
export let onText = 'on'
export let offText = 'off'
export let onChange = (isChecked: boolean) => {}
const handleChange = (e: Event) => {
const target = e.target as HTMLInputElement
const isChecked = target.checked
e.preventDefault()
onChange(isChecked)
}
</script>
<div class="form-control w-fit">
<label class="label cursor-pointer">
<span class="label-text mr-2"
>{title} is
<span class="text-{checked ? onClass : offClass}"
>{checked ? onText : offText}</span
></span
>
<input
type="checkbox"
class="toggle bg-{checked ? onClass : offClass} hover:bg-{checked
? onClass
: offClass}"
{checked}
on:change={handleChange}
/>
</label>
</div>

View File

@@ -0,0 +1,36 @@
<script lang="ts">
import Card from '$components/cards/Card.svelte'
import CardHeader from '$components/cards/CardHeader.svelte'
import { DOCS_URL } from '$src/env'
import { client } from '$src/pocketbase-client'
import { instance } from '../store'
import ErrorMessage from '../settings/ErrorMessage.svelte'
import Toggle from '../Toggle.svelte'
const { updateInstance } = client()
$: ({ id, syncAdmin } = $instance)
let errorMessage = ''
const handleChange = (isChecked: boolean) => {
// Update the database with the new value
updateInstance({ id, fields: { syncAdmin: isChecked } })
.then(() => 'saved')
.catch((error) => {
errorMessage = error.data.message || error.message
})
}
</script>
<CardHeader documentation={DOCS_URL(`/usage/admin-sync`)}>
Admin Sync
</CardHeader>
<p class="mb-8">
Your instance will have an admin login that matches your pockethost.io login.
</p>
<ErrorMessage message={errorMessage} />
<Toggle title="Admin Sync" checked={!!syncAdmin} onChange={handleChange} />

View File

@@ -6,7 +6,8 @@
import { client } from '$src/pocketbase-client'
import { globalInstancesStore } from '$util/stores'
import { instance } from '../store'
import ErrorMessage from './ErrorMessage.svelte'
import ErrorMessage from '../settings/ErrorMessage.svelte'
import AlertBar from '$src/components/AlertBar.svelte'
$: ({ id, maintenance, version } = $instance)
@@ -63,37 +64,41 @@
}
</script>
<Card>
<CardHeader documentation={DOCS_URL(`/usage/delete`)}>
Delete Instance
</CardHeader>
<CardHeader documentation={DOCS_URL(`/usage/delete`)}>
Delete Instance
</CardHeader>
<div class="mb-8">
Deleting your instance will immediately and permanently delete your
instance:
<ul class="ml-10 text-error">
<li>Your subdomain</li>
<li><pre>pb_data/*</pre></li>
<li><pre>pb_public/*</pre></li>
<li><pre>pb_migrations/*</pre></li>
<li><pre>pb_static/*</pre></li>
</ul>
If you are storing files on S3, you must delete them separately.
</div>
{#if !maintenance}
<AlertBar
message="Instance must be powered off before deleting."
type="error"
/>
{/if}
<ErrorMessage message={errorMessage} />
<div class="mb-8">
Deleting your instance will immediately and permanently delete your instance:
<ul class="ml-10 text-error">
<li>Your subdomain</li>
<li><pre>pb_data/*</pre></li>
<li><pre>pb_public/*</pre></li>
<li><pre>pb_migrations/*</pre></li>
<li><pre>pb_static/*</pre></li>
</ul>
If you are storing files on S3, you must delete them separately.
</div>
<form
class="flex change-version-form-container-query gap-4"
on:submit={handleSave}
<ErrorMessage message={errorMessage} />
<form
class="flex change-version-form-container-query gap-4"
on:submit={handleSave}
>
<button
type="submit"
class="btn btn-error"
disabled={!maintenance || isButtonDisabled}>Delete Instance</button
>
<button
type="submit"
class="btn btn-error"
disabled={!maintenance || isButtonDisabled}>Delete Instance</button
>
</form>
</Card>
</form>
<style>
.change-version-form-container-query {

View File

@@ -0,0 +1,39 @@
<script lang="ts">
import Card from '$components/cards/Card.svelte'
import CardHeader from '$components/cards/CardHeader.svelte'
import { DOCS_URL } from '$src/env'
import { client } from '$src/pocketbase-client'
import { instance } from '../store'
import ErrorMessage from '../settings/ErrorMessage.svelte'
import Toggle from '../Toggle.svelte'
const { updateInstance } = client()
$: ({ id, dev } = $instance)
let errorMessage = ''
const handleChange = (isChecked: boolean) => {
updateInstance({ id, fields: { dev: isChecked } })
.then(() => 'saved')
.catch((error) => {
errorMessage = error.data.message || error.message
})
}
</script>
<CardHeader documentation={DOCS_URL(`/usage/dev-mode`)}>Dev Mode</CardHeader>
<p class="mb-8">
Starting with PocketBase v0.20.1, your instance will show debugging output in
the instance logs. Performance is degraded while Dev Mode is active.
</p>
<ErrorMessage message={errorMessage} />
<Toggle
title="Dev Mode"
onChange={handleChange}
checked={!!dev}
onClass="warning"
/>

View File

@@ -31,7 +31,9 @@
/^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,24}$/
$: {
isButtonDisabled = !!formCname.trim() && !regex.test(formCname)
isButtonDisabled =
(!!formCname.trim() && !regex.test(formCname)) ||
(!formCname.trim() && !cname.trim())
}
const onRename = (e: Event) => {
e.preventDefault()
@@ -76,54 +78,52 @@
}
</script>
<Card>
<CardHeader documentation={DOCS_URL(`/usage/custom-domain`)}>
Custom Domain (CNAME)
</CardHeader>
<CardHeader documentation={DOCS_URL(`/usage/custom-domain`)}>
Custom Domain (CNAME)
</CardHeader>
<div class="mb-8">
Use a custom domain (CNAME) with your PocketHost instance.
</div>
{#if formCname && regex.test(formCname.trim())}
<div class="mb-8">Go to your DNS provider and add a CNAME entry.</div>
<div class="mb-4">
<CodeSample
code={`${formCname} CNAME ${INSTANCE_BARE_HOST($instance)}`}
language={dns}
/>
</div>
{/if}
<AlertBar message={successMessage} type="success" />
<AlertBar message={errorMessage} type="error" />
{#if cname}
{#if !cname_active}
<AlertBar
message={`Your custom domain name is pending. Go find <a class='btn btn-primary' target='_blank' href="https://discord.com/channels/1128192380500193370/1189948945967882250">@noaxis on Discord</a> to complete setup.`}
type="warning"
/>
{:else}
<AlertBar message={`Your custom domain name is active.`} type="success" />
{/if}
{/if}
<form
class="flex rename-instance-form-container-query gap-4"
on:submit={onRename}
>
<input
title="Only valid domain name patterns are allowed"
type="text"
bind:value={formCname}
class="input input-bordered w-full"
<div class="mb-8">
Use a custom domain (CNAME) with your PocketHost instance.
</div>
{#if formCname && regex.test(formCname.trim())}
<div class="mb-8">Go to your DNS provider and add a CNAME entry.</div>
<div class="mb-4">
<CodeSample
code={`${formCname} CNAME ${INSTANCE_BARE_HOST($instance)}`}
language={dns}
/>
</div>
{/if}
<button type="submit" class="btn btn-error" disabled={isButtonDisabled}
>Update Custom Domain</button
>
</form>
</Card>
<AlertBar message={successMessage} type="success" />
<AlertBar message={errorMessage} type="error" />
{#if cname}
{#if !cname_active}
<AlertBar
message={`Your custom domain name is pending. Go find <a class='btn btn-primary' target='_blank' href="https://discord.com/channels/1128192380500193370/1189948945967882250">@noaxis on Discord</a> to complete setup.`}
type="warning"
/>
{:else}
<AlertBar message={`Your custom domain name is active.`} type="success" />
{/if}
{/if}
<form
class="flex rename-instance-form-container-query gap-4"
on:submit={onRename}
>
<input
title="Only valid domain name patterns are allowed"
type="text"
bind:value={formCname}
class="input input-bordered w-full"
/>
<button type="submit" class="btn btn-error" disabled={isButtonDisabled}
>Update Custom Domain</button
>
</form>
<style>
.rename-instance-form-container-query {

View File

@@ -0,0 +1,58 @@
<script lang="ts">
import CodeSample from '$components/CodeSample.svelte'
import Card from '$components/cards/Card.svelte'
import CardHeader from '$components/cards/CardHeader.svelte'
import { DOCS_URL, FTP_URL } from '$src/env'
import { client } from '$src/pocketbase-client'
import { bash } from 'svelte-highlight/languages'
const { user } = client()
const { email } = user() || {}
// This will hide the component if the email was not found
if (!email) {
throw new Error(`Email expected here`)
}
const ftpUrl = FTP_URL(email)
</script>
<h2>FTP Access</h2>
<div class="mb-8">
Securely access your instance files via FTPS. Use your PocketHost account
login and password.
</div>
<div class="mb-12">
<CodeSample code={`ftp ${ftpUrl}`} language={bash} />
</div>
<table class="table">
<thead>
<tr>
<th class="border-b-2 border-neutral">Directory</th>
<th class="border-b-2 border-neutral">Description</th>
</tr>
</thead>
<tbody>
<tr>
<th>pb_data</th>
<td
>The PocketBase data directory, including upload storage and database
backups</td
>
</tr>
<tr>
<th>pb_public</th>
<td>Public files, such as a web frontend</td>
</tr>
<tr>
<th>pb_migrations</th>
<td>The PocketBase migrations directory</td>
</tr>
<tr>
<th>pb_hooks</th>
<td>The PocketBase JS hooks directory</td>
</tr>
</tbody>
</table>

View File

@@ -82,10 +82,12 @@
})
</script>
<p class="mb-4">
<h2>Logs</h2>
<div class="mb-4">
Instance logs appear here in realtime, including <code>console.log</code> from
JavaScript hooks.
</p>
</div>
<dialog id="loggingFullscreenModal" class="modal backdrop-blur">
<div class="modal-box max-w-[90vw] h-[90vh]">

View File

@@ -56,37 +56,35 @@
}
</script>
<Card>
<CardHeader documentation={DOCS_URL(`/usage/rename-instance`)}>
Rename Instance
</CardHeader>
<CardHeader documentation={DOCS_URL(`/usage/rename-instance`)}>
Rename Instance
</CardHeader>
<p class="mb-8">
Renaming your instance will cause it to become <strong class="text-error"
>inaccessible</strong
> by the old instance name. You also may not be able to change it back if someone
else choose it.
</p>
<p class="mb-8">
Renaming your instance will cause it to become <strong class="text-error"
>inaccessible</strong
> by the old instance name. You also may not be able to change it back if someone
else choose it.
</p>
<AlertBar message={errorMessage} type="error" />
<AlertBar message={errorMessage} type="error" />
<form
class="flex rename-instance-form-container-query gap-4"
on:submit={onRename}
<form
class="flex rename-instance-form-container-query gap-4"
on:submit={onRename}
>
<input
title="Only letters and dashes are allowed"
required
type="text"
bind:value={formSubdomain}
class="input input-bordered w-full"
/>
<button type="submit" class="btn btn-error" disabled={isButtonDisabled}
>Rename Instance</button
>
<input
title="Only letters and dashes are allowed"
required
type="text"
bind:value={formSubdomain}
class="input input-bordered w-full"
/>
<button type="submit" class="btn btn-error" disabled={isButtonDisabled}
>Rename Instance</button
>
</form>
</Card>
</form>
<style>
.rename-instance-form-container-query {

View File

@@ -13,4 +13,5 @@
<title>{subdomain} secrets - PocketHost</title>
</svelte:head>
<h2>Secrets</h2>
<SecretsInner />

View File

@@ -79,34 +79,33 @@
</script>
<div class="mb-8">
<h4 class="flex items-center font-bold h-9 text-lg mb-3">
Add an Environment Variable
</h4>
{#if successfulSave}
<AlertBar
message="Your new environment variable has been saved."
type="success"
/>
{/if}
<AlertBar message={errorMessage} type="error" />
<form on:submit={handleSubmit} class="mb-4">
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label class="label" for="secret-key">
<span class="label-text">Key</span>
</label>
<input
id="secret-key"
type="text"
bind:value={secretKey}
placeholder="KEY"
class="input input-bordered w-full max-w-xs"
/>
</div>
<div>
<label class="label" for="secret-value">
<span class="label-text">Value</span>
</label>
<input
id="secret-value"
type="text"
bind:value={secretValue}
placeholder="VALUE"
class="input input-bordered w-full max-w-xs"
/>
</div>
@@ -125,13 +124,4 @@
>
</div>
</form>
{#if successfulSave}
<AlertBar
message="Your new environment variable has been saved."
type="success"
/>
{/if}
<AlertBar message={errorMessage} type="error" />
</div>

View File

@@ -6,8 +6,6 @@
import { reduce } from '@s-libs/micro-dash'
import { logger, UpdateInstancePayload } from 'pockethost'
let showSecretKeys = false
const handleDelete = (name: string) => async (e: Event) => {
e.preventDefault()
logger().debug(`Deleting ${name}`)
@@ -29,21 +27,6 @@
}
</script>
<div class="flex items-center justify-between mb-3 h-9">
<h4 class="font-bold text-lg">Current Environment Variables</h4>
<div class="form-control">
<label class="label cursor-pointer">
<span class="label-text text-accent mr-2">Show Secrets</span>
<input
type="checkbox"
class="toggle toggle-sm"
bind:checked={showSecretKeys}
/>
</label>
</div>
</div>
<table class="table">
<thead>
<tr>
@@ -58,10 +41,8 @@
<tr transition:fade>
<th>{item.name}</th>
<td
>{showSecretKeys
? item.value
: item.value.slice(0, 2) +
item.value.slice(2).replaceAll(/./g, '*')}</td
>{item.value.slice(0, 2) +
item.value.slice(2).replaceAll(/./g, '*')}</td
>
<td class="text-right">
<button

View File

@@ -6,8 +6,6 @@
import List from './List.svelte'
import { items } from './stores'
// TODO: Hot Reload is causing an infinite loop in the network tab for some reason. Wasn't able to figure out why
$: {
const { id, secrets } = $instance
items.clear()
@@ -17,24 +15,27 @@
})
}
// Keep track of which tab the user has selected
let activeTab = 0
// Toggle between the tabs on click
const handleTabChange = (id: number) => {
activeTab = id
}
$: code =
`// pb_hooks/env-test.pb.js\n\n` +
($items.length > 0
? $items
.map(
({ name, value }) =>
`const ${name} = process.env.${name}\nconsole.log("${name}: ", ${name})`,
)
.join('\n')
: `const YOUR_KEY = process.env.YOUR_KEY`)
</script>
<p class="mb-4">
<div class="mb-4">
These secrets are forwarded to your <code>pocketbase</code> as environment
variables, which are also accessible from any <code>pb_hooks</code> you have created.
</p>
</div>
<!-- If the user has any secrets, render them in a code block -->
{#if $items.length > 0}
<div class="mb-8">
<CodeSample code={`const YOUR_KEY = process.env.YOUR_KEY`} />
<CodeSample {code} />
</div>
{/if}
@@ -45,32 +46,5 @@
</div>
{/if}
<div class="tabs mb-4 border-b-[1px] border-neutral">
<button
on:click={() => handleTabChange(0)}
type="button"
class="tab border-b-2 {activeTab === 0
? 'tab-active font-bold border-base-content'
: 'border-neutral'}"
><i class="fa-regular fa-plus mr-2"></i> Add New</button
>
<button
on:click={() => handleTabChange(1)}
type="button"
class="tab border-b-2 {activeTab === 1
? 'tab-active font-bold border-base-content'
: 'border-neutral'}"
><i class="fa-regular fa-list mr-2"></i> Current List</button
>
</div>
<div>
{#if activeTab === 0}
<Form />
{/if}
{#if activeTab === 1}
<List />
{/if}
</div>
<List />
<Form />

View File

@@ -1,14 +1,13 @@
<script lang="ts">
import { assertExists } from 'pockethost/common'
import { instance } from '../store'
import AdminSync from './AdminSync.svelte'
import CustomDomain from './CustomDomain.svelte'
import AdminSync from '../admin-sync/+page.svelte'
import CustomDomain from '../domain/+page.svelte'
import DangerZoneTitle from './DangerZoneTitle.svelte'
import DeleteInstance from './DeleteInstance.svelte'
import DevMode from './DevMode.svelte'
import Maintenance from './Maintenance.svelte'
import RenameInstance from './RenameInstance.svelte'
import VersionChange from './VersionChange/VersionChange.svelte'
import DeleteInstance from '../delete/+page.svelte'
import DevMode from '../dev/+page.svelte'
import RenameInstance from '../rename/+page.svelte'
import VersionChange from '../version/+page.svelte'
$: ({ status, version, id } = $instance)
@@ -25,8 +24,6 @@
<div class="grid lg:grid-cols-3 gap-4 mb-4">
<RenameInstance />
<Maintenance />
<VersionChange />
<AdminSync />

View File

@@ -1,49 +0,0 @@
<script lang="ts">
import Card from '$components/cards/Card.svelte'
import CardHeader from '$components/cards/CardHeader.svelte'
import { DOCS_URL } from '$src/env'
import { client } from '$src/pocketbase-client'
import { instance } from '../store'
import ErrorMessage from './ErrorMessage.svelte'
const { updateInstance } = client()
$: ({ id, syncAdmin } = $instance)
let errorMessage = ''
const handleChange = (e: Event) => {
const target = e.target as HTMLInputElement
const isChecked = target.checked
// Update the database with the new value
updateInstance({ id, fields: { syncAdmin: isChecked } })
.then(() => 'saved')
.catch((error) => {
errorMessage = error.data.message || error.message
})
}
</script>
<Card>
<CardHeader documentation={DOCS_URL(`/usage/admin-sync`)}>
Admin Sync
</CardHeader>
<p class="mb-8">
Your instance will have an admin login that matches your pockethost.io
login.
</p>
<ErrorMessage message={errorMessage} />
<label class="label cursor-pointer justify-center gap-4">
<span class="label-text">Admin Sync</span>
<input
type="checkbox"
class="toggle toggle-warning"
checked={!!syncAdmin}
on:change={handleChange}
/>
</label>
</Card>

View File

@@ -1,47 +0,0 @@
<script lang="ts">
import Card from '$components/cards/Card.svelte'
import CardHeader from '$components/cards/CardHeader.svelte'
import { DOCS_URL } from '$src/env'
import { client } from '$src/pocketbase-client'
import { instance } from '../store'
import ErrorMessage from './ErrorMessage.svelte'
const { updateInstance } = client()
$: ({ id, dev } = $instance)
let errorMessage = ''
const handleChange = (e: Event) => {
const target = e.target as HTMLInputElement
const isChecked = target.checked
// Update the database with the new value
updateInstance({ id, fields: { dev: isChecked } })
.then(() => 'saved')
.catch((error) => {
errorMessage = error.data.message || error.message
})
}
</script>
<Card>
<CardHeader documentation={DOCS_URL(`/usage/dev-mode`)}>Dev Mode</CardHeader>
<p class="mb-8">
Starting with PocketBase v0.20.1, your instance will show debugging output
in the instance logs. Performance is degraded while Dev Mode is active.
</p>
<ErrorMessage message={errorMessage} />
<label class="label cursor-pointer justify-center gap-4">
<span class="label-text">Dev Mode</span>
<input
type="checkbox"
class="toggle toggle-warning"
checked={!!dev}
on:change={handleChange}
/>
</label>
</Card>

View File

@@ -1,78 +0,0 @@
<script lang="ts">
import Card from '$components/cards/Card.svelte'
import CardHeader from '$components/cards/CardHeader.svelte'
import { DOCS_URL } from '$src/env'
import { client } from '$src/pocketbase-client'
import { userStore } from '$util/stores'
import { instance } from '../store'
import ErrorMessage from './ErrorMessage.svelte'
const { updateInstance } = client()
let errorMessage = ''
$: ({ id, maintenance, notifyMaintenanceMode } = $instance)
const handleMaintenanceChange = (e: Event) => {
const target = e.target as HTMLInputElement
const maintenance = target.checked
// Update the database with the new value
updateInstance({ id, fields: { maintenance } })
.then(() => 'saved')
.catch((error) => {
error.data.message || error.message
})
}
const handleNotifyMaintenanceChange = (e: Event) => {
const target = e.target as HTMLInputElement
const notifyMaintenanceMode = target.checked
// Update the database with the new value
updateInstance({ id, fields: { notifyMaintenanceMode } })
.then(() => 'saved')
.catch((error) => {
error.data.message || error.message
})
}
</script>
<Card>
<CardHeader documentation={DOCS_URL(`/usage/maintenance`)}>
Maintenance Mode
</CardHeader>
<p class="mb-8">
Your PocketHost instance will not be accessible while in maintenance mode.
Use this when you are upgrading, downgrading, or backing up your data.
</p>
<ErrorMessage message={errorMessage} />
<label class="label cursor-pointer justify-center gap-4">
<span class="label-text">Maintenance Mode</span>
<input
type="checkbox"
class="toggle toggle-warning"
checked={!!maintenance}
on:change={handleMaintenanceChange}
/>
</label>
<label class="label cursor-pointer justify-center gap-4">
<span class="label-text">Email on Maintenance Mode</span>
<input
type="checkbox"
class="toggle toggle-success"
checked={!!notifyMaintenanceMode}
on:change={handleNotifyMaintenanceChange}
/>
</label>
{#if !$userStore?.notifyMaintenanceMode}
<div class="text-error">
Warning: Maintenance Mode is globally deactivated. This setting will have
no effect. See account settings.
</div>
{/if}
</Card>

View File

@@ -3,7 +3,7 @@
import CardHeader from '$components/cards/CardHeader.svelte'
import { DOCS_URL } from '$src/env'
import { client } from '$src/pocketbase-client'
import { instance } from '../../store'
import { instance } from '../store'
import VersionPicker from './VersionPicker.svelte'
import AlertBar from '$components/AlertBar.svelte'
@@ -58,35 +58,39 @@
}
</script>
<Card>
<CardHeader documentation={DOCS_URL(`/usage/upgrading`)}>
Version Change
</CardHeader>
<CardHeader documentation={DOCS_URL(`/usage/upgrading`)}>
Version Change
</CardHeader>
<p class="mb-8">
Changing your version can only be done when the instance is in maintenance
mode. We recommend you <strong>do a full backup</strong> before making a
change. We support
<a href="https://github.com/pocketbase/pocketbase/releases" class="link"
>every release</a
> of PocketBase.
</p>
{#if !maintenance}
<AlertBar
message="Your instance must be powered off to change the version."
type="error"
/>
{/if}
<AlertBar message={errorMessage} type="error" />
<div class="mb-8">
We recommend you <strong>do a full backup</strong>
before making a change. We support the latest patch of
<a href="https://github.com/pocketbase/pocketbase/releases" class="link"
>every minor release</a
> of PocketBase.
</div>
<form
class="flex change-version-form-container-query gap-4"
on:submit={handleSave}
<AlertBar message={errorMessage} type="error" />
<form
class="flex change-version-form-container-query gap-4"
on:submit={handleSave}
>
<VersionPicker bind:selectedVersion />
<button
type="submit"
class="btn btn-error"
disabled={!maintenance || isButtonDisabled}>Change Version</button
>
<VersionPicker bind:selectedVersion disabled={!maintenance} />
<button
type="submit"
class="btn btn-error"
disabled={!maintenance || isButtonDisabled}>Change Version</button
>
</form>
</Card>
</form>
<style>
.change-version-form-container-query {

View File

@@ -10,8 +10,12 @@
// Function to fetch versions - replace with your actual fetch logic
async function fetchVersions(): Promise<string[]> {
const { versions } = await client().client.send(`/api/versions`, {})
return versions
const { versions } = await client().client.send<{ versions: string[] }>(
`/api/versions`,
{},
)
return versions.filter((v) => v.endsWith('*'))
}
onMount(() => {

View File

@@ -34,7 +34,7 @@
<input
type="checkbox"
class="toggle {instance.maintenance
? 'toggle-error'
? 'bg-red-500 hover:bg-red-500'
: 'toggle-success'}"
checked={!instance.maintenance}
on:change={handleMaintenanceChange(instance.id)}
@@ -42,8 +42,7 @@
</div>
</div>
<div class="flex flex-wrap gap-2"></div>
<div class="card-actions">
<div class="card-actions flex justify-between mt-5">
<a href={`/app/instances/${instance.id}`} class="btn btn-primary">
<i class="fa-regular fa-circle-info"></i>
<span>Details</span>

View File

@@ -1,7 +1,13 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./src/**/*.{svelte,js,ts,md}'],
safelist: [`lg:pl-72`, `toggle-error`, `toggle-success`],
safelist: [
'lg:pl-72',
{
pattern: /(toggle|text|bg)-(error|success|warning|red-500)/,
variants: ['responsive', 'hover'],
},
],
theme: {
extend: {
animation: {