Added user-specific task list.
This commit is contained in:
@@ -7,8 +7,8 @@ from attract.node_types.task import node_type_task
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def fetch_task_parent_info(node):
|
||||
"""Extends the node with some parent info.
|
||||
def fetch_task_extra_info(node):
|
||||
"""Extends the node with some info about its parent and project.
|
||||
|
||||
This allows us to link to the shot the task is attached to.
|
||||
However, such a link requires at least knowing the parent node type,
|
||||
@@ -18,11 +18,18 @@ def fetch_task_parent_info(node):
|
||||
if node.get('node_type') != node_type_task['name']:
|
||||
return
|
||||
|
||||
fetch_task_parent_info(node)
|
||||
fetch_task_project_info(node)
|
||||
|
||||
|
||||
def fetch_task_parent_info(node):
|
||||
"""Store node parent info in node['_parent_info']."""
|
||||
|
||||
parent_id = node.get('parent')
|
||||
if not parent_id:
|
||||
return
|
||||
|
||||
nodes_coll = current_app.data.driver.db['nodes']
|
||||
nodes_coll = current_app.db()['nodes']
|
||||
parent = nodes_coll.find_one({'_id': parent_id},
|
||||
projection={'node_type': 1,
|
||||
'name': 1})
|
||||
@@ -35,11 +42,32 @@ def fetch_task_parent_info(node):
|
||||
node['_parent_info'] = parent
|
||||
|
||||
|
||||
def fetch_task_project_info(node):
|
||||
"""Store node project info in node['_project_info']."""
|
||||
|
||||
project_id = node.get('project')
|
||||
if not project_id:
|
||||
log.warning('Task node %s has no project!', node['_id'])
|
||||
return
|
||||
|
||||
proj_coll = current_app.db()['projects']
|
||||
project = proj_coll.find_one({'_id': project_id},
|
||||
projection={'name': 1,
|
||||
'url': 1})
|
||||
if project is None:
|
||||
log.warning("Task node %s has project %s, but the project doesn't exist.",
|
||||
node['_id'], project_id)
|
||||
return
|
||||
|
||||
project.pop('_id') # always there, but also already included in the node.
|
||||
node['_project_info'] = project
|
||||
|
||||
|
||||
def fetch_tasks_parent_info(nodes):
|
||||
for node in nodes['_items']:
|
||||
fetch_task_parent_info(node)
|
||||
fetch_task_extra_info(node)
|
||||
|
||||
|
||||
def setup_app(app):
|
||||
app.on_fetched_item_nodes += fetch_task_parent_info
|
||||
app.on_fetched_item_nodes += fetch_task_extra_info
|
||||
app.on_fetched_resource_nodes += fetch_tasks_parent_info
|
||||
|
@@ -2,6 +2,7 @@ import logging
|
||||
|
||||
from flask import Blueprint, render_template, request
|
||||
import flask
|
||||
import flask_login
|
||||
|
||||
import pillarsdk
|
||||
from pillar.web.system_util import pillar_api
|
||||
@@ -19,8 +20,24 @@ log = logging.getLogger(__name__)
|
||||
|
||||
@blueprint.route('/')
|
||||
def index():
|
||||
user = flask_login.current_user
|
||||
if not user.is_authenticated:
|
||||
return render_template('attract/tasks/index.html')
|
||||
|
||||
api = pillar_api()
|
||||
|
||||
# TODO: also include tasks assigned to any of the user's groups.
|
||||
tasks = pillarsdk.Node.all({
|
||||
'where': {
|
||||
'properties.assigned_to.users': user.objectid,
|
||||
'node_type': node_type_task['name'],
|
||||
}
|
||||
}, api=api)
|
||||
|
||||
return render_template('attract/tasks/for_user.html',
|
||||
tasks=tasks['_items'],
|
||||
task_count=tasks['_meta']['total'])
|
||||
|
||||
|
||||
@blueprint.route('/<task_id>', methods=['DELETE'])
|
||||
def delete(task_id):
|
||||
@@ -86,7 +103,6 @@ def save(project, task_id):
|
||||
@perproject_blueprint.route('/create', methods=['POST'])
|
||||
@attract_project_view()
|
||||
def create_task(project):
|
||||
|
||||
task_type = request.form['task_type']
|
||||
parent = request.form.get('parent', None)
|
||||
|
||||
|
@@ -15,16 +15,18 @@ function _remove_task_from_list(task_id) {
|
||||
/**
|
||||
* Open an item such as tasks/shots in the #item-details div
|
||||
*/
|
||||
function item_open(item_id, item_type, pushState)
|
||||
function item_open(item_id, item_type, pushState, project_url)
|
||||
{
|
||||
if (item_id === undefined || item_type === undefined) {
|
||||
throw new ReferenceError("item_open(" + item_id + ", " + item_type + ") called.");
|
||||
}
|
||||
|
||||
var project_url = ProjectUtils.projectUrl();
|
||||
if (typeof project_url === 'undefined') {
|
||||
project_url = ProjectUtils.projectUrl();
|
||||
if (typeof project_url === 'undefined') {
|
||||
throw new ReferenceError("ProjectUtils.projectUrl() undefined");
|
||||
}
|
||||
}
|
||||
|
||||
if ($(window).scrollTop() > 0) {
|
||||
$("html, body").animate({scrollTop: 0 }, '500', 'swing');
|
||||
@@ -76,9 +78,10 @@ function item_open(item_id, item_type, pushState)
|
||||
);
|
||||
}
|
||||
|
||||
function task_open(task_id)
|
||||
// Fine if project_url is undefined, but that requires ProjectUtils.projectUrl().
|
||||
function task_open(task_id, project_url)
|
||||
{
|
||||
item_open(task_id, 'task');
|
||||
item_open(task_id, 'task', true, project_url);
|
||||
|
||||
if (ProjectUtils.context() == 'shot'){
|
||||
$('[id^="shot-"]').removeClass('active');
|
||||
@@ -360,6 +363,7 @@ $(function() {
|
||||
$("a.task-link[data-task-id]").click(function(e) {
|
||||
e.preventDefault();
|
||||
var task_id = e.delegateTarget.dataset.taskId;
|
||||
task_open(task_id);
|
||||
var project_url = e.delegateTarget.dataset.projectUrl; // fine if undefined
|
||||
task_open(task_id, project_url);
|
||||
});
|
||||
});
|
||||
|
@@ -6,6 +6,8 @@ $color-background-nav: hsl(hue($color-background), 20%, 25%)
|
||||
$color-background-nav-light: hsl(hue($color-background), 20%, 35%)
|
||||
$color-background-nav-dark: hsl(hue($color-background), 20%, 15%)
|
||||
|
||||
$color-background-active: #dafff5 // background colour for active items.
|
||||
|
||||
$font-body: 'Roboto'
|
||||
$font-headings: 'Lato'
|
||||
$font-size: 14px
|
||||
|
@@ -79,7 +79,7 @@
|
||||
border-color: $color-background-dark
|
||||
border-right-color: $color-primary
|
||||
text-decoration: none
|
||||
background-color: rgba($color-background, .5)
|
||||
background-color: $color-background-active
|
||||
|
||||
.status-indicator
|
||||
transform: scale(1.1)
|
||||
|
@@ -36,7 +36,7 @@
|
||||
| {% block footer_scripts %}
|
||||
script.
|
||||
{% if open_task_id %}
|
||||
$(function() { task_open('{{ open_task_id }}'); });
|
||||
$(function() { item_open('{{ open_task_id }}', 'task', false); });
|
||||
{% endif %}
|
||||
|
||||
script(src="{{ url_for('static_attract', filename='assets/js/vendor/clipboard.min.js')}}")
|
||||
|
45
src/templates/attract/tasks/for_user.jade
Normal file
45
src/templates/attract/tasks/for_user.jade
Normal file
@@ -0,0 +1,45 @@
|
||||
| {% extends 'attract/layout.html' %}
|
||||
| {% block bodyattrs %}{{ super() }} data-context='task'{% endblock %}
|
||||
| {% block page_title %}Tasks for you{% endblock %}
|
||||
| {% block body %}
|
||||
#col_main
|
||||
.col_header.task-list-header
|
||||
| Your tasks ({{ task_count }})
|
||||
|
||||
#task-list.col-list
|
||||
| {% for task in tasks %}
|
||||
//- NOTE: this is tightly linked to the JS in tasks.js, function task_add()
|
||||
a.col-list-item.task-list-item(
|
||||
class="status-{{ task.properties.status }} task-link",
|
||||
title="In project '{{ task._project_info.name }}'",
|
||||
href="{{ url_for('attract.tasks.perproject.view_task', project_url=task._project_info.url, task_id=task._id) }}")
|
||||
span.status-indicator
|
||||
span.name {{ task.name }}
|
||||
span.type {{ task.properties.task_type }}
|
||||
| {% endfor %}
|
||||
|
||||
.col-splitter
|
||||
|
||||
#col_right
|
||||
.col_header
|
||||
span.header_text
|
||||
#status-bar
|
||||
#item-details
|
||||
.item-details-empty
|
||||
| Select a Task
|
||||
| {% endblock %}
|
||||
|
||||
| {% block footer_scripts %}
|
||||
script.
|
||||
{% if open_task_id %}
|
||||
$(function() { task_open('{{ open_task_id }}'); });
|
||||
{% endif %}
|
||||
|
||||
script(src="{{ url_for('static_attract', filename='assets/js/vendor/clipboard.min.js')}}")
|
||||
script(src="{{ url_for('static_attract', filename='assets/js/vendor/jquery-resizable.min.js')}}")
|
||||
script.
|
||||
$("#col_main").resizable({
|
||||
handleSelector: ".col-splitter",
|
||||
resizeHeight: false
|
||||
});
|
||||
| {% endblock %}
|
Reference in New Issue
Block a user