First commit of POC version
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h4 class="mb-4">Pending Users</h4>
|
||||
<ul class="list-group">
|
||||
{% for user in users %}
|
||||
<li class="list-group-item d-flex justify-content-between">
|
||||
{{ user.name }}
|
||||
<a class="btn btn-sm btn-success" href="/admin/approve/{{ user.id }}">Approve</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,68 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ title or "L@PP" }}</title>
|
||||
|
||||
<link href="/static/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="/static/jquery.min.js"></script>
|
||||
<script src="/static/bootstrap.min.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
padding-top: 64px;
|
||||
}
|
||||
.topbar {
|
||||
height: 56px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="bg-light">
|
||||
|
||||
<!-- Top Bar -->
|
||||
<nav class="navbar fixed-top navbar-light bg-white border-bottom topbar">
|
||||
<div class="container-fluid">
|
||||
<span class="navbar-brand fw-semibold">
|
||||
<a class="btn btn-light" href="{{ logo_url or '/' }}" role="button">L@PP</a>
|
||||
{% if button_top_url1 and button_top_txt1 %}
|
||||
<a href="{{ button_top_url1 }}"><img style="width: 2em; height: 2em" src="/static/{{ button_top_txt1 }}.svg"></a>
|
||||
{% endif %}
|
||||
{% if button_top_url2 and button_top_txt2 %}
|
||||
<a href="{{ button_top_url2 }}"><img style="width: 2em; height: 2em" src="/static/{{ button_top_txt2 }}.svg"></a>
|
||||
{% endif %}
|
||||
</span>
|
||||
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
{% if current_user.is_authenticated %}
|
||||
<span class="text-muted small d-none d-sm-inline">
|
||||
{{ current_user.name }}
|
||||
</span>
|
||||
<a href="{{ url_for('auth.logout') }}"
|
||||
>
|
||||
<img style="width: 2em; height: 2em" src="/static/logout.svg">
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('auth.login') }}"
|
||||
>
|
||||
<img style="width: 2em; height: 2em" src="/static/login.svg"></a>
|
||||
</a>
|
||||
<a href="{{ url_for('auth.register') }}"
|
||||
>
|
||||
<img style="width: 2em; height: 2em" src="/static/register.svg"></a>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container py-4">
|
||||
<div class="mx-auto" style="max-width: 420px;">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<form method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="list">
|
||||
|
||||
<article>
|
||||
{{ form.field1(class="") }}
|
||||
{{ form.field2(class="") }}
|
||||
{{ form.field3(class="") }}
|
||||
{{ form.field4(class="") }}
|
||||
</article>
|
||||
|
||||
</div>
|
||||
|
||||
<button type="submit" class="contrast">{{ form.submit.label }}</button>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,40 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<table id="flowerlist">
|
||||
{% for flower in flowers %}
|
||||
<tr class="flowerlist">
|
||||
<td class="flowerlist">
|
||||
<a href="javascript:DoSubmit('{{flower[0]}}')">
|
||||
{{ flower[1] }}, {{ flower[2] }}, {{ flower[3] }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="right"><span style="white-space: nowrap;">{{ flower[4][:10] }}</span></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<form id="gotopage" action="{{ url_for('data-record-show') }}" method="POST">
|
||||
<input type="hidden" id="_io" name="id" value="">
|
||||
</form>
|
||||
|
||||
<script language="javascript">
|
||||
var $rows = $('#flowerlist tr');
|
||||
$('#search').keyup(function() {
|
||||
var val = $.trim($(this).val()).replace(/ +/g, ' ').toLowerCase();
|
||||
|
||||
$rows.show().filter(function() {
|
||||
var text = $(this).text().replace(/\s+/g, ' ').toLowerCase();
|
||||
return !~text.indexOf(val);
|
||||
}).hide();
|
||||
});
|
||||
|
||||
$('#search').keyup();
|
||||
|
||||
function DoSubmit(id) {
|
||||
$('#_id').val(id);
|
||||
$('#gotopage').submit();
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,12 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Hello, {{ current_user.username }}!</h1>
|
||||
<p>Welcome to your modern minimal dashboard.</p>
|
||||
|
||||
{% if not current_user.is_authenticated %}
|
||||
<p>
|
||||
<a href="{{ url_for('login') }}">Login</a> or
|
||||
<a href="{{ url_for('register') }}">Register</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,101 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<script>
|
||||
let image_to_update = ''
|
||||
|
||||
// handle Delete
|
||||
function handleDelete(button) {
|
||||
window.location.href = '/item_delete/'+button.name ;
|
||||
}
|
||||
|
||||
// handle AddOne
|
||||
function handleAddOne(button) {
|
||||
const response = fetch('/item_addone/'+button.name);
|
||||
}
|
||||
|
||||
// handle Add with quantity
|
||||
function handleAddWithQuantity(button, q) {
|
||||
const response = fetch('/item_addquantity/'+button.name+'/'+q);
|
||||
}
|
||||
|
||||
//trigger change category button
|
||||
function clickedCategoryButton(image) {
|
||||
image_to_update = image
|
||||
}
|
||||
|
||||
// selected the category
|
||||
function clickedUpdateCategory4Item(icon) {
|
||||
image_to_update.src="{{ iconpath }}" + icon.name + ".svg"
|
||||
const response = fetch('/item_update_category/'+image_to_update.name+'/'+icon.name);
|
||||
$('#staticBackdrop').modal('hide');
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#myInput").on("keyup", function() {
|
||||
var value = $(this).val().toLowerCase();
|
||||
$("#myList tbody tr").filter(function() {
|
||||
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<form method="post">
|
||||
<div class=".container">
|
||||
<div class="d-flex justify-content-between">
|
||||
<input class="form-control" id="myInput" type="text" name="newItem" placeholder="Search.."/>
|
||||
|
||||
<button class="btn btn-success">+</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<br/>
|
||||
|
||||
<table id="myList" style="width: 100%; background-color: white;">
|
||||
<tbody>
|
||||
{% for item in items %}
|
||||
<tr style="border-bottom: 1px solid lightgray;">
|
||||
<td style="padding: 5px;">
|
||||
<a class="btn btn-{% if item.is_suggestion %}primary{% else %}info{% endif %} btn-sm" name="{{ item.id }}" onclick='handleAddOne(this);'> + </a>
|
||||
{{ item.label }}</td>
|
||||
<td style="text-align: right">
|
||||
{% if item.quantity %}
|
||||
<a class="btn btn-outline-primary btn-sm" name="{{ item.id }}" onclick='handleAddWithQuantity(this, {{ item.quantity }} );'>{{ item.quantity }}{{ item.unit }}</a>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<a href="" data-bs-toggle="modal" data-bs-target="#staticBackdrop"><img id="category4itemid_{{ item.id }}" name="{{item.id}}" src="{{ iconpath }}{{ item.category }}.svg" style="height: 2em;" alt="..." onclick='clickedCategoryButton(this);'></a>
|
||||
|
||||
|
||||
<a class="btn btn-danger btn-sm" name="{{ item.id }}" onclick='handleDelete(this);'>-</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Category</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{% for icon in icons %}
|
||||
<a name= "{{ icon }}" onclick='clickedUpdateCategory4Item(this);'><img style="border: 10px solid white; height: 4em; width: 4em;" src="{{ iconpath }}{{ icon }}.svg" alt="..."></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Exit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,64 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<script>
|
||||
const IDLE_TIME = 10000; // 10 seconds of inactivity required after user activity
|
||||
const MIN_REFRESH_GAP = 20000; // 20 seconds minimum between refreshes
|
||||
|
||||
function recordInteraction() {
|
||||
|
||||
// Reset idle timer
|
||||
if (idleTimeout) {
|
||||
clearTimeout(idleTimeout);
|
||||
}
|
||||
|
||||
idleTimeout = setTimeout(checkAndRefresh, IDLE_TIME);
|
||||
}
|
||||
|
||||
function checkAndRefresh() {
|
||||
window.location.reload(true);
|
||||
idleTimeout = setTimeout(checkAndRefresh, MIN_REFRESH_GAP);
|
||||
}
|
||||
|
||||
// User activity listeners
|
||||
["click", "touchstart", "keydown"].forEach(event => {
|
||||
document.addEventListener(event, recordInteraction, { passive: true });
|
||||
});
|
||||
|
||||
// Start idle timer on load
|
||||
idleTimeout = setTimeout(checkAndRefresh, MIN_REFRESH_GAP);
|
||||
|
||||
document.addEventListener("visibilitychange", () => {
|
||||
if (document.hidden && idleTimeout) clearTimeout(idleTimeout);
|
||||
if (!document.hidden) checkAndRefresh();
|
||||
});
|
||||
|
||||
// handle Checboc clicks
|
||||
function handleCBClick(cb) {
|
||||
const response = fetch('/item_update/'+cb.name+'/'+cb.checked);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<div class="list-group">
|
||||
{% for item in items %}
|
||||
<label class="list-group-item {% if item.is_checked %}text-muted{% endif %} d-flex justify-content-between">
|
||||
<div>
|
||||
<input class="form-check-input me-1" type="checkbox" value="" name="{{ item.id }}" {% if item.is_checked %}CHECKED{% endif %} onclick='handleCBClick(this);'>
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<div>
|
||||
{% if item.quantity > 1 %}
|
||||
{{ item.quantity }}{{ item.unit }}
|
||||
{% endif %}
|
||||
<img src="/static/categories/{{ item.category }}.svg" style="height: 2em;" alt="...">
|
||||
</div>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,56 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
{% if error_id %}
|
||||
<div class="alert alert-danger" role="alert">
|
||||
You gave a duplicate name.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<ul class="list-group">
|
||||
{% for il in ilists %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<form method="post">
|
||||
<input class="form-control mb-3{% if error_id==il.id %} is-invalid{% endif %}" name="name" value="{{ il.name }}" required>
|
||||
<input type="hidden" name="iid" value="{{ il.id }}">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" value="{{ il.is_active }}" name="is_active" {% if il.is_active %}CHECKED{% endif %}>
|
||||
<label class="form-check-label" for="is_active">
|
||||
Is active
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{% for u in users %}
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="checkbox" name="shares_{{ u.id }}" value="{{ u.name }}" {% if u.shares_in_list(il.id) %}CHECKED{% endif %}>
|
||||
<label class="form-check-label" for="inlineCheckbox1">{{ u.name }}</label>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="to_be_deleted">
|
||||
<label class="form-check-label" for="to_be_deleted">
|
||||
Must be deleted
|
||||
</label>
|
||||
</div>
|
||||
<input type="hidden" name="owner_user_id" value="{{ il.owner_user_id }}">
|
||||
|
||||
<input type="image" src="/static/save.svg" alt="Save" style="width: 2em; height: 2em;">
|
||||
</form>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<br/>
|
||||
New:<br/>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<form method="post">
|
||||
<input class="form-control mb-3{% if error_id==9999 %} is-invalid{% endif %}" name="name" placeholder="{{ newlist.name }}" required>
|
||||
<input type="image" src="/static/save.svg" alt="Save" style="width: 2em; height: 2em;">
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{{ error_id }}
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,18 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div class="list-group">
|
||||
{% for il in ilists %}
|
||||
<a class="list-group-item d-flex justify-content-between align-items-center" href="/items/{{ il.id }}">
|
||||
{{ il.name }}
|
||||
<span class="badge bg-primary rounded-pill">{{ il.items_left() }} / {{ il.items_total() }}</span>
|
||||
</a>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<a href="{{ url_for('lists.edit') }}"><img style="width: 3em; height: 3em" src="/static/edit.svg"></a>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,15 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3 class="text-center mb-4"><img style="width: 3em; height: 3em" src="/static/login.svg"></h3>
|
||||
<form method="post">
|
||||
<input class="form-control mb-3" name="name" placeholder="Name" required>
|
||||
<input class="form-control mb-3" name="password" type="password" placeholder="Password" required>
|
||||
<input
|
||||
type="image"
|
||||
src="/static/save.svg"
|
||||
alt="Save"
|
||||
style="width: 2em; height: 2em;"
|
||||
>
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,6 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="alert alert-info text-center">
|
||||
Your account is pending admin approval.
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,14 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h3 class="text-center mb-4"><img style="width: 3em; height: 3em" src="/static/register.svg"></h3>
|
||||
<form method="post">
|
||||
<input class="form-control mb-3" name="name" placeholder="New Name" required>
|
||||
<input class="form-control mb-3" name="password" type="password" placeholder="New Password" required>
|
||||
<input
|
||||
type="image"
|
||||
src="/static/save.svg"
|
||||
alt="Save"
|
||||
style="width: 2em; height: 2em;"
|
||||
>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,34 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<h2>Secure Data</h2>
|
||||
|
||||
<form method="POST">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="grid">
|
||||
<article>
|
||||
<label>{{ form.field1.label }}</label>
|
||||
{{ form.field1(class="") }}
|
||||
</article>
|
||||
|
||||
<article>
|
||||
<label>{{ form.field2.label }}</label>
|
||||
{{ form.field2(class="") }}
|
||||
</article>
|
||||
|
||||
<article>
|
||||
<label>{{ form.field3.label }}</label>
|
||||
{{ form.field3(class="") }}
|
||||
</article>
|
||||
|
||||
<article>
|
||||
<label>{{ form.field4.label }}</label>
|
||||
{{ form.field4(class="") }}
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="contrast">{{ form.submit.label }}</button>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,30 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h2>User Management</h2>
|
||||
|
||||
<div class="grid">
|
||||
{% for u in users %}
|
||||
<article>
|
||||
<header>
|
||||
<h3>{{ u.name }}</h3>
|
||||
<p>ID: {{ u.id }}</p>
|
||||
</header>
|
||||
|
||||
<p><strong>Role:</strong> {{ u.role }}</p>
|
||||
|
||||
<footer>
|
||||
{% if not u.is_admin %}
|
||||
<a href="{{ url_for('user_admit', user_id=u.id) }}">Promote to Admin</a>
|
||||
{% else %}
|
||||
<span>Admin</span>
|
||||
{% endif %}
|
||||
|
|
||||
<a href="{{ url_for('user_delete', user_id=u.id) }}"
|
||||
onclick="return confirm('Delete {{ u.username }}?');">
|
||||
Delete
|
||||
</a>
|
||||
</footer>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user