mirror of
https://gitlab.com/JKANetwork/powerfulcomputermanager.git
synced 2026-03-03 00:56:45 +01:00
First version with web gui
This commit is contained in:
275
admin/admin.py
Normal file
275
admin/admin.py
Normal file
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/python3
|
||||
from flask import Flask, url_for, render_template, request, Response,redirect,make_response
|
||||
import os
|
||||
import jinja2
|
||||
import requests
|
||||
import hashlib #SHA256
|
||||
import json
|
||||
import base64
|
||||
import configparser
|
||||
from datetime import datetime
|
||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
|
||||
BUILD=1
|
||||
APIC_VER=2
|
||||
|
||||
# Load config to comunicate with API or use default
|
||||
try:
|
||||
config = configparser.ConfigParser()
|
||||
config.read(os.path.relpath('..\\client\\configpcm.ini'))
|
||||
c_server = config['General']['server']
|
||||
except:
|
||||
c_server = "https://127.0.0.1:3333" #Default server api address
|
||||
|
||||
app = Flask(__name__,static_url_path="/assets", static_folder='assets', template_folder="templates")
|
||||
|
||||
|
||||
def returnvalueapi(suburl,field="Name"):
|
||||
global c_server
|
||||
passha256=request.cookies.get('admin_logued')
|
||||
if 'Password=' in suburl:
|
||||
twopart = ""
|
||||
elif '?' in suburl:
|
||||
twopart = '&Password='+str(passha256)
|
||||
else:
|
||||
twopart = '?Password='+str(passha256)
|
||||
|
||||
r=(requests.post(c_server+suburl+twopart, verify=False).text).replace("\'", "\"").replace('\\"',"'").replace(': None',': "None"')
|
||||
try:
|
||||
#print(suburl+twopart+"->"+r)
|
||||
jsonobj = json.loads(r)
|
||||
return jsonobj[field]
|
||||
except:
|
||||
print('Error: '+str(r))
|
||||
return str({'TEXT':r,'RESULT':'ERROR'})
|
||||
|
||||
def returnTable(suburl,field=["Name"]):
|
||||
global c_server
|
||||
passha256=request.cookies.get('admin_logued')
|
||||
if isinstance(field,str):
|
||||
if field != 'ASIS': # Do not touch if it says that we have to return table AS IS
|
||||
field=[field] # Convert to list
|
||||
if 'Password=' in suburl:
|
||||
twopart = ""
|
||||
elif '?' in suburl:
|
||||
twopart = '&Password='+str(passha256)
|
||||
else:
|
||||
twopart= '?Password='+str(passha256)
|
||||
try:
|
||||
r=(requests.post(c_server+suburl+twopart, verify=False).text).replace("\'", "\"").replace('\\"',"'").replace(': None',': "None"')
|
||||
jsonobj = json.loads(r)
|
||||
if field == 'ASIS':
|
||||
return jsonobj
|
||||
else:
|
||||
listitems = []
|
||||
for ite in jsonobj: # Run in array from json
|
||||
to = []
|
||||
for i in field:
|
||||
to.append(str(ite[i]))
|
||||
listitems.append(to)
|
||||
return listitems
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
@app.route("/admin",methods=['GET'])
|
||||
@app.route("/admin/",methods=['GET'])
|
||||
def pAdminIndex(): #Admin Index page
|
||||
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
|
||||
return render_template('/login.tmpl', title="Login")
|
||||
table = returnTable("/get/computers",['ID_C','Name','RAM','CPUName','SOVersion','SOCaption','HDD','LastConnection','RAMFree'])
|
||||
|
||||
for lista in table:
|
||||
lista.append(returnTable("/get/groups?ComputerID="+lista[0],["Name"])) #lista[9]¿
|
||||
if lista[6] is not None:
|
||||
try:
|
||||
lista[6]=json.loads(base64.b64decode(lista[6]).decode('UTF-8'))
|
||||
except:
|
||||
lista[6]=json.loads(str("{}"))
|
||||
else:
|
||||
lista[6]=json.loads(str("{}"))
|
||||
#print (lista[6])
|
||||
try:
|
||||
lista[7] = datetime.fromtimestamp(int(lista[7])).strftime('%Y-%m-%d %H:%M:%S') # LastConnection
|
||||
except:
|
||||
lista[7] = "Never"
|
||||
return render_template('/adminindex.tmpl', title="Admin Dashboard",tablecomputers=table)
|
||||
|
||||
@app.route("/admin/addcomputer",methods=['GET'])
|
||||
def pAdminAddcomputer():
|
||||
computeradd=request.args.get('computeradd')
|
||||
if computeradd is not None:
|
||||
r = returnvalueapi("/add/computer?ComputerName="+computeradd,field="RESULT")
|
||||
if r == "OK":
|
||||
return redirect('/admin')
|
||||
else:
|
||||
return "ERROR"
|
||||
else:
|
||||
return redirect('/admin')
|
||||
|
||||
@app.route("/admin/delcomputer",methods=['GET'])
|
||||
def pAdminDelcomputer():
|
||||
computerdel=request.args.get('computerdel')
|
||||
r = returnvalueapi("/del/computer?ComputerID="+computerdel,field="RESULT")
|
||||
if r == "OK":
|
||||
return redirect('/admin')
|
||||
else:
|
||||
return "ERROR"
|
||||
|
||||
@app.route("/admin/computer",methods=['GET'])
|
||||
def pAdminComputer(): #Admin see one group
|
||||
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
|
||||
return render_template('/login.tmpl', title="Login")
|
||||
|
||||
computerid=request.args.get('ID_C')
|
||||
if computerid is not None and computerid.isnumeric():
|
||||
computername = returnvalueapi('/get/computers?ComputerID='+str(computerid),"Name")
|
||||
groups = returnTable("/get/groups?ComputerName="+str(computername),['ID_G','Name'])
|
||||
#####IT DOESNT HAVE TEMPLATE CREATED
|
||||
return render_template('/admincomputer.tmpl', title="Computer "+computername,computerid=computerid,computername=computername,groups=groups)
|
||||
return redirect('/admin')
|
||||
|
||||
|
||||
@app.route("/admin/groups",methods=['GET'])
|
||||
def pAdminGroups(): #Admin Index groups
|
||||
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
|
||||
return render_template('/login.tmpl', title="Login")
|
||||
table = returnTable("/get/groups",['ID_G','Name'])
|
||||
|
||||
for lista in table:
|
||||
lista.append(returnTable("/get/computersgrp?GroupID="+lista[0],['ID_C','Name'])) #lista[3]¿
|
||||
lista.append(returnTable("/get/cookgrp?GroupID="+lista[0],['CookName'])) #lista[4]¿
|
||||
return render_template('/admingroups.tmpl', title="Groups",tablegroups=table)
|
||||
|
||||
|
||||
@app.route("/admin/group",methods=['GET'])
|
||||
def pAdminGroup(): #Admin see one group
|
||||
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
|
||||
return render_template('/login.tmpl', title="Login")
|
||||
|
||||
groupid=request.args.get('ID_G')
|
||||
if groupid is not None and groupid.isnumeric():
|
||||
groupname=returnvalueapi('/get/groups?GroupID='+str(groupid),"Name")
|
||||
computers = returnTable("/get/computers",['ID_C','Name'])
|
||||
datagroup = (returnTable("/get/computersgrp?GroupID="+groupid,['ID_C','Name'])) #lista[0]¿
|
||||
tem = (returnTable("/get/cookgrp?GroupID="+groupid,['CookName'])) #lista[1]¿
|
||||
cooksdata = []
|
||||
for cook in tem:
|
||||
to = []
|
||||
to.append(cook[0])
|
||||
to.append(returnvalueapi('/get/lastrevisioncook?CookName='+cook[0],"Revision"))
|
||||
to.append(returnTable("/get/statuscook?CookName="+cook[0],'ASIS'))
|
||||
cooksdata.append(to)
|
||||
|
||||
tem = (returnTable("/get/cookall",'ASIS')) #Lista de todas las recetas
|
||||
allcooks = []
|
||||
for cook in tem['CookName']:
|
||||
to = []
|
||||
to.append(cook)
|
||||
to.append(returnvalueapi('/get/lastrevisioncook?CookName='+cook,"Revision"))
|
||||
allcooks.append(to)
|
||||
|
||||
return render_template('/admingroup.tmpl', title="Group "+groupname,groupname=groupname,groupid=groupid,datagroup=datagroup,cooksdata=cooksdata,computers=computers,allcooks=allcooks)
|
||||
return redirect('/admin/groups')
|
||||
|
||||
@app.route("/admin/group/addcook",methods=['GET'])
|
||||
def pAdminGroupAddcook(): #Add cook form enter
|
||||
cooktoadd=request.args.get('cooknameadd')
|
||||
groupid=request.args.get('groupid')
|
||||
if cooktoadd != None and groupid != None:
|
||||
r = returnvalueapi("/add/cookgrp?CookName="+cooktoadd+"&GroupID="+groupid,field="RESULT")
|
||||
if r == "OK":
|
||||
return redirect('/admin/group?ID_G='+groupid)
|
||||
|
||||
|
||||
@app.route("/admin/group/addcomputer",methods=['GET'])
|
||||
def pAdminGroupAddcomputer(): #Add computer form enter
|
||||
computertoadd=request.args.get('computeridadd')
|
||||
groupid=request.args.get('groupid')
|
||||
if computertoadd != None and groupid != None:
|
||||
r = returnvalueapi("/add/grpcomputer?ComputerID="+computertoadd+"&GroupID="+groupid,field="RESULT")
|
||||
if r == "OK":
|
||||
return redirect('/admin/group?ID_G='+groupid)
|
||||
|
||||
|
||||
@app.route("/admin/group/delcomputer",methods=['GET'])
|
||||
def pAdminGroupDelcomputer(): #Add computer form enter
|
||||
computertodel=request.args.get('computernamedel')
|
||||
groupid=request.args.get('groupid')
|
||||
if computertodel != None and groupid != None:
|
||||
r = returnvalueapi("/del/grpcomputer?ComputerName="+computertodel+"&GroupID="+groupid,field="RESULT")
|
||||
if r == "OK":
|
||||
return redirect('/admin/group?ID_G='+groupid)
|
||||
else:
|
||||
return redirect('/admin/group?ID_G='+groupid)
|
||||
|
||||
|
||||
@app.route("/admin/cook",methods=['GET'])
|
||||
def pAdminCook(): #Admin Index groups
|
||||
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
|
||||
return render_template('/login.tmpl', title="Login")
|
||||
|
||||
cookname=request.args.get('CookName')
|
||||
if cookname != None:
|
||||
groupscook=returnTable('/get/grpcook?CookName='+str(cookname),['Name'])
|
||||
allgroups=returnTable('/get/groups',['ID_G','Name'])
|
||||
return render_template('/admincook.tmpl', title="Cook "+cookname,cookname=cookname,allgroups=allgroups,groupscook=groupscook)
|
||||
|
||||
@app.route("/admin/cook/addgroup",methods=['GET'])
|
||||
def pAdminCookAddgroup(): # Add cook to group
|
||||
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
|
||||
return render_template('/login.tmpl', title="Login")
|
||||
cookname=request.args.get('cooknameadd')
|
||||
groupid=request.args.get('groupidadd')
|
||||
if cookname != None and groupid != None:
|
||||
returnvalueapi('/add/cookgrp?CookName='+cookname+'&GroupID='+groupid,'RESULT')
|
||||
return redirect('/admin/cook?CookName='+cookname)
|
||||
else:
|
||||
return "Error of arguments"
|
||||
|
||||
@app.route("/admin/cook/delgroup",methods=['GET'])
|
||||
def pAdminCookDelgroup(): # Add cook to group
|
||||
if returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE') != '0':
|
||||
return render_template('/login.tmpl', title="Login")
|
||||
cookname=request.args.get('cooknamedel')
|
||||
groupname=request.args.get('groupnamedel')
|
||||
if cookname != None and groupname != None:
|
||||
ret = returnvalueapi('/del/cookgrp?CookName='+cookname+'&GroupName='+groupname,'RESULT')
|
||||
if ret != '0':
|
||||
return "Error "+str(ret)
|
||||
return redirect('/admin/cook?CookName='+cookname)
|
||||
else:
|
||||
return "Error of arguments"
|
||||
|
||||
|
||||
|
||||
@app.route("/",methods=['GET'])
|
||||
def pIndex(): #Index page
|
||||
howispasswd=returnvalueapi('/check/password?Password='+str(request.cookies.get('admin_logued')),'EXITCODE')
|
||||
if howispasswd == '0': # Logued
|
||||
return redirect(url_for('pAdminIndex'))
|
||||
if howispasswd == '1' or howispasswd == '2': # Has to login
|
||||
return render_template('/login.tmpl')
|
||||
if howispasswd == '3': # No password yet
|
||||
return 'Yet to do it..'
|
||||
|
||||
@app.route("/login",methods=['GET','POST'])
|
||||
def pLogin(): #Login
|
||||
if request.values.get('password'):
|
||||
trpass = hashlib.sha256(request.values.get('password').encode()).hexdigest()
|
||||
#print(returnvalueapi('/check/password?Password='+trpass,'EXITCODE'))
|
||||
if returnvalueapi('/check/password?Password='+trpass,'EXITCODE') == '0':
|
||||
res = make_response(redirect(url_for('pAdminIndex')))
|
||||
res.set_cookie("admin_logued",value=trpass)
|
||||
return res
|
||||
else:
|
||||
return render_template('/login.tmpl')
|
||||
else:
|
||||
return render_template('/login.tmpl')
|
||||
|
||||
print("Build: "+str(BUILD))
|
||||
print("API Client Compatible Version: "+str(APIC_VER))
|
||||
|
||||
app.run(debug=True,port=3434,ssl_context='adhoc',host='0.0.0.0',threaded=True) #Default is port 3434
|
||||
7
admin/assets/css/bootstrap.min.css
vendored
Normal file
7
admin/assets/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
93
admin/assets/css/dashboard.css
Normal file
93
admin/assets/css/dashboard.css
Normal file
@@ -0,0 +1,93 @@
|
||||
body {
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
.feather {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sidebar
|
||||
*/
|
||||
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100; /* Behind the navbar */
|
||||
padding: 0;
|
||||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
.sidebar-sticky {
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 48px; /* Height of navbar */
|
||||
height: calc(100vh - 48px);
|
||||
padding-top: .5rem;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
|
||||
}
|
||||
|
||||
.sidebar .nav-link {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.sidebar .nav-link .feather {
|
||||
margin-right: 4px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.sidebar .nav-link:hover .feather,
|
||||
.sidebar .nav-link.active .feather {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.sidebar-heading {
|
||||
font-size: .75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/*
|
||||
* Navbar
|
||||
*/
|
||||
|
||||
.navbar-brand {
|
||||
padding-top: .75rem;
|
||||
padding-bottom: .75rem;
|
||||
font-size: 1rem;
|
||||
background-color: rgba(0, 0, 0, .25);
|
||||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25);
|
||||
}
|
||||
|
||||
.navbar .form-control {
|
||||
padding: .75rem 1rem;
|
||||
border-width: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.form-control-dark {
|
||||
color: #fff;
|
||||
background-color: rgba(255, 255, 255, .1);
|
||||
border-color: rgba(255, 255, 255, .1);
|
||||
}
|
||||
|
||||
.form-control-dark:focus {
|
||||
border-color: transparent;
|
||||
box-shadow: 0 0 0 3px rgba(255, 255, 255, .25);
|
||||
}
|
||||
|
||||
/*
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
.border-top { border-top: 1px solid #e5e5e5; }
|
||||
.border-bottom { border-bottom: 1px solid #e5e5e5; }
|
||||
BIN
admin/assets/images/blue-mocha-grunge.jpg
Normal file
BIN
admin/assets/images/blue-mocha-grunge.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
admin/assets/images/cream-dust.png
Normal file
BIN
admin/assets/images/cream-dust.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 661 B |
BIN
admin/assets/images/glyphicons-halflings-white.png
Normal file
BIN
admin/assets/images/glyphicons-halflings-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
BIN
admin/assets/images/glyphicons-halflings.png
Normal file
BIN
admin/assets/images/glyphicons-halflings.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
10
admin/assets/js/Chart.min.js
vendored
Normal file
10
admin/assets/js/Chart.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
admin/assets/js/bootstrap.min.js
vendored
Normal file
7
admin/assets/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
13
admin/assets/js/feather-4.24.1.min.js
vendored
Normal file
13
admin/assets/js/feather-4.24.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
admin/assets/js/jquery-3.2.1.slim.min.js
vendored
Normal file
4
admin/assets/js/jquery-3.2.1.slim.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5
admin/assets/js/popper.min.js
vendored
Normal file
5
admin/assets/js/popper.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
32
admin/templates/admincomputer.tmpl
Normal file
32
admin/templates/admincomputer.tmpl
Normal file
@@ -0,0 +1,32 @@
|
||||
{# -*- coding: utf-8 -*- #} {# NOT DID ALREADY!!! #}
|
||||
{% extends 'baseadmin.tmpl' %}
|
||||
{% block content %}
|
||||
<h2>Computer {{computername}}</h2>
|
||||
<br>
|
||||
<h2>Groups of {{computername}}</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Group Name</th>
|
||||
<th>Cooks</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in tablegroups %} {#['ID_G','Name','Cooks[CookName]']#}
|
||||
<tr>
|
||||
<td><a href="/admin/group?ID_G={{item.0}}">{{item.1}}</a></td>
|
||||
<td style='width:50%;'>
|
||||
{% for x in item.2 %}
|
||||
{{x.0}},
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td><a class="btn btn-outline-danger btn-sm" data-wgroup="{{item.1}}" data-toggle="modal" data-target="#delGroup">Delete {{computername}} from group {{item.1}}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
{% endblock %}
|
||||
92
admin/templates/admincook.tmpl
Normal file
92
admin/templates/admincook.tmpl
Normal file
@@ -0,0 +1,92 @@
|
||||
{# -*- coding: utf-8 -*- #}
|
||||
{% extends 'baseadmin.tmpl' %}
|
||||
{% block content %}
|
||||
|
||||
<!-- Modal Delete Group From Cook -->
|
||||
<div class="modal fade" id="modalDelete" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form method="get" action="/admin/cook/delgroup">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Delete group from cook {{cookname}}</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="cooknamedel" id="cooknamedel" value="{{cookname}}"/>
|
||||
<p>Are you sure?<br>
|
||||
<label for="groupnamedel" class="col-form-label">Group:</label>
|
||||
</div>
|
||||
<input type="text" readonly="readonly" class="form-control" name="groupnamedel" id="groupnamedel">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-danger">Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Add Group To Cook -->
|
||||
<div class="modal fade" id="modalAdd" tabindex="-1" role="dialog" aria-labelledby="modalAddLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form method="get" action="/admin/cook/addgroup">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalAddLabel">Add cook to Group {{groupname}}</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<p>Add group to cook {{cookname}}<br>
|
||||
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="cooknameadd" id="cooknameadd" value="{{cookname}}"/>
|
||||
<label for="groupidadd" class="col-form-label">Group:</label>
|
||||
<select class="form-control" name="groupidadd" id="groupidadd">
|
||||
{% for item in allgroups %}
|
||||
<option value="{{item.0}}">{{item.1}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Groups of cook {{cookname}}</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Group Name</th>
|
||||
<th style="align:right">Delete Group from this Cook</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in groupscook %} {#['Name']#}
|
||||
<tr>
|
||||
<td style='width:64px'>{{item.0}}</td>
|
||||
<td><a href="/admin/group?ID_G={{item.0}}">{{item.0}}</a></td>
|
||||
<td><a class="btn btn-outline-danger btn-sm" data-wgroup="{{item.0}}" data-toggle="modal" data-target="#modalDelete">Remove group {{item.0}} from cook {{cookname}}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td>#</td>
|
||||
<td colspan="2"><a class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#modalAdd">Add group to {{cookname}}</a></td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#modalDelete').on('show.bs.modal', function (event) {
|
||||
var button = $(event.relatedTarget) // Button that triggered the modal
|
||||
var recipient = button.data('wgroup') // Extract info from data-* attributes
|
||||
var modal = $(this)
|
||||
modal.find('#groupnamedel').val(recipient)
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
150
admin/templates/admingroup.tmpl
Normal file
150
admin/templates/admingroup.tmpl
Normal file
@@ -0,0 +1,150 @@
|
||||
{# -*- coding: utf-8 -*- #}
|
||||
{% extends 'baseadmin.tmpl' %}
|
||||
{% block content %}
|
||||
|
||||
<!-- Modal Delete Computer From Group -->
|
||||
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form method="get" action="/admin/group/delcomputer">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">Delete computer from Group {{groupname}}</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="groupid" id="groupid" value="{{groupid}}"/>
|
||||
<p>Are you sure?<br>
|
||||
<label for="computername" class="col-form-label">Computer:</label>
|
||||
</div>
|
||||
<input type="text" readonly="readonly" class="form-control" name="computernamedel" id="computernamedel">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-danger">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Add Computer To Group -->
|
||||
<div class="modal fade" id="modalAdd" tabindex="-1" role="dialog" aria-labelledby="modalAddLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form method="get" action="/admin/group/addcomputer">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalAddLabel">Add computer to Group {{groupname}}</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<p>Add computer to group {{groupname}}<br>
|
||||
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="groupid" value="{{groupid}}"/>
|
||||
<label for="computername2" class="col-form-label">Computer:</label>
|
||||
<select class="form-control" name="computeridadd" id="computeridadd">
|
||||
{% for item in computers %}
|
||||
<option value="{{item.0}}">{{item.1}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Add Cook To Group -->
|
||||
<div class="modal fade" id="modalAddCook" tabindex="-1" role="dialog" aria-labelledby="modalAddCookLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form method="get" action="/admin/group/addcook">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalAddCookLabel">Add Cook to Group {{groupname}}</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<p>Add cook to group {{groupname}}<br>
|
||||
<input type="text" readonly="readonly" class="form-control" hidden="hidden" name="groupid" value="{{groupid}}"/>
|
||||
<label for="cookname" class="col-form-label">Cook name:</label>
|
||||
<select class="form-control" name="cooknameadd" id="cooknameadd">
|
||||
{% for item in allcooks %}
|
||||
<option value="{{item.0}}">{{item.0}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h2>Computers of group {{groupname}}</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Computer Name</th>
|
||||
<th style="align:right">Delete computer from Group</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in datagroup %} {#['ID_C','Name']#}
|
||||
<tr>
|
||||
<td style='width:64px'>{{item.0}}</td>
|
||||
<td><a href="/admin/computer?ID_C={{item.0}}">{{item.1}}</a></td>
|
||||
<td><a class="btn btn-outline-danger btn-sm" {#href="/admin/groupcomputerdel?ID_C={{item.0}}&ID_G={{groupid}}"#} data-wcomputer="{{item.1}}" data-toggle="modal" data-target="#exampleModal">Delete {{item.1}} from group {{groupname}}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td>#</td>
|
||||
<td colspan="2"><a class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#modalAdd">Add computer to {{groupname}}</a></td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h2>Cooks of group {{groupname}}</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Cook Name</th>
|
||||
<th style="width:64px">Cook Last Revision</th>
|
||||
<th>Applied to</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="3"><a class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#modalAddCook">Add new cook to group {{groupname}}</a></td>
|
||||
</tr>
|
||||
{% for item in cooksdata %} {#['CookName','LastRevision','AppliedTo']#}
|
||||
<tr>
|
||||
<td><a href="/admin/cook?CookName={{item.0}}">{{item.0}}</a></td>
|
||||
<td>{{item.1}}</td>
|
||||
<td>
|
||||
{% for subitem in item.2|sort(attribute='Revision')|sort(attribute='Name') %} {# item.2 = AppliedTo #}
|
||||
{{subitem.Name}}{% if subitem.Revision|int < item.1|int %}<span style="color:red">({{subitem.Revision}})</span>{% elif subitem.Error != 0 %}<span style="color:orange;font-weigth:bold;font-style:italic" title="{{subitem.ErrorDesc}}">(Error r.{{subitem.Revision}})</span>{% endif %},
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#exampleModal').on('show.bs.modal', function (event) {
|
||||
var button = $(event.relatedTarget) // Button that triggered the modal
|
||||
var recipient = button.data('wcomputer') // Extract info from data-* attributes
|
||||
var modal = $(this)
|
||||
//modal.find('.modal-title').text('New message to ' + recipient)
|
||||
modal.find('#computernamedel').val(recipient)
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
35
admin/templates/admingroups.tmpl
Normal file
35
admin/templates/admingroups.tmpl
Normal file
@@ -0,0 +1,35 @@
|
||||
{# -*- coding: utf-8 -*- #}
|
||||
{% extends 'baseadmin.tmpl' %}
|
||||
{% block content %}
|
||||
<h2>Groups</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Group Name</th>
|
||||
<th>Cooks</th>
|
||||
<th>Computers</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in tablegroups %} {#['ID_G','Name','Computers[ID_C,Name]','Cooks[CookName]']#}
|
||||
<tr>
|
||||
<td>{{item.0}}</td>
|
||||
<td><a href="/admin/group?ID_G={{item.0}}">{{item.1}}</a></td>
|
||||
<td style='width:50%;'>
|
||||
{% for x in item.3 %}
|
||||
{{x.0}},
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>
|
||||
{% for x in item.2 %}
|
||||
{{x.1}},
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
102
admin/templates/adminindex.tmpl
Normal file
102
admin/templates/adminindex.tmpl
Normal file
@@ -0,0 +1,102 @@
|
||||
{# -*- coding: utf-8 -*- #}
|
||||
{% extends 'baseadmin.tmpl' %}
|
||||
{% block content %}
|
||||
|
||||
<!-- Modal Add Computer To Database -->
|
||||
<div class="modal fade" id="modalAdd" tabindex="-1" role="dialog" aria-labelledby="modalAddLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form method="get" action="/admin/addcomputer">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalAddLabel">Add computer to Database</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<p>Add computer to database<br>
|
||||
<label for="computeradd" class="col-form-label">Computer:</label>
|
||||
<input name="computeradd" id="computeradd" type="text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Delete Computer To Database -->
|
||||
<div class="modal fade" id="modalDel" tabindex="-1" role="dialog" aria-labelledby="modalDelLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form method="get" action="/admin/delcomputer">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modalDelLabel">Delete computer to Database. NOT REVERSIBLE</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<p>Delete computer from database. NOT REVERSIBLE<br>
|
||||
<label for="computerdel" class="col-form-label">Computer:</label>
|
||||
<select class="form-control" name="computerdel" id="computerdel">
|
||||
{% for item in tablecomputers %} {#['ID_C','Name',.....]#}
|
||||
<option value="{{item.0}}">{{item.1}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-danger">DELETE</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Computers</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Computer</th>
|
||||
<th>Operating System</th>
|
||||
<th>Groups</th>
|
||||
<th>CPU</th>
|
||||
<th>RAM (RAMUsed/RAM) Mb</th>
|
||||
<th>HDD</th>
|
||||
<th>Last ping</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="8"><a class="btn btn-outline-success btn-sm" data-toggle="modal" data-target="#modalAdd">Add computer to database</a></td>
|
||||
</tr>
|
||||
{% for item in tablecomputers %} {#['ID_C','Name','RAM','CPUName','SOVersion','SOCaption','HDD','LastConnection','RamFree','GroupsNames']#}
|
||||
<tr>
|
||||
<td>{{item.0}}</td>
|
||||
<td>{{item.1}}</td>
|
||||
<td>{{item.5}} {{item.4}}</td>
|
||||
<td width='200px'>
|
||||
{% for x in item.9 %}
|
||||
{{x.0}},
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>{{item.3}}</td>
|
||||
<td>{{item.2|int - item.8|int}}/{{item.2}}</td>
|
||||
<td>
|
||||
{% for x in item.6 %}
|
||||
{{x.Volume}}({{x.FreeSpace}}/{{x.Capacity}} GB)<br>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<td>{{item.7}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td colspan="8"><a class="btn btn-outline-danger btn-sm" data-toggle="modal" data-target="#modalDel">Delete computer to database</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
84
admin/templates/baseadmin.tmpl
Normal file
84
admin/templates/baseadmin.tmpl
Normal file
@@ -0,0 +1,84 @@
|
||||
{# -*- coding: utf-8 -*- #}
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<!--<link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">-->
|
||||
|
||||
<title>{{title}} - Powerful Computer Manager</title>
|
||||
|
||||
<link rel="canonical" href="index.html">
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
|
||||
|
||||
<!-- Custom styles for this template -->
|
||||
<link href="{{ url_for('static', filename='css/dashboard.css') }}" rel="stylesheet">
|
||||
|
||||
<!-- Jquery JS -->
|
||||
<script src="{{ url_for('static', filename='js/jquery-3.2.1.slim.min.js') }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
|
||||
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">Company name</a>
|
||||
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
|
||||
<ul class="navbar-nav px-3">
|
||||
<li class="nav-item text-nowrap">
|
||||
<a class="nav-link" href="#">Sign out</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<nav class="col-md-2 d-none d-md-block bg-light sidebar">
|
||||
<div class="sidebar-sticky pt-4">
|
||||
<ul class="nav flex-column pt-4">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.path == "/admin/" or request.path == "/admin" %}active{% endif %}" href="/admin">
|
||||
<span data-feather="home"></span>
|
||||
Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.path == "/admin/groups" or request.path == "/admin/group" %}active{% endif %}" href="/admin/groups">
|
||||
<span data-feather="file"></span>
|
||||
Groups
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">{{title}}</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
</div>
|
||||
</div>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap core JavaScript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="{{ url_for('static', filename='js/popper.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script>
|
||||
|
||||
<!-- Icons -->
|
||||
<script src="{{ url_for('static', filename='js/feather-4.24.1.min.js') }}"></script>
|
||||
<script>
|
||||
feather.replace()
|
||||
</script>
|
||||
|
||||
<!-- Graphs -->
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
17
admin/templates/login.tmpl
Normal file
17
admin/templates/login.tmpl
Normal file
@@ -0,0 +1,17 @@
|
||||
{# -*- coding: utf-8 -*- #}
|
||||
{% extends 'baseadmin.tmpl' %}
|
||||
{% block content %}
|
||||
<h2>Login</h2>
|
||||
<form action="/login" method="POST">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<tr>
|
||||
<td>Password<input type="password" name="password" id="password" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><button type="submit">Login</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
304
admin/templates/test.html
Normal file
304
admin/templates/test.html
Normal file
@@ -0,0 +1,304 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">
|
||||
|
||||
<title>Dashboard Template for Bootstrap</title>
|
||||
|
||||
<link rel="canonical" href="index.html">
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link href="../../admin/assets/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Custom styles for this template -->
|
||||
<link href="../../admin/assets/css/dashboard.css" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
|
||||
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="#">Company name</a>
|
||||
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
|
||||
<ul class="navbar-nav px-3">
|
||||
<li class="nav-item text-nowrap">
|
||||
<a class="nav-link" href="#">Sign out</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<nav class="col-md-2 d-none d-md-block bg-light sidebar">
|
||||
<div class="sidebar-sticky">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#">
|
||||
<span data-feather="home"></span>
|
||||
Dashboard <span class="sr-only">(current)</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<span data-feather="file"></span>
|
||||
Orders
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<span data-feather="shopping-cart"></span>
|
||||
Products
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<span data-feather="users"></span>
|
||||
Customers
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<span data-feather="bar-chart-2"></span>
|
||||
Reports
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<span data-feather="layers"></span>
|
||||
Integrations
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||
<span>Saved reports</span>
|
||||
<a class="d-flex align-items-center text-muted" href="#">
|
||||
<span data-feather="plus-circle"></span>
|
||||
</a>
|
||||
</h6>
|
||||
<ul class="nav flex-column mb-2">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<span data-feather="file-text"></span>
|
||||
Current month
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<span data-feather="file-text"></span>
|
||||
Last quarter
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<span data-feather="file-text"></span>
|
||||
Social engagement
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">
|
||||
<span data-feather="file-text"></span>
|
||||
Year-end sale
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Dashboard</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<div class="btn-group mr-2">
|
||||
<button class="btn btn-sm btn-outline-secondary">Share</button>
|
||||
<button class="btn btn-sm btn-outline-secondary">Export</button>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-outline-secondary dropdown-toggle">
|
||||
<span data-feather="calendar"></span>
|
||||
This week
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas class="my-4" id="myChart" width="900" height="380"></canvas>
|
||||
|
||||
<h2>Section title</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Header</th>
|
||||
<th>Header</th>
|
||||
<th>Header</th>
|
||||
<th>Header</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1,001</td>
|
||||
<td>Lorem</td>
|
||||
<td>ipsum</td>
|
||||
<td>dolor</td>
|
||||
<td>sit</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,002</td>
|
||||
<td>amet</td>
|
||||
<td>consectetur</td>
|
||||
<td>adipiscing</td>
|
||||
<td>elit</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,003</td>
|
||||
<td>Integer</td>
|
||||
<td>nec</td>
|
||||
<td>odio</td>
|
||||
<td>Praesent</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,003</td>
|
||||
<td>libero</td>
|
||||
<td>Sed</td>
|
||||
<td>cursus</td>
|
||||
<td>ante</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,004</td>
|
||||
<td>dapibus</td>
|
||||
<td>diam</td>
|
||||
<td>Sed</td>
|
||||
<td>nisi</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,005</td>
|
||||
<td>Nulla</td>
|
||||
<td>quis</td>
|
||||
<td>sem</td>
|
||||
<td>at</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,006</td>
|
||||
<td>nibh</td>
|
||||
<td>elementum</td>
|
||||
<td>imperdiet</td>
|
||||
<td>Duis</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,007</td>
|
||||
<td>sagittis</td>
|
||||
<td>ipsum</td>
|
||||
<td>Praesent</td>
|
||||
<td>mauris</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,008</td>
|
||||
<td>Fusce</td>
|
||||
<td>nec</td>
|
||||
<td>tellus</td>
|
||||
<td>sed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,009</td>
|
||||
<td>augue</td>
|
||||
<td>semper</td>
|
||||
<td>porta</td>
|
||||
<td>Mauris</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,010</td>
|
||||
<td>massa</td>
|
||||
<td>Vestibulum</td>
|
||||
<td>lacinia</td>
|
||||
<td>arcu</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,011</td>
|
||||
<td>eget</td>
|
||||
<td>nulla</td>
|
||||
<td>Class</td>
|
||||
<td>aptent</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,012</td>
|
||||
<td>taciti</td>
|
||||
<td>sociosqu</td>
|
||||
<td>ad</td>
|
||||
<td>litora</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,013</td>
|
||||
<td>torquent</td>
|
||||
<td>per</td>
|
||||
<td>conubia</td>
|
||||
<td>nostra</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,014</td>
|
||||
<td>per</td>
|
||||
<td>inceptos</td>
|
||||
<td>himenaeos</td>
|
||||
<td>Curabitur</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1,015</td>
|
||||
<td>sodales</td>
|
||||
<td>ligula</td>
|
||||
<td>in</td>
|
||||
<td>libero</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap core JavaScript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="../../admin/assets/js/jquery-3.2.1.slim.min.js"></script>
|
||||
<script src="../../admin/assets/js/popper.min.js"></script>
|
||||
<script src="../../admin/assets/js/bootstrap.min.js"></script>
|
||||
|
||||
<!-- Icons -->
|
||||
<script src="../../admin/assets/js/feather-4.24.1.min.js"></script>
|
||||
<script>
|
||||
feather.replace()
|
||||
</script>
|
||||
|
||||
<!-- Graphs -->
|
||||
<script src="../../admin/assets/js/Chart.min.js"></script>
|
||||
<script>
|
||||
var ctx = document.getElementById("myChart");
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
||||
datasets: [{
|
||||
data: [15339, 21345, 18483, 24003, 23489, 24092, 12034],
|
||||
lineTension: 0,
|
||||
backgroundColor: 'transparent',
|
||||
borderColor: '#007bff',
|
||||
borderWidth: 4,
|
||||
pointBackgroundColor: '#007bff'
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: false
|
||||
}
|
||||
}]
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user