This commit is contained in:
Kostiantyn Stoliarskyi 2023-05-11 10:16:13 +03:00
parent a2e9d0dd4d
commit b611ad6b65
3 changed files with 28 additions and 215 deletions

View File

@ -1386,12 +1386,8 @@ input:checked + .toggle-bg {
height: 2.75rem;
}
.h-2 {
height: 0.5rem;
}
.h-2\.5 {
height: 0.625rem;
.h-14 {
height: 3.5rem;
}
.h-3 {
@ -1442,14 +1438,6 @@ input:checked + .toggle-bg {
height: 100vh;
}
.h-10 {
height: 2.5rem;
}
.h-14 {
height: 3.5rem;
}
.max-h-full {
max-height: 100%;
}
@ -1466,12 +1454,8 @@ input:checked + .toggle-bg {
width: 91.666667%;
}
.w-2 {
width: 0.5rem;
}
.w-2\.5 {
width: 0.625rem;
.w-14 {
width: 3.5rem;
}
.w-2\/3 {
@ -1530,14 +1514,6 @@ input:checked + .toggle-bg {
width: 100vw;
}
.w-10 {
width: 2.5rem;
}
.w-14 {
width: 3.5rem;
}
.max-w-2xl {
max-width: 42rem;
}
@ -1951,6 +1927,11 @@ input:checked + .toggle-bg {
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
.border-red-700 {
--tw-border-opacity: 1;
border-color: rgb(200 30 30 / var(--tw-border-opacity));
}
.border-transparent {
border-color: transparent;
}
@ -1960,11 +1941,6 @@ input:checked + .toggle-bg {
border-color: rgb(255 255 255 / var(--tw-border-opacity));
}
.border-red-700 {
--tw-border-opacity: 1;
border-color: rgb(200 30 30 / var(--tw-border-opacity));
}
.bg-blue-50 {
--tw-bg-opacity: 1;
background-color: rgb(235 245 255 / var(--tw-bg-opacity));
@ -2015,11 +1991,6 @@ input:checked + .toggle-bg {
background-color: rgb(222 247 236 / var(--tw-bg-opacity));
}
.bg-green-400 {
--tw-bg-opacity: 1;
background-color: rgb(49 196 141 / var(--tw-bg-opacity));
}
.bg-red-100 {
--tw-bg-opacity: 1;
background-color: rgb(253 232 232 / var(--tw-bg-opacity));
@ -2030,11 +2001,6 @@ input:checked + .toggle-bg {
background-color: rgb(240 82 82 / var(--tw-bg-opacity));
}
.bg-red-600 {
--tw-bg-opacity: 1;
background-color: rgb(224 36 36 / var(--tw-bg-opacity));
}
.bg-red-700 {
--tw-bg-opacity: 1;
background-color: rgb(200 30 30 / var(--tw-bg-opacity));
@ -2361,16 +2327,16 @@ input:checked + .toggle-bg {
color: rgb(240 82 82 / var(--tw-text-opacity));
}
.text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.text-red-700 {
--tw-text-opacity: 1;
color: rgb(200 30 30 / var(--tw-text-opacity));
}
.text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.opacity-0 {
opacity: 0;
}
@ -2483,11 +2449,6 @@ input:checked + .toggle-bg {
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
}
.hover\:bg-gray-50:hover {
--tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
}
.hover\:bg-red-800:hover {
--tw-bg-opacity: 1;
background-color: rgb(155 28 28 / var(--tw-bg-opacity));
@ -2709,15 +2670,15 @@ input:checked + .toggle-bg {
border-color: rgb(17 24 39 / var(--tw-border-opacity));
}
:is(.dark .dark\:border-transparent) {
border-color: transparent;
}
:is(.dark .dark\:border-red-500) {
--tw-border-opacity: 1;
border-color: rgb(240 82 82 / var(--tw-border-opacity));
}
:is(.dark .dark\:border-transparent) {
border-color: transparent;
}
:is(.dark .dark\:bg-blue-600) {
--tw-bg-opacity: 1;
background-color: rgb(28 100 242 / var(--tw-bg-opacity));
@ -2806,16 +2767,16 @@ input:checked + .toggle-bg {
color: rgb(251 213 213 / var(--tw-text-opacity));
}
:is(.dark .dark\:text-white) {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
:is(.dark .dark\:text-red-500) {
--tw-text-opacity: 1;
color: rgb(240 82 82 / var(--tw-text-opacity));
}
:is(.dark .dark\:text-white) {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
:is(.dark .dark\:placeholder-gray-400)::-moz-placeholder {
--tw-placeholder-opacity: 1;
color: rgb(156 163 175 / var(--tw-placeholder-opacity));
@ -2861,6 +2822,11 @@ input:checked + .toggle-bg {
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
:is(.dark .dark\:hover\:bg-red-600:hover) {
--tw-bg-opacity: 1;
background-color: rgb(224 36 36 / var(--tw-bg-opacity));
}
:is(.dark .dark\:hover\:bg-red-700:hover) {
--tw-bg-opacity: 1;
background-color: rgb(200 30 30 / var(--tw-bg-opacity));
@ -2871,11 +2837,6 @@ input:checked + .toggle-bg {
background-color: rgb(3 102 114 / var(--tw-bg-opacity));
}
:is(.dark .dark\:hover\:bg-red-600:hover) {
--tw-bg-opacity: 1;
background-color: rgb(224 36 36 / var(--tw-bg-opacity));
}
:is(.dark .dark\:hover\:text-blue-500:hover) {
--tw-text-opacity: 1;
color: rgb(63 131 248 / var(--tw-text-opacity));

View File

@ -1,114 +0,0 @@
<!-- prettier-ignore -->
{% extends 'base.html' %}
{% block content %}
<div class="w-full relative overflow-x-auto shadow-md sm:rounded-lg mt-5 mr-64">
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead
class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400"
>
<tr>
<th scope="col" class="px-6 py-3">#</th> <th scope="col" class="px-6 py-3">Name</th> <th scope="col" class="px-6 py-3">Active</th> <th scope="col" class="px-6 py-3">Actions</th>
</tr>
</thead>
<tbody>
{% for user in users %}
<tr
class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600"
>
<td class="w-4 p-4">
<div class="flex items-center">
{{ loop.index + page.skip }}
</div>
</td>
<td
scope="row"
class="flex items-center px-6 py-4 text-gray-900 whitespace-nowrap dark:text-white"
>
<div class="pl-3">
<div class="text-base font-semibold">{{ user.username }}</div>
</div>
</td>
<td class="p-4 text-base font-normal text-gray-900 whitespace-nowrap dark:text-white">
<div class="flex items-center">
<!-- prettier-ignore -->
{% if user.activated %}<div class="flex items-center"><div class="h-2.5 w-2.5 rounded-full bg-green-400 mr-2"></div> Active</div></div>{% else %}<div class="flex items-center"><div class="h-2.5 w-2.5 rounded-full bg-red-500 mr-2"></div> Offline</div>{% endif %}
</td>
<td class="p-4 space-x-2 whitespace-nowrap">
<button type="button" data-target="{{user.json}}" class="user-edit-button inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white rounded-lg bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
<svg class="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M17.414 2.586a2 2 0 00-2.828 0L7 10.172V13h2.828l7.586-7.586a2 2 0 000-2.828z"></path><path fill-rule="evenodd" d="M2 6a2 2 0 012-2h4a1 1 0 010 2H4v10h10v-4a1 1 0 112 0v4a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" clip-rule="evenodd"></path></svg>
Edit user
</button>
<button data-user-id={{ user.id }} type="button" class="inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white bg-red-600 rounded-lg hover:bg-red-800 focus:ring-4 focus:ring-red-300 dark:focus:ring-red-900 delete-user-btn">
<svg class="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd"></path></svg>
Delete user
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if page.pages > 1 %}
<div class="container content-center mt-3 flex bg-white dark:bg-gray-800">
<nav aria-label="Page navigation example" class="mx-auto">
<ul class="inline-flex items-center -space-x-px">
<li>
<!-- prettier-ignore -->
<a href="{{ url_for('user.get_all') }}?page=1&q={{page.query}}" class="block px-3 py-2 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
<span class="sr-only">First</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> <path fill-rule="evenodd" d="M15.79 14.77a.75.75 0 01-1.06.02l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 111.04 1.08L11.832 10l3.938 3.71a.75.75 0 01.02 1.06zm-6 0a.75.75 0 01-1.06.02l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 111.04 1.08L5.832 10l3.938 3.71a.75.75 0 01.02 1.06z" clip-rule="evenodd" /> </svg>
</a>
</li>
<li>
<!-- prettier-ignore -->
<a href="{{ url_for('user.get_all') }}?page={{page.page-1 if page.page > 1 else 1}}&q={{page.query}}" class="block px-3 py-2 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
<span class="sr-only">Previous</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> <path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" /> </svg>
</a>
</li>
<!-- prettier-ignore -->
{% for p in page.pages_for_links %}
<li>
<!-- prettier-ignore -->
{% if p == page.page %}
<!-- prettier-ignore -->
<a href="{{ url_for('user.get_all') }}?page={{p}}&q={{page.query}}" aria-current="page" class="z-10 px-3 py-2 leading-tight text-blue-600 border border-blue-300 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white">{{p}}</a>
{% else %}
<!-- prettier-ignore -->
<a href="{{ url_for('user.get_all') }}?page={{p}}&q={{page.query}}" class="px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">{{p}}</a>
{% endif %}
</li>
{% endfor %}
<li>
<!-- prettier-ignore -->
<a href="{{ url_for('user.get_all') }}?page={{page.page+1 if page.page < page.pages else page.pages}}&q={{page.query}}" class="block px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 rounded-r-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
<!-- prettier-ignore -->
<span class="sr-only">Next</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> <path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" /> </svg>
</a>
</li>
<li>
<!-- prettier-ignore -->
<a href="{{ url_for('user.get_all') }}?page={{page.pages}}&q={{page.query}}" class="block px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 rounded-r-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
<!-- prettier-ignore -->
<span class="sr-only">Last</span>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" class="w-5 h-5"> <path fill-rule="evenodd" d="M10.21 14.77a.75.75 0 01.02-1.06L14.168 10 10.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" /> <path fill-rule="evenodd" d="M4.21 14.77a.75.75 0 01.02-1.06L8.168 10 4.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" /> </svg>
</a>
</li>
</ul>
</nav>
</div>
</div>
{% endif %}
</div>
{% include 'user/add.html' %}
<!-- prettier-ignore -->
{% endblock %}
<!-- prettier-ignore -->
{% block scripts %}
{% endblock %}

View File

@ -7,46 +7,12 @@ from app import models as m, db
from tests.utils import login
def test_list(populate: FlaskClient):
login(populate)
DEFAULT_PAGE_SIZE = app.config["DEFAULT_PAGE_SIZE"]
response = populate.get("/user/")
assert response
assert response.status_code == 200
html = response.data.decode()
users = m.User.query.order_by(m.User.id).limit(11).all()
assert len(users) == 11
for user in users[:DEFAULT_PAGE_SIZE]:
assert user.username in html
assert users[10].username not in html
populate.application.config["PAGE_LINKS_NUMBER"] = 6
response = populate.get("/user/?page=6")
assert response
assert response.status_code == 200
html = response.data.decode()
assert "/user/?page=6" in html
assert "/user/?page=3" in html
assert "/user/?page=8" in html
assert "/user/?page=10" not in html
assert "/user/?page=2" not in html
def test_create_admin(runner: FlaskCliRunner):
res: Result = runner.invoke(args=["create-admin"])
assert "admin created" in res.output
assert m.User.query.filter_by(username=app.config["ADMIN_USERNAME"]).first()
def test_delete_user(populate: FlaskClient):
login(populate)
users = m.User.query.all()
uc = len(users)
response = populate.delete("/user/delete/1")
assert m.User.query.count() < uc
assert response.status_code == 200
def test_search_user(populate: FlaskClient, runner: FlaskCliRunner):
_, current_user = login(populate)
MAX_SEARCH_RESULTS = populate.application.config["MAX_SEARCH_RESULTS"]