Update static/js/03-admin.js
This commit is contained in:
parent
9e0b24e29a
commit
368fd18aa7
@ -9,6 +9,72 @@ Glow.closeAdminPanel = () => {
|
|||||||
Glow.els.adminFab.focus();
|
Glow.els.adminFab.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Glow.setAdminTab = tab => {
|
||||||
|
Glow.state.adminTab = ["rooms", "users", "teams"].includes(tab) ? tab : "rooms";
|
||||||
|
|
||||||
|
const isRooms = Glow.state.adminTab === "rooms";
|
||||||
|
const isUsers = Glow.state.adminTab === "users";
|
||||||
|
const isTeams = Glow.state.adminTab === "teams";
|
||||||
|
|
||||||
|
Glow.els.adminTabRooms?.classList.toggle("active", isRooms);
|
||||||
|
Glow.els.adminTabUsers?.classList.toggle("active", isUsers);
|
||||||
|
Glow.els.adminTabTeams?.classList.toggle("active", isTeams);
|
||||||
|
|
||||||
|
Glow.els.adminTabRooms?.setAttribute("aria-selected", String(isRooms));
|
||||||
|
Glow.els.adminTabUsers?.setAttribute("aria-selected", String(isUsers));
|
||||||
|
Glow.els.adminTabTeams?.setAttribute("aria-selected", String(isTeams));
|
||||||
|
|
||||||
|
Glow.els.adminRoomsPanel?.classList.toggle("hidden", !isRooms);
|
||||||
|
Glow.els.adminUsersPanel?.classList.toggle("hidden", !isUsers);
|
||||||
|
Glow.els.adminTeamsPanel?.classList.toggle("hidden", !isTeams);
|
||||||
|
};
|
||||||
|
|
||||||
|
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")
|
||||||
|
? "admin-user-name"
|
||||||
|
: className.includes("team")
|
||||||
|
? "admin-team-name"
|
||||||
|
: "admin-room-name";
|
||||||
|
name.textContent = title;
|
||||||
|
|
||||||
|
const info = document.createElement("div");
|
||||||
|
info.className =
|
||||||
|
className.includes("user")
|
||||||
|
? "admin-user-info"
|
||||||
|
: className.includes("team")
|
||||||
|
? "admin-team-info"
|
||||||
|
: "admin-room-info";
|
||||||
|
info.textContent = subtitle || "";
|
||||||
|
|
||||||
|
details.append(name, info);
|
||||||
|
|
||||||
|
const actionsWrap = document.createElement("div");
|
||||||
|
actionsWrap.className =
|
||||||
|
className.includes("user")
|
||||||
|
? "admin-user-actions"
|
||||||
|
: className.includes("team")
|
||||||
|
? "admin-team-actions"
|
||||||
|
: "admin-room-actions";
|
||||||
|
|
||||||
|
for (const action of actions) {
|
||||||
|
actionsWrap.append(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
row.append(details, actionsWrap);
|
||||||
|
return row;
|
||||||
|
};
|
||||||
|
|
||||||
Glow.renderAdminUsers = users => {
|
Glow.renderAdminUsers = users => {
|
||||||
Glow.els.adminUsers.replaceChildren();
|
Glow.els.adminUsers.replaceChildren();
|
||||||
|
|
||||||
@ -25,39 +91,18 @@ Glow.renderAdminUsers = users => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const user of users) {
|
for (const user of users) {
|
||||||
const row = document.createElement("div");
|
|
||||||
row.className = "admin-user";
|
|
||||||
|
|
||||||
const details = document.createElement("div");
|
|
||||||
|
|
||||||
const name = document.createElement("div");
|
|
||||||
name.className = "admin-user-name";
|
|
||||||
name.textContent = `${user.username} · ${user.role}`;
|
|
||||||
|
|
||||||
const info = document.createElement("div");
|
|
||||||
info.className = "admin-user-info";
|
|
||||||
info.textContent =
|
|
||||||
`${user.status} · ${user.message_count} message(s)` +
|
|
||||||
(user.restricted_until
|
|
||||||
? ` · until ${new Date(user.restricted_until).toLocaleString()}`
|
|
||||||
: "");
|
|
||||||
|
|
||||||
details.append(name, info);
|
|
||||||
|
|
||||||
const actions = document.createElement("div");
|
|
||||||
actions.className = "admin-user-actions";
|
|
||||||
|
|
||||||
const current =
|
const current =
|
||||||
Glow.state.currentUser &&
|
Glow.state.currentUser &&
|
||||||
Number(Glow.state.currentUser.id) === Number(user.id);
|
Number(Glow.state.currentUser.id) === Number(user.id);
|
||||||
|
|
||||||
|
const actions = [];
|
||||||
|
|
||||||
if (!current && Glow.isAdmin()) {
|
if (!current && Glow.isAdmin()) {
|
||||||
const role = document.createElement("button");
|
const role = document.createElement("button");
|
||||||
role.className = "small-button";
|
role.className = "small-button";
|
||||||
role.type = "button";
|
role.type = "button";
|
||||||
role.textContent =
|
role.textContent =
|
||||||
user.role === "moderator" ? "Make user" : "Make moderator";
|
user.role === "moderator" ? "Make user" : "Make moderator";
|
||||||
|
|
||||||
role.addEventListener("click", () => {
|
role.addEventListener("click", () => {
|
||||||
Glow.updateAdminUser(user.id, {
|
Glow.updateAdminUser(user.id, {
|
||||||
role: user.role === "moderator" ? "user" : "moderator"
|
role: user.role === "moderator" ? "user" : "moderator"
|
||||||
@ -69,7 +114,6 @@ Glow.renderAdminUsers = users => {
|
|||||||
restrict.type = "button";
|
restrict.type = "button";
|
||||||
restrict.textContent =
|
restrict.textContent =
|
||||||
user.status === "restricted" ? "Unrestrict" : "Restrict";
|
user.status === "restricted" ? "Unrestrict" : "Restrict";
|
||||||
|
|
||||||
restrict.addEventListener("click", () => {
|
restrict.addEventListener("click", () => {
|
||||||
Glow.toggleRestriction(user);
|
Glow.toggleRestriction(user);
|
||||||
});
|
});
|
||||||
@ -79,16 +123,25 @@ Glow.renderAdminUsers = users => {
|
|||||||
blacklist.type = "button";
|
blacklist.type = "button";
|
||||||
blacklist.textContent =
|
blacklist.textContent =
|
||||||
user.status === "blacklisted" ? "Unblacklist" : "Blacklist";
|
user.status === "blacklisted" ? "Unblacklist" : "Blacklist";
|
||||||
|
|
||||||
blacklist.addEventListener("click", () => {
|
blacklist.addEventListener("click", () => {
|
||||||
Glow.toggleBlacklist(user);
|
Glow.toggleBlacklist(user);
|
||||||
});
|
});
|
||||||
|
|
||||||
actions.append(role, restrict, blacklist);
|
actions.push(role, restrict, blacklist);
|
||||||
}
|
}
|
||||||
|
|
||||||
row.append(details, actions);
|
Glow.els.adminUsers.append(
|
||||||
Glow.els.adminUsers.append(row);
|
Glow.buildAdminRow({
|
||||||
|
title: `${user.username} · ${user.role}`,
|
||||||
|
subtitle:
|
||||||
|
`${user.status} · ${user.message_count} message(s)` +
|
||||||
|
(user.restricted_until
|
||||||
|
? ` · until ${new Date(user.restricted_until).toLocaleString()}`
|
||||||
|
: ""),
|
||||||
|
actions,
|
||||||
|
className: "admin-user"
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,25 +161,7 @@ Glow.renderAdminRooms = rooms => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const room of rooms) {
|
for (const room of rooms) {
|
||||||
const row = document.createElement("div");
|
const actions = [];
|
||||||
row.className = "admin-room";
|
|
||||||
|
|
||||||
const details = document.createElement("div");
|
|
||||||
|
|
||||||
const name = document.createElement("div");
|
|
||||||
name.className = "admin-room-name";
|
|
||||||
name.textContent = `${room.name} · ${room.visibility}`;
|
|
||||||
|
|
||||||
const info = document.createElement("div");
|
|
||||||
info.className = "admin-room-info";
|
|
||||||
info.textContent =
|
|
||||||
`/${room.slug}` +
|
|
||||||
(room.description ? ` · ${room.description}` : "");
|
|
||||||
|
|
||||||
details.append(name, info);
|
|
||||||
|
|
||||||
const actions = document.createElement("div");
|
|
||||||
actions.className = "admin-room-actions";
|
|
||||||
|
|
||||||
if (Glow.isAdmin()) {
|
if (Glow.isAdmin()) {
|
||||||
const edit = document.createElement("button");
|
const edit = document.createElement("button");
|
||||||
@ -134,8 +169,7 @@ Glow.renderAdminRooms = rooms => {
|
|||||||
edit.type = "button";
|
edit.type = "button";
|
||||||
edit.textContent = "Edit";
|
edit.textContent = "Edit";
|
||||||
edit.addEventListener("click", () => Glow.editRoom(room));
|
edit.addEventListener("click", () => Glow.editRoom(room));
|
||||||
|
actions.push(edit);
|
||||||
actions.append(edit);
|
|
||||||
|
|
||||||
if (room.visibility === "private") {
|
if (room.visibility === "private") {
|
||||||
const members = document.createElement("button");
|
const members = document.createElement("button");
|
||||||
@ -154,7 +188,7 @@ Glow.renderAdminRooms = rooms => {
|
|||||||
Glow.createInviteLink(room);
|
Glow.createInviteLink(room);
|
||||||
});
|
});
|
||||||
|
|
||||||
actions.append(members, invite);
|
actions.push(members, invite);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (room.slug !== "general") {
|
if (room.slug !== "general") {
|
||||||
@ -163,13 +197,128 @@ Glow.renderAdminRooms = rooms => {
|
|||||||
remove.type = "button";
|
remove.type = "button";
|
||||||
remove.textContent = "Delete";
|
remove.textContent = "Delete";
|
||||||
remove.addEventListener("click", () => Glow.deleteRoom(room));
|
remove.addEventListener("click", () => Glow.deleteRoom(room));
|
||||||
|
actions.push(remove);
|
||||||
actions.append(remove);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
row.append(details, actions);
|
Glow.els.adminRooms.append(
|
||||||
Glow.els.adminRooms.append(row);
|
Glow.buildAdminRow({
|
||||||
|
title: `${room.name} · ${room.visibility}`,
|
||||||
|
subtitle:
|
||||||
|
`/${room.slug}` +
|
||||||
|
(room.description ? ` · ${room.description}` : ""),
|
||||||
|
actions,
|
||||||
|
className: "admin-room"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Glow.renderAdminTeamsChannels = () => {
|
||||||
|
const box = Glow.els.adminTeamsChannels;
|
||||||
|
if (!box) return;
|
||||||
|
box.replaceChildren();
|
||||||
|
|
||||||
|
const heading = document.createElement("h3");
|
||||||
|
heading.textContent = "Teams / channels";
|
||||||
|
box.append(heading);
|
||||||
|
|
||||||
|
const team = Glow.state.activeTeam;
|
||||||
|
const channel = Glow.state.activeChannel || Glow.state.activeRoom;
|
||||||
|
|
||||||
|
if (!team) {
|
||||||
|
const empty = document.createElement("p");
|
||||||
|
empty.className = "admin-empty";
|
||||||
|
empty.textContent = "Select a team to manage team/channel actions.";
|
||||||
|
box.append(empty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const teamActions = [];
|
||||||
|
if (team.can_manage) {
|
||||||
|
const editTeam = document.createElement("button");
|
||||||
|
editTeam.className = "small-button";
|
||||||
|
editTeam.type = "button";
|
||||||
|
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.addEventListener("click", () => Glow.manageTeamMembers?.(team));
|
||||||
|
|
||||||
|
const invite = document.createElement("button");
|
||||||
|
invite.className = "small-button";
|
||||||
|
invite.type = "button";
|
||||||
|
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.addEventListener("click", () => Glow.openCreateChannelDialog?.(team));
|
||||||
|
|
||||||
|
teamActions.push(editTeam, members, invite, addChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
box.append(
|
||||||
|
Glow.buildAdminRow({
|
||||||
|
title: team.name,
|
||||||
|
subtitle: team.description || `/${team.slug}`,
|
||||||
|
actions: teamActions,
|
||||||
|
className: "admin-team-row"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
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.";
|
||||||
|
box.append(empty);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of channels) {
|
||||||
|
const actions = [];
|
||||||
|
const isActive = channel && item.slug === channel.slug;
|
||||||
|
|
||||||
|
if (team.can_manage) {
|
||||||
|
const edit = document.createElement("button");
|
||||||
|
edit.className = "small-button";
|
||||||
|
edit.type = "button";
|
||||||
|
edit.textContent = "Edit";
|
||||||
|
edit.addEventListener("click", () => {
|
||||||
|
Glow.openEditChannelDialog?.(team, item);
|
||||||
|
});
|
||||||
|
actions.push(edit);
|
||||||
|
|
||||||
|
if (!item.legacy_room_id) {
|
||||||
|
const remove = document.createElement("button");
|
||||||
|
remove.className = "small-button danger";
|
||||||
|
remove.type = "button";
|
||||||
|
remove.textContent = "Delete";
|
||||||
|
remove.addEventListener("click", async () => {
|
||||||
|
const previous = Glow.state.activeChannel;
|
||||||
|
Glow.state.activeChannel = item;
|
||||||
|
await Glow.deleteCurrentChannel?.(team);
|
||||||
|
Glow.state.activeChannel = previous;
|
||||||
|
});
|
||||||
|
actions.push(remove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
box.append(
|
||||||
|
Glow.buildAdminRow({
|
||||||
|
title: `${isActive ? "• " : ""}# ${item.name}`,
|
||||||
|
subtitle: item.description || `/${item.slug}`,
|
||||||
|
actions,
|
||||||
|
className: "admin-team-row"
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -179,8 +328,15 @@ Glow.openAdminPanel = async () => {
|
|||||||
Glow.els.adminPanel.classList.add("open");
|
Glow.els.adminPanel.classList.add("open");
|
||||||
Glow.els.adminPanel.setAttribute("aria-hidden", "false");
|
Glow.els.adminPanel.setAttribute("aria-hidden", "false");
|
||||||
|
|
||||||
Glow.els.adminUsers.textContent = "Loading users…";
|
if (Glow.els.adminUsers) {
|
||||||
Glow.els.adminRooms.textContent = "Loading rooms…";
|
Glow.els.adminUsers.textContent = "Loading users…";
|
||||||
|
}
|
||||||
|
if (Glow.els.adminRooms) {
|
||||||
|
Glow.els.adminRooms.textContent = "Loading rooms…";
|
||||||
|
}
|
||||||
|
if (Glow.els.adminTeamsChannels) {
|
||||||
|
Glow.els.adminTeamsChannels.textContent = "Loading teams/channels…";
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [usersData, roomsData] = await Promise.all([
|
const [usersData, roomsData] = await Promise.all([
|
||||||
@ -190,7 +346,9 @@ Glow.openAdminPanel = async () => {
|
|||||||
|
|
||||||
Glow.renderAdminUsers(usersData.users || []);
|
Glow.renderAdminUsers(usersData.users || []);
|
||||||
Glow.renderAdminRooms(roomsData.rooms || []);
|
Glow.renderAdminRooms(roomsData.rooms || []);
|
||||||
Glow.updateAdminPreferenceButtons();
|
Glow.renderAdminTeamsChannels();
|
||||||
|
|
||||||
|
Glow.setAdminTab(Glow.state.adminTab || "rooms");
|
||||||
|
|
||||||
setTimeout(() => Glow.els.closeAdminButton.focus(), 0);
|
setTimeout(() => Glow.els.closeAdminButton.focus(), 0);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -203,15 +361,7 @@ Glow.updateThemeButton = () => {
|
|||||||
Glow.els.themeButton.textContent = "Accent color";
|
Glow.els.themeButton.textContent = "Accent color";
|
||||||
};
|
};
|
||||||
|
|
||||||
Glow.updateAdminPreferenceButtons = () => {
|
Glow.updateAdminPreferenceButtons = () => {};
|
||||||
Glow.els.typingToggleButton.textContent =
|
|
||||||
`Typing indicators: ${Glow.state.typingIndicatorsEnabled ? "on" : "off"}`;
|
|
||||||
|
|
||||||
Glow.els.notificationsToggleButton.textContent =
|
|
||||||
`Notifications: ${Glow.state.notificationsEnabled ? "on" : "off"}`;
|
|
||||||
|
|
||||||
Glow.updateThemeButton();
|
|
||||||
};
|
|
||||||
|
|
||||||
Glow.openAccentColorPicker = async () => {
|
Glow.openAccentColorPicker = async () => {
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
@ -590,7 +740,7 @@ Glow.manageRoomMembers = async room => {
|
|||||||
row.className = "member-row";
|
row.className = "member-row";
|
||||||
|
|
||||||
const name = document.createElement("span");
|
const name = document.createElement("span");
|
||||||
name.textContent = `${member.username} · ${member.membership_role}`;
|
name.textContent = `${member.username} · ${member.membership_role}`;
|
||||||
|
|
||||||
const remove = document.createElement("button");
|
const remove = document.createElement("button");
|
||||||
remove.className = "small-button danger";
|
remove.className = "small-button danger";
|
||||||
@ -687,3 +837,15 @@ Glow.createInviteLink = async room => {
|
|||||||
Glow.showToast(error.message, "error");
|
Glow.showToast(error.message, "error");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Glow.els.adminTabRooms?.addEventListener("click", () => {
|
||||||
|
Glow.setAdminTab("rooms");
|
||||||
|
});
|
||||||
|
|
||||||
|
Glow.els.adminTabUsers?.addEventListener("click", () => {
|
||||||
|
Glow.setAdminTab("users");
|
||||||
|
});
|
||||||
|
|
||||||
|
Glow.els.adminTabTeams?.addEventListener("click", () => {
|
||||||
|
Glow.setAdminTab("teams");
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user