mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-23 11:36:09 +10:00
Merge pull request #7659 from Razer6/feature/shortcuts
Awesome keyboard shortcuts for GitLab
This commit is contained in:
@@ -10,6 +10,7 @@ v 7.3.0
|
||||
- Support Unix domain sockets for Redis
|
||||
- Store session Redis keys in 'session:gitlab:' namespace
|
||||
- Deprecate LDAP account takeover based on partial LDAP email / GitLab username match
|
||||
- Keyboard shortcuts for productivity (Robert Schilling)
|
||||
|
||||
v 7.2.0
|
||||
- Explore page
|
||||
|
||||
@@ -156,6 +156,9 @@ gem "rack-attack"
|
||||
# Ace editor
|
||||
gem 'ace-rails-ap'
|
||||
|
||||
# Keyboard shortcuts
|
||||
gem 'mousetrap-rails'
|
||||
|
||||
# Semantic UI Sass for Sidebar
|
||||
gem 'semantic-ui-sass', '~> 0.16.1.0'
|
||||
|
||||
|
||||
@@ -287,6 +287,7 @@ GEM
|
||||
mime-types (1.25.1)
|
||||
mini_portile (0.6.0)
|
||||
minitest (5.3.5)
|
||||
mousetrap-rails (1.4.6)
|
||||
multi_json (1.10.1)
|
||||
multi_xml (0.5.5)
|
||||
multipart-post (1.2.0)
|
||||
@@ -636,6 +637,7 @@ DEPENDENCIES
|
||||
launchy
|
||||
letter_opener
|
||||
minitest (~> 5.3.0)
|
||||
mousetrap-rails
|
||||
mysql2
|
||||
nprogress-rails
|
||||
omniauth (~> 1.1.3)
|
||||
|
||||
@@ -33,6 +33,12 @@
|
||||
#= require nprogress-turbolinks
|
||||
#= require dropzone
|
||||
#= require semantic-ui/sidebar
|
||||
#= require mousetrap
|
||||
#= require shortcuts
|
||||
#= require shortcuts_navigation
|
||||
#= require shortcuts_dashboard_navigation
|
||||
#= require shortcuts_issueable
|
||||
#= require shortcuts_network
|
||||
#= require_tree .
|
||||
|
||||
window.slugify = (text) ->
|
||||
@@ -119,6 +125,13 @@ $ ->
|
||||
# Initialize select2 selects
|
||||
$('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)
|
||||
|
||||
# Close select2 on escape
|
||||
$('.js-select2').bind 'select2-close', ->
|
||||
setTimeout ( ->
|
||||
$('.select2-container-active').removeClass('select2-container-active')
|
||||
$(':focus').blur()
|
||||
), 1
|
||||
|
||||
# Initialize tooltips
|
||||
$('.has_tooltip').tooltip()
|
||||
|
||||
@@ -151,20 +164,6 @@ $ ->
|
||||
# Show/Hide the profile menu when hovering the account box
|
||||
$('.account-box').hover -> $(@).toggleClass('hover')
|
||||
|
||||
# Focus search field by pressing 's' key
|
||||
$(document).keypress (e) ->
|
||||
# Don't do anything if typing in an input
|
||||
return if $(e.target).is(":input")
|
||||
|
||||
switch e.which
|
||||
when 115
|
||||
$("#search").focus()
|
||||
e.preventDefault()
|
||||
when 63
|
||||
new Shortcuts()
|
||||
e.preventDefault()
|
||||
|
||||
|
||||
# Commit show suppressed diff
|
||||
$(".diff-content").on "click", ".supp_diff_link", ->
|
||||
$(@).next('table').show()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class BranchGraph
|
||||
class @BranchGraph
|
||||
constructor: (@element, @options) ->
|
||||
@preparedCommits = {}
|
||||
@mtime = 0
|
||||
@@ -120,23 +120,32 @@ class BranchGraph
|
||||
@top.toFront()
|
||||
|
||||
bindEvents: ->
|
||||
drag = {}
|
||||
element = @element
|
||||
|
||||
$(element).scroll (event) =>
|
||||
@renderPartialGraph()
|
||||
|
||||
$(window).on
|
||||
keydown: (event) =>
|
||||
# left
|
||||
element.scrollLeft element.scrollLeft() - 50 if event.keyCode is 37
|
||||
# top
|
||||
element.scrollTop element.scrollTop() - 50 if event.keyCode is 38
|
||||
# right
|
||||
element.scrollLeft element.scrollLeft() + 50 if event.keyCode is 39
|
||||
# bottom
|
||||
element.scrollTop element.scrollTop() + 50 if event.keyCode is 40
|
||||
@renderPartialGraph()
|
||||
scrollDown: =>
|
||||
@element.scrollTop @element.scrollTop() + 50
|
||||
@renderPartialGraph()
|
||||
|
||||
scrollUp: =>
|
||||
@element.scrollTop @element.scrollTop() - 50
|
||||
@renderPartialGraph()
|
||||
|
||||
scrollLeft: =>
|
||||
@element.scrollLeft @element.scrollLeft() - 50
|
||||
@renderPartialGraph()
|
||||
|
||||
scrollRight: =>
|
||||
@element.scrollLeft @element.scrollLeft() + 50
|
||||
@renderPartialGraph()
|
||||
|
||||
scrollBottom: =>
|
||||
@element.scrollTop @element.find('svg').height()
|
||||
|
||||
scrollTop: =>
|
||||
@element.scrollTop 0
|
||||
|
||||
appendLabel: (x, y, commit) ->
|
||||
return unless commit.refs
|
||||
@@ -325,5 +334,3 @@ Raphael::textWrap = (t, width) ->
|
||||
b = t.getBBox()
|
||||
h = Math.abs(b.y2) - Math.abs(b.y) + 1
|
||||
t.attr y: b.y + h
|
||||
|
||||
@BranchGraph = BranchGraph
|
||||
|
||||
@@ -15,50 +15,84 @@ class Dispatcher
|
||||
return false
|
||||
|
||||
path = page.split(':')
|
||||
shortcut_handler = null
|
||||
|
||||
switch page
|
||||
when 'projects:issues:index'
|
||||
Issues.init()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'projects:issues:show'
|
||||
new Issue()
|
||||
shortcut_handler = new ShortcutsIssueable()
|
||||
when 'projects:milestones:show'
|
||||
new Milestone()
|
||||
when 'projects:issues:new'
|
||||
GitLab.GfmAutoComplete.setup()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'projects:merge_requests:new'
|
||||
GitLab.GfmAutoComplete.setup()
|
||||
new Diff()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'projects:merge_requests:show'
|
||||
new Diff()
|
||||
shortcut_handler = new ShortcutsIssueable()
|
||||
when "projects:merge_requests:diffs"
|
||||
new Diff()
|
||||
when 'projects:merge_requests:index'
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'dashboard:show'
|
||||
new Dashboard()
|
||||
new Activities()
|
||||
when 'projects:commit:show'
|
||||
new Commit()
|
||||
new Diff()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'projects:commits:show'
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'groups:show', 'projects:show'
|
||||
new Activities()
|
||||
when 'projects:new', 'projects:edit'
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'projects:new'
|
||||
new Project()
|
||||
when 'projects:edit'
|
||||
new Project()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'projects:teams:members:index'
|
||||
new TeamMembers()
|
||||
when 'groups:members'
|
||||
new GroupMembers()
|
||||
when 'projects:tree:show'
|
||||
new TreeView()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'projects:blob:show'
|
||||
new BlobView()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'projects:labels:new', 'projects:labels:edit'
|
||||
new Labels()
|
||||
when 'projects:network:show'
|
||||
# Ensure we don't create a particular shortcut handler here. This is
|
||||
# already created, where the network graph is created.
|
||||
shortcut_handler = true
|
||||
|
||||
switch path.first()
|
||||
when 'admin' then new Admin()
|
||||
when 'dashboard'
|
||||
shortcut_handler = new ShortcutsDashboardNavigation()
|
||||
when 'projects'
|
||||
new Wikis() if path[1] == 'wikis'
|
||||
switch path[1]
|
||||
when 'wikis'
|
||||
new Wikis()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'snippets', 'labels', 'graphs'
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
when 'team_members', 'deploy_keys', 'hooks', 'services', 'protected_branches'
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
|
||||
|
||||
# If we haven't installed a custom shortcut handler, install the default one
|
||||
if not shortcut_handler
|
||||
new Shortcuts()
|
||||
|
||||
initSearch: ->
|
||||
opts = $('.search-autocomplete-opts')
|
||||
path = opts.data('autocomplete-path')
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
class Network
|
||||
class @Network
|
||||
constructor: (opts) ->
|
||||
$("#filter_ref").click ->
|
||||
$(this).closest('form').submit()
|
||||
|
||||
branch_graph = new BranchGraph($(".network-graph"), opts)
|
||||
@branch_graph = new BranchGraph($(".network-graph"), opts)
|
||||
|
||||
vph = $(window).height() - 250
|
||||
$('.network-graph').css 'height': (vph + 'px')
|
||||
|
||||
@Network = Network
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
class Shortcuts
|
||||
class @Shortcuts
|
||||
constructor: ->
|
||||
@enabledHelp = []
|
||||
Mousetrap.reset()
|
||||
Mousetrap.bind('?', @selectiveHelp)
|
||||
Mousetrap.bind('s', Shortcuts.focusSearch)
|
||||
|
||||
selectiveHelp: (e) =>
|
||||
Shortcuts.showHelp(e, @enabledHelp)
|
||||
|
||||
@showHelp: (e, location) ->
|
||||
if $('#modal-shortcuts').length > 0
|
||||
$('#modal-shortcuts').modal('show')
|
||||
else
|
||||
$.ajax(
|
||||
url: '/help/shortcuts',
|
||||
dataType: "script"
|
||||
dataType: 'script',
|
||||
success: (e) ->
|
||||
if location and location.length > 0
|
||||
for l in location
|
||||
$(l).show()
|
||||
else
|
||||
$('.hidden-shortcut').show()
|
||||
$('.js-more-help-button').remove()
|
||||
)
|
||||
e.preventDefault()
|
||||
|
||||
@Shortcuts = Shortcuts
|
||||
@focusSearch: (e) ->
|
||||
$('#search').focus()
|
||||
e.preventDefault()
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#= require shortcuts
|
||||
|
||||
class @ShortcutsDashboardNavigation extends Shortcuts
|
||||
constructor: ->
|
||||
super()
|
||||
Mousetrap.bind('g a', -> ShortcutsDashboardNavigation.findAndollowLink('.shortcuts-activity'))
|
||||
Mousetrap.bind('g p', -> ShortcutsDashboardNavigation.findAndollowLink('.shortcuts-projects'))
|
||||
Mousetrap.bind('g i', -> ShortcutsDashboardNavigation.findAndollowLink('.shortcuts-issues'))
|
||||
Mousetrap.bind('g m', -> ShortcutsDashboardNavigation.findAndollowLink('.shortcuts-merge_requests'))
|
||||
|
||||
@findAndollowLink: (selector) ->
|
||||
link = $(selector).attr('href')
|
||||
if link
|
||||
window.location = link
|
||||
@@ -0,0 +1,19 @@
|
||||
#= require shortcuts_navigation
|
||||
|
||||
class @ShortcutsIssueable extends ShortcutsNavigation
|
||||
constructor: (isMergeRequest) ->
|
||||
super()
|
||||
Mousetrap.bind('a', ->
|
||||
$('.js-assignee').select2('open')
|
||||
return false
|
||||
)
|
||||
Mousetrap.bind('m', ->
|
||||
$('.js-milestone').select2('open')
|
||||
return false
|
||||
)
|
||||
|
||||
if isMergeRequest
|
||||
@enabledHelp.push('.hidden-shortcut.merge_reuests')
|
||||
else
|
||||
@enabledHelp.push('.hidden-shortcut.issues')
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#= require shortcuts
|
||||
|
||||
class @ShortcutsNavigation extends Shortcuts
|
||||
constructor: ->
|
||||
super()
|
||||
Mousetrap.bind('g a', -> ShortcutsNavigation.findAndollowLink('.shortcuts-activity'))
|
||||
Mousetrap.bind('g f', -> ShortcutsNavigation.findAndollowLink('.shortcuts-tree'))
|
||||
Mousetrap.bind('g c', -> ShortcutsNavigation.findAndollowLink('.shortcuts-commits'))
|
||||
Mousetrap.bind('g n', -> ShortcutsNavigation.findAndollowLink('.shortcuts-network'))
|
||||
Mousetrap.bind('g g', -> ShortcutsNavigation.findAndollowLink('.shortcuts-graphs'))
|
||||
Mousetrap.bind('g i', -> ShortcutsNavigation.findAndollowLink('.shortcuts-issues'))
|
||||
Mousetrap.bind('g m', -> ShortcutsNavigation.findAndollowLink('.shortcuts-merge_requests'))
|
||||
Mousetrap.bind('g w', -> ShortcutsNavigation.findAndollowLink('.shortcuts-wiki'))
|
||||
Mousetrap.bind('g s', -> ShortcutsNavigation.findAndollowLink('.shortcuts-snippets'))
|
||||
@enabledHelp.push('.hidden-shortcut.project')
|
||||
|
||||
@findAndollowLink: (selector) ->
|
||||
link = $(selector).attr('href')
|
||||
if link
|
||||
window.location = link
|
||||
@@ -0,0 +1,12 @@
|
||||
#= require shortcuts_navigation
|
||||
|
||||
class @ShortcutsNetwork extends ShortcutsNavigation
|
||||
constructor: (@graph) ->
|
||||
super()
|
||||
Mousetrap.bind(['left', 'h'], @graph.scrollLeft)
|
||||
Mousetrap.bind(['right', 'l'], @graph.scrollRight)
|
||||
Mousetrap.bind(['up', 'k'], @graph.scrollUp)
|
||||
Mousetrap.bind(['down', 'j'], @graph.scrollDown)
|
||||
Mousetrap.bind(['shift+up', 'shift+k'], @graph.scrollTop)
|
||||
Mousetrap.bind(['shift+down', 'shift+j'], @graph.scrollBottom)
|
||||
@enabledHelp.push('.hidden-shortcut.network')
|
||||
@@ -16,3 +16,4 @@ body {
|
||||
.container .content {
|
||||
margin: 0 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,3 +17,56 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.shortcut-mappings {
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
|
||||
tbody:first-child tr:first-child {
|
||||
padding-top: 0
|
||||
}
|
||||
|
||||
th {
|
||||
padding-top: 15px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: #333;
|
||||
text-align: left
|
||||
}
|
||||
|
||||
td {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
vertical-align: top;
|
||||
line-height: 20px
|
||||
}
|
||||
|
||||
.shortcut {
|
||||
padding-right: 10px;
|
||||
color: #999;
|
||||
text-align: right;
|
||||
white-space: nowrap
|
||||
}
|
||||
|
||||
.key {
|
||||
@extend .label;
|
||||
@extend .label-inverse;
|
||||
font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
padding: 3px 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
body.modal-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal .modal-dialog {
|
||||
width: 860px;
|
||||
}
|
||||
|
||||
@@ -3,30 +3,207 @@
|
||||
.modal-content
|
||||
.modal-header
|
||||
%a.close{href: "#", "data-dismiss" => "modal"} ×
|
||||
%h3 Keyboard Shortcuts
|
||||
.modal-body
|
||||
%h5 Global Shortcuts
|
||||
%p
|
||||
%span.label.label-inverse s
|
||||
–
|
||||
Focus Search
|
||||
%p
|
||||
%span.label.label-inverse ?
|
||||
–
|
||||
Show this dialog
|
||||
%h4
|
||||
Keyboard Shortcuts
|
||||
%small
|
||||
= link_to '(Show all)', '#', class: 'js-more-help-button'
|
||||
.modal-body.shortcuts-cheatsheet
|
||||
.col-lg-4
|
||||
%table.shortcut-mappings
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Global Shortcuts
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key s
|
||||
%td Focus Search
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key ?
|
||||
%td Show this dialog
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project Files browsing
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.icon-arrow-up
|
||||
%td Move selection up
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.icon-arrow-down
|
||||
%td Move selection down
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key enter
|
||||
%td Open Selection
|
||||
|
||||
%h5 Project Files browsing
|
||||
%p
|
||||
%span.label.label-inverse
|
||||
%i.icon-arrow-up
|
||||
–
|
||||
Move selection up
|
||||
%p
|
||||
%span.label.label-inverse
|
||||
%i.icon-arrow-down
|
||||
–
|
||||
Move selection down
|
||||
%p
|
||||
%span.label.label-inverse Enter
|
||||
–
|
||||
Open selection
|
||||
.col-lg-4
|
||||
%table.shortcut-mappings
|
||||
%tbody{ class: 'hidden-shortcut project', style: 'display:none' }
|
||||
%tr
|
||||
%th
|
||||
%th Global Dashboard
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key a
|
||||
%td
|
||||
Go to the activity feed
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key p
|
||||
%td
|
||||
Go to projects
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key i
|
||||
%td
|
||||
Go to issues
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key m
|
||||
%td
|
||||
Go to merge requests
|
||||
%tbody
|
||||
%tr
|
||||
%th
|
||||
%th Project
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key a
|
||||
%td
|
||||
Go to the activity feed
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key f
|
||||
%td
|
||||
Go to files
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key c
|
||||
%td
|
||||
Go to commits
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key n
|
||||
%td
|
||||
Go to network graph
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key g
|
||||
%td
|
||||
Go to graphs
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key i
|
||||
%td
|
||||
Go to issues
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key m
|
||||
%td
|
||||
Go to merge requests
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key g
|
||||
.key s
|
||||
%td
|
||||
Go to snippets
|
||||
.col-lg-4
|
||||
%table.shortcut-mappings
|
||||
%tbody{ class: 'hidden-shortcut network', style: 'display:none' }
|
||||
%tr
|
||||
%th
|
||||
%th Network Graph
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.icon-arrow-left
|
||||
\/
|
||||
.key h
|
||||
%td Scroll left
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.icon-arrow-right
|
||||
\/
|
||||
.key l
|
||||
%td Scroll right
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.icon-arrow-up
|
||||
\/
|
||||
.key k
|
||||
%td Scroll up
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
%i.icon-arrow-down
|
||||
\/
|
||||
.key j
|
||||
%td Scroll down
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
shift
|
||||
%i.icon-arrow-up
|
||||
\/
|
||||
.key
|
||||
shift k
|
||||
%td Scroll to top
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key
|
||||
shift
|
||||
%i.icon-arrow-down
|
||||
\/
|
||||
.key
|
||||
shift j
|
||||
%td Scroll to bottom
|
||||
%tbody{ class: 'hidden-shortcut issues', style: 'display:none' }
|
||||
%tr
|
||||
%th
|
||||
%th Issues
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key a
|
||||
%td Change assignee
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key m
|
||||
%td Change milestone
|
||||
%tbody{ class: 'hidden-shortcut merge_reuests', style: 'display:none' }
|
||||
%tr
|
||||
%th
|
||||
%th Merge Requests
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key a
|
||||
%td Change assignee
|
||||
%tr
|
||||
%td.shortcut
|
||||
.key m
|
||||
%td Change milestone
|
||||
|
||||
|
||||
:javascript
|
||||
$('.js-more-help-button').click(function(e){
|
||||
$(this).remove()
|
||||
$('.hidden-shortcut').show()
|
||||
e.preventDefault()
|
||||
});
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
= link_to "getting help", "https://www.gitlab.com/getting-help/"
|
||||
%li
|
||||
Use the
|
||||
= link_to "search bar", '#', onclick: "$('#search').focus();"
|
||||
= link_to 'search bar', '#', onclick: 'Shortcuts.focusSearch(event)'
|
||||
on the top of this page
|
||||
%li
|
||||
Use
|
||||
= link_to "shortcuts", '#', onclick: "new Shortcuts()"
|
||||
= link_to 'shortcuts', '#', onclick: 'Shortcuts.showHelp(event)'
|
||||
|
||||
@@ -8,3 +8,10 @@
|
||||
= hidden_field_tag :repository_ref, @ref
|
||||
= submit_tag 'Go' if ENV['RAILS_ENV'] == 'test'
|
||||
.search-autocomplete-opts.hide{:'data-autocomplete-path' => search_autocomplete_path, :'data-autocomplete-project-id' => @project.try(:id), :'data-autocomplete-project-ref' => @ref }
|
||||
|
||||
:javascript
|
||||
$('.search-input').on('keyup', function(e) {
|
||||
if (e.keyCode == 27) {
|
||||
$('.search-input').blur()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
%ul
|
||||
= nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
|
||||
= link_to root_path, title: "Home" do
|
||||
= link_to root_path, title: 'Home', class: 'shortcuts-activity' do
|
||||
Activity
|
||||
= nav_link(path: 'dashboard#projects') do
|
||||
= link_to projects_dashboard_path do
|
||||
= link_to projects_dashboard_path, class: 'shortcuts-projects' do
|
||||
Projects
|
||||
= nav_link(path: 'dashboard#issues') do
|
||||
= link_to issues_dashboard_path do
|
||||
= link_to issues_dashboard_path, class: 'shortcuts-issues' do
|
||||
Issues
|
||||
%span.count= current_user.assigned_issues.opened.count
|
||||
= nav_link(path: 'dashboard#merge_requests') do
|
||||
= link_to merge_requests_dashboard_path do
|
||||
= link_to merge_requests_dashboard_path, class: 'shortcuts-merge_requests' do
|
||||
Merge Requests
|
||||
%span.count= current_user.assigned_merge_requests.opened.count
|
||||
= nav_link(controller: :help) do
|
||||
|
||||
@@ -1,44 +1,43 @@
|
||||
%ul
|
||||
%ul.project-navigation
|
||||
= nav_link(path: 'projects#show', html_options: {class: "home"}) do
|
||||
= link_to project_path(@project), title: "Project" do
|
||||
Project
|
||||
|
||||
= link_to project_path(@project), title: 'Project', class: 'shortcuts-activity' do
|
||||
Activity
|
||||
- if project_nav_tab? :files
|
||||
= nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
|
||||
= link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref)
|
||||
= link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref), class: 'shortcuts-tree'
|
||||
|
||||
- if project_nav_tab? :commits
|
||||
= nav_link(controller: %w(commit commits compare repositories tags branches)) do
|
||||
= link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref)
|
||||
= link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref), class: 'shortcuts-commits'
|
||||
|
||||
- if project_nav_tab? :network
|
||||
= nav_link(controller: %w(network)) do
|
||||
= link_to "Network", project_network_path(@project, @ref || @repository.root_ref)
|
||||
= link_to "Network", project_network_path(@project, @ref || @repository.root_ref), class: 'shortcuts-network'
|
||||
|
||||
- if project_nav_tab? :graphs
|
||||
= nav_link(controller: %w(graphs)) do
|
||||
= link_to "Graphs", project_graph_path(@project, @ref || @repository.root_ref)
|
||||
= link_to "Graphs", project_graph_path(@project, @ref || @repository.root_ref), class: 'shortcuts-graphs'
|
||||
|
||||
- if project_nav_tab? :issues
|
||||
= nav_link(controller: %w(issues milestones labels)) do
|
||||
= link_to url_for_project_issues do
|
||||
= link_to url_for_project_issues, class: 'shortcuts-issues' do
|
||||
Issues
|
||||
- if @project.used_default_issues_tracker?
|
||||
%span.count.issue_counter= @project.issues.opened.count
|
||||
|
||||
- if project_nav_tab? :merge_requests
|
||||
= nav_link(controller: :merge_requests) do
|
||||
= link_to project_merge_requests_path(@project) do
|
||||
= link_to project_merge_requests_path(@project), class: 'shortcuts-merge_requests' do
|
||||
Merge Requests
|
||||
%span.count.merge_counter= @project.merge_requests.opened.count
|
||||
|
||||
- if project_nav_tab? :wiki
|
||||
= nav_link(controller: :wikis) do
|
||||
= link_to 'Wiki', project_wiki_path(@project, :home)
|
||||
= link_to 'Wiki', project_wiki_path(@project, :home), class: 'shortcuts-wiki'
|
||||
|
||||
- if project_nav_tab? :snippets
|
||||
= nav_link(controller: :snippets) do
|
||||
= link_to 'Snippets', project_snippets_path(@project)
|
||||
= link_to 'Snippets', project_snippets_path(@project), class: 'shortcuts-snippets'
|
||||
|
||||
- if project_nav_tab? :settings
|
||||
= nav_link(html_options: {class: "#{project_tab_class}"}) do
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Assignee:
|
||||
|
||||
- if can?(current_user, :modify_issue, @issue)
|
||||
= project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @issue.assignee_id)
|
||||
= project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id)
|
||||
- elsif issue.assignee
|
||||
= link_to_member(@project, @issue.assignee)
|
||||
- else
|
||||
@@ -15,7 +15,7 @@
|
||||
%strong.append-right-10
|
||||
Milestone:
|
||||
- if can?(current_user, :modify_issue, @issue)
|
||||
= f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone" }, {class: 'select2 select2-compact'})
|
||||
= f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
|
||||
= hidden_field_tag :issue_context
|
||||
= f.submit class: 'btn'
|
||||
- elsif issue.milestone
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Assignee:
|
||||
|
||||
- if can?(current_user, :modify_merge_request, @merge_request)
|
||||
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @merge_request.assignee_id)
|
||||
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id)
|
||||
- elsif merge_request.assignee
|
||||
= link_to_member(@project, @merge_request.assignee)
|
||||
- else
|
||||
@@ -15,7 +15,7 @@
|
||||
%strong.append-right-10
|
||||
Milestone:
|
||||
- if can?(current_user, :modify_merge_request, @merge_request)
|
||||
= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2 select2-compact'})
|
||||
= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
|
||||
= hidden_field_tag :merge_request_context
|
||||
= f.submit class: 'btn'
|
||||
- elsif merge_request.milestone
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
= spinner nil, true
|
||||
|
||||
:javascript
|
||||
new Network({
|
||||
network_graph = new Network({
|
||||
url: '#{project_network_path(@project, @ref, @options.merge(format: :json))}',
|
||||
commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}',
|
||||
ref: '#{@ref}',
|
||||
commit_id: '#{@commit.id}'
|
||||
})
|
||||
new ShortcutsNetwork(network_graph.branch_graph)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
@dashboard
|
||||
Feature: Dashboard shortcuts
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
And I visit dashboard page
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to projects tab
|
||||
Given I press "g" and "p"
|
||||
Then the active main tab should be Projects
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to issue tab
|
||||
Given I press "g" and "i"
|
||||
Then the active main tab should be Issues
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to merge requests tab
|
||||
Given I press "g" and "m"
|
||||
Then the active main tab should be Merge Requests
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
@dashboard
|
||||
Feature: Project shortcuts
|
||||
Background:
|
||||
Given I sign in as a user
|
||||
And I own a project
|
||||
And I visit my project's home page
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to files tab
|
||||
Given I press "g" and "f"
|
||||
Then the active main tab should be Files
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to commits tab
|
||||
Given I press "g" and "c"
|
||||
Then the active main tab should be Commits
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to network tab
|
||||
Given I press "g" and "n"
|
||||
Then the active main tab should be Network
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to graphs tab
|
||||
Given I press "g" and "g"
|
||||
Then the active main tab should be Graphs
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to issues tab
|
||||
Given I press "g" and "i"
|
||||
Then the active main tab should be Issues
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to merge requests tab
|
||||
Given I press "g" and "m"
|
||||
Then the active main tab should be Merge Requests
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to snippets tab
|
||||
Given I press "g" and "s"
|
||||
Then the active main tab should be Snippets
|
||||
|
||||
@javascript
|
||||
Scenario: Navigate to wiki tab
|
||||
Given I press "g" and "w"
|
||||
Then the active main tab should be Wiki
|
||||
@@ -3,19 +3,7 @@ class DashboardActiveTab < Spinach::FeatureSteps
|
||||
include SharedPaths
|
||||
include SharedActiveTab
|
||||
|
||||
Then 'the active main tab should be Home' do
|
||||
ensure_active_main_tab('Activity')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Issues' do
|
||||
ensure_active_main_tab('Issues')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Merge Requests' do
|
||||
ensure_active_main_tab('Merge Requests')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Help' do
|
||||
step 'the active main tab should be Help' do
|
||||
ensure_active_main_tab('Help')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
class DashboardShortcuts < Spinach::FeatureSteps
|
||||
include SharedAuthentication
|
||||
include SharedPaths
|
||||
include SharedProject
|
||||
include SharedActiveTab
|
||||
end
|
||||
@@ -3,44 +3,7 @@ class ProjectActiveTab < Spinach::FeatureSteps
|
||||
include SharedPaths
|
||||
include SharedProject
|
||||
include SharedActiveTab
|
||||
|
||||
# Main Tabs
|
||||
|
||||
Then 'the active main tab should be Home' do
|
||||
ensure_active_main_tab('Project')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Settings' do
|
||||
ensure_active_main_tab('Settings')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Files' do
|
||||
ensure_active_main_tab('Files')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Commits' do
|
||||
ensure_active_main_tab('Commits')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Network' do
|
||||
ensure_active_main_tab('Network')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Issues' do
|
||||
ensure_active_main_tab('Issues')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Merge Requests' do
|
||||
ensure_active_main_tab('Merge Requests')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Wall' do
|
||||
ensure_active_main_tab('Wall')
|
||||
end
|
||||
|
||||
Then 'the active main tab should be Wiki' do
|
||||
ensure_active_main_tab('Wiki')
|
||||
end
|
||||
include SharedProjectTab
|
||||
|
||||
# Sub Tabs: Home
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
class ProjectShortcuts < Spinach::FeatureSteps
|
||||
include SharedAuthentication
|
||||
include SharedPaths
|
||||
include SharedProject
|
||||
include SharedProjectTab
|
||||
|
||||
step 'I press "g" and "f"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('f')
|
||||
end
|
||||
|
||||
step 'I press "g" and "c"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('c')
|
||||
end
|
||||
|
||||
step 'I press "g" and "n"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('n')
|
||||
end
|
||||
|
||||
step 'I press "g" and "g"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('g')
|
||||
end
|
||||
|
||||
step 'I press "g" and "s"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('s')
|
||||
end
|
||||
|
||||
step 'I press "g" and "w"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('w')
|
||||
end
|
||||
end
|
||||
@@ -24,4 +24,24 @@ module SharedActiveTab
|
||||
And 'no other sub navs should be active' do
|
||||
page.should have_selector('div.content ul.nav-stacked-menu li.active', count: 1)
|
||||
end
|
||||
|
||||
step 'the active main tab should be Home' do
|
||||
ensure_active_main_tab('Activity')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Projects' do
|
||||
ensure_active_main_tab('Projects')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Issues' do
|
||||
ensure_active_main_tab('Issues')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Merge Requests' do
|
||||
ensure_active_main_tab('Merge Requests')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Help' do
|
||||
ensure_active_main_tab('Help')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
module SharedProjectTab
|
||||
include Spinach::DSL
|
||||
include SharedActiveTab
|
||||
|
||||
step 'the active main tab should be Home' do
|
||||
ensure_active_main_tab('Activity')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Files' do
|
||||
ensure_active_main_tab('Files')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Commits' do
|
||||
ensure_active_main_tab('Commits')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Network' do
|
||||
ensure_active_main_tab('Network')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Graphs' do
|
||||
ensure_active_main_tab('Graphs')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Issues' do
|
||||
ensure_active_main_tab('Issues')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Merge Requests' do
|
||||
ensure_active_main_tab('Merge Requests')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Snippets' do
|
||||
ensure_active_main_tab('Snippets')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Wiki' do
|
||||
ensure_active_main_tab('Wiki')
|
||||
end
|
||||
|
||||
step 'the active main tab should be Settings' do
|
||||
ensure_active_main_tab('Settings')
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
module SharedActiveTab
|
||||
include Spinach::DSL
|
||||
|
||||
step 'I press "g" and "p"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('p')
|
||||
end
|
||||
|
||||
step 'I press "g" and "i"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('i')
|
||||
end
|
||||
|
||||
step 'I press "g" and "m"' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('m')
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user