##// END OF EJS Templates
notifications: different approach with fixed/standard container
ergo -
r1483:211476f5 default
parent child Browse files
Show More
@@ -1,18 +1,17 b''
1 <link rel="import" href="../../../../../../bower_components/polymer/polymer.html">
1 <link rel="import" href="../../../../../../bower_components/polymer/polymer.html">
2 <link rel="import" href="../channelstream-connection/channelstream-connection.html">
2 <link rel="import" href="../channelstream-connection/channelstream-connection.html">
3 <link rel="import" href="../rhodecode-toast/rhodecode-toast.html">
3 <link rel="import" href="../rhodecode-toast/rhodecode-toast.html">
4 <link rel="import" href="../rhodecode-favicon/rhodecode-favicon.html">
4 <link rel="import" href="../rhodecode-favicon/rhodecode-favicon.html">
5
5
6 <dom-module id="rhodecode-app">
6 <dom-module id="rhodecode-app">
7 <template>
7 <template>
8 <channelstream-connection
8 <channelstream-connection
9 id="channelstream-connection"
9 id="channelstream-connection"
10 on-channelstream-listen-message="receivedMessage"
10 on-channelstream-listen-message="receivedMessage"
11 on-channelstream-connected="handleConnected"
11 on-channelstream-connected="handleConnected"
12 on-channelstream-subscribed="handleSubscribed">
12 on-channelstream-subscribed="handleSubscribed">
13 </channelstream-connection>
13 </channelstream-connection>
14 <rhodecode-favicon></rhodecode-favicon>
14 <rhodecode-favicon></rhodecode-favicon>
15 <rhodecode-toast id="notifications"></rhodecode-toast>
16 </template>
15 </template>
17 <script src="rhodecode-app.js"></script>
16 <script src="rhodecode-app.js"></script>
18 </dom-module>
17 </dom-module>
@@ -1,137 +1,141 b''
1 ccLog = Logger.get('RhodeCodeApp');
1 ccLog = Logger.get('RhodeCodeApp');
2 ccLog.setLevel(Logger.OFF);
2 ccLog.setLevel(Logger.OFF);
3
3
4 var rhodeCodeApp = Polymer({
4 var rhodeCodeApp = Polymer({
5 is: 'rhodecode-app',
5 is: 'rhodecode-app',
6 attached: function () {
6 attached: function () {
7 ccLog.debug('rhodeCodeApp created');
7 ccLog.debug('rhodeCodeApp created');
8 $.Topic('/notifications').subscribe(this.handleNotifications.bind(this));
8 $.Topic('/notifications').subscribe(this.handleNotifications.bind(this));
9 $.Topic('/favicon/update').subscribe(this.faviconUpdate.bind(this));
9 $.Topic('/favicon/update').subscribe(this.faviconUpdate.bind(this));
10 $.Topic('/connection_controller/subscribe').subscribe(
10 $.Topic('/connection_controller/subscribe').subscribe(
11 this.subscribeToChannelTopic.bind(this));
11 this.subscribeToChannelTopic.bind(this));
12 // this event can be used to coordinate plugins to do their
12 // this event can be used to coordinate plugins to do their
13 // initialization before channelstream is kicked off
13 // initialization before channelstream is kicked off
14 $.Topic('/__MAIN_APP__').publish({});
14 $.Topic('/__MAIN_APP__').publish({});
15
15
16 for (var i = 0; i < alertMessagePayloads.length; i++) {
16 for (var i = 0; i < alertMessagePayloads.length; i++) {
17 $.Topic('/notifications').publish(alertMessagePayloads[i]);
17 $.Topic('/notifications').publish(alertMessagePayloads[i]);
18 }
18 }
19 this.kickoffChannelstreamPlugin();
19 this.kickoffChannelstreamPlugin();
20 },
20 },
21
21
22 /** proxy to channelstream connection */
22 /** proxy to channelstream connection */
23 getChannelStreamConnection: function () {
23 getChannelStreamConnection: function () {
24 return this.$['channelstream-connection'];
24 return this.$['channelstream-connection'];
25 },
25 },
26
26
27 handleNotifications: function (data) {
27 handleNotifications: function (data) {
28 this.$['notifications'].handleNotification(data);
28 var elem = document.getElementById('notifications');
29 if(elem){
30 elem.handleNotification(data);
31 }
32
29 },
33 },
30
34
31 faviconUpdate: function (data) {
35 faviconUpdate: function (data) {
32 this.$$('rhodecode-favicon').counter = data.count;
36 this.$$('rhodecode-favicon').counter = data.count;
33 },
37 },
34
38
35 /** opens connection to ws server */
39 /** opens connection to ws server */
36 kickoffChannelstreamPlugin: function (data) {
40 kickoffChannelstreamPlugin: function (data) {
37 ccLog.debug('kickoffChannelstreamPlugin');
41 ccLog.debug('kickoffChannelstreamPlugin');
38 var channels = ['broadcast'];
42 var channels = ['broadcast'];
39 var addChannels = this.checkViewChannels();
43 var addChannels = this.checkViewChannels();
40 for (var i = 0; i < addChannels.length; i++) {
44 for (var i = 0; i < addChannels.length; i++) {
41 channels.push(addChannels[i]);
45 channels.push(addChannels[i]);
42 }
46 }
43 if (window.CHANNELSTREAM_SETTINGS && CHANNELSTREAM_SETTINGS.enabled){
47 if (window.CHANNELSTREAM_SETTINGS && CHANNELSTREAM_SETTINGS.enabled){
44 var channelstreamConnection = this.getChannelStreamConnection();
48 var channelstreamConnection = this.getChannelStreamConnection();
45 channelstreamConnection.connectUrl = CHANNELSTREAM_URLS.connect;
49 channelstreamConnection.connectUrl = CHANNELSTREAM_URLS.connect;
46 channelstreamConnection.subscribeUrl = CHANNELSTREAM_URLS.subscribe;
50 channelstreamConnection.subscribeUrl = CHANNELSTREAM_URLS.subscribe;
47 channelstreamConnection.websocketUrl = CHANNELSTREAM_URLS.ws + '/ws';
51 channelstreamConnection.websocketUrl = CHANNELSTREAM_URLS.ws + '/ws';
48 channelstreamConnection.longPollUrl = CHANNELSTREAM_URLS.longpoll + '/listen';
52 channelstreamConnection.longPollUrl = CHANNELSTREAM_URLS.longpoll + '/listen';
49 // some channels might already be registered by topic
53 // some channels might already be registered by topic
50 for (var i = 0; i < channels.length; i++) {
54 for (var i = 0; i < channels.length; i++) {
51 channelstreamConnection.push('channels', channels[i]);
55 channelstreamConnection.push('channels', channels[i]);
52 }
56 }
53 // append any additional channels registered in other plugins
57 // append any additional channels registered in other plugins
54 $.Topic('/connection_controller/subscribe').processPrepared();
58 $.Topic('/connection_controller/subscribe').processPrepared();
55 channelstreamConnection.connect();
59 channelstreamConnection.connect();
56 }
60 }
57 },
61 },
58
62
59 checkViewChannels: function () {
63 checkViewChannels: function () {
60 var channels = []
64 var channels = []
61 // subscribe to PR repo channel for PR's'
65 // subscribe to PR repo channel for PR's'
62 if (templateContext.pull_request_data.pull_request_id) {
66 if (templateContext.pull_request_data.pull_request_id) {
63 var channelName = '/repo$' + templateContext.repo_name + '$/pr/' +
67 var channelName = '/repo$' + templateContext.repo_name + '$/pr/' +
64 String(templateContext.pull_request_data.pull_request_id);
68 String(templateContext.pull_request_data.pull_request_id);
65 channels.push(channelName);
69 channels.push(channelName);
66 }
70 }
67 return channels;
71 return channels;
68 },
72 },
69
73
70 /** subscribes users from channels in channelstream */
74 /** subscribes users from channels in channelstream */
71 subscribeToChannelTopic: function (channels) {
75 subscribeToChannelTopic: function (channels) {
72 var channelstreamConnection = this.getChannelStreamConnection();
76 var channelstreamConnection = this.getChannelStreamConnection();
73 var toSubscribe = channelstreamConnection.calculateSubscribe(channels);
77 var toSubscribe = channelstreamConnection.calculateSubscribe(channels);
74 ccLog.debug('subscribeToChannelTopic', toSubscribe);
78 ccLog.debug('subscribeToChannelTopic', toSubscribe);
75 if (toSubscribe.length > 0) {
79 if (toSubscribe.length > 0) {
76 // if we are connected then subscribe
80 // if we are connected then subscribe
77 if (channelstreamConnection.connected) {
81 if (channelstreamConnection.connected) {
78 channelstreamConnection.subscribe(toSubscribe);
82 channelstreamConnection.subscribe(toSubscribe);
79 }
83 }
80 // not connected? just push channels onto the stack
84 // not connected? just push channels onto the stack
81 else {
85 else {
82 for (var i = 0; i < toSubscribe.length; i++) {
86 for (var i = 0; i < toSubscribe.length; i++) {
83 channelstreamConnection.push('channels', toSubscribe[i]);
87 channelstreamConnection.push('channels', toSubscribe[i]);
84 }
88 }
85 }
89 }
86 }
90 }
87 },
91 },
88
92
89 /** publish received messages into correct topic */
93 /** publish received messages into correct topic */
90 receivedMessage: function (event) {
94 receivedMessage: function (event) {
91 for (var i = 0; i < event.detail.length; i++) {
95 for (var i = 0; i < event.detail.length; i++) {
92 var message = event.detail[i];
96 var message = event.detail[i];
93 if (message.message.topic) {
97 if (message.message.topic) {
94 ccLog.debug('publishing', message.message.topic);
98 ccLog.debug('publishing', message.message.topic);
95 $.Topic(message.message.topic).publish(message);
99 $.Topic(message.message.topic).publish(message);
96 }
100 }
97 else if (message.type === 'presence'){
101 else if (message.type === 'presence'){
98 $.Topic('/connection_controller/presence').publish(message);
102 $.Topic('/connection_controller/presence').publish(message);
99 }
103 }
100 else {
104 else {
101 ccLog.warn('unhandled message', message);
105 ccLog.warn('unhandled message', message);
102 }
106 }
103 }
107 }
104 },
108 },
105
109
106 handleConnected: function (event) {
110 handleConnected: function (event) {
107 var channelstreamConnection = this.getChannelStreamConnection();
111 var channelstreamConnection = this.getChannelStreamConnection();
108 channelstreamConnection.set('channelsState',
112 channelstreamConnection.set('channelsState',
109 event.detail.channels_info);
113 event.detail.channels_info);
110 channelstreamConnection.set('userState', event.detail.state);
114 channelstreamConnection.set('userState', event.detail.state);
111 channelstreamConnection.set('channels', event.detail.channels);
115 channelstreamConnection.set('channels', event.detail.channels);
112 this.propagageChannelsState();
116 this.propagageChannelsState();
113 },
117 },
114 handleSubscribed: function (event) {
118 handleSubscribed: function (event) {
115 var channelstreamConnection = this.getChannelStreamConnection();
119 var channelstreamConnection = this.getChannelStreamConnection();
116 var channelInfo = event.detail.channels_info;
120 var channelInfo = event.detail.channels_info;
117 var channelKeys = Object.keys(event.detail.channels_info);
121 var channelKeys = Object.keys(event.detail.channels_info);
118 for (var i = 0; i < channelKeys.length; i++) {
122 for (var i = 0; i < channelKeys.length; i++) {
119 var key = channelKeys[i];
123 var key = channelKeys[i];
120 channelstreamConnection.set(['channelsState', key], channelInfo[key]);
124 channelstreamConnection.set(['channelsState', key], channelInfo[key]);
121 }
125 }
122 channelstreamConnection.set('channels', event.detail.channels);
126 channelstreamConnection.set('channels', event.detail.channels);
123 this.propagageChannelsState();
127 this.propagageChannelsState();
124 },
128 },
125 /** propagates channel states on topics */
129 /** propagates channel states on topics */
126 propagageChannelsState: function (event) {
130 propagageChannelsState: function (event) {
127 var channelstreamConnection = this.getChannelStreamConnection();
131 var channelstreamConnection = this.getChannelStreamConnection();
128 var channel_data = channelstreamConnection.channelsState;
132 var channel_data = channelstreamConnection.channelsState;
129 var channels = channelstreamConnection.channels;
133 var channels = channelstreamConnection.channels;
130 for (var i = 0; i < channels.length; i++) {
134 for (var i = 0; i < channels.length; i++) {
131 var key = channels[i];
135 var key = channels[i];
132 $.Topic('/connection_controller/channel_update').publish(
136 $.Topic('/connection_controller/channel_update').publish(
133 {channel: key, state: channel_data[key]}
137 {channel: key, state: channel_data[key]}
134 );
138 );
135 }
139 }
136 }
140 }
137 });
141 });
@@ -1,30 +1,24 b''
1 <link rel="import" href="../../../../../../bower_components/paper-button/paper-button.html">
1 <link rel="import" href="../../../../../../bower_components/paper-button/paper-button.html">
2 <link rel="import" href="../../../../../../bower_components/paper-toast/paper-toast.html">
2 <link rel="import" href="../../../../../../bower_components/paper-toast/paper-toast.html">
3 <link rel="import" href="../rhodecode-unsafe-html/rhodecode-unsafe-html.html">
3 <link rel="import" href="../rhodecode-unsafe-html/rhodecode-unsafe-html.html">
4 <dom-module id="rhodecode-toast">
4 <dom-module id="rhodecode-toast">
5 <template>
5 <template>
6 <style include="shared-styles"></style>
6 <style include="shared-styles"></style>
7 <link rel="stylesheet" href="rhodecode-toast.css">
7 <link rel="stylesheet" href="rhodecode-toast.css">
8
8 <template is="dom-if" if="[[hasToasts]]">
9 <paper-toast id="p-toast"
9 <div class$="container toast-message-holder [[conditionalClass(isFixed)]]" >
10 duration="0"
10 <template is="dom-repeat" items="[[toasts]]">
11 horizontal-offset="100"
11 <div class$="alert alert-[[item.level]]">
12 horizontal-align="auto"
12 <rhodecode-unsafe-html text="[[item.message]]"></rhodecode-unsafe-html>
13 vertical-align="top"
14 on-iron-overlay-closed="handleClosed"
15 always-on-top>
16 <div class="toast-message-holder">
17 <template is="dom-repeat" items="{{toasts}}">
18 <div class$="alert alert-{{item.level}}">
19 <rhodecode-unsafe-html text="{{item.message}}"></rhodecode-unsafe-html>
20 </div>
13 </div>
21 </template>
14 </template>
22 </div>
15
23 <div class="toast-close">
16 <div class="toast-close">
24 <button on-tap="dismissNotifications" class="btn btn-default">{{_gettext('Close')}}</button>
17 <button on-tap="dismissNotifications" class="btn btn-default">[[_gettext('Close')]]</button>
25 </div>
18 </div>
26 </paper-toast>
19 </div>
20 </template>
27 </template>
21 </template>
28
22
29 <script src="rhodecode-toast.js"></script>
23 <script src="rhodecode-toast.js"></script>
30 </dom-module>
24 </dom-module>
@@ -1,40 +1,75 b''
1 Polymer({
1 Polymer({
2 is: 'rhodecode-toast',
2 is: 'rhodecode-toast',
3 properties: {
3 properties: {
4 toasts: {
4 toasts: {
5 type: Array,
5 type: Array,
6 value: function(){
6 value: function(){
7 return []
7 return []
8 }
8 }
9 },
10 isFixed: {
11 type: Boolean,
12 value: false
13 },
14 hasToasts: {
15 type: Boolean,
16 computed: '_computeHasToasts(toasts.*)'
9 }
17 }
10 },
18 },
11 observers: [
19 observers: [
12 '_changedToasts(toasts.splices)'
20 '_changedToasts(toasts.splices)'
13 ],
21 ],
22
23 _computeHasToasts: function(){
24 return this.toasts.length > 0;
25 },
26
27 _debouncedCalc: function(){
28 // calculate once in a while
29 this.debounce('debouncedCalc', this.toastInWindow, 25);
30 },
31
32 conditionalClass: function(){
33 return this.isFixed ? 'fixed': '';
34 },
35
36 toastInWindow: function() {
37 if (!this._headerNode){
38 return true
39 }
40 var headerHeight = this._headerNode.offsetHeight;
41 var scrollPosition = window.scrollY;
42
43 if (this.isFixed){
44 this.isFixed = 1 <= scrollPosition;
45 }
46 else{
47 this.isFixed = headerHeight <= scrollPosition;
48 }
49 },
50
51 attached: function(){
52 this._headerNode = document.querySelector('.header', document);
53 this.listen(window,'scroll', '_debouncedCalc');
54 this.listen(window,'resize', '_debouncedCalc');
55 this._debouncedCalc();
56 },
14 _changedToasts: function(newValue, oldValue){
57 _changedToasts: function(newValue, oldValue){
15 this.$['p-toast'].notifyResize();
16 $.Topic('/favicon/update').publish({count: this.toasts.length});
58 $.Topic('/favicon/update').publish({count: this.toasts.length});
17 },
59 },
18 dismissNotifications: function(){
60 dismissNotifications: function(){
19 this.$['p-toast'].close();
20 $.Topic('/favicon/update').publish({count: 0});
61 $.Topic('/favicon/update').publish({count: 0});
21 },
22 handleClosed: function(){
23 this.splice('toasts', 0);
62 this.splice('toasts', 0);
24 },
63 },
25 open: function(){
26 this.$['p-toast'].open();
27 },
28 handleNotification: function(data){
64 handleNotification: function(data){
29 if (!templateContext.rhodecode_user.notification_status && !data.message.force) {
65 if (!templateContext.rhodecode_user.notification_status && !data.message.force) {
30 // do not act if notifications are disabled
66 // do not act if notifications are disabled
31 return
67 return
32 }
68 }
33 this.push('toasts',{
69 this.push('toasts',{
34 level: data.message.level,
70 level: data.message.level,
35 message: data.message.message
71 message: data.message.message
36 });
72 });
37 this.open();
38 },
73 },
39 _gettext: _gettext
74 _gettext: _gettext
40 });
75 });
@@ -1,29 +1,22 b''
1 @import '../../../../css/variables';
1 @import '../../../../css/variables';
2 @import '../../../../css/mixins';
2 @import '../../../../css/mixins';
3
3
4 paper-toast{
4 .alert{
5 width: 100%;
5 margin: 10px 0;
6 min-width: 400px;
7 padding: 0px;
8 --paper-toast-background-color: transparent;
9 --paper-toast-color: #000000;
10 .box-shadow(none);
11 }
6 }
12 paper-toast a{
7
13 font-weight: bold
8 .toast-close{
9 text-align: right;
14 }
10 }
15
11
16 .toast-message-holder {
12 .toast-message-holder{
17 }
13 background-color: #ffffff;
18 .toast-close {
14
19 right: -5px;
15 &.fixed{
20 position: absolute;
16 position: fixed;
21 bottom: -45px;
17 padding: 10px;
22 paper-button{
18 top: 0;
23 .box-shadow(0 2px 5px 0 rgba(0, 0, 0, 0.15));
19 width: 1200px;
20 z-index: 1;
24 }
21 }
25 }
22 }
26 paper-toast .alert{
27 margin: @padding 0 0 0;
28 .box-shadow(0 2px 5px 0 rgba(0, 0, 0, 0.15));
29 }
@@ -1,598 +1,601 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.mako"/>
2 <%inherit file="root.mako"/>
3
3
4 <div class="outerwrapper">
4 <div class="outerwrapper">
5 <!-- HEADER -->
5 <!-- HEADER -->
6 <div class="header">
6 <div class="header">
7 <div id="header-inner" class="wrapper">
7 <div id="header-inner" class="wrapper">
8 <div id="logo">
8 <div id="logo">
9 <div class="logo-wrapper">
9 <div class="logo-wrapper">
10 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
10 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
11 </div>
11 </div>
12 %if c.rhodecode_name:
12 %if c.rhodecode_name:
13 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
13 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
14 %endif
14 %endif
15 </div>
15 </div>
16 <!-- MENU BAR NAV -->
16 <!-- MENU BAR NAV -->
17 ${self.menu_bar_nav()}
17 ${self.menu_bar_nav()}
18 <!-- END MENU BAR NAV -->
18 <!-- END MENU BAR NAV -->
19 </div>
19 </div>
20 </div>
20 </div>
21 ${self.menu_bar_subnav()}
21 ${self.menu_bar_subnav()}
22 <!-- END HEADER -->
22 <!-- END HEADER -->
23
23
24 <!-- CONTENT -->
24 <!-- CONTENT -->
25 <div id="content" class="wrapper">
25 <div id="content" class="wrapper">
26
27 <rhodecode-toast id="notifications"></rhodecode-toast>
28
26 <div class="main">
29 <div class="main">
27 ${next.main()}
30 ${next.main()}
28 </div>
31 </div>
29 </div>
32 </div>
30 <!-- END CONTENT -->
33 <!-- END CONTENT -->
31
34
32 </div>
35 </div>
33 <!-- FOOTER -->
36 <!-- FOOTER -->
34 <div id="footer">
37 <div id="footer">
35 <div id="footer-inner" class="title wrapper">
38 <div id="footer-inner" class="title wrapper">
36 <div>
39 <div>
37 <p class="footer-link-right">
40 <p class="footer-link-right">
38 % if c.visual.show_version:
41 % if c.visual.show_version:
39 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
42 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
40 % endif
43 % endif
41 &copy; 2010-${h.datetime.today().year}, <a href="${h.url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
44 &copy; 2010-${h.datetime.today().year}, <a href="${h.url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
42 % if c.visual.rhodecode_support_url:
45 % if c.visual.rhodecode_support_url:
43 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
46 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
44 % endif
47 % endif
45 </p>
48 </p>
46 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
49 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
47 <p class="server-instance" style="display:${sid}">
50 <p class="server-instance" style="display:${sid}">
48 ## display hidden instance ID if specially defined
51 ## display hidden instance ID if specially defined
49 % if c.rhodecode_instanceid:
52 % if c.rhodecode_instanceid:
50 ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid}
53 ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid}
51 % endif
54 % endif
52 </p>
55 </p>
53 </div>
56 </div>
54 </div>
57 </div>
55 </div>
58 </div>
56
59
57 <!-- END FOOTER -->
60 <!-- END FOOTER -->
58
61
59 ### MAKO DEFS ###
62 ### MAKO DEFS ###
60
63
61 <%def name="menu_bar_subnav()">
64 <%def name="menu_bar_subnav()">
62 </%def>
65 </%def>
63
66
64 <%def name="breadcrumbs(class_='breadcrumbs')">
67 <%def name="breadcrumbs(class_='breadcrumbs')">
65 <div class="${class_}">
68 <div class="${class_}">
66 ${self.breadcrumbs_links()}
69 ${self.breadcrumbs_links()}
67 </div>
70 </div>
68 </%def>
71 </%def>
69
72
70 <%def name="admin_menu()">
73 <%def name="admin_menu()">
71 <ul class="admin_menu submenu">
74 <ul class="admin_menu submenu">
72 <li><a href="${h.url('admin_home')}">${_('Admin journal')}</a></li>
75 <li><a href="${h.url('admin_home')}">${_('Admin journal')}</a></li>
73 <li><a href="${h.url('repos')}">${_('Repositories')}</a></li>
76 <li><a href="${h.url('repos')}">${_('Repositories')}</a></li>
74 <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
77 <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
75 <li><a href="${h.url('users')}">${_('Users')}</a></li>
78 <li><a href="${h.url('users')}">${_('Users')}</a></li>
76 <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
79 <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
77 <li><a href="${h.url('admin_permissions_application')}">${_('Permissions')}</a></li>
80 <li><a href="${h.url('admin_permissions_application')}">${_('Permissions')}</a></li>
78 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
81 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
79 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
82 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
80 <li><a href="${h.url('admin_defaults_repositories')}">${_('Defaults')}</a></li>
83 <li><a href="${h.url('admin_defaults_repositories')}">${_('Defaults')}</a></li>
81 <li class="last"><a href="${h.url('admin_settings')}">${_('Settings')}</a></li>
84 <li class="last"><a href="${h.url('admin_settings')}">${_('Settings')}</a></li>
82 </ul>
85 </ul>
83 </%def>
86 </%def>
84
87
85
88
86 <%def name="dt_info_panel(elements)">
89 <%def name="dt_info_panel(elements)">
87 <dl class="dl-horizontal">
90 <dl class="dl-horizontal">
88 %for dt, dd, title, show_items in elements:
91 %for dt, dd, title, show_items in elements:
89 <dt>${dt}:</dt>
92 <dt>${dt}:</dt>
90 <dd title="${title}">
93 <dd title="${title}">
91 %if callable(dd):
94 %if callable(dd):
92 ## allow lazy evaluation of elements
95 ## allow lazy evaluation of elements
93 ${dd()}
96 ${dd()}
94 %else:
97 %else:
95 ${dd}
98 ${dd}
96 %endif
99 %endif
97 %if show_items:
100 %if show_items:
98 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
101 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
99 %endif
102 %endif
100 </dd>
103 </dd>
101
104
102 %if show_items:
105 %if show_items:
103 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
106 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
104 %for item in show_items:
107 %for item in show_items:
105 <dt></dt>
108 <dt></dt>
106 <dd>${item}</dd>
109 <dd>${item}</dd>
107 %endfor
110 %endfor
108 </div>
111 </div>
109 %endif
112 %endif
110
113
111 %endfor
114 %endfor
112 </dl>
115 </dl>
113 </%def>
116 </%def>
114
117
115
118
116 <%def name="gravatar(email, size=16)">
119 <%def name="gravatar(email, size=16)">
117 <%
120 <%
118 if (size > 16):
121 if (size > 16):
119 gravatar_class = 'gravatar gravatar-large'
122 gravatar_class = 'gravatar gravatar-large'
120 else:
123 else:
121 gravatar_class = 'gravatar'
124 gravatar_class = 'gravatar'
122 %>
125 %>
123 <%doc>
126 <%doc>
124 TODO: johbo: For now we serve double size images to make it smooth
127 TODO: johbo: For now we serve double size images to make it smooth
125 for retina. This is how it worked until now. Should be replaced
128 for retina. This is how it worked until now. Should be replaced
126 with a better solution at some point.
129 with a better solution at some point.
127 </%doc>
130 </%doc>
128 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
131 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
129 </%def>
132 </%def>
130
133
131
134
132 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
135 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
133 <% email = h.email_or_none(contact) %>
136 <% email = h.email_or_none(contact) %>
134 <div class="rc-user tooltip" title="${h.author_string(email)}">
137 <div class="rc-user tooltip" title="${h.author_string(email)}">
135 ${self.gravatar(email, size)}
138 ${self.gravatar(email, size)}
136 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
139 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
137 </div>
140 </div>
138 </%def>
141 </%def>
139
142
140
143
141 ## admin menu used for people that have some admin resources
144 ## admin menu used for people that have some admin resources
142 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
145 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
143 <ul class="submenu">
146 <ul class="submenu">
144 %if repositories:
147 %if repositories:
145 <li class="local-admin-repos"><a href="${h.url('repos')}">${_('Repositories')}</a></li>
148 <li class="local-admin-repos"><a href="${h.url('repos')}">${_('Repositories')}</a></li>
146 %endif
149 %endif
147 %if repository_groups:
150 %if repository_groups:
148 <li class="local-admin-repo-groups"><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
151 <li class="local-admin-repo-groups"><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
149 %endif
152 %endif
150 %if user_groups:
153 %if user_groups:
151 <li class="local-admin-user-groups"><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
154 <li class="local-admin-user-groups"><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
152 %endif
155 %endif
153 </ul>
156 </ul>
154 </%def>
157 </%def>
155
158
156 <%def name="repo_page_title(repo_instance)">
159 <%def name="repo_page_title(repo_instance)">
157 <div class="title-content">
160 <div class="title-content">
158 <div class="title-main">
161 <div class="title-main">
159 ## SVN/HG/GIT icons
162 ## SVN/HG/GIT icons
160 %if h.is_hg(repo_instance):
163 %if h.is_hg(repo_instance):
161 <i class="icon-hg"></i>
164 <i class="icon-hg"></i>
162 %endif
165 %endif
163 %if h.is_git(repo_instance):
166 %if h.is_git(repo_instance):
164 <i class="icon-git"></i>
167 <i class="icon-git"></i>
165 %endif
168 %endif
166 %if h.is_svn(repo_instance):
169 %if h.is_svn(repo_instance):
167 <i class="icon-svn"></i>
170 <i class="icon-svn"></i>
168 %endif
171 %endif
169
172
170 ## public/private
173 ## public/private
171 %if repo_instance.private:
174 %if repo_instance.private:
172 <i class="icon-repo-private"></i>
175 <i class="icon-repo-private"></i>
173 %else:
176 %else:
174 <i class="icon-repo-public"></i>
177 <i class="icon-repo-public"></i>
175 %endif
178 %endif
176
179
177 ## repo name with group name
180 ## repo name with group name
178 ${h.breadcrumb_repo_link(c.rhodecode_db_repo)}
181 ${h.breadcrumb_repo_link(c.rhodecode_db_repo)}
179
182
180 </div>
183 </div>
181
184
182 ## FORKED
185 ## FORKED
183 %if repo_instance.fork:
186 %if repo_instance.fork:
184 <p>
187 <p>
185 <i class="icon-code-fork"></i> ${_('Fork of')}
188 <i class="icon-code-fork"></i> ${_('Fork of')}
186 <a href="${h.url('summary_home',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
189 <a href="${h.url('summary_home',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
187 </p>
190 </p>
188 %endif
191 %endif
189
192
190 ## IMPORTED FROM REMOTE
193 ## IMPORTED FROM REMOTE
191 %if repo_instance.clone_uri:
194 %if repo_instance.clone_uri:
192 <p>
195 <p>
193 <i class="icon-code-fork"></i> ${_('Clone from')}
196 <i class="icon-code-fork"></i> ${_('Clone from')}
194 <a href="${h.url(h.safe_str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
197 <a href="${h.url(h.safe_str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
195 </p>
198 </p>
196 %endif
199 %endif
197
200
198 ## LOCKING STATUS
201 ## LOCKING STATUS
199 %if repo_instance.locked[0]:
202 %if repo_instance.locked[0]:
200 <p class="locking_locked">
203 <p class="locking_locked">
201 <i class="icon-repo-lock"></i>
204 <i class="icon-repo-lock"></i>
202 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
205 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
203 </p>
206 </p>
204 %elif repo_instance.enable_locking:
207 %elif repo_instance.enable_locking:
205 <p class="locking_unlocked">
208 <p class="locking_unlocked">
206 <i class="icon-repo-unlock"></i>
209 <i class="icon-repo-unlock"></i>
207 ${_('Repository not locked. Pull repository to lock it.')}
210 ${_('Repository not locked. Pull repository to lock it.')}
208 </p>
211 </p>
209 %endif
212 %endif
210
213
211 </div>
214 </div>
212 </%def>
215 </%def>
213
216
214 <%def name="repo_menu(active=None)">
217 <%def name="repo_menu(active=None)">
215 <%
218 <%
216 def is_active(selected):
219 def is_active(selected):
217 if selected == active:
220 if selected == active:
218 return "active"
221 return "active"
219 %>
222 %>
220
223
221 <!--- CONTEXT BAR -->
224 <!--- CONTEXT BAR -->
222 <div id="context-bar">
225 <div id="context-bar">
223 <div class="wrapper">
226 <div class="wrapper">
224 <ul id="context-pages" class="horizontal-list navigation">
227 <ul id="context-pages" class="horizontal-list navigation">
225 <li class="${is_active('summary')}"><a class="menulink" href="${h.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
228 <li class="${is_active('summary')}"><a class="menulink" href="${h.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
226 <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
229 <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
227 <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li>
230 <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li>
228 <li class="${is_active('compare')}">
231 <li class="${is_active('compare')}">
229 <a class="menulink" href="${h.url('compare_home',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a>
232 <a class="menulink" href="${h.url('compare_home',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a>
230 </li>
233 </li>
231 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
234 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
232 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
235 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
233 <li class="${is_active('showpullrequest')}">
236 <li class="${is_active('showpullrequest')}">
234 <a class="menulink" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}">
237 <a class="menulink" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}">
235 %if c.repository_pull_requests:
238 %if c.repository_pull_requests:
236 <span class="pr_notifications">${c.repository_pull_requests}</span>
239 <span class="pr_notifications">${c.repository_pull_requests}</span>
237 %endif
240 %endif
238 <div class="menulabel">${_('Pull Requests')}</div>
241 <div class="menulabel">${_('Pull Requests')}</div>
239 </a>
242 </a>
240 </li>
243 </li>
241 %endif
244 %endif
242 <li class="${is_active('options')}">
245 <li class="${is_active('options')}">
243 <a class="menulink" href="#" class="dropdown"><div class="menulabel">${_('Options')} <div class="show_more"></div></div></a>
246 <a class="menulink" href="#" class="dropdown"><div class="menulabel">${_('Options')} <div class="show_more"></div></div></a>
244 <ul class="submenu">
247 <ul class="submenu">
245 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
248 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
246 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
249 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
247 %endif
250 %endif
248 %if c.rhodecode_db_repo.fork:
251 %if c.rhodecode_db_repo.fork:
249 <li><a href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1], target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1], merge=1)}">
252 <li><a href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1], target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1], merge=1)}">
250 ${_('Compare fork')}</a></li>
253 ${_('Compare fork')}</a></li>
251 %endif
254 %endif
252
255
253 <li><a href="${h.url('search_repo_home',repo_name=c.repo_name)}">${_('Search')}</a></li>
256 <li><a href="${h.url('search_repo_home',repo_name=c.repo_name)}">${_('Search')}</a></li>
254
257
255 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
258 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
256 %if c.rhodecode_db_repo.locked[0]:
259 %if c.rhodecode_db_repo.locked[0]:
257 <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
260 <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
258 %else:
261 %else:
259 <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
262 <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
260 %endif
263 %endif
261 %endif
264 %endif
262 %if c.rhodecode_user.username != h.DEFAULT_USER:
265 %if c.rhodecode_user.username != h.DEFAULT_USER:
263 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
266 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
264 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
267 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
265 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
268 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
266 %endif
269 %endif
267 %endif
270 %endif
268 </ul>
271 </ul>
269 </li>
272 </li>
270 </ul>
273 </ul>
271 </div>
274 </div>
272 <div class="clear"></div>
275 <div class="clear"></div>
273 </div>
276 </div>
274 <!--- END CONTEXT BAR -->
277 <!--- END CONTEXT BAR -->
275
278
276 </%def>
279 </%def>
277
280
278 <%def name="usermenu(active=False)">
281 <%def name="usermenu(active=False)">
279 ## USER MENU
282 ## USER MENU
280 <li id="quick_login_li" class="${'active' if active else ''}">
283 <li id="quick_login_li" class="${'active' if active else ''}">
281 <a id="quick_login_link" class="menulink childs">
284 <a id="quick_login_link" class="menulink childs">
282 ${gravatar(c.rhodecode_user.email, 20)}
285 ${gravatar(c.rhodecode_user.email, 20)}
283 <span class="user">
286 <span class="user">
284 %if c.rhodecode_user.username != h.DEFAULT_USER:
287 %if c.rhodecode_user.username != h.DEFAULT_USER:
285 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
288 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
286 %else:
289 %else:
287 <span>${_('Sign in')}</span>
290 <span>${_('Sign in')}</span>
288 %endif
291 %endif
289 </span>
292 </span>
290 </a>
293 </a>
291
294
292 <div class="user-menu submenu">
295 <div class="user-menu submenu">
293 <div id="quick_login">
296 <div id="quick_login">
294 %if c.rhodecode_user.username == h.DEFAULT_USER:
297 %if c.rhodecode_user.username == h.DEFAULT_USER:
295 <h4>${_('Sign in to your account')}</h4>
298 <h4>${_('Sign in to your account')}</h4>
296 ${h.form(h.route_path('login', _query={'came_from': h.url.current()}), needs_csrf_token=False)}
299 ${h.form(h.route_path('login', _query={'came_from': h.url.current()}), needs_csrf_token=False)}
297 <div class="form form-vertical">
300 <div class="form form-vertical">
298 <div class="fields">
301 <div class="fields">
299 <div class="field">
302 <div class="field">
300 <div class="label">
303 <div class="label">
301 <label for="username">${_('Username')}:</label>
304 <label for="username">${_('Username')}:</label>
302 </div>
305 </div>
303 <div class="input">
306 <div class="input">
304 ${h.text('username',class_='focus',tabindex=1)}
307 ${h.text('username',class_='focus',tabindex=1)}
305 </div>
308 </div>
306
309
307 </div>
310 </div>
308 <div class="field">
311 <div class="field">
309 <div class="label">
312 <div class="label">
310 <label for="password">${_('Password')}:</label>
313 <label for="password">${_('Password')}:</label>
311 %if h.HasPermissionAny('hg.password_reset.enabled')():
314 %if h.HasPermissionAny('hg.password_reset.enabled')():
312 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'), class_='pwd_reset')}</span>
315 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'), class_='pwd_reset')}</span>
313 %endif
316 %endif
314 </div>
317 </div>
315 <div class="input">
318 <div class="input">
316 ${h.password('password',class_='focus',tabindex=2)}
319 ${h.password('password',class_='focus',tabindex=2)}
317 </div>
320 </div>
318 </div>
321 </div>
319 <div class="buttons">
322 <div class="buttons">
320 <div class="register">
323 <div class="register">
321 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
324 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
322 ${h.link_to(_("Don't have an account ?"),h.route_path('register'))}
325 ${h.link_to(_("Don't have an account ?"),h.route_path('register'))}
323 %endif
326 %endif
324 </div>
327 </div>
325 <div class="submit">
328 <div class="submit">
326 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
329 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
327 </div>
330 </div>
328 </div>
331 </div>
329 </div>
332 </div>
330 </div>
333 </div>
331 ${h.end_form()}
334 ${h.end_form()}
332 %else:
335 %else:
333 <div class="">
336 <div class="">
334 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
337 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
335 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
338 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
336 <div class="email">${c.rhodecode_user.email}</div>
339 <div class="email">${c.rhodecode_user.email}</div>
337 </div>
340 </div>
338 <div class="">
341 <div class="">
339 <ol class="links">
342 <ol class="links">
340 <li>${h.link_to(_(u'My account'),h.url('my_account'))}</li>
343 <li>${h.link_to(_(u'My account'),h.url('my_account'))}</li>
341 % if c.rhodecode_user.personal_repo_group:
344 % if c.rhodecode_user.personal_repo_group:
342 <li>${h.link_to(_(u'My personal group'), h.url('repo_group_home', group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
345 <li>${h.link_to(_(u'My personal group'), h.url('repo_group_home', group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
343 % endif
346 % endif
344 <li class="logout">
347 <li class="logout">
345 ${h.secure_form(h.route_path('logout'))}
348 ${h.secure_form(h.route_path('logout'))}
346 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
349 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
347 ${h.end_form()}
350 ${h.end_form()}
348 </li>
351 </li>
349 </ol>
352 </ol>
350 </div>
353 </div>
351 %endif
354 %endif
352 </div>
355 </div>
353 </div>
356 </div>
354 %if c.rhodecode_user.username != h.DEFAULT_USER:
357 %if c.rhodecode_user.username != h.DEFAULT_USER:
355 <div class="pill_container">
358 <div class="pill_container">
356 % if c.unread_notifications == 0:
359 % if c.unread_notifications == 0:
357 <a class="menu_link_notifications empty" href="${h.url('notifications')}">${c.unread_notifications}</a>
360 <a class="menu_link_notifications empty" href="${h.url('notifications')}">${c.unread_notifications}</a>
358 % else:
361 % else:
359 <a class="menu_link_notifications" href="${h.url('notifications')}">${c.unread_notifications}</a>
362 <a class="menu_link_notifications" href="${h.url('notifications')}">${c.unread_notifications}</a>
360 % endif
363 % endif
361 </div>
364 </div>
362 % endif
365 % endif
363 </li>
366 </li>
364 </%def>
367 </%def>
365
368
366 <%def name="menu_items(active=None)">
369 <%def name="menu_items(active=None)">
367 <%
370 <%
368 def is_active(selected):
371 def is_active(selected):
369 if selected == active:
372 if selected == active:
370 return "active"
373 return "active"
371 return ""
374 return ""
372 %>
375 %>
373 <ul id="quick" class="main_nav navigation horizontal-list">
376 <ul id="quick" class="main_nav navigation horizontal-list">
374 <!-- repo switcher -->
377 <!-- repo switcher -->
375 <li class="${is_active('repositories')} repo_switcher_li has_select2">
378 <li class="${is_active('repositories')} repo_switcher_li has_select2">
376 <input id="repo_switcher" name="repo_switcher" type="hidden">
379 <input id="repo_switcher" name="repo_switcher" type="hidden">
377 </li>
380 </li>
378
381
379 ## ROOT MENU
382 ## ROOT MENU
380 %if c.rhodecode_user.username != h.DEFAULT_USER:
383 %if c.rhodecode_user.username != h.DEFAULT_USER:
381 <li class="${is_active('journal')}">
384 <li class="${is_active('journal')}">
382 <a class="menulink" title="${_('Show activity journal')}" href="${h.url('journal')}">
385 <a class="menulink" title="${_('Show activity journal')}" href="${h.url('journal')}">
383 <div class="menulabel">${_('Journal')}</div>
386 <div class="menulabel">${_('Journal')}</div>
384 </a>
387 </a>
385 </li>
388 </li>
386 %else:
389 %else:
387 <li class="${is_active('journal')}">
390 <li class="${is_active('journal')}">
388 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.url('public_journal')}">
391 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.url('public_journal')}">
389 <div class="menulabel">${_('Public journal')}</div>
392 <div class="menulabel">${_('Public journal')}</div>
390 </a>
393 </a>
391 </li>
394 </li>
392 %endif
395 %endif
393 <li class="${is_active('gists')}">
396 <li class="${is_active('gists')}">
394 <a class="menulink childs" title="${_('Show Gists')}" href="${h.url('gists')}">
397 <a class="menulink childs" title="${_('Show Gists')}" href="${h.url('gists')}">
395 <div class="menulabel">${_('Gists')}</div>
398 <div class="menulabel">${_('Gists')}</div>
396 </a>
399 </a>
397 </li>
400 </li>
398 <li class="${is_active('search')}">
401 <li class="${is_active('search')}">
399 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.url('search')}">
402 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.url('search')}">
400 <div class="menulabel">${_('Search')}</div>
403 <div class="menulabel">${_('Search')}</div>
401 </a>
404 </a>
402 </li>
405 </li>
403 % if h.HasPermissionAll('hg.admin')('access admin main page'):
406 % if h.HasPermissionAll('hg.admin')('access admin main page'):
404 <li class="${is_active('admin')}">
407 <li class="${is_active('admin')}">
405 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
408 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
406 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
409 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
407 </a>
410 </a>
408 ${admin_menu()}
411 ${admin_menu()}
409 </li>
412 </li>
410 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
413 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
411 <li class="${is_active('admin')}">
414 <li class="${is_active('admin')}">
412 <a class="menulink childs" title="${_('Delegated Admin settings')}">
415 <a class="menulink childs" title="${_('Delegated Admin settings')}">
413 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
416 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
414 </a>
417 </a>
415 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
418 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
416 c.rhodecode_user.repository_groups_admin,
419 c.rhodecode_user.repository_groups_admin,
417 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
420 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
418 </li>
421 </li>
419 % endif
422 % endif
420 % if c.debug_style:
423 % if c.debug_style:
421 <li class="${is_active('debug_style')}">
424 <li class="${is_active('debug_style')}">
422 <a class="menulink" title="${_('Style')}" href="${h.url('debug_style_home')}">
425 <a class="menulink" title="${_('Style')}" href="${h.url('debug_style_home')}">
423 <div class="menulabel">${_('Style')}</div>
426 <div class="menulabel">${_('Style')}</div>
424 </a>
427 </a>
425 </li>
428 </li>
426 % endif
429 % endif
427 ## render extra user menu
430 ## render extra user menu
428 ${usermenu(active=(active=='my_account'))}
431 ${usermenu(active=(active=='my_account'))}
429 </ul>
432 </ul>
430
433
431 <script type="text/javascript">
434 <script type="text/javascript">
432 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
435 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
433
436
434 /*format the look of items in the list*/
437 /*format the look of items in the list*/
435 var format = function(state, escapeMarkup){
438 var format = function(state, escapeMarkup){
436 if (!state.id){
439 if (!state.id){
437 return state.text; // optgroup
440 return state.text; // optgroup
438 }
441 }
439 var obj_dict = state.obj;
442 var obj_dict = state.obj;
440 var tmpl = '';
443 var tmpl = '';
441
444
442 if(obj_dict && state.type == 'repo'){
445 if(obj_dict && state.type == 'repo'){
443 if(obj_dict['repo_type'] === 'hg'){
446 if(obj_dict['repo_type'] === 'hg'){
444 tmpl += '<i class="icon-hg"></i> ';
447 tmpl += '<i class="icon-hg"></i> ';
445 }
448 }
446 else if(obj_dict['repo_type'] === 'git'){
449 else if(obj_dict['repo_type'] === 'git'){
447 tmpl += '<i class="icon-git"></i> ';
450 tmpl += '<i class="icon-git"></i> ';
448 }
451 }
449 else if(obj_dict['repo_type'] === 'svn'){
452 else if(obj_dict['repo_type'] === 'svn'){
450 tmpl += '<i class="icon-svn"></i> ';
453 tmpl += '<i class="icon-svn"></i> ';
451 }
454 }
452 if(obj_dict['private']){
455 if(obj_dict['private']){
453 tmpl += '<i class="icon-lock" ></i> ';
456 tmpl += '<i class="icon-lock" ></i> ';
454 }
457 }
455 else if(visual_show_public_icon){
458 else if(visual_show_public_icon){
456 tmpl += '<i class="icon-unlock-alt"></i> ';
459 tmpl += '<i class="icon-unlock-alt"></i> ';
457 }
460 }
458 }
461 }
459 if(obj_dict && state.type == 'commit') {
462 if(obj_dict && state.type == 'commit') {
460 tmpl += '<i class="icon-tag"></i>';
463 tmpl += '<i class="icon-tag"></i>';
461 }
464 }
462 if(obj_dict && state.type == 'group'){
465 if(obj_dict && state.type == 'group'){
463 tmpl += '<i class="icon-folder-close"></i> ';
466 tmpl += '<i class="icon-folder-close"></i> ';
464 }
467 }
465 tmpl += escapeMarkup(state.text);
468 tmpl += escapeMarkup(state.text);
466 return tmpl;
469 return tmpl;
467 };
470 };
468
471
469 var formatResult = function(result, container, query, escapeMarkup) {
472 var formatResult = function(result, container, query, escapeMarkup) {
470 return format(result, escapeMarkup);
473 return format(result, escapeMarkup);
471 };
474 };
472
475
473 var formatSelection = function(data, container, escapeMarkup) {
476 var formatSelection = function(data, container, escapeMarkup) {
474 return format(data, escapeMarkup);
477 return format(data, escapeMarkup);
475 };
478 };
476
479
477 $("#repo_switcher").select2({
480 $("#repo_switcher").select2({
478 cachedDataSource: {},
481 cachedDataSource: {},
479 minimumInputLength: 2,
482 minimumInputLength: 2,
480 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
483 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
481 dropdownAutoWidth: true,
484 dropdownAutoWidth: true,
482 formatResult: formatResult,
485 formatResult: formatResult,
483 formatSelection: formatSelection,
486 formatSelection: formatSelection,
484 containerCssClass: "repo-switcher",
487 containerCssClass: "repo-switcher",
485 dropdownCssClass: "repo-switcher-dropdown",
488 dropdownCssClass: "repo-switcher-dropdown",
486 escapeMarkup: function(m){
489 escapeMarkup: function(m){
487 // don't escape our custom placeholder
490 // don't escape our custom placeholder
488 if(m.substr(0,23) == '<div class="menulabel">'){
491 if(m.substr(0,23) == '<div class="menulabel">'){
489 return m;
492 return m;
490 }
493 }
491
494
492 return Select2.util.escapeMarkup(m);
495 return Select2.util.escapeMarkup(m);
493 },
496 },
494 query: $.debounce(250, function(query){
497 query: $.debounce(250, function(query){
495 self = this;
498 self = this;
496 var cacheKey = query.term;
499 var cacheKey = query.term;
497 var cachedData = self.cachedDataSource[cacheKey];
500 var cachedData = self.cachedDataSource[cacheKey];
498
501
499 if (cachedData) {
502 if (cachedData) {
500 query.callback({results: cachedData.results});
503 query.callback({results: cachedData.results});
501 } else {
504 } else {
502 $.ajax({
505 $.ajax({
503 url: "${h.url('goto_switcher_data')}",
506 url: "${h.url('goto_switcher_data')}",
504 data: {'query': query.term},
507 data: {'query': query.term},
505 dataType: 'json',
508 dataType: 'json',
506 type: 'GET',
509 type: 'GET',
507 success: function(data) {
510 success: function(data) {
508 self.cachedDataSource[cacheKey] = data;
511 self.cachedDataSource[cacheKey] = data;
509 query.callback({results: data.results});
512 query.callback({results: data.results});
510 },
513 },
511 error: function(data, textStatus, errorThrown) {
514 error: function(data, textStatus, errorThrown) {
512 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
515 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
513 }
516 }
514 })
517 })
515 }
518 }
516 })
519 })
517 });
520 });
518
521
519 $("#repo_switcher").on('select2-selecting', function(e){
522 $("#repo_switcher").on('select2-selecting', function(e){
520 e.preventDefault();
523 e.preventDefault();
521 window.location = e.choice.url;
524 window.location = e.choice.url;
522 });
525 });
523
526
524 </script>
527 </script>
525 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
528 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
526 </%def>
529 </%def>
527
530
528 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
531 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
529 <div class="modal-dialog">
532 <div class="modal-dialog">
530 <div class="modal-content">
533 <div class="modal-content">
531 <div class="modal-header">
534 <div class="modal-header">
532 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
535 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
533 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
536 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
534 </div>
537 </div>
535 <div class="modal-body">
538 <div class="modal-body">
536 <div class="block-left">
539 <div class="block-left">
537 <table class="keyboard-mappings">
540 <table class="keyboard-mappings">
538 <tbody>
541 <tbody>
539 <tr>
542 <tr>
540 <th></th>
543 <th></th>
541 <th>${_('Site-wide shortcuts')}</th>
544 <th>${_('Site-wide shortcuts')}</th>
542 </tr>
545 </tr>
543 <%
546 <%
544 elems = [
547 elems = [
545 ('/', 'Open quick search box'),
548 ('/', 'Open quick search box'),
546 ('g h', 'Goto home page'),
549 ('g h', 'Goto home page'),
547 ('g g', 'Goto my private gists page'),
550 ('g g', 'Goto my private gists page'),
548 ('g G', 'Goto my public gists page'),
551 ('g G', 'Goto my public gists page'),
549 ('n r', 'New repository page'),
552 ('n r', 'New repository page'),
550 ('n g', 'New gist page'),
553 ('n g', 'New gist page'),
551 ]
554 ]
552 %>
555 %>
553 %for key, desc in elems:
556 %for key, desc in elems:
554 <tr>
557 <tr>
555 <td class="keys">
558 <td class="keys">
556 <span class="key tag">${key}</span>
559 <span class="key tag">${key}</span>
557 </td>
560 </td>
558 <td>${desc}</td>
561 <td>${desc}</td>
559 </tr>
562 </tr>
560 %endfor
563 %endfor
561 </tbody>
564 </tbody>
562 </table>
565 </table>
563 </div>
566 </div>
564 <div class="block-left">
567 <div class="block-left">
565 <table class="keyboard-mappings">
568 <table class="keyboard-mappings">
566 <tbody>
569 <tbody>
567 <tr>
570 <tr>
568 <th></th>
571 <th></th>
569 <th>${_('Repositories')}</th>
572 <th>${_('Repositories')}</th>
570 </tr>
573 </tr>
571 <%
574 <%
572 elems = [
575 elems = [
573 ('g s', 'Goto summary page'),
576 ('g s', 'Goto summary page'),
574 ('g c', 'Goto changelog page'),
577 ('g c', 'Goto changelog page'),
575 ('g f', 'Goto files page'),
578 ('g f', 'Goto files page'),
576 ('g F', 'Goto files page with file search activated'),
579 ('g F', 'Goto files page with file search activated'),
577 ('g p', 'Goto pull requests page'),
580 ('g p', 'Goto pull requests page'),
578 ('g o', 'Goto repository settings'),
581 ('g o', 'Goto repository settings'),
579 ('g O', 'Goto repository permissions settings'),
582 ('g O', 'Goto repository permissions settings'),
580 ]
583 ]
581 %>
584 %>
582 %for key, desc in elems:
585 %for key, desc in elems:
583 <tr>
586 <tr>
584 <td class="keys">
587 <td class="keys">
585 <span class="key tag">${key}</span>
588 <span class="key tag">${key}</span>
586 </td>
589 </td>
587 <td>${desc}</td>
590 <td>${desc}</td>
588 </tr>
591 </tr>
589 %endfor
592 %endfor
590 </tbody>
593 </tbody>
591 </table>
594 </table>
592 </div>
595 </div>
593 </div>
596 </div>
594 <div class="modal-footer">
597 <div class="modal-footer">
595 </div>
598 </div>
596 </div><!-- /.modal-content -->
599 </div><!-- /.modal-content -->
597 </div><!-- /.modal-dialog -->
600 </div><!-- /.modal-dialog -->
598 </div><!-- /.modal -->
601 </div><!-- /.modal -->
General Comments 0
You need to be logged in to leave comments. Login now