Navigation: Unified cloud navigation
* Removed main drop down menu * Added "My cloud" to user menu * Attract/Flamenco is found under Production Tools menu * Attract/Flamenco has the same navigation as its project
This commit is contained in:
@@ -10,7 +10,7 @@ from pillar.api.utils import str2id
|
|||||||
from pillar.web.utils import mass_attach_project_pictures
|
from pillar.web.utils import mass_attach_project_pictures
|
||||||
import pillar.web.subquery
|
import pillar.web.subquery
|
||||||
from pillar.web.system_util import pillar_api
|
from pillar.web.system_util import pillar_api
|
||||||
from pillar.web.projects.routes import project_view
|
from pillar.web.projects.routes import project_view, project_navigation_links
|
||||||
import pillarsdk
|
import pillarsdk
|
||||||
|
|
||||||
from attract import current_attract
|
from attract import current_attract
|
||||||
@@ -64,10 +64,12 @@ def index():
|
|||||||
except (ValueError, wz_exceptions.NotFound):
|
except (ValueError, wz_exceptions.NotFound):
|
||||||
act.link = None
|
act.link = None
|
||||||
|
|
||||||
|
project = session.get('attract_last_project')
|
||||||
return render_template('attract/index.html',
|
return render_template('attract/index.html',
|
||||||
tasks=tasks,
|
tasks=tasks,
|
||||||
projs_with_summaries=projs_with_summaries,
|
projs_with_summaries=projs_with_summaries,
|
||||||
activities=activities)
|
activities=activities,
|
||||||
|
project=project)
|
||||||
|
|
||||||
|
|
||||||
def error_project_not_setup_for_attract():
|
def error_project_not_setup_for_attract():
|
||||||
@@ -92,8 +94,6 @@ def attract_project_view(extra_project_projections: dict=None, extension_props=F
|
|||||||
:param full_project: skip projections altogether, fetching the whole project.
|
:param full_project: skip projections altogether, fetching the whole project.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from . import EXTENSION_NAME
|
|
||||||
|
|
||||||
if callable(extra_project_projections):
|
if callable(extra_project_projections):
|
||||||
raise TypeError('Use with @attract_project_view() <-- note the parentheses')
|
raise TypeError('Use with @attract_project_view() <-- note the parentheses')
|
||||||
|
|
||||||
@@ -101,14 +101,14 @@ def attract_project_view(extra_project_projections: dict=None, extension_props=F
|
|||||||
'_id': 1,
|
'_id': 1,
|
||||||
'name': 1,
|
'name': 1,
|
||||||
'node_types': 1,
|
'node_types': 1,
|
||||||
|
'nodes_featured': 1,
|
||||||
|
'extension_props': 1,
|
||||||
# We don't need this here, but this way the wrapped function has access
|
# We don't need this here, but this way the wrapped function has access
|
||||||
# to the orignal URL passed to it.
|
# to the orignal URL passed to it.
|
||||||
'url': 1,
|
'url': 1,
|
||||||
}
|
}
|
||||||
if extra_project_projections:
|
if extra_project_projections:
|
||||||
projections.update(extra_project_projections)
|
projections.update(extra_project_projections)
|
||||||
if extension_props:
|
|
||||||
projections['extension_props.%s' % EXTENSION_NAME] = 1
|
|
||||||
|
|
||||||
def decorator(wrapped):
|
def decorator(wrapped):
|
||||||
@functools.wraps(wrapped)
|
@functools.wraps(wrapped)
|
||||||
|
@@ -5,6 +5,8 @@ import flask
|
|||||||
|
|
||||||
import pillarsdk
|
import pillarsdk
|
||||||
import pillar.api.utils
|
import pillar.api.utils
|
||||||
|
from pillar import current_app
|
||||||
|
from pillar.web.projects.routes import project_navigation_links
|
||||||
from pillar.web.system_util import pillar_api
|
from pillar.web.system_util import pillar_api
|
||||||
|
|
||||||
from attract.routes import attract_project_view
|
from attract.routes import attract_project_view
|
||||||
@@ -30,6 +32,8 @@ def for_project(project, attract_props, task_id=None, asset_id=None):
|
|||||||
project, attract_props, task_id, asset_id)
|
project, attract_props, task_id, asset_id)
|
||||||
|
|
||||||
can_create = current_attract.auth.current_user_may(current_attract.auth.Actions.USE)
|
can_create = current_attract.auth.current_user_may(current_attract.auth.Actions.USE)
|
||||||
|
navigation_links = project_navigation_links(project, pillar_api())
|
||||||
|
extension_sidebar_links = current_app.extension_sidebar_links(project)
|
||||||
|
|
||||||
return render_template('attract/assets/for_project.html',
|
return render_template('attract/assets/for_project.html',
|
||||||
assets=assets,
|
assets=assets,
|
||||||
@@ -40,7 +44,10 @@ def for_project(project, attract_props, task_id=None, asset_id=None):
|
|||||||
project=project,
|
project=project,
|
||||||
attract_props=attract_props,
|
attract_props=attract_props,
|
||||||
can_create_task=can_create,
|
can_create_task=can_create,
|
||||||
can_create_asset=can_create)
|
can_create_asset=can_create,
|
||||||
|
navigation_links=navigation_links,
|
||||||
|
extension_sidebar_links=extension_sidebar_links,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@perproject_blueprint.route('/<asset_id>')
|
@perproject_blueprint.route('/<asset_id>')
|
||||||
|
@@ -6,6 +6,8 @@ import werkzeug.exceptions as wz_exceptions
|
|||||||
|
|
||||||
import pillarsdk
|
import pillarsdk
|
||||||
import pillar.api.utils
|
import pillar.api.utils
|
||||||
|
from pillar import current_app
|
||||||
|
from pillar.web.projects.routes import project_navigation_links
|
||||||
from pillar.web.system_util import pillar_api
|
from pillar.web.system_util import pillar_api
|
||||||
|
|
||||||
from attract.routes import attract_project_view
|
from attract.routes import attract_project_view
|
||||||
@@ -38,6 +40,8 @@ def for_project(project, attract_props, task_id=None, shot_id=None):
|
|||||||
if shot.properties.used_in_edit),
|
if shot.properties.used_in_edit),
|
||||||
}
|
}
|
||||||
can_create_task = current_attract.auth.current_user_may(current_attract.auth.Actions.USE)
|
can_create_task = current_attract.auth.current_user_may(current_attract.auth.Actions.USE)
|
||||||
|
navigation_links = project_navigation_links(project, pillar_api())
|
||||||
|
extension_sidebar_links = current_app.extension_sidebar_links(project)
|
||||||
|
|
||||||
return render_template('attract/shots/for_project.html',
|
return render_template('attract/shots/for_project.html',
|
||||||
shots=shots,
|
shots=shots,
|
||||||
@@ -48,7 +52,9 @@ def for_project(project, attract_props, task_id=None, shot_id=None):
|
|||||||
project=project,
|
project=project,
|
||||||
attract_props=attract_props,
|
attract_props=attract_props,
|
||||||
stats=stats,
|
stats=stats,
|
||||||
can_create_task=can_create_task)
|
can_create_task=can_create_task,
|
||||||
|
navigation_links=navigation_links,
|
||||||
|
extension_sidebar_links=extension_sidebar_links)
|
||||||
|
|
||||||
|
|
||||||
@perproject_blueprint.route('/<shot_id>')
|
@perproject_blueprint.route('/<shot_id>')
|
||||||
|
@@ -7,6 +7,7 @@ import flask_login
|
|||||||
import werkzeug.exceptions as wz_exceptions
|
import werkzeug.exceptions as wz_exceptions
|
||||||
|
|
||||||
import pillarsdk
|
import pillarsdk
|
||||||
|
from pillar.web.projects.routes import project_navigation_links
|
||||||
from pillar.web.system_util import pillar_api
|
from pillar.web.system_util import pillar_api
|
||||||
import pillar.api.utils
|
import pillar.api.utils
|
||||||
import pillar.web.subquery
|
import pillar.web.subquery
|
||||||
@@ -47,16 +48,20 @@ def delete(task_id):
|
|||||||
|
|
||||||
|
|
||||||
@perproject_blueprint.route('/', endpoint='index')
|
@perproject_blueprint.route('/', endpoint='index')
|
||||||
@attract_project_view()
|
@attract_project_view(extension_props=False)
|
||||||
def for_project(project, task_id=None):
|
def for_project(project, task_id=None):
|
||||||
tasks = current_attract.task_manager.tasks_for_project(project['_id'])
|
tasks = current_attract.task_manager.tasks_for_project(project['_id'])
|
||||||
can_create_task = current_attract.auth.current_user_may(current_attract.auth.Actions.USE)
|
can_create_task = current_attract.auth.current_user_may(current_attract.auth.Actions.USE)
|
||||||
|
navigation_links = project_navigation_links(project, pillar_api())
|
||||||
|
extension_sidebar_links = current_app.extension_sidebar_links(project)
|
||||||
|
|
||||||
return render_template('attract/tasks/for_project.html',
|
return render_template('attract/tasks/for_project.html',
|
||||||
tasks=tasks['_items'],
|
tasks=tasks['_items'],
|
||||||
open_task_id=task_id,
|
open_task_id=task_id,
|
||||||
project=project,
|
project=project,
|
||||||
can_create_task=can_create_task)
|
can_create_task=can_create_task,
|
||||||
|
navigation_links=navigation_links,
|
||||||
|
extension_sidebar_links=extension_sidebar_links)
|
||||||
|
|
||||||
|
|
||||||
@perproject_blueprint.route('/<task_id>')
|
@perproject_blueprint.route('/<task_id>')
|
||||||
|
@@ -78,7 +78,7 @@ nav.sidebar
|
|||||||
.table-head
|
.table-head
|
||||||
&.is-fixed
|
&.is-fixed
|
||||||
position: fixed
|
position: fixed
|
||||||
top: 42px
|
top: 84px
|
||||||
z-index: 1
|
z-index: 1
|
||||||
pointer-events: none
|
pointer-events: none
|
||||||
background-color: white
|
background-color: white
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
| {% extends 'attract/layout.html' %}
|
| {% extends 'attract/layout.html' %}
|
||||||
| {% block bodyattrs %}{{ super() }} data-context='asset'{% endblock %}
|
| {% block bodyattrs %}{{ super() }} data-context='asset'{% endblock %}
|
||||||
| {% block page_title %}Assets - {{ project.name }}{% endblock %}
|
| {% block page_title %}Assets - {{ project.name }}{% endblock %}
|
||||||
| {% block body %}
|
| {% block attractbody %}
|
||||||
#col_main
|
#col_main
|
||||||
.col_header.item-list-header
|
.col_header.item-list-header
|
||||||
a.item-project(href="{{url_for('projects.view', project_url=project.url)}}") {{ project.name }}
|
a.item-project(href="{{url_for('projects.view', project_url=project.url)}}") {{ project.name }}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
| {% block bodyattrs %}{{ super() }} data-context='dashboard'{% endblock %}
|
| {% block bodyattrs %}{{ super() }} data-context='dashboard'{% endblock %}
|
||||||
| {% block page_title %}Dashboard{% endblock %}
|
| {% block page_title %}Dashboard{% endblock %}
|
||||||
|
|
||||||
| {% block body %}
|
| {% block attractbody %}
|
||||||
#col_main
|
#col_main
|
||||||
.dashboard
|
.dashboard
|
||||||
.d-stats.pt-2.px-2
|
.d-stats.pt-2.px-2
|
||||||
|
@@ -1,38 +1,24 @@
|
|||||||
doctype html
|
| {% extends 'projects/view.html' %}
|
||||||
html(lang="en")
|
include ../../../../pillar/src/templates/mixins/components
|
||||||
head
|
|
||||||
meta(charset="utf-8")
|
|
||||||
title {% if self.page_title() %}{% block page_title %}{% endblock %} — {% endif %}Attract
|
|
||||||
meta(name="viewport", content="width=device-width, initial-scale=1.0")
|
|
||||||
|
|
||||||
| {% block head %}{% endblock %}
|
| {% set title = 'production-tools' %}
|
||||||
|
|
||||||
link(href='//fonts.googleapis.com/css?family=Roboto:300,400', rel='stylesheet', type='text/css')
|
| {% block css %}
|
||||||
|
| {{ super() }}
|
||||||
link(href="{{ url_for('static_pillar', filename='assets/css/font-pillar.css') }}", rel="stylesheet")
|
|
||||||
link(href="{{ url_for('static_attract', filename='assets/css/main.css') }}", rel="stylesheet")
|
link(href="{{ url_for('static_attract', filename='assets/css/main.css') }}", rel="stylesheet")
|
||||||
link(href="{{ url_for('static_attract', filename='assets/css/plugins/js_select2.css') }}", rel="stylesheet")
|
link(href="{{ url_for('static_attract', filename='assets/css/plugins/js_select2.css') }}", rel="stylesheet")
|
||||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery-3.1.0.min.js')}}")
|
|
||||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.bootstrap-3.3.7.min.js') }}")
|
|
||||||
script(src="{{ url_for('static_pillar', filename='assets/js/tutti.min.js') }}")
|
|
||||||
script.
|
|
||||||
pillar.utils.initCurrentUser({{ current_user | json | safe }});
|
|
||||||
script(src="{{ url_for('static_attract', filename='assets/js/generated/tutti.min.js') }}")
|
|
||||||
|
|
||||||
link(href="{{ url_for('static_attract', filename='assets/img/favicon.png') }}", rel="shortcut icon")
|
link(href="{{ url_for('static_attract', filename='assets/img/favicon.png') }}", rel="shortcut icon")
|
||||||
link(href="{{ url_for('static_attract', filename='assets/img/apple-touch-icon-precomposed.png') }}", rel="icon apple-touch-icon-precomposed", sizes="192x192")
|
link(href="{{ url_for('static_attract', filename='assets/img/apple-touch-icon-precomposed.png') }}", rel="icon apple-touch-icon-precomposed", sizes="192x192")
|
||||||
|
| {% endblock css %}
|
||||||
|
|
||||||
| {% block style %}{% endblock %}
|
| {% block head %}
|
||||||
|
script(src="{{ url_for('static_attract', filename='assets/js/generated/tutti.min.js') }}")
|
||||||
|
| {% endblock head %}
|
||||||
|
|
||||||
body("{% block bodyattrs %}{% if project %}data-project-url='{{ project.url }}'{% endif %}{% endblock %}")
|
| {% block body %}
|
||||||
#app-main
|
#app-main
|
||||||
#col_sidebar
|
#col_sidebar
|
||||||
nav.sidebar(role='navigation')
|
nav.sidebar(role='navigation')
|
||||||
a.navbar-brand(
|
|
||||||
href="{{ url_for('main.homepage') }}",
|
|
||||||
title="Blender Cloud")
|
|
||||||
span.app-logo
|
|
||||||
i.pi-blender-cloud
|
|
||||||
ul
|
ul
|
||||||
li
|
li
|
||||||
a.navbar-item.attract(href="{{ url_for('attract.index') }}",
|
a.navbar-item.attract(href="{{ url_for('attract.index') }}",
|
||||||
@@ -66,56 +52,16 @@ html(lang="en")
|
|||||||
data-url="{{ url_for('attract.help', project_url=project.url) }}")
|
data-url="{{ url_for('attract.help', project_url=project.url) }}")
|
||||||
i.pi-question
|
i.pi-question
|
||||||
| {% endif %}
|
| {% endif %}
|
||||||
|
| {% block attractbody %}
|
||||||
|
| {% endblock attractbody %}
|
||||||
|
| {% endblock body %}
|
||||||
|
|
||||||
| {% include 'menus/notifications.html' %}
|
| {% block footer_scripts_pre %}
|
||||||
| {% include 'menus/user.html' %}
|
|
||||||
|
|
||||||
| {% block body %}
|
|
||||||
#col_left
|
|
||||||
#col_main
|
|
||||||
h1 Main
|
|
||||||
#col_right
|
|
||||||
h1 Right
|
|
||||||
| {% endblock %}
|
|
||||||
|
|
||||||
.modal#modal(role="dialog", tabindex="-1")
|
|
||||||
.modal-dialog(role="document")
|
|
||||||
.modal-content
|
|
||||||
.modal-header
|
|
||||||
span.modal-title.title
|
|
||||||
button.close(type="button", data-dismiss="modal", aria-label="Close")
|
|
||||||
i.pi-cancel
|
|
||||||
.modal-body
|
|
||||||
|
|
||||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.select2.min.js') }}", async=true)
|
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.select2.min.js') }}", async=true)
|
||||||
script(src="{{ url_for('static_attract', filename='assets/js/vendor/moment-2.15.2.min.js') }}")
|
script(src="{{ url_for('static_attract', filename='assets/js/vendor/moment-2.15.2.min.js') }}")
|
||||||
script(src="{{ url_for('static_attract', filename='assets/js/vendor/pikaday.js') }}")
|
script(src="{{ url_for('static_attract', filename='assets/js/vendor/pikaday.js') }}")
|
||||||
| {% if current_user.is_authenticated %}
|
| {% if project %}
|
||||||
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.typewatch-3.0.0.min.js') }}")
|
|
||||||
script.
|
script.
|
||||||
// When sending an AJAX request, always add the X-CSRFToken header to it.
|
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}", projectUrl: "{{project.url}}"});
|
||||||
var csrf_token = "{{ csrf_token() }}";
|
|
||||||
$.ajaxSetup({
|
|
||||||
beforeSend: function (xhr, settings) {
|
|
||||||
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
|
|
||||||
xhr.setRequestHeader("X-CSRFToken", csrf_token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
| {% endif %}
|
| {% endif %}
|
||||||
|
| {% endblock footer_scripts_pre %}
|
||||||
script.
|
|
||||||
{% if project %}
|
|
||||||
$('.js-help').openModalUrl('Help', "{{ url_for('attract.help', project_url=project.url) }}");
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
{% if current_user.is_authenticated %}
|
|
||||||
getNotificationsLoop(); // Check for new notifications in the background
|
|
||||||
|
|
||||||
// Resize #notifications and change overflow for scrollbars
|
|
||||||
$(window).on("resize", function() { notificationsResize(); });
|
|
||||||
{% endif %}
|
|
||||||
});
|
|
||||||
|
|
||||||
| {% block footer_scripts %}{% endblock %}
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
| {% extends 'attract/layout.html' %}
|
| {% extends 'attract/layout.html' %}
|
||||||
| {% block page_title %}{{ project.name }} - Attract{% endblock %}
|
| {% block page_title %}{{ project.name }} - Attract{% endblock %}
|
||||||
| {% block body %}
|
| {% block attractbody %}
|
||||||
#page-container
|
#page-container
|
||||||
#page-content
|
#page-content
|
||||||
.project
|
.project
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
| {% extends 'attract/layout.html' %}
|
| {% extends 'attract/layout.html' %}
|
||||||
| {% block bodyattrs %}{{ super() }} data-context='shot'{% endblock %}
|
| {% block bodyattrs %}{{ super() }} data-context='shot'{% endblock %}
|
||||||
| {% block page_title %}Shots - {{ project.name }}{% endblock %}
|
| {% block page_title %}Shots - {{ project.name }}{% endblock %}
|
||||||
| {% block body %}
|
| {% block attractbody %}
|
||||||
#col_main
|
#col_main
|
||||||
.col_header.item-list-header
|
.col_header.item-list-header
|
||||||
a.item-project(href="{{url_for('projects.view', project_url=project.url)}}") {{ project.name }}
|
a.item-project(href="{{url_for('projects.view', project_url=project.url)}}") {{ project.name }}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
| {% extends 'attract/layout.html' %}
|
| {% extends 'attract/layout.html' %}
|
||||||
| {% block page_title %}Shots{% endblock %}
|
| {% block page_title %}Shots{% endblock %}
|
||||||
| {% block body %}
|
| {% block attractbody %}
|
||||||
#col_main
|
#col_main
|
||||||
h1 Attract projects
|
h1 Attract projects
|
||||||
ul
|
ul
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
li.tabs-attract(
|
li
|
||||||
title="Attract",
|
a.navbar-item(
|
||||||
data-toggle="tooltip",
|
href="{{ url_for('attract.project_index', project_url=project.url) }}"
|
||||||
data-placement="right")
|
title="Attract Production Tracking")
|
||||||
| {% if project %}
|
|
||||||
a(href="{{url_for('attract.project_index', project_url=project.url, _external=True)}}")
|
|
||||||
i.pi-attract
|
i.pi-attract
|
||||||
| {% endif %}
|
span Production Tracking
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
| {% extends 'attract/layout.html' %}
|
| {% extends 'attract/layout.html' %}
|
||||||
| {% block bodyattrs %}{{ super() }} data-context='task'{% endblock %}
|
| {% block bodyattrs %}{{ super() }} data-context='task'{% endblock %}
|
||||||
| {% block page_title %}Tasks - {{ project.name }} {% endblock %}
|
| {% block page_title %}Tasks - {{ project.name }} {% endblock %}
|
||||||
| {% block body %}
|
| {% block attractbody %}
|
||||||
|
|
||||||
#col_main
|
#col_main
|
||||||
.col_header.item-list-header
|
.col_header.item-list-header
|
||||||
a.item-project(href="{{url_for('projects.view', project_url=project.url)}}") {{ project.name }}
|
a.item-project(href="{{url_for('projects.view', project_url=project.url)}}") {{ project.name }}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
| {% extends 'attract/layout.html' %}
|
| {% extends 'attract/layout.html' %}
|
||||||
| {% block bodyattrs %}{{ super() }} data-context='task'{% endblock %}
|
| {% block bodyattrs %}{{ super() }} data-context='task'{% endblock %}
|
||||||
| {% block page_title %}Tasks for You{% endblock %}
|
| {% block page_title %}Tasks for You{% endblock %}
|
||||||
| {% block body %}
|
| {% block attractbody %}
|
||||||
#col_main
|
#col_main
|
||||||
| {% from "attract/tasks/task_list_for_user.html" import task_list_for_user %}
|
| {% from "attract/tasks/task_list_for_user.html" import task_list_for_user %}
|
||||||
| {{ task_list_for_user(task_count, tasks) }}
|
| {{ task_list_for_user(task_count, tasks) }}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
| {% extends 'attract/layout.html' %}
|
| {% extends 'attract/layout.html' %}
|
||||||
| {% block page_title %}Tasks{% endblock %}
|
| {% block page_title %}Tasks{% endblock %}
|
||||||
| {% block body %}
|
| {% block attractbody %}
|
||||||
#col_main
|
#col_main
|
||||||
.col_header Tasks
|
.col_header Tasks
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user