added paginated users table

This commit is contained in:
Rohan Sircar 2020-07-24 11:31:11 +05:30
parent b6c4cb1575
commit e569420ca5
14 changed files with 213 additions and 185 deletions

View File

@ -1,6 +1,7 @@
{ {
"dependencies": { "dependencies": {
"@types/bootbox": "^5.2.0", "@types/bootbox": "^5.2.0",
"@types/datatables.net": "^1.10.19",
"@types/dompurify": "^2.0.0", "@types/dompurify": "^2.0.0",
"@types/jquery": "^3.3.31", "@types/jquery": "^3.3.31",
"@types/markdown-it": "^0.0.9", "@types/markdown-it": "^0.0.9",

View File

@ -4,18 +4,24 @@ import log from "loglevel";
import { AlertifyNotificationService } from "../common/service/AlertifyNotificationService"; import { AlertifyNotificationService } from "../common/service/AlertifyNotificationService";
import { stats } from "./pages/Home"; import { stats } from "./pages/Home";
import { Credentials } from "../common/global/Credentials"; import { Credentials } from "../common/global/Credentials";
import { getOtherUsers } from "../common/ajax/Users";
import { viewUsers } from "./pages/user/ViewUsers";
log.setLevel("TRACE"); log.setLevel("TRACE");
const es = EncryptionServiceFactory.getEncryptionService(); const es = EncryptionServiceFactory.getEncryptionService();
const ns = new AlertifyNotificationService(); const ns = new AlertifyNotificationService();
const authToken = Credentials.authToken const authToken = Credentials.authToken;
$("#changePassphraseForm").on("submit", (event) => { $("#changePassphraseForm").on("submit", (event) => {
event.preventDefault(); event.preventDefault();
changePassphrase(es, ns, authToken); changePassphrase(es, ns, authToken);
}); });
const pathMatcher = (path: string) => window.location.pathname == path const pathMatcher = (path: string) => window.location.pathname == path;
if(pathMatcher("/admin")) { if (pathMatcher("/admin")) {
stats() stats();
}
if (pathMatcher("/admin/users")) {
// $("#usersTableBody").html("");
viewUsers(authToken);
} }

View File

@ -0,0 +1,35 @@
import moment from "moment";
import { capitalize } from "../../../common/util/Util";
export async function viewUsers(authToken: string) {
// const users = await getOtherUsers(authToken);
const usersTable = $("#usersTable").DataTable({
ajax: {
url: "/api/admin/get/users",
headers: {
"X-AUTH-TOKEN": authToken,
},
dataSrc: "",
},
columns: [
{ data: "id" },
{ data: "userName" },
{
data: "role",
render: (data: string) => {
return capitalize(data.replace("_", " ").toLowerCase());
},
},
{
data: "joinDate",
render: (data: string, type) => {
return type === "sort"
? data
: moment.utc(data).format("DD/MM/YY").toString();
},
},
],
lengthMenu: [2, 10, 25, 50, 75, 100],
});
}

View File

@ -8,7 +8,7 @@ import { StatsDTO } from "../dto/StatsDTO";
import { createApiHeaders } from "./util"; import { createApiHeaders } from "./util";
export async function getAllMessages(user: string, authToken: string) { export async function getAllMessages(user: string, authToken: string) {
let response = await fetch(`${Routes.Admin.getAllMessagesURL}${user}`, { let response = await fetch(`${Routes.Admin.getAllMessages}${user}`, {
method: "GET", method: "GET",
headers: createApiHeaders(authToken), headers: createApiHeaders(authToken),
}); });
@ -16,7 +16,7 @@ export async function getAllMessages(user: string, authToken: string) {
} }
async function getAllRegularUsers(authToken: string) { async function getAllRegularUsers(authToken: string) {
let response = await fetch(`${Routes.Admin.getAllRegularUsersURL}`, { let response = await fetch(`${Routes.Admin.getOtherUsers}`, {
method: "GET", method: "GET",
headers: createApiHeaders(authToken), headers: createApiHeaders(authToken),
}); });
@ -34,7 +34,7 @@ export async function sendReencryptedMessages(
// headers.append('Accept','application/json') // headers.append('Accept','application/json')
headers.append("Content-Type", "application/json"); headers.append("Content-Type", "application/json");
headers.append("X-AUTH-TOKEN", authToken); headers.append("X-AUTH-TOKEN", authToken);
fetch(Routes.Admin.reencryptURL, { fetch(Routes.Admin.reencrypt, {
method: "POST", method: "POST",
headers: headers, headers: headers,
body: JSON.stringify(rencryptionDTOs), body: JSON.stringify(rencryptionDTOs),
@ -74,6 +74,6 @@ export async function getStats(authToken: string) {
const response = await fetch("/api/stats/", { const response = await fetch("/api/stats/", {
headers: createApiHeaders(authToken), headers: createApiHeaders(authToken),
method: "GET", method: "GET",
}) });
return (await response.json()) as StatsDTO; return (await response.json()) as StatsDTO;
} }

View File

@ -0,0 +1,15 @@
import { Routes } from "../routes/Routes";
import { createApiHeaders } from "./util";
import { AdminUserDTO } from "../dto/AdminUserDTO";
export async function getOtherUsers(
authToken: string
): Promise<AdminUserDTO[]> {
const response = await fetch(Routes.Admin.getOtherUsers, {
method: "GET",
headers: createApiHeaders(authToken),
});
let data = (await response.json()) as AdminUserDTO[];
return data;
}

View File

@ -0,0 +1,6 @@
export interface AdminUserDTO {
id: number;
userName: string;
role: string;
joinDate: string;
}

View File

@ -1,5 +1,5 @@
export namespace Admin { export namespace Admin {
export const getAllMessagesURL = `/api/admin/get/messages/`; //hostAddress set in thymeleaf backend export const getAllMessages = `/api/admin/get/messages/`; //hostAddress set in thymeleaf backend
export const reencryptURL = `/api/admin/post/re-encrypt`; export const reencrypt = `/api/admin/post/re-encrypt`;
export const getAllRegularUsersURL = `/api/admin/get/users`; export const getOtherUsers = `/api/admin/get/users`;
} }

View File

@ -0,0 +1,16 @@
/**
* Capitalizes first letters of words in string.
* @param {string} str String to be modified
* @param {boolean=false} lower Whether all other letters should be lowercased
* @return {string}
* @usage
* capitalize('fix this string'); // -> 'Fix This String'
* capitalize('javaSCrIPT'); // -> 'JavaSCrIPT'
* capitalize('javaSCrIPT', true); // -> 'Javascript'
*/
export function capitalize(str: string, lower = false): string {
return (lower ? str.toLowerCase() : str).replace(
/(?:^|\s|["'([{])+\S/g,
(match) => match.toUpperCase()
);
}

View File

@ -1,33 +1,33 @@
.text-primary-dark { .text-primary-dark {
/* color: #67b2fd; */ /* color: #67b2fd; */
color: #7accff; color: #7accff;
} }
.border-left-primary-dark { .border-left-primary-dark {
border-left: 0.25rem solid #7accff !important; border-left: 0.25rem solid #7accff !important;
} }
.sidebar .nav-item .collapse .collapse-inner .collapse-item, .sidebar .nav-item .collapse .collapse-inner .collapse-item,
.sidebar .nav-item .collapsing .collapse-inner .collapse-item { .sidebar .nav-item .collapsing .collapse-inner .collapse-item {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
margin: 0 0.5rem; margin: 0 0.5rem;
display: block; display: block;
color: #fff; color: #fff;
text-decoration: none; text-decoration: none;
border-radius: 0.35rem; border-radius: 0.35rem;
white-space: nowrap; white-space: nowrap;
} }
.sidebar-dark .nav-item .nav-link i { .sidebar-dark .nav-item .nav-link i {
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
} }
.sidebar-dark .nav-item .nav-link { .sidebar-dark .nav-item .nav-link {
color: rgba(255, 255, 255, 0.95); color: rgba(255, 255, 255, 0.95);
} }
.sidebar-dark .nav-item .nav-link[data-toggle="collapse"]::after { .sidebar-dark .nav-item .nav-link[data-toggle="collapse"]::after {
color: rgba(255, 255, 255, 0.8); color: rgba(255, 255, 255, 0.8);
} }
.sidebar .nav-item .collapse .collapse-inner .collapse-item:hover, .sidebar .nav-item .collapse .collapse-inner .collapse-item:hover,
@ -40,7 +40,7 @@
} */ } */
.text-info { .text-info {
color: #5bd6e8 !important; color: #5bd6e8 !important;
} }
/* :root { /* :root {
@ -48,14 +48,18 @@
} */ } */
.sidebar-dark hr.sidebar-divider { .sidebar-dark hr.sidebar-divider {
border-top: 1px solid rgba(255, 255, 255, 0.5); border-top: 1px solid rgba(255, 255, 255, 0.5);
} }
body { body {
background: #333; background: #333;
color: #fff; color: #fff;
} }
#wrapper #content-wrapper { #wrapper #content-wrapper {
background-color: #333; background-color: #333;
}
table.table-bordered.dataTable {
border-right-width: 1px;
} }

View File

@ -0,0 +1,8 @@
label,
#usersTable_info,
.dataTables_paginate,
.paginate_button,
#usersTable_next,
#usersTable_previous {
color: white !important;
}

File diff suppressed because one or more lines are too long

View File

@ -12,9 +12,9 @@
<th:block th:include="fragments/admin :: headFragment"></th:block> <th:block th:include="fragments/admin :: headFragment"></th:block>
<style> <style>
.sidebar { /* .sidebar {
height: 100%; height: 100%;
} } */
</style> </style>
</head> </head>
<!-- TODO <!-- TODO
@ -49,7 +49,7 @@
<!-- Content Row --> <!-- Content Row -->
<div class="row"> <div class="row">
<div class="col-lg-10 offset-lg-1"> <div class="col">
<!-- Approach --> <!-- Approach -->
<div class="card bg-dark border border-dark text-white shadow mb-4"> <div class="card bg-dark border border-dark text-white shadow mb-4">
@ -57,156 +57,56 @@
<h6 class="m-0 font-weight-bold text-white">Users</h6> <h6 class="m-0 font-weight-bold text-white">Users</h6>
</div> </div>
<div class="card-body"> <div class="card-body">
<table data-toggle="table" class="text-white"> <div class="table-responsive">
<thead> <table data-toggle="table" class="table table-bordered text-white" width="100%"
<tr> cellspacing="0" id="usersTable">
<th>User ID</th> <thead>
<th>User Name</th> <tr>
<th>Role</th> <th>User ID</th>
<th>Registration Date</th> <th>User Name</th>
<th>Action</th> <th>Role</th>
</tr> <th>Registration Date</th>
</thead> <!-- <th>Action</th> -->
<tbody> </tr>
<tr> </thead>
<td>1</td> <tbody id="usersTableBody">
<td>Item 1</td>
<td>$1</td> </tbody>
<td></td> </table>
<td><button class="btn btn-info"><i </div>
class="fas fa-ellipsis-h"></i></button></td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
<tr>
<td>2</td>
<td>Item 2</td>
<td>$2</td>
</tr>
</tbody>
</table>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- /.container-fluid -->
</div> </div>
<!-- /.container-fluid --> <!-- End of Main Content -->
<div th:include="fragments/admin :: footer"></div>
</div> </div>
<!-- End of Main Content --> <!-- End of Content Wrapper -->
<div th:include="fragments/admin :: footer"></div>
</div> </div>
<!-- End of Content Wrapper --> <!-- End of Page Wrapper -->
</div> <th:block th:include="fragments/admin :: modal"></th:block>
<!-- End of Page Wrapper --> <div th:if="false">
<th:block th:include="admin :: modal"></th:block>
</div>
<th:block th:include="fragments/admin :: modal"></th:block> <template id="users-table-template">
<div th:if="false"> <tr>
<th:block th:include="admin :: modal"></th:block> <td>{{id}}</td>
</div> <td>{{userName}}</td>
<td>{{role}}</td>
<template id="users-table-template"> <td>{{joinDate}}</td>
<tr> <td><button class="btn btn-info"><i class="fas fa-ellipsis-h"></i></button></td>
<td>{{id}}</td> </tr>
<td>{{userName}}</td> </template>
<td>{{role}}</td>
<td>{{joinDate}}</td>
<td></td>
</tr>
</template>
</body> </body>

View File

@ -17,33 +17,62 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css"
th:if="false"> th:if="false">
<th:block th:fragment="headFragment">
<script th:src="@{/js/adminBundle.js}" src="../../static/js/adminBundle.js" defer="defer"></script>
<script th:src="@{/js/admin.js}" src="../../static/js/admin.js" defer="defer"></script>
<script th:src="@{/js/sb-admin-2.js}" src="../../static/js/sb-admin-2.js" defer="defer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.js" defer></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous" defer></script> <th:block th:fragment="headFragment">
<!-- <script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous" defer></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"
defer></script> defer></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"
defer></script> defer></script>
<script src="https://unpkg.com/bootstrap-table@1.17.1/dist/bootstrap-table.min.js" defer></script> <!-- <script src="https://unpkg.com/bootstrap-table@1.17.1/dist/bootstrap-table.min.js" defer></script> -->
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/js/jquery.dataTables.min.js"
integrity="sha512-BkpSL20WETFylMrcirBahHfSnY++H2O1W+UnEEO4yNIl+jI2+zowyoGJpbtk6bx97fBXf++WJHSSK2MV4ghPcg=="
crossorigin="anonymous"></script> -->
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/js/dataTables.bootstrap.min.js"
integrity="sha512-F0E+jKGaUC90odiinxkfeS3zm9uUT1/lpusNtgXboaMdA3QFMUez0pBmAeXGXtGxoGZg3bLmrkSkbK1quua4/Q=="
crossorigin="anonymous"></script> -->
<!-- <link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/css/dataTables.bootstrap4.min.css"
integrity="sha512-PT0RvABaDhDQugEbpNMwgYBCnGCiTZMh9yOzUsJHDgl/dMhD9yjHAwoumnUk3JydV3QTcIkNDuN40CJxik5+WQ=="
crossorigin="anonymous" /> -->
<script th:src="@{/js/adminBundle.js}" src="../../static/js/adminBundle.js" defer="defer"></script>
<!-- <script th:src="@{/js/admin.js}" src="../../static/js/admin.js" defer="defer"></script> -->
<script th:src="@{/js/sb-admin-2.js}" src="../../static/js/sb-admin-2.js" defer="defer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.js" defer></script>
<link href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" rel="stylesheet"> <link href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" rel="stylesheet">
<link href="http://fonts.googleapis.com/css?family=Roboto:400,700,300" rel="stylesheet" type="text/css"> <link href="http://fonts.googleapis.com/css?family=Roboto:400,700,300" rel="stylesheet" type="text/css">
<link th:href="@{/css/sb-admin-2.css}" href="../../static/css/sb-admin-2.css" rel="stylesheet"> <link th:href="@{/css/sb-admin-2.css}" href="../../static/css/sb-admin-2.css" rel="stylesheet">
<link th:href="@{/css/admin-custom.css}" href="../../static/css/admin-custom.css" rel="stylesheet">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css"
integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous"> integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.17.1/dist/bootstrap-table.min.css"> <!-- <link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.17.1/dist/bootstrap-table.min.css"> -->
<!-- <link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.21/css/jquery.dataTables.min.css"
integrity="sha512-1k7mWiTNoyx2XtmI96o+hdjP8nn0f3Z2N4oF/9ZZRgijyV4omsKOXEnqL1gKQNPy2MTSP9rIEWGcH/CInulptA=="
crossorigin="anonymous" /> -->
<!-- <link rel="stylesheet" th:href="@{/css/admin-table.css}" href="../../../resources/static/css/admin-table.css"> -->
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.10.21/datatables.min.css" />
<script type="text/javascript" src="https://cdn.datatables.net/v/bs4/dt-1.10.21/datatables.min.js"></script>
<link rel="stylesheet" th:href="@{/css/dataTables.bootstrap4.min.css}"
href="../../../resources/static/css/dataTables.bootstrap4.min.css">
<link th:href="@{/css/admin-custom.css}" href="../../static/css/admin-custom.css" rel="stylesheet">
</th:block> </th:block>

View File

@ -9,6 +9,13 @@
dependencies: dependencies:
"@types/jquery" "*" "@types/jquery" "*"
"@types/datatables.net@^1.10.19":
version "1.10.19"
resolved "https://registry.yarnpkg.com/@types/datatables.net/-/datatables.net-1.10.19.tgz#17c5f94433f761086131c6c8dc055a0e1099d1f9"
integrity sha512-WuzgytEmsIpVYZbkce+EvK1UqBI7/cwcC/WgYeAtXdq2zi+yWzJwMT5Yb6irAiOi52DBjeAEeRt3bYzFYvHWCQ==
dependencies:
"@types/jquery" "*"
"@types/dompurify@^2.0.0": "@types/dompurify@^2.0.0":
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.0.0.tgz#9616caa5bf2569aea2e4889d4f929d968c081b40" resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.0.0.tgz#9616caa5bf2569aea2e4889d4f929d968c081b40"