
14 changed files with 285 additions and 26 deletions
@ -0,0 +1,85 @@ |
|||||||
|
/*! |
||||||
|
Waypoints Infinite Scroll Shortcut - 4.0.1 |
||||||
|
Copyright © 2011-2016 Caleb Troughton |
||||||
|
Licensed under the MIT license. |
||||||
|
https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
|
||||||
|
*/ |
||||||
|
(function() { |
||||||
|
'use strict' |
||||||
|
|
||||||
|
var $ = window.jQuery |
||||||
|
var Waypoint = window.Waypoint |
||||||
|
|
||||||
|
/* http://imakewebthings.com/waypoints/shortcuts/infinite-scroll */ |
||||||
|
function Infinite(options) { |
||||||
|
this.options = $.extend({}, Infinite.defaults, options) |
||||||
|
this.container = this.options.element |
||||||
|
if (this.options.container !== 'auto') { |
||||||
|
this.container = this.options.container |
||||||
|
} |
||||||
|
this.$container = $(this.container) |
||||||
|
this.$more = $(this.options.more) |
||||||
|
|
||||||
|
if (this.$more.length) { |
||||||
|
this.setupHandler() |
||||||
|
this.waypoint = new Waypoint(this.options) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* Private */ |
||||||
|
Infinite.prototype.setupHandler = function() { |
||||||
|
this.options.handler = $.proxy(function() { |
||||||
|
this.options.onBeforePageLoad() |
||||||
|
this.destroy() |
||||||
|
this.$container.addClass(this.options.loadingClass) |
||||||
|
|
||||||
|
$.get($(this.options.more).attr('href'), $.proxy(function(data) { |
||||||
|
var $data = $($.parseHTML(data)) |
||||||
|
var $newMore = $data.find(this.options.more) |
||||||
|
|
||||||
|
var $items = $data.find(this.options.items) |
||||||
|
if (!$items.length) { |
||||||
|
$items = $data.filter(this.options.items) |
||||||
|
} |
||||||
|
|
||||||
|
this.$container.append($items) |
||||||
|
this.$container.removeClass(this.options.loadingClass) |
||||||
|
|
||||||
|
if (!$newMore.length) { |
||||||
|
$newMore = $data.filter(this.options.more) |
||||||
|
} |
||||||
|
if ($newMore.length) { |
||||||
|
this.$more.replaceWith($newMore) |
||||||
|
this.$more = $newMore |
||||||
|
this.waypoint = new Waypoint(this.options) |
||||||
|
this.$container.append(this.$more) |
||||||
|
} |
||||||
|
else { |
||||||
|
this.$more.remove() |
||||||
|
} |
||||||
|
|
||||||
|
this.options.onAfterPageLoad($items) |
||||||
|
}, this)) |
||||||
|
}, this) |
||||||
|
} |
||||||
|
|
||||||
|
/* Public */ |
||||||
|
Infinite.prototype.destroy = function() { |
||||||
|
if (this.waypoint) { |
||||||
|
this.waypoint.destroy() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Infinite.defaults = { |
||||||
|
container: 'auto', |
||||||
|
items: '.infinite-item', |
||||||
|
more: '.infinite-more-link', |
||||||
|
offset: 'bottom-in-view', |
||||||
|
loadingClass: 'infinite-loading', |
||||||
|
onBeforePageLoad: $.noop, |
||||||
|
onAfterPageLoad: $.noop |
||||||
|
} |
||||||
|
|
||||||
|
Waypoint.Infinite = Infinite |
||||||
|
}()) |
||||||
|
; |
@ -0,0 +1,7 @@ |
|||||||
|
/*! |
||||||
|
Waypoints Infinite Scroll Shortcut - 4.0.1 |
||||||
|
Copyright © 2011-2016 Caleb Troughton |
||||||
|
Licensed under the MIT license. |
||||||
|
https://github.com/imakewebthings/waypoints/blob/master/licenses.txt
|
||||||
|
*/ |
||||||
|
!function(){"use strict";function t(n){this.options=i.extend({},t.defaults,n),this.container=this.options.element,"auto"!==this.options.container&&(this.container=this.options.container),this.$container=i(this.container),this.$more=i(this.options.more),this.$more.length&&(this.setupHandler(),this.waypoint=new o(this.options))}var i=window.jQuery,o=window.Waypoint;t.prototype.setupHandler=function(){this.options.handler=i.proxy(function(){this.options.onBeforePageLoad(),this.destroy(),this.$container.addClass(this.options.loadingClass),i.get(i(this.options.more).attr("href"),i.proxy(function(t){var n=i(i.parseHTML(t)),e=n.find(this.options.more),s=n.find(this.options.items);s.length||(s=n.filter(this.options.items)),this.$container.append(s),this.$container.removeClass(this.options.loadingClass),e.length||(e=n.filter(this.options.more)),e.length?(this.$more.replaceWith(e),this.$more=e,this.waypoint=new o(this.options)):this.$more.remove(),this.options.onAfterPageLoad(s)},this))},this)},t.prototype.destroy=function(){this.waypoint&&this.waypoint.destroy()},t.defaults={container:"auto",items:".infinite-item",more:".infinite-more-link",offset:"bottom-in-view",loadingClass:"infinite-loading",onBeforePageLoad:i.noop,onAfterPageLoad:i.noop},o.Infinite=t}(); |
File diff suppressed because one or more lines are too long
@ -1,29 +1,18 @@ |
|||||||
{% extends "ordr3:templates/layout_small.jinja2" %} |
{% extends "ordr3:templates/layout_full.jinja2" %} |
||||||
|
|
||||||
{% block subtitle %} My Account {% endblock subtitle %} |
{% block subtitle %} My Account {% endblock subtitle %} |
||||||
|
|
||||||
{% block content %} |
{% block content %} |
||||||
|
|
||||||
<div class="container"> |
<div class="col-2 o3-sidebar"></div> |
||||||
<div class="row o3-registration-card"> |
<div class="col-5"> |
||||||
<div class="col"></div> |
<h4 class="mb-2 text-muted mb-4">Edit your account</h4> |
||||||
<div class="col"> |
|
||||||
<div class="card"> |
|
||||||
<div class="card-header bg-dark text-light"> |
|
||||||
<h2 class="card-title text-center pt-1">Ordr</h5> |
|
||||||
</div> |
|
||||||
<div class="card-body"> |
|
||||||
<h6 class="card-subtitle mb-2 text-muted text-center mt-1 mb-4">Edit your account</h6> |
|
||||||
{{form.render()|safe}} |
{{form.render()|safe}} |
||||||
<hr> |
<hr> |
||||||
<p class="mt-4"> |
<p class="mt-4"> |
||||||
<a href="{{request.resource_url(request.root, 'mypassword')}}" class="btn btn-outline-secondary">Change Password</a> |
<a href="{{request.resource_url(request.root, 'mypassword')}}" class="btn btn-outline-secondary">Change Password</a> |
||||||
</p> |
</p> |
||||||
</div> |
</div> |
||||||
</div> |
<div class="col-5"></div> |
||||||
</div> |
|
||||||
<div class="col"></div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
{% endblock content %} |
{% endblock content %} |
||||||
|
@ -0,0 +1,40 @@ |
|||||||
|
{% extends "ordr3:templates/layout_full.jinja2" %} |
||||||
|
|
||||||
|
{% block subtitle %} Manage Users {% endblock subtitle %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
|
||||||
|
<div class="col-2 o3-sidebar"> |
||||||
|
|
||||||
|
<nav class="nav nav-pills flex-column"> |
||||||
|
<div class="nav-link disabled text-small" tabindex="-1" aria-disabled="true">Role</div> |
||||||
|
<a class="nav-link {% if filter_role == 'all' %}active{% endif %}" href="{{ request.resource_url(context) }}">All</a> |
||||||
|
{% for role in roles %} |
||||||
|
<a class="nav-link {% if filter_role == role.name.lower() %}active{% endif %}" href="{{ request.resource_url(context, query={'role':role.name.lower()}) }}">{{role.name.lower()}}</a> |
||||||
|
{% endfor %} |
||||||
|
</nav> |
||||||
|
|
||||||
|
</div> |
||||||
|
<div class="col-10"> |
||||||
|
<table class="table table-hover o3-data-table"> |
||||||
|
<thead> |
||||||
|
<tr> |
||||||
|
<th scope="col">Username</th> |
||||||
|
<th scope="col">First Name</th> |
||||||
|
<th scope="col">Last Name</th> |
||||||
|
<th scope="col">Email</th> |
||||||
|
<th scope="col">Role</th> |
||||||
|
<th scope="col">Actions</th> |
||||||
|
</tr> |
||||||
|
</thead> |
||||||
|
<tbody class="infinite-container"> |
||||||
|
{% include 'ordr3:templates/users/list_content.jinja2' %} |
||||||
|
</tbody> |
||||||
|
</table> |
||||||
|
{% if not users %} |
||||||
|
<p class="bg-light text-center pt-2 pb-2">No data available</p> |
||||||
|
{% endif %} |
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %} |
@ -0,0 +1,24 @@ |
|||||||
|
{% import 'ordr3:templates/macros.jinja2' as macros with context %} |
||||||
|
{% for user in users %} |
||||||
|
<tr class="infinite-item"> |
||||||
|
<td><a href="{{request.resource_url(request.root, 'orders', query={'user':user.username})}}" title="show orders">{{ user.username }}</a></td> |
||||||
|
<td>{{ user.first_name }}</td> |
||||||
|
<td>{{ user.last_name }}</td> |
||||||
|
<td><a class="o3-copy" title="copy to clipboard">{{ user.email }}</a></td> |
||||||
|
<td>{{ user.role.name.capitalize() }}</td> |
||||||
|
<td class="o3-actions"> |
||||||
|
<a href="{{ request.resource_url(context, user.username, 'edit') }}" title="Edit user">{{ macros.icon("pencil")}}</a> |
||||||
|
<a href="{{ request.resource_url(context, user.username, 'delete') }}" title="Delete user">{{ macros.icon("trash")}}</a> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
{% endfor %} |
||||||
|
{% if next_offset %} |
||||||
|
<tr class="infinite-more-link" href="{{ request.resource_url(context, query={'o':next_offset, 'role':filter_role.lower()}) }}"> |
||||||
|
<td colspan="6"> |
||||||
|
<button class="btn btn-outline-primary btn-small"> |
||||||
|
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> |
||||||
|
Loading... |
||||||
|
</button> |
||||||
|
</td> |
||||||
|
</tr> |
||||||
|
{% endif %} |
@ -0,0 +1,55 @@ |
|||||||
|
from sqlalchemy import func |
||||||
|
from pyramid.view import view_config |
||||||
|
|
||||||
|
from .. import models |
||||||
|
|
||||||
|
|
||||||
|
def _get_role(request): |
||||||
|
role_param = request.GET.get("role", "") |
||||||
|
try: |
||||||
|
return models.UserRole[role_param.upper()] |
||||||
|
except KeyError: |
||||||
|
return None |
||||||
|
|
||||||
|
|
||||||
|
def _get_offset(request): |
||||||
|
offset_param = request.GET.get("o", 0) |
||||||
|
try: |
||||||
|
return int(offset_param) |
||||||
|
except ValueError: |
||||||
|
return 0 |
||||||
|
|
||||||
|
|
||||||
|
@view_config( |
||||||
|
context="ordr3:resources.UserList", |
||||||
|
permission="view", |
||||||
|
request_method="GET", |
||||||
|
renderer="ordr3:templates/users/list.jinja2", |
||||||
|
) |
||||||
|
@view_config( |
||||||
|
context="ordr3:resources.UserList", |
||||||
|
permission="view", |
||||||
|
request_method="GET", |
||||||
|
xhr=True, |
||||||
|
renderer="ordr3:templates/users/list_content.jinja2", |
||||||
|
) |
||||||
|
def list(context, request): |
||||||
|
role = _get_role(request) |
||||||
|
offset = _get_offset(request) |
||||||
|
limit = 12 |
||||||
|
|
||||||
|
query = request.repo.session.query(models.User) |
||||||
|
if role: |
||||||
|
query = query.filter(models.User.role == role) |
||||||
|
query = query.order_by(func.lower(models.User.username)) |
||||||
|
users = query[offset : offset + limit] # noqa: E203 |
||||||
|
|
||||||
|
next_offset = None if limit != len(users) else (offset + limit) |
||||||
|
filter_role = "all" if role is None else role.name.lower() |
||||||
|
|
||||||
|
return { |
||||||
|
"filter_role": filter_role, |
||||||
|
"roles": models.UserRole, |
||||||
|
"users": users, |
||||||
|
"next_offset": next_offset, |
||||||
|
} |
Loading…
Reference in new issue