User Fetch Fix + Routes + More Fixes
This commit is contained in:
parent
fffd0bdbbf
commit
e5d504b6c7
44
admin/dist/main.js
vendored
44
admin/dist/main.js
vendored
File diff suppressed because one or more lines are too long
7
admin/src/404.js
Normal file
7
admin/src/404.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
export default class View404 extends React.Component {
|
||||||
|
render() {
|
||||||
|
return <b>404 Not found</b>
|
||||||
|
}
|
||||||
|
}
|
@ -37,4 +37,8 @@ export default class API {
|
|||||||
async getNotifications() {
|
async getNotifications() {
|
||||||
return this.apiCall("notifications/fetch");
|
return this.apiCall("notifications/fetch");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchUsers(pageNum = 1) {
|
||||||
|
return this.apiCall("user/fetch", { page: pageNum });
|
||||||
|
}
|
||||||
};
|
};
|
@ -0,0 +1,2 @@
|
|||||||
|
.page-link { color: #222629; }
|
||||||
|
.page-link:hover { color: black; }
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import './include/index.css';
|
|
||||||
import './include/adminlte.min.css';
|
import './include/adminlte.min.css';
|
||||||
|
import './include/index.css';
|
||||||
import API from './api.js';
|
import API from './api.js';
|
||||||
import Header from './header.js';
|
import Header from './header.js';
|
||||||
import Sidebar from './sidebar.js';
|
import Sidebar from './sidebar.js';
|
||||||
@ -9,7 +9,9 @@ import UserOverview from './users.js';
|
|||||||
import Overview from './overview.js'
|
import Overview from './overview.js'
|
||||||
import Icon from "./icon";
|
import Icon from "./icon";
|
||||||
import Dialog from "./dialog";
|
import Dialog from "./dialog";
|
||||||
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
|
import {BrowserRouter as Router, Route} from 'react-router-dom'
|
||||||
|
import View404 from "./404";
|
||||||
|
import Switch from "react-router-dom/es/Switch";
|
||||||
|
|
||||||
class AdminDashboard extends React.Component {
|
class AdminDashboard extends React.Component {
|
||||||
|
|
||||||
@ -21,12 +23,14 @@ class AdminDashboard extends React.Component {
|
|||||||
dialog: { onClose: () => this.hideDialog() },
|
dialog: { onClose: () => this.hideDialog() },
|
||||||
notifications: { }
|
notifications: { }
|
||||||
};
|
};
|
||||||
|
this.controlObj = {
|
||||||
|
showDialog: this.showDialog.bind(this),
|
||||||
|
api: this.api
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdate() {
|
onUpdate() {
|
||||||
if (this.state.loaded) {
|
this.fetchNotifications();
|
||||||
this.fetchNotifications();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showDialog(message, title) {
|
showDialog(message, title) {
|
||||||
@ -43,7 +47,7 @@ class AdminDashboard extends React.Component {
|
|||||||
if (!res.success) {
|
if (!res.success) {
|
||||||
this.showDialog("Error fetching notifications: " + res.msg, "Error fetching notifications");
|
this.showDialog("Error fetching notifications: " + res.msg, "Error fetching notifications");
|
||||||
} else {
|
} else {
|
||||||
this.setState({...this.state, notifications: res.notifications});
|
this.setState({...this.state, notifications: res.notifications });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -54,7 +58,7 @@ class AdminDashboard extends React.Component {
|
|||||||
document.location = "/admin";
|
document.location = "/admin";
|
||||||
} else {
|
} else {
|
||||||
this.fetchNotifications();
|
this.fetchNotifications();
|
||||||
setInterval(this.onUpdate.bind(this), 60000);
|
setInterval(this.onUpdate.bind(this), 60*1000);
|
||||||
this.setState({...this.state, loaded: true});
|
this.setState({...this.state, loaded: true});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -66,29 +70,16 @@ class AdminDashboard extends React.Component {
|
|||||||
return <b>Loading… <Icon icon={"spinner"} /></b>
|
return <b>Loading… <Icon icon={"spinner"} /></b>
|
||||||
}
|
}
|
||||||
|
|
||||||
const controlObj = {
|
|
||||||
notifications: this.state.notifications,
|
|
||||||
showDialog: this.showDialog.bind(this),
|
|
||||||
api: this.api
|
|
||||||
};
|
|
||||||
|
|
||||||
const createView = (view) => {
|
|
||||||
controlObj.currentView = view;
|
|
||||||
switch (view) {
|
|
||||||
case "users":
|
|
||||||
return <UserOverview {...controlObj} />;
|
|
||||||
case "dashboard":
|
|
||||||
default:
|
|
||||||
return <Overview {...controlObj} />;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return <Router>
|
return <Router>
|
||||||
<Header {...controlObj} />
|
<Header {...this.controlObj} notifications={this.state.notifications} />
|
||||||
<Sidebar {...controlObj} />
|
<Sidebar {...this.controlObj} notifications={this.state.notifications} />
|
||||||
<div className={"content-wrapper p-2"}>
|
<div className={"content-wrapper p-2"}>
|
||||||
<section className={"content"}>
|
<section className={"content"}>
|
||||||
<Route path={"/admin/:view"} component={(obj) => createView(obj.match.params.view)}/>
|
<Switch>
|
||||||
|
<Route path={"/admin/dashboard"}><Overview {...this.controlObj} /></Route>
|
||||||
|
<Route path={"/admin/users"}><UserOverview {...this.controlObj} /></Route>
|
||||||
|
<Route path={"*"}><View404 /></Route>
|
||||||
|
</Switch>
|
||||||
<Dialog {...this.state.dialog}/>
|
<Dialog {...this.state.dialog}/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -97,6 +88,6 @@ class AdminDashboard extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AdminDashboard />,
|
<AdminDashboard />,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
|
@ -2,6 +2,7 @@ import * as React from "react";
|
|||||||
|
|
||||||
export default class Overview extends React.Component {
|
export default class Overview extends React.Component {
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div>Overview</div>
|
return <div>Overview</div>
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,180 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import Icon from "./icon";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import {getPeriodString} from "./global";
|
||||||
|
|
||||||
export default class UserOverview extends React.Component {
|
export default class UserOverview extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.parent = {
|
||||||
|
showDialog: props.showDialog || function() {},
|
||||||
|
api: props.api,
|
||||||
|
};
|
||||||
|
this.state = {
|
||||||
|
loaded: false,
|
||||||
|
users: {
|
||||||
|
data: {},
|
||||||
|
page: 1,
|
||||||
|
pageCount: 1
|
||||||
|
},
|
||||||
|
groups: {
|
||||||
|
data: {},
|
||||||
|
page: 1,
|
||||||
|
pageCount: 1
|
||||||
|
},
|
||||||
|
errors: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchUsers(page) {
|
||||||
|
page = page || this.state.users.page;
|
||||||
|
this.setState({ ...this.state, users: { ...this.state.users, data: { }, pageCount: 1 } });
|
||||||
|
this.parent.api.fetchUsers(page).then((res) => {
|
||||||
|
if (res.success) {
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
loaded: true,
|
||||||
|
users: {
|
||||||
|
data: res.users,
|
||||||
|
pageCount: res.pageCount,
|
||||||
|
page: page
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
loaded: true,
|
||||||
|
errors: this.state.errors.slice().push(res.msg)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.setState({ ...this.state, loaded: false });
|
||||||
|
this.fetchUsers(1);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div>UserOverview</div>
|
|
||||||
|
if (!this.state.loaded) {
|
||||||
|
return <div className={"text-center mt-4"}>
|
||||||
|
<h3>Loading… <Icon icon={"spinner"}/></h3>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<div className="content-header">
|
||||||
|
<div className="container-fluid">
|
||||||
|
<div className="row mb-2">
|
||||||
|
<div className="col-sm-6">
|
||||||
|
<h1 className="m-0 text-dark">Users & Groups</h1>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-6">
|
||||||
|
<ol className="breadcrumb float-sm-right">
|
||||||
|
<li className="breadcrumb-item"><Link to={"/admin/dashboard"}>Home</Link></li>
|
||||||
|
<li className="breadcrumb-item active">Users</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
<div className={"content-fluid"}>
|
||||||
|
<div className={"row"}>
|
||||||
|
<div className={"col-lg-6"}>
|
||||||
|
{ this.createUserCard() }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
createUserCard() {
|
||||||
|
|
||||||
|
let userRows = [];
|
||||||
|
for (let uid in this.state.users.data) {
|
||||||
|
if (!this.state.users.data.hasOwnProperty(uid)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let user = this.state.users.data[uid];
|
||||||
|
let groups = [];
|
||||||
|
|
||||||
|
for (let groupId in user.groups) {
|
||||||
|
if (user.groups.hasOwnProperty(groupId)) {
|
||||||
|
let groupName = user.groups[groupId];
|
||||||
|
let color = (groupId === "1" ? "danger" : "secondary");
|
||||||
|
groups.push(<span key={"group-" + groupId} className={"mr-1 badge badge-" + color}>{groupName}</span>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
userRows.push(
|
||||||
|
<tr key={"user-" + uid}>
|
||||||
|
<td>{user.name}</td>
|
||||||
|
<td>{user.email}</td>
|
||||||
|
<td>{groups}</td>
|
||||||
|
<td>{getPeriodString(user.registered_at)}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pages = [];
|
||||||
|
let previousDisabled = (this.state.users.page === 1 ? " disabled" : "");
|
||||||
|
let nextDisabled = (this.state.users.page >= this.state.users.pageCount ? " disabled" : "");
|
||||||
|
|
||||||
|
for (let i = 1; i <= this.state.users.pageCount; i++) {
|
||||||
|
let active = (this.state.users.page === i ? " active" : "");
|
||||||
|
pages.push(
|
||||||
|
<li key={"page-" + i} className={"page-item" + active}>
|
||||||
|
<a className={"page-link"} href={"#"} onClick={() => this.fetchUsers(i)}>
|
||||||
|
{i}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className={"card"}>
|
||||||
|
<div className={"card-header border-0"}>
|
||||||
|
<h3 className={"card-title"}>Users</h3>
|
||||||
|
<div className={"card-tools"}>
|
||||||
|
<a href={"#"} className={"btn btn-tool btn-sm"} onClick={() => this.fetchUsers()}>
|
||||||
|
<Icon icon={"sync"}/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"card-body table-responsive p-0"}>
|
||||||
|
<table className={"table table-striped table-valign-middle"}>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Groups</th>
|
||||||
|
<th>Registered</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{ userRows }
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<nav aria-label={""}>
|
||||||
|
<ul className={"pagination p-2 m-0 justify-content-end"}>
|
||||||
|
<li className={"page-item" + previousDisabled}>
|
||||||
|
<a className={"page-link"} href={"#"} onClick={() => this.fetchUsers(this.state.users.page - 1)}>
|
||||||
|
Previous
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{ pages }
|
||||||
|
<li className={"page-item" + nextDisabled}>
|
||||||
|
<a className={"page-link"} href={"#"} onClick={() => this.fetchUsers(this.state.users.page + 1)}>
|
||||||
|
Next
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ use \Api\Request;
|
|||||||
|
|
||||||
class Fetch extends Request {
|
class Fetch extends Request {
|
||||||
|
|
||||||
const SELECT_SIZE = 20;
|
const SELECT_SIZE = 10;
|
||||||
|
|
||||||
private int $userCount;
|
private int $userCount;
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ class Fetch extends Request {
|
|||||||
$groupId = intval($row["groupId"]);
|
$groupId = intval($row["groupId"]);
|
||||||
$groupName = $row["groupName"];
|
$groupName = $row["groupName"];
|
||||||
if (!isset($this->result["users"][$userId])) {
|
if (!isset($this->result["users"][$userId])) {
|
||||||
$this->result["users"][] = array(
|
$this->result["users"][$userId] = array(
|
||||||
"uid" => $userId,
|
"uid" => $userId,
|
||||||
"name" => $row["name"],
|
"name" => $row["name"],
|
||||||
"email" => $row["email"],
|
"email" => $row["email"],
|
||||||
@ -86,7 +86,7 @@ class Fetch extends Request {
|
|||||||
$this->result["users"][$userId]["groups"][$groupId] = $groupName;
|
$this->result["users"][$userId]["groups"][$groupId] = $groupName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->result["pages"] = intval(ceil($this->userCount / Fetch::SELECT_SIZE));
|
$this->result["pageCount"] = intval(ceil($this->userCount / Fetch::SELECT_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->success;
|
return $this->success;
|
||||||
|
@ -2,276 +2,17 @@
|
|||||||
|
|
||||||
namespace Views\Admin;
|
namespace Views\Admin;
|
||||||
|
|
||||||
// Source: https://adminlte.io/themes/v3/
|
|
||||||
|
|
||||||
use Documents\Document404\Body404;
|
|
||||||
use Elements\Body;
|
use Elements\Body;
|
||||||
use Elements\Script;
|
use Elements\Script;
|
||||||
use Elements\View;
|
|
||||||
use Views\View404;
|
|
||||||
|
|
||||||
class AdminDashboardBody extends Body {
|
class AdminDashboardBody extends Body {
|
||||||
|
|
||||||
private array $errorMessages;
|
|
||||||
private array $notifications;
|
|
||||||
|
|
||||||
public function __construct($document) {
|
public function __construct($document) {
|
||||||
parent::__construct($document);
|
parent::__construct($document);
|
||||||
$this->errorMessages = array();
|
|
||||||
$this->notifications = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getNotifications() : array {
|
|
||||||
$req = new \Api\Notifications\Fetch($this->getDocument()->getUser());
|
|
||||||
if(!$req->execute()) {
|
|
||||||
$this->errorMessages[] = $req->getLastError();
|
|
||||||
return array();
|
|
||||||
} else {
|
|
||||||
return $req->getResult()['notifications'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getHeader() {
|
|
||||||
|
|
||||||
// Locale
|
|
||||||
$home = L("Home");
|
|
||||||
$search = L("Search");
|
|
||||||
|
|
||||||
// Icons
|
|
||||||
$iconMenu = $this->createIcon("bars");
|
|
||||||
$iconNotification = $this->createIcon("bell", "far");
|
|
||||||
$iconSearch = $this->createIcon("search");
|
|
||||||
$iconMail = $this->createIcon("envelope", "fas");
|
|
||||||
|
|
||||||
// Notifications
|
|
||||||
$numNotifications = count($this->notifications);
|
|
||||||
if ($numNotifications === 0) {
|
|
||||||
$notificationText = L("No new notifications");
|
|
||||||
} else if($numNotifications === 1) {
|
|
||||||
$notificationText = L("1 new notification");
|
|
||||||
} else {
|
|
||||||
$notificationText = sprintf(L("%d new notification"), $numNotifications);
|
|
||||||
}
|
|
||||||
|
|
||||||
$html =
|
|
||||||
"<nav class=\"main-header navbar navbar-expand navbar-white navbar-light\">
|
|
||||||
|
|
||||||
<!-- Left navbar links -->
|
|
||||||
<ul class=\"navbar-nav\">
|
|
||||||
<li class=\"nav-item\">
|
|
||||||
<a class=\"nav-link\" data-widget=\"pushmenu\" href=\"#\" role=\"button\">$iconMenu</a>
|
|
||||||
</li>
|
|
||||||
<li class=\"nav-item d-none d-sm-inline-block\">
|
|
||||||
<a href=\"/\" class=\"nav-link\">$home</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<!-- SEARCH FORM -->
|
|
||||||
<form class=\"form-inline ml-3\">
|
|
||||||
<div class=\"input-group input-group-sm\">
|
|
||||||
<input class=\"form-control form-control-navbar\" type=\"search\" placeholder=\"$search\" aria-label=\"$search\">
|
|
||||||
<div class=\"input-group-append\">
|
|
||||||
<button class=\"btn btn-navbar\" type=\"submit\">
|
|
||||||
$iconSearch
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Right navbar links -->
|
|
||||||
<ul class=\"navbar-nav ml-auto\">
|
|
||||||
<!-- Notifications Dropdown Menu -->
|
|
||||||
<li class=\"nav-item dropdown\">
|
|
||||||
<a class=\"nav-link\" data-toggle=\"dropdown\" href=\"#\">
|
|
||||||
$iconNotification
|
|
||||||
<span class=\"badge badge-warning navbar-badge\">$numNotifications</span>
|
|
||||||
</a>
|
|
||||||
<div class=\"dropdown-menu dropdown-menu-lg dropdown-menu-right\">
|
|
||||||
<span class=\"dropdown-item dropdown-header\">$notificationText</span>
|
|
||||||
<div class=\"dropdown-divider\"></div>";
|
|
||||||
|
|
||||||
// Notifications
|
|
||||||
$i = 0;
|
|
||||||
foreach($this->notifications as $notification) {
|
|
||||||
|
|
||||||
$title = $notification["title"];
|
|
||||||
$notificationId = $notification["uid"];
|
|
||||||
$createdAt = getPeriodString($notification["created_at"]);
|
|
||||||
|
|
||||||
if ($i > 0) {
|
|
||||||
$html .= "<div class=\"dropdown-divider\"></div>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$html .=
|
|
||||||
"<a href=\"#\" class=\"dropdown-item\" data-id=\"$notificationId\">
|
|
||||||
$iconMail<span class=\"ml-2\">$title</span>
|
|
||||||
<span class=\"float-right text-muted text-sm\">$createdAt</span>
|
|
||||||
</a>";
|
|
||||||
|
|
||||||
$i++;
|
|
||||||
if ($i >= 5) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$html .= "<a href=\"#\" class=\"dropdown-item dropdown-footer\">See All Notifications</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>";
|
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getSidebar() {
|
|
||||||
|
|
||||||
$logout = L("Logout");
|
|
||||||
$iconLogout = $this->createIcon("arrow-left", "fas", "nav-icon");
|
|
||||||
|
|
||||||
$menuEntries = array(
|
|
||||||
"dashboard" => array(
|
|
||||||
"name" => "Dashboard",
|
|
||||||
"icon" => "tachometer-alt"
|
|
||||||
),
|
|
||||||
"users" => array(
|
|
||||||
"name" => "Users",
|
|
||||||
"icon" => "users"
|
|
||||||
),
|
|
||||||
"settings" => array(
|
|
||||||
"name" => "Settings",
|
|
||||||
"icon" => "tools"
|
|
||||||
),
|
|
||||||
"help" => array(
|
|
||||||
"name" => "Help",
|
|
||||||
"icon" => "question-circle"
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
$notificationCount = count($this->notifications);
|
|
||||||
if ($notificationCount > 0) {
|
|
||||||
$menuEntries["dashboard"]["badge"] = array("type" => "warning", "value" => $notificationCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentView = $_GET["view"] ?? "dashboard";
|
|
||||||
|
|
||||||
$html =
|
|
||||||
"<aside class=\"main-sidebar sidebar-dark-primary elevation-4\">
|
|
||||||
<!-- Brand Logo -->
|
|
||||||
<a href=\"/admin\" class=\"brand-link\">
|
|
||||||
<img src=\"/img/web_base_logo.png\" alt=\"WebBase Logo\" class=\"brand-image img-circle elevation-3\"
|
|
||||||
style=\"opacity: .8\">
|
|
||||||
<span class=\"brand-text font-weight-light\">WebBase</span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Sidebar -->
|
|
||||||
<div class=\"sidebar\">
|
|
||||||
|
|
||||||
<!-- Sidebar Menu -->
|
|
||||||
<nav class=\"mt-2\">
|
|
||||||
<ul class=\"nav nav-pills nav-sidebar flex-column\" data-widget=\"treeview\" role=\"menu\" data-accordion=\"false\">";
|
|
||||||
|
|
||||||
foreach($menuEntries as $view => $menuEntry) {
|
|
||||||
$name = L($menuEntry["name"]);
|
|
||||||
$icon = $this->createIcon($menuEntry["icon"], "fas", "nav-icon");
|
|
||||||
$active = ($currentView === $view) ? " active" : "";
|
|
||||||
$badge = $menuEntry["badge"] ?? "";
|
|
||||||
if($badge) {
|
|
||||||
$badgeType = $badge["type"];
|
|
||||||
$badgeValue = $badge["value"];
|
|
||||||
$badge = "<span class=\"badge badge-$badgeType right\">$badgeValue</span>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$html .=
|
|
||||||
"<li class=\"nav-item\">
|
|
||||||
<a href=\"?view=$view\" class=\"nav-link$active\">
|
|
||||||
$icon<p>$name$badge</p>
|
|
||||||
</a>
|
|
||||||
</li>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$html .= "<li class=\"nav-item\">
|
|
||||||
<a href=\"#\" id=\"btnLogout\" class=\"nav-link\">
|
|
||||||
$iconLogout<p>$logout</p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</aside>";
|
|
||||||
|
|
||||||
return $html;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getView() {
|
|
||||||
|
|
||||||
$views = array(
|
|
||||||
"dashboard" => Dashboard::class,
|
|
||||||
"users" => UserOverview::class,
|
|
||||||
"404" => View404::class,
|
|
||||||
);
|
|
||||||
|
|
||||||
$currentView = $_GET["view"] ?? "dashboard";
|
|
||||||
if (!isset($views[$currentView])) {
|
|
||||||
$currentView = "404";
|
|
||||||
}
|
|
||||||
|
|
||||||
$view = new $views[$currentView]($this->getDocument());
|
|
||||||
assert($view instanceof View);
|
|
||||||
$code = $view->getCode();
|
|
||||||
|
|
||||||
if ($view instanceof AdminView) {
|
|
||||||
$this->errorMessages = array_merge($this->errorMessages, $view->getErrorMessages());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function loadView() {
|
|
||||||
parent::loadView();
|
|
||||||
|
|
||||||
$head = $this->getDocument()->getHead();
|
|
||||||
// $head->addJS("/js/admin.min.js");
|
|
||||||
// $head->loadAdminlte();
|
|
||||||
|
|
||||||
// $this->notifications = $this->getNotifications();
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getContent() {
|
|
||||||
|
|
||||||
$view = $this->getView();
|
|
||||||
$html = "<div class=\"content-wrapper p-2\">";
|
|
||||||
|
|
||||||
foreach($this->errorMessages as $errorMessage) {
|
|
||||||
$html .= $this->createErrorText($errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
$html .= $view;
|
|
||||||
$html .= "</div>";
|
|
||||||
return $html;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCode() {
|
public function getCode() {
|
||||||
$html = parent::getCode();
|
$html = parent::getCode();
|
||||||
|
|
||||||
// $this->getDocument()->getHead()->addJS("/js/admin.min.js");
|
|
||||||
|
|
||||||
/*
|
|
||||||
$header = $this->getHeader();
|
|
||||||
$sidebar = $this->getSidebar();
|
|
||||||
$content = $this->getContent();
|
|
||||||
|
|
||||||
|
|
||||||
$html .=
|
|
||||||
"<!-- LICENSE: /docs/LICENSE_ADMINLTE -->
|
|
||||||
<body class=\"hold-transition sidebar-mini layout-fixed\">
|
|
||||||
<div class=\"wrapper\">
|
|
||||||
$header
|
|
||||||
$sidebar
|
|
||||||
$content
|
|
||||||
</div>
|
|
||||||
</body>";
|
|
||||||
*/
|
|
||||||
|
|
||||||
$script = new Script(Script::MIME_TEXT_JAVASCRIPT, "/js/admin.min.js");
|
$script = new Script(Script::MIME_TEXT_JAVASCRIPT, "/js/admin.min.js");
|
||||||
$html .= "<body><div class=\"wrapper\" id=\"root\">$script</div></body>";
|
$html .= "<body><div class=\"wrapper\" id=\"root\">$script</div></body>";
|
||||||
return $html;
|
return $html;
|
||||||
|
44
js/admin.min.js
vendored
44
js/admin.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user