Extract main.ts controllers
This commit is contained in:
606
client/src/input/adminController.ts
Normal file
606
client/src/input/adminController.ts
Normal file
@@ -0,0 +1,606 @@
|
||||
import { handleListControlKey } from './listController';
|
||||
import { getEditSessionAction } from './editSession';
|
||||
import { handleYesNoMenuInput, YES_NO_OPTIONS } from './yesNoMenu';
|
||||
import type { IncomingMessage, OutgoingMessage } from '../network/protocol';
|
||||
import type { GameMode } from '../state/gameState';
|
||||
|
||||
export type AdminMenuAction = {
|
||||
id: string;
|
||||
label: string;
|
||||
tooltip?: string;
|
||||
};
|
||||
|
||||
export type AdminRoleSummary = {
|
||||
id: number;
|
||||
name: string;
|
||||
isSystem: boolean;
|
||||
userCount: number;
|
||||
permissions: string[];
|
||||
};
|
||||
|
||||
export type AdminUserSummary = {
|
||||
id: string;
|
||||
username: string;
|
||||
role: string;
|
||||
status: 'active' | 'disabled';
|
||||
};
|
||||
|
||||
export type AdminPendingUserMutation =
|
||||
| { action: 'set_role'; username: string; role: string }
|
||||
| { action: 'ban'; username: string }
|
||||
| { action: 'unban'; username: string }
|
||||
| { action: 'delete_account'; username: string };
|
||||
|
||||
type AdminPendingUserAction = 'set_role' | 'ban' | 'unban' | 'delete_account' | null;
|
||||
|
||||
type AdminControllerDeps = {
|
||||
state: {
|
||||
mode: GameMode;
|
||||
nicknameInput: string;
|
||||
cursorPos: number;
|
||||
};
|
||||
signalingSend: (message: OutgoingMessage) => void;
|
||||
announceMenuEntry: (title: string, firstOption: string) => void;
|
||||
updateStatus: (message: string) => void;
|
||||
sfxUiBlip: () => void;
|
||||
sfxUiCancel: () => void;
|
||||
applyTextInputEdit: (code: string, key: string, maxLength: number, ctrlKey?: boolean, allowReplaceOnNextType?: boolean) => void;
|
||||
setReplaceTextOnNextType: (value: boolean) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates the admin menu/runtime controller so `main.ts` can treat admin flows as one subsystem.
|
||||
*/
|
||||
export function createAdminController(deps: AdminControllerDeps): {
|
||||
setServerAdminMenuActions: (actions: Array<{ id: string; label: string; tooltip?: string }> | null | undefined) => void;
|
||||
getAvailableAdminActions: () => AdminMenuAction[];
|
||||
openAdminMenu: () => void;
|
||||
handleAdminRolesList: (message: Extract<IncomingMessage, { type: 'admin_roles_list' }>) => void;
|
||||
handleAdminUsersList: (message: Extract<IncomingMessage, { type: 'admin_users_list' }>) => void;
|
||||
handleAdminActionResult: (message: Extract<IncomingMessage, { type: 'admin_action_result' }>) => void;
|
||||
handleAdminMenuModeInput: (code: string, key: string) => void;
|
||||
handleAdminRoleListModeInput: (code: string, key: string) => void;
|
||||
handleAdminRolePermissionListModeInput: (code: string, key: string) => void;
|
||||
handleAdminRoleDeleteReplacementModeInput: (code: string, key: string) => void;
|
||||
handleAdminUserListModeInput: (code: string, key: string) => void;
|
||||
handleAdminUserRoleSelectModeInput: (code: string, key: string) => void;
|
||||
handleAdminUserDeleteConfirmModeInput: (code: string, key: string) => void;
|
||||
handleAdminRoleNameEditModeInput: (code: string, key: string, ctrlKey: boolean) => void;
|
||||
} {
|
||||
const adminMenuActions: AdminMenuAction[] = [];
|
||||
let serverAdminMenuActions: AdminMenuAction[] = [];
|
||||
let adminMenuIndex = 0;
|
||||
let adminRoles: AdminRoleSummary[] = [];
|
||||
let adminRoleIndex = 0;
|
||||
let adminPermissionKeys: string[] = [];
|
||||
let adminPermissionTooltips: Record<string, string> = {};
|
||||
let adminRolePermissionIndex = 0;
|
||||
let adminRoleDeleteReplacementIndex = 0;
|
||||
let adminUsers: AdminUserSummary[] = [];
|
||||
let adminUserIndex = 0;
|
||||
let adminPendingUserAction: AdminPendingUserAction = null;
|
||||
let adminSelectedRoleName = '';
|
||||
let adminSelectedUsername = '';
|
||||
let adminPendingUserMutation: AdminPendingUserMutation | null = null;
|
||||
let adminDeleteConfirmIndex = 0;
|
||||
|
||||
function setServerAdminMenuActions(actions: Array<{ id: string; label: string; tooltip?: string }> | null | undefined): void {
|
||||
serverAdminMenuActions = (actions || [])
|
||||
.map((entry) => ({
|
||||
id: String(entry.id || '').trim(),
|
||||
label: String(entry.label || '').trim(),
|
||||
tooltip: typeof entry.tooltip === 'string' && entry.tooltip.trim().length > 0 ? entry.tooltip.trim() : undefined,
|
||||
}))
|
||||
.filter((entry) => entry.id.length > 0 && entry.label.length > 0);
|
||||
}
|
||||
|
||||
function getAvailableAdminActions(): AdminMenuAction[] {
|
||||
return [...serverAdminMenuActions];
|
||||
}
|
||||
|
||||
function openAdminMenu(): void {
|
||||
const actions = getAvailableAdminActions();
|
||||
if (actions.length === 0) {
|
||||
deps.updateStatus('No admin actions available.');
|
||||
deps.sfxUiCancel();
|
||||
return;
|
||||
}
|
||||
adminMenuActions.splice(0, adminMenuActions.length, ...actions);
|
||||
adminMenuIndex = 0;
|
||||
deps.state.mode = 'adminMenu';
|
||||
deps.announceMenuEntry('Admin', adminMenuActions[0].label);
|
||||
}
|
||||
|
||||
function handleAdminRolesList(message: Extract<IncomingMessage, { type: 'admin_roles_list' }>): void {
|
||||
adminRoles = [...message.roles].sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }));
|
||||
adminPermissionKeys = [...message.permissionKeys].sort((a, b) => a.localeCompare(b));
|
||||
adminPermissionTooltips = { ...(message.permissionTooltips ?? {}) };
|
||||
if (adminPendingUserAction === 'set_role' && adminSelectedUsername) {
|
||||
deps.state.mode = 'adminUserRoleSelect';
|
||||
const selectedUser = adminUsers.find((entry) => entry.username === adminSelectedUsername);
|
||||
const currentRoleIndex =
|
||||
selectedUser ? adminRoles.findIndex((entry) => entry.name === selectedUser.role) : -1;
|
||||
adminRoleIndex = currentRoleIndex >= 0 ? currentRoleIndex : 0;
|
||||
const first = adminRoles[0];
|
||||
if (first && adminRoles[adminRoleIndex]) {
|
||||
deps.announceMenuEntry('Roles', adminRoles[adminRoleIndex].name);
|
||||
} else {
|
||||
deps.updateStatus('No roles available.');
|
||||
deps.sfxUiCancel();
|
||||
deps.state.mode = 'normal';
|
||||
adminPendingUserAction = null;
|
||||
adminSelectedUsername = '';
|
||||
}
|
||||
return;
|
||||
}
|
||||
deps.state.mode = 'adminRoleList';
|
||||
adminRoleIndex = 0;
|
||||
const first = adminRoles[0];
|
||||
if (first) {
|
||||
deps.announceMenuEntry('Roles', `${first.name}, ${first.userCount}`);
|
||||
} else {
|
||||
deps.updateStatus('No roles found.');
|
||||
deps.sfxUiCancel();
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdminUsersList(message: Extract<IncomingMessage, { type: 'admin_users_list' }>): void {
|
||||
adminUsers = [...message.users].sort((a, b) => a.username.localeCompare(b.username, undefined, { sensitivity: 'base' }));
|
||||
if (adminUsers.length === 0) {
|
||||
deps.updateStatus('No users available.');
|
||||
deps.sfxUiCancel();
|
||||
deps.state.mode = 'normal';
|
||||
adminPendingUserAction = null;
|
||||
return;
|
||||
}
|
||||
deps.state.mode = 'adminUserList';
|
||||
adminUserIndex = 0;
|
||||
const first = adminUsers[0];
|
||||
deps.announceMenuEntry('Users', `${first.username}, ${first.role}, ${first.status}`);
|
||||
}
|
||||
|
||||
function handleAdminActionResult(message: Extract<IncomingMessage, { type: 'admin_action_result' }>): void {
|
||||
if (message.action === 'role_update_permissions') {
|
||||
return;
|
||||
}
|
||||
const suppressStatusMessage =
|
||||
message.ok && message.action === 'user_set_role' && adminPendingUserMutation?.action === 'set_role';
|
||||
if (!suppressStatusMessage) {
|
||||
deps.updateStatus(message.message);
|
||||
}
|
||||
if (!message.ok) {
|
||||
adminPendingUserMutation = null;
|
||||
deps.sfxUiCancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (adminPendingUserMutation) {
|
||||
if (adminPendingUserMutation.action === 'set_role') {
|
||||
const target = adminUsers.find((entry) => entry.username === adminPendingUserMutation.username);
|
||||
if (target) {
|
||||
target.role = adminPendingUserMutation.role;
|
||||
}
|
||||
if (deps.state.mode === 'adminUserRoleSelect') {
|
||||
deps.state.mode = 'adminUserList';
|
||||
adminPendingUserAction = 'set_role';
|
||||
const userIndex = adminUsers.findIndex((entry) => entry.username === adminPendingUserMutation.username);
|
||||
if (userIndex >= 0) {
|
||||
adminUserIndex = userIndex;
|
||||
const selected = adminUsers[adminUserIndex];
|
||||
deps.updateStatus(`${selected.username}, ${selected.role}, ${selected.status}.`);
|
||||
}
|
||||
}
|
||||
} else if (adminPendingUserMutation.action === 'ban') {
|
||||
adminUsers = adminUsers.filter((entry) => entry.username !== adminPendingUserMutation.username);
|
||||
if (deps.state.mode === 'adminUserList' && adminPendingUserAction === 'ban') {
|
||||
if (adminUsers.length > 0) {
|
||||
adminUserIndex = Math.max(0, Math.min(adminUserIndex, adminUsers.length - 1));
|
||||
} else {
|
||||
deps.state.mode = 'adminMenu';
|
||||
adminPendingUserAction = null;
|
||||
}
|
||||
}
|
||||
} else if (adminPendingUserMutation.action === 'unban') {
|
||||
adminUsers = adminUsers.filter((entry) => entry.username !== adminPendingUserMutation.username);
|
||||
if (deps.state.mode === 'adminUserList' && adminPendingUserAction === 'unban') {
|
||||
if (adminUsers.length > 0) {
|
||||
adminUserIndex = Math.max(0, Math.min(adminUserIndex, adminUsers.length - 1));
|
||||
} else {
|
||||
deps.state.mode = 'adminMenu';
|
||||
adminPendingUserAction = null;
|
||||
}
|
||||
}
|
||||
} else if (adminPendingUserMutation.action === 'delete_account') {
|
||||
adminUsers = adminUsers.filter((entry) => entry.username !== adminPendingUserMutation.username);
|
||||
if (deps.state.mode === 'adminUserList' && adminPendingUserAction === 'delete_account') {
|
||||
if (adminUsers.length > 0) {
|
||||
adminUserIndex = Math.max(0, Math.min(adminUserIndex, adminUsers.length - 1));
|
||||
} else {
|
||||
deps.state.mode = 'adminMenu';
|
||||
adminPendingUserAction = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
adminPendingUserMutation = null;
|
||||
}
|
||||
|
||||
if (message.action === 'role_create' && message.role) {
|
||||
adminRoles.push({
|
||||
id: message.role.id,
|
||||
name: message.role.name,
|
||||
isSystem: message.role.isSystem,
|
||||
userCount: message.role.userCount,
|
||||
permissions: [...message.role.permissions],
|
||||
});
|
||||
adminRoles.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }));
|
||||
}
|
||||
if (message.action === 'role_delete' && message.roleName) {
|
||||
adminRoles = adminRoles.filter((entry) => entry.name !== message.roleName);
|
||||
if (deps.state.mode === 'adminRoleList') {
|
||||
adminRoleIndex = Math.max(0, Math.min(adminRoleIndex, Math.max(0, adminRoles.length)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdminMenuModeInput(code: string, key: string): void {
|
||||
if (adminMenuActions.length === 0) {
|
||||
deps.state.mode = 'normal';
|
||||
return;
|
||||
}
|
||||
const control = handleListControlKey(code, key, adminMenuActions, adminMenuIndex, (entry) => entry.label);
|
||||
if (control.type === 'move') {
|
||||
adminMenuIndex = control.index;
|
||||
deps.updateStatus(adminMenuActions[adminMenuIndex].label);
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (code === 'Space') {
|
||||
deps.updateStatus(adminMenuActions[adminMenuIndex]?.tooltip ?? 'No tooltip available.');
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'select') {
|
||||
const selected = adminMenuActions[adminMenuIndex];
|
||||
if (!selected) return;
|
||||
if (selected.id === 'manage_roles') {
|
||||
deps.signalingSend({ type: 'admin_roles_list' });
|
||||
deps.updateStatus('Loading roles...');
|
||||
return;
|
||||
}
|
||||
if (selected.id === 'change_user_role') {
|
||||
adminPendingUserAction = 'set_role';
|
||||
deps.signalingSend({ type: 'admin_users_list', action: 'set_role' });
|
||||
deps.updateStatus('Loading users...');
|
||||
return;
|
||||
}
|
||||
if (selected.id === 'ban_user') {
|
||||
adminPendingUserAction = 'ban';
|
||||
deps.signalingSend({ type: 'admin_users_list', action: 'ban' });
|
||||
deps.updateStatus('Loading users...');
|
||||
return;
|
||||
}
|
||||
if (selected.id === 'unban_user') {
|
||||
adminPendingUserAction = 'unban';
|
||||
deps.signalingSend({ type: 'admin_users_list', action: 'unban' });
|
||||
deps.updateStatus('Loading users...');
|
||||
return;
|
||||
}
|
||||
if (selected.id === 'delete_account') {
|
||||
adminPendingUserAction = 'delete_account';
|
||||
deps.signalingSend({ type: 'admin_users_list', action: 'delete_account' });
|
||||
deps.updateStatus('Loading users...');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (control.type === 'cancel') {
|
||||
deps.state.mode = 'normal';
|
||||
deps.updateStatus('Cancelled.');
|
||||
deps.sfxUiCancel();
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdminRoleListModeInput(code: string, key: string): void {
|
||||
const entries: Array<{ label: string; role?: AdminRoleSummary }> = [
|
||||
...adminRoles.map((role) => ({ label: `${role.name}, ${role.userCount}`, role })),
|
||||
{ label: 'Add role' },
|
||||
];
|
||||
const control = handleListControlKey(code, key, entries, adminRoleIndex, (entry) => entry.label);
|
||||
if (control.type === 'move') {
|
||||
adminRoleIndex = control.index;
|
||||
deps.updateStatus(entries[adminRoleIndex]?.label || '');
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'select') {
|
||||
const selected = entries[adminRoleIndex];
|
||||
if (!selected) return;
|
||||
if (!selected.role) {
|
||||
deps.state.mode = 'adminRoleNameEdit';
|
||||
deps.state.nicknameInput = '';
|
||||
deps.state.cursorPos = 0;
|
||||
deps.setReplaceTextOnNextType(false);
|
||||
deps.updateStatus('New role name.');
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
adminSelectedRoleName = selected.role.name;
|
||||
adminRolePermissionIndex = 0;
|
||||
deps.state.mode = 'adminRolePermissionList';
|
||||
deps.updateStatus(`${adminSelectedRoleName} permissions.`);
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'cancel') {
|
||||
deps.state.mode = 'normal';
|
||||
deps.updateStatus('Cancelled.');
|
||||
deps.sfxUiCancel();
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdminRolePermissionListModeInput(code: string, key: string): void {
|
||||
const role = adminRoles.find((entry) => entry.name === adminSelectedRoleName);
|
||||
if (!role) {
|
||||
deps.state.mode = 'adminRoleList';
|
||||
return;
|
||||
}
|
||||
const entries = [...adminPermissionKeys, '__delete_role__'];
|
||||
const control = handleListControlKey(code, key, entries, adminRolePermissionIndex, (entry) =>
|
||||
entry === '__delete_role__' ? `Delete role ${role.name}` : `${entry}: ${role.permissions.includes(entry) ? 'on' : 'off'}`,
|
||||
);
|
||||
if (control.type === 'move') {
|
||||
adminRolePermissionIndex = control.index;
|
||||
const value = entries[adminRolePermissionIndex];
|
||||
if (value === '__delete_role__') {
|
||||
deps.updateStatus(`Delete role ${role.name}.`);
|
||||
} else {
|
||||
deps.updateStatus(`${value}: ${role.permissions.includes(value) ? 'on' : 'off'}`);
|
||||
}
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (code === 'Space') {
|
||||
const value = entries[adminRolePermissionIndex];
|
||||
if (value === '__delete_role__') {
|
||||
deps.updateStatus('Delete the current role and reassign affected users.');
|
||||
} else {
|
||||
deps.updateStatus(adminPermissionTooltips[value] || 'No tooltip available.');
|
||||
}
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'select') {
|
||||
const value = entries[adminRolePermissionIndex];
|
||||
if (value === '__delete_role__') {
|
||||
if (role.name === 'admin' || role.name === 'user') {
|
||||
deps.updateStatus('Admin and user roles cannot be deleted.');
|
||||
deps.sfxUiCancel();
|
||||
return;
|
||||
}
|
||||
const replacementCandidates = adminRoles.filter((entry) => entry.name !== role.name);
|
||||
if (replacementCandidates.length === 0) {
|
||||
deps.updateStatus('No replacement role available.');
|
||||
deps.sfxUiCancel();
|
||||
return;
|
||||
}
|
||||
adminRoleDeleteReplacementIndex = 0;
|
||||
deps.state.mode = 'adminRoleDeleteReplacement';
|
||||
deps.updateStatus(`Replacement role: ${replacementCandidates[0].name}.`);
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
const nextPermissions = new Set(role.permissions);
|
||||
if (nextPermissions.has(value)) {
|
||||
nextPermissions.delete(value);
|
||||
} else {
|
||||
nextPermissions.add(value);
|
||||
}
|
||||
role.permissions = [...nextPermissions].sort((a, b) => a.localeCompare(b));
|
||||
deps.signalingSend({ type: 'admin_role_update_permissions', role: role.name, permissions: role.permissions });
|
||||
deps.updateStatus(`${value}: ${role.permissions.includes(value) ? 'on' : 'off'}`);
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'cancel') {
|
||||
deps.state.mode = 'adminRoleList';
|
||||
deps.updateStatus('Roles.');
|
||||
deps.sfxUiCancel();
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdminRoleDeleteReplacementModeInput(code: string, key: string): void {
|
||||
const candidates = adminRoles.filter((entry) => entry.name !== adminSelectedRoleName);
|
||||
if (candidates.length === 0) {
|
||||
deps.state.mode = 'adminRolePermissionList';
|
||||
return;
|
||||
}
|
||||
const control = handleListControlKey(code, key, candidates, adminRoleDeleteReplacementIndex, (entry) => entry.name);
|
||||
if (control.type === 'move') {
|
||||
adminRoleDeleteReplacementIndex = control.index;
|
||||
deps.updateStatus(candidates[adminRoleDeleteReplacementIndex].name);
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'select') {
|
||||
const replacement = candidates[adminRoleDeleteReplacementIndex];
|
||||
deps.signalingSend({
|
||||
type: 'admin_role_delete',
|
||||
role: adminSelectedRoleName,
|
||||
replacementRole: replacement.name,
|
||||
});
|
||||
deps.state.mode = 'adminRoleList';
|
||||
deps.updateStatus(`Deleting ${adminSelectedRoleName}...`);
|
||||
return;
|
||||
}
|
||||
if (control.type === 'cancel') {
|
||||
deps.state.mode = 'adminRolePermissionList';
|
||||
deps.updateStatus(`${adminSelectedRoleName} permissions.`);
|
||||
deps.sfxUiCancel();
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdminUserListModeInput(code: string, key: string): void {
|
||||
if (adminUsers.length === 0) {
|
||||
deps.state.mode = 'normal';
|
||||
adminPendingUserAction = null;
|
||||
return;
|
||||
}
|
||||
const control = handleListControlKey(code, key, adminUsers, adminUserIndex, (entry) => `${entry.username}, ${entry.role}, ${entry.status}`);
|
||||
if (control.type === 'move') {
|
||||
adminUserIndex = control.index;
|
||||
const selected = adminUsers[adminUserIndex];
|
||||
deps.updateStatus(`${selected.username}, ${selected.role}, ${selected.status}.`);
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'select') {
|
||||
const selected = adminUsers[adminUserIndex];
|
||||
if (!selected) return;
|
||||
adminSelectedUsername = selected.username;
|
||||
if (adminPendingUserAction === 'set_role') {
|
||||
deps.signalingSend({ type: 'admin_roles_list' });
|
||||
deps.updateStatus(`Select new role for ${selected.username}.`);
|
||||
return;
|
||||
}
|
||||
if (adminPendingUserAction === 'ban') {
|
||||
adminPendingUserMutation = { action: 'ban', username: selected.username };
|
||||
deps.signalingSend({ type: 'admin_user_ban', username: selected.username });
|
||||
adminPendingUserAction = 'ban';
|
||||
return;
|
||||
}
|
||||
if (adminPendingUserAction === 'unban') {
|
||||
adminPendingUserMutation = { action: 'unban', username: selected.username };
|
||||
deps.signalingSend({ type: 'admin_user_unban', username: selected.username });
|
||||
adminPendingUserAction = 'unban';
|
||||
return;
|
||||
}
|
||||
if (adminPendingUserAction === 'delete_account') {
|
||||
adminDeleteConfirmIndex = 0;
|
||||
deps.state.mode = 'adminUserDeleteConfirm';
|
||||
deps.announceMenuEntry(`Delete account ${selected.username}?`, YES_NO_OPTIONS[adminDeleteConfirmIndex].label);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (control.type === 'cancel') {
|
||||
deps.state.mode = 'adminMenu';
|
||||
adminPendingUserAction = null;
|
||||
deps.updateStatus('Admin menu.');
|
||||
deps.sfxUiCancel();
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdminUserRoleSelectModeInput(code: string, key: string): void {
|
||||
if (adminRoles.length === 0) {
|
||||
deps.state.mode = 'normal';
|
||||
adminPendingUserAction = null;
|
||||
return;
|
||||
}
|
||||
const control = handleListControlKey(code, key, adminRoles, adminRoleIndex, (entry) => entry.name);
|
||||
if (control.type === 'move') {
|
||||
adminRoleIndex = control.index;
|
||||
deps.updateStatus(adminRoles[adminRoleIndex].name);
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'select') {
|
||||
const selectedRole = adminRoles[adminRoleIndex];
|
||||
adminPendingUserMutation = { action: 'set_role', username: adminSelectedUsername, role: selectedRole.name };
|
||||
deps.signalingSend({ type: 'admin_user_set_role', username: adminSelectedUsername, role: selectedRole.name });
|
||||
return;
|
||||
}
|
||||
if (control.type === 'cancel') {
|
||||
deps.state.mode = 'adminUserList';
|
||||
deps.updateStatus('Select user.');
|
||||
deps.sfxUiCancel();
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdminUserDeleteConfirmModeInput(code: string, key: string): void {
|
||||
if (!adminSelectedUsername || adminPendingUserAction !== 'delete_account') {
|
||||
deps.state.mode = 'adminUserList';
|
||||
return;
|
||||
}
|
||||
const control = handleYesNoMenuInput(code, key, adminDeleteConfirmIndex);
|
||||
if (control.type === 'move') {
|
||||
adminDeleteConfirmIndex = control.index;
|
||||
deps.updateStatus(YES_NO_OPTIONS[adminDeleteConfirmIndex].label);
|
||||
deps.sfxUiBlip();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'cancel') {
|
||||
deps.state.mode = 'adminUserList';
|
||||
const selected = adminUsers[adminUserIndex];
|
||||
if (selected) {
|
||||
deps.updateStatus(`${selected.username}, ${selected.role}, ${selected.status}.`);
|
||||
} else {
|
||||
deps.updateStatus('Select user.');
|
||||
}
|
||||
deps.sfxUiCancel();
|
||||
return;
|
||||
}
|
||||
if (control.type === 'select') {
|
||||
const choice = YES_NO_OPTIONS[adminDeleteConfirmIndex];
|
||||
if (choice.id === 'no') {
|
||||
deps.state.mode = 'adminUserList';
|
||||
const selected = adminUsers[adminUserIndex];
|
||||
if (selected) {
|
||||
deps.updateStatus(`${selected.username}, ${selected.role}, ${selected.status}.`);
|
||||
} else {
|
||||
deps.updateStatus('Select user.');
|
||||
}
|
||||
deps.sfxUiCancel();
|
||||
return;
|
||||
}
|
||||
deps.state.mode = 'adminUserList';
|
||||
deps.updateStatus(`Deleting account ${adminSelectedUsername}...`);
|
||||
adminPendingUserMutation = { action: 'delete_account', username: adminSelectedUsername };
|
||||
deps.signalingSend({ type: 'admin_user_delete', username: adminSelectedUsername });
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdminRoleNameEditModeInput(code: string, key: string, ctrlKey: boolean): void {
|
||||
const editAction = getEditSessionAction(code);
|
||||
if (editAction === 'submit') {
|
||||
const name = deps.state.nicknameInput.trim().toLowerCase();
|
||||
if (!name) {
|
||||
deps.updateStatus('Role name required.');
|
||||
deps.sfxUiCancel();
|
||||
return;
|
||||
}
|
||||
deps.signalingSend({ type: 'admin_role_create', name });
|
||||
deps.state.mode = 'adminRoleList';
|
||||
deps.state.nicknameInput = '';
|
||||
deps.state.cursorPos = 0;
|
||||
deps.setReplaceTextOnNextType(false);
|
||||
deps.updateStatus(`Creating role ${name}...`);
|
||||
return;
|
||||
}
|
||||
if (editAction === 'cancel') {
|
||||
deps.state.mode = 'adminRoleList';
|
||||
deps.state.nicknameInput = '';
|
||||
deps.state.cursorPos = 0;
|
||||
deps.setReplaceTextOnNextType(false);
|
||||
deps.updateStatus('Cancelled.');
|
||||
deps.sfxUiCancel();
|
||||
return;
|
||||
}
|
||||
deps.applyTextInputEdit(code, key, 32, ctrlKey, true);
|
||||
}
|
||||
|
||||
return {
|
||||
setServerAdminMenuActions,
|
||||
getAvailableAdminActions,
|
||||
openAdminMenu,
|
||||
handleAdminRolesList,
|
||||
handleAdminUsersList,
|
||||
handleAdminActionResult,
|
||||
handleAdminMenuModeInput,
|
||||
handleAdminRoleListModeInput,
|
||||
handleAdminRolePermissionListModeInput,
|
||||
handleAdminRoleDeleteReplacementModeInput,
|
||||
handleAdminUserListModeInput,
|
||||
handleAdminUserRoleSelectModeInput,
|
||||
handleAdminUserDeleteConfirmModeInput,
|
||||
handleAdminRoleNameEditModeInput,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user