Update static/js/03-admin.js
This commit is contained in:
parent
c0a58bbde8
commit
86b0a7a5ab
@ -6,7 +6,7 @@ window.Glow = window.Glow || {};
|
||||
Glow.closeAdminPanel = () => {
|
||||
Glow.els.adminPanel.classList.remove("open");
|
||||
Glow.els.adminPanel.setAttribute("aria-hidden", "true");
|
||||
Glow.els.adminFab.focus();
|
||||
Glow.els.adminFab?.focus();
|
||||
};
|
||||
|
||||
Glow.setAdminTab = tab => {
|
||||
@ -29,16 +29,12 @@ Glow.setAdminTab = tab => {
|
||||
Glow.els.adminTeamsPanel?.classList.toggle("hidden", !isTeams);
|
||||
};
|
||||
|
||||
Glow.buildAdminRow = ({
|
||||
title,
|
||||
subtitle,
|
||||
actions = [],
|
||||
className = ""
|
||||
}) => {
|
||||
Glow.buildAdminRow = ({ title, subtitle, actions = [], className = "" }) => {
|
||||
const row = document.createElement("div");
|
||||
row.className = className || "admin-room";
|
||||
|
||||
const details = document.createElement("div");
|
||||
|
||||
const name = document.createElement("div");
|
||||
name.className =
|
||||
className.includes("user")
|
||||
@ -79,13 +75,13 @@ Glow.renderAdminUsers = users => {
|
||||
Glow.els.adminUsers.replaceChildren();
|
||||
|
||||
const heading = document.createElement("h3");
|
||||
heading.textContent = "Users";
|
||||
heading.textContent = "users";
|
||||
Glow.els.adminUsers.append(heading);
|
||||
|
||||
if (!users.length) {
|
||||
const empty = document.createElement("p");
|
||||
empty.className = "admin-empty";
|
||||
empty.textContent = "No users found.";
|
||||
empty.textContent = "no users found.";
|
||||
Glow.els.adminUsers.append(empty);
|
||||
return;
|
||||
}
|
||||
@ -102,7 +98,7 @@ Glow.renderAdminUsers = users => {
|
||||
role.className = "small-button";
|
||||
role.type = "button";
|
||||
role.textContent =
|
||||
user.role === "moderator" ? "Make user" : "Make moderator";
|
||||
user.role === "moderator" ? "make user" : "make moderator";
|
||||
role.addEventListener("click", () => {
|
||||
Glow.updateAdminUser(user.id, {
|
||||
role: user.role === "moderator" ? "user" : "moderator"
|
||||
@ -113,7 +109,7 @@ Glow.renderAdminUsers = users => {
|
||||
restrict.className = "small-button";
|
||||
restrict.type = "button";
|
||||
restrict.textContent =
|
||||
user.status === "restricted" ? "Unrestrict" : "Restrict";
|
||||
user.status === "restricted" ? "unrestrict" : "restrict";
|
||||
restrict.addEventListener("click", () => {
|
||||
Glow.toggleRestriction(user);
|
||||
});
|
||||
@ -122,7 +118,7 @@ Glow.renderAdminUsers = users => {
|
||||
blacklist.className = "small-button danger";
|
||||
blacklist.type = "button";
|
||||
blacklist.textContent =
|
||||
user.status === "blacklisted" ? "Unblacklist" : "Blacklist";
|
||||
user.status === "blacklisted" ? "unblacklist" : "blacklist";
|
||||
blacklist.addEventListener("click", () => {
|
||||
Glow.toggleBlacklist(user);
|
||||
});
|
||||
@ -132,11 +128,11 @@ Glow.renderAdminUsers = users => {
|
||||
|
||||
Glow.els.adminUsers.append(
|
||||
Glow.buildAdminRow({
|
||||
title: `${user.username} · ${user.role}`,
|
||||
title: `${user.username} · ${user.role}`,
|
||||
subtitle:
|
||||
`${user.status} · ${user.message_count} message(s)` +
|
||||
`${user.status} · ${user.message_count} message(s)` +
|
||||
(user.restricted_until
|
||||
? ` · until ${new Date(user.restricted_until).toLocaleString()}`
|
||||
? ` · until ${new Date(user.restricted_until).toLocaleString()}`
|
||||
: ""),
|
||||
actions,
|
||||
className: "admin-user"
|
||||
@ -149,13 +145,13 @@ Glow.renderAdminRooms = rooms => {
|
||||
Glow.els.adminRooms.replaceChildren();
|
||||
|
||||
const heading = document.createElement("h3");
|
||||
heading.textContent = "Rooms";
|
||||
heading.textContent = "rooms";
|
||||
Glow.els.adminRooms.append(heading);
|
||||
|
||||
if (!rooms.length) {
|
||||
const empty = document.createElement("p");
|
||||
empty.className = "admin-empty";
|
||||
empty.textContent = "No rooms found.";
|
||||
empty.textContent = "no rooms found.";
|
||||
Glow.els.adminRooms.append(empty);
|
||||
return;
|
||||
}
|
||||
@ -167,7 +163,7 @@ Glow.renderAdminRooms = rooms => {
|
||||
const edit = document.createElement("button");
|
||||
edit.className = "small-button";
|
||||
edit.type = "button";
|
||||
edit.textContent = "Edit";
|
||||
edit.textContent = "edit";
|
||||
edit.addEventListener("click", () => Glow.editRoom(room));
|
||||
actions.push(edit);
|
||||
|
||||
@ -175,7 +171,7 @@ Glow.renderAdminRooms = rooms => {
|
||||
const members = document.createElement("button");
|
||||
members.className = "small-button";
|
||||
members.type = "button";
|
||||
members.textContent = "Members";
|
||||
members.textContent = "members";
|
||||
members.addEventListener("click", () => {
|
||||
Glow.manageRoomMembers(room);
|
||||
});
|
||||
@ -183,7 +179,7 @@ Glow.renderAdminRooms = rooms => {
|
||||
const invite = document.createElement("button");
|
||||
invite.className = "small-button";
|
||||
invite.type = "button";
|
||||
invite.textContent = "Invite link";
|
||||
invite.textContent = "invite link";
|
||||
invite.addEventListener("click", () => {
|
||||
Glow.createInviteLink(room);
|
||||
});
|
||||
@ -195,7 +191,7 @@ Glow.renderAdminRooms = rooms => {
|
||||
const remove = document.createElement("button");
|
||||
remove.className = "small-button danger";
|
||||
remove.type = "button";
|
||||
remove.textContent = "Delete";
|
||||
remove.textContent = "delete";
|
||||
remove.addEventListener("click", () => Glow.deleteRoom(room));
|
||||
actions.push(remove);
|
||||
}
|
||||
@ -203,10 +199,8 @@ Glow.renderAdminRooms = rooms => {
|
||||
|
||||
Glow.els.adminRooms.append(
|
||||
Glow.buildAdminRow({
|
||||
title: `${room.name} · ${room.visibility}`,
|
||||
subtitle:
|
||||
`/${room.slug}` +
|
||||
(room.description ? ` · ${room.description}` : ""),
|
||||
title: `${room.name} · ${room.visibility}`,
|
||||
subtitle: `/${room.slug}` + (room.description ? ` · ${room.description}` : ""),
|
||||
actions,
|
||||
className: "admin-room"
|
||||
})
|
||||
@ -220,7 +214,7 @@ Glow.renderAdminTeamsChannels = () => {
|
||||
box.replaceChildren();
|
||||
|
||||
const heading = document.createElement("h3");
|
||||
heading.textContent = "Teams / channels";
|
||||
heading.textContent = "teams / channels";
|
||||
box.append(heading);
|
||||
|
||||
const team = Glow.state.activeTeam;
|
||||
@ -229,7 +223,7 @@ Glow.renderAdminTeamsChannels = () => {
|
||||
if (!team) {
|
||||
const empty = document.createElement("p");
|
||||
empty.className = "admin-empty";
|
||||
empty.textContent = "Select a team to manage team/channel actions.";
|
||||
empty.textContent = "select a team to manage team or channel actions.";
|
||||
box.append(empty);
|
||||
return;
|
||||
}
|
||||
@ -239,25 +233,25 @@ Glow.renderAdminTeamsChannels = () => {
|
||||
const editTeam = document.createElement("button");
|
||||
editTeam.className = "small-button";
|
||||
editTeam.type = "button";
|
||||
editTeam.textContent = "Edit team";
|
||||
editTeam.textContent = "edit team";
|
||||
editTeam.addEventListener("click", () => Glow.openEditTeamDialog?.(team));
|
||||
|
||||
const members = document.createElement("button");
|
||||
members.className = "small-button";
|
||||
members.type = "button";
|
||||
members.textContent = "Members";
|
||||
members.textContent = "members";
|
||||
members.addEventListener("click", () => Glow.manageTeamMembers?.(team));
|
||||
|
||||
const invite = document.createElement("button");
|
||||
invite.className = "small-button";
|
||||
invite.type = "button";
|
||||
invite.textContent = "Invite";
|
||||
invite.textContent = "invite";
|
||||
invite.addEventListener("click", () => Glow.createTeamInviteLink?.(team));
|
||||
|
||||
const addChannel = document.createElement("button");
|
||||
addChannel.className = "small-button";
|
||||
addChannel.type = "button";
|
||||
addChannel.textContent = "Add channel";
|
||||
addChannel.textContent = "add channel";
|
||||
addChannel.addEventListener("click", () => Glow.openCreateChannelDialog?.(team));
|
||||
|
||||
teamActions.push(editTeam, members, invite, addChannel);
|
||||
@ -273,11 +267,10 @@ Glow.renderAdminTeamsChannels = () => {
|
||||
);
|
||||
|
||||
const channels = Array.isArray(Glow.state.channels) ? Glow.state.channels : [];
|
||||
|
||||
if (!channels.length) {
|
||||
const empty = document.createElement("p");
|
||||
empty.className = "admin-empty";
|
||||
empty.textContent = "No channels available for this team.";
|
||||
empty.textContent = "no channels available for this team.";
|
||||
box.append(empty);
|
||||
return;
|
||||
}
|
||||
@ -290,7 +283,7 @@ Glow.renderAdminTeamsChannels = () => {
|
||||
const edit = document.createElement("button");
|
||||
edit.className = "small-button";
|
||||
edit.type = "button";
|
||||
edit.textContent = "Edit";
|
||||
edit.textContent = "edit";
|
||||
edit.addEventListener("click", () => {
|
||||
Glow.openEditChannelDialog?.(team, item);
|
||||
});
|
||||
@ -300,7 +293,7 @@ Glow.renderAdminTeamsChannels = () => {
|
||||
const remove = document.createElement("button");
|
||||
remove.className = "small-button danger";
|
||||
remove.type = "button";
|
||||
remove.textContent = "Delete";
|
||||
remove.textContent = "delete";
|
||||
remove.addEventListener("click", async () => {
|
||||
const previous = Glow.state.activeChannel;
|
||||
Glow.state.activeChannel = item;
|
||||
@ -313,7 +306,7 @@ Glow.renderAdminTeamsChannels = () => {
|
||||
|
||||
box.append(
|
||||
Glow.buildAdminRow({
|
||||
title: `${isActive ? "• " : ""}# ${item.name}`,
|
||||
title: `${isActive ? "• " : ""}# ${item.name}`,
|
||||
subtitle: item.description || `/${item.slug}`,
|
||||
actions,
|
||||
className: "admin-team-row"
|
||||
@ -329,13 +322,13 @@ Glow.openAdminPanel = async () => {
|
||||
Glow.els.adminPanel.setAttribute("aria-hidden", "false");
|
||||
|
||||
if (Glow.els.adminUsers) {
|
||||
Glow.els.adminUsers.textContent = "Loading users…";
|
||||
Glow.els.adminUsers.textContent = "loading users…";
|
||||
}
|
||||
if (Glow.els.adminRooms) {
|
||||
Glow.els.adminRooms.textContent = "Loading rooms…";
|
||||
Glow.els.adminRooms.textContent = "loading rooms…";
|
||||
}
|
||||
if (Glow.els.adminTeamsChannels) {
|
||||
Glow.els.adminTeamsChannels.textContent = "Loading teams/channels…";
|
||||
Glow.els.adminTeamsChannels.textContent = "loading teams/channels…";
|
||||
}
|
||||
|
||||
try {
|
||||
@ -347,127 +340,14 @@ Glow.openAdminPanel = async () => {
|
||||
Glow.renderAdminUsers(usersData.users || []);
|
||||
Glow.renderAdminRooms(roomsData.rooms || []);
|
||||
Glow.renderAdminTeamsChannels();
|
||||
|
||||
Glow.setAdminTab(Glow.state.adminTab || "rooms");
|
||||
|
||||
setTimeout(() => Glow.els.closeAdminButton.focus(), 0);
|
||||
setTimeout(() => Glow.els.closeAdminButton?.focus(), 0);
|
||||
} catch (error) {
|
||||
Glow.showToast(error.message, "error");
|
||||
Glow.showToast(error.message || "could not load moderation data.", "error");
|
||||
}
|
||||
};
|
||||
|
||||
Glow.updateThemeButton = () => {
|
||||
if (!Glow.els.themeButton) return;
|
||||
Glow.els.themeButton.textContent = "Accent color";
|
||||
};
|
||||
|
||||
Glow.updateAdminPreferenceButtons = () => {};
|
||||
|
||||
Glow.openAccentColorPicker = async () => {
|
||||
const container = document.createElement("div");
|
||||
container.className = "accent-picker";
|
||||
|
||||
const description = document.createElement("p");
|
||||
description.className = "accent-picker-description";
|
||||
description.textContent =
|
||||
"Choose an accent color for focus rings, buttons, selected controls, and highlighted mentions. It is stored only in this browser unless saved in account settings.";
|
||||
|
||||
const label = document.createElement("label");
|
||||
label.className = "accent-picker-label";
|
||||
label.textContent = "Accent color";
|
||||
|
||||
const row = document.createElement("div");
|
||||
row.className = "accent-picker-row";
|
||||
|
||||
const colorInput = document.createElement("input");
|
||||
colorInput.className = "accent-color-input";
|
||||
colorInput.type = "color";
|
||||
colorInput.value =
|
||||
Glow.normalizeAccentColor(Glow.state.accentColor) ||
|
||||
Glow.DEFAULT_ACCENT_COLOR;
|
||||
colorInput.setAttribute("aria-label", "Choose accent color");
|
||||
|
||||
const hexInput = document.createElement("input");
|
||||
hexInput.className = "field accent-hex-input";
|
||||
hexInput.type = "text";
|
||||
hexInput.value = colorInput.value;
|
||||
hexInput.maxLength = 7;
|
||||
hexInput.autocomplete = "off";
|
||||
hexInput.autocapitalize = "off";
|
||||
hexInput.spellcheck = false;
|
||||
hexInput.placeholder = "#f7dce8";
|
||||
hexInput.setAttribute(
|
||||
"aria-label",
|
||||
"Accent color hexadecimal value"
|
||||
);
|
||||
|
||||
const preview = document.createElement("span");
|
||||
preview.className = "accent-preview";
|
||||
preview.style.background = colorInput.value;
|
||||
preview.setAttribute("aria-hidden", "true");
|
||||
|
||||
const error = document.createElement("div");
|
||||
error.className = "accent-picker-error";
|
||||
error.setAttribute("role", "status");
|
||||
|
||||
const updatePreview = value => {
|
||||
const normalized = Glow.normalizeAccentColor(value);
|
||||
|
||||
if (!normalized) {
|
||||
preview.style.background = "transparent";
|
||||
error.textContent =
|
||||
"Use a six-digit hex color, such as #7dd3fc.";
|
||||
return false;
|
||||
}
|
||||
|
||||
preview.style.background = normalized;
|
||||
error.textContent = "";
|
||||
|
||||
if (colorInput.value !== normalized) {
|
||||
colorInput.value = normalized;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
colorInput.addEventListener("input", () => {
|
||||
const color = Glow.normalizeAccentColor(colorInput.value);
|
||||
if (!color) return;
|
||||
hexInput.value = color;
|
||||
updatePreview(color);
|
||||
});
|
||||
|
||||
hexInput.addEventListener("input", () => {
|
||||
updatePreview(hexInput.value.trim());
|
||||
});
|
||||
|
||||
row.append(colorInput, hexInput, preview);
|
||||
label.append(row);
|
||||
container.append(description, label, error);
|
||||
|
||||
const result = await Glow.openDialog({
|
||||
title: "Accent color",
|
||||
body: container,
|
||||
confirmText: "Save color",
|
||||
cancelText: "Cancel"
|
||||
});
|
||||
|
||||
if (!result) return;
|
||||
|
||||
const accent = Glow.normalizeAccentColor(hexInput.value);
|
||||
|
||||
if (!accent) {
|
||||
Glow.showToast(
|
||||
"Choose a valid six-digit hexadecimal color.",
|
||||
"error"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Glow.applyAccentColor(accent);
|
||||
Glow.showToast("Accent color updated.");
|
||||
};
|
||||
|
||||
Glow.toggleRestriction = async user => {
|
||||
if (user.status === "restricted") {
|
||||
return Glow.updateAdminUser(user.id, {
|
||||
@ -477,14 +357,14 @@ Glow.toggleRestriction = async user => {
|
||||
}
|
||||
|
||||
const values = await Glow.openDialog({
|
||||
title: `Restrict ${user.username}`,
|
||||
body: "Enter the restriction duration in minutes.",
|
||||
confirmText: "Restrict",
|
||||
title: `restrict ${user.username}`,
|
||||
body: "enter the restriction duration in minutes.",
|
||||
confirmText: "restrict",
|
||||
danger: true,
|
||||
fields: [
|
||||
{
|
||||
name: "minutes",
|
||||
label: "Duration in minutes",
|
||||
label: "duration in minutes",
|
||||
type: "number",
|
||||
value: "60",
|
||||
maxLength: 5
|
||||
@ -495,20 +375,14 @@ Glow.toggleRestriction = async user => {
|
||||
if (!values) return;
|
||||
|
||||
const minutes = Number(values.minutes);
|
||||
|
||||
if (!Number.isFinite(minutes) || minutes < 1 || minutes > 43200) {
|
||||
Glow.showToast(
|
||||
"Enter a duration between 1 minute and 30 days.",
|
||||
"error"
|
||||
);
|
||||
Glow.showToast("enter a duration between 1 minute and 30 days.", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
await Glow.updateAdminUser(user.id, {
|
||||
status: "restricted",
|
||||
restricted_until: new Date(
|
||||
Date.now() + minutes * 60 * 1000
|
||||
).toISOString()
|
||||
restricted_until: new Date(Date.now() + minutes * 60 * 1000).toISOString()
|
||||
});
|
||||
};
|
||||
|
||||
@ -517,12 +391,12 @@ Glow.toggleBlacklist = async user => {
|
||||
|
||||
const result = await Glow.openDialog({
|
||||
title: blacklisting
|
||||
? `Blacklist ${user.username}?`
|
||||
: `Unblacklist ${user.username}?`,
|
||||
? `blacklist ${user.username}?`
|
||||
: `unblacklist ${user.username}?`,
|
||||
body: blacklisting
|
||||
? "The account will be denied access immediately."
|
||||
: "The account will be restored to active status.",
|
||||
confirmText: blacklisting ? "Blacklist" : "Unblacklist",
|
||||
? "the account will be denied access immediately."
|
||||
: "the account will be restored to active status.",
|
||||
confirmText: blacklisting ? "blacklist" : "unblacklist",
|
||||
danger: blacklisting
|
||||
});
|
||||
|
||||
@ -541,36 +415,36 @@ Glow.updateAdminUser = async (userId, changes) => {
|
||||
body: JSON.stringify(changes)
|
||||
});
|
||||
|
||||
Glow.showToast("User updated.");
|
||||
Glow.showToast("user updated.");
|
||||
await Glow.openAdminPanel();
|
||||
} catch (error) {
|
||||
Glow.showToast(error.message, "error");
|
||||
Glow.showToast(error.message || "could not update user.", "error");
|
||||
}
|
||||
};
|
||||
|
||||
Glow.createRoom = async () => {
|
||||
const values = await Glow.openDialog({
|
||||
title: "Create room",
|
||||
body: "Choose a room name, description, and visibility.",
|
||||
confirmText: "Create",
|
||||
title: "create room",
|
||||
body: "choose a room name, description, and visibility.",
|
||||
confirmText: "create",
|
||||
fields: [
|
||||
{
|
||||
name: "name",
|
||||
label: "Room name",
|
||||
placeholder: "Project chat",
|
||||
label: "room name",
|
||||
placeholder: "project chat",
|
||||
maxLength: 60
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
label: "Description",
|
||||
placeholder: "Optional room description",
|
||||
label: "description",
|
||||
placeholder: "optional room description",
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
maxLength: 300
|
||||
},
|
||||
{
|
||||
name: "visibility",
|
||||
label: "Visibility: public or private",
|
||||
label: "visibility: public or private",
|
||||
value: "public",
|
||||
maxLength: 7
|
||||
}
|
||||
@ -579,46 +453,41 @@ Glow.createRoom = async () => {
|
||||
|
||||
if (!values) return;
|
||||
|
||||
const visibility = values.visibility.toLowerCase();
|
||||
|
||||
const visibility = String(values.visibility || "").toLowerCase();
|
||||
if (!["public", "private"].includes(visibility)) {
|
||||
Glow.showToast("Visibility must be public or private.", "error");
|
||||
Glow.showToast("visibility must be public or private.", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await Glow.apiRequest("/api/rooms", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
await Glow.apiCreateRoom({
|
||||
name: values.name,
|
||||
description: values.description,
|
||||
visibility
|
||||
})
|
||||
});
|
||||
|
||||
Glow.showToast("Room created.");
|
||||
Glow.showToast("room created.");
|
||||
await Glow.loadRooms();
|
||||
await Glow.openAdminPanel();
|
||||
} catch (error) {
|
||||
Glow.showToast(error.message, "error");
|
||||
Glow.showToast(error.message || "could not create room.", "error");
|
||||
}
|
||||
};
|
||||
|
||||
Glow.editRoom = async room => {
|
||||
const values = await Glow.openDialog({
|
||||
title: `Edit ${room.name}`,
|
||||
confirmText: "Save",
|
||||
title: `edit ${room.name}`,
|
||||
confirmText: "save",
|
||||
fields: [
|
||||
{
|
||||
name: "name",
|
||||
label: "Room name",
|
||||
label: "room name",
|
||||
value: room.name,
|
||||
maxLength: 60
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
label: "Description",
|
||||
label: "description",
|
||||
value: room.description || "",
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
@ -626,7 +495,7 @@ Glow.editRoom = async room => {
|
||||
},
|
||||
{
|
||||
name: "visibility",
|
||||
label: "Visibility: public or private",
|
||||
label: "visibility: public or private",
|
||||
value: room.visibility,
|
||||
maxLength: 7
|
||||
}
|
||||
@ -635,10 +504,9 @@ Glow.editRoom = async room => {
|
||||
|
||||
if (!values) return;
|
||||
|
||||
const visibility = values.visibility.toLowerCase();
|
||||
|
||||
const visibility = String(values.visibility || "").toLowerCase();
|
||||
if (!["public", "private"].includes(visibility)) {
|
||||
Glow.showToast("Visibility must be public or private.", "error");
|
||||
Glow.showToast("visibility must be public or private.", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -651,13 +519,8 @@ Glow.editRoom = async room => {
|
||||
|
||||
Glow.updateRoom = async (slug, changes) => {
|
||||
try {
|
||||
await Glow.apiRequest(`/api/rooms/${encodeURIComponent(slug)}`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(changes)
|
||||
});
|
||||
|
||||
Glow.showToast("Room updated.");
|
||||
await Glow.apiUpdateRoom(slug, changes);
|
||||
Glow.showToast("room updated.");
|
||||
await Glow.loadRooms();
|
||||
|
||||
if (!Glow.state.activeDm) {
|
||||
@ -666,15 +529,15 @@ Glow.updateRoom = async (slug, changes) => {
|
||||
|
||||
await Glow.openAdminPanel();
|
||||
} catch (error) {
|
||||
Glow.showToast(error.message, "error");
|
||||
Glow.showToast(error.message || "could not update room.", "error");
|
||||
}
|
||||
};
|
||||
|
||||
Glow.deleteRoom = async room => {
|
||||
const result = await Glow.openDialog({
|
||||
title: `Delete ${room.name}?`,
|
||||
body: "This permanently deletes the room and every message in it.",
|
||||
confirmText: "Delete room",
|
||||
title: `delete ${room.name}?`,
|
||||
body: "this permanently deletes the room and every message in it.",
|
||||
confirmText: "delete room",
|
||||
danger: true
|
||||
});
|
||||
|
||||
@ -685,7 +548,7 @@ Glow.deleteRoom = async room => {
|
||||
method: "DELETE"
|
||||
});
|
||||
|
||||
Glow.showToast("Room deleted.");
|
||||
Glow.showToast("room deleted.");
|
||||
await Glow.loadRooms();
|
||||
|
||||
if (!Glow.state.activeDm) {
|
||||
@ -694,43 +557,39 @@ Glow.deleteRoom = async room => {
|
||||
|
||||
await Glow.openAdminPanel();
|
||||
} catch (error) {
|
||||
Glow.showToast(error.message, "error");
|
||||
Glow.showToast(error.message || "could not delete room.", "error");
|
||||
}
|
||||
};
|
||||
|
||||
Glow.clearActiveRoom = async () => {
|
||||
const room = Glow.state.activeRoom;
|
||||
|
||||
if (!room || Glow.state.activeDm) return;
|
||||
|
||||
const result = await Glow.openDialog({
|
||||
title: `Clear ${room.name}?`,
|
||||
body: "All messages in this room will be permanently deleted.",
|
||||
confirmText: "Clear room",
|
||||
title: `clear ${room.name}?`,
|
||||
body: "all messages in this room will be permanently deleted.",
|
||||
confirmText: "clear room",
|
||||
danger: true
|
||||
});
|
||||
|
||||
if (!result) return;
|
||||
|
||||
try {
|
||||
await Glow.apiRequest(
|
||||
`/api/rooms/${encodeURIComponent(room.slug)}/messages`,
|
||||
{ method: "DELETE" }
|
||||
);
|
||||
await Glow.apiRequest(`/api/rooms/${encodeURIComponent(room.slug)}/messages`, {
|
||||
method: "DELETE"
|
||||
});
|
||||
|
||||
Glow.clearMessages();
|
||||
Glow.renderEmptyState();
|
||||
Glow.showToast("Room messages cleared.");
|
||||
Glow.showToast("room messages cleared.");
|
||||
} catch (error) {
|
||||
Glow.showToast(error.message, "error");
|
||||
Glow.showToast(error.message || "could not clear room.", "error");
|
||||
}
|
||||
};
|
||||
|
||||
Glow.manageRoomMembers = async room => {
|
||||
try {
|
||||
const data = await Glow.apiRequest(
|
||||
`/api/rooms/${encodeURIComponent(room.slug)}/members`
|
||||
);
|
||||
const data = await Glow.apiRequest(`/api/rooms/${encodeURIComponent(room.slug)}/members`);
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.className = "member-list";
|
||||
@ -740,12 +599,12 @@ Glow.manageRoomMembers = async room => {
|
||||
row.className = "member-row";
|
||||
|
||||
const name = document.createElement("span");
|
||||
name.textContent = `${member.username} · ${member.membership_role}`;
|
||||
name.textContent = `${member.username} · ${member.membership_role}`;
|
||||
|
||||
const remove = document.createElement("button");
|
||||
remove.className = "small-button danger";
|
||||
remove.type = "button";
|
||||
remove.textContent = "Remove";
|
||||
remove.textContent = "remove";
|
||||
remove.disabled = member.membership_role === "owner";
|
||||
|
||||
remove.addEventListener("click", async () => {
|
||||
@ -754,12 +613,11 @@ Glow.manageRoomMembers = async room => {
|
||||
`/api/rooms/${encodeURIComponent(room.slug)}/members/${member.id}`,
|
||||
{ method: "DELETE" }
|
||||
);
|
||||
|
||||
Glow.showToast("Member removed.");
|
||||
Glow.showToast("member removed.");
|
||||
Glow.closeDialog({});
|
||||
Glow.manageRoomMembers(room);
|
||||
} catch (error) {
|
||||
Glow.showToast(error.message, "error");
|
||||
Glow.showToast(error.message || "could not remove member.", "error");
|
||||
}
|
||||
});
|
||||
|
||||
@ -770,11 +628,11 @@ Glow.manageRoomMembers = async room => {
|
||||
const values = await Glow.openDialog({
|
||||
title: `${room.name} members`,
|
||||
body: container,
|
||||
confirmText: "Add member",
|
||||
confirmText: "add member",
|
||||
fields: [
|
||||
{
|
||||
name: "username",
|
||||
label: "Username to add",
|
||||
label: "username to add",
|
||||
placeholder: "username",
|
||||
maxLength: 30
|
||||
}
|
||||
@ -783,46 +641,37 @@ Glow.manageRoomMembers = async room => {
|
||||
|
||||
if (!values?.username) return;
|
||||
|
||||
await Glow.apiRequest(
|
||||
`/api/rooms/${encodeURIComponent(room.slug)}/members`,
|
||||
{
|
||||
await Glow.apiRequest(`/api/rooms/${encodeURIComponent(room.slug)}/members`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username: values.username })
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Glow.showToast("Member added.");
|
||||
Glow.showToast("member added.");
|
||||
await Glow.manageRoomMembers(room);
|
||||
} catch (error) {
|
||||
Glow.showToast(error.message, "error");
|
||||
Glow.showToast(error.message || "could not manage room members.", "error");
|
||||
}
|
||||
};
|
||||
|
||||
Glow.createInviteLink = async room => {
|
||||
try {
|
||||
const data = await Glow.apiRequest(
|
||||
`/api/rooms/${encodeURIComponent(room.slug)}/invites`,
|
||||
{
|
||||
const data = await Glow.apiRequest(`/api/rooms/${encodeURIComponent(room.slug)}/invites`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({})
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const url = new URL(
|
||||
data.invite.url,
|
||||
window.location.origin
|
||||
).toString();
|
||||
const url = new URL(data.invite.url, window.location.origin).toString();
|
||||
|
||||
const values = await Glow.openDialog({
|
||||
title: "Private-room invite link",
|
||||
body: "Copy and share this link. It can be used once before it expires.",
|
||||
confirmText: "Copy link",
|
||||
title: "private-room invite link",
|
||||
body: "copy and share this link. it can be used once before it expires.",
|
||||
confirmText: "copy link",
|
||||
fields: [
|
||||
{
|
||||
name: "invite",
|
||||
label: "Invite link",
|
||||
label: "invite link",
|
||||
value: url,
|
||||
maxLength: 500
|
||||
}
|
||||
@ -831,10 +680,10 @@ Glow.createInviteLink = async room => {
|
||||
|
||||
if (values) {
|
||||
await navigator.clipboard.writeText(url);
|
||||
Glow.showToast("Invite link copied.");
|
||||
Glow.showToast("invite link copied.");
|
||||
}
|
||||
} catch (error) {
|
||||
Glow.showToast(error.message, "error");
|
||||
Glow.showToast(error.message || "could not create invite link.", "error");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user