more v0.5 features
- users can now override global settings - added update message
This commit is contained in:
parent
621a22b670
commit
83c19616cc
@ -1,11 +1,7 @@
|
|||||||
#### Config.ini Readme
|
#### Config.ini Readme
|
||||||
|
|
||||||
##### Settings
|
##### Settings
|
||||||
This is the configuration entry for DashMachine's settings. DashMachine will not work if
|
This is the configuration entry for DashMachine's settings. DashMachine will not work if this is missing. As for all config entries, [Settings] can only appear once in the config. If you change the config.ini file, you either have to restart the container (or python script) or click the ‘save’ button in the config section of settings for the config to be applied.
|
||||||
this is missing. As for all config entries, [Settings] can only appear once in the config.
|
|
||||||
If you change the config.ini file, you either have to restart the container
|
|
||||||
(or python script) or click the ‘save’ button in the config section of settings for the
|
|
||||||
config to be applied.
|
|
||||||
```ini
|
```ini
|
||||||
[Settings]
|
[Settings]
|
||||||
theme = light
|
theme = light
|
||||||
@ -14,7 +10,9 @@ background = None
|
|||||||
roles = admin,user,public_user
|
roles = admin,user,public_user
|
||||||
home_access_groups = admin_only
|
home_access_groups = admin_only
|
||||||
settings_access_groups = admin_only
|
settings_access_groups = admin_only
|
||||||
|
home_view_mode = grid
|
||||||
custom_app_title = DashMachine
|
custom_app_title = DashMachine
|
||||||
|
sidebar_default = open
|
||||||
```
|
```
|
||||||
|
|
||||||
| Variable | Required | Description | Options |
|
| Variable | Required | Description | Options |
|
||||||
@ -26,36 +24,32 @@ custom_app_title = DashMachine
|
|||||||
| roles | No | User roles for access groups. | comma separated string, if not defined, this is set to 'admin,user,public_user'. Note: admin, user, public_user roles are required and will be added automatically if omitted. |
|
| roles | No | User roles for access groups. | comma separated string, if not defined, this is set to 'admin,user,public_user'. Note: admin, user, public_user roles are required and will be added automatically if omitted. |
|
||||||
| home_access_groups | No | Define which access groups can access the /home page | Groups defined in your config. If not defined, default is admin_only |
|
| home_access_groups | No | Define which access groups can access the /home page | Groups defined in your config. If not defined, default is admin_only |
|
||||||
| settings_access_groups | No | Define which access groups can access the /settings page | Groups defined in your config. If not defined, default is admin_only |
|
| settings_access_groups | No | Define which access groups can access the /settings page | Groups defined in your config. If not defined, default is admin_only |
|
||||||
|
| home_view_mode | No | Choose the default for view mode on /home | grid, list |
|
||||||
| custom_app_title | No | Change the title of the app for browser tabs | string |
|
| custom_app_title | No | Change the title of the app for browser tabs | string |
|
||||||
|
| sidebar_default | No | Select the default state for the sidebar | open, closed, no_sidebar |
|
||||||
|
|
||||||
##### Users
|
##### Users
|
||||||
Each user requires a config entry, and there must be at least one user in the config
|
Each user requires a config entry, and there must be at least one user in the config (otherwise the default user is added). Each user has a username, a role for configuring access groups, and a password. By default there is one user, named 'admin', with role 'admin' and password 'admin'. To change this user's name, password or role, just modify the config entry's variables and press save. To add a new user, add another user config entry UNDER all existing user config entries. A user with role 'admin' must appear first in the config. Do not change the order of users in the config once they have been defined, otherwise their passwords will not match the next time the config is applied. When users are removed from the config, they are deleted and their cached password is also deleted when the config is applied.
|
||||||
(otherwise the default user is added). Each user has a username, a role for configuring
|
|
||||||
access groups, and a password. By default there is one user, named 'admin', with role
|
|
||||||
'admin' and password 'admin'. To change this user's name, password or role,
|
|
||||||
just modify the config entry's variables and press save. To add a new user, add another
|
|
||||||
user config entry UNDER all existing user config entries. A user with role 'admin' must
|
|
||||||
appear first in the config. Do not change the order of users in the config
|
|
||||||
once they have been defined, otherwise their passwords will not match the next time the
|
|
||||||
config is applied. When users are removed from the config, they are deleted and their
|
|
||||||
cached password is also deleted when the config is applied.
|
|
||||||
```ini
|
```ini
|
||||||
[Username]
|
[admin]
|
||||||
role = admin
|
role = admin
|
||||||
password = admin
|
password = admin
|
||||||
confirm_password = admin
|
confirm_password = admin
|
||||||
```
|
```
|
||||||
|
|
||||||
| Variable | Required | Description | Options |
|
| Variable | Required | Description | Options |
|
||||||
|------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
|
|------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|
|
||||||
| [Username] | Yes | The user's name for logging in | [Username] |
|
| [Username] | Yes | The user's name for logging in | [Username] |
|
||||||
| role | Yes | The user's role. This is used for access groups and controlling who can view /home and /settings. There must be at least one 'admin' user, and it must be defined first in the config. Otherwise, the first user will be set to admin. | string |
|
| role | Yes | The user's role. This is used for access groups and controlling who can view /home and /settings. There must be at least one 'admin' user, and it must be defined first in the config. Otherwise, the first user will be set to admin. | string |
|
||||||
| password | No | Add a password to this variable to change the password for this user. The password will be hashed, cached and removed from the config. When adding a new user, specify the password, otherwise 'admin' will be used. | string |
|
| password | No | Add a password to this variable to change the password for this user. The password will be hashed, cached and removed from the config. When adding a new user, specify the password, otherwise 'admin' will be used. | string |
|
||||||
| confirm_password | No | When adding a new user or changing an existing user's password you must confirm the password in this variable | string |
|
| confirm_password | No | When adding a new user or changing an existing user's password you must confirm the password in this variable | string |
|
||||||
|
| theme | No | Override the theme from Settings for this user | same as Settings |
|
||||||
|
| accent | No | Override the accent from Settings for this user | same as Settings |
|
||||||
|
| sidebar_default | No | Override the sidebar_default from Settings for this user | same as Settings |
|
||||||
|
| home_view_mode | No | Override the home_view_mode from Settings for this user | same as Settings |
|
||||||
|
|
||||||
##### Apps
|
##### Apps
|
||||||
These entries are the cards that you see one the home page, as well as the sidenav. Entries
|
These entries are the cards that you see one the home page, as well as the sidenav. Entries must be unique. They are displayed in the order that they appear in config.ini
|
||||||
must be unique. They are displayed in the order that they appear in config.ini
|
|
||||||
```ini
|
```ini
|
||||||
[App Name]
|
[App Name]
|
||||||
prefix = https://
|
prefix = https://
|
||||||
@ -83,10 +77,7 @@ groups = admin_only
|
|||||||
| groups | No | Optionally the access groups that can see this app. | comma separated string |
|
| groups | No | Optionally the access groups that can see this app. | comma separated string |
|
||||||
|
|
||||||
##### Access Groups
|
##### Access Groups
|
||||||
You can create access groups to control what user roles can access parts of the ui. Access groups are just a collection of roles, and each user has an attribute 'role'. Each
|
You can create access groups to control what user roles can access parts of the ui. Access groups are just a collection of roles, and each user has an attribute 'role'. Each application can have an access group, if the user's role is not in the group, the app will be hidden. Also, in the settings entry you can specify `home_access_groups` and `settings_access_groups` to control which groups can access /home and /settings
|
||||||
application can have an access group, if the user's role is not in the group, the app will be hidden.
|
|
||||||
Also, in the settings entry you can specify `home_access_groups` and `settings_access_groups` to control
|
|
||||||
which groups can access /home and /settings
|
|
||||||
```ini
|
```ini
|
||||||
[admin_only]
|
[admin_only]
|
||||||
roles = admin
|
roles = admin
|
||||||
@ -132,12 +123,7 @@ roles = admin
|
|||||||
>Dashmachine will automatically add `admin,user,public_user`, so really you would have 4 roles: `my_people,admin,user,public_user`. Also, the `admin_only` group is required and added by default if omitted.
|
>Dashmachine will automatically add `admin,user,public_user`, so really you would have 4 roles: `my_people,admin,user,public_user`. Also, the `admin_only` group is required and added by default if omitted.
|
||||||
|
|
||||||
#### Data Source Platforms
|
#### Data Source Platforms
|
||||||
DashMachine includes several different 'platforms' for displaying data on your dash applications.
|
DashMachine includes several different 'platforms' for displaying data on your dash applications. Platforms are essentially plugins. All data source config entries require the `platform` variable, which tells DashMachine which platform file in the platform folder to load. **Note:** you are able to load your own platform files by placing them in the platform folder and referencing them in the config. However currently they will be deleted if you update the application, if you would like to make them permanent, submit a pull request for it to be added by default!
|
||||||
Platforms are essentially plugins. All data source config entries require the `platform` variable,
|
|
||||||
which tells DashMachine which platform file in the platform folder to load. **Note:** you are able to
|
|
||||||
load your own platform files by placing them in the platform folder and referencing them in the config.
|
|
||||||
However currently they will be deleted if you update the application, if you would like to make them
|
|
||||||
permanent, submit a pull request for it to be added by default!
|
|
||||||
|
|
||||||
> To add a data source to your app, add a data source config entry from one of the samples below
|
> To add a data source to your app, add a data source config entry from one of the samples below
|
||||||
**above** the application entry in config.ini, then add the following to your app config entry:
|
**above** the application entry in config.ini, then add the following to your app config entry:
|
||||||
|
@ -1 +0,0 @@
|
|||||||
$2b$12$fB4kz89m4U7Dc9vpXLhDQ.47iNO4.XuIwqdD63lp8tMWIDgMN4y.a
|
|
@ -74,6 +74,8 @@ def read_config():
|
|||||||
"custom_app_title", "DashMachine"
|
"custom_app_title", "DashMachine"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
settings.sidebar_default = config["Settings"].get("sidebar_default", "open")
|
||||||
|
|
||||||
db.session.add(settings)
|
db.session.add(settings)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
@ -82,6 +84,10 @@ def read_config():
|
|||||||
user = User()
|
user = User()
|
||||||
user.username = section
|
user.username = section
|
||||||
user.role = config[section]["role"]
|
user.role = config[section]["role"]
|
||||||
|
user.sidebar_default = config[section].get("sidebar_default", None)
|
||||||
|
user.home_view_mode = config[section].get("home_view_mode", "grid")
|
||||||
|
user.theme = config[section].get("theme", None)
|
||||||
|
user.accent = config[section].get("accent", None)
|
||||||
user.password = ""
|
user.password = ""
|
||||||
if not User.query.filter_by(role="admin").first() and user.role != "admin":
|
if not User.query.filter_by(role="admin").first() and user.role != "admin":
|
||||||
print(
|
print(
|
||||||
|
@ -5,13 +5,13 @@ from htmlmin.main import minify
|
|||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from flask import render_template, url_for, redirect, request, Blueprint, jsonify
|
from flask import render_template, url_for, redirect, request, Blueprint, jsonify
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from dashmachine.main.models import Files, Apps, DataSources, Tags
|
from dashmachine.main.models import Files, Apps, DataSources
|
||||||
from dashmachine.main.forms import TagsForm
|
|
||||||
from dashmachine.main.utils import (
|
from dashmachine.main.utils import (
|
||||||
public_route,
|
|
||||||
check_groups,
|
check_groups,
|
||||||
get_data_source,
|
get_data_source,
|
||||||
|
mark_update_message_read,
|
||||||
)
|
)
|
||||||
|
from dashmachine.user_system.models import User
|
||||||
from dashmachine.settings_system.models import Settings
|
from dashmachine.settings_system.models import Settings
|
||||||
from dashmachine.paths import cache_folder, user_data_folder
|
from dashmachine.paths import cache_folder, user_data_folder
|
||||||
from dashmachine import app, db
|
from dashmachine import app, db
|
||||||
@ -35,28 +35,9 @@ def response_minify(response):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
# blocks access to all pages (except public routes) unless the user is
|
|
||||||
# signed in.
|
|
||||||
@main.before_app_request
|
|
||||||
def check_valid_login():
|
|
||||||
|
|
||||||
if any(
|
|
||||||
[
|
|
||||||
request.endpoint.startswith("static"),
|
|
||||||
current_user.is_authenticated,
|
|
||||||
getattr(app.view_functions[request.endpoint], "is_public", False),
|
|
||||||
]
|
|
||||||
):
|
|
||||||
return
|
|
||||||
|
|
||||||
else:
|
|
||||||
return redirect(url_for("user_system.login"))
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# /home
|
# /home
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@public_route
|
|
||||||
@main.route("/")
|
@main.route("/")
|
||||||
@main.route("/home", methods=["GET"])
|
@main.route("/home", methods=["GET"])
|
||||||
def home():
|
def home():
|
||||||
@ -66,7 +47,6 @@ def home():
|
|||||||
return render_template("main/home.html")
|
return render_template("main/home.html")
|
||||||
|
|
||||||
|
|
||||||
@public_route
|
|
||||||
@main.route("/app_view?<app_id>", methods=["GET"])
|
@main.route("/app_view?<app_id>", methods=["GET"])
|
||||||
def app_view(app_id):
|
def app_view(app_id):
|
||||||
settings = Settings.query.first()
|
settings = Settings.query.first()
|
||||||
@ -85,20 +65,25 @@ def load_data_source():
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@public_route
|
@main.route("/change_home_view_mode?<mode>%<user_id>", methods=["GET"])
|
||||||
@main.route("/change_home_view_mode?<mode>", methods=["GET"])
|
def change_home_view_mode(mode, user_id):
|
||||||
def change_home_view_mode(mode):
|
user = User.query.filter_by(id=user_id).first()
|
||||||
config = ConfigParser()
|
config = ConfigParser()
|
||||||
config.read(os.path.join(user_data_folder, "config.ini"))
|
config.read(os.path.join(user_data_folder, "config.ini"))
|
||||||
config.set("Settings", "home_view_mode", mode)
|
config.set(user.username, "home_view_mode", mode)
|
||||||
config.write(open(os.path.join(user_data_folder, "config.ini"), "w"))
|
config.write(open(os.path.join(user_data_folder, "config.ini"), "w"))
|
||||||
settings = Settings.query.first()
|
user.home_view_mode = mode
|
||||||
settings.home_view_mode = mode
|
db.session.merge(user)
|
||||||
db.session.merge(settings)
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return redirect(url_for("main.home"))
|
return redirect(url_for("main.home"))
|
||||||
|
|
||||||
|
|
||||||
|
@main.route("/update_message_read", methods=["GET"])
|
||||||
|
def update_message_read():
|
||||||
|
mark_update_message_read()
|
||||||
|
return "ok"
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# TCDROP routes
|
# TCDROP routes
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -2,9 +2,16 @@ import os
|
|||||||
import importlib
|
import importlib
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from dashmachine.paths import dashmachine_folder, images_folder
|
from markdown2 import markdown
|
||||||
|
from dashmachine.paths import (
|
||||||
|
dashmachine_folder,
|
||||||
|
images_folder,
|
||||||
|
root_folder,
|
||||||
|
user_data_folder,
|
||||||
|
)
|
||||||
from dashmachine.main.models import Groups
|
from dashmachine.main.models import Groups
|
||||||
from dashmachine.main.read_config import read_config
|
from dashmachine.main.read_config import read_config
|
||||||
|
from dashmachine.version import version as dashmachine_version
|
||||||
from dashmachine import db
|
from dashmachine import db
|
||||||
|
|
||||||
|
|
||||||
@ -94,3 +101,35 @@ def resize_template_app_images():
|
|||||||
image = Image.open(fp)
|
image = Image.open(fp)
|
||||||
image.thumbnail((64, 64))
|
image.thumbnail((64, 64))
|
||||||
image.save(fp)
|
image.save(fp)
|
||||||
|
|
||||||
|
|
||||||
|
def get_update_message_html():
|
||||||
|
try:
|
||||||
|
with open(os.path.join(user_data_folder, ".has_read_update"), "r") as has_read:
|
||||||
|
has_read_version = has_read.read()
|
||||||
|
except FileNotFoundError:
|
||||||
|
has_read_version = None
|
||||||
|
if not has_read_version or has_read_version.strip() != dashmachine_version:
|
||||||
|
with open(
|
||||||
|
os.path.join(root_folder, "update_message.md"), "r"
|
||||||
|
) as update_message:
|
||||||
|
md = update_message.read()
|
||||||
|
|
||||||
|
config_html = markdown(
|
||||||
|
md,
|
||||||
|
extras=[
|
||||||
|
"tables",
|
||||||
|
"fenced-code-blocks",
|
||||||
|
"break-on-newline",
|
||||||
|
"header-ids",
|
||||||
|
"code-friendly",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return config_html
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def mark_update_message_read():
|
||||||
|
with open(os.path.join(user_data_folder, ".has_read_update"), "w") as has_read:
|
||||||
|
has_read.write(dashmachine_version)
|
||||||
|
@ -13,14 +13,17 @@ root_folder = get_root_folder()
|
|||||||
|
|
||||||
dashmachine_folder = os.path.join(root_folder, "dashmachine")
|
dashmachine_folder = os.path.join(root_folder, "dashmachine")
|
||||||
|
|
||||||
auth_cache = os.path.join(dashmachine_folder, "auth_cache")
|
|
||||||
|
|
||||||
template_apps_folder = os.path.join(root_folder, "template_apps")
|
template_apps_folder = os.path.join(root_folder, "template_apps")
|
||||||
|
|
||||||
platform_folder = os.path.join(dashmachine_folder, "platform")
|
platform_folder = os.path.join(dashmachine_folder, "platform")
|
||||||
|
|
||||||
user_data_folder = os.path.join(dashmachine_folder, "user_data")
|
user_data_folder = os.path.join(dashmachine_folder, "user_data")
|
||||||
|
|
||||||
|
auth_cache = os.path.join(user_data_folder, "auth_cache")
|
||||||
|
|
||||||
|
if not os.path.isdir(auth_cache):
|
||||||
|
os.mkdir(auth_cache)
|
||||||
|
|
||||||
static_folder = os.path.join(dashmachine_folder, "static")
|
static_folder = os.path.join(dashmachine_folder, "static")
|
||||||
|
|
||||||
images_folder = os.path.join(static_folder, "images")
|
images_folder = os.path.join(static_folder, "images")
|
||||||
|
@ -11,3 +11,4 @@ class Settings(db.Model):
|
|||||||
settings_access_groups = db.Column(db.String())
|
settings_access_groups = db.Column(db.String())
|
||||||
home_view_mode = db.Column(db.String())
|
home_view_mode = db.Column(db.String())
|
||||||
custom_app_title = db.Column(db.String())
|
custom_app_title = db.Column(db.String())
|
||||||
|
sidebar_default = db.Column(db.String())
|
||||||
|
@ -4,7 +4,7 @@ from jsmin import jsmin
|
|||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from dashmachine import app
|
from dashmachine import app
|
||||||
from dashmachine.main.models import Apps
|
from dashmachine.main.models import Apps
|
||||||
from dashmachine.main.utils import check_groups
|
from dashmachine.main.utils import check_groups, get_update_message_html
|
||||||
from dashmachine.main.forms import TagsForm
|
from dashmachine.main.forms import TagsForm
|
||||||
from dashmachine.settings_system.models import Settings
|
from dashmachine.settings_system.models import Settings
|
||||||
from dashmachine.paths import static_folder, backgrounds_images_folder
|
from dashmachine.paths import static_folder, backgrounds_images_folder
|
||||||
@ -100,6 +100,7 @@ def context_processor():
|
|||||||
f"static/images/backgrounds/"
|
f"static/images/backgrounds/"
|
||||||
f"{random.choice(os.listdir(backgrounds_images_folder))}"
|
f"{random.choice(os.listdir(backgrounds_images_folder))}"
|
||||||
)
|
)
|
||||||
|
update_message = get_update_message_html()
|
||||||
return dict(
|
return dict(
|
||||||
test_key="test",
|
test_key="test",
|
||||||
process_js_sources=process_js_sources,
|
process_js_sources=process_js_sources,
|
||||||
@ -107,4 +108,5 @@ def context_processor():
|
|||||||
apps=apps,
|
apps=apps,
|
||||||
settings=settings,
|
settings=settings,
|
||||||
tags_form=tags_form,
|
tags_form=tags_form,
|
||||||
|
update_message=update_message,
|
||||||
)
|
)
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
-ms-user-select: all;
|
-ms-user-select: all;
|
||||||
user-select: all;
|
user-select: all;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
#config-readme th {
|
#config-readme th {
|
||||||
color: var(--theme-primary);
|
color: var(--theme-primary);
|
||||||
|
@ -67,6 +67,13 @@ function hide_sidenav() {
|
|||||||
localStorage.setItem('sidenav_hidden', 'true');
|
localStorage.setItem('sidenav_hidden', 'true');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function no_sidebar() {
|
||||||
|
$("#main-sidenav").remove();
|
||||||
|
$("#main.main-full").css('padding-left', 0);
|
||||||
|
$("#no-sidenav").removeClass('hide');
|
||||||
|
localStorage.setItem('sidenav_hidden', 'no_sidebar');
|
||||||
|
}
|
||||||
|
|
||||||
function show_sidenav(){
|
function show_sidenav(){
|
||||||
$("#main-sidenav").removeClass('hide');
|
$("#main-sidenav").removeClass('hide');
|
||||||
$("#main.main-full").css('padding-left', 64);
|
$("#main.main-full").css('padding-left', 64);
|
||||||
@ -74,26 +81,80 @@ function show_sidenav(){
|
|||||||
localStorage.setItem('sidenav_hidden', null);
|
localStorage.setItem('sidenav_hidden', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function apply_settings(settings_theme, settings_accent){
|
function apply_settings(settings){
|
||||||
localStorage.setItem('mode', settings_theme);
|
// theme
|
||||||
document.documentElement.setAttribute('data-theme', settings_theme);
|
if (settings['user_theme'] != "None" && settings['user_theme'].length > 1) {
|
||||||
localStorage.setItem('accent', settings_accent);
|
console.log(settings['user_theme'].length)
|
||||||
document.documentElement.setAttribute('data-accent', settings_accent);
|
localStorage.setItem('mode', settings['user_theme']);
|
||||||
|
document.documentElement.setAttribute('data-theme', settings['user_theme']);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('mode', settings['settings_theme']);
|
||||||
|
document.documentElement.setAttribute('data-theme', settings['settings_theme']);
|
||||||
|
}
|
||||||
|
// accent
|
||||||
|
if (settings['user_accent'] != "None" && settings['user_accent'].length > 1) {
|
||||||
|
localStorage.setItem('accent', settings['user_accent']);
|
||||||
|
document.documentElement.setAttribute('data-accent', settings['user_accent']);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('accent', settings['settings_accent']);
|
||||||
|
document.documentElement.setAttribute('data-accent', settings['settings_accent']);
|
||||||
|
}
|
||||||
|
if (settings['settings_sidebar_default'] == "closed"){
|
||||||
|
localStorage.setItem('sidenav_hidden', 'true');
|
||||||
|
} else if (settings['settings_sidebar_default'] == "open"){
|
||||||
|
localStorage.setItem('sidenav_hidden', 'false');
|
||||||
|
} else if (settings['settings_sidebar_default'] == "no_sidebar"){
|
||||||
|
localStorage.setItem('sidenav_hidden', 'no_sidebar');
|
||||||
|
}
|
||||||
|
if (settings['user_sidebar_default'] == "closed"){
|
||||||
|
localStorage.setItem('sidenav_hidden', 'true');
|
||||||
|
} else if (settings['user_sidebar_default'] == "open"){
|
||||||
|
localStorage.setItem('sidenav_hidden', 'false');
|
||||||
|
} else if (settings['user_sidebar_default'] == "no_sidebar"){
|
||||||
|
localStorage.setItem('sidenav_hidden', 'no_sidebar');
|
||||||
|
}
|
||||||
|
if (localStorage.getItem('sidenav_hidden') === 'true'){
|
||||||
|
hide_sidenav();
|
||||||
|
} else if (localStorage.getItem('sidenav_hidden') === 'no_sidebar'){
|
||||||
|
no_sidebar();
|
||||||
|
} else if (settings['user_name'].length < 1) {
|
||||||
|
no_sidebar();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
// Document ready function
|
// Document ready function
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
apply_settings($("#settings-theme").val(), $("#settings-accent").val());
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
apply_settings({
|
||||||
|
settings_theme: $("#settings-theme").val(),
|
||||||
|
settings_accent: $("#settings-accent").val(),
|
||||||
|
settings_sidebar_default: $("#settings-sidebar_default").val(),
|
||||||
|
user_name: $("#user-name").val(),
|
||||||
|
user_theme: $("#user-theme").val(),
|
||||||
|
user_accent: $("#user-accent").val(),
|
||||||
|
user_sidebar_default: $("#user-sidebar_default").val(),
|
||||||
|
});
|
||||||
|
|
||||||
// INITS
|
// INITS
|
||||||
init_select();
|
init_select();
|
||||||
|
|
||||||
if (localStorage.getItem('sidenav_hidden') === 'true'){
|
$("#update-message-modal").modal({
|
||||||
hide_sidenav();
|
dismissible: false
|
||||||
|
});
|
||||||
|
if ($("#update-message-content").text().length > 1){
|
||||||
|
$("#update-message-modal").modal('open');
|
||||||
}
|
}
|
||||||
|
$("#update-message-read-btn").on('click', function(e) {
|
||||||
|
$.ajax({
|
||||||
|
url: $(this).attr('data-url'),
|
||||||
|
type: 'GET',
|
||||||
|
success: function(data){
|
||||||
|
$("#update-message-modal").modal('close');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$("#hide-sidenav").on('click', function(e) {
|
$("#hide-sidenav").on('click', function(e) {
|
||||||
hide_sidenav();
|
hide_sidenav();
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
{% from 'global_macros.html' import button %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html id="html" class="loading" lang="en" data-textdirection="ltr">
|
<html id="html" class="loading" lang="en" data-textdirection="ltr">
|
||||||
@ -47,18 +48,44 @@
|
|||||||
data-menu="vertical-dark-menu" data-col="2-columns">
|
data-menu="vertical-dark-menu" data-col="2-columns">
|
||||||
<input id="copy-input" style="white-space: pre" class="hide">
|
<input id="copy-input" style="white-space: pre" class="hide">
|
||||||
|
|
||||||
|
{# System settings from database #}
|
||||||
<input id="settings-theme" class="hide" value="{{ settings.theme }}">
|
<input id="settings-theme" class="hide" value="{{ settings.theme }}">
|
||||||
<input id="settings-accent" class="hide" value="{{ settings.accent }}">
|
<input id="settings-accent" class="hide" value="{{ settings.accent }}">
|
||||||
|
<input id="settings-sidebar_default" class="hide" value="{{ settings.sidebar_default }}">
|
||||||
|
|
||||||
|
{# User settings from database #}
|
||||||
|
<input id="user-name" class="hide" value="{{ current_user.username }}">
|
||||||
|
<input id="user-theme" class="hide" value="{{ current_user.theme }}">
|
||||||
|
<input id="user-accent" class="hide" value="{{ current_user.accent }}">
|
||||||
|
<input id="user-sidebar_default" class="hide" value="{{ current_user.sidebar_default }}">
|
||||||
|
|
||||||
<script src="static/js/vendors/jquery.min.js"></script>
|
<script src="static/js/vendors/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<div id="update-message-modal" class="modal">
|
||||||
|
<div id="update-message-content" class="modal-content">
|
||||||
|
{{ update_message|safe }}
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
{{ button(
|
||||||
|
id="update-message-read-btn",
|
||||||
|
data={"url": url_for('main.update_message_read')},
|
||||||
|
icon="check_circle",
|
||||||
|
text="read"
|
||||||
|
) }}
|
||||||
|
|
||||||
|
{{ button(
|
||||||
|
class="modal-close",
|
||||||
|
icon="restore",
|
||||||
|
text="later"
|
||||||
|
) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% block header %}{% endblock header %}
|
{% block header %}{% endblock header %}
|
||||||
|
|
||||||
{% block sidenav %}{% endblock sidenav %}
|
{% block sidenav %}{% endblock sidenav %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}{% endblock content %}
|
||||||
{% endblock content %}
|
|
||||||
|
|
||||||
{% block footer %}{% endblock footer %}
|
{% block footer %}{% endblock footer %}
|
||||||
|
|
||||||
@ -86,13 +113,6 @@
|
|||||||
</style>
|
</style>
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
<!-- GLOBAL DOCUMENT VIEWER -->
|
|
||||||
<div id="pdf-viewer-modal" class="modal full-height-modal" style="overflow: hidden;">
|
|
||||||
<div class="modal-content p-0">
|
|
||||||
<embed id="pdf-viewer-modal-embed" src="" style="width: 100%; min-height: 99.4vh;">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@ -28,13 +28,13 @@
|
|||||||
<i class="material-icons prefix card-search-icon">search</i>
|
<i class="material-icons prefix card-search-icon">search</i>
|
||||||
<input type="text" id="apps-filter" class="card-filter theme-surface-transparent" placeholder="Search apps" autofocus>
|
<input type="text" id="apps-filter" class="card-filter theme-surface-transparent" placeholder="Search apps" autofocus>
|
||||||
|
|
||||||
{% if current_user.role == "admin" %}
|
{% if current_user.is_authenticated %}
|
||||||
{% if settings.home_view_mode == "list" %}
|
{% if current_user.home_view_mode == "list" %}
|
||||||
<a href="{{ url_for('main.change_home_view_mode', mode="grid") }}">
|
<a href="{{ url_for('main.change_home_view_mode', mode="grid", user_id=current_user.id) }}">
|
||||||
<i class="material-icons right filter-action pointer">apps</i>
|
<i class="material-icons right filter-action pointer">apps</i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url_for('main.change_home_view_mode', mode="list") }}">
|
<a href="{{ url_for('main.change_home_view_mode', mode="list", user_id=current_user.id) }}">
|
||||||
<i class="material-icons right filter-action pointer">list</i>
|
<i class="material-icons right filter-action pointer">list</i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -51,7 +51,7 @@
|
|||||||
{% if apps %}
|
{% if apps %}
|
||||||
{# If tags are enabled, render the apps like this #}
|
{# If tags are enabled, render the apps like this #}
|
||||||
{% if tags_form.tags.choices|count > 1 %}
|
{% if tags_form.tags.choices|count > 1 %}
|
||||||
{% if settings.home_view_mode == "list" %}
|
{% if settings.home_view_mode == "list" or current_user.home_view_mode == "list" %}
|
||||||
|
|
||||||
<div class="col s12 m12 l8">
|
<div class="col s12 m12 l8">
|
||||||
<div id="list-view-collection" class="collection">
|
<div id="list-view-collection" class="collection">
|
||||||
@ -96,8 +96,7 @@
|
|||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{# otherwise, render the apps like this #}
|
{# otherwise, render the apps like this #}
|
||||||
{% if settings.home_view_mode == "list" %}
|
{% if settings.home_view_mode == "list" or current_user.home_view_mode == "list" %}
|
||||||
|
|
||||||
<div class="col s12 m12 l8">
|
<div class="col s12 m12 l8">
|
||||||
<div id="list-view-collection" class="collection">
|
<div id="list-view-collection" class="collection">
|
||||||
{% for app in apps %}
|
{% for app in apps %}
|
||||||
|
@ -31,13 +31,13 @@
|
|||||||
<span class="menu-title" data-i18n="">Logout</span>
|
<span class="menu-title" data-i18n="">Logout</span>
|
||||||
</a></li>
|
</a></li>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="bold"><a id="logout-sidenav" class="waves-effect waves-cyan" href="{{ url_for('user_system.login') }}">
|
<li class="bold"><a id="login-sidenav" class="waves-effect waves-cyan" href="{{ url_for('user_system.login') }}">
|
||||||
<i class="material-icons-outlined">account_circle</i>
|
<i class="material-icons-outlined">account_circle</i>
|
||||||
<span class="menu-title" data-i18n="">Login</span>
|
<span class="menu-title" data-i18n="">Login</span>
|
||||||
</a></li>
|
</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<li class="bold"><a id="hide-sidenav" class="waves-effect waves-cyan" href="#">
|
<li class="bold"><a id="hide-sidenav" class="waves-effect waves-cyan hide-on-med-and-down" href="#">
|
||||||
<i class="material-icons-outlined">menu_open</i>
|
<i class="material-icons-outlined">menu_open</i>
|
||||||
<span class="menu-title" data-i18n="">Hide Sidenav</span>
|
<span class="menu-title" data-i18n="">Hide Sidenav</span>
|
||||||
</a></li>
|
</a></li>
|
||||||
@ -62,6 +62,27 @@
|
|||||||
{% endblock sidenav%}
|
{% endblock sidenav%}
|
||||||
|
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
|
<div id="no-sidenav" class="card theme-surface-transparent hide" style="position: fixed; bottom: 0; right: 10px;">
|
||||||
|
<div class="card-content p-1">
|
||||||
|
<span>
|
||||||
|
{% if current_user.is_authenticated %}
|
||||||
|
<a class="waves-effect waves-cyan" href="{{ url_for('user_system.logout') }}">
|
||||||
|
<i class="material-icons-outlined icon-btn">exit_to_app</i>
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="waves-effect waves-cyan" href="{{ url_for('user_system.login') }}">
|
||||||
|
<i class="material-icons-outlined icon-btn">account_circle</i>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<a class="waves-effect waves-cyan" href="{{ url_for('settings_system.settings') }}">
|
||||||
|
<i class="material-icons-outlined icon-btn">settings</i>
|
||||||
|
</a>
|
||||||
|
<a class="waves-effect waves-cyan" href="{{ url_for('main.home') }}">
|
||||||
|
<i class="material-icons-outlined icon-btn">dashboard</i>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- BEGIN: Footer-->
|
<!-- BEGIN: Footer-->
|
||||||
<!-- <footer class="page-footer footer footer-static footer-light navbar-border navbar-shadow">
|
<!-- <footer class="page-footer footer footer-static footer-light navbar-border navbar-shadow">
|
||||||
<div class="footer-copyright">
|
<div class="footer-copyright">
|
||||||
|
@ -12,3 +12,8 @@ class User(db.Model, UserMixin):
|
|||||||
username = db.Column(db.String(120), unique=True, nullable=False)
|
username = db.Column(db.String(120), unique=True, nullable=False)
|
||||||
password = db.Column(db.String(60), nullable=False)
|
password = db.Column(db.String(60), nullable=False)
|
||||||
role = db.Column(db.String())
|
role = db.Column(db.String())
|
||||||
|
theme = db.Column(db.String())
|
||||||
|
background = db.Column(db.String())
|
||||||
|
accent = db.Column(db.String())
|
||||||
|
home_view_mode = db.Column(db.String(), default="grid")
|
||||||
|
sidebar_default = db.Column(db.String())
|
||||||
|
@ -5,7 +5,9 @@ background = None
|
|||||||
roles = admin,user,public_user
|
roles = admin,user,public_user
|
||||||
home_access_groups = admin_only
|
home_access_groups = admin_only
|
||||||
settings_access_groups = admin_only
|
settings_access_groups = admin_only
|
||||||
|
home_view_mode = grid
|
||||||
custom_app_title = DashMachine
|
custom_app_title = DashMachine
|
||||||
|
sidebar_default = open
|
||||||
|
|
||||||
[admin]
|
[admin]
|
||||||
role = admin
|
role = admin
|
||||||
|
12
update_message.md
Normal file
12
update_message.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
##### Updated to version 0.5!
|
||||||
|
> In this version, I removed the need for database migrations by making the database 100% dynamic. Meaning when you run dashmachine your old site.db file will be deleted and a new one will be created using the data from config.ini. This will make adding features in the future easier and updates will break things less. To accomplish this you will notice that user management has been moved to config.ini. If you are upgrading from a previous version, your user table was deleted. Please login with default user/pass (which is now 'admin' and 'admin') and take a look at the users section in the readme to add users.
|
||||||
|
|
||||||
|
**Changelog**
|
||||||
|
- ui fixes
|
||||||
|
- users are now managed through config.ini
|
||||||
|
- no more alembic, completely dynamic database, created on startup
|
||||||
|
- users can now override global settings
|
||||||
|
- added update message
|
||||||
|
- performance fixes
|
||||||
|
- added setting for hiding sidebar by default
|
||||||
|
- fixes #41
|
Loading…
x
Reference in New Issue
Block a user