feat(cutover): hard legacy cutover — drop projects/stacks/sites/deploys
Build / build (push) Successful in 10m39s
Build / build (push) Successful in 10m39s
The clean-break delete that closes the workload-first refactor arc.
Net diff: ~30 backend files deleted, ~20 modified, ~12k LOC removed
on the Go side; entire /projects /stacks /sites /deploy frontend
trees gone; ~6.7k LOC removed on the Svelte/TypeScript side.
Backend
- API handlers gone: internal/api/{projects,stages,stage_env,stacks,
static_sites,deploys,instances,volume_browser}.go
- Store CRUD + tests gone: internal/store/{projects,stages,stage_env,
stacks,static_sites,static_site_secrets,deploys,poll_state,volumes,
workload_sync}.go (+ _test.go siblings)
- Legacy deployer pipeline gone: internal/deployer/{bluegreen,promote,
rollback,subdomain,resolver_test}.go; deployer.go trimmed to just the
dispatch surface used by the plugin pipeline
- internal/staticsite/{manager,healthcheck}.go and
internal/stack/manager.go gone (the rest of those packages stay as
helpers imported by the static + compose plugins)
- internal/registry/poller.go gone (legacy registry poller)
- internal/volume.ResolvePath gone; ResolveWorkloadPath stays
- internal/webhook: handleWebhook (project) + handleSiteWebhook (site)
gone; only POST /api/webhook/triggers/{secret} remains
- workload-side webhook URL handlers (getWorkloadWebhook +
regenerateWorkloadWebhook + EnsureWorkloadWebhookSecret +
SetWorkloadWebhookSecret + GetWorkloadByWebhookSecret) gone — they
minted URLs that would 404 against the new trigger-only ingress
- cmd/server/main.go: dropped staticsite.Manager, stack.Manager,
staticsite.HealthChecker, registry poller, SetSiteSyncTriggerer,
SetStaticSiteManager, SetStackManager, wireStaticBackend
- store/store.go: idempotent DROP TABLE IF EXISTS for every legacy
table (projects, stages, stage_env, volumes, deploys, deploy_logs,
poll_states, stacks, stack_revisions, stack_deploys, static_sites,
static_site_secrets); FK order children-then-parents
- store/models.go: dropped Project, Stage, Deploy, DeployLog, StageEnv,
Volume, StaticSite, StaticSiteSecret, Stack, StackRevision,
StackDeploy types; kept WorkloadKind constants as documented strings
- internal/store/helpers.go (new): BoolToInt, rowScanner,
GenerateWebhookSecret extracted from deleted CRUD files
- internal/api/secrets.go (new): forwards to store.GenerateWebhookSecret
so api + store paths share one secret-generation impl (no
panic-vs-UUID-fallback divergence)
- internal/reconciler/reconciler.go: dropped legacy stack-by-compose
+ static-site label paths; only canonical tinyforge.workload.id
dispatch remains
- providers (gitea_content/github_provider/gitlab_provider) gained
path-traversal rejection on every tree entry
- internal/webhook ParsedImage / ParseImageRef demoted to package-
private (no external callers)
Frontend
- /projects /stacks /sites /deploy routes deleted (entire trees)
- ProjectCard / InstanceCard / StaleContainerCard components deleted
- api.ts: dropped every project/stage/stack/site/deploy/instance
helper + types (Project, Stage, Stack, StaticSite, Deploy,
Instance, Volume, etc.); kept Workload, Container, App, Settings,
Registry, EventTrigger, LogScanRule, webhook envelopes
- WorkloadWebhook type + getWorkloadWebhook/regenerateWorkloadWebhook
api functions gone (mirror of the backend deletion above)
- web/src/routes/+layout.svelte: dropped /projects /sites /stacks
/deploy nav entries, trimmed quick-nav keymap
- web/src/routes/+page.svelte: dashboard rewrite — reads
listWorkloads + listContainers only; 4-card stat grid
(workloads/running/failed/stale) + recent workloads strip
- navCounts.ts, SystemHealthCard.svelte, ContainerLogs.svelte,
ContainerStats.svelte, StatusBadge.svelte, TagCombobox.svelte,
proxies/+page.svelte, containers/+page.svelte all rewired to the
workload-first surface
- AbortController plumbing on dashboard, nav-counts, stale page,
SystemHealthCard so navigation doesn't leave dangling fetches
- i18n: dropped projects.*, projectDetail.*, envEditor.*,
volumeEditor.*, volumeBrowser.*, quickDeploy.*, sites.*, stacks.*,
instance.*, confirm.* namespaces; en/ru parity preserved (1042
keys each)
Hardening from go-reviewer + security-reviewer + typescript-reviewer
subagent passes (0 CRITICAL across all three; 1 HIGH + ~12 MEDIUM
addressed inline before commit):
- Sec H1: dead-end workload webhook URL handlers (would mint URLs
that 404 the new trigger-only ingress) deleted across backend +
frontend
- Go M1: IsTerminalDeployStatus dropped (no production callers)
- Go M2: ParsedImage/ParseImageRef lowercased (in-package only)
- Go M6: generateWebhookSecret unified — api shim forwards to
store.GenerateWebhookSecret
- Doc/comment freshness: stage_id (no longer FK), ProxyRoute legacy
field names, workloadIDRow rationale, webhook_deliveries.target_type
enum, WebhookDeliveryLog component header
Doc
- WORKLOAD_REFACTOR_TODO: cutover marked DONE; all three Priority 1
items are now shipped. Next focus is Priority 3 polish (apps.* i18n
+ codemap entries) and Priority 4 tests.
Behavioral notes for operators upgrading from a pre-cutover build
- Existing rows in the dropped tables disappear on first boot.
- Legacy webhook URLs at /api/webhook/{secret} and
/api/webhook/sites/{secret} return 404; CI configs must repoint to
/api/webhook/triggers/{secret} (the trigger-split boot backfill
lifted any embedded workload secret onto a Trigger row, so the
secret value itself carries over).
- Frontend routes /projects /stacks /sites /deploy are gone; nav
links replaced with /apps and /triggers.
This commit is contained in:
+30
-576
@@ -18,38 +18,27 @@
|
||||
"eventTriggers": "Triggers",
|
||||
"logScanRules": "Log Rules",
|
||||
"triggers": "Triggers",
|
||||
"projects": "Projects",
|
||||
"deploy": "Deploy",
|
||||
"proxies": "Proxies",
|
||||
"events": "Events",
|
||||
"settings": "Settings",
|
||||
"logout": "Log out",
|
||||
"dns": "DNS Records",
|
||||
"sites": "Sites",
|
||||
"stacks": "Stacks",
|
||||
"containers": "Containers"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
"quickDeploy": "Quick Deploy",
|
||||
"totalProjects": "Total Projects",
|
||||
"runningInstances": "Running Instances",
|
||||
"failedInstances": "Failed Instances",
|
||||
"projects": "Projects",
|
||||
"newApp": "New app",
|
||||
"totalWorkloads": "Total Workloads",
|
||||
"runningContainers": "Running Containers",
|
||||
"failedContainers": "Failed Containers",
|
||||
"recentWorkloads": "Recent Workloads",
|
||||
"retry": "Retry",
|
||||
"noProjects": "No projects yet.",
|
||||
"addFirst": "Add your first project",
|
||||
"noWorkloads": "No workloads yet.",
|
||||
"noWorkloadsDesc": "Create an app and forge your first workload to get started.",
|
||||
"loadFailed": "Failed to load dashboard",
|
||||
"staleContainers": "Stale Containers",
|
||||
"unusedImagesWarning": "Unused Docker images are taking up disk space",
|
||||
"unusedImages": "unused images",
|
||||
"staticSites": "Static Sites",
|
||||
"totalSites": "Total Sites",
|
||||
"deployedSites": "deployed",
|
||||
"failedSites": "failed",
|
||||
"noSites": "No static sites yet.",
|
||||
"addFirstSite": "Deploy your first site",
|
||||
"viewAllSites": "View all sites",
|
||||
"systemHealth": "System health",
|
||||
"daemons": "Daemons",
|
||||
"systemResources": "System resources",
|
||||
@@ -92,240 +81,9 @@
|
||||
"retentionLabel": "Stats retention (hours)",
|
||||
"retentionHelp": "How long resource samples are kept. 0 disables collection. Range: 0–24h."
|
||||
},
|
||||
"projects": {
|
||||
"title": "Projects",
|
||||
"addProject": "Add Project",
|
||||
"cancel": "Cancel",
|
||||
"newProject": "New Project",
|
||||
"name": "Name",
|
||||
"image": "Image",
|
||||
"port": "Port",
|
||||
"tagPicker": {
|
||||
"registry": "Registry",
|
||||
"created": "Created",
|
||||
"view": "View",
|
||||
"noProjects": "No projects configured yet.",
|
||||
"getStarted": "Click \"Add Project\" to get started.",
|
||||
"createProject": "Create Project",
|
||||
"creating": "Creating...",
|
||||
"healthcheck": "Healthcheck Path",
|
||||
"nameRequired": "Name and image are required.",
|
||||
"loadFailed": "Failed to load projects",
|
||||
"createFailed": "Failed to create project",
|
||||
"browseImages": "Browse Images",
|
||||
"selectImage": "Select an image",
|
||||
"noImages": "No images found",
|
||||
"loadingImages": "Loading images...",
|
||||
"imageLoadFailed": "Failed to load images",
|
||||
"alreadyAdded": "Already added",
|
||||
"portHelpText": "Auto-detected from EXPOSE if empty",
|
||||
"healthcheckHelpText": "Auto-detected from image if empty",
|
||||
"searchPlaceholder": "Search projects by name, image, or registry...",
|
||||
"noMatchingProjects": "No projects match your search."
|
||||
},
|
||||
"projectDetail": {
|
||||
"webhookTitle": "Project webhook",
|
||||
"webhookDesc": "POST an image reference to this URL from your CI pipeline to trigger a deploy. Stage routing uses each stage's tag pattern.",
|
||||
"outgoingWebhookTitle": "Outgoing webhook (project)",
|
||||
"outgoingWebhookDesc": "Where Tinyforge posts deploy events for this project. Stages can override; if none set, inherits from global settings.",
|
||||
"outgoingFallbackGlobal": "the global integrations setting",
|
||||
"notificationUrlLabel": "Outgoing webhook URL",
|
||||
"notificationUrlHelp": "Leave empty to inherit from global settings. Stages can override per-stage.",
|
||||
"stageNotificationUrlLabel": "Outgoing webhook URL (this stage)",
|
||||
"stageNotificationUrlHelp": "Leave empty to inherit from the project, then global settings.",
|
||||
"stageOutgoingTitle": "Outgoing webhook (stage)",
|
||||
"stageOutgoingDesc": "Where Tinyforge posts deploy events for this stage. Most-specific tier wins.",
|
||||
"stageFallbackLabel": "the project or global settings",
|
||||
"deleteProject": "Delete Project",
|
||||
"envVars": "Environment Variables",
|
||||
"volumes": "Volume Mounts",
|
||||
"stages": "Stages",
|
||||
"noStages": "No stages configured for this project.",
|
||||
"pattern": "Pattern",
|
||||
"autoDeploy": "auto-deploy",
|
||||
"requiresConfirm": "requires confirm",
|
||||
"instances": "instances",
|
||||
"deployNewVersion": "Deploy new version",
|
||||
"selectTag": "Select tag to deploy",
|
||||
"loadingTags": "Loading tags...",
|
||||
"chooseTag": "Choose a tag...",
|
||||
"enterTag": "Enter image tag (e.g., dev-abc123)",
|
||||
"registryTag": "Registry",
|
||||
"localTag": "Local",
|
||||
"alsoLocal": "Also available locally",
|
||||
"searchTags": "Search tags...",
|
||||
"deployTag": "Tag",
|
||||
"deploy": "Deploy",
|
||||
"deploying": "Deploying...",
|
||||
"recentDeploys": "Recent Deploys",
|
||||
"noDeployHistory": "No deploy history for this project.",
|
||||
"tag": "Tag",
|
||||
"status": "Status",
|
||||
"started": "Started",
|
||||
"finished": "Finished",
|
||||
"error": "Error",
|
||||
"noInstancesRunning": "No instances running",
|
||||
"deleteConfirmTitle": "Delete Project",
|
||||
"deleteConfirmMessage": "This will permanently delete the project '{name}' and all its stages, instances, and deploy history. This cannot be undone.",
|
||||
"loadFailed": "Failed to load project",
|
||||
"deleteFailed": "Failed to delete project",
|
||||
"deployFailed": "Deploy failed",
|
||||
"nameLabel": "Name *",
|
||||
"imageLabel": "Image *",
|
||||
"portLabel": "Port",
|
||||
"healthcheckLabel": "Healthcheck Path",
|
||||
"saving": "Saving...",
|
||||
"addStage": "Add Stage",
|
||||
"tagPattern": "Tag Pattern",
|
||||
"tagPatternHelp": "Glob pattern (e.g., dev-*, v*)",
|
||||
"maxInstances": "Max Instances",
|
||||
"autoDeployLabel": "Auto Deploy",
|
||||
"enableProxy": "Enable Proxy",
|
||||
"accessListId": "NPM Access List ID",
|
||||
"accessListIdHelp": "Override the global access list for this project. Clear to inherit from NPM settings.",
|
||||
"localImages": "Local Docker Images",
|
||||
"imageTag": "Tag",
|
||||
"imageId": "Image ID",
|
||||
"imageSize": "Size",
|
||||
"imageCreated": "Created",
|
||||
"cpuLimit": "CPU Limit (cores)",
|
||||
"cpuLimitHelp": "e.g., 0.5, 1, 2. Leave 0 for unlimited",
|
||||
"memoryLimit": "Memory Limit (MB)",
|
||||
"memoryLimitHelp": "e.g., 256, 512, 1024. Leave 0 for unlimited",
|
||||
"npmProxy": "NPM Proxy",
|
||||
"creating": "Creating...",
|
||||
"createStage": "Create Stage",
|
||||
"noProxy": "No Proxy",
|
||||
"deleteStage": "Delete stage",
|
||||
"deleteStageConfirm": "Delete stage \"{name}\"?",
|
||||
"stageCreated": "Stage \"{name}\" created",
|
||||
"stageUpdated": "Stage updated",
|
||||
"stageUpdateFailed": "Failed to update stage",
|
||||
"stageDeleted": "Stage \"{name}\" deleted",
|
||||
"projectUpdated": "Project updated",
|
||||
"updateFailed": "Failed to update project",
|
||||
"stageCreateFailed": "Failed to create stage",
|
||||
"stageDeleteFailed": "Failed to delete stage"
|
||||
},
|
||||
"envEditor": {
|
||||
"title": "Environment Variables",
|
||||
"description": "Manage per-stage environment variable overrides. Stage-level values override project-level defaults.",
|
||||
"stage": "Stage",
|
||||
"projectDefaults": "Project-Level Defaults",
|
||||
"noProjectEnv": "No project-level environment variables defined yet.",
|
||||
"stageOverrides": "Stage Overrides",
|
||||
"key": "Key",
|
||||
"value": "Value",
|
||||
"secret": "Secret",
|
||||
"source": "Source",
|
||||
"actions": "Actions",
|
||||
"overridden": "overridden",
|
||||
"inherited": "inherited",
|
||||
"overridesProject": "overrides project",
|
||||
"stageOnly": "stage only",
|
||||
"edit": "Edit",
|
||||
"change": "Change",
|
||||
"delete": "Delete",
|
||||
"save": "Save",
|
||||
"add": "Add",
|
||||
"adding": "Adding...",
|
||||
"noStages": "No stages configured. Add stages to the project first.",
|
||||
"loadFailed": "Failed to load project",
|
||||
"envAdded": "Environment variable added",
|
||||
"envUpdated": "Environment variable updated",
|
||||
"envDeleted": "Environment variable deleted",
|
||||
"addFailed": "Failed to add env var",
|
||||
"updateFailed": "Failed to update env var",
|
||||
"deleteFailed": "Failed to delete env var",
|
||||
"loadEnvFailed": "Failed to load env vars",
|
||||
"leaveEmptyToKeep": "Leave empty to keep current",
|
||||
"deleteTitle": "Delete Environment Variable",
|
||||
"deleteMessage": "Are you sure you want to delete this environment variable? This action cannot be undone."
|
||||
},
|
||||
"volumeEditor": {
|
||||
"title": "Volume Mounts",
|
||||
"description": "Configure volume mounts for containers. Choose a scope to control how volumes are shared between deploys.",
|
||||
"sourceHost": "Source (Host)",
|
||||
"targetContainer": "Target (Container)",
|
||||
"scope": "Scope",
|
||||
"nameColumn": "Name",
|
||||
"namePlaceholder": "e.g. shared-db",
|
||||
"requiresName": "requires name",
|
||||
"noHostPath": "no host path",
|
||||
"tmpfs": "tmpfs (in-memory)",
|
||||
"actions": "Actions",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"save": "Save",
|
||||
"add": "Add",
|
||||
"adding": "Adding...",
|
||||
"scopeGuide": "Volume Scopes",
|
||||
"noVolumes": "No volumes configured yet. Add one above.",
|
||||
"volumeAdded": "Volume added",
|
||||
"volumeUpdated": "Volume updated",
|
||||
"volumeDeleted": "Volume deleted",
|
||||
"loadFailed": "Failed to load volumes",
|
||||
"addFailed": "Failed to add volume",
|
||||
"updateFailed": "Failed to update volume",
|
||||
"deleteFailed": "Failed to delete volume"
|
||||
},
|
||||
"volumeBrowser": {
|
||||
"title": "Volume Browser",
|
||||
"loadFailed": "Failed to load directory",
|
||||
"empty": "This directory is empty.",
|
||||
"name": "Name",
|
||||
"size": "Size",
|
||||
"modified": "Modified",
|
||||
"downloadAll": "Download volume as ZIP",
|
||||
"downloadFolder": "Download folder as ZIP",
|
||||
"upload": "Upload files",
|
||||
"uploaded": "Uploaded",
|
||||
"files": "file(s)",
|
||||
"uploadFailed": "Failed to upload files",
|
||||
"browse": "Browse",
|
||||
"download": "Download"
|
||||
},
|
||||
"quickDeploy": {
|
||||
"title": "Quick Deploy",
|
||||
"description": "Deploy a container image with zero configuration. Paste an image URL, review the defaults, and deploy.",
|
||||
"step1": "1. Enter Image URL",
|
||||
"imageUrl": "Image URL",
|
||||
"imageUrlHelp": "Full image URL including tag (e.g., git.example.com/user/app:dev-abc123)",
|
||||
"inspect": "Inspect",
|
||||
"inspecting": "Inspecting...",
|
||||
"step2": "2. Review Configuration",
|
||||
"reviewDesc": "These defaults were detected from the image. Adjust as needed before deploying.",
|
||||
"projectName": "Project Name",
|
||||
"port": "Port",
|
||||
"portHelp": "Container port to expose (1-65535)",
|
||||
"healthCheckPath": "Health Check Path",
|
||||
"healthCheckHelp": "Optional HTTP path for health verification",
|
||||
"stage": "Stage",
|
||||
"development": "Development",
|
||||
"release": "Release",
|
||||
"production": "Production",
|
||||
"stageHelp": "Deployment stage for this image",
|
||||
"subdomainOverride": "Subdomain Override",
|
||||
"subdomainHelp": "Leave empty to use the default subdomain pattern",
|
||||
"envVars": "Environment Variables",
|
||||
"envVarsHelp": "One per line, KEY=VALUE format",
|
||||
"step3": "3. Deploy",
|
||||
"deployDesc": "A new project will be created and the container will be deployed immediately.",
|
||||
"deployBtn": "Deploy",
|
||||
"inspectedSuccess": "Image inspected successfully",
|
||||
"deployedSuccess": "Deployed {name} successfully!",
|
||||
"inspectFailed": "Failed to inspect image",
|
||||
"deployFailed": "Deployment failed",
|
||||
"browseImages": "Browse",
|
||||
"selectImage": "Select an image from a registry",
|
||||
"noImages": "No images found",
|
||||
"loadingImages": "Loading...",
|
||||
"imageLoadFailed": "Failed to load images",
|
||||
"autoDeployLabel": "Deploy immediately",
|
||||
"lowercaseHint": "Lowercase with hyphens",
|
||||
"imageAlreadyExists": "Image already deployed",
|
||||
"conflictDescription": "A project using this image already exists. You can open the existing project to deploy a new version, or create a separate project.",
|
||||
"openProject": "Open project \u2192",
|
||||
"createNewAnyway": "Create New Project"
|
||||
"local": "Local"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Settings",
|
||||
@@ -489,7 +247,7 @@
|
||||
"testing": "Testing...",
|
||||
"testSuccess": "NPM connection successful",
|
||||
"testFailed": "NPM connection failed",
|
||||
"saveFailedConnection": "Cannot save \u2014 connection test failed",
|
||||
"saveFailedConnection": "Cannot save — connection test failed",
|
||||
"remoteMode": "Remote NPM",
|
||||
"remoteModeHelp": "Enable when NPM runs on a different machine than Docker. Forwards to Server IP with published host ports.",
|
||||
"remoteModeWarning": "Requires Server IP in General settings. Ports are auto-mapped to random host ports.",
|
||||
@@ -613,117 +371,28 @@
|
||||
"networkError": "Network error"
|
||||
},
|
||||
"proxies": {
|
||||
"title": "Proxy Manager",
|
||||
"create": "Create Proxy",
|
||||
"standalone": "Standalone Proxies",
|
||||
"managed": "Managed Proxies",
|
||||
"noProxies": "No proxies found",
|
||||
"noProxiesDesc": "Create a standalone proxy or deploy a project with proxy enabled.",
|
||||
"filter": {
|
||||
"search": "Search by domain or destination...",
|
||||
"health": "Health",
|
||||
"type": "Type",
|
||||
"all": "All",
|
||||
"clear": "Clear filters"
|
||||
},
|
||||
"health": {
|
||||
"healthy": "Healthy",
|
||||
"unhealthy": "Unhealthy",
|
||||
"unknown": "Unknown"
|
||||
},
|
||||
"lastChecked": "Last checked"
|
||||
},
|
||||
"sites": {
|
||||
"webhookTitle": "Site webhook",
|
||||
"webhookDesc": "Point your Git provider's push webhook at this URL. Tinyforge will re-sync the site on matching refs (branch for push trigger, tag pattern for tag trigger). Send an empty body for an unconditional sync.",
|
||||
"outgoingUrlTitle": "Outgoing webhook URL (this site)",
|
||||
"outgoingUrlDesc": "Where Tinyforge posts site_sync_success / site_sync_failure events for this site. Empty falls through to global settings.",
|
||||
"outgoingWebhookTitle": "Outgoing webhook (site)",
|
||||
"outgoingWebhookDesc": "HMAC signing secret and test sender for the resolved outgoing URL.",
|
||||
"outgoingFallbackGlobal": "the global integrations setting",
|
||||
"title": "Static Sites",
|
||||
"addSite": "New Site",
|
||||
"newSite": "New Static Site",
|
||||
"createSite": "Create Site",
|
||||
"noSites": "No static sites",
|
||||
"noSitesDesc": "Deploy static content from a Git repository folder.",
|
||||
"searchPlaceholder": "Search sites by name, domain, or repo...",
|
||||
"noMatching": "No sites match your search.",
|
||||
"name": "Name",
|
||||
"title": "Proxy Routes",
|
||||
"description": "Active proxy routes from deployed containers and static sites.",
|
||||
"domain": "Domain",
|
||||
"mode": "Mode",
|
||||
"project": "Project / Site",
|
||||
"stage": "Stage / Mode",
|
||||
"tag": "Tag",
|
||||
"port": "Port",
|
||||
"status": "Status",
|
||||
"lastSync": "Last Sync",
|
||||
"deploy": "Deploy",
|
||||
"stop": "Stop",
|
||||
"start": "Start",
|
||||
"openSite": "Open Site",
|
||||
"confirmDelete": "Delete Site",
|
||||
"confirmDeleteMsg": "This will permanently delete the site and remove its container",
|
||||
"confirmDeleteSecret": "Delete Secret",
|
||||
"confirmDeleteSecretMsg": "Are you sure you want to delete secret",
|
||||
"siteInfo": "Site Information",
|
||||
"folder": "Folder",
|
||||
"syncTrigger": "Sync Trigger",
|
||||
"commitSha": "Commit SHA",
|
||||
"secrets": "Secrets",
|
||||
"addSecret": "Add Secret",
|
||||
"noSecrets": "No secrets configured. Add secrets if your site needs server-side API keys.",
|
||||
"secretKey": "Key",
|
||||
"secretValue": "Value",
|
||||
"encryptSecret": "Encrypt value",
|
||||
"saveSecret": "Add Secret",
|
||||
"step1Title": "1. Repository",
|
||||
"step2Title": "2. Select Branch",
|
||||
"step3Title": "3. Select Folder",
|
||||
"step4Title": "4. Configuration",
|
||||
"step5Title": "5. Review & Create",
|
||||
"fullRepoUrl": "Repository URL",
|
||||
"fullRepoUrlHelp": "Paste a full URL to auto-fill the fields below (e.g., https://git.example.com/owner/repo)",
|
||||
"serverUrl": "Server URL",
|
||||
"repoUrl": "Git Server URL",
|
||||
"repoUrlHelp": "Paste a full repo URL or enter the server base URL (Gitea, Forgejo, Gogs)",
|
||||
"repoOwner": "Owner",
|
||||
"repoName": "Repository",
|
||||
"accessToken": "Access Token",
|
||||
"accessTokenPlaceholder": "Optional — for private repos",
|
||||
"accessTokenHelp": "Personal access token with repo read permissions. Leave empty for public repos.",
|
||||
"noToken": "None (public repo)",
|
||||
"testConnection": "Test Connection",
|
||||
"connectionSuccess": "Repository is accessible",
|
||||
"loadingBranches": "Loading branches...",
|
||||
"selectBranch": "Select a branch",
|
||||
"chooseBranch": "Choose a branch...",
|
||||
"branch": "Branch",
|
||||
"loadingTree": "Loading repository tree...",
|
||||
"selectFolder": "Select the folder containing your site files",
|
||||
"selectedFolder": "Selected folder",
|
||||
"siteName": "Site Name",
|
||||
"domainHelp": "Public domain for the site. Proxy will be configured automatically.",
|
||||
"modeStaticDesc": "HTML, CSS, JS, images served via Nginx",
|
||||
"modeDenoDesc": "Static files + server-side API from api/ folder",
|
||||
"triggerManual": "Manual",
|
||||
"triggerPush": "On Push",
|
||||
"triggerTag": "On Tag",
|
||||
"tagPattern": "Tag Pattern",
|
||||
"tagPatternHelp": "Glob pattern for matching tags (e.g., v*, pages-*)",
|
||||
"renderMarkdown": "Render Markdown files to HTML",
|
||||
"provider": "Git Provider",
|
||||
"detectedProvider": "Auto-detected",
|
||||
"browseRepos": "Browse repositories",
|
||||
"selectRepo": "Select a repository",
|
||||
"storage": "Persistent Storage",
|
||||
"enableStorage": "Enable persistent storage",
|
||||
"storageHelp": "Mounts a Docker volume at /app/data for your Deno backend to read and write files that persist across deployments.",
|
||||
"storageLimitMB": "Storage Limit (MB)",
|
||||
"storageLimitHelp": "Maximum storage size in megabytes. 0 = unlimited.",
|
||||
"storageVolume": "Volume",
|
||||
"dataPath": "Data Path",
|
||||
"storageMountPath": "Mount Path",
|
||||
"storageLimit": "Limit",
|
||||
"storageUsed": "Used",
|
||||
"storageOfLimit": "of limit used",
|
||||
"unlimited": "Unlimited"
|
||||
"source": "Source",
|
||||
"sourceContainer": "Container",
|
||||
"sourceStatic": "Static Site",
|
||||
"sourceDeno": "Deno Site",
|
||||
"filterAll": "All",
|
||||
"filterContainers": "Containers",
|
||||
"filterSites": "Sites",
|
||||
"noRoutes": "No proxy routes",
|
||||
"noRoutesDesc": "Proxy routes are created automatically when you deploy a container with proxy enabled or publish a static site.",
|
||||
"searchPlaceholder": "Search by domain, project, or tag...",
|
||||
"noMatch": "No routes match your search.",
|
||||
"loadFailed": "Failed to load proxy routes",
|
||||
"route": "route",
|
||||
"routes": "routes"
|
||||
},
|
||||
"common": {
|
||||
"cancel": "Cancel",
|
||||
@@ -775,24 +444,9 @@
|
||||
"lastSeen": "Last seen"
|
||||
}
|
||||
},
|
||||
"instance": {
|
||||
"stopConfirm": "This will stop the running container. The instance can be started again later.",
|
||||
"restartConfirm": "This will restart the container, causing brief downtime.",
|
||||
"removeConfirm": "This will permanently remove the container and its proxy configuration. This cannot be undone.",
|
||||
"actionFailed": "Action failed"
|
||||
},
|
||||
"empty": {
|
||||
"noProjects": "No projects yet",
|
||||
"noProjectsDesc": "Get started by creating your first project or use Quick Deploy.",
|
||||
"createProject": "Create Project",
|
||||
"noInstances": "No instances",
|
||||
"noInstancesDesc": "Deploy a new version to see instances here.",
|
||||
"noDeploys": "No deploy history",
|
||||
"noDeploysDesc": "Deploy history will appear here after your first deployment.",
|
||||
"noRegistries": "No registries",
|
||||
"noRegistriesDesc": "Add a container registry to enable image detection.",
|
||||
"noVolumes": "No volumes",
|
||||
"noVolumesDesc": "Configure volume mounts for persistent data.",
|
||||
"noUsers": "No users",
|
||||
"noUsersDesc": "Add local users to manage access."
|
||||
},
|
||||
@@ -808,15 +462,6 @@
|
||||
"requiredWhenUpdating": "{field} is required when updating credentials",
|
||||
"requiredForNew": "{field} is required for new registries"
|
||||
},
|
||||
"confirm": {
|
||||
"stopInstance": "Stop Instance",
|
||||
"startInstance": "Start Instance",
|
||||
"restartInstance": "Restart Instance",
|
||||
"removeInstance": "Remove Instance",
|
||||
"stopAction": "Stop",
|
||||
"restartAction": "Restart",
|
||||
"removeAction": "Remove"
|
||||
},
|
||||
"theme": {
|
||||
"light": "Light",
|
||||
"dark": "Dark",
|
||||
@@ -842,75 +487,6 @@
|
||||
"cleanupFailed": "Cleanup failed",
|
||||
"loadFailed": "Failed to load stale containers"
|
||||
},
|
||||
"proxies": {
|
||||
"title": "Proxies",
|
||||
"create": "Create Proxy",
|
||||
"noProxies": "No proxies configured yet.",
|
||||
"noProxiesDesc": "Create a standalone proxy or deploy a project to see proxies here.",
|
||||
"standalone": "Standalone Proxies",
|
||||
"managed": "Managed",
|
||||
"lastChecked": "Last checked",
|
||||
"health": {
|
||||
"healthy": "Healthy",
|
||||
"unhealthy": "Unhealthy",
|
||||
"unknown": "Unknown"
|
||||
},
|
||||
"filter": {
|
||||
"search": "Search proxies...",
|
||||
"health": "Health",
|
||||
"type": "Type",
|
||||
"all": "All",
|
||||
"clear": "Clear filters"
|
||||
},
|
||||
"form": {
|
||||
"title": "Create Proxy",
|
||||
"editTitle": "Edit Proxy",
|
||||
"destination": "Destination URL / IP",
|
||||
"port": "Port",
|
||||
"domain": "Domain",
|
||||
"domainHelp": "The public domain for this proxy.",
|
||||
"validate": "Validate",
|
||||
"validating": "Validating...",
|
||||
"create": "Create Proxy",
|
||||
"save": "Save Changes",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"deleteConfirm": "Delete this proxy? This cannot be undone."
|
||||
},
|
||||
"validation": {
|
||||
"title": "Destination Validation",
|
||||
"syntax": "URL syntax",
|
||||
"dns": "DNS resolution",
|
||||
"tcp": "TCP connection",
|
||||
"http": "HTTP response",
|
||||
"checking": "Checking...",
|
||||
"skipped": "Skipped"
|
||||
}
|
||||
},
|
||||
"proxies": {
|
||||
"title": "Proxy Routes",
|
||||
"description": "Active proxy routes from deployed containers and static sites.",
|
||||
"domain": "Domain",
|
||||
"project": "Project / Site",
|
||||
"stage": "Stage / Mode",
|
||||
"tag": "Tag",
|
||||
"port": "Port",
|
||||
"status": "Status",
|
||||
"source": "Source",
|
||||
"sourceContainer": "Container",
|
||||
"sourceStatic": "Static Site",
|
||||
"sourceDeno": "Deno Site",
|
||||
"filterAll": "All",
|
||||
"filterContainers": "Containers",
|
||||
"filterSites": "Sites",
|
||||
"noRoutes": "No proxy routes",
|
||||
"noRoutesDesc": "Proxy routes are created automatically when you deploy a container with proxy enabled or publish a static site.",
|
||||
"searchPlaceholder": "Search by domain, project, or tag...",
|
||||
"noMatch": "No routes match your search.",
|
||||
"loadFailed": "Failed to load proxy routes",
|
||||
"route": "route",
|
||||
"routes": "routes"
|
||||
},
|
||||
"logs": {
|
||||
"title": "Container Logs",
|
||||
"lines": "lines",
|
||||
@@ -1049,128 +625,6 @@
|
||||
"en": "English",
|
||||
"ru": "Russian"
|
||||
},
|
||||
"stacks": {
|
||||
"eyebrow": "THE FORGE",
|
||||
"title": "Stacks",
|
||||
"lede": "Compose blueprints, forged as <em>atomic units</em>. Spin up services, iterate on revisions, roll back without breaking a sweat.",
|
||||
"newStack": "New stack",
|
||||
"refresh": "Refresh",
|
||||
"total": "Total",
|
||||
"running": "Running",
|
||||
"deploying": "Forging",
|
||||
"failed": "Failed",
|
||||
"stopped": "Cold",
|
||||
"empty": {
|
||||
"title": "The anvil is cold.",
|
||||
"desc": "Upload a docker-compose.yml to forge your first stack."
|
||||
},
|
||||
"card": {
|
||||
"noDescription": "No description",
|
||||
"updated": "Updated",
|
||||
"start": "Start",
|
||||
"stop": "Stop",
|
||||
"delete": "Delete",
|
||||
"open": "Open"
|
||||
},
|
||||
"new": {
|
||||
"eyebrow": "NEW BLUEPRINT",
|
||||
"title": "Forge a new stack.",
|
||||
"lede": "Upload or paste a <code>docker-compose.yml</code>. All services in the blueprint deploy as a single atomic unit.",
|
||||
"back": "Stacks",
|
||||
"name": "Name",
|
||||
"namePlaceholder": "my-app-stack",
|
||||
"nameHint": "Lowercase, hyphenated. Used as the compose project name.",
|
||||
"description": "Description",
|
||||
"descriptionPlaceholder": "What does this stack do?",
|
||||
"composeYaml": "Compose YAML",
|
||||
"required": "required",
|
||||
"optional": "optional",
|
||||
"loadSample": "Load sample",
|
||||
"uploadFile": "Upload file",
|
||||
"dropHere": "Drop a docker-compose.yml here",
|
||||
"dropSub": "or click to browse · or use <strong>Load sample</strong> above",
|
||||
"lines": "{n} lines",
|
||||
"bytes": "{n} bytes",
|
||||
"clear": "Clear",
|
||||
"deployImmediate": "Deploy immediately",
|
||||
"deployHint": "Strike while the iron's hot. If unchecked, the stack is saved cold.",
|
||||
"cancel": "Cancel",
|
||||
"forging": "Forging…",
|
||||
"forgeAndDeploy": "Forge & deploy",
|
||||
"saveBlueprint": "Save blueprint",
|
||||
"errorRequired": "Name and compose YAML are required.",
|
||||
"errorCreate": "Failed to create stack"
|
||||
},
|
||||
"detail": {
|
||||
"manifest": "MANIFEST",
|
||||
"loading": "Loading blueprint…",
|
||||
"composeProject": "COMPOSE PROJECT",
|
||||
"noDescription": "No description",
|
||||
"refresh": "Refresh",
|
||||
"start": "Start",
|
||||
"stop": "Stop",
|
||||
"delete": "Delete",
|
||||
"fault": "FAULT",
|
||||
"err": "ERR",
|
||||
"stats": {
|
||||
"services": "Services",
|
||||
"servicesSub": "in blueprint",
|
||||
"running": "Running",
|
||||
"runningSub": "active containers",
|
||||
"revisions": "Revisions",
|
||||
"revisionsSub": "in history",
|
||||
"current": "Current",
|
||||
"currentSub": "deployed"
|
||||
},
|
||||
"services": {
|
||||
"title": "Services",
|
||||
"count": "{n} on the floor",
|
||||
"empty": "— no containers running —"
|
||||
},
|
||||
"tabs": {
|
||||
"blueprint": "Blueprint",
|
||||
"revisions": "Revisions",
|
||||
"logs": "Logs"
|
||||
},
|
||||
"yaml": {
|
||||
"currentRevision": "Current revision",
|
||||
"edit": "Edit & redeploy",
|
||||
"cancel": "Cancel",
|
||||
"forging": "Forging…",
|
||||
"deployNew": "Deploy new revision"
|
||||
},
|
||||
"revisions": {
|
||||
"current": "CURRENT",
|
||||
"by": "by",
|
||||
"rollback": "← Rollback to this revision",
|
||||
"rollbackTitle": "Rollback to revision?",
|
||||
"rollbackMessage": "Create a new revision from rev {n} and redeploy the stack.",
|
||||
"rollbackConfirm": "Rollback"
|
||||
},
|
||||
"logs": {
|
||||
"service": "Service:",
|
||||
"allServices": "All services",
|
||||
"fetching": "Fetching…",
|
||||
"fetch": "Fetch logs",
|
||||
"empty": "— no logs loaded. tap fetch. —"
|
||||
},
|
||||
"delete": {
|
||||
"title": "Delete stack?",
|
||||
"messageBase": "This runs 'docker compose down' and removes \"{name}\".",
|
||||
"messageVolumes": " Named volumes will also be removed.",
|
||||
"confirm": "Delete"
|
||||
},
|
||||
"errors": {
|
||||
"load": "Failed to load stack",
|
||||
"stop": "Stop failed",
|
||||
"start": "Start failed",
|
||||
"update": "Update failed",
|
||||
"rollback": "Rollback failed",
|
||||
"delete": "Delete failed",
|
||||
"fetchLogs": "Failed to load logs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"timezone": {
|
||||
"eyebrow": "The Forge // Chronograph",
|
||||
"title": "Display timezone",
|
||||
|
||||
Reference in New Issue
Block a user