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__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def fetch_task_parent_info(node):
|
def fetch_task_extra_info(node):
|
||||||
"""Extends the node with some parent info.
|
"""Extends the node with some info about its parent and project.
|
||||||
|
|
||||||
This allows us to link to the shot the task is attached to.
|
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,
|
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']:
|
if node.get('node_type') != node_type_task['name']:
|
||||||
return
|
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')
|
parent_id = node.get('parent')
|
||||||
if not parent_id:
|
if not parent_id:
|
||||||
return
|
return
|
||||||
|
|
||||||
nodes_coll = current_app.data.driver.db['nodes']
|
nodes_coll = current_app.db()['nodes']
|
||||||
parent = nodes_coll.find_one({'_id': parent_id},
|
parent = nodes_coll.find_one({'_id': parent_id},
|
||||||
projection={'node_type': 1,
|
projection={'node_type': 1,
|
||||||
'name': 1})
|
'name': 1})
|
||||||
@@ -35,11 +42,32 @@ def fetch_task_parent_info(node):
|
|||||||
node['_parent_info'] = parent
|
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):
|
def fetch_tasks_parent_info(nodes):
|
||||||
for node in nodes['_items']:
|
for node in nodes['_items']:
|
||||||
fetch_task_parent_info(node)
|
fetch_task_extra_info(node)
|
||||||
|
|
||||||
|
|
||||||
def setup_app(app):
|
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
|
app.on_fetched_resource_nodes += fetch_tasks_parent_info
|
||||||
|
@@ -2,6 +2,7 @@ import logging
|
|||||||
|
|
||||||
from flask import Blueprint, render_template, request
|
from flask import Blueprint, render_template, request
|
||||||
import flask
|
import flask
|
||||||
|
import flask_login
|
||||||
|
|
||||||
import pillarsdk
|
import pillarsdk
|
||||||
from pillar.web.system_util import pillar_api
|
from pillar.web.system_util import pillar_api
|
||||||
@@ -19,7 +20,23 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
@blueprint.route('/')
|
@blueprint.route('/')
|
||||||
def index():
|
def index():
|
||||||
return render_template('attract/tasks/index.html')
|
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'])
|
@blueprint.route('/<task_id>', methods=['DELETE'])
|
||||||
@@ -86,7 +103,6 @@ def save(project, task_id):
|
|||||||
@perproject_blueprint.route('/create', methods=['POST'])
|
@perproject_blueprint.route('/create', methods=['POST'])
|
||||||
@attract_project_view()
|
@attract_project_view()
|
||||||
def create_task(project):
|
def create_task(project):
|
||||||
|
|
||||||
task_type = request.form['task_type']
|
task_type = request.form['task_type']
|
||||||
parent = request.form.get('parent', None)
|
parent = request.form.get('parent', None)
|
||||||
|
|
||||||
|
@@ -15,15 +15,17 @@ function _remove_task_from_list(task_id) {
|
|||||||
/**
|
/**
|
||||||
* Open an item such as tasks/shots in the #item-details div
|
* 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) {
|
if (item_id === undefined || item_type === undefined) {
|
||||||
throw new ReferenceError("item_open(" + item_id + ", " + item_type + ") called.");
|
throw new ReferenceError("item_open(" + item_id + ", " + item_type + ") called.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var project_url = ProjectUtils.projectUrl();
|
|
||||||
if (typeof project_url === 'undefined') {
|
if (typeof project_url === 'undefined') {
|
||||||
throw new ReferenceError("ProjectUtils.projectUrl() undefined");
|
project_url = ProjectUtils.projectUrl();
|
||||||
|
if (typeof project_url === 'undefined') {
|
||||||
|
throw new ReferenceError("ProjectUtils.projectUrl() undefined");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($(window).scrollTop() > 0) {
|
if ($(window).scrollTop() > 0) {
|
||||||
@@ -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'){
|
if (ProjectUtils.context() == 'shot'){
|
||||||
$('[id^="shot-"]').removeClass('active');
|
$('[id^="shot-"]').removeClass('active');
|
||||||
@@ -360,6 +363,7 @@ $(function() {
|
|||||||
$("a.task-link[data-task-id]").click(function(e) {
|
$("a.task-link[data-task-id]").click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var task_id = e.delegateTarget.dataset.taskId;
|
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-light: hsl(hue($color-background), 20%, 35%)
|
||||||
$color-background-nav-dark: hsl(hue($color-background), 20%, 15%)
|
$color-background-nav-dark: hsl(hue($color-background), 20%, 15%)
|
||||||
|
|
||||||
|
$color-background-active: #dafff5 // background colour for active items.
|
||||||
|
|
||||||
$font-body: 'Roboto'
|
$font-body: 'Roboto'
|
||||||
$font-headings: 'Lato'
|
$font-headings: 'Lato'
|
||||||
$font-size: 14px
|
$font-size: 14px
|
||||||
|
@@ -79,7 +79,7 @@
|
|||||||
border-color: $color-background-dark
|
border-color: $color-background-dark
|
||||||
border-right-color: $color-primary
|
border-right-color: $color-primary
|
||||||
text-decoration: none
|
text-decoration: none
|
||||||
background-color: rgba($color-background, .5)
|
background-color: $color-background-active
|
||||||
|
|
||||||
.status-indicator
|
.status-indicator
|
||||||
transform: scale(1.1)
|
transform: scale(1.1)
|
||||||
|
@@ -36,7 +36,7 @@
|
|||||||
| {% block footer_scripts %}
|
| {% block footer_scripts %}
|
||||||
script.
|
script.
|
||||||
{% if open_task_id %}
|
{% if open_task_id %}
|
||||||
$(function() { task_open('{{ open_task_id }}'); });
|
$(function() { item_open('{{ open_task_id }}', 'task', false); });
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
script(src="{{ url_for('static_attract', filename='assets/js/vendor/clipboard.min.js')}}")
|
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