diff --git a/pkg/miniapp/miniapp.go b/pkg/miniapp/miniapp.go
index e7b3b2437..515c1a5ae 100644
--- a/pkg/miniapp/miniapp.go
+++ b/pkg/miniapp/miniapp.go
@@ -575,6 +575,15 @@ func (h *Handler) apiDev(w http.ResponseWriter, r *http.Request) {
writeJSON(w, map[string]any{"error": err.Error()})
return
}
+ case "unregister":
+ if req.ID == "" {
+ writeJSON(w, map[string]any{"error": "id is required"})
+ return
+ }
+ if err := h.UnregisterDevTarget(req.ID); err != nil {
+ writeJSON(w, map[string]any{"error": err.Error()})
+ return
+ }
default:
writeJSON(w, map[string]any{"error": "unknown action"})
return
diff --git a/pkg/miniapp/static/index.html b/pkg/miniapp/static/index.html
index ec8c62837..583b38efe 100644
--- a/pkg/miniapp/static/index.html
+++ b/pkg/miniapp/static/index.html
@@ -684,6 +684,26 @@
text-overflow: ellipsis;
white-space: nowrap;
}
+ .dev-target-delete {
+ flex-shrink: 0;
+ width: 24px;
+ height: 24px;
+ padding: 6px;
+ margin: -6px;
+ margin-left: 8px;
+ border-radius: 50%;
+ color: var(--hint);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: color 0.15s, background 0.15s;
+ -webkit-tap-highlight-color: transparent;
+ }
+ .dev-target-delete:active {
+ color: #ff3b30;
+ background: rgba(255, 59, 48, 0.1);
+ }
@@ -1346,12 +1366,23 @@ function renderDevFromData(data) {
'' +
'' + escapeHtml(t.name) + '' +
'' + escapeHtml(displayUrl) + '' +
+ '×' +
'';
}).join('');
}
// Delegate click on target cards
document.getElementById('dev-targets-list').addEventListener('click', function(e) {
+ var delBtn = e.target.closest('.dev-target-delete');
+ if (delBtn) {
+ e.stopPropagation();
+ var id = delBtn.dataset.delId;
+ var name = delBtn.dataset.delName;
+ if (confirm('Remove "' + name + '"?')) {
+ postDevUnregister(id);
+ }
+ return;
+ }
var card = e.target.closest('[data-dev-id]');
if (!card) return;
postDevAction(card.dataset.devId);
@@ -1372,6 +1403,18 @@ async function postDevAction(id) {
} catch(e) {}
}
+async function postDevUnregister(id) {
+ try {
+ var res = await fetch(API_BASE + '/miniapp/api/dev?initData=' + encodeURIComponent(initData), {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ action: 'unregister', id: id }),
+ });
+ var data = await res.json();
+ if (!data.error) renderDevFromData(data);
+ } catch(e) {}
+}
+
function loadDev() {
apiFetch('/miniapp/api/dev').then(renderDevFromData).catch(function() {});
}