added way to delete channels

This commit is contained in:
peterino2 2026-02-03 20:41:17 -08:00
parent a90a9f0a0d
commit 4ae6004239
4 changed files with 67 additions and 10 deletions

9
db.ts
View File

@ -386,16 +386,21 @@ export function deleteChannelFromDb(id: string): void {
// Queue persistence functions
export function saveChannelQueue(channelId: string, trackIds: string[]): void {
// Delete existing queue
db.query("BEGIN").run();
try {
db.query("DELETE FROM channel_queue WHERE channel_id = ?").run(channelId);
// Insert new queue
const insert = db.query(
"INSERT INTO channel_queue (channel_id, track_id, position) VALUES (?, ?, ?)"
);
for (let i = 0; i < trackIds.length; i++) {
insert.run(channelId, trackIds[i], i);
}
db.query("COMMIT").run();
} catch (e) {
db.query("ROLLBACK").run();
throw e;
}
}
export function loadChannelQueue(channelId: string): string[] {

View File

@ -50,6 +50,28 @@
}
};
// Delete a channel
M.deleteChannel = async function(channelId) {
const channel = M.channels?.find(c => c.id === channelId);
if (!channel) return;
if (channel.isDefault) {
M.showToast("Cannot delete default channel");
return;
}
if (!confirm(`Delete channel "${channel.name}"?`)) return;
try {
const res = await fetch(`/api/channels/${channelId}`, { method: "DELETE" });
if (!res.ok) {
const err = await res.json();
M.showToast(err.error || "Failed to delete channel");
return;
}
M.showToast(`Channel "${channel.name}" deleted`);
} catch (e) {
M.showToast("Failed to delete channel");
}
};
// New channel creation with slideout input
M.createNewChannel = async function() {
const header = M.$("#channels-panel .panel-header");
@ -129,14 +151,29 @@
const listenersHtml = Object.entries(counts).map(([name, count]) =>
`<div class="listener">${name}${count > 1 ? ` <span class="listener-mult">x${count}</span>` : ""}</div>`
).join("");
// Show delete button for non-default channels if user is admin or creator
const canDelete = !ch.isDefault && M.currentUser &&
(M.currentUser.isAdmin || ch.createdBy === M.currentUser.id);
const deleteBtn = canDelete ? `<button class="btn-delete-channel" title="Delete channel">×</button>` : "";
div.innerHTML = `
<div class="channel-header">
<span class="channel-name">${ch.name}</span>
${deleteBtn}
<span class="listener-count">${ch.listenerCount}</span>
</div>
<div class="channel-listeners">${listenersHtml}</div>
`;
div.querySelector(".channel-header").onclick = () => M.switchChannel(ch.id);
const headerEl = div.querySelector(".channel-header");
headerEl.querySelector(".channel-name").onclick = () => M.switchChannel(ch.id);
const delBtn = headerEl.querySelector(".btn-delete-channel");
if (delBtn) {
delBtn.onclick = (e) => {
e.stopPropagation();
M.deleteChannel(ch.id);
};
}
container.appendChild(div);
}
};

View File

@ -29,6 +29,9 @@ h3 { font-size: 0.8rem; color: #666; margin-bottom: 0.3rem; text-transform: uppe
#channels-list .channel-header:hover { background: #222; }
#channels-list .channel-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.8rem; }
#channels-list .listener-count { font-size: 0.65rem; color: #666; flex-shrink: 0; margin-left: 0.3rem; }
#channels-list .btn-delete-channel { background: none; border: none; color: #666; font-size: 0.9rem; cursor: pointer; padding: 0 0.2rem; line-height: 1; opacity: 0; transition: opacity 0.15s; }
#channels-list .channel-header:hover .btn-delete-channel { opacity: 1; }
#channels-list .btn-delete-channel:hover { color: #e44; }
#channels-list .channel-listeners { display: flex; flex-direction: column; margin-left: 0.5rem; border-left: 1px solid #333; padding-left: 0.3rem; }
#channels-list .listener { font-size: 0.65rem; color: #aaa; padding: 0.05rem 0; position: relative; }
#channels-list .listener::before { content: ""; position: absolute; left: -0.3rem; top: 50%; width: 0.2rem; height: 1px; background: #333; }

View File

@ -475,6 +475,18 @@ serve({
if (!user.is_admin && channel.createdBy !== user.id) {
return Response.json({ error: "Access denied" }, { status: 403 });
}
// Move connected clients to default channel before deleting
const defaultChannel = [...channels.values()].find(c => c.isDefault);
if (defaultChannel && channel.clients.size > 0) {
for (const ws of channel.clients) {
channel.removeClient(ws);
ws.data.channelId = defaultChannel.id;
defaultChannel.addClient(ws);
ws.send(JSON.stringify({ type: "switched", channelId: defaultChannel.id }));
}
}
channels.delete(channelId);
deleteChannelFromDb(channelId);
broadcastChannelList();