feat(remote-ingress): add Remote Ingress hub integration, OpsServer UI, APIs, and docs

This commit is contained in:
2026-02-18 18:47:18 +00:00
parent 86e6c4f600
commit dce1de8c4b
13 changed files with 456 additions and 43 deletions

View File

@@ -176,13 +176,39 @@ export class OpsViewRemoteIngress extends DeesElement {
return html`
<ops-sectionheading>Remote Ingress</ops-sectionheading>
${this.riState.newEdgeSecret ? html`
${this.riState.newEdgeId ? html`
<div class="secretDialog">
<strong>Edge Secret (copy now - shown only once):</strong>
<code>${this.riState.newEdgeSecret}</code>
<div class="warning">This secret will not be shown again. Save it securely.</div>
<strong>Edge created successfully!</strong>
<div class="warning">Copy the connection token now. Use it with edge.start({ token: '...' }).</div>
<dees-button
@click=${() => 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</dees-button>
<dees-button
@click=${() => appstate.remoteIngressStatePart.dispatchAction(appstate.clearNewEdgeIdAction, null)}
>Dismiss</dees-button>
</div>
` : ''}
@@ -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 });