-
Edge Secret (copy now - shown only once):
-
${this.riState.newEdgeSecret}
-
This secret will not be shown again. Save it securely.
+
Edge created successfully!
+
Copy the connection token now. Use it with edge.start({ token: '...' }).
appstate.remoteIngressStatePart.dispatchAction(appstate.clearNewEdgeSecretAction, null)}
+ @click=${async () => {
+ const { DeesToast } = await import('@design.estate/dees-catalog');
+ try {
+ const response = await appstate.fetchConnectionToken(this.riState.newEdgeId);
+ if (response.success && response.token) {
+ if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
+ await navigator.clipboard.writeText(response.token);
+ } else {
+ const textarea = document.createElement('textarea');
+ textarea.value = response.token;
+ textarea.style.position = 'fixed';
+ textarea.style.opacity = '0';
+ document.body.appendChild(textarea);
+ textarea.select();
+ document.execCommand('copy');
+ document.body.removeChild(textarea);
+ }
+ DeesToast.show({ message: 'Connection token copied!', type: 'success', duration: 3000 });
+ } else {
+ DeesToast.show({ message: response.message || 'Failed to get token', type: 'error', duration: 4000 });
+ }
+ } catch (err) {
+ DeesToast.show({ message: `Failed: ${err.message}`, type: 'error', duration: 4000 });
+ }
+ }}
+ >Copy Connection Token
+
appstate.remoteIngressStatePart.dispatchAction(appstate.clearNewEdgeIdAction, null)}
>Dismiss
` : ''}
@@ -348,7 +374,7 @@ export class OpsViewRemoteIngress extends DeesElement {
},
{
name: 'Copy Token',
- iconName: 'lucide:clipboard-copy',
+ iconName: 'lucide:ClipboardCopy',
type: ['inRow', 'contextmenu'] as any,
actionFunc: async (actionData: any) => {
const edge = actionData.item as interfaces.data.IRemoteIngress;
@@ -356,7 +382,19 @@ export class OpsViewRemoteIngress extends DeesElement {
try {
const response = await appstate.fetchConnectionToken(edge.id);
if (response.success && response.token) {
- await navigator.clipboard.writeText(response.token);
+ // Use clipboard API with fallback for non-HTTPS contexts
+ if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
+ await navigator.clipboard.writeText(response.token);
+ } else {
+ const textarea = document.createElement('textarea');
+ textarea.value = response.token;
+ textarea.style.position = 'fixed';
+ textarea.style.opacity = '0';
+ document.body.appendChild(textarea);
+ textarea.select();
+ document.execCommand('copy');
+ document.body.removeChild(textarea);
+ }
DeesToast.show({ message: `Connection token copied for ${edge.name}`, type: 'success', duration: 3000 });
} else {
DeesToast.show({ message: response.message || 'Failed to get token', type: 'error', duration: 4000 });
diff --git a/ts_web/readme.md b/ts_web/readme.md
index 6efeaa7..5468740 100644
--- a/ts_web/readme.md
+++ b/ts_web/readme.md
@@ -40,6 +40,15 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
- Expiry date monitoring and alerts
- Per-domain backoff status for failed provisions
- One-click reprovisioning per domain
+- Certificate import, export, and deletion
+
+### 🌍 Remote Ingress Management
+- Edge node registration with name, ports, and tags
+- Real-time connection status (connected/disconnected/disabled)
+- Public IP and active tunnel count per edge
+- Auto-derived port display with manual/derived breakdown
+- **Connection token generation** — one-click "Copy Token" for easy edge provisioning
+- Enable/disable, edit, secret regeneration, and delete actions
### 📜 Log Viewer
- Real-time log streaming
@@ -85,6 +94,7 @@ ts_web/
├── ops-view-network.ts # Network monitoring
├── ops-view-emails.ts # Email queue management
├── ops-view-certificates.ts # Certificate overview & reprovisioning
+ ├── ops-view-remoteingress.ts # Remote ingress edge management
├── ops-view-logs.ts # Log viewer
├── ops-view-config.ts # Configuration display
├── ops-view-security.ts # Security dashboard
@@ -106,6 +116,8 @@ The app uses `@push.rocks/smartstate` with multiple state parts:
| `logStatePart` | Soft | Recent logs, streaming status, filters |
| `networkStatePart` | Soft | Connections, IPs, throughput rates |
| `emailOpsStatePart` | Soft | Email queues, bounces, suppression list |
+| `certificateStatePart` | Soft | Certificate list, summary, loading state |
+| `remoteIngressStatePart` | Soft | Edge list, statuses, new edge secret |
### Actions
@@ -128,6 +140,23 @@ fetchSecurityIncidentsAction() // Security events
fetchBounceRecordsAction() // Bounce records
resendEmailAction(emailId) // Re-queue failed email
removeFromSuppressionAction(email) // Remove from suppression list
+
+// Certificates
+fetchCertificateOverviewAction() // All certificates with summary
+reprovisionCertificateAction(domain) // Reprovision a certificate
+deleteCertificateAction(domain) // Delete a certificate
+importCertificateAction(cert) // Import a certificate
+fetchCertificateExport(domain) // Export (standalone function)
+
+// Remote Ingress
+fetchRemoteIngressAction() // Edges + statuses
+createRemoteIngressAction(data) // Create new edge
+updateRemoteIngressAction(data) // Update edge settings
+deleteRemoteIngressAction(id) // Remove edge
+regenerateRemoteIngressSecretAction(id) // New secret
+toggleRemoteIngressAction(id, enabled) // Enable/disable
+clearNewEdgeSecretAction() // Dismiss secret banner
+fetchConnectionToken(edgeId) // Get connection token (standalone function)
```
### Client-Side Routing
@@ -141,6 +170,7 @@ removeFromSuppressionAction(email) // Remove from suppression list
/emails/failed → Failed emails
/emails/security → Security incidents
/certificates → Certificate management
+/remoteingress → Remote ingress edge management
/logs → Log viewer
/configuration → System configuration
/security → Security dashboard