feat: rename Docker Watcher to Tinyforge
Build / build (push) Successful in 12m20s

Rebrand the project as Tinyforge to reflect its evolution from a Docker
container watcher into a self-hosted mini CI/deployment platform.

Rename covers: Go module path, Docker labels, DB/config filenames,
JWT issuer, Dockerfile binary, docker-compose, CI workflows, frontend
i18n, README with static sites docs, and all code comments.
This commit is contained in:
2026-04-12 21:30:23 +03:00
parent 8d2c5a063b
commit 791cd4d6af
68 changed files with 512 additions and 224 deletions
+31 -7
View File
@@ -25,6 +25,29 @@
let logContainer: HTMLDivElement | undefined = $state();
let eventSource: EventSource | null = null;
// Batch incoming SSE log lines to avoid per-line re-renders.
let pendingLines: string[] = [];
let flushTimer: ReturnType<typeof setTimeout> | null = null;
function flushPendingLines() {
flushTimer = null;
if (pendingLines.length === 0) return;
let updated = [...lines, ...pendingLines];
pendingLines = [];
if (updated.length > tailCount * 2) {
updated = updated.slice(-tailCount);
}
lines = updated;
scrollToBottom();
}
function enqueueLine(line: string) {
pendingLines.push(line);
if (!flushTimer) {
flushTimer = setTimeout(flushPendingLines, 150);
}
}
async function loadLogs() {
loading = true;
error = '';
@@ -49,12 +72,7 @@
try {
const data = JSON.parse(e.data);
if (data.line) {
lines = [...lines, data.line];
// Trim to max lines.
if (lines.length > tailCount * 2) {
lines = lines.slice(-tailCount);
}
scrollToBottom();
enqueueLine(data.line);
}
} catch { /* ignore parse errors */ }
};
@@ -69,6 +87,9 @@
eventSource.close();
eventSource = null;
}
// Flush any buffered lines before stopping.
if (flushTimer) { clearTimeout(flushTimer); flushTimer = null; }
flushPendingLines();
following = false;
}
@@ -90,7 +111,10 @@
// Load on mount.
$effect(() => { loadLogs(); });
onDestroy(() => { stopFollowing(); });
onDestroy(() => {
stopFollowing();
if (flushTimer) { clearTimeout(flushTimer); flushTimer = null; }
});
</script>
<div class="rounded-xl border border-[var(--border-primary)] bg-[var(--surface-page)] shadow-lg">
+7 -2
View File
@@ -19,8 +19,11 @@
$effect(() => {
let cancelled = false;
let inflight = false;
async function load() {
if (inflight) return; // Skip if previous request still pending.
inflight = true;
try {
const result = await api.fetchContainerStats(projectId, stageId, instanceId);
if (!cancelled) {
@@ -31,13 +34,15 @@
if (!cancelled) {
error = true;
}
} finally {
inflight = false;
}
}
load();
// Poll every 10 seconds.
const interval = setInterval(load, 10_000);
// Poll every 30 seconds (reduced from 10s to limit concurrent connections).
const interval = setInterval(load, 30_000);
return () => {
cancelled = true;
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Lucide-based SVG icon components for Docker Watcher.
* Lucide-based SVG icon components for Tinyforge.
* Task 2: Inline SVGs from Lucide icon set as Svelte components.
*
* Each icon is a standalone .svelte component accepting size and class props.
+3 -3
View File
@@ -1,6 +1,6 @@
{
"app": {
"name": "Docker Watcher",
"name": "Tinyforge",
"version": "v0.1"
},
"health": {
@@ -508,7 +508,7 @@
"password": "Password"
},
"login": {
"title": "Docker Watcher",
"title": "Tinyforge",
"subtitle": "Sign in to your account",
"username": "Username",
"password": "Password",
@@ -819,7 +819,7 @@
},
"dns": {
"title": "DNS Records",
"description": "View and manage DNS records created by Docker Watcher.",
"description": "View and manage DNS records created by Tinyforge.",
"wildcardActive": "Wildcard DNS Mode Active",
"wildcardActiveDesc": "DNS records are managed externally via wildcard DNS. Disable wildcard DNS in Settings to manage records individually.",
"refresh": "Refresh",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"app": {
"name": "Docker Watcher",
"name": "Tinyforge",
"version": "v0.1"
},
"health": {
@@ -508,7 +508,7 @@
"password": "Пароль"
},
"login": {
"title": "Docker Watcher",
"title": "Tinyforge",
"subtitle": "Войдите в свой аккаунт",
"username": "Имя пользователя",
"password": "Пароль",
@@ -819,7 +819,7 @@
},
"dns": {
"title": "DNS-записи",
"description": "Просмотр и управление DNS-записями, созданными Docker Watcher.",
"description": "Просмотр и управление DNS-записями, созданными Tinyforge.",
"wildcardActive": "Режим Wildcard DNS активен",
"wildcardActiveDesc": "DNS-записи управляются внешне через wildcard DNS. Отключите wildcard DNS в настройках для индивидуального управления записями.",
"refresh": "Обновить",
+1 -1
View File
@@ -1,7 +1,7 @@
/**
* SSE client helper with auto-reconnect and exponential backoff.
*
* Provides type-safe event handling for Docker Watcher's real-time
* Provides type-safe event handling for Tinyforge's real-time
* event streams (deploy logs and instance status changes).
*/
+23
View File
@@ -0,0 +1,23 @@
/**
* Simple pub/sub bus for SSE event_log payloads.
*
* The layout component publishes events from the single global SSE connection.
* Pages (e.g. /events) subscribe without opening a duplicate SSE connection.
*/
import type { EventLogSSEPayload } from '$lib/sse';
type Listener = (payload: EventLogSSEPayload) => void;
const listeners = new Set<Listener>();
export function subscribeEventLog(fn: Listener): () => void {
listeners.add(fn);
return () => { listeners.delete(fn); };
}
export function publishEventLog(payload: EventLogSSEPayload): void {
for (const fn of listeners) {
fn(payload);
}
}