This is our first "full page", in that we have a navbar. A large number of TODOs are left here as we're simply changing templates rather than updating views, but those gaps will be closed in a future change.
Signed-off-by: Stephen Finucane <step...@that.guru> --- patchwork/templates/patchwork/login.html | 5 +- patchwork/templates/patchwork/profile.html | 432 ++++++++++++------ templates/base2.html | 82 ++++ .../registration/password_reset_confirm.html | 4 + .../registration/password_reset_done.html | 4 + .../registration/password_reset_form.html | 4 + 6 files changed, 395 insertions(+), 136 deletions(-) diff --git patchwork/templates/patchwork/login.html patchwork/templates/patchwork/login.html index ef609f1f..b8ab462c 100644 --- patchwork/templates/patchwork/login.html +++ patchwork/templates/patchwork/login.html @@ -2,8 +2,7 @@ {% block title %}Sign in to Patchwork{% endblock %} -{% block headers %} -{% endblock %} +{% block navigation %}{% endblock %} {% block body %} <section class="hero is-primary is-fullheight"> @@ -75,3 +74,5 @@ for (var i = 0; i < btns.length; i++) { } </script> {% endblock %} + +{% block footer %}{% endblock %} diff --git patchwork/templates/patchwork/profile.html patchwork/templates/patchwork/profile.html index 552dde47..7a0b54fe 100644 --- patchwork/templates/patchwork/profile.html +++ patchwork/templates/patchwork/profile.html @@ -1,173 +1,337 @@ -{% extends "base.html" %} +{% extends "base2.html" %} {% block title %}{{ user.username }}{% endblock %} -{% block heading %}Your Profile{% endblock %} {% block body %} -<h1>Your Profile</h1> +<div class="container" style="margin-top: 1rem;"> + <div class="columns"> + <div class="column is-3"> + <aside class="menu"> + <p class="menu-label"> + Overview + </p> + <ul class="menu-list"> + <li><a href="#projects">Projects</a></li> + <li><a href="#bundles">Bundles</a></li> + <li><a href="#todo">Todo List</a></li> + </ul> + <p class="menu-label"> + Settings + </p> + <ul class="menu-list"> + <li><a href="#profile">Profile</a></li> + <li><a href="#linked-emails">Linked emails</a></li> + <li><a href="#profile-settings">Profile settings</a></li> + <li><a href="#security">Security</a></li> + </ul> + </aside> + </div> + <div class="column is-9"> + <h1 id="overview" class="title"> + <a href="#overview" title="Permalink to this section"></a> + Overview + </h1> + + <section class="block"> + <h2 id="projects" class="title is-4"> + <a href="#projects" title="Permalink to this section">#</a> + Projects + </h2> {% if user.profile.maintainer_projects.count %} -<p> - Maintainer of + <p> + Maintainer of {% for project in user.profile.maintainer_projects.all %} - <a href="{% url 'patch-list' project_id=project.linkname %}">{{ project.linkname }}</a>{% if not forloop.last %},{% endif %} + <a href="{% url 'patch-list' project_id=project.linkname %}">{{ project.linkname }}</a>{% if not forloop.last %},{% endif %} {% endfor %}. -</p> + </p> {% endif %} - {% if user.profile.contributor_projects.count %} -<p> - Contributor to + <p> + Contributor to {% for project in user.profile.contributor_projects.all %} - <a href="{% url 'patch-list' project_id=project.linkname %}">{{ project.linkname }}</a>{% if not forloop.last %},{% endif %} + <a href="{% url 'patch-list' project_id=project.linkname %}">{{ project.linkname }}</a>{% if not forloop.last %},{% endif %} {% endfor %}. -</p> + </p> {% endif %} + </section> -<div class="leftcol"> - <div class="box"> - <h2>Todo</h2> - <p> - Your <a href="{% url 'user-todos' %}">todo list</a> contains patches that - have been delegated to you. + <section class="block"> + <h2 id="bundles" class="title is-4"> + <a href="#bundles" title="Permalink to this section">#</a> + Bundles + </h2> +{% if bundles %} + <p>You have the following bundle{{ bundles|length|pluralize }}:</p> + <ul> +{% for bundle in bundles %} + <li><a href="{{ bundle.get_absolute_url }}">{{ bundle.name }}</a></li> +{% endfor %} + </ul> + <p> + Visit the <a href="{% url 'user-bundles' %}">bundles page</a> to manage your bundles. + </p> +{% else %} + <p>You have no bundles.</p> +{% endif %} + </section> + + <section class="block"> + <h2 id="todo" class="title is-4"> + <a href="#todo" title="Permalink to this section">#</a> + Todo List + </h2> + <p> + Your <a href="{% url 'user-todos' %}">todo list</a> contains patches that + have been delegated to you. + </p> + <p> {% if user.profile.n_todo_patches %} - Your have {{ user.profile.n_todo_patches }} - patch{{ user.profile.n_todo_patches|pluralize:"es" }} in your todo list. + Your have {{ user.profile.n_todo_patches }} + patch{{ user.profile.n_todo_patches|pluralize:"es" }} in your todo list. {% else %} - You have no patches in your todo list at present. + You have no patches in your todo list at present. {% endif %} - </p> - </div> + </p> + </section> - <div class="box"> - <h2>Linked email addresses</h2> - <p> - The following email addresses are associated with this Patchwork account. - Adding alternative addresses allows Patchwork to group contributions that - you have made under different addresses. - </p> - <p> - The "notify?" column allows you to opt-in or opt-out of automated - Patchwork notification emails. Setting it to "no" will disable automated - notifications for that address. - </p> - <p> - Adding a new email address will send a confirmation email to that address. - </p> - <table class="vertical"> - <tr> - <th>email</th> - <th>action</th> - <th>notify?</th> - </tr> + <h1 id="settings" class="title"> + <a href="#settings" title="Permalink to this section"></a> + Settings + </h1> + +{# TODO: Add view to enable this #} + <section class="block"> + <h2 id="profile" class="title is-4"> + <a href="#profile" title="Permalink to this section">#</a> + Profile + </h2> + <form method="post"> + {% csrf_token %} + <div class="field"> + <label for="id_username" class="label"> + Username + </label> + <div class="control"> + <input id="id_username" type="text" name="name" class="input" value="{{ user.username }}" disabled> + </div> + </div> + <div class="field"> + <label for="id_first_name" class="label"> + First name + </label> + <div class="control"> + <input id="id_first_name" type="text" name="first_name" class="input" autocomplete="given-name" value="{{ user.first_name }}"> + </div> + </div> + <div class="field"> + <label for="id_last_name" class="label"> + Last name + </label> + <div class="control"> + <input id="id_last_name" type="text" name="last_name" class="input" autocomplete="family-name" value="{{ user.last_name }}"> + </div> + </div> + <div class="control"> + <button class="button is-primary is-disabled">Save</button> + </div> + </form> + </section> + + <section class="block"> + <h2 id="linked-emails" class="title is-4"> + <a href="#linked-emails" title="Permalink to this section">#</a> + Linked emails + </h2> {% for email in linked_emails %} - <tr> - <td>{{ email.email }}</td> - <td> + <div class="card"> + <div class="card-content"> + <div class="columns"> + <div class="column"> + <span>{{ email.email }}</span> +{% if user.email == email.email %} + <span class="tag is-primary is-medium">Primary</span> +{% endif %} + </div> {% if user.email != email.email %} - <form action="{% url 'user-unlink' person_id=email.id %}" method="post"> - {% csrf_token %} - <input type="submit" value="Unlink"/> - </form> + <div class="column is-narrow"> + <form method="post" action="{% url 'user-unlink' person_id=email.id %}"> + {% csrf_token %} + <button class="button is-danger">Unlink</button> + </form> + </div> +{# TODO: Add view to enable this #} + <div class="column is-narrow"> + <form method="post"> + {% csrf_token %} + <button class="button is-info">Make primary</button> + </form> + </div> {% endif %} - </td> - <td> + <div class="column is-narrow"> {% if email.is_optout %} - <form method="post" action="{% url 'mail-optin' %}"> - {% csrf_token %} - No, - <input type="hidden" name="email" value="{{ email.email }}"/> - <input type="submit" value="Opt-in"/> - </form> + <form method="post" action="{% url 'mail-optin' %}"> + {% csrf_token %} + <input type="hidden" name="email" value="{{ email.email }}"/> + <button class="button is-info is-right">Opt-in</button> + </form> {% else %} - <form method="post" action="{% url 'mail-optout' %}"> - {% csrf_token %} - Yes, - <input type="hidden" name="email" value="{{ email.email }}"/> - <input type="submit" value="Opt-out"/> - </form> + <form method="post" action="{% url 'mail-optout' %}"> + {% csrf_token %} + <input type="hidden" name="email" value="{{ email.email }}"/> + <button class="button is-info">Opt-out</button> + </form> {% endif %} - </td> - </tr> + </div> + </div> + </div> + </div> {% endfor %} - <tr> - <td colspan="3"> - <form action="{% url 'user-link' %}" method="post"> + <div class="block"></div> + <div class="block"> + <form class="block" method="post" action="{% url 'user-link' %}"> {% csrf_token %} - {{ linkform.email }} - <input type="submit" value="Add"/> + <label for="id_email" class="label"> + Add email address + </label> + <div class="field is-grouped"> + <div class="control"> + <input id="id_email" type="email" name="email" placeholder="e.g. bobsm...@example.com" class="input" required> + </div> + <div class="control"> + <button class="button is-info"> + Add email + </button> + </div> + </div> </form> - </td> - </tr> - </table> - </div> -</div> - -<div class="rightcol"> - <div class="box"> - <h2>Bundles</h2> -{% if bundles %} - <p>You have the following bundle{{ bundles|length|pluralize }}:</p> - <ul> -{% for bundle in bundles %} - <li><a href="{{ bundle.get_absolute_url }}">{{ bundle.name }}</a></li> -{% endfor %} - </ul> - <p>Visit the <a href="{%url 'user-bundles' %}">bundles page</a> to manage your bundles.</p> -{% else %} - <p>You have no bundles.</p> -{% endif %} - </div> + </div> + </section> - <div class="box"> - <h2>Settings</h2> + <section class="block"> + <h2 id="profile-settings" class="title is-4"> + <a href="#profile-settings" title="Permalink to this section">#</a> + Profile settings + </h2> + <form class="block" method="post"> + {% csrf_token %} + <div class="field"> + <label for="id_items_per_page" class="label"> + Items per page + </label> + <div class="control"> + <input id="id_items_per_page" type="number" name="items_per_page" class="input" value="{{ user.profile.items_per_page }}" required> + <p class="help">Number of items to display per page</p> + </div> + </div> + <div class="field"> + <p class="label"> + Show patch IDs + </p> + <div class="control"> + <label class="radio"> + <input type="radio" name="show_ids"> + Yes + </label> + <label class="radio"> + <input type="radio" name="show_ids"> + No + </label> + <p class="help">Show click-to-copy patch IDs in the list view</p> + </div> + </div> + <div class="control"> + <button class="button is-primary is-disabled">Update settings</button> + </div> + </form> + </section> - <form method="post"> - {% csrf_token %} - <table class="form"> - {{ profileform }} - <tr> - <td></td> - <td><input type="submit" value="Apply"/></td> - </tr> - </table> - </form> - </div> - - <div class="box"> - <h2>Authentication</h2> - - <table class="form"> - <tr> - <th>Password:</th> - <td><a href="{% url 'password_change' %}">Change password</a> - </tr> -{% if rest_api_enabled %} - <tr> - <th>API Token:</th> - <td> -{% if api_token %} - <input id="token" style="width: 25em;" readonly value="{{ api_token }}"> - <button type="button" class="btn-copy" title="Copy to clipboard" data-clipboard-target="#token">Copy</button> -{% endif %} - </td> - <tr> - <th></th> - <td> + <section class="block"> + <h2 id="security" class="title is-4"> + <a href="#security" title="Permalink to this section">#</a> + Security + </h2> + <form class="block" method="post" action="{% url 'password_change' %}"> + {% csrf_token %} + <div class="field"> + <label for="id_old_password" class="label"> + Current password + </label> + <div class="control"> + <input id="id_old_password" type="password" name="old_password" class="input" required> + </div> + </div> + <div class="field"> + <label for="id_new_password1" class="label"> + New password + </label> + <div class="control"> + <input id="id_new_password1" type="password" name="new_password1" class="input" required> + </div> + </div> + <div class="field"> + <label for="id_new_password2" class="label"> + Confirm password + </label> + <div class="control"> + <input id="id_new_password2" type="password" name="new_password2" class="input" required> + </div> + </div> + <div class="control"> + <button class="button is-primary is-disabled">Update password</button> + </div> + </form> + <div class="block"> + <label for="id_api_token" class="label"> + API token + </label> + <div class="field has-addons"> + <div class="control is-expanded"> + <input id="id_api_token" type="text" name="name" class="input" value="{{ api_token|default_if_none:'' }}" disabled> + </div> +{# TODO: wire this up #} + <div class="control"> + <button class="button is-info"> + Copy + </button> + </div> + </div> <form method="post" action="{% url 'generate_token' %}"> {% csrf_token %} + <div class="control"> {% if api_token %} - <input type="submit" value="Regenerate token"/> + <button class="button is-primary">Regenerate token</button> {% else %} - <input type="submit" value="Generate token"/> + <button class="button is-primary">Generate token</button> {% endif %} + </div> </form> - </td> - </tr> -{% endif %} - </table> + </div> + </section> + </div> </div> </div> -<p style="clear: both"></p> +<script> +document.addEventListener('DOMContentLoaded', () => { + // Get all "navbar-burger" elements + const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); + + // Check if there are any navbar burgers + if ($navbarBurgers.length > 0) { + // Add a click event on each of them + $navbarBurgers.forEach( el => { + el.addEventListener('click', () => { + // Get the target from the "data-target" attribute + const target = el.dataset.target; + const $target = document.getElementById(target); + + // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu" + el.classList.toggle('is-active'); + $target.classList.toggle('is-active'); + }); + }); + } +}); +</script> {% endblock %} diff --git templates/base2.html templates/base2.html index ac6b43bc..6380c37b 100644 --- templates/base2.html +++ templates/base2.html @@ -10,6 +10,88 @@ {% block headers %}{% endblock %} </head> <body> +{% block navigation %} + <nav class="navbar is-white" role="navigation" aria-label="main navigation"> + <div class="container"> + <div class="navbar-brand"> + <a class="navbar-item brand-text" href="/">Patchwork</a> + <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navMenu"> + <span aria-hidden="true"></span> + <span aria-hidden="true"></span> + <span aria-hidden="true"></span> + </a> + </div> + <div id="navMenu" class="navbar-menu"> + <div class="navbar-start"> + <a class="navbar-item" href="{% url 'user-todos' %}">Todo List</a> + <a class="navbar-item" href="{% url 'user-bundles' %}">Bundles</a> + <a class="navbar-item" href="{% url 'project-list' %}">Projects</a> + </div> + <div class="navbar-end"> +{% if user.is_authenticated %} + <div class="navbar-item has-dropdown is-hoverable"> + <a class="navbar-link"> + <span class="icon-text"> + <span class="icon"> + <i class="fa fa-user"></i> + </span> + <span>{{ user.username }}</span> + </span> + </a> + <div class="navbar-dropdown is-right"> + <a class="navbar-item" href="{% url 'user-todos' %}"> + Todo List + </a> + <a class="navbar-item" href="{% url 'user-bundles' %}"> + Bundles + </a> + <a class="navbar-item" href="{% url 'user-profile' %}"> + Profile + </a> +{% if user.is_staff %} + <hr class="navbar-divider"> + <a class="navbar-item" href="{% url 'admin:index' %}"> + Patchwork Settings + </a> +{% endif %} + <hr class="navbar-divider"> + <a class="navbar-item" href="{% url 'auth_logout' %}"> + Sign out + </a> + </div> + </div> +{% else %} + <div class="navbar-item"> + <div class="buttons"> + <a href="{% url 'user-register' %}" class="button is-primary"> + <strong>Sign up</strong> + </a> + <a href="{% url 'auth_login' %}" class="button is-light"> + Log in + </a> + </div> + </div> +{% endif %} + </div> + </div> + </div> + </nav> +{% endblock %} {% block body %}{% endblock %} +{% block footer %} + <div class="block"></div> + + <footer class="footer"> + <div class="content has-text-centered"> + <p> + <a href="https://github.com/getpatchwork/patchwork/">Patchwork patch tracking system</a> + • + Version {{ version }} + • + <a href="{% url 'about' %}">About Patchwork</a> + </p> + </div> + </footer> +{% endblock %} </body> </html> diff --git templates/registration/password_reset_confirm.html templates/registration/password_reset_confirm.html index 1c91eb1b..90a7e136 100644 --- templates/registration/password_reset_confirm.html +++ templates/registration/password_reset_confirm.html @@ -3,6 +3,8 @@ {% block title %}Password reset confirmation{% endblock %} {% block heading %}Password reset confirmation{% endblock %} +{% block navigation %}{% endblock %} + {% block body %} <section class="hero is-primary is-fullheight"> <div class="hero-body"> @@ -75,3 +77,5 @@ </div> </section> {% endblock %} + +{% block footer %}{% endblock %} diff --git templates/registration/password_reset_done.html templates/registration/password_reset_done.html index ebd38e68..65b65e77 100644 --- templates/registration/password_reset_done.html +++ templates/registration/password_reset_done.html @@ -2,6 +2,8 @@ {% block title %}Password reset email sent!{% endblock %} +{% block navigation %}{% endblock %} + {% block body %} <section class="hero is-primary is-fullheight"> <div class="hero-body"> @@ -26,3 +28,5 @@ </div> </section> {% endblock %} + +{% block footer %}{% endblock %} diff --git templates/registration/password_reset_form.html templates/registration/password_reset_form.html index 431b4696..4f0c3a6a 100644 --- templates/registration/password_reset_form.html +++ templates/registration/password_reset_form.html @@ -2,6 +2,8 @@ {% block title %}Forgot your password?{% endblock %} +{% block navigation %}{% endblock %} + {% block body %} <section class="hero is-primary is-fullheight"> <div class="hero-body"> @@ -46,3 +48,5 @@ </div> </section> {% endblock %} + +{% block footer %}{% endblock %} -- 2.31.1 _______________________________________________ Patchwork mailing list Patchwork@lists.ozlabs.org https://lists.ozlabs.org/listinfo/patchwork