diff --git a/resources/assets/src/js/__tests__/admin.test.js b/resources/assets/src/js/__tests__/admin.test.js
index 8dac73c8..e2382f0b 100644
--- a/resources/assets/src/js/__tests__/admin.test.js
+++ b/resources/assets/src/js/__tests__/admin.test.js
@@ -65,6 +65,8 @@ describe('tests for "customize" module', () => {
describe('tests for "players" module', () => {
const modulePath = '../admin/players';
+ // TODO: test initializing players table
+
it('show "change player texture" modal dialog', () => {
const trans = jest.fn(key => key);
const showModal = jest.fn();
@@ -401,6 +403,8 @@ describe('tests for "players" module', () => {
describe('tests for "plugins" module', () => {
const modulePath = '../admin/plugins';
+ // TODO: test initializing plugins table
+
it('enable a plugin', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
@@ -673,6 +677,8 @@ describe('tests for "update" module', () => {
describe('tests for "users" module', () => {
const modulePath = '../admin/users';
+ // TODO: test initializing users table
+
it('change user email', async () => {
const fetch = jest.fn()
.mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' }))
@@ -1126,6 +1132,7 @@ describe('tests for "common" module', () => {
const fetch = jest.fn()
.mockReturnValue(Promise.resolve({ errno: 0, msg: 'Recorded.' }));
+ $.fn.dataTable = { defaults: {} };
window.document.cookie = '';
window.fetch = fetch;
window.blessing = {
@@ -1148,27 +1155,4 @@ describe('tests for "common" module', () => {
await sendFeedback();
expect(fetch).toHaveBeenCalledTimes(1);
});
-
- it('initialize data tables', () => {
- $.fn.dataTable = { defaults: {} };
- const initUsersTable = jest.fn();
- const initPlayersTable = jest.fn();
- const initPluginsTable = jest.fn();
- window.initUsersTable = initUsersTable;
- window.initPlayersTable = initPlayersTable;
- window.initPluginsTable = initPluginsTable;
- const { initTables } = require(modulePath);
-
- document.body.innerHTML = '
';
- initTables();
- expect(initUsersTable).toBeCalled();
-
- document.body.innerHTML = '';
- initTables();
- expect(initPlayersTable).toBeCalled();
-
- document.body.innerHTML = '';
- initTables();
- expect($.pluginsTable).not.toBeNull();
- });
});
diff --git a/resources/assets/src/js/admin/common.js b/resources/assets/src/js/admin/common.js
index 22e0d012..19690091 100644
--- a/resources/assets/src/js/admin/common.js
+++ b/resources/assets/src/js/admin/common.js
@@ -1,29 +1,13 @@
-/* global initUsersTable, initPlayersTable, initPluginsTable */
-
'use strict';
-$.pluginsTable = null;
-
-$(document).ready(initTables);
-
-function initTables() {
- $.extend(true, $.fn.dataTable.defaults, {
- language: trans('vendor.datatables'),
- scrollX: true,
- pageLength: 25,
- autoWidth: false,
- processing: true,
- serverSide: true
- });
-
- if ($('#user-table').length === 1) {
- initUsersTable();
- } else if ($('#player-table').length === 1) {
- initPlayersTable();
- } else if ($('#plugin-table').length === 1) {
- $.pluginsTable = initPluginsTable();
- }
-}
+$.extend(true, $.fn.dataTable.defaults, {
+ language: trans('vendor.datatables'),
+ scrollX: true,
+ pageLength: 25,
+ autoWidth: false,
+ processing: true,
+ serverSide: true
+});
async function sendFeedback() {
if (document.cookie.replace(/(?:(?:^|.*;\s*)feedback_sent\s*=\s*([^;]*).*$)|^.*$/, '$1') !== '') {
@@ -55,6 +39,5 @@ async function sendFeedback() {
if (process.env.NODE_ENV === 'test') {
module.exports = {
sendFeedback,
- initTables
};
}
diff --git a/resources/assets/src/js/admin/players.js b/resources/assets/src/js/admin/players.js
index 439363cb..c7609125 100644
--- a/resources/assets/src/js/admin/players.js
+++ b/resources/assets/src/js/admin/players.js
@@ -1,5 +1,88 @@
'use strict';
+if ($('#player-table').length === 1) {
+ $(document).ready(initPlayersTable);
+}
+
+function initPlayersTable() {
+ const specificUid = getQueryString('uid');
+ const query = specificUid ? `?uid=${specificUid}` : '';
+
+ $('#player-table').DataTable({
+ ajax: url(`admin/player-data${query}`),
+ scrollY: ($('.content-wrapper').height() - $('.content-header').outerHeight()) * 0.7,
+ fnDrawCallback: () => $('[data-toggle="tooltip"]').tooltip(),
+ columnDefs: playersTableColumnDefs
+ });
+}
+
+const playersTableColumnDefs = [
+ {
+ targets: 0,
+ data: 'pid',
+ width: '1%'
+ },
+ {
+ targets: 1,
+ data: 'uid',
+ render: (data, type, row) => `${data}`
+ },
+ {
+ targets: 2,
+ data: 'player_name'
+ },
+ {
+ targets: 3,
+ data: 'preference',
+ render: data => {
+ return `
+ `;
+ }
+ },
+ {
+ targets: 4,
+ searchable: false,
+ orderable: false,
+ render: (data, type, row) => ['steve', 'alex', 'cape'].reduce((html, type) => {
+ const currentTypeTid = row[`tid_${type}`];
+ const imageId = `${row.pid}-${currentTypeTid}`;
+
+ if (currentTypeTid === 0) {
+ return html + ``;
+ } else {
+ return html + `
+
+
+ `;
+ }
+ }, '')
+ },
+ {
+ targets: 5,
+ data: 'last_modified'
+ },
+ {
+ targets: 6,
+ searchable: false,
+ orderable: false,
+ render: (data, type, row) => `
+
+
+
+
+ ${trans('admin.deletePlayer')}`
+ }
+];
+
async function changePreference() {
try {
const { errno, msg } = await fetch({
@@ -100,7 +183,7 @@ async function changePlayerName(pid, oldName) {
}
} catch (error) {
showAjaxError(error);
- }
+ }
}
function changeOwner(pid) {
@@ -193,6 +276,7 @@ async function deletePlayer(pid) {
if (process.env.NODE_ENV === 'test') {
module.exports = {
+ initPlayersTable,
changeOwner,
showNicknameInSwal,
deletePlayer,
diff --git a/resources/assets/src/js/admin/plugins.js b/resources/assets/src/js/admin/plugins.js
index d2157742..8088f087 100644
--- a/resources/assets/src/js/admin/plugins.js
+++ b/resources/assets/src/js/admin/plugins.js
@@ -1,5 +1,67 @@
'use strict';
+if ($('#plugin-table').length === 1) {
+ $(document).ready(initPluginsTable);
+}
+
+function initPluginsTable() {
+ $.pluginsTable = $('#plugin-table').DataTable({
+ ajax: url('admin/plugins/data'),
+ fnDrawCallback: () => $('[data-toggle="tooltip"]').tooltip(),
+ columnDefs: pluginsTableColumnDefs
+ });
+}
+
+const pluginsTableColumnDefs = [
+ {
+ targets: 0,
+ data: 'title'
+ },
+ {
+ targets: 1,
+ data: 'description',
+ width: '35%'
+ },
+ {
+ targets: 2,
+ data: 'author',
+ render: data => isEmpty(data.url) ? data.author : `${data.author}`
+ },
+ {
+ targets: 3,
+ data: 'version'
+ },
+ {
+ targets: 4,
+ data: 'status'
+ },
+ {
+ targets: 5,
+ data: 'operations',
+ searchable: false,
+ orderable: false,
+ render: (data, type, row) => {
+ let toggleButton, configViewButton;
+
+ if (data.enabled) {
+ toggleButton = `${trans('admin.disablePlugin')}`;
+ } else {
+ toggleButton = `${trans('admin.enablePlugin')}`;
+ }
+
+ if (data.enabled && data.hasConfigView) {
+ configViewButton = `${trans('admin.configurePlugin')}`;
+ } else {
+ configViewButton = `${trans('admin.configurePlugin')}`;
+ }
+
+ const deletePluginButton = `${trans('admin.deletePlugin')}`;
+
+ return toggleButton + configViewButton + deletePluginButton;
+ }
+ }
+];
+
async function enablePlugin(name) {
try {
const { errno, msg } = await fetch({
@@ -69,6 +131,7 @@ async function deletePlugin(name) {
if (process.env.NODE_ENV === 'test') {
module.exports = {
+ initPluginsTable,
deletePlugin,
enablePlugin,
disablePlugin,
diff --git a/resources/assets/src/js/admin/tables.js b/resources/assets/src/js/admin/tables.js
deleted file mode 100644
index 70c57d3b..00000000
--- a/resources/assets/src/js/admin/tables.js
+++ /dev/null
@@ -1,289 +0,0 @@
-'use strict';
-
-function initUsersTable() {
- const uid = getQueryString('uid');
- const dataUrl = url('admin/user-data') + (uid ? `?uid=${uid}` : '');
-
- $('#user-table').DataTable({
- ajax: dataUrl,
- scrollY: ($('.content-wrapper').height() - $('.content-header').outerHeight()) * 0.7,
- fnDrawCallback: () => {
- $('[data-toggle="tooltip"]').tooltip();
- },
- rowCallback: (row, data) => {
- $(row).attr('id', `user-${data.uid}`);
- },
- columnDefs: [
- {
- targets: 0,
- data: 'uid',
- width: '1%'
- },
- {
- targets: 1,
- data: 'email'
- },
- {
- targets: 2,
- data: 'nickname'
- },
- {
- targets: 3,
- data: 'score',
- render: data => {
- return ``;
- }
- },
- {
- targets: 4,
- data: 'players_count',
- searchable: false,
- orderable: false,
- render: (data, type, row) => {
- return `${data}`;
- }
- },
- {
- targets: 5,
- data: 'permission',
- className: 'status',
- render: data => {
- switch (data) {
- case -1:
- return trans('admin.banned');
- case 0:
- return trans('admin.normal');
- case 1:
- return trans('admin.admin');
- case 2:
- return trans('admin.superAdmin');
- }
- }
- },
- {
- targets: 6,
- data: 'register_at'
- },
- {
- targets: 7,
- data: 'operations',
- searchable: false,
- orderable: false,
- render: (data, type, row) => {
- let adminOption = '', bannedOption = '', deleteUserButton;
- if (row.permission !== 2) {
- if (data === 2) {
- if (row.permission === 1) {
- adminOption = `
- ${trans('admin.unsetAdmin')}`;
- } else {
- adminOption = `
- ${trans('admin.setAdmin')}`;
- }
- }
- if (row.permission === -1) {
- bannedOption = `
- ${trans('admin.unban')}`;
- } else {
- bannedOption = `
- ${trans('admin.ban')}`;
- }
- }
-
- if (data === 2) {
- if (row.permission === 2) {
- deleteUserButton = `
- ${trans('admin.deleteUser')}`;
- } else {
- deleteUserButton = `
- ${trans('admin.deleteUser')}`;
- }
- } else {
- if (row.permission === 1 || row.permission === 2) {
- deleteUserButton = `
- ${trans('admin.deleteUser')}`;
- } else {
- deleteUserButton = `
- ${trans('admin.deleteUser')}`;
- }
- }
-
- return `
-
-
-
-
- ${deleteUserButton}`;
- }
- }
- ]
- });
-}
-
-function initPlayersTable() {
- const uid = getQueryString('uid');
- const dataUrl = url('admin/player-data') + (uid ? `?uid=${uid}` : '');
-
- $('#player-table').DataTable({
- ajax: dataUrl,
- scrollY: ($('.content-wrapper').height() - $('.content-header').outerHeight()) * 0.7,
- fnDrawCallback: () => {
- $('[data-toggle="tooltip"]').tooltip();
- },
- columnDefs: [
- {
- targets: 0,
- data: 'pid',
- width: '1%'
- },
- {
- targets: 1,
- data: 'uid',
- render: (data, type, row) => {
- return `${data}`;
- }
- },
- {
- targets: 2,
- data: 'player_name'
- },
- {
- targets: 3,
- data: 'preference',
- render: data => {
- return `
- `;
- }
- },
- {
- targets: 4,
- searchable: false,
- orderable: false,
- render: (data, type, row) => {
- const html = { steve: '', alex: '', cape: '' };
- ['steve', 'alex', 'cape'].forEach(textureType => {
- if (row['tid_' + textureType] === 0) {
- html[textureType] = ``;
- } else {
- html[textureType] = `
-
-
- `;
- }
- });
- return html.steve + html.alex + html.cape;
- }
- },
- {
- targets: 5,
- data: 'last_modified'
- },
- {
- targets: 6,
- searchable: false,
- orderable: false,
- render: (data, type, row) => {
- return `
-
-
-
-
- ${trans('admin.deletePlayer')}`;
- }
- }
- ]
- });
-}
-
-function initPluginsTable() {
- return $('#plugin-table').DataTable({
- ajax: url('admin/plugins/data'),
- fnDrawCallback: () => {
- $('[data-toggle="tooltip"]').tooltip();
- },
- columnDefs: [
- {
- targets: 0,
- data: 'title'
- },
- {
- targets: 1,
- data: 'description',
- width: '35%'
- },
- {
- targets: 2,
- data: 'author',
- render: data => {
- if (data.url === '' || data.url === null) {
- return data.author;
- } else {
- return `${data.author}`;
- }
- }
- },
- {
- targets: 3,
- data: 'version'
- },
- {
- targets: 4,
- data: 'status'
- },
- {
- targets: 5,
- data: 'operations',
- searchable: false,
- orderable: false,
- render: (data, type, row) => {
- let switchEnableButton, configViewButton;
- if (data.enabled) {
- switchEnableButton = `
- ${trans('admin.disablePlugin')}`;
- } else {
- switchEnableButton = `
- ${trans('admin.enablePlugin')}`;
- }
- if (data.enabled && data.hasConfigView) {
- configViewButton = `
- ${trans('admin.configurePlugin')}`;
- } else {
- configViewButton = `
- ${trans('admin.configurePlugin')}`;
- }
- const deletePluginButton = `
- ${trans('admin.deletePlugin')}`;
- return switchEnableButton + configViewButton + deletePluginButton;
- }
- }
- ]
- });
-}
-
-if (process.env.NODE_ENV === 'test') {
- module.exports = {
- initUsersTable,
- initPlayersTable,
- initPluginsTable,
- };
-}
diff --git a/resources/assets/src/js/admin/users.js b/resources/assets/src/js/admin/users.js
index 4074823f..e69c52e0 100644
--- a/resources/assets/src/js/admin/users.js
+++ b/resources/assets/src/js/admin/users.js
@@ -1,5 +1,122 @@
'use strict';
+if ($('#user-table').length === 1) {
+ $(document).ready(initUsersTable);
+}
+
+function initUsersTable() {
+ const specificUid = getQueryString('uid');
+ const query = specificUid ? `?uid=${specificUid}` : '';
+
+ $('#user-table').DataTable({
+ ajax: url(`admin/user-data${query}`),
+ scrollY: ($('.content-wrapper').height() - $('.content-header').outerHeight()) * 0.7,
+ fnDrawCallback: () => $('[data-toggle="tooltip"]').tooltip(),
+ rowCallback: (row, data) => $(row).attr('id', `user-${data.uid}`),
+ columnDefs: usersTableColumnDefs
+ });
+}
+
+const userPermissions = {
+ '-1': 'banned',
+ '0': 'normal',
+ '1': 'admin',
+ '2': 'superAdmin'
+};
+
+const usersTableColumnDefs = [
+ {
+ targets: 0,
+ data: 'uid',
+ width: '1%'
+ },
+ {
+ targets: 1,
+ data: 'email'
+ },
+ {
+ targets: 2,
+ data: 'nickname'
+ },
+ {
+ targets: 3,
+ data: 'score',
+ render: data => ``
+ },
+ {
+ targets: 4,
+ data: 'players_count',
+ searchable: false,
+ orderable: false,
+ render: (data, type, row) => `${data}`
+ },
+ {
+ targets: 5,
+ data: 'permission',
+ className: 'status',
+ render: data => trans('admin.' + userPermissions[data])
+ },
+ {
+ targets: 6,
+ data: 'register_at'
+ },
+ {
+ targets: 7,
+ data: 'operations',
+ searchable: false,
+ orderable: false,
+ render: renderUsersTableOperations
+ }
+];
+
+function renderUsersTableOperations(currentUserPermission, type, row) {
+ let adminOption = '', bannedOption = '', deleteUserButton;
+
+ if (row.permission !== 2) {
+ // Only SUPER admins are allowed to set/unset admins
+ if (currentUserPermission === 2) {
+ const adminStatus = row.permission === 1 ? 'admin' : 'normal';
+ adminOption = `
+ ${ adminStatus === 'admin' ? trans('admin.unsetAdmin') : trans('admin.setAdmin') }
+ `;
+ }
+
+ const banStatus = row.permission === -1 ? 'banned' : 'normal';
+ bannedOption = `
+ ${ banStatus === 'banned' ? trans('admin.unban') : trans('admin.ban') }
+ `;
+ }
+
+ if (currentUserPermission === 2) {
+ if (row.permission === 2) {
+ deleteUserButton = `${trans('admin.deleteUser')}`;
+ } else {
+ deleteUserButton = `${trans('admin.deleteUser')}`;
+ }
+ } else {
+ if (row.permission === 1 || row.permission === 2) {
+ deleteUserButton = `${trans('admin.deleteUser')}`;
+ } else {
+ deleteUserButton = `${trans('admin.deleteUser')}`;
+ }
+ }
+
+ return `
+
+
+
+
+ ${deleteUserButton}`;
+}
+
async function changeUserEmail(uid) {
const dom = $(`tr#user-${uid} > td:nth-child(2)`);
let newUserEmail = '';
@@ -217,6 +334,7 @@ $('body').on('keypress', '.score', function(event){
if (process.env.NODE_ENV === 'test') {
module.exports = {
+ initUsersTable,
changeUserPwd,
changeBanStatus,
changeUserEmail,
diff --git a/resources/assets/src/sass/admin.scss b/resources/assets/src/sass/admin.scss
index 685f3627..d07c9126 100644
--- a/resources/assets/src/sass/admin.scss
+++ b/resources/assets/src/sass/admin.scss
@@ -24,6 +24,8 @@ td {
img {
margin-left: 10px;
}
+
+ cursor: pointer;
}
a:first-child > img {
diff --git a/resources/lang/en/locale.js b/resources/lang/en/locale.js
index 91040913..40665440 100644
--- a/resources/lang/en/locale.js
+++ b/resources/lang/en/locale.js
@@ -140,8 +140,8 @@
newUserPassword: 'Please enter the new password:',
deleteUserNotice: 'Are you sure to delete this user? It\' permanent.',
scoreTip: 'Press ENTER to submit new score',
- doubleClickToSeeUser: 'Double click to see info of this user',
- doubleClickToSeePlayers: 'Double click to see his/her players',
+ inspectHisOwner: 'Click to inspect the owner of this player',
+ inspectHisPlayers: 'Click to inspect the players he owns',
// Status
banned: 'Banned',
diff --git a/resources/lang/zh_CN/locale.js b/resources/lang/zh_CN/locale.js
index df98ee6a..860aa3ef 100644
--- a/resources/lang/zh_CN/locale.js
+++ b/resources/lang/zh_CN/locale.js
@@ -142,8 +142,8 @@
newUserPassword: '请输入新密码:',
deleteUserNotice: '真的要删除此用户吗?此操作不可恢复',
scoreTip: '输入修改后的积分,回车提交',
- doubleClickToSeeUser: '双击可查看该用户的信息',
- doubleClickToSeePlayers: '双击可查看该用户的角色',
+ inspectHisOwner: '点击查看该角色的所有者',
+ inspectHisPlayers: '点击查看该用户的角色',
// Status
banned: '封禁',