feat: enable proxy toggle on quick deploy, event log clearing, and UX fixes
- Add enable_proxy toggle to Quick Deploy form (defaults to on)
- Add DELETE /api/events/log/{id} and DELETE /api/events/log endpoints
- Add Clear All button with confirmation on Events page
- Rename "NPM Proxy" to "Enable Proxy" on stage form (provider-agnostic)
- Fix polling interval validation (min 60s) and number input trim errors
- Fix domain field no longer required in settings
This commit is contained in:
@@ -215,6 +215,7 @@ export function quickDeploy(data: {
|
||||
registry?: string;
|
||||
port?: number;
|
||||
force?: boolean;
|
||||
enable_proxy?: boolean;
|
||||
}): Promise<{ project: Project; status: string }> {
|
||||
return post<{ project: Project; status: string }>('/api/deploy/quick', data);
|
||||
}
|
||||
@@ -540,6 +541,14 @@ export function fetchEventLogStats(): Promise<EventLogStats> {
|
||||
return get<EventLogStats>('/api/events/log/stats');
|
||||
}
|
||||
|
||||
export function deleteEvent(id: number): Promise<{ status: string }> {
|
||||
return del<{ status: string }>(`/api/events/log/${id}`);
|
||||
}
|
||||
|
||||
export function clearAllEvents(): Promise<{ status: string; count: number }> {
|
||||
return del<{ status: string; count: number }>('/api/events/log');
|
||||
}
|
||||
|
||||
// ── Stale Containers ────────────────────────────────────────────────
|
||||
|
||||
export function fetchStaleContainers(): Promise<StaleContainer[]> {
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
"tagPatternHelp": "Glob pattern (e.g., dev-*, v*)",
|
||||
"maxInstances": "Max Instances",
|
||||
"autoDeployLabel": "Auto Deploy",
|
||||
"enableProxy": "Enable Proxy",
|
||||
"npmProxy": "NPM Proxy",
|
||||
"creating": "Creating...",
|
||||
"createStage": "Create Stage",
|
||||
@@ -658,6 +659,11 @@
|
||||
"noEventsDesc": "Events will appear here as they occur.",
|
||||
"loadMore": "Load more",
|
||||
"newEvents": "new events",
|
||||
"clearAll": "Clear All",
|
||||
"clearAllTitle": "Clear Event Log",
|
||||
"clearAllMessage": "This will permanently delete all event log entries. This cannot be undone.",
|
||||
"cleared": "Cleared {count} events",
|
||||
"clearFailed": "Failed to clear events",
|
||||
"filter": {
|
||||
"severity": "Severity",
|
||||
"source": "Source",
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
"tagPatternHelp": "Glob-шаблон (напр., dev-*, v*)",
|
||||
"maxInstances": "Макс. экземпляров",
|
||||
"autoDeployLabel": "Авто-деплой",
|
||||
"enableProxy": "Включить прокси",
|
||||
"npmProxy": "NPM прокси",
|
||||
"creating": "Создание...",
|
||||
"createStage": "Создать стадию",
|
||||
@@ -658,6 +659,11 @@
|
||||
"noEventsDesc": "События будут отображаться здесь по мере их возникновения.",
|
||||
"loadMore": "Загрузить ещё",
|
||||
"newEvents": "новых событий",
|
||||
"clearAll": "Очистить всё",
|
||||
"clearAllTitle": "Очистить журнал событий",
|
||||
"clearAllMessage": "Все записи журнала событий будут удалены безвозвратно.",
|
||||
"cleared": "Удалено {count} событий",
|
||||
"clearFailed": "Не удалось очистить события",
|
||||
"filter": {
|
||||
"severity": "Уровень",
|
||||
"source": "Источник",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { inspectImage, quickDeploy, listRegistries, listRegistryImages, deployInstance } from '$lib/api';
|
||||
import type { InspectResult, EntityPickerItem, Project } from '$lib/types';
|
||||
import FormField from '$lib/components/FormField.svelte';
|
||||
import ToggleSwitch from '$lib/components/ToggleSwitch.svelte';
|
||||
import EntityPicker from '$lib/components/EntityPicker.svelte';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import { toasts } from '$lib/stores/toast';
|
||||
@@ -20,6 +21,7 @@
|
||||
let stage = $state('dev');
|
||||
let subdomain = $state('');
|
||||
let envVars = $state('');
|
||||
let enableProxy = $state(true);
|
||||
|
||||
let errors = $state<Record<string, string>>({});
|
||||
|
||||
@@ -140,7 +142,7 @@
|
||||
if (!validateAll()) return;
|
||||
deploying = true;
|
||||
try {
|
||||
const result = await quickDeploy({ image: imageUrl.trim(), name: projectName.trim(), port: parseInt(port, 10), force });
|
||||
const result = await quickDeploy({ image: imageUrl.trim(), name: projectName.trim(), port: parseInt(port, 10), force, enable_proxy: enableProxy });
|
||||
toasts.success($t('quickDeploy.deployedSuccess', { name: projectName }));
|
||||
// Redirect to the new project page.
|
||||
if (result.project?.id) {
|
||||
@@ -288,6 +290,11 @@
|
||||
<div class="mt-4">
|
||||
<FormField label={$t('quickDeploy.envVars')} name="envVars" type="textarea" bind:value={envVars} placeholder={"KEY=value\nANOTHER_KEY=another_value"} helpText={$t('quickDeploy.envVarsHelp')} />
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center gap-3">
|
||||
<ToggleSwitch bind:checked={enableProxy} label={$t('projectDetail.enableProxy')} />
|
||||
<span class="text-sm text-[var(--text-secondary)]">{$t('projectDetail.enableProxy')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 -->
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { t } from '$lib/i18n';
|
||||
import { fetchEventLog, fetchEventLogStats } from '$lib/api';
|
||||
import { fetchEventLog, fetchEventLogStats, clearAllEvents } from '$lib/api';
|
||||
import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
|
||||
import { toasts } from '$lib/stores/toast';
|
||||
import { connectGlobalEvents, type SSEConnection, type EventLogSSEPayload } from '$lib/sse';
|
||||
import type { EventLogEntry, EventLogStats } from '$lib/types';
|
||||
import EventLogEntryComponent from '$lib/components/EventLogEntry.svelte';
|
||||
@@ -35,6 +37,7 @@
|
||||
|
||||
let sseConnection: SSEConnection | null = null;
|
||||
let listEl: HTMLDivElement | undefined = $state();
|
||||
let showClearConfirm = $state(false);
|
||||
|
||||
// ── Date range to ISO string ─────────────────────────────────
|
||||
|
||||
@@ -212,9 +215,18 @@
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-2xl font-bold text-[var(--text-primary)]">{$t('events.title')}</h1>
|
||||
{#if stats.total > 0}
|
||||
<span class="text-xs text-[var(--text-tertiary)] tabular-nums">{stats.total} total</span>
|
||||
{/if}
|
||||
<div class="flex items-center gap-3">
|
||||
{#if stats.total > 0}
|
||||
<span class="text-xs text-[var(--text-tertiary)] tabular-nums">{stats.total} total</span>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => { showClearConfirm = true; }}
|
||||
class="rounded-lg border border-[var(--border-primary)] px-3 py-1.5 text-xs font-medium text-[var(--text-secondary)] hover:bg-[var(--surface-card-hover)] hover:text-[var(--color-danger)] transition-colors"
|
||||
>
|
||||
{$t('events.clearAll')}
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter bar (includes severity stats as pill counts) -->
|
||||
@@ -285,3 +297,24 @@
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<ConfirmDialog
|
||||
open={showClearConfirm}
|
||||
title={$t('events.clearAllTitle')}
|
||||
message={$t('events.clearAllMessage')}
|
||||
confirmLabel={$t('events.clearAll')}
|
||||
confirmVariant="danger"
|
||||
onconfirm={async () => {
|
||||
showClearConfirm = false;
|
||||
try {
|
||||
const result = await clearAllEvents();
|
||||
toasts.success($t('events.cleared', { count: String(result.count) }));
|
||||
events = [];
|
||||
stats = { info: 0, warn: 0, error: 0, total: 0 };
|
||||
offset = 0;
|
||||
} catch (err) {
|
||||
toasts.error(err instanceof Error ? err.message : $t('events.clearFailed'));
|
||||
}
|
||||
}}
|
||||
oncancel={() => { showClearConfirm = false; }}
|
||||
/>
|
||||
|
||||
@@ -349,9 +349,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<label class="text-sm font-medium text-[var(--text-primary)]">{$t('projectDetail.npmProxy')}</label>
|
||||
<label class="text-sm font-medium text-[var(--text-primary)]">{$t('projectDetail.enableProxy')}</label>
|
||||
<div class="flex items-center h-[38px]">
|
||||
<ToggleSwitch bind:checked={stageEnableProxy} label={$t('projectDetail.npmProxy')} />
|
||||
<ToggleSwitch bind:checked={stageEnableProxy} label={$t('projectDetail.enableProxy')} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user