diff --git a/.attic/container-new.png b/.attic/container-new.png new file mode 100644 index 00000000..dd251717 Binary files /dev/null and b/.attic/container-new.png differ diff --git a/.attic/group-new.png b/.attic/group-new.png new file mode 100644 index 00000000..92f7af3c Binary files /dev/null and b/.attic/group-new.png differ diff --git a/.attic/nodeimport.png b/.attic/nodeimport.png new file mode 100644 index 00000000..db51bf58 Binary files /dev/null and b/.attic/nodeimport.png differ diff --git a/.gitignore b/.gitignore index 37d7e734..45adf944 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules .env +.tmp-verify/ diff --git a/create-a-container/client/.gitignore b/create-a-container/client/.gitignore new file mode 100644 index 00000000..f523d209 --- /dev/null +++ b/create-a-container/client/.gitignore @@ -0,0 +1,8 @@ +node_modules +dist +dist-ssr +*.local +.vite +*.log +.DS_Store +*.tsbuildinfo diff --git a/create-a-container/client/README.md b/create-a-container/client/README.md new file mode 100644 index 00000000..6296fa2f --- /dev/null +++ b/create-a-container/client/README.md @@ -0,0 +1,23 @@ +# Manager Client + +Vite + React 19 + TypeScript SPA for the Create-a-Container manager. Styles via Tailwind 4 and `@mieweb/ui` (BlueHive brand). + +## Develop + +```bash +npm install +npm run dev # http://localhost:5173 (proxies /api/* to Express; other routes are SPA-handled) +``` + +Express must be running on `http://localhost:3000` (or set `VITE_API_TARGET`). + +## Build + +```bash +npm run build # outputs to dist/, served by Express in production +``` + +## Layout + +- `src/app/` — router, layouts, shell +- `src/styles/` — Tailwind + `@mieweb/ui` brand entry diff --git a/create-a-container/client/index.html b/create-a-container/client/index.html new file mode 100644 index 00000000..31fb436c --- /dev/null +++ b/create-a-container/client/index.html @@ -0,0 +1,14 @@ + + +
+ + + + +{subtitle}
} +{description}
+ )} +
+ {created.key}
+
+
+ + Sign in to your Container Manager account to continue. +
+
+ Protected by push-approved sign-in.{' '}
+
+ We sent a push notification to your registered device. Tap{' '} + Approve to + finish signing in. +
++ No device is enrolled for push 2FA on this account. Contact an administrator to receive + an enrollment invite. +
++ {status.message || `Status: ${status.status}`} +
++ {state.message || + (state.status === 'active' + ? 'Your account is ready. You can sign in.' + : 'Your account is awaiting administrator approval.')} +
++ Scan this QR code with the push-notification app to register your device for 2FA. +
+ {qrLoading && ( +
+ {row.output}
+
+ ))
+ )}
+ <%= apiKey.keyPrefix %>********<%= apiKey.id %>No API keys found. Create one to get started.
-<%= key.keyPrefix %>********
-
- <% if (key.description) { %>
- Description: <%= key.description %>
- <% } %> - -
-
- Created: <%= new Date(key.createdAt).toLocaleDateString() %>
- Last Used: <%= key.lastUsedAt ? new Date(key.lastUsedAt).toLocaleDateString() : 'Never' %>
-
-
| Key Prefix | -Description | -Last Used | -Created | -Actions | -
|---|---|---|---|---|
|
- No API keys found. Create one to get started. - |
- ||||
| - <%= key.keyPrefix %>******** - | -- <% if (key.description) { %> - <%= key.description %> - <% } else { %> - No description - <% } %> - | -- <% if (key.lastUsedAt) { %> - <%= new Date(key.lastUsedAt).toLocaleString() %> - <% } else { %> - Never - <% } %> - | -- <%= new Date(key.createdAt).toLocaleString() %> - | -
-
-
- View
-
-
-
- |
-
<%= apiKey.keyPrefix %>********
- <%= apiKey.id %>
-
- | Hostname | -Status | -IPv4 | -Template | -Node | -SSH Port | -HTTP | -Actions | -
|---|---|---|---|---|---|---|---|
| <%= r.hostname %> | -- <% if (r.status === 'running') { %> - Running - <% } else if (r.status === 'pending') { %> - - - Pending - - <% } else if (r.status === 'creating') { %> - - - Creating - - <% } else if (r.status === 'failed') { %> - Failed - <% } else if (r.status === 'restarting') { %> - - - Restarting - - <% } else { %> - <%= r.status || 'Unknown' %> - <% } %> - <% if (r.creationJobId && (r.status === 'pending' || r.status === 'creating' || r.status === 'failed')) { %> - - Details - - <% } %> - | -<%= r.ipv4Address || '-' %> | -<%= r.template || '-' %> | -- <% if (r.nodeApiUrl && r.containerId) { %> - <%= r.nodeName %> - <% } else { %> - <%= r.nodeName %> - <% } %> - | -- <% if (r.sshPort && r.sshHost) { %> - <%= r.sshPort %> - - - <% } else { %> - <%= r.sshPort || '-' %> - <% } %> - | -
- <% if (r.httpEntries && r.httpEntries.length > 0) { %>
- <% r.httpEntries.forEach((entry, i) => { %>
- <% if (i > 0) { %> <% } %> - <% if (entry.externalUrl) { %> - <%= entry.port %> - <% } else { %> - <%= entry.port %> - <% } %> - <% }) %> - <% } else { %> - - - <% } %> - |
- - <% if (r.status === 'running' || r.status === 'failed') { %> - Edit - - <% } %> - - | -
| - No containers found. Click "New Container" to create your first one. - | -|||||||
| Domain Name | -Default Site | -ACME Email | -ACME Directory | -Cloudflare API Email | -Actions | -
|---|---|---|---|---|---|
| <%= domain.name %> | -<%= domain.defaultSite || '-' %> | -<%= domain.acmeEmail || '-' %> | -<%= domain.acmeDirectoryUrl || '-' %> | -<%= domain.cloudflareApiEmail || '-' %> | -- Edit - - | -
| - No external domains found. Click "New External Domain" to create your first one. - | -|||||
Permanently delete this group
-| GID | -Name | -Admin Group | -User Count | -Actions | -
|---|---|---|---|---|
| No groups found | -||||
| <%= row.gidNumber %> | -<%= row.cn %> | -- <% if (row.isAdmin) { %> - Yes - <% } else { %> - No - <% } %> - | -<%= row.userCount %> | -- Edit - - | -
Command:
-<%= job.command %>
- Created:
- <%= new Date(job.createdAt).toLocaleString() %> -Created By:
- <%= job.createdBy || 'System' %> -