- reduced the size of app cards, moving description to a pop-open
- broke up config readme into 3 tabs, and 3 .md files - changed 'app templates' to 'card templates' - added 'collection' cards - added 'custom' cards - added options for setting tag icons and sort position - removed list view to focus on different card types on /home - added ability to collapse/expand tags on /home - added setting for having tags default to collapsed state - added settings for the default state of the sidebar - created a public user view with no sidebar - added sidebar default overrides for users
This commit is contained in:
parent
c28c29c2e0
commit
ff6b2372b3
@ -1,4 +1,12 @@
|
|||||||
#### Config.ini Readme
|
- [Main Settings](#main-settings)
|
||||||
|
* [Settings](#settings)
|
||||||
|
* [Users](#users)
|
||||||
|
* [Access Groups](#access-groups)
|
||||||
|
- [Cards](#cards)
|
||||||
|
* [Apps](#apps)
|
||||||
|
- [Data Source Platforms](#data-source-platforms)
|
||||||
|
|
||||||
|
#### Main Settings
|
||||||
|
|
||||||
##### Settings
|
##### Settings
|
||||||
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 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.
|
||||||
@ -10,7 +18,6 @@ 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
|
sidebar_default = open
|
||||||
```
|
```
|
||||||
@ -24,7 +31,6 @@ sidebar_default = open
|
|||||||
| 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 |
|
| sidebar_default | No | Select the default state for the sidebar | open, closed, no_sidebar |
|
||||||
|
|
||||||
@ -46,35 +52,6 @@ confirm_password = admin
|
|||||||
| theme | No | Override the theme from Settings for this user | same as Settings |
|
| 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 |
|
| 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 |
|
| 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
|
|
||||||
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
|
|
||||||
```ini
|
|
||||||
[App Name]
|
|
||||||
prefix = https://
|
|
||||||
url = your-website.com
|
|
||||||
icon = static/images/apps/default.png
|
|
||||||
sidebar_icon = static/images/apps/default.png
|
|
||||||
description = Example description
|
|
||||||
open_in = iframe
|
|
||||||
data_sources = None
|
|
||||||
tags = Example Tag
|
|
||||||
groups = admin_only
|
|
||||||
```
|
|
||||||
|
|
||||||
| Variable | Required | Description | Options |
|
|
||||||
|--------------|----------|-------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------|
|
|
||||||
| [App Name] | Yes | The name of your app. | [App Name] |
|
|
||||||
| prefix | Yes | The prefix for the app's url. | web prefix, e.g. http:// or https:// |
|
|
||||||
| url | Yes | The url for your app. | web url, e.g. myapp.com |
|
|
||||||
| open_in | Yes | open the app in the current tab, an iframe or a new tab | iframe, new_tab, this_tab |
|
|
||||||
| icon | Yes | Icon for the dashboard. | /static/images/icons/yourpicture.png, external link to image |
|
|
||||||
| sidebar_icon | No | Icon for the sidenav. | /static/images/icons/yourpicture.png, external link to image |
|
|
||||||
| description | No | A short description for the app. | string |
|
|
||||||
| data_sources | No | Data sources to be included on the app's card.*Note: you must have a data source set up in the config above this application entry. | comma separated string |
|
|
||||||
| tags | No | Optionally specify tags for organization on /home | 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 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
|
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
|
||||||
@ -122,6 +99,36 @@ 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.
|
||||||
|
|
||||||
|
#### Cards
|
||||||
|
|
||||||
|
##### Apps
|
||||||
|
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
|
||||||
|
```ini
|
||||||
|
[App Name]
|
||||||
|
prefix = https://
|
||||||
|
url = your-website.com
|
||||||
|
icon = static/images/apps/default.png
|
||||||
|
sidebar_icon = static/images/apps/default.png
|
||||||
|
description = Example description
|
||||||
|
open_in = iframe
|
||||||
|
data_sources = None
|
||||||
|
tags = Example Tag
|
||||||
|
groups = admin_only
|
||||||
|
```
|
||||||
|
|
||||||
|
| Variable | Required | Description | Options |
|
||||||
|
|--------------|----------|-------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------|
|
||||||
|
| [App Name] | Yes | The name of your app. | [App Name] |
|
||||||
|
| prefix | Yes | The prefix for the app's url. | web prefix, e.g. http:// or https:// |
|
||||||
|
| url | Yes | The url for your app. | web url, e.g. myapp.com |
|
||||||
|
| open_in | Yes | open the app in the current tab, an iframe or a new tab | iframe, new_tab, this_tab |
|
||||||
|
| icon | Yes | Icon for the dashboard. | /static/images/icons/yourpicture.png, external link to image |
|
||||||
|
| sidebar_icon | No | Icon for the sidenav. | /static/images/icons/yourpicture.png, external link to image |
|
||||||
|
| description | No | A short description for the app. | string |
|
||||||
|
| data_sources | No | Data sources to be included on the app's card.*Note: you must have a data source set up in the config above this application entry. | comma separated string |
|
||||||
|
| tags | No | Optionally specify tags for organization on /home | comma separated string |
|
||||||
|
| groups | No | Optionally the access groups that can see this app. | comma separated string |
|
||||||
|
|
||||||
#### Data Source Platforms
|
#### Data Source Platforms
|
||||||
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!
|
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!
|
||||||
|
|
||||||
|
@ -28,6 +28,8 @@ class Apps(db.Model):
|
|||||||
data_template = db.Column(db.String())
|
data_template = db.Column(db.String())
|
||||||
groups = db.Column(db.String())
|
groups = db.Column(db.String())
|
||||||
tags = db.Column(db.String())
|
tags = db.Column(db.String())
|
||||||
|
type = db.Column(db.String())
|
||||||
|
urls = db.Column(db.String())
|
||||||
|
|
||||||
|
|
||||||
class DataSources(db.Model):
|
class DataSources(db.Model):
|
||||||
@ -58,3 +60,5 @@ class Groups(db.Model):
|
|||||||
class Tags(db.Model):
|
class Tags(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
name = db.Column(db.String())
|
name = db.Column(db.String())
|
||||||
|
icon = db.Column(db.String())
|
||||||
|
sort_pos = db.Column(db.Integer)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import json
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from dashmachine.main.models import Apps, Groups, DataSources, DataSourcesArgs, Tags
|
from dashmachine.main.models import Apps, Groups, DataSources, DataSourcesArgs, Tags
|
||||||
from dashmachine.user_system.models import User
|
from dashmachine.user_system.models import User
|
||||||
@ -68,7 +69,6 @@ def read_config():
|
|||||||
settings.settings_access_groups = config["Settings"].get(
|
settings.settings_access_groups = config["Settings"].get(
|
||||||
"settings_access_groups", "admin_only"
|
"settings_access_groups", "admin_only"
|
||||||
)
|
)
|
||||||
settings.home_view_mode = config["Settings"].get("home_view_mode", "grid")
|
|
||||||
|
|
||||||
settings.custom_app_title = config["Settings"].get(
|
settings.custom_app_title = config["Settings"].get(
|
||||||
"custom_app_title", "DashMachine"
|
"custom_app_title", "DashMachine"
|
||||||
@ -76,6 +76,8 @@ def read_config():
|
|||||||
|
|
||||||
settings.sidebar_default = config["Settings"].get("sidebar_default", "open")
|
settings.sidebar_default = config["Settings"].get("sidebar_default", "open")
|
||||||
|
|
||||||
|
settings.tags_expanded = config["Settings"].get("tags_expanded", "True")
|
||||||
|
|
||||||
db.session.add(settings)
|
db.session.add(settings)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
@ -85,9 +87,9 @@ def read_config():
|
|||||||
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.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.theme = config[section].get("theme", None)
|
||||||
user.accent = config[section].get("accent", None)
|
user.accent = config[section].get("accent", None)
|
||||||
|
user.tags_expanded = config[section].get("tags_expanded", 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(
|
||||||
@ -146,35 +148,25 @@ def read_config():
|
|||||||
# App creation
|
# App creation
|
||||||
app = Apps()
|
app = Apps()
|
||||||
app.name = section
|
app.name = section
|
||||||
if "prefix" in config[section]:
|
app.type = config[section].get("type", "app")
|
||||||
app.prefix = config[section]["prefix"]
|
|
||||||
else:
|
app.prefix = config[section].get("prefix", None)
|
||||||
|
if app.type == "app" and not app.prefix:
|
||||||
return {"msg": f"Invalid Config: {section} does not contain prefix."}
|
return {"msg": f"Invalid Config: {section} does not contain prefix."}
|
||||||
|
|
||||||
if "url" in config[section]:
|
app.url = config[section].get("url", None)
|
||||||
app.url = config[section]["url"]
|
if app.type == "app" and not app.url:
|
||||||
else:
|
|
||||||
return {"msg": f"Invalid Config: {section} does not contain url."}
|
return {"msg": f"Invalid Config: {section} does not contain url."}
|
||||||
|
|
||||||
if "icon" in config[section]:
|
app.icon = config[section].get("icon", None)
|
||||||
app.icon = config[section]["icon"]
|
|
||||||
else:
|
|
||||||
app.icon = None
|
|
||||||
|
|
||||||
if "sidebar_icon" in config[section]:
|
app.sidebar_icon = config[section].get("sidebar_icon", None)
|
||||||
app.sidebar_icon = config[section]["sidebar_icon"]
|
|
||||||
else:
|
|
||||||
app.sidebar_icon = app.icon
|
|
||||||
|
|
||||||
if "description" in config[section]:
|
app.description = config[section].get("description", None)
|
||||||
app.description = config[section]["description"]
|
|
||||||
else:
|
|
||||||
app.description = None
|
|
||||||
|
|
||||||
if "open_in" in config[section]:
|
app.open_in = config[section].get("open_in", "this_tab")
|
||||||
app.open_in = config[section]["open_in"]
|
|
||||||
else:
|
app.urls = config[section].get("urls", None)
|
||||||
app.open_in = "this_tab"
|
|
||||||
|
|
||||||
if "groups" in config[section]:
|
if "groups" in config[section]:
|
||||||
for group_name in config[section]["groups"].split(","):
|
for group_name in config[section]["groups"].split(","):
|
||||||
@ -186,14 +178,18 @@ def read_config():
|
|||||||
else:
|
else:
|
||||||
app.groups = None
|
app.groups = None
|
||||||
|
|
||||||
|
# Tags creation
|
||||||
if "tags" in config[section]:
|
if "tags" in config[section]:
|
||||||
app.tags = config[section]["tags"].title()
|
app.tags = config[section]["tags"]
|
||||||
for tag in app.tags.split(","):
|
for tag in app.tags.split(","):
|
||||||
tag = tag.strip().title()
|
tag = tag.strip()
|
||||||
if not Tags.query.filter_by(name=tag).first():
|
if not Tags.query.filter_by(name=tag).first():
|
||||||
tag_db = Tags(name=tag)
|
tag_db = Tags(name=tag)
|
||||||
db.session.add(tag_db)
|
db.session.add(tag_db)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
tag_db.sort_pos = tag_db.id
|
||||||
|
db.session.merge(tag_db)
|
||||||
|
db.session.commit()
|
||||||
else:
|
else:
|
||||||
if Tags.query.first():
|
if Tags.query.first():
|
||||||
app.tags = "Untagged"
|
app.tags = "Untagged"
|
||||||
@ -227,6 +223,23 @@ def read_config():
|
|||||||
db.session.add(group)
|
db.session.add(group)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
tags_settings = config["Settings"].get("tags", None)
|
||||||
|
if tags_settings:
|
||||||
|
tags_settings = tags_settings.replace("},{", "}%,%{").split("%,%")
|
||||||
|
|
||||||
|
for tag_setting in tags_settings:
|
||||||
|
tag_json = json.loads(tag_setting)
|
||||||
|
tag = Tags.query.filter_by(name=tag_json.get("name", None)).first()
|
||||||
|
if tag:
|
||||||
|
icon = tag_json.get("icon", None)
|
||||||
|
if icon:
|
||||||
|
tag.icon = icon
|
||||||
|
sort_pos = tag_json.get("sort_pos", None)
|
||||||
|
if icon:
|
||||||
|
tag.sort_pos = sort_pos
|
||||||
|
db.session.merge(tag)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
clean_auth_cache()
|
clean_auth_cache()
|
||||||
if not User.query.first():
|
if not User.query.first():
|
||||||
user = User()
|
user = User()
|
||||||
|
@ -48,14 +48,20 @@ def home():
|
|||||||
|
|
||||||
|
|
||||||
@main.route("/app_view?<app_id>", methods=["GET"])
|
@main.route("/app_view?<app_id>", methods=["GET"])
|
||||||
def app_view(app_id):
|
@main.route("/app_view?<url>", methods=["GET"])
|
||||||
|
def app_view(app_id, url=None):
|
||||||
settings = Settings.query.first()
|
settings = Settings.query.first()
|
||||||
if not check_groups(settings.home_access_groups, current_user):
|
if not check_groups(settings.home_access_groups, current_user):
|
||||||
return redirect(url_for("user_system.login"))
|
return redirect(url_for("user_system.login"))
|
||||||
|
|
||||||
|
if url:
|
||||||
|
title = url
|
||||||
|
|
||||||
|
if not url:
|
||||||
app_db = Apps.query.filter_by(id=app_id).first()
|
app_db = Apps.query.filter_by(id=app_id).first()
|
||||||
return render_template(
|
url = f"{app_db.prefix}{app_db.url}"
|
||||||
"main/app-view.html", url=f"{app_db.prefix}{app_db.url}", title=app_db.name
|
title = app_db.name
|
||||||
)
|
return render_template("main/app-view.html", url=url, title=title)
|
||||||
|
|
||||||
|
|
||||||
@main.route("/load_data_source", methods=["GET"])
|
@main.route("/load_data_source", methods=["GET"])
|
||||||
@ -65,19 +71,6 @@ def load_data_source():
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@main.route("/change_home_view_mode?<mode>%<user_id>", methods=["GET"])
|
|
||||||
def change_home_view_mode(mode, user_id):
|
|
||||||
user = User.query.filter_by(id=user_id).first()
|
|
||||||
config = ConfigParser()
|
|
||||||
config.read(os.path.join(user_data_folder, "config.ini"))
|
|
||||||
config.set(user.username, "home_view_mode", mode)
|
|
||||||
config.write(open(os.path.join(user_data_folder, "config.ini"), "w"))
|
|
||||||
user.home_view_mode = mode
|
|
||||||
db.session.merge(user)
|
|
||||||
db.session.commit()
|
|
||||||
return redirect(url_for("main.home"))
|
|
||||||
|
|
||||||
|
|
||||||
@main.route("/update_message_read", methods=["GET"])
|
@main.route("/update_message_read", methods=["GET"])
|
||||||
def update_message_read():
|
def update_message_read():
|
||||||
mark_update_message_read()
|
mark_update_message_read()
|
||||||
|
@ -9,6 +9,6 @@ class Settings(db.Model):
|
|||||||
roles = db.Column(db.String())
|
roles = db.Column(db.String())
|
||||||
home_access_groups = db.Column(db.String())
|
home_access_groups = db.Column(db.String())
|
||||||
settings_access_groups = db.Column(db.String())
|
settings_access_groups = 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())
|
sidebar_default = db.Column(db.String())
|
||||||
|
tags_expanded = db.Column(db.String())
|
||||||
|
@ -18,19 +18,8 @@ def load_files_html():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_config_html():
|
def convert_html_to_md(md):
|
||||||
with open(os.path.join(root_folder, "config_readme.md")) as readme_file:
|
html = markdown(
|
||||||
md = readme_file.read()
|
|
||||||
platforms = os.listdir(platform_folder)
|
|
||||||
platforms = sorted(platforms)
|
|
||||||
for platform in platforms:
|
|
||||||
name, extension = os.path.splitext(platform)
|
|
||||||
if extension.lower() == ".py":
|
|
||||||
module = importlib.import_module(f"dashmachine.platform.{name}", ".")
|
|
||||||
if module.__doc__:
|
|
||||||
md += module.__doc__
|
|
||||||
|
|
||||||
config_html = markdown(
|
|
||||||
md,
|
md,
|
||||||
extras=[
|
extras=[
|
||||||
"tables",
|
"tables",
|
||||||
@ -40,4 +29,28 @@ def get_config_html():
|
|||||||
"code-friendly",
|
"code-friendly",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
return config_html
|
return html
|
||||||
|
|
||||||
|
|
||||||
|
def get_config_html():
|
||||||
|
with open(os.path.join(root_folder, "readme_settings.md")) as readme_file:
|
||||||
|
md = readme_file.read()
|
||||||
|
html = {"settings": convert_html_to_md(md)}
|
||||||
|
|
||||||
|
with open(os.path.join(root_folder, "readme_cards.md")) as readme_file:
|
||||||
|
md = readme_file.read()
|
||||||
|
html["cards"] = convert_html_to_md(md)
|
||||||
|
|
||||||
|
with open(os.path.join(root_folder, "readme_data_sources.md")) as readme_file:
|
||||||
|
md = readme_file.read()
|
||||||
|
platforms = os.listdir(platform_folder)
|
||||||
|
platforms = sorted(platforms)
|
||||||
|
for platform in platforms:
|
||||||
|
name, extension = os.path.splitext(platform)
|
||||||
|
if extension.lower() == ".py":
|
||||||
|
module = importlib.import_module(f"dashmachine.platform.{name}", ".")
|
||||||
|
if module.__doc__:
|
||||||
|
md += module.__doc__
|
||||||
|
html["data_sources"] = convert_html_to_md(md)
|
||||||
|
|
||||||
|
return html
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import os
|
import os
|
||||||
|
import json
|
||||||
import random
|
import random
|
||||||
from jsmin import jsmin
|
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, Tags
|
||||||
from dashmachine.main.utils import check_groups, get_update_message_html
|
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
|
||||||
@ -73,24 +74,38 @@ def process_css_sources(process_bundle=None, src=None, app_global=False):
|
|||||||
return html
|
return html
|
||||||
|
|
||||||
|
|
||||||
|
def tag_sort_func(e):
|
||||||
|
return e.sort_pos
|
||||||
|
|
||||||
|
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
def context_processor():
|
def context_processor():
|
||||||
apps = []
|
apps = []
|
||||||
|
temp_tags = []
|
||||||
tags = []
|
tags = []
|
||||||
apps_db = Apps.query.all()
|
apps_db = Apps.query.all()
|
||||||
for app_db in apps_db:
|
for app_db in apps_db:
|
||||||
|
if app_db.urls:
|
||||||
|
url_list = app_db.urls.replace("},{", "}%,%{").split("%,%")
|
||||||
|
app_db.urls_json = []
|
||||||
|
for url in url_list:
|
||||||
|
app_db.urls_json.append(json.loads(url))
|
||||||
if not app_db.groups:
|
if not app_db.groups:
|
||||||
app_db.groups = None
|
app_db.groups = None
|
||||||
if check_groups(app_db.groups, current_user):
|
if check_groups(app_db.groups, current_user):
|
||||||
apps.append(app_db)
|
apps.append(app_db)
|
||||||
if app_db.tags:
|
if app_db.tags:
|
||||||
tags += app_db.tags.split(",")
|
temp_tags += app_db.tags.split(",")
|
||||||
|
|
||||||
tags_form = TagsForm()
|
tags_form = TagsForm()
|
||||||
if len(tags) > 0:
|
if len(temp_tags) > 0:
|
||||||
tags = [tag.strip() for tag in tags]
|
temp_tags = list(dict.fromkeys([tag.strip() for tag in temp_tags]))
|
||||||
tags = list(dict.fromkeys(tags))
|
tags_form.tags.choices += [(tag, tag) for tag in temp_tags]
|
||||||
tags_form.tags.choices += [(tag, tag) for tag in tags]
|
for tag in temp_tags:
|
||||||
|
tag_db = Tags.query.filter_by(name=tag).first()
|
||||||
|
if tag_db:
|
||||||
|
tags.append(tag_db)
|
||||||
|
tags.sort(key=tag_sort_func)
|
||||||
settings = Settings.query.first()
|
settings = Settings.query.first()
|
||||||
if settings.background == "random":
|
if settings.background == "random":
|
||||||
if len(os.listdir(backgrounds_images_folder)) < 1:
|
if len(os.listdir(backgrounds_images_folder)) < 1:
|
||||||
@ -107,6 +122,7 @@ def context_processor():
|
|||||||
process_css_sources=process_css_sources,
|
process_css_sources=process_css_sources,
|
||||||
apps=apps,
|
apps=apps,
|
||||||
settings=settings,
|
settings=settings,
|
||||||
|
tags=tags,
|
||||||
tags_form=tags_form,
|
tags_form=tags_form,
|
||||||
update_message=update_message,
|
update_message=update_message,
|
||||||
)
|
)
|
||||||
|
@ -399,7 +399,10 @@ input:disabled {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: var(--theme-surface);
|
background: var(--theme-surface);
|
||||||
}
|
}
|
||||||
|
.card .card-reveal {
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--theme-surface);
|
||||||
|
}
|
||||||
|
|
||||||
/* TABS */
|
/* TABS */
|
||||||
.tabs {
|
.tabs {
|
||||||
|
@ -17,11 +17,16 @@
|
|||||||
@media screen and (max-width: 992px) {
|
@media screen and (max-width: 992px) {
|
||||||
.tags-select-col {
|
.tags-select-col {
|
||||||
top: 0;
|
top: 0;
|
||||||
width: calc(100vw - 45px) !important;
|
/*width: calc(100vw - 45px) !important;*/
|
||||||
margin-left: 15px !important;
|
/*margin-left: 15px !important;*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-card .card-reveal {
|
||||||
|
position:
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#list-view-collection .app-a {
|
#list-view-collection .app-a {
|
||||||
background: rgba(var(--theme-surface-rgb), 0.8);
|
background: rgba(var(--theme-surface-rgb), 0.8);
|
||||||
}
|
}
|
||||||
|
@ -28,18 +28,18 @@
|
|||||||
background: var(--theme-surface-1);
|
background: var(--theme-surface-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#config-readme h5 {
|
#settings-readme h5, #cards-readme h5, #data-sources-readme h5 {
|
||||||
color: var(--theme-primary);
|
color: var(--theme-primary);
|
||||||
margin-top: 5%;
|
margin-top: 5%;
|
||||||
}
|
}
|
||||||
#config-readme h4 {
|
#settings-readme h4, #cards-readme h4, #data-sources-readme h4 {
|
||||||
color: var(--theme-color-font-muted);
|
color: var(--theme-color-font-muted);
|
||||||
margin-top: 5%;
|
margin-top: 5%;
|
||||||
}
|
}
|
||||||
#configini-readme {
|
#configini-readme {
|
||||||
margin-top: 2% !important;
|
margin-top: 2% !important;
|
||||||
}
|
}
|
||||||
#config-readme code {
|
#settings-readme code, #cards-readme code, #data-sources-readme code {
|
||||||
-webkit-touch-callout: all;
|
-webkit-touch-callout: all;
|
||||||
-webkit-user-select: all;
|
-webkit-user-select: all;
|
||||||
-khtml-user-select: all;
|
-khtml-user-select: all;
|
||||||
@ -49,10 +49,10 @@
|
|||||||
cursor: text;
|
cursor: text;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
#config-readme th {
|
#settings-readme th, #cards-readme th, #data-sources-readme th {
|
||||||
color: var(--theme-primary);
|
color: var(--theme-primary);
|
||||||
}
|
}
|
||||||
#config-readme td {
|
#settings-readme td, #cards-readme td, #data-sources-readme td {
|
||||||
-webkit-touch-callout: text !important;
|
-webkit-touch-callout: text !important;
|
||||||
-webkit-user-select: text !important;
|
-webkit-user-select: text !important;
|
||||||
-khtml-user-select: text !important;
|
-khtml-user-select: text !important;
|
||||||
@ -61,6 +61,6 @@
|
|||||||
user-select: text !important;
|
user-select: text !important;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
#config-readme strong {
|
#settings-readme strong, #cards-readme strong, #data-sources-readme strong {
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
}
|
}
|
@ -1,22 +1,49 @@
|
|||||||
var d = document.getElementById("dashboard-sidenav");
|
var d = document.getElementById("dashboard-sidenav");
|
||||||
d.className += " active theme-primary";
|
d.className += " active theme-primary";
|
||||||
|
|
||||||
|
function get_data_source(el){
|
||||||
|
el.html("");
|
||||||
|
el.closest('.col').find('.data-source-loading').removeClass('hide');
|
||||||
|
$.ajax({
|
||||||
|
async: true,
|
||||||
|
url: el.attr('data-url'),
|
||||||
|
type: 'GET',
|
||||||
|
data: {id: el.attr('data-id')},
|
||||||
|
success: function(data){
|
||||||
|
el.closest('.col').find('.data-source-loading').addClass('hide');
|
||||||
|
el.html(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$( document ).ready(function() {
|
$( document ).ready(function() {
|
||||||
$(".tooltipped").tooltip();
|
$(".tooltipped").tooltip();
|
||||||
$("#apps-filter").on('keyup', function(e) {
|
$("#apps-filter").on('keyup', function(e) {
|
||||||
|
$(".toggle-tag-expand-btn").each(function(e) {
|
||||||
|
if ($(this).attr("data-expanded") == 'false'){
|
||||||
|
$(this)[0].click();
|
||||||
|
}
|
||||||
|
});
|
||||||
var value = $(this).val().toLowerCase();
|
var value = $(this).val().toLowerCase();
|
||||||
$(".app-a").each(function(i, e) {
|
|
||||||
if ($(this).attr("data-name").toLowerCase().indexOf(value) > -1
|
$(".app-card").each(function(e) {
|
||||||
|| $(this).attr("data-description").toLowerCase().indexOf(value) > -1) {
|
var x = 0
|
||||||
|
$(this).find('.searchable').each(function(e) {
|
||||||
|
if ($(this).text().toLowerCase().indexOf(value) > -1) {
|
||||||
|
x = x + 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (x > 0){
|
||||||
$(this).removeClass('hide');
|
$(this).removeClass('hide');
|
||||||
} else {
|
} else {
|
||||||
$(this).addClass('hide');
|
$(this).addClass('hide');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(".tag-group").each(function(i, e) {
|
$(".tag-group").each(function(i, e) {
|
||||||
var x = 0
|
var x = 0
|
||||||
$(this).find('.app-a').each(function(i, e) {
|
$(this).find('.app-card').each(function(i, e) {
|
||||||
if ($(this).hasClass("hide") === false){
|
if ($(this).hasClass("hide") === false){
|
||||||
x = x + 1
|
x = x + 1
|
||||||
}
|
}
|
||||||
@ -30,22 +57,22 @@ $( document ).ready(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$(".data-source-container").each(function(e) {
|
$(".data-source-container").each(function(e) {
|
||||||
var el = $(this);
|
get_data_source($(this));
|
||||||
$.ajax({
|
});
|
||||||
async: true,
|
|
||||||
url: el.attr('data-url'),
|
$(".refresh-data-source-btn").on('click', function(e) {
|
||||||
type: 'GET',
|
e.preventDefault();
|
||||||
data: {id: el.attr('data-id')},
|
$(this).closest('.app-card').find(".data-source-container").each(function(e) {
|
||||||
success: function(data){
|
get_data_source($(this));
|
||||||
el.closest('.col').find('.data-source-loading').addClass('hide');
|
|
||||||
el.html(data);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#tags-select").on('change', function(e) {
|
$("#tags-select").on('change', function(e) {
|
||||||
var value = $(this).val();
|
var value = $(this).val();
|
||||||
$(".tag-group").each(function(i, e) {
|
$(".tag-group").each(function(i, e) {
|
||||||
|
if ($(this).find('.toggle-tag-expand-btn').attr("data-expanded") == "false"){
|
||||||
|
$(this).find('.toggle-tag-expand-btn')[0].click();
|
||||||
|
}
|
||||||
if ($(this).attr("data-tag").indexOf(value) > -1 || value === "All tags") {
|
if ($(this).attr("data-tag").indexOf(value) > -1 || value === "All tags") {
|
||||||
$(this).removeClass('filtered');
|
$(this).removeClass('filtered');
|
||||||
} else {
|
} else {
|
||||||
@ -54,4 +81,52 @@ $( document ).ready(function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(".toggle-tag-expand-btn").on('click', function(e) {
|
||||||
|
if ($(this).attr("data-expanded") == "true"){
|
||||||
|
$(this).attr("data-expanded", "false");
|
||||||
|
$(this).text('keyboard_arrow_down');
|
||||||
|
$(this).closest('.tag-group').find('.tag-apps-row').addClass('hide');
|
||||||
|
} else {
|
||||||
|
$(this).attr("data-expanded", "true");
|
||||||
|
$(this).text('keyboard_arrow_up');
|
||||||
|
$(this).closest('.tag-group').find('.tag-apps-row').removeClass('hide');
|
||||||
|
}
|
||||||
|
var x = 0
|
||||||
|
$(".toggle-tag-expand-btn").each(function(e) {
|
||||||
|
if ($(this).attr("data-expanded") == "true") {
|
||||||
|
x = x + 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (x > 0) {
|
||||||
|
$("#toggle-tag-expand-all-btn").text('unfold_less');
|
||||||
|
} else {
|
||||||
|
$("#toggle-tag-expand-all-btn").text('unfold_more');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#toggle-tag-expand-all-btn").on('click', function(e) {
|
||||||
|
if ($(this).text() == "unfold_more") {
|
||||||
|
$(".toggle-tag-expand-btn").each(function(e) {
|
||||||
|
$(this)[0].click();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$(".toggle-tag-expand-btn").each(function(e) {
|
||||||
|
if ($(this).attr("data-expanded") == "true"){
|
||||||
|
$(this)[0].click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($("#settings-tags_expanded").val() == "False" || $("#user-tags_expanded").val() == "False"){
|
||||||
|
$(".toggle-tag-expand-btn").each(function(e) {
|
||||||
|
$(this)[0].click();
|
||||||
|
});
|
||||||
|
if ($("#user-tags_expanded").val() == "True"){
|
||||||
|
$(".toggle-tag-expand-btn").each(function(e) {
|
||||||
|
$(this)[0].click();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
@ -2,7 +2,7 @@ var d = document.getElementById("settings-sidenav");
|
|||||||
d.className += " active theme-primary";
|
d.className += " active theme-primary";
|
||||||
|
|
||||||
$( document ).ready(function() {
|
$( document ).ready(function() {
|
||||||
$("#config-readme table").addClass('responsive-table');
|
$("#settings-readme table").addClass('responsive-table');
|
||||||
initTCdrop('#images-tcdrop');
|
initTCdrop('#images-tcdrop');
|
||||||
$("#user-modal").modal({
|
$("#user-modal").modal({
|
||||||
onCloseEnd: function () {
|
onCloseEnd: function () {
|
||||||
|
@ -52,12 +52,14 @@
|
|||||||
<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 }}">
|
<input id="settings-sidebar_default" class="hide" value="{{ settings.sidebar_default }}">
|
||||||
|
<input id="settings-tags_expanded" class="hide" value="{{ settings.tags_expanded }}">
|
||||||
|
|
||||||
{# User settings from database #}
|
{# User settings from database #}
|
||||||
<input id="user-name" class="hide" value="{{ current_user.username }}">
|
<input id="user-name" class="hide" value="{{ current_user.username }}">
|
||||||
<input id="user-theme" class="hide" value="{{ current_user.theme }}">
|
<input id="user-theme" class="hide" value="{{ current_user.theme }}">
|
||||||
<input id="user-accent" class="hide" value="{{ current_user.accent }}">
|
<input id="user-accent" class="hide" value="{{ current_user.accent }}">
|
||||||
<input id="user-sidebar_default" class="hide" value="{{ current_user.sidebar_default }}">
|
<input id="user-sidebar_default" class="hide" value="{{ current_user.sidebar_default }}">
|
||||||
|
<input id="user-tags_expanded" class="hide" value="{{ current_user.tags_expanded }}">
|
||||||
|
|
||||||
<script src="static/js/vendors/jquery.min.js"></script>
|
<script src="static/js/vendors/jquery.min.js"></script>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{% extends "main/layout.html" %}
|
{% extends "main/layout.html" %}
|
||||||
{% from 'global_macros.html' import data, preload_circle, select %}
|
{% from 'global_macros.html' import data, preload_circle, select %}
|
||||||
{% from 'main/macros.html' import GridViewApp, ListViewApp %}
|
{% from 'main/macros.html' import App, Collection, Custom %}
|
||||||
|
|
||||||
{% block page_vendor_css %}
|
{% block page_vendor_css %}
|
||||||
{% endblock page_vendor_css %}
|
{% endblock page_vendor_css %}
|
||||||
@ -23,26 +23,16 @@
|
|||||||
<div id="main" class="main-full">
|
<div id="main" class="main-full">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row card-filter-container">
|
<div class="row card-filter-container">
|
||||||
<div class="col s12 l4 input-field">
|
<div class="col s12 m12 l6 xl4 input-field">
|
||||||
<span>
|
<span>
|
||||||
<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.is_authenticated %}
|
<i id="toggle-tag-expand-all-btn" class="material-icons right filter-action pointer">unfold_less</i>
|
||||||
{% if current_user.home_view_mode == "list" %}
|
|
||||||
<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>
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
<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>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% if tags_form.tags.choices|count > 1 %}
|
{% if tags_form.tags.choices|count > 1 %}
|
||||||
<div class="input-field col s12 l2 tags-select-col theme-surface-transparent">
|
<div class="input-field col s6 m4 l2 offset-s3 offset-m4 tags-select-col theme-surface-transparent">
|
||||||
{{ tags_form.tags(id='tags-select') }}
|
{{ tags_form.tags(id='tags-select') }}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -50,69 +40,47 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
{% 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|count > 1 %}
|
||||||
{% if settings.home_view_mode == "list" or current_user.home_view_mode == "list" %}
|
{% for tag in tags %}
|
||||||
|
<div class="tag-group" data-tag="{{ tag.name }}">
|
||||||
<div class="col s12 m12 l8">
|
|
||||||
<div id="list-view-collection" class="collection">
|
|
||||||
{% for tag in tags_form.tags.choices %}
|
|
||||||
{% if tag[0] != 'All tags' %}
|
|
||||||
<div class="tag-group" data-tag="{{ tag[0] }}">
|
|
||||||
<a class="collection-item font-weight-600 theme-on-primary-text theme-primary" style="font-size: 1.2em">{{ tag[0] }}</a>
|
|
||||||
{% for app in apps %}
|
|
||||||
{% if app.tags and tag[0] in app.tags %}
|
|
||||||
{{ ListViewApp(app) }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
{% for tag in tags_form.tags.choices %}
|
|
||||||
{% if tag[0] != 'All tags' %}
|
|
||||||
<div class="tag-group" data-tag="{{ tag[0] }}">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col s12 m6 l2">
|
|
||||||
<div class="card center-align theme-primary">
|
|
||||||
<h5 class="theme-on-primary-text">{{ tag[0] }}</h5>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
{% for app in apps %}
|
|
||||||
{% if app.tags and tag[0] in app.tags %}
|
|
||||||
{{ GridViewApp(app) }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
</div>
|
<div class="row">
|
||||||
|
<div class="col s12 m12 l6 xl4">
|
||||||
|
<div class="card theme-surface-transparent">
|
||||||
|
<div class="card-content pt-1 pb-1">
|
||||||
|
<h5 class="">
|
||||||
|
{% if tag.icon %}
|
||||||
|
<i class="material-icons-outlined mr-2 theme-primary-text" style="position: relative; top: .2rem">{{ tag.icon }}</i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{{ tag.name }}
|
||||||
|
<i class="material-icons-outlined theme-secondary-text icon-btn toggle-tag-expand-btn right" data-expanded="true">keyboard_arrow_up</i>
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row tag-apps-row">
|
||||||
|
{% for app in apps %}
|
||||||
|
{% if app.tags and tag.name in app.tags %}
|
||||||
|
{% if app.type == "app" %}
|
||||||
|
{{ App(app) }}
|
||||||
|
{% elif app.type == "collection" %}
|
||||||
|
{{ Collection(app) }}
|
||||||
|
{% elif app.type == "custom" %}
|
||||||
|
{{ Custom(app) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{# otherwise, render the apps like this #}
|
{# otherwise, render the apps like this #}
|
||||||
{% if settings.home_view_mode == "list" or current_user.home_view_mode == "list" %}
|
|
||||||
<div class="col s12 m12 l8">
|
|
||||||
<div id="list-view-collection" class="collection">
|
|
||||||
{% for app in apps %}
|
|
||||||
{{ ListViewApp(app) }}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
{% for app in apps %}
|
{% for app in apps %}
|
||||||
{{ GridViewApp(app) }}
|
{{ GridViewApp(app) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url_for('settings_system.settings') }}">
|
<a href="{{ url_for('settings_system.settings') }}">
|
||||||
<div class="col s12 m6 l3">
|
<div class="col s12 m6 l3">
|
||||||
|
@ -43,11 +43,13 @@
|
|||||||
</a></li>
|
</a></li>
|
||||||
|
|
||||||
{% for app in apps %}
|
{% for app in apps %}
|
||||||
|
{% if app.type == "app" and app.sidebar_icon %}
|
||||||
<li class="bold">
|
<li class="bold">
|
||||||
{{ AppAnchor(app) }}
|
{{ AppAnchor(app) }}
|
||||||
<img src="{{ app.sidebar_icon }}" style="position: relative; top: 5px; left: 2px; margin-right: 18px; height: 24px">
|
<img src="{{ app.sidebar_icon }}" style="position: relative; top: 5px; left: 2px; margin-right: 18px; height: 24px">
|
||||||
<span class="menu-title" data-i18n="">{{ app.name }}</span>
|
<span class="menu-title" data-i18n="">{{ app.name }}</span>
|
||||||
</a></li>
|
</a></li>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
{% from 'global_macros.html' import preload_circle %}
|
{% from 'global_macros.html' import preload_circle %}
|
||||||
|
|
||||||
{% macro AppAnchor(app, classes=None) %}
|
{% macro AppAnchor(app, classes=None, override=None) %}
|
||||||
{% if app.open_in == 'iframe' %}
|
{% if override == 'iframe' or app.open_in == 'iframe' and override == None %}
|
||||||
<a href="{{ url_for('main.app_view', app_id=app.id) }}" class="app-a {{ classes }}" data-name="{{ app.name }}" data-description="{{ app.description }}" data-tags="{{ app.tags }}">
|
<a href="{{ url_for('main.app_view', app_id=app.id) }}" class="app-a {{ classes }}" data-name="{{ app.name }}" data-description="{{ app.description }}" data-tags="{{ app.tags }}">
|
||||||
{% elif app.open_in == 'this_tab' %}
|
{% elif override == 'this_tab' or app.open_in == 'this_tab' and override == None %}
|
||||||
<a href="{{ app.prefix }}{{ app.url }}" class="app-a {{ classes }}" data-name="{{ app.name }}" data-description="{{ app.description }}" data-tags="{{ app.tags }}">
|
<a href="{{ app.prefix }}{{ app.url }}" class="app-a {{ classes }}" data-name="{{ app.name }}" data-description="{{ app.description }}" data-tags="{{ app.tags }}">
|
||||||
{% elif app.open_in == "new_tab" %}
|
{% elif override == 'new_tab' or app.open_in == "new_tab" and override == None %}
|
||||||
<a href="{{ app.prefix }}{{ app.url }}" target="_blank" class="app-a {{ classes }}" data-name="{{ app.name }}" data-description="{{ app.description }}" data-tags="{{ app.tags }}">
|
<a href="{{ app.prefix }}{{ app.url }}" target="_blank" class="app-a {{ classes }}" data-name="{{ app.name }}" data-description="{{ app.description }}" data-tags="{{ app.tags }}">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro GridViewApp(app) %}
|
{% macro App(app) %}
|
||||||
|
<div class="col s12 m6 l4 xl3 app-card">
|
||||||
|
<div class="card theme-surface-transparent">
|
||||||
{{ AppAnchor(app) }}
|
{{ AppAnchor(app) }}
|
||||||
<div class="col s12 m6 l3">
|
<div class="card-content center-align scrollbar pt-3 pb-0" style="max-height: 86px; min-height: 86px; scrollbar-width: none;">
|
||||||
<div class="card theme-surface-transparent app-card">
|
|
||||||
<div class="card-content center-align scrollbar" style="max-height: 118px; min-height: 118px; scrollbar-width: none;">
|
|
||||||
{% if app.data_sources.count() > 0 %}
|
{% if app.data_sources.count() > 0 %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col s6 center-align">
|
<div class="col s6 center-align">
|
||||||
@ -22,7 +22,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col s6 left-align">
|
<div class="col s6 left-align">
|
||||||
<span class="data-source-loading">{{ preload_circle() }}</span>
|
<div class="progress data-source-loading">
|
||||||
|
<div class="indeterminate"></div>
|
||||||
|
</div>
|
||||||
{% for data_source in app.data_sources %}
|
{% for data_source in app.data_sources %}
|
||||||
<p class="data-source-container"
|
<p class="data-source-container"
|
||||||
data-url="{{ url_for('main.load_data_source') }}"
|
data-url="{{ url_for('main.load_data_source') }}"
|
||||||
@ -35,52 +37,80 @@
|
|||||||
<img src="{{ app.icon }}" height="64px">
|
<img src="{{ app.icon }}" height="64px">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="card-action center-align scrollbar" style="max-height: 127px; min-height: 127px; scrollbar-width: none;">
|
</a>
|
||||||
<h5 class="app-name-{{ app.id }}">{{ app.name }}
|
<div class="card-action center-align scrollbar pr-0" style="max-height: 60px; min-height: 60px; scrollbar-width: none;">
|
||||||
</h5>
|
<span class="app-name-{{ app.id }} font-weight-900 card-title theme-primary-text searchable" style="font-size: 1.2rem">{{ app.name }}
|
||||||
{% if app.description %}
|
<i class="material-icons activator right theme-secondary-text">more_vert</i>
|
||||||
<span class="theme-secondary-text app-description">{{ app.description }}</span>
|
{% if app.data_sources.count() > 0 %}
|
||||||
{% else %}
|
<i class="material-icons pointer right theme-secondary-text refresh-data-source-btn">refresh</i>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
<style>
|
<style>
|
||||||
.app-name-{{ app.id }} {
|
.app-name-{{ app.id }} {
|
||||||
margin-top: 35px;
|
margin-top: 35px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
</div>
|
||||||
|
<div class="card-reveal">
|
||||||
|
<span class="card-title">{{ app.name }}<i class="material-icons right">close</i></span>
|
||||||
|
{% if app.description %}
|
||||||
|
<p class="theme-secondary-text app-description searchable">{{ app.description|safe }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
|
||||||
{# </a> This closes AppAnchor() #}
|
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro ListViewApp(app) %}
|
{% macro Collection(app) %}
|
||||||
{{ AppAnchor(app, classes="collection-item") }}
|
<div class="col s12 m6 l4 xl3 app-card">
|
||||||
<div class="row">
|
<div class="card theme-surface-transparent scrollbar" style="max-height: 146px; min-height: 146px;">
|
||||||
<div class="col s12
|
<div class="card-content">
|
||||||
{% if app.data_sources.count() > 0 %}
|
<span class="font-weight-900 card-title theme-primary-text">
|
||||||
l6
|
{% if app.icon %}
|
||||||
{% else %}
|
<i class="material-icons-outlined right">{{app.icon}}</i>
|
||||||
l12
|
|
||||||
{% endif %}">
|
|
||||||
<img src="{{ app.icon }}" class="app-icon">
|
|
||||||
<span class="theme-muted-text app-name">{{ app.name }}</span>
|
|
||||||
{% if app.description %}
|
|
||||||
<i class="material-icons-outlined tooltipped" data-position="top" data-tooltip="{{ app.description }}">info</i>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<text class="searchable">{{ app.name }}</text>
|
||||||
|
</span>
|
||||||
|
<div class="collection">
|
||||||
|
{% for url in app.urls_json %}
|
||||||
|
|
||||||
|
<div class="collection-item">
|
||||||
|
{% if url['icon'] %}
|
||||||
|
<img src="{{ url['icon'] }}" height="24px" class="mr-2" style="position: relative; top: 5px;">
|
||||||
|
{% endif %}
|
||||||
|
{% if url['open_in'] == 'this_tab' %}
|
||||||
|
<a href="{{ url['url'] }}" class="font-weight-700 searchable" style="font-size: 1.1rem">
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url['url'] }}" target="_blank" class="font-weight-700 searchable" style="font-size: 1.1rem">
|
||||||
|
{% endif %}
|
||||||
|
{{ url['name'] }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro Custom(app) %}
|
||||||
|
<div class="col s12 m6 l4 xl3 app-card">
|
||||||
|
<div class="card theme-surface-transparent scrollbar" style="max-height: 146px; min-height: 146px;">
|
||||||
|
<div class="hide searchable">{{ app.name }}</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="col s12">
|
||||||
|
<div class="progress data-source-loading">
|
||||||
|
<div class="indeterminate"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col s12 l6 right-align">
|
|
||||||
{% if app.data_sources.count() > 0 %}
|
|
||||||
<span class="data-source-loading">{{ preload_circle() }}</span>
|
|
||||||
{% for data_source in app.data_sources %}
|
{% for data_source in app.data_sources %}
|
||||||
<span class="data-source-container theme-primary-text"
|
<p class="data-source-container"
|
||||||
data-url="{{ url_for('main.load_data_source') }}"
|
data-url="{{ url_for('main.load_data_source') }}"
|
||||||
data-id="{{ data_source.id }}">
|
data-id="{{ data_source.id }}">
|
||||||
</span>
|
</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</div>
|
||||||
{# </a> This closes AppAnchor() #}
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
@ -63,18 +63,22 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col s12 mb-2">
|
<div class="col s12 mb-2">
|
||||||
<ul class="tabs tabs-fixed-width">
|
<ul class="tabs tabs-fixed-width">
|
||||||
<li class="tab col s3"><a href="#config-readme">
|
<li class="tab col s3"><a href="#settings-readme">
|
||||||
<i class="material-icons-outlined">info</i>
|
<i class="material-icons-outlined">settings</i>
|
||||||
|
</a></li>
|
||||||
|
|
||||||
|
<li class="tab col s3"><a href="#cards-readme">
|
||||||
|
<i class="material-icons-outlined">aspect_ratio</i>
|
||||||
|
</a></li>
|
||||||
|
|
||||||
|
<li class="tab col s3"><a href="#data-sources-readme">
|
||||||
|
<i class="material-icons-outlined">language</i>
|
||||||
</a></li>
|
</a></li>
|
||||||
|
|
||||||
<li class="tab col s3"><a href="#images">
|
<li class="tab col s3"><a href="#images">
|
||||||
<i class="material-icons-outlined">photo_library</i>
|
<i class="material-icons-outlined">photo_library</i>
|
||||||
</a></li>
|
</a></li>
|
||||||
|
|
||||||
<li class="tab col s3"><a href="#apps">
|
|
||||||
<i class="material-icons-outlined">apps</i>
|
|
||||||
</a></li>
|
|
||||||
|
|
||||||
<li class="tab col s3"><a href="#about">
|
<li class="tab col s3"><a href="#about">
|
||||||
<i class="material-icons-outlined">security</i>
|
<i class="material-icons-outlined">security</i>
|
||||||
</a></li>
|
</a></li>
|
||||||
@ -85,8 +89,14 @@
|
|||||||
{{ FilesTab() }}
|
{{ FilesTab() }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="apps" class="col s12 scrollbar settings-page-card-right">
|
<div id="settings-readme" class="col s12 scrollbar settings-page-card-right scrollbar-x">
|
||||||
<h5>App Templates</h5>
|
{{ config_readme['settings']|safe }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="cards-readme" class="col s12 scrollbar settings-page-card-right scrollbar-x">
|
||||||
|
<h4>Cards</h4>
|
||||||
|
<h5>Card Templates</h5>
|
||||||
|
<span>Search for preconfigured cards included with DashMachine.</span>
|
||||||
<div class="row card-filter-container">
|
<div class="row card-filter-container">
|
||||||
<div class="col s12 input-field">
|
<div class="col s12 input-field">
|
||||||
<span>
|
<span>
|
||||||
@ -105,10 +115,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{ config_readme['cards']|safe }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="config-readme" class="col s12 scrollbar settings-page-card-right scrollbar-x">
|
<div id="data-sources-readme" class="col s12 scrollbar settings-page-card-right scrollbar-x">
|
||||||
{{ config_readme|safe }}
|
{{ config_readme['data_sources']|safe }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="about" class="col s12 scrollbar settings-page-card-right">
|
<div id="about" class="col s12 scrollbar settings-page-card-right">
|
||||||
|
@ -15,5 +15,5 @@ class User(db.Model, UserMixin):
|
|||||||
theme = db.Column(db.String())
|
theme = db.Column(db.String())
|
||||||
background = db.Column(db.String())
|
background = db.Column(db.String())
|
||||||
accent = db.Column(db.String())
|
accent = db.Column(db.String())
|
||||||
home_view_mode = db.Column(db.String(), default="grid")
|
|
||||||
sidebar_default = db.Column(db.String())
|
sidebar_default = db.Column(db.String())
|
||||||
|
tags_expanded = db.Column(db.String())
|
||||||
|
@ -5,7 +5,6 @@ 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
|
sidebar_default = open
|
||||||
|
|
||||||
|
61
readme_cards.md
Normal file
61
readme_cards.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
##### Apps
|
||||||
|
These entries are the standard card type for displaying apps on your dashboard and sidenav.
|
||||||
|
```ini
|
||||||
|
[App Name]
|
||||||
|
prefix = https://
|
||||||
|
url = your-website.com
|
||||||
|
icon = static/images/apps/default.png
|
||||||
|
sidebar_icon = static/images/apps/default.png
|
||||||
|
description = Example description
|
||||||
|
open_in = iframe
|
||||||
|
data_sources = None
|
||||||
|
tags = Example Tag
|
||||||
|
groups = admin_only
|
||||||
|
```
|
||||||
|
|
||||||
|
| Variable | Required | Description | Options |
|
||||||
|
|--------------|----------|-------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------|
|
||||||
|
| [App Name] | Yes | The name of your app. | [App Name] |
|
||||||
|
| prefix | Yes | The prefix for the app's url. | web prefix, e.g. http:// or https:// |
|
||||||
|
| url | Yes | The url for your app. | web url, e.g. myapp.com |
|
||||||
|
| open_in | Yes | open the app in the current tab, an iframe or a new tab | iframe, new_tab, this_tab |
|
||||||
|
| icon | Yes | Icon for the dashboard. | /static/images/icons/yourpicture.png, external link to image |
|
||||||
|
| sidebar_icon | No | Icon for the sidenav. | /static/images/icons/yourpicture.png, external link to image |
|
||||||
|
| description | No | A short description for the app. | string |
|
||||||
|
| data_sources | No | Data sources to be included on the app's card.*Note: you must have a data source set up in the config above this application entry. | comma separated string |
|
||||||
|
| tags | No | Optionally specify tags for organization on /home | comma separated string |
|
||||||
|
| groups | No | Optionally specify the access groups that can see this app. | comma separated string |
|
||||||
|
|
||||||
|
##### Collection
|
||||||
|
These entries provide a card on the dashboard containing a list of links.
|
||||||
|
```ini
|
||||||
|
[Collection Name]
|
||||||
|
type = collection
|
||||||
|
icon = collections_bookmark
|
||||||
|
urls = {"url": "google.com", "icon": "static/images/apps/default.png", "name": "Google", "open_in": "new_tab"},{"url": "duckduckgo.com", "icon": "static/images/apps/default.png", "name": "DuckDuckGo", "open_in": "iframe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Variable | Required | Description | Options |
|
||||||
|
|-------------------|----------|----------------------------------------------------------------------------------------------|-------------------------------------|
|
||||||
|
| [Collection Name] | Yes | Name for the collection | [Collection Name] |
|
||||||
|
| type | Yes | This tells DashMachine what type of card this is. | collection |
|
||||||
|
| icon | No | The material design icon class for the collection. | https://material.io/resources/icons |
|
||||||
|
| urls | Yes | The urls to include in your collection. Json options are "url", "icon", "name" and "open_in" | comma separated json dicts, "open_in" only has options "this_tab", "new_tab" |
|
||||||
|
| tags | No | Optionally specify tags for organization on /home | comma separated string |
|
||||||
|
| groups | No | Optionally specify the access groups that can see this app. | comma separated string |
|
||||||
|
|
||||||
|
##### Custom Card
|
||||||
|
These entries provide an empty card on the dashboard to be populated by a data source. This allows the data source to populate the entire card.
|
||||||
|
```ini
|
||||||
|
[Collection Name]
|
||||||
|
type = custom
|
||||||
|
data_sources = my_data_source
|
||||||
|
```
|
||||||
|
|
||||||
|
| Variable | Required | Description | Options |
|
||||||
|
|-------------------|----------|----------------------------------------------------------------------------------------------|-------------------------------------|
|
||||||
|
| [Collection Name] | Yes | Name for the collection | [Collection Name] |
|
||||||
|
| type | Yes | This tells DashMachine what type of card this is. | custom |
|
||||||
|
| tags | No | Optionally specify tags for organization on /home | comma separated string |
|
||||||
|
| groups | No | Optionally specify the access groups that can see this app. | comma separated string |
|
6
readme_data_sources.md
Normal file
6
readme_data_sources.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#### Data Source Platforms
|
||||||
|
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!
|
||||||
|
|
||||||
|
> 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:
|
||||||
|
`data_source = variable_name`
|
95
readme_settings.md
Normal file
95
readme_settings.md
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#### Main Settings
|
||||||
|
|
||||||
|
##### Settings
|
||||||
|
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.
|
||||||
|
```ini
|
||||||
|
[Settings]
|
||||||
|
theme = light
|
||||||
|
accent = orange
|
||||||
|
background = None
|
||||||
|
roles = admin,user,public_user
|
||||||
|
home_access_groups = admin_only
|
||||||
|
settings_access_groups = admin_only
|
||||||
|
custom_app_title = DashMachine
|
||||||
|
sidebar_default = open
|
||||||
|
tags_expanded = True
|
||||||
|
```
|
||||||
|
|
||||||
|
| Variable | Required | Description | Options |
|
||||||
|
|------------------------|----------|----------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| [Settings] | Yes | Config section name. | [Settings] |
|
||||||
|
| theme | Yes | UI theme. | light, dark |
|
||||||
|
| accent | Yes | UI accent color | orange, red, pink, purple, deepPurple, indigo, blue, lightBlue,cyan, teal, green, lightGreen, lime, yellow, amber, deepOrange, brown, grey, blueGrey |
|
||||||
|
| background | Yes | Background image for the UI | /static/images/backgrounds/yourpicture.png, external link to image, None, random |
|
||||||
|
| 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 |
|
||||||
|
| 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 |
|
||||||
|
| 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 |
|
||||||
|
| tags | No | Set custom options for your tags. Json options are "name", "icon", "sort_pos" | comma separated json dicts. For "icon" use material design icons: https://material.io/resources/icons |
|
||||||
|
| tags_expanded | No | Set to False to have your tags collapsed by default | True, False |
|
||||||
|
|
||||||
|
##### Users
|
||||||
|
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.
|
||||||
|
```ini
|
||||||
|
[admin]
|
||||||
|
role = admin
|
||||||
|
password = admin
|
||||||
|
confirm_password = admin
|
||||||
|
```
|
||||||
|
|
||||||
|
| Variable | Required | Description | Options |
|
||||||
|
|------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|
|
||||||
|
| [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 |
|
||||||
|
| 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 |
|
||||||
|
| 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 |
|
||||||
|
|
||||||
|
##### 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 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
|
||||||
|
[admin_only]
|
||||||
|
roles = admin
|
||||||
|
```
|
||||||
|
|
||||||
|
| Variable | Required | Description | Options |
|
||||||
|
|--------------|----------|--------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
|
||||||
|
| [Group Name] | Yes | Name for access group. | [Group Name] |
|
||||||
|
| roles | Yes | A comma separated list of user roles allowed to view apps in this access group | Roles defined in your config. If not defined, defaults are admin and public_user |
|
||||||
|
|
||||||
|
> Say we wanted to create a limited user that still has a login, but can only access `/home` and certain apps we would first create a group:
|
||||||
|
>```ini
|
||||||
|
>[users]
|
||||||
|
>roles = admin, user
|
||||||
|
>```
|
||||||
|
>then we would change in the `[Settings]` entry:
|
||||||
|
>```ini
|
||||||
|
>home_access_groups = users
|
||||||
|
>```
|
||||||
|
>By default here, the `user` user could access `/home`, but would see no apps. To allow access, we would add to apps:
|
||||||
|
>```ini
|
||||||
|
>groups = users
|
||||||
|
>```
|
||||||
|
>Say we then wanted to allow some access for users without a login (`public_user`), we would add:
|
||||||
|
>```ini
|
||||||
|
>[public]
|
||||||
|
>roles = admin, user, public_user
|
||||||
|
>```
|
||||||
|
>then we would change in the `[Settings]` entry:
|
||||||
|
>```ini
|
||||||
|
>home_access_groups = public
|
||||||
|
>```
|
||||||
|
>By default here, the `public_user` user could access `/home`, but would see no apps. To allow access, we would add to apps:
|
||||||
|
>```ini
|
||||||
|
>groups = public
|
||||||
|
>```
|
||||||
|
|
||||||
|
|
||||||
|
>It’s also important to note, when setting up roles in `[Settings]`, say we had roles set like this:
|
||||||
|
>```ini
|
||||||
|
>roles = my_people
|
||||||
|
>```
|
||||||
|
>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.
|
Loading…
x
Reference in New Issue
Block a user