mirror of
https://github.com/Manuel83/craftbeerpi3
synced 2026-08-09 18:52:40 +02:00
- Login Added. Default Password is „beer“
- Several UI Adjustments - still work in progress - New API Method to add custom JavaScript to CraftBeerPi - Global Action Buttons added - Register new Web Modules for complete custom UI
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import time
|
||||
from flask_classy import route
|
||||
from flask_login import login_required
|
||||
|
||||
from modules.core.db import DBModel
|
||||
from modules.core.core import cbpi
|
||||
from modules.core.baseview import BaseView
|
||||
@@ -21,6 +23,7 @@ class ActorView(BaseView):
|
||||
def _post_put_callback(self, m):
|
||||
self.api.actor.init_one(m.id)
|
||||
|
||||
@login_required
|
||||
@route("<int:id>/switch/on", methods=["POST"])
|
||||
def on(self, id):
|
||||
"""
|
||||
@@ -42,6 +45,7 @@ class ActorView(BaseView):
|
||||
self.api.actor.on(id)
|
||||
return ('', 204)
|
||||
|
||||
@login_required
|
||||
@route("<int:id>/switch/off", methods=["POST"])
|
||||
def off(self, id):
|
||||
"""
|
||||
@@ -63,6 +67,7 @@ class ActorView(BaseView):
|
||||
self.api.actor.off(id)
|
||||
return ('', 204)
|
||||
|
||||
@login_required
|
||||
@route("<int:id>/power/<int:power>", methods=["POST"])
|
||||
def power(self, id, power):
|
||||
"""
|
||||
@@ -90,6 +95,7 @@ class ActorView(BaseView):
|
||||
self.api.actor.power(id, power)
|
||||
return ('', 204)
|
||||
|
||||
@login_required
|
||||
@route("<int:id>/toggle", methods=["POST"])
|
||||
def toggle(self, id):
|
||||
"""
|
||||
@@ -108,10 +114,7 @@ class ActorView(BaseView):
|
||||
200:
|
||||
description: Actor toggled
|
||||
"""
|
||||
if self.api.cache.get("actors").get(id).state == 0:
|
||||
self.on(id)
|
||||
else:
|
||||
self.off(id)
|
||||
cbpi.actor.toggle(id)
|
||||
return ('', 204)
|
||||
|
||||
def toggleTimeJob(self, id, t):
|
||||
@@ -121,6 +124,7 @@ class ActorView(BaseView):
|
||||
self.api.cache.get("actors").get(int(id)).timer = None
|
||||
self.toggle(int(id))
|
||||
|
||||
@login_required
|
||||
@route("/<id>/toggle/<int:t>", methods=["POST"])
|
||||
def toggleTime(self, id, t):
|
||||
"""
|
||||
@@ -145,9 +149,11 @@ class ActorView(BaseView):
|
||||
200:
|
||||
description: Actor toggled
|
||||
"""
|
||||
t = self.api._socketio.start_background_task(target=self.toggleTimeJob, id=id, t=t)
|
||||
self.api.actor.toggle_timeout(id, t)
|
||||
#t = self.api._socketio.start_background_task(target=self.toggleTimeJob, id=id, t=t)
|
||||
return ('', 204)
|
||||
|
||||
@login_required
|
||||
@route('<int:id>/action/<method>', methods=["POST"])
|
||||
def action(self, id, method):
|
||||
"""
|
||||
@@ -172,7 +178,8 @@ class ActorView(BaseView):
|
||||
200:
|
||||
description: Actor Action called
|
||||
"""
|
||||
cbpi.cache.get("actors").get(id).instance.__getattribute__(method)()
|
||||
|
||||
self.api.actor.action(id, method)
|
||||
return ('', 204)
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ class Dummy(Actor):
|
||||
@cbpi.addon.kettle.controller()
|
||||
class MyController(KettleController):
|
||||
|
||||
|
||||
def run(self):
|
||||
while self.is_running():
|
||||
print "HALLO"
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
|
||||
from os.path import join
|
||||
|
||||
from modules.core.basetypes import Actor, Sensor
|
||||
from modules.core.core import cbpi
|
||||
from modules.core.proptypes import Property
|
||||
@@ -33,4 +37,11 @@ class Dummy(Sensor):
|
||||
@cbpi.addon.core.action(key="clear", label="Clear all Logs")
|
||||
def woohoo(cbpi):
|
||||
print "COOL"
|
||||
cbpi.notify(headline="HELLO WORLD",message="")
|
||||
dir = "./logs"
|
||||
test = os.listdir(dir)
|
||||
|
||||
for item in test:
|
||||
|
||||
if item.endswith(".log"):
|
||||
os.remove(join(dir, item))
|
||||
cbpi.notify(headline="Logs Deleted",message="All Logs Cleared")
|
||||
|
||||
@@ -7,6 +7,10 @@ from modules.core.proptypes import Property
|
||||
class Dummy(Step):
|
||||
|
||||
|
||||
@cbpi.addon.step.action("WOHOO")
|
||||
def myaction(self):
|
||||
print "HALLO"
|
||||
|
||||
text = Property.Text(label="Text", configurable=True, description="WOHOOO")
|
||||
|
||||
def execute(self):
|
||||
|
||||
@@ -87,6 +87,9 @@ class StepAPI(BaseAPI):
|
||||
return func
|
||||
return real_decorator
|
||||
|
||||
|
||||
|
||||
|
||||
class ActorAPI(BaseAPI):
|
||||
|
||||
key = "actor_types"
|
||||
@@ -150,6 +153,8 @@ class CoreAPI(BaseAPI):
|
||||
self.cbpi.cache["init"] = []
|
||||
self.cbpi.cache["js"] = {}
|
||||
self.cbpi.cache["background"] = []
|
||||
self.cbpi.cache["web_menu"] =[]
|
||||
|
||||
def init(self):
|
||||
|
||||
self.cbpi.cache["init"] = sorted(self.cbpi.cache["init"], key=lambda k: k['order'])
|
||||
@@ -173,6 +178,9 @@ class CoreAPI(BaseAPI):
|
||||
def add_js(self, name, file):
|
||||
self.cbpi.cache["js"][name] = file
|
||||
|
||||
def add_menu_link(self, name, path):
|
||||
self.cbpi.cache["web_menu"].append(dict(name=name, path=path))
|
||||
|
||||
def initializer(self, order=0, **options):
|
||||
def decorator(f):
|
||||
self.cbpi.cache.get("init").append({"function": f, "order": order})
|
||||
|
||||
@@ -246,4 +246,5 @@ class Step(Base):
|
||||
self.__dirty = True
|
||||
super(Step, self).__setattr__(name, value)
|
||||
else:
|
||||
super(Step, self).__setattr__(name, value)
|
||||
super(Step, self).__setattr__(name, value)
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from flask import request, json
|
||||
from flask_classy import route, FlaskView
|
||||
from flask_login import login_required
|
||||
|
||||
from modules.core.core import cbpi
|
||||
|
||||
|
||||
@@ -9,6 +11,7 @@ class BaseView(FlaskView):
|
||||
cache_key = None
|
||||
api = cbpi
|
||||
|
||||
@login_required
|
||||
@route('/<int:id>', methods=["GET"])
|
||||
def getOne(self, id):
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
@@ -16,6 +19,7 @@ class BaseView(FlaskView):
|
||||
else:
|
||||
return json.dumps(self.model.get_one(id))
|
||||
|
||||
@login_required
|
||||
@route('/', methods=["GET"])
|
||||
def getAll(self):
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
@@ -30,6 +34,7 @@ class BaseView(FlaskView):
|
||||
def _post_post_callback(self, m):
|
||||
pass
|
||||
|
||||
@login_required
|
||||
@route('/', methods=["POST"])
|
||||
def post(self):
|
||||
|
||||
@@ -50,7 +55,7 @@ class BaseView(FlaskView):
|
||||
def _post_put_callback(self, m):
|
||||
pass
|
||||
|
||||
|
||||
@login_required
|
||||
@route('/<int:id>', methods=["PUT"])
|
||||
def put(self, id):
|
||||
data = request.json
|
||||
@@ -78,6 +83,7 @@ class BaseView(FlaskView):
|
||||
def _post_delete_callback(self, id):
|
||||
pass
|
||||
|
||||
@login_required
|
||||
@route('/<int:id>', methods=["DELETE"])
|
||||
def delete(self, id):
|
||||
if self.api.cache.get(self.cache_key) is not None:
|
||||
|
||||
+53
-1
@@ -7,6 +7,7 @@ from datetime import datetime
|
||||
from functools import wraps, update_wrapper
|
||||
from importlib import import_module
|
||||
from time import localtime, strftime
|
||||
import time
|
||||
|
||||
from flask import Flask, redirect, json, g, make_response
|
||||
from flask_socketio import SocketIO
|
||||
@@ -17,6 +18,7 @@ from modules.core.basetypes import Sensor, Actor
|
||||
from modules.database.dbmodel import Kettle
|
||||
|
||||
|
||||
|
||||
class ComplexEncoder(json.JSONEncoder):
|
||||
def default(self, obj):
|
||||
try:
|
||||
@@ -109,6 +111,12 @@ class ActorCore(object):
|
||||
print e
|
||||
return False
|
||||
|
||||
def toggle(self, id):
|
||||
if self.cbpi.cache.get("actors").get(id).state == 0:
|
||||
self.on(id)
|
||||
else:
|
||||
self.off(id)
|
||||
|
||||
def power(self, id, power):
|
||||
try:
|
||||
actor = self.cbpi.cache["actors"].get(int(id))
|
||||
@@ -121,6 +129,20 @@ class ActorCore(object):
|
||||
print e
|
||||
return False
|
||||
|
||||
def action(self, id, method):
|
||||
self.cbpi.cache.get("actors").get(id).instance.__getattribute__(method)()
|
||||
|
||||
|
||||
def toggle_timeout(self, id, seconds):
|
||||
|
||||
def toggle( id, seconds):
|
||||
self.cbpi.cache.get("actors").get(int(id)).timer = int(time.time()) + int(seconds)
|
||||
self.toggle(int(id))
|
||||
self.cbpi.sleep(seconds)
|
||||
self.cbpi.cache.get("actors").get(int(id)).timer = None
|
||||
self.toggle(int(id))
|
||||
job = self.cbpi._socketio.start_background_task(target=toggle, id=id, seconds=seconds)
|
||||
|
||||
def get_state(self, actor_id):
|
||||
print actor_id
|
||||
print self.cbpi
|
||||
@@ -183,6 +205,10 @@ class SensorCore(object):
|
||||
with open(filename, "a") as file:
|
||||
file.write(msg)
|
||||
|
||||
def action(self, id, method):
|
||||
self.cbpi.cache.get("sensors").get(id).instance.__getattribute__(method)()
|
||||
|
||||
|
||||
|
||||
class BrewingCore(object):
|
||||
def __init__(self, cbpi):
|
||||
@@ -207,6 +233,32 @@ class BrewingCore(object):
|
||||
self.cbpi.emit("SET_KETTLE_TARGET_TEMP", id=id, temp=temp)
|
||||
|
||||
|
||||
def toggle_automatic(self, id):
|
||||
kettle = self.cbpi.cache.get("kettle")[id]
|
||||
if kettle.state is False:
|
||||
# Start controller
|
||||
if kettle.logic is not None:
|
||||
cfg = kettle.config.copy()
|
||||
cfg.update(dict(api=cbpi, kettle_id=kettle.id, heater=kettle.heater, sensor=kettle.sensor))
|
||||
instance = self.get_controller(kettle.logic).get("class")(**cfg)
|
||||
instance.init()
|
||||
kettle.instance = instance
|
||||
|
||||
def run(instance):
|
||||
instance.run()
|
||||
|
||||
t = self.cbpi._socketio.start_background_task(target=run, instance=instance)
|
||||
kettle.state = not kettle.state
|
||||
self.cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
|
||||
self.cbpi.emit("KETTLE_CONTROLLER_STARTED", id=id)
|
||||
else:
|
||||
# Stop controller
|
||||
kettle.instance.stop()
|
||||
kettle.state = not kettle.state
|
||||
self.cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
|
||||
self.cbpi.emit("KETTLE_CONTROLLER_STOPPED", id=id)
|
||||
|
||||
|
||||
class FermentationCore(object):
|
||||
def __init__(self, cbpi):
|
||||
self.cbpi = cbpi
|
||||
@@ -313,7 +365,7 @@ class CraftBeerPI(object):
|
||||
return cfg.value
|
||||
|
||||
def emit(self, key, **kwargs):
|
||||
print key, kwargs
|
||||
|
||||
if self.eventbus.get(key) is not None:
|
||||
for value in self.eventbus[key]:
|
||||
if value["async"] is False:
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import sqlite3
|
||||
import os
|
||||
from modules.core.core import cbpi
|
||||
from modules.core.db import get_db
|
||||
|
||||
def execute_file(curernt_version, data):
|
||||
if curernt_version >= data["version"]:
|
||||
cbpi._app.logger.info("SKIP DB FILE: %s" % data["file"])
|
||||
return
|
||||
try:
|
||||
with sqlite3.connect("craftbeerpi.db") as conn:
|
||||
with open('./update/%s' % data["file"], 'r') as f:
|
||||
d = f.read()
|
||||
sqlCommands = d.split(";")
|
||||
cur = conn.cursor()
|
||||
for s in sqlCommands:
|
||||
cur.execute(s)
|
||||
cur.execute("INSERT INTO schema_info (version,filename) values (?,?)", (data["version"], data["file"]))
|
||||
conn.commit()
|
||||
|
||||
except sqlite3.OperationalError as err:
|
||||
print "EXCEPT"
|
||||
print err
|
||||
|
||||
@cbpi.addon.core.initializer(order=-9999)
|
||||
def init(cbpi):
|
||||
|
||||
with cbpi._app.app_context():
|
||||
conn = get_db()
|
||||
cur = conn.cursor()
|
||||
current_version = None
|
||||
try:
|
||||
cur.execute("SELECT max(version) as m FROM schema_info")
|
||||
m = cur.fetchone()
|
||||
current_version = m["m"]
|
||||
except:
|
||||
pass
|
||||
result = []
|
||||
for filename in os.listdir("./update"):
|
||||
print filename
|
||||
if filename.endswith(".sql"):
|
||||
d = {"version": int(filename[:filename.index('_')]), "file": filename}
|
||||
result.append(d)
|
||||
execute_file(current_version, d)
|
||||
@@ -1,36 +0,0 @@
|
||||
import flask_login
|
||||
from modules.core.core import cbpi, addon
|
||||
|
||||
class User(flask_login.UserMixin):
|
||||
pass
|
||||
|
||||
@addon.core.initializer(order=0)
|
||||
def log(cbpi):
|
||||
|
||||
|
||||
cbpi._login_manager = flask_login.LoginManager()
|
||||
cbpi._login_manager.init_app(cbpi._app)
|
||||
@cbpi._app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
user = User()
|
||||
user.id = "manuel"
|
||||
flask_login.login_user(user)
|
||||
return "OK"
|
||||
|
||||
@cbpi._app.route('/logout')
|
||||
def logout():
|
||||
flask_login.logout_user()
|
||||
return 'Logged out'
|
||||
|
||||
@cbpi._login_manager.user_loader
|
||||
def user_loader(email):
|
||||
if email not in cbpi.cache["users"]:
|
||||
return
|
||||
|
||||
user = User()
|
||||
user.id = email
|
||||
return user
|
||||
|
||||
@cbpi._login_manager.unauthorized_handler
|
||||
def unauthorized_handler():
|
||||
return 'Unauthorized :-('
|
||||
@@ -214,39 +214,9 @@ class KettleView(BaseView):
|
||||
description: User created
|
||||
"""
|
||||
|
||||
kettle = cbpi.cache.get("kettle")[id]
|
||||
if kettle.state is False:
|
||||
# Start controller
|
||||
if kettle.logic is not None:
|
||||
cfg = kettle.config.copy()
|
||||
cfg.update(dict(api=cbpi, kettle_id=kettle.id, heater=kettle.heater, sensor=kettle.sensor))
|
||||
instance = cbpi.brewing.get_controller(kettle.logic).get("class")(**cfg)
|
||||
instance.init()
|
||||
kettle.instance = instance
|
||||
def run(instance):
|
||||
instance.run()
|
||||
t = self.api._socketio.start_background_task(target=run, instance=instance)
|
||||
kettle.state = not kettle.state
|
||||
cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
|
||||
cbpi.emit("KETTLE_CONTROLLER_STARTED", id=id)
|
||||
else:
|
||||
# Stop controller
|
||||
kettle.instance.stop()
|
||||
kettle.state = not kettle.state
|
||||
cbpi.ws_emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(id))
|
||||
cbpi.emit("KETTLE_CONTROLLER_STOPPED", id=id)
|
||||
self.api.brewing.toggle_automatic(id)
|
||||
return ('', 204)
|
||||
|
||||
#@cbpi.event("SET_TARGET_TEMP")
|
||||
def set_target_temp(id, temp):
|
||||
'''
|
||||
Change Taget Temp Event
|
||||
:param id: kettle id
|
||||
:param temp: target temp to set
|
||||
:return: None
|
||||
'''
|
||||
KettleView().postTargetTemp(id, temp)
|
||||
|
||||
@cbpi.addon.core.backgroundjob(key="read_target_temps", interval=5)
|
||||
def read_target_temps(api):
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import flask_login
|
||||
from flask import request
|
||||
|
||||
from modules.core.core import cbpi, addon
|
||||
|
||||
class User(flask_login.UserMixin):
|
||||
pass
|
||||
|
||||
@addon.core.initializer(order=0)
|
||||
def log(cbpi):
|
||||
|
||||
|
||||
cbpi._login_manager = flask_login.LoginManager()
|
||||
cbpi._login_manager.init_app(cbpi._app)
|
||||
@cbpi._app.route('/login', methods=['POST'])
|
||||
def login():
|
||||
|
||||
data = request.json
|
||||
password = cbpi.get_config_parameter("password", None)
|
||||
|
||||
if password is None:
|
||||
return ('',500)
|
||||
|
||||
if password == data.get("password",""):
|
||||
user = User()
|
||||
user.id = "craftbeerpi"
|
||||
flask_login.login_user(user)
|
||||
return ('',204)
|
||||
else:
|
||||
return ('',401)
|
||||
|
||||
|
||||
@cbpi._app.route('/logout', methods=['POST'])
|
||||
def logout():
|
||||
flask_login.logout_user()
|
||||
return 'Logged out'
|
||||
|
||||
@cbpi._login_manager.user_loader
|
||||
def user_loader(user):
|
||||
|
||||
print cbpi.get_config_parameter("password_security", "NO")
|
||||
print user
|
||||
|
||||
if cbpi.get_config_parameter("password_security", "NO") == "YES":
|
||||
if user != "craftbeerpi":
|
||||
return
|
||||
user = User()
|
||||
user.id = user
|
||||
return user
|
||||
else:
|
||||
user = User()
|
||||
user.id = user
|
||||
return user
|
||||
|
||||
@cbpi._login_manager.unauthorized_handler
|
||||
def unauthorized_handler():
|
||||
return ('Please login',401)
|
||||
@@ -34,7 +34,7 @@ class SensorView(BaseView):
|
||||
200:
|
||||
description: Sensor Action called
|
||||
"""
|
||||
cbpi.cache.get("sensors").get(id).instance.__getattribute__(method)()
|
||||
cbpi.sensor.action(id, method)
|
||||
return ('', 204)
|
||||
|
||||
def _post_post_callback(self, m):
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import yaml
|
||||
from flask import json, url_for, Response
|
||||
from flask_classy import FlaskView, route
|
||||
from flask_login import login_required, current_user
|
||||
from git import Repo, Git
|
||||
from modules.core.core import cbpi
|
||||
import pprint
|
||||
@@ -13,6 +14,7 @@ class SystemView(FlaskView):
|
||||
from subprocess import call
|
||||
call("halt")
|
||||
|
||||
@login_required
|
||||
@route('/shutdown', methods=['POST'])
|
||||
def shutdown(self):
|
||||
"""
|
||||
@@ -33,6 +35,7 @@ class SystemView(FlaskView):
|
||||
from subprocess import call
|
||||
call("reboot")
|
||||
|
||||
@login_required
|
||||
@route('/reboot', methods=['POST'])
|
||||
def reboot(self):
|
||||
"""
|
||||
@@ -47,6 +50,7 @@ class SystemView(FlaskView):
|
||||
self.doReboot()
|
||||
return ('', 204)
|
||||
|
||||
@login_required
|
||||
@route('/tags/<name>', methods=['GET'])
|
||||
def checkout_tag(self,name):
|
||||
repo = Repo('./')
|
||||
@@ -58,6 +62,7 @@ class SystemView(FlaskView):
|
||||
cbpi.notify("Checkout successful", "Please restart the system")
|
||||
return ('', 204)
|
||||
|
||||
@login_required
|
||||
@route('/git/status', methods=['GET'])
|
||||
def git_status(self):
|
||||
"""
|
||||
@@ -92,6 +97,7 @@ class SystemView(FlaskView):
|
||||
return json.dumps({"tags": tags, "headcommit": str(repo.head.commit), "branchname": branch_name,
|
||||
"master": {"changes": changes}})
|
||||
|
||||
@login_required
|
||||
@route('/check_update', methods=['GET'])
|
||||
def check_update(self):
|
||||
"""
|
||||
@@ -114,6 +120,7 @@ class SystemView(FlaskView):
|
||||
|
||||
return json.dumps(changes)
|
||||
|
||||
@login_required
|
||||
@route('/git/pull', methods=['POST'])
|
||||
def update(self):
|
||||
"""
|
||||
@@ -131,6 +138,24 @@ class SystemView(FlaskView):
|
||||
cbpi.notify("Pull successful", "The lasted updated was downloaded. Please restart the system")
|
||||
return ('', 204)
|
||||
|
||||
@route('/connect', methods=['GET'])
|
||||
def connect(self):
|
||||
"""
|
||||
Connect
|
||||
---
|
||||
tags:
|
||||
- system
|
||||
responses:
|
||||
200:
|
||||
description: CraftBeerPi System Cache
|
||||
"""
|
||||
|
||||
if self.api.get_config_parameter("setup", "YES") == "YES":
|
||||
return json.dumps(dict(setup=True, loggedin= current_user.is_authenticated ))
|
||||
else:
|
||||
return json.dumps(dict(setup=False, loggedin= current_user.is_authenticated))
|
||||
|
||||
@login_required
|
||||
@route('/dump', methods=['GET'])
|
||||
def dump(self):
|
||||
"""
|
||||
|
||||
+15
-6
@@ -1,4 +1,4 @@
|
||||
from flask import Blueprint
|
||||
from flask import Blueprint,render_template
|
||||
|
||||
from modules.core.core import cbpi
|
||||
|
||||
@@ -11,11 +11,20 @@ def init(cbpi):
|
||||
|
||||
@react.route('/', methods=["GET"])
|
||||
def index():
|
||||
return react.send_static_file("index.html")
|
||||
|
||||
|
||||
|
||||
|
||||
#return react.send_static_file("index.html")
|
||||
|
||||
js_files = []
|
||||
for key, value in cbpi.cache["js"].iteritems():
|
||||
js_files.append(value)
|
||||
|
||||
print js_files
|
||||
return render_template('index.html', js_files=js_files)
|
||||
|
||||
|
||||
|
||||
@cbpi._app.errorhandler(404)
|
||||
def page_not_found(e):
|
||||
return render_template('404.html'), 404
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
padding-right: 5px;
|
||||
padding-left: 5px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: sans-serif;
|
||||
|
||||
}
|
||||
|
||||
+44
-48
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
|
||||
<link rel="stylesheet" href="/ui/static/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/ui/static/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="/ui/static/bootstrap.dark.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Dosis:200,500" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Dosis', sans-serif;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
<title>CraftBeerPi 3.1</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>CraftBeerPi - Page not Found!</h1>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
|
||||
<link rel="stylesheet" href="static/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="static/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="static/bootstrap.dark.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Dosis:200,500" rel="stylesheet">
|
||||
<style>
|
||||
|
||||
body, h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Dosis', sans-serif;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
<title>CraftBeerPi 3.1</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root" ></div>
|
||||
{% for file in js_files %}
|
||||
|
||||
<script src="{{ file }}" type="text/javascript"></script>
|
||||
{% endfor %}
|
||||
<script src="static/bundle.js" type="text/javascript"></script>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user