MikroWizard Initial commit | MikroFront Welcome to the world :)

This commit is contained in:
sepehr 2024-07-07 14:48:52 +03:30
commit b97aec6b97
203 changed files with 41097 additions and 0 deletions

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
/node_modules/
*.log
*.swo
*.swp
.vimrc
.nvimrc
.angular/
/dist/

25
Dockerfile Normal file
View 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
View 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
View file

@ -0,0 +1,222 @@
[![@coreui angular](https://img.shields.io/badge/@coreui%20-angular-lightgrey.svg?style=flat-square)](https://github.com/coreui/angular)
[![npm-coreui-angular][npm-coreui-angular-badge]][npm-coreui-angular]
[![NPM downloads][npm-coreui-angular-download]][npm-coreui-angular]
[![@coreui coreui](https://img.shields.io/badge/@coreui%20-coreui-lightgrey.svg?style=flat-square)](https://github.com/coreui/coreui)
[![npm package][npm-coreui-badge]][npm-coreui]
[![NPM downloads][npm-coreui-download]][npm-coreui]
![angular](https://img.shields.io/badge/angular-^16.2.0-lightgrey.svg?style=flat-square&logo=angular)
[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 cant 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

83
package.json Normal file
View 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
View 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
View 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
View file

@ -0,0 +1,8 @@
{
"/api": {
"target": "http://127.0.0.1/",
"secure": false,
"changeOrigin": true,
"pathRewrite": {"^/api" : ""}
}
}

2
reqs.txt Normal file
View file

@ -0,0 +1,2 @@
cryptography==3.4.8
Requests==2.32.2

1
run-docker.sh Executable file
View 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

View 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 {
}

View 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
View 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
View 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 {
}

View 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' }
}
];

View file

@ -0,0 +1,6 @@
<!--<c-footer>-->
<div>
<a href="https://mikrowizard.com" target="_blank">MikroWizard</a>
<span> &copy; 2024 </span>
</div>
<!--</c-footer>-->

View file

@ -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();
});
});

View file

@ -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();
}
}

View file

@ -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>

View file

@ -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();
});
});

View file

@ -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();
}
}

View file

@ -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>

View file

@ -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);
}
}

View 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(/#.*$/, '');
}
});
}
}

View file

@ -0,0 +1,3 @@
export * from './default-footer/default-footer.component';
export * from './default-header/default-header.component';
export * from './default-layout.component';

View file

@ -0,0 +1 @@
export * from './default-layout';

View 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'
}

View 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;
}
}

View 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);
})
}
}

View 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;
}
}

View 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));
}
}

View 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;
}
}

View 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 {}

View 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>

View 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;
}
}

View 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;
});
}
}

View 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 {}

View 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 {
}

View 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>

View 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;
}
}
}

View 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;
});
}
}

View 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 {
}

View 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 {
}

View 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>

View 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;
});
}
}

View 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 {}

View 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 {
}

View 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>

View 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();
}
}

View 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 {}

View 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 {
}

View 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>

View file

@ -0,0 +1,7 @@
:host {
.legend {
small {
font-size: x-small;
}
}
}

View 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();
});
});

View 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);
}
}

View 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 {}

View 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 {
}

View 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>

View 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;
}
}

View 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;
});
}
}

View 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 {}

View 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 {
}

View 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>

View 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);
}
}

View 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 {}

View 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 {
}

View 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">
&nbsp; {{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">
&nbsp; {{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>

View 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;
});
}
}

View 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 {}

View 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>

View 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);
});
}
}

View 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 {
}

View 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 {
}

View 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>

View 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();
});
});

View 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!";
});
// });
}
}

View 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>

View 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();
});
});

View 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() { }
}

View 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>

View 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();
});
});

View 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() { }
}

View 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 {
}

View 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 {
}

View 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 {
}

View 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">
&nbsp; {{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>

View 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