mirror of
https://github.com/MikroWizard/mikrofront.git
synced 2025-06-20 18:05:39 +02:00
MikroWizard Initial commit | MikroFront Welcome to the world :)
This commit is contained in:
commit
b97aec6b97
203 changed files with 41097 additions and 0 deletions
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
/node_modules/
|
||||
*.log
|
||||
*.swo
|
||||
*.swp
|
||||
.vimrc
|
||||
.nvimrc
|
||||
.angular/
|
||||
/dist/
|
25
Dockerfile
Normal file
25
Dockerfile
Normal file
|
@ -0,0 +1,25 @@
|
|||
FROM nginx:latest AS ngi
|
||||
|
||||
RUN apt-get update && apt-get -y install cron
|
||||
RUN touch /var/log/cron.log
|
||||
COPY reqs.txt /reqs.txt
|
||||
|
||||
RUN set -ex \
|
||||
&& buildDeps=' \
|
||||
build-essential \
|
||||
gcc \
|
||||
' \
|
||||
&& deps=' \
|
||||
htop \
|
||||
' \
|
||||
&& apt-get install -y python3 pip $buildDeps $deps --no-install-recommends && pip install -r /reqs.txt --break-system-packages
|
||||
COPY front-update.py /
|
||||
COPY mwcrontab /etc/cron.d/mwcrontab
|
||||
RUN chmod 0644 /etc/cron.d/mwcrontab
|
||||
|
||||
RUN crontab /etc/cron.d/mwcrontab
|
||||
|
||||
COPY /dist/mikrowizard /usr/share/nginx/html
|
||||
COPY /nginx.conf /etc/nginx/conf.d/default.conf
|
||||
EXPOSE 80
|
||||
CMD cron;nginx -g "daemon off;"
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017-2023 creativeLabs Łukasz Holeczek
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
222
README.md
Normal file
222
README.md
Normal file
|
@ -0,0 +1,222 @@
|
|||
[](https://github.com/coreui/angular)
|
||||
[![npm-coreui-angular][npm-coreui-angular-badge]][npm-coreui-angular]
|
||||
[![NPM downloads][npm-coreui-angular-download]][npm-coreui-angular]
|
||||
[](https://github.com/coreui/coreui)
|
||||
[![npm package][npm-coreui-badge]][npm-coreui]
|
||||
[![NPM downloads][npm-coreui-download]][npm-coreui]
|
||||

|
||||
|
||||
[npm-coreui-angular]: https://www.npmjs.com/package/@coreui/angular
|
||||
[npm-coreui-angular-badge]: https://img.shields.io/npm/v/@coreui/angular.png?style=flat-square
|
||||
[npm-coreui-angular-badge-next]: https://img.shields.io/npm/v/@coreui/angular/next?style=flat-square&color=red
|
||||
[npm-coreui-angular-download]: https://img.shields.io/npm/dm/@coreui/angular.svg?style=flat-square
|
||||
[npm-coreui]: https://www.npmjs.com/package/@coreui/coreui
|
||||
[npm-coreui-badge]: https://img.shields.io/npm/v/@coreui/coreui.png?style=flat-square
|
||||
[npm-coreui-download]: https://img.shields.io/npm/dm/@coreui/coreui.svg?style=flat-square
|
||||
|
||||
# CoreUI Free Admin Dashboard Template for Angular 16
|
||||
|
||||
CoreUI is meant to be the UX game changer. Pure & transparent code is devoid of redundant components, so the app is light enough to offer ultimate user experience. This means mobile devices also, where the navigation is just as easy and intuitive as on a desktop or laptop. The CoreUI Layout API lets you customize your project for almost any device – be it Mobile, Web or WebApp – CoreUI covers them all!
|
||||
|
||||
- [CoreUI Angular Admin Dashboard Template & UI Components Library](https://coreui.io/angular)
|
||||
- [CoreUI Angular Demo](https://coreui.io/angular/demo/4.3/free/)
|
||||
- [CoreUI Angular Docs](https://coreui.io/angular/docs/)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [Versions](#versions)
|
||||
* [CoreUI Pro](#coreui-pro)
|
||||
* [Quick Start](#quick-start)
|
||||
* [Installation](#installation)
|
||||
* [Basic usage](#basic-usage)
|
||||
* [What's included](#whats-included)
|
||||
* [Documentation](#documentation)
|
||||
* [Versioning](#versioning)
|
||||
* [Creators](#creators)
|
||||
* [Community](#community)
|
||||
* [Copyright and License](#copyright-and-license)
|
||||
|
||||
## Versions
|
||||
|
||||
* [CoreUI Free Bootstrap Admin Template](https://github.com/coreui/coreui-free-bootstrap-admin-template)
|
||||
* [CoreUI Free Angular Admin Template](https://github.com/coreui/coreui-free-angular-admin-template)
|
||||
* [CoreUI Free React.js Admin Template](https://github.com/coreui/coreui-free-react-admin-template)
|
||||
* [CoreUI Free Vue.js Admin Template](https://github.com/coreui/coreui-free-vue-admin-template)
|
||||
|
||||
## CoreUI Pro
|
||||
|
||||
**Only customers with [Enterpise Membership Plan](https://coreui.io/pro/#buy) have access to private GitHub CoreUI Pro repository.**
|
||||
|
||||
* 💪 [CoreUI Pro Angular Admin Template](https://coreui.io/product/angular-dashboard-template/)
|
||||
* 💪 [CoreUI Pro Bootstrap Admin Template](https://coreui.io/product/bootstrap-dashboard-template/)
|
||||
* 💪 [CoreUI Pro React Admin Template](https://coreui.io/product/react-dashboard-template/)
|
||||
* 💪 [CoreUI Pro Next.js Admin Template](https://coreui.io/product/next-js-dashboard-template/)
|
||||
* 💪 [CoreUI Pro Vue Admin Template](https://coreui.io/product/vue-dashboard-template/)
|
||||
|
||||
## Quick Start
|
||||
|
||||
- [Download the latest release](https://github.com/coreui/coreui-free-angular-admin-template/)
|
||||
- Clone the repo: `git clone https://github.com/coreui/coreui-free-angular-admin-template.git`
|
||||
|
||||
#### <i>Prerequisites</i>
|
||||
Before you begin, make sure your development environment includes `Node.js®` and an `npm` package manager.
|
||||
|
||||
###### Node.js
|
||||
[**Angular 16**](https://angular.io/guide/what-is-angular) requires `Node.js` LTS version `^16.14` or `^18.10`.
|
||||
|
||||
- To check your version, run `node -v` in a terminal/console window.
|
||||
- To get `Node.js`, go to [nodejs.org](https://nodejs.org/).
|
||||
|
||||
###### Angular CLI
|
||||
Install the Angular CLI globally using a terminal/console window.
|
||||
```bash
|
||||
npm install -g @angular/cli
|
||||
```
|
||||
|
||||
### Installation
|
||||
|
||||
``` bash
|
||||
$ npm install
|
||||
$ npm update
|
||||
```
|
||||
|
||||
### Basic usage
|
||||
|
||||
``` bash
|
||||
# dev server with hot reload at http://localhost:4200
|
||||
$ npm start
|
||||
```
|
||||
|
||||
Navigate to [http://localhost:4200](http://localhost:4200). The app will automatically reload if you change any of the source files.
|
||||
|
||||
#### Build
|
||||
|
||||
Run `build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
```bash
|
||||
# build for production with minification
|
||||
$ npm run build
|
||||
```
|
||||
## What's included
|
||||
|
||||
Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this:
|
||||
|
||||
```
|
||||
coreui-free-angular-admin-template
|
||||
├── src/ # project root
|
||||
│ ├── app/ # main app directory
|
||||
| │ ├── containers/ # layout containers
|
||||
| | │ └── default-layout/ # layout containers
|
||||
| | | └── _nav.js # sidebar navigation config
|
||||
| │ ├── icons/ # icons set for the app
|
||||
| │ └── views/ # application views
|
||||
│ ├── assets/ # images, icons, etc.
|
||||
│ ├── components/ # components for demo only
|
||||
│ ├── scss/ # scss styles
|
||||
│ └── index.html # html template
|
||||
│
|
||||
├── angular.json
|
||||
├── README.md
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation for the CoreUI Admin Template is hosted at our website [CoreUI for Angular](https://coreui.io/angular/)
|
||||
|
||||
---
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.0.0.
|
||||
|
||||
## Versioning
|
||||
|
||||
For transparency into our release cycle and in striving to maintain backward compatibility, CoreUI Free Admin Template is maintained under [the Semantic Versioning guidelines](http://semver.org/).
|
||||
|
||||
See [the Releases section of our project](https://github.com/coreui/coreui-free-angular-admin-template/releases) for changelogs for each release version.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
|
||||
## Creators
|
||||
|
||||
**Łukasz Holeczek**
|
||||
* <https://twitter.com/lukaszholeczek>
|
||||
* <https://github.com/mrholek>
|
||||
* <https://github.com/coreui>
|
||||
|
||||
**CoreUI team**
|
||||
* https://github.com/orgs/coreui/people
|
||||
|
||||
## Community
|
||||
|
||||
Get updates on CoreUI's development and chat with the project maintainers and community members.
|
||||
|
||||
- Follow [@core_ui on Twitter](https://twitter.com/core_ui).
|
||||
- Read and subscribe to [CoreUI Blog](https://coreui.io/blog/).
|
||||
|
||||
## Support CoreUI Development
|
||||
|
||||
CoreUI is an MIT-licensed open source project and is completely free to use. However, the amount of effort needed to maintain and develop new features for the project is not sustainable without proper financial backing. You can support development by buying the [CoreUI PRO](https://coreui.io/pricing/) or by becoming a sponsor via [Open Collective](https://opencollective.com/coreui/).
|
||||
|
||||
<!--- StartOpenCollectiveBackers -->
|
||||
|
||||
### Platinum Sponsors
|
||||
|
||||
Support this project by [becoming a Platinum Sponsor](https://opencollective.com/coreui/contribute/platinum-sponsor-40959/). A large company logo will be added here with a link to your website.
|
||||
|
||||
<a href="https://opencollective.com/coreui/contribute/platinum-sponsor-40959/checkout"><img src="https://opencollective.com/coreui/tiers/platinum-sponsor/0/avatar.svg?avatarHeight=100"></a>
|
||||
|
||||
### Gold Sponsors
|
||||
|
||||
Support this project by [becoming a Gold Sponsor](https://opencollective.com/coreui/contribute/gold-sponsor-40960/). A big company logo will be added here with a link to your website.
|
||||
|
||||
<a href="https://opencollective.com/coreui/contribute/gold-sponsor-40960/checkout"><img src="https://opencollective.com/coreui/tiers/gold-sponsor/0/avatar.svg?avatarHeight=100"></a>
|
||||
|
||||
### Silver Sponsors
|
||||
|
||||
Support this project by [becoming a Silver Sponsor](https://opencollective.com/coreui/contribute/silver-sponsor-40967/). A medium company logo will be added here with a link to your website.
|
||||
|
||||
<a href="https://opencollective.com/coreui/contribute/silver-sponsor-40967/checkout"><img src="https://opencollective.com/coreui/tiers/gold-sponsor/0/avatar.svg?avatarHeight=100"></a>
|
||||
|
||||
### Bronze Sponsors
|
||||
|
||||
Support this project by [becoming a Bronze Sponsor](https://opencollective.com/coreui/contribute/bronze-sponsor-40966/). The company avatar will show up here with a link to your OpenCollective Profile.
|
||||
|
||||
<a href="https://opencollective.com/coreui/contribute/bronze-sponsor-40966/checkout"><img src="https://opencollective.com/coreui/tiers/bronze-sponsor/0/avatar.svg?avatarHeight=100"></a>
|
||||
|
||||
### Backers
|
||||
|
||||
Thanks to all the backers and sponsors! Support this project by [becoming a backer](https://opencollective.com/coreui/contribute/backer-40965/).
|
||||
|
||||
<a href="https://opencollective.com/coreui/contribute/backer-40965/checkout" target="_blank" rel="noopener"><img src="https://opencollective.com/coreui/backers.svg?width=890"></a>
|
||||
|
||||
<!--- EndOpenCollectiveBackers -->
|
||||
|
||||
## Copyright and License
|
||||
|
||||
copyright 2017-2023 creativeLabs Łukasz Holeczek.
|
||||
|
||||
|
||||
Code released under [the MIT license](https://github.com/coreui/coreui-free-react-admin-template/blob/master/LICENSE).
|
||||
There is only one limitation you can't re-distribute the CoreUI as stock. You can’t do this if you modify the CoreUI. In the past, we faced some problems with persons who tried to sell CoreUI based templates.
|
122
angular.json
Normal file
122
angular.json
Normal file
|
@ -0,0 +1,122 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"cli": {
|
||||
"analytics": false
|
||||
},
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"mikrowizard": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
},
|
||||
"@schematics/angular:application": {
|
||||
"strict": true
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/mikrowizard",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": [
|
||||
"@angular/localize/init",
|
||||
"zone.js"
|
||||
],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"preserveSymlinks": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/scss/styles.scss",
|
||||
"node_modules/@easyfonts/font-awesome-v6/fontawesome.css",
|
||||
"node_modules/@easyfonts/font-awesome-v6/solid.css",
|
||||
"node_modules/@easyfonts/font-awesome-v6/regular.css",
|
||||
"node_modules/@easyfonts/font-awesome-v6/brands.css",
|
||||
|
||||
],
|
||||
"scripts": [],
|
||||
"allowedCommonJsDependencies": [
|
||||
"chart.js"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "1500kb",
|
||||
"maximumError": "6mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "mikrowizard:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "mikrowizard:build:development"
|
||||
}
|
||||
},
|
||||
"proxyConfig": "proxy.conf.json",
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "mikrowizard:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/scss/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
build.sh
Executable file
7
build.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
# run in dev mode
|
||||
|
||||
npm run build --prod
|
||||
python3 version_generate.py
|
||||
sudo docker build --rm -t mikrofront .
|
||||
|
189
front-update.py
Normal file
189
front-update.py
Normal file
|
@ -0,0 +1,189 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# mule1.py: independent worker process
|
||||
# - a TCP server as an example
|
||||
|
||||
import time
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
import requests
|
||||
import logging
|
||||
import os
|
||||
import hashlib
|
||||
import zipfile
|
||||
import subprocess
|
||||
import json
|
||||
from cryptography.fernet import Fernet
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
log = logging.getLogger("updater")
|
||||
log.setLevel(logging.INFO)
|
||||
API_URL="http://host.docker.internal:8181"
|
||||
Config_File="/conf/server-conf.json"
|
||||
Version_File="/usr/share/nginx/html/version.json"
|
||||
# Example usage
|
||||
def check_sha256(filename, expect):
|
||||
"""Check if the file with the name "filename" matches the SHA-256 sum
|
||||
in "expect"."""
|
||||
h = hashlib.sha256()
|
||||
# This will raise an exception if the file doesn't exist. Catching
|
||||
# and handling it is left as an exercise for the reader.
|
||||
try:
|
||||
with open(filename, 'rb') as fh:
|
||||
# Read and hash the file in 4K chunks. Reading the whole
|
||||
# file at once might consume a lot of memory if it is
|
||||
# large.
|
||||
while True:
|
||||
data = fh.read(4096)
|
||||
if len(data) == 0:
|
||||
break
|
||||
else:
|
||||
h.update(data)
|
||||
return expect == h.hexdigest()
|
||||
except Exception as e:
|
||||
return False
|
||||
|
||||
def crypt_data(text,key):
|
||||
# Encryption: Encrypting password using Fernet symmetric encryption
|
||||
key = Fernet.generate_key()
|
||||
cipher_suite = Fernet(key)
|
||||
# Encrypting
|
||||
encrypted_password = cipher_suite.encrypt(text.encode()).decode()
|
||||
return encrypted_password
|
||||
|
||||
|
||||
def decrypt_data(text,key):
|
||||
# Encryption: Decrypting password using Fernet symmetric encryption
|
||||
cipher_suite = Fernet(key)
|
||||
# Decrypting password
|
||||
decrypted_password = cipher_suite.decrypt(text.encode()).decode()
|
||||
return decrypted_password
|
||||
|
||||
def extract_zip_reload(filename,dst):
|
||||
"""Extract the contents of the zip file "filename" to the directory
|
||||
"dst". Then reload the updated modules."""
|
||||
with zipfile.ZipFile(filename, 'r') as zip_ref:
|
||||
zip_ref.extractall(dst)
|
||||
# run db migrate
|
||||
# dir ="/usr/share/nginx/html/"
|
||||
# cmd = "cd {}; PYTHONPATH={}py PYSRV_CONFIG_PATH={} python3 scripts/dbmigrate.py".format(dir, dir, "/conf/server-conf.json")
|
||||
# p = subprocess.Popen(cmd, shell=True)
|
||||
# (output, err) = p.communicate()
|
||||
#This makes the wait possible
|
||||
# p_status = p.wait()
|
||||
#touch server reload file /app/reload
|
||||
os.remove(filename)
|
||||
# Path('/app/reload').touch()
|
||||
|
||||
def load_config_file():
|
||||
try:
|
||||
with open(Config_File, 'r') as fh:
|
||||
config = json.load(fh)
|
||||
return config
|
||||
except Exception as e:
|
||||
log.error(e)
|
||||
return False
|
||||
|
||||
def get_serial_from_api():
|
||||
url=API_URL+"/api/get_version"
|
||||
config=load_config_file()
|
||||
key=False
|
||||
if config:
|
||||
key=config.get('PYSRV_CRYPT_KEY',False)
|
||||
else:
|
||||
return False
|
||||
if not key:
|
||||
return False
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response = response.json()
|
||||
return json.loads(decrypt_data(response['result'],key))
|
||||
except Exception as e:
|
||||
log.error(e)
|
||||
return False
|
||||
|
||||
|
||||
def get_version_from_file():
|
||||
try:
|
||||
with open(Version_File, 'r') as fh:
|
||||
version = json.load(fh)
|
||||
return version.get('version', '0.0.0')
|
||||
except Exception as e:
|
||||
log.error(e)
|
||||
return '0.0.0'
|
||||
|
||||
|
||||
def main():
|
||||
while True:
|
||||
try:
|
||||
next_hour = (time.time() // 3600 + 1) * 3600
|
||||
sleep_time = next_hour - time.time()
|
||||
|
||||
res=get_serial_from_api()
|
||||
hwid=res['serial']
|
||||
username=res['username']
|
||||
version=get_version_from_file()
|
||||
|
||||
params={
|
||||
"serial_number": hwid,
|
||||
"username": username.strip(),
|
||||
"front":True,
|
||||
"version": version
|
||||
}
|
||||
url="http://mikrowizard.com/wp-json/mikrowizard/v1/get_update"
|
||||
# send post request to server mikrowizard.com with params in json
|
||||
response = requests.post(url, json=params)
|
||||
# get response from server
|
||||
res = response
|
||||
try:
|
||||
if res.status_code == 200:
|
||||
res=res.json()
|
||||
if 'token' in res:
|
||||
params={
|
||||
"token":res['token'],
|
||||
"file_name":res['filename'],
|
||||
"username":username.strip(),
|
||||
"front":True
|
||||
}
|
||||
log.info("Update available/Downloading...")
|
||||
else:
|
||||
log.info("Update not available")
|
||||
time.sleep(sleep_time)
|
||||
continue
|
||||
except Exception as e:
|
||||
log.error(e)
|
||||
|
||||
# check if filename exist in /app/py and checksum is same then dont continue
|
||||
if check_sha256("/usr/share/nginx/"+res['filename'], res['sha256']):
|
||||
log.error("Checksum match, File exist")
|
||||
extract_zip_reload("/usr/share/nginx/"+res['filename'],"/usr/share/nginx/")
|
||||
time.sleep(sleep_time)
|
||||
continue
|
||||
download_url="http://mikrowizard.com/wp-json/mikrowizard/v1/download_update"
|
||||
# send post request to server mikrowizard.com with params in json
|
||||
r = requests.post(download_url,json=params,stream=True)
|
||||
if "invalid" in r.text or r.text=='false':
|
||||
log.error(r)
|
||||
log.error("Invalid response")
|
||||
time.sleep(30)
|
||||
continue
|
||||
with open("/usr/share/nginx/"+res['filename'], 'wb') as fd:
|
||||
for chunk in r.iter_content(chunk_size=128):
|
||||
fd.write(chunk)
|
||||
if check_sha256("/usr/share/nginx/"+res['filename'], res['sha256']):
|
||||
log.error("Update downloaded")
|
||||
log.error("/usr/share/nginx/"+res['filename'])
|
||||
extract_zip_reload("/usr/share/nginx/"+res['filename'],"/usr/share/nginx/")
|
||||
else:
|
||||
log.error("Checksum not match")
|
||||
os.remove("/usr/share/nginx/"+res['filename'])
|
||||
time.sleep(sleep_time)
|
||||
except Exception as e:
|
||||
log.error(e)
|
||||
time.sleep(30)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
44
karma.conf.js
Normal file
44
karma.conf.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/coreui-free-angular-admin-template'),
|
||||
subdir: '.',
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
3
mwcrontab
Normal file
3
mwcrontab
Normal file
|
@ -0,0 +1,3 @@
|
|||
# must be ended with a new line "LF" (Unix) and not "CRLF" (Windows)
|
||||
* * * * * /usr/bin/python3 /front-update.py > /var/log/cron.log 2>&1
|
||||
# An empty line is required at the end of this file for a valid cron file.
|
38
nginx.conf
Normal file
38
nginx.conf
Normal file
|
@ -0,0 +1,38 @@
|
|||
server {
|
||||
listen 80;
|
||||
sendfile on;
|
||||
default_type application/octet-stream;
|
||||
|
||||
gzip on;
|
||||
gzip_http_version 1.1;
|
||||
gzip_disable "MSIE [1-6]\.";
|
||||
gzip_min_length 256;
|
||||
gzip_vary on;
|
||||
gzip_proxied expired no-cache no-store private auth;
|
||||
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
gzip_comp_level 9;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html =404;
|
||||
}
|
||||
location /api {
|
||||
proxy_pass http://host.docker.internal:8181;
|
||||
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $realip_remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
}
|
||||
location /api/frontver {
|
||||
add_header Cache-Control 'no-store';
|
||||
add_header Cache-Control 'no-cache';
|
||||
expires 0;
|
||||
index version.json;
|
||||
alias /usr/share/nginx/html;
|
||||
}
|
||||
}
|
23691
package-lock.json
generated
Normal file
23691
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
83
package.json
Normal file
83
package.json
Normal file
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"name": "MikroWizard",
|
||||
"version": "1.0.0",
|
||||
"copyright": "MikroWizard mikrowizard.com",
|
||||
"license": "AGPL",
|
||||
"author": "MikroWizard Team (https://github.com/MikroWizard)",
|
||||
"homepage": "https://MikroWizard.com",
|
||||
"config": {
|
||||
"coreui_library_short_version": "coreui 4.5 , mikrowizard 1.0.0",
|
||||
"coreui_library_docs_url": "https://coreui.io/angular/docs/"
|
||||
},
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --proxy-config proxy.conf.json --host 0.0.0.0",
|
||||
"startnp": "ng serve --proxy-config=./proxy.conf.ts --host 0.0.0.0",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^17.3.5",
|
||||
"@angular/cdk": "^16.2.9",
|
||||
"@angular/common": "^17.3.5",
|
||||
"@angular/compiler": "^17.3.5",
|
||||
"@angular/core": "^17.3.5",
|
||||
"@angular/forms": "^17.3.5",
|
||||
"@angular/language-service": "^17.3.5",
|
||||
"@angular/material": "^17.3.5",
|
||||
"@angular/platform-browser": "^17.3.5",
|
||||
"@angular/platform-browser-dynamic": "^17.3.5",
|
||||
"@angular/router": "^17.3.5",
|
||||
"@coreui/angular": "~4.5.27",
|
||||
"@coreui/angular-chartjs": "~4.5.27",
|
||||
"@coreui/chartjs": "^3.1.2",
|
||||
"@coreui/coreui": "~4.2.6",
|
||||
"@coreui/icons": "^3.0.1",
|
||||
"@coreui/icons-angular": "~4.5.27",
|
||||
"@coreui/utils": "^2.0.2",
|
||||
"@easyfonts/font-awesome-v6": "^6.0.6",
|
||||
"@generic-ui/fabric": "^0.19.0",
|
||||
"@generic-ui/hermes": "^0.19.0",
|
||||
"@generic-ui/ngx-grid": "^0.19.0",
|
||||
"chart.js": "^3.9.1",
|
||||
"date-fns": "^3.6.0",
|
||||
"date-fns-jalali": "^3.6.0-0",
|
||||
"date-fns-tz": "^3.1.3",
|
||||
"font-awesome": "^4.7.0",
|
||||
"install": "^0.13.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mat-progress-buttons": "^9.3.1",
|
||||
"ngx-cron-editor": "^0.8.1",
|
||||
"ngx-date-fns": "^11.0.0",
|
||||
"ngx-highlightjs": "^12.0.0",
|
||||
"ngx-mat-select-search": "^7.0.6",
|
||||
"ngx-material-date-fns-adapter": "^18.0.0",
|
||||
"ngx-scrollbar": "^13.0.3",
|
||||
"ngx-super-select": "^3.17.0",
|
||||
"rxjs": "~7.8.1",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^17.3.5",
|
||||
"@angular/cli": "^17.3.5",
|
||||
"@angular/compiler-cli": "^17.3.5",
|
||||
"@angular/localize": "^17.3.5",
|
||||
"@types/jasmine": "^5.1.1",
|
||||
"@types/lodash-es": "^4.17.10",
|
||||
"@types/node": "^18.19.34",
|
||||
"jasmine-core": "^5.1.1",
|
||||
"karma": "^6.4.2",
|
||||
"karma-chrome-launcher": "^3.2.0",
|
||||
"karma-coverage": "^2.2.1",
|
||||
"karma-jasmine": "^5.1.0",
|
||||
"karma-jasmine-html-reporter": "^2.1.0",
|
||||
"typescript": "~5.4.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.14.0 || ^18.10.0",
|
||||
"npm": ">= 6"
|
||||
}
|
||||
}
|
8
proxy.conf.json
Normal file
8
proxy.conf.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"/api": {
|
||||
"target": "http://172.17.0.1:8181/",
|
||||
"secure": false,
|
||||
"changeOrigin": true,
|
||||
"pathRewrite": {"^/api" : ""}
|
||||
}
|
||||
}
|
22
proxy.conf.ts
Normal file
22
proxy.conf.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
const PROXY_CONFIG = [
|
||||
{
|
||||
context: [
|
||||
"/api/frontver/"
|
||||
],
|
||||
target: "http://127.0.0.1/",
|
||||
secure: false,
|
||||
"changeOrigin": true,
|
||||
logLevel: "debug",
|
||||
},
|
||||
{
|
||||
context: [
|
||||
"/api"
|
||||
],
|
||||
target: "http://172.17.0.1:8181/",
|
||||
secure: false,
|
||||
"changeOrigin": true,
|
||||
}
|
||||
]
|
||||
|
||||
module.exports = PROXY_CONFIG;
|
8
proxy.conf2.json
Normal file
8
proxy.conf2.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"/api": {
|
||||
"target": "http://127.0.0.1/",
|
||||
"secure": false,
|
||||
"changeOrigin": true,
|
||||
"pathRewrite": {"^/api" : ""}
|
||||
}
|
||||
}
|
2
reqs.txt
Normal file
2
reqs.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
cryptography==3.4.8
|
||||
Requests==2.32.2
|
1
run-docker.sh
Executable file
1
run-docker.sh
Executable file
|
@ -0,0 +1 @@
|
|||
sudo docker run --rm -it --add-host=host.docker.internal:host-gateway --name mikrofront-dev --add-host=host.docker.internal:host-gateway -p 80:80 -v /opt/mikrowizard/:/conf/ mikrofront
|
135
src/app/app-routing.module.ts
Normal file
135
src/app/app-routing.module.ts
Normal file
|
@ -0,0 +1,135 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { DefaultLayoutComponent } from './containers';
|
||||
import { Page404Component } from './views/pages/page404/page404.component';
|
||||
import { Page500Component } from './views/pages/page500/page500.component';
|
||||
import { LoginComponent } from './views/pages/login/login.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'dashboard',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: DefaultLayoutComponent,
|
||||
data: {
|
||||
title: 'Home'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'dashboard',
|
||||
loadChildren: () =>
|
||||
import('./views/dashboard/dashboard.module').then((m) => m.DashboardModule)
|
||||
},
|
||||
{
|
||||
path: 'devices',
|
||||
loadChildren: () =>
|
||||
import('./views/devices/devices.module').then((m) => m.DevicesModule)
|
||||
},
|
||||
{
|
||||
path: 'device-stats',
|
||||
loadChildren: () =>
|
||||
import('./views/device_detail/device.module').then((m) => m.DeviceModule)
|
||||
},
|
||||
{
|
||||
path: 'deviceGroup',
|
||||
loadChildren: () =>
|
||||
import('./views/devices_group/devgroup.module').then((m) => m.DevicesGroupModule)
|
||||
},
|
||||
{
|
||||
path: 'authlog',
|
||||
loadChildren: () =>
|
||||
import('./views/auth_log/auth.module').then((m) => m.AuthModule)
|
||||
},
|
||||
{
|
||||
path: 'devlogs',
|
||||
loadChildren: () =>
|
||||
import('./views/device_logs/devlogs.module').then((m) => m.DevLogsModule)
|
||||
},
|
||||
{
|
||||
path: 'syslog',
|
||||
loadChildren: () =>
|
||||
import('./views/syslog/syslog.module').then((m) => m.SyslogModule)
|
||||
},
|
||||
{
|
||||
path: 'backups',
|
||||
loadChildren: () =>
|
||||
import('./views/backups/backups.module').then((m) => m.BackupsModule)
|
||||
},
|
||||
{
|
||||
path: 'settings',
|
||||
loadChildren: () =>
|
||||
import('./views/settings/settings.module').then((m) => m.SettingsModule)
|
||||
},
|
||||
{
|
||||
path: 'accountlog',
|
||||
loadChildren: () =>
|
||||
import('./views/acc_log/acc.module').then((m) => m.AccModule)
|
||||
},
|
||||
{
|
||||
path: 'user_tasks',
|
||||
loadChildren: () =>
|
||||
import('./views/user_tasks/user_tasks.module').then((m) => m.UserTasksModule)
|
||||
},
|
||||
{
|
||||
path: 'snippets',
|
||||
loadChildren: () =>
|
||||
import('./views/snippets/snippets.module').then((m) => m.SnippetsModule)
|
||||
},
|
||||
{
|
||||
path: 'user_manager',
|
||||
loadChildren: () =>
|
||||
import('./views/user_manager/user_manager.module').then((m) => m.UserManagerModule)
|
||||
},
|
||||
{
|
||||
path: 'permissions',
|
||||
loadChildren: () =>
|
||||
import('./views/permissions/permissions.module').then((m) => m.PermissionsModule)
|
||||
},
|
||||
{
|
||||
path: 'pages',
|
||||
loadChildren: () =>
|
||||
import('./views/pages/pages.module').then((m) => m.PagesModule)
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '404',
|
||||
component: Page404Component,
|
||||
data: {
|
||||
title: 'Page 404'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '500',
|
||||
component: Page500Component,
|
||||
data: {
|
||||
title: 'Page 500'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
component: LoginComponent,
|
||||
data: {
|
||||
title: 'Login Page'
|
||||
}
|
||||
},
|
||||
{path: '**', redirectTo: 'dashboard'}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(routes, {
|
||||
scrollPositionRestoration: 'top',
|
||||
anchorScrolling: 'enabled',
|
||||
initialNavigation: 'enabledBlocking'
|
||||
// relativeLinkResolution: 'legacy'
|
||||
})
|
||||
],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule {
|
||||
}
|
28
src/app/app.component.spec.ts
Normal file
28
src/app/app.component.spec.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'CoreUI Free Angular Admin Template'`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app.title).toEqual('CoreUI Free Angular Admin Template');
|
||||
});
|
||||
});
|
33
src/app/app.component.ts
Normal file
33
src/app/app.component.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router, NavigationEnd } from '@angular/router';
|
||||
|
||||
import { IconSetService } from '@coreui/icons-angular';
|
||||
import { iconSubset } from './icons/icon-subset';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: '<router-outlet></router-outlet>',
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
title = 'MikroWizard , Mikrotik router managent system';
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private titleService: Title,
|
||||
private iconSetService: IconSetService
|
||||
) {
|
||||
titleService.setTitle(this.title);
|
||||
// iconSet singleton
|
||||
iconSetService.icons = { ...iconSubset };
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
console.log(this.router.url);
|
||||
this.router.events.subscribe((evt) => {
|
||||
if (!(evt instanceof NavigationEnd)) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
116
src/app/app.module.ts
Normal file
116
src/app/app.module.ts
Normal file
|
@ -0,0 +1,116 @@
|
|||
import { NgModule ,APP_INITIALIZER} from '@angular/core';
|
||||
import { HashLocationStrategy, LocationStrategy, PathLocationStrategy } from '@angular/common';
|
||||
import { BrowserModule, Title } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ReactiveFormsModule,FormsModule } from '@angular/forms';
|
||||
|
||||
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
// Import routing module
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { provideDateFnsAdapter } from 'ngx-material-date-fns-adapter';
|
||||
|
||||
// Import app component
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
// Import containers
|
||||
import { DefaultFooterComponent, DefaultHeaderComponent, DefaultLayoutComponent } from './containers';
|
||||
import { MikroWizardProvider } from './providers/mikrowizard/provider';
|
||||
import { dataProvider } from './providers/mikrowizard/data';
|
||||
import { loginChecker } from './providers/login_checker';
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
import { provideHighlightOptions, Highlight, HighlightAuto } from 'ngx-highlightjs';
|
||||
|
||||
import {
|
||||
AvatarModule,
|
||||
BadgeModule,
|
||||
BreadcrumbModule,
|
||||
ButtonGroupModule,
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
DropdownModule,
|
||||
FooterModule,
|
||||
FormModule,
|
||||
GridModule,
|
||||
HeaderModule,
|
||||
ListGroupModule,
|
||||
NavModule,
|
||||
ProgressModule,
|
||||
SharedModule,
|
||||
SidebarModule,
|
||||
TabsModule,
|
||||
UtilitiesModule,
|
||||
ModalModule
|
||||
} from '@coreui/angular';
|
||||
|
||||
import { IconModule, IconSetService } from '@coreui/icons-angular';
|
||||
|
||||
const APP_CONTAINERS = [
|
||||
DefaultFooterComponent,
|
||||
DefaultHeaderComponent,
|
||||
DefaultLayoutComponent
|
||||
];
|
||||
export function loginStatusProviderFactory(provider: loginChecker) {
|
||||
return () => provider.load();
|
||||
}
|
||||
@NgModule({
|
||||
declarations: [AppComponent, ...APP_CONTAINERS],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
AppRoutingModule,
|
||||
AvatarModule,
|
||||
BreadcrumbModule,
|
||||
FooterModule,
|
||||
DropdownModule,
|
||||
GridModule,
|
||||
HeaderModule,
|
||||
SidebarModule,
|
||||
IconModule,
|
||||
NavModule,
|
||||
HttpClientModule,
|
||||
ButtonModule,
|
||||
FormModule,
|
||||
UtilitiesModule,
|
||||
ButtonGroupModule,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
SidebarModule,
|
||||
SharedModule,
|
||||
TabsModule,
|
||||
ListGroupModule,
|
||||
ProgressModule,
|
||||
BadgeModule,
|
||||
ListGroupModule,
|
||||
CardModule,
|
||||
NgScrollbarModule,
|
||||
ModalModule,
|
||||
FontAwesomeModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: LocationStrategy,
|
||||
useClass: HashLocationStrategy
|
||||
},
|
||||
MikroWizardProvider,
|
||||
dataProvider,
|
||||
loginChecker,
|
||||
IconSetService,
|
||||
provideDateFnsAdapter(),
|
||||
provideHighlightOptions({
|
||||
fullLibraryLoader: () => import('highlight.js'),
|
||||
lineNumbersLoader: () => import('ngx-highlightjs/line-numbers')
|
||||
}),
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: loginStatusProviderFactory,
|
||||
deps: [loginChecker],
|
||||
multi: true,
|
||||
},
|
||||
Title
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
158
src/app/containers/default-layout/_nav.ts
Normal file
158
src/app/containers/default-layout/_nav.ts
Normal file
|
@ -0,0 +1,158 @@
|
|||
import { INavData } from '@coreui/angular';
|
||||
|
||||
export const navItems: INavData[] = [
|
||||
{
|
||||
name: 'Dashboard',
|
||||
url: '/dashboard',
|
||||
iconComponent: { name: 'cil-speedometer' },
|
||||
|
||||
},
|
||||
{
|
||||
title: true,
|
||||
name: 'Device Managment'
|
||||
},
|
||||
{
|
||||
name: 'Devices',
|
||||
url: '/devices',
|
||||
icon: 'fa-solid fa-server'
|
||||
},
|
||||
{
|
||||
name: 'Device Groups',
|
||||
url: '/deviceGroup',
|
||||
// linkProps: { fragment: 'someAnchor' },
|
||||
icon: 'fa-solid fa-layer-group'
|
||||
},
|
||||
// {
|
||||
// name: 'Tools',
|
||||
// url: '/login',
|
||||
// icon: 'fa-solid fa-screwdriver-wrench',
|
||||
// children: [
|
||||
// {
|
||||
// name: 'BW test',
|
||||
// url: '/login',
|
||||
// icon: 'fa-solid fa-file-circle-check'
|
||||
// },
|
||||
// {
|
||||
// name: 'Ping test',
|
||||
// url: '/register',
|
||||
// icon: 'fa-solid fa-arrow-right-arrow-left'
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
name: 'Backup & Config',
|
||||
title: true
|
||||
},
|
||||
{
|
||||
name: 'Task Planer',
|
||||
url: '/user_tasks',
|
||||
icon: 'fa-solid fa-calendar-week'
|
||||
},
|
||||
{
|
||||
name: 'Backups',
|
||||
url: '/backups',
|
||||
icon: 'fa-solid fa-database'
|
||||
},
|
||||
{
|
||||
name: 'snippets',
|
||||
url: '/snippets',
|
||||
icon: 'fa-solid fa-code'
|
||||
},
|
||||
// {
|
||||
// name: 'Tools',
|
||||
// url: '/login',
|
||||
// icon: 'fa-solid fa-screwdriver-wrench',
|
||||
// children: [
|
||||
// {
|
||||
// name: 'Backup comparator',
|
||||
// url: '/login',
|
||||
// icon: 'fa-solid fa-code-compare'
|
||||
// },
|
||||
// {
|
||||
// name: 'Backup search',
|
||||
// url: '/register',
|
||||
// icon: 'fa-solid fa-magnifying-glass-arrow-right'
|
||||
// },
|
||||
// {
|
||||
// name: 'batch execute',
|
||||
// url: '/register',
|
||||
// icon: 'fa-solid fa-terminal'
|
||||
// },
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
name: 'Reports',
|
||||
title: true
|
||||
},
|
||||
{
|
||||
name: 'Authentication',
|
||||
url: '/authlog',
|
||||
icon: 'fa-solid fa-check-to-slot',
|
||||
|
||||
},
|
||||
{
|
||||
name: 'Accounting',
|
||||
url: '/accountlog',
|
||||
icon: 'fa-solid fa-list-check',
|
||||
|
||||
},
|
||||
{
|
||||
name: 'Device Logs',
|
||||
url: '/devlogs',
|
||||
icon: 'fa-regular fa-rectangle-list',
|
||||
|
||||
},
|
||||
{
|
||||
name: 'System Logs',
|
||||
url: '/syslog',
|
||||
icon: 'fa-solid fa-person-circle-question',
|
||||
|
||||
},
|
||||
{
|
||||
title: true,
|
||||
name: 'Users'
|
||||
},
|
||||
{
|
||||
name: 'Users Management',
|
||||
url: '/user_manager',
|
||||
icon: 'fa-solid fa-user-gear' ,
|
||||
},
|
||||
{
|
||||
name: 'Permissions',
|
||||
url: '/permissions',
|
||||
icon: 'fa-solid fa-users' ,
|
||||
},
|
||||
{
|
||||
title: true,
|
||||
name: 'System',
|
||||
class: 'py-0'
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
url: '/settings',
|
||||
icon: 'fa-solid fa-gear' ,
|
||||
},
|
||||
// {
|
||||
// name: 'Backup',
|
||||
// url: '/login',
|
||||
// icon: 'cil-star' ,
|
||||
// },
|
||||
{
|
||||
title: true,
|
||||
name: 'Links',
|
||||
class: 'py-0'
|
||||
},
|
||||
{
|
||||
name: 'Docs',
|
||||
url: 'https://mikrowizard.com/docs',
|
||||
iconComponent: { name: 'cil-description' },
|
||||
attributes: { target: '_blank', class: '-text-dark' },
|
||||
class: 'mt-auto'
|
||||
},
|
||||
{
|
||||
name: 'Buy Pro',
|
||||
url: 'https://mikrowizard.com/pricing/',
|
||||
icon:'fa-solid fa-money-check-dollar',
|
||||
attributes: { target: '_blank' }
|
||||
}
|
||||
];
|
|
@ -0,0 +1,6 @@
|
|||
<!--<c-footer>-->
|
||||
<div>
|
||||
<a href="https://mikrowizard.com" target="_blank">MikroWizard</a>
|
||||
<span> © 2024 </span>
|
||||
</div>
|
||||
<!--</c-footer>-->
|
|
@ -0,0 +1,25 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DefaultFooterComponent } from './default-footer.component';
|
||||
|
||||
describe('DefaultFooterComponent', () => {
|
||||
let component: DefaultFooterComponent;
|
||||
let fixture: ComponentFixture<DefaultFooterComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DefaultFooterComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DefaultFooterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { FooterComponent } from '@coreui/angular';
|
||||
|
||||
@Component({
|
||||
selector: 'app-default-footer',
|
||||
templateUrl: './default-footer.component.html',
|
||||
styleUrls: ['./default-footer.component.scss'],
|
||||
})
|
||||
export class DefaultFooterComponent extends FooterComponent {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
|
||||
|
||||
<!--<c-header class="mb-4 d-print-none" position="sticky">-->
|
||||
<ng-container>
|
||||
<c-container [fluid]="true">
|
||||
<button
|
||||
toggle="visible"
|
||||
cHeaderToggler
|
||||
[cSidebarToggle]="sidebarId"
|
||||
class="ps-1"
|
||||
>
|
||||
<svg cIcon
|
||||
name="cilMenu"
|
||||
size="lg"
|
||||
></svg>
|
||||
</button>
|
||||
<!-- <c-header-nav class="d-none d-lg-flex me-auto">
|
||||
<c-nav-item>
|
||||
<a cNavLink routerLink="/dashboard" routerLinkActive="active">
|
||||
Dashboard
|
||||
</a>
|
||||
</c-nav-item>
|
||||
<c-nav-item>
|
||||
<a cNavLink routerLink="/users" routerLinkActive="active">Users</a>
|
||||
</c-nav-item>
|
||||
<c-nav-item>
|
||||
<a cNavLink routerLink="/settings" routerLinkActive="active">
|
||||
Settings
|
||||
</a>
|
||||
</c-nav-item>
|
||||
</c-header-nav> -->
|
||||
|
||||
<!-- <c-header-nav class="d-none d-lg-flex">
|
||||
<c-nav-item>
|
||||
<a routerLink="./" cNavLink>
|
||||
<svg cIcon name="cilBell" size="lg"></svg>
|
||||
</a>
|
||||
</c-nav-item>
|
||||
<c-nav-item>
|
||||
<a routerLink="./" cNavLink>
|
||||
<svg cIcon name="cilList" size="lg"></svg>
|
||||
</a>
|
||||
</c-nav-item>
|
||||
<c-nav-item>
|
||||
<a routerLink="./" cNavLink>
|
||||
<svg cIcon name="cilEnvelopeOpen" size="lg"></svg>
|
||||
</a>
|
||||
</c-nav-item>
|
||||
</c-header-nav> -->
|
||||
<c-header-nav class="ms-3">
|
||||
<ng-container *ngTemplateOutlet="userDropdown"></ng-container>
|
||||
</c-header-nav>
|
||||
|
||||
</c-container>
|
||||
<c-header-divider></c-header-divider>
|
||||
<c-container [fluid]="true">
|
||||
<c-breadcrumb-router class="ms-2"></c-breadcrumb-router>
|
||||
</c-container>
|
||||
</ng-container>
|
||||
<!--</c-header>-->
|
||||
|
||||
<ng-template #userDropdown>
|
||||
<c-dropdown alignment="end" variant="nav-item">
|
||||
<button
|
||||
cButton
|
||||
color=""
|
||||
[caret]="false"
|
||||
cDropdownToggle
|
||||
class="py-0"
|
||||
>
|
||||
<svg cIcon class="me-2" name="cilUser"></svg>
|
||||
{{fname}} {{lname}}
|
||||
</button>
|
||||
<ul cDropdownMenu class="pt-0 pr-5 w-auto">
|
||||
<li>
|
||||
<h6 cDropdownHeader class="bg-light fw-semibold py-2">User Menu</h6>
|
||||
</li>
|
||||
<li>
|
||||
<button (click)="callParent()" cDropdownItem>
|
||||
<svg cIcon class="me-2" name="cilUser"></svg>
|
||||
Change password
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<a routerLink="./" (click)="logout()" cDropdownItem>
|
||||
<svg cIcon class="me-2" name="cilExitToApp"></svg>
|
||||
Logout
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</c-dropdown>
|
||||
</ng-template>
|
|
@ -0,0 +1,43 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import {
|
||||
AvatarModule,
|
||||
BadgeModule,
|
||||
BreadcrumbModule,
|
||||
DropdownModule,
|
||||
GridModule,
|
||||
HeaderModule,
|
||||
NavModule, SidebarModule
|
||||
} from '@coreui/angular';
|
||||
import { IconSetService } from '@coreui/icons-angular';
|
||||
import { iconSubset } from '../../../icons/icon-subset';
|
||||
import { DefaultHeaderComponent } from './default-header.component';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
describe('DefaultHeaderComponent', () => {
|
||||
let component: DefaultHeaderComponent;
|
||||
let fixture: ComponentFixture<DefaultHeaderComponent>;
|
||||
let iconSetService: IconSetService;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [DefaultHeaderComponent],
|
||||
imports: [GridModule, HeaderModule, NavModule, BadgeModule, AvatarModule, DropdownModule, BreadcrumbModule, RouterTestingModule, SidebarModule],
|
||||
providers: [IconSetService]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
iconSetService = TestBed.inject(IconSetService);
|
||||
iconSetService.icons = { ...iconSubset };
|
||||
|
||||
fixture = TestBed.createComponent(DefaultHeaderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,67 @@
|
|||
import { Component, Input ,Output,EventEmitter} from '@angular/core';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { loginChecker } from '../../../providers/login_checker';
|
||||
import { Router } from "@angular/router";
|
||||
import { dataProvider } from '../../../providers/mikrowizard/data';
|
||||
import { User } from '../../../providers/mikrowizard/user';
|
||||
|
||||
import { ClassToggleService, HeaderComponent } from '@coreui/angular';
|
||||
|
||||
@Component({
|
||||
selector: 'app-default-header',
|
||||
templateUrl: './default-header.component.html',
|
||||
})
|
||||
export class DefaultHeaderComponent extends HeaderComponent {
|
||||
|
||||
@Input() sidebarId: string = "sidebar";
|
||||
@Output() UserModalEvent = new EventEmitter<any>();
|
||||
|
||||
public newMessages = new Array(4)
|
||||
public newTasks = new Array(5)
|
||||
public newNotifications = new Array(5)
|
||||
public current_user: User;
|
||||
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
public fname: string;
|
||||
public lname: string;
|
||||
public UserProfileModalVisible : boolean = false;
|
||||
|
||||
constructor(
|
||||
private classToggler: ClassToggleService,
|
||||
private router: Router,
|
||||
private login_checker: loginChecker,
|
||||
private data_provider: dataProvider,
|
||||
) {
|
||||
super();
|
||||
var _self = this;
|
||||
var session_info: string = localStorage.getItem('current_user') || "[]]";
|
||||
this.current_user = JSON.parse(session_info);
|
||||
}
|
||||
|
||||
submit(){
|
||||
}
|
||||
|
||||
get_user_info() {
|
||||
var _self = this;
|
||||
this.uid = this.current_user.partner_id;
|
||||
this.uname = this.current_user.name;
|
||||
this.fname = this.current_user.firstname;
|
||||
this.lname = this.current_user.lastname;
|
||||
}
|
||||
|
||||
callParent(): void {
|
||||
this.UserModalEvent.next('test');
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.data_provider.logout().then(res => {
|
||||
this.router.navigate(['login']);
|
||||
})
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
var _self = this;
|
||||
this.get_user_info();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<!--sidebar-->
|
||||
<c-sidebar
|
||||
#sidebar="cSidebar"
|
||||
class="d-print-none sidebar sidebar-fixed"
|
||||
id="sidebar"
|
||||
visible
|
||||
>
|
||||
<c-sidebar-brand
|
||||
[brandFull]="{
|
||||
src: 'assets/img/brand/logo-MIkroWizard-big-white.svg',
|
||||
width: 200,
|
||||
height: 46,
|
||||
alt: 'MikroWizard Logo'
|
||||
}"
|
||||
[brandNarrow]="{
|
||||
src: 'assets/img/brand/logo-MIkroWizard-small-color.svg',
|
||||
width: 46,
|
||||
height: 46,
|
||||
alt: 'MikroWizard Logo'
|
||||
}"
|
||||
routerLink="./"
|
||||
/>
|
||||
|
||||
<ng-scrollbar pointerEventsMethod="scrollbar">
|
||||
<c-sidebar-nav
|
||||
[navItems]="navItems"
|
||||
dropdownMode="close"
|
||||
/>
|
||||
</ng-scrollbar>
|
||||
<c-sidebar-toggler
|
||||
*ngIf="!sidebar.narrow"
|
||||
toggle="unfoldable"
|
||||
cSidebarToggle="sidebar"
|
||||
/>
|
||||
</c-sidebar>
|
||||
|
||||
<!--main-->
|
||||
<div class="wrapper d-flex flex-column min-vh-100 bg-light dark:bg-transparent">
|
||||
<!--app-header-->
|
||||
<app-default-header (UserModalEvent)="show_user_modal()" class="mb-4 d-print-none header header-sticky" position="sticky" sidebarId="sidebar" />
|
||||
<!--app-body-->
|
||||
<div class="body flex-grow-1 px-3">
|
||||
<c-container breakpoint="fluid" class="h-auto">
|
||||
<router-outlet />
|
||||
</c-container>
|
||||
</div>
|
||||
<!--app footer-->
|
||||
<app-default-footer />
|
||||
</div>
|
||||
|
||||
<c-modal #UserProfileModal backdrop="static" size="lg" [(visible)]="UserProfileModalVisible" id="UserProfileModal">
|
||||
<c-modal-header>
|
||||
<h5 cModalTitle>Change Password Form of<code><b>{{ uname }}({{ fname }} {{lname}})</b></code></h5>
|
||||
<button [cModalToggle]="UserProfileModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
|
||||
<div [cFormFloating]="true" class="mb-3">
|
||||
<input type="password" cFormControl id="floatingInput" [(ngModel)]="password['cupass']" placeholder="Current Password" />
|
||||
<label cLabel for="floatingInput">Current Password</label>
|
||||
</div>
|
||||
|
||||
<div [cFormFloating]="true" class="mb-3">
|
||||
<input type="password" cFormControl (ngModelChange)="password_changed('pass1',$event)" [(ngModel)]="password['pass1']" id="floatingInput" placeholder="New Password" />
|
||||
<label cLabel for="floatingInput">New Password</label>
|
||||
</div>
|
||||
|
||||
<div [cFormFloating]="true" class="mb-3">
|
||||
<input type="password" cFormControl (ngModelChange)="password_changed('pass2',$event)" [(ngModel)]="password['pass2']" [valid]="passvalid['pass2']" id="floatingInput" placeholder="New Password confirm" />
|
||||
<label cLabel for="floatingInput">New Password confirm</label>
|
||||
</div>
|
||||
<code *ngIf="error"><i class="fa-solid fa-triangle-exclamation"></i><small> {{error}}</small></code>
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<button (click)="submit()" cButton color="primary">submit</button>
|
||||
<button [cModalToggle]="UserProfileModal.id" cButton color="secondary">
|
||||
Close
|
||||
</button>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
|
@ -0,0 +1,7 @@
|
|||
:host {
|
||||
ng-scrollbar {
|
||||
--scrollbar-thumb-color: var(--cui-border-color, #999);
|
||||
--scrollbar-track-color: var(--cui-body-color, #fff);
|
||||
--scrollbar-hover-size: calc(var(--scrollbar-size) * 1.5);
|
||||
}
|
||||
}
|
125
src/app/containers/default-layout/default-layout.component.ts
Normal file
125
src/app/containers/default-layout/default-layout.component.ts
Normal file
|
@ -0,0 +1,125 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router, NavigationEnd } from "@angular/router";
|
||||
import { loginChecker } from '../../providers/login_checker';
|
||||
import { User } from '../../providers/mikrowizard/user';
|
||||
import { navItems } from './_nav';
|
||||
import { dataProvider } from '../../providers/mikrowizard/data';
|
||||
import { version } from 'os';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: './default-layout.component.html',
|
||||
styleUrls: ['./default-layout.component.scss'],
|
||||
})
|
||||
export class DefaultLayoutComponent implements OnInit {
|
||||
|
||||
public navItems = navItems;
|
||||
public current_user: User;
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
public fname: string;
|
||||
public lname: string;
|
||||
public UserProfileModalVisible:boolean;
|
||||
public error:any=false;
|
||||
public password:any={
|
||||
'cupass':'',
|
||||
'pass1':'',
|
||||
'pass2':''
|
||||
};
|
||||
|
||||
public passvalid:any={
|
||||
'cupass':false,
|
||||
'pass1':false,
|
||||
'pass2':false
|
||||
};
|
||||
version=require('../../../../package.json').version;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private login_checker: loginChecker,
|
||||
private data_provider: dataProvider,
|
||||
|
||||
) {
|
||||
var _self = this;
|
||||
var session_info: string = localStorage.getItem('current_user') || "[]";
|
||||
this.current_user = JSON.parse(session_info);
|
||||
this.router.events.subscribe((ev) => {
|
||||
if (ev instanceof NavigationEnd) {
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(['login']);
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
password_changed(variable:string,value:any){
|
||||
var _self=this;
|
||||
this.password[variable]=value;
|
||||
console.dir(this.password['pass1']);
|
||||
console.dir(this.password['pass2']);
|
||||
if(this.password['pass1']==this.password['pass2']){
|
||||
_self.passvalid['pass2']=true;
|
||||
}
|
||||
else{
|
||||
_self.passvalid['pass2']=false;
|
||||
}
|
||||
}
|
||||
|
||||
show_user_modal(){
|
||||
this.UserProfileModalVisible = true;
|
||||
}
|
||||
|
||||
submit(){
|
||||
var _self=this;
|
||||
if(!_self.passvalid['pass2']){
|
||||
return;
|
||||
}
|
||||
this.data_provider.change_password(this.password['cupass'], this.password['pass1']).then(res => {
|
||||
if(res['status']=='success'){
|
||||
_self.logout();
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(['login']);
|
||||
}, 100);
|
||||
}
|
||||
else{
|
||||
_self.error=res['err'];
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
console.dir(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
get_user_info() {
|
||||
var _self = this;
|
||||
this.uid = this.current_user.partner_id;
|
||||
this.uname = this.current_user.name;
|
||||
this.fname = this.current_user.firstname;
|
||||
this.lname = this.current_user.lastname;
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.data_provider.logout();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
var _self = this;
|
||||
this.get_user_info();
|
||||
_self.data_provider.get_front_version().then((res:any) => {
|
||||
console.log("ressssssssssssssssss");
|
||||
console.dir(res['version']);
|
||||
console.dir(this.version);
|
||||
if(res['version']!=this.version){
|
||||
console.dir("New version is available. Please refresh the page.");
|
||||
window.location.href = window.location.href.replace(/#.*$/, '');
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
3
src/app/containers/default-layout/index.ts
Normal file
3
src/app/containers/default-layout/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export * from './default-footer/default-footer.component';
|
||||
export * from './default-header/default-header.component';
|
||||
export * from './default-layout.component';
|
1
src/app/containers/index.ts
Normal file
1
src/app/containers/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './default-layout';
|
281
src/app/icons/icon-subset.ts
Normal file
281
src/app/icons/icon-subset.ts
Normal file
|
@ -0,0 +1,281 @@
|
|||
import {
|
||||
cibCcAmex,
|
||||
cibCcApplePay,
|
||||
cibCcMastercard,
|
||||
cibCcPaypal,
|
||||
cibCcStripe,
|
||||
cibCcVisa,
|
||||
cibFacebook,
|
||||
cibGoogle,
|
||||
cibLinkedin,
|
||||
cibSkype,
|
||||
cibTwitter,
|
||||
cifBr,
|
||||
cifEs,
|
||||
cifFr,
|
||||
cifIn,
|
||||
cifPl,
|
||||
cifUs,
|
||||
cilAlignCenter,
|
||||
cilAlignLeft,
|
||||
cilAlignRight,
|
||||
cilApplicationsSettings,
|
||||
cilArrowBottom,
|
||||
cilArrowRight,
|
||||
cilArrowTop,
|
||||
cilBasket,
|
||||
cilBell,
|
||||
cilBold,
|
||||
cilBookmark,
|
||||
cilCalculator,
|
||||
cilCalendar,
|
||||
cilChart,
|
||||
cilChartPie,
|
||||
cilCheck,
|
||||
cilChevronLeft,
|
||||
cilChevronRight,
|
||||
cilCloudDownload,
|
||||
cilCode,
|
||||
cilCommentSquare,
|
||||
cilCreditCard,
|
||||
cilCursor,
|
||||
cilDescription,
|
||||
cilDollar,
|
||||
cilDrop,
|
||||
cilEnvelopeClosed,
|
||||
cilEnvelopeOpen,
|
||||
cilFile,
|
||||
cilHome,
|
||||
cilInbox,
|
||||
cilIndentDecrease,
|
||||
cilIndentIncrease,
|
||||
cilItalic,
|
||||
cilJustifyCenter,
|
||||
cilLayers,
|
||||
cilList,
|
||||
cilListNumbered,
|
||||
cilLocationPin,
|
||||
cilLockLocked,
|
||||
cilMagnifyingGlass,
|
||||
cilMap,
|
||||
cilMediaPlay,
|
||||
cilMenu,
|
||||
cilMoon,
|
||||
cilNotes,
|
||||
cilOptions,
|
||||
cilPaperclip,
|
||||
cilPaperPlane,
|
||||
cilPen,
|
||||
cilPencil,
|
||||
cilPeople,
|
||||
cilPrint,
|
||||
cilPuzzle,
|
||||
cilReportSlash,
|
||||
cilSave,
|
||||
cilSettings,
|
||||
cilShare,
|
||||
cilShareAll,
|
||||
cilShareBoxed,
|
||||
cilSpeech,
|
||||
cilSpeedometer,
|
||||
cilSpreadsheet,
|
||||
cilStar,
|
||||
cilSun,
|
||||
cilTags,
|
||||
cilTask,
|
||||
cilTrash,
|
||||
cilUnderline,
|
||||
cilUser,
|
||||
cilUserFemale,
|
||||
cilUserFollow,
|
||||
cilUserUnfollow,
|
||||
cilExitToApp
|
||||
} from '@coreui/icons';
|
||||
|
||||
export const iconSubset = {
|
||||
cibCcAmex,
|
||||
cibCcApplePay,
|
||||
cibCcMastercard,
|
||||
cibCcPaypal,
|
||||
cibCcStripe,
|
||||
cibCcVisa,
|
||||
cibFacebook,
|
||||
cibGoogle,
|
||||
cibLinkedin,
|
||||
cibSkype,
|
||||
cibTwitter,
|
||||
cifBr,
|
||||
cifEs,
|
||||
cifFr,
|
||||
cifIn,
|
||||
cifPl,
|
||||
cifUs,
|
||||
cilAlignCenter,
|
||||
cilAlignLeft,
|
||||
cilAlignRight,
|
||||
cilApplicationsSettings,
|
||||
cilArrowBottom,
|
||||
cilArrowRight,
|
||||
cilArrowTop,
|
||||
cilBasket,
|
||||
cilBell,
|
||||
cilBold,
|
||||
cilBookmark,
|
||||
cilCalculator,
|
||||
cilCalendar,
|
||||
cilChart,
|
||||
cilChartPie,
|
||||
cilCheck,
|
||||
cilChevronLeft,
|
||||
cilChevronRight,
|
||||
cilCloudDownload,
|
||||
cilCode,
|
||||
cilCommentSquare,
|
||||
cilCreditCard,
|
||||
cilCursor,
|
||||
cilDescription,
|
||||
cilDollar,
|
||||
cilDrop,
|
||||
cilEnvelopeClosed,
|
||||
cilEnvelopeOpen,
|
||||
cilFile,
|
||||
cilHome,
|
||||
cilInbox,
|
||||
cilIndentDecrease,
|
||||
cilIndentIncrease,
|
||||
cilItalic,
|
||||
cilJustifyCenter,
|
||||
cilLayers,
|
||||
cilList,
|
||||
cilListNumbered,
|
||||
cilLocationPin,
|
||||
cilLockLocked,
|
||||
cilMagnifyingGlass,
|
||||
cilMap,
|
||||
cilMediaPlay,
|
||||
cilMenu,
|
||||
cilMoon,
|
||||
cilNotes,
|
||||
cilOptions,
|
||||
cilPaperclip,
|
||||
cilPaperPlane,
|
||||
cilPen,
|
||||
cilPencil,
|
||||
cilPeople,
|
||||
cilPrint,
|
||||
cilPuzzle,
|
||||
cilReportSlash,
|
||||
cilSave,
|
||||
cilSettings,
|
||||
cilShare,
|
||||
cilShareAll,
|
||||
cilShareBoxed,
|
||||
cilSpeech,
|
||||
cilSpeedometer,
|
||||
cilSpreadsheet,
|
||||
cilStar,
|
||||
cilSun,
|
||||
cilTags,
|
||||
cilTask,
|
||||
cilTrash,
|
||||
cilUnderline,
|
||||
cilUser,
|
||||
cilUserFemale,
|
||||
cilUserFollow,
|
||||
cilUserUnfollow,
|
||||
cilExitToApp
|
||||
};
|
||||
|
||||
export enum IconSubset {
|
||||
cibCcAmex = 'cibCcAmex',
|
||||
cibCcApplePay = 'cibCcApplePay',
|
||||
cibCcMastercard = 'cibCcMastercard',
|
||||
cibCcPaypal = 'cibCcPaypal',
|
||||
cibCcStripe = 'cibCcStripe',
|
||||
cibCcVisa = 'cibCcVisa',
|
||||
cibFacebook = 'cibFacebook',
|
||||
cibGoogle = 'cibGoogle',
|
||||
cibLinkedin = 'cibLinkedin',
|
||||
cibSkype = 'cibSkype',
|
||||
cibTwitter = 'cibTwitter',
|
||||
cifBr = 'cifBr',
|
||||
cifEs = 'cifEs',
|
||||
cifFr = 'cifFr',
|
||||
cifIn = 'cifIn',
|
||||
cifPl = 'cifPl',
|
||||
cifUs = 'cifUs',
|
||||
cilAlignCenter = 'cilAlignCenter',
|
||||
cilAlignLeft = 'cilAlignLeft',
|
||||
cilAlignRight = 'cilAlignRight',
|
||||
cilApplicationsSettings = 'cilApplicationsSettings',
|
||||
cilArrowBottom = 'cilArrowBottom',
|
||||
cilArrowRight = 'cilArrowRight',
|
||||
cilArrowTop = 'cilArrowTop',
|
||||
cilBasket = 'cilBasket',
|
||||
cilBell = 'cilBell',
|
||||
cilBold = 'cilBold',
|
||||
cilBookmark = 'cilBookmark',
|
||||
cilCalculator = 'cilCalculator',
|
||||
cilCalendar = 'cilCalendar',
|
||||
cilChart = 'cilChart',
|
||||
cilChartPie = 'cilChartPie',
|
||||
cilCheck = 'cilCheck',
|
||||
cilChevronLeft = 'cilChevronLeft',
|
||||
cilChevronRight = 'cilChevronRight',
|
||||
cilCloudDownload = 'cilCloudDownload',
|
||||
cilCode = 'cilCode',
|
||||
cilCommentSquare = 'cilCommentSquare',
|
||||
cilCreditCard = 'cilCreditCard',
|
||||
cilCursor = 'cilCursor',
|
||||
cilDescription = 'cilDescription',
|
||||
cilDollar = 'cilDollar',
|
||||
cilDrop = 'cilDrop',
|
||||
cilEnvelopeClosed = 'cilEnvelopeClosed',
|
||||
cilEnvelopeOpen = 'cilEnvelopeOpen',
|
||||
cilFile = 'cilFile',
|
||||
cilHome = 'cilHome',
|
||||
cilInbox = 'cilInbox',
|
||||
cilIndentDecrease = 'cilIndentDecrease',
|
||||
cilIndentIncrease = 'cilIndentIncrease',
|
||||
cilItalic = 'cilItalic',
|
||||
cilJustifyCenter = 'cilJustifyCenter',
|
||||
cilLayers = 'cilLayers',
|
||||
cilList = 'cilList',
|
||||
cilListNumbered = 'cilListNumbered',
|
||||
cilLocationPin = 'cilLocationPin',
|
||||
cilLockLocked = 'cilLockLocked',
|
||||
cilMagnifyingGlass = 'cilMagnifyingGlass',
|
||||
cilMap = 'cilMap',
|
||||
cilMediaPlay = 'cilMediaPlay',
|
||||
cilMenu = 'cilMenu',
|
||||
cilMoon = 'cilMoon',
|
||||
cilNotes = 'cilNotes',
|
||||
cilOptions = 'cilOptions',
|
||||
cilPaperclip = 'cilPaperclip',
|
||||
cilPaperPlane = 'cilPaperPlane',
|
||||
cilPen = 'cilPen',
|
||||
cilPencil = 'cilPencil',
|
||||
cilPeople = 'cilPeople',
|
||||
cilPrint = 'cilPrint',
|
||||
cilPuzzle = 'cilPuzzle',
|
||||
cilReportSlash = 'cilReportSlash',
|
||||
cilSave = 'cilSave',
|
||||
cilSettings = 'cilSettings',
|
||||
cilShare = 'cilShare',
|
||||
cilShareAll = 'cilShareAll',
|
||||
cilShareBoxed = 'cilShareBoxed',
|
||||
cilSpeech = 'cilSpeech',
|
||||
cilSpeedometer = 'cilSpeedometer',
|
||||
cilSpreadsheet = 'cilSpreadsheet',
|
||||
cilStar = 'cilStar',
|
||||
cilSun = 'cilSun',
|
||||
cilTags = 'cilTags',
|
||||
cilTask = 'cilTask',
|
||||
cilTrash = 'cilTrash',
|
||||
cilUnderline = 'cilUnderline',
|
||||
cilUser = 'cilUser',
|
||||
cilUserFemale = 'cilUserFemale',
|
||||
cilUserFollow = 'cilUserFollow',
|
||||
cilUserUnfollow = 'cilUserUnfollow',
|
||||
cilExitToApp = 'cilExitToApp'
|
||||
}
|
28
src/app/providers/login_checker.ts
Normal file
28
src/app/providers/login_checker.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { dataProvider } from './mikrowizard/data';
|
||||
|
||||
@Injectable()
|
||||
export class loginChecker {
|
||||
private logged_in: boolean = false;
|
||||
private pinging: boolean = false;
|
||||
|
||||
constructor(private data_provider: dataProvider) {
|
||||
}
|
||||
public isLoggedIn(): boolean {
|
||||
return this.logged_in;
|
||||
}
|
||||
load() {
|
||||
var _self = this;
|
||||
return this.data_provider.isLoggedIn().then(result => {
|
||||
_self.logged_in = result;
|
||||
}).catch(err => {
|
||||
_self.logged_in = false;
|
||||
})
|
||||
}
|
||||
setStatus(status: boolean): void {
|
||||
this.logged_in = status;
|
||||
}
|
||||
setPinging(ping: boolean): void {
|
||||
this.pinging = ping;
|
||||
}
|
||||
}
|
86
src/app/providers/messaging.service.ts
Normal file
86
src/app/providers/messaging.service.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { AngularFireDatabase } from '@angular/fire/database';
|
||||
import { AngularFireAuth } from '@angular/fire/auth';
|
||||
import { AngularFireMessaging } from '@angular/fire/messaging';
|
||||
import { mergeMapTo } from 'rxjs/operators';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { BehaviorSubject } from 'rxjs'
|
||||
import { dataProvider } from './odoorpchttp/data';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingService {
|
||||
|
||||
currentMessage = new BehaviorSubject(null);
|
||||
|
||||
constructor(
|
||||
private angularFireDB: AngularFireDatabase,
|
||||
private angularFireAuth: AngularFireAuth,
|
||||
private data_provider: dataProvider,
|
||||
private toastr: ToastrService,
|
||||
private angularFireMessaging: AngularFireMessaging,
|
||||
) {
|
||||
this.angularFireMessaging.messaging.subscribe(
|
||||
(_messaging) => {
|
||||
_messaging.onMessage = _messaging.onMessage.bind(_messaging);
|
||||
_messaging.onTokenRefresh = _messaging.onTokenRefresh.bind(_messaging);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* update token in firebase database
|
||||
*
|
||||
* @param userId userId as a key
|
||||
* @param token token as a value
|
||||
*/
|
||||
updateToken(userId, token) {
|
||||
// we can change this function to request our backend service
|
||||
this.angularFireAuth.authState.pipe(take(1)).subscribe(
|
||||
() => {
|
||||
const data = {};
|
||||
data[userId] = token
|
||||
this.angularFireDB.object('fcmTokens/').update(data)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* request permission for notification from firebase cloud messaging
|
||||
*
|
||||
* @param userId userId
|
||||
*/
|
||||
requestPermission(userId) {
|
||||
this.angularFireMessaging.requestToken.subscribe(
|
||||
(token) => {
|
||||
this.data_provider.update_FBC_token(token).then(result => {
|
||||
if(result.result!='success'){
|
||||
console.error('Unable to write token.');
|
||||
}
|
||||
});
|
||||
this.updateToken(userId, token);
|
||||
},
|
||||
(err) => {
|
||||
console.error('Unable to get permission to notify.', err);
|
||||
}
|
||||
);
|
||||
}
|
||||
shownotification(payload){
|
||||
if(typeof(payload) !== 'undefined'){
|
||||
if(document.visibilityState){
|
||||
this.toastr.warning(payload.notification.title, payload.notification.body,{
|
||||
disableTimeOut:true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* hook method when new notification received in foreground
|
||||
*/
|
||||
receiveMessage() {
|
||||
this.angularFireMessaging.messages.subscribe(
|
||||
(payload) => {
|
||||
this.shownotification(payload);
|
||||
this.currentMessage.next(payload);
|
||||
})
|
||||
}
|
||||
}
|
455
src/app/providers/mikrowizard/data.ts
Normal file
455
src/app/providers/mikrowizard/data.ts
Normal file
|
@ -0,0 +1,455 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
// import { MikroWizardrpcProvider } from '../MikroWizardrpc/MikroWizardrpc';
|
||||
import { MikroWizardProvider } from './provider';
|
||||
|
||||
|
||||
import { User } from './user';
|
||||
|
||||
@Injectable()
|
||||
export class dataProvider {
|
||||
|
||||
// public serverUrl: string = "/api";
|
||||
public serverUrl: string = "";
|
||||
private db: string = "NothingImportant";
|
||||
|
||||
constructor(
|
||||
// private http: HTTP,
|
||||
// public MikroWizardRPC: MikroWizardrpcProvider,
|
||||
public MikroWizardRPC: MikroWizardProvider,
|
||||
) {
|
||||
this.MikroWizardRPC.init({
|
||||
MikroWizard_server: this.serverUrl
|
||||
});
|
||||
}
|
||||
|
||||
isLoggedIn() {
|
||||
return this.MikroWizardRPC.isLoggedIn();
|
||||
}
|
||||
|
||||
login(username: string = "", password: string = "", ga: string = "") {
|
||||
var _self = this;
|
||||
this.MikroWizardRPC.clearCookeis();
|
||||
return this.MikroWizardRPC.login(this.db, username, password, ga).then(res => {
|
||||
if ('uid' in res && res['uid']) {
|
||||
let usr: User = new User(
|
||||
res.name,
|
||||
res.username,
|
||||
res.partner_id,
|
||||
res.uid,
|
||||
res.first_name,
|
||||
res.last_name,
|
||||
res.role,
|
||||
res.perms,
|
||||
res.tz,
|
||||
);
|
||||
// console.dir(JSON.stringify(usr))
|
||||
localStorage.setItem('current_user', JSON.stringify(usr));
|
||||
}
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
logout() {
|
||||
var _self = this;
|
||||
_self.MikroWizardRPC.clearCookeis();
|
||||
this.MikroWizardRPC.setNewSession('', '');
|
||||
localStorage.removeItem('current_user');
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/logout", {});
|
||||
}
|
||||
|
||||
////
|
||||
//// MikroWizard API
|
||||
////
|
||||
get_front_version(){
|
||||
return this.MikroWizardRPC.sendHttpGetRequest("/api/frontver/");
|
||||
}
|
||||
change_password(oldpass:string,newpass:string){
|
||||
var data={
|
||||
'oldpass':oldpass,
|
||||
'newpass':newpass
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/user/change_password", data);
|
||||
}
|
||||
dashboard_stats(versioncheck:boolean){
|
||||
var data={
|
||||
'versioncheck':versioncheck
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dashboard/stats", data);
|
||||
}
|
||||
|
||||
dashboard_traffic(delta:string){
|
||||
var data={
|
||||
'delta':delta
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dashboard/traffic", data);
|
||||
}
|
||||
|
||||
get_dev_list(data:any) {
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dev/list", data);
|
||||
}
|
||||
|
||||
get_devgroup_list() {
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/list", {});
|
||||
}
|
||||
|
||||
get_devgroup_members(gid:number) {
|
||||
var data={
|
||||
'gid':gid
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/members", data);
|
||||
}
|
||||
delete_group(id:number){
|
||||
var data={
|
||||
'gid':id
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/delete", data);
|
||||
}
|
||||
|
||||
delete_devices(devids:any){
|
||||
var data = {
|
||||
'devids':devids
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dev/delete", data);
|
||||
}
|
||||
|
||||
get_dev_info(id: number) {
|
||||
var data={
|
||||
'devid':id
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dev/info", data);
|
||||
}
|
||||
|
||||
get_editform(id: number) {
|
||||
var data={
|
||||
'devid':id
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dev/get_editform", data);
|
||||
}
|
||||
save_editform(data:any){
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dev/save_editform", data);
|
||||
}
|
||||
get_dev_sensors(id: number,delta:string="5m",total_type:string="bps") {
|
||||
var data={
|
||||
'devid':id,
|
||||
'delta':delta,
|
||||
'total':total_type
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dev/sensors", data);
|
||||
}
|
||||
|
||||
get_dev_ifstat(id: number,delta:string="5m",iface:string="ether1",type:string="bps") {
|
||||
var data={
|
||||
'devid':id,
|
||||
'delta':delta,
|
||||
'type':type,
|
||||
'interface':iface
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/dev/ifstat", data);
|
||||
}
|
||||
|
||||
get_auth_logs(filters:any) {
|
||||
var data=filters;
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/auth/list", data);
|
||||
}
|
||||
|
||||
get_account_logs(filters:any) {
|
||||
var data=filters;
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/account/list", data);
|
||||
}
|
||||
|
||||
get_dev_logs(filters:any) {
|
||||
var data=filters;
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/devlogs/list", data);
|
||||
}
|
||||
|
||||
get_syslog(filters:any) {
|
||||
var data=filters;
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/syslog/list", data);
|
||||
}
|
||||
get_details_grouped(devid:number=0){
|
||||
var data={
|
||||
'devid':devid
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/devlogs/details/list", data);
|
||||
}
|
||||
|
||||
scan_devs(type:string,info:any){
|
||||
var data: any={
|
||||
'type':type
|
||||
}
|
||||
if(type=="ip"){
|
||||
data = Object.assign(data, info);
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/scanner/scan", data);
|
||||
}
|
||||
|
||||
get_groups(searchstr:string=""){
|
||||
var data={
|
||||
'searchstr':searchstr
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/search/groups", data);
|
||||
}
|
||||
|
||||
get_devices(searchstr:string=""){
|
||||
var data={
|
||||
'searchstr':searchstr
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/search/devices", data);
|
||||
}
|
||||
|
||||
update_save_group(group:any){
|
||||
var data={
|
||||
...group
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/update_save_group", data);
|
||||
}
|
||||
|
||||
get_snippets(name:string,desc:string,content:string,page:number=0,size:number=1000){
|
||||
var data={
|
||||
'name':name,
|
||||
'description':desc,
|
||||
'content':content,
|
||||
'page':page,
|
||||
'size':size
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/snippet/list", data);
|
||||
}
|
||||
|
||||
save_snippet(data:any){
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/snippet/save", {...data});
|
||||
}
|
||||
|
||||
delete_snippet(id:number){
|
||||
var data={
|
||||
'id':id
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/snippet/delete", data);
|
||||
}
|
||||
|
||||
get_user_task_list() {
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/list", {});
|
||||
}
|
||||
|
||||
|
||||
Add_task(data:any,members:any) {
|
||||
data['members']=members;
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/create", data);
|
||||
}
|
||||
|
||||
Delete_task(taskid:Number) {
|
||||
var data={
|
||||
'taskid':taskid,
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/delete", data);
|
||||
}
|
||||
|
||||
Edit_task(data:any,members:any) {
|
||||
data['members']=members;
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/edit", data);
|
||||
}
|
||||
|
||||
get_task_members(taskid:Number) {
|
||||
var data={
|
||||
'taskid':taskid,
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/taskmember/details", data);
|
||||
}
|
||||
|
||||
|
||||
get_users(page:Number,size:Number,search:string) {
|
||||
var data={
|
||||
'page':page,
|
||||
'size':size,
|
||||
'search':search
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/users/list", data);
|
||||
}
|
||||
|
||||
get_perms(page:Number,size:Number,search:string) {
|
||||
var data={
|
||||
'page':page,
|
||||
'size':size,
|
||||
'search':search
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/perms/list", data);
|
||||
}
|
||||
|
||||
create_perm(name:string,perms:any) {
|
||||
var data={
|
||||
'name':name,
|
||||
'perms':perms
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/perms/create", data);
|
||||
}
|
||||
|
||||
edit_perm(id:Number,name:string,perms:any) {
|
||||
|
||||
var data = {
|
||||
'id':id,
|
||||
'name':name,
|
||||
'perms':perms
|
||||
}
|
||||
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/perms/edit", data);
|
||||
}
|
||||
|
||||
delete_perm(id:number){
|
||||
var data={
|
||||
'id':id
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/perms/delete", data);
|
||||
}
|
||||
|
||||
user_perms(uid:string) {
|
||||
|
||||
var data = {
|
||||
'uid':uid,
|
||||
}
|
||||
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/userperms/list", data);
|
||||
}
|
||||
|
||||
Add_user_perm(uid:Number,permid:Number,devgroupid:Number){
|
||||
|
||||
var data = {
|
||||
'uid':uid,
|
||||
'pid':permid,
|
||||
'gid':devgroupid
|
||||
}
|
||||
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/userperms/create", data);
|
||||
}
|
||||
Delete_user_perm(id:number){
|
||||
var data={
|
||||
'id':id
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/userperms/delete", data);
|
||||
}
|
||||
edit_user(data:any) {
|
||||
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/user/edit", data);
|
||||
}
|
||||
|
||||
create_user(data:any) {
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/user/create", data);
|
||||
}
|
||||
delete_user(id:number){
|
||||
var data={
|
||||
'uid':id
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/user/delete", data);
|
||||
}
|
||||
check_firmware(devids:any) {
|
||||
var data = {
|
||||
'devids':devids
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/check_firmware_update", data);
|
||||
}
|
||||
|
||||
get_firms(page:Number,size:Number,search:any) {
|
||||
var data = {
|
||||
'page':page,
|
||||
'size':size,
|
||||
'search':search
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/get_firms", data);
|
||||
}
|
||||
|
||||
get_backups(devid:Number=0,page:Number,size:Number,search:any) {
|
||||
var data = {
|
||||
'devid':devid,
|
||||
'page':page,
|
||||
'size':size,
|
||||
'search':search
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/backup/list", data);
|
||||
}
|
||||
|
||||
|
||||
get_backup(id:number){
|
||||
var data = {
|
||||
'id':id
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/backup/get", data);
|
||||
}
|
||||
|
||||
get_downloadable_firms() {
|
||||
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/get_downloadable_firms", {});
|
||||
}
|
||||
|
||||
download_firmware_to_repository(version:string){
|
||||
var data = {
|
||||
'version':version
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/download_firmware_to_repository", data);
|
||||
}
|
||||
|
||||
save_firmware_setting(updatebehavior:string,firmwaretoinstall:string,firmwaretoinstallv6:string){
|
||||
var data = {
|
||||
'updatebehavior':updatebehavior,
|
||||
'firmwaretoinstall':firmwaretoinstall,
|
||||
'firmwaretoinstallv6':firmwaretoinstallv6
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/update_firmware_settings", data);
|
||||
}
|
||||
|
||||
update_firmware(devids:string){
|
||||
var data = {
|
||||
'devids':devids
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/update_firmware", data);
|
||||
}
|
||||
|
||||
upgrade_firmware(devids:string){
|
||||
var data = {
|
||||
'devids':devids
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/upgrade_firmware", data);
|
||||
}
|
||||
|
||||
reboot_devices(devids:string){
|
||||
var data = {
|
||||
'devids':devids
|
||||
}
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/reboot_devices", data);
|
||||
}
|
||||
|
||||
get_settings(){
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/sysconfig/get_all", {});
|
||||
}
|
||||
|
||||
save_sys_setting(data:any){
|
||||
return this.MikroWizardRPC.sendJsonRequest("/api/sysconfig/save_all", data);
|
||||
}
|
||||
|
||||
|
||||
////
|
||||
//// End api funcs
|
||||
////
|
||||
setupSession(context: any, session: any) {
|
||||
this.MikroWizardRPC.clearCookeis();
|
||||
this.MikroWizardRPC.setNewSession(context, session);
|
||||
}
|
||||
|
||||
checkSessionExpired(error: any) {
|
||||
console.log(error);
|
||||
if ('title' in error && error.title == "session_expired")
|
||||
this.logout();
|
||||
return Promise.reject(error.message || error);
|
||||
}
|
||||
|
||||
|
||||
setSession(context: any, session_id: any) {
|
||||
this.MikroWizardRPC.setNewSession(context, session_id);
|
||||
}
|
||||
|
||||
getSessionInfo() {
|
||||
return this.MikroWizardRPC.getSessionInfo();
|
||||
}
|
||||
|
||||
getFullUrl(url: any) {
|
||||
return this.serverUrl + url;
|
||||
}
|
||||
}
|
209
src/app/providers/mikrowizard/provider.ts
Normal file
209
src/app/providers/mikrowizard/provider.ts
Normal file
|
@ -0,0 +1,209 @@
|
|||
import { Injectable, Inject } from '@angular/core';
|
||||
|
||||
import { HttpClient,HttpResponse } from '@angular/common/http';
|
||||
|
||||
class Cookies { // cookies doesn't work with Android default browser / Ionic
|
||||
private session_id: string = "";
|
||||
|
||||
delete_sessionId() {
|
||||
this.session_id = "";
|
||||
document.cookie = "";
|
||||
}
|
||||
|
||||
get_sessionId() {
|
||||
return document
|
||||
.cookie.split("; ")
|
||||
.filter(x => { return x.indexOf("session_id") === 0; })
|
||||
.map(x => { return x.split("=")[1]; })
|
||||
.pop() || this.session_id || "";
|
||||
}
|
||||
|
||||
set_sessionId(val: string) {
|
||||
// document.cookie = `session_id=${val}`;
|
||||
// this.session_id = val;
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class MikroWizardProvider {
|
||||
|
||||
private MikroWizard_server: string;
|
||||
private http_auth: string;
|
||||
private cookies: Cookies;
|
||||
private uniq_id_counter: number = 0;
|
||||
private shouldManageSessionId: boolean = false; // try without first
|
||||
private context: Object = {"lang": "en_US"};
|
||||
private headers: any;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
this.cookies = new Cookies();
|
||||
}
|
||||
|
||||
private buildRequest(url: string, params: any) {
|
||||
this.uniq_id_counter += 1;
|
||||
if (this.shouldManageSessionId) {
|
||||
params.session_id = this.cookies.get_sessionId();
|
||||
}
|
||||
|
||||
this.headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Session-Id": this.cookies.get_sessionId(),
|
||||
"Authorization": "Basic " + btoa(`${this.http_auth}`)
|
||||
};
|
||||
return params;
|
||||
}
|
||||
|
||||
private handleMikroWizardErrors(response: any) {
|
||||
//response = JSON.parse(response.data);
|
||||
if (!response.error) {
|
||||
if (typeof response.result === 'string' || response.result instanceof String)
|
||||
return JSON.parse(response.result);
|
||||
return response.result;
|
||||
}
|
||||
|
||||
let error = response.error;
|
||||
let errorObj = {
|
||||
title: " ",
|
||||
message: "",
|
||||
fullTrace: error
|
||||
};
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
private handleRequestErrors(response: any) {
|
||||
if (!response.error) {
|
||||
if (typeof response.result === 'string' || response.result instanceof String)
|
||||
return JSON.parse(response.result);
|
||||
return response.result;
|
||||
}
|
||||
|
||||
let error = response.error;
|
||||
let errorObj = {
|
||||
title: " ",
|
||||
message: "",
|
||||
fullTrace: error
|
||||
};
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
private handleHttpErrors(error: any) {
|
||||
try{
|
||||
console.log(error, Object.getOwnPropertyNames(error));
|
||||
}
|
||||
catch(e){
|
||||
console.log(error);
|
||||
}
|
||||
return Promise.reject(error.message || error);
|
||||
}
|
||||
|
||||
public init(configs: any) {
|
||||
this.MikroWizard_server = configs.MikroWizard_server;
|
||||
this.http_auth = configs.http_auth || null;
|
||||
}
|
||||
|
||||
public setMikroWizardServer(MikroWizard_server: string) {
|
||||
this.MikroWizard_server = MikroWizard_server;
|
||||
}
|
||||
|
||||
public setHttpAuth(http_auth: string) {
|
||||
this.http_auth = http_auth;
|
||||
}
|
||||
public sendRequestauth(url: string, params: Object){
|
||||
let body = this.buildRequest(url, params);
|
||||
console.dir(body);
|
||||
return this.http.post(this.MikroWizard_server + url, body, {observe: "response",headers: this.headers,withCredentials:true});
|
||||
}
|
||||
public sendRequest(url: string, params: Object): Promise<any> {
|
||||
let body = this.buildRequest(url, params);
|
||||
return this.http.post(this.MikroWizard_server + url, body, {headers: this.headers,withCredentials:true})
|
||||
.toPromise()
|
||||
.then((response: any) => this.handleMikroWizardErrors(response))
|
||||
.catch((response: any) => this.handleHttpErrors(response));
|
||||
}
|
||||
|
||||
public sendJsonRequest(url: string, params: Object) {
|
||||
let headers = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
return this.http.post(url, params,
|
||||
{headers:this.headers,withCredentials:true}
|
||||
).toPromise()
|
||||
.then(this.handleRequestErrors)
|
||||
.catch(this.handleHttpErrors);
|
||||
}
|
||||
|
||||
public sendHttpRequest(url: string, params: any) {
|
||||
let headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
};
|
||||
return this.http.post(this.MikroWizard_server + url, params,
|
||||
{headers:headers,withCredentials:true}
|
||||
).toPromise()
|
||||
.then(this.handleRequestErrors)
|
||||
.catch(this.handleHttpErrors);
|
||||
}
|
||||
public sendHttpGetRequest(url: string) {
|
||||
let headers = {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
};
|
||||
return this.http.get( url,
|
||||
{ responseType: 'json' }
|
||||
).toPromise()
|
||||
}
|
||||
|
||||
public getServerInfo() {
|
||||
return this.sendRequest("/api/version_info", {});
|
||||
}
|
||||
|
||||
public getSessionInfo() {
|
||||
return this.sendRequest("/api/me", {});
|
||||
}
|
||||
//Set-Cookie
|
||||
public login(db: string, login: string, password: string, ga: string) {
|
||||
let params = {
|
||||
username : login,
|
||||
password : password,
|
||||
// token: token,
|
||||
ga: ga
|
||||
};
|
||||
let $this = this;
|
||||
return this.sendRequest("/api/login", params);
|
||||
}
|
||||
|
||||
public isLoggedIn() {
|
||||
return this.getSessionInfo().then(function(result: any) {
|
||||
// console.dir("result");
|
||||
console.dir(result);
|
||||
// return true;
|
||||
if ( "uid" in result === false ) return false;
|
||||
else return true;
|
||||
});
|
||||
}
|
||||
|
||||
public clearCookeis() {
|
||||
this.cookies = new Cookies();
|
||||
}
|
||||
|
||||
public logout() {
|
||||
this.clearCookeis();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public getUserContext(context: any) {
|
||||
localStorage.setItem("user_context", JSON.stringify(context));
|
||||
|
||||
}
|
||||
|
||||
public getContext() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public setNewSession(user_context: any, session_id: any) {
|
||||
this.context = user_context;
|
||||
localStorage.setItem("user_context", JSON.stringify(this.context));
|
||||
}
|
||||
}
|
21
src/app/providers/mikrowizard/user.ts
Normal file
21
src/app/providers/mikrowizard/user.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
export class User {
|
||||
name: string;
|
||||
username: string;
|
||||
firstname: string;
|
||||
lastname: string;
|
||||
partner_id: number;
|
||||
id: number;
|
||||
role: string;
|
||||
perms:any;
|
||||
tz:string;
|
||||
constructor(name: any, username: any, partner_id: any, user_id: any,firstname: any,lastname: any,role: any,perms:any,tz:string) { this.name = name;
|
||||
this.username = username;
|
||||
this.partner_id = partner_id;
|
||||
this.id = user_id;
|
||||
this.firstname = firstname;
|
||||
this.lastname = lastname;
|
||||
this.role = role;
|
||||
this.perms = perms;
|
||||
this.tz=tz;
|
||||
}
|
||||
}
|
20
src/app/views/acc_log/acc-routing.module.ts
Normal file
20
src/app/views/acc_log/acc-routing.module.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { AccComponent } from "./acc.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: "",
|
||||
component: AccComponent,
|
||||
data: {
|
||||
title: $localize`Accounting Logs`,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AccRoutingModule {}
|
112
src/app/views/acc_log/acc.component.html
Normal file
112
src/app/views/acc_log/acc.component.html
Normal file
|
@ -0,0 +1,112 @@
|
|||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-4">
|
||||
<c-card-header>
|
||||
<c-row>
|
||||
<c-col xs [lg]="11">
|
||||
Accunting Logs
|
||||
</c-col>
|
||||
<c-col xs [lg]="1">
|
||||
<button (click)="toggleCollapse()" cButton class="me-1" color="primary"><i
|
||||
class="fa-solid fa-filter mr-1"></i>Filter</button>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-card-header>
|
||||
<c-card-body>
|
||||
<c-row>
|
||||
<div [visible]="filters_visible" cCollapse>
|
||||
<c-col xs [lg]="12" class="example-form">
|
||||
<mat-form-field>
|
||||
<mat-label>Start date</mat-label>
|
||||
<input matInput [matDatepicker]="picker1" (dateChange)="reinitgrid('start',$event)"
|
||||
[(ngModel)]="filters['start_time']" />
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker1></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>End date</mat-label>
|
||||
<input matInput [matDatepicker]="picker2" (dateChange)="reinitgrid('end',$event)"
|
||||
[(ngModel)]="filters['end_time']" />
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker2></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Select section</mat-label>
|
||||
<mat-select placeholder="Event Section" (ngModelChange)="reinitgrid('section',$event)"
|
||||
[(ngModel)]="filters['section']" #multiSelect>
|
||||
<mat-option value="All">All</mat-option>
|
||||
<mat-option *ngFor="let sec of event_section " [value]="sec">
|
||||
{{sec}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Select action</mat-label>
|
||||
<mat-select placeholder="Event Section" (ngModelChange)="reinitgrid('action',$event)"
|
||||
[(ngModel)]="filters['action']" #multiSelect>
|
||||
<mat-option value="All">All</mat-option>
|
||||
<mat-option *ngFor="let ac of event_action" [value]="ac">
|
||||
{{ac}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Config</mat-label>
|
||||
<input (ngModelChange)="reinitgrid('config',$event)" [(ngModel)]="filters['config']" matInput>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>IP</mat-label>
|
||||
<input (ngModelChange)="reinitgrid('ip',$event)" [(ngModel)]="filters['ip']" matInput>
|
||||
</mat-form-field>
|
||||
</c-col>
|
||||
|
||||
</div>
|
||||
|
||||
</c-row>
|
||||
<gui-grid [rowDetail]="rowDetail" [source]="source" [columnMenu]="columnMenu" [paging]="paging"
|
||||
[sorting]="sorting" [infoPanel]="infoPanel" [autoResizeWidth]=true>
|
||||
<gui-grid-column header="#No" type="NUMBER" field="index" width=25 align="CENTER">
|
||||
<ng-template let-value="item.index" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Device Name" field="name">
|
||||
<ng-template let-value="item.name" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Device IP" field="devip">
|
||||
<ng-template let-value="item.devip" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Username" field="username">
|
||||
<ng-template let-value="item.username" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Action" field="action">
|
||||
<ng-template let-value="item.action" let-item="item" let-index="index">
|
||||
<div>{{value}}</div>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Section" field="section">
|
||||
<ng-template let-value="item.section" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Date" field="created">
|
||||
<ng-template let-value="item.created" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Message" field="message" [enabled]="false">
|
||||
<ng-template let-value="item.message" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
86
src/app/views/acc_log/acc.component.scss
Normal file
86
src/app/views/acc_log/acc.component.scss
Normal file
|
@ -0,0 +1,86 @@
|
|||
@use '@angular/material' as mat;
|
||||
|
||||
:host {
|
||||
.legend {
|
||||
small {
|
||||
font-size: x-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
.gui-drawer-content{
|
||||
background-color: #efefef!important;
|
||||
|
||||
}
|
||||
.log-detail{
|
||||
padding:30px 10px;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
.log-detail h1{
|
||||
font-size:2em;
|
||||
font-weight:bold;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
.log-detail small{
|
||||
position:relative;
|
||||
top:-7px;
|
||||
padding:0;
|
||||
font-weight:bold;
|
||||
font-size:1.1em;
|
||||
}
|
||||
.log-detail table {
|
||||
width: 100%;
|
||||
border-collapse: collapse!important;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #fff!important;
|
||||
}
|
||||
.log-detail th {
|
||||
text-align: left;
|
||||
}
|
||||
.log-detail th,
|
||||
.log-detail td {
|
||||
border: 1px solid #dfdfdf!important;
|
||||
padding: 1rem!important;
|
||||
}
|
||||
|
||||
.log-detail code{
|
||||
padding:5px!important;
|
||||
display:block;
|
||||
background:#1d1f21;
|
||||
color:#c5c8c6;
|
||||
border-bottom-left-radius:3px;
|
||||
border-bottom-right-radius:3px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.log-detail .code-title{
|
||||
background-color:#393e42!important;;
|
||||
width:100%;
|
||||
padding:2px 15px;
|
||||
display:inline-block;
|
||||
margin-top:10px;
|
||||
color:#d2d2d2;
|
||||
border-top-left-radius:3px;
|
||||
border-top-right-radius:3px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
|
||||
.example-form {
|
||||
@include mat.button-density(-5);
|
||||
|
||||
@include mat.form-field-density(-5);
|
||||
@include mat.button-toggle-density(-5);
|
||||
@include mat.datepicker-density(-5);
|
||||
@include mat.all-component-densities(-5);
|
||||
@include mat.icon-button-density(-5);
|
||||
@include mat.icon-density(-5);
|
||||
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) .mat-mdc-floating-label { display: inline; }
|
||||
mat-form-field *{
|
||||
font-size:13px!important;
|
||||
}
|
||||
.mat-mdc-form-field-infix{
|
||||
width:150px;
|
||||
}
|
||||
}
|
204
src/app/views/acc_log/acc.component.ts
Normal file
204
src/app/views/acc_log/acc.component.ts
Normal file
|
@ -0,0 +1,204 @@
|
|||
import { Component, OnInit, ViewEncapsulation } from "@angular/core";
|
||||
import { dataProvider } from "../../providers/mikrowizard/data";
|
||||
import { Router, ActivatedRoute } from "@angular/router";
|
||||
import { loginChecker } from "../../providers/login_checker";
|
||||
import {
|
||||
GuiRowDetail,
|
||||
GuiSelectedRow,
|
||||
GuiInfoPanel,
|
||||
GuiColumn,
|
||||
GuiColumnMenu,
|
||||
GuiPaging,
|
||||
GuiPagingDisplay,
|
||||
GuiRowSelectionMode,
|
||||
GuiRowSelection,
|
||||
GuiRowSelectionType,
|
||||
} from "@generic-ui/ngx-grid";
|
||||
import { formatInTimeZone } from "date-fns-tz";
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: "acc.component.html",
|
||||
styleUrls: ["acc.component.scss"],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class AccComponent implements OnInit {
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
public tz: string;
|
||||
public filterText: string;
|
||||
public filters: any = {
|
||||
devid: false,
|
||||
ip: "",
|
||||
command: "",
|
||||
user: false,
|
||||
state: "all",
|
||||
with: "all",
|
||||
start_time: false,
|
||||
end_time: false,
|
||||
};
|
||||
public filters_visible: boolean = false;
|
||||
public event_action: any = [];
|
||||
public event_section: any = [];
|
||||
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private login_checker: loginChecker,
|
||||
) {
|
||||
var _self = this;
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["login"]);
|
||||
}, 100);
|
||||
}
|
||||
this.data_provider.getSessionInfo().then((res) => {
|
||||
_self.uid = res.uid;
|
||||
_self.uname = res.name;
|
||||
_self.tz = res.tz;
|
||||
const userId = _self.uid;
|
||||
|
||||
if (res.role != "admin") {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["/user/dashboard"]);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
//get datagrid data
|
||||
function isNotEmpty(value: any): boolean {
|
||||
return value !== undefined && value !== null && value !== "";
|
||||
}
|
||||
}
|
||||
public source: Array<any> = [];
|
||||
public columns: Array<GuiColumn> = [];
|
||||
public loading: boolean = true;
|
||||
public rows: any = [];
|
||||
public Selectedrows: any;
|
||||
public devid: number = 0;
|
||||
public sorting = {
|
||||
enabled: true,
|
||||
multiSorting: true,
|
||||
};
|
||||
rowDetail: GuiRowDetail = {
|
||||
enabled: true,
|
||||
template: (item) => {
|
||||
return `
|
||||
<div class='log-detail'>
|
||||
<h1>${item.name}</h1>
|
||||
<small>${item.devip}</small>
|
||||
<table>
|
||||
<tr>
|
||||
<td>User Address</td>
|
||||
<td>${item.address}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>User Name</td>
|
||||
<td>${item.username}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Connection Type</td>
|
||||
<td>${item.ctype}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Section</td>
|
||||
<td>${item.section}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Exec time</td>
|
||||
<td>${item.created}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="code-title">Executed Config</div>
|
||||
<code>
|
||||
${item.config}
|
||||
</code>
|
||||
</div>`;
|
||||
},
|
||||
};
|
||||
|
||||
public paging: GuiPaging = {
|
||||
enabled: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSizes: [5, 10, 25, 50],
|
||||
display: GuiPagingDisplay.ADVANCED,
|
||||
};
|
||||
|
||||
public columnMenu: GuiColumnMenu = {
|
||||
enabled: true,
|
||||
sort: true,
|
||||
columnsManager: true,
|
||||
};
|
||||
|
||||
public infoPanel: GuiInfoPanel = {
|
||||
enabled: true,
|
||||
infoDialog: false,
|
||||
columnsManager: true,
|
||||
schemaManager: true,
|
||||
};
|
||||
|
||||
public rowSelection: boolean | GuiRowSelection = {
|
||||
enabled: true,
|
||||
type: GuiRowSelectionType.CHECKBOX,
|
||||
mode: GuiRowSelectionMode.MULTIPLE,
|
||||
};
|
||||
|
||||
reinitgrid(field: string, $event: any) {
|
||||
if (field == "start") this.filters["start_time"] = $event.target.value;
|
||||
else if (field == "end") this.filters["end_time"] = $event.target.value;
|
||||
else if (field == "ip") this.filters["ip"] = $event;
|
||||
else if (field == "section") this.filters["section"] = $event;
|
||||
else if (field == "config") this.filters["config"] = $event;
|
||||
else if (field == "action") this.filters["action"] = $event;
|
||||
this.initGridTable();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.devid = Number(this.route.snapshot.paramMap.get("devid"));
|
||||
if (this.devid > 0) {
|
||||
this.filters["devid"] = this.devid;
|
||||
}
|
||||
this.initGridTable();
|
||||
}
|
||||
OnDestroy(): void {}
|
||||
onSelectedRows(rows: Array<GuiSelectedRow>): void {
|
||||
this.rows = rows;
|
||||
this.Selectedrows = rows.map((m: GuiSelectedRow) => m.source.id);
|
||||
}
|
||||
|
||||
removefilter(filter: any) {
|
||||
delete this.filters[filter];
|
||||
this.initGridTable();
|
||||
}
|
||||
toggleCollapse(): void {
|
||||
this.filters_visible = !this.filters_visible;
|
||||
}
|
||||
logger(item: any) {
|
||||
console.dir(item);
|
||||
}
|
||||
|
||||
initGridTable(): void {
|
||||
var _self = this;
|
||||
this.data_provider.get_account_logs(this.filters).then((res) => {
|
||||
let index = 1;
|
||||
this.source = res.map((d: any) => {
|
||||
d.index = index;
|
||||
if (!_self.event_section.includes(d.section))
|
||||
_self.event_section.push(d.section);
|
||||
|
||||
if (!_self.event_action.includes(d.action))
|
||||
_self.event_action.push(d.action);
|
||||
d.created = formatInTimeZone(
|
||||
d.created.split(".")[0] + ".000Z",
|
||||
_self.tz,
|
||||
"yyyy-MM-dd HH:mm:ss XXX"
|
||||
);
|
||||
index += 1;
|
||||
return d;
|
||||
});
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
42
src/app/views/acc_log/acc.module.ts
Normal file
42
src/app/views/acc_log/acc.module.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
|
||||
import {
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
FormModule,
|
||||
GridModule,
|
||||
CollapseModule,
|
||||
} from "@coreui/angular";
|
||||
|
||||
import { AccRoutingModule } from "./acc-routing.module";
|
||||
import { AccComponent } from "./acc.component";
|
||||
import { GuiGridModule } from "@generic-ui/ngx-grid";
|
||||
|
||||
import { MatDatepickerModule } from "@angular/material/datepicker";
|
||||
import { MatInputModule } from "@angular/material/input";
|
||||
import { MatFormFieldModule } from "@angular/material/form-field";
|
||||
import { MatSelectModule } from "@angular/material/select";
|
||||
|
||||
import { FormsModule } from "@angular/forms";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
AccRoutingModule,
|
||||
CardModule,
|
||||
CommonModule,
|
||||
GridModule,
|
||||
FormsModule,
|
||||
ButtonModule,
|
||||
FormModule,
|
||||
ButtonModule,
|
||||
GuiGridModule,
|
||||
CollapseModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatDatepickerModule,
|
||||
MatSelectModule,
|
||||
],
|
||||
declarations: [AccComponent],
|
||||
})
|
||||
export class AccModule {}
|
21
src/app/views/auth_log/auth-routing.module.ts
Normal file
21
src/app/views/auth_log/auth-routing.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { AuthComponent } from './auth.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: AuthComponent,
|
||||
data: {
|
||||
title: $localize`Authentication Logs`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AuthRoutingModule {
|
||||
}
|
142
src/app/views/auth_log/auth.component.html
Normal file
142
src/app/views/auth_log/auth.component.html
Normal file
|
@ -0,0 +1,142 @@
|
|||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-4">
|
||||
<c-card-header>
|
||||
<c-row>
|
||||
<c-col xs [lg]="11">
|
||||
Authentication Logs
|
||||
</c-col>
|
||||
<c-col xs [lg]="1">
|
||||
<button (click)="toggleCollapse()" cButton class="me-1" color="primary"><i
|
||||
class="fa-solid fa-filter mr-1"></i>Filter</button>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-card-header>
|
||||
<c-card-body>
|
||||
<c-row>
|
||||
<div [visible]="filters_visible" cCollapse>
|
||||
<c-col xs [lg]="12" class="example-form">
|
||||
<mat-form-field>
|
||||
<mat-label>Start date</mat-label>
|
||||
<input matInput [matDatepicker]="picker1" (dateChange)="reinitgrid('start',$event)"
|
||||
[(ngModel)]="filters['start_time']" />
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker1></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>End date</mat-label>
|
||||
<input matInput [matDatepicker]="picker2" (dateChange)="reinitgrid('end',$event)"
|
||||
[(ngModel)]="filters['end_time']" />
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker2></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Connection Type</mat-label>
|
||||
<mat-select placeholder="Connection Type" (ngModelChange)="reinitgrid('connection_type',$event)"
|
||||
[(ngModel)]="filters['connection_type']" #multiSelect>
|
||||
<mat-option value="All">All</mat-option>
|
||||
<mat-option *ngFor="let con of connection_types " [value]="con">
|
||||
{{con}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Select action</mat-label>
|
||||
<mat-select placeholder="State" (ngModelChange)="reinitgrid('state',$event)"
|
||||
[(ngModel)]="filters['state']" #multiSelect>
|
||||
<mat-option value="All">All</mat-option>
|
||||
<mat-option *ngFor="let ac of ['Logged In','Logged Out','Failed']" [value]="ac">
|
||||
{{ac}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field >
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Server</mat-label>
|
||||
<mat-select placeholder="Server" (ngModelChange)="reinitgrid('server',$event)"
|
||||
[(ngModel)]="filters['server']" #multiSelect>
|
||||
<mat-option value="All">All</mat-option>
|
||||
<mat-option *ngFor="let ac of ['Local','Mikrowizard']" [value]="ac">
|
||||
{{ac}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field >
|
||||
<mat-form-field>
|
||||
<mat-label>Device IP</mat-label>
|
||||
<input (ngModelChange)="reinitgrid('devip',$event)" [(ngModel)]="filters['devip']" matInput>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>IP/MAC</mat-label>
|
||||
<input (ngModelChange)="reinitgrid('ip',$event)" [(ngModel)]="filters['ip']" matInput>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Username</mat-label>
|
||||
<input (ngModelChange)="reinitgrid('user',$event)" [(ngModel)]="filters['user']" matInput>
|
||||
</mat-form-field>
|
||||
</c-col>
|
||||
|
||||
</div>
|
||||
|
||||
</c-row>
|
||||
<gui-grid [source]="source" [paging]="paging" [columnMenu]="columnMenu" [sorting]="sorting"
|
||||
[infoPanel]="infoPanel" [autoResizeWidth]=true>
|
||||
<gui-grid-column header="#No" type="NUMBER" field="index" width=25 align="CENTER">
|
||||
<ng-template let-value="item.index" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Device Name" field="name">
|
||||
<ng-template let-value="item.name" let-item="item" let-index="index">
|
||||
<i *ngIf="item.stype=='local'" cTooltip="local user"
|
||||
style="color: rgb(255, 42, 0); margin-right: 3px;font-size: .7em;" class="fa-solid fa-user-tie"></i>
|
||||
<i *ngIf="item.stype=='radius'" cTooltip="Update failed"
|
||||
style="color: rgb(9, 97, 20); margin-right: 3px;font-size: .7em;" class="fa-solid fa-server"></i>
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Device IP" field="devip">
|
||||
<ng-template let-value="item.devip" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Username" field="username">
|
||||
<ng-template let-value="item.username" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="With" field="by">
|
||||
<ng-template let-value="item.by" let-item="item" let-index="index">
|
||||
<div>{{value}}</div>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="IP Address" field="ip">
|
||||
<ng-template let-value="item.ip" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
|
||||
<gui-grid-column header="Time/Msg" field="duration">
|
||||
<ng-template let-value="item.duration" let-item="item" let-index="index">
|
||||
<span *ngIf="item.ltype!='failed'">{{value}}</span>
|
||||
<span *ngIf="item.ltype=='failed'">{{item.message}}</span>
|
||||
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
|
||||
<gui-grid-column header="State" field="ltype" [width]="110">
|
||||
<ng-template let-value="item.ltype" let-item="item.id" let-index="index">
|
||||
<c-badge color="success" *ngIf="value=='loggedin'"> Logged In</c-badge>
|
||||
<c-badge color="warning" *ngIf="value=='loggedout'"> Logged Out</c-badge>
|
||||
<c-badge color="danger" *ngIf="value=='failed'"> Failed</c-badge>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Date" field="created">
|
||||
<ng-template let-value="item.created" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
36
src/app/views/auth_log/auth.component.scss
Normal file
36
src/app/views/auth_log/auth.component.scss
Normal file
|
@ -0,0 +1,36 @@
|
|||
|
||||
@use '@angular/material' as mat;
|
||||
// Plus imports for other components in your app.
|
||||
|
||||
// Include the common styles for Angular Material. We include this here so that you only
|
||||
// have to load a single css file for Angular Material in your app.
|
||||
// Be sure that you only ever include this mixin once!
|
||||
|
||||
// Include theme styles for core and each component used in your app.
|
||||
// Alternatively, you can import and @include the theme mixins for each component
|
||||
// that you are using.
|
||||
.example-form {
|
||||
@include mat.button-density(-5);
|
||||
|
||||
@include mat.form-field-density(-5);
|
||||
@include mat.button-toggle-density(-5);
|
||||
@include mat.datepicker-density(-5);
|
||||
@include mat.all-component-densities(-5);
|
||||
@include mat.icon-button-density(-5);
|
||||
@include mat.icon-density(-5);
|
||||
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) .mat-mdc-floating-label { display: inline; }
|
||||
mat-form-field *{
|
||||
font-size:13px!important;
|
||||
}
|
||||
.mat-mdc-form-field-infix{
|
||||
width:150px;
|
||||
}
|
||||
}
|
||||
|
||||
:host {
|
||||
.legend {
|
||||
small {
|
||||
font-size: x-small;
|
||||
}
|
||||
}
|
||||
}
|
222
src/app/views/auth_log/auth.component.ts
Normal file
222
src/app/views/auth_log/auth.component.ts
Normal file
|
@ -0,0 +1,222 @@
|
|||
import { Component, OnInit, ViewEncapsulation } from "@angular/core";
|
||||
import { dataProvider } from "../../providers/mikrowizard/data";
|
||||
import { Router, ActivatedRoute } from "@angular/router";
|
||||
import { loginChecker } from "../../providers/login_checker";
|
||||
import {
|
||||
GuiSelectedRow,
|
||||
GuiInfoPanel,
|
||||
GuiColumn,
|
||||
GuiColumnMenu,
|
||||
GuiPaging,
|
||||
GuiPagingDisplay,
|
||||
GuiRowSelectionMode,
|
||||
GuiRowSelection,
|
||||
GuiRowSelectionType,
|
||||
} from "@generic-ui/ngx-grid";
|
||||
import { formatInTimeZone } from "date-fns-tz";
|
||||
|
||||
interface IUser {
|
||||
name: string;
|
||||
state: string;
|
||||
registered: string;
|
||||
country: string;
|
||||
usage: number;
|
||||
period: string;
|
||||
payment: string;
|
||||
activity: string;
|
||||
avatar: string;
|
||||
status: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "auth.component.html",
|
||||
styleUrls: ["auth.component.scss"],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class AuthComponent implements OnInit {
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
public tz: string = "UTC";
|
||||
public filterText: string;
|
||||
public devid: number = 0;
|
||||
public filters: any = {
|
||||
devid: false,
|
||||
ip: "",
|
||||
devip: "",
|
||||
user: "",
|
||||
state: "All",
|
||||
server: "All",
|
||||
connection_type: "All",
|
||||
start_time: false,
|
||||
end_time: false,
|
||||
};
|
||||
public filters_visible: boolean = false;
|
||||
public connection_types: any = [];
|
||||
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private router: Router,
|
||||
private login_checker: loginChecker,
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
var _self = this;
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["login"]);
|
||||
}, 100);
|
||||
}
|
||||
this.data_provider.getSessionInfo().then((res) => {
|
||||
_self.uid = res.uid;
|
||||
_self.uname = res.name;
|
||||
_self.tz = res.tz;
|
||||
const userId = _self.uid;
|
||||
|
||||
if (res.role != "admin") {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["/user/dashboard"]);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
//get datagrid data
|
||||
function isNotEmpty(value: any): boolean {
|
||||
return value !== undefined && value !== null && value !== "";
|
||||
}
|
||||
}
|
||||
public source: Array<any> = [];
|
||||
public columns: Array<GuiColumn> = [];
|
||||
public loading: boolean = true;
|
||||
public rows: any = [];
|
||||
public Selectedrows: any;
|
||||
|
||||
public sorting = {
|
||||
enabled: true,
|
||||
multiSorting: true,
|
||||
};
|
||||
|
||||
public paging: GuiPaging = {
|
||||
enabled: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSizes: [5, 10, 25, 50],
|
||||
display: GuiPagingDisplay.ADVANCED,
|
||||
};
|
||||
|
||||
public columnMenu: GuiColumnMenu = {
|
||||
enabled: true,
|
||||
sort: true,
|
||||
columnsManager: true,
|
||||
};
|
||||
|
||||
public infoPanel: GuiInfoPanel = {
|
||||
enabled: true,
|
||||
infoDialog: false,
|
||||
columnsManager: true,
|
||||
schemaManager: true,
|
||||
};
|
||||
|
||||
public rowSelection: boolean | GuiRowSelection = {
|
||||
enabled: true,
|
||||
type: GuiRowSelectionType.CHECKBOX,
|
||||
mode: GuiRowSelectionMode.MULTIPLE,
|
||||
};
|
||||
|
||||
reinitgrid(field: string, $event: any) {
|
||||
if (field == "start") this.filters["start_time"] = $event.target.value;
|
||||
else if (field == "end") this.filters["end_time"] = $event.target.value;
|
||||
else if (field == "ip") this.filters["ip"] = $event;
|
||||
else if (field == "devip") this.filters["devip"] = $event;
|
||||
else if (field == "user") this.filters["user"] = $event;
|
||||
else if (field == "connection_type")
|
||||
this.filters["connection_type"] = $event;
|
||||
else if (field == "state") this.filters["state"] = $event;
|
||||
else if (field == "server") this.filters["server"] = $event;
|
||||
this.initGridTable();
|
||||
}
|
||||
secondsToString(seconds: number) {
|
||||
var years = Math.floor(seconds / 31536000);
|
||||
var max = 2;
|
||||
var current = 0;
|
||||
var str = "";
|
||||
if (years && current < max) {
|
||||
str += years + "y ";
|
||||
current++;
|
||||
}
|
||||
var days = Math.floor((seconds %= 31536000) / 86400);
|
||||
if (days && current < max) {
|
||||
str += days + "d ";
|
||||
current++;
|
||||
}
|
||||
var hours = Math.floor((seconds %= 86400) / 3600);
|
||||
if (hours && current < max) {
|
||||
str += hours + "h ";
|
||||
current++;
|
||||
}
|
||||
var minutes = Math.floor((seconds %= 3600) / 60);
|
||||
if (minutes && current < max) {
|
||||
str += minutes + "m ";
|
||||
current++;
|
||||
}
|
||||
var seconds = seconds % 60;
|
||||
if (seconds && current < max) {
|
||||
str += seconds + "s ";
|
||||
current++;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
ngOnInit(): void {
|
||||
this.devid = Number(this.route.snapshot.paramMap.get("devid"));
|
||||
if (this.devid > 0) {
|
||||
this.filters["devid"] = this.devid;
|
||||
}
|
||||
this.initGridTable();
|
||||
}
|
||||
onSelectedRows(rows: Array<GuiSelectedRow>): void {
|
||||
this.rows = rows;
|
||||
this.Selectedrows = rows.map((m: GuiSelectedRow) => m.source.id);
|
||||
}
|
||||
|
||||
removefilter(filter: any) {
|
||||
delete this.filters[filter];
|
||||
this.initGridTable();
|
||||
}
|
||||
toggleCollapse(): void {
|
||||
this.filters_visible = !this.filters_visible;
|
||||
}
|
||||
logger(item: any) {
|
||||
console.dir(item);
|
||||
}
|
||||
|
||||
initGridTable(): void {
|
||||
var _self = this;
|
||||
this.data_provider.get_auth_logs(this.filters).then((res) => {
|
||||
let index = 1;
|
||||
this.source = res.map((d: any) => {
|
||||
d.index = index;
|
||||
if (!_self.connection_types.includes(d.by))
|
||||
_self.connection_types.push(d.by);
|
||||
|
||||
if (!d.sessionid) {
|
||||
d.stype = "local";
|
||||
d.duration = "Local Access";
|
||||
} else {
|
||||
d.stype = "radius";
|
||||
if (d.ended != 0) {
|
||||
d.duration = _self.secondsToString(d.ended - d.started);
|
||||
} else {
|
||||
d.duration = "live";
|
||||
}
|
||||
}
|
||||
d.created = formatInTimeZone(
|
||||
d.created.split(".")[0] + ".000Z",
|
||||
_self.tz,
|
||||
"yyyy-MM-dd HH:mm:ss XXX"
|
||||
);
|
||||
index += 1;
|
||||
return d;
|
||||
});
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
41
src/app/views/auth_log/auth.module.ts
Normal file
41
src/app/views/auth_log/auth.module.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import {
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
GridModule,
|
||||
CollapseModule,
|
||||
BadgeModule,
|
||||
} from '@coreui/angular';
|
||||
import { AuthRoutingModule } from './auth-routing.module';
|
||||
import { AuthComponent } from './auth.component';
|
||||
import { GuiGridModule } from '@generic-ui/ngx-grid';
|
||||
|
||||
import { faCoffee } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import {MatDatepickerModule} from '@angular/material/datepicker';
|
||||
import {MatInputModule} from '@angular/material/input';
|
||||
import {MatFormFieldModule} from '@angular/material/form-field';
|
||||
import {MatSelectModule} from '@angular/material/select';
|
||||
@NgModule({
|
||||
imports: [
|
||||
AuthRoutingModule,
|
||||
CardModule,
|
||||
CommonModule,
|
||||
GridModule,
|
||||
FormsModule,
|
||||
ButtonModule,
|
||||
GuiGridModule,
|
||||
CollapseModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatDatepickerModule,
|
||||
MatSelectModule,
|
||||
BadgeModule
|
||||
],
|
||||
declarations: [AuthComponent]
|
||||
})
|
||||
export class AuthModule {
|
||||
}
|
21
src/app/views/backups/backups-routing.module.ts
Normal file
21
src/app/views/backups/backups-routing.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { BackupsComponent } from './backups.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: BackupsComponent,
|
||||
data: {
|
||||
title: $localize`Backups`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class BackupsRoutingModule {
|
||||
}
|
68
src/app/views/backups/backups.component.html
Normal file
68
src/app/views/backups/backups.component.html
Normal file
|
@ -0,0 +1,68 @@
|
|||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-4">
|
||||
<c-card-header>Backups</c-card-header>
|
||||
<c-card-body>
|
||||
<c-badge color="warning" *ngIf="devid!=0">Filtered Result For Device ID {{devid}}</c-badge>
|
||||
|
||||
<gui-grid [source]="source" [searching]="searching" [paging]="paging" [columnMenu]="columnMenu"
|
||||
[sorting]="sorting" [infoPanel]="infoPanel" [columnMenu]="columnMenu" [sorting]="sorting"
|
||||
[infoPanel]="infoPanel" [autoResizeWidth]=true>
|
||||
<gui-grid-column header="#No" type="NUMBER" field="index" width=25 align="CENTER">
|
||||
<ng-template let-value="item.index" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Device Name" field="devname">
|
||||
<ng-template let-value="item.devname" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Device IP" field="devip">
|
||||
<ng-template let-value="item.devip" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="backup Time" field="createdC">
|
||||
<ng-template let-value="item.createdC" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="File Size" field="filesize">
|
||||
<ng-template let-value="item.filesize" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="MAC" field="devmac" [enabled]="false">
|
||||
<ng-template let-value="item.devmac" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Action" field="id">
|
||||
<ng-template let-value="item.id" let-item="item" let-index="index">
|
||||
<button cButton color="info" size="sm" (click)="ShowBackup(item.id)" class="mx-1"><i
|
||||
style="margin: 1px 5px;color:#ffffff;" class="fa-solid fa-eye"></i>Show backup</button>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
||||
|
||||
<c-modal #BakcupModal backdrop="static" [(visible)]="BakcupModalVisible" id="BakcupModal" size="xl">
|
||||
<c-modal-header>
|
||||
<h6 cModalTitle>Please Confirm Action </h6>
|
||||
<button [cModalToggle]="BakcupModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
<pre>
|
||||
<code *ngIf="!loading" language="properties" style="height:70vh" [highlight]="codeForHighlightAuto"
|
||||
lineNumbers></code></pre>
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<button [cModalToggle]="BakcupModal.id" cButton color="info">
|
||||
Close
|
||||
</button>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
0
src/app/views/backups/backups.component.scss
Normal file
0
src/app/views/backups/backups.component.scss
Normal file
153
src/app/views/backups/backups.component.ts
Normal file
153
src/app/views/backups/backups.component.ts
Normal file
|
@ -0,0 +1,153 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { dataProvider } from "../../providers/mikrowizard/data";
|
||||
import { Router, ActivatedRoute } from "@angular/router";
|
||||
import { loginChecker } from "../../providers/login_checker";
|
||||
import {
|
||||
GuiSearching,
|
||||
GuiInfoPanel,
|
||||
GuiColumn,
|
||||
GuiColumnMenu,
|
||||
GuiPaging,
|
||||
GuiPagingDisplay,
|
||||
GuiRowSelectionMode,
|
||||
GuiRowSelection,
|
||||
GuiRowSelectionType,
|
||||
} from "@generic-ui/ngx-grid";
|
||||
import { formatInTimeZone } from "date-fns-tz";
|
||||
|
||||
interface IUser {
|
||||
name: string;
|
||||
state: string;
|
||||
registered: string;
|
||||
country: string;
|
||||
usage: number;
|
||||
period: string;
|
||||
payment: string;
|
||||
activity: string;
|
||||
avatar: string;
|
||||
status: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "backups.component.html",
|
||||
})
|
||||
export class BackupsComponent implements OnInit {
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
public tz: string = "UTC";
|
||||
public filterText: string;
|
||||
public filters: any = {};
|
||||
public codeForHighlightAuto: string = "";
|
||||
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private router: Router,
|
||||
private login_checker: loginChecker,
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
var _self = this;
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["login"]);
|
||||
}, 100);
|
||||
}
|
||||
this.data_provider.getSessionInfo().then((res) => {
|
||||
_self.uid = res.uid;
|
||||
_self.uname = res.name;
|
||||
_self.tz = res.tz;
|
||||
const userId = _self.uid;
|
||||
|
||||
if (res.role != "admin") {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["/user/dashboard"]);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
//get datagrid data
|
||||
function isNotEmpty(value: any): boolean {
|
||||
return value !== undefined && value !== null && value !== "";
|
||||
}
|
||||
}
|
||||
|
||||
public source: Array<any> = [];
|
||||
public columns: Array<GuiColumn> = [];
|
||||
public loading: boolean = true;
|
||||
public rows: any = [];
|
||||
public Selectedrows: any;
|
||||
public BakcupModalVisible: boolean = false;
|
||||
public devid: number = 0;
|
||||
|
||||
public sorting = {
|
||||
enabled: true,
|
||||
multiSorting: true,
|
||||
};
|
||||
searching: GuiSearching = {
|
||||
enabled: true,
|
||||
placeholder: "Search Devices",
|
||||
};
|
||||
public paging: GuiPaging = {
|
||||
enabled: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSizes: [5, 10, 25, 50],
|
||||
display: GuiPagingDisplay.ADVANCED,
|
||||
};
|
||||
|
||||
public columnMenu: GuiColumnMenu = {
|
||||
enabled: true,
|
||||
sort: true,
|
||||
columnsManager: true,
|
||||
};
|
||||
|
||||
public infoPanel: GuiInfoPanel = {
|
||||
enabled: true,
|
||||
infoDialog: false,
|
||||
columnsManager: true,
|
||||
schemaManager: true,
|
||||
};
|
||||
|
||||
public rowSelection: boolean | GuiRowSelection = {
|
||||
enabled: true,
|
||||
type: GuiRowSelectionType.CHECKBOX,
|
||||
mode: GuiRowSelectionMode.MULTIPLE,
|
||||
};
|
||||
|
||||
ngOnInit(): void {
|
||||
this.devid = Number(this.route.snapshot.paramMap.get("devid"));
|
||||
this.initGridTable();
|
||||
}
|
||||
|
||||
logger(item: any) {
|
||||
console.dir(item);
|
||||
}
|
||||
|
||||
ShowBackup(id: number) {
|
||||
this.BakcupModalVisible = true;
|
||||
this.loading = true;
|
||||
this.data_provider.get_backup(id).then((res) => {
|
||||
this.codeForHighlightAuto = res.content;
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
initGridTable(): void {
|
||||
var _self=this;
|
||||
this.data_provider.get_backups(this.devid, 0, 0, false).then((res) => {
|
||||
let index = 1;
|
||||
this.source = res.map((d: any) => {
|
||||
d.index = index;
|
||||
d.createdC = formatInTimeZone(
|
||||
d.created.split(".")[0] + ".000Z",
|
||||
_self.tz,
|
||||
"yyyy-MM-dd HH:mm:ss XXX"
|
||||
);
|
||||
// d.created = [d.created.split("T")[0],d.created.split("T")[1].split(".")[0]].join(" ")
|
||||
index += 1;
|
||||
return d;
|
||||
});
|
||||
console.dir(this.source);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
36
src/app/views/backups/backups.module.ts
Normal file
36
src/app/views/backups/backups.module.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Highlight, HighlightAuto } from "ngx-highlightjs";
|
||||
import { HighlightLineNumbers } from "ngx-highlightjs/line-numbers";
|
||||
|
||||
import {
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
GridModule,
|
||||
CollapseModule,
|
||||
BadgeModule,
|
||||
ModalModule,
|
||||
} from "@coreui/angular";
|
||||
import { BackupsRoutingModule } from "./backups-routing.module";
|
||||
import { BackupsComponent } from "./backups.component";
|
||||
import { GuiGridModule } from "@generic-ui/ngx-grid";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BackupsRoutingModule,
|
||||
CardModule,
|
||||
CommonModule,
|
||||
GridModule,
|
||||
ButtonModule,
|
||||
ButtonModule,
|
||||
GuiGridModule,
|
||||
CollapseModule,
|
||||
BadgeModule,
|
||||
Highlight,
|
||||
HighlightAuto,
|
||||
HighlightLineNumbers,
|
||||
ModalModule,
|
||||
],
|
||||
declarations: [BackupsComponent],
|
||||
})
|
||||
export class BackupsModule {}
|
21
src/app/views/dashboard/dashboard-routing.module.ts
Normal file
21
src/app/views/dashboard/dashboard-routing.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { DashboardComponent } from './dashboard.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DashboardComponent,
|
||||
data: {
|
||||
title: $localize`Dashboard`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DashboardRoutingModule {
|
||||
}
|
168
src/app/views/dashboard/dashboard.component.html
Normal file
168
src/app/views/dashboard/dashboard.component.html
Normal file
|
@ -0,0 +1,168 @@
|
|||
<c-row *ngIf="stats">
|
||||
<c-col xs>
|
||||
<c-card *ngIf="stats" class="mb-1">
|
||||
<c-card-header>Past 24 Hour Statics</c-card-header>
|
||||
<c-card-body>
|
||||
<c-row>
|
||||
<c-col md="12" xl="12" xs="12">
|
||||
<c-row>
|
||||
<c-col class="mb-sm-1 mb-0">
|
||||
<c-widget-stat-f [title]="'Failed Logins'" class="mb-1" color="danger" padding
|
||||
value="{{stats['FailedLogins']}}">
|
||||
<ng-template cTemplateId="widgetIconTemplate">
|
||||
<i style="font-size: 2em;" class="fa-solid fa-person-circle-exclamation"></i>
|
||||
</ng-template>
|
||||
</c-widget-stat-f>
|
||||
</c-col>
|
||||
<c-col class="mb-sm-1 mb-0">
|
||||
<c-widget-stat-f [title]="'Success Logins'" class="mb-1" color="success" padding
|
||||
value="{{stats['SuccessfulLogins']}}">
|
||||
<ng-template cTemplateId="widgetIconTemplate">
|
||||
<i style="font-size: 2em;" class="fa-solid fa-arrow-right-to-bracket"></i>
|
||||
</ng-template>
|
||||
</c-widget-stat-f>
|
||||
</c-col>
|
||||
<c-col class="mb-sm-1 mb-0">
|
||||
<c-widget-stat-f [title]="'Critical Events'" class="mb-1" color="danger" padding
|
||||
value="{{stats['Critical']}}">
|
||||
<ng-template cTemplateId="widgetIconTemplate">
|
||||
<i style="font-size: 2em;" class="fa-solid fa-skull-crossbones"></i>
|
||||
</ng-template>
|
||||
</c-widget-stat-f>
|
||||
</c-col>
|
||||
<c-col class="mb-sm-1 mb-0">
|
||||
<c-widget-stat-f [title]="'Warning Events'" class="mb-1" color="warning" padding
|
||||
value="{{stats['Warning']}}">
|
||||
<ng-template cTemplateId="widgetIconTemplate">
|
||||
<i style="font-size: 2em;" class="fa-solid fa-triangle-exclamation"></i>
|
||||
</ng-template>
|
||||
</c-widget-stat-f>
|
||||
</c-col>
|
||||
<c-col class="mb-sm-1 mb-0">
|
||||
<c-widget-stat-f [title]="'Info Events'" class="mb-1" color="info" padding value="{{stats['Info']}}">
|
||||
<ng-template cTemplateId="widgetIconTemplate">
|
||||
<i style="font-size: 2em;" class="fa-solid fa-circle-info"></i>
|
||||
</ng-template>
|
||||
</c-widget-stat-f>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-card-body>
|
||||
<c-card-footer class="pb-0">
|
||||
<c-col xs>
|
||||
<c-row>
|
||||
<c-col md="12" xl="12" xs="12">
|
||||
<c-row>
|
||||
<c-col class="mb-0 pb-0">
|
||||
<div class="border-start border-start-4 border-start-info pt-1 px-3 mb-1">
|
||||
<div class="text-medium-emphasis small">Total users</div>
|
||||
<div class="fs-6 fw-semibold">{{stats['Users']}}</div>
|
||||
</div>
|
||||
</c-col>
|
||||
<c-col class="mb-0 pb-0">
|
||||
<div class="border-start border-start-4 border-start-warning pt-1 px-3 mb-1">
|
||||
<div class="text-medium-emphasis small">Total Devices</div>
|
||||
<div class="fs-6 fw-semibold">{{stats['Devices']}}</div>
|
||||
</div>
|
||||
</c-col>
|
||||
<c-col class="mb-0 pb-0">
|
||||
<div class="border-start border-start-4 border-start-success pt-1 px-3 mb-1">
|
||||
<div class="text-medium-emphasis small">Total Events</div>
|
||||
<div class="fs-6 fw-semibold">{{stats['Events']}}</div>
|
||||
</div>
|
||||
</c-col>
|
||||
<c-col class="mb-0 pb-0">
|
||||
<div class="border-start border-start-4 border-start-success pt-1 px-3 mb-1">
|
||||
<div class="text-medium-emphasis small">Total Auth Logs</div>
|
||||
<div class="fs-6 fw-semibold">{{stats['Auth']}}</div>
|
||||
</div>
|
||||
</c-col>
|
||||
<c-col class="mb-0 pb-0">
|
||||
<div class="border-start border-start-4 border-start-success pt-1 px-3 mb-1">
|
||||
<div class="text-medium-emphasis small">Total Acc Logs</div>
|
||||
<div class="fs-6 fw-semibold">{{stats['Acc']}}</div>
|
||||
</div>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-col>
|
||||
</c-card-footer>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
||||
|
||||
<c-card class="mb-1">
|
||||
<c-card-body>
|
||||
<c-row>
|
||||
<c-col sm="5">
|
||||
<h4 class="card-title mb-0" id="traffic">Total Devices Traffic</h4>
|
||||
</c-col>
|
||||
<c-col class="d-none d-md-block" sm="7">
|
||||
<form [formGroup]="trafficRadioGroup">
|
||||
<c-button-group class="float-end me-3" role="group">
|
||||
<input class="btn-check" formControlName="trafficRadio" type="radio" value="5m" />
|
||||
<label (click)="setTrafficPeriod('5m')" cButton cFormCheckLabel color="secondary" variant="outline">5
|
||||
Minues</label>
|
||||
|
||||
<input class="btn-check" formControlName="trafficRadio" type="radio" value="1h" />
|
||||
<label (click)="setTrafficPeriod('1h')" cButton cFormCheckLabel color="secondary"
|
||||
variant="outline">Hourly</label>
|
||||
|
||||
<input class="btn-check" formControlName="trafficRadio" type="radio" value="daily" />
|
||||
<label (click)="setTrafficPeriod('daily')" cButton cFormCheckLabel color="secondary"
|
||||
variant="outline">Daily</label>
|
||||
<input class="btn-check" formControlName="trafficRadio" type="radio" value="live" />
|
||||
<label (click)="setTrafficPeriod('live')" cButton cFormCheckLabel color="secondary"
|
||||
variant="outline">Live</label>
|
||||
</c-button-group>
|
||||
</form>
|
||||
</c-col>
|
||||
</c-row>
|
||||
<c-chart [data]="chart_data" [options]="options" [height]="200" type="line">
|
||||
</c-chart>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
<c-row>
|
||||
<c-col xl="6" *ngIf="stats" lg="12" class="h-100">
|
||||
<c-widget-stat-b [title]="stats['version']" class="mb-1 h-100" value="Version">
|
||||
<div class="my-1">
|
||||
<code style="padding: 0!important;">Serial:</code> <small
|
||||
style="background-color: #ccc;padding: 5px;border-radius: 5px;cursor: pointer;" (click)="copy_this()"
|
||||
[cdkCopyToClipboard]="stats['serial']">{{ stats['serial'] }}</small>
|
||||
<span *ngIf="copy_msg" style="color: #fff!important;" class="badge text-bg-success mx-1"><i
|
||||
class="fa-solid fa-check"></i>Copy</span>
|
||||
</div>
|
||||
<div *ngIf="!stats['license']" class="my-1">
|
||||
<c-badge color="danger">Not Registred</c-badge>
|
||||
<a class="mx-1" target="_blank" href="http://MikroWizard.com">Learn how to register and get automatic
|
||||
updates!</a>
|
||||
</div>
|
||||
<div *ngIf="stats['license']" class="my-1">
|
||||
<c-badge color="success">Registred</c-badge>
|
||||
<c-badge class="mx-1" color="info">License Type : {{stats['license']}}</c-badge>
|
||||
</div>
|
||||
</c-widget-stat-b>
|
||||
</c-col>
|
||||
|
||||
<c-col xl="6" lg="12" class="h-100">
|
||||
<c-card class="mb-1 p-1 h-100" *ngIf="stats">
|
||||
<c-carousel [dark]="true" [animate]="false" [wrap]="false" [interval]="1000000">
|
||||
<c-carousel-indicators></c-carousel-indicators>
|
||||
<c-carousel-inner>
|
||||
<c-carousel-item style="display: flex;" *ngFor="let slide of stats['blog']; index as i;">
|
||||
<img [src]="slide.media_content" alt="{{slide.title}}" class="d-block" loading="lazy" style=" float: left;"
|
||||
height="150px" />
|
||||
<div style="padding: 20px;">
|
||||
<h5>{{slide.title}}</h5>
|
||||
<p style="max-width: 90%;" [innerHTML]="slide.summery"></p>
|
||||
</div>
|
||||
</c-carousel-item>
|
||||
</c-carousel-inner>
|
||||
<c-carousel-control [routerLink] caption="Previous" direction="prev"></c-carousel-control>
|
||||
<c-carousel-control [routerLink] caption="Next" direction="next"></c-carousel-control>
|
||||
</c-carousel>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
217
src/app/views/dashboard/dashboard.component.ts
Normal file
217
src/app/views/dashboard/dashboard.component.ts
Normal file
|
@ -0,0 +1,217 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { UntypedFormControl, UntypedFormGroup } from "@angular/forms";
|
||||
import { dataProvider } from "../../providers/mikrowizard/data";
|
||||
import { loginChecker } from "../../providers/login_checker";
|
||||
import { Router } from "@angular/router";
|
||||
import { formatInTimeZone } from "date-fns-tz";
|
||||
|
||||
interface IUser {
|
||||
name: string;
|
||||
state: string;
|
||||
registered: string;
|
||||
country: string;
|
||||
usage: number;
|
||||
period: string;
|
||||
payment: string;
|
||||
activity: string;
|
||||
avatar: string;
|
||||
status: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "dashboard.component.html",
|
||||
})
|
||||
export class DashboardComponent implements OnInit {
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
public tz: string;
|
||||
public copy_msg: any = false;
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private router: Router,
|
||||
private login_checker: loginChecker
|
||||
) {
|
||||
var _self = this;
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["login"]);
|
||||
}, 100);
|
||||
}
|
||||
this.data_provider.getSessionInfo().then((res) => {
|
||||
_self.uid = res.uid;
|
||||
_self.uname = res.name;
|
||||
_self.tz = res.tz;
|
||||
const userId = _self.uid;
|
||||
});
|
||||
//get datagrid data
|
||||
function isNotEmpty(value: any): boolean {
|
||||
return value !== undefined && value !== null && value !== "";
|
||||
}
|
||||
}
|
||||
|
||||
public trafficRadioGroup = new UntypedFormGroup({
|
||||
trafficRadio: new UntypedFormControl("5m"),
|
||||
});
|
||||
public chart_data: any = {};
|
||||
Chartoptions = {
|
||||
plugins: {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function (context: any) {
|
||||
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
|
||||
let label = context.dataset.label || "";
|
||||
var res = context.parsed.y;
|
||||
let unitIndex = 0;
|
||||
// if (res>8) res /=8;
|
||||
while (res >= 1024 && unitIndex < units.length - 1) {
|
||||
res /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
switch (context.dataset.unit) {
|
||||
case "rx":
|
||||
return "rx/s :" + res.toFixed(3) + " " + units[unitIndex];
|
||||
break;
|
||||
case "tx":
|
||||
return "tx/s :" + res.toFixed(3) + " " + units[unitIndex];
|
||||
break;
|
||||
case "rxp":
|
||||
return "rxp/s :" + context.parsed.y;
|
||||
break;
|
||||
case "txp":
|
||||
return "txp/s :" + context.parsed.y;
|
||||
break;
|
||||
default:
|
||||
return context.parsed.y;
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
maintainAspectRatio: true,
|
||||
scales: {
|
||||
x: { display: false },
|
||||
yA: {
|
||||
display: true,
|
||||
stacked: true,
|
||||
position: "left",
|
||||
type: "linear",
|
||||
color: "#17522f",
|
||||
grid: {
|
||||
color: "rgba(23, 82, 47, 0.3)",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#f86c6b",
|
||||
pointHoverBackgroundColor: "#f86c6b",
|
||||
borderWidth: 1,
|
||||
borderDash: [8, 5],
|
||||
},
|
||||
ticks: {
|
||||
color: "#17522f",
|
||||
callback: function (value: any, index: any, ticks: any) {
|
||||
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
|
||||
var res = value;
|
||||
let unitIndex = 0;
|
||||
while (res >= 1024 && unitIndex < units.length - 1) {
|
||||
res /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
return res.toFixed(3) + " " + units[unitIndex];
|
||||
},
|
||||
},
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
yB: {
|
||||
display: true,
|
||||
stacked: true,
|
||||
position: "right",
|
||||
type: "linear",
|
||||
grid: {
|
||||
color: "rgba(23, 82, 47, 0.3)",
|
||||
backgroundColor: "transparent",
|
||||
borderColor: "#f86c6b",
|
||||
pointHoverBackgroundColor: "#f86c6b",
|
||||
borderWidth: 1,
|
||||
borderDash: [8, 5],
|
||||
},
|
||||
border: {
|
||||
width: 2,
|
||||
},
|
||||
ticks: {
|
||||
color: "#171951",
|
||||
callback: function (value: any, index: any, ticks: any) {
|
||||
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
|
||||
var res = value;
|
||||
let unitIndex = 0;
|
||||
while (res >= 1024 && unitIndex < units.length - 1) {
|
||||
res /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
return res.toFixed(3) + " " + units[unitIndex];
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
borderWidth: 1,
|
||||
tension: 0.4,
|
||||
},
|
||||
point: {
|
||||
radius: 2,
|
||||
hitRadius: 10,
|
||||
hoverRadius: 6,
|
||||
},
|
||||
},
|
||||
};
|
||||
public options: any;
|
||||
public delta: string = "5m";
|
||||
public stats: any = false;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.options = this.Chartoptions;
|
||||
this.initStats();
|
||||
this.initTrafficChart();
|
||||
}
|
||||
|
||||
initTrafficChart(): void {
|
||||
var _self = this;
|
||||
this.data_provider.dashboard_traffic(this.delta).then((res) => {
|
||||
let labels = res["data"]["labels"].map((d: any) => {
|
||||
return (d = formatInTimeZone(
|
||||
d.split(".")[0] + ".000Z",
|
||||
_self.tz,
|
||||
"yyyy-MM-dd HH:mm:ss"
|
||||
));
|
||||
});
|
||||
_self.chart_data = { datasets: res["data"]["datasets"], labels: labels };
|
||||
});
|
||||
}
|
||||
initStats() {
|
||||
var _self = this;
|
||||
this.data_provider.dashboard_stats(true).then((res) => {
|
||||
console.dir(res);
|
||||
_self.stats = res;
|
||||
});
|
||||
}
|
||||
|
||||
copy_this() {
|
||||
//show text copy to clipboard for 3 seconds
|
||||
this.copy_msg = true;
|
||||
setTimeout(() => {
|
||||
this.copy_msg = false;
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// Traffic Chart
|
||||
setTrafficPeriod(value: string): void {
|
||||
this.trafficRadioGroup.setValue({ trafficRadio: value });
|
||||
this.delta = value;
|
||||
this.initTrafficChart();
|
||||
}
|
||||
}
|
43
src/app/views/dashboard/dashboard.module.ts
Normal file
43
src/app/views/dashboard/dashboard.module.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import {
|
||||
ButtonGroupModule,
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
GridModule,
|
||||
WidgetModule,
|
||||
ProgressModule,
|
||||
TemplateIdDirective,
|
||||
BadgeModule,
|
||||
CarouselModule,
|
||||
} from "@coreui/angular";
|
||||
|
||||
import { ChartjsModule } from "@coreui/angular-chartjs";
|
||||
|
||||
import { DashboardRoutingModule } from "./dashboard-routing.module";
|
||||
import { DashboardComponent } from "./dashboard.component";
|
||||
import { ClipboardModule } from "@angular/cdk/clipboard";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
DashboardRoutingModule,
|
||||
CardModule,
|
||||
WidgetModule,
|
||||
CommonModule,
|
||||
GridModule,
|
||||
ProgressModule,
|
||||
ReactiveFormsModule,
|
||||
ButtonModule,
|
||||
TemplateIdDirective,
|
||||
ButtonModule,
|
||||
ButtonGroupModule,
|
||||
ChartjsModule,
|
||||
CarouselModule,
|
||||
BadgeModule,
|
||||
ClipboardModule,
|
||||
],
|
||||
declarations: [DashboardComponent],
|
||||
})
|
||||
export class DashboardModule {}
|
21
src/app/views/device_detail/device-routing.module.ts
Normal file
21
src/app/views/device_detail/device-routing.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { DeviceComponent } from './device.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DeviceComponent,
|
||||
data: {
|
||||
title: $localize`Device Detail`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DeviceRoutingModule {
|
||||
}
|
167
src/app/views/device_detail/device.component.html
Normal file
167
src/app/views/device_detail/device.component.html
Normal file
|
@ -0,0 +1,167 @@
|
|||
<c-alert style="margin-bottom: 5px;margin-top: 5px;" *ngIf="!loading && devdata['update_availble']"
|
||||
(click)="logger(devdata['sensors'])" color="warning">Firmware
|
||||
Update availble For This Device!</c-alert>
|
||||
<c-alert style="margin-bottom: 5px;margin-top: 5px;" *ngIf="!loading && devdata['upgrade_availble']"
|
||||
(click)="logger(devdata['upgrade_availble'])" color="info">Device is updated but needs to upgrade firmware!</c-alert>
|
||||
|
||||
<c-row *ngIf="!loading">
|
||||
<c-col xs>
|
||||
<c-card class="mb-1">
|
||||
<c-card-header>
|
||||
<c-row>
|
||||
<c-col md="3">
|
||||
<h3>{{devdata['name'] }}<small style="font-size: 50%;"> ( {{devdata['ip'] }} )</small></h3>
|
||||
</c-col>
|
||||
<c-col md="9" class="justify-content-end" style="text-align: end;">
|
||||
<c-button-group class="mb-2" aria-label="Upate interval" role="group">
|
||||
<button cButton color="primary" (click)="delta='5m';updateData()" [active]="delta=='5m'">5 minute</button>
|
||||
<button cButton color="primary" (click)="delta='1h';updateData()" [active]="delta=='1h'">Hourly</button>
|
||||
<button cButton color="primary" (click)="delta='daily';updateData()"
|
||||
[active]="delta=='daily'">Daily</button>
|
||||
<button cButton color="primary" (click)="delta='live';updateData()" [active]="delta=='live'">Live</button>
|
||||
</c-button-group>
|
||||
</c-col>
|
||||
</c-row>
|
||||
|
||||
</c-card-header>
|
||||
|
||||
<c-card-body>
|
||||
<app-widgets-dropdown *ngIf="!loading" [devicedata]=devsensors></app-widgets-dropdown>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
||||
|
||||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-1">
|
||||
<c-card-body>
|
||||
<c-row style="flex-direction:row">
|
||||
<ng-container *ngFor="let item of devdata | keyvalue; index as i">
|
||||
<!-- <c-col *ngIf="checkitem(item)" class="mb-2" >
|
||||
<c-card color="dark" textColor="white" class="h-100 ">
|
||||
<c-card-header style="padding: 5px 0 2px 9px;text-transform: capitalize;">{{item.key}}</c-card-header>
|
||||
<c-card-body class="bg-gradient" style="padding:2px 0 2px 9px;">
|
||||
<p cCardText>{{item.value}}</p>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col> -->
|
||||
<c-input-group *ngIf="checkitem(item)" class="mr-0 ml-0 mb-1"
|
||||
style="padding-right:unset;width: auto;flex: 1 1 auto;flex-flow: nowrap;flex: unset;">
|
||||
<span
|
||||
style="padding: 0.175rem 0.35rem;background-color:#4f5d73;text-transform: capitalize;color:#fff;font-size:0.7rem"
|
||||
cInputGroupText>{{item.key}}</span>
|
||||
<!-- <input cFormControl disabled style="font-size:0.8rem" [value]="item.value"/> -->
|
||||
<span _ngcontent-ng-c666080582="" cinputgrouptext=""
|
||||
style="padding: 0.175rem 0.35rem;color: rgba(44, 56, 74, 0.95);font-size: 0.7rem;background-color: #d8dbe0;border-color: #b1b7c1;"
|
||||
class="input-group-text">{{ item.value }}</span>
|
||||
<!-- <span style="background-color:#4f5d73;text-transform: capitalize;color:#fff;font-size:0.8rem" cInputGroupText >{{item.key}}</span> -->
|
||||
|
||||
</c-input-group>
|
||||
</ng-container>
|
||||
</c-row>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
||||
<!-- Mikrotik interfaces table -->
|
||||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-1">
|
||||
<c-card-body>
|
||||
<c-row style="flex-direction:row">
|
||||
<gui-grid [source]="interfaces" [columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel"
|
||||
[rowSelection]="rowSelection" [autoResizeWidth]=true>
|
||||
<gui-grid-column header="Name" field="name">
|
||||
<ng-template let-value="item.name" let-item="item" let-index="index">
|
||||
|
||||
{{value}} - {{item['default-name']}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
|
||||
<gui-grid-column header="MAC" field="mac-address">
|
||||
<ng-template let-value="item['mac-address']" let-item="item" let-index="index">
|
||||
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="rx" field="rx-byte">
|
||||
<ng-template let-value="item['rx-byte']" let-item="item" let-index="index">
|
||||
|
||||
<div>{{convert_bw_human(value,'rx')}}</div>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="tx" field="tx-byte">
|
||||
<ng-template let-value="item['tx-byte']" let-item="item" let-index="index">
|
||||
|
||||
{{convert_bw_human(value,'tx')}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="l2mtu" field="l2mtu">
|
||||
<ng-template let-value="item.l2mtu" let-item="item" let-index="index">
|
||||
|
||||
curr:{{value}}<br />
|
||||
max : {{item['max-l2mtu']}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="rx/s" field="rx-bits-per-second" [enabled]="false">
|
||||
<ng-template let-value="item['rx-bits-per-second']" let-item="item" let-index="index">
|
||||
|
||||
{{convert_bw_human(value,'rx')}}
|
||||
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="tx/s" field="tx-bits-per-second" [enabled]="false">
|
||||
<ng-template let-value="item['tx-bits-per-second']" let-item="item" let-index="index">
|
||||
|
||||
{{convert_bw_human(value,'tx')}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Created" field="created" [enabled]="false">
|
||||
<ng-template let-value="item.created" let-item="item.id" let-index="index">
|
||||
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Last Up" field="last-link-up-time">
|
||||
<ng-template let-value="item['last-link-up-time']" let-item="item" let-index="index">
|
||||
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Created" field="created" [enabled]="false">
|
||||
<ng-template let-value="item.created" let-item="item.id" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Actions" field="action" width="100" align="center">
|
||||
<ng-template let-value="item.id" let-item="item" let-index="index">
|
||||
<button cButton color="info" size="sm" (click)="show_interface_rate(item['default-name'])"
|
||||
class="mx-1"><i class="fa-solid fa-chart-line"></i></button>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
</c-row>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
||||
|
||||
|
||||
|
||||
<c-modal #staticBackdropModal backdrop="static" size="xl" [visible]="InterfaceChartModalVisible"
|
||||
id="InterfaceChartModal">
|
||||
<c-modal-header>
|
||||
<h5 cModalTitle>{{interface_rate['name']}}</h5>
|
||||
<button [cModalToggle]="staticBackdropModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
<c-chart [data]="interface_rate" [options]="options" type="line">
|
||||
</c-chart>
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<button [cModalToggle]="staticBackdropModal.id" cButton color="secondary">
|
||||
Close
|
||||
</button>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
7
src/app/views/device_detail/device.component.scss
Normal file
7
src/app/views/device_detail/device.component.scss
Normal file
|
@ -0,0 +1,7 @@
|
|||
:host {
|
||||
.legend {
|
||||
small {
|
||||
font-size: x-small;
|
||||
}
|
||||
}
|
||||
}
|
36
src/app/views/device_detail/device.component.spec.ts
Normal file
36
src/app/views/device_detail/device.component.spec.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ButtonModule, DropdownModule, GridModule, WidgetModule } from '@coreui/angular';
|
||||
import { IconModule } from '@coreui/icons-angular';
|
||||
import { ChartjsModule } from '@coreui/angular-chartjs';
|
||||
import { IconSetService } from '@coreui/icons-angular';
|
||||
import { iconSubset } from '../../icons/icon-subset';
|
||||
import { DeviceComponent } from './device.component';
|
||||
|
||||
describe('DeviceComponent', () => {
|
||||
let component: DeviceComponent;
|
||||
let fixture: ComponentFixture<DeviceComponent>;
|
||||
let iconSetService: IconSetService;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ DeviceComponent ],
|
||||
imports: [WidgetModule, DropdownModule, IconModule, ButtonModule, ChartjsModule, GridModule],
|
||||
providers: [IconSetService]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
iconSetService = TestBed.inject(IconSetService);
|
||||
iconSetService.icons = { ...iconSubset };
|
||||
|
||||
fixture = TestBed.createComponent(DeviceComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
437
src/app/views/device_detail/device.component.ts
Normal file
437
src/app/views/device_detail/device.component.ts
Normal file
|
@ -0,0 +1,437 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { Router, ActivatedRoute } from "@angular/router";
|
||||
import { dataProvider } from "../../providers/mikrowizard/data";
|
||||
import { loginChecker } from "../../providers/login_checker";
|
||||
import {
|
||||
GuiInfoPanel,
|
||||
GuiColumn,
|
||||
GuiColumnMenu,
|
||||
GuiPaging,
|
||||
GuiPagingDisplay,
|
||||
GuiRowSelectionMode,
|
||||
GuiRowSelection,
|
||||
GuiRowSelectionType,
|
||||
} from "@generic-ui/ngx-grid";
|
||||
import { __setFunctionName } from "tslib";
|
||||
interface IUser {
|
||||
name: string;
|
||||
state: string;
|
||||
registered: string;
|
||||
country: string;
|
||||
usage: number;
|
||||
period: string;
|
||||
payment: string;
|
||||
activity: string;
|
||||
avatar: string;
|
||||
status: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "device.component.html",
|
||||
styleUrls: ["device.component.scss"],
|
||||
})
|
||||
export class DeviceComponent implements OnInit {
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
public tz: string;
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private login_checker: loginChecker
|
||||
) {
|
||||
var _self = this;
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["login"]);
|
||||
}, 100);
|
||||
}
|
||||
this.data_provider.getSessionInfo().then((res) => {
|
||||
_self.uid = res.uid;
|
||||
_self.uname = res.name;
|
||||
_self.tz = res.tz;
|
||||
const userId = _self.uid;
|
||||
|
||||
if (res.role != "admin") {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["/user/dashboard"]);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
//get datagrid data
|
||||
function isNotEmpty(value: any): boolean {
|
||||
return value !== undefined && value !== null && value !== "";
|
||||
}
|
||||
}
|
||||
public devdata: any;
|
||||
public devsensors: any;
|
||||
public columns: Array<GuiColumn> = [];
|
||||
public loading: boolean = true;
|
||||
public InterfaceChartModalVisible: boolean = false;
|
||||
public rows: any = [];
|
||||
public Selectedrows: any;
|
||||
public devid: number = 0;
|
||||
public data_interval: any;
|
||||
public delta: string = "5m";
|
||||
public total_type: string = "bps";
|
||||
public interface_rate: any = {};
|
||||
public options: any;
|
||||
public sorting = {
|
||||
enabled: true,
|
||||
multiSorting: true,
|
||||
};
|
||||
public interfaces: Array<any> = [];
|
||||
public paging: GuiPaging = {
|
||||
enabled: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSizes: [5, 10, 25, 50],
|
||||
display: GuiPagingDisplay.ADVANCED,
|
||||
};
|
||||
|
||||
public columnMenu: GuiColumnMenu = {
|
||||
enabled: true,
|
||||
sort: true,
|
||||
columnsManager: true,
|
||||
};
|
||||
|
||||
public infoPanel: GuiInfoPanel = {
|
||||
enabled: true,
|
||||
infoDialog: false,
|
||||
columnsManager: true,
|
||||
schemaManager: true,
|
||||
};
|
||||
|
||||
public rowSelection: boolean | GuiRowSelection = {
|
||||
enabled: true,
|
||||
type: GuiRowSelectionType.CHECKBOX,
|
||||
mode: GuiRowSelectionMode.MULTIPLE,
|
||||
};
|
||||
|
||||
Chartoptions = {
|
||||
plugins: {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function (context: any) {
|
||||
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
|
||||
let label = context.dataset.label || "";
|
||||
var res = context.parsed.y;
|
||||
let unitIndex = 0;
|
||||
// if (res>8) res /=8;
|
||||
while (res >= 1024 && unitIndex < units.length - 1) {
|
||||
res /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
switch (context.dataset.unit) {
|
||||
case "rx":
|
||||
return "rx/s :" + res.toFixed(3) + " " + units[unitIndex];
|
||||
break;
|
||||
case "tx":
|
||||
return "tx/s :" + res.toFixed(3) + " " + units[unitIndex];
|
||||
break;
|
||||
case "rxp":
|
||||
return "rxp/s :" + context.parsed.y;
|
||||
break;
|
||||
case "txp":
|
||||
return "txp/s :" + context.parsed.y;
|
||||
break;
|
||||
default:
|
||||
return context.parsed.y;
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
maintainAspectRatio: true,
|
||||
scales: {
|
||||
x: { display: false },
|
||||
yA: {
|
||||
display: true,
|
||||
stacked: true,
|
||||
position: "left",
|
||||
type: "linear",
|
||||
color: "#17522f",
|
||||
grid: {
|
||||
color: "rgba(23, 82, 47, 0.3)",
|
||||
borderDash: [5, 5],
|
||||
},
|
||||
ticks: {
|
||||
color: "#17522f",
|
||||
callback: function (value: any, index: any, ticks: any) {
|
||||
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
|
||||
var res = value;
|
||||
let unitIndex = 0;
|
||||
while (res >= 1024 && unitIndex < units.length - 1) {
|
||||
res /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
return res.toFixed(3) + " " + units[unitIndex];
|
||||
},
|
||||
},
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
yB: {
|
||||
display: true,
|
||||
stacked: true,
|
||||
position: "right",
|
||||
type: "linear",
|
||||
grid: {
|
||||
color: "rgba(23, 25, 81, 0.3)",
|
||||
borderDash: [8, 8],
|
||||
},
|
||||
border: {
|
||||
width: 2,
|
||||
},
|
||||
ticks: {
|
||||
color: "#171951",
|
||||
callback: function (value: any, index: any, ticks: any) {
|
||||
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
|
||||
var res = value;
|
||||
let unitIndex = 0;
|
||||
while (res >= 1024 && unitIndex < units.length - 1) {
|
||||
res /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
return res.toFixed(3) + " " + units[unitIndex];
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
borderWidth: 1,
|
||||
tension: 0.4,
|
||||
},
|
||||
point: {
|
||||
radius: 4,
|
||||
hitRadius: 10,
|
||||
hoverRadius: 6,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
ngOnInit(): void {
|
||||
this.devid = Number(this.route.snapshot.paramMap.get("id"));
|
||||
this.options = this.Chartoptions;
|
||||
this.initDeviceInfo();
|
||||
}
|
||||
|
||||
optionsDefault = {
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
maintainAspectRatio: true,
|
||||
scales: {
|
||||
x: {
|
||||
grid: {
|
||||
display: false,
|
||||
drawBorder: false,
|
||||
},
|
||||
ticks: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
y: {
|
||||
display: false,
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
ticks: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
borderWidth: 1,
|
||||
tension: 0.4,
|
||||
},
|
||||
point: {
|
||||
radius: 4,
|
||||
hitRadius: 10,
|
||||
hoverRadius: 6,
|
||||
},
|
||||
},
|
||||
};
|
||||
setOptions() {
|
||||
for (let idx = 0; idx < 5; idx++) {
|
||||
const options = JSON.parse(JSON.stringify(this.optionsDefault));
|
||||
switch (idx) {
|
||||
case 0: {
|
||||
this.options.push(options);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
options.scales.y.min = -9;
|
||||
options.scales.y.max = 39;
|
||||
this.options.push(options);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
options.scales.x = { display: false };
|
||||
options.scales.y = { display: false };
|
||||
options.elements.line.borderWidth = 2;
|
||||
options.elements.point.radius = 2;
|
||||
this.options.push(options);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
options.scales.x.grid = { display: false, drawTicks: false };
|
||||
options.scales.x.grid = {
|
||||
display: false,
|
||||
drawTicks: false,
|
||||
drawBorder: false,
|
||||
};
|
||||
options.scales.y.min = undefined;
|
||||
options.scales.y.max = undefined;
|
||||
options.elements = {};
|
||||
this.options.push(options);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
options.plugins = {
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function (context: any) {
|
||||
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
|
||||
let label = context.dataset.label || "";
|
||||
var res = context.parsed.y;
|
||||
let unitIndex = 0;
|
||||
// if (res>8) res /=8;
|
||||
while (res >= 1024 && unitIndex < units.length - 1) {
|
||||
res /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
switch (context.dataset.unit) {
|
||||
case "rx":
|
||||
return "rx/s :" + res.toFixed(3) + " " + units[unitIndex];
|
||||
break;
|
||||
case "tx":
|
||||
return "tx/s :" + res.toFixed(3) + " " + units[unitIndex];
|
||||
break;
|
||||
case "rxp":
|
||||
return "rxp/s :" + context.parsed.y;
|
||||
break;
|
||||
case "txp":
|
||||
return "txp/s :" + context.parsed.y;
|
||||
break;
|
||||
default:
|
||||
return context.parsed.y;
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
};
|
||||
options.scales = {
|
||||
x: { display: false },
|
||||
yA: {
|
||||
display: false,
|
||||
stacked: true,
|
||||
position: "left",
|
||||
type: "linear",
|
||||
scaleLabel: {
|
||||
display: true,
|
||||
},
|
||||
},
|
||||
yB: {
|
||||
display: false,
|
||||
stacked: true,
|
||||
position: "right",
|
||||
type: "linear",
|
||||
},
|
||||
};
|
||||
options.elements.line.borderWidth = 2;
|
||||
options.elements.point.radius = 2;
|
||||
this.options.push(options);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger(item: any) {
|
||||
console.dir(item);
|
||||
}
|
||||
updateData(): void {
|
||||
var _self = this;
|
||||
this.data_provider.get_dev_info(this.devid).then((res) => {
|
||||
_self.devdata = res;
|
||||
_self.interfaces = res.interfaces;
|
||||
_self.data_provider
|
||||
.get_dev_sensors(_self.devid, _self.delta, _self.total_type)
|
||||
.then((res) => {
|
||||
_self.devsensors = res;
|
||||
_self.loading = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
checkitem(item: any) {
|
||||
if (item.value && !item.key.match("sensors|id|_availble|interfaces")) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
convert_bw_human(mynumber: number = 0, unit: string) {
|
||||
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
|
||||
let unitIndex = 0;
|
||||
while (mynumber >= 1024 && unitIndex < units.length - 1) {
|
||||
mynumber /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
switch (unit) {
|
||||
case "rx":
|
||||
return mynumber.toFixed(3) + " " + units[unitIndex];
|
||||
break;
|
||||
case "tx":
|
||||
return mynumber.toFixed(3) + " " + units[unitIndex];
|
||||
break;
|
||||
default:
|
||||
return mynumber;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
show_interface_rate(name: string) {
|
||||
var _self = this;
|
||||
_self.InterfaceChartModalVisible = false;
|
||||
this.data_provider
|
||||
.get_dev_ifstat(_self.devid, _self.delta, name, _self.total_type)
|
||||
.then((res) => {
|
||||
_self.interface_rate = res["data"];
|
||||
_self.InterfaceChartModalVisible = true;
|
||||
});
|
||||
}
|
||||
|
||||
initDeviceInfo(): void {
|
||||
var _self = this;
|
||||
clearInterval(this.data_interval);
|
||||
this.updateData();
|
||||
this.data_interval = setInterval(() => {
|
||||
this.data_provider.get_dev_info(this.devid).then((res) => {
|
||||
_self.devdata = res;
|
||||
|
||||
_self.interfaces = res.interfaces;
|
||||
_self.data_provider
|
||||
.get_dev_sensors(_self.devid, _self.delta, _self.total_type)
|
||||
.then((res) => {
|
||||
_self.devsensors = res;
|
||||
_self.loading = false;
|
||||
});
|
||||
});
|
||||
}, 1000000);
|
||||
}
|
||||
}
|
42
src/app/views/device_detail/device.module.ts
Normal file
42
src/app/views/device_detail/device.module.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
|
||||
import {
|
||||
ButtonGroupModule,
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
FormModule,
|
||||
GridModule,
|
||||
ProgressModule,
|
||||
NavbarModule,
|
||||
AlertModule,
|
||||
ModalModule,
|
||||
} from "@coreui/angular";
|
||||
import { ChartjsModule } from "@coreui/angular-chartjs";
|
||||
|
||||
import { DeviceRoutingModule } from "./device-routing.module";
|
||||
import { DeviceComponent } from "./device.component";
|
||||
import { GuiGridModule } from "@generic-ui/ngx-grid";
|
||||
|
||||
import { WidgetsModule } from "../widgets/widgets.module";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
DeviceRoutingModule,
|
||||
CardModule,
|
||||
AlertModule,
|
||||
CommonModule,
|
||||
GridModule,
|
||||
ProgressModule,
|
||||
FormModule,
|
||||
ButtonModule,
|
||||
ButtonGroupModule,
|
||||
ChartjsModule,
|
||||
WidgetsModule,
|
||||
GuiGridModule,
|
||||
NavbarModule,
|
||||
ModalModule,
|
||||
],
|
||||
declarations: [DeviceComponent],
|
||||
})
|
||||
export class DeviceModule {}
|
21
src/app/views/device_logs/devlogs-routing.module.ts
Normal file
21
src/app/views/device_logs/devlogs-routing.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { DevLogsComponent } from './devlogs.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DevLogsComponent,
|
||||
data: {
|
||||
title: $localize`Device Logs`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DevLogsRoutingModule {
|
||||
}
|
139
src/app/views/device_logs/devlogs.component.html
Normal file
139
src/app/views/device_logs/devlogs.component.html
Normal file
|
@ -0,0 +1,139 @@
|
|||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-4">
|
||||
<c-card-header>
|
||||
<c-row>
|
||||
<c-col xs [lg]="11">
|
||||
Device LOGS
|
||||
</c-col>
|
||||
<c-col xs [lg]="1">
|
||||
<button (click)="toggleCollapse()" cButton class="me-1" color="primary"><i
|
||||
class="fa-solid fa-filter mr-1"></i>Filter</button>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-card-header>
|
||||
<c-card-body>
|
||||
<c-row>
|
||||
<div [visible]="filters_visible" cCollapse>
|
||||
<c-col xs [lg]="12" class="example-form">
|
||||
<mat-form-field>
|
||||
<mat-label>Start date</mat-label>
|
||||
<input matInput [matDatepicker]="picker1" (dateChange)="reinitgrid('start',$event)"
|
||||
[(ngModel)]="filters['start_time']" />
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker1></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>End date</mat-label>
|
||||
<input matInput [matDatepicker]="picker2" (dateChange)="reinitgrid('end',$event)"
|
||||
[(ngModel)]="filters['end_time']" />
|
||||
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker2></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field *ngIf="event_types_filtered.length>0">
|
||||
<mat-label>Select event type</mat-label>
|
||||
<mat-select placeholder="Event Type" [multiple]="true" (ngModelChange)="reinitgrid('detail',$event)"
|
||||
[(ngModel)]="filters['detail']" #multiSelect>
|
||||
<mat-option>
|
||||
<ngx-mat-select-search [showToggleAllCheckbox]="true" placeholderLabel="Find type..."
|
||||
[formControl]="bankMultiFilterCtrl"></ngx-mat-select-search>
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let bank of event_types_filtered " [value]="bank">
|
||||
{{bank}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Select event type</mat-label>
|
||||
<mat-select placeholder="Event Level" (ngModelChange)="reinitgrid('level',$event)"
|
||||
[(ngModel)]="filters['level']" #multiSelect>
|
||||
<mat-option value="All">All</mat-option>
|
||||
<mat-option *ngFor="let level of ['Critical','Warning','Error','info'] " [value]="level">
|
||||
{{level}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Status</mat-label>
|
||||
<mat-select placeholder="Event Status" (ngModelChange)="reinitgrid('status',$event)"
|
||||
[(ngModel)]="filters['status']" #multiSelect>
|
||||
<mat-option value="All">All</mat-option>
|
||||
<mat-option [value]="true">Fixed</mat-option>
|
||||
<mat-option [value]="false">Not Fixed</mat-option>
|
||||
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Comment</mat-label>
|
||||
<input (ngModelChange)="reinitgrid('comment',$event)" [(ngModel)]="filters['comment']" matInput>
|
||||
</mat-form-field>
|
||||
</c-col>
|
||||
|
||||
</div>
|
||||
|
||||
</c-row>
|
||||
<gui-grid wid [rowDetail]="rowDetail" [horizontalGrid]="true" [rowHeight]="52" [source]="source"
|
||||
[columnMenu]="columnMenu" [paging]="paging" [sorting]="sorting" [infoPanel]="infoPanel"
|
||||
[autoResizeWidth]="true">
|
||||
<gui-grid-column header="#No" type="NUMBER" field="index" width="1" align="CENTER">
|
||||
<ng-template let-value="item.index" let-item="item" let-index="index">
|
||||
{{ value }}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
|
||||
<gui-grid-column header="level" width='90' wid field="level">
|
||||
<ng-template let-value="item.level" let-item="item" let-index="index">
|
||||
<c-badge style="cursor: pointer; font-weight: normal" color="danger" *ngIf="value == 'Critical'">{{ value
|
||||
}}</c-badge>
|
||||
<c-badge style="cursor: pointer; font-weight: normal" color="warning" *ngIf="value == 'Error'">{{ value
|
||||
}}</c-badge>
|
||||
<c-badge style="cursor: pointer; font-weight: normal" color="warning" *ngIf="value == 'Warning'">{{ value
|
||||
}}</c-badge>
|
||||
<c-badge style="cursor: pointer; font-weight: normal; min-width: 60px;" color="info"
|
||||
*ngIf="value == 'info'">{{ value }}</c-badge>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Event" width='200' field="detail">
|
||||
<ng-template let-value="item.detail" let-item="item" let-index="index">
|
||||
{{ value }}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Detail" field="comment">
|
||||
<ng-template let-value="item.comment" let-item="item" let-index="index">
|
||||
|
||||
<div class="gui-dev-info">
|
||||
{{ value }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Source" width='90' field="src">
|
||||
<ng-template let-value="item.src" let-item="item" let-index="index">
|
||||
{{ value }}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="status" width='100' field="status" align="CENTER">
|
||||
<ng-template let-value="item.status" let-item="item" let-index="index">
|
||||
<c-badge style=" cursor: pointer; font-weight: normal" color="success"
|
||||
*ngIf="value == true">Fixed</c-badge>
|
||||
<c-badge style="cursor: pointer; font-weight: normal" color="danger" *ngIf="value != true">Not
|
||||
Fixed</c-badge>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="eventtime" width='200' field="eventtime">
|
||||
<ng-template let-value="item.eventtime" let-item="item" let-index="index">
|
||||
{{ value }}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Device" width='200' field="name">
|
||||
<ng-template let-value="item.name" let-item="item" let-index="index">
|
||||
<div class="gui-dev-info">
|
||||
<span class="gui-dev-info-name">{{ value }}</span>
|
||||
<span class="gui-dev-info-ip">{{ item.devip }}</span>
|
||||
</div>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
125
src/app/views/device_logs/devlogs.component.scss
Normal file
125
src/app/views/device_logs/devlogs.component.scss
Normal file
|
@ -0,0 +1,125 @@
|
|||
@use '@angular/material' as mat;
|
||||
|
||||
:host {
|
||||
.legend {
|
||||
small {
|
||||
font-size: x-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
// .gui-drawer-content{
|
||||
// background-color: #efefef!important;
|
||||
|
||||
// }
|
||||
.log-detail{
|
||||
padding:30px 10px;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
.log-detail h1{
|
||||
font-size:2em;
|
||||
font-weight:bold;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
.log-detail small{
|
||||
position:relative;
|
||||
top:-7px;
|
||||
padding:0;
|
||||
font-weight:bold;
|
||||
font-size:1.1em;
|
||||
}
|
||||
.log-detail table {
|
||||
width: 100%;
|
||||
border-collapse: collapse!important;
|
||||
margin: 5px 0 0 0;
|
||||
padding: 0;
|
||||
background-color: #ffffff29 !important;
|
||||
color: #000;
|
||||
}
|
||||
.log-detail th {
|
||||
text-align: left;
|
||||
}
|
||||
.log-detail th,
|
||||
.log-detail td {
|
||||
border: 1px solid #ffffff4a!important;
|
||||
padding: 0.5rem!important;
|
||||
}
|
||||
.gui-close-icon-wrapper .gui-close-icon:after,.gui-close-icon-wrapper .gui-close-icon:before {
|
||||
background-color: #ffffff !important;
|
||||
|
||||
}
|
||||
.log-detail code{
|
||||
padding:5px!important;
|
||||
display:block;
|
||||
background:#1d1f21;
|
||||
color:#c5c8c6;
|
||||
border-bottom-left-radius:3px;
|
||||
border-bottom-right-radius:3px;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.log-detail .code-title{
|
||||
background-color:#393e42!important;;
|
||||
width:100%;
|
||||
padding:2px 15px;
|
||||
display:inline-block;
|
||||
margin-top:10px;
|
||||
color:#d2d2d2;
|
||||
border-top-left-radius:3px;
|
||||
border-top-right-radius:3px;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.gui-row-detail{
|
||||
height:100%;
|
||||
}
|
||||
|
||||
.gui-dev-info {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
white-space: normal;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
.gui-dev-info-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.gui-dev-info-ip {
|
||||
color: #525252;
|
||||
font-style: italic;
|
||||
font-size: 13px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.gui-row-detail > div{
|
||||
height:100%;
|
||||
}
|
||||
.gui-row-detail .log-detail{
|
||||
height:100%;
|
||||
}
|
||||
|
||||
.gui-structure{
|
||||
min-height: 550px;
|
||||
}
|
||||
|
||||
|
||||
.example-form {
|
||||
@include mat.button-density(-5);
|
||||
|
||||
@include mat.form-field-density(-5);
|
||||
@include mat.button-toggle-density(-5);
|
||||
@include mat.datepicker-density(-5);
|
||||
@include mat.all-component-densities(-5);
|
||||
@include mat.icon-button-density(-5);
|
||||
@include mat.icon-density(-5);
|
||||
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) .mat-mdc-floating-label { display: inline; }
|
||||
mat-form-field *{
|
||||
font-size:13px!important;
|
||||
}
|
||||
.mat-mdc-form-field-infix{
|
||||
width:150px;
|
||||
}
|
||||
}
|
234
src/app/views/device_logs/devlogs.component.ts
Normal file
234
src/app/views/device_logs/devlogs.component.ts
Normal file
|
@ -0,0 +1,234 @@
|
|||
import { Component, OnInit, ViewEncapsulation } from "@angular/core";
|
||||
import { FormControl } from "@angular/forms";
|
||||
import { dataProvider } from "../../providers/mikrowizard/data";
|
||||
import { Router, ActivatedRoute } from "@angular/router";
|
||||
import { loginChecker } from "../../providers/login_checker";
|
||||
import {
|
||||
GuiRowDetail,
|
||||
GuiInfoPanel,
|
||||
GuiColumn,
|
||||
GuiColumnMenu,
|
||||
GuiPaging,
|
||||
GuiPagingDisplay,
|
||||
GuiRowSelectionMode,
|
||||
GuiRowSelection,
|
||||
GuiRowSelectionType,
|
||||
} from "@generic-ui/ngx-grid";
|
||||
import { formatInTimeZone } from "date-fns-tz";
|
||||
import { takeUntil } from "rxjs/operators";
|
||||
import { Subject } from "rxjs";
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: "devlogs.component.html",
|
||||
styleUrls: ["devlogs.component.scss"],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class DevLogsComponent implements OnInit {
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
public tz: string = "UTC"
|
||||
public filterText: string;
|
||||
public filters: any = {
|
||||
start_time: false,
|
||||
end_time: false,
|
||||
detail: [],
|
||||
level: false,
|
||||
comment: "",
|
||||
status: "all",
|
||||
};
|
||||
public event_types: any = [];
|
||||
public event_types_filtered: any = [];
|
||||
public filters_visible: boolean = false;
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private login_checker: loginChecker
|
||||
) {
|
||||
var _self = this;
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["login"]);
|
||||
}, 100);
|
||||
}
|
||||
this.data_provider.getSessionInfo().then((res) => {
|
||||
_self.uid = res.uid;
|
||||
_self.uname = res.name;
|
||||
_self.tz = res.tz;
|
||||
const userId = _self.uid;
|
||||
|
||||
if (res.role != "admin") {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["/user/dashboard"]);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
//get datagrid data
|
||||
function isNotEmpty(value: any): boolean {
|
||||
return value !== undefined && value !== null && value !== "";
|
||||
}
|
||||
}
|
||||
public source: Array<any> = [];
|
||||
public columns: Array<GuiColumn> = [];
|
||||
public loading: boolean = true;
|
||||
public rows: any = [];
|
||||
public Selectedrows: any;
|
||||
public devid: number = 0;
|
||||
public sorting = {
|
||||
enabled: true,
|
||||
multiSorting: true,
|
||||
};
|
||||
public bankMultiFilterCtrl: FormControl = new FormControl<string>("");
|
||||
protected _onDestroy = new Subject<void>();
|
||||
|
||||
public campaignOnestart: any;
|
||||
public campaignOneend: any;
|
||||
rowDetail: GuiRowDetail = {
|
||||
enabled: true,
|
||||
template: (item) => {
|
||||
return `
|
||||
<div class='log-detail' style="color:#fff;background-color:${(() => {
|
||||
if (item.level == "Critical") return "#e55353";
|
||||
else if (item.level == "Warning") return "#f9b115";
|
||||
else item.level == "Info";
|
||||
return "#3399ff";
|
||||
})()}">
|
||||
<h1>Device :</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Device Name</td>
|
||||
<td>${item.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Device IP</td>
|
||||
<td>${item.devip}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Device MAC</td>
|
||||
<td>${item.mac}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h1 style="margin-top: 10px;">Alert Detail :
|
||||
|
||||
</h1>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Event</td>
|
||||
<td>${item.detail}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Event Status</td>
|
||||
<td><span (click)="logger(${item})" style="display:inline-block;background-color:${
|
||||
item.status ? "green" : "#db4848"
|
||||
} ;padding: 4px 10px;border-radius: 5px;line-height: 10px;color: rgba(255, 255, 255, 0.87);">${
|
||||
item.status ? "Fixed" : "Not Fixed"
|
||||
}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Event Category</td>
|
||||
<td>${item.eventtype}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Exec time</td>
|
||||
<td>${item.eventtime}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Detail</td>
|
||||
<td>${item.comment}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Source</td>
|
||||
<td>${item.src}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>`;
|
||||
},
|
||||
};
|
||||
|
||||
public paging: GuiPaging = {
|
||||
enabled: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSizes: [5, 10, 25, 50],
|
||||
display: GuiPagingDisplay.ADVANCED,
|
||||
};
|
||||
|
||||
public columnMenu: GuiColumnMenu = {
|
||||
enabled: true,
|
||||
sort: true,
|
||||
columnsManager: true,
|
||||
};
|
||||
|
||||
public infoPanel: GuiInfoPanel = {
|
||||
enabled: true,
|
||||
infoDialog: false,
|
||||
columnsManager: true,
|
||||
schemaManager: true,
|
||||
};
|
||||
|
||||
public rowSelection: boolean | GuiRowSelection = {
|
||||
enabled: true,
|
||||
type: GuiRowSelectionType.CHECKBOX,
|
||||
mode: GuiRowSelectionMode.MULTIPLE,
|
||||
};
|
||||
ngOnInit(): void {
|
||||
var _self = this;
|
||||
this.devid = Number(this.route.snapshot.paramMap.get("devid"));
|
||||
if (this.devid > 0) {
|
||||
this.filters["devid"] = this.devid;
|
||||
}
|
||||
this.initGridTable();
|
||||
|
||||
this.bankMultiFilterCtrl.valueChanges
|
||||
.pipe(takeUntil(this._onDestroy))
|
||||
.subscribe(() => {
|
||||
let search = this.bankMultiFilterCtrl.value;
|
||||
if (!search) {
|
||||
this.event_types_filtered = this.event_types;
|
||||
}
|
||||
_self.event_types_filtered = _self.event_types_filtered.filter(
|
||||
(item: any) => item.toLowerCase().indexOf(search.toLowerCase()) > -1
|
||||
);
|
||||
console.dir(_self.event_types_filtered);
|
||||
});
|
||||
}
|
||||
toggleCollapse(): void {
|
||||
this.filters_visible = !this.filters_visible;
|
||||
}
|
||||
logger(item: any) {
|
||||
console.dir(item);
|
||||
}
|
||||
reinitgrid(field: string, $event: any) {
|
||||
if (field == "start") this.filters["start_time"] = $event.target.value;
|
||||
else if (field == "end") this.filters["end_time"] = $event.target.value;
|
||||
else if (field == "detail") this.filters["detail"] = $event;
|
||||
else if (field == "level") this.filters["level"] = $event;
|
||||
else if (field == "comment") this.filters["comment"] = $event;
|
||||
else if (field == "status") this.filters["status"] = $event;
|
||||
this.initGridTable();
|
||||
}
|
||||
initGridTable(): void {
|
||||
var _self = this;
|
||||
this.data_provider.get_dev_logs(this.filters).then((res) => {
|
||||
let index = 1;
|
||||
this.source = res.map((d: any) => {
|
||||
d.index = index;
|
||||
if (d.detail.indexOf("Link Down") >= 0) d.detail = "Link Down";
|
||||
else if (d.detail.indexOf("Link Up") >= 0) d.detail = "Link Up";
|
||||
if (!_self.event_types.includes(d.detail))
|
||||
_self.event_types.push(d.detail);
|
||||
d.eventtime = formatInTimeZone(
|
||||
d.eventtime.split(".")[0] + ".000Z",
|
||||
_self.tz,
|
||||
"yyyy-MM-dd HH:mm:ss XXX"
|
||||
);
|
||||
index += 1;
|
||||
return d;
|
||||
});
|
||||
_self.event_types_filtered = _self.event_types;
|
||||
console.dir(this.source);
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
47
src/app/views/device_logs/devlogs.module.ts
Normal file
47
src/app/views/device_logs/devlogs.module.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { ReactiveFormsModule } from "@angular/forms";
|
||||
|
||||
import {
|
||||
ButtonGroupModule,
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
FormModule,
|
||||
GridModule,
|
||||
CollapseModule,
|
||||
BadgeModule,
|
||||
} from "@coreui/angular";
|
||||
import { NgxMatSelectSearchModule } from "ngx-mat-select-search";
|
||||
import { DevLogsRoutingModule } from "./devlogs-routing.module";
|
||||
import { DevLogsComponent } from "./devlogs.component";
|
||||
import { GuiGridModule } from "@generic-ui/ngx-grid";
|
||||
import { MatDatepickerModule } from "@angular/material/datepicker";
|
||||
import { MatInputModule } from "@angular/material/input";
|
||||
import { MatFormFieldModule } from "@angular/material/form-field";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
|
||||
import { MatSelectModule } from "@angular/material/select";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
DevLogsRoutingModule,
|
||||
CardModule,
|
||||
CommonModule,
|
||||
GridModule,
|
||||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
FormModule,
|
||||
ButtonModule,
|
||||
ButtonGroupModule,
|
||||
GuiGridModule,
|
||||
CollapseModule,
|
||||
BadgeModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
MatSelectModule,
|
||||
NgxMatSelectSearchModule,
|
||||
MatDatepickerModule,
|
||||
],
|
||||
declarations: [DevLogsComponent],
|
||||
})
|
||||
export class DevLogsModule {}
|
21
src/app/views/devices/devices-routing.module.ts
Normal file
21
src/app/views/devices/devices-routing.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { DevicesComponent } from './devices.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DevicesComponent,
|
||||
data: {
|
||||
title: $localize`Device List`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DevicesRoutingModule {
|
||||
}
|
346
src/app/views/devices/devices.component.html
Normal file
346
src/app/views/devices/devices.component.html
Normal file
|
@ -0,0 +1,346 @@
|
|||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-4">
|
||||
<c-card-header>
|
||||
<c-row>
|
||||
<c-col xs [lg]="3">
|
||||
Devices
|
||||
</c-col>
|
||||
<c-col xs [lg]="9">
|
||||
<h6 style="text-align: right;">
|
||||
<button cButton color="danger" class="mx-1" size="sm" style="color: #fff;">{{updates.length}} Updatable
|
||||
</button>
|
||||
<button cButton color="warning" class="mx-1" size="sm" style="color: #fff;">{{upgrades.length}}
|
||||
Upgradable</button>
|
||||
|
|
||||
<button cButton color="dark" (click)="scanwizard(1,'')" [cModalToggle]="ScannerModal.id" class="mx-1"
|
||||
size="sm" style="color: #fff;"><i class="fa-solid fa-magnifying-glass"></i> Scanner</button>
|
||||
</h6>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-card-header>
|
||||
<c-card-body>
|
||||
<c-row>
|
||||
<c-col [lg]="3">
|
||||
<c-input-group *ngIf="groups.length>0">
|
||||
<span cInputGroupText>Group</span>
|
||||
<select [(ngModel)]="selected_group" (change)="groupselected($event)" cSelect>
|
||||
<option value="0" [selected]="selected_group == 0">Select a group</option>
|
||||
<option *ngFor="let g of groups" [value]="g.id" [selected]=" selected_group == g.id ">{{g.name}}
|
||||
</option>
|
||||
</select>
|
||||
</c-input-group>
|
||||
|
||||
</c-col>
|
||||
</c-row>
|
||||
<gui-grid #grid [rowClass]="rowClass" [source]="source" [searching]="searching" [paging]="paging"
|
||||
[columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel" [rowSelection]="rowSelection"
|
||||
(selectedRows)="onSelectedRows($event)" [autoResizeWidth]=true>
|
||||
<gui-grid-column header="Name" field="name">
|
||||
<ng-template let-value="item.name" let-item="item" let-index="index">
|
||||
<img *ngIf="item.status=='updating'" width="20px" src="assets/img/loading.svg" />
|
||||
<i *ngIf="item.status=='updated'" cTooltip="Tooltip text"
|
||||
style="color: green; margin-right: 3px;font-size: .7em;" class="fa-solid fa-check"></i>
|
||||
<i *ngIf="item.status=='failed'" cTooltip="Update failed"
|
||||
style="color: red; margin-right: 3px;font-size: .7em;" class="fa-solid fa-x"></i>
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="CPU Type" field="arch">
|
||||
<ng-template let-value="item.arch" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Firmware" field="current_firmware">
|
||||
<ng-template let-value="item.current_firmware" let-item="item" let-index="index">
|
||||
<div>{{value}}</div>
|
||||
<i *ngIf="item.update_availble" cTooltip="Firmware Update availble"
|
||||
class="fa-solid fa-up-long text-primary mx-1"></i>
|
||||
<i *ngIf="item.update_availble" cTooltip="Device Firmware not Upgraded"
|
||||
class="fa-solid fa-microchip text-danger mx-1"></i>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="IP Address" field="ip">
|
||||
<ng-template let-value="item.ip" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="MAC Address" field="mac">
|
||||
<ng-template let-value="item.mac" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="License" field="license" [enabled]="false">
|
||||
<ng-template let-value="item.license" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Interface" field="interface" [enabled]="false">
|
||||
<ng-template let-value="item.interface" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Created" field="created" [enabled]="false">
|
||||
<ng-template let-value="item.created" let-item="item.id" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Uptime" field="uptime">
|
||||
<ng-template let-value="item.uptime" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Created" field="created" [enabled]="false">
|
||||
<ng-template let-value="item.created" let-item="item.id" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column align="center" [cellEditing]="false" [sorting]="false" header="Action">
|
||||
<ng-template let-value="value" let-item="item">
|
||||
<button size="sm" shape="rounded-0" variant="outline" cButton color="primary" (click)="show_detail(item)"
|
||||
style="border: none;padding: 4px 7px;"><i class="fa-regular fa-eye"></i><small> Details</small>
|
||||
</button>
|
||||
<button color="primary" shape="rounded-0" variant="ghost" style="padding: 4px 7px;"
|
||||
[matMenuTriggerFor]="menu" cButton>
|
||||
<i class="fa-solid fa-bars"></i>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<div cListGroup>
|
||||
<li cListGroupItem [active]="false" color="dark">Actions Menu</li>
|
||||
<button size="sm" (click)="single_device_action(item,'edit')" style="padding: 4px 7px;"
|
||||
cListGroupItem><i class="fa-solid fa-pencil"></i><small>
|
||||
Edit Device</small></button>
|
||||
<button size="sm" (click)="single_device_action(item,'firmware')" style="padding: 4px 7px;"
|
||||
cListGroupItem><i class="text-primary fa-solid fa-magnifying-glass"></i><small>
|
||||
Check Firmware</small></button>
|
||||
<button size="sm" (click)="single_device_action(item,'update')" style="padding: 4px 7px;"
|
||||
cListGroupItem><i class="text-primary fa-solid fa-upload"></i><small>
|
||||
Update Firmware</small></button>
|
||||
<!-- <button size="sm" (click)="single_device_action(item,'upgrade')" style="padding: 4px 7px;"
|
||||
cListGroupItem><i class="text-primary fa-solid fa-microchip"></i><small>
|
||||
Upgrade Firmware</small></button> -->
|
||||
<button size="sm" (click)="single_device_action(item,'logauth')" style="padding: 4px 7px;"
|
||||
cListGroupItem><i class="text-primary fa-regular fa-clock"></i><small>
|
||||
Show Auth Logs</small></button>
|
||||
<button size="sm" (click)="single_device_action(item,'logacc')" style="padding: 4px 7px;"
|
||||
cListGroupItem><i class="text-primary fa-solid fa-table-list"></i><small>
|
||||
Show Acc Logs</small></button>
|
||||
<button size="sm" (click)="single_device_action(item,'backup')" style="padding: 4px 7px;"
|
||||
cListGroupItem><i class="text-success fa-solid fa-database"></i><small>
|
||||
Show Backups</small></button>
|
||||
<button size="sm" (click)="single_device_action(item,'delete')" style="padding: 4px 7px;"
|
||||
cListGroupItem><i class="text-danger fa-solid fa-trash"></i><small>
|
||||
Delete Device</small></button>
|
||||
</div>
|
||||
</mat-menu>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
<c-navbar *ngIf="rows.length!= 0" class="bg-light" colorScheme="light" expand="lg">
|
||||
<c-container [fluid]="true">
|
||||
<a cNavbarBrand href="javascript:;">
|
||||
Batch Action :
|
||||
</a>
|
||||
<button [cNavbarToggler]="collapseRef"></button>
|
||||
<div #collapseRef="cCollapse" [navbar]="true" cCollapse>
|
||||
<c-navbar-nav class="me-auto mb-2 mb-lg-0">
|
||||
<c-nav-item>
|
||||
<c-dropdown variant="nav-item" [popper]="false">
|
||||
<a cDropdownToggle cNavLink>Select</a>
|
||||
<ul cDropdownMenu dark>
|
||||
<li><button cDropdownItem (click)="ConfirmAction='checkfirm';ConfirmModalVisible=true">Check
|
||||
Firmware</button></li>
|
||||
<li><button cDropdownItem
|
||||
(click)="ConfirmAction='update';ConfirmModalVisible=true">Update</button></li>
|
||||
<!-- <li><button cDropdownItem>Upgrade</button></li>
|
||||
<li><button cDropdownItem>Update and Upgrade</button></li> -->
|
||||
</ul>
|
||||
</c-dropdown>
|
||||
</c-nav-item>
|
||||
</c-navbar-nav>
|
||||
</div>
|
||||
</c-container>
|
||||
</c-navbar>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
||||
|
||||
|
||||
<c-modal #ScannerModal [visible]="scanwizard_modal" (visibleChange)="handleScanwizard_modal($event)" backdrop="static"
|
||||
id="ScannerModal">
|
||||
<c-modal-header>
|
||||
<h5 cModalTitle>Scanner Wizard</h5>
|
||||
<button [cModalToggle]="ScannerModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
<div *ngIf="scanwizard_step==1" class="mb-5" style="text-align: center;">
|
||||
<h5 class="mb-5">Please select searching method</h5>
|
||||
<button cButton color="info" (click)="scanwizard(2,'chip')" [disabled]="true" class="mx-1" size="lg"><img width="100px"
|
||||
src="assets/img/chip.png" /><br />Layer2 Scan</button>
|
||||
<button cButton color="info" (click)="scanwizard(2,'ip')" class="mx-1" size="lg"><img width="100px"
|
||||
src="assets/img/tcpip.png" /><br />TCP/IP Scan</button>
|
||||
</div>
|
||||
<div *ngIf="scanwizard_step==2 && scan_type=='ip'" class="mb-2" style="text-align: center;">
|
||||
<h5 class="mb-5">Please Provide needed information</h5>
|
||||
<c-input-group class="mb-3">
|
||||
<span cInputGroupText>Start IP</span>
|
||||
<input aria-label="start" cFormControl [(ngModel)]="ip_scanner['start']" [valid]="checkvalid('start')"
|
||||
placeholder="192.168.1.1" />
|
||||
<span cInputGroupText>End IP</span>
|
||||
<input aria-label="end" cFormControl [(ngModel)]="ip_scanner['end']" [valid]="checkvalid('end')"
|
||||
placeholder="192.168.1.255" />
|
||||
</c-input-group>
|
||||
<c-input-group class="mb-3">
|
||||
<span cInputGroupText>Username</span>
|
||||
<input aria-label="start" cFormControl [(ngModel)]="ip_scanner['user']" placeholder="Default username" />
|
||||
</c-input-group>
|
||||
<c-input-group class="mb-3">
|
||||
<span cInputGroupText>Password</span>
|
||||
<input aria-label="end" cFormControl [(ngModel)]="ip_scanner['password']" placeholder="********" />
|
||||
</c-input-group>
|
||||
<c-input-group class="mb-3">
|
||||
<span cInputGroupText>Port</span>
|
||||
<input aria-label="end" cFormControl [valid]="checkvalid('port')" [(ngModel)]="ip_scanner['port']"
|
||||
placeholder="8728" />
|
||||
</c-input-group>
|
||||
<button cButton color="info" (click)="scanwizard(3,'ip')" class="mx-1" size="lg">Start Scanning</button>
|
||||
</div>
|
||||
<div class="mwand" *ngIf="scanwizard_step==3">
|
||||
<svg viewBox="0 0 203 148.27">
|
||||
<g id="wand">
|
||||
<g class="cls-1">
|
||||
<path d="M194.63,152.18v-7.76C194.6,147,194.6,149.59,194.63,152.18Z" transform="translate(-10 -31.06)" />
|
||||
</g>
|
||||
<rect class="cls-2" x="5.07" y="129.83" width="117.08" height="17.1"
|
||||
transform="translate(-77.95 30.6) rotate(-35.06)" />
|
||||
<rect class="cls-3" x="106.38" y="88.26" width="32.89" height="17.1"
|
||||
transform="translate(-43.33 57.07) rotate(-35.06)" />
|
||||
<ellipse class="cls-4" cx="136.21" cy="87.42" rx="3.29" ry="8.55"
|
||||
transform="translate(-35.5 63.06) rotate(-35.06)" />
|
||||
<ellipse class="cls-2" cx="15.6" cy="172.07" rx="3.29" ry="8.55"
|
||||
transform="translate(-106.02 9.13) rotate(-35.06)" />
|
||||
<ellipse class="cls-3" cx="109.5" cy="106.16" rx="3.29" ry="8.55"
|
||||
transform="translate(-51.12 51.12) rotate(-35.06)" />
|
||||
<path class="cls-5" d="M138.71,85.25s4.26,6.06,2.68,9L20.15,179.32s-3.27.49-7.53-5.57Z"
|
||||
transform="translate(-10 -31.06)" />
|
||||
</g>
|
||||
<g id="stars">
|
||||
<g id="star1">
|
||||
<polygon class="cls-6"
|
||||
points="142.22 4.88 138.59 13.13 147.13 17.7 137.94 19.78 139.9 28.82 132.07 23.15 125.96 29.86 125.38 20.71 115.81 20.03 122.93 14.3 117.1 6.74 126.55 8.74 128.85 0 133.51 8.22 142.22 4.88" />
|
||||
<polygon class="cls-7"
|
||||
points="142.29 4.89 136.56 13.87 144.96 17.35 136.17 18.98 138.3 26.2 131.33 20.74 125.88 29.85 132.06 23.11 139.91 28.82 137.95 19.81 147.12 17.74 138.59 13.11 142.29 4.89" />
|
||||
</g>
|
||||
<g id="star2">
|
||||
<polygon class="cls-6"
|
||||
points="166.3 14.45 165.13 17.09 167.87 18.55 164.93 19.22 165.55 22.12 163.04 20.3 161.09 22.45 160.9 19.52 157.83 19.3 160.11 17.46 158.25 15.04 161.27 15.68 162.01 12.88 163.51 15.52 166.3 14.45" />
|
||||
<polygon class="cls-7"
|
||||
points="166.32 14.45 164.48 17.33 167.18 18.44 164.36 18.96 165.04 21.28 162.81 19.53 161.06 22.45 163.04 20.29 165.56 22.12 164.93 19.23 167.87 18.57 165.13 17.08 166.32 14.45" />
|
||||
</g>
|
||||
<g id="star3">
|
||||
<polygon class="cls-6"
|
||||
points="202.01 38.12 194.78 46.34 203 54.75 191.61 53.79 190.56 64.97 183.57 55.54 174.05 61.06 176.73 50.27 165.91 45.98 176.24 41.95 172.26 31.08 182.46 36.84 188.33 27.58 190.71 38.8 202.01 38.12" />
|
||||
<polygon class="cls-7"
|
||||
points="202.08 38.15 192.17 46.45 200.62 53.55 189.85 52.21 189.67 61.34 183.6 52.48 173.96 61.03 183.58 55.49 190.57 64.97 191.6 53.83 202.97 54.79 194.8 46.31 202.08 38.15" />
|
||||
</g>
|
||||
<g id="star4">
|
||||
<polygon class="cls-6"
|
||||
points="155.07 63.05 153.01 67.75 157.87 70.35 152.64 71.52 153.75 76.67 149.3 73.44 145.83 77.25 145.5 72.05 140.06 71.67 144.1 68.41 140.79 64.11 146.16 65.25 147.47 60.28 150.13 64.95 155.07 63.05" />
|
||||
<polygon class="cls-7"
|
||||
points="155.11 63.06 151.86 68.17 156.63 70.14 151.63 71.07 152.84 75.17 148.88 72.07 145.78 77.25 149.29 73.42 153.76 76.67 152.65 71.54 157.86 70.36 153.01 67.73 155.11 63.06" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<h5>{{scanwizard_prompt}}</h5>
|
||||
</div>
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<small *ngIf="scan_type=='ip'" style="margin: 0 auto;">Empty username and password means system default
|
||||
configuration</small>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
||||
|
||||
|
||||
<c-modal #ConfirmModal backdrop="static" [(visible)]="ConfirmModalVisible" id="runConfirmModal">
|
||||
<c-modal-header>
|
||||
<h6 cModalTitle>Please Confirm Action </h6>
|
||||
<button [cModalToggle]="ConfirmModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
<span *ngIf="ConfirmAction=='checkfirm'">Are you sure that You want to Check firmware of selected devices for
|
||||
update?</span>
|
||||
<span *ngIf="ConfirmAction=='update'">Are you sure that You want to <code>update firmware</code> of selected
|
||||
devices?</span>
|
||||
<ng-container *ngIf="ConfirmAction=='delete'">
|
||||
Are you sure that You want to<code>Delete Device {{selected_device.name}} ?</code><br />
|
||||
<hr>
|
||||
<p class="text-danger">
|
||||
All Related Configuration will be deleted/Modified :<br /><br />
|
||||
* User Permision Related to this Device<br />
|
||||
* Device Groups including this Device<br />
|
||||
* All Logs related to this device<br />
|
||||
</p>
|
||||
</ng-container>
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<button *ngIf="ConfirmAction=='checkfirm'" (click)="check_firmware()" cButton color="danger">
|
||||
Yes
|
||||
</button>
|
||||
<button *ngIf="ConfirmAction=='update'" (click)="update_firmware()" cButton color="danger">
|
||||
Yes
|
||||
</button>
|
||||
<button *ngIf="ConfirmAction=='delete'" (click)="delete_device()" cButton color="danger">
|
||||
Yes,Delete Device
|
||||
</button>
|
||||
<button cButton [cModalToggle]="ConfirmModal.id" color="info">
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
||||
|
||||
<c-modal #EditDevModal backdrop="static" [(visible)]="EditDevModalVisible" id="EditDevModal">
|
||||
<c-modal-header>
|
||||
<h6 cModalTitle>Editing Device</h6>
|
||||
<button [cModalToggle]="EditDevModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body *ngIf="EditDevModalVisible">
|
||||
<c-input-group class="mb-3">
|
||||
<span cInputGroupText>Username</span>
|
||||
<input aria-label="start" [(ngModel)]="selected_device['editform']['user_name']" cFormControl
|
||||
placeholder=" username" />
|
||||
</c-input-group>
|
||||
<c-input-group class="mb-3">
|
||||
<span cInputGroupText>Password</span>
|
||||
<input aria-label="start" [type]="show_pass ? 'text' : 'password'"
|
||||
[(ngModel)]="selected_device['editform']['password']" cFormControl placeholder=" username" />
|
||||
<button cButton (click)="show_pass=!show_pass" color="secondary" variant="outline">
|
||||
<i *ngIf="show_pass" class="fa-solid fa-eye"></i>
|
||||
<i *ngIf="!show_pass" class="fa-solid fa-eye-slash"></i>
|
||||
</button>
|
||||
</c-input-group>
|
||||
<c-input-group class="mb-3">
|
||||
<span cInputGroupText>ip</span>
|
||||
<input aria-label="start" [(ngModel)]="selected_device['editform']['ip']" cFormControl
|
||||
placeholder="Default username" />
|
||||
</c-input-group>
|
||||
<c-input-group class="mb-3">
|
||||
<span cInputGroupText>peer ip</span>
|
||||
<select aria-label="Default select example" cFormControl [(ngModel)]="selected_device['editform']['peer_ip']" cSelect>
|
||||
<option *ngFor="let o of selected_device['editform']['ips']" [value]="o">{{o}}</option>
|
||||
</select>
|
||||
</c-input-group>
|
||||
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<button cButton (click)="save_device()" color="danger">
|
||||
Save
|
||||
</button>
|
||||
<button cButton [cModalToggle]="EditDevModal.id" color="info">
|
||||
Cancel
|
||||
</button>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
||||
|
||||
<c-toaster position="fixed" placement="top-end"></c-toaster>
|
460
src/app/views/devices/devices.component.ts
Normal file
460
src/app/views/devices/devices.component.ts
Normal file
|
@ -0,0 +1,460 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
QueryList,
|
||||
ViewChild,
|
||||
ViewChildren,
|
||||
} from "@angular/core";
|
||||
import { dataProvider } from "../../providers/mikrowizard/data";
|
||||
import { Router, ActivatedRoute } from "@angular/router";
|
||||
import { loginChecker } from "../../providers/login_checker";
|
||||
import {
|
||||
GuiGridComponent,
|
||||
GuiGridApi,
|
||||
GuiRowClass,
|
||||
GuiSearching,
|
||||
GuiSelectedRow,
|
||||
GuiInfoPanel,
|
||||
GuiColumn,
|
||||
GuiColumnMenu,
|
||||
GuiPaging,
|
||||
GuiPagingDisplay,
|
||||
GuiRowSelectionMode,
|
||||
GuiRowSelection,
|
||||
GuiRowSelectionType,
|
||||
} from "@generic-ui/ngx-grid";
|
||||
import { ToasterComponent } from "@coreui/angular";
|
||||
import { AppToastComponent } from "../toast-simple/toast.component";
|
||||
|
||||
interface IUser {
|
||||
name: string;
|
||||
state: string;
|
||||
registered: string;
|
||||
country: string;
|
||||
usage: number;
|
||||
period: string;
|
||||
payment: string;
|
||||
activity: string;
|
||||
avatar: string;
|
||||
status: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "devices.component.html",
|
||||
})
|
||||
export class DevicesComponent implements OnInit, OnDestroy {
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private login_checker: loginChecker
|
||||
) {
|
||||
var _self = this;
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["login"]);
|
||||
}, 100);
|
||||
}
|
||||
this.data_provider.getSessionInfo().then((res) => {
|
||||
_self.uid = res.uid;
|
||||
_self.uname = res.name;
|
||||
const userId = _self.uid;
|
||||
|
||||
if (res.role != "admin") {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["/user/dashboard"]);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
//get datagrid data
|
||||
function isNotEmpty(value: any): boolean {
|
||||
return value !== undefined && value !== null && value !== "";
|
||||
}
|
||||
}
|
||||
@ViewChild("grid", { static: true }) gridComponent: GuiGridComponent;
|
||||
@ViewChildren(ToasterComponent) viewChildren!: QueryList<ToasterComponent>;
|
||||
public source: Array<any> = [];
|
||||
public columns: Array<GuiColumn> = [];
|
||||
public loading: boolean = true;
|
||||
public rows: any = [];
|
||||
public Selectedrows: any;
|
||||
public upgrades: any = [];
|
||||
public updates: any = [];
|
||||
public scanwizard_step: number = 1;
|
||||
public scanwizard_modal: boolean = false;
|
||||
public ConfirmModalVisible: boolean = false;
|
||||
public EditDevModalVisible: boolean = false;
|
||||
public ConfirmAction: string = "checkfirm";
|
||||
public scan_type: string = "ip";
|
||||
public scan_timer: any;
|
||||
public list_update_timer: any;
|
||||
public scanwizard_prompt: string = "Scanning Network!";
|
||||
public groups: any = [];
|
||||
public selected_group: number = 0;
|
||||
public selected_devices: any = {};
|
||||
public selected_device: any = {};
|
||||
public show_pass: boolean = false;
|
||||
toasterForm = {
|
||||
autohide: true,
|
||||
delay: 3000,
|
||||
position: "fixed",
|
||||
fade: true,
|
||||
closeButton: true,
|
||||
};
|
||||
rowClass: GuiRowClass = {
|
||||
class: "row-highlighted",
|
||||
};
|
||||
public sorting = {
|
||||
enabled: true,
|
||||
multiSorting: true,
|
||||
};
|
||||
public ip_scanner: any;
|
||||
|
||||
searching: GuiSearching = {
|
||||
enabled: true,
|
||||
placeholder: "Search Devices",
|
||||
};
|
||||
|
||||
public paging: GuiPaging = {
|
||||
enabled: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSizes: [5, 10, 25, 50],
|
||||
display: GuiPagingDisplay.ADVANCED,
|
||||
};
|
||||
|
||||
public columnMenu: GuiColumnMenu = {
|
||||
enabled: true,
|
||||
sort: true,
|
||||
columnsManager: true,
|
||||
};
|
||||
|
||||
public infoPanel: GuiInfoPanel = {
|
||||
enabled: true,
|
||||
infoDialog: false,
|
||||
columnsManager: true,
|
||||
schemaManager: true,
|
||||
};
|
||||
|
||||
public rowSelection: GuiRowSelection = {
|
||||
enabled: true,
|
||||
type: GuiRowSelectionType.CHECKBOX,
|
||||
mode: GuiRowSelectionMode.MULTIPLE,
|
||||
};
|
||||
|
||||
ngOnInit(): void {
|
||||
this.selected_group = Number(this.route.snapshot.paramMap.get("id"));
|
||||
this.initGridTable();
|
||||
this.get_groups();
|
||||
}
|
||||
|
||||
show_detail(item: any) {
|
||||
this.router.navigate(["/device-stats", { id: item.id }]);
|
||||
}
|
||||
|
||||
single_device_action(dev: any, action: string) {
|
||||
const api: GuiGridApi = this.gridComponent.api;
|
||||
api.unselectAll();
|
||||
this.Selectedrows = [dev["id"]];
|
||||
switch (action) {
|
||||
case "edit":
|
||||
this.edit_device_form(dev);
|
||||
break;
|
||||
case "firmware":
|
||||
this.check_firmware();
|
||||
break;
|
||||
case "update":
|
||||
this.update_firmware();
|
||||
break;
|
||||
case "upgrade":
|
||||
this.upgrade_firmware();
|
||||
break;
|
||||
case "logauth":
|
||||
this.router.navigate(["/authlog", { devid: dev.id }]);
|
||||
break;
|
||||
case "logacc":
|
||||
this.router.navigate(["/accountlog", { devid: dev.id }]);
|
||||
break;
|
||||
case "backup":
|
||||
this.router.navigate(["/backups", { devid: dev.id }]);
|
||||
break;
|
||||
case "reboot":
|
||||
this.reboot_devices();
|
||||
break;
|
||||
case "delete":
|
||||
this.ConfirmAction = "delete";
|
||||
this.ConfirmModalVisible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
edit_device_form(dev: any) {
|
||||
var _self = this;
|
||||
this.selected_device = dev;
|
||||
this.data_provider.get_editform(dev.id).then((res) => {
|
||||
if ("error" in res) {
|
||||
if (res.error.indexOf("Unauthorized")) {
|
||||
_self.show_toast(
|
||||
"Error",
|
||||
"You are not authorized to perform this action",
|
||||
"danger"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.selected_device["editform"] = res;
|
||||
this.EditDevModalVisible = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
save_device() {
|
||||
var _self = this;
|
||||
this.data_provider
|
||||
.save_editform(this.selected_device["editform"])
|
||||
.then((res) => {
|
||||
_self.show_toast("Success", "Device Saved", "success");
|
||||
this.initGridTable();
|
||||
this.EditDevModalVisible = false;
|
||||
});
|
||||
}
|
||||
groupselected(item: any) {
|
||||
this.selected_group = item.target.value;
|
||||
if (this.selected_group != 0) {
|
||||
this.router.navigate([".", { id: this.selected_group }]);
|
||||
}
|
||||
this.initGridTable();
|
||||
}
|
||||
|
||||
delete_device() {
|
||||
var _self = this;
|
||||
this.ConfirmModalVisible = false;
|
||||
this.data_provider.delete_devices(this.Selectedrows).then((res) => {
|
||||
_self.show_toast("Success", "Device Deleted", "success");
|
||||
this.initGridTable();
|
||||
});
|
||||
}
|
||||
|
||||
onSelectedRows(rows: Array<GuiSelectedRow>): void {
|
||||
this.rows = rows;
|
||||
this.Selectedrows = rows.map((m: GuiSelectedRow) => m.source.id);
|
||||
}
|
||||
|
||||
checkvalid(type: string): boolean {
|
||||
var rx =
|
||||
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
||||
if (type == "start") return rx.test(this.ip_scanner.start);
|
||||
else if (type == "end") return rx.test(this.ip_scanner.end);
|
||||
else if (type == "port") {
|
||||
if (this.ip_scanner.port == "") return true;
|
||||
return Boolean(Number(this.ip_scanner.port));
|
||||
} else return false;
|
||||
}
|
||||
|
||||
scanwizard(step: number, type: string) {
|
||||
var _self = this;
|
||||
this.data_provider.scan_devs(this.scan_type, {}).then((res) => {
|
||||
if (res.status == true) {
|
||||
_self.scanwizard_step = 3;
|
||||
this.wait_scan();
|
||||
return;
|
||||
}
|
||||
if (step == 1) {
|
||||
_self.scan_type = "";
|
||||
_self.ip_scanner = {
|
||||
start: "",
|
||||
end: "",
|
||||
port: "",
|
||||
user: "",
|
||||
password: "",
|
||||
};
|
||||
}
|
||||
if (step == 2) {
|
||||
_self.scan_type = "";
|
||||
if (type == "ip") {
|
||||
_self.scan_type = "ip";
|
||||
} else if (type == "chip") {
|
||||
_self.scan_type = "mac";
|
||||
}
|
||||
}
|
||||
if (step == 3) {
|
||||
if (_self.scan_type == "ip") {
|
||||
if (_self.ip_scanner.start == "" || _self.ip_scanner.end == "") {
|
||||
return;
|
||||
}
|
||||
//test if start and end are valid ip addresses and port is valid
|
||||
if (
|
||||
!_self.checkvalid("start") ||
|
||||
!_self.checkvalid("end") ||
|
||||
!_self.checkvalid("port")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (_self.ip_scanner.port == "") {
|
||||
_self.ip_scanner.port = false;
|
||||
}
|
||||
if (_self.ip_scanner.user == "") {
|
||||
_self.ip_scanner.user = false;
|
||||
}
|
||||
if (_self.ip_scanner.password == "") {
|
||||
_self.ip_scanner.password = false;
|
||||
}
|
||||
|
||||
_self.data_provider
|
||||
.scan_devs(_self.scan_type, _self.ip_scanner)
|
||||
.then((res) => {
|
||||
_self.scanwizard_prompt = "Scanning Network!";
|
||||
_self.wait_scan();
|
||||
});
|
||||
} else if (type == "chip") {
|
||||
_self.data_provider
|
||||
.scan_devs(_self.scan_type, _self.ip_scanner)
|
||||
.then((res) => {
|
||||
// console.dir(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
_self.scanwizard_step = step;
|
||||
});
|
||||
}
|
||||
|
||||
wait_scan() {
|
||||
clearTimeout(this.scan_timer);
|
||||
var _self = this;
|
||||
this.scan_timer = setTimeout(function () {
|
||||
_self.data_provider.scan_devs(_self.scan_type, {}).then((res) => {
|
||||
if (res.status == false) {
|
||||
_self.initGridTable();
|
||||
_self.scanwizard_prompt = "Scanning done! Reloading data";
|
||||
setTimeout(function () {
|
||||
_self.scanwizard_modal = false;
|
||||
}, 3000);
|
||||
} else {
|
||||
_self.wait_scan();
|
||||
}
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
logger(item: any) {
|
||||
console.dir(item);
|
||||
}
|
||||
|
||||
handleScanwizard_modal(event: any) {
|
||||
this.scanwizard_modal = event;
|
||||
}
|
||||
show_toast(title: string, body: string, color: string) {
|
||||
const { ...props } = { ...this.toasterForm, color, title, body };
|
||||
const componentRef = this.viewChildren.first.addToast(
|
||||
AppToastComponent,
|
||||
props,
|
||||
{}
|
||||
);
|
||||
componentRef.instance["closeButton"] = props.closeButton;
|
||||
}
|
||||
check_firmware() {
|
||||
var _self = this;
|
||||
this.data_provider
|
||||
.check_firmware(this.Selectedrows.toString())
|
||||
.then((res) => {
|
||||
_self.show_toast("info", "Checking Firmwares", "light");
|
||||
_self.ConfirmModalVisible = false;
|
||||
setTimeout(function () {
|
||||
if (_self.Selectedrows.length < 1) _self.initGridTable();
|
||||
}, 1);
|
||||
});
|
||||
}
|
||||
|
||||
update_firmware() {
|
||||
var _self = this;
|
||||
this.data_provider
|
||||
.update_firmware(this.Selectedrows.toString())
|
||||
.then((res) => {
|
||||
_self.show_toast("info", "Updating Firmwares Sent", "light");
|
||||
_self.initGridTable();
|
||||
});
|
||||
}
|
||||
|
||||
upgrade_firmware() {
|
||||
var _self = this;
|
||||
this.data_provider
|
||||
.upgrade_firmware(this.Selectedrows.toString())
|
||||
.then((res) => {
|
||||
_self.show_toast("info", "Upgrading Firmwares", "light");
|
||||
_self.initGridTable();
|
||||
});
|
||||
}
|
||||
|
||||
reboot_devices() {
|
||||
var _self = this;
|
||||
this.data_provider
|
||||
.reboot_devices(this.Selectedrows.toString())
|
||||
.then((res) => {
|
||||
_self.show_toast("info", "Reboot sent", "light");
|
||||
_self.ConfirmModalVisible = !_self.ConfirmModalVisible;
|
||||
_self.initGridTable();
|
||||
});
|
||||
}
|
||||
|
||||
get_groups() {
|
||||
var _self = this;
|
||||
this.data_provider.get_devgroup_list().then((res) => {
|
||||
_self.groups = res;
|
||||
});
|
||||
}
|
||||
|
||||
initGridTable(): void {
|
||||
var _self = this;
|
||||
_self.upgrades = [];
|
||||
_self.updates = [];
|
||||
clearTimeout(this.list_update_timer);
|
||||
var data = {
|
||||
group_id: this.selected_group,
|
||||
search: false,
|
||||
page: this.paging.page,
|
||||
size: this.paging.pageSize,
|
||||
};
|
||||
|
||||
_self.data_provider.get_dev_list(data).then((res) => {
|
||||
_self.source = res.map((x: any) => {
|
||||
if (x.upgrade_availble) _self.upgrades.push(x);
|
||||
if (x.update_availble) _self.updates.push(x);
|
||||
return x;
|
||||
});
|
||||
_self.device_interval();
|
||||
_self.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
device_interval() {
|
||||
var _self = this;
|
||||
var data = {
|
||||
group_id: this.selected_group,
|
||||
search: false,
|
||||
page: this.paging.page,
|
||||
size: this.paging.pageSize,
|
||||
};
|
||||
clearTimeout(this.list_update_timer);
|
||||
_self.list_update_timer = setTimeout(function () {
|
||||
// _self.data_provider.get_dev_list(data).then(res => {
|
||||
// _self.source =res.map( (x:any) => {
|
||||
// if(x.upgrade_availble)
|
||||
// _self.upgrades.push(x);
|
||||
// if(x.update_availble)
|
||||
// _self.updates.push(x);
|
||||
// return x;
|
||||
// });
|
||||
// // _self.device_interval()
|
||||
// _self.loading = false;
|
||||
// });
|
||||
//we don't want to reload table if user is selected devices from list
|
||||
if (_self.Selectedrows.length < 1) _self.initGridTable();
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
clearTimeout(this.scan_timer);
|
||||
}
|
||||
}
|
50
src/app/views/devices/devices.module.ts
Normal file
50
src/app/views/devices/devices.module.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
|
||||
import {
|
||||
ButtonGroupModule,
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
FormModule,
|
||||
GridModule,
|
||||
NavModule,
|
||||
NavbarModule,
|
||||
CollapseModule,
|
||||
DropdownModule,
|
||||
BadgeModule,
|
||||
ToastModule,
|
||||
ModalModule,
|
||||
ListGroupModule,
|
||||
TooltipModule,
|
||||
} from "@coreui/angular";
|
||||
import { MatMenuModule } from "@angular/material/menu";
|
||||
import { DevicesRoutingModule } from "./devices-routing.module";
|
||||
import { DevicesComponent } from "./devices.component";
|
||||
import { GuiGridModule } from "@generic-ui/ngx-grid";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
DevicesRoutingModule,
|
||||
CardModule,
|
||||
NavModule,
|
||||
CommonModule,
|
||||
GridModule,
|
||||
FormModule,
|
||||
ButtonModule,
|
||||
ButtonGroupModule,
|
||||
GuiGridModule,
|
||||
NavbarModule,
|
||||
CollapseModule,
|
||||
DropdownModule,
|
||||
BadgeModule,
|
||||
ModalModule,
|
||||
ToastModule,
|
||||
FormsModule,
|
||||
ListGroupModule,
|
||||
MatMenuModule,
|
||||
TooltipModule,
|
||||
],
|
||||
declarations: [DevicesComponent],
|
||||
})
|
||||
export class DevicesModule {}
|
21
src/app/views/devices_group/devgroup-routing.module.ts
Normal file
21
src/app/views/devices_group/devgroup-routing.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { DevicesGroupComponent } from './devgroup.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DevicesGroupComponent,
|
||||
data: {
|
||||
title: $localize`Device Group`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DevicesGroupRoutingModule {
|
||||
}
|
178
src/app/views/devices_group/devgroup.component.html
Normal file
178
src/app/views/devices_group/devgroup.component.html
Normal file
|
@ -0,0 +1,178 @@
|
|||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-4">
|
||||
<c-card-header>
|
||||
<c-row>
|
||||
<c-col xs [lg]="10">
|
||||
Device Groups
|
||||
</c-col>
|
||||
<c-col xs [lg]="2" style="text-align: right;">
|
||||
<button cButton color="primary" (click)="editAddGroup({},'showadd')"><i
|
||||
class="fa-solid fa-plus"></i></button>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-card-header>
|
||||
<c-card-body>
|
||||
<gui-grid [source]="source" [columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel"
|
||||
[autoResizeWidth]=true>
|
||||
<gui-grid-column header="Name" field="name">
|
||||
<ng-template let-value="item.name" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Devices" field="array_agg" align="CENTER">
|
||||
<ng-template let-value="item.array_agg" let-item="item" let-index="index">
|
||||
<ng-container *ngIf="item.id==1 ; then Default;else NotDefault">
|
||||
</ng-container>
|
||||
<ng-template #Default>
|
||||
<c-badge color="info">All Devices</c-badge>
|
||||
</ng-template>
|
||||
<ng-template #NotDefault>
|
||||
<c-badge color="info" *ngIf="value[0]==null && item.id!=1">0 Members</c-badge>
|
||||
<c-badge color="info" *ngIf="value[0]!=null">{{value.length}} Members</c-badge>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Create Time" field="created">
|
||||
<ng-template let-value="item.created" let-item="item" let-index="index">
|
||||
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
|
||||
<gui-grid-column header="Actions" field="action">
|
||||
<ng-template let-value="item.id" let-item="item" let-index="index">
|
||||
<button [disabled]="value==1" cButton color="warning" size="sm" (click)="editAddGroup(item,'showedit');"
|
||||
class="mx-1"><i class="fa-regular fa-pen-to-square"></i></button>
|
||||
<button [disabled]="value==1" cButton color="info" size="sm" (click)="show_members(item.id);"
|
||||
class="mx-1"><i class="fa-regular fa-eye"></i></button>
|
||||
<button [disabled]="value==1" cButton color="danger" size="sm" (click)="show_delete_group(item);"
|
||||
class="mx-1"><i class="fa-regular fa-trash-can"></i></button>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
||||
|
||||
|
||||
|
||||
<c-modal #EditGroupModal backdrop="static" size="lg" [(visible)]="EditGroupModalVisible" id="EditGroupModal">
|
||||
<c-modal-header>
|
||||
<h5 cModalTitle> Group Edit</h5>
|
||||
<button [cModalToggle]="EditGroupModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
<c-input-group class="mb-3">
|
||||
<div [cFormFloating]="true" class="mb-3">
|
||||
<input cFormControl id="floatingInput" placeholder="Group Name" [(ngModel)]="currentGroup['name']" />
|
||||
<label cLabel for="floatingInput">Group Name</label>
|
||||
</div>
|
||||
</c-input-group>
|
||||
<c-input-group class="mb-3">
|
||||
<h5>Group Members :</h5>
|
||||
<gui-grid [autoResizeWidth]="true" [searching]="searching" [source]="groupMembers" [columnMenu]="columnMenu"
|
||||
[sorting]="sorting" [infoPanel]="infoPanel" [rowSelection]="rowSelection"
|
||||
(selectedRows)="onSelectedRowsMembers($event)" [autoResizeWidth]=true [paging]="paging">
|
||||
<gui-grid-column header="Member Name" field="name">
|
||||
<ng-template let-value="item.name" let-item="item" let-index="index">
|
||||
{{value}} </ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="perm Name" field="ip">
|
||||
<ng-template let-value="item.ip" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Actions" width="120" field="action">
|
||||
<ng-template let-value="item.id" let-item="item" let-index="index">
|
||||
<button cButton color="danger" size="sm" (click)="remove_from_group(item.id)"><i
|
||||
class="fa-regular fa-trash-can"></i></button>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
<br />
|
||||
<button *ngIf="MemberRows.length!= 0" style="margin: 10px 0;" cButton color="danger" size="sm"><i
|
||||
class="fa-regular fa-trash-can"></i>Delete {{MemberRows.length}} Selected</button>
|
||||
</c-input-group>
|
||||
<hr />
|
||||
<button cButton color="primary" (click)="show_new_member_form()">+ Add new Members</button>
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<button cButton color="primary" (click)="save_group()">save</button>
|
||||
<button [cModalToggle]="EditGroupModal.id" cButton color="secondary">
|
||||
Close
|
||||
</button>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
||||
|
||||
<c-modal #NewMemberModal backdrop="static" size="lg" [(visible)]="NewMemberModalVisible" id="NewMemberModal">
|
||||
<c-modal-header>
|
||||
<h5 cModalTitle>Members not in Group</h5>
|
||||
<button (click)="NewMemberModalVisible=!NewMemberModalVisible" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
<c-input-group class="mb-3">
|
||||
<h5>Members Availble to add:</h5>
|
||||
<gui-grid [autoResizeWidth]="true" *ngIf="NewMemberModalVisible" [searching]="searching"
|
||||
[source]="availbleMembers" [columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel"
|
||||
[rowSelection]="rowSelection" (selectedRows)="onSelectedRowsNewMembers($event)" [autoResizeWidth]=true
|
||||
[paging]="paging">
|
||||
<gui-grid-column header="Group Name" field="name">
|
||||
<ng-template let-value="item.name" let-item="item" let-index="index">
|
||||
{{value}} </ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="perm Name" field="ip">
|
||||
<ng-template let-value="item.ip" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="perm Name" field="mac">
|
||||
<ng-template let-value="item.mac" let-item="item" let-index="index">
|
||||
{{value}}
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
<br />
|
||||
</c-input-group>
|
||||
<hr />
|
||||
</c-modal-body>
|
||||
|
||||
<c-modal-footer>
|
||||
<button *ngIf="NewMemberRows.length!= 0" (click)="add_new_members()" cButton color="primary">Add {{
|
||||
NewMemberRows.length }}</button>
|
||||
<button (click)="NewMemberModalVisible=!NewMemberModalVisible" cButton color="secondary">
|
||||
Close
|
||||
</button>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
||||
|
||||
|
||||
|
||||
|
||||
<c-modal #ConfirmModal backdrop="static" [(visible)]="ConfirmModalVisible" id="ConfirmModal">
|
||||
<c-modal-header>
|
||||
<h5 cModalTitle> Are You Sure?</h5>
|
||||
<button [cModalToggle]="ConfirmModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
<ng-container *ngIf="ConfirmAction=='delete'">
|
||||
<span>
|
||||
Are you sure that you want to delete <b class="text-danger-emphasis">{{currentGroup['name']}}</b>?
|
||||
</span>
|
||||
<br />
|
||||
<p class="text-danger">
|
||||
All Related Configuration will be deleted/Modified :<br />
|
||||
* User Permision Related to this group<br />
|
||||
* Tasks including this Group<br />
|
||||
</p>
|
||||
</ng-container>
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<button cButton color="danger" (click)="delete_group()">Confirm</button>
|
||||
<button [cModalToggle]="ConfirmModal.id" cButton color="secondary">
|
||||
Close
|
||||
</button>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
240
src/app/views/devices_group/devgroup.component.ts
Normal file
240
src/app/views/devices_group/devgroup.component.ts
Normal file
|
@ -0,0 +1,240 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { dataProvider } from "../../providers/mikrowizard/data";
|
||||
import { Router } from "@angular/router";
|
||||
import { loginChecker } from "../../providers/login_checker";
|
||||
import {
|
||||
GuiSearching,
|
||||
GuiSelectedRow,
|
||||
GuiInfoPanel,
|
||||
GuiColumn,
|
||||
GuiColumnMenu,
|
||||
GuiPaging,
|
||||
GuiPagingDisplay,
|
||||
GuiRowSelectionMode,
|
||||
GuiRowSelection,
|
||||
GuiRowSelectionType,
|
||||
} from "@generic-ui/ngx-grid";
|
||||
|
||||
interface IUser {
|
||||
name: string;
|
||||
state: string;
|
||||
registered: string;
|
||||
country: string;
|
||||
usage: number;
|
||||
period: string;
|
||||
payment: string;
|
||||
activity: string;
|
||||
avatar: string;
|
||||
status: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "devgroup.component.html",
|
||||
})
|
||||
export class DevicesGroupComponent implements OnInit {
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private router: Router,
|
||||
private login_checker: loginChecker
|
||||
) {
|
||||
var _self = this;
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["login"]);
|
||||
}, 100);
|
||||
}
|
||||
this.data_provider.getSessionInfo().then((res) => {
|
||||
_self.uid = res.uid;
|
||||
_self.uname = res.name;
|
||||
const userId = _self.uid;
|
||||
|
||||
if (res.role != "admin") {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["/user/dashboard"]);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
//get datagrid data
|
||||
function isNotEmpty(value: any): boolean {
|
||||
return value !== undefined && value !== null && value !== "";
|
||||
}
|
||||
}
|
||||
public source: Array<any> = [];
|
||||
public columns: Array<GuiColumn> = [];
|
||||
public loading: boolean = true;
|
||||
public MemberRows: any = [];
|
||||
public NewMemberRows: any = [];
|
||||
|
||||
public SelectedMemberRows: any;
|
||||
public SelectedNewMemberRows: any;
|
||||
public ConfirmModalVisible: boolean = false;
|
||||
public ConfirmAction: string = "delete";
|
||||
public EditGroupModalVisible: boolean = false;
|
||||
public NewMemberModalVisible: boolean = false;
|
||||
public groupMembers: any = [];
|
||||
public availbleMembers: any = [];
|
||||
public currentGroup: any = {
|
||||
array_agg: [],
|
||||
created: "",
|
||||
id: 0,
|
||||
name: "",
|
||||
};
|
||||
public DefaultCurrentGroup: any = {
|
||||
array_agg: [],
|
||||
created: "",
|
||||
id: 0,
|
||||
name: "",
|
||||
};
|
||||
public sorting = {
|
||||
enabled: true,
|
||||
multiSorting: true,
|
||||
};
|
||||
|
||||
searching: GuiSearching = {
|
||||
enabled: true,
|
||||
placeholder: "Search Devices",
|
||||
};
|
||||
|
||||
public paging: GuiPaging = {
|
||||
enabled: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSizes: [5, 10, 25, 50],
|
||||
display: GuiPagingDisplay.ADVANCED,
|
||||
};
|
||||
|
||||
public columnMenu: GuiColumnMenu = {
|
||||
enabled: true,
|
||||
sort: true,
|
||||
columnsManager: true,
|
||||
};
|
||||
|
||||
public infoPanel: GuiInfoPanel = {
|
||||
enabled: true,
|
||||
infoDialog: false,
|
||||
columnsManager: true,
|
||||
schemaManager: true,
|
||||
};
|
||||
|
||||
public rowSelection: boolean | GuiRowSelection = {
|
||||
enabled: true,
|
||||
type: GuiRowSelectionType.CHECKBOX,
|
||||
mode: GuiRowSelectionMode.MULTIPLE,
|
||||
};
|
||||
|
||||
ngOnInit(): void {
|
||||
this.initGridTable();
|
||||
}
|
||||
|
||||
public show_members(id: number) {
|
||||
this.router.navigate(["devices", { id: id }]);
|
||||
}
|
||||
|
||||
public show_delete_group(item: any) {
|
||||
this.currentGroup = item;
|
||||
this.ConfirmModalVisible = true;
|
||||
this.ConfirmAction = "delete";
|
||||
}
|
||||
public delete_group() {
|
||||
var _self = this;
|
||||
this.data_provider.delete_group(this.currentGroup.id).then((res) => {
|
||||
_self.initGridTable();
|
||||
_self.ConfirmModalVisible = false;
|
||||
});
|
||||
}
|
||||
|
||||
onSelectedRowsMembers(rows: Array<GuiSelectedRow>): void {
|
||||
this.MemberRows = rows;
|
||||
this.SelectedMemberRows = rows.map((m: GuiSelectedRow) => m.source.id);
|
||||
}
|
||||
onSelectedRowsNewMembers(rows: Array<GuiSelectedRow>): void {
|
||||
this.NewMemberRows = rows;
|
||||
this.SelectedNewMemberRows = rows.map((m: GuiSelectedRow) => m.source.id);
|
||||
}
|
||||
add_new_members() {
|
||||
var _self = this;
|
||||
this.currentGroup["array_agg"] = [
|
||||
...new Set(
|
||||
this.currentGroup["array_agg"].concat(this.SelectedNewMemberRows)
|
||||
),
|
||||
];
|
||||
this.groupMembers = [
|
||||
...new Set(
|
||||
this.groupMembers.concat(
|
||||
this.NewMemberRows.map((m: GuiSelectedRow) => m.source)
|
||||
)
|
||||
),
|
||||
];
|
||||
this.NewMemberModalVisible = false;
|
||||
}
|
||||
remove_from_group(id: number) {
|
||||
var _self = this;
|
||||
this.currentGroup["array_agg"] = this.currentGroup["array_agg"].filter(
|
||||
(x: any) => x != id
|
||||
);
|
||||
this.groupMembers = this.groupMembers.filter((x: any) => x.id != id);
|
||||
}
|
||||
|
||||
save_group() {
|
||||
var _self = this;
|
||||
this.data_provider.update_save_group(this.currentGroup).then((res) => {
|
||||
_self.initGridTable();
|
||||
_self.EditGroupModalVisible = false;
|
||||
});
|
||||
}
|
||||
|
||||
editAddGroup(item: any, action: string) {
|
||||
var _self = this;
|
||||
if (action == "showadd") {
|
||||
this.currentGroup = { ...this.DefaultCurrentGroup };
|
||||
this.groupMembers = [];
|
||||
this.EditGroupModalVisible = true;
|
||||
return;
|
||||
}
|
||||
this.currentGroup = item;
|
||||
this.groupMembers = [];
|
||||
this.data_provider.get_devgroup_members(item.id).then((res) => {
|
||||
_self.groupMembers = res;
|
||||
_self.currentGroup = { ...item };
|
||||
// simple hack to remove null from devices list
|
||||
_self.currentGroup["array_agg"] = item["array_agg"].filter(
|
||||
(x: any) => x != null
|
||||
);
|
||||
_self.EditGroupModalVisible = true;
|
||||
});
|
||||
}
|
||||
|
||||
show_new_member_form() {
|
||||
this.NewMemberModalVisible = true;
|
||||
var _self = this;
|
||||
_self.availbleMembers = [];
|
||||
this.SelectedNewMemberRows = [];
|
||||
this.NewMemberRows = [];
|
||||
var data = {
|
||||
group_id: false,
|
||||
search: false,
|
||||
page: false,
|
||||
size: 10000,
|
||||
};
|
||||
_self.data_provider.get_dev_list(data).then((res) => {
|
||||
_self.availbleMembers = res.filter(
|
||||
(x: any) => !_self.currentGroup["array_agg"].includes(x.id)
|
||||
);
|
||||
_self.NewMemberModalVisible = true;
|
||||
});
|
||||
}
|
||||
|
||||
logger(item: any) {
|
||||
console.dir(item);
|
||||
}
|
||||
initGridTable(): void {
|
||||
this.data_provider.get_devgroup_list().then((res) => {
|
||||
this.source = res;
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
35
src/app/views/devices_group/devgroup.module.ts
Normal file
35
src/app/views/devices_group/devgroup.module.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
|
||||
import {
|
||||
ButtonGroupModule,
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
FormModule,
|
||||
GridModule,
|
||||
CollapseModule,
|
||||
ModalModule,
|
||||
} from "@coreui/angular";
|
||||
import { DevicesGroupRoutingModule } from "./devgroup-routing.module";
|
||||
import { DevicesGroupComponent } from "./devgroup.component";
|
||||
import { GuiGridModule } from "@generic-ui/ngx-grid";
|
||||
import { BadgeModule } from "@coreui/angular";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
@NgModule({
|
||||
imports: [
|
||||
DevicesGroupRoutingModule,
|
||||
CardModule,
|
||||
CommonModule,
|
||||
GridModule,
|
||||
FormsModule,
|
||||
FormModule,
|
||||
ButtonModule,
|
||||
ButtonGroupModule,
|
||||
GuiGridModule,
|
||||
CollapseModule,
|
||||
ModalModule,
|
||||
BadgeModule,
|
||||
],
|
||||
declarations: [DevicesGroupComponent],
|
||||
})
|
||||
export class DevicesGroupModule {}
|
16
src/app/views/icons/coreui-icons.component.html
Normal file
16
src/app/views/icons/coreui-icons.component.html
Normal file
|
@ -0,0 +1,16 @@
|
|||
<div class="fade-in">
|
||||
<c-card>
|
||||
<c-card-header>
|
||||
{{ title }}
|
||||
<app-docs-link href="https://github.com/coreui/coreui-icons" text="GitHub"></app-docs-link>
|
||||
</c-card-header>
|
||||
<c-card-body>
|
||||
<c-row class="text-center">
|
||||
<c-col *ngFor="let icon of icons" class="mb-5" md="3" sm="4" xl="2" xs="6">
|
||||
<svg cIcon [name]="icon[0]" [title]="icon[0]" size="3xl"></svg>
|
||||
<div>{{ toKebabCase(icon[0]) }}</div>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</div>
|
46
src/app/views/icons/coreui-icons.component.ts
Normal file
46
src/app/views/icons/coreui-icons.component.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { IconSetService } from '@coreui/icons-angular';
|
||||
import { brandSet, flagSet, freeSet } from '@coreui/icons';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'coreui-icons.component.html',
|
||||
providers: [IconSetService],
|
||||
})
|
||||
export class CoreUIIconsComponent implements OnInit {
|
||||
public title = 'CoreUI Icons';
|
||||
public icons!: [string, string[]][];
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute, public iconSet: IconSetService
|
||||
) {
|
||||
iconSet.icons = { ...freeSet, ...brandSet, ...flagSet };
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const path = this.route?.routeConfig?.path;
|
||||
let prefix = 'cil';
|
||||
if (path === 'coreui-icons') {
|
||||
this.title = `${this.title} - Free`;
|
||||
prefix = 'cil';
|
||||
} else if (path === 'brands') {
|
||||
this.title = `${this.title} - Brands`;
|
||||
prefix = 'cib';
|
||||
} else if (path === 'flags') {
|
||||
this.title = `${this.title} - Flags`;
|
||||
prefix = 'cif';
|
||||
}
|
||||
this.icons = this.getIconsView(prefix);
|
||||
}
|
||||
|
||||
toKebabCase(str: string) {
|
||||
return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
|
||||
getIconsView(prefix: string) {
|
||||
return Object.entries(this.iconSet.icons).filter((icon) => {
|
||||
return icon[0].startsWith(prefix);
|
||||
});
|
||||
}
|
||||
}
|
48
src/app/views/icons/icons-routing.module.ts
Normal file
48
src/app/views/icons/icons-routing.module.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { CoreUIIconsComponent } from './coreui-icons.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
data: {
|
||||
title: 'Icons'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
pathMatch: 'full',
|
||||
redirectTo: 'coreui-icons'
|
||||
},
|
||||
{
|
||||
path: 'coreui-icons',
|
||||
component: CoreUIIconsComponent,
|
||||
data: {
|
||||
title: 'CoreUI Icons'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'brands',
|
||||
component: CoreUIIconsComponent,
|
||||
data: {
|
||||
title: 'Brands'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'flags',
|
||||
component: CoreUIIconsComponent,
|
||||
data: {
|
||||
title: 'Flags'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class IconsRoutingModule {
|
||||
}
|
25
src/app/views/icons/icons.module.ts
Normal file
25
src/app/views/icons/icons.module.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { CardModule, GridModule } from '@coreui/angular';
|
||||
import { IconModule } from '@coreui/icons-angular';
|
||||
|
||||
import { CoreUIIconsComponent } from './coreui-icons.component';
|
||||
import { IconsRoutingModule } from './icons-routing.module';
|
||||
import { DocsComponentsModule } from '@docs-components/docs-components.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IconsRoutingModule,
|
||||
CardModule,
|
||||
GridModule,
|
||||
IconModule,
|
||||
CommonModule,
|
||||
DocsComponentsModule
|
||||
],
|
||||
declarations: [
|
||||
CoreUIIconsComponent
|
||||
]
|
||||
})
|
||||
export class IconsModule {
|
||||
}
|
51
src/app/views/pages/login/login.component.html
Normal file
51
src/app/views/pages/login/login.component.html
Normal file
|
@ -0,0 +1,51 @@
|
|||
<div class="bg-light min-vh-100 d-flex flex-row align-items-center">
|
||||
<c-container>
|
||||
<c-row class="justify-content-center">
|
||||
<c-col md="8">
|
||||
<c-card-group>
|
||||
<c-card [ngStyle]="{'width.%': 44}" class="text-white py-5" style="background-color: #303c54;">
|
||||
<c-card-body class="text-center">
|
||||
<img style="width: 200px;" src="assets/img/brand/mikrowizard-full.jpg">
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
<c-card class="p-4">
|
||||
<c-card-body>
|
||||
<form cForm [formGroup]="loginForm" >
|
||||
<h1>Login</h1>
|
||||
<p class="text-medium-emphasis">Sign In to your account</p>
|
||||
<c-input-group class="mb-3">
|
||||
<span cInputGroupText>
|
||||
<svg cIcon name="cilUser"></svg>
|
||||
</span>
|
||||
<input autoComplete="username" cFormControl placeholder="Username" formControlName="username" required #username/>
|
||||
</c-input-group>
|
||||
<c-input-group class="mb-1">
|
||||
<span cInputGroupText>
|
||||
<svg cIcon name="cilLockLocked"></svg>
|
||||
</span>
|
||||
<input
|
||||
autoComplete="current-password"
|
||||
cFormControl
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
formControlName="password"
|
||||
required #password
|
||||
/>
|
||||
</c-input-group>
|
||||
<code *ngIf="error_msg"><i class="fa-solid fa-triangle-exclamation"></i><small> {{error_msg}}</small></code>
|
||||
<c-row>
|
||||
<c-col mb-3 xs="6">
|
||||
<button type="submit" cButton (click)="onClickSubmit()" class="px-4" color="primary">
|
||||
Login
|
||||
</button>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</form>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
|
||||
</c-card-group>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-container>
|
||||
</div>
|
0
src/app/views/pages/login/login.component.scss
Normal file
0
src/app/views/pages/login/login.component.scss
Normal file
35
src/app/views/pages/login/login.component.spec.ts
Normal file
35
src/app/views/pages/login/login.component.spec.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ButtonModule, CardModule, FormModule, GridModule } from '@coreui/angular';
|
||||
import { LoginComponent } from './login.component';
|
||||
import { IconModule } from '@coreui/icons-angular';
|
||||
import { IconSetService } from '@coreui/icons-angular';
|
||||
import { iconSubset } from '../../../icons/icon-subset';
|
||||
|
||||
describe('LoginComponent', () => {
|
||||
let component: LoginComponent;
|
||||
let fixture: ComponentFixture<LoginComponent>;
|
||||
let iconSetService: IconSetService;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ LoginComponent ],
|
||||
imports: [FormModule, CardModule, GridModule, ButtonModule, IconModule],
|
||||
providers: [IconSetService]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
iconSetService = TestBed.inject(IconSetService);
|
||||
iconSetService.icons = { ...iconSubset };
|
||||
|
||||
fixture = TestBed.createComponent(LoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
66
src/app/views/pages/login/login.component.ts
Normal file
66
src/app/views/pages/login/login.component.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { dataProvider } from '../../../providers/mikrowizard/data';
|
||||
import { loginChecker } from '../../../providers/login_checker';
|
||||
import { Validators, FormControl, FormGroup} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class LoginComponent {
|
||||
public loginForm: FormGroup;
|
||||
public forgotForm: FormGroup;
|
||||
public error_msg: string = "";
|
||||
public forgot_error_msg: string = "";
|
||||
public success_msg: string = "";
|
||||
public submitted = false;
|
||||
public forgot_page: boolean = false;
|
||||
public forgot_btn_disable: boolean = false;
|
||||
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private data_provider: dataProvider,
|
||||
private login_checker: loginChecker,
|
||||
) {
|
||||
this.createForm();
|
||||
};
|
||||
|
||||
createForm() {
|
||||
this.loginForm = new FormGroup({
|
||||
username: new FormControl(''),
|
||||
password: new FormControl(''),
|
||||
ga_code: new FormControl(''),
|
||||
});
|
||||
this.forgotForm = new FormGroup({
|
||||
email: new FormControl(''),
|
||||
});
|
||||
}
|
||||
|
||||
onClickSubmit(){
|
||||
var _self = this;
|
||||
let uname = _self.loginForm.get('username')!.value;
|
||||
let passwd = _self.loginForm.get('password')!.value;
|
||||
let ga_code = '';
|
||||
console.dir(uname);
|
||||
_self.data_provider.login(uname, passwd, '').then(res => {
|
||||
if ('uid' in res && res['uid']){
|
||||
_self.error_msg = "";
|
||||
_self.login_checker.setStatus(true);
|
||||
_self.router.navigate(['/'], {replaceUrl: true});
|
||||
}
|
||||
else {
|
||||
if ('reason' in res) {
|
||||
}
|
||||
else
|
||||
_self.error_msg = res.error;
|
||||
}
|
||||
}).catch(err => {
|
||||
_self.error_msg = "Wrong username or password!";
|
||||
});
|
||||
// });
|
||||
}
|
||||
|
||||
}
|
22
src/app/views/pages/page404/page404.component.html
Normal file
22
src/app/views/pages/page404/page404.component.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<div class="bg-light min-vh-100 d-flex flex-row align-items-center">
|
||||
<c-container>
|
||||
<c-row class="justify-content-center">
|
||||
<c-col md="6">
|
||||
<div class="clearfix">
|
||||
<h1 class="float-start display-3 me-4">404</h1>
|
||||
<h4 class="pt-3">Oops! You're lost.</h4>
|
||||
<p class="text-medium-emphasis float-start">
|
||||
The page you are looking for was not found.
|
||||
</p>
|
||||
</div>
|
||||
<c-input-group class="input-prepend">
|
||||
<span cInputGroupText>
|
||||
<svg cIcon name="cilMagnifyingGlass"></svg>
|
||||
</span>
|
||||
<input cFormControl placeholder="What are you looking for?" type="text" />
|
||||
<button cButton color="info">Search</button>
|
||||
</c-input-group>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-container>
|
||||
</div>
|
0
src/app/views/pages/page404/page404.component.scss
Normal file
0
src/app/views/pages/page404/page404.component.scss
Normal file
35
src/app/views/pages/page404/page404.component.spec.ts
Normal file
35
src/app/views/pages/page404/page404.component.spec.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ButtonModule, FormModule, GridModule } from '@coreui/angular';
|
||||
import { IconModule } from '@coreui/icons-angular';
|
||||
import { IconSetService } from '@coreui/icons-angular';
|
||||
import { iconSubset } from '../../../icons/icon-subset';
|
||||
import { Page404Component } from './page404.component';
|
||||
|
||||
describe('Page404Component', () => {
|
||||
let component: Page404Component;
|
||||
let fixture: ComponentFixture<Page404Component>;
|
||||
let iconSetService: IconSetService;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ Page404Component ],
|
||||
imports: [FormModule, GridModule, ButtonModule, IconModule],
|
||||
providers: [IconSetService]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
iconSetService = TestBed.inject(IconSetService);
|
||||
iconSetService.icons = { ...iconSubset };
|
||||
|
||||
fixture = TestBed.createComponent(Page404Component);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
12
src/app/views/pages/page404/page404.component.ts
Normal file
12
src/app/views/pages/page404/page404.component.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-page404',
|
||||
templateUrl: './page404.component.html',
|
||||
styleUrls: ['./page404.component.scss']
|
||||
})
|
||||
export class Page404Component {
|
||||
|
||||
constructor() { }
|
||||
|
||||
}
|
22
src/app/views/pages/page500/page500.component.html
Normal file
22
src/app/views/pages/page500/page500.component.html
Normal file
|
@ -0,0 +1,22 @@
|
|||
<div class="bg-light min-vh-100 d-flex flex-row align-items-center">
|
||||
<c-container>
|
||||
<c-row class="justify-content-center">
|
||||
<c-col md="6">
|
||||
<span class="clearfix">
|
||||
<h1 class="float-start display-3 me-4">500</h1>
|
||||
<h4 class="pt-3">Houston, we have a problem!</h4>
|
||||
<p class="text-medium-emphasis float-start">
|
||||
The page you are looking for is temporarily unavailable.
|
||||
</p>
|
||||
</span>
|
||||
<c-input-group class="input-prepend">
|
||||
<span cInputGroupText>
|
||||
<svg cIcon name="cilMagnifyingGlass"></svg>
|
||||
</span>
|
||||
<input cFormControl placeholder="What are you looking for?" type="text" />
|
||||
<button cButton color="info">Search</button>
|
||||
</c-input-group>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-container>
|
||||
</div>
|
0
src/app/views/pages/page500/page500.component.scss
Normal file
0
src/app/views/pages/page500/page500.component.scss
Normal file
35
src/app/views/pages/page500/page500.component.spec.ts
Normal file
35
src/app/views/pages/page500/page500.component.spec.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ButtonModule, FormModule, GridModule } from '@coreui/angular';
|
||||
import { IconModule } from '@coreui/icons-angular';
|
||||
import { IconSetService } from '@coreui/icons-angular';
|
||||
import { iconSubset } from '../../../icons/icon-subset';
|
||||
import { Page500Component } from './page500.component';
|
||||
|
||||
describe('Page500Component', () => {
|
||||
let component: Page500Component;
|
||||
let fixture: ComponentFixture<Page500Component>;
|
||||
let iconSetService: IconSetService;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ Page500Component ],
|
||||
imports: [GridModule, ButtonModule, FormModule, IconModule],
|
||||
providers: [IconSetService]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
iconSetService = TestBed.inject(IconSetService);
|
||||
iconSetService.icons = { ...iconSubset };
|
||||
|
||||
fixture = TestBed.createComponent(Page500Component);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
12
src/app/views/pages/page500/page500.component.ts
Normal file
12
src/app/views/pages/page500/page500.component.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-page500',
|
||||
templateUrl: './page500.component.html',
|
||||
styleUrls: ['./page500.component.scss']
|
||||
})
|
||||
export class Page500Component {
|
||||
|
||||
constructor() { }
|
||||
|
||||
}
|
36
src/app/views/pages/pages-routing.module.ts
Normal file
36
src/app/views/pages/pages-routing.module.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { Page404Component } from './page404/page404.component';
|
||||
import { Page500Component } from './page500/page500.component';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '404',
|
||||
component: Page404Component,
|
||||
data: {
|
||||
title: 'Page 404'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '500',
|
||||
component: Page500Component,
|
||||
data: {
|
||||
title: 'Page 500'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'login',
|
||||
component: LoginComponent,
|
||||
data: {
|
||||
title: 'Login Page'
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class PagesRoutingModule {
|
||||
}
|
32
src/app/views/pages/pages.module.ts
Normal file
32
src/app/views/pages/pages.module.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { PagesRoutingModule } from './pages-routing.module';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { Page404Component } from './page404/page404.component';
|
||||
import { Page500Component } from './page500/page500.component';
|
||||
import { ButtonModule, CardModule, FormModule, GridModule } from '@coreui/angular';
|
||||
import { IconModule } from '@coreui/icons-angular';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
LoginComponent,
|
||||
Page404Component,
|
||||
Page500Component
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
PagesRoutingModule,
|
||||
CardModule,
|
||||
ButtonModule,
|
||||
GridModule,
|
||||
IconModule,
|
||||
FormModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule
|
||||
]
|
||||
})
|
||||
export class PagesModule {
|
||||
}
|
21
src/app/views/permissions/permissions-routing.module.ts
Normal file
21
src/app/views/permissions/permissions-routing.module.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { PermissionsComponent } from './permissions.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: PermissionsComponent,
|
||||
data: {
|
||||
title: $localize`Permissions`
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class PermissionsRoutingModule {
|
||||
}
|
137
src/app/views/permissions/permissions.component.html
Normal file
137
src/app/views/permissions/permissions.component.html
Normal file
|
@ -0,0 +1,137 @@
|
|||
<c-row>
|
||||
<c-col xs>
|
||||
<c-card class="mb-4">
|
||||
<c-card-header>
|
||||
<c-row>
|
||||
<c-col xs [lg]="10">
|
||||
Permissions
|
||||
</c-col>
|
||||
<c-col xs [lg]="2" style="text-align: right;">
|
||||
<button cButton color="primary" (click)="editAddTask({},'showadd')"><i
|
||||
class="fa-solid fa-plus"></i></button>
|
||||
</c-col>
|
||||
</c-row>
|
||||
</c-card-header>
|
||||
<c-card-body>
|
||||
<gui-grid [rowHeight]="82" [autoResizeWidth]="true" [source]="source" [columnMenu]="columnMenu"
|
||||
[sorting]="sorting" [autoResizeWidth]=true [paging]="paging">
|
||||
<gui-grid-column header="Name" field="name">
|
||||
<ng-template let-value="item.name" let-item="item" let-index="index">
|
||||
{{value}} </ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column width="auto" header="Perms" field="perms">
|
||||
<ng-template let-value="item.role" let-item="item" let-index="index">
|
||||
<div style="text-wrap: initial;">
|
||||
<ng-container *ngFor="let perm of item['perms'] | keyvalue">
|
||||
<c-badge *ngIf="perm.value" class="m-1" color="success">{{perm.key}}</c-badge>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
<gui-grid-column header="Actions" width="120" field="action">
|
||||
<ng-template let-value="item.id" let-item="item" let-index="index">
|
||||
<button cButton color="warning" size="sm" class="mx-1" (click)="editAddTask(item,'edit');"><i
|
||||
class="fa-regular fa-pen-to-square"></i></button>
|
||||
<button cButton color="danger" size="sm" (click)="confirm_delete(item);"><i
|
||||
class="fa-regular fa-trash-can"></i></button>
|
||||
</ng-template>
|
||||
</gui-grid-column>
|
||||
</gui-grid>
|
||||
</c-card-body>
|
||||
</c-card>
|
||||
</c-col>
|
||||
</c-row>
|
||||
<c-modal-header>
|
||||
|
||||
|
||||
<c-modal #EditTaskModal backdrop="static" size="lg" [(visible)]="EditTaskModalVisible" id="EditTaskModal">
|
||||
<c-modal-header>
|
||||
<h5 *ngIf="action=='edit'" cModalTitle>Editing Permission {{SelectedPerm['name']}}</h5>
|
||||
<h5 *ngIf="action=='add'" cModalTitle>Adding new Permission Rule</h5>
|
||||
<button [cModalToggle]="EditTaskModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
|
||||
<div [cFormFloating]="true" class="mb-3">
|
||||
<input cFormControl id="floatingInput" placeholder="permname" [(ngModel)]="permname" />
|
||||
<label cLabel for="floatingInput">Name</label>
|
||||
</div>
|
||||
<c-row>
|
||||
<c-col>
|
||||
<c-form-check *ngFor='let val of ["api","ftp","password","read","romon","sniff","telnet","tikapp","winbox"]'
|
||||
[switch]="true">
|
||||
<input cFormCheckInput [(ngModel)]="perms[val] " type="checkbox" />
|
||||
<label cFormCheckLabel>{{ val}}</label>
|
||||
</c-form-check>
|
||||
</c-col>
|
||||
<c-col>
|
||||
<c-form-check
|
||||
*ngFor='let val of ["dude","local","policy","reboot","rest-api","sensitive","ssh","test","web","write"]'
|
||||
[switch]="true">
|
||||
<input cFormCheckInput [(ngModel)]="perms[val] " type="checkbox" />
|
||||
<label cFormCheckLabel>{{ val}}</label>
|
||||
</c-form-check>
|
||||
</c-col>
|
||||
</c-row>
|
||||
<ng-container *ngIf="SelectedMembers.length>0 && EditTaskModalVisible">
|
||||
<c-badge class="mx-1" *ngFor="let id of splitids(SelectedPermItems)"
|
||||
color="dark">{{get_member_by_id(id).name}}</c-badge>
|
||||
</ng-container>
|
||||
<!--
|
||||
<c-input-group class="mb-3">
|
||||
<cron-editor #cronEditorDemo1 [(ngModel)]="SelectedPerm['cron']" [options]="cronOptions">Cron here...</cron-editor>
|
||||
</c-input-group>
|
||||
-->
|
||||
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<button *ngIf="action=='add'" (click)="submit('add')" cButton color="primary">Add</button>
|
||||
<button *ngIf="action=='edit'" (click)="submit('edit')" cButton color="primary">save</button>
|
||||
<button [cModalToggle]="EditTaskModal.id" cButton color="secondary">
|
||||
Close
|
||||
</button>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
||||
|
||||
|
||||
<c-modal #DeleteConfirmModal backdrop="static" [(visible)]="DeleteConfirmModalVisible" id="DeleteConfirmModal">
|
||||
<c-modal-header>
|
||||
<h5 cModalTitle>Confirm delete {{ SelectedPerm['name'] }}</h5>
|
||||
<button [cModalToggle]="DeleteConfirmModal.id" cButtonClose></button>
|
||||
</c-modal-header>
|
||||
<c-modal-body>
|
||||
Are you sure that You want to delete following Permission?
|
||||
<br />
|
||||
<br />
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<td><b>Permission name : </b>{{ SelectedPerm['name'] }}
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<ng-container *ngFor="let perm of SelectedPerm['perms'] | keyvalue">
|
||||
<c-badge *ngIf="perm.value" class="m-1" color="success">{{perm.key}}</c-badge>
|
||||
</ng-container>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><code
|
||||
style="padding: 0!important;"><b>Warning:</b> ALL Given <b>device access</b> related to this permision in Users Section <b>will be deleted</b> for each user</code>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</c-modal-body>
|
||||
<c-modal-footer>
|
||||
<button (click)="confirm_delete('',true)" cButton color="danger">
|
||||
Yes,Delete!
|
||||
</button>
|
||||
<button [cModalToggle]="DeleteConfirmModal.id" cButton color="info">
|
||||
Close
|
||||
</button>
|
||||
</c-modal-footer>
|
||||
</c-modal>
|
||||
|
||||
|
||||
<c-toaster position="fixed" placement="top-end"></c-toaster>
|
260
src/app/views/permissions/permissions.component.ts
Normal file
260
src/app/views/permissions/permissions.component.ts
Normal file
|
@ -0,0 +1,260 @@
|
|||
import { Component, OnInit, QueryList, ViewChildren } from "@angular/core";
|
||||
import { dataProvider } from "../../providers/mikrowizard/data";
|
||||
import { Router } from "@angular/router";
|
||||
import { loginChecker } from "../../providers/login_checker";
|
||||
import {
|
||||
GuiColumn,
|
||||
GuiColumnMenu,
|
||||
GuiPaging,
|
||||
GuiPagingDisplay,
|
||||
} from "@generic-ui/ngx-grid";
|
||||
|
||||
import { ToasterComponent } from "@coreui/angular";
|
||||
import { AppToastComponent } from "../toast-simple/toast.component";
|
||||
|
||||
interface IUser {
|
||||
name: string;
|
||||
state: string;
|
||||
registered: string;
|
||||
country: string;
|
||||
usage: number;
|
||||
period: string;
|
||||
payment: string;
|
||||
activity: string;
|
||||
avatar: string;
|
||||
status: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "permissions.component.html",
|
||||
})
|
||||
export class PermissionsComponent implements OnInit {
|
||||
public uid: number;
|
||||
public uname: string;
|
||||
|
||||
constructor(
|
||||
private data_provider: dataProvider,
|
||||
private router: Router,
|
||||
private login_checker: loginChecker
|
||||
) {
|
||||
var _self = this;
|
||||
if (!this.login_checker.isLoggedIn()) {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["login"]);
|
||||
}, 100);
|
||||
}
|
||||
this.data_provider.getSessionInfo().then((res) => {
|
||||
_self.uid = res.uid;
|
||||
_self.uname = res.name;
|
||||
const userId = _self.uid;
|
||||
|
||||
if (res.role != "admin") {
|
||||
setTimeout(function () {
|
||||
_self.router.navigate(["/user/dashboard"]);
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
//get datagrid data
|
||||
function isNotEmpty(value: any): boolean {
|
||||
return value !== undefined && value !== null && value !== "";
|
||||
}
|
||||
}
|
||||
@ViewChildren(ToasterComponent) viewChildren!: QueryList<ToasterComponent>;
|
||||
|
||||
public source: Array<any> = [];
|
||||
public columns: Array<GuiColumn> = [];
|
||||
public loading: boolean = true;
|
||||
public rows: any = [];
|
||||
public SelectedPerm: any = {};
|
||||
public SelectedPermItems: string = "";
|
||||
|
||||
public EditTaskModalVisible: boolean = false;
|
||||
public DeleteConfirmModalVisible: boolean = false;
|
||||
public Members: any = "";
|
||||
public SelectedMembers: any = [];
|
||||
|
||||
public action: string = "add";
|
||||
public permid: number = 0;
|
||||
public permname: string = "";
|
||||
public perms: { [index: string]: boolean } = {
|
||||
api: false,
|
||||
ftp: false,
|
||||
password: false,
|
||||
read: false,
|
||||
romon: false,
|
||||
sniff: false,
|
||||
telnet: false,
|
||||
tikapp: false,
|
||||
winbox: false,
|
||||
dude: false,
|
||||
local: false,
|
||||
policy: false,
|
||||
reboot: false,
|
||||
"rest-api": false,
|
||||
sensitive: false,
|
||||
ssh: false,
|
||||
test: false,
|
||||
web: false,
|
||||
write: false,
|
||||
};
|
||||
|
||||
toasterForm = {
|
||||
autohide: true,
|
||||
delay: 3000,
|
||||
position: "fixed",
|
||||
fade: true,
|
||||
closeButton: true,
|
||||
};
|
||||
|
||||
public sorting = {
|
||||
enabled: true,
|
||||
multiSorting: true,
|
||||
};
|
||||
|
||||
public paging: GuiPaging = {
|
||||
enabled: true,
|
||||
page: 1,
|
||||
pageSize: 10,
|
||||
pageSizes: [5, 10, 25, 50],
|
||||
display: GuiPagingDisplay.ADVANCED,
|
||||
};
|
||||
|
||||
public columnMenu: GuiColumnMenu = {
|
||||
enabled: true,
|
||||
sort: true,
|
||||
columnsManager: true,
|
||||
};
|
||||
show_toast(title: string, body: string, color: string) {
|
||||
const { ...props } = { ...this.toasterForm, color, title, body };
|
||||
const componentRef = this.viewChildren.first.addToast(
|
||||
AppToastComponent,
|
||||
props,
|
||||
{}
|
||||
);
|
||||
componentRef.instance["closeButton"] = props.closeButton;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.initGridTable();
|
||||
}
|
||||
submit(action: string) {
|
||||
var _self = this;
|
||||
if (action == "add") {
|
||||
this.data_provider
|
||||
.create_perm(_self.permname, _self.perms)
|
||||
.then((res) => {
|
||||
if (res["status"] == "failed") {
|
||||
_self.show_toast(
|
||||
"Error",
|
||||
res.err,
|
||||
"danger"
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
_self.initGridTable();
|
||||
this.EditTaskModalVisible = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.data_provider
|
||||
.edit_perm(_self.permid, _self.permname, _self.perms)
|
||||
.then((res) => {
|
||||
if (res["status"] == "failed") {
|
||||
_self.show_toast(
|
||||
"Error",
|
||||
res.err,
|
||||
"danger"
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
_self.initGridTable();
|
||||
this.EditTaskModalVisible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
editAddTask(item: any, action: string) {
|
||||
if (action == "showadd") {
|
||||
this.permname = item["name"];
|
||||
this.perms = {
|
||||
api: false,
|
||||
ftp: false,
|
||||
password: false,
|
||||
read: false,
|
||||
romon: false,
|
||||
sniff: false,
|
||||
telnet: false,
|
||||
tikapp: false,
|
||||
winbox: false,
|
||||
dude: false,
|
||||
local: false,
|
||||
policy: false,
|
||||
reboot: false,
|
||||
"rest-api": false,
|
||||
sensitive: false,
|
||||
ssh: false,
|
||||
test: false,
|
||||
web: false,
|
||||
write: false,
|
||||
};
|
||||
this.permid = 0;
|
||||
this.action = "add";
|
||||
this.EditTaskModalVisible = true;
|
||||
return;
|
||||
}
|
||||
this.action = "edit";
|
||||
this.permname = item["name"];
|
||||
this.perms = item.perms;
|
||||
this.permid = item["id"];
|
||||
this.EditTaskModalVisible = true;
|
||||
}
|
||||
|
||||
splitids(ids: string = "") {
|
||||
return ids.split(",");
|
||||
}
|
||||
|
||||
get_member_by_id(id: string) {
|
||||
return this.Members.find((x: any) => x.id == id);
|
||||
}
|
||||
|
||||
confirm_delete(item: any = "", del: boolean = false) {
|
||||
if (!del) {
|
||||
this.SelectedPerm = { ...item };
|
||||
this.DeleteConfirmModalVisible = true;
|
||||
} else {
|
||||
var _self = this;
|
||||
this.data_provider.delete_perm(_self.SelectedPerm["id"]).then((res) => {
|
||||
if (res["status"] == "failed") {
|
||||
_self.show_toast(
|
||||
"Error",
|
||||
res.err,
|
||||
"danger"
|
||||
);
|
||||
return;
|
||||
}
|
||||
else{
|
||||
_self.initGridTable();
|
||||
_self.DeleteConfirmModalVisible = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
logger(item: any) {
|
||||
console.dir(item);
|
||||
}
|
||||
|
||||
initGridTable(): void {
|
||||
var _self = this;
|
||||
var page = 1;
|
||||
var pageSize = 10;
|
||||
var searchstr = "";
|
||||
this.data_provider.get_perms(page, pageSize, searchstr).then((res) => {
|
||||
_self.source = res.map((x: any) => {
|
||||
return x;
|
||||
});
|
||||
_self.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue