Some more stuff
This commit is contained in:
parent
7124038b5b
commit
32df152ca7
124
admin/dist/main.js
vendored
124
admin/dist/main.js
vendored
File diff suppressed because one or more lines are too long
@ -1,7 +1,30 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import Icon from "./elements/icon";
|
||||||
|
|
||||||
export default class View404 extends React.Component {
|
export default class View404 extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return <b>404 Not found</b>
|
return <div className={"error-page"}>
|
||||||
|
<h2 className={"headline text-warning"}>404</h2>
|
||||||
|
<div className={"error-content"}>
|
||||||
|
<h3>
|
||||||
|
<Icon icon={"exclamation-triangle"} classes={"text-warning"}/> Oops! Page not found.
|
||||||
|
</h3>
|
||||||
|
<p>
|
||||||
|
We could not find the page you were looking for.
|
||||||
|
Meanwhile, you may <Link to={"/admin/dashboard"}>return to dashboard</Link> or try using the search form.
|
||||||
|
</p>
|
||||||
|
<form className={"search-form"} onSubmit={(e) => e.preventDefault()}>
|
||||||
|
<div className={"input-group"}>
|
||||||
|
<input type={"text"} name={"search"} className={"form-control"} placeholder={"Search"} />
|
||||||
|
<div className={"input-group-append"}>
|
||||||
|
<button type="submit" name="submit" className={"btn btn-warning"}>
|
||||||
|
<Icon icon={"search"}/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
18
admin/src/elements/alert.js
Normal file
18
admin/src/elements/alert.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import Icon from "./icon";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
|
||||||
|
export default function Alert(props) {
|
||||||
|
|
||||||
|
const onClose = props.onClose || function() { };
|
||||||
|
const title = props.title || "Untitled Alert";
|
||||||
|
const message = props.message || "Alert message";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={"alert alert-danger alert-dismissible"}>
|
||||||
|
<button type="button" className={"close"} data-dismiss={"alert"} aria-hidden={"true"} onClick={onClose}>×</button>
|
||||||
|
<h5><Icon icon={"ban"} classes={"icon"} /> {title}</h5>
|
||||||
|
{message}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -14,7 +14,12 @@ export default function Icon(props) {
|
|||||||
classes.push("fa-spin");
|
classes.push("fa-spin");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let newProps = {...props, className: classes.join(" ") };
|
||||||
|
delete newProps["classes"];
|
||||||
|
delete newProps["type"];
|
||||||
|
delete newProps["icon"];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<i className={classes.join(" ")} />
|
<i {...newProps} />
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -1,19 +1,15 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import Icon from "./icon";
|
import Icon from "./elements/icon";
|
||||||
import {useState} from "react";
|
import {useState} from "react";
|
||||||
import {getPeriodString} from "./global";
|
import {getPeriodString} from "./global";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
|
||||||
export default function Header(props) {
|
export default function Header(props) {
|
||||||
|
|
||||||
const parent = {
|
const parent = {
|
||||||
onChangeView: props.onChangeView || function() {},
|
|
||||||
notifications: props.notifications || { },
|
notifications: props.notifications || { },
|
||||||
};
|
};
|
||||||
|
|
||||||
function onChangeView(view) {
|
|
||||||
parent.onChangeView(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
const [dropdownVisible, showDropdown] = useState(false);
|
const [dropdownVisible, showDropdown] = useState(false);
|
||||||
const mailIcon = <Icon icon={"envelope"} type={"fas"} />;
|
const mailIcon = <Icon icon={"envelope"} type={"fas"} />;
|
||||||
|
|
||||||
@ -31,11 +27,11 @@ export default function Header(props) {
|
|||||||
const notification = parent.notifications[uid];
|
const notification = parent.notifications[uid];
|
||||||
const createdAt = getPeriodString(notification.created_at);
|
const createdAt = getPeriodString(notification.created_at);
|
||||||
notificationItems.push(
|
notificationItems.push(
|
||||||
<a href="#" className={"dropdown-item"} key={"notification-" + uid}>
|
<Link to={"/admin/logs?notification=" + uid} className={"dropdown-item"} key={"notification-" + uid}>
|
||||||
{mailIcon}
|
{mailIcon}
|
||||||
<span className={"ml-2"}>{notification.title}</span>
|
<span className={"ml-2"}>{notification.title}</span>
|
||||||
<span className={"float-right text-muted text-sm"}>{createdAt}</span>
|
<span className={"float-right text-muted text-sm"}>{createdAt}</span>
|
||||||
</a>);
|
</Link>);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -49,9 +45,9 @@ export default function Header(props) {
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className={"nav-item d-none d-sm-inline-block"}>
|
<li className={"nav-item d-none d-sm-inline-block"}>
|
||||||
<a href={"#"} onClick={() => onChangeView("dashboard")} className={"nav-link"}>
|
<Link to={"/admin/dashboard"} className={"nav-link"}>
|
||||||
Home
|
Home
|
||||||
</a>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -84,7 +80,7 @@ export default function Header(props) {
|
|||||||
</span>
|
</span>
|
||||||
{notificationItems}
|
{notificationItems}
|
||||||
<div className={"dropdown-divider"} />
|
<div className={"dropdown-divider"} />
|
||||||
<a href={"#"} onClick={() => onChangeView("dashboard")} className={"dropdown-item dropdown-footer"}>See All Notifications</a>
|
<Link to={"/admin/logs"} className={"dropdown-item dropdown-footer"}>See All Notifications</Link>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -5,13 +5,13 @@ 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';
|
||||||
import UserOverview from './users.js';
|
import UserOverview from './views/users.js';
|
||||||
import Overview from './overview.js'
|
import Overview from './views/overview.js'
|
||||||
import Icon from "./icon";
|
import Icon from "./elements/icon";
|
||||||
import Dialog from "./dialog";
|
import Dialog from "./elements/dialog";
|
||||||
import {BrowserRouter as Router, Route} from 'react-router-dom'
|
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom'
|
||||||
import View404 from "./404";
|
import View404 from "./404";
|
||||||
import Switch from "react-router-dom/es/Switch";
|
import Logs from "./views/logs";
|
||||||
|
|
||||||
class AdminDashboard extends React.Component {
|
class AdminDashboard extends React.Component {
|
||||||
|
|
||||||
@ -78,6 +78,7 @@ class AdminDashboard extends React.Component {
|
|||||||
<Switch>
|
<Switch>
|
||||||
<Route path={"/admin/dashboard"}><Overview {...this.controlObj} /></Route>
|
<Route path={"/admin/dashboard"}><Overview {...this.controlObj} /></Route>
|
||||||
<Route path={"/admin/users"}><UserOverview {...this.controlObj} /></Route>
|
<Route path={"/admin/users"}><UserOverview {...this.controlObj} /></Route>
|
||||||
|
<Route path={"/admin/logs"}><Logs {...this.controlObj} /></Route>
|
||||||
<Route path={"*"}><View404 /></Route>
|
<Route path={"*"}><View404 /></Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
<Dialog {...this.state.dialog}/>
|
<Dialog {...this.state.dialog}/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Icon from "./icon";
|
import Icon from "./elements/icon";
|
||||||
import {Link, NavLink} from "react-router-dom";
|
import {Link, NavLink} from "react-router-dom";
|
||||||
|
|
||||||
export default function Sidebar(props) {
|
export default function Sidebar(props) {
|
||||||
@ -32,6 +32,10 @@ export default function Sidebar(props) {
|
|||||||
"name": "Settings",
|
"name": "Settings",
|
||||||
"icon": "tools"
|
"icon": "tools"
|
||||||
},
|
},
|
||||||
|
"logs": {
|
||||||
|
"name": "Logs & Notifications",
|
||||||
|
"icon": "file-medical-alt"
|
||||||
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"name": "Help",
|
"name": "Help",
|
||||||
"icon": "question-circle"
|
"icon": "question-circle"
|
||||||
@ -41,7 +45,7 @@ export default function Sidebar(props) {
|
|||||||
let numNotifications = Object.keys(props.notifications).length;
|
let numNotifications = Object.keys(props.notifications).length;
|
||||||
if (numNotifications > 0) {
|
if (numNotifications > 0) {
|
||||||
if (numNotifications > 9) numNotifications = "9+";
|
if (numNotifications > 9) numNotifications = "9+";
|
||||||
menuItems["dashboard"]["badge"] = { type: "warning", value: numNotifications };
|
menuItems["logs"]["badge"] = { type: "warning", value: numNotifications };
|
||||||
}
|
}
|
||||||
|
|
||||||
let li = [];
|
let li = [];
|
||||||
|
41
admin/src/views/logs.js
Normal file
41
admin/src/views/logs.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
|
||||||
|
export default class Logs extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
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">Logs & Notifications</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">Logs</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={"content"}>
|
||||||
|
<div className={"content-fluid"}>
|
||||||
|
<div className={"row"}>
|
||||||
|
<div className={"col-lg-6"}>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className={"col-lg-6"}>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,16 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import Icon from "./icon";
|
import Icon from "../elements/icon";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import {getPeriodString} from "./global";
|
import {getPeriodString} from "../global";
|
||||||
|
import Alert from "../elements/alert";
|
||||||
|
|
||||||
export default class UserOverview extends React.Component {
|
export default class UserOverview extends React.Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.parent = {
|
this.parent = {
|
||||||
showDialog: props.showDialog || function() {},
|
showDialog: props.showDialog || function () {
|
||||||
|
},
|
||||||
api: props.api,
|
api: props.api,
|
||||||
};
|
};
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -16,12 +18,14 @@ export default class UserOverview extends React.Component {
|
|||||||
users: {
|
users: {
|
||||||
data: {},
|
data: {},
|
||||||
page: 1,
|
page: 1,
|
||||||
pageCount: 1
|
pageCount: 1,
|
||||||
|
totalCount: 0,
|
||||||
},
|
},
|
||||||
groups: {
|
groups: {
|
||||||
data: {},
|
data: {},
|
||||||
page: 1,
|
page: 1,
|
||||||
pageCount: 1
|
pageCount: 1,
|
||||||
|
totalCount: 0,
|
||||||
},
|
},
|
||||||
errors: []
|
errors: []
|
||||||
};
|
};
|
||||||
@ -29,7 +33,7 @@ export default class UserOverview extends React.Component {
|
|||||||
|
|
||||||
fetchGroups(page) {
|
fetchGroups(page) {
|
||||||
page = page || this.state.groups.page;
|
page = page || this.state.groups.page;
|
||||||
this.setState({ ...this.state, groups: { ...this.state.groups, data: { }, page: 1 } });
|
this.setState({...this.state, groups: {...this.state.groups, data: {}, page: 1, totalCount: 0}});
|
||||||
this.parent.api.fetchGroups(page).then((res) => {
|
this.parent.api.fetchGroups(page).then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -37,13 +41,16 @@ export default class UserOverview extends React.Component {
|
|||||||
groups: {
|
groups: {
|
||||||
data: res.groups,
|
data: res.groups,
|
||||||
pageCount: res.pageCount,
|
pageCount: res.pageCount,
|
||||||
page: page
|
page: page,
|
||||||
|
totalCount: res.totalCount,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
let errors = this.state.errors.slice();
|
||||||
|
errors.push({title: "Error fetching groups", message: res.msg});
|
||||||
this.setState({
|
this.setState({
|
||||||
...this.state,
|
...this.state,
|
||||||
errors: this.state.errors.slice().push(res.msg)
|
errors: errors
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!this.state.loaded) {
|
if (!this.state.loaded) {
|
||||||
@ -54,7 +61,7 @@ export default class UserOverview extends React.Component {
|
|||||||
|
|
||||||
fetchUsers(page) {
|
fetchUsers(page) {
|
||||||
page = page || this.state.users.page;
|
page = page || this.state.users.page;
|
||||||
this.setState({ ...this.state, users: { ...this.state.users, data: { }, pageCount: 1 } });
|
this.setState({...this.state, users: {...this.state.users, data: {}, pageCount: 1, totalCount: 0}});
|
||||||
this.parent.api.fetchUsers(page).then((res) => {
|
this.parent.api.fetchUsers(page).then((res) => {
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -63,14 +70,17 @@ export default class UserOverview extends React.Component {
|
|||||||
users: {
|
users: {
|
||||||
data: res.users,
|
data: res.users,
|
||||||
pageCount: res.pageCount,
|
pageCount: res.pageCount,
|
||||||
page: page
|
page: page,
|
||||||
|
totalCount: res.totalCount,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
let errors = this.state.errors.slice();
|
||||||
|
errors.push({title: "Error fetching users", message: res.msg});
|
||||||
this.setState({
|
this.setState({
|
||||||
...this.state,
|
...this.state,
|
||||||
loaded: true,
|
loaded: true,
|
||||||
errors: this.state.errors.slice().push(res.msg)
|
errors: errors
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -81,6 +91,14 @@ export default class UserOverview extends React.Component {
|
|||||||
this.fetchGroups(1);
|
this.fetchGroups(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeError(i) {
|
||||||
|
if (i >= 0 && i < this.state.errors.length) {
|
||||||
|
let errors = this.state.errors.slice();
|
||||||
|
errors.splice(i, 1);
|
||||||
|
this.setState({...this.state, errors: errors});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
if (!this.state.loaded) {
|
if (!this.state.loaded) {
|
||||||
@ -89,6 +107,11 @@ export default class UserOverview extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let errors = [];
|
||||||
|
for (let i = 0; i < this.state.errors.length; i++) {
|
||||||
|
errors.push(<Alert key={"error-" + i} onClose={() => this.removeError(i)} {...this.state.errors[i]}/>)
|
||||||
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className="content-header">
|
<div className="content-header">
|
||||||
<div className="container-fluid">
|
<div className="container-fluid">
|
||||||
@ -106,6 +129,7 @@ export default class UserOverview extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={"content"}>
|
<div className={"content"}>
|
||||||
|
{errors}
|
||||||
<div className={"content-fluid"}>
|
<div className={"content-fluid"}>
|
||||||
<div className={"row"}>
|
<div className={"row"}>
|
||||||
<div className={"col-lg-6"}>
|
<div className={"col-lg-6"}>
|
||||||
@ -135,7 +159,8 @@ export default class UserOverview extends React.Component {
|
|||||||
if (user.groups.hasOwnProperty(groupId)) {
|
if (user.groups.hasOwnProperty(groupId)) {
|
||||||
let groupName = user.groups[groupId];
|
let groupName = user.groups[groupId];
|
||||||
let color = (groupId === "1" ? "danger" : "secondary");
|
let color = (groupId === "1" ? "danger" : "secondary");
|
||||||
groups.push(<span key={"group-" + groupId} className={"mr-1 badge badge-" + color}>{groupName}</span>);
|
groups.push(<span key={"group-" + groupId}
|
||||||
|
className={"mr-1 badge badge-" + color}>{groupName}</span>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,20 +212,27 @@ export default class UserOverview extends React.Component {
|
|||||||
{userRows}
|
{userRows}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<nav aria-label={""}>
|
<nav className={"row m-0"}>
|
||||||
|
<div className={"col-6 pl-3 pt-3 pb-3 text-muted"}>
|
||||||
|
Total: {this.state.users.totalCount}
|
||||||
|
</div>
|
||||||
|
<div className={"col-6 p-0"}>
|
||||||
<ul className={"pagination p-2 m-0 justify-content-end"}>
|
<ul className={"pagination p-2 m-0 justify-content-end"}>
|
||||||
<li className={"page-item" + previousDisabled}>
|
<li className={"page-item" + previousDisabled}>
|
||||||
<a className={"page-link"} href={"#"} onClick={() => this.fetchUsers(this.state.users.page - 1)}>
|
<a className={"page-link"} href={"#"}
|
||||||
|
onClick={() => this.fetchUsers(this.state.users.page - 1)}>
|
||||||
Previous
|
Previous
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{pages}
|
{pages}
|
||||||
<li className={"page-item" + nextDisabled}>
|
<li className={"page-item" + nextDisabled}>
|
||||||
<a className={"page-link"} href={"#"} onClick={() => this.fetchUsers(this.state.users.page + 1)}>
|
<a className={"page-link"} href={"#"}
|
||||||
|
onClick={() => this.fetchUsers(this.state.users.page + 1)}>
|
||||||
Next
|
Next
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
@ -259,20 +291,27 @@ export default class UserOverview extends React.Component {
|
|||||||
{groupRows}
|
{groupRows}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<nav aria-label={""}>
|
<nav className={"row m-0"}>
|
||||||
|
<div className={"col-6 pl-3 pt-3 pb-3 text-muted"}>
|
||||||
|
Total: {this.state.groups.totalCount}
|
||||||
|
</div>
|
||||||
|
<div className={"col-6 p-0"}>
|
||||||
<ul className={"pagination p-2 m-0 justify-content-end"}>
|
<ul className={"pagination p-2 m-0 justify-content-end"}>
|
||||||
<li className={"page-item" + previousDisabled}>
|
<li className={"page-item" + previousDisabled}>
|
||||||
<a className={"page-link"} href={"#"} onClick={() => this.fetchGroups(this.state.groups.page - 1)}>
|
<a className={"page-link"} href={"#"}
|
||||||
|
onClick={() => this.fetchGroups(this.state.groups.page - 1)}>
|
||||||
Previous
|
Previous
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{pages}
|
{pages}
|
||||||
<li className={"page-item" + nextDisabled}>
|
<li className={"page-item" + nextDisabled}>
|
||||||
<a className={"page-link"} href={"#"} onClick={() => this.fetchGroups(this.state.groups.page + 1)}>
|
<a className={"page-link"} href={"#"}
|
||||||
|
onClick={() => this.fetchGroups(this.state.groups.page + 1)}>
|
||||||
Next
|
Next
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
@ -76,6 +76,7 @@ class Fetch extends Request {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
$this->result["pageCount"] = intval(ceil($this->groupCount / Fetch::SELECT_SIZE));
|
$this->result["pageCount"] = intval(ceil($this->groupCount / Fetch::SELECT_SIZE));
|
||||||
|
$this->result["totalCount"] = $this->groupCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->success;
|
return $this->success;
|
||||||
|
@ -87,6 +87,7 @@ class Fetch extends Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->result["pageCount"] = intval(ceil($this->userCount / Fetch::SELECT_SIZE));
|
$this->result["pageCount"] = intval(ceil($this->userCount / Fetch::SELECT_SIZE));
|
||||||
|
$this->result["totalCount"] = $this->userCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->success;
|
return $this->success;
|
||||||
|
124
js/admin.min.js
vendored
124
js/admin.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user