Projects overview

* Added projects overview
* Added modal for new project
* Added error codes and validation for new project path
projects
Domeniko Gentner 3 years ago
parent 76cf02a1f0
commit 285a808ee4
  1. 43
      labertasche/blueprints/bp_dashboard.py
  2. 12
      labertasche/helper/__init__.py
  3. 2
      static/css/labertasche.css
  4. 16
      static/css/sass/labertasche.scss
  5. 68
      static/js/dashboard.js
  6. 120
      templates/project_overview.html

@ -6,11 +6,11 @@
# * _repo : https://git.tuxstash.de/gothseidank/labertasche
# * _license : This project is under MIT License
# *********************************************************************************/
from flask import Blueprint, render_template, request, redirect
from flask import Blueprint, render_template, request, redirect, make_response, jsonify
from flask_login import login_required
from labertasche.database import labertasche_db as db
from labertasche.models import TLocation, TComments, TEmail
from labertasche.helper import dates_of_the_week, export_location
from labertasche.models import TLocation, TComments, TEmail, TProjects
from labertasche.helper import dates_of_the_week, export_location, get_id_from_project_name
from sqlalchemy import func
import re
@ -18,15 +18,48 @@ import re
bp_dashboard = Blueprint("bp_dashboard", __name__, url_prefix='/dashboard')
@bp_dashboard.route('/')
@bp_dashboard.route("/")
@login_required
def dashboard_index():
t_projects = db.session.query(TProjects).all()
projects = list()
for each in t_projects:
comments = db.session.query(TComments).filter(TComments.project_id == each.id_project) \
.filter(TComments.is_published == True) \
.filter(TComments.is_spam == False).count()
unpub_comments = db.session.query(TComments).filter(TComments.project_id == each.id_project) \
.filter(TComments.is_spam == False) \
.filter(TComments.is_published == False).count()
spam = db.session.query(TComments).filter(TComments.project_id == each.id_project) \
.filter(TComments.is_spam == True).count()
projects.append(dict({
"id_project": each.id_project,
"name": each.name,
"total_comments": comments,
"total_spam": spam,
"total_unpublished": unpub_comments
}))
return render_template('project_overview.html', projects=projects)
@bp_dashboard.route("/project/new", methods=['POST'])
@login_required
def dashboard_new_project():
return make_response(jsonify(status='too-short'), 200)
@bp_dashboard.route('/<project>/')
@login_required
def dashboard_project_index(project: str):
proj_id = get_id_from_project_name(project)
dates = dates_of_the_week()
spam = list()
published = list()
unpublished = list()
for each in dates:
spam_comments = db.session.query(TComments).filter(func.DATE(TComments.created_on) == each.date())\
spam_comments = db.session.query(TComments).filter(TComments.project_id == proj_id)\
.filter(func.DATE(TComments.created_on) == each.date())\
.filter(TComments.is_spam == True).all()
pub_comments = db.session.query(TComments).filter(func.DATE(TComments.created_on) == each.date()) \

@ -8,7 +8,7 @@
# *********************************************************************************/
import datetime
import json
from labertasche.models import TLocation, TComments
from labertasche.models import TLocation, TComments, TProjects
from labertasche.settings import Settings
from labertasche.database import labertasche_db as db
from functools import wraps
@ -192,3 +192,13 @@ def dates_of_the_week():
date_list.append(monday)
date_list.append((monday + datetime.timedelta(days=1, hours=23, minutes=59, seconds=59)))
return date_list
def get_id_from_project_name(name: str) -> int:
"""
Returns the id of a project name
:param name: The display name of the project
:return: the ID of the project
"""
proj = db.session.query(TProjects).filter(TProjects.name == name).first()
return proj.id_project

File diff suppressed because one or more lines are too long

@ -23,7 +23,10 @@ $navbar-burger-color: black;
$footer-background-color: #393f4d;
$footer-color: true;
$card-header-color: white;
$card-header-color: black;
$card-header-background-color: #feda6a;
$card-footer-background-color: #feda6a;
$card-background-color: grey;
$table-head-background-color: #feda6a;
$table-body-background-color: white;
@ -78,6 +81,11 @@ canvas{
border: 2px solid #feda6a;
}
.brdr-darkslate{
border: 2px solid #1d1e22;
}
.bg-compliment{
background-color: #384667;
}
@ -85,3 +93,9 @@ canvas{
.fg-yellow{
color: #feda6a;
}
.my-shadow-subtle{
-webkit-box-shadow: 5px 5px 5px 0 rgba(0,0,0,0.75);
-moz-box-shadow: 5px 5px 5px 0 rgba(0,0,0,0.75);
box-shadow: 5px 5px 5px 0 rgba(0,0,0,0.75);
}

@ -19,3 +19,71 @@ function dashboard_mailsearch(search_txt)
}
}
}
function new_project_save() {
let modal_ok = document.getElementById('modal-ok');
let modal_cancel = document.getElementById('modal-cancel');
let short_help = document.getElementById('new-project-too-short');
let short_help_invalid = document.getElementById('new-project-invalid-name');
let name = document.getElementById('project-name').value
short_help.classList.add('is-hidden');
short_help_invalid.classList.add('is-hidden');
// Validate input
if (name.length === 0) {
short_help.classList.remove('is-hidden');
return false;
}
if (/^\w+$/.test(name) === false){
short_help_invalid.classList.remove('is-hidden');
return false;
}
modal_ok.classList.add('is-loading');
modal_cancel.classList.add('is-hidden');
fetch(window.location.protocol + "//" + window.location.host + '/dashboard/project/new',
{
mode: "cors",
headers: {
'Access-Control-Allow-Origin': '*',
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
// use real location
body: JSON.stringify({
"name": name
})
})
.then(async function (response) {
let result = await response.json();
result = result['status'];
modal_ok.classList.remove('is-loading');
modal_cancel.classList.remove('is-hidden');
if (result === "ok"){
hide_modal('modal-new-project');
}
if (result === "too-short"){
short_help.classList.remove('is-hidden');
}
if (result === "invalid-name"){
short_help_invalid.classList.remove('is-hidden');
}
})
.catch(function (exc) {
console.log(exc);
})
}
function hide_modal(id_name)
{
let el = document.getElementById(id_name);
el.classList.remove("is-active");
}
function show_modal(id_name)
{
let el = document.getElementById(id_name);
el.classList.add("is-active");
}

@ -0,0 +1,120 @@
{% extends "base.html" %}
{% block main %}
<div style="min-height: 100vh;" class="container bg-deepmatte p-6 brdr-yayellow">
<h1 class="is-size-2 mb-3 is-uppercase">Select project</h1>
<div class="columns is-multiline">
<div class="column is-4">
<div class="card my-shadow-subtle brdr-darkslate">
<div class="card-header">
<div class="card-header-title">
<p class="is-size-4 is-uppercase">
NEW PROJECT
</p>
</div>
</div>
<div class="card-content has-text-white">
<div class="level is-mobile">
<div class="level-item has-text-centered">
<div>
<p class="heading is-capitalized">Comments</p>
<p class="is-size-4 has-text-weight-bold has-text-white">n/a</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="heading is-capitalized">Unpublished</p>
<p class="is-size-4 has-text-weight-bold has-text-white">n/a</p>
</div>
</div>
<div class="level-item has-text-centered">
<div class="ml-4">
<p class="heading is-capitalized">Spam</p>
<p class="is-size-4 has-text-weight-bold has-text-white">n/a</p>
</div>
</div>
</div>
</div>
<div class="card-footer">
<div class="card-footer-item">
<a class="has-text-weight-bold has-text-black is-uppercase"
onclick="show_modal('modal-new-project');"
href="#">NEW</a>
</div>
</div>
</div>
</div>
{% for project in projects %}
<div class="column is-4">
<div class="card my-shadow-subtle brdr-darkslate">
<div class="card-header">
<div class="card-header-title">
<p class="is-size-4 is-uppercase">
{{ project['name'] }}
</p>
</div>
</div>
<div class="card-content has-text-white">
<div class="level is-mobile">
<div class="level-item has-text-centered">
<div>
<p class="heading is-capitalized">Comments</p>
<p class="is-size-4 has-text-weight-bold has-text-white">{{ project['total_comments'] }}</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="heading is-capitalized">Unpublished</p>
<p class="is-size-4 has-text-weight-bold has-text-white">{{ project['total_unpublished'] }}</p>
</div>
</div>
<div class="level-item has-text-centered">
<div class="ml-4">
<p class="heading is-capitalized">Spam</p>
<p class="is-size-4 has-text-weight-bold has-text-white">{{ project['total_spam'] }}</p>
</div>
</div>
</div>
</div>
<div class="card-footer">
<div class="card-footer-item">
<a class="has-text-weight-bold has-text-black is-uppercase" href="#">EDIT</a>
</div>
<div class="card-footer-item">
<a class="has-text-weight-bold has-text-black is-uppercase" href="#">DELETE</a>
</div>
<div class="card-footer-item">
<a class="has-text-weight-bold has-text-black is-uppercase"
href="{{ url_for('bp_dashboard.dashboard_project_index', project=project['name'])}}">VIEW</a>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<div class="modal is-active" id="modal-new-project">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">New Project</p>
<button class="delete" aria-label="close"></button>
</header>
<section class="modal-card-body">
<label for="project-name" class="has-text-black">PROJECT NAME
<input class="input is-success"
type="text"
name="project-name"
id="project-name"
placeholder="Type a name without special characters.."
>
</label>
<p id="new-project-too-short" class="is-hidden help has-text-danger">Input too short. Needs at least 1 character!</p>
<p id="new-project-invalid-name" class="is-hidden help has-text-danger">Input is invalid. Please use only a-z and 0-9.</p>
</section>
<footer class="modal-card-foot">
<button id="modal-ok" onclick="new_project_save()" class="button is-success">Save</button>
<button id="modal-cancel" onclick="hide_modal('modal-new-project')" class="button is-danger">Cancel</button>
</footer>
</div>
</div>
{% endblock %}
Loading…
Cancel
Save