forked from OpenPDU/openpdu
wip
This commit is contained in:
20
source/config.go
Normal file
20
source/config.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readConfig() {
|
||||||
|
viper.SetConfigName("openpdu.yaml") // name of config file (without extension)
|
||||||
|
viper.SetConfigType("yaml")
|
||||||
|
viper.AddConfigPath("/etc/openpdu/") // path to look for the config file in
|
||||||
|
viper.AddConfigPath(".") // optionally look for config in the working directory
|
||||||
|
err := viper.ReadInConfig() // Find and read the config file
|
||||||
|
if err != nil { // Handle errors reading the config file
|
||||||
|
log.Printf("Fatal error config file: %s \n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
viper.SetDefault("hostname", "openpdu")
|
||||||
|
}
|
||||||
196
source/exmain.go
196
source/exmain.go
@@ -1,196 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"gopkg.in/macaron.v1"
|
|
||||||
// "github.com/go-macaron/pongo2"
|
|
||||||
mypongo2 "github.com/flosch/pongo2"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const CFGFILE = "/config/config.json"
|
|
||||||
|
|
||||||
const WEBSITETPLFILE = "/app/website.tpl"
|
|
||||||
const WEBSITENGINXFILE = "/etc/nginx/conf.d/websites.conf"
|
|
||||||
|
|
||||||
const ADMINTPLFILE = "/app/admin.tpl"
|
|
||||||
const ADMINNGINXFILE = "/etc/nginx/conf.d/admin.conf"
|
|
||||||
|
|
||||||
var Config struct {
|
|
||||||
Admin Website `json:"admin"`
|
|
||||||
Websites []Website `json:"websites"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Website struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
Url string `json:"url"`
|
|
||||||
Aliases []string `json:"aliases"`
|
|
||||||
Http Http `json:"http"`
|
|
||||||
Https Https `json:"https"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Http struct {
|
|
||||||
Redirect_to_https bool `json:"redirect_to_https"`
|
|
||||||
Locations []Location `json:"locations"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Https struct {
|
|
||||||
Http2 bool `json:"http2"`
|
|
||||||
Letsencrypt bool `json:"letsencrypt"`
|
|
||||||
Locations []Location `json:"locations"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Location struct {
|
|
||||||
Location string `json:"location"`
|
|
||||||
Destination string `json:"destination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadConfig() {
|
|
||||||
jsonFile, err := os.Open(CFGFILE)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
defer jsonFile.Close()
|
|
||||||
|
|
||||||
jsonParser := json.NewDecoder(jsonFile)
|
|
||||||
if err = jsonParser.Decode(&Config); err != nil {
|
|
||||||
log.Println("Error parsing config file: ", err.Error())
|
|
||||||
}
|
|
||||||
log.Println("Successfully parsed: " + CFGFILE)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func startServer() {
|
|
||||||
m := macaron.Classic()
|
|
||||||
// m.Use(macaron.Static("public")) // static files served by nginx
|
|
||||||
m.Get("/", myHandler)
|
|
||||||
|
|
||||||
log.Println("Server is running...")
|
|
||||||
log.Println(http.ListenAndServe("0.0.0.0:4000", m))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
loadConfig()
|
|
||||||
writeAdminTemplate()
|
|
||||||
writeTemplate()
|
|
||||||
nginxReloadConfig()
|
|
||||||
startServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func nginxReloadConfig() {
|
|
||||||
// TODO: check why this is always in error but it's working...
|
|
||||||
_, err := exec.Command("/usr/sbin/nginx", "-s", "reload").Output()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Successfully reloaded nginx config")
|
|
||||||
} else {
|
|
||||||
log.Printf("could not reload nginx: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeTemplate() {
|
|
||||||
t, err := mypongo2.FromFile(WEBSITETPLFILE)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("could not render: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Create(WEBSITENGINXFILE)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("cannot open: %s", WEBSITENGINXFILE)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
for _, v := range Config.Websites {
|
|
||||||
|
|
||||||
var http_locations []map[string]string
|
|
||||||
var https_locations []map[string]string
|
|
||||||
|
|
||||||
for _, s := range v.Http.Locations {
|
|
||||||
loc := map[string]string{
|
|
||||||
"location": s.Location,
|
|
||||||
"destination": s.Destination,
|
|
||||||
}
|
|
||||||
http_locations = append(http_locations, loc)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range v.Https.Locations {
|
|
||||||
loc := map[string]string{
|
|
||||||
"location": s.Location,
|
|
||||||
"destination": s.Destination,
|
|
||||||
}
|
|
||||||
https_locations = append(https_locations, loc)
|
|
||||||
}
|
|
||||||
|
|
||||||
data := mypongo2.Context{
|
|
||||||
"url": v.Url,
|
|
||||||
"name": v.Name,
|
|
||||||
"http2": v.Https.Http2,
|
|
||||||
"aliases": v.Aliases,
|
|
||||||
"http_redirect_to_https": v.Http.Redirect_to_https,
|
|
||||||
"https_locations": https_locations,
|
|
||||||
"http_locations": http_locations,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := t.ExecuteWriter(data, f); err != nil {
|
|
||||||
log.Printf("could not execute: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Successfully created: %s", WEBSITENGINXFILE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeAdminTemplate() {
|
|
||||||
t, err := mypongo2.FromFile(ADMINTPLFILE)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("could not render: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Create(ADMINNGINXFILE)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("cannot open: %s", ADMINNGINXFILE)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
data := mypongo2.Context{
|
|
||||||
"url": Config.Admin.Url,
|
|
||||||
"http2": Config.Admin.Https.Http2,
|
|
||||||
"http_redirect_to_https": Config.Admin.Http.Redirect_to_https,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := t.ExecuteWriter(data, f); err != nil {
|
|
||||||
log.Printf("could not execute: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Successfully created: %s", ADMINNGINXFILE)
|
|
||||||
}
|
|
||||||
|
|
||||||
func myHandler(ctx *macaron.Context) string {
|
|
||||||
return "The request path is: " + ctx.Req.RequestURI
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
mypongo2.RegisterFilter("filterdomaindots", PongoFilterDomainDots)
|
|
||||||
}
|
|
||||||
|
|
||||||
func PongoFilterDomainDots(in *mypongo2.Value, param *mypongo2.Value) (out *mypongo2.Value, err *mypongo2.Error) {
|
|
||||||
if !in.IsString() {
|
|
||||||
return nil, &mypongo2.Error{
|
|
||||||
Sender: "you should use only strings",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s := in.String()
|
|
||||||
s = strings.Replace(s, ".", "\\.", -1)
|
|
||||||
|
|
||||||
return mypongo2.AsValue(s), nil
|
|
||||||
}
|
|
||||||
85
source/i2c.go
Normal file
85
source/i2c.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"periph.io/x/periph/conn/i2c"
|
||||||
|
"periph.io/x/periph/conn/i2c/i2creg"
|
||||||
|
"periph.io/x/periph/host"
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2CBoard bla
|
||||||
|
type I2CBoard struct {
|
||||||
|
i2cdev i2c.Dev
|
||||||
|
channels uint
|
||||||
|
data []byte
|
||||||
|
inverted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// MyBoard bla
|
||||||
|
var MyBoard = I2CBoard{
|
||||||
|
channels: 8,
|
||||||
|
inverted: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b I2CBoard) channelStatus(ch uint) (bool, error) {
|
||||||
|
if b.channels <= 0 {
|
||||||
|
return false, errors.New("Board without channels")
|
||||||
|
}
|
||||||
|
if ch >= b.channels {
|
||||||
|
return false, errors.New("Invalid channel")
|
||||||
|
}
|
||||||
|
write := []byte{0x0A}
|
||||||
|
b.data = make([]byte, 2)
|
||||||
|
err := b.i2cdev.Tx(write, b.data)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
byteToConsider := ch / b.channels
|
||||||
|
value := (b.data[byteToConsider] >> ch & 1) == 1
|
||||||
|
if b.inverted {
|
||||||
|
value = !value
|
||||||
|
}
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initI2C() {
|
||||||
|
// Make sure periph is initialized.
|
||||||
|
if _, err := host.Init(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use i2creg I²C bus registry to find the first available I²C bus.
|
||||||
|
mybus, err := i2creg.Open("/dev/i2c-0")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// defer mybus.Close()
|
||||||
|
|
||||||
|
// bus 0
|
||||||
|
// Dev is a valid conn.Conn.
|
||||||
|
mydevice := &i2c.Dev{Addr: 0x27, Bus: mybus}
|
||||||
|
|
||||||
|
// Send a command 0x10 and expect a 5 bytes reply.
|
||||||
|
// write := []byte{0x10}
|
||||||
|
write := []byte{0x0}
|
||||||
|
// read := make([]byte, 5)
|
||||||
|
// if err := d.Tx(write, read); err != nil {
|
||||||
|
if _, err := mydevice.Write(write); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
MyBoard.i2cdev = *mydevice
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var i uint
|
||||||
|
for i = 0; i < 8; i++ {
|
||||||
|
v, err := MyBoard.channelStatus(i)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
log.Printf("Channel %d status: %v", i, v)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
110
source/main.go
110
source/main.go
@@ -2,126 +2,28 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
"github.com/go-macaron/pongo2"
|
|
||||||
|
|
||||||
"gopkg.in/macaron.v1"
|
|
||||||
"net/http"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
// "periph.io/x/periph"
|
// "periph.io/x/periph"
|
||||||
"periph.io/x/periph/host"
|
|
||||||
"periph.io/x/periph/conn/i2c"
|
|
||||||
"periph.io/x/periph/conn/i2c/i2creg"
|
|
||||||
"time"
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Dictionary aaa
|
||||||
type Dictionary map[string]interface{}
|
type Dictionary map[string]interface{}
|
||||||
|
|
||||||
func readConfig() {
|
|
||||||
viper.SetConfigName("openpdu.yaml") // name of config file (without extension)
|
|
||||||
viper.SetConfigType("yaml")
|
|
||||||
viper.AddConfigPath("/etc/openpdu/") // path to look for the config file in
|
|
||||||
viper.AddConfigPath(".") // optionally look for config in the working directory
|
|
||||||
err := viper.ReadInConfig() // Find and read the config file
|
|
||||||
if err != nil { // Handle errors reading the config file
|
|
||||||
log.Printf("Fatal error config file: %s \n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
viper.SetDefault("hostname","openpdu")
|
|
||||||
}
|
|
||||||
|
|
||||||
func initI2C() {
|
|
||||||
// Make sure periph is initialized.
|
|
||||||
if _, err := host.Init(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use i2creg I²C bus registry to find the first available I²C bus.
|
|
||||||
b, err := i2creg.Open("/dev/i2c-0")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer b.Close()
|
|
||||||
|
|
||||||
// bus 0
|
|
||||||
// Dev is a valid conn.Conn.
|
|
||||||
d := &i2c.Dev{Addr: 0x27, Bus: b}
|
|
||||||
|
|
||||||
// Send a command 0x10 and expect a 5 bytes reply.
|
|
||||||
// write := []byte{0x10}
|
|
||||||
write := []byte{0x0}
|
|
||||||
// read := make([]byte, 5)
|
|
||||||
// if err := d.Tx(write, read); err != nil {
|
|
||||||
if _, err := d.Write(write); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
|
||||||
|
|
||||||
write := []byte{0x0A}
|
|
||||||
read := make([]byte, 5)
|
|
||||||
if err := d.Tx(write, read); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
log.Printf("%v\n", read)
|
|
||||||
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// func myHandler(ctx *macaron.Context) string {
|
|
||||||
// ctx.Data["name"] = "jeremy"
|
|
||||||
// ctx.HTML(200, "hello") // 200 is the response code.
|
|
||||||
|
|
||||||
// return "The request path is: " + ctx.Req.RequestURI
|
|
||||||
// }
|
|
||||||
|
|
||||||
func startServer() {
|
|
||||||
m := macaron.Classic()
|
|
||||||
m.Use(pongo2.Pongoer())
|
|
||||||
m.Use(macaron.Static("static"))
|
|
||||||
// m.Get("/", myHandler)
|
|
||||||
|
|
||||||
m.Get("/", func(ctx *macaron.Context) {
|
|
||||||
ctx.Data["pluglist"] = []Dictionary{
|
|
||||||
{"id": 1, "description": "p1"},
|
|
||||||
{"id": 2, "description": "p2"},
|
|
||||||
{"id": 3, "description": "p3"},
|
|
||||||
{"id": 4, "description": "p4"},
|
|
||||||
{"id": 5, "description": "p5"},
|
|
||||||
{"id": 6, "description": "p6"},
|
|
||||||
{"id": 7, "description": "p7"},
|
|
||||||
{"id": 8, "description": "p8"},
|
|
||||||
}
|
|
||||||
ctx.HTML(200, "status") // 200 is the response code.
|
|
||||||
})
|
|
||||||
|
|
||||||
m.Get("/boards", func(ctx *macaron.Context) {
|
|
||||||
ctx.HTML(200, "boards") // 200 is the response code.
|
|
||||||
})
|
|
||||||
|
|
||||||
log.Println("Server is running...")
|
|
||||||
log.Println(http.ListenAndServe("0.0.0.0:4000", m))
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
readConfig()
|
readConfig()
|
||||||
|
|
||||||
nam := viper.Get("name")
|
nam := viper.Get("hostname")
|
||||||
log.Printf("name: %v\n", nam)
|
log.Printf("hostname: %v\n", nam)
|
||||||
|
|
||||||
|
|
||||||
initI2C()
|
initI2C()
|
||||||
|
|
||||||
startServer()
|
startServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// https://github.com/ColorlibHQ/AdminLTE/archive/v2.4.17.tar.gz
|
// https://github.com/ColorlibHQ/AdminLTE/archive/v2.4.17.tar.gz
|
||||||
|
|
||||||
/* TODO
|
/* TODO
|
||||||
|
|||||||
91
source/webui.go
Normal file
91
source/webui.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-macaron/pongo2"
|
||||||
|
"gopkg.in/macaron.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func startServer() {
|
||||||
|
m := macaron.Classic()
|
||||||
|
m.Use(pongo2.Pongoer())
|
||||||
|
m.Use(macaron.Static("static"))
|
||||||
|
// m.Get("/", myHandler)
|
||||||
|
|
||||||
|
m.Get("/", func(ctx *macaron.Context) {
|
||||||
|
ctx.Data["pluglist"] = []Dictionary{
|
||||||
|
{"id": 1, "description": "p1"},
|
||||||
|
{"id": 2, "description": "p2"},
|
||||||
|
{"id": 3, "description": "p3"},
|
||||||
|
{"id": 4, "description": "p4"},
|
||||||
|
{"id": 5, "description": "p5"},
|
||||||
|
{"id": 6, "description": "p6"},
|
||||||
|
{"id": 7, "description": "p7"},
|
||||||
|
{"id": 8, "description": "p8"},
|
||||||
|
}
|
||||||
|
ctx.HTML(200, "status") // 200 is the response code.
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Get("/json/status", func(ctx *macaron.Context) {
|
||||||
|
|
||||||
|
p0, err := MyBoard.channelStatus(0)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p1, err := MyBoard.channelStatus(1)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p2, err := MyBoard.channelStatus(2)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p3, err := MyBoard.channelStatus(3)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p4, err := MyBoard.channelStatus(4)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p5, err := MyBoard.channelStatus(5)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p6, err := MyBoard.channelStatus(6)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p7, err := MyBoard.channelStatus(7)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 = p1 && p2 && p3 && p4 && p5 && p6 && p7
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, Dictionary{
|
||||||
|
"data": [][]string{
|
||||||
|
{"0", "p0", fmt.Sprint(p0)},
|
||||||
|
{"1", "p1", fmt.Sprint(p1)},
|
||||||
|
{"2", "p2", fmt.Sprint(p2)},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
m.Get("/boards", func(ctx *macaron.Context) {
|
||||||
|
ctx.HTML(200, "boards") // 200 is the response code.
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Println("Server is running...")
|
||||||
|
log.Println(http.ListenAndServe("0.0.0.0:4000", m))
|
||||||
|
}
|
||||||
42
static/googlefonts/fonts.css
Normal file
42
static/googlefonts/fonts.css
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Source Sans Pro Light Italic'), local('SourceSansPro-LightItalic'), url(source-sans-pro-v13-latin-300italic.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Source Sans Pro Italic'), local('SourceSansPro-Italic'), url(source-sans-pro-v13-latin-italic.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
src: local('Source Sans Pro SemiBold Italic'), local('SourceSansPro-SemiBoldItalic'), url(source-sans-pro-v13-latin-600italic.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(source-sans-pro-v13-latin-300.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Source Sans Pro Regular'), local('SourceSansPro-Regular'), url(source-sans-pro-v13-latin-regular.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(source-sans-pro-v13-latin-600.ttf) format('truetype');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Source Sans Pro';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), url(source-sans-pro-v13-latin-700.ttf) format('truetype');
|
||||||
|
}
|
||||||
BIN
static/googlefonts/source-sans-pro-v13-latin-300.ttf
Normal file
BIN
static/googlefonts/source-sans-pro-v13-latin-300.ttf
Normal file
Binary file not shown.
BIN
static/googlefonts/source-sans-pro-v13-latin-300italic.ttf
Normal file
BIN
static/googlefonts/source-sans-pro-v13-latin-300italic.ttf
Normal file
Binary file not shown.
BIN
static/googlefonts/source-sans-pro-v13-latin-600.ttf
Normal file
BIN
static/googlefonts/source-sans-pro-v13-latin-600.ttf
Normal file
Binary file not shown.
BIN
static/googlefonts/source-sans-pro-v13-latin-600italic.ttf
Normal file
BIN
static/googlefonts/source-sans-pro-v13-latin-600italic.ttf
Normal file
Binary file not shown.
BIN
static/googlefonts/source-sans-pro-v13-latin-700.ttf
Normal file
BIN
static/googlefonts/source-sans-pro-v13-latin-700.ttf
Normal file
Binary file not shown.
BIN
static/googlefonts/source-sans-pro-v13-latin-700italic.ttf
Normal file
BIN
static/googlefonts/source-sans-pro-v13-latin-700italic.ttf
Normal file
Binary file not shown.
BIN
static/googlefonts/source-sans-pro-v13-latin-italic.ttf
Normal file
BIN
static/googlefonts/source-sans-pro-v13-latin-italic.ttf
Normal file
Binary file not shown.
BIN
static/googlefonts/source-sans-pro-v13-latin-regular.ttf
Normal file
BIN
static/googlefonts/source-sans-pro-v13-latin-regular.ttf
Normal file
Binary file not shown.
@@ -1,52 +1,64 @@
|
|||||||
{% with pagetitle="Boards configuration" pageselected="boards" %}
|
<!DOCTYPE html>
|
||||||
{% include "common/layout-before.html" %}
|
<html>
|
||||||
|
<head>
|
||||||
|
{% include "common/common-head.html" %}
|
||||||
|
</head>
|
||||||
|
<body class="hold-transition skin-blue sidebar-mini">
|
||||||
|
<div class="wrapper">
|
||||||
|
|
||||||
|
{% include "common/page-header.html" %}
|
||||||
|
{% with pageselected="boards" %}
|
||||||
|
{% include "common/sidebar-menu.html" %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
<!-- Content Wrapper. Contains page content -->
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<!-- Content Header (Page header) -->
|
||||||
|
<section class="content-header">
|
||||||
|
<h1>
|
||||||
|
Boards configuration
|
||||||
|
</h1>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Main content -->
|
||||||
|
<section class="content">
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
|
<div class="box-header">
|
||||||
|
<h3 class="box-title">Hover Data Table</h3>
|
||||||
|
</div>
|
||||||
<!-- /.box-header -->
|
<!-- /.box-header -->
|
||||||
<div class="box-body no-padding">
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<tr>
|
|
||||||
<th style="width: 15px">#</th>
|
|
||||||
<th>Plug name</th>
|
|
||||||
<th style="width: 30px">Status</th>
|
|
||||||
<th>Power load</th>
|
|
||||||
<th style="width: 100px">Command</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{% for plug in pluglist %}
|
<div class="box-body">
|
||||||
|
<table id="example2" class="table table-bordered table-hover">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ plug.id }}</td>
|
<th>Rendering engine</th>
|
||||||
<td>{{ plug.description }}</td>
|
<th>Browser</th>
|
||||||
<td>off</td>
|
<th>Platform(s)</th>
|
||||||
<td>
|
<th>Engine version</th>
|
||||||
<div class="progress progress-xs">
|
<th>CSS grade</th>
|
||||||
<div class="progress-bar progress-bar-danger" style="width: 55%"></div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<button type="button" class="btn btn-info">Toggle</button>
|
|
||||||
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown">
|
|
||||||
<span class="caret"></span>
|
|
||||||
<span class="sr-only">Toggle Dropdown</span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
|
||||||
<li><a href="#">On</a></li>
|
|
||||||
<li><a href="#">Off</a></li>
|
|
||||||
<li class="divider"></li>
|
|
||||||
<li><a href="#">Edit</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th>Rendering engine</th>
|
||||||
|
<th>Browser</th>
|
||||||
|
<th>Platform(s)</th>
|
||||||
|
<th>Engine version</th>
|
||||||
|
<th>CSS grade</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.box-body -->
|
<!-- /.box-body -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<!-- /.box -->
|
<!-- /.box -->
|
||||||
</div>
|
</div>
|
||||||
@@ -54,5 +66,39 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
<!-- /.row -->
|
||||||
|
|
||||||
{% include "common/layout-after.html" %}
|
|
||||||
{% endwith %}
|
|
||||||
|
</section>
|
||||||
|
<!-- /.content -->
|
||||||
|
</div>
|
||||||
|
<!-- /.content-wrapper -->
|
||||||
|
|
||||||
|
{% include "common/footer.html" %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- ./wrapper -->
|
||||||
|
|
||||||
|
{% include "common/common-js.html" %}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- DataTables -->
|
||||||
|
<script src="../../bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
|
||||||
|
<script src="../../bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
$('#example2').DataTable({
|
||||||
|
'paging' : true,
|
||||||
|
'lengthChange': true,
|
||||||
|
'searching' : true,
|
||||||
|
'ordering' : true,
|
||||||
|
'info' : true,
|
||||||
|
'autoWidth' : true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
26
templates/common/common-head.html
Normal file
26
templates/common/common-head.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>OpenPDU</title>
|
||||||
|
<!-- Tell the browser to be responsive to screen width -->
|
||||||
|
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||||
|
<!-- Bootstrap 3.3.7 -->
|
||||||
|
<link rel="stylesheet" href="../../bower_components/bootstrap/dist/css/bootstrap.min.css">
|
||||||
|
<!-- Font Awesome -->
|
||||||
|
<link rel="stylesheet" href="../../bower_components/font-awesome/css/font-awesome.min.css">
|
||||||
|
<!-- Ionicons -->
|
||||||
|
<link rel="stylesheet" href="../../bower_components/Ionicons/css/ionicons.min.css">
|
||||||
|
<!-- Theme style -->
|
||||||
|
<link rel="stylesheet" href="adminlte/css/AdminLTE.min.css">
|
||||||
|
<!-- AdminLTE Skins. Choose a skin from the css/skins
|
||||||
|
folder instead of downloading all of them to reduce the load. -->
|
||||||
|
<link rel="stylesheet" href="adminlte/css/skins/_all-skins.min.css">
|
||||||
|
|
||||||
|
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||||
|
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||||
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
<!-- Google Font -->
|
||||||
|
<link rel="stylesheet" href="../../googlefonts/fonts.css">
|
||||||
@@ -1,15 +1,3 @@
|
|||||||
</section>
|
|
||||||
<!-- /.content -->
|
|
||||||
</div>
|
|
||||||
<!-- /.content-wrapper -->
|
|
||||||
|
|
||||||
{% include "common/footer.html" %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<!-- ./wrapper -->
|
|
||||||
|
|
||||||
<!-- jQuery 3 -->
|
<!-- jQuery 3 -->
|
||||||
<script src="../../bower_components/jquery/dist/jquery.min.js"></script>
|
<script src="../../bower_components/jquery/dist/jquery.min.js"></script>
|
||||||
<!-- Bootstrap 3.3.7 -->
|
<!-- Bootstrap 3.3.7 -->
|
||||||
@@ -20,6 +8,3 @@
|
|||||||
<script src="../../bower_components/fastclick/lib/fastclick.js"></script>
|
<script src="../../bower_components/fastclick/lib/fastclick.js"></script>
|
||||||
<!-- AdminLTE App -->
|
<!-- AdminLTE App -->
|
||||||
<script src="adminlte/js/adminlte.min.js"></script>
|
<script src="adminlte/js/adminlte.min.js"></script>
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
||||||
<title>OpenPDU</title>
|
|
||||||
<!-- Tell the browser to be responsive to screen width -->
|
|
||||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
|
||||||
<!-- Bootstrap 3.3.7 -->
|
|
||||||
<link rel="stylesheet" href="../../bower_components/bootstrap/dist/css/bootstrap.min.css">
|
|
||||||
<!-- Font Awesome -->
|
|
||||||
<link rel="stylesheet" href="../../bower_components/font-awesome/css/font-awesome.min.css">
|
|
||||||
<!-- Ionicons -->
|
|
||||||
<link rel="stylesheet" href="../../bower_components/Ionicons/css/ionicons.min.css">
|
|
||||||
<!-- Theme style -->
|
|
||||||
<link rel="stylesheet" href="adminlte/css/AdminLTE.min.css">
|
|
||||||
<!-- AdminLTE Skins. Choose a skin from the css/skins
|
|
||||||
folder instead of downloading all of them to reduce the load. -->
|
|
||||||
<link rel="stylesheet" href="adminlte/css/skins/_all-skins.min.css">
|
|
||||||
|
|
||||||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
|
||||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
|
||||||
<!--[if lt IE 9]>
|
|
||||||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
|
|
||||||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
|
||||||
<![endif]-->
|
|
||||||
|
|
||||||
<!-- Google Font -->
|
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
|
|
||||||
</head>
|
|
||||||
<body class="hold-transition skin-blue sidebar-mini">
|
|
||||||
<div class="wrapper">
|
|
||||||
|
|
||||||
<header class="main-header">
|
|
||||||
<!-- Logo -->
|
|
||||||
<a href="../../index2.html" class="logo">
|
|
||||||
<!-- mini logo for sidebar mini 50x50 pixels -->
|
|
||||||
<span class="logo-mini">O<b>P</b></span>
|
|
||||||
<!-- logo for regular state and mobile devices -->
|
|
||||||
<span class="logo-lg">Open<b>PDU</b></span>
|
|
||||||
</a>
|
|
||||||
<!-- Header Navbar: style can be found in header.less -->
|
|
||||||
<nav class="navbar navbar-static-top">
|
|
||||||
<!-- Sidebar toggle button-->
|
|
||||||
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
|
|
||||||
<span class="sr-only">Toggle navigation</span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
<span class="icon-bar"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="navbar-custom-menu">
|
|
||||||
<ul class="nav navbar-nav">
|
|
||||||
<!-- User Account: style can be found in dropdown.less -->
|
|
||||||
<li class="dropdown user user-menu">
|
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
|
||||||
<span class="hidden-xs">Admin</span>
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<!-- Menu Footer-->
|
|
||||||
<li class="user-footer">
|
|
||||||
<a href="#" class="btn btn-default btn-flat">Change password</a>
|
|
||||||
</li>
|
|
||||||
<li class="user-footer">
|
|
||||||
<a href="#" class="btn btn-default btn-flat">Sign out</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{% include "common/sidebar-menu.html" %}
|
|
||||||
|
|
||||||
<!-- Content Wrapper. Contains page content -->
|
|
||||||
<div class="content-wrapper">
|
|
||||||
<!-- Content Header (Page header) -->
|
|
||||||
<section class="content-header">
|
|
||||||
<h1>
|
|
||||||
{{ pagetitle }}
|
|
||||||
</h1>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- Main content -->
|
|
||||||
<section class="content">
|
|
||||||
|
|
||||||
39
templates/common/page-header.html
Normal file
39
templates/common/page-header.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<header class="main-header">
|
||||||
|
<!-- Logo -->
|
||||||
|
<a href="../../index2.html" class="logo">
|
||||||
|
<!-- mini logo for sidebar mini 50x50 pixels -->
|
||||||
|
<span class="logo-mini">O<b>P</b></span>
|
||||||
|
<!-- logo for regular state and mobile devices -->
|
||||||
|
<span class="logo-lg">Open<b>PDU</b></span>
|
||||||
|
</a>
|
||||||
|
<!-- Header Navbar: style can be found in header.less -->
|
||||||
|
<nav class="navbar navbar-static-top">
|
||||||
|
<!-- Sidebar toggle button-->
|
||||||
|
<a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
|
||||||
|
<span class="sr-only">Toggle navigation</span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
<span class="icon-bar"></span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="navbar-custom-menu">
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<!-- User Account: style can be found in dropdown.less -->
|
||||||
|
<li class="dropdown user user-menu">
|
||||||
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||||
|
<span class="hidden-xs">Admin</span>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<!-- Menu Footer-->
|
||||||
|
<li class="user-footer">
|
||||||
|
<a href="#" class="btn btn-default btn-flat">Change password</a>
|
||||||
|
</li>
|
||||||
|
<li class="user-footer">
|
||||||
|
<a href="#" class="btn btn-default btn-flat">Sign out</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
@@ -41,11 +41,6 @@
|
|||||||
<li><a href="/settings/restore"><i class="fa fa-circle-o"></i> restore</a></li>
|
<li><a href="/settings/restore"><i class="fa fa-circle-o"></i> restore</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<a href="/logs">
|
|
||||||
<i class="fa fa-file-text-o"></i> <span>Logs</span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<!-- /.sidebar -->
|
<!-- /.sidebar -->
|
||||||
|
|||||||
@@ -1,49 +1,47 @@
|
|||||||
{% with pagetitle="Outlet status" pageselected="status" %}
|
<!DOCTYPE html>
|
||||||
{% include "common/layout-before.html" %}
|
<html>
|
||||||
|
<head>
|
||||||
|
{% include "common/common-head.html" %}
|
||||||
|
</head>
|
||||||
|
<body class="hold-transition skin-blue sidebar-mini">
|
||||||
|
<div class="wrapper">
|
||||||
|
|
||||||
|
{% include "common/page-header.html" %}
|
||||||
|
{% with pageselected="status" %}
|
||||||
|
{% include "common/sidebar-menu.html" %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
<!-- Content Wrapper. Contains page content -->
|
||||||
|
<div class="content-wrapper">
|
||||||
|
<!-- Content Header (Page header) -->
|
||||||
|
<section class="content-header">
|
||||||
|
<h1>
|
||||||
|
Outlet status
|
||||||
|
</h1>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- Main content -->
|
||||||
|
<section class="content">
|
||||||
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
|
|
||||||
<!-- /.box-header -->
|
<div class="box-body">
|
||||||
<div class="box-body no-padding">
|
<table id="example2" class="table table-bordered table-hover">
|
||||||
<table class="table table-condensed">
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width: 15px">#</th>
|
<th style="width: 15px">#</th>
|
||||||
<th>Plug name</th>
|
<th>Plug name</th>
|
||||||
<th style="width: 30px">Status</th>
|
<th style="width: 30px">Status</th>
|
||||||
<th>Power load</th>
|
<th style="width: 300px">Power load</th>
|
||||||
<th style="width: 100px">Command</th>
|
<th style="width: 150px">Command</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
{% for plug in pluglist %}
|
</tbody>
|
||||||
<tr>
|
|
||||||
<td>{{ plug.id }}</td>
|
|
||||||
<td>{{ plug.description }}</td>
|
|
||||||
<td>off</td>
|
|
||||||
<td>
|
|
||||||
<div class="progress progress-xs">
|
|
||||||
<div class="progress-bar progress-bar-danger" style="width: 55%"></div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div class="btn-group">
|
|
||||||
<button type="button" class="btn btn-info">Toggle</button>
|
|
||||||
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown">
|
|
||||||
<span class="caret"></span>
|
|
||||||
<span class="sr-only">Toggle Dropdown</span>
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" role="menu">
|
|
||||||
<li><a href="#">On</a></li>
|
|
||||||
<li><a href="#">Off</a></li>
|
|
||||||
<li class="divider"></li>
|
|
||||||
<li><a href="#">Edit</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.box-body -->
|
<!-- /.box-body -->
|
||||||
@@ -54,5 +52,67 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
<!-- /.row -->
|
||||||
|
|
||||||
{% include "common/layout-after.html" %}
|
</section>
|
||||||
{% endwith %}
|
<!-- /.content -->
|
||||||
|
</div>
|
||||||
|
<!-- /.content-wrapper -->
|
||||||
|
|
||||||
|
{% include "common/footer.html" %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- ./wrapper -->
|
||||||
|
|
||||||
|
{% include "common/common-js.html" %}
|
||||||
|
|
||||||
|
<!-- DataTables -->
|
||||||
|
<script src="../../bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
|
||||||
|
<script src="../../bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
var btnhtml = `<div class="btn-group">
|
||||||
|
<button type="button" class="btn btn-info" script="toggle">Toggle</button>
|
||||||
|
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown">
|
||||||
|
<span class="caret"></span>
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu" role="menu">
|
||||||
|
<li><a href="#">On</a></li>
|
||||||
|
<li><a href="#">Off</a></li>
|
||||||
|
<li class="divider"></li>
|
||||||
|
<li><a href="#">Edit</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
|
||||||
|
$('#example2').DataTable({
|
||||||
|
'ajax': '/json/status',
|
||||||
|
"columns" : [
|
||||||
|
{ "data" : 0 },
|
||||||
|
{ "data" : 1 },
|
||||||
|
{ "data" : 2 },
|
||||||
|
{ "data" : null, "defaultContent": "<div class='progress progress-xs'><div class='progress-bar progress-bar-danger' style='width: 55%'></div></div>"},
|
||||||
|
{ "data" : null, "defaultContent":btnhtml }
|
||||||
|
],
|
||||||
|
'paging' : true,
|
||||||
|
'lengthChange': true,
|
||||||
|
'searching' : true,
|
||||||
|
'ordering' : true,
|
||||||
|
'info' : true
|
||||||
|
});
|
||||||
|
|
||||||
|
// fa-toggle-off
|
||||||
|
|
||||||
|
$('#example2 tbody').on( 'click', '[script="toggle"]', function () {
|
||||||
|
alert( 'ciao' );
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
} );
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
Reference in New Issue
Block a user