From d57fdb5eb52222be4f6b6b2c5c96942a847b108c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Valenta?= <git@imaniti.org> Date: Sat, 18 Feb 2023 19:49:56 +0900 Subject: [PATCH] wip - contract table --- contracts/admin.py | 5 +- contracts/forms.py | 2 + contracts/models.py | 38 ++++-- contracts/templates/contracts/index.html | 28 ++++- contracts/views.py | 13 +- media/.gitignore | 0 oidc/templates/oidc/base.html | 32 ----- oidc/templates/oidc/login.html | 5 - oidc/urls.py | 4 +- oidc/views.py | 8 -- package.json | 2 + registry/settings/base.py | 6 +- requirements/base.txt | 1 + shared/static/shared/default_avatar.svg | 59 +++++++++ shared/templates/shared/includes/base.html | 136 +++++++++++---------- static_src/base.js | 22 ++++ 16 files changed, 236 insertions(+), 125 deletions(-) create mode 100644 media/.gitignore delete mode 100644 oidc/templates/oidc/base.html delete mode 100644 oidc/templates/oidc/login.html create mode 100644 shared/static/shared/default_avatar.svg diff --git a/contracts/admin.py b/contracts/admin.py index fbac371..5c97886 100644 --- a/contracts/admin.py +++ b/contracts/admin.py @@ -2,7 +2,10 @@ from django.contrib import admin from shared.admin import MarkdownxGuardedModelAdmin -from .forms import ContractAdminForm, SigneeAdminForm +from .forms import ( + ContractAdminForm, + SigneeAdminForm, +) from .models import ( Contract, Contractee, diff --git a/contracts/forms.py b/contracts/forms.py index f6c1dc0..1ee82f7 100644 --- a/contracts/forms.py +++ b/contracts/forms.py @@ -1,6 +1,8 @@ from django import forms from webpack_loader.loader import WebpackLoader +from .models import Contractee, Signee + class ContractAdminForm(forms.ModelForm): class Media: diff --git a/contracts/models.py b/contracts/models.py index b25179a..375b08d 100644 --- a/contracts/models.py +++ b/contracts/models.py @@ -1,6 +1,7 @@ from django.conf import settings from django.db import models from django_countries.fields import CountryField +from colorfield.fields import ColorField from markdownx.models import MarkdownxField from shared.models import NameStrMixin @@ -84,8 +85,7 @@ class Signee(models.Model): verbose_name="Organizační složka", ) - color = models.CharField( - max_length=6, # e.g. "ffffff" + color = ColorField( blank=True, null=True, verbose_name="Barva", @@ -107,6 +107,14 @@ class Signee(models.Model): if self.department is not None: result += f", {self.department}" + representative_names = [] + + for representative in self.representatives.all(): + representative_names.append(representative.name) + + if len(representative_names) != 0: + result += " - zástupci " + ", ".join(representative_names) + return result @@ -187,9 +195,7 @@ class Contractee(models.Model): verbose_name="Organizační složka", ) - # TODO: Input validation - color = models.CharField( - max_length=6, # e.g. "ffffff" + color = ColorField( blank=True, null=True, verbose_name="Barva", @@ -205,6 +211,14 @@ class Contractee(models.Model): if self.department is not None: result += f", {self.department}" + representative_names = [] + + for representative in self.representatives.all(): + representative_names.append(representative.name) + + if len(representative_names) != 0: + result += " - zástupci " + ", ".join(representative_names) + return result @@ -496,7 +510,12 @@ class ContracteeSignature(models.Model): verbose_name_plural = "Podpisy našich smluvních stran" def __str__(self) -> str: - representatives = ", ".join(self.contractee.representatives) + representative_names = [] + + for representative in self.contractee.representatives.all(): + representative_names.append(representative.name) + + representatives = ", ".join(representative_names) result = self.contractee.name if len(representatives) != 0: @@ -531,7 +550,12 @@ class SigneeSignature(models.Model): verbose_name_plural = "Podpisy ostatních smluvních stran" def __str__(self) -> str: - representatives = ", ".join(self.signee.representatives) + representative_names = [] + + for representative in self.signee.representatives.all(): + representative_names.append(representative.name) + + representatives = ", ".join(representative_names) result = self.signee.name if len(representatives) != 0: diff --git a/contracts/templates/contracts/index.html b/contracts/templates/contracts/index.html index 79cce94..982d4e4 100644 --- a/contracts/templates/contracts/index.html +++ b/contracts/templates/contracts/index.html @@ -1,5 +1,31 @@ {% extends "shared/includes/base.html" %} {% block content %} - + <h1 class="head-alt-lg mb-10">{{ title }}</h1> + <table class="table table--striped table--bordered"> + <thead> + <tr> + <td>Identifikátor</td> + <td>Typ</td> + <td>Právní stav</td> + <td>Účinná od</td> + <td>Platná do</td> + <td>Naše smluvní strana</td> + <td>Ostatní smluvní strany</td> + </tr> + </thead> + <tbody> + {% for contract in page %} + <tr> + <td>{{ contract.identifier }}</td> + <td>{{ contract.get_type_display }}</td> + <td>{{ contract.get_legal_state_display }}</td> + <td>{{ contract.valid_start_date }}</td> + <td>{{ contract.valid_end_date }}</td> + <td></td> + <td></td> + </tr> + {% endfor %} + </tbody> + </table> {% endblock %} diff --git a/contracts/views.py b/contracts/views.py index 36fa1cc..369c042 100644 --- a/contracts/views.py +++ b/contracts/views.py @@ -1,17 +1,28 @@ from django.conf import settings from django.shortcuts import render +from django.core.paginator import Paginator + +from .models import Contract # Create your views here. def index(request): + contracts = Contract.objects.all() + paginator = Paginator(contracts, 25) + + page = paginator.get_page( + request.GET.get('page') + ) + return render( request, "contracts/index.html", { "site_url": settings.SITE_URL, "user": request.user, - "title": "Title", + "title": "Seznam smluv", "description": "Description", + "page": page, } ) diff --git a/media/.gitignore b/media/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/oidc/templates/oidc/base.html b/oidc/templates/oidc/base.html deleted file mode 100644 index 610ef36..0000000 --- a/oidc/templates/oidc/base.html +++ /dev/null @@ -1,32 +0,0 @@ -{% load static %} -{% load render_bundle from webpack_loader %} - -<!DOCTYPE html> -<html lang="cs" class="h-full"> - <head> - <meta encoding="utf-8"> - <link - rel="stylesheet" - type="text/css" - href="{% static "shared/style.css" %}" - > - - <link - rel="stylesheet" - href="https://gfonts.pirati.cz/css2?family=Bebas+Neue&family=Roboto+Condensed:ital,wght@0,300;0,400;0,700;1,300;1,400;1,700&display=swap" - > - - <link - rel="stylesheet" - type="text/css" - href="{% static "shared/fonts/pirati-ui/style.css" %}" - > - - <title>{% block current_page %}{% endblock %}</title> - - {% render_bundle "base" %} - </head> - <body> - {% block content %}{% endblock %} - </body> -</html> diff --git a/oidc/templates/oidc/login.html b/oidc/templates/oidc/login.html deleted file mode 100644 index f31980a..0000000 --- a/oidc/templates/oidc/login.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends "oidc/base.html" %} - -{% block content %} - <a href="{% url "oidc_authentication_init" %}">Přihlásit se</a> -{% endblock %} diff --git a/oidc/urls.py b/oidc/urls.py index a15ad64..139738a 100644 --- a/oidc/urls.py +++ b/oidc/urls.py @@ -3,6 +3,4 @@ from django.urls import path from . import views app_name = "oidc" -urlpatterns = [ - path("login", views.login, name="login"), -] +urlpatterns = [] diff --git a/oidc/views.py b/oidc/views.py index 23dbba5..e69de29 100644 --- a/oidc/views.py +++ b/oidc/views.py @@ -1,8 +0,0 @@ -from django.shortcuts import render - - -def login(request): - return render( - request, - "oidc/login.html", - ) diff --git a/package.json b/package.json index b6d5d92..83f28d5 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "dependencies": { "css-loader": "^6.7.3", "jquery": "^3.6.3", + "style-loader": "^3.3.1", "tailwindcss": "^3.2.4", + "tippy.js": "^6.3.7", "vue": "v2-latest", "webpack": "^5.75.0", "webpack-bundle-tracker": "^1.8.0", diff --git a/registry/settings/base.py b/registry/settings/base.py index 0495288..3d354b1 100644 --- a/registry/settings/base.py +++ b/registry/settings/base.py @@ -35,6 +35,7 @@ SECRET_KEY = env.str("SECRET_KEY") ALLOWED_HOSTS = [] STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles") +MEDIA_ROOT = os.path.join(BASE_DIR, "media") SITE_URL = env.str("SITE_URL") @@ -48,6 +49,7 @@ INSTALLED_APPS = [ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + "colorfield", "guardian", "markdownx", "pirates", @@ -129,9 +131,9 @@ AUTHENTICATION_BACKENDS = ( "guardian.backends.ObjectPermissionBackend", ) -LOGIN_URL = "/oidc/login" +LOGIN_URL = "/" LOGIN_REDIRECT_URL = "/" -LOGOUT_REDIRECT_URL = "/oidc/login" +LOGOUT_REDIRECT_URL = "/" OIDC_RP_CLIENT_ID = env.str("OIDC_RP_CLIENT_ID") OIDC_RP_CLIENT_SECRET = env.str("OIDC_RP_CLIENT_SECRET") diff --git a/requirements/base.txt b/requirements/base.txt index 9ebad7d..62a0fab 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -4,6 +4,7 @@ psycopg2-binary==2.9.5 django-webpack-loader==1.8.0 nodeenv==1.7.0 pirates==0.6.0 +django-colorfield==0.8.0 django-markdownx==4.0.0b1 django-environ==0.9.0 django-http-exceptions==1.4.0 diff --git a/shared/static/shared/default_avatar.svg b/shared/static/shared/default_avatar.svg new file mode 100644 index 0000000..ca87d5c --- /dev/null +++ b/shared/static/shared/default_avatar.svg @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + version="1.1" + width="560" + height="560" + fill="#ffffff" + id="svg15"> + <metadata + id="metadata19"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title>Abstract user icon</dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <title + id="title2">Abstract user icon</title> + <defs + id="defs7"> + <clipPath + id="circular-border"> + <circle + cx="300" + cy="300" + r="250" + id="circle4" /> + </clipPath> + </defs> + <circle + cx="280" + cy="280" + fill="#000000" + id="circle9" + r="280" + style="fill:#f5f5f5;fill-opacity:1" /> + <circle + cx="280" + cy="210" + r="100" + id="circle11" + style="fill:#262626;fill-opacity:1" /> + <circle + cx="300" + cy="550" + r="190" + clip-path="url(#circular-border)" + id="circle13" + transform="translate(-20,-20)" + style="fill:#262626;fill-opacity:1" /> +</svg> diff --git a/shared/templates/shared/includes/base.html b/shared/templates/shared/includes/base.html index a10c433..93d15aa 100644 --- a/shared/templates/shared/includes/base.html +++ b/shared/templates/shared/includes/base.html @@ -6,20 +6,20 @@ <head> <meta charset="utf-8"> - <meta name="title" content="{{ title }}"> + <meta name="title" content="{{ title }} | Registr smluv Pirátské strany"> <meta name="description" content="{{ description }}"> {% comment %}Open Graph / Facebook{% endcomment %} <meta property="og:type" content="website"> <meta property="og:url" content="{{ site_url }}"> - <meta property="og:title" content="{{ title }}"> + <meta property="og:title" content="{{ title }} | Registr smluv Pirátské strany"> <meta property="og:description" content="{{ description }}"> {% comment %}<meta property="og:image" content="">{% endcomment %} {% comment %}Twitter{% endcomment %} <meta property="twitter:card" content="app"> <meta property="twitter:url" content="{{ site_url }}"> - <meta property="twitter:title" content="{{ title }}"> + <meta property="twitter:title" content="{{ title }} | Registr smluv Pirátské strany"> <meta property="twitter:description" content="{{ description }}"> {% comment %}<meta property="twitter:image" content="">{% endcomment %} @@ -43,76 +43,82 @@ {% render_bundle "shared" %} {% render_bundle "base" %} - <title>{{ title }}</title> + <title>{{ title }} | Registr smluv Pirátské strany</title> </head> <body> - <header> - <nav class="navbar navbar--simple __js-root"> - <ui-app inline-template> - <ui-navbar inline-template> - <div> - <div class="container container--default navbar__content" :class="{'navbar__content--initialized': true}"> - <div class="navbar__brand my-4 flex items-center lg:pr-8 lg:my-0"> - <a href="/"> - <img src="https://styleguide.pirati.cz/2.11.x/images/logo-round-white.svg" class="w-8" /> - </a> - <a href="/" class="pl-4 font-bold text-xl lg:border-r lg:border-grey-300 lg:pr-8">Registr smluv</a> - </div> - - <div class="navbar__menutoggle my-4 flex justify-end lg:hidden"> - <a href="#" @click="show = !show" class="no-underline hover:no-underline"> - <i class="ico--menu text-3xl"></i> - </a> - </div> - - <div v-if="show || isLgScreenSize" class="navbar__main navbar__section navbar__section--expandable container-padding--zero lg:container-padding--auto"> - <ul class="navbar-menu text-white"> - <li class="navbar-menu__item"> - <a href="#TODO" data-href="#TODO" class="navbar-menu__link">Všechny smlouvy</a> - </li> + <nav class="navbar navbar--simple __js-root"> + <ui-app inline-template> + <ui-navbar inline-template> + <div> + <div class="container container--default navbar__content" :class="{'navbar__content--initialized': true}"> + <div class="navbar__brand my-4 flex items-center lg:pr-8 lg:my-0"> + <a href="/"> + <img src="https://styleguide.pirati.cz/2.11.x/images/logo-round-white.svg" class="w-8" /> + </a> + <a href="/" class="pl-4 font-bold text-xl hover:no-underline lg:border-r lg:border-grey-300 lg:pr-8">Registr smluv</a> + </div> + + <div class="navbar__menutoggle my-4 flex justify-end lg:hidden"> + <a href="#" @click="show = !show" class="no-underline hover:no-underline"> + <i class="ico--menu text-3xl"></i> + </a> + </div> + + <div v-if="show || isLgScreenSize" class="navbar__main navbar__section navbar__section--expandable container-padding--zero lg:container-padding--auto"> + <ul class="navbar-menu text-white"> + <li class="navbar-menu__item"> + <a href="{% url "contracts:index" %}" data-href="{% url "contracts:index" %}" class="navbar-menu__link">Všechny smlouvy</a> + </li> + <li class="navbar-menu__item"> + <a href="#TODO" data-href="#TODO" class="navbar-menu__link">Hledání</a> + </li> + {% if user.is_staff %} <li class="navbar-menu__item"> - <a href="#TODO" data-href="#TODO" class="navbar-menu__link">Hledání</a> + <a href="{% url "admin:index" %}" data-href="{% url "admin:index" %}" class="navbar-menu__link">Administrace</a> </li> - </ul> - </div> - - <div v-if="show || isLgScreenSize" class="navbar__actions navbar__section navbar__section--expandable container-padding--zero lg:container-padding--auto self-start flex flex-col sm:flex-row lg:flex-col sm:space-x-4 space-y-2 sm:space-y-0 lg:space-y-2 xl:flex-row xl:space-x-2 xl:space-y-0"> - {% if user %} - <div class="flex items-center space-x-4"> - <span class="head-heavy-2xs">{{ user.get_username }}</span> - <div class="avatar avatar--2xs"> - <img - src="https://randomuser.me/api/portraits/women/83.jpg" - alt="Tvůj profilový obrázek" - > - </div> - <form action="{% url "oidc_logout" %}" method="POST"> - {% csrf_token %} - <button - class="text-grey-200 hover:text-white" - type="submit" - ><i class="ico--log-out"></i></button> - </form> - </div> - {% else %} - <a - class="btn btn--white btn--hoveractive cursor-pointer" - href="{% url "oidc:login" %}" - > - <div class="btn__body">Přihlásit se</div> - </a> {% endif %} - </div> + </ul> + </div> + + <div v-if="show || isLgScreenSize" class="navbar__actions navbar__section navbar__section--expandable container-padding--zero lg:container-padding--auto self-start flex flex-col sm:flex-row lg:flex-col sm:space-x-4 space-y-2 sm:space-y-0 lg:space-y-2 xl:flex-row xl:space-x-2 xl:space-y-0"> + {% if user %} + <div class="flex items-center space-x-4"> + <span class="head-heavy-2xs">{{ user.get_username }}</span> + <div class="avatar avatar--2xs"> + <img + src="{% static "shared/default_avatar.svg" %}" + alt="Tvůj profilový obrázek" + > + </div> + <form action="{% url "oidc_logout" %}" method="POST"> + {% csrf_token %} + <button + class="text-grey-200 hover:text-white __tooltipped" + type="submit" + aria-label="Odhlásit se" + ><i class="ico--log-out"></i></button> + </form> + </div> + {% else %} + <a + class="btn btn--white btn--hoveractive cursor-pointer" + href="{% url "oidc_authentication_init" %}" + > + <div class="btn__body">Přihlásit se</div> + </a> + {% endif %} </div> </div> - </ui-navbar> - </ui-app> - </nav> - </header> + </div> + </ui-navbar> + </ui-app> + </nav> - <main> - {% block content %}{% endblock %} - </main> + <div class="container container--default py-8 lg:py-24"> + <main> + {% block content %}{% endblock %} + </main> + </div> <script src="https://styleguide.pirati.cz/2.11.x/js/main.bundle.js" diff --git a/static_src/base.js b/static_src/base.js index 156d4b7..524be4c 100644 --- a/static_src/base.js +++ b/static_src/base.js @@ -1,3 +1,25 @@ +import $ from "jquery"; + import Vue from "vue/dist/vue.esm.browser.min"; +import tippy from "tippy.js"; +import "tippy.js/dist/tippy.css"; +import "tippy.js/themes/light-border.css"; +import "tippy.js/animations/scale-subtle.css"; + window["Vue"] = Vue; + +$(window).ready( + () => { + // Add tooltips + for (const tooltipElement of $('.__tooltipped')) { + tippy( + tooltipElement, + { + content: tooltipElement.getAttribute("aria-label"), + animation: "scale-subtle" + } + ) + } + } +); -- GitLab