improvements
Some checks failed
Build and Push Svelte Docker Image / build (push) Failing after 6m22s
Some checks failed
Build and Push Svelte Docker Image / build (push) Failing after 6m22s
This commit is contained in:
parent
56a553bac9
commit
c1dc531995
@ -9,47 +9,47 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build Svelte app
|
||||
run: npm run build
|
||||
- name: Build Svelte app
|
||||
run: npm run build
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to Gitea Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: git.vinylnostalgia.com
|
||||
username: ${{ secrets.RUNNER_USERNAME }}
|
||||
password: ${{ secrets.RUNNER_PASSWORD }}
|
||||
- name: Login to Gitea Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: git.vinylnostalgia.com
|
||||
username: ${{ secrets.RUNNER_USERNAME }}
|
||||
password: ${{ secrets.RUNNER_PASSWORD }}
|
||||
|
||||
- name: Generate Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: git.vinylnostalgia.com/mo/ava
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=sha
|
||||
- name: Generate Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: git.vinylnostalgia.com/mo/caddyui
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=sha
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
@ -17,211 +17,216 @@
|
||||
Textarea,
|
||||
Spinner
|
||||
} from 'flowbite-svelte';
|
||||
import { fly, fade } from 'svelte/transition';
|
||||
import type { Upstream, CAInfo } from './CaddyService';
|
||||
|
||||
let config: Record<string, any> = {};
|
||||
// State variables
|
||||
let config = {};
|
||||
let upstreams: Upstream[] = [];
|
||||
let caInfo: CAInfo | null = null;
|
||||
let caCertificates: string = '';
|
||||
let showConfigModal: boolean = false;
|
||||
let showCAModal: boolean = false;
|
||||
let loadingConfig: boolean = false;
|
||||
let loadingUpstreams: boolean = false;
|
||||
let newConfig: string = '';
|
||||
let configPath: string = '';
|
||||
let caId: string = 'local';
|
||||
let activeTab: string = 'config';
|
||||
let caCertificates = '';
|
||||
let showConfigModal = false;
|
||||
let showCAModal = false;
|
||||
let loadingConfig = false;
|
||||
let loadingUpstreams = false;
|
||||
let newConfig = '';
|
||||
let configPath = '';
|
||||
let caId = 'local';
|
||||
let activeTab = 'config'; // Tracks the active tab
|
||||
|
||||
configStore.subscribe((value) => (config = value));
|
||||
upstreamsStore.subscribe((value) => (upstreams = value));
|
||||
// Subscribe to stores
|
||||
configStore.subscribe((value: any) => (config = value));
|
||||
upstreamsStore.subscribe((value: any) => (upstreams = value));
|
||||
|
||||
onMount(async () => {
|
||||
await refreshData();
|
||||
});
|
||||
|
||||
async function refreshData(): Promise<void> {
|
||||
// Fetch and refresh data
|
||||
async function refreshData() {
|
||||
loadingConfig = true;
|
||||
try {
|
||||
loadingConfig = true;
|
||||
await CaddyService.getConfig();
|
||||
await CaddyService.getUpstreams();
|
||||
} catch (error) {
|
||||
alert(`Failed to refresh data: ${(error as Error).message}`);
|
||||
alert(`Error refreshing data: ${(error as Error).message}`);
|
||||
} finally {
|
||||
loadingConfig = false;
|
||||
loadingUpstreams = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleUpdateConfig(): Promise<void> {
|
||||
// Update configuration
|
||||
async function handleUpdateConfig() {
|
||||
try {
|
||||
loadingConfig = true;
|
||||
await CaddyService.updateConfig(configPath, JSON.parse(newConfig));
|
||||
await refreshData();
|
||||
showConfigModal = false;
|
||||
} catch (error) {
|
||||
alert(`Failed to update config: ${(error as Error).message}`);
|
||||
alert(`Error updating config: ${(error as Error).message}`);
|
||||
} finally {
|
||||
loadingConfig = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleLoadConfig(): Promise<void> {
|
||||
// Load new configuration
|
||||
async function handleLoadConfig() {
|
||||
try {
|
||||
loadingConfig = true;
|
||||
await CaddyService.loadConfig(JSON.parse(newConfig));
|
||||
await refreshData();
|
||||
showConfigModal = false;
|
||||
} catch (error) {
|
||||
alert(`Failed to load config: ${(error as Error).message}`);
|
||||
alert(`Error loading config: ${(error as Error).message}`);
|
||||
} finally {
|
||||
loadingConfig = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleStopServer(): Promise<void> {
|
||||
// Stop the Caddy server
|
||||
async function handleStopServer() {
|
||||
if (confirm('Are you sure you want to stop the Caddy server?')) {
|
||||
try {
|
||||
await CaddyService.stopServer();
|
||||
alert('Caddy server stopped successfully');
|
||||
} catch (error) {
|
||||
alert(`Failed to stop server: ${(error as Error).message}`);
|
||||
alert(`Error stopping server: ${(error as Error).message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleGetCAInfo(): Promise<void> {
|
||||
// Fetch CA information
|
||||
async function handleGetCAInfo() {
|
||||
try {
|
||||
caInfo = await CaddyService.getCAInfo(caId);
|
||||
caCertificates = await CaddyService.getCACertificates(caId);
|
||||
showCAModal = true;
|
||||
} catch (error) {
|
||||
alert(`Failed to get CA info: ${(error as Error).message}`);
|
||||
alert(`Error fetching CA info: ${(error as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Change active tab
|
||||
function handleTabChange(tab: string) {
|
||||
activeTab = tab;
|
||||
}
|
||||
|
||||
import { Cog, ServerCrash, Shield, RefreshCw } from 'lucide-svelte';
|
||||
</script>
|
||||
|
||||
<main class="container mx-auto p-4 bg-gray-50 min-h-screen">
|
||||
<h1 class="text-4xl font-bold mb-6 text-caddy-green">Caddy UI</h1>
|
||||
<main class="container mx-auto min-h-screen bg-gray-50 p-6">
|
||||
<header class="mb-6">
|
||||
<h1 class="text-caddy-green text-4xl font-bold">Caddy Dashboard</h1>
|
||||
<p class="mt-2 text-gray-700">
|
||||
Manage your Caddy server configurations, upstreams, and CA information easily.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<Tabs style="pills">
|
||||
<!-- Removed bind:active -->
|
||||
<TabItem
|
||||
open={activeTab === 'config'}
|
||||
on:click={() => handleTabChange('config')}
|
||||
title="Configuration"
|
||||
class="flex items-center gap-2"
|
||||
></TabItem>
|
||||
/>
|
||||
<TabItem
|
||||
open={activeTab === 'upstreams'}
|
||||
on:click={() => handleTabChange('upstreams')}
|
||||
title="Upstreams"
|
||||
class="flex items-center gap-2"
|
||||
></TabItem>
|
||||
|
||||
/>
|
||||
<TabItem
|
||||
open={activeTab === 'ca_management'}
|
||||
on:click={() => handleTabChange('ca_management')}
|
||||
title="CA Management"
|
||||
class="flex items-center gap-2"
|
||||
></TabItem>
|
||||
/>
|
||||
</Tabs>
|
||||
|
||||
<!-- Display content based on the activeTab -->
|
||||
<!-- Tab Content -->
|
||||
{#if activeTab === 'config'}
|
||||
<div class="mt-6">
|
||||
<section class="mt-6">
|
||||
<Card class="shadow-lg">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h2 class="text-2xl font-semibold text-caddy-blue">Current Configuration</h2>
|
||||
<Button
|
||||
color="green"
|
||||
on:click={() => (showConfigModal = true)}
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
<RefreshCw size="16" />
|
||||
<header class="mb-4 flex items-center justify-between">
|
||||
<h2 class="text-caddy-blue text-2xl font-semibold">Current Configuration</h2>
|
||||
<Button on:click={() => (showConfigModal = true)} class="flex items-center gap-2">
|
||||
Update Configuration
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
{#if loadingConfig}
|
||||
<div class="flex justify-center p-4">
|
||||
<Spinner size="xl" color="blue" />
|
||||
</div>
|
||||
{:else}
|
||||
<pre class="bg-gray-100 p-4 rounded-lg overflow-x-auto text-sm">{JSON.stringify(
|
||||
config,
|
||||
null,
|
||||
2
|
||||
)}</pre>
|
||||
<pre class="overflow-x-auto rounded-lg bg-gray-100 p-4 text-sm">
|
||||
{JSON.stringify(config, null, 2)}
|
||||
</pre>
|
||||
{/if}
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{#if activeTab === 'upstreams'}
|
||||
<div class="mt-6">
|
||||
<section class="mt-6">
|
||||
<Card class="shadow-lg">
|
||||
<h2 class="text-2xl font-semibold mb-4 text-caddy-blue">Upstreams</h2>
|
||||
<header class="mb-4">
|
||||
<h2 class="text-caddy-blue text-2xl font-semibold">Upstreams</h2>
|
||||
</header>
|
||||
{#if loadingUpstreams}
|
||||
<div class="flex justify-center p-4">
|
||||
<Spinner size="xl" color="blue" />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="overflow-x-auto">
|
||||
<Table striped={true} hoverable={true}>
|
||||
<TableHead>
|
||||
<TableHeadCell>Address</TableHeadCell>
|
||||
<TableHeadCell>Requests</TableHeadCell>
|
||||
<TableHeadCell>Fails</TableHeadCell>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{#each upstreams as upstream}
|
||||
<TableBodyRow>
|
||||
<TableBodyCell>{upstream.address}</TableBodyCell>
|
||||
<TableBodyCell>{upstream.num_requests}</TableBodyCell>
|
||||
<TableBodyCell>{upstream.fails}</TableBodyCell>
|
||||
</TableBodyRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<Table striped hoverable>
|
||||
<TableHead>
|
||||
<TableHeadCell>Address</TableHeadCell>
|
||||
<TableHeadCell>Requests</TableHeadCell>
|
||||
<TableHeadCell>Fails</TableHeadCell>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{#each upstreams as upstream}
|
||||
<TableBodyRow>
|
||||
<TableBodyCell>{upstream.address}</TableBodyCell>
|
||||
<TableBodyCell>{upstream.num_requests}</TableBodyCell>
|
||||
<TableBodyCell>{upstream.fails}</TableBodyCell>
|
||||
</TableBodyRow>
|
||||
{/each}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{/if}
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{#if activeTab === 'ca_management'}
|
||||
<div class="mt-6">
|
||||
<section class="mt-6">
|
||||
<Card class="shadow-lg">
|
||||
<h2 class="text-2xl font-semibold mb-4 text-caddy-blue">CA Management</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<Input type="text" placeholder="CA ID (e.g., local)" bind:value={caId} />
|
||||
<Button color="green" on:click={handleGetCAInfo}>Get CA Info</Button>
|
||||
<header class="mb-4">
|
||||
<h2 class="text-caddy-blue text-2xl font-semibold">CA Management</h2>
|
||||
</header>
|
||||
<div class="flex items-center gap-4">
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Enter CA ID (e.g., local)"
|
||||
bind:value={caId}
|
||||
class="flex-1"
|
||||
/>
|
||||
<Button on:click={handleGetCAInfo}>Get CA Info</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<footer class="mt-6 flex justify-end">
|
||||
<Button color="red" on:click={handleStopServer} class="flex items-center gap-2">
|
||||
Stop Caddy Server
|
||||
</Button>
|
||||
</footer>
|
||||
</main>
|
||||
|
||||
<div class="mt-6 flex justify-end">
|
||||
<Button color="red" on:click={handleStopServer} class="flex items-center gap-2">
|
||||
<ServerCrash size="16" />
|
||||
Stop Caddy Server
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Modal bind:open={showConfigModal} size="xl" autoclose={false} class="w-full max-w-4xl">
|
||||
<h2 class="text-2xl font-semibold mb-4 text-caddy-blue">Update Configuration</h2>
|
||||
<!-- Modals -->
|
||||
<Modal bind:open={showConfigModal} size="xl" autoclose={false}>
|
||||
<h2 class="text-caddy-blue mb-4 text-2xl font-semibold">Update Configuration</h2>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Config path (e.g., apps/http/servers/myserver/listen)"
|
||||
class="mb-4"
|
||||
bind:value={configPath}
|
||||
class="mb-4"
|
||||
/>
|
||||
<Textarea
|
||||
rows={10}
|
||||
@ -229,32 +234,29 @@
|
||||
bind:value={newConfig}
|
||||
class="mb-4"
|
||||
/>
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button color="light" on:click={() => (showConfigModal = false)}>Cancel</Button>
|
||||
<Button color="green" on:click={handleUpdateConfig}>Update Config</Button>
|
||||
<div class="flex justify-end gap-4">
|
||||
<Button on:click={() => (showConfigModal = false)}>Cancel</Button>
|
||||
<Button color="green" on:click={handleUpdateConfig}>Update</Button>
|
||||
<Button color="blue" on:click={handleLoadConfig}>Load Full Config</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<Modal bind:open={showCAModal} size="xl" autoclose={false}>
|
||||
<h2 class="text-2xl font-semibold mb-4 text-caddy-blue">CA Information</h2>
|
||||
<h2 class="text-caddy-blue mb-4 text-2xl font-semibold">CA Information</h2>
|
||||
{#if caInfo}
|
||||
<div class="mb-4 space-y-2">
|
||||
<p><strong class="text-caddy-green">ID:</strong> {caInfo.id}</p>
|
||||
<p><strong class="text-caddy-green">Name:</strong> {caInfo.name}</p>
|
||||
<p><strong class="text-caddy-green">Root CN:</strong> {caInfo.root_common_name}</p>
|
||||
<p>
|
||||
<strong class="text-caddy-green">Intermediate CN:</strong>
|
||||
{caInfo.intermediate_common_name}
|
||||
</p>
|
||||
<div class="space-y-4">
|
||||
<p><strong>ID:</strong> {caInfo.id}</p>
|
||||
<p><strong>Name:</strong> {caInfo.name}</p>
|
||||
<p><strong>Root CN:</strong> {caInfo.root_common_name}</p>
|
||||
<p><strong>Intermediate CN:</strong> {caInfo.intermediate_common_name}</p>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold mb-2 text-caddy-blue">Certificates</h3>
|
||||
<Textarea rows={10} readonly value={caCertificates} class="mb-4" />
|
||||
<h3 class="text-caddy-blue mt-4 text-lg font-semibold">Certificates</h3>
|
||||
<Textarea readonly rows={10} value={caCertificates} />
|
||||
{:else}
|
||||
<p class="text-gray-600">No CA information available.</p>
|
||||
<p>No CA information available.</p>
|
||||
{/if}
|
||||
<div class="flex justify-end">
|
||||
<Button color="blue" on:click={() => (showCAModal = false)}>Close</Button>
|
||||
<div class="mt-4 flex justify-end">
|
||||
<Button on:click={() => (showCAModal = false)}>Close</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@ -262,20 +264,10 @@
|
||||
:global(body) {
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
:global(.text-caddy-green) {
|
||||
color: #00add8;
|
||||
}
|
||||
|
||||
:global(.text-caddy-blue) {
|
||||
color: #0097b7;
|
||||
}
|
||||
|
||||
:global(.bg-caddy-green) {
|
||||
background-color: #00add8;
|
||||
}
|
||||
|
||||
:global(.bg-caddy-blue) {
|
||||
background-color: #0097b7;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user