- started the wiki system

- improved collections
- implemented auto expand on hover
This commit is contained in:
Ross Mountjoy 2020-05-21 11:10:31 -04:00
parent daa4fe6c8f
commit 88c1f5fb15
24 changed files with 733 additions and 95 deletions

View File

@ -1,7 +1,7 @@
import os import os
from flask import render_template, Blueprint, redirect from flask import render_template, Blueprint, redirect, request
from flask_login import current_user from flask_login import current_user
from dashmachine.paths import root_folder from dashmachine.paths import root_folder, wiki_folder
from dashmachine.docs_system.core_docs import ( from dashmachine.docs_system.core_docs import (
settings_doc_dict, settings_doc_dict,
user_settings_doc_dict, user_settings_doc_dict,
@ -15,8 +15,11 @@ from dashmachine.docs_system.utils import (
get_md_from_file, get_md_from_file,
get_md_from_dict, get_md_from_dict,
get_toc_md_from_dicts, get_toc_md_from_dicts,
create_edit_wiki,
) )
from dashmachine.moment import create_moment
from dashmachine.main.utils import get_apps_and_tags, get_access_group from dashmachine.main.utils import get_apps_and_tags, get_access_group
from dashmachine.main.models import Wiki, WikiTags
docs_system = Blueprint("docs_system", __name__) docs_system = Blueprint("docs_system", __name__)
@ -92,3 +95,88 @@ def docs_data_sources():
apps=apps, apps=apps,
tags=tags, tags=tags,
) )
@docs_system.route("/wiki_tags", methods=["GET"])
def wiki_tags():
access_group, redirect_url = get_access_group(current_user, page="wikis")
if redirect_url:
return redirect(redirect_url)
apps, tags = get_apps_and_tags(access_group)
wiki_tags_db = WikiTags.query.all()
return render_template(
"docs_system/wiki-tags.html",
access_group=access_group,
apps=apps,
tags=tags,
wiki_tags=wiki_tags_db,
)
@docs_system.route("/wikis", methods=["GET"])
def wikis():
access_group, redirect_url = get_access_group(current_user, page="wikis")
if redirect_url:
return redirect(redirect_url)
apps, tags = get_apps_and_tags(access_group)
if request.args.get("tag", None):
tag = WikiTags.query.filter_by(id=request.args.get("tag")).first()
wikis_db = tag.wikis
else:
tag = None
wikis_db = Wiki.query.all()
for wiki_db in wikis_db:
wiki_db.updated_moment = create_moment(wiki_db.updated)
return render_template(
"docs_system/wikis.html",
access_group=access_group,
apps=apps,
tags=tags,
wikis=wikis_db,
tag=tag,
)
@docs_system.route("/wiki-<permalink>", methods=["GET"])
def wiki(permalink=None):
access_group, redirect_url = get_access_group(current_user, page="wiki")
if redirect_url:
return redirect(redirect_url)
apps, tags = get_apps_and_tags(access_group)
wiki_db = Wiki.query.filter_by(permalink=permalink).first()
if wiki_db:
wiki_fp = os.path.join(wiki_folder, f"{wiki_db.name}.md")
with open(wiki_fp, "r") as file:
wiki_md = file.read()
wiki_md_html = get_md_from_file(file=wiki_db.name, full_path=wiki_fp)
else:
wiki_md_html = None
if wiki_db.wiki_tags.count() > 0:
wiki_db.tags_str = ",".join([tag.name for tag in wiki_db.wiki_tags])
return render_template(
"docs_system/wiki.html",
access_group=access_group,
wiki=wiki_db,
wiki_md_html=wiki_md_html,
wiki_md=wiki_md,
apps=apps,
tags=tags,
)
@docs_system.route("/save_wiki", methods=["POST"])
def save_wiki():
create_edit_wiki(
permalink=request.form.get("wiki_permalink", None),
permalink_new=request.form.get("wiki_permalink_new", None),
name=request.form.get("wiki_name", None),
author=request.form.get("wiki_author", None),
description=request.form.get("wiki_description", None),
md=request.form.get("config", None),
tags=request.form.get("wiki_tags", None),
)
return "ok"

View File

@ -1,7 +1,12 @@
import os import os
from shutil import copy2
from secrets import token_hex
from datetime import datetime
from markdown2 import markdown from markdown2 import markdown
from flask import render_template_string, url_for from configparser import ConfigParser
from dashmachine.paths import docs_folder from flask import render_template_string
from dashmachine import db
from dashmachine.paths import docs_folder, wiki_folder, wiki_config_file, root_folder
from dashmachine.docs_system.core_docs import ( from dashmachine.docs_system.core_docs import (
base_md_string, base_md_string,
doc_toc_string, doc_toc_string,
@ -9,6 +14,15 @@ from dashmachine.docs_system.core_docs import (
custom_card_doc_dict, custom_card_doc_dict,
collections_doc_dict, collections_doc_dict,
) )
from dashmachine.main.models import Wiki, WikiTags
def row2dict(row):
d = {}
for column in row.__table__.columns:
d[column.name] = str(getattr(row, column.name))
return d
def convert_html_to_md(md): def convert_html_to_md(md):
@ -56,3 +70,99 @@ def get_card_doc_dict(card_type):
if card_type == "custom": if card_type == "custom":
card_doc_dict = custom_card_doc_dict card_doc_dict = custom_card_doc_dict
return card_doc_dict return card_doc_dict
def create_edit_wiki(
permalink=None,
permalink_new=None,
name="Unnamed Wiki",
author=None,
description=None,
md="",
tags=None,
):
wiki = Wiki.query.filter_by(permalink=permalink).first()
if not wiki:
wiki = Wiki()
if not permalink:
wiki.permalink = token_hex(12)
else:
wiki.permalink = permalink
wiki.created = datetime.now()
editing = False
else:
editing = True
if permalink_new:
wiki.permalink = permalink_new
wiki.name = name
wiki.author = author
wiki.description = description
wiki.md = md
wiki.updated = datetime.now()
if not wiki.created:
wiki.created = datetime.now()
if editing:
db.session.merge(wiki)
else:
db.session.add(wiki)
db.session.commit()
if tags:
for tag_name in tags.split(","):
tag_name = tag_name.strip()
tag = WikiTags.query.filter_by(name=tag_name).first()
if not tag:
tag = WikiTags(name=tag_name)
tag.wikis.append(wiki)
db.session.merge(tag)
db.session.commit()
create_wiki_files(wiki)
def create_wiki_files(wiki):
with open(os.path.join(wiki_folder, f"{wiki.name}.md"), "w") as md_file:
md_file.write(wiki.md)
config = ConfigParser(interpolation=None)
config.read(wiki_config_file)
if wiki.name not in config.sections():
config.add_section(wiki.name)
for key, value in row2dict(wiki).items():
if key not in ["id", "md", "name"]:
config.set(wiki.name, key, value)
config.set(wiki.name, "tags", ",".join([tag.name for tag in wiki.wiki_tags]))
config.write(open(wiki_config_file, "w"))
def build_wiki_from_wiki_folder():
if not os.path.isdir(wiki_folder):
os.mkdir(wiki_folder)
if not os.path.isfile(wiki_config_file):
default_config = os.path.join(root_folder, "default_wiki_config.ini")
new_config = os.path.join(wiki_folder, "wiki_config.ini")
copy2(default_config, new_config)
config = ConfigParser(interpolation=None)
config.read(wiki_config_file)
for section in config.sections():
if section != "WikiSettings":
with open(os.path.join(wiki_folder, f"{section}.md"), "r") as file:
md = file.read()
wiki = config[section]
create_edit_wiki(
name=section,
author=wiki.get("author", None),
description=wiki.get("description", None),
md=md,
tags=wiki.get("tags", None),
permalink=wiki.get("permalink", None),
)

View File

@ -12,6 +12,12 @@ rel_apps_tags = db.Table(
db.Column("app_id", db.Integer, db.ForeignKey("apps.id")), db.Column("app_id", db.Integer, db.ForeignKey("apps.id")),
) )
rel_wiki_wiki_tags = db.Table(
"rel_wiki_wiki_tags",
db.Column("wiki_tag_id", db.Integer, db.ForeignKey("wiki_tags.id")),
db.Column("wiki_id", db.Integer, db.ForeignKey("wiki.id")),
)
class Files(db.Model): class Files(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -63,3 +69,26 @@ class Tags(db.Model):
apps = db.relationship( apps = db.relationship(
"Apps", secondary=rel_apps_tags, backref=db.backref("tags", lazy="dynamic"), "Apps", secondary=rel_apps_tags, backref=db.backref("tags", lazy="dynamic"),
) )
class WikiTags(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String())
wikis = db.relationship(
"Wiki",
secondary=rel_wiki_wiki_tags,
backref=db.backref("wiki_tags", lazy="dynamic"),
)
class Wiki(db.Model):
id = db.Column(db.Integer, primary_key=True)
permalink = db.Column(db.String())
name = db.Column(db.String())
author = db.Column(db.String())
description = db.Column(db.String())
md = db.Column(db.String())
score = db.Column(db.Integer, default=0)
created = db.Column(db.String())
updated = db.Column(db.String())
url = db.Column(db.String())

View File

@ -17,6 +17,7 @@ from dashmachine.paths import (
from dashmachine.main.models import Tags from dashmachine.main.models import Tags
from dashmachine.main.read_config import read_config from dashmachine.main.read_config import read_config
from dashmachine.user_system.models import AccessGroups from dashmachine.user_system.models import AccessGroups
from dashmachine.docs_system.utils import build_wiki_from_wiki_folder
from dashmachine.version import version as dashmachine_version from dashmachine.version import version as dashmachine_version
from dashmachine import db from dashmachine import db
@ -85,6 +86,9 @@ def dashmachine_init():
if getattr(platform, "on_startup", None): if getattr(platform, "on_startup", None):
platform.on_startup() platform.on_startup()
# build wiki
build_wiki_from_wiki_folder()
def get_access_group(user, page=None): def get_access_group(user, page=None):
access_groups = [] access_groups = []

78
dashmachine/moment.py Normal file
View File

@ -0,0 +1,78 @@
from dateutil import parser
from datetime import datetime
def create_moment(dt):
# get current time, database object time, get the difference in minutes
now_datetime = datetime.now()
item_datetime = parser.parse(dt)
obj_time = item_datetime.strftime("%-I:%M")
obj_day = item_datetime.strftime("%x")
minutes_diff = (now_datetime - item_datetime).total_seconds() / 60.0
if minutes_diff > 0:
# if the time difference is less than 5 minutes
if minutes_diff < 5.0:
moment = "Just now"
# if the time difference is less than 1 hour
elif minutes_diff < 60.0:
minutes_diff = round(minutes_diff)
moment = f"{minutes_diff} minutes ago"
# if the time difference is less than 1 day
elif minutes_diff < 1440.0:
minutes_diff = round(minutes_diff / 60.0)
if minutes_diff == 1:
hour = "hour"
else:
hour = "hours"
moment = f"{minutes_diff} {hour} ago"
# if the time difference is less than 1 week
elif minutes_diff < 10080.0:
day = item_datetime.strftime("%a")
moment = f"{day} at {obj_time}"
# if the time difference is less than 1 year
elif minutes_diff < 525600.0:
day = item_datetime.strftime("%-m/%-d")
moment = f"{day} at {obj_time}"
# if the time difference is more than 1 year
else:
moment = f"{obj_day} at {obj_time}"
else:
# if the time difference is less than 5 minutes in the future
if minutes_diff > -5.0:
moment = "Now"
# if the time difference is less than 1 hour
elif minutes_diff > -60.0:
minutes_diff = round(abs(minutes_diff))
moment = f"in {abs(minutes_diff)} minutes"
# if the time difference is less than 1 day in the future
elif minutes_diff > -1440.0:
minutes_diff = round(abs(minutes_diff) / 60.0)
if minutes_diff == 1:
hour = "hour"
else:
hour = "hours"
moment = f"in {abs(minutes_diff)} {hour}"
# if the time difference is less than 1 week in the future
elif minutes_diff > -10080.0:
day = item_datetime.strftime("%a")
moment = f"{day} at {obj_time}"
# if the time difference is less than 1 year in the future
elif minutes_diff > -525600.0:
day = item_datetime.strftime("%-m/%-d")
moment = f"{day} at {obj_time}"
# if the time difference is more than 1 year in the future
else:
moment = f"{obj_day} at {obj_time}"
return moment

View File

@ -23,6 +23,10 @@ user_data_folder = os.path.join(dashmachine_folder, "user_data")
custom_platforms_folder = os.path.join(user_data_folder, "platform") custom_platforms_folder = os.path.join(user_data_folder, "platform")
wiki_folder = os.path.join(user_data_folder, "wiki")
wiki_config_file = os.path.join(wiki_folder, "wiki_config.ini")
auth_cache = os.path.join(user_data_folder, "auth_cache") auth_cache = os.path.join(user_data_folder, "auth_cache")
if not os.path.isdir(auth_cache): if not os.path.isdir(auth_cache):

View File

@ -1,6 +1,11 @@
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
from wtforms import TextAreaField from wtforms import TextAreaField, StringField
class ConfigForm(FlaskForm): class ConfigForm(FlaskForm):
config = TextAreaField() config = TextAreaField()
wiki_name = StringField()
wiki_permalink_new = StringField()
wiki_author = StringField()
wiki_description = TextAreaField()
wiki_tags = StringField()

View File

@ -21,3 +21,12 @@
/*margin-left: 15px !important;*/ /*margin-left: 15px !important;*/
} }
} }
.expandable-card {
max-height: 146px;
min-height: 146px;
border: 0;
}
.collection-url-collection-item:hover {
background: var(--theme-background) !important;
}

View File

@ -0,0 +1,47 @@
function reset_config_editor(){
$("#config-card-title").text("Config.ini");
$("#save-config-btn").removeClass('hide');
$("#save-editing-wiki-btn").addClass('hide');
$("#wiki-config-form").addClass('hide');
config_textarea_codemirror.toTextArea();
$("#config-textarea").val($("#config-editor-config-data").val());
init_codemirror('properties');
}
$( document ).ready(function() {
$("#edit-wiki-btn").on('click', function(e) {
config_textarea_codemirror.setValue($(this).attr("data-md"));
config_textarea_codemirror.toTextArea();
init_codemirror('markdown');
$("#wiki-config-form-permalink").val($(this).attr('data-permalink'));
$("#wiki-config-form-permalink-new").val($(this).attr('data-permalink'));
$("#wiki-config-form-name").val($(this).attr('data-name'));
$("#wiki-config-form-author").val($(this).attr('data-author'));
$("#wiki-config-form-description").val($(this).attr('data-description'));
$("#wiki-config-form-tags").val($(this).attr('data-tags'));
M.updateTextFields();
$("#wiki-config-form").removeClass('hide');
$("#config-editor-sidenav").sidenav('open');
$("#save-config-btn").addClass('hide');
$("#save-editing-wiki-btn").removeClass('hide');
$("#config-card-title").text(`Editing ${$(this).attr("data-name")}`);
$("#close-config-editor-sidenav").one('click', function (e) {
reset_config_editor();
})
$("#save-editing-wiki-btn").on('click', function(e) {
M.toast({html: "Reloading.."})
config_textarea_codemirror.save();
$.ajax({
url: $(this).attr('data-url'),
type: 'POST',
data: $("#config-form").serialize(),
success: function(data){
location.reload();
}
});
});
});
});

View File

@ -1,10 +1,5 @@
sleep(500).then(() => { sleep(500).then(() => {
var config_textarea_codemirror = CodeMirror.fromTextArea(document.getElementById("config-textarea"), { init_codemirror('properties');
lineNumbers: true,
mode: 'properties',
theme: 'dashmachine',
scrollbarStyle: null,
});
$("#save-config-btn").on('click', function(e) { $("#save-config-btn").on('click', function(e) {
$.ajax({ $.ajax({

View File

@ -178,6 +178,13 @@ function load_card_editor() {
} }
}); });
} }
function reset_config_editor(){
$("#config-card-title").text("Config.ini");
config_textarea_codemirror.setValue($("#config-editor-config-data").val());
config_textarea_codemirror.toTextArea();
init_codemirror('properties');
}
function load_config_editor() { function load_config_editor() {
$("#config-editor-sidenav").sidenav({ $("#config-editor-sidenav").sidenav({
edge: 'left', edge: 'left',
@ -189,7 +196,7 @@ function load_config_editor() {
$("#settings-editor-sidenav").sidenav('close'); $("#settings-editor-sidenav").sidenav('close');
$("#card-editor-sidenav").sidenav('close'); $("#card-editor-sidenav").sidenav('close');
$("#main-sidenav").sidenav('close'); $("#main-sidenav").sidenav('close');
} },
}); });
$.ajax({ $.ajax({
url: $("#config-editor-container").attr('data-url'), url: $("#config-editor-container").attr('data-url'),
@ -203,6 +210,16 @@ function load_config_editor() {
} }
}); });
} }
var config_textarea_codemirror = ""
function init_codemirror(mode) {
config_textarea_codemirror = CodeMirror.fromTextArea(document.getElementById("config-textarea"), {
lineNumbers: true,
mode: mode,
theme: 'dashmachine',
scrollbarStyle: null,
});
}
function load_settings_editor() { function load_settings_editor() {
$("#settings-editor-sidenav").sidenav({ $("#settings-editor-sidenav").sidenav({
edge: 'left', edge: 'left',

View File

@ -34,6 +34,27 @@ function init_home_cards(){
} }
}); });
}); });
$(".expandable-card").on('mouseenter', function(e) {
var width = $(this).width();
var avail_space = $(window).height() - $(this).offset().top + $(this).height();
console.log(avail_space)
$(this).css("position", "absolute");
$(this).css("max-height", "unset");
$(this).css("overflow", "auto");
$(this).css("height", "auto");
$(this).css("width", width);
$(this).css("z-index", 9999);
});
$(".expandable-card").on('mouseleave', function(e) {
var width = $(this).width()
$(this).css("position", "relative");
$(this).css("max-height", "146px");
$(this).css("overflow", "hidden");
$(this).css("height", "146px");
$(this).css("width", width);
$(this).css("z-index", 1);
});
} }
@ -59,4 +80,5 @@ $( document ).ready(function() {
$('#add-new-app-tap-target').tapTarget(); $('#add-new-app-tap-target').tapTarget();
$('#add-new-app-tap-target').tapTarget('open'); $('#add-new-app-tap-target').tapTarget('open');
}); });

View File

@ -1,5 +1,4 @@
{% extends "main/layout.html" %} {% extends "main/layout.html" %}
{% from 'global_macros.html' import DMLogo, button %}
{% block page_vendor_css %} {% block page_vendor_css %}
{% endblock page_vendor_css %} {% endblock page_vendor_css %}
@ -8,68 +7,13 @@
{{ process_css_sources(src="docs_system/docs-base.css")|safe }} {{ process_css_sources(src="docs_system/docs-base.css")|safe }}
{% endblock page_lvl_css %} {% endblock page_lvl_css %}
{% macro NavItems() %}
<li>
{{ button(
icon="check_circle",
float="",
href=url_for('docs_system.docs_home'),
text="Setup"
) }}
</li>
<li>
{{ button(
icon="settings",
float="",
href=url_for('docs_system.docs_main_settings'),
text="Settings"
) }}
</li>
<li>
{{ button(
icon="aspect_ratio",
float="",
href=url_for('docs_system.docs_cards'),
text="Cards"
) }}
</li>
<li>
{{ button(
icon="language",
float="",
href=url_for('docs_system.docs_data_sources'),
text="Data Sources"
) }}
</li>
{% endmacro %}
{% block content %} {% block content %}
<div class="navbar-fixed"> {% block navbar %}{% endblock navbar %}
<nav class="nav-extended theme-surface pl-1 z-depth-1" style="border-radius: 0 0 10px 10px">
<div class="nav-wrapper">
<a href="{{ url_for('docs_system.docs_home') }}" class="brand-logo right theme-primary-text">{{ DMLogo(size="32px", style="position: relative; top: 6px") }} Docs</a>
<a href="#" data-target="mobile-demo" class="sidenav-trigger"><i class="material-icons-outlined theme-primary-text">menu</i></a>
<ul id="nav-mobile" class="hide-on-med-and-down">
{{ NavItems() }}
</ul>
</div>
<div class="nav-content">
<ul class="tabs theme-surface" style="border-bottom-right-radius: 10px;">
{% block tabs %}{% endblock tabs %}
</ul>
</div>
</nav>
</div>
<ul class="sidenav" id="mobile-demo" style="top: 110px"> <div id="main" class="main-full {% block main_class %}{% endblock main_class %}">
{{ NavItems() }}
</ul>
<div id="main" class="main-full mt-3 ml-1">
<div id="md-container"> <div id="md-container">
{% block tabs_content %}{% endblock tabs_content %} {% block md_content %}{% endblock md_content %}
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}

View File

@ -1,4 +1,4 @@
{% extends "docs_system/docs-base.html" %} {% extends "docs_system/docs-layout.html" %}
{% block tabs %} {% block tabs %}
<li class="tab"><a class="active" href="#cards-apps">Apps</a></li> <li class="tab"><a class="active" href="#cards-apps">Apps</a></li>

View File

@ -1,4 +1,4 @@
{% extends "docs_system/docs-base.html" %} {% extends "docs_system/docs-layout.html" %}
{% block tabs %} {% block tabs %}
<li class="tab"><a class="active" href="#data-sources-main">Data Sources</a></li> <li class="tab"><a class="active" href="#data-sources-main">Data Sources</a></li>

View File

@ -1,4 +1,4 @@
{% extends "docs_system/docs-base.html" %} {% extends "docs_system/docs-layout.html" %}
{% block tabs %} {% block tabs %}
<li class="tab"><a class="active" href="#setup-about">About</a></li> <li class="tab"><a class="active" href="#setup-about">About</a></li>

View File

@ -0,0 +1,67 @@
{% extends "docs_system/docs-base.html" %}
{% from 'global_macros.html' import DMLogo, button %}
{% macro NavItems() %}
<li>
{{ button(
icon="check_circle",
float="",
href=url_for('docs_system.docs_home'),
text="Setup"
) }}
</li>
<li>
{{ button(
icon="settings",
float="",
href=url_for('docs_system.docs_main_settings'),
text="Settings"
) }}
</li>
<li>
{{ button(
icon="aspect_ratio",
float="",
href=url_for('docs_system.docs_cards'),
text="Cards"
) }}
</li>
<li>
{{ button(
icon="language",
float="",
href=url_for('docs_system.docs_data_sources'),
text="Data Sources"
) }}
</li>
{% endmacro %}
{% block main_class %}mt-3 ml-1{% endblock main_class %}
{% block navbar %}
<div class="navbar-fixed">
<nav class="nav-extended theme-surface pl-1 z-depth-1" style="border-radius: 0 0 10px 10px">
<div class="nav-wrapper">
<a href="{{ url_for('docs_system.docs_home') }}" class="brand-logo right theme-primary-text">{{ DMLogo(size="32px", style="position: relative; top: 6px") }} Docs</a>
<a href="#" data-target="mobile-demo" class="sidenav-trigger"><i class="material-icons-outlined theme-primary-text">menu</i></a>
<ul id="nav-mobile" class="hide-on-med-and-down">
{{ NavItems() }}
</ul>
</div>
<div class="nav-content">
<ul class="tabs theme-surface" style="border-bottom-right-radius: 10px;">
{% block tabs %}{% endblock tabs %}
</ul>
</div>
</nav>
</div>
<ul class="sidenav" id="mobile-demo" style="top: 110px">
{{ NavItems() }}
</ul>
{% endblock navbar %}
{% block md_content %}
{% block tabs_content %}{% endblock tabs_content %}
{% endblock md_content %}

View File

@ -1,4 +1,4 @@
{% extends "docs_system/docs-base.html" %} {% extends "docs_system/docs-layout.html" %}
{% block tabs %} {% block tabs %}
<li class="tab"><a class="active" href="#main-settings">Main Settings</a></li> <li class="tab"><a class="active" href="#main-settings">Main Settings</a></li>

View File

@ -0,0 +1,53 @@
{% extends "main/layout.html" %}
{% block page_vendor_css %}
{% endblock page_vendor_css %}
{% block page_lvl_css %}
{# {{ process_css_sources(src="main/home.css")|safe }}#}
{% endblock page_lvl_css %}
{% block content %}
<div id="main" class="main-full">
<div class="container">
<div class="row card-filter-container" style="padding-left: 10px">
<div class="col s12 m12 l4 xl3 input-field">
<span>
<i class="material-icons prefix card-search-icon">search</i>
<input type="text" id="wiki-tags-search" class="card-filter theme-surface" placeholder="Search tags">
{# <i class="material-icons right filter-action pointer">language</i>#}
</span>
</div>
</div>
<div class="row" style="padding-left: 10px">
<div class="col s12">
<h4 class="theme-muted-text mb-0">Tags
<i class="material-icons-outlined icon-btn">add</i>
</h4>
</div>
{% for wiki_tag in wiki_tags %}
<div class="col s12 m12 l4 xl3">
<div class="card">
<a href="{{ url_for('docs_system.wikis', tag=wiki_tag.id) }}">
<div class="card-content">
<span class="font-weight-900" style="font-size: 1.2rem">{{ wiki_tag.name }}</span>
</div>
</a>
<div class="card-action theme-primary theme-on-primary-text pt-1 pb-1">
<i class="material-icons-outlined icon-btn">edit</i>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock content %}
{% block page_vendor_js %}
{% endblock page_vendor_js %}
{% block page_lvl_js %}
{# {{ process_js_sources(src="main/home.js")|safe }}#}
{% endblock page_lvl_js %}

View File

@ -0,0 +1,54 @@
{% extends "docs_system/docs-base.html" %}
{% block md_content %}
<div class="row" style="padding-left: 8px;">
<div class="col s12 l6 xl6 hide">
<div class="card">
<div class="card-content">
<h5>Wiki</h5>
</div>
<div class="card-action">
tags!
</div>
</div>
</div>
<div class="col s12">
<div class="card">
<div class="card-content theme-primary theme-on-primary-text" style="padding: 1rem">
<div class="row">
<div class="col s12 m6">
<span class="font-weight-900 theme-on-primary-text">{{ wiki.name }}</span><br>
<span class="theme-on-primary-text">{{ wiki.description }}</span>
</div>
<div class="col s12 m6 right-align">
<span class="theme-on-primary-text">
<i id="edit-wiki-btn"
class="material-icons-outlined icon-btn"
data-permalink="{{ wiki.permalink }}"
data-name="{{ wiki.name }}"
data-author="{{ wiki.author }}"
data-description="{{ wiki.description }}"
data-tags="{{ wiki.tags_str }}"
data-md="{{ wiki_md }}">edit
</i>
<i class="material-icons-outlined icon-btn">delete</i>
</span>
</div>
</div>
</div>
<div class="card-action">
{% if wiki %}
<div id="wiki-md-container">
{{ wiki_md_html|safe }}
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock md_content %}
{% block page_lvl_js %}
{{ process_js_sources(src="docs_system/wiki.js")|safe }}
{% endblock page_lvl_js %}

View File

@ -0,0 +1,55 @@
{% extends "main/layout.html" %}
{% block page_vendor_css %}
{% endblock page_vendor_css %}
{% block page_lvl_css %}
{# {{ process_css_sources(src="main/home.css")|safe }}#}
{% endblock page_lvl_css %}
{% block content %}
<div id="main" class="main-full">
<div class="container">
<div class="row card-filter-container" style="padding-left: 10px">
<div class="col s12 m12 l4 xl3 input-field">
<span>
<i class="material-icons prefix card-search-icon">search</i>
<input type="text" id="wikis-search" class="card-filter theme-surface" placeholder="Search wikis">
{# <i class="material-icons right filter-action pointer">language</i>#}
</span>
</div>
</div>
<div class="row" style="padding-left: 10px">
<div class="col s12">
<h4 class="theme-muted-text mb-0">{{ tag.name }}
<i class="material-icons-outlined icon-btn">add</i>
</h4>
</div>
{% for wiki in wikis %}
<div class="col s12 m12 l4 xl3">
<div class="card">
<a href="{{ url_for('docs_system.wiki', permalink=wiki.permalink) }}">
<div class="card-content">
<span class="font-weight-900" style="font-size: 1.2rem">{{ wiki.name }}</span><br>
<span class="theme-secondary-text">{{ wiki.description }}</span><br>
<span> {{ wiki.updated_moment }}</span>
</div>
</a>
<div class="card-action theme-primary theme-on-primary-text pt-1 pb-1">
<i class="material-icons-outlined icon-btn">link</i>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock content %}
{% block page_vendor_js %}
{% endblock page_vendor_js %}
{% block page_lvl_js %}
{# {{ process_js_sources(src="main/home.js")|safe }}#}
{% endblock page_lvl_js %}

View File

@ -5,7 +5,7 @@
{% for tag in tags %} {% for tag in tags %}
<div class="tag-group" data-tag="{{ tag.name }}"> <div class="tag-group" data-tag="{{ tag.name }}">
{% if tag.name != "Untagged" %} {% if tag.name != "Untagged" %}
<div class="row" style="z-index: 2"> <div class="row" style="z-index: 2;">
<div class="col s12 m12 l6 xl4"> <div class="col s12 m12 l6 xl4">
<div class="card theme-surface-transparent mt-0 tag-group-btn pointer"> <div class="card theme-surface-transparent mt-0 tag-group-btn pointer">
<div class="card-content pt-0 pb-0"> <div class="card-content pt-0 pb-0">
@ -21,7 +21,7 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
<div class="row tag-apps-row"> <div class="row tag-apps-row" style="min-height: 161px">
{% for app in tag.apps %} {% for app in tag.apps %}
{% if app.type == "app" %} {% if app.type == "app" %}
{{ App(app) }} {{ App(app) }}
@ -146,40 +146,39 @@
{% macro Collection(app) %} {% macro Collection(app) %}
<div class="col s12 m6 l4 xl3 xxl2 app-card"> <div class="col s12 m6 l4 xl3 xxl2 app-card">
<div class="card theme-surface-transparent scrollbar mt-0" style="max-height: 146px; min-height: 146px;"> <div class="collection expandable-card with-header mt-0 z-depth-1 theme-surface-transparent">
<div class="card-content">
<span class="font-weight-900 card-title theme-primary-text"> <div class="collection-header theme-primary">
<span class="font-weight-900 card-title theme-on-primary-text">
{% if app.icon %} {% if app.icon %}
<i class="material-icons-outlined right">{{app.icon}}</i> <i class="material-icons-outlined right">{{app.icon}}</i>
{% endif %} {% endif %}
<text class="searchable">{{ app.name }}</text> <text class="searchable">{{ app.name }}</text>
</span> </span>
<div class="collection"> </div>
{% for url in app.urls_json %}
<div class="collection-item"> {% for url in app.urls_json %}
{% if url['icon'] %}
<img src="{{ url['icon'] }}" height="24px" class="mr-2" style="position: relative; top: 5px;">
{% endif %}
{% if url['open_in'] == 'this_tab' %} {% if url['open_in'] == 'this_tab' %}
<a href="{{ url['url'] }}" class="font-weight-700 searchable" style="font-size: 1.1rem"> <a href="{{ url['url'] }}" class="font-weight-700 searchable" style="font-size: 1.1rem">
{% else %} {% else %}
<a href="{{ url['url'] }}" target="_blank" class="font-weight-700 searchable" style="font-size: 1.1rem"> <a href="{{ url['url'] }}" target="_blank" class="font-weight-700 searchable" style="font-size: 1.1rem">
{% endif %} {% endif %}
{{ url['name'] }} <div class="collection-item theme-surface-transparent collection-url-collection-item">
</a> {% if url['icon'] %}
</div> <img src="{{ url['icon'] }}" height="24px" class="mr-2" style="position: relative; top: 5px;">
{% endif %}
{{ url['name'] }}
</div>
</a>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
</div>
</div>
{% endmacro %} {% endmacro %}
{% macro Custom(app) %} {% macro Custom(app) %}
<div class="col s12 m6 l4 xl3 xxl2 app-card"> <div class="col s12 m6 l4 xl3 xxl2 app-card">
<div class="card theme-surface-transparent scrollbar mt-0" style="max-height: 146px; min-height: 146px;"> <div class="card theme-surface-transparent expandable-card mt-0" style="max-height: 146px; min-height: 146px;">
<div class="hide searchable">{{ app.name }}</div> <div class="hide searchable">{{ app.name }}</div>
<div class="card-content"> <div class="card-content">
<div class="col s12"> <div class="col s12">

View File

@ -46,6 +46,16 @@
) }} ) }}
{{ button( {{ button(
icon="save",
id="save-editing-wiki-btn",
float="right",
class="ml-0 mt-1 mb-1 hide",
data={'url': url_for('docs_system.save_wiki')},
text="save"
) }}
{{ button(
id="close-config-editor-sidenav",
icon="close", icon="close",
float="right", float="right",
class="ml-0 mt-1 mb-1 sidenav-close theme-secondary ", class="ml-0 mt-1 mb-1 sidenav-close theme-secondary ",
@ -62,6 +72,46 @@
</div> </div>
</div> </div>
<form id="config-form"> <form id="config-form">
<div id="wiki-config-form hide">
<input id="wiki-config-form-permalink" class="hide" name="wiki_permalink">
{{ input(
id="wiki-config-form-permalink-new",
size="s12",
label="Wiki permalink",
form_obj=config_form.wiki_permalink_new
) }}
{{ input(
id="wiki-config-form-name",
size="s12",
label="Wiki name",
form_obj=config_form.wiki_name
) }}
{{ input(
id="wiki-config-form-author",
size="s12",
label="Wiki author",
form_obj=config_form.wiki_author
) }}
{{ input(
id="wiki-config-form-description",
size="s12",
class="materialize-textarea",
label="Wiki description",
form_obj=config_form.wiki_description
) }}
{{ input(
id="wiki-config-form-tags",
size="s12",
label="Wiki tags",
form_obj=config_form.wiki_tags
) }}
</div>
{{ input( {{ input(
size="s12", size="s12",
col_class="config-textarea-col", col_class="config-textarea-col",
@ -70,10 +120,12 @@
id="config-textarea" id="config-textarea"
) }} ) }}
</form> </form>
<textarea id="config-editor-config-data" class="hide">{{ config_form.config.data }}</textarea>
</div> </div>
</div> </div>
<script src="static/vendors/codemirror/lib/codemirror.js"></script> <script src="static/vendors/codemirror/lib/codemirror.js"></script>
<script src="static/vendors/codemirror/mode/properties/properties.js"></script> <script src="static/vendors/codemirror/mode/properties/properties.js"></script>
<script src="static/vendors/codemirror/mode/markdown/markdown.js"></script>
{{ process_js_sources(src="main/config-editor.js")|safe }} {{ process_js_sources(src="main/config-editor.js")|safe }}
{% endmacro %} {% endmacro %}

6
default_wiki_config.ini Normal file
View File

@ -0,0 +1,6 @@
[WikiSettings]
theme = light
accent = orange
background = None
roles = admin,user,public_user
custom_app_title = DashMachine