added list view, and possibly some bugs ;)

This commit is contained in:
Ross Mountjoy 2020-02-12 18:17:23 -05:00
parent c59d2cab27
commit 131a49030e
15 changed files with 237 additions and 106 deletions

View File

@ -36,20 +36,12 @@ def read_config():
# Settings creation # Settings creation
if section == "Settings": if section == "Settings":
settings = Settings() settings = Settings()
if "theme" in config["Settings"]:
settings.theme = config["Settings"]["theme"]
else:
settings.theme = "light"
if "accent" in config["Settings"]: settings.theme = config["Settings"].get("theme", "light")
settings.accent = config["Settings"]["accent"]
else:
settings.accent = "orange"
if "background" in config["Settings"]: settings.accent = config["Settings"].get("accent", "orange")
settings.background = config["Settings"]["background"]
else: settings.background = config["Settings"].get("background", "None")
settings.background = "None"
if "roles" in config["Settings"]: if "roles" in config["Settings"]:
settings.roles = config["Settings"]["roles"] settings.roles = config["Settings"]["roles"]
@ -62,17 +54,14 @@ def read_config():
else: else:
settings.roles = "admin,user,public_user" settings.roles = "admin,user,public_user"
if "home_access_groups" in config["Settings"]: settings.home_access_groups = config["Settings"].get(
settings.home_access_groups = config["Settings"]["home_access_groups"] "home_access_groups", "admin_only"
else: )
settings.home_access_groups = "admin_only"
if "settings_access_groups" in config["Settings"]: settings.settings_access_groups = config["Settings"].get(
settings.settings_access_groups = config["Settings"][ "settings_access_groups", "admin_only"
"settings_access_groups" )
] settings.home_view_mode = config["Settings"].get("home_view_mode", "grid")
else:
settings.settings_access_groups = "admin_only"
db.session.add(settings) db.session.add(settings)
db.session.commit() db.session.commit()

View File

@ -2,6 +2,7 @@ import os
import glob import glob
from secrets import token_hex from secrets import token_hex
from htmlmin.main import minify from htmlmin.main import minify
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, Tags
@ -12,7 +13,7 @@ from dashmachine.main.utils import (
get_data_source, get_data_source,
) )
from dashmachine.settings_system.models import Settings from dashmachine.settings_system.models import Settings
from dashmachine.paths import cache_folder from dashmachine.paths import cache_folder, user_data_folder
from dashmachine import app, db from dashmachine import app, db
@ -57,7 +58,7 @@ def check_valid_login():
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@public_route @public_route
@main.route("/") @main.route("/")
@main.route("/home", methods=["GET", "POST"]) @main.route("/home", methods=["GET"])
def home(): def home():
tags_form = TagsForm() tags_form = TagsForm()
tags_form.tags.choices += [ tags_form.tags.choices += [
@ -88,6 +89,20 @@ def load_data_source():
return data return data
@public_route
@main.route("/change_home_view_mode?<mode>", methods=["GET"])
def change_home_view_mode(mode):
config = ConfigParser()
config.read(os.path.join(user_data_folder, "config.ini"))
config.set("Settings", "home_view_mode", mode)
config.write(open(os.path.join(user_data_folder, "config.ini"), "w"))
settings = Settings.query.first()
settings.home_view_mode = mode
db.session.merge(settings)
db.session.commit()
return redirect(url_for("main.home"))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# TCDROP routes # TCDROP routes
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -56,14 +56,6 @@ def public_route(decorated_function):
def dashmachine_init(): def dashmachine_init():
db.create_all() db.create_all()
db.session.commit() db.session.commit()
migrate_cmd = "python " + os.path.join(root_folder, "manage_db.py db stamp head")
subprocess.run(migrate_cmd, stderr=subprocess.PIPE, shell=True, encoding="utf-8")
migrate_cmd = "python " + os.path.join(root_folder, "manage_db.py db migrate")
subprocess.run(migrate_cmd, stderr=subprocess.PIPE, shell=True, encoding="utf-8")
upgrade_cmd = "python " + os.path.join(root_folder, "manage_db.py db upgrade")
subprocess.run(upgrade_cmd, stderr=subprocess.PIPE, shell=True, encoding="utf-8")
read_template_apps() read_template_apps()
user_data_folder = os.path.join(dashmachine_folder, "user_data") user_data_folder = os.path.join(dashmachine_folder, "user_data")

View File

@ -9,3 +9,4 @@ 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())

View File

@ -620,7 +620,7 @@ input:disabled {
.sidenav { .sidenav {
background-color: var(--theme-surface); background-color: var(--theme-surface);
top: unset; top: unset;
overflow: scroll; overflow-y: scroll;
scrollbar-width: none; scrollbar-width: none;
} }

View File

@ -20,4 +20,38 @@
width: calc(100vw - 45px) !important; width: calc(100vw - 45px) !important;
margin-left: 15px !important; margin-left: 15px !important;
} }
}
#list-view-collection .app-a {
background: rgba(var(--theme-surface-rgb), 0.8);
}
#list-view-collection .app-a:hover {
background: var(--theme-surface-1);
}
#list-view-collection .app-name {
font-size: 1.3rem;
position: relative;
margin-left: 1rem;
bottom: 2px;
}
#list-view-collection .app-description {
margin-left: .4rem;
}
#list-view-collection .app-icon {
height: 24px;
position: relative;
top: 4px;
}
#list-view-collection {
border: 0;
}
#list-view-collection .data-source-container {
position: relative;
top: 6px;
}
#list-view-collection .material-icons-outlined {
font-size: 1.2rem;
position: relative;
margin-left: .5rem;
top: 1px;
} }

View File

@ -18,8 +18,8 @@
min-height: calc(100vh - 142px) !important; min-height: calc(100vh - 142px) !important;
} }
.settings-page-card-left { .settings-page-card-left {
max-height: calc(100vh - 30px); max-height: calc(100vh - 130px) !important;
min-height: calc(100vh - 30px); min-height: calc(100vh - 130px) !important;
} }
#apps .dropdown-content { #apps .dropdown-content {

View File

@ -3,6 +3,7 @@ d.className += " active theme-primary";
$( document ).ready(function() { $( document ).ready(function() {
$(".tooltipped").tooltip();
$("#apps-filter").on('keyup', function(e) { $("#apps-filter").on('keyup', function(e) {
var value = $(this).val().toLowerCase(); var value = $(this).val().toLowerCase();
$(".app-a").each(function(i, e) { $(".app-a").each(function(i, e) {

View File

@ -1,5 +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 %}
{% block page_vendor_css %} {% block page_vendor_css %}
{% endblock page_vendor_css %} {% endblock page_vendor_css %}
@ -26,6 +27,18 @@
<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.role == "admin" %}
{% if settings.home_view_mode == "list" %}
<a href="{{ url_for('main.change_home_view_mode', mode="grid") }}">
<i class="material-icons right filter-action pointer tooltipped" data-position="top" data-tooltip="List view">apps</i>
</a>
{% else %}
<a href="{{ url_for('main.change_home_view_mode', mode="list") }}">
<i class="material-icons right filter-action pointer tooltipped" data-position="top" data-tooltip="List view">list</i>
</a>
{% endif %}
{% endif %}
</span> </span>
</div> </div>
{% if tags_form.tags.choices|count > 1 %} {% if tags_form.tags.choices|count > 1 %}
@ -37,54 +50,14 @@
<div class="row"> <div class="row">
{% if apps %} {% if apps %}
{% for app in apps %} {% if settings.home_view_mode == "list" %}
{% if app.open_in == 'iframe' %} {{ ListViewApp(apps) }}
<a href="{{ url_for('main.app_view', app_id=app.id) }}" class="app-a" data-name="{{ app.name }}" data-description="{{ app.description }}" data-tags="{{ app.tags }}"> {% else %}
{% elif app.open_in == 'this_tab' %} {% for app in apps %}
<a href="{{ app.prefix }}{{ app.url }}" class="app-a" data-name="{{ app.name }}" data-description="{{ app.description }}" data-tags="{{ app.tags }}"> {{ GridViewApp(app) }}
{% elif app.open_in == "new_tab" %} {% endfor %}
<a href="{{ app.prefix }}{{ app.url }}" target="_blank" class="app-a" data-name="{{ app.name }}" data-description="{{ app.description }}" data-tags="{{ app.tags }}"> {% endif %}
{% endif %}
<div class="col s12 m6 l3">
<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 %}
<div class="row">
<div class="col s6 center-align">
<img src="{{ app.icon }}" height="64px">
</div>
<div class="col s6 left-align">
<span class="data-source-loading">{{ preload_circle() }}</span>
{% for data_source in app.data_sources %}
<p class="data-source-container"
data-url="{{ url_for('main.load_data_source') }}"
data-id="{{ data_source.id }}">
</p>
{% endfor %}
</div>
</div>
{% else %}
<img src="{{ app.icon }}" height="64px">
{% endif %}
</div>
<div class="card-action center-align scrollbar" style="max-height: 127px; min-height: 127px; scrollbar-width: none;">
<h5 class="app-name-{{ app.id }}">{{ app.name }}
</h5>
{% if app.description %}
<span class="theme-secondary-text">{{ app.description }}</span>
{% else %}
<style>
.app-name-{{ app.id }} {
margin-top: 35px;
}
</style>
{% endif %}
</div>
</div>
</div>
</a>
{% endfor %}
{% 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">

View File

@ -1,4 +1,5 @@
{% extends "main/base.html" %} {% extends "main/base.html" %}
{% from 'main/macros.html' import AppAnchor %}
{% block header %} {% block header %}
<!-- BEGIN: Header--> <!-- BEGIN: Header-->
@ -43,13 +44,7 @@
{% for app in apps %} {% for app in apps %}
<li class="bold"> <li class="bold">
{% if app.open_in == 'iframe' %} {{ AppAnchor(app) }}
<a id="dashboard-sidenav" class="waves-effect waves-cyan" href="{{ url_for('main.app_view', app_id=app.id) }}">
{% elif app.open_in == "this_tab" %}
<a id="dashboard-sidenav" class="waves-effect waves-cyan" href="{{ app.prefix }}{{ app.url }}">
{% elif app.open_in == "new_tab" %}
<a id="dashboard-sidenav" class="waves-effect waves-cyan" href="{{ app.prefix }}{{ app.url }}" target="_blank">
{% endif %}
<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>

View File

@ -0,0 +1,92 @@
{% from 'global_macros.html' import preload_circle %}
{% macro AppAnchor(app, classes=None) %}
{% if app.open_in == 'iframe' %}
<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' %}
<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" %}
<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 %}
{% endmacro %}
{% macro GridViewApp(app) %}
{{ AppAnchor(app) }}
<div class="col s12 m6 l3">
<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 %}
<div class="row">
<div class="col s6 center-align">
<img src="{{ app.icon }}" height="64px">
</div>
<div class="col s6 left-align">
<span class="data-source-loading">{{ preload_circle() }}</span>
{% for data_source in app.data_sources %}
<p class="data-source-container"
data-url="{{ url_for('main.load_data_source') }}"
data-id="{{ data_source.id }}">
</p>
{% endfor %}
</div>
</div>
{% else %}
<img src="{{ app.icon }}" height="64px">
{% endif %}
</div>
<div class="card-action center-align scrollbar" style="max-height: 127px; min-height: 127px; scrollbar-width: none;">
<h5 class="app-name-{{ app.id }}">{{ app.name }}
</h5>
{% if app.description %}
<span class="theme-secondary-text">{{ app.description }}</span>
{% else %}
<style>
.app-name-{{ app.id }} {
margin-top: 35px;
}
</style>
{% endif %}
</div>
</div>
</div>
</a>
{# </a> This closes AppAnchor() #}
{% endmacro %}
{% macro ListViewApp(apps) %}
<div class="col s12 m12 l8">
<div id="list-view-collection" class="collection">
{% for app in apps %}
{{ AppAnchor(app, classes="collection-item") }}
<div class="row">
<div class="col s12
{% if app.data_sources.count() > 0 %}
l6
{% else %}
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 %}
</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 %}
<span class="data-source-container theme-primary-text"
data-url="{{ url_for('main.load_data_source') }}"
data-id="{{ data_source.id }}">
</span>
{% endfor %}
{% endif %}
</div>
</div>
</a>
{# </a> This closes AppAnchor() #}
{% endfor %}
</div>
</div>
{% endmacro %}

View File

@ -26,31 +26,33 @@
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col s12 m12 l6"> <div class="col s12 m12 l6">
<div class="card scrollbar settings-page-card-left"> <div class="card">
<div class="card-content"> <div class="card-content">
<div class="row"> <div class="row">
<div class="col s12"> <div class="col s12">
<h5>Config.ini</h5> <span>
<span style="font-size: 2rem; position: relative; top: 8px;">Config.ini</span>
{{ button( {{ button(
icon="save", icon="save",
id="save-config-btn", id="save-config-btn",
float="left", float="right",
class="ml-0 mt-1 mb-1", class="ml-0 mt-1 mb-1",
data={'url': url_for('settings_system.save_config')}, data={'url': url_for('settings_system.save_config')},
text="save" text="save"
) }} ) }}
</div> </span>
<div class="divider"></div>
<form id="config-form">
{{ input(
size="s12",
class="materialize-textarea code",
form_obj=config_form.config,
id="config-textarea"
) }}
</form>
</div> </div>
</div>
</div>
<div class="card-action scrollbar settings-page-card-left">
<form id="config-form">
{{ input(
size="s12",
class="materialize-textarea code",
form_obj=config_form.config,
id="config-textarea"
) }}
</form>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1 +1 @@
version = "v0.32" version = "v0.33"

View File

@ -0,0 +1,28 @@
"""empty message
Revision ID: ff5eb645bfe4
Revises: 885c5f9b33d5
Create Date: 2020-02-12 16:09:39.133644
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "ff5eb645bfe4"
down_revision = "885c5f9b33d5"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column("settings", sa.Column("home_view_mode", sa.String(), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("settings", "home_view_mode")
# ### end Alembic commands ###

9
run.py
View File

@ -1,5 +1,14 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os
from dashmachine.paths import root_folder
os.system("python " + os.path.join(root_folder, "manage_db.py db stamp head"))
os.system("python " + os.path.join(root_folder, "manage_db.py db migrate"))
os.system("python " + os.path.join(root_folder, "manage_db.py db upgrade"))
from dashmachine import app from dashmachine import app
from dashmachine.main.utils import dashmachine_init from dashmachine.main.utils import dashmachine_init