summaryrefslogtreecommitdiff
path: root/app/assets
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2017-01-19 15:31:04 +0100
committerKamil Trzcinski <ayufan@ayufan.eu>2017-01-19 15:31:04 +0100
commit8171a1932b3c5e55ad3ea8402ac68ff14692ca32 (patch)
treecdcef619d3df923e634bd61228179d80e88c61f6 /app/assets
parent8c9a4ed373f4b517aeae669e64023dc52c8d704a (diff)
parent1cc6d206b5d4cf09bb502a254703f3a2de2dbeb7 (diff)
downloadgitlab-ce-8171a1932b3c5e55ad3ea8402ac68ff14692ca32.tar.gz
Merge remote-tracking branch 'origin/master' into 21698-redis-runner-last-build
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/images/auth_buttons/authentiq_64.pngbin0 -> 17679 bytes
-rw-r--r--app/assets/javascripts/abuse_reports.js.es63
-rw-r--r--app/assets/javascripts/admin.js4
-rw-r--r--app/assets/javascripts/api.js11
-rw-r--r--app/assets/javascripts/application.js18
-rw-r--r--app/assets/javascripts/awards_handler.js4
-rw-r--r--app/assets/javascripts/behaviors/autosize.js3
-rw-r--r--app/assets/javascripts/behaviors/quick_submit.js3
-rw-r--r--app/assets/javascripts/blob/blob_ci_yaml.js.es64
-rw-r--r--app/assets/javascripts/blob/blob_dockerfile_selector.js.es618
-rw-r--r--app/assets/javascripts/blob/blob_dockerfile_selectors.js.es627
-rw-r--r--app/assets/javascripts/blob/blob_file_dropzone.js4
-rw-r--r--app/assets/javascripts/blob/blob_gitignore_selector.js3
-rw-r--r--app/assets/javascripts/blob/blob_gitignore_selectors.js4
-rw-r--r--app/assets/javascripts/blob/blob_license_selector.js3
-rw-r--r--app/assets/javascripts/blob/blob_license_selectors.js.es64
-rw-r--r--app/assets/javascripts/blob/template_selector.js.es63
-rw-r--r--app/assets/javascripts/blob_edit/blob_edit_bundle.js5
-rw-r--r--app/assets/javascripts/blob_edit/edit_blob.js10
-rw-r--r--app/assets/javascripts/boards/boards_bundle.js.es67
-rw-r--r--app/assets/javascripts/boards/components/board.js.es631
-rw-r--r--app/assets/javascripts/boards/components/board_blank_state.js.es65
-rw-r--r--app/assets/javascripts/boards/components/board_card.js.es64
-rw-r--r--app/assets/javascripts/boards/components/board_delete.js.es64
-rw-r--r--app/assets/javascripts/boards/components/board_list.js.es65
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.js.es65
-rw-r--r--app/assets/javascripts/boards/components/board_sidebar.js.es68
-rw-r--r--app/assets/javascripts/boards/components/new_list_dropdown.js.es611
-rw-r--r--app/assets/javascripts/boards/filters/due_date_filters.js.es63
-rw-r--r--app/assets/javascripts/boards/mixins/sortable_default_options.js.es65
-rw-r--r--app/assets/javascripts/boards/models/issue.js.es69
-rw-r--r--app/assets/javascripts/boards/models/label.js.es65
-rw-r--r--app/assets/javascripts/boards/models/list.js.es67
-rw-r--r--app/assets/javascripts/boards/models/milestone.js.es67
-rw-r--r--app/assets/javascripts/boards/models/user.js.es67
-rw-r--r--app/assets/javascripts/boards/services/board_service.js.es68
-rw-r--r--app/assets/javascripts/boards/stores/boards_store.js.es65
-rw-r--r--app/assets/javascripts/boards/vue_resource_interceptor.js.es64
-rw-r--r--app/assets/javascripts/breakpoints.js6
-rw-r--r--app/assets/javascripts/build.js144
-rw-r--r--app/assets/javascripts/build_variables.js.es63
-rw-r--r--app/assets/javascripts/ci_lint_editor.js.es618
-rw-r--r--app/assets/javascripts/commit.js4
-rw-r--r--app/assets/javascripts/commit/file.js4
-rw-r--r--app/assets/javascripts/commits.js8
-rw-r--r--app/assets/javascripts/compare_autocomplete.js.es610
-rw-r--r--app/assets/javascripts/copy_to_clipboard.js3
-rw-r--r--app/assets/javascripts/create_label.js.es64
-rw-r--r--app/assets/javascripts/diff.js.es619
-rw-r--r--app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es65
-rw-r--r--app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es68
-rw-r--r--app/assets/javascripts/diff_notes/components/resolve_btn.js.es617
-rw-r--r--app/assets/javascripts/diff_notes/components/resolve_count.js.es66
-rw-r--r--app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es66
-rw-r--r--app/assets/javascripts/diff_notes/diff_notes_bundle.js.es67
-rw-r--r--app/assets/javascripts/diff_notes/mixins/discussion.js.es63
-rw-r--r--app/assets/javascripts/diff_notes/models/discussion.js.es69
-rw-r--r--app/assets/javascripts/diff_notes/models/note.js.es67
-rw-r--r--app/assets/javascripts/diff_notes/services/resolve.js.es66
-rw-r--r--app/assets/javascripts/diff_notes/stores/comments.js.es65
-rw-r--r--app/assets/javascripts/dispatcher.js.es681
-rw-r--r--app/assets/javascripts/droplab/droplab.js701
-rw-r--r--app/assets/javascripts/droplab/droplab_ajax.js79
-rw-r--r--app/assets/javascripts/droplab/droplab_ajax_filter.js145
-rw-r--r--app/assets/javascripts/droplab/droplab_filter.js60
-rw-r--r--app/assets/javascripts/dropzone_input.js3
-rw-r--r--app/assets/javascripts/due_date_select.js.es610
-rw-r--r--app/assets/javascripts/environments/components/environment.js.es622
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.js.es62
-rw-r--r--app/assets/javascripts/environments/components/environment_external_url.js.es62
-rw-r--r--app/assets/javascripts/environments/components/environment_item.js.es630
-rw-r--r--app/assets/javascripts/environments/components/environment_rollback.js.es62
-rw-r--r--app/assets/javascripts/environments/components/environment_stop.js.es62
-rw-r--r--app/assets/javascripts/environments/components/environment_terminal_button.js.es627
-rw-r--r--app/assets/javascripts/environments/environments_bundle.js.es610
-rw-r--r--app/assets/javascripts/environments/services/environments_service.js.es62
-rw-r--r--app/assets/javascripts/extensions/object.js.es626
-rw-r--r--app/assets/javascripts/files_comment_button.js4
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_hint.js.es666
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_non_user.js.es644
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_user.js.es653
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_utils.js.es679
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_bundle.js7
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6102
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6193
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js.es6171
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es683
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es645
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js.es6240
-rw-r--r--app/assets/javascripts/gl_dropdown.js39
-rw-r--r--app/assets/javascripts/gl_field_errors.js.es62
-rw-r--r--app/assets/javascripts/gl_form.js10
-rw-r--r--app/assets/javascripts/graphs/stat_graph_contributors.js7
-rw-r--r--app/assets/javascripts/graphs/stat_graph_contributors_graph.js4
-rw-r--r--app/assets/javascripts/group_label_subscription.js.es63
-rw-r--r--app/assets/javascripts/groups_select.js6
-rw-r--r--app/assets/javascripts/importer_status.js7
-rw-r--r--app/assets/javascripts/issuable.js.es621
-rw-r--r--app/assets/javascripts/issuable/issuable_bundle.js.es61
-rw-r--r--app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es642
-rw-r--r--app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js.es669
-rw-r--r--app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js.es613
-rw-r--r--app/assets/javascripts/issuable/time_tracking/components/help_state.js.es624
-rw-r--r--app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js.es611
-rw-r--r--app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js.es613
-rw-r--r--app/assets/javascripts/issuable/time_tracking/components/time_tracker.js.es6118
-rw-r--r--app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es661
-rw-r--r--app/assets/javascripts/issuable_context.js4
-rw-r--r--app/assets/javascripts/issuable_form.js9
-rw-r--r--app/assets/javascripts/issue.js6
-rw-r--r--app/assets/javascripts/issues_bulk_assignment.js.es697
-rw-r--r--app/assets/javascripts/label_manager.js.es65
-rw-r--r--app/assets/javascripts/labels_select.js151
-rw-r--r--app/assets/javascripts/lib/ace.js1
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js.es6 (renamed from app/assets/javascripts/lib/utils/common_utils.js)50
-rw-r--r--app/assets/javascripts/lib/utils/custom_event_polyfill.js.es612
-rw-r--r--app/assets/javascripts/lib/utils/notify.js3
-rw-r--r--app/assets/javascripts/lib/utils/pretty_time.js.es626
-rw-r--r--app/assets/javascripts/lib/utils/text_utility.js51
-rw-r--r--app/assets/javascripts/lib/vue_resource.js.es62
-rw-r--r--app/assets/javascripts/line_highlighter.js3
-rw-r--r--app/assets/javascripts/member_expiration_date.js.es6 (renamed from app/assets/javascripts/member_expiration_date.js)17
-rw-r--r--app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es66
-rw-r--r--app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js.es64
-rw-r--r--app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js.es66
-rw-r--r--app/assets/javascripts/merge_conflicts/merge_conflict_service.js.es63
-rw-r--r--app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es65
-rw-r--r--app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es65
-rw-r--r--app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js.es63
-rw-r--r--app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js.es63
-rw-r--r--app/assets/javascripts/merge_request.js24
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.es642
-rw-r--r--app/assets/javascripts/merge_request_widget.js.es626
-rw-r--r--app/assets/javascripts/merge_request_widget/ci_bundle.js.es642
-rw-r--r--app/assets/javascripts/merged_buttons.js3
-rw-r--r--app/assets/javascripts/milestone.js4
-rw-r--r--app/assets/javascripts/milestone_select.js6
-rw-r--r--app/assets/javascripts/mini_pipeline_graph_dropdown.js.es696
-rw-r--r--app/assets/javascripts/namespace_select.js10
-rw-r--r--app/assets/javascripts/network/branch_graph.js22
-rw-r--r--app/assets/javascripts/network/network.js4
-rw-r--r--app/assets/javascripts/network/network_bundle.js5
-rw-r--r--app/assets/javascripts/notes.js184
-rw-r--r--app/assets/javascripts/notifications_dropdown.js6
-rw-r--r--app/assets/javascripts/pipelines.js.es63
-rw-r--r--app/assets/javascripts/preview_markdown.js118
-rw-r--r--app/assets/javascripts/profile/gl_crop.js.es63
-rw-r--r--app/assets/javascripts/profile/profile.js.es613
-rw-r--r--app/assets/javascripts/project.js6
-rw-r--r--app/assets/javascripts/project_find_file.js4
-rw-r--r--app/assets/javascripts/project_import.js4
-rw-r--r--app/assets/javascripts/project_label_subscription.js.es63
-rw-r--r--app/assets/javascripts/project_select.js7
-rw-r--r--app/assets/javascripts/projects_list.js7
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es63
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_create.js.es64
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es65
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_edit.js.es66
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es63
-rw-r--r--app/assets/javascripts/protected_branches/protected_branches_bundle.js1
-rw-r--r--app/assets/javascripts/render_gfm.js16
-rw-r--r--app/assets/javascripts/render_math.js55
-rw-r--r--app/assets/javascripts/right_sidebar.js4
-rw-r--r--app/assets/javascripts/search.js10
-rw-r--r--app/assets/javascripts/search_autocomplete.js.es610
-rw-r--r--app/assets/javascripts/shortcuts.js6
-rw-r--r--app/assets/javascripts/shortcuts_blob.js4
-rw-r--r--app/assets/javascripts/shortcuts_dashboard_navigation.js4
-rw-r--r--app/assets/javascripts/shortcuts_find_file.js4
-rw-r--r--app/assets/javascripts/shortcuts_issuable.js6
-rw-r--r--app/assets/javascripts/shortcuts_navigation.js4
-rw-r--r--app/assets/javascripts/shortcuts_network.js4
-rw-r--r--app/assets/javascripts/sidebar.js.es64
-rw-r--r--app/assets/javascripts/single_file_diff.js25
-rw-r--r--app/assets/javascripts/snippet/snippet_bundle.js4
-rw-r--r--app/assets/javascripts/snippets_list.js.es63
-rw-r--r--app/assets/javascripts/star.js4
-rw-r--r--app/assets/javascripts/subbable_resource.js.es63
-rw-r--r--app/assets/javascripts/syntax_highlight.js9
-rw-r--r--app/assets/javascripts/templates/issuable_template_selector.js.es66
-rw-r--r--app/assets/javascripts/templates/issuable_template_selectors.js.es63
-rw-r--r--app/assets/javascripts/terminal/terminal.js.es662
-rw-r--r--app/assets/javascripts/terminal/terminal_bundle.js.es67
-rw-r--r--app/assets/javascripts/todos.js.es67
-rw-r--r--app/assets/javascripts/u2f/authenticate.js.es6 (renamed from app/assets/javascripts/u2f/authenticate.js)44
-rw-r--r--app/assets/javascripts/u2f/error.js5
-rw-r--r--app/assets/javascripts/u2f/register.js9
-rw-r--r--app/assets/javascripts/user.js.es64
-rw-r--r--app/assets/javascripts/user_tabs.js.es63
-rw-r--r--app/assets/javascripts/username_validator.js.es65
-rw-r--r--app/assets/javascripts/users/calendar.js5
-rw-r--r--app/assets/javascripts/users_select.js6
-rw-r--r--app/assets/javascripts/vue_pagination/index.js.es6148
-rw-r--r--app/assets/javascripts/vue_pipelines_index/index.js.es642
-rw-r--r--app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es699
-rw-r--r--app/assets/javascripts/vue_pipelines_index/pipeline_url.js.es663
-rw-r--r--app/assets/javascripts/vue_pipelines_index/pipelines.js.es6131
-rw-r--r--app/assets/javascripts/vue_pipelines_index/stage.js.es669
-rw-r--r--app/assets/javascripts/vue_pipelines_index/stages.js.es621
-rw-r--r--app/assets/javascripts/vue_pipelines_index/status.js.es634
-rw-r--r--app/assets/javascripts/vue_pipelines_index/store.js.es669
-rw-r--r--app/assets/javascripts/vue_pipelines_index/time_ago.js.es673
-rw-r--r--app/assets/javascripts/vue_realtime_listener/index.js.es618
-rw-r--r--app/assets/javascripts/zen_mode.js5
-rw-r--r--app/assets/stylesheets/framework.scss4
-rw-r--r--app/assets/stylesheets/framework/animations.scss74
-rw-r--r--app/assets/stylesheets/framework/avatar.scss6
-rw-r--r--app/assets/stylesheets/framework/awards.scss20
-rw-r--r--app/assets/stylesheets/framework/badges.scss6
-rw-r--r--app/assets/stylesheets/framework/blocks.scss20
-rw-r--r--app/assets/stylesheets/framework/buttons.scss29
-rw-r--r--app/assets/stylesheets/framework/callout.scss2
-rw-r--r--app/assets/stylesheets/framework/common.scss20
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss35
-rw-r--r--app/assets/stylesheets/framework/emojis.scss (renamed from app/assets/stylesheets/pages/emojis.scss)2
-rw-r--r--app/assets/stylesheets/framework/files.scss51
-rw-r--r--app/assets/stylesheets/framework/filters.scss115
-rw-r--r--app/assets/stylesheets/framework/forms.scss8
-rw-r--r--app/assets/stylesheets/framework/gitlab-theme.scss35
-rw-r--r--app/assets/stylesheets/framework/header.scss31
-rw-r--r--app/assets/stylesheets/framework/icons.scss (renamed from app/assets/stylesheets/pages/icons.scss)12
-rw-r--r--app/assets/stylesheets/framework/images.scss2
-rw-r--r--app/assets/stylesheets/framework/issue_box.scss2
-rw-r--r--app/assets/stylesheets/framework/layout.scss56
-rw-r--r--app/assets/stylesheets/framework/lists.scss67
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss6
-rw-r--r--app/assets/stylesheets/framework/mixins.scss2
-rw-r--r--app/assets/stylesheets/framework/mobile.scss10
-rw-r--r--app/assets/stylesheets/framework/nav.scss109
-rw-r--r--app/assets/stylesheets/framework/page-header.scss5
-rw-r--r--app/assets/stylesheets/framework/panels.scss22
-rw-r--r--app/assets/stylesheets/framework/selects.scss4
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss23
-rw-r--r--app/assets/stylesheets/framework/snippets.scss (renamed from app/assets/stylesheets/pages/snippets.scss)10
-rw-r--r--app/assets/stylesheets/framework/tables.scss4
-rw-r--r--app/assets/stylesheets/framework/timeline.scss6
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap.scss4
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap_variables.scss19
-rw-r--r--app/assets/stylesheets/framework/typography.scss14
-rw-r--r--app/assets/stylesheets/framework/variables.scss128
-rw-r--r--app/assets/stylesheets/framework/wells.scss6
-rw-r--r--app/assets/stylesheets/framework/zen.scss4
-rw-r--r--app/assets/stylesheets/highlight/white.scss8
-rw-r--r--app/assets/stylesheets/mailers/highlighted_diff_email.scss6
-rw-r--r--app/assets/stylesheets/notify.scss12
-rw-r--r--app/assets/stylesheets/pages/boards.scss28
-rw-r--r--app/assets/stylesheets/pages/branches.scss55
-rw-r--r--app/assets/stylesheets/pages/builds.scss158
-rw-r--r--app/assets/stylesheets/pages/ci_projects.scss2
-rw-r--r--app/assets/stylesheets/pages/commit.scss132
-rw-r--r--app/assets/stylesheets/pages/commits.scss191
-rw-r--r--app/assets/stylesheets/pages/cycle_analytics.scss34
-rw-r--r--app/assets/stylesheets/pages/deploy_keys.scss13
-rw-r--r--app/assets/stylesheets/pages/detail_page.scss9
-rw-r--r--app/assets/stylesheets/pages/diff.scss14
-rw-r--r--app/assets/stylesheets/pages/editor.scss59
-rw-r--r--app/assets/stylesheets/pages/environments.scss33
-rw-r--r--app/assets/stylesheets/pages/events.scss4
-rw-r--r--app/assets/stylesheets/pages/explore.scss8
-rw-r--r--app/assets/stylesheets/pages/groups.scss8
-rw-r--r--app/assets/stylesheets/pages/help.scss2
-rw-r--r--app/assets/stylesheets/pages/issuable.scss188
-rw-r--r--app/assets/stylesheets/pages/issues.scss8
-rw-r--r--app/assets/stylesheets/pages/labels.scss10
-rw-r--r--app/assets/stylesheets/pages/lint.scss10
-rw-r--r--app/assets/stylesheets/pages/login.scss13
-rw-r--r--app/assets/stylesheets/pages/members.scss37
-rw-r--r--app/assets/stylesheets/pages/merge_conflicts.scss2
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss40
-rw-r--r--app/assets/stylesheets/pages/milestone.scss12
-rw-r--r--app/assets/stylesheets/pages/note_form.scss24
-rw-r--r--app/assets/stylesheets/pages/notes.scss70
-rw-r--r--app/assets/stylesheets/pages/notifications.scss14
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss794
-rw-r--r--app/assets/stylesheets/pages/profile.scss33
-rw-r--r--app/assets/stylesheets/pages/profiles/preferences.scss4
-rw-r--r--app/assets/stylesheets/pages/projects.scss121
-rw-r--r--app/assets/stylesheets/pages/search.scss20
-rw-r--r--app/assets/stylesheets/pages/settings.scss2
-rw-r--r--app/assets/stylesheets/pages/status.scss50
-rw-r--r--app/assets/stylesheets/pages/todos.scss2
-rw-r--r--app/assets/stylesheets/pages/tree.scss38
-rw-r--r--app/assets/stylesheets/pages/wiki.scss4
-rw-r--r--app/assets/stylesheets/pages/xterm.scss2
284 files changed, 6976 insertions, 1839 deletions
diff --git a/app/assets/images/auth_buttons/authentiq_64.png b/app/assets/images/auth_buttons/authentiq_64.png
new file mode 100644
index 00000000000..81767bbcc54
--- /dev/null
+++ b/app/assets/images/auth_buttons/authentiq_64.png
Binary files differ
diff --git a/app/assets/javascripts/abuse_reports.js.es6 b/app/assets/javascripts/abuse_reports.js.es6
index 82e526ae0ef..8a260aae1b1 100644
--- a/app/assets/javascripts/abuse_reports.js.es6
+++ b/app/assets/javascripts/abuse_reports.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable no-param-reassign */
+
((global) => {
const MAX_MESSAGE_LENGTH = 500;
const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js
index 31852e4750c..5a7d823e84c 100644
--- a/app/assets/javascripts/admin.js
+++ b/app/assets/javascripts/admin.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-arrow-callback, camelcase, quotes, comma-dangle, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-arrow-callback, camelcase, quotes, comma-dangle, padded-blocks, max-len */
+/* global Turbolinks */
+
(function() {
this.Admin = (function() {
function Admin() {
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 1c625e2f2b1..f60f27d1210 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -1,6 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, quotes, object-shorthand, camelcase, no-var, no-undef, comma-dangle, prefer-arrow-callback, indent, object-curly-spacing, quote-props, no-param-reassign, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, quotes, object-shorthand, camelcase, no-var, comma-dangle, prefer-arrow-callback, indent, object-curly-spacing, quote-props, no-param-reassign, padded-blocks, max-len */
+
(function() {
- this.Api = {
+ var Api = {
groupsPath: "/api/:version/groups.json",
groupPath: "/api/:version/groups/:id.json",
namespacesPath: "/api/:version/namespaces.json",
@@ -10,6 +11,7 @@
licensePath: "/api/:version/templates/licenses/:key",
gitignorePath: "/api/:version/templates/gitignores/:key",
gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key",
+ dockerfilePath: "/api/:version/dockerfiles/:key",
issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key",
group: function(group_id, callback) {
var url = Api.buildUrl(Api.groupPath)
@@ -119,6 +121,10 @@
return callback(file);
});
},
+ dockerfileYml: function(key, callback) {
+ var url = Api.buildUrl(Api.dockerfilePath).replace(':key', key);
+ $.get(url, callback);
+ },
issueTemplate: function(namespacePath, projectPath, key, type, callback) {
var url = Api.buildUrl(Api.issuableTemplatePath)
.replace(':key', key)
@@ -140,4 +146,5 @@
}
};
+ window.Api = Api;
}).call(this);
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index b7c4673c8e3..f0615481ed2 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -1,4 +1,11 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, no-undef, quotes, consistent-return, prefer-arrow-callback, comma-dangle, object-shorthand, no-new, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, quotes, consistent-return, prefer-arrow-callback, comma-dangle, object-shorthand, no-new, max-len */
+/* global bp */
+/* global Cookies */
+/* global Flash */
+/* global ConfirmDangerModal */
+/* global AwardsHandler */
+/* global Aside */
+
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
@@ -51,6 +58,7 @@
/*= require_directory ./extensions */
/*= require_directory ./lib/utils */
/*= require_directory ./u2f */
+/*= require_directory ./droplab */
/*= require_directory . */
/*= require fuzzaldrin-plus */
/*= require es6-promise.auto */
@@ -82,6 +90,14 @@
// Set the default path for all cookies to GitLab's root directory
Cookies.defaults.path = gon.relative_url_root || '/';
+ // `hashchange` is not triggered when link target is already in window.location
+ $body.on('click', 'a[href^="#"]', function() {
+ var href = this.getAttribute('href');
+ if (href.substr(1) === gl.utils.getLocationHash()) {
+ setTimeout(gl.utils.handleLocationHash, 1);
+ }
+ });
+
// prevent default action for disabled buttons
$('.btn').click(function(e) {
if ($(this).hasClass('disabled')) {
diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js
index f4302e2e9f6..107a7978a87 100644
--- a/app/assets/javascripts/awards_handler.js
+++ b/app/assets/javascripts/awards_handler.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, spaced-comment, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-template, quotes, comma-dangle, no-param-reassign, no-void, radix, keyword-spacing, space-before-blocks, brace-style, no-underscore-dangle, no-undef, no-plusplus, no-return-assign, camelcase, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, spaced-comment, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-template, quotes, comma-dangle, no-param-reassign, no-void, radix, keyword-spacing, space-before-blocks, brace-style, no-underscore-dangle, no-plusplus, no-return-assign, camelcase, padded-blocks */
+/* global Cookies */
+
(function() {
this.AwardsHandler = (function() {
var FROM_SENTENCE_REGEX = /(?:, and | and |, )/; //For separating lists produced by ruby's Array#toSentence
diff --git a/app/assets/javascripts/behaviors/autosize.js b/app/assets/javascripts/behaviors/autosize.js
index a5d62f881fe..c62a4c5a456 100644
--- a/app/assets/javascripts/behaviors/autosize.js
+++ b/app/assets/javascripts/behaviors/autosize.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, consistent-return, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, consistent-return, padded-blocks, max-len */
+/* global autosize */
/*= require jquery.ba-resize */
/*= require autosize */
diff --git a/app/assets/javascripts/behaviors/quick_submit.js b/app/assets/javascripts/behaviors/quick_submit.js
index 4edcaa15fe5..586f941a6e3 100644
--- a/app/assets/javascripts/behaviors/quick_submit.js
+++ b/app/assets/javascripts/behaviors/quick_submit.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-undef, prefer-arrow-callback, camelcase, max-len, consistent-return, quotes, object-shorthand, comma-dangle, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, prefer-arrow-callback, camelcase, consistent-return, quotes, object-shorthand, comma-dangle, padded-blocks, max-len */
+
// Quick Submit behavior
//
// When a child field of a form with a `js-quick-submit` class receives a
diff --git a/app/assets/javascripts/blob/blob_ci_yaml.js.es6 b/app/assets/javascripts/blob/blob_ci_yaml.js.es6
index 37531aaec9b..57bd13eecf8 100644
--- a/app/assets/javascripts/blob/blob_ci_yaml.js.es6
+++ b/app/assets/javascripts/blob/blob_ci_yaml.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable padded-blocks, no-param-reassign, comma-dangle */
+/* global Api */
+
/*= require blob/template_selector */
((global) => {
diff --git a/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 b/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6
new file mode 100644
index 00000000000..bdf95017613
--- /dev/null
+++ b/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6
@@ -0,0 +1,18 @@
+/* global Api */
+/*= require blob/template_selector */
+
+(() => {
+ const global = window.gl || (window.gl = {});
+
+ class BlobDockerfileSelector extends gl.TemplateSelector {
+ requestFile(query) {
+ return Api.dockerfileYml(query.name, this.requestFileSuccess.bind(this));
+ }
+
+ requestFileSuccess(file) {
+ return super.requestFileSuccess(file);
+ }
+ }
+
+ global.BlobDockerfileSelector = BlobDockerfileSelector;
+})();
diff --git a/app/assets/javascripts/blob/blob_dockerfile_selectors.js.es6 b/app/assets/javascripts/blob/blob_dockerfile_selectors.js.es6
new file mode 100644
index 00000000000..9cee79fa5d5
--- /dev/null
+++ b/app/assets/javascripts/blob/blob_dockerfile_selectors.js.es6
@@ -0,0 +1,27 @@
+(() => {
+ const global = window.gl || (window.gl = {});
+
+ class BlobDockerfileSelectors {
+ constructor({ editor, $dropdowns } = {}) {
+ this.editor = editor;
+ this.$dropdowns = $dropdowns || $('.js-dockerfile-selector');
+ this.initSelectors();
+ }
+
+ initSelectors() {
+ const editor = this.editor;
+ this.$dropdowns.each((i, dropdown) => {
+ const $dropdown = $(dropdown);
+ return new gl.BlobDockerfileSelector({
+ editor,
+ pattern: /(Dockerfile)/,
+ data: $dropdown.data('data'),
+ wrapper: $dropdown.closest('.js-dockerfile-selector-wrap'),
+ dropdown: $dropdown,
+ });
+ });
+ }
+ }
+
+ global.BlobDockerfileSelectors = BlobDockerfileSelectors;
+})();
diff --git a/app/assets/javascripts/blob/blob_file_dropzone.js b/app/assets/javascripts/blob/blob_file_dropzone.js
index e0a2e8ac12e..eab686c45c3 100644
--- a/app/assets/javascripts/blob/blob_file_dropzone.js
+++ b/app/assets/javascripts/blob/blob_file_dropzone.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, camelcase, no-undef, object-shorthand, quotes, comma-dangle, prefer-arrow-callback, no-unused-vars, prefer-template, no-useless-escape, no-alert, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, camelcase, object-shorthand, quotes, comma-dangle, prefer-arrow-callback, no-unused-vars, prefer-template, no-useless-escape, no-alert, padded-blocks, max-len */
+/* global Dropzone */
+
(function() {
this.BlobFileDropzone = (function() {
function BlobFileDropzone(form, method) {
diff --git a/app/assets/javascripts/blob/blob_gitignore_selector.js b/app/assets/javascripts/blob/blob_gitignore_selector.js
index 7e8f1062ab3..15563e429a0 100644
--- a/app/assets/javascripts/blob/blob_gitignore_selector.js
+++ b/app/assets/javascripts/blob/blob_gitignore_selector.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, padded-blocks */
+/* global Api */
/*= require blob/template_selector */
diff --git a/app/assets/javascripts/blob/blob_gitignore_selectors.js b/app/assets/javascripts/blob/blob_gitignore_selectors.js
index 9a694daa010..d7f95093688 100644
--- a/app/assets/javascripts/blob/blob_gitignore_selectors.js
+++ b/app/assets/javascripts/blob/blob_gitignore_selectors.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-cond-assign, no-sequences, no-undef, comma-dangle, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-cond-assign, no-sequences, comma-dangle, padded-blocks, max-len */
+/* global BlobGitignoreSelector */
+
(function() {
this.BlobGitignoreSelectors = (function() {
function BlobGitignoreSelectors(opts) {
diff --git a/app/assets/javascripts/blob/blob_license_selector.js b/app/assets/javascripts/blob/blob_license_selector.js
index 9a77fe35d55..d9c6f65a083 100644
--- a/app/assets/javascripts/blob/blob_license_selector.js
+++ b/app/assets/javascripts/blob/blob_license_selector.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, comma-dangle, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, comma-dangle, padded-blocks */
+/* global Api */
/*= require blob/template_selector */
diff --git a/app/assets/javascripts/blob/blob_license_selectors.js.es6 b/app/assets/javascripts/blob/blob_license_selectors.js.es6
index adeb8ba1318..268640681d4 100644
--- a/app/assets/javascripts/blob/blob_license_selectors.js.es6
+++ b/app/assets/javascripts/blob/blob_license_selectors.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable no-unused-vars, no-param-reassign, padded-blocks */
+/* global BlobLicenseSelector */
+
((global) => {
class BlobLicenseSelectors {
constructor({ $dropdowns, editor }) {
diff --git a/app/assets/javascripts/blob/template_selector.js.es6 b/app/assets/javascripts/blob/template_selector.js.es6
index 0ff5c0fab05..7a1ee9998c8 100644
--- a/app/assets/javascripts/blob/template_selector.js.es6
+++ b/app/assets/javascripts/blob/template_selector.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable indent, comma-dangle, object-shorthand, func-names, space-before-function-paren, arrow-parens, no-unused-vars, class-methods-use-this, no-var, consistent-return, prefer-const, no-param-reassign, space-in-parens, max-len */
+
((global) => {
class TemplateSelector {
constructor({ dropdown, data, pattern, wrapper, editor, fileEndpoint, $input } = {}) {
diff --git a/app/assets/javascripts/blob_edit/blob_edit_bundle.js b/app/assets/javascripts/blob_edit/blob_edit_bundle.js
index b8eb0f60a8e..8c40e36a80a 100644
--- a/app/assets/javascripts/blob_edit/blob_edit_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_edit_bundle.js
@@ -1,4 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-undef, no-new, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-new, padded-blocks, max-len */
+/* global EditBlob */
+/* global NewCommitForm */
+
/*= require_tree . */
(function() {
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index 0c74aaaa852..fa43ff611cc 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -1,4 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, camelcase, no-param-reassign, no-undef, quotes, prefer-template, no-new, comma-dangle, one-var, one-var-declaration-per-line, prefer-arrow-callback, no-else-return, no-unused-vars, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, camelcase, no-param-reassign, quotes, prefer-template, no-new, comma-dangle, one-var, one-var-declaration-per-line, prefer-arrow-callback, no-else-return, no-unused-vars, padded-blocks, max-len */
+/* global ace */
+/* global BlobGitignoreSelectors */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
@@ -33,6 +36,9 @@
new gl.BlobCiYamlSelectors({
editor: this.editor
});
+ new gl.BlobDockerfileSelectors({
+ editor: this.editor
+ });
}
EditBlob.prototype.initModePanesAndLinks = function() {
@@ -57,7 +63,7 @@
content: this.editor.getValue()
}, function(response) {
currentPane.empty().append(response);
- return currentPane.syntaxHighlight();
+ return currentPane.renderGFM();
});
} else {
this.$toggleButton.show();
diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js.es6
index 7ba918a05f8..2c9ab61c94d 100644
--- a/app/assets/javascripts/boards/boards_bundle.js.es6
+++ b/app/assets/javascripts/boards/boards_bundle.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable one-var, indent, quote-props, comma-dangle, space-before-function-paren */
+/* global Vue */
+/* global BoardService */
+
//= require vue
//= require vue-resource
//= require Sortable
@@ -70,7 +73,7 @@ $(() => {
});
gl.IssueBoardsSearch = new Vue({
- el: '#js-boards-seach',
+ el: '#js-boards-search',
data: {
filters: Store.state.filters
},
diff --git a/app/assets/javascripts/boards/components/board.js.es6 b/app/assets/javascripts/boards/components/board.js.es6
index 31de3b25284..8d1a0f482f9 100644
--- a/app/assets/javascripts/boards/components/board.js.es6
+++ b/app/assets/javascripts/boards/components/board.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, space-before-function-paren, one-var, indent, radix */
+/* global Vue */
+/* global Sortable */
+
//= require ./board_blank_state
//= require ./board_delete
//= require ./board_list
@@ -42,14 +45,28 @@
const issue = this.list.findIssue(this.detailIssue.issue.id);
if (issue) {
+ const offsetLeft = this.$el.offsetLeft;
const boardsList = document.querySelectorAll('.boards-list')[0];
- const right = (this.$el.offsetLeft + this.$el.offsetWidth) - boardsList.offsetWidth;
- const left = boardsList.scrollLeft - this.$el.offsetLeft;
+ const left = boardsList.scrollLeft - offsetLeft;
+ let right = (offsetLeft + this.$el.offsetWidth);
+
+ if (window.innerWidth > 768 && boardsList.classList.contains('is-compact')) {
+ // -290 here because width of boardsList is animating so therefore
+ // getting the width here is incorrect
+ // 290 is the width of the sidebar
+ right -= (boardsList.offsetWidth - 290);
+ } else {
+ right -= boardsList.offsetWidth;
+ }
if (right - boardsList.scrollLeft > 0) {
- boardsList.scrollLeft = right;
+ $(boardsList).animate({
+ scrollLeft: right
+ }, this.sortableOptions.animation);
} else if (left > 0) {
- boardsList.scrollLeft = this.$el.offsetLeft;
+ $(boardsList).animate({
+ scrollLeft: offsetLeft
+ }, this.sortableOptions.animation);
}
}
},
@@ -62,7 +79,7 @@
}
},
mounted () {
- const options = gl.issueBoards.getBoardSortableDefaultOptions({
+ this.sortableOptions = gl.issueBoards.getBoardSortableDefaultOptions({
disabled: this.disabled,
group: 'boards',
draggable: '.is-draggable',
@@ -81,7 +98,7 @@
}
});
- this.sortable = Sortable.create(this.$el.parentNode, options);
+ this.sortable = Sortable.create(this.$el.parentNode, this.sortableOptions);
},
});
})();
diff --git a/app/assets/javascripts/boards/components/board_blank_state.js.es6 b/app/assets/javascripts/boards/components/board_blank_state.js.es6
index 691487b272a..0a47a22fad2 100644
--- a/app/assets/javascripts/boards/components/board_blank_state.js.es6
+++ b/app/assets/javascripts/boards/components/board_blank_state.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable space-before-function-paren, comma-dangle, semi */
+/* global Vue */
+/* global ListLabel */
+
(() => {
const Store = gl.issueBoards.BoardsStore;
diff --git a/app/assets/javascripts/boards/components/board_card.js.es6 b/app/assets/javascripts/boards/components/board_card.js.es6
index 2299dafd217..5fc50280811 100644
--- a/app/assets/javascripts/boards/components/board_card.js.es6
+++ b/app/assets/javascripts/boards/components/board_card.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, space-before-function-paren, dot-notation */
+/* global Vue */
+
(() => {
const Store = gl.issueBoards.BoardsStore;
diff --git a/app/assets/javascripts/boards/components/board_delete.js.es6 b/app/assets/javascripts/boards/components/board_delete.js.es6
index c45e1926c5c..861600424a5 100644
--- a/app/assets/javascripts/boards/components/board_delete.js.es6
+++ b/app/assets/javascripts/boards/components/board_delete.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, space-before-function-paren, no-alert */
+/* global Vue */
+
(() => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
diff --git a/app/assets/javascripts/boards/components/board_list.js.es6 b/app/assets/javascripts/boards/components/board_list.js.es6
index 43ebeef39c4..6711930622b 100644
--- a/app/assets/javascripts/boards/components/board_list.js.es6
+++ b/app/assets/javascripts/boards/components/board_list.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, space-before-function-paren, max-len, no-plusplus */
+/* global Vue */
+/* global Sortable */
+
//= require ./board_card
//= require ./board_new_issue
diff --git a/app/assets/javascripts/boards/components/board_new_issue.js.es6 b/app/assets/javascripts/boards/components/board_new_issue.js.es6
index a7989a2ff4c..2386d3a613c 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.js.es6
+++ b/app/assets/javascripts/boards/components/board_new_issue.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, no-unused-vars */
+/* global Vue */
+/* global ListIssue */
+
(() => {
const Store = gl.issueBoards.BoardsStore;
diff --git a/app/assets/javascripts/boards/components/board_sidebar.js.es6 b/app/assets/javascripts/boards/components/board_sidebar.js.es6
index 1644a772737..02459722bbf 100644
--- a/app/assets/javascripts/boards/components/board_sidebar.js.es6
+++ b/app/assets/javascripts/boards/components/board_sidebar.js.es6
@@ -1,4 +1,10 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, space-before-function-paren, no-new */
+/* global Vue */
+/* global IssuableContext */
+/* global MilestoneSelect */
+/* global LabelsSelect */
+/* global Sidebar */
+
(() => {
const Store = gl.issueBoards.BoardsStore;
diff --git a/app/assets/javascripts/boards/components/new_list_dropdown.js.es6 b/app/assets/javascripts/boards/components/new_list_dropdown.js.es6
index 10ce746deb5..3f5cf8420a8 100644
--- a/app/assets/javascripts/boards/components/new_list_dropdown.js.es6
+++ b/app/assets/javascripts/boards/components/new_list_dropdown.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, func-names, no-new, space-before-function-paren, one-var, indent */
+
(() => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
@@ -45,10 +46,10 @@
return $li.append($a.prepend($labelColor));
},
- search: {
- fields: ['title']
- },
- filterable: true,
+ search: {
+ fields: ['title']
+ },
+ filterable: true,
selectable: true,
multiSelect: true,
clicked (label, $el, e) {
diff --git a/app/assets/javascripts/boards/filters/due_date_filters.js.es6 b/app/assets/javascripts/boards/filters/due_date_filters.js.es6
index 9eceac4eddd..7e192e90fe6 100644
--- a/app/assets/javascripts/boards/filters/due_date_filters.js.es6
+++ b/app/assets/javascripts/boards/filters/due_date_filters.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* global Vue */
+
Vue.filter('due-date', (value) => {
const date = new Date(value);
return $.datepicker.formatDate('M d, yy', date);
diff --git a/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6 b/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6
index 5f99de39122..d5859444a32 100644
--- a/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6
+++ b/app/assets/javascripts/boards/mixins/sortable_default_options.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable no-unused-vars, no-mixed-operators, prefer-const, comma-dangle, semi */
+/* global DocumentTouch */
+
((w) => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
@@ -18,6 +20,7 @@
gl.issueBoards.getBoardSortableDefaultOptions = (obj) => {
let defaultSortOptions = {
+ animation: 200,
forceFallback: true,
fallbackClass: 'is-dragging',
fallbackOnBody: true,
diff --git a/app/assets/javascripts/boards/models/issue.js.es6 b/app/assets/javascripts/boards/models/issue.js.es6
index 21d735e8231..cd942c8332b 100644
--- a/app/assets/javascripts/boards/models/issue.js.es6
+++ b/app/assets/javascripts/boards/models/issue.js.es6
@@ -1,4 +1,9 @@
-/* eslint-disable */
+/* eslint-disable no-unused-vars, space-before-function-paren, arrow-body-style, space-in-parens, arrow-parens, comma-dangle, max-len */
+/* global Vue */
+/* global ListLabel */
+/* global ListMilestone */
+/* global ListUser */
+
class ListIssue {
constructor (obj) {
this.id = obj.iid;
@@ -66,3 +71,5 @@ class ListIssue {
return Vue.http.patch(url, data);
}
}
+
+window.ListIssue = ListIssue;
diff --git a/app/assets/javascripts/boards/models/label.js.es6 b/app/assets/javascripts/boards/models/label.js.es6
index 0910fe9a854..9af88d167d6 100644
--- a/app/assets/javascripts/boards/models/label.js.es6
+++ b/app/assets/javascripts/boards/models/label.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable no-unused-vars, space-before-function-paren */
+
class ListLabel {
constructor (obj) {
this.id = obj.id;
@@ -9,3 +10,5 @@ class ListLabel {
this.priority = (obj.priority !== null) ? obj.priority : Infinity;
}
}
+
+window.ListLabel = ListLabel;
diff --git a/app/assets/javascripts/boards/models/list.js.es6 b/app/assets/javascripts/boards/models/list.js.es6
index 429bd27c3fb..fb13f529b11 100644
--- a/app/assets/javascripts/boards/models/list.js.es6
+++ b/app/assets/javascripts/boards/models/list.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable space-before-function-paren, no-underscore-dangle, class-methods-use-this, consistent-return, no-plusplus, prefer-const, space-in-parens, no-shadow, no-param-reassign, max-len, no-unused-vars */
+/* global ListIssue */
+/* global ListLabel */
+
class List {
constructor (obj) {
this.id = obj.id;
@@ -145,3 +148,5 @@ class List {
});
}
}
+
+window.List = List;
diff --git a/app/assets/javascripts/boards/models/milestone.js.es6 b/app/assets/javascripts/boards/models/milestone.js.es6
index a48969e19c9..c867b06d320 100644
--- a/app/assets/javascripts/boards/models/milestone.js.es6
+++ b/app/assets/javascripts/boards/models/milestone.js.es6
@@ -1,7 +1,10 @@
-/* eslint-disable */
+/* eslint-disable no-unused-vars */
+
class ListMilestone {
- constructor (obj) {
+ constructor(obj) {
this.id = obj.id;
this.title = obj.title;
}
}
+
+window.ListMilestone = ListMilestone;
diff --git a/app/assets/javascripts/boards/models/user.js.es6 b/app/assets/javascripts/boards/models/user.js.es6
index 583a973fc46..8e9de4d4cbb 100644
--- a/app/assets/javascripts/boards/models/user.js.es6
+++ b/app/assets/javascripts/boards/models/user.js.es6
@@ -1,9 +1,12 @@
-/* eslint-disable */
+/* eslint-disable no-unused-vars */
+
class ListUser {
- constructor (user) {
+ constructor(user) {
this.id = user.id;
this.name = user.name;
this.username = user.username;
this.avatar = user.avatar_url;
}
}
+
+window.ListUser = ListUser;
diff --git a/app/assets/javascripts/boards/services/board_service.js.es6 b/app/assets/javascripts/boards/services/board_service.js.es6
index f59a2ed7937..f18633f0913 100644
--- a/app/assets/javascripts/boards/services/board_service.js.es6
+++ b/app/assets/javascripts/boards/services/board_service.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable space-before-function-paren, comma-dangle, no-param-reassign, camelcase, prefer-const, no-extra-semi, max-len, no-unused-vars */
+/* global Vue */
+
class BoardService {
constructor (root, boardId) {
this.lists = Vue.resource(`${root}/${boardId}/lists{/id}`, {}, {
@@ -63,4 +65,6 @@ class BoardService {
issue
});
}
-};
+}
+
+window.BoardService = BoardService;
diff --git a/app/assets/javascripts/boards/stores/boards_store.js.es6 b/app/assets/javascripts/boards/stores/boards_store.js.es6
index bb2a4de8b18..e7a14ea5bca 100644
--- a/app/assets/javascripts/boards/stores/boards_store.js.es6
+++ b/app/assets/javascripts/boards/stores/boards_store.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, space-before-function-paren, one-var, indent, space-in-parens, no-shadow, radix, dot-notation, semi, max-len */
+/* global Cookies */
+/* global List */
+
(() => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
diff --git a/app/assets/javascripts/boards/vue_resource_interceptor.js.es6 b/app/assets/javascripts/boards/vue_resource_interceptor.js.es6
index 80f137ca12e..3723a2039f9 100644
--- a/app/assets/javascripts/boards/vue_resource_interceptor.js.es6
+++ b/app/assets/javascripts/boards/vue_resource_interceptor.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable func-names, prefer-arrow-callback, no-unused-vars, no-plusplus */
+/* global Vue */
+
Vue.http.interceptors.push((request, next) => {
Vue.activeResources = Vue.activeResources ? Vue.activeResources + 1 : 1;
diff --git a/app/assets/javascripts/breakpoints.js b/app/assets/javascripts/breakpoints.js
index e7ceb602601..a7e72430141 100644
--- a/app/assets/javascripts/breakpoints.js
+++ b/app/assets/javascripts/breakpoints.js
@@ -1,6 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, quotes, no-shadow, prefer-arrow-callback, prefer-template, consistent-return, padded-blocks, no-return-assign, new-parens, no-param-reassign, no-undef, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, quotes, no-shadow, prefer-arrow-callback, prefer-template, consistent-return, padded-blocks, no-return-assign, new-parens, no-param-reassign, max-len */
+
(function() {
- this.Breakpoints = (function() {
+ var Breakpoints = (function() {
var BreakpointInstance, instance;
function Breakpoints() {}
@@ -68,4 +69,5 @@
};
})(this));
+ window.Breakpoints = Breakpoints;
}).call(this);
diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js
index 116a47b0907..fca47002870 100644
--- a/app/assets/javascripts/build.js
+++ b/app/assets/javascripts/build.js
@@ -1,6 +1,11 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, no-param-reassign, no-undef, quotes, yoda, no-else-return, consistent-return, comma-dangle, semi, object-shorthand, prefer-template, one-var, one-var-declaration-per-line, no-unused-vars, max-len, vars-on-top, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, no-param-reassign, quotes, yoda, no-else-return, consistent-return, comma-dangle, semi, object-shorthand, prefer-template, one-var, one-var-declaration-per-line, no-unused-vars, max-len, vars-on-top, padded-blocks */
+/* global Breakpoints */
+/* global Turbolinks */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+ var AUTO_SCROLL_OFFSET = 75;
+ var DOWN_BUILD_TRACE = '#down-build-trace';
this.Build = (function() {
Build.interval = null;
@@ -16,6 +21,17 @@
this.buildStage = options.buildStage;
this.updateDropdown = bind(this.updateDropdown, this);
this.$document = $(document);
+ this.$body = $('body');
+ this.$buildTrace = $('#build-trace');
+ this.$autoScrollContainer = $('.autoscroll-container');
+ this.$autoScrollStatus = $('#autoscroll-status');
+ this.$autoScrollStatusText = this.$autoScrollStatus.find('.status-text');
+ this.$upBuildTrace = $('#up-build-trace');
+ this.$downBuildTrace = $(DOWN_BUILD_TRACE);
+ this.$scrollTopBtn = $('#scroll-top');
+ this.$scrollBottomBtn = $('#scroll-bottom');
+ this.$buildRefreshAnimation = $('.js-build-refresh');
+
clearInterval(Build.interval);
// Init breakpoint checker
this.bp = Breakpoints.get();
@@ -29,6 +45,7 @@
this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this));
this.$document.off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
+ this.$document.on('scroll', this.initScrollMonitor.bind(this));
$(window).off('resize.build').on('resize.build', this.sidebarOnResize.bind(this));
$('a', this.$buildScroll).off('click.stepTrace').on('click.stepTrace', this.stepTrace);
this.updateArtifactRemoveDate();
@@ -37,18 +54,6 @@
this.initScrollButtonAffix();
}
if (this.buildStatus === "running" || this.buildStatus === "pending") {
- // Bind autoscroll button to follow build output
- $('#autoscroll-button').on('click', function() {
- var state;
- state = $(this).data("state");
- if ("enabled" === state) {
- $(this).data("state", "disabled");
- return $(this).text("Enable autoscroll");
- } else {
- $(this).data("state", "enabled");
- return $(this).text("Disable autoscroll");
- }
- });
Build.interval = setInterval((function(_this) {
// Check for new build output if user still watching build page
// Only valid for runnig build when output changes during time
@@ -87,10 +92,14 @@
dataType: 'json',
success: function(buildData) {
$('.js-build-output').html(buildData.trace_html);
+ if (window.location.hash === DOWN_BUILD_TRACE) {
+ $("html,body").scrollTop(this.$buildTrace.height());
+ }
if (removeRefreshStatuses.indexOf(buildData.status) >= 0) {
- return $('.js-build-refresh').remove();
+ this.$buildRefreshAnimation.remove();
+ return this.initScrollMonitor();
}
- }
+ }.bind(this)
});
};
@@ -100,6 +109,8 @@
dataType: "json",
success: (function(_this) {
return function(log) {
+ var pageUrl;
+
if (log.state) {
_this.state = log.state;
}
@@ -111,7 +122,12 @@
}
return _this.checkAutoscroll();
} else if (log.status !== _this.buildStatus) {
- return Turbolinks.visit(_this.pageUrl);
+ pageUrl = _this.pageUrl;
+ if (_this.$autoScrollStatus.data('state') === 'enabled') {
+ pageUrl += DOWN_BUILD_TRACE;
+ }
+
+ return Turbolinks.visit(pageUrl);
}
};
})(this)
@@ -119,22 +135,95 @@
};
Build.prototype.checkAutoscroll = function() {
- if ("enabled" === $("#autoscroll-button").data("state")) {
- return $("html,body").scrollTop($("#build-trace").height());
+ if (this.$autoScrollStatus.data("state") === "enabled") {
+ return $("html,body").scrollTop(this.$buildTrace.height());
+ }
+
+ // Handle a situation where user started new build
+ // but never scrolled a page
+ if (!this.$scrollTopBtn.is(':visible') &&
+ !this.$scrollBottomBtn.is(':visible') &&
+ !gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
+ this.$scrollBottomBtn.show();
}
};
Build.prototype.initScrollButtonAffix = function() {
- var $body, $buildTrace;
- $body = $('body');
- $buildTrace = $('#build-trace');
- return this.$buildScroll.affix({
- offset: {
- bottom: function() {
- return $body.outerHeight() - ($buildTrace.outerHeight() + $buildTrace.offset().top);
- }
+ // Hide everything initially
+ this.$scrollTopBtn.hide();
+ this.$scrollBottomBtn.hide();
+ this.$autoScrollContainer.hide();
+ }
+
+ // Page scroll listener to detect if user has scrolling page
+ // and handle following cases
+ // 1) User is at Top of Build Log;
+ // - Hide Top Arrow button
+ // - Show Bottom Arrow button
+ // - Disable Autoscroll and hide indicator (when build is running)
+ // 2) User is at Bottom of Build Log;
+ // - Show Top Arrow button
+ // - Hide Bottom Arrow button
+ // - Enable Autoscroll and show indicator (when build is running)
+ // 3) User is somewhere in middle of Build Log;
+ // - Show Top Arrow button
+ // - Show Bottom Arrow button
+ // - Disable Autoscroll and hide indicator (when build is running)
+ Build.prototype.initScrollMonitor = function() {
+ if (!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
+ // User is somewhere in middle of Build Log
+
+ this.$scrollTopBtn.show();
+
+ if (this.buildStatus === 'success' || this.buildStatus === 'failed') { // Check if Build is completed
+ this.$scrollBottomBtn.show();
+ } else if (this.$buildRefreshAnimation.is(':visible') && !gl.utils.isInViewport(this.$buildRefreshAnimation.get(0))) {
+ this.$scrollBottomBtn.show();
+ } else {
+ this.$scrollBottomBtn.hide();
}
- });
+
+ // Hide Autoscroll Status Indicator
+ if (this.$scrollBottomBtn.is(':visible')) {
+ this.$autoScrollContainer.hide();
+ this.$autoScrollStatusText.removeClass('animate');
+ } else {
+ this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show();
+ this.$autoScrollStatusText.addClass('animate');
+ }
+ } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && !gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
+ // User is at Top of Build Log
+
+ this.$scrollTopBtn.hide();
+ this.$scrollBottomBtn.show();
+
+ this.$autoScrollContainer.hide();
+ this.$autoScrollStatusText.removeClass('animate');
+ } else if ((!gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) ||
+ (this.$buildRefreshAnimation.is(':visible') && gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)))) {
+ // User is at Bottom of Build Log
+
+ this.$scrollTopBtn.show();
+ this.$scrollBottomBtn.hide();
+
+ // Show and Reposition Autoscroll Status Indicator
+ this.$autoScrollContainer.css({ top: this.$body.outerHeight() - AUTO_SCROLL_OFFSET }).show();
+ this.$autoScrollStatusText.addClass('animate');
+ } else if (gl.utils.isInViewport(this.$upBuildTrace.get(0)) && gl.utils.isInViewport(this.$downBuildTrace.get(0))) {
+ // Build Log height is small
+
+ this.$scrollTopBtn.hide();
+ this.$scrollBottomBtn.hide();
+
+ // Hide Autoscroll Status Indicator
+ this.$autoScrollContainer.hide();
+ this.$autoScrollStatusText.removeClass('animate');
+ }
+
+ if (this.buildStatus === "running" || this.buildStatus === "pending") {
+ // Check if Refresh Animation is in Viewport and enable Autoscroll, disable otherwise.
+ this.$autoScrollStatus.data("state", gl.utils.isInViewport(this.$buildRefreshAnimation.get(0)) ? 'enabled' : 'disabled');
+ }
};
Build.prototype.shouldHideSidebarForViewport = function() {
@@ -193,6 +282,7 @@
};
Build.prototype.stepTrace = function(e) {
+ var $currentTarget;
e.preventDefault();
$currentTarget = $(e.currentTarget);
$.scrollTo($currentTarget.attr('href'), {
diff --git a/app/assets/javascripts/build_variables.js.es6 b/app/assets/javascripts/build_variables.js.es6
index 0ecd20bc11e..993424d422f 100644
--- a/app/assets/javascripts/build_variables.js.es6
+++ b/app/assets/javascripts/build_variables.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable func-names, prefer-arrow-callback, space-before-blocks, space-before-function-paren, comma-spacing, max-len */
+
$(function(){
$('.reveal-variables').off('click').on('click',function(){
$('.js-build').toggle().niceScroll();
diff --git a/app/assets/javascripts/ci_lint_editor.js.es6 b/app/assets/javascripts/ci_lint_editor.js.es6
new file mode 100644
index 00000000000..56ffaa765a8
--- /dev/null
+++ b/app/assets/javascripts/ci_lint_editor.js.es6
@@ -0,0 +1,18 @@
+(() => {
+ window.gl = window.gl || {};
+
+ class CILintEditor {
+ constructor() {
+ this.editor = window.ace.edit('ci-editor');
+ this.textarea = document.querySelector('#content');
+
+ this.editor.getSession().setMode('ace/mode/yaml');
+ this.editor.on('input', () => {
+ const content = this.editor.getSession().getValue();
+ this.textarea.value = content;
+ });
+ }
+ }
+
+ gl.CILintEditor = CILintEditor;
+})();
diff --git a/app/assets/javascripts/commit.js b/app/assets/javascripts/commit.js
index 67509ea7d91..67b33a4d7ee 100644
--- a/app/assets/javascripts/commit.js
+++ b/app/assets/javascripts/commit.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-undef, padded-blocks */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, padded-blocks */
+/* global CommitFile */
+
(function() {
this.Commit = (function() {
function Commit() {
diff --git a/app/assets/javascripts/commit/file.js b/app/assets/javascripts/commit/file.js
index 600bac8834a..27512312c7c 100644
--- a/app/assets/javascripts/commit/file.js
+++ b/app/assets/javascripts/commit/file.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, padded-blocks */
+/* global ImageFile */
+
(function() {
this.CommitFile = (function() {
function CommitFile(file) {
diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js
index 3627aaf5080..24a6e4ff0e9 100644
--- a/app/assets/javascripts/commits.js
+++ b/app/assets/javascripts/commits.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, consistent-return, no-undef, no-return-assign, no-param-reassign, one-var, no-var, one-var-declaration-per-line, no-unused-vars, prefer-template, object-shorthand, comma-dangle, padded-blocks, max-len, prefer-arrow-callback */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, consistent-return, no-return-assign, no-param-reassign, one-var, no-var, one-var-declaration-per-line, no-unused-vars, prefer-template, object-shorthand, comma-dangle, padded-blocks, max-len, prefer-arrow-callback */
+/* global Pager */
+
(function() {
this.CommitsList = (function() {
function CommitsList() {}
@@ -6,8 +8,8 @@
CommitsList.timer = null;
CommitsList.init = function(limit) {
- $("body").on("click", ".day-commits-table li.commit", function(event) {
- if (event.target.nodeName !== "A") {
+ $("body").on("click", ".day-commits-table li.commit", function(e) {
+ if (e.target.nodeName !== "A") {
location.href = $(this).attr("url");
e.stopPropagation();
return false;
diff --git a/app/assets/javascripts/compare_autocomplete.js.es6 b/app/assets/javascripts/compare_autocomplete.js.es6
index bd980f87e72..251f2ded347 100644
--- a/app/assets/javascripts/compare_autocomplete.js.es6
+++ b/app/assets/javascripts/compare_autocomplete.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, object-shorthand, comma-dangle, prefer-arrow-callback, no-else-return, newline-per-chained-call, no-dupe-keys, wrap-iife, padded-blocks, max-len */
+
(function() {
this.CompareAutocomplete = (function() {
function CompareAutocomplete() {
@@ -54,6 +55,13 @@
$('.dropdown-toggle-text', $dropdown).text(text);
$dropdownContainer.removeClass('open');
});
+
+ $dropdownContainer.on('click', '.dropdown-content a', (e) => {
+ $dropdown.prop('title', e.target.text.replace(/_+?/g, '-'));
+ if ($dropdown.hasClass('has-tooltip')) {
+ $dropdown.tooltip('fixTitle');
+ }
+ });
});
};
diff --git a/app/assets/javascripts/copy_to_clipboard.js b/app/assets/javascripts/copy_to_clipboard.js
index efa228a75d9..6a13f38588d 100644
--- a/app/assets/javascripts/copy_to_clipboard.js
+++ b/app/assets/javascripts/copy_to_clipboard.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-undef, prefer-template, quotes, no-unused-vars, prefer-arrow-callback, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, prefer-arrow-callback, padded-blocks, max-len */
+/* global Clipboard */
/*= require clipboard */
diff --git a/app/assets/javascripts/create_label.js.es6 b/app/assets/javascripts/create_label.js.es6
index 744aa0afa03..947c129d5b5 100644
--- a/app/assets/javascripts/create_label.js.es6
+++ b/app/assets/javascripts/create_label.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, comma-dangle, prefer-template, quotes, no-param-reassign, wrap-iife, max-len */
+/* global Api */
+
(function (w) {
class CreateLabelDropdown {
constructor ($el, namespacePath, projectPath) {
diff --git a/app/assets/javascripts/diff.js.es6 b/app/assets/javascripts/diff.js.es6
index 9cf33e62958..5e1a4c948aa 100644
--- a/app/assets/javascripts/diff.js.es6
+++ b/app/assets/javascripts/diff.js.es6
@@ -20,7 +20,7 @@
.on('click', '.js-unfold', this.handleClickUnfold.bind(this))
.on('click', '.diff-line-num a', this.handleClickLineNum.bind(this));
- this.highlighSelectedLine();
+ this.openAnchoredDiff();
}
handleClickUnfold(e) {
@@ -61,13 +61,22 @@
$.get(link, params, response => $target.parent().replaceWith(response));
}
- openAnchoredDiff(anchoredDiff, cb) {
- const diffTitle = $(`#file-path-${anchoredDiff}`);
+ openAnchoredDiff(cb) {
+ const locationHash = gl.utils.getLocationHash();
+ const anchoredDiff = locationHash && locationHash.split('_')[0];
+
+ if (!anchoredDiff) return;
+
+ const diffTitle = $(`#${anchoredDiff}`);
const diffFile = diffTitle.closest('.diff-file');
const nothingHereBlock = $('.nothing-here-block:visible', diffFile);
if (nothingHereBlock.length) {
- diffFile.singleFileDiff(true, cb);
- } else {
+ const clickTarget = $('.file-title, .click-to-expand', diffFile);
+ diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => {
+ this.highlighSelectedLine();
+ if (cb) cb();
+ });
+ } else if (cb) {
cb();
}
}
diff --git a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es6 b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es6
index 52e2846d279..c59d3996fab 100644
--- a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es6
+++ b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, quotes, no-lonely-if, semi, max-len */
+/* global Vue */
+/* global CommentsStore */
+
(() => {
const CommentAndResolveBtn = Vue.extend({
props: {
diff --git a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es6 b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es6
index 983e554b9c1..f47867fc3b0 100644
--- a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es6
+++ b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js.es6
@@ -1,6 +1,10 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, one-var, indent, space-before-function-paren, no-plusplus, no-lonely-if, no-continue, brace-style, max-len, quotes, semi */
+/* global Vue */
+/* global DiscussionMixins */
+/* global CommentsStore */
+
(() => {
- JumpToDiscussion = Vue.extend({
+ const JumpToDiscussion = Vue.extend({
mixins: [DiscussionMixins],
props: {
discussionId: String
diff --git a/app/assets/javascripts/diff_notes/components/resolve_btn.js.es6 b/app/assets/javascripts/diff_notes/components/resolve_btn.js.es6
index 27af9fc96ad..5852b8bbdb7 100644
--- a/app/assets/javascripts/diff_notes/components/resolve_btn.js.es6
+++ b/app/assets/javascripts/diff_notes/components/resolve_btn.js.es6
@@ -1,4 +1,9 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, no-new, max-len */
+/* global Vue */
+/* global CommentsStore */
+/* global ResolveService */
+/* global Flash */
+
(() => {
const ResolveBtn = Vue.extend({
props: {
@@ -54,9 +59,11 @@
},
methods: {
updateTooltip: function () {
- $(this.$refs.button)
- .tooltip('hide')
- .tooltip('fixTitle');
+ this.$nextTick(() => {
+ $(this.$refs.button)
+ .tooltip('hide')
+ .tooltip('fixTitle');
+ });
},
resolve: function () {
if (!this.canResolve) return;
@@ -85,7 +92,7 @@
new Flash('An error occurred when trying to resolve a comment. Please try again.', 'alert');
}
- this.$nextTick(this.updateTooltip);
+ this.updateTooltip();
});
}
},
diff --git a/app/assets/javascripts/diff_notes/components/resolve_count.js.es6 b/app/assets/javascripts/diff_notes/components/resolve_count.js.es6
index 9522ccb49da..72cdae812bc 100644
--- a/app/assets/javascripts/diff_notes/components/resolve_count.js.es6
+++ b/app/assets/javascripts/diff_notes/components/resolve_count.js.es6
@@ -1,4 +1,8 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, object-shorthand, func-names, no-param-reassign */
+/* global Vue */
+/* global DiscussionMixins */
+/* global CommentsStore */
+
((w) => {
w.ResolveCount = Vue.extend({
mixins: [DiscussionMixins],
diff --git a/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es6 b/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es6
index b945a09fcbe..ee5f62b2d9e 100644
--- a/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es6
+++ b/app/assets/javascripts/diff_notes/components/resolve_discussion_btn.js.es6
@@ -1,4 +1,8 @@
-/* eslint-disable */
+/* eslint-disable object-shorthand, func-names, space-before-function-paren, comma-dangle, no-else-return, quotes, max-len */
+/* global Vue */
+/* global CommentsStore */
+/* global ResolveService */
+
(() => {
const ResolveDiscussionBtn = Vue.extend({
props: {
diff --git a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6
index bd4c20aed8b..1b3a57d0962 100644
--- a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6
+++ b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6
@@ -1,6 +1,7 @@
-/* eslint-disable */
-//= require vue
-//= require vue-resource
+/* eslint-disable func-names, comma-dangle, new-cap, no-new */
+/* global Vue */
+/* global ResolveCount */
+
//= require_directory ./models
//= require_directory ./stores
//= require_directory ./services
diff --git a/app/assets/javascripts/diff_notes/mixins/discussion.js.es6 b/app/assets/javascripts/diff_notes/mixins/discussion.js.es6
index 7a929017f36..a9ea18bf82b 100644
--- a/app/assets/javascripts/diff_notes/mixins/discussion.js.es6
+++ b/app/assets/javascripts/diff_notes/mixins/discussion.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable object-shorthand, func-names, guard-for-in, no-restricted-syntax, comma-dangle, no-plusplus, no-param-reassign, max-len */
+
((w) => {
w.DiscussionMixins = {
computed: {
diff --git a/app/assets/javascripts/diff_notes/models/discussion.js.es6 b/app/assets/javascripts/diff_notes/models/discussion.js.es6
index badcdccc840..fa518ba4d33 100644
--- a/app/assets/javascripts/diff_notes/models/discussion.js.es6
+++ b/app/assets/javascripts/diff_notes/models/discussion.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable space-before-function-paren, camelcase, guard-for-in, no-restricted-syntax, no-unused-vars, max-len */
+/* global Vue */
+/* global NoteModel */
+
class DiscussionModel {
constructor (discussionId) {
this.id = discussionId;
@@ -69,7 +72,7 @@ class DiscussionModel {
gl.utils.localTimeAgo($('.js-timeago', `${discussionSelector}`));
} else {
- $discussionHeadline.remove();
+ $discussionHeadline.remove();
}
}
@@ -89,3 +92,5 @@ class DiscussionModel {
return false;
}
}
+
+window.DiscussionModel = DiscussionModel;
diff --git a/app/assets/javascripts/diff_notes/models/note.js.es6 b/app/assets/javascripts/diff_notes/models/note.js.es6
index d0541b02632..f3a7cba5ef6 100644
--- a/app/assets/javascripts/diff_notes/models/note.js.es6
+++ b/app/assets/javascripts/diff_notes/models/note.js.es6
@@ -1,6 +1,7 @@
-/* eslint-disable */
+/* eslint-disable camelcase, no-unused-vars */
+
class NoteModel {
- constructor (discussionId, noteId, canResolve, resolved, resolved_by) {
+ constructor(discussionId, noteId, canResolve, resolved, resolved_by) {
this.discussionId = discussionId;
this.id = noteId;
this.canResolve = canResolve;
@@ -8,3 +9,5 @@ class NoteModel {
this.resolved_by = resolved_by;
}
}
+
+window.NoteModel = NoteModel;
diff --git a/app/assets/javascripts/diff_notes/services/resolve.js.es6 b/app/assets/javascripts/diff_notes/services/resolve.js.es6
index 86953ce7ffb..78c74985f78 100644
--- a/app/assets/javascripts/diff_notes/services/resolve.js.es6
+++ b/app/assets/javascripts/diff_notes/services/resolve.js.es6
@@ -1,4 +1,8 @@
-/* eslint-disable */
+/* eslint-disable class-methods-use-this, one-var, indent, camelcase, no-new, comma-dangle, semi, no-param-reassign, max-len */
+/* global Vue */
+/* global Flash */
+/* global CommentsStore */
+
((w) => {
class ResolveServiceClass {
constructor() {
diff --git a/app/assets/javascripts/diff_notes/stores/comments.js.es6 b/app/assets/javascripts/diff_notes/stores/comments.js.es6
index f42ca406bb1..1a7abbc6f75 100644
--- a/app/assets/javascripts/diff_notes/stores/comments.js.es6
+++ b/app/assets/javascripts/diff_notes/stores/comments.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable object-shorthand, func-names, camelcase, prefer-const, no-restricted-syntax, guard-for-in, comma-dangle, max-len, no-param-reassign */
+/* global Vue */
+/* global DiscussionModel */
+
((w) => {
w.CommentsStore = {
state: {},
diff --git a/app/assets/javascripts/dispatcher.js.es6 b/app/assets/javascripts/dispatcher.js.es6
index 413117c2226..99a34651639 100644
--- a/app/assets/javascripts/dispatcher.js.es6
+++ b/app/assets/javascripts/dispatcher.js.es6
@@ -1,4 +1,42 @@
-/* eslint-disable */
+/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len, padded-blocks */
+/* global UsernameValidator */
+/* global ActiveTabMemoizer */
+/* global ShortcutsNavigation */
+/* global Build */
+/* global Issuable */
+/* global Issue */
+/* global ShortcutsIssuable */
+/* global ZenMode */
+/* global Milestone */
+/* global GLForm */
+/* global IssuableForm */
+/* global LabelsSelect */
+/* global MilestoneSelect */
+/* global MergedButtons */
+/* global Commit */
+/* global NotificationsForm */
+/* global TreeView */
+/* global NotificationsDropdown */
+/* global UsersSelect */
+/* global GroupAvatar */
+/* global LineHighlighter */
+/* global ShortcutsBlob */
+/* global ProjectFork */
+/* global BuildArtifacts */
+/* global GroupsSelect */
+/* global Search */
+/* global Admin */
+/* global NamespaceSelects */
+/* global ShortcutsDashboardNavigation */
+/* global Project */
+/* global ProjectAvatar */
+/* global CompareAutocomplete */
+/* global ProjectNew */
+/* global Star */
+/* global ProjectShow */
+/* global Labels */
+/* global Shortcuts */
+
(function() {
var Dispatcher;
@@ -26,6 +64,17 @@
new UsernameValidator();
new ActiveTabMemoizer();
break;
+ case 'sessions:create':
+ if (!gon.u2f) break;
+ window.gl.u2fAuthenticate = new gl.U2FAuthenticate(
+ $("#js-authenticate-u2f"),
+ '#js-login-u2f-form',
+ gon.u2f,
+ document.querySelector('#js-login-2fa-device'),
+ document.querySelector('.js-2fa-form'),
+ );
+ window.gl.u2fAuthenticate.start();
+ break;
case 'projects:boards:show':
case 'projects:boards:index':
shortcut_handler = new ShortcutsNavigation();
@@ -35,8 +84,13 @@
break;
case 'projects:merge_requests:index':
case 'projects:issues:index':
+ if (gl.FilteredSearchManager) {
+ new gl.FilteredSearchManager();
+ }
Issuable.init();
- new gl.IssuableBulkActions();
+ new gl.IssuableBulkActions({
+ prefixId: page === 'projects:merge_requests:index' ? 'merge_request_' : 'issue_',
+ });
shortcut_handler = new ShortcutsNavigation();
break;
case 'projects:issues:show':
@@ -98,7 +152,6 @@
new MergedButtons();
break;
case 'projects:merge_requests:commits':
- case 'projects:merge_requests:builds':
new MergedButtons();
break;
case "projects:merge_requests:diffs":
@@ -106,10 +159,6 @@
new ZenMode();
new MergedButtons();
break;
- case 'projects:merge_requests:index':
- shortcut_handler = new ShortcutsNavigation();
- Issuable.init();
- break;
case 'dashboard:activity':
new gl.Activities();
break;
@@ -122,8 +171,10 @@
new ZenMode();
shortcut_handler = new ShortcutsNavigation();
break;
- case 'projects:commit:builds':
- new gl.Pipelines();
+ case 'projects:commit:pipelines':
+ new gl.MiniPipelineGraph({
+ container: '.js-pipeline-table',
+ });
break;
case 'projects:commits:show':
case 'projects:activity':
@@ -162,7 +213,9 @@
new gl.Members();
new UsersSelect();
break;
- case 'projects:project_members:index':
+ case 'projects:members:show':
+ new gl.MemberExpirationDate('.js-access-expiration-date-groups');
+ new GroupsSelect();
new gl.MemberExpirationDate();
new gl.Members();
new UsersSelect();
@@ -208,10 +261,6 @@
case 'projects:artifacts:browse':
new BuildArtifacts();
break;
- case 'projects:group_links:index':
- new gl.MemberExpirationDate();
- new GroupsSelect();
- break;
case 'search:show':
new Search();
break;
@@ -222,6 +271,10 @@
case 'projects:variables:index':
new gl.ProjectVariables();
break;
+ case 'ci:lints:create':
+ case 'ci:lints:show':
+ new gl.CILintEditor();
+ break;
}
switch (path.first()) {
case 'admin':
diff --git a/app/assets/javascripts/droplab/droplab.js b/app/assets/javascripts/droplab/droplab.js
new file mode 100644
index 00000000000..ed545ec8748
--- /dev/null
+++ b/app/assets/javascripts/droplab/droplab.js
@@ -0,0 +1,701 @@
+/* eslint-disable */
+// Determine where to place this
+if (typeof Object.assign != 'function') {
+ Object.assign = function (target, varArgs) { // .length of function is 2
+ 'use strict';
+ if (target == null) { // TypeError if undefined or null
+ throw new TypeError('Cannot convert undefined or null to object');
+ }
+
+ var to = Object(target);
+
+ for (var index = 1; index < arguments.length; index++) {
+ var nextSource = arguments[index];
+
+ if (nextSource != null) { // Skip over if undefined or null
+ for (var nextKey in nextSource) {
+ // Avoid bugs when hasOwnProperty is shadowed
+ if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
+ to[nextKey] = nextSource[nextKey];
+ }
+ }
+ }
+ }
+ return to;
+ };
+}
+
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.droplab = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+var DATA_TRIGGER = 'data-dropdown-trigger';
+var DATA_DROPDOWN = 'data-dropdown';
+
+module.exports = {
+ DATA_TRIGGER: DATA_TRIGGER,
+ DATA_DROPDOWN: DATA_DROPDOWN,
+}
+
+},{}],2:[function(require,module,exports){
+// Custom event support for IE
+if ( typeof CustomEvent === "function" ) {
+ module.exports = CustomEvent;
+} else {
+ require('./window')(function(w){
+ var CustomEvent = function ( event, params ) {
+ params = params || { bubbles: false, cancelable: false, detail: undefined };
+ var evt = document.createEvent( 'CustomEvent' );
+ evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
+ return evt;
+ }
+ CustomEvent.prototype = w.Event.prototype;
+
+ w.CustomEvent = CustomEvent;
+ });
+ module.exports = CustomEvent;
+}
+
+},{"./window":11}],3:[function(require,module,exports){
+var CustomEvent = require('./custom_event_polyfill');
+var utils = require('./utils');
+
+var DropDown = function(list) {
+ this.hidden = true;
+ this.list = list;
+ this.items = [];
+ this.getItems();
+ this.addEvents();
+ this.initialState = list.innerHTML;
+};
+
+Object.assign(DropDown.prototype, {
+ getItems: function() {
+ this.items = [].slice.call(this.list.querySelectorAll('li'));
+ return this.items;
+ },
+
+ clickEvent: function(e) {
+ // climb up the tree to find the LI
+ var selected = utils.closest(e.target, 'LI');
+
+ if(selected) {
+ e.preventDefault();
+ this.hide();
+ var listEvent = new CustomEvent('click.dl', {
+ detail: {
+ list: this,
+ selected: selected,
+ data: e.target.dataset,
+ },
+ });
+ this.list.dispatchEvent(listEvent);
+ }
+ },
+
+ addEvents: function() {
+ this.clickWrapper = this.clickEvent.bind(this);
+ // event delegation.
+ this.list.addEventListener('click', this.clickWrapper);
+ },
+
+ toggle: function() {
+ if(this.hidden) {
+ this.show();
+ } else {
+ this.hide();
+ }
+ },
+
+ setData: function(data) {
+ this.data = data;
+ this.render(data);
+ },
+
+ addData: function(data) {
+ this.data = (this.data || []).concat(data);
+ this.render(data);
+ },
+
+ // call render manually on data;
+ render: function(data){
+ // debugger
+ // empty the list first
+ var sampleItem;
+ var newChildren = [];
+ var toAppend;
+
+ for(var i = 0; i < this.items.length; i++) {
+ var item = this.items[i];
+ sampleItem = item;
+ if(item.parentNode && item.parentNode.dataset.hasOwnProperty('dynamic')) {
+ item.parentNode.removeChild(item);
+ }
+ }
+
+ newChildren = this.data.map(function(dat){
+ var html = utils.t(sampleItem.outerHTML, dat);
+ var template = document.createElement('div');
+ template.innerHTML = html;
+ // console.log(template.content)
+
+ // Help set the image src template
+ var imageTags = template.querySelectorAll('img[data-src]');
+ // debugger
+ for(var i = 0; i < imageTags.length; i++) {
+ var imageTag = imageTags[i];
+ imageTag.src = imageTag.getAttribute('data-src');
+ imageTag.removeAttribute('data-src');
+ }
+
+ if(dat.hasOwnProperty('droplab_hidden') && dat.droplab_hidden){
+ template.firstChild.style.display = 'none'
+ }else{
+ template.firstChild.style.display = 'block';
+ }
+ return template.firstChild.outerHTML;
+ });
+ toAppend = this.list.querySelector('ul[data-dynamic]');
+ if(toAppend) {
+ toAppend.innerHTML = newChildren.join('');
+ } else {
+ this.list.innerHTML = newChildren.join('');
+ }
+ },
+
+ show: function() {
+ // debugger
+ this.list.style.display = 'block';
+ this.hidden = false;
+ },
+
+ hide: function() {
+ // debugger
+ this.list.style.display = 'none';
+ this.hidden = true;
+ },
+
+ destroy: function() {
+ if (!this.hidden) {
+ this.hide();
+ }
+
+ this.list.removeEventListener('click', this.clickWrapper);
+ }
+});
+
+module.exports = DropDown;
+
+},{"./custom_event_polyfill":2,"./utils":10}],4:[function(require,module,exports){
+require('./window')(function(w){
+ module.exports = function(deps) {
+ deps = deps || {};
+ var window = deps.window || w;
+ var document = deps.document || window.document;
+ var CustomEvent = deps.CustomEvent || require('./custom_event_polyfill');
+ var HookButton = deps.HookButton || require('./hook_button');
+ var HookInput = deps.HookInput || require('./hook_input');
+ var utils = deps.utils || require('./utils');
+ var DATA_TRIGGER = require('./constants').DATA_TRIGGER;
+
+ var DropLab = function(hook){
+ if (!(this instanceof DropLab)) return new DropLab(hook);
+ this.ready = false;
+ this.hooks = [];
+ this.queuedData = [];
+ this.config = {};
+ this.loadWrapper;
+ if(typeof hook !== 'undefined'){
+ this.addHook(hook);
+ }
+ };
+
+
+ Object.assign(DropLab.prototype, {
+ load: function() {
+ this.loadWrapper();
+ },
+
+ loadWrapper: function(){
+ var dropdownTriggers = [].slice.apply(document.querySelectorAll('['+DATA_TRIGGER+']'));
+ this.addHooks(dropdownTriggers).init();
+ },
+
+ addData: function () {
+ var args = [].slice.apply(arguments);
+ this.applyArgs(args, '_addData');
+ },
+
+ setData: function() {
+ var args = [].slice.apply(arguments);
+ this.applyArgs(args, '_setData');
+ },
+
+ destroy: function() {
+ for(var i = 0; i < this.hooks.length; i++) {
+ this.hooks[i].destroy();
+ }
+ this.hooks = [];
+ this.removeEvents();
+ },
+
+ applyArgs: function(args, methodName) {
+ if(this.ready) {
+ this[methodName].apply(this, args);
+ } else {
+ this.queuedData = this.queuedData || [];
+ this.queuedData.push(args);
+ }
+ },
+
+ _addData: function(trigger, data) {
+ this._processData(trigger, data, 'addData');
+ },
+
+ _setData: function(trigger, data) {
+ this._processData(trigger, data, 'setData');
+ },
+
+ _processData: function(trigger, data, methodName) {
+ for(var i = 0; i < this.hooks.length; i++) {
+ var hook = this.hooks[i];
+ if(hook.trigger.dataset.hasOwnProperty('id')) {
+ if(hook.trigger.dataset.id === trigger) {
+ hook.list[methodName](data);
+ }
+ }
+ }
+ },
+
+ addEvents: function() {
+ var self = this;
+ this.windowClickedWrapper = function(e){
+ var thisTag = e.target;
+ if(thisTag.tagName !== 'UL'){
+ // climb up the tree to find the UL
+ thisTag = utils.closest(thisTag, 'UL');
+ }
+ if(utils.isDropDownParts(thisTag)){ return }
+ if(utils.isDropDownParts(e.target)){ return }
+ for(var i = 0; i < self.hooks.length; i++) {
+ self.hooks[i].list.hide();
+ }
+ }.bind(this);
+ w.addEventListener('click', this.windowClickedWrapper);
+ },
+
+ removeEvents: function(){
+ w.removeEventListener('click', this.windowClickedWrapper);
+ w.removeEventListener('load', this.loadWrapper);
+ },
+
+ changeHookList: function(trigger, list, plugins, config) {
+ trigger = document.querySelector('[data-id="'+trigger+'"]');
+ // list = document.querySelector(list);
+ this.hooks.every(function(hook, i) {
+ if(hook.trigger === trigger) {
+ hook.destroy();
+ this.hooks.splice(i, 1);
+ this.addHook(trigger, list, plugins, config);
+ return false;
+ }
+ return true
+ }.bind(this));
+ },
+
+ addHook: function(hook, list, plugins, config) {
+ if(!(hook instanceof HTMLElement) && typeof hook === 'string'){
+ hook = document.querySelector(hook);
+ }
+ if(!list){
+ list = document.querySelector(hook.dataset[utils.toDataCamelCase(DATA_TRIGGER)]);
+ }
+
+ if(hook) {
+ if(hook.tagName === 'A' || hook.tagName === 'BUTTON') {
+ this.hooks.push(new HookButton(hook, list, plugins, config));
+ } else if(hook.tagName === 'INPUT') {
+ this.hooks.push(new HookInput(hook, list, plugins, config));
+ }
+ }
+ return this;
+ },
+
+ addHooks: function(hooks, plugins, config) {
+ for(var i = 0; i < hooks.length; i++) {
+ var hook = hooks[i];
+ this.addHook(hook, null, plugins, config);
+ }
+ return this;
+ },
+
+ setConfig: function(obj){
+ this.config = obj;
+ },
+
+ init: function () {
+ this.addEvents();
+ var readyEvent = new CustomEvent('ready.dl', {
+ detail: {
+ dropdown: this,
+ },
+ });
+ window.dispatchEvent(readyEvent);
+ this.ready = true;
+ for(var i = 0; i < this.queuedData.length; i++) {
+ this.addData.apply(this, this.queuedData[i]);
+ }
+ this.queuedData = [];
+ return this;
+ },
+ });
+
+ return DropLab;
+ };
+});
+
+},{"./constants":1,"./custom_event_polyfill":2,"./hook_button":6,"./hook_input":7,"./utils":10,"./window":11}],5:[function(require,module,exports){
+var DropDown = require('./dropdown');
+
+var Hook = function(trigger, list, plugins, config){
+ this.trigger = trigger;
+ this.list = new DropDown(list);
+ this.type = 'Hook';
+ this.event = 'click';
+ this.plugins = plugins || [];
+ this.config = config || {};
+ this.id = trigger.dataset.id;
+};
+
+Object.assign(Hook.prototype, {
+
+ addEvents: function(){},
+
+ constructor: Hook,
+});
+
+module.exports = Hook;
+
+},{"./dropdown":3}],6:[function(require,module,exports){
+var CustomEvent = require('./custom_event_polyfill');
+var Hook = require('./hook');
+
+var HookButton = function(trigger, list, plugins, config) {
+ Hook.call(this, trigger, list, plugins, config);
+ this.type = 'button';
+ this.event = 'click';
+ this.addEvents();
+ this.addPlugins();
+};
+
+HookButton.prototype = Object.create(Hook.prototype);
+
+Object.assign(HookButton.prototype, {
+ addPlugins: function() {
+ for(var i = 0; i < this.plugins.length; i++) {
+ this.plugins[i].init(this);
+ }
+ },
+
+ clicked: function(e){
+ var buttonEvent = new CustomEvent('click.dl', {
+ detail: {
+ hook: this,
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ this.list.show();
+ e.target.dispatchEvent(buttonEvent);
+ },
+
+ addEvents: function(){
+ this.clickedWrapper = this.clicked.bind(this);
+ this.trigger.addEventListener('click', this.clickedWrapper);
+ },
+
+ removeEvents: function(){
+ this.trigger.removeEventListener('click', this.clickedWrapper);
+ },
+
+ restoreInitialState: function() {
+ this.list.list.innerHTML = this.list.initialState;
+ },
+
+ removePlugins: function() {
+ for(var i = 0; i < this.plugins.length; i++) {
+ this.plugins[i].destroy();
+ }
+ },
+
+ destroy: function() {
+ this.restoreInitialState();
+ this.removeEvents();
+ this.removePlugins();
+ },
+
+
+ constructor: HookButton,
+});
+
+
+module.exports = HookButton;
+
+},{"./custom_event_polyfill":2,"./hook":5}],7:[function(require,module,exports){
+var CustomEvent = require('./custom_event_polyfill');
+var Hook = require('./hook');
+
+var HookInput = function(trigger, list, plugins, config) {
+ Hook.call(this, trigger, list, plugins, config);
+ this.type = 'input';
+ this.event = 'input';
+ this.addPlugins();
+ this.addEvents();
+};
+
+Object.assign(HookInput.prototype, {
+ addPlugins: function() {
+ var self = this;
+ for(var i = 0; i < this.plugins.length; i++) {
+ this.plugins[i].init(self);
+ }
+ },
+
+ addEvents: function(){
+ var self = this;
+
+ this.mousedown = function mousedown(e) {
+ var mouseEvent = new CustomEvent('mousedown.dl', {
+ detail: {
+ hook: self,
+ text: e.target.value,
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ e.target.dispatchEvent(mouseEvent);
+ }
+
+ this.input = function input(e) {
+ var inputEvent = new CustomEvent('input.dl', {
+ detail: {
+ hook: self,
+ text: e.target.value,
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ e.target.dispatchEvent(inputEvent);
+ self.list.show();
+ }
+
+ this.keyup = function keyup(e) {
+ keyEvent(e, 'keyup.dl');
+ }
+
+ this.keydown = function keydown(e) {
+ keyEvent(e, 'keydown.dl');
+ }
+
+ function keyEvent(e, keyEventName){
+ var keyEvent = new CustomEvent(keyEventName, {
+ detail: {
+ hook: self,
+ text: e.target.value,
+ which: e.which,
+ key: e.key,
+ },
+ bubbles: true,
+ cancelable: true
+ });
+ e.target.dispatchEvent(keyEvent);
+ self.list.show();
+ }
+
+ this.events = this.events || {};
+ this.events.mousedown = this.mousedown;
+ this.events.input = this.input;
+ this.events.keyup = this.keyup;
+ this.events.keydown = this.keydown;
+ this.trigger.addEventListener('mousedown', this.mousedown);
+ this.trigger.addEventListener('input', this.input);
+ this.trigger.addEventListener('keyup', this.keyup);
+ this.trigger.addEventListener('keydown', this.keydown);
+ },
+
+ removeEvents: function(){
+ this.trigger.removeEventListener('mousedown', this.mousedown);
+ this.trigger.removeEventListener('input', this.input);
+ this.trigger.removeEventListener('keyup', this.keyup);
+ this.trigger.removeEventListener('keydown', this.keydown);
+ },
+
+ restoreInitialState: function() {
+ this.list.list.innerHTML = this.list.initialState;
+ },
+
+ removePlugins: function() {
+ for(var i = 0; i < this.plugins.length; i++) {
+ this.plugins[i].destroy();
+ }
+ },
+
+ destroy: function() {
+ this.restoreInitialState();
+ this.removeEvents();
+ this.removePlugins();
+ this.list.destroy();
+ }
+});
+
+module.exports = HookInput;
+
+},{"./custom_event_polyfill":2,"./hook":5}],8:[function(require,module,exports){
+var DropLab = require('./droplab')();
+var DATA_TRIGGER = require('./constants').DATA_TRIGGER;
+var keyboard = require('./keyboard')();
+var setup = function() {
+ window.DropLab = DropLab;
+};
+
+
+module.exports = setup();
+
+},{"./constants":1,"./droplab":4,"./keyboard":9}],9:[function(require,module,exports){
+require('./window')(function(w){
+ module.exports = function(){
+ var currentKey;
+ var currentFocus;
+ var currentIndex = 0;
+ var isUpArrow = false;
+ var isDownArrow = false;
+ var removeHighlight = function removeHighlight(list) {
+ var listItems = list.list.querySelectorAll('li');
+ for(var i = 0; i < listItems.length; i++) {
+ listItems[i].classList.remove('dropdown-active');
+ }
+ return listItems;
+ };
+
+ var setMenuForArrows = function setMenuForArrows(list) {
+ var listItems = removeHighlight(list);
+ if(currentIndex>0){
+ if(!listItems[currentIndex-1]){
+ currentIndex = currentIndex-1;
+ }
+ listItems[currentIndex-1].classList.add('dropdown-active');
+ }
+ };
+
+ var mousedown = function mousedown(e) {
+ var list = e.detail.hook.list;
+ removeHighlight(list);
+ list.show();
+ currentIndex = 0;
+ isUpArrow = false;
+ isDownArrow = false;
+ };
+ var selectItem = function selectItem(list) {
+ var listItems = removeHighlight(list);
+ var currentItem = listItems[currentIndex-1];
+ var listEvent = new CustomEvent('click.dl', {
+ detail: {
+ list: list,
+ selected: currentItem,
+ data: currentItem.dataset,
+ },
+ });
+ list.list.dispatchEvent(listEvent);
+ list.hide();
+ }
+
+ var keydown = function keydown(e){
+ var typedOn = e.target;
+ isUpArrow = false;
+ isDownArrow = false;
+
+ if(e.detail.which){
+ currentKey = e.detail.which;
+ if(currentKey === 13){
+ selectItem(e.detail.hook.list);
+ return;
+ }
+ if(currentKey === 38) {
+ isUpArrow = true;
+ }
+ if(currentKey === 40) {
+ isDownArrow = true;
+ }
+ } else if(e.detail.key) {
+ currentKey = e.detail.key;
+ if(currentKey === 'Enter'){
+ selectItem(e.detail.hook.list);
+ return;
+ }
+ if(currentKey === 'ArrowUp') {
+ isUpArrow = true;
+ }
+ if(currentKey === 'ArrowDown') {
+ isDownArrow = true;
+ }
+ }
+ if(isUpArrow){ currentIndex--; }
+ if(isDownArrow){ currentIndex++; }
+ if(currentIndex < 0){ currentIndex = 0; }
+ setMenuForArrows(e.detail.hook.list);
+ };
+
+ w.addEventListener('mousedown.dl', mousedown);
+ w.addEventListener('keydown.dl', keydown);
+ };
+});
+},{"./window":11}],10:[function(require,module,exports){
+var DATA_TRIGGER = require('./constants').DATA_TRIGGER;
+var DATA_DROPDOWN = require('./constants').DATA_DROPDOWN;
+
+var toDataCamelCase = function(attr){
+ return this.camelize(attr.split('-').slice(1).join(' '));
+};
+
+// the tiniest damn templating I can do
+var t = function(s,d){
+ for(var p in d)
+ s=s.replace(new RegExp('{{'+p+'}}','g'), d[p]);
+ return s;
+};
+
+var camelize = function(str) {
+ return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(letter, index) {
+ return index == 0 ? letter.toLowerCase() : letter.toUpperCase();
+ }).replace(/\s+/g, '');
+};
+
+var closest = function(thisTag, stopTag) {
+ while(thisTag.tagName !== stopTag && thisTag.tagName !== 'HTML'){
+ thisTag = thisTag.parentNode;
+ }
+ return thisTag;
+};
+
+var isDropDownParts = function(target) {
+ if(target.tagName === 'HTML') { return false; }
+ return (
+ target.hasAttribute(DATA_TRIGGER) ||
+ target.hasAttribute(DATA_DROPDOWN)
+ );
+};
+
+module.exports = {
+ toDataCamelCase: toDataCamelCase,
+ t: t,
+ camelize: camelize,
+ closest: closest,
+ isDropDownParts: isDropDownParts,
+};
+
+},{"./constants":1}],11:[function(require,module,exports){
+module.exports = function(callback) {
+ return (function() {
+ callback(this);
+ }).call(null);
+};
+
+},{}]},{},[8])(8)
+});
diff --git a/app/assets/javascripts/droplab/droplab_ajax.js b/app/assets/javascripts/droplab/droplab_ajax.js
new file mode 100644
index 00000000000..f20610b3811
--- /dev/null
+++ b/app/assets/javascripts/droplab/droplab_ajax.js
@@ -0,0 +1,79 @@
+/* eslint-disable */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g=(g.droplab||(g.droplab = {}));g=(g.ajax||(g.ajax = {}));g=(g.datasource||(g.datasource = {}));g.js = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+/* global droplab */
+
+require('../window')(function(w){
+ function droplabAjaxException(message) {
+ this.message = message;
+ }
+
+ w.droplabAjax = {
+ _loadUrlData: function _loadUrlData(url) {
+ return new Promise(function(resolve, reject) {
+ var xhr = new XMLHttpRequest;
+ xhr.open('GET', url, true);
+ xhr.onreadystatechange = function () {
+ if(xhr.readyState === XMLHttpRequest.DONE) {
+ if (xhr.status === 200) {
+ var data = JSON.parse(xhr.responseText);
+ return resolve(data);
+ } else {
+ return reject([xhr.responseText, xhr.status]);
+ }
+ }
+ };
+ xhr.send();
+ });
+ },
+
+ init: function init(hook) {
+ var self = this;
+ var config = hook.config.droplabAjax;
+
+ if (!config || !config.endpoint || !config.method) {
+ return;
+ }
+
+ if (config.method !== 'setData' && config.method !== 'addData') {
+ return;
+ }
+
+ if (config.loadingTemplate) {
+ var dynamicList = hook.list.list.querySelector('[data-dynamic]');
+
+ var loadingTemplate = document.createElement('div');
+ loadingTemplate.innerHTML = config.loadingTemplate;
+ loadingTemplate.setAttribute('data-loading-template', '');
+
+ this.listTemplate = dynamicList.outerHTML;
+ dynamicList.outerHTML = loadingTemplate.outerHTML;
+ }
+
+ this._loadUrlData(config.endpoint)
+ .then(function(d) {
+ if (config.loadingTemplate) {
+ var dataLoadingTemplate = hook.list.list.querySelector('[data-loading-template]');
+
+ if (dataLoadingTemplate) {
+ dataLoadingTemplate.outerHTML = self.listTemplate;
+ }
+ }
+ hook.list[config.method].call(hook.list, d);
+ }).catch(function(e) {
+ throw new droplabAjaxException(e.message || e);
+ });
+ },
+
+ destroy: function() {
+ }
+ };
+});
+},{"../window":2}],2:[function(require,module,exports){
+module.exports = function(callback) {
+ return (function() {
+ callback(this);
+ }).call(null);
+};
+
+},{}]},{},[1])(1)
+}); \ No newline at end of file
diff --git a/app/assets/javascripts/droplab/droplab_ajax_filter.js b/app/assets/javascripts/droplab/droplab_ajax_filter.js
new file mode 100644
index 00000000000..af163f76851
--- /dev/null
+++ b/app/assets/javascripts/droplab/droplab_ajax_filter.js
@@ -0,0 +1,145 @@
+/* eslint-disable */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g=(g.droplab||(g.droplab = {}));g=(g.ajax||(g.ajax = {}));g=(g.datasource||(g.datasource = {}));g.js = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+/* global droplab */
+
+require('../window')(function(w){
+ w.droplabAjaxFilter = {
+ init: function(hook) {
+ this.destroyed = false;
+ this.hook = hook;
+ this.notLoading();
+
+ this.debounceTriggerWrapper = this.debounceTrigger.bind(this);
+ this.hook.trigger.addEventListener('keydown.dl', this.debounceTriggerWrapper);
+ this.hook.trigger.addEventListener('focus', this.debounceTriggerWrapper);
+ this.trigger(true);
+ },
+
+ notLoading: function notLoading() {
+ this.loading = false;
+ },
+
+ debounceTrigger: function debounceTrigger(e) {
+ var NON_CHARACTER_KEYS = [16, 17, 18, 20, 37, 38, 39, 40, 91, 93];
+ var invalidKeyPressed = NON_CHARACTER_KEYS.indexOf(e.detail.which || e.detail.keyCode) > -1;
+ var focusEvent = e.type === 'focus';
+
+ if (invalidKeyPressed || this.loading) {
+ return;
+ }
+
+ if (this.timeout) {
+ clearTimeout(this.timeout);
+ }
+
+ this.timeout = setTimeout(this.trigger.bind(this, focusEvent), 200);
+ },
+
+ trigger: function trigger(getEntireList) {
+ var config = this.hook.config.droplabAjaxFilter;
+ var searchValue = this.trigger.value;
+
+ if (!config || !config.endpoint || !config.searchKey) {
+ return;
+ }
+
+ if (config.searchValueFunction) {
+ searchValue = config.searchValueFunction();
+ }
+
+ if (config.loadingTemplate && this.hook.list.data === undefined ||
+ this.hook.list.data.length === 0) {
+ var dynamicList = this.hook.list.list.querySelector('[data-dynamic]');
+
+ var loadingTemplate = document.createElement('div');
+ loadingTemplate.innerHTML = config.loadingTemplate;
+ loadingTemplate.setAttribute('data-loading-template', true);
+
+ this.listTemplate = dynamicList.outerHTML;
+ dynamicList.outerHTML = loadingTemplate.outerHTML;
+ }
+
+ if (getEntireList) {
+ searchValue = '';
+ }
+
+ if (config.searchKey === searchValue) {
+ return this.list.show();
+ }
+
+ this.loading = true;
+
+ var params = config.params || {};
+ params[config.searchKey] = searchValue;
+ var self = this;
+ this._loadUrlData(config.endpoint + this.buildParams(params)).then(function(data) {
+ if (config.loadingTemplate && self.hook.list.data === undefined ||
+ self.hook.list.data.length === 0) {
+ const dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
+
+ if (dataLoadingTemplate) {
+ dataLoadingTemplate.outerHTML = self.listTemplate;
+ }
+ }
+
+ if (!self.destroyed) {
+ var hookListChildren = self.hook.list.list.children;
+ var onlyDynamicList = hookListChildren.length === 1 && hookListChildren[0].hasAttribute('data-dynamic');
+
+ if (onlyDynamicList && data.length === 0) {
+ self.hook.list.hide();
+ }
+
+ self.hook.list.setData.call(self.hook.list, data);
+ }
+ self.notLoading();
+ });
+ },
+
+ _loadUrlData: function _loadUrlData(url) {
+ return new Promise(function(resolve, reject) {
+ var xhr = new XMLHttpRequest;
+ xhr.open('GET', url, true);
+ xhr.onreadystatechange = function () {
+ if(xhr.readyState === XMLHttpRequest.DONE) {
+ if (xhr.status === 200) {
+ var data = JSON.parse(xhr.responseText);
+ return resolve(data);
+ } else {
+ return reject([xhr.responseText, xhr.status]);
+ }
+ }
+ };
+ xhr.send();
+ });
+ },
+
+ buildParams: function(params) {
+ if (!params) return '';
+ var paramsArray = Object.keys(params).map(function(param) {
+ return param + '=' + (params[param] || '');
+ });
+ return '?' + paramsArray.join('&');
+ },
+
+ destroy: function destroy() {
+ if (this.timeout) {
+ clearTimeout(this.timeout);
+ }
+
+ this.destroyed = true;
+
+ this.hook.trigger.removeEventListener('keydown.dl', this.debounceTriggerWrapper);
+ this.hook.trigger.removeEventListener('focus', this.debounceTriggerWrapper);
+ }
+ };
+});
+},{"../window":2}],2:[function(require,module,exports){
+module.exports = function(callback) {
+ return (function() {
+ callback(this);
+ }).call(null);
+};
+
+},{}]},{},[1])(1)
+}); \ No newline at end of file
diff --git a/app/assets/javascripts/droplab/droplab_filter.js b/app/assets/javascripts/droplab/droplab_filter.js
new file mode 100644
index 00000000000..41a220831f9
--- /dev/null
+++ b/app/assets/javascripts/droplab/droplab_filter.js
@@ -0,0 +1,60 @@
+/* eslint-disable */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g=(g.droplab||(g.droplab = {}));g=(g.filter||(g.filter = {}));g.js = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+/* global droplab */
+
+require('../window')(function(w){
+ w.droplabFilter = {
+
+ keydownWrapper: function(e){
+ var list = e.detail.hook.list;
+ var data = list.data;
+ var value = e.detail.hook.trigger.value.toLowerCase();
+ var config = e.detail.hook.config.droplabFilter;
+ var matches = [];
+ var filterFunction;
+ // will only work on dynamically set data
+ if(!data){
+ return;
+ }
+
+ if (config && config.filterFunction && typeof config.filterFunction === 'function') {
+ filterFunction = config.filterFunction;
+ } else {
+ filterFunction = function(o){
+ // cheap string search
+ o.droplab_hidden = o[config.template].toLowerCase().indexOf(value) === -1;
+ return o;
+ };
+ }
+
+ matches = data.map(function(o) {
+ return filterFunction(o, value);
+ });
+ list.render(matches);
+ },
+
+ init: function init(hookInput) {
+ var config = hookInput.config.droplabFilter;
+
+ if (!config || (!config.template && !config.filterFunction)) {
+ return;
+ }
+
+ this.hookInput = hookInput;
+ this.hookInput.trigger.addEventListener('keyup.dl', this.keydownWrapper);
+ },
+
+ destroy: function destroy(){
+ this.hookInput.trigger.removeEventListener('keyup.dl', this.keydownWrapper);
+ }
+ };
+});
+},{"../window":2}],2:[function(require,module,exports){
+module.exports = function(callback) {
+ return (function() {
+ callback(this);
+ }).call(null);
+};
+
+},{}]},{},[1])(1)
+}); \ No newline at end of file
diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js
index e1e76bca6ad..56cb39be642 100644
--- a/app/assets/javascripts/dropzone_input.js
+++ b/app/assets/javascripts/dropzone_input.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, one-var, no-var, one-var-declaration-per-line, no-unused-vars, camelcase, no-undef, quotes, no-useless-concat, prefer-template, quote-props, comma-dangle, object-shorthand, consistent-return, no-plusplus, prefer-arrow-callback, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, one-var, no-var, one-var-declaration-per-line, no-unused-vars, camelcase, quotes, no-useless-concat, prefer-template, quote-props, comma-dangle, object-shorthand, consistent-return, no-plusplus, prefer-arrow-callback, padded-blocks */
+/* global Dropzone */
/*= require preview_markdown */
diff --git a/app/assets/javascripts/due_date_select.js.es6 b/app/assets/javascripts/due_date_select.js.es6
index e84f5ac9183..201f9fdc3fe 100644
--- a/app/assets/javascripts/due_date_select.js.es6
+++ b/app/assets/javascripts/due_date_select.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable wrap-iife, func-names, space-before-function-paren, comma-dangle, prefer-template, consistent-return, class-methods-use-this, arrow-body-style, prefer-const, padded-blocks, no-unused-vars, no-underscore-dangle, no-new, max-len, semi, no-sequences, no-unused-expressions, no-param-reassign */
+
(function(global) {
class DueDateSelect {
constructor({ $dropdown, $loading } = {}) {
@@ -79,9 +80,12 @@
}
parseSelectedDate() {
- this.rawSelectedDate = $("input[name='" + this.fieldName + "']").val();
+ this.rawSelectedDate = $(`input[name='${this.fieldName}']`).val();
+
if (this.rawSelectedDate.length) {
- let dateObj = new Date(this.rawSelectedDate);
+ // Construct Date object manually to avoid buggy dateString support within Date constructor
+ const dateArray = this.rawSelectedDate.split('-').map(v => parseInt(v, 10));
+ const dateObj = new Date(dateArray[0], dateArray[1] - 1, dateArray[2]);
this.displayedDate = $.datepicker.formatDate('M d, yy', dateObj);
} else {
this.displayedDate = 'No due date';
diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js.es6
index 1db29dd47fb..8b6fafb6104 100644
--- a/app/assets/javascripts/environments/components/environment.js.es6
+++ b/app/assets/javascripts/environments/components/environment.js.es6
@@ -18,7 +18,7 @@
* The environments array is a recursive tree structure and we need to filter
* both root level environments and children environments.
*
- * In order to acomplish that, both `filterState` and `filterEnvironmnetsByState`
+ * In order to acomplish that, both `filterState` and `filterEnvironmentsByState`
* functions work together.
* The first one works as the filter that verifies if the given environment matches
* the given state.
@@ -34,9 +34,9 @@
* @param {Array} array
* @return {Array}
*/
- const filterEnvironmnetsByState = (fn, arr) => arr.map((item) => {
+ const filterEnvironmentsByState = (fn, arr) => arr.map((item) => {
if (item.children) {
- const filteredChildren = filterEnvironmnetsByState(fn, item.children).filter(Boolean);
+ const filteredChildren = filterEnvironmentsByState(fn, item.children).filter(Boolean);
if (filteredChildren.length) {
item.children = filteredChildren;
return item;
@@ -45,7 +45,7 @@
return fn(item);
}).filter(Boolean);
- window.gl.environmentsList.EnvironmentsComponent = Vue.component('environment-component', {
+ gl.environmentsList.EnvironmentsComponent = Vue.component('environment-component', {
props: {
store: {
type: Object,
@@ -55,7 +55,7 @@
},
components: {
- 'environment-item': window.gl.environmentsList.EnvironmentItem,
+ 'environment-item': gl.environmentsList.EnvironmentItem,
},
data() {
@@ -76,12 +76,13 @@
helpPagePath: environmentsData.helpPagePath,
commitIconSvg: environmentsData.commitIconSvg,
playIconSvg: environmentsData.playIconSvg,
+ terminalIconSvg: environmentsData.terminalIconSvg,
};
},
computed: {
filteredEnvironments() {
- return filterEnvironmnetsByState(filterState(this.visibility), this.state.environments);
+ return filterEnvironmentsByState(filterState(this.visibility), this.state.environments);
},
scope() {
@@ -102,7 +103,7 @@
},
/**
- * Fetches all the environmnets and stores them.
+ * Fetches all the environments and stores them.
* Toggles loading property.
*/
created() {
@@ -164,8 +165,7 @@
{{state.availableCounter}}
</span>
</a>
- </li>
- <li v-bind:class="{ 'active' : scope === 'stopped' }">
+ </li><li v-bind:class="{ 'active' : scope === 'stopped' }">
<a :href="projectStoppedEnvironmentsPath">
Stopped
<span class="badge js-stopped-environments-count">
@@ -216,7 +216,7 @@
<th class="environments-deploy">Last deployment</th>
<th class="environments-build">Build</th>
<th class="environments-commit">Commit</th>
- <th class="environments-date"></th>
+ <th class="environments-date">Created</th>
<th class="hidden-xs environments-actions"></th>
</tr>
</thead>
@@ -231,6 +231,7 @@
:can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"
:play-icon-svg="playIconSvg"
+ :terminal-icon-svg="terminalIconSvg"
:commit-icon-svg="commitIconSvg"></tr>
<tr v-if="model.isOpen && model.children && model.children.length > 0"
@@ -241,6 +242,7 @@
:can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"
:play-icon-svg="playIconSvg"
+ :terminal-icon-svg="terminalIconSvg"
:commit-icon-svg="commitIconSvg">
</tr>
diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js.es6
index 7c743705d51..81468f4d3bc 100644
--- a/app/assets/javascripts/environments/components/environment_actions.js.es6
+++ b/app/assets/javascripts/environments/components/environment_actions.js.es6
@@ -5,7 +5,7 @@
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
- window.gl.environmentsList.ActionsComponent = Vue.component('actions-component', {
+ gl.environmentsList.ActionsComponent = Vue.component('actions-component', {
props: {
actions: {
type: Array,
diff --git a/app/assets/javascripts/environments/components/environment_external_url.js.es6 b/app/assets/javascripts/environments/components/environment_external_url.js.es6
index aed65b33c04..6592c1b5f0f 100644
--- a/app/assets/javascripts/environments/components/environment_external_url.js.es6
+++ b/app/assets/javascripts/environments/components/environment_external_url.js.es6
@@ -5,7 +5,7 @@
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
- window.gl.environmentsList.ExternalUrlComponent = Vue.component('external-url-component', {
+ gl.environmentsList.ExternalUrlComponent = Vue.component('external-url-component', {
props: {
externalUrl: {
type: String,
diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6
index 2e046a60146..0e6bc3fdb2c 100644
--- a/app/assets/javascripts/environments/components/environment_item.js.es6
+++ b/app/assets/javascripts/environments/components/environment_item.js.es6
@@ -8,6 +8,7 @@
/*= require ./environment_external_url */
/*= require ./environment_stop */
/*= require ./environment_rollback */
+/*= require ./environment_terminal_button */
(() => {
/**
@@ -28,11 +29,12 @@
gl.environmentsList.EnvironmentItem = Vue.component('environment-item', {
components: {
- 'commit-component': window.gl.CommitComponent,
- 'actions-component': window.gl.environmentsList.ActionsComponent,
- 'external-url-component': window.gl.environmentsList.ExternalUrlComponent,
- 'stop-component': window.gl.environmentsList.StopComponent,
- 'rollback-component': window.gl.environmentsList.RollbackComponent,
+ 'commit-component': gl.CommitComponent,
+ 'actions-component': gl.environmentsList.ActionsComponent,
+ 'external-url-component': gl.environmentsList.ExternalUrlComponent,
+ 'stop-component': gl.environmentsList.StopComponent,
+ 'rollback-component': gl.environmentsList.RollbackComponent,
+ 'terminal-button-component': gl.environmentsList.TerminalButtonComponent,
},
props: {
@@ -68,6 +70,12 @@
type: String,
required: false,
},
+
+ terminalIconSvg: {
+ type: String,
+ required: false,
+ },
+
},
data() {
@@ -175,7 +183,7 @@
* @returns {String}
*/
createdDate() {
- return window.gl.environmentsList.timeagoInstance.format(
+ return gl.environmentsList.timeagoInstance.format(
this.model.last_deployment.deployable.created_at,
);
},
@@ -449,7 +457,7 @@
</span>
</td>
- <td>
+ <td class="environments-build-cell">
<a v-if="shouldRenderBuildName"
class="build-link"
:href="model.last_deployment.deployable.build_path">
@@ -506,6 +514,14 @@
</stop-component>
</div>
+ <div v-if="model.terminal_path"
+ class="inline js-terminal-button-container">
+ <terminal-button-component
+ :terminal-icon-svg="terminalIconSvg"
+ :terminal-path="model.terminal_path">
+ </terminal-button-component>
+ </div>
+
<div v-if="canRetry && canCreateDeployment"
class="inline js-rollback-component-container">
<rollback-component
diff --git a/app/assets/javascripts/environments/components/environment_rollback.js.es6 b/app/assets/javascripts/environments/components/environment_rollback.js.es6
index 6d4e8fad604..b52298b4a88 100644
--- a/app/assets/javascripts/environments/components/environment_rollback.js.es6
+++ b/app/assets/javascripts/environments/components/environment_rollback.js.es6
@@ -5,7 +5,7 @@
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
- window.gl.environmentsList.RollbackComponent = Vue.component('rollback-component', {
+ gl.environmentsList.RollbackComponent = Vue.component('rollback-component', {
props: {
retryUrl: {
type: String,
diff --git a/app/assets/javascripts/environments/components/environment_stop.js.es6 b/app/assets/javascripts/environments/components/environment_stop.js.es6
index 7292f924e5c..0a29f2f36e9 100644
--- a/app/assets/javascripts/environments/components/environment_stop.js.es6
+++ b/app/assets/javascripts/environments/components/environment_stop.js.es6
@@ -5,7 +5,7 @@
window.gl = window.gl || {};
window.gl.environmentsList = window.gl.environmentsList || {};
- window.gl.environmentsList.StopComponent = Vue.component('stop-component', {
+ gl.environmentsList.StopComponent = Vue.component('stop-component', {
props: {
stopUrl: {
type: String,
diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 b/app/assets/javascripts/environments/components/environment_terminal_button.js.es6
new file mode 100644
index 00000000000..050184ba497
--- /dev/null
+++ b/app/assets/javascripts/environments/components/environment_terminal_button.js.es6
@@ -0,0 +1,27 @@
+/*= require vue */
+/* global Vue */
+
+(() => {
+ window.gl = window.gl || {};
+ window.gl.environmentsList = window.gl.environmentsList || {};
+
+ gl.environmentsList.TerminalButtonComponent = Vue.component('terminal-button-component', {
+ props: {
+ terminalPath: {
+ type: String,
+ default: '',
+ },
+ terminalIconSvg: {
+ type: String,
+ default: '',
+ },
+ },
+
+ template: `
+ <a class="btn terminal-button"
+ :href="terminalPath">
+ <span class="js-terminal-icon-container" v-html="terminalIconSvg"></span>
+ </a>
+ `,
+ });
+})();
diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6
index 20eee7976ec..9f24a6a4f88 100644
--- a/app/assets/javascripts/environments/environments_bundle.js.es6
+++ b/app/assets/javascripts/environments/environments_bundle.js.es6
@@ -7,15 +7,17 @@
$(() => {
window.gl = window.gl || {};
- if (window.gl.EnvironmentsListApp) {
- window.gl.EnvironmentsListApp.$destroy(true);
+ if (gl.EnvironmentsListApp) {
+ gl.EnvironmentsListApp.$destroy(true);
}
- const Store = window.gl.environmentsList.EnvironmentsStore;
+ const Store = gl.environmentsList.EnvironmentsStore;
- window.gl.EnvironmentsListApp = new window.gl.environmentsList.EnvironmentsComponent({
+ gl.EnvironmentsListApp = new gl.environmentsList.EnvironmentsComponent({
el: document.querySelector('#environments-list-view'),
+
propsData: {
store: Store.create(),
},
+
});
});
diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js.es6
index 15ec7b76c3d..575a45d9802 100644
--- a/app/assets/javascripts/environments/services/environments_service.js.es6
+++ b/app/assets/javascripts/environments/services/environments_service.js.es6
@@ -20,3 +20,5 @@ class EnvironmentsService {
return this.environments.get();
}
}
+
+window.EnvironmentsService = EnvironmentsService;
diff --git a/app/assets/javascripts/extensions/object.js.es6 b/app/assets/javascripts/extensions/object.js.es6
new file mode 100644
index 00000000000..70a2d765abd
--- /dev/null
+++ b/app/assets/javascripts/extensions/object.js.es6
@@ -0,0 +1,26 @@
+/* eslint-disable no-restricted-syntax */
+
+// Adapted from https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Polyfill
+if (typeof Object.assign !== 'function') {
+ Object.assign = function assign(target, ...args) {
+ if (target == null) { // TypeError if undefined or null
+ throw new TypeError('Cannot convert undefined or null to object');
+ }
+
+ const to = Object(target);
+
+ for (let index = 0; index < args.length; index += 1) {
+ const nextSource = args[index];
+
+ if (nextSource != null) { // Skip over if undefined or null
+ for (const nextKey in nextSource) {
+ // Avoid bugs when hasOwnProperty is shadowed
+ if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
+ to[nextKey] = nextSource[nextKey];
+ }
+ }
+ }
+ }
+ return to;
+ };
+}
diff --git a/app/assets/javascripts/files_comment_button.js b/app/assets/javascripts/files_comment_button.js
index 0122e847161..785f2869970 100644
--- a/app/assets/javascripts/files_comment_button.js
+++ b/app/assets/javascripts/files_comment_button.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, max-len, one-var, one-var-declaration-per-line, quotes, prefer-template, newline-per-chained-call, comma-dangle, new-cap, no-else-return, padded-blocks, consistent-return, no-undef, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, max-len, one-var, one-var-declaration-per-line, quotes, prefer-template, newline-per-chained-call, comma-dangle, new-cap, no-else-return, padded-blocks, consistent-return */
+/* global FilesCommentButton */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js.es6 b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6
new file mode 100644
index 00000000000..63c20f57520
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/dropdown_hint.js.es6
@@ -0,0 +1,66 @@
+/*= require filtered_search/filtered_search_dropdown */
+
+/* global droplabFilter */
+
+(() => {
+ class DropdownHint extends gl.FilteredSearchDropdown {
+ constructor(droplab, dropdown, input, filter) {
+ super(droplab, dropdown, input, filter);
+ this.config = {
+ droplabFilter: {
+ template: 'hint',
+ filterFunction: gl.DropdownUtils.filterHint,
+ },
+ };
+ }
+
+ itemClicked(e) {
+ const { selected } = e.detail;
+
+ if (selected.tagName === 'LI') {
+ if (selected.hasAttribute('data-value')) {
+ this.dismissDropdown();
+ } else {
+ const token = selected.querySelector('.js-filter-hint').innerText.trim();
+ const tag = selected.querySelector('.js-filter-tag').innerText.trim();
+
+ if (tag.length) {
+ gl.FilteredSearchDropdownManager.addWordToInput(token.replace(':', ''));
+ }
+ this.dismissDropdown();
+ this.dispatchInputEvent();
+ }
+ }
+ }
+
+ renderContent() {
+ const dropdownData = [{
+ icon: 'fa-pencil',
+ hint: 'author:',
+ tag: '&lt;@author&gt;',
+ }, {
+ icon: 'fa-user',
+ hint: 'assignee:',
+ tag: '&lt;@assignee&gt;',
+ }, {
+ icon: 'fa-clock-o',
+ hint: 'milestone:',
+ tag: '&lt;%milestone&gt;',
+ }, {
+ icon: 'fa-tag',
+ hint: 'label:',
+ tag: '&lt;~label&gt;',
+ }];
+
+ this.droplab.changeHookList(this.hookId, this.dropdown, [droplabFilter], this.config);
+ this.droplab.setData(this.hookId, dropdownData);
+ }
+
+ init() {
+ this.droplab.addHook(this.input, this.dropdown, [droplabFilter], this.config).init();
+ }
+ }
+
+ window.gl = window.gl || {};
+ gl.DropdownHint = DropdownHint;
+})();
diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6
new file mode 100644
index 00000000000..f06c3fc9c6f
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js.es6
@@ -0,0 +1,44 @@
+/*= require filtered_search/filtered_search_dropdown */
+
+/* global droplabAjax */
+/* global droplabFilter */
+
+(() => {
+ class DropdownNonUser extends gl.FilteredSearchDropdown {
+ constructor(droplab, dropdown, input, filter, endpoint, symbol) {
+ super(droplab, dropdown, input, filter);
+ this.symbol = symbol;
+ this.config = {
+ droplabAjax: {
+ endpoint,
+ method: 'setData',
+ loadingTemplate: this.loadingTemplate,
+ },
+ droplabFilter: {
+ filterFunction: gl.DropdownUtils.filterWithSymbol.bind(null, this.symbol),
+ },
+ };
+ }
+
+ itemClicked(e) {
+ super.itemClicked(e, (selected) => {
+ const title = selected.querySelector('.js-data-value').innerText.trim();
+ return `${this.symbol}${gl.DropdownUtils.getEscapedText(title)}`;
+ });
+ }
+
+ renderContent(forceShowList = false) {
+ this.droplab
+ .changeHookList(this.hookId, this.dropdown, [droplabAjax, droplabFilter], this.config);
+ super.renderContent(forceShowList);
+ }
+
+ init() {
+ this.droplab
+ .addHook(this.input, this.dropdown, [droplabAjax, droplabFilter], this.config).init();
+ }
+ }
+
+ window.gl = window.gl || {};
+ gl.DropdownNonUser = DropdownNonUser;
+})();
diff --git a/app/assets/javascripts/filtered_search/dropdown_user.js.es6 b/app/assets/javascripts/filtered_search/dropdown_user.js.es6
new file mode 100644
index 00000000000..e80d266ae89
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/dropdown_user.js.es6
@@ -0,0 +1,53 @@
+/*= require filtered_search/filtered_search_dropdown */
+
+/* global droplabAjaxFilter */
+
+(() => {
+ class DropdownUser extends gl.FilteredSearchDropdown {
+ constructor(droplab, dropdown, input, filter) {
+ super(droplab, dropdown, input, filter);
+ this.config = {
+ droplabAjaxFilter: {
+ endpoint: '/autocomplete/users.json',
+ searchKey: 'search',
+ params: {
+ per_page: 20,
+ active: true,
+ project_id: this.getProjectId(),
+ current_user: true,
+ },
+ searchValueFunction: this.getSearchInput.bind(this),
+ loadingTemplate: this.loadingTemplate,
+ },
+ };
+ }
+
+ itemClicked(e) {
+ super.itemClicked(e,
+ selected => selected.querySelector('.dropdown-light-content').innerText.trim());
+ }
+
+ renderContent(forceShowList = false) {
+ this.droplab.changeHookList(this.hookId, this.dropdown, [droplabAjaxFilter], this.config);
+ super.renderContent(forceShowList);
+ }
+
+ getProjectId() {
+ return this.input.getAttribute('data-project-id');
+ }
+
+ getSearchInput() {
+ const query = this.input.value.trim();
+ const { lastToken } = gl.FilteredSearchTokenizer.processTokens(query);
+
+ return lastToken.value || '';
+ }
+
+ init() {
+ this.droplab.addHook(this.input, this.dropdown, [droplabAjaxFilter], this.config).init();
+ }
+ }
+
+ window.gl = window.gl || {};
+ gl.DropdownUser = DropdownUser;
+})();
diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js.es6 b/app/assets/javascripts/filtered_search/dropdown_utils.js.es6
new file mode 100644
index 00000000000..c27ef3042d1
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/dropdown_utils.js.es6
@@ -0,0 +1,79 @@
+(() => {
+ class DropdownUtils {
+ static getEscapedText(text) {
+ let escapedText = text;
+ const hasSpace = text.indexOf(' ') !== -1;
+ const hasDoubleQuote = text.indexOf('"') !== -1;
+
+ // Encapsulate value with quotes if it has spaces
+ // Known side effect: values's with both single and double quotes
+ // won't escape properly
+ if (hasSpace) {
+ if (hasDoubleQuote) {
+ escapedText = `'${text}'`;
+ } else {
+ // Encapsulate singleQuotes or if it hasSpace
+ escapedText = `"${text}"`;
+ }
+ }
+
+ return escapedText;
+ }
+
+ static filterWithSymbol(filterSymbol, item, query) {
+ const updatedItem = item;
+ const { lastToken, searchToken } = gl.FilteredSearchTokenizer.processTokens(query);
+
+ if (lastToken !== searchToken) {
+ const title = updatedItem.title.toLowerCase();
+ let value = lastToken.value.toLowerCase();
+
+ if ((value[0] === '"' || value[0] === '\'') && title.indexOf(' ') !== -1) {
+ value = value.slice(1);
+ }
+
+ // Eg. filterSymbol = ~ for labels
+ const matchWithoutSymbol = lastToken.symbol === filterSymbol && title.indexOf(value) !== -1;
+ const match = title.indexOf(`${lastToken.symbol}${value}`) !== -1;
+
+ updatedItem.droplab_hidden = !match && !matchWithoutSymbol;
+ } else {
+ updatedItem.droplab_hidden = false;
+ }
+
+ return updatedItem;
+ }
+
+ static filterHint(item, query) {
+ const updatedItem = item;
+ let { lastToken } = gl.FilteredSearchTokenizer.processTokens(query);
+ lastToken = lastToken.key || lastToken || '';
+
+ if (!lastToken || query.split('').last() === ' ') {
+ updatedItem.droplab_hidden = false;
+ } else if (lastToken) {
+ const split = lastToken.split(':');
+ const tokenName = split[0].split(' ').last();
+
+ const match = updatedItem.hint.indexOf(tokenName.toLowerCase()) === -1;
+ updatedItem.droplab_hidden = tokenName ? match : false;
+ }
+
+ return updatedItem;
+ }
+
+ static setDataValueIfSelected(filter, selected) {
+ const dataValue = selected.getAttribute('data-value');
+
+ if (dataValue) {
+ gl.FilteredSearchDropdownManager.addWordToInput(filter, dataValue);
+ }
+
+ // Return boolean based on whether it was set
+ return dataValue !== null;
+ }
+ }
+
+ window.gl = window.gl || {};
+ gl.DropdownUtils = DropdownUtils;
+})();
diff --git a/app/assets/javascripts/filtered_search/filtered_search_bundle.js b/app/assets/javascripts/filtered_search/filtered_search_bundle.js
new file mode 100644
index 00000000000..d188718c5f3
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/filtered_search_bundle.js
@@ -0,0 +1,7 @@
+ // This is a manifest file that'll be compiled into including all the files listed below.
+ // Add new JavaScript code in separate files in this directory and they'll automatically
+ // be included in the compiled file accessible from http://example.com/assets/application.js
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+ // the compiled file.
+ //
+ /*= require_tree . */
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6
new file mode 100644
index 00000000000..886d8113f4a
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js.es6
@@ -0,0 +1,102 @@
+(() => {
+ const DATA_DROPDOWN_TRIGGER = 'data-dropdown-trigger';
+
+ class FilteredSearchDropdown {
+ constructor(droplab, dropdown, input, filter) {
+ this.droplab = droplab;
+ this.hookId = input.getAttribute('data-id');
+ this.input = input;
+ this.filter = filter;
+ this.dropdown = dropdown;
+ this.loadingTemplate = `<div class="filter-dropdown-loading">
+ <i class="fa fa-spinner fa-spin"></i>
+ </div>`;
+ this.bindEvents();
+ }
+
+ bindEvents() {
+ this.itemClickedWrapper = this.itemClicked.bind(this);
+ this.dropdown.addEventListener('click.dl', this.itemClickedWrapper);
+ }
+
+ unbindEvents() {
+ this.dropdown.removeEventListener('click.dl', this.itemClickedWrapper);
+ }
+
+ getCurrentHook() {
+ return this.droplab.hooks.filter(h => h.id === this.hookId)[0] || null;
+ }
+
+ itemClicked(e, getValueFunction) {
+ const { selected } = e.detail;
+
+ if (selected.tagName === 'LI' && selected.innerHTML) {
+ const dataValueSet = gl.DropdownUtils.setDataValueIfSelected(this.filter, selected);
+
+ if (!dataValueSet) {
+ const value = getValueFunction(selected);
+ gl.FilteredSearchDropdownManager.addWordToInput(this.filter, value);
+ }
+
+ this.dismissDropdown();
+ }
+ }
+
+ setAsDropdown() {
+ this.input.setAttribute(DATA_DROPDOWN_TRIGGER, `#${this.dropdown.id}`);
+ }
+
+ setOffset(offset = 0) {
+ this.dropdown.style.left = `${offset}px`;
+ }
+
+ renderContent(forceShowList = false) {
+ if (forceShowList && this.getCurrentHook().list.hidden) {
+ this.getCurrentHook().list.show();
+ }
+ }
+
+ render(forceRenderContent = false, forceShowList = false) {
+ this.setAsDropdown();
+
+ const currentHook = this.getCurrentHook();
+ const firstTimeInitialized = currentHook === null;
+
+ if (firstTimeInitialized || forceRenderContent) {
+ this.renderContent(forceShowList);
+ } else if (currentHook.list.list.id !== this.dropdown.id) {
+ this.renderContent(forceShowList);
+ }
+ }
+
+ dismissDropdown() {
+ // Focusing on the input will dismiss dropdown
+ // (default droplab functionality)
+ this.input.focus();
+ }
+
+ dispatchInputEvent() {
+ // Propogate input change to FilteredSearchDropdownManager
+ // so that it can determine which dropdowns to open
+ this.input.dispatchEvent(new Event('input'));
+ }
+
+ hideDropdown() {
+ this.getCurrentHook().list.hide();
+ }
+
+ resetFilters() {
+ const hook = this.getCurrentHook();
+ const data = hook.list.data;
+ const results = data.map((o) => {
+ const updated = o;
+ updated.droplab_hidden = false;
+ return updated;
+ });
+ hook.list.render(results);
+ }
+ }
+
+ window.gl = window.gl || {};
+ gl.FilteredSearchDropdown = FilteredSearchDropdown;
+})();
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
new file mode 100644
index 00000000000..1cd0483877a
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6
@@ -0,0 +1,193 @@
+/* global DropLab */
+
+(() => {
+ class FilteredSearchDropdownManager {
+ constructor() {
+ this.tokenizer = gl.FilteredSearchTokenizer;
+ this.filteredSearchInput = document.querySelector('.filtered-search');
+
+ this.setupMapping();
+
+ this.cleanupWrapper = this.cleanup.bind(this);
+ document.addEventListener('page:fetch', this.cleanupWrapper);
+ }
+
+ cleanup() {
+ if (this.droplab) {
+ this.droplab.destroy();
+ this.droplab = null;
+ }
+
+ this.setupMapping();
+
+ document.removeEventListener('page:fetch', this.cleanupWrapper);
+ }
+
+ setupMapping() {
+ this.mapping = {
+ author: {
+ reference: null,
+ gl: 'DropdownUser',
+ element: document.querySelector('#js-dropdown-author'),
+ },
+ assignee: {
+ reference: null,
+ gl: 'DropdownUser',
+ element: document.querySelector('#js-dropdown-assignee'),
+ },
+ milestone: {
+ reference: null,
+ gl: 'DropdownNonUser',
+ extraArguments: ['milestones.json', '%'],
+ element: document.querySelector('#js-dropdown-milestone'),
+ },
+ label: {
+ reference: null,
+ gl: 'DropdownNonUser',
+ extraArguments: ['labels.json', '~'],
+ element: document.querySelector('#js-dropdown-label'),
+ },
+ hint: {
+ reference: null,
+ gl: 'DropdownHint',
+ element: document.querySelector('#js-dropdown-hint'),
+ },
+ };
+ }
+
+ static addWordToInput(tokenName, tokenValue = '') {
+ const input = document.querySelector('.filtered-search');
+ const word = `${tokenName}:${tokenValue}`;
+
+ const { lastToken, searchToken } = gl.FilteredSearchTokenizer.processTokens(input.value);
+ const lastSearchToken = searchToken.split(' ').last();
+ const lastInputCharacter = input.value[input.value.length - 1];
+ const lastInputTrimmedCharacter = input.value.trim()[input.value.trim().length - 1];
+
+ // Remove the typed tokenName
+ if (word.indexOf(lastSearchToken) === 0 && searchToken !== '') {
+ // Remove spaces after the colon
+ if (lastInputCharacter === ' ' && lastInputTrimmedCharacter === ':') {
+ input.value = input.value.trim();
+ }
+
+ input.value = input.value.slice(0, -1 * lastSearchToken.length);
+ } else if (lastInputCharacter !== ' ' || (lastToken && lastToken.value[lastToken.value.length - 1] === ' ')) {
+ // Remove the existing tokenValue
+ const lastTokenString = `${lastToken.key}:${lastToken.symbol}${lastToken.value}`;
+ input.value = input.value.slice(0, -1 * lastTokenString.length);
+ }
+
+ input.value += word;
+ }
+
+ updateCurrentDropdownOffset() {
+ this.updateDropdownOffset(this.currentDropdown);
+ }
+
+ updateDropdownOffset(key) {
+ if (!this.font) {
+ this.font = window.getComputedStyle(this.filteredSearchInput).font;
+ }
+
+ const filterIconPadding = 27;
+ const offset = gl.text
+ .getTextWidth(this.filteredSearchInput.value, this.font) + filterIconPadding;
+
+ this.mapping[key].reference.setOffset(offset);
+ }
+
+ load(key, firstLoad = false) {
+ const mappingKey = this.mapping[key];
+ const glClass = mappingKey.gl;
+ const element = mappingKey.element;
+ let forceShowList = false;
+
+ if (!mappingKey.reference) {
+ const dl = this.droplab;
+ const defaultArguments = [null, dl, element, this.filteredSearchInput, key];
+ const glArguments = defaultArguments.concat(mappingKey.extraArguments || []);
+
+ // Passing glArguments to `new gl[glClass](<arguments>)`
+ mappingKey.reference = new (Function.prototype.bind.apply(gl[glClass], glArguments))();
+ }
+
+ if (firstLoad) {
+ mappingKey.reference.init();
+ }
+
+ if (this.currentDropdown === 'hint') {
+ // Force the dropdown to show if it was clicked from the hint dropdown
+ forceShowList = true;
+ }
+
+ this.updateDropdownOffset(key);
+ mappingKey.reference.render(firstLoad, forceShowList);
+
+ this.currentDropdown = key;
+ }
+
+ loadDropdown(dropdownName = '') {
+ let firstLoad = false;
+
+ if (!this.droplab) {
+ firstLoad = true;
+ this.droplab = new DropLab();
+ }
+
+ const match = gl.FilteredSearchTokenKeys.searchByKey(dropdownName.toLowerCase());
+ const shouldOpenFilterDropdown = match && this.currentDropdown !== match.key
+ && this.mapping[match.key];
+ const shouldOpenHintDropdown = !match && this.currentDropdown !== 'hint';
+
+ if (shouldOpenFilterDropdown || shouldOpenHintDropdown) {
+ const key = match && match.key ? match.key : 'hint';
+ this.load(key, firstLoad);
+ }
+ }
+
+ setDropdown() {
+ const { lastToken, searchToken } = this.tokenizer
+ .processTokens(this.filteredSearchInput.value);
+
+ if (this.filteredSearchInput.value.split('').last() === ' ') {
+ this.updateCurrentDropdownOffset();
+ }
+
+ if (lastToken === searchToken && lastToken !== null) {
+ // Token is not fully initialized yet because it has no value
+ // Eg. token = 'label:'
+
+ const split = lastToken.split(':');
+ const dropdownName = split[0].split(' ').last();
+ this.loadDropdown(split.length > 1 ? dropdownName : '');
+ } else if (lastToken) {
+ // Token has been initialized into an object because it has a value
+ this.loadDropdown(lastToken.key);
+ } else {
+ this.loadDropdown('hint');
+ }
+ }
+
+ resetDropdowns() {
+ // Force current dropdown to hide
+ this.mapping[this.currentDropdown].reference.hideDropdown();
+
+ // Re-Load dropdown
+ this.setDropdown();
+
+ // Reset filters for current dropdown
+ this.mapping[this.currentDropdown].reference.resetFilters();
+
+ // Reposition dropdown so that it is aligned with cursor
+ this.updateDropdownOffset(this.currentDropdown);
+ }
+
+ destroyDroplab() {
+ this.droplab.destroy();
+ }
+ }
+
+ window.gl = window.gl || {};
+ gl.FilteredSearchDropdownManager = FilteredSearchDropdownManager;
+})();
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
new file mode 100644
index 00000000000..ffd0d7e9cba
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6
@@ -0,0 +1,171 @@
+/* global Turbolinks */
+
+(() => {
+ class FilteredSearchManager {
+ constructor() {
+ this.filteredSearchInput = document.querySelector('.filtered-search');
+ this.clearSearchButton = document.querySelector('.clear-search');
+
+ if (this.filteredSearchInput) {
+ this.tokenizer = gl.FilteredSearchTokenizer;
+ this.dropdownManager = new gl.FilteredSearchDropdownManager();
+
+ this.bindEvents();
+ this.loadSearchParamsFromURL();
+ this.dropdownManager.setDropdown();
+
+ this.cleanupWrapper = this.cleanup.bind(this);
+ document.addEventListener('page:fetch', this.cleanupWrapper);
+ }
+ }
+
+ cleanup() {
+ this.unbindEvents();
+ document.removeEventListener('page:fetch', this.cleanupWrapper);
+ }
+
+ bindEvents() {
+ this.setDropdownWrapper = this.dropdownManager.setDropdown.bind(this.dropdownManager);
+ this.toggleClearSearchButtonWrapper = this.toggleClearSearchButton.bind(this);
+ this.checkForEnterWrapper = this.checkForEnter.bind(this);
+ this.clearSearchWrapper = this.clearSearch.bind(this);
+ this.checkForBackspaceWrapper = this.checkForBackspace.bind(this);
+
+ this.filteredSearchInput.addEventListener('input', this.setDropdownWrapper);
+ this.filteredSearchInput.addEventListener('input', this.toggleClearSearchButtonWrapper);
+ this.filteredSearchInput.addEventListener('keydown', this.checkForEnterWrapper);
+ this.filteredSearchInput.addEventListener('keyup', this.checkForBackspaceWrapper);
+ this.clearSearchButton.addEventListener('click', this.clearSearchWrapper);
+ }
+
+ unbindEvents() {
+ this.filteredSearchInput.removeEventListener('input', this.setDropdownWrapper);
+ this.filteredSearchInput.removeEventListener('input', this.toggleClearSearchButtonWrapper);
+ this.filteredSearchInput.removeEventListener('keydown', this.checkForEnterWrapper);
+ this.filteredSearchInput.removeEventListener('keyup', this.checkForBackspaceWrapper);
+ this.clearSearchButton.removeEventListener('click', this.clearSearchWrapper);
+ }
+
+ checkForBackspace(e) {
+ // 8 = Backspace Key
+ // 46 = Delete Key
+ if (e.keyCode === 8 || e.keyCode === 46) {
+ // Reposition dropdown so that it is aligned with cursor
+ this.dropdownManager.updateCurrentDropdownOffset();
+ }
+ }
+
+ checkForEnter(e) {
+ if (e.keyCode === 13) {
+ e.preventDefault();
+
+ // Prevent droplab from opening dropdown
+ this.dropdownManager.destroyDroplab();
+
+ this.search();
+ }
+ }
+
+ toggleClearSearchButton(e) {
+ if (e.target.value) {
+ this.clearSearchButton.classList.remove('hidden');
+ } else {
+ this.clearSearchButton.classList.add('hidden');
+ }
+ }
+
+ clearSearch(e) {
+ e.preventDefault();
+
+ this.filteredSearchInput.value = '';
+ this.clearSearchButton.classList.add('hidden');
+
+ this.dropdownManager.resetDropdowns();
+ }
+
+ loadSearchParamsFromURL() {
+ const params = gl.utils.getUrlParamsArray();
+ const inputValues = [];
+
+ params.forEach((p) => {
+ const split = p.split('=');
+ const keyParam = decodeURIComponent(split[0]);
+ const value = split[1];
+
+ // Check if it matches edge conditions listed in gl.FilteredSearchTokenKeys
+ const condition = gl.FilteredSearchTokenKeys.searchByConditionUrl(p);
+
+ if (condition) {
+ inputValues.push(`${condition.tokenKey}:${condition.value}`);
+ } else {
+ // Sanitize value since URL converts spaces into +
+ // Replace before decode so that we know what was originally + versus the encoded +
+ const sanitizedValue = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : value;
+ const match = gl.FilteredSearchTokenKeys.searchByKeyParam(keyParam);
+
+ if (match) {
+ const indexOf = keyParam.indexOf('_');
+ const sanitizedKey = indexOf !== -1 ? keyParam.slice(0, keyParam.indexOf('_')) : keyParam;
+ const symbol = match.symbol;
+ let quotationsToUse = '';
+
+ if (sanitizedValue.indexOf(' ') !== -1) {
+ // Prefer ", but use ' if required
+ quotationsToUse = sanitizedValue.indexOf('"') === -1 ? '"' : '\'';
+ }
+
+ inputValues.push(`${sanitizedKey}:${symbol}${quotationsToUse}${sanitizedValue}${quotationsToUse}`);
+ } else if (!match && keyParam === 'search') {
+ inputValues.push(sanitizedValue);
+ }
+ }
+ });
+
+ // Trim the last space value
+ this.filteredSearchInput.value = inputValues.join(' ');
+
+ if (inputValues.length > 0) {
+ this.clearSearchButton.classList.remove('hidden');
+ }
+ }
+
+ search() {
+ const paths = [];
+ const { tokens, searchToken } = this.tokenizer.processTokens(this.filteredSearchInput.value);
+ const currentState = gl.utils.getParameterByName('state') || 'opened';
+ paths.push(`state=${currentState}`);
+
+ tokens.forEach((token) => {
+ const condition = gl.FilteredSearchTokenKeys
+ .searchByConditionKeyValue(token.key, token.value.toLowerCase());
+ const { param } = gl.FilteredSearchTokenKeys.searchByKey(token.key);
+ const keyParam = param ? `${token.key}_${param}` : token.key;
+ let tokenPath = '';
+
+ if (condition) {
+ tokenPath = condition.url;
+ } else {
+ let tokenValue = token.value;
+
+ if ((tokenValue[0] === '\'' && tokenValue[tokenValue.length - 1] === '\'') ||
+ (tokenValue[0] === '"' && tokenValue[tokenValue.length - 1] === '"')) {
+ tokenValue = tokenValue.slice(1, tokenValue.length - 1);
+ }
+
+ tokenPath = `${keyParam}=${encodeURIComponent(tokenValue)}`;
+ }
+
+ paths.push(tokenPath);
+ });
+
+ if (searchToken) {
+ paths.push(`search=${encodeURIComponent(searchToken)}`);
+ }
+
+ Turbolinks.visit(`?scope=all&utf8=✓&${paths.join('&')}`);
+ }
+ }
+
+ window.gl = window.gl || {};
+ gl.FilteredSearchManager = FilteredSearchManager;
+})();
diff --git a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6
new file mode 100644
index 00000000000..e46373024b6
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js.es6
@@ -0,0 +1,83 @@
+(() => {
+ const tokenKeys = [{
+ key: 'author',
+ type: 'string',
+ param: 'username',
+ symbol: '@',
+ }, {
+ key: 'assignee',
+ type: 'string',
+ param: 'username',
+ symbol: '@',
+ }, {
+ key: 'milestone',
+ type: 'string',
+ param: 'title',
+ symbol: '%',
+ }, {
+ key: 'label',
+ type: 'array',
+ param: 'name[]',
+ symbol: '~',
+ }];
+
+ const conditions = [{
+ url: 'assignee_id=0',
+ tokenKey: 'assignee',
+ value: 'none',
+ }, {
+ url: 'milestone_title=No+Milestone',
+ tokenKey: 'milestone',
+ value: 'none',
+ }, {
+ url: 'milestone_title=%23upcoming',
+ tokenKey: 'milestone',
+ value: 'upcoming',
+ }, {
+ url: 'label_name[]=No+Label',
+ tokenKey: 'label',
+ value: 'none',
+ }];
+
+ class FilteredSearchTokenKeys {
+ static get() {
+ return tokenKeys;
+ }
+
+ static getConditions() {
+ return conditions;
+ }
+
+ static searchByKey(key) {
+ return tokenKeys.find(tokenKey => tokenKey.key === key) || null;
+ }
+
+ static searchBySymbol(symbol) {
+ return tokenKeys.find(tokenKey => tokenKey.symbol === symbol) || null;
+ }
+
+ static searchByKeyParam(keyParam) {
+ return tokenKeys.find((tokenKey) => {
+ let tokenKeyParam = tokenKey.key;
+
+ if (tokenKey.param) {
+ tokenKeyParam += `_${tokenKey.param}`;
+ }
+
+ return keyParam === tokenKeyParam;
+ }) || null;
+ }
+
+ static searchByConditionUrl(url) {
+ return conditions.find(condition => condition.url === url) || null;
+ }
+
+ static searchByConditionKeyValue(key, value) {
+ return conditions
+ .find(condition => condition.tokenKey === key && condition.value === value) || null;
+ }
+ }
+
+ window.gl = window.gl || {};
+ gl.FilteredSearchTokenKeys = FilteredSearchTokenKeys;
+})();
diff --git a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6
new file mode 100644
index 00000000000..cf53845a48b
--- /dev/null
+++ b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js.es6
@@ -0,0 +1,45 @@
+(() => {
+ class FilteredSearchTokenizer {
+ static processTokens(input) {
+ // Regex extracts `(token):(symbol)(value)`
+ // Values that start with a double quote must end in a double quote (same for single)
+ const tokenRegex = /(\w+):([~%@]?)(?:('[^']*'{0,1})|("[^"]*"{0,1})|(\S+))/g;
+ const tokens = [];
+ let lastToken = null;
+ const searchToken = input.replace(tokenRegex, (match, key, symbol, v1, v2, v3) => {
+ let tokenValue = v1 || v2 || v3;
+ let tokenSymbol = symbol;
+
+ if (tokenValue === '~' || tokenValue === '%' || tokenValue === '@') {
+ tokenSymbol = tokenValue;
+ tokenValue = '';
+ }
+
+ tokens.push({
+ key,
+ value: tokenValue || '',
+ symbol: tokenSymbol || '',
+ });
+ return '';
+ }).replace(/\s{2,}/g, ' ').trim() || '';
+
+ if (tokens.length > 0) {
+ const last = tokens[tokens.length - 1];
+ const lastString = `${last.key}:${last.symbol}${last.value}`;
+ lastToken = input.lastIndexOf(lastString) ===
+ input.length - lastString.length ? last : searchToken;
+ } else {
+ lastToken = searchToken;
+ }
+
+ return {
+ tokens,
+ lastToken,
+ searchToken,
+ };
+ }
+ }
+
+ window.gl = window.gl || {};
+ gl.FilteredSearchTokenizer = FilteredSearchTokenizer;
+})();
diff --git a/app/assets/javascripts/gfm_auto_complete.js.es6 b/app/assets/javascripts/gfm_auto_complete.js.es6
index 2f3da745119..6ca543c2b00 100644
--- a/app/assets/javascripts/gfm_auto_complete.js.es6
+++ b/app/assets/javascripts/gfm_auto_complete.js.es6
@@ -1,19 +1,29 @@
-/* eslint-disable */
+/* eslint-disable func-names, space-before-function-paren, no-template-curly-in-string, comma-dangle, object-shorthand, quotes, dot-notation, no-else-return, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-param-reassign, no-useless-escape, prefer-template, consistent-return, wrap-iife, prefer-arrow-callback, camelcase, no-unused-vars, no-useless-return, padded-blocks, vars-on-top, indent, no-extra-semi, no-multi-spaces, semi, max-len */
+
// Creates the variables for setting up GFM auto-completion
(function() {
- if (window.GitLab == null) {
- window.GitLab = {};
+ if (window.gl == null) {
+ window.gl = {};
}
function sanitize(str) {
return str.replace(/<(?:.|\n)*?>/gm, '');
}
- GitLab.GfmAutoComplete = {
- dataLoading: false,
- dataLoaded: false,
+ window.gl.GfmAutoComplete = {
+ dataSources: {},
+ defaultLoadingData: ['loading'],
cachedData: {},
- dataSource: '',
+ isLoadingData: {},
+ atTypeMap: {
+ ':': 'emojis',
+ '@': 'members',
+ '#': 'issues',
+ '!': 'mergeRequests',
+ '~': 'labels',
+ '%': 'milestones',
+ '/': 'commands'
+ },
// Emoji
Emoji: {
template: '<li>${name} <img alt="${name}" height="20" src="${path}" width="20" /></li>'
@@ -34,46 +44,45 @@
template: '<li>${title}</li>'
},
Loading: {
- template: '<li><i class="fa fa-refresh fa-spin"></i> Loading...</li>'
+ template: '<li style="pointer-events: none;"><i class="fa fa-refresh fa-spin"></i> Loading...</li>'
},
DefaultOptions: {
sorter: function(query, items, searchKey) {
- // Highlight first item only if at least one char was typed
- this.setting.highlightFirst = this.setting.alwaysHighlightFirst || query.length > 0;
- if ((items[0].name != null) && items[0].name === 'loading') {
+ this.setting.highlightFirst = query.length > 0;
+ if (gl.GfmAutoComplete.isLoading(items)) {
return items;
}
return $.fn.atwho["default"].callbacks.sorter(query, items, searchKey);
},
filter: function(query, data, searchKey) {
- if (data[0] === 'loading') {
+ if (gl.GfmAutoComplete.isLoading(data)) {
+ gl.GfmAutoComplete.fetchData(this.$inputor, this.at);
return data;
+ } else {
+ return $.fn.atwho["default"].callbacks.filter(query, data, searchKey);
}
- return $.fn.atwho["default"].callbacks.filter(query, data, searchKey);
},
beforeInsert: function(value) {
if (value && !this.setting.skipSpecialCharacterTest) {
var withoutAt = value.substring(1);
if (withoutAt && /[^\w\d]/.test(withoutAt)) value = value.charAt() + '"' + withoutAt + '"';
}
- if (!GitLab.GfmAutoComplete.dataLoaded) {
- return this.at;
- } else {
- return value;
- }
+ return value;
},
matcher: function (flag, subtext) {
// The below is taken from At.js source
// Tweaked to commands to start without a space only if char before is a non-word character
// https://github.com/ichord/At.js
- var _a, _y, regexp, match;
- subtext = subtext.split(' ').pop();
+ var _a, _y, regexp, match, atSymbolsWithBar, atSymbolsWithoutBar;
+ atSymbolsWithBar = Object.keys(this.app.controllers).join('|');
+ atSymbolsWithoutBar = Object.keys(this.app.controllers).join('');
+ subtext = subtext.split(/\s+/g).pop();
flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
_a = decodeURI("%C3%80");
_y = decodeURI("%C3%BF");
- regexp = new RegExp("(?:\\B|\\W|\\s)" + flag + "(?!\\W)([A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]*)|([^\\x00-\\xff]*)$", 'gi');
+ regexp = new RegExp("^(?:\\B|[^a-zA-Z0-9_" + atSymbolsWithoutBar + "]|\\s)" + flag + "(?![" + atSymbolsWithBar + "])([A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]*)$", 'gi');
match = regexp.exec(subtext);
@@ -84,69 +93,44 @@
}
}
},
- setup: _.debounce(function(input) {
+ setup: function(input) {
// Add GFM auto-completion to all input fields, that accept GFM input.
this.input = input || $('.js-gfm-input');
- // destroy previous instances
- this.destroyAtWho();
- // set up instances
- this.setupAtWho();
-
- if (this.dataSource && !this.dataLoading && !this.cachedData) {
- this.dataLoading = true;
- return this.fetchData(this.dataSource)
- .done((data) => {
- this.dataLoading = false;
- this.loadData(data);
- });
- };
-
- if (this.cachedData != null) {
- return this.loadData(this.cachedData);
- }
- }, 1000),
- setupAtWho: function() {
+ this.setupLifecycle();
+ },
+ setupLifecycle() {
+ this.input.each((i, input) => {
+ const $input = $(input);
+ $input.off('focus.setupAtWho').on('focus.setupAtWho', this.setupAtWho.bind(this, $input));
+ });
+ },
+ setupAtWho: function($input) {
// Emoji
- this.input.atwho({
+ $input.atwho({
at: ':',
- displayTpl: (function(_this) {
- return function(value) {
- if (value.path != null) {
- return _this.Emoji.template;
- } else {
- return _this.Loading.template;
- }
- };
- })(this),
+ displayTpl: function(value) {
+ return value.path != null ? this.Emoji.template : this.Loading.template;
+ }.bind(this),
insertTpl: ':${name}:',
- data: ['loading'],
- startWithSpace: false,
skipSpecialCharacterTest: true,
+ data: this.defaultLoadingData,
callbacks: {
sorter: this.DefaultOptions.sorter,
- filter: this.DefaultOptions.filter,
beforeInsert: this.DefaultOptions.beforeInsert,
- matcher: this.DefaultOptions.matcher
+ filter: this.DefaultOptions.filter
}
});
// Team Members
- this.input.atwho({
+ $input.atwho({
at: '@',
- displayTpl: (function(_this) {
- return function(value) {
- if (value.username != null) {
- return _this.Members.template;
- } else {
- return _this.Loading.template;
- }
- };
- })(this),
+ displayTpl: function(value) {
+ return value.username != null ? this.Members.template : this.Loading.template;
+ }.bind(this),
insertTpl: '${atwho-at}${username}',
searchKey: 'search',
- data: ['loading'],
- startWithSpace: false,
alwaysHighlightFirst: true,
skipSpecialCharacterTest: true,
+ data: this.defaultLoadingData,
callbacks: {
sorter: this.DefaultOptions.sorter,
filter: this.DefaultOptions.filter,
@@ -177,22 +161,15 @@
}
}
});
- this.input.atwho({
+ $input.atwho({
at: '#',
alias: 'issues',
searchKey: 'search',
- displayTpl: (function(_this) {
- return function(value) {
- if (value.title != null) {
- return _this.Issues.template;
- } else {
- return _this.Loading.template;
- }
- };
- })(this),
- data: ['loading'],
+ displayTpl: function(value) {
+ return value.title != null ? this.Issues.template : this.Loading.template;
+ }.bind(this),
+ data: this.defaultLoadingData,
insertTpl: '${atwho-at}${id}',
- startWithSpace: false,
callbacks: {
sorter: this.DefaultOptions.sorter,
filter: this.DefaultOptions.filter,
@@ -212,26 +189,20 @@
}
}
});
- this.input.atwho({
+ $input.atwho({
at: '%',
alias: 'milestones',
searchKey: 'search',
- displayTpl: (function(_this) {
- return function(value) {
- if (value.title != null) {
- return _this.Milestones.template;
- } else {
- return _this.Loading.template;
- }
- };
- })(this),
insertTpl: '${atwho-at}${title}',
- data: ['loading'],
- startWithSpace: false,
+ displayTpl: function(value) {
+ return value.title != null ? this.Milestones.template : this.Loading.template;
+ }.bind(this),
+ data: this.defaultLoadingData,
callbacks: {
matcher: this.DefaultOptions.matcher,
sorter: this.DefaultOptions.sorter,
beforeInsert: this.DefaultOptions.beforeInsert,
+ filter: this.DefaultOptions.filter,
beforeSave: function(milestones) {
return $.map(milestones, function(m) {
if (m.title == null) {
@@ -246,21 +217,14 @@
}
}
});
- this.input.atwho({
+ $input.atwho({
at: '!',
alias: 'mergerequests',
searchKey: 'search',
- displayTpl: (function(_this) {
- return function(value) {
- if (value.title != null) {
- return _this.Issues.template;
- } else {
- return _this.Loading.template;
- }
- };
- })(this),
- data: ['loading'],
- startWithSpace: false,
+ displayTpl: function(value) {
+ return value.title != null ? this.Issues.template : this.Loading.template;
+ }.bind(this),
+ data: this.defaultLoadingData,
insertTpl: '${atwho-at}${id}',
callbacks: {
sorter: this.DefaultOptions.sorter,
@@ -281,18 +245,30 @@
}
}
});
- this.input.atwho({
+ $input.atwho({
at: '~',
alias: 'labels',
searchKey: 'search',
- displayTpl: this.Labels.template,
+ data: this.defaultLoadingData,
+ displayTpl: function(value) {
+ return this.isLoading(value) ? this.Loading.template : this.Labels.template;
+ }.bind(this),
insertTpl: '${atwho-at}${title}',
- startWithSpace: false,
callbacks: {
matcher: this.DefaultOptions.matcher,
- sorter: this.DefaultOptions.sorter,
beforeInsert: this.DefaultOptions.beforeInsert,
+ filter: this.DefaultOptions.filter,
+ sorter: this.DefaultOptions.sorter,
beforeSave: function(merges) {
+ if (gl.GfmAutoComplete.isLoading(merges)) return merges;
+ var sanitizeLabelTitle;
+ sanitizeLabelTitle = function(title) {
+ if (/[\w\?&]+\s+[\w\?&]+/g.test(title)) {
+ return "\"" + (sanitize(title)) + "\"";
+ } else {
+ return sanitize(title);
+ }
+ };
return $.map(merges, function(m) {
return {
title: sanitize(m.title),
@@ -304,12 +280,14 @@
}
});
// We don't instantiate the slash commands autocomplete for note and issue/MR edit forms
- this.input.filter('[data-supports-slash-commands="true"]').atwho({
+ $input.filter('[data-supports-slash-commands="true"]').atwho({
at: '/',
alias: 'commands',
searchKey: 'search',
skipSpecialCharacterTest: true,
+ data: this.defaultLoadingData,
displayTpl: function(value) {
+ if (this.isLoading(value)) return this.Loading.template;
var tpl = '<li>/${name}';
if (value.aliases.length > 0) {
tpl += ' <small>(or /<%- aliases.join(", /") %>)</small>';
@@ -322,7 +300,7 @@
}
tpl += '</li>';
return _.template(tpl)(value);
- },
+ }.bind(this),
insertTpl: function(value) {
var tpl = "/${name} ";
var reference_prefix = null;
@@ -340,6 +318,7 @@
filter: this.DefaultOptions.filter,
beforeInsert: this.DefaultOptions.beforeInsert,
beforeSave: function(commands) {
+ if (gl.GfmAutoComplete.isLoading(commands)) return commands;
return $.map(commands, function(c) {
var search = c.name;
if (c.aliases.length > 0) {
@@ -367,32 +346,29 @@
});
return;
},
- destroyAtWho: function() {
- return this.input.atwho('destroy');
- },
- fetchData: function(dataSource) {
- return $.getJSON(dataSource);
+ fetchData: function($input, at) {
+ if (this.isLoadingData[at]) return;
+ this.isLoadingData[at] = true;
+ if (this.cachedData[at]) {
+ this.loadData($input, at, this.cachedData[at]);
+ } else {
+ $.getJSON(this.dataSources[this.atTypeMap[at]], (data) => {
+ this.loadData($input, at, data);
+ }).fail(() => { this.isLoadingData[at] = false; });
+ }
},
- loadData: function(data) {
- this.cachedData = data;
- this.dataLoaded = true;
- // load members
- this.input.atwho('load', '@', data.members);
- // load issues
- this.input.atwho('load', 'issues', data.issues);
- // load milestones
- this.input.atwho('load', 'milestones', data.milestones);
- // load merge requests
- this.input.atwho('load', 'mergerequests', data.mergerequests);
- // load emojis
- this.input.atwho('load', ':', data.emojis);
- // load labels
- this.input.atwho('load', '~', data.labels);
- // load commands
- this.input.atwho('load', '/', data.commands);
+ loadData: function($input, at, data) {
+ this.isLoadingData[at] = false;
+ this.cachedData[at] = data;
+ $input.atwho('load', at, data);
// This trigger at.js again
// otherwise we would be stuck with loading until the user types
- return $(':focus').trigger('keyup');
+ return $input.trigger('keyup');
+ },
+ isLoading(data) {
+ if (!data || !data.length) return false;
+ if (Array.isArray(data)) data = data[0];
+ return data === this.defaultLoadingData[0] || data.name === this.defaultLoadingData[0];
}
};
diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js
index 9a91018a8e4..00859728c30 100644
--- a/app/assets/javascripts/gl_dropdown.js
+++ b/app/assets/javascripts/gl_dropdown.js
@@ -1,4 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, one-var, one-var-declaration-per-line, space-before-blocks, prefer-rest-params, max-len, vars-on-top, no-plusplus, wrap-iife, no-unused-vars, quotes, no-shadow, no-cond-assign, prefer-arrow-callback, semi, no-return-assign, no-else-return, camelcase, no-undef, comma-dangle, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, padded-blocks, prefer-template, no-param-reassign, no-loop-func, no-extra-semi, keyword-spacing, no-mixed-operators, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, one-var, one-var-declaration-per-line, space-before-blocks, prefer-rest-params, max-len, vars-on-top, no-plusplus, wrap-iife, no-unused-vars, quotes, no-shadow, no-cond-assign, prefer-arrow-callback, semi, no-return-assign, no-else-return, camelcase, comma-dangle, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, padded-blocks, prefer-template, no-param-reassign, no-loop-func, no-extra-semi, keyword-spacing, no-mixed-operators */
+/* global fuzzaldrinPlus */
+/* global Turbolinks */
+
(function() {
var GitLabDropdown, GitLabDropdownFilter, GitLabDropdownRemote,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
@@ -20,7 +23,6 @@
this.filterInputBlur = (ref = this.options.filterInputBlur) != null ? ref : true;
$inputContainer = this.input.parent();
$clearButton = $inputContainer.find('.js-dropdown-input-clear');
- this.indeterminateIds = [];
$clearButton.on('click', (function(_this) {
// Clear click
return function(e) {
@@ -188,7 +190,7 @@
})();
GitLabDropdown = (function() {
- var ACTIVE_CLASS, FILTER_INPUT, INDETERMINATE_CLASS, LOADING_CLASS, PAGE_TWO_CLASS, NON_SELECTABLE_CLASSES, SELECTABLE_CLASSES, currentIndex;
+ var ACTIVE_CLASS, FILTER_INPUT, INDETERMINATE_CLASS, LOADING_CLASS, PAGE_TWO_CLASS, NON_SELECTABLE_CLASSES, SELECTABLE_CLASSES, CURSOR_SELECT_SCROLL_PADDING, currentIndex;
LOADING_CLASS = "is-loading";
@@ -341,16 +343,18 @@
selector = ".dropdown-page-one .dropdown-content a";
}
this.dropdown.on("click", selector, function(e) {
- var $el, selected;
+ var $el, selected, selectedObj, isMarking;
$el = $(this);
selected = self.rowClicked($el);
+ selectedObj = selected ? selected[0] : null;
+ isMarking = selected ? selected[1] : null;
if (self.options.clicked) {
- self.options.clicked(selected, $el, e);
+ self.options.clicked(selectedObj, $el, e, isMarking);
}
// Update label right after all modifications in dropdown has been done
if (self.options.toggleLabel) {
- self.updateLabel(selected, $el, self);
+ self.updateLabel(selectedObj, $el, self);
}
$el.trigger('blur');
@@ -441,12 +445,6 @@
this.resetRows();
this.addArrowKeyEvent();
- if (this.options.setIndeterminateIds) {
- this.options.setIndeterminateIds.call(this);
- }
- if (this.options.setActiveIds) {
- this.options.setActiveIds.call(this);
- }
// Makes indeterminate items effective
if (this.fullData && this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) {
this.parseData(this.fullData);
@@ -478,12 +476,7 @@
this.removeArrayKeyEvent();
$input = this.dropdown.find(".dropdown-input-field");
if (this.options.filterable) {
- $input.blur().val("");
- }
- // Triggering 'keyup' will re-render the dropdown which is not always required
- // specially if we want to keep the state of the dropdown needed for bulk-assignment
- if (!this.options.persistWhenHide) {
- $input.trigger("input");
+ $input.blur();
}
if (this.dropdown.find(".dropdown-toggle-page").length) {
$('.dropdown-menu', this.dropdown).removeClass(PAGE_TWO_CLASS);
@@ -617,7 +610,8 @@
};
GitLabDropdown.prototype.rowClicked = function(el) {
- var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value;
+ var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value, isMarking;
+
fieldName = this.options.fieldName;
isInput = $(this.el).is('input');
if (this.renderedData) {
@@ -638,7 +632,7 @@
el.addClass(ACTIVE_CLASS);
}
- return selectedObject;
+ return [selectedObject];
}
field = [];
@@ -656,6 +650,7 @@
}
if (el.hasClass(ACTIVE_CLASS)) {
+ isMarking = false;
el.removeClass(ACTIVE_CLASS);
if (field && field.length) {
if (isInput) {
@@ -665,6 +660,7 @@
}
}
} else if (el.hasClass(INDETERMINATE_CLASS)) {
+ isMarking = true;
el.addClass(ACTIVE_CLASS);
el.removeClass(INDETERMINATE_CLASS);
if (field && field.length && value == null) {
@@ -674,6 +670,7 @@
this.addInput(fieldName, value, selectedObject);
}
} else {
+ isMarking = true;
if (!this.options.multiSelect || el.hasClass('dropdown-clear-active')) {
this.dropdown.find("." + ACTIVE_CLASS).removeClass(ACTIVE_CLASS);
if (!isInput) {
@@ -694,7 +691,7 @@
}
}
- return selectedObject;
+ return [selectedObject, isMarking];
};
GitLabDropdown.prototype.focusTextInput = function() {
diff --git a/app/assets/javascripts/gl_field_errors.js.es6 b/app/assets/javascripts/gl_field_errors.js.es6
index 6ce392d2a5b..63f9cafa8d0 100644
--- a/app/assets/javascripts/gl_field_errors.js.es6
+++ b/app/assets/javascripts/gl_field_errors.js.es6
@@ -1,4 +1,4 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign, padded-blocks */
//= require gl_field_error
diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js
index db5d9e75b3a..04814fa0843 100644
--- a/app/assets/javascripts/gl_form.js
+++ b/app/assets/javascripts/gl_form.js
@@ -1,4 +1,8 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-undef, no-new, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-new, padded-blocks, max-len */
+/* global GitLab */
+/* global DropzoneInput */
+/* global autosize */
+
(function() {
this.GLForm = (function() {
function GLForm(form) {
@@ -26,13 +30,13 @@
this.form.addClass('gfm-form');
// remove notify commit author checkbox for non-commit notes
gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button'));
- GitLab.GfmAutoComplete.setup(this.form.find('.js-gfm-input'));
+ gl.GfmAutoComplete.setup(this.form.find('.js-gfm-input'));
new DropzoneInput(this.form);
autosize(this.textarea);
// form and textarea event listeners
this.addEventListeners();
- gl.text.init(this.form);
}
+ gl.text.init(this.form);
// hide discard button
this.form.find('.js-note-discard').hide();
return this.form.show();
diff --git a/app/assets/javascripts/graphs/stat_graph_contributors.js b/app/assets/javascripts/graphs/stat_graph_contributors.js
index c3a132b3c75..2d08a7c6ac3 100644
--- a/app/assets/javascripts/graphs/stat_graph_contributors.js
+++ b/app/assets/javascripts/graphs/stat_graph_contributors.js
@@ -1,4 +1,9 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, no-undef, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, camelcase, one-var-declaration-per-line, quotes, no-param-reassign, quote-props, comma-dangle, prefer-template, max-len, no-return-assign, padded-blocks */
+/* global ContributorsGraph */
+/* global ContributorsAuthorGraph */
+/* global ContributorsMasterGraph */
+/* global ContributorsStatGraphUtil */
+/* global d3 */
/*= require d3 */
diff --git a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js
index cb2448e8cc7..9c5e9381e52 100644
--- a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js
+++ b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, one-var, no-var, space-before-blocks, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, padded-blocks, no-undef, newline-per-chained-call, no-else-return, max-len */
+/* eslint-disable func-names, space-before-function-paren, one-var, no-var, space-before-blocks, prefer-rest-params, max-len, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, comma-dangle, no-return-assign, prefer-arrow-callback, quotes, prefer-template, padded-blocks, newline-per-chained-call, no-else-return */
+/* global d3 */
+/* global ContributorsGraph */
/*= require d3 */
diff --git a/app/assets/javascripts/group_label_subscription.js.es6 b/app/assets/javascripts/group_label_subscription.js.es6
index eea6cd40859..8e10e424412 100644
--- a/app/assets/javascripts/group_label_subscription.js.es6
+++ b/app/assets/javascripts/group_label_subscription.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable func-names, object-shorthand, comma-dangle, wrap-iife, space-before-function-paren, no-param-reassign, padded-blocks, max-len */
+
(function(global) {
class GroupLabelSubscription {
constructor(container) {
diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js
index 3dc6f05ca20..99700e7562a 100644
--- a/app/assets/javascripts/groups_select.js
+++ b/app/assets/javascripts/groups_select.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, one-var, camelcase, one-var-declaration-per-line, quotes, object-shorthand, no-undef, prefer-arrow-callback, comma-dangle, consistent-return, yoda, prefer-rest-params, prefer-spread, no-unused-vars, prefer-template, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, one-var, camelcase, one-var-declaration-per-line, quotes, object-shorthand, prefer-arrow-callback, comma-dangle, consistent-return, yoda, prefer-rest-params, prefer-spread, no-unused-vars, prefer-template, padded-blocks, max-len */
+/* global Api */
+
(function() {
var slice = [].slice;
@@ -14,7 +16,7 @@
multiple: $(select).hasClass('multiselect'),
minimumInputLength: 0,
query: function(query) {
- options = { all_available: all_available, skip_groups: skip_groups };
+ var options = { all_available: all_available, skip_groups: skip_groups };
return Api.groups(query.term, options, function(groups) {
var data;
data = {
diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js
index 9425b6ed9d4..fa795be07ed 100644
--- a/app/assets/javascripts/importer_status.js
+++ b/app/assets/javascripts/importer_status.js
@@ -1,6 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, camelcase, no-var, one-var, one-var-declaration-per-line, prefer-template, quotes, object-shorthand, comma-dangle, no-unused-vars, prefer-arrow-callback, no-else-return, padded-blocks, vars-on-top, no-new, no-undef, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, camelcase, no-var, one-var, one-var-declaration-per-line, prefer-template, quotes, object-shorthand, comma-dangle, no-unused-vars, prefer-arrow-callback, no-else-return, padded-blocks, vars-on-top, no-new, max-len */
+
(function() {
- this.ImporterStatus = (function() {
+ window.ImporterStatus = (function() {
function ImporterStatus(jobs_url, import_url) {
this.jobs_url = jobs_url;
this.import_url = import_url;
@@ -75,7 +76,7 @@
var jobsImportPath = $('.js-importer-status').data('jobs-import-path');
var importPath = $('.js-importer-status').data('import-path');
- new ImporterStatus(jobsImportPath, importPath);
+ new window.ImporterStatus(jobsImportPath, importPath);
}
});
}).call(this);
diff --git a/app/assets/javascripts/issuable.js.es6 b/app/assets/javascripts/issuable.js.es6
index 46503c290ae..9c3c96c20ed 100644
--- a/app/assets/javascripts/issuable.js.es6
+++ b/app/assets/javascripts/issuable.js.es6
@@ -1,10 +1,13 @@
-/* eslint-disable */
-(function() {
+/* eslint-disable no-param-reassign, func-names, no-var, camelcase, no-unused-vars, object-shorthand, space-before-function-paren, no-return-assign, comma-dangle, consistent-return, one-var, one-var-declaration-per-line, quotes, prefer-template, prefer-arrow-callback, prefer-const, padded-blocks, wrap-iife, max-len */
+/* global Issuable */
+/* global Turbolinks */
+
+((global) => {
var issuable_created;
issuable_created = false;
- this.Issuable = {
+ global.Issuable = {
init: function() {
Issuable.initTemplates();
Issuable.initSearch();
@@ -108,7 +111,11 @@
filterResults: (function(_this) {
return function(form) {
var formAction, formData, issuesUrl;
- formData = form.serialize();
+ formData = form.serializeArray();
+ formData = formData.filter(function(data) {
+ return data.value !== '';
+ });
+ formData = $.param(formData);
formAction = form.attr('action');
issuesUrl = formAction;
issuesUrl += "" + (formAction.indexOf('?') < 0 ? '?' : '&');
@@ -141,6 +148,9 @@
const $issuesOtherFilters = $('.issues-other-filters');
const $issuesBulkUpdate = $('.issues_bulk_update');
+ this.issuableBulkActions.willUpdateLabels = false;
+ this.issuableBulkActions.setOriginalDropdownData();
+
if ($checkedIssues.length > 0) {
let ids = $.map($checkedIssues, function(value) {
return $(value).data('id');
@@ -152,7 +162,6 @@
$updateIssuesIds.val([]);
$issuesBulkUpdate.hide();
$issuesOtherFilters.show();
- this.issuableBulkActions.willUpdateLabels = false;
}
return true;
},
@@ -179,4 +188,4 @@
}
};
-}).call(this);
+})(window);
diff --git a/app/assets/javascripts/issuable/issuable_bundle.js.es6 b/app/assets/javascripts/issuable/issuable_bundle.js.es6
new file mode 100644
index 00000000000..7d0465aa8b4
--- /dev/null
+++ b/app/assets/javascripts/issuable/issuable_bundle.js.es6
@@ -0,0 +1 @@
+//= require ./time_tracking/time_tracking_bundle
diff --git a/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6
new file mode 100644
index 00000000000..72433df2818
--- /dev/null
+++ b/app/assets/javascripts/issuable/time_tracking/components/collapsed_state.js.es6
@@ -0,0 +1,42 @@
+/* global Vue */
+//= require lib/utils/pretty_time
+
+(() => {
+ Vue.component('time-tracking-collapsed-state', {
+ name: 'time-tracking-collapsed-state',
+ props: [
+ 'showComparisonState',
+ 'showSpentOnlyState',
+ 'showEstimateOnlyState',
+ 'showNoTimeTrackingState',
+ 'timeSpentHumanReadable',
+ 'timeEstimateHumanReadable',
+ 'stopwatchSvg',
+ ],
+ methods: {
+ abbreviateTime(timeStr) {
+ return gl.utils.prettyTime.abbreviateTime(timeStr);
+ },
+ },
+ template: `
+ <div class='sidebar-collapsed-icon'>
+ <div v-html='stopwatchSvg'></div>
+ <div class='time-tracking-collapsed-summary'>
+ <div class='compare' v-if='showComparisonState'>
+ <span>{{ abbreviateTime(timeSpentHumanReadable) }} / {{ abbreviateTime(timeEstimateHumanReadable) }}</span>
+ </div>
+ <div class='estimate-only' v-if='showEstimateOnlyState'>
+ <span class='bold'>-- / {{ abbreviateTime(timeEstimateHumanReadable) }}</span>
+ </div>
+ <div class='spend-only' v-if='showSpentOnlyState'>
+ <span class='bold'>{{ abbreviateTime(timeSpentHumanReadable) }} / --</span>
+ </div>
+ <div class='no-tracking' v-if='showNoTimeTrackingState'>
+ <span class='no-value'>None</span>
+ </div>
+ </div>
+ </div>
+ `,
+ });
+})();
+
diff --git a/app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js.es6
new file mode 100644
index 00000000000..6abbd5dd167
--- /dev/null
+++ b/app/assets/javascripts/issuable/time_tracking/components/comparison_pane.js.es6
@@ -0,0 +1,69 @@
+/* global Vue */
+//= require lib/utils/pretty_time
+
+(() => {
+ const prettyTime = gl.utils.prettyTime;
+
+ Vue.component('time-tracking-comparison-pane', {
+ name: 'time-tracking-comparison-pane',
+ props: [
+ 'timeSpent',
+ 'timeEstimate',
+ 'timeSpentHumanReadable',
+ 'timeEstimateHumanReadable',
+ ],
+ computed: {
+ parsedRemaining() {
+ const diffSeconds = this.timeEstimate - this.timeSpent;
+ return prettyTime.parseSeconds(diffSeconds);
+ },
+ timeRemainingHumanReadable() {
+ return prettyTime.stringifyTime(this.parsedRemaining);
+ },
+ timeRemainingTooltip() {
+ const prefix = this.timeRemainingMinutes < 0 ? 'Over by' : 'Time remaining:';
+ return `${prefix} ${this.timeRemainingHumanReadable}`;
+ },
+ /* Diff values for comparison meter */
+ timeRemainingMinutes() {
+ return this.timeEstimate - this.timeSpent;
+ },
+ timeRemainingPercent() {
+ return `${Math.floor((this.timeSpent / this.timeEstimate) * 100)}%`;
+ },
+ timeRemainingStatusClass() {
+ return this.timeEstimate >= this.timeSpent ? 'within_estimate' : 'over_estimate';
+ },
+ /* Parsed time values */
+ parsedEstimate() {
+ return prettyTime.parseSeconds(this.timeEstimate);
+ },
+ parsedSpent() {
+ return prettyTime.parseSeconds(this.timeSpent);
+ },
+ },
+ template: `
+ <div class='time-tracking-comparison-pane'>
+ <div class='compare-meter' data-toggle='tooltip' data-placement='top' role='timeRemainingDisplay'
+ :aria-valuenow='timeRemainingTooltip'
+ :title='timeRemainingTooltip'
+ :data-original-title='timeRemainingTooltip'
+ :class='timeRemainingStatusClass'>
+ <div class='meter-container' role='timeSpentPercent' :aria-valuenow='timeRemainingPercent'>
+ <div :style='{ width: timeRemainingPercent }' class='meter-fill'></div>
+ </div>
+ <div class='compare-display-container'>
+ <div class='compare-display pull-left'>
+ <span class='compare-label'>Spent</span>
+ <span class='compare-value spent'>{{ timeSpentHumanReadable }}</span>
+ </div>
+ <div class='compare-display estimated pull-right'>
+ <span class='compare-label'>Est</span>
+ <span class='compare-value'>{{ timeEstimateHumanReadable }}</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ `,
+ });
+})();
diff --git a/app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js.es6
new file mode 100644
index 00000000000..309e9f2f9ef
--- /dev/null
+++ b/app/assets/javascripts/issuable/time_tracking/components/estimate_only_pane.js.es6
@@ -0,0 +1,13 @@
+/* global Vue */
+(() => {
+ Vue.component('time-tracking-estimate-only-pane', {
+ name: 'time-tracking-estimate-only-pane',
+ props: ['timeEstimateHumanReadable'],
+ template: `
+ <div class='time-tracking-estimate-only-pane'>
+ <span class='bold'>Estimated:</span>
+ {{ timeEstimateHumanReadable }}
+ </div>
+ `,
+ });
+})();
diff --git a/app/assets/javascripts/issuable/time_tracking/components/help_state.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/help_state.js.es6
new file mode 100644
index 00000000000..d7ced6d7151
--- /dev/null
+++ b/app/assets/javascripts/issuable/time_tracking/components/help_state.js.es6
@@ -0,0 +1,24 @@
+/* global Vue */
+(() => {
+ Vue.component('time-tracking-help-state', {
+ name: 'time-tracking-help-state',
+ props: ['docsUrl'],
+ template: `
+ <div class='time-tracking-help-state'>
+ <div class='time-tracking-info'>
+ <h4>Track time with slash commands</h4>
+ <p>Slash commands can be used in the issues description and comment boxes.</p>
+ <p>
+ <code>/estimate</code>
+ will update the estimated time with the latest command.
+ </p>
+ <p>
+ <code>/spend</code>
+ will update the sum of the time spent.
+ </p>
+ <a class='btn btn-default learn-more-button' :href='docsUrl'>Learn more</a>
+ </div>
+ </div>
+ `,
+ });
+})();
diff --git a/app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js.es6
new file mode 100644
index 00000000000..1d2ca643b5b
--- /dev/null
+++ b/app/assets/javascripts/issuable/time_tracking/components/no_tracking_pane.js.es6
@@ -0,0 +1,11 @@
+/* global Vue */
+(() => {
+ Vue.component('time-tracking-no-tracking-pane', {
+ name: 'time-tracking-no-tracking-pane',
+ template: `
+ <div class='time-tracking-no-tracking-pane'>
+ <span class='no-value'>No estimate or time spent</span>
+ </div>
+ `,
+ });
+})();
diff --git a/app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js.es6
new file mode 100644
index 00000000000..ed283fec3c3
--- /dev/null
+++ b/app/assets/javascripts/issuable/time_tracking/components/spent_only_pane.js.es6
@@ -0,0 +1,13 @@
+/* global Vue */
+(() => {
+ Vue.component('time-tracking-spent-only-pane', {
+ name: 'time-tracking-spent-only-pane',
+ props: ['timeSpentHumanReadable'],
+ template: `
+ <div class='time-tracking-spend-only-pane'>
+ <span class='bold'>Spent:</span>
+ {{ timeSpentHumanReadable }}
+ </div>
+ `,
+ });
+})();
diff --git a/app/assets/javascripts/issuable/time_tracking/components/time_tracker.js.es6 b/app/assets/javascripts/issuable/time_tracking/components/time_tracker.js.es6
new file mode 100644
index 00000000000..26563a7713b
--- /dev/null
+++ b/app/assets/javascripts/issuable/time_tracking/components/time_tracker.js.es6
@@ -0,0 +1,118 @@
+/* global Vue */
+//= require ./help_state
+//= require ./collapsed_state
+//= require ./spent_only_pane
+//= require ./no_tracking_pane
+//= require ./estimate_only_pane
+//= require ./comparison_pane
+
+(() => {
+ Vue.component('issuable-time-tracker', {
+ name: 'issuable-time-tracker',
+ props: [
+ 'time_estimate',
+ 'time_spent',
+ 'human_time_estimate',
+ 'human_time_spent',
+ 'stopwatchSvg',
+ 'docsUrl',
+ ],
+ data() {
+ return {
+ showHelp: false,
+ };
+ },
+ computed: {
+ timeSpent() {
+ return this.time_spent;
+ },
+ timeEstimate() {
+ return this.time_estimate;
+ },
+ timeEstimateHumanReadable() {
+ return this.human_time_estimate;
+ },
+ timeSpentHumanReadable() {
+ return this.human_time_spent;
+ },
+ hasTimeSpent() {
+ return !!this.timeSpent;
+ },
+ hasTimeEstimate() {
+ return !!this.timeEstimate;
+ },
+ showComparisonState() {
+ return this.hasTimeEstimate && this.hasTimeSpent;
+ },
+ showEstimateOnlyState() {
+ return this.hasTimeEstimate && !this.hasTimeSpent;
+ },
+ showSpentOnlyState() {
+ return this.hasTimeSpent && !this.hasTimeEstimate;
+ },
+ showNoTimeTrackingState() {
+ return !this.hasTimeEstimate && !this.hasTimeSpent;
+ },
+ showHelpState() {
+ return !!this.showHelp;
+ },
+ },
+ methods: {
+ toggleHelpState(show) {
+ this.showHelp = show;
+ },
+ },
+ template: `
+ <div class='time_tracker time-tracking-component-wrap' v-cloak>
+ <time-tracking-collapsed-state
+ :show-comparison-state='showComparisonState'
+ :show-help-state='showHelpState'
+ :show-spent-only-state='showSpentOnlyState'
+ :show-estimate-only-state='showEstimateOnlyState'
+ :time-spent-human-readable='timeSpentHumanReadable'
+ :time-estimate-human-readable='timeEstimateHumanReadable'
+ :stopwatch-svg='stopwatchSvg'>
+ </time-tracking-collapsed-state>
+ <div class='title hide-collapsed'>
+ Time tracking
+ <div class='help-button pull-right'
+ v-if='!showHelpState'
+ @click='toggleHelpState(true)'>
+ <i class='fa fa-question-circle'></i>
+ </div>
+ <div class='close-help-button pull-right'
+ v-if='showHelpState'
+ @click='toggleHelpState(false)'>
+ <i class='fa fa-close'></i>
+ </div>
+ </div>
+ <div class='time-tracking-content hide-collapsed'>
+ <time-tracking-estimate-only-pane
+ v-if='showEstimateOnlyState'
+ :time-estimate-human-readable='timeEstimateHumanReadable'>
+ </time-tracking-estimate-only-pane>
+ <time-tracking-spent-only-pane
+ v-if='showSpentOnlyState'
+ :time-spent-human-readable='timeSpentHumanReadable'>
+ </time-tracking-spent-only-pane>
+ <time-tracking-no-tracking-pane
+ v-if='showNoTimeTrackingState'>
+ </time-tracking-no-tracking-pane>
+ <time-tracking-comparison-pane
+ v-if='showComparisonState'
+ :time-estimate='timeEstimate'
+ :time-spent='timeSpent'
+ :time-spent-human-readable='timeSpentHumanReadable'
+ :time-estimate-human-readable='timeEstimateHumanReadable'>
+ </time-tracking-comparison-pane>
+ <transition name='help-state-toggle'>
+ <time-tracking-help-state
+ v-if='showHelpState'
+ :docs-url='docsUrl'>
+ </time-tracking-help-state>
+ </transition>
+ </div>
+ </div>
+ `,
+ });
+})();
diff --git a/app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6 b/app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6
new file mode 100644
index 00000000000..0b8da2b1f4f
--- /dev/null
+++ b/app/assets/javascripts/issuable/time_tracking/time_tracking_bundle.js.es6
@@ -0,0 +1,61 @@
+/* global Vue */
+//= require ./components/time_tracker
+//= require smart_interval
+//= require subbable_resource
+
+(() => {
+ /* This Vue instance represents what will become the parent instance for the
+ * sidebar. It will be responsible for managing `issuable` state and propagating
+ * changes to sidebar components. We will want to create a separate service to
+ * interface with the server at that point.
+ */
+
+ class IssuableTimeTracking {
+ constructor(issuableJSON) {
+ const parsedIssuable = JSON.parse(issuableJSON);
+ return this.initComponent(parsedIssuable);
+ }
+
+ initComponent(parsedIssuable) {
+ this.parentInstance = new Vue({
+ el: '#issuable-time-tracker',
+ data: {
+ issuable: parsedIssuable,
+ },
+ methods: {
+ fetchIssuable() {
+ return gl.IssuableResource.get.call(gl.IssuableResource, {
+ type: 'GET',
+ url: gl.IssuableResource.endpoint,
+ });
+ },
+ updateState(data) {
+ this.issuable = data;
+ },
+ subscribeToUpdates() {
+ gl.IssuableResource.subscribe(data => this.updateState(data));
+ },
+ listenForSlashCommands() {
+ $(document).on('ajax:success', '.gfm-form', (e, data) => {
+ const subscribedCommands = ['spend_time', 'time_estimate'];
+ const changedCommands = data.commands_changes;
+
+ if (changedCommands && _.intersection(subscribedCommands, changedCommands).length) {
+ this.fetchIssuable();
+ }
+ });
+ },
+ },
+ created() {
+ this.fetchIssuable();
+ },
+ mounted() {
+ this.subscribeToUpdates();
+ this.listenForSlashCommands();
+ },
+ });
+ }
+ }
+
+ gl.IssuableTimeTracking = IssuableTimeTracking;
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/issuable_context.js b/app/assets/javascripts/issuable_context.js
index 317818951fd..4aaad111082 100644
--- a/app/assets/javascripts/issuable_context.js
+++ b/app/assets/javascripts/issuable_context.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, no-undef, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, padded-blocks, max-len */
+/* global UsersSelect */
+
(function() {
this.IssuableContext = (function() {
function IssuableContext(currentUser) {
diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js
index 50fdbc89c7c..1c4086517fe 100644
--- a/app/assets/javascripts/issuable_form.js
+++ b/app/assets/javascripts/issuable_form.js
@@ -1,4 +1,9 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-undef, no-new, quotes, object-shorthand, no-unused-vars, comma-dangle, radix, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new, quotes, object-shorthand, no-unused-vars, comma-dangle, radix, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, padded-blocks, max-len */
+/* global GitLab */
+/* global UsersSelect */
+/* global ZenMode */
+/* global Autosave */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
@@ -14,7 +19,7 @@
this.renderWipExplanation = bind(this.renderWipExplanation, this);
this.resetAutosave = bind(this.resetAutosave, this);
this.handleSubmit = bind(this.handleSubmit, this);
- GitLab.GfmAutoComplete.setup();
+ gl.GfmAutoComplete.setup();
new UsersSelect();
new ZenMode();
this.titleField = this.form.find("input[name*='[title]']");
diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js
index 8540b199aba..61e8531153b 100644
--- a/app/assets/javascripts/issue.js
+++ b/app/assets/javascripts/issue.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-undef, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, padded-blocks, max-len */
+/* global Flash */
/*= require flash */
/*= require jquery.waitforimages */
@@ -138,15 +139,12 @@
return;
}
return $.getJSON($container.data('path')).error(function() {
- $container.find('.checking').hide();
$container.find('.unavailable').show();
return new Flash('Failed to check if a new branch can be created.', 'alert');
}).success(function(data) {
if (data.can_create_branch) {
- $container.find('.checking').hide();
$container.find('.available').show();
} else {
- $container.find('.checking').hide();
return $container.find('.unavailable').show();
}
});
diff --git a/app/assets/javascripts/issues_bulk_assignment.js.es6 b/app/assets/javascripts/issues_bulk_assignment.js.es6
index 9697fb33566..52fd5d71b18 100644
--- a/app/assets/javascripts/issues_bulk_assignment.js.es6
+++ b/app/assets/javascripts/issues_bulk_assignment.js.es6
@@ -1,10 +1,14 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, quotes, consistent-return, func-names, array-callback-return, space-before-function-paren, prefer-arrow-callback, radix, max-len, padded-blocks, no-unused-expressions, no-sequences, no-underscore-dangle, no-unused-vars, no-param-reassign */
+/* global Issuable */
+/* global Flash */
+
((global) => {
class IssuableBulkActions {
- constructor({ container, form, issues } = {}) {
- this.container = container || $('.content'),
+ constructor({ container, form, issues, prefixId } = {}) {
+ this.prefixId = prefixId || 'issue_';
this.form = form || this.getElement('.bulk-update');
+ this.$labelDropdown = this.form.find('.js-label-select');
this.issues = issues || this.getElement('.issues-list .issue');
this.form.data('bulkActions', this);
this.willUpdateLabels = false;
@@ -13,10 +17,6 @@
Issuable.initChecks();
}
- getElement(selector) {
- return this.container.find(selector);
- }
-
bindEvents() {
return this.form.off('submit').on('submit', this.onFormSubmit.bind(this));
}
@@ -70,10 +70,7 @@
getUnmarkedIndeterminedLabels() {
const result = [];
- const labelsToKeep = [];
-
- this.getElement('.labels-filter .is-indeterminate')
- .each((i, el) => labelsToKeep.push($(el).data('labelId')));
+ const labelsToKeep = this.$labelDropdown.data('indeterminate');
this.getLabelsFromSelection().forEach((id) => {
if (labelsToKeep.indexOf(id) === -1) {
@@ -103,45 +100,65 @@
}
};
if (this.willUpdateLabels) {
- this.getLabelsToApply().map(function(id) {
- return formData.update.add_label_ids.push(id);
- });
- this.getLabelsToRemove().map(function(id) {
- return formData.update.remove_label_ids.push(id);
- });
+ formData.update.add_label_ids = this.$labelDropdown.data('marked');
+ formData.update.remove_label_ids = this.$labelDropdown.data('unmarked');
}
return formData;
}
- getLabelsToApply() {
+ setOriginalDropdownData() {
+ const $labelSelect = $('.bulk-update .js-label-select');
+ $labelSelect.data('common', this.getOriginalCommonIds());
+ $labelSelect.data('marked', this.getOriginalMarkedIds());
+ $labelSelect.data('indeterminate', this.getOriginalIndeterminateIds());
+ }
+
+ // From issuable's initial bulk selection
+ getOriginalCommonIds() {
const labelIds = [];
- const $labels = this.form.find('.labels-filter input[name="update[label_ids][]"]');
- $labels.each(function(k, label) {
- if (label) {
- return labelIds.push(parseInt($(label).val()));
- }
+
+ this.getElement('.selected_issue:checked').each((i, el) => {
+ labelIds.push(this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels'));
});
- return labelIds;
+ return _.intersection.apply(this, labelIds);
}
+ // From issuable's initial bulk selection
+ getOriginalMarkedIds() {
+ const labelIds = [];
+ this.getElement('.selected_issue:checked').each((i, el) => {
+ labelIds.push(this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels'));
+ });
+ return _.intersection.apply(this, labelIds);
+ }
- /**
- * Returns Label IDs that will be removed from issue selection
- * @return {Array} Array of labels IDs
- */
-
- getLabelsToRemove() {
- const result = [];
- const indeterminatedLabels = this.getUnmarkedIndeterminedLabels();
- const labelsToApply = this.getLabelsToApply();
- indeterminatedLabels.map(function(id) {
- // We need to exclude label IDs that will be applied
- // By not doing this will cause issues from selection to not add labels at all
- if (labelsToApply.indexOf(id) === -1) {
- return result.push(id);
- }
+ // From issuable's initial bulk selection
+ getOriginalIndeterminateIds() {
+ const uniqueIds = [];
+ const labelIds = [];
+ let issuableLabels = [];
+
+ // Collect unique label IDs for all checked issues
+ this.getElement('.selected_issue:checked').each((i, el) => {
+ issuableLabels = this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels');
+ issuableLabels.forEach((labelId) => {
+ // Store unique IDs
+ if (uniqueIds.indexOf(labelId) === -1) {
+ uniqueIds.push(labelId);
+ }
+ });
+ // Store array of IDs per issuable
+ labelIds.push(issuableLabels);
});
- return result;
+ // Add uniqueIds to add it as argument for _.intersection
+ labelIds.unshift(uniqueIds);
+ // Return IDs that are present but not in all selected issueables
+ return _.difference(uniqueIds, _.intersection.apply(this, labelIds));
+ }
+
+ getElement(selector) {
+ this.scopeEl = this.scopeEl || $('.content');
+ return this.scopeEl.find(selector);
}
}
diff --git a/app/assets/javascripts/label_manager.js.es6 b/app/assets/javascripts/label_manager.js.es6
index 175623e7448..33c5e35324d 100644
--- a/app/assets/javascripts/label_manager.js.es6
+++ b/app/assets/javascripts/label_manager.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, class-methods-use-this, no-underscore-dangle, no-param-reassign, no-unused-vars, consistent-return, func-names, space-before-function-paren, padded-blocks, max-len */
+/* global Flash */
+
((global) => {
class LabelManager {
@@ -104,4 +106,3 @@
gl.LabelManager = LabelManager;
})(window.gl || (window.gl = {}));
-
diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js
index f334f35594d..ec2fc87bece 100644
--- a/app/assets/javascripts/labels_select.js
+++ b/app/assets/javascripts/labels_select.js
@@ -1,12 +1,16 @@
-/* eslint-disable no-useless-return, func-names, space-before-function-paren, wrap-iife, no-var, no-underscore-dangle, prefer-arrow-callback, max-len, one-var, no-unused-vars, one-var-declaration-per-line, prefer-template, no-new, consistent-return, object-shorthand, comma-dangle, no-shadow, no-param-reassign, brace-style, vars-on-top, quotes, no-lonely-if, no-else-return, no-undef, semi, dot-notation, no-empty, no-return-assign, camelcase, prefer-spread, padded-blocks, max-len */
+/* eslint-disable no-useless-return, func-names, space-before-function-paren, wrap-iife, no-var, no-underscore-dangle, prefer-arrow-callback, max-len, one-var, no-unused-vars, one-var-declaration-per-line, prefer-template, no-new, consistent-return, object-shorthand, comma-dangle, no-shadow, no-param-reassign, brace-style, vars-on-top, quotes, no-lonely-if, no-else-return, semi, dot-notation, no-empty, no-return-assign, camelcase, prefer-spread, padded-blocks */
+/* global Issuable */
+/* global ListLabel */
+
(function() {
this.LabelsSelect = (function() {
function LabelsSelect() {
var _this;
_this = this;
$('.js-label-select').each(function(i, dropdown) {
- var $block, $colorPreview, $dropdown, $form, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, defaultLabel, enableLabelCreateButton, issueURLSplit, issueUpdateURL, labelHTMLTemplate, labelNoneHTMLTemplate, labelUrl, namespacePath, projectPath, saveLabelData, selectedLabel, showAny, showNo, $sidebarLabelTooltip, initialSelected, $toggleText, fieldName, useId, propertyName, showMenuAbove;
+ var $block, $colorPreview, $dropdown, $form, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, defaultLabel, enableLabelCreateButton, issueURLSplit, issueUpdateURL, labelHTMLTemplate, labelNoneHTMLTemplate, labelUrl, namespacePath, projectPath, saveLabelData, selectedLabel, showAny, showNo, $sidebarLabelTooltip, initialSelected, $toggleText, fieldName, useId, propertyName, showMenuAbove, $container, $dropdownContainer;
$dropdown = $(dropdown);
+ $dropdownContainer = $dropdown.closest('.labels-filter');
$toggleText = $dropdown.find('.dropdown-toggle-text');
namespacePath = $dropdown.data('namespace-path');
projectPath = $dropdown.data('project-path');
@@ -122,7 +126,7 @@
});
});
};
- return $dropdown.glDropdown({
+ $dropdown.glDropdown({
showMenuAbove: showMenuAbove,
data: function(term, callback) {
return $.ajax({
@@ -169,33 +173,40 @@
});
},
renderRow: function(label, instance) {
- var $a, $li, active, color, colorEl, indeterminate, removesAll, selectedClass, spacing;
+ var $a, $li, color, colorEl, indeterminate, removesAll, selectedClass, spacing, i, marked, dropdownName, dropdownValue;
$li = $('<li>');
$a = $('<a href="#">');
selectedClass = [];
removesAll = label.id <= 0 || (label.id == null);
if ($dropdown.hasClass('js-filter-bulk-update')) {
- indeterminate = instance.indeterminateIds;
- active = instance.activeIds;
+ indeterminate = $dropdown.data('indeterminate') || [];
+ marked = $dropdown.data('marked') || [];
+
if (indeterminate.indexOf(label.id) !== -1) {
selectedClass.push('is-indeterminate');
}
- if (active.indexOf(label.id) !== -1) {
+
+ if (marked.indexOf(label.id) !== -1) {
// Remove is-indeterminate class if the item will be marked as active
i = selectedClass.indexOf('is-indeterminate');
if (i !== -1) {
selectedClass.splice(i, 1);
}
selectedClass.push('is-active');
- // Add input manually
- instance.addInput(this.fieldName, label.id);
}
- }
- if (this.id(label) && $form.find("input[type='hidden'][name='" + ($dropdown.data('fieldName')) + "'][value='" + this.id(label).toString().replace(/'/g, '\\\'') + "']").length) {
- selectedClass.push('is-active');
- }
- if ($dropdown.hasClass('js-multiselect') && removesAll) {
- selectedClass.push('dropdown-clear-active');
+ } else {
+ if (this.id(label)) {
+ dropdownName = $dropdown.data('fieldName');
+ dropdownValue = this.id(label).toString().replace(/'/g, '\\\'');
+
+ if ($form.find("input[type='hidden'][name='" + dropdownName + "'][value='" + dropdownValue + "']").length) {
+ selectedClass.push('is-active');
+ }
+ }
+
+ if ($dropdown.hasClass('js-multiselect') && removesAll) {
+ selectedClass.push('dropdown-clear-active');
+ }
}
if (label.duplicate) {
spacing = 100 / label.color.length;
@@ -231,7 +242,6 @@
// Return generated html
return $li.html($a).prop('outerHTML');
},
- persistWhenHide: $dropdown.data('persistWhenHide'),
search: {
fields: ['title']
},
@@ -310,18 +320,15 @@
}
}
}
- if ($dropdown.hasClass('js-filter-bulk-update')) {
- // If we are persisting state we need the classes
- if (!this.options.persistWhenHide) {
- return $dropdown.parent().find('.is-active, .is-indeterminate').removeClass();
- }
- }
},
multiSelect: $dropdown.hasClass('js-multiselect'),
vue: $dropdown.hasClass('js-issue-board-sidebar'),
- clicked: function(label, $el, e) {
+ clicked: function(label, $el, e, isMarking) {
var isIssueIndex, isMRIndex, page;
- _this.enableBulkLabelDropdown();
+
+ page = $('body').data('page');
+ isIssueIndex = page === 'projects:issues:index';
+ isMRIndex = page === 'projects:merge_requests:index';
if ($dropdown.parent().find('.is-active:not(.dropdown-clear-active)').length) {
$dropdown.parent()
@@ -330,12 +337,11 @@
}
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {
+ _this.enableBulkLabelDropdown();
+ _this.setDropdownData($dropdown, isMarking, this.id(label));
return;
}
- page = $('body').data('page');
- isIssueIndex = page === 'projects:issues:index';
- isMRIndex = page === 'projects:merge_requests:index';
if ($('html').hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar')) {
if (label.isAny) {
gl.issueBoards.BoardsStore.state.filters['label_name'] = [];
@@ -397,17 +403,10 @@
}
}
},
- setIndeterminateIds: function() {
- if (this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) {
- return this.indeterminateIds = _this.getIndeterminateIds();
- }
- },
- setActiveIds: function() {
- if (this.dropdown.find('.dropdown-menu-toggle').hasClass('js-filter-bulk-update')) {
- return this.activeIds = _this.getActiveIds();
- }
- }
});
+
+ // Set dropdown data
+ _this.setOriginalDropdownData($dropdownContainer, $dropdown);
});
this.bindEvents();
}
@@ -420,34 +419,9 @@
if ($('.selected_issue:checked').length) {
return;
}
- // Remove inputs
- $('.issues_bulk_update .labels-filter input[type="hidden"]').remove();
- // Also restore button text
return $('.issues_bulk_update .labels-filter .dropdown-toggle-text').text('Label');
};
- LabelsSelect.prototype.getIndeterminateIds = function() {
- var label_ids;
- label_ids = [];
- $('.selected_issue:checked').each(function(i, el) {
- var issue_id;
- issue_id = $(el).data('id');
- return label_ids.push($("#issue_" + issue_id).data('labels'));
- });
- return _.flatten(label_ids);
- };
-
- LabelsSelect.prototype.getActiveIds = function() {
- var label_ids;
- label_ids = [];
- $('.selected_issue:checked').each(function(i, el) {
- var issue_id;
- issue_id = $(el).data('id');
- return label_ids.push($("#issue_" + issue_id).data('labels'));
- });
- return _.intersection.apply(_, label_ids);
- };
-
LabelsSelect.prototype.enableBulkLabelDropdown = function() {
var issuableBulkActions;
if ($('.selected_issue:checked').length) {
@@ -456,8 +430,59 @@
}
};
- return LabelsSelect;
+ LabelsSelect.prototype.setDropdownData = function($dropdown, isMarking, value) {
+ var i, markedIds, unmarkedIds, indeterminateIds;
+ var issuableBulkActions = $('.bulk-update').data('bulkActions');
+ markedIds = $dropdown.data('marked') || [];
+ unmarkedIds = $dropdown.data('unmarked') || [];
+ indeterminateIds = $dropdown.data('indeterminate') || [];
+
+ if (isMarking) {
+ markedIds.push(value);
+
+ i = indeterminateIds.indexOf(value);
+ if (i > -1) {
+ indeterminateIds.splice(i, 1);
+ }
+
+ i = unmarkedIds.indexOf(value);
+ if (i > -1) {
+ unmarkedIds.splice(i, 1);
+ }
+ } else {
+ // If marked item (not common) is unmarked
+ i = markedIds.indexOf(value);
+ if (i > -1) {
+ markedIds.splice(i, 1);
+ }
+
+ // If an indeterminate item is being unmarked
+ if (issuableBulkActions.getOriginalIndeterminateIds().indexOf(value) > -1) {
+ unmarkedIds.push(value);
+ }
+
+ // If a marked item is being unmarked
+ // (a marked item could also be a label that is present in all selection)
+ if (issuableBulkActions.getOriginalCommonIds().indexOf(value) > -1) {
+ unmarkedIds.push(value);
+ }
+ }
+
+ $dropdown.data('marked', markedIds);
+ $dropdown.data('unmarked', unmarkedIds);
+ $dropdown.data('indeterminate', indeterminateIds);
+ };
+
+ LabelsSelect.prototype.setOriginalDropdownData = function($container, $dropdown) {
+ var labels = [];
+ $container.find('[name="label_name[]"]').map(function() {
+ return labels.push(this.value);
+ });
+ $dropdown.data('marked', labels);
+ };
+
+ return LabelsSelect;
})();
}).call(this);
diff --git a/app/assets/javascripts/lib/ace.js b/app/assets/javascripts/lib/ace.js
index b1718e89d3d..4cdf99cae72 100644
--- a/app/assets/javascripts/lib/ace.js
+++ b/app/assets/javascripts/lib/ace.js
@@ -1,3 +1,2 @@
-/* eslint-disable */
/*= require ace-rails-ap */
/*= require ace/ext-searchbox */
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js.es6
index 8fa80502d92..0c6a3cc3170 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js.es6
@@ -93,8 +93,22 @@
}
};
- gl.utils.getPagePath = function() {
- return $('body').data('page').split(':')[0];
+ // Check if element scrolled into viewport from above or below
+ // Courtesy http://stackoverflow.com/a/7557433/414749
+ w.gl.utils.isInViewport = function(el) {
+ var rect = el.getBoundingClientRect();
+
+ return (
+ rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <= window.innerHeight &&
+ rect.right <= window.innerWidth
+ );
+ };
+
+ gl.utils.getPagePath = function(index) {
+ index = index || 0;
+ return $('body').data('page').split(':')[index];
};
gl.utils.parseUrl = function (url) {
@@ -110,10 +124,42 @@
return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : '/' + parsedUrl.pathname;
};
+ gl.utils.getUrlParamsArray = function () {
+ // We can trust that each param has one & since values containing & will be encoded
+ // Remove the first character of search as it is always ?
+ return window.location.search.slice(1).split('&');
+ };
+
gl.utils.isMetaKey = function(e) {
return e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
};
+ gl.utils.scrollToElement = function($el) {
+ var top = $el.offset().top;
+ gl.navBarHeight = gl.navBarHeight || $('.navbar-gitlab').height();
+ gl.navLinksHeight = gl.navLinksHeight || $('.nav-links').height();
+ gl.mrTabsHeight = gl.mrTabsHeight || $('.merge-request-tabs').height();
+
+ return $('body, html').animate({
+ scrollTop: top - (gl.navBarHeight + gl.navLinksHeight + gl.mrTabsHeight)
+ }, 200);
+ };
+
+ /**
+ this will take in the `name` of the param you want to parse in the url
+ if the name does not exist this function will return `null`
+ otherwise it will return the value of the param key provided
+ */
+ w.gl.utils.getParameterByName = (name) => {
+ const url = window.location.href;
+ name = name.replace(/[[\]]/g, '\\$&');
+ const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`);
+ const results = regex.exec(url);
+ if (!results) return null;
+ if (!results[2]) return '';
+ return decodeURIComponent(results[2].replace(/\+/g, ' '));
+ };
+
})(window);
}).call(this);
diff --git a/app/assets/javascripts/lib/utils/custom_event_polyfill.js.es6 b/app/assets/javascripts/lib/utils/custom_event_polyfill.js.es6
deleted file mode 100644
index 5ae978010c9..00000000000
--- a/app/assets/javascripts/lib/utils/custom_event_polyfill.js.es6
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * CustomEvent support for IE
- */
-if (typeof window.CustomEvent !== 'function') {
- window.CustomEvent = function CustomEvent(e, params) {
- const options = params || { bubbles: false, cancelable: false, detail: undefined };
- const evt = document.createEvent('CustomEvent');
- evt.initCustomEvent(e, options.bubbles, options.cancelable, options.detail);
- return evt;
- };
- window.CustomEvent.prototype = window.Event.prototype;
-}
diff --git a/app/assets/javascripts/lib/utils/notify.js b/app/assets/javascripts/lib/utils/notify.js
index d0fe69260a5..3c9ad0e67c8 100644
--- a/app/assets/javascripts/lib/utils/notify.js
+++ b/app/assets/javascripts/lib/utils/notify.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, consistent-return, no-undef, prefer-arrow-callback, no-return-assign, object-shorthand, comma-dangle, no-param-reassign, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, consistent-return, prefer-arrow-callback, no-return-assign, object-shorthand, comma-dangle, no-param-reassign, padded-blocks, max-len */
+
(function() {
(function(w) {
var notificationGranted, notifyMe, notifyPermissions;
diff --git a/app/assets/javascripts/lib/utils/pretty_time.js.es6 b/app/assets/javascripts/lib/utils/pretty_time.js.es6
index ccaf447eb0b..ae397212e55 100644
--- a/app/assets/javascripts/lib/utils/pretty_time.js.es6
+++ b/app/assets/javascripts/lib/utils/pretty_time.js.es6
@@ -4,13 +4,13 @@
* stringifyTime condensed or non-condensed, abbreviateTimelengths)
* */
- class PrettyTime {
-
+ const utils = window.gl.utils = gl.utils || {};
+ const prettyTime = utils.prettyTime = {
/*
* Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # }
* Seconds can be negative or positive, zero or non-zero.
*/
- static parseSeconds(seconds) {
+ parseSeconds(seconds) {
const DAYS_PER_WEEK = 5;
const HOURS_PER_DAY = 8;
const MINUTES_PER_HOUR = 60;
@@ -24,7 +24,7 @@
minutes: 1,
};
- let unorderedMinutes = PrettyTime.secondsToMinutes(seconds);
+ let unorderedMinutes = prettyTime.secondsToMinutes(seconds);
return _.mapObject(timePeriodConstraints, (minutesPerPeriod) => {
const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
@@ -33,35 +33,33 @@
return periodCount;
});
- }
+ },
/*
* Accepts a timeObject and returns a condensed string representation of it
* (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included.
*/
- static stringifyTime(timeObject) {
+ stringifyTime(timeObject) {
const reducedTime = _.reduce(timeObject, (memo, unitValue, unitName) => {
const isNonZero = !!unitValue;
return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo;
}, '').trim();
return reducedTime.length ? reducedTime : '0m';
- }
+ },
/*
* Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns
* the first non-zero unit/value pair.
*/
- static abbreviateTime(timeStr) {
+ abbreviateTime(timeStr) {
return timeStr.split(' ')
.filter(unitStr => unitStr.charAt(0) !== '0')[0];
- }
+ },
- static secondsToMinutes(seconds) {
+ secondsToMinutes(seconds) {
return Math.abs(seconds / 60);
- }
- }
-
- gl.PrettyTime = PrettyTime;
+ },
+ };
})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js
index ac44b81ee22..c856a26ae40 100644
--- a/app/assets/javascripts/lib/utils/text_utility.js
+++ b/app/assets/javascripts/lib/utils/text_utility.js
@@ -17,6 +17,21 @@
gl.text.replaceRange = function(s, start, end, substitute) {
return s.substring(0, start) + substitute + s.substring(end);
};
+ gl.text.getTextWidth = function(text, font) {
+ /**
+ * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
+ *
+ * @param {String} text The text to be rendered.
+ * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
+ *
+ * @see http://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
+ */
+ // re-use canvas object for better performance
+ var canvas = gl.text.getTextWidth.canvas || (gl.text.getTextWidth.canvas = document.createElement('canvas'));
+ var context = canvas.getContext('2d');
+ context.font = font;
+ return context.measureText(text).width;
+ };
gl.text.selectedText = function(text, textarea) {
return text.substring(textarea.selectionStart, textarea.selectionEnd);
};
@@ -44,9 +59,25 @@
}
};
gl.text.insertText = function(textArea, text, tag, blockTag, selected, wrap) {
- var insertText, inserted, selectedSplit, startChar;
+ var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine;
+ removedLastNewLine = false;
+ removedFirstNewLine = false;
+
+ // Remove the first newline
+ if (selected.indexOf('\n') === 0) {
+ removedFirstNewLine = true;
+ selected = selected.replace(/\n+/, '');
+ }
+
+ // Remove the last newline
+ if (textArea.selectionEnd - textArea.selectionStart > selected.replace(/\n$/, '').length) {
+ removedLastNewLine = true;
+ selected = selected.replace(/\n$/, '');
+ }
+
selectedSplit = selected.split('\n');
startChar = !wrap && textArea.selectionStart > 0 ? '\n' : '';
+
if (selectedSplit.length > 1 && (!wrap || (blockTag != null))) {
if (blockTag != null) {
insertText = this.blockTagText(text, textArea, blockTag, selected);
@@ -62,6 +93,15 @@
} else {
insertText = "" + startChar + tag + selected + (wrap ? tag : ' ');
}
+
+ if (removedFirstNewLine) {
+ insertText = '\n' + insertText;
+ }
+
+ if (removedLastNewLine) {
+ insertText += '\n';
+ }
+
if (document.queryCommandSupported('insertText')) {
inserted = document.execCommand('insertText', false, insertText);
}
@@ -74,9 +114,9 @@
document.execCommand("ms-endUndoUnit");
} catch (error) {}
}
- return this.moveCursor(textArea, tag, wrap);
+ return this.moveCursor(textArea, tag, wrap, removedLastNewLine);
};
- gl.text.moveCursor = function(textArea, tag, wrapped) {
+ gl.text.moveCursor = function(textArea, tag, wrapped, removedLastNewLine) {
var pos;
if (!textArea.setSelectionRange) {
return;
@@ -87,6 +127,11 @@
} else {
pos = textArea.selectionStart;
}
+
+ if (removedLastNewLine) {
+ pos -= 1;
+ }
+
return textArea.setSelectionRange(pos, pos);
}
};
diff --git a/app/assets/javascripts/lib/vue_resource.js.es6 b/app/assets/javascripts/lib/vue_resource.js.es6
new file mode 100644
index 00000000000..eff1dcabfa2
--- /dev/null
+++ b/app/assets/javascripts/lib/vue_resource.js.es6
@@ -0,0 +1,2 @@
+//= require vue
+//= require vue-resource
diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js
index b0f834705c3..9af89b79f84 100644
--- a/app/assets/javascripts/line_highlighter.js
+++ b/app/assets/javascripts/line_highlighter.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, no-underscore-dangle, no-param-reassign, no-undef, prefer-template, quotes, comma-dangle, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, spaced-comment, radix, no-else-return, max-len, no-plusplus, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, no-underscore-dangle, no-param-reassign, prefer-template, quotes, comma-dangle, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, spaced-comment, radix, no-else-return, max-len, no-plusplus, padded-blocks */
+
// LineHighlighter
//
// Handles single- and multi-line selection and highlight for blob views.
diff --git a/app/assets/javascripts/member_expiration_date.js b/app/assets/javascripts/member_expiration_date.js.es6
index 7741cd29793..bf6c0ec2798 100644
--- a/app/assets/javascripts/member_expiration_date.js
+++ b/app/assets/javascripts/member_expiration_date.js.es6
@@ -1,30 +1,29 @@
-/* eslint-disable func-names, space-before-function-paren, vars-on-top, no-var, object-shorthand, comma-dangle, max-len */
-(function() {
+(() => {
// Add datepickers to all `js-access-expiration-date` elements. If those elements are
// children of an element with the `clearable-input` class, and have a sibling
// `js-clear-input` element, then show that element when there is a value in the
// datepicker, and make clicking on that element clear the field.
//
- gl.MemberExpirationDate = function() {
+ window.gl = window.gl || {};
+ gl.MemberExpirationDate = (selector = '.js-access-expiration-date') => {
function toggleClearInput() {
$(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== '');
}
-
- var inputs = $('.js-access-expiration-date');
+ const inputs = $(selector);
inputs.datepicker({
dateFormat: 'yy-mm-dd',
minDate: 1,
- onSelect: function () {
+ onSelect: function onSelect() {
$(this).trigger('change');
toggleClearInput.call(this);
- }
+ },
});
- inputs.next('.js-clear-input').on('click', function(event) {
+ inputs.next('.js-clear-input').on('click', function clicked(event) {
event.preventDefault();
- var input = $(this).closest('.clearable-input').find('.js-access-expiration-date');
+ const input = $(this).closest('.clearable-input').find(selector);
input.datepicker('setDate', null)
.trigger('change');
toggleClearInput.call(input);
diff --git a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es6 b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es6
index 9e4ffd07dbd..f95b079c972 100644
--- a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es6
+++ b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js.es6
@@ -1,4 +1,8 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, quote-props, no-useless-computed-key, object-shorthand, prefer-const, no-new, padded-blocks, no-param-reassign, semi, max-len */
+/* global Vue */
+/* global ace */
+/* global Flash */
+
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
diff --git a/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js.es6 b/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js.es6
index 23c4618af70..74544b7d0c7 100644
--- a/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js.es6
+++ b/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable padded-blocks, no-param-reassign, comma-dangle */
+/* global Vue */
+
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
diff --git a/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js.es6 b/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js.es6
index 4ccbdcd6daa..78c00c31c16 100644
--- a/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js.es6
+++ b/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable padded-blocks, no-param-reassign, comma-dangle */
+/* global Vue */
+
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
@@ -19,7 +21,7 @@
</td>
<td class="diff-line-num old_line" :class="lineCssClass(line)" v-if="!line.isHeader">{{line.lineNumber}}</td>
<td class="line_content parallel" :class="lineCssClass(line)" v-if="!line.isHeader" v-html="line.richText"></td>
- </template>
+ </template>
</tr>
</table>
`,
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_service.js.es6 b/app/assets/javascripts/merge_conflicts/merge_conflict_service.js.es6
index 8a7519b0786..8df3170edac 100644
--- a/app/assets/javascripts/merge_conflicts/merge_conflict_service.js.es6
+++ b/app/assets/javascripts/merge_conflicts/merge_conflict_service.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable no-param-reassign, comma-dangle, no-extra-semi, padded-blocks */
+
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es6 b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es6
index f94e51e783c..53b44007510 100644
--- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es6
+++ b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, object-shorthand, no-dupe-keys, no-param-reassign, no-plusplus, camelcase, prefer-const, no-nested-ternary, no-continue, semi, func-call-spacing, no-spaced-func, padded-blocks, max-len */
+/* global Cookies */
+/* global Vue */
+
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6
index 815443fb54e..83520702f9b 100644
--- a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6
+++ b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable new-cap, comma-dangle, no-new, semi */
+/* global Vue */
+/* global Flash */
+
//= require vue
//= require ./merge_conflict_store
//= require ./merge_conflict_service
diff --git a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js.es6 b/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js.es6
index c8de586aa21..e89b35d5407 100644
--- a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js.es6
+++ b/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable no-param-reassign, comma-dangle, padded-blocks */
+
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
diff --git a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js.es6 b/app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js.es6
index 88c3a20ce13..a4aca85d460 100644
--- a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js.es6
+++ b/app/assets/javascripts/merge_conflicts/mixins/line_conflict_utils.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable no-param-reassign, quote-props, comma-dangle, padded-blocks */
+
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js
index 88c3636be6c..244c2f6746c 100644
--- a/app/assets/javascripts/merge_request.js
+++ b/app/assets/javascripts/merge_request.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, no-undef, no-underscore-dangle, one-var, one-var-declaration-per-line, consistent-return, dot-notation, quote-props, comma-dangle, object-shorthand, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, no-underscore-dangle, one-var, one-var-declaration-per-line, consistent-return, dot-notation, quote-props, comma-dangle, object-shorthand, padded-blocks, max-len, prefer-arrow-callback */
+/* global MergeRequestTabs */
/*= require jquery.waitforimages */
/*= require task_list */
@@ -26,6 +27,7 @@
// Prevent duplicate event bindings
this.disableTaskList();
this.initMRBtnListeners();
+ this.initCommitMessageListeners();
if ($("a.btn-close").length) {
this.initTaskList();
}
@@ -107,6 +109,26 @@
// note so that we can re-use its form here
};
+ MergeRequest.prototype.initCommitMessageListeners = function() {
+ var textarea = $('textarea.js-commit-message');
+
+ $('a.js-with-description-link').on('click', function(e) {
+ e.preventDefault();
+
+ textarea.val(textarea.data('messageWithDescription'));
+ $('p.js-with-description-hint').hide();
+ $('p.js-without-description-hint').show();
+ });
+
+ $('a.js-without-description-link').on('click', function(e) {
+ e.preventDefault();
+
+ textarea.val(textarea.data('messageWithoutDescription'));
+ $('p.js-with-description-hint').show();
+ $('p.js-without-description-hint').hide();
+ });
+ };
+
return MergeRequest;
})();
diff --git a/app/assets/javascripts/merge_request_tabs.js.es6 b/app/assets/javascripts/merge_request_tabs.js.es6
index 3ec0f1fd613..4c8c28af755 100644
--- a/app/assets/javascripts/merge_request_tabs.js.es6
+++ b/app/assets/javascripts/merge_request_tabs.js.es6
@@ -59,16 +59,13 @@
class MergeRequestTabs {
- constructor({ action, setUrl, buildsLoaded, stubLocation } = {}) {
+ constructor({ action, setUrl, stubLocation } = {}) {
this.diffsLoaded = false;
- this.buildsLoaded = false;
this.pipelinesLoaded = false;
this.commitsLoaded = false;
this.fixedLayoutPref = null;
this.setUrl = setUrl !== undefined ? setUrl : true;
- this.buildsLoaded = buildsLoaded || false;
-
this.setCurrentAction = this.setCurrentAction.bind(this);
this.tabShown = this.tabShown.bind(this);
this.showTab = this.showTab.bind(this);
@@ -119,10 +116,6 @@
$.scrollTo('.merge-request-details .merge-request-tabs', {
offset: -navBarHeight,
});
- } else if (action === 'builds') {
- this.loadBuilds($target.attr('href'));
- this.expandView();
- this.resetViewContainer();
} else if (action === 'pipelines') {
this.loadPipelines($target.attr('href'));
this.expandView();
@@ -180,8 +173,8 @@
setCurrentAction(action) {
this.currentAction = action === 'show' ? 'notes' : action;
- // Remove a trailing '/commits' '/diffs' '/builds' '/pipelines' '/new' '/new/diffs'
- let newState = location.pathname.replace(/\/(commits|diffs|builds|pipelines|new|new\/diffs)(\.html)?\/?$/, '');
+ // Remove a trailing '/commits' '/diffs' '/pipelines' '/new' '/new/diffs'
+ let newState = location.pathname.replace(/\/(commits|diffs|pipelines|new|new\/diffs)(\.html)?\/?$/, '');
// Append the new action if we're on a tab other than 'notes'
if (this.currentAction !== 'notes') {
@@ -244,29 +237,8 @@
}
this.diffsLoaded = true;
- const diffPage = new gl.Diff();
-
- const locationHash = gl.utils.getLocationHash();
- const anchoredDiff = locationHash && locationHash.split('_')[0];
- if (anchoredDiff) {
- diffPage.openAnchoredDiff(anchoredDiff, () => this.scrollToElement('#diffs'));
- }
- },
- });
- }
-
- loadBuilds(source) {
- if (this.buildsLoaded) {
- return;
- }
- this.ajaxGet({
- url: `${source}.json`,
- success: (data) => {
- document.querySelector('div#builds').innerHTML = data.html;
- gl.utils.localTimeAgo($('.js-timeago', 'div#builds'));
- this.buildsLoaded = true;
- new gl.Pipelines();
- this.scrollToElement('#builds');
+ new gl.Diff();
+ this.scrollToElement('#diffs');
},
});
}
@@ -282,6 +254,10 @@
gl.utils.localTimeAgo($('.js-timeago', '#pipelines'));
this.pipelinesLoaded = true;
this.scrollToElement('#pipelines');
+
+ new gl.MiniPipelineGraph({
+ container: '.js-pipeline-table',
+ });
},
});
}
diff --git a/app/assets/javascripts/merge_request_widget.js.es6 b/app/assets/javascripts/merge_request_widget.js.es6
index 7022aa1263b..0305aeb07d9 100644
--- a/app/assets/javascripts/merge_request_widget.js.es6
+++ b/app/assets/javascripts/merge_request_widget.js.es6
@@ -1,5 +1,10 @@
-/* eslint-disable */
- ((global) => {
+/* eslint-disable max-len, no-var, func-names, space-before-function-paren, vars-on-top, no-plusplus, comma-dangle, no-return-assign, consistent-return, no-param-reassign, one-var, one-var-declaration-per-line, quotes, prefer-template, no-else-return, prefer-arrow-callback, no-unused-vars, no-underscore-dangle, no-shadow, no-mixed-operators, template-curly-spacing, camelcase, default-case, wrap-iife, semi, padded-blocks */
+/* global notify */
+/* global notifyPermissions */
+/* global merge_request_widget */
+/* global Turbolinks */
+
+((global) => {
var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
const DEPLOYMENT_TEMPLATE = `<div class="mr-widget-heading" id="<%- id %>">
@@ -27,7 +32,7 @@
</div>
</div>`;
- global.MergeRequestWidget = (function() {
+ global.MergeRequestWidget = (function() {
function MergeRequestWidget(opts) {
// Initialize MergeRequestWidget behavior
//
@@ -69,7 +74,7 @@
MergeRequestWidget.prototype.addEventListeners = function() {
var allowedPages;
- allowedPages = ['show', 'commits', 'builds', 'pipelines', 'changes'];
+ allowedPages = ['show', 'commits', 'pipelines', 'changes'];
$(document).on('page:change.merge_request', (function(_this) {
return function() {
var page;
@@ -82,10 +87,10 @@
};
MergeRequestWidget.prototype.retrieveSuccessIcon = function() {
- const $ciSuccessIcon = $('.js-success-icon');
- this.$ciSuccessIcon = $ciSuccessIcon.html();
- $ciSuccessIcon.remove();
- }
+ const $ciSuccessIcon = $('.js-success-icon');
+ this.$ciSuccessIcon = $ciSuccessIcon.html();
+ $ciSuccessIcon.remove();
+ }
MergeRequestWidget.prototype.mergeInProgress = function(deleteSourceBranch) {
if (deleteSourceBranch == null) {
@@ -168,7 +173,6 @@
message = message.replace('{{title}}', data.title);
notify(title, message, _this.opts.gitlab_icon, function() {
this.close();
- return Turbolinks.visit(_this.opts.builds_path);
});
}
}
@@ -204,7 +208,7 @@
const template = _.template(templateString)(environment)
this.$widgetBody.before(template);
}
- };
+ };
MergeRequestWidget.prototype.showCIStatus = function(state) {
var allowed_states;
@@ -246,4 +250,4 @@
})();
- })(window.gl || (window.gl = {}));
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/merge_request_widget/ci_bundle.js.es6 b/app/assets/javascripts/merge_request_widget/ci_bundle.js.es6
new file mode 100644
index 00000000000..2b074994b4a
--- /dev/null
+++ b/app/assets/javascripts/merge_request_widget/ci_bundle.js.es6
@@ -0,0 +1,42 @@
+/* global merge_request_widget */
+
+(() => {
+ $(() => {
+ /* TODO: This needs a better home, or should be refactored. It was previously contained
+ * in a script tag in app/views/projects/merge_requests/widget/open/_accept.html.haml,
+ * but Vue chokes on script tags and prevents their execution. So it was moved here
+ * temporarily.
+ * */
+
+ if ($('.accept-mr-form').length) {
+ $('.accept-mr-form').on('ajax:send', () => {
+ $('.accept-mr-form :input').disable();
+ });
+
+ $('.accept_merge_request').on('click', () => {
+ $('.js-merge-button').html('<i class="fa fa-spinner fa-spin"></i> Merge in progress');
+ });
+
+ $('.merge_when_build_succeeds').on('click', () => {
+ $('#merge_when_build_succeeds').val('1');
+ });
+
+ $('.js-merge-dropdown a').on('click', (e) => {
+ e.preventDefault();
+ $(this).closest('form').submit();
+ });
+ } else if ($('.rebase-in-progress').length) {
+ merge_request_widget.rebaseInProgress();
+ } else if ($('.rebase-mr-form').length) {
+ $('.rebase-mr-form').on('ajax:send', () => {
+ $('.rebase-mr-form :input').disable();
+ });
+
+ $('.js-rebase-button').on('click', () => {
+ $('.js-rebase-button').html("<i class='fa fa-spinner fa-spin'></i> Rebase in progress");
+ });
+ } else {
+ merge_request_widget.getMergeStatus();
+ }
+ });
+})();
diff --git a/app/assets/javascripts/merged_buttons.js b/app/assets/javascripts/merged_buttons.js
index 15a12c3d985..9f8af46c715 100644
--- a/app/assets/javascripts/merged_buttons.js
+++ b/app/assets/javascripts/merged_buttons.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, padded-blocks, max-len */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js
index db7561a3a75..42152362e60 100644
--- a/app/assets/javascripts/milestone.js
+++ b/app/assets/javascripts/milestone.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-use-before-define, camelcase, quotes, object-shorthand, no-shadow, no-unused-vars, no-undef, comma-dangle, no-var, prefer-template, no-underscore-dangle, consistent-return, one-var, one-var-declaration-per-line, default-case, prefer-arrow-callback, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-use-before-define, camelcase, quotes, object-shorthand, no-shadow, no-unused-vars, comma-dangle, no-var, prefer-template, no-underscore-dangle, consistent-return, one-var, one-var-declaration-per-line, default-case, prefer-arrow-callback, padded-blocks, max-len */
+/* global Flash */
+
(function() {
this.Milestone = (function() {
Milestone.updateIssue = function(li, issue_url, data) {
diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js
index 67796083790..28054b78249 100644
--- a/app/assets/javascripts/milestone_select.js
+++ b/app/assets/javascripts/milestone_select.js
@@ -1,4 +1,8 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-underscore-dangle, prefer-arrow-callback, max-len, one-var, one-var-declaration-per-line, no-unused-vars, object-shorthand, comma-dangle, no-else-return, no-self-compare, consistent-return, no-undef, no-param-reassign, no-shadow, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-underscore-dangle, prefer-arrow-callback, max-len, one-var, one-var-declaration-per-line, no-unused-vars, object-shorthand, comma-dangle, no-else-return, no-self-compare, consistent-return, no-param-reassign, no-shadow, padded-blocks */
+/* global Vue */
+/* global Issuable */
+/* global ListMilestone */
+
(function() {
this.MilestoneSelect = (function() {
function MilestoneSelect(currentProject) {
diff --git a/app/assets/javascripts/mini_pipeline_graph_dropdown.js.es6 b/app/assets/javascripts/mini_pipeline_graph_dropdown.js.es6
new file mode 100644
index 00000000000..90b3366f14b
--- /dev/null
+++ b/app/assets/javascripts/mini_pipeline_graph_dropdown.js.es6
@@ -0,0 +1,96 @@
+/* eslint-disable no-new */
+/* global Flash */
+
+/**
+ * In each pipelines table we have a mini pipeline graph for each pipeline.
+ *
+ * When we click in a pipeline stage, we need to make an API call to get the
+ * builds list to render in a dropdown.
+ *
+ * The container should be the table element.
+ *
+ * The stage icon clicked needs to have the following HTML structure:
+ * <div>
+ * <button class="dropdown js-builds-dropdown-button"></button>
+ * <div class="js-builds-dropdown-container"></div>
+ * </div>
+ */
+(() => {
+ class MiniPipelineGraph {
+ constructor(opts = {}) {
+ this.container = opts.container || '';
+ this.dropdownListSelector = '.js-builds-dropdown-container';
+ this.getBuildsList = this.getBuildsList.bind(this);
+
+ this.bindEvents();
+ }
+
+ /**
+ * Adds and removes the event listener.
+ */
+ bindEvents() {
+ const dropdownButtonSelector = 'button.js-builds-dropdown-button';
+
+ $(this.container).off('click', dropdownButtonSelector, this.getBuildsList)
+ .on('click', dropdownButtonSelector, this.getBuildsList);
+ }
+
+ /**
+ * For the clicked stage, renders the given data in the dropdown list.
+ *
+ * @param {HTMLElement} stageContainer
+ * @param {Object} data
+ */
+ renderBuildsList(stageContainer, data) {
+ const dropdownContainer = stageContainer.parentElement.querySelector(
+ `${this.dropdownListSelector} .js-builds-dropdown-list`,
+ );
+
+ dropdownContainer.innerHTML = data;
+ }
+
+ /**
+ * For the clicked stage, gets the list of builds.
+ *
+ * @param {Object} e
+ * @return {Promise}
+ */
+ getBuildsList(e) {
+ const button = e.currentTarget;
+ const endpoint = button.dataset.stageEndpoint;
+
+ return $.ajax({
+ dataType: 'json',
+ type: 'GET',
+ url: endpoint,
+ beforeSend: () => {
+ this.renderBuildsList(button, '');
+ this.toggleLoading(button);
+ },
+ success: (data) => {
+ this.toggleLoading(button);
+ this.renderBuildsList(button, data.html);
+ },
+ error: () => {
+ this.toggleLoading(button);
+ new Flash('An error occurred while fetching the builds.', 'alert');
+ },
+ });
+ }
+
+ /**
+ * Toggles the visibility of the loading icon.
+ *
+ * @param {HTMLElement} stageContainer
+ * @return {type}
+ */
+ toggleLoading(stageContainer) {
+ stageContainer.parentElement.querySelector(
+ `${this.dropdownListSelector} .js-builds-dropdown-loading`,
+ ).classList.toggle('hidden');
+ }
+ }
+
+ window.gl = window.gl || {};
+ window.gl.MiniPipelineGraph = MiniPipelineGraph;
+})();
diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js
index 87c903ec576..6633f2c2709 100644
--- a/app/assets/javascripts/namespace_select.js
+++ b/app/assets/javascripts/namespace_select.js
@@ -1,8 +1,10 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, one-var, vars-on-top, one-var-declaration-per-line, comma-dangle, object-shorthand, no-else-return, prefer-template, quotes, no-undef, prefer-arrow-callback, padded-blocks, no-param-reassign, no-cond-assign, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, one-var, vars-on-top, one-var-declaration-per-line, comma-dangle, object-shorthand, no-else-return, prefer-template, quotes, prefer-arrow-callback, padded-blocks, no-param-reassign, no-cond-assign, max-len */
+/* global Api */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
- this.NamespaceSelect = (function() {
+ window.NamespaceSelect = (function() {
function NamespaceSelect(opts) {
this.onSelectItem = bind(this.onSelectItem, this);
var fieldName, showAny;
@@ -64,7 +66,7 @@
})();
- this.NamespaceSelects = (function() {
+ window.NamespaceSelects = (function() {
function NamespaceSelects(opts) {
var ref;
if (opts == null) {
@@ -74,7 +76,7 @@
this.$dropdowns.each(function(i, dropdown) {
var $dropdown;
$dropdown = $(dropdown);
- return new NamespaceSelect({
+ return new window.NamespaceSelect({
dropdown: $dropdown
});
});
diff --git a/app/assets/javascripts/network/branch_graph.js b/app/assets/javascripts/network/branch_graph.js
index e3dc599b90a..20a68780cd5 100644
--- a/app/assets/javascripts/network/branch_graph.js
+++ b/app/assets/javascripts/network/branch_graph.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, comma-dangle, one-var, one-var-declaration-per-line, no-mixed-operators, new-cap, no-undef, no-plusplus, no-loop-func, no-floating-decimal, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase, max-len, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, comma-dangle, one-var, one-var-declaration-per-line, no-mixed-operators, new-cap, no-plusplus, no-loop-func, no-floating-decimal, consistent-return, no-unused-vars, prefer-template, prefer-arrow-callback, camelcase, max-len, padded-blocks */
+/* global Raphael */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
@@ -354,7 +356,7 @@
icon = this.image(gon.relative_url_root + commit.author.icon, x, y, 20, 20);
nameText = this.text(x + 25, y + 10, commit.author.name);
idText = this.text(x, y + 35, commit.id);
- messageText = this.text(x, y + 50, commit.message);
+ messageText = this.text(x, y + 50, commit.message.replace(/\r?\n/g, " \n "));
textSet = this.set(icon, nameText, idText, messageText).attr({
"text-anchor": "start",
font: "12px Monaco, monospace"
@@ -366,6 +368,7 @@
idText.attr({
fill: "#AAA"
});
+ messageText.node.style["white-space"] = "pre";
this.textWrap(messageText, boxWidth - 50);
rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({
fill: "#FFF",
@@ -402,16 +405,21 @@
s.push("\n");
x = 0;
}
- x += word.length * letterWidth;
- s.push(word + " ");
+ if (word === "\n") {
+ s.push("\n");
+ x = 0;
+ } else {
+ s.push(word + " ");
+ x += word.length * letterWidth;
+ }
}
t.attr({
- text: s.join("")
+ text: s.join("").trim()
});
b = t.getBBox();
- h = Math.abs(b.y2) - Math.abs(b.y) + 1;
+ h = Math.abs(b.y2) + 1;
return t.attr({
- y: b.y + h
+ y: h
});
};
diff --git a/app/assets/javascripts/network/network.js b/app/assets/javascripts/network/network.js
index 5a8f723a27b..2367d2497b2 100644
--- a/app/assets/javascripts/network/network.js
+++ b/app/assets/javascripts/network/network.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, no-undef, quote-props, prefer-template, comma-dangle, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, quote-props, prefer-template, comma-dangle, padded-blocks, max-len */
+/* global BranchGraph */
+
(function() {
this.Network = (function() {
function Network(opts) {
diff --git a/app/assets/javascripts/network/network_bundle.js b/app/assets/javascripts/network/network_bundle.js
index 732d92845cb..17833d3419a 100644
--- a/app/assets/javascripts/network/network_bundle.js
+++ b/app/assets/javascripts/network/network_bundle.js
@@ -1,4 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, quotes, no-var, vars-on-top, camelcase, no-undef, comma-dangle, consistent-return, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, quotes, no-var, vars-on-top, camelcase, comma-dangle, consistent-return, padded-blocks, max-len */
+/* global Network */
+/* global ShortcutsNetwork */
+
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index 0ca0e255595..fac21f8cd32 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -1,4 +1,9 @@
-/* eslint-disable no-restricted-properties, func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, camelcase, no-unused-expressions, quotes, max-len, one-var, one-var-declaration-per-line, default-case, prefer-template, no-undef, consistent-return, no-alert, no-return-assign, no-param-reassign, prefer-arrow-callback, no-else-return, comma-dangle, no-new, brace-style, no-lonely-if, vars-on-top, no-unused-vars, semi, indent, no-sequences, no-shadow, newline-per-chained-call, no-useless-escape, radix, padded-blocks, max-len */
+/* eslint-disable no-restricted-properties, func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, camelcase, no-unused-expressions, quotes, max-len, one-var, one-var-declaration-per-line, default-case, prefer-template, consistent-return, no-alert, no-return-assign, no-param-reassign, prefer-arrow-callback, no-else-return, comma-dangle, no-new, brace-style, no-lonely-if, vars-on-top, no-unused-vars, semi, indent, no-sequences, no-shadow, newline-per-chained-call, no-useless-escape, radix, padded-blocks */
+/* global Flash */
+/* global GLForm */
+/* global Autosave */
+/* global ResolveService */
+/* global mrRefreshWidgetUrl */
/*= require autosave */
/*= require autosize */
@@ -48,6 +53,12 @@
this.setupMainTargetNoteForm();
this.initTaskList();
this.collapseLongCommitList();
+
+ // We are in the Merge Requests page so we need another edit form for Changes tab
+ if (gl.utils.getPagePath(1) === 'merge_requests') {
+ $('.note-edit-form').clone()
+ .addClass('mr-note-edit-form').insertAfter('.note-edit-form');
+ }
}
Notes.prototype.addBinding = function() {
@@ -59,7 +70,7 @@
// change note in UI after update
$(document).on("ajax:success", "form.edit-note", this.updateNote);
// Edit note link
- $(document).on("click", ".js-note-edit", this.showEditForm);
+ $(document).on("click", ".js-note-edit", this.showEditForm.bind(this));
$(document).on("click", ".note-edit-cancel", this.cancelEdit);
// Reopen and close actions for Issue/MR combined with note form submit
$(document).on("click", ".js-comment-button", this.updateCloseButton);
@@ -234,6 +245,16 @@
};
+ Notes.prototype.handleCreateChanges = function(note) {
+ if (typeof note === 'undefined') {
+ return;
+ }
+
+ if (note.commands_changes && note.commands_changes.indexOf('merge') !== -1) {
+ $.get(mrRefreshWidgetUrl);
+ }
+ };
+
/*
Render note in main comments area.
@@ -305,7 +326,7 @@
}
row = form.closest("tr");
note_html = $(note.html);
- note_html.syntaxHighlight();
+ note_html.renderGFM();
// is this the first note of discussion?
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']");
if ((note.original_discussion_id != null) && discussionContainer.length === 0) {
@@ -322,7 +343,7 @@
discussionContainer.append(note_html);
// Init discussion on 'Discussion' page if it is merge request page
if ($('body').attr('data-page').indexOf('projects:merge_request') === 0) {
- $('ul.main-notes-list').append(note.discussion_html).syntaxHighlight();
+ $('ul.main-notes-list').append(note.discussion_html).renderGFM();
}
} else {
// append new note to all matching discussions
@@ -419,6 +440,7 @@
*/
Notes.prototype.addNote = function(xhr, note, status) {
+ this.handleCreateChanges(note);
return this.renderNote(note);
};
@@ -462,8 +484,9 @@
var $html, $note_li;
// Convert returned HTML to a jQuery object so we can modify it further
$html = $(note.html);
+ this.revertNoteEditForm();
gl.utils.localTimeAgo($('.js-timeago', $html));
- $html.syntaxHighlight();
+ $html.renderGFM();
$html.find('.js-task-list-container').taskList('enable');
// Find the note's `li` element by ID and replace it with the updated HTML
$note_li = $('.note-row-' + note.id);
@@ -476,48 +499,56 @@
};
+ Notes.prototype.checkContentToAllowEditing = function($el) {
+ var initialContent = $el.find('.original-note-content').text().trim();
+ var currentContent = $el.find('.note-textarea').val();
+ var isAllowed = true;
+
+ if (currentContent === initialContent) {
+ this.removeNoteEditForm($el);
+ }
+ else {
+ var $buttons = $el.find('.note-form-actions');
+ var isWidgetVisible = gl.utils.isInViewport($el.get(0));
+
+ if (!isWidgetVisible) {
+ gl.utils.scrollToElement($el);
+ }
+
+ $el.find('.js-edit-warning').show();
+ isAllowed = false;
+ }
+
+ return isAllowed;
+ }
+
+
/*
Called in response to clicking the edit note link
Replaces the note text with the note edit form
Adds a data attribute to the form with the original content of the note for cancellations
- */
-
+ */
Notes.prototype.showEditForm = function(e, scrollTo, myLastNote) {
- var $noteText, done, form, note;
e.preventDefault();
- note = $(this).closest(".note");
- note.addClass("is-editting");
- form = note.find(".note-edit-form");
- form.addClass('current-note-edit-form');
- // Show the attachment delete link
- note.find(".js-note-attachment-delete").show();
- done = function($noteText) {
- var noteTextVal;
- // Neat little trick to put the cursor at the end
- noteTextVal = $noteText.val();
- // Store the original note text in a data attribute to retrieve if a user cancels edit.
- form.find('form.edit-note').data('original-note', noteTextVal);
- return $noteText.val('').val(noteTextVal);
- };
- new GLForm(form);
- if ((scrollTo != null) && (myLastNote != null)) {
- // scroll to the bottom
- // so the open of the last element doesn't make a jump
- $('html, body').scrollTop($(document).height());
- return $('html, body').animate({
- scrollTop: myLastNote.offset().top - 150
- }, 500, function() {
- var $noteText;
- $noteText = form.find(".js-note-text");
- $noteText.focus();
- return done($noteText);
- });
- } else {
- $noteText = form.find('.js-note-text');
- $noteText.focus();
- return done($noteText);
+
+ var $target = $(e.target);
+ var $editForm = $(this.getEditFormSelector($target));
+ var $note = $target.closest('.note');
+ var $currentlyEditing = $('.note.is-editting:visible');
+
+ if ($currentlyEditing.length) {
+ var isEditAllowed = this.checkContentToAllowEditing($currentlyEditing);
+
+ if (!isEditAllowed) {
+ return;
+ }
}
+
+ $note.find('.js-note-attachment-delete').show();
+ $editForm.addClass('current-note-edit-form');
+ $note.addClass('is-editting');
+ this.putEditFormInPlace($target);
};
@@ -528,19 +559,41 @@
*/
Notes.prototype.cancelEdit = function(e) {
- var note;
e.preventDefault();
- note = $(e.target).closest('.note');
+ var $target = $(e.target);
+ var note = $target.closest('.note');
+ note.find('.js-edit-warning').hide();
+ this.revertNoteEditForm($target);
return this.removeNoteEditForm(note);
};
+ Notes.prototype.revertNoteEditForm = function($target) {
+ $target = $target || $('.note.is-editting:visible');
+ var selector = this.getEditFormSelector($target);
+ var $editForm = $(selector);
+
+ $editForm.insertBefore('.notes-form');
+ $editForm.find('.js-comment-button').enable();
+ $editForm.find('.js-edit-warning').hide();
+ };
+
+ Notes.prototype.getEditFormSelector = function($el) {
+ var selector = '.note-edit-form:not(.mr-note-edit-form)';
+
+ if ($el.parents('#diffs').length) {
+ selector = '.note-edit-form.mr-note-edit-form';
+ }
+
+ return selector;
+ };
+
Notes.prototype.removeNoteEditForm = function(note) {
- var form;
- form = note.find(".current-note-edit-form");
- note.removeClass("is-editting");
- form.removeClass("current-note-edit-form");
+ var form = note.find('.current-note-edit-form');
+ note.removeClass('is-editting');
+ form.removeClass('current-note-edit-form');
+ form.find('.js-edit-warning').hide();
// Replace markdown textarea text with original note text.
- return form.find(".js-note-text").val(form.find('form.edit-note').data('original-note'));
+ return form.find('.js-note-text').val(form.find('form.edit-note').data('original-note'));
};
@@ -671,7 +724,7 @@
*/
Notes.prototype.addDiffNote = function(e) {
- var $link, addForm, hasNotes, lineType, newForm, nextRow, noteForm, notesContent, replyButton, row, rowCssToAdd, targetContent;
+ var $link, addForm, hasNotes, lineType, newForm, nextRow, noteForm, notesContent, notesContentSelector, replyButton, row, rowCssToAdd, targetContent;
e.preventDefault();
$link = $(e.currentTarget);
row = $link.closest("tr");
@@ -833,15 +886,46 @@
Notes.prototype.initTaskList = function() {
this.enableTaskList();
- return $(document).on('tasklist:changed', '.note .js-task-list-container', this.updateTaskList);
+ return $(document).on('tasklist:changed', '.note .js-task-list-container', this.updateTaskList.bind(this));
};
Notes.prototype.enableTaskList = function() {
return $('.note .js-task-list-container').taskList('enable');
};
- Notes.prototype.updateTaskList = function() {
- return $('form', this).submit();
+ Notes.prototype.putEditFormInPlace = function($el) {
+ var $editForm = $(this.getEditFormSelector($el));
+ var $note = $el.closest('.note');
+
+ $editForm.insertAfter($note.find('.note-text'));
+
+ var $originalContentEl = $note.find('.original-note-content');
+ var originalContent = $originalContentEl.text().trim();
+ var postUrl = $originalContentEl.data('post-url');
+ var targetId = $originalContentEl.data('target-id');
+ var targetType = $originalContentEl.data('target-type');
+
+ new GLForm($editForm.find('form'));
+
+ $editForm.find('form')
+ .attr('action', postUrl)
+ .attr('data-remote', 'true');
+ $editForm.find('.js-form-target-id').val(targetId);
+ $editForm.find('.js-form-target-type').val(targetType);
+ $editForm.find('.js-note-text').focus().val(originalContent);
+ $editForm.find('.js-md-write-button').trigger('click');
+ $editForm.find('.referenced-users').hide();
+ }
+
+ Notes.prototype.updateTaskList = function(e) {
+ var $target = $(e.target);
+ var $list = $target.closest('.js-task-list-container');
+ var $editForm = $(this.getEditFormSelector($target));
+ var $note = $list.closest('.note');
+
+ this.putEditFormInPlace($list);
+ $editForm.find('#note_note').val($note.find('.original-task-list').val());
+ $('form', $list).submit();
};
Notes.prototype.updateNotesCount = function(updateCount) {
diff --git a/app/assets/javascripts/notifications_dropdown.js b/app/assets/javascripts/notifications_dropdown.js
index b152d26733f..5d0d594073d 100644
--- a/app/assets/javascripts/notifications_dropdown.js
+++ b/app/assets/javascripts/notifications_dropdown.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, consistent-return, prefer-arrow-callback, no-else-return, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, consistent-return, prefer-arrow-callback, no-else-return, padded-blocks, max-len */
+/* global Flash */
+
(function() {
this.NotificationsDropdown = (function() {
function NotificationsDropdown() {
@@ -17,7 +19,7 @@
});
$(document).off('ajax:success', '.notification-form').on('ajax:success', '.notification-form', function(e, data) {
if (data.saved) {
- return $(e.currentTarget).closest('.notification-dropdown').replaceWith(data.html);
+ return $(e.currentTarget).closest('.js-notification-dropdown').replaceWith(data.html);
} else {
return new Flash('Failed to save new settings', 'alert');
}
diff --git a/app/assets/javascripts/pipelines.js.es6 b/app/assets/javascripts/pipelines.js.es6
index fb95648e1c7..0b09ad113a3 100644
--- a/app/assets/javascripts/pipelines.js.es6
+++ b/app/assets/javascripts/pipelines.js.es6
@@ -1,6 +1,7 @@
+/* eslint-disable no-new, guard-for-in, no-restricted-syntax, no-continue, padded-blocks, no-param-reassign, max-len */
+
//= require lib/utils/bootstrap_linked_tabs
-/* eslint-disable */
((global) => {
class Pipelines {
diff --git a/app/assets/javascripts/preview_markdown.js b/app/assets/javascripts/preview_markdown.js
index 3723aa24942..89f7e976934 100644
--- a/app/assets/javascripts/preview_markdown.js
+++ b/app/assets/javascripts/preview_markdown.js
@@ -1,13 +1,17 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, one-var, one-var-declaration-per-line, wrap-iife, no-else-return, consistent-return, object-shorthand, comma-dangle, no-param-reassign, padded-blocks, no-undef, camelcase, prefer-arrow-callback, max-len */
+/* eslint-disable func-names, no-var, object-shorthand, comma-dangle, prefer-arrow-callback */
+
// MarkdownPreview
//
// Handles toggling the "Write" and "Preview" tab clicks, rendering the preview,
// and showing a warning when more than `x` users are referenced.
//
-(function() {
- var lastTextareaPreviewed, markdownPreview, previewButtonSelector, writeButtonSelector;
+(function () {
+ var lastTextareaPreviewed;
+ var markdownPreview;
+ var previewButtonSelector;
+ var writeButtonSelector;
- this.MarkdownPreview = (function() {
+ window.MarkdownPreview = (function () {
function MarkdownPreview() {}
// Minimum number of users referenced before triggering a warning
@@ -15,75 +19,73 @@
MarkdownPreview.prototype.ajaxCache = {};
- MarkdownPreview.prototype.showPreview = function(form) {
- var mdText, preview;
- preview = form.find('.js-md-preview');
- mdText = form.find('textarea.markdown-area').val();
+ MarkdownPreview.prototype.showPreview = function ($form) {
+ var mdText;
+ var preview = $form.find('.js-md-preview');
+ if (preview.hasClass('md-preview-loading')) {
+ return;
+ }
+ mdText = $form.find('textarea.markdown-area').val();
+
if (mdText.trim().length === 0) {
preview.text('Nothing to preview.');
- return this.hideReferencedUsers(form);
+ this.hideReferencedUsers($form);
} else {
- preview.text('Loading...');
- return this.renderMarkdown(mdText, (function(_this) {
- return function(response) {
- preview.html(response.body);
- preview.syntaxHighlight();
- return _this.renderReferencedUsers(response.references.users, form);
- };
- })(this));
+ preview.addClass('md-preview-loading').text('Loading...');
+ this.fetchMarkdownPreview(mdText, (function (response) {
+ preview.removeClass('md-preview-loading').html(response.body);
+ preview.renderGFM();
+ this.renderReferencedUsers(response.references.users, $form);
+ }).bind(this));
}
};
- MarkdownPreview.prototype.renderMarkdown = function(text, success) {
+ MarkdownPreview.prototype.fetchMarkdownPreview = function (text, success) {
if (!window.preview_markdown_path) {
return;
}
if (text === this.ajaxCache.text) {
- return success(this.ajaxCache.response);
+ success(this.ajaxCache.response);
+ return;
}
- return $.ajax({
+ $.ajax({
type: 'POST',
url: window.preview_markdown_path,
data: {
text: text
},
dataType: 'json',
- success: (function(_this) {
- return function(response) {
- _this.ajaxCache = {
- text: text,
- response: response
- };
- return success(response);
+ success: (function (response) {
+ this.ajaxCache = {
+ text: text,
+ response: response
};
- })(this)
+ success(response);
+ }).bind(this)
});
};
- MarkdownPreview.prototype.hideReferencedUsers = function(form) {
- var referencedUsers;
- referencedUsers = form.find('.referenced-users');
- return referencedUsers.hide();
+ MarkdownPreview.prototype.hideReferencedUsers = function ($form) {
+ $form.find('.referenced-users').hide();
};
- MarkdownPreview.prototype.renderReferencedUsers = function(users, form) {
+ MarkdownPreview.prototype.renderReferencedUsers = function (users, $form) {
var referencedUsers;
- referencedUsers = form.find('.referenced-users');
+ referencedUsers = $form.find('.referenced-users');
if (referencedUsers.length) {
if (users.length >= this.referenceThreshold) {
referencedUsers.show();
- return referencedUsers.find('.js-referenced-users-count').text(users.length);
+ referencedUsers.find('.js-referenced-users-count').text(users.length);
} else {
- return referencedUsers.hide();
+ referencedUsers.hide();
}
}
};
return MarkdownPreview;
+ }());
- })();
-
- markdownPreview = new MarkdownPreview();
+ markdownPreview = new window.MarkdownPreview();
previewButtonSelector = '.js-md-preview-button';
@@ -91,19 +93,14 @@
lastTextareaPreviewed = null;
- $.fn.setupMarkdownPreview = function() {
- var $form, form_textarea;
- $form = $(this);
- form_textarea = $form.find('textarea.markdown-area');
- form_textarea.on('input', function() {
- return markdownPreview.hideReferencedUsers($form);
- });
- return form_textarea.on('blur', function() {
- return markdownPreview.showPreview($form);
+ $.fn.setupMarkdownPreview = function () {
+ var $form = $(this);
+ $form.find('textarea.markdown-area').on('input', function () {
+ markdownPreview.hideReferencedUsers($form);
});
};
- $(document).on('markdown-preview:show', function(e, $form) {
+ $(document).on('markdown-preview:show', function (e, $form) {
if (!$form) {
return;
}
@@ -114,10 +111,10 @@
// toggle content
$form.find('.md-write-holder').hide();
$form.find('.md-preview-holder').show();
- return markdownPreview.showPreview($form);
+ markdownPreview.showPreview($form);
});
- $(document).on('markdown-preview:hide', function(e, $form) {
+ $(document).on('markdown-preview:hide', function (e, $form) {
if (!$form) {
return;
}
@@ -128,34 +125,33 @@
// toggle content
$form.find('.md-write-holder').show();
$form.find('textarea.markdown-area').focus();
- return $form.find('.md-preview-holder').hide();
+ $form.find('.md-preview-holder').hide();
});
- $(document).on('markdown-preview:toggle', function(e, keyboardEvent) {
+ $(document).on('markdown-preview:toggle', function (e, keyboardEvent) {
var $target;
$target = $(keyboardEvent.target);
if ($target.is('textarea.markdown-area')) {
$(document).triggerHandler('markdown-preview:show', [$target.closest('form')]);
- return keyboardEvent.preventDefault();
+ keyboardEvent.preventDefault();
} else if (lastTextareaPreviewed) {
$target = lastTextareaPreviewed;
$(document).triggerHandler('markdown-preview:hide', [$target.closest('form')]);
- return keyboardEvent.preventDefault();
+ keyboardEvent.preventDefault();
}
});
- $(document).on('click', previewButtonSelector, function(e) {
+ $(document).on('click', previewButtonSelector, function (e) {
var $form;
e.preventDefault();
$form = $(this).closest('form');
- return $(document).triggerHandler('markdown-preview:show', [$form]);
+ $(document).triggerHandler('markdown-preview:show', [$form]);
});
- $(document).on('click', writeButtonSelector, function(e) {
+ $(document).on('click', writeButtonSelector, function (e) {
var $form;
e.preventDefault();
$form = $(this).closest('form');
- return $(document).triggerHandler('markdown-preview:hide', [$form]);
+ $(document).triggerHandler('markdown-preview:hide', [$form]);
});
-
-}).call(this);
+}());
diff --git a/app/assets/javascripts/profile/gl_crop.js.es6 b/app/assets/javascripts/profile/gl_crop.js.es6
index 6da6c1d0295..b4b6da41f63 100644
--- a/app/assets/javascripts/profile/gl_crop.js.es6
+++ b/app/assets/javascripts/profile/gl_crop.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable no-useless-escape, max-len, padded-blocks, quotes, no-var, no-underscore-dangle, func-names, space-before-function-paren, no-unused-vars, no-return-assign, object-shorthand, one-var, one-var-declaration-per-line, comma-dangle, consistent-return, class-methods-use-this, no-plusplus, new-parens, semi */
+
((global) => {
// Matches everything but the file name
diff --git a/app/assets/javascripts/profile/profile.js.es6 b/app/assets/javascripts/profile/profile.js.es6
index 3eb81808bd6..aef2e3a3fa8 100644
--- a/app/assets/javascripts/profile/profile.js.es6
+++ b/app/assets/javascripts/profile/profile.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len, padded-blocks */
+/* global Flash */
+
((global) => {
class Profile {
@@ -39,15 +41,12 @@
}
beforeUpdateUsername() {
- $('.loading-username').show();
- $(this).find('.update-success').hide();
- return $(this).find('.update-failed').hide();
+ $('.loading-username', this).removeClass('hidden');
}
afterUpdateUsername() {
- $('.loading-username').hide();
- $(this).find('.btn-save').enable();
- return $(this).find('.loading-gif').hide();
+ $('.loading-username', this).addClass('hidden');
+ $('button[type=submit]', this).enable();
}
onUpdateNotifs(e, data) {
diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js
index 016d999d77e..fcf3a4af956 100644
--- a/app/assets/javascripts/project.js
+++ b/app/assets/javascripts/project.js
@@ -1,4 +1,8 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, consistent-return, no-undef, no-new, prefer-arrow-callback, no-return-assign, one-var, one-var-declaration-per-line, object-shorthand, comma-dangle, no-else-return, newline-per-chained-call, no-shadow, semi, vars-on-top, indent, prefer-template, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, consistent-return, no-new, prefer-arrow-callback, no-return-assign, one-var, one-var-declaration-per-line, object-shorthand, comma-dangle, no-else-return, newline-per-chained-call, no-shadow, semi, vars-on-top, indent, prefer-template, padded-blocks, max-len */
+/* global Cookies */
+/* global Turbolinks */
+/* global ProjectSelect */
+
(function() {
this.Project = (function() {
function Project() {
diff --git a/app/assets/javascripts/project_find_file.js b/app/assets/javascripts/project_find_file.js
index 804306a3293..1bd232314d0 100644
--- a/app/assets/javascripts/project_find_file.js
+++ b/app/assets/javascripts/project_find_file.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, consistent-return, one-var, one-var-declaration-per-line, no-cond-assign, max-len, no-undef, object-shorthand, no-param-reassign, comma-dangle, no-plusplus, prefer-template, no-unused-vars, no-return-assign, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, consistent-return, one-var, one-var-declaration-per-line, no-cond-assign, max-len, object-shorthand, no-param-reassign, comma-dangle, no-plusplus, prefer-template, no-unused-vars, no-return-assign, padded-blocks */
+/* global fuzzaldrinPlus */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
diff --git a/app/assets/javascripts/project_import.js b/app/assets/javascripts/project_import.js
index c99e55234cf..02dafcfb865 100644
--- a/app/assets/javascripts/project_import.js
+++ b/app/assets/javascripts/project_import.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, padded-blocks, max-len */
+/* global Turbolinks */
+
(function() {
this.ProjectImport = (function() {
function ProjectImport() {
diff --git a/app/assets/javascripts/project_label_subscription.js.es6 b/app/assets/javascripts/project_label_subscription.js.es6
index 03a115cb35b..b8d6a198996 100644
--- a/app/assets/javascripts/project_label_subscription.js.es6
+++ b/app/assets/javascripts/project_label_subscription.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable wrap-iife, func-names, space-before-function-paren, object-shorthand, comma-dangle, one-var, one-var-declaration-per-line, no-restricted-syntax, prefer-const, max-len, no-param-reassign, padded-blocks */
+
(function(global) {
class ProjectLabelSubscription {
constructor(container) {
diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js
index fe1f96872f3..38bc2e1c3a0 100644
--- a/app/assets/javascripts/project_select.js
+++ b/app/assets/javascripts/project_select.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-var, comma-dangle, object-shorthand, one-var, one-var-declaration-per-line, no-undef, no-else-return, quotes, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-var, comma-dangle, object-shorthand, one-var, one-var-declaration-per-line, no-else-return, quotes, padded-blocks, max-len */
+/* global Api */
+
(function() {
this.ProjectSelect = (function() {
function ProjectSelect() {
@@ -13,6 +15,7 @@
},
data: function(term, callback) {
var finalCallback, projectsCallback;
+ var orderBy = $dropdown.data('order-by');
finalCallback = function(projects) {
return callback(projects);
};
@@ -32,7 +35,7 @@
if (this.groupId) {
return Api.groupProjects(this.groupId, term, projectsCallback);
} else {
- return Api.projects(term, this.orderBy, projectsCallback);
+ return Api.projects(term, orderBy, projectsCallback);
}
},
url: function(project) {
diff --git a/app/assets/javascripts/projects_list.js b/app/assets/javascripts/projects_list.js
index dbf530bed41..4548dc68fe1 100644
--- a/app/assets/javascripts/projects_list.js
+++ b/app/assets/javascripts/projects_list.js
@@ -1,6 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, object-shorthand, quotes, no-var, one-var, one-var-declaration-per-line, no-undef, prefer-arrow-callback, consistent-return, no-unused-vars, camelcase, prefer-template, comma-dangle, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, object-shorthand, quotes, no-var, one-var, one-var-declaration-per-line, prefer-arrow-callback, consistent-return, no-unused-vars, camelcase, prefer-template, comma-dangle, padded-blocks, max-len */
+
(function() {
- this.ProjectsList = {
+ window.ProjectsList = {
init: function() {
$(".projects-list-filter").off('keyup');
this.initSearch();
@@ -9,7 +10,7 @@
initSearch: function() {
var debounceFilter, projectsListFilter;
projectsListFilter = $('.projects-list-filter');
- debounceFilter = _.debounce(ProjectsList.filterResults, 500);
+ debounceFilter = _.debounce(window.ProjectsList.filterResults, 500);
return projectsListFilter.on('keyup', function(e) {
if (projectsListFilter.val() !== '') {
return debounceFilter();
diff --git a/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es6
index 2d60947a666..4aef1c84b56 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es6
+++ b/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable arrow-parens, no-param-reassign, no-irregular-whitespace, object-shorthand, no-else-return, comma-dangle, semi, padded-blocks, max-len */
+
(global => {
global.gl = global.gl || {};
diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_create.js.es6
index c45c9d8ff22..f26fba979a4 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_create.js.es6
+++ b/app/assets/javascripts/protected_branches/protected_branch_create.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable no-new, arrow-parens, no-param-reassign, no-irregular-whitespace, comma-dangle, padded-blocks, semi, max-len */
+/* global ProtectedBranchDropdown */
+
(global => {
global.gl = global.gl || {};
diff --git a/app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es6
index e3f226e9a2a..03f4531abf5 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es6
+++ b/app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, no-unused-vars */
+
class ProtectedBranchDropdown {
constructor(options) {
this.onSelect = options.onSelect;
@@ -75,3 +76,5 @@ class ProtectedBranchDropdown {
this.$dropdownFooter.toggleClass('hidden', !branchName);
}
}
+
+window.ProtectedBranchDropdown = ProtectedBranchDropdown;
diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_edit.js.es6
index ac3142ffb07..4ff2fa5a80f 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_edit.js.es6
+++ b/app/assets/javascripts/protected_branches/protected_branch_edit.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable no-new, arrow-parens, no-param-reassign, no-irregular-whitespace, padded-blocks, comma-dangle, no-trailing-spaces, semi, max-len */
+/* global Flash */
+
(global => {
global.gl = global.gl || {};
@@ -33,7 +35,7 @@
const $allowedToPushInput = this.$wrap.find(`input[name="${this.$allowedToPushDropdown.data('fieldName')}"]`);
// Do not update if one dropdown has not selected any option
- if (!($allowedToMergeInput.length && $allowedToPushInput.length)) return;
+ if (!($allowedToMergeInput.length && $allowedToPushInput.length)) return;
$.ajax({
type: 'POST',
diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es6
index 705378a364d..b6972ef2e16 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es6
+++ b/app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable arrow-parens, no-param-reassign, no-irregular-whitespace, no-new, comma-dangle, semi, padded-blocks, max-len */
+
(global => {
global.gl = global.gl || {};
diff --git a/app/assets/javascripts/protected_branches/protected_branches_bundle.js b/app/assets/javascripts/protected_branches/protected_branches_bundle.js
index 17e34163831..15b3affd469 100644
--- a/app/assets/javascripts/protected_branches/protected_branches_bundle.js
+++ b/app/assets/javascripts/protected_branches/protected_branches_bundle.js
@@ -1,2 +1 @@
-/* eslint-disable */
/*= require_tree . */
diff --git a/app/assets/javascripts/render_gfm.js b/app/assets/javascripts/render_gfm.js
new file mode 100644
index 00000000000..bbb2f186655
--- /dev/null
+++ b/app/assets/javascripts/render_gfm.js
@@ -0,0 +1,16 @@
+/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-undef, no-else-return, prefer-arrow-callback, padded-blocks, max-len */
+// Render Gitlab flavoured Markdown
+//
+// Delegates to syntax highlight and render math
+//
+(function() {
+ $.fn.renderGFM = function() {
+ this.find('.js-syntax-highlight').syntaxHighlight();
+ this.find('.js-render-math').renderMath();
+ };
+
+ $(document).on('ready page:load', function() {
+ return $('body').renderGFM();
+ });
+
+}).call(this);
diff --git a/app/assets/javascripts/render_math.js b/app/assets/javascripts/render_math.js
new file mode 100644
index 00000000000..209e7a8661d
--- /dev/null
+++ b/app/assets/javascripts/render_math.js
@@ -0,0 +1,55 @@
+/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-undef, no-else-return, prefer-arrow-callback, padded-blocks, max-len, no-console */
+// Renders math using KaTeX in any element with the
+// `js-render-math` class
+//
+// ### Example Markup
+//
+// <code class="js-render-math"></div>
+//
+(function() {
+ // Only load once
+ var katexLoaded = false;
+
+ // Loop over all math elements and render math
+ var renderWithKaTeX = function (elements) {
+ elements.each(function () {
+ var mathNode = $('<span></span>');
+ var $this = $(this);
+
+ var display = $this.attr('data-math-style') === 'display';
+ try {
+ katex.render($this.text(), mathNode.get(0), { displayMode: display });
+ mathNode.insertAfter($this);
+ $this.remove();
+ } catch (err) {
+ // What can we do??
+ console.log(err.message);
+ }
+ });
+ };
+
+ $.fn.renderMath = function() {
+ var $this = this;
+ if ($this.length === 0) return;
+
+ if (katexLoaded) renderWithKaTeX($this);
+ else {
+ // Request CSS file so it is in the cache
+ $.get(gon.katex_css_url, function() {
+ var css = $('<link>',
+ { rel: 'stylesheet',
+ type: 'text/css',
+ href: gon.katex_css_url,
+ });
+ css.appendTo('head');
+
+ // Load KaTeX js
+ $.getScript(gon.katex_js_url, function() {
+ katexLoaded = true;
+ renderWithKaTeX($this); // Run KaTeX
+ });
+ });
+ }
+ };
+
+}).call(this);
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 440b5da756d..b1e844b7302 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-unused-vars, semi, consistent-return, one-var, one-var-declaration-per-line, no-undef, quotes, prefer-template, object-shorthand, comma-dangle, no-else-return, no-param-reassign, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-unused-vars, semi, consistent-return, one-var, one-var-declaration-per-line, quotes, prefer-template, object-shorthand, comma-dangle, no-else-return, no-param-reassign, padded-blocks, max-len */
+/* global Cookies */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js
index 1d208f1494c..5945cab4cf0 100644
--- a/app/assets/javascripts/search.js
+++ b/app/assets/javascripts/search.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, object-shorthand, no-undef, prefer-arrow-callback, comma-dangle, prefer-template, quotes, no-else-return, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, object-shorthand, prefer-arrow-callback, comma-dangle, prefer-template, quotes, no-else-return, padded-blocks, max-len */
+/* global Api */
+
(function() {
this.Search = (function() {
function Search() {
@@ -10,6 +12,9 @@
selectable: true,
filterable: true,
fieldName: 'group_id',
+ search: {
+ fields: ['name']
+ },
data: function(term, callback) {
return Api.groups(term, {}, function(data) {
data.unshift({
@@ -38,6 +43,9 @@
selectable: true,
filterable: true,
fieldName: 'project_id',
+ search: {
+ fields: ['name']
+ },
data: function(term, callback) {
return Api.projects(term, 'id', function(data) {
data.unshift({
diff --git a/app/assets/javascripts/search_autocomplete.js.es6 b/app/assets/javascripts/search_autocomplete.js.es6
index 5fa94556501..cec8856d4e7 100644
--- a/app/assets/javascripts/search_autocomplete.js.es6
+++ b/app/assets/javascripts/search_autocomplete.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, no-return-assign, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-unused-vars, no-cond-assign, consistent-return, object-shorthand, prefer-arrow-callback, func-names, space-before-function-paren, no-plusplus, prefer-template, quotes, class-methods-use-this, no-unused-expressions, no-sequences, wrap-iife, no-lonely-if, no-else-return, no-param-reassign, vars-on-top, padded-blocks, no-extra-semi, indent, max-len */
+
((global) => {
const KEYCODE = {
@@ -141,8 +142,9 @@
}
getCategoryContents() {
- var dashboardOptions, groupOptions, issuesPath, items, mrPath, name, options, projectOptions, userId, utils;
+ var dashboardOptions, groupOptions, issuesPath, items, mrPath, name, options, projectOptions, userId, userName, utils;
userId = gon.current_user_id;
+ userName = gon.current_username;
utils = gl.utils, projectOptions = gl.projectOptions, groupOptions = gl.groupOptions, dashboardOptions = gl.dashboardOptions;
if (utils.isInGroupsPage() && groupOptions) {
options = groupOptions[utils.getGroupSlug()];
@@ -157,10 +159,10 @@
header: "" + name
}, {
text: 'Issues assigned to me',
- url: issuesPath + "/?assignee_id=" + userId
+ url: issuesPath + "/?assignee_username=" + userName
}, {
text: "Issues I've created",
- url: issuesPath + "/?author_id=" + userId
+ url: issuesPath + "/?author_username=" + userName
}, 'separator', {
text: 'Merge requests assigned to me',
url: mrPath + "/?assignee_id=" + userId
diff --git a/app/assets/javascripts/shortcuts.js b/app/assets/javascripts/shortcuts.js
index fa2168723be..5ea00f408f4 100644
--- a/app/assets/javascripts/shortcuts.js
+++ b/app/assets/javascripts/shortcuts.js
@@ -1,4 +1,8 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, no-undef, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-plusplus, no-else-return, comma-dangle, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-plusplus, no-else-return, comma-dangle, padded-blocks, max-len */
+/* global Mousetrap */
+/* global Turbolinks */
+/* global findFileURL */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
diff --git a/app/assets/javascripts/shortcuts_blob.js b/app/assets/javascripts/shortcuts_blob.js
index 65305b8c22f..c26903038b4 100644
--- a/app/assets/javascripts/shortcuts_blob.js
+++ b/app/assets/javascripts/shortcuts_blob.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, consistent-return, padded-blocks, no-undef, max-len */
+/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, consistent-return, padded-blocks */
+/* global Shortcuts */
+/* global Mousetrap */
/*= require shortcuts */
diff --git a/app/assets/javascripts/shortcuts_dashboard_navigation.js b/app/assets/javascripts/shortcuts_dashboard_navigation.js
index 1b9a265ba39..4549742bbcb 100644
--- a/app/assets/javascripts/shortcuts_dashboard_navigation.js
+++ b/app/assets/javascripts/shortcuts_dashboard_navigation.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-arrow-callback, consistent-return, no-return-assign, padded-blocks, no-undef, max-len */
+/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-arrow-callback, consistent-return, no-return-assign, padded-blocks */
+/* global Mousetrap */
+/* global Shortcuts */
/*= require shortcuts */
diff --git a/app/assets/javascripts/shortcuts_find_file.js b/app/assets/javascripts/shortcuts_find_file.js
index 68cd6fad04e..3a81380eef0 100644
--- a/app/assets/javascripts/shortcuts_find_file.js
+++ b/app/assets/javascripts/shortcuts_find_file.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, padded-blocks, no-undef, max-len */
+/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, padded-blocks */
+/* global Mousetrap */
+/* global ShortcutsNavigation */
/*= require shortcuts_navigation */
diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js
index c4899f3566a..b892fbc3393 100644
--- a/app/assets/javascripts/shortcuts_issuable.js
+++ b/app/assets/javascripts/shortcuts_issuable.js
@@ -1,4 +1,8 @@
-/* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, one-var-declaration-per-line, quotes, prefer-arrow-callback, consistent-return, prefer-template, no-mixed-operators, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, one-var-declaration-per-line, quotes, prefer-arrow-callback, consistent-return, prefer-template, no-mixed-operators, padded-blocks */
+/* global Mousetrap */
+/* global Turbolinks */
+/* global ShortcutsNavigation */
+/* global sidebar */
/*= require mousetrap */
/*= require shortcuts_navigation */
diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/shortcuts_navigation.js
index 7d4d6364c70..0776d0a9b67 100644
--- a/app/assets/javascripts/shortcuts_navigation.js
+++ b/app/assets/javascripts/shortcuts_navigation.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-arrow-callback, consistent-return, no-return-assign, padded-blocks, no-undef, max-len */
+/* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-arrow-callback, consistent-return, no-return-assign, padded-blocks */
+/* global Mousetrap */
+/* global Shortcuts */
/*= require shortcuts */
diff --git a/app/assets/javascripts/shortcuts_network.js b/app/assets/javascripts/shortcuts_network.js
index a4095d2c06b..ecc3fab84c3 100644
--- a/app/assets/javascripts/shortcuts_network.js
+++ b/app/assets/javascripts/shortcuts_network.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, padded-blocks, no-undef, max-len */
+/* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, padded-blocks, max-len */
+/* global Mousetrap */
+/* global ShortcutsNavigation */
/*= require shortcuts_navigation */
diff --git a/app/assets/javascripts/sidebar.js.es6 b/app/assets/javascripts/sidebar.js.es6
index a23ca449c4b..9790a44972d 100644
--- a/app/assets/javascripts/sidebar.js.es6
+++ b/app/assets/javascripts/sidebar.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable arrow-parens, class-methods-use-this, no-param-reassign, padded-blocks */
+/* global Cookies */
+
((global) => {
let singleton;
diff --git a/app/assets/javascripts/single_file_diff.js b/app/assets/javascripts/single_file_diff.js
index 0d48e69cce9..9602526063e 100644
--- a/app/assets/javascripts/single_file_diff.js
+++ b/app/assets/javascripts/single_file_diff.js
@@ -1,8 +1,9 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, one-var, one-var-declaration-per-line, consistent-return, no-param-reassign, padded-blocks, no-undef, max-len */
+/* eslint-disable func-names, prefer-arrow-callback, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, one-var, one-var-declaration-per-line, consistent-return, no-param-reassign, padded-blocks, max-len */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
- this.SingleFileDiff = (function() {
+ window.SingleFileDiff = (function() {
var COLLAPSED_HTML, ERROR_HTML, LOADING_HTML, WRAPPER;
WRAPPER = '<div class="diff-content diff-wrap-lines"></div>';
@@ -13,8 +14,7 @@
COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <a class="click-to-expand">Click to expand it.</a></div>';
- function SingleFileDiff(file, forceLoad, cb) {
- var clickTarget;
+ function SingleFileDiff(file) {
this.file = file;
this.toggleDiff = bind(this.toggleDiff, this);
this.content = $('.diff-content', this.file);
@@ -32,14 +32,13 @@
this.content.after(this.collapsedContent);
this.$toggleIcon.addClass('fa-caret-down');
}
- clickTarget = $('.file-title, .click-to-expand', this.file).on('click', this.toggleDiff);
- if (forceLoad) {
- this.toggleDiff({ target: clickTarget }, cb);
- }
+
+ $('.file-title, .click-to-expand', this.file).on('click', (function (e) {
+ this.toggleDiff($(e.target));
+ }).bind(this));
}
- SingleFileDiff.prototype.toggleDiff = function(e, cb) {
- var $target = $(e.target);
+ SingleFileDiff.prototype.toggleDiff = function($target, cb) {
if (!$target.hasClass('file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
this.isOpen = !this.isOpen;
if (!this.isOpen && !this.hasError) {
@@ -90,10 +89,10 @@
})();
- $.fn.singleFileDiff = function(forceLoad, cb) {
+ $.fn.singleFileDiff = function() {
return this.each(function() {
- if (!$.data(this, 'singleFileDiff') || forceLoad) {
- return $.data(this, 'singleFileDiff', new SingleFileDiff(this, forceLoad, cb));
+ if (!$.data(this, 'singleFileDiff')) {
+ return $.data(this, 'singleFileDiff', new window.SingleFileDiff(this));
}
});
};
diff --git a/app/assets/javascripts/snippet/snippet_bundle.js b/app/assets/javascripts/snippet/snippet_bundle.js
index 2c8ecba7de4..18512d179b3 100644
--- a/app/assets/javascripts/snippet/snippet_bundle.js
+++ b/app/assets/javascripts/snippet/snippet_bundle.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, no-undef, quotes, semi, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, semi, padded-blocks, max-len */
+/* global ace */
+
/*= require_tree . */
(function() {
diff --git a/app/assets/javascripts/snippets_list.js.es6 b/app/assets/javascripts/snippets_list.js.es6
index c3afc3f2246..6f913326a3a 100644
--- a/app/assets/javascripts/snippets_list.js.es6
+++ b/app/assets/javascripts/snippets_list.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable arrow-parens, no-param-reassign, space-before-function-paren, func-names, no-var, semi, max-len */
+
(global => {
global.gl = global.gl || {};
diff --git a/app/assets/javascripts/star.js b/app/assets/javascripts/star.js
index 32803fa790b..f1fc526bf2e 100644
--- a/app/assets/javascripts/star.js
+++ b/app/assets/javascripts/star.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-unused-vars, one-var, no-var, one-var-declaration-per-line, prefer-arrow-callback, no-new, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-unused-vars, one-var, no-var, one-var-declaration-per-line, prefer-arrow-callback, no-new, padded-blocks, max-len */
+/* global Flash */
+
(function() {
this.Star = (function() {
function Star() {
diff --git a/app/assets/javascripts/subbable_resource.js.es6 b/app/assets/javascripts/subbable_resource.js.es6
index 932120157a3..d8191605128 100644
--- a/app/assets/javascripts/subbable_resource.js.es6
+++ b/app/assets/javascripts/subbable_resource.js.es6
@@ -1,6 +1,3 @@
-//= require vue
-//= require vue-resource
-
(() => {
/*
* SubbableResource can be extended to provide a pubsub-style service for one-off REST
diff --git a/app/assets/javascripts/syntax_highlight.js b/app/assets/javascripts/syntax_highlight.js
index bd37d69165f..5d0fa62c50a 100644
--- a/app/assets/javascripts/syntax_highlight.js
+++ b/app/assets/javascripts/syntax_highlight.js
@@ -1,4 +1,5 @@
-/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-undef, no-else-return, prefer-arrow-callback, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, consistent-return, no-var, no-else-return, prefer-arrow-callback, padded-blocks, max-len */
+
// Syntax Highlighter
//
// Applies a syntax highlighting color scheme CSS class to any element with the
@@ -9,8 +10,10 @@
// <div class="js-syntax-highlight"></div>
//
(function() {
+
$.fn.syntaxHighlight = function() {
var $children;
+
if ($(this).hasClass('js-syntax-highlight')) {
// Given the element itself, apply highlighting
return $(this).addClass(gon.user_color_scheme);
@@ -23,8 +26,4 @@
}
};
- $(document).on('ready page:load', function() {
- return $('.js-syntax-highlight').syntaxHighlight();
- });
-
}).call(this);
diff --git a/app/assets/javascripts/templates/issuable_template_selector.js.es6 b/app/assets/javascripts/templates/issuable_template_selector.js.es6
index 93a3d67ee9f..bdec948fb63 100644
--- a/app/assets/javascripts/templates/issuable_template_selector.js.es6
+++ b/app/assets/javascripts/templates/issuable_template_selector.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable prefer-const, comma-dangle, max-len, no-useless-return, object-curly-spacing, no-param-reassign, max-len */
+/* global Api */
+
/*= require ../blob/template_selector */
((global) => {
@@ -21,7 +23,7 @@
});
$('.no-template', this.dropdown.parent()).on('click', () => {
- this.currentTemplate = '';
+ this.currentTemplate.content = '';
this.setInputValueToTemplateContent();
$('.dropdown-toggle-text', this.dropdown).text('Choose a template');
});
diff --git a/app/assets/javascripts/templates/issuable_template_selectors.js.es6 b/app/assets/javascripts/templates/issuable_template_selectors.js.es6
index 0a3890e85fe..7310b9de074 100644
--- a/app/assets/javascripts/templates/issuable_template_selectors.js.es6
+++ b/app/assets/javascripts/templates/issuable_template_selectors.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable no-new, comma-dangle, class-methods-use-this, prefer-const, no-param-reassign */
+
((global) => {
class IssuableTemplateSelectors {
constructor({ $dropdowns, editor } = {}) {
diff --git a/app/assets/javascripts/terminal/terminal.js.es6 b/app/assets/javascripts/terminal/terminal.js.es6
new file mode 100644
index 00000000000..6b9422b1816
--- /dev/null
+++ b/app/assets/javascripts/terminal/terminal.js.es6
@@ -0,0 +1,62 @@
+/* global Terminal */
+
+(() => {
+ class GLTerminal {
+
+ constructor(options) {
+ this.options = options || {};
+
+ this.options.cursorBlink = options.cursorBlink || true;
+ this.options.screenKeys = options.screenKeys || true;
+ this.container = document.querySelector(options.selector);
+
+ this.setSocketUrl();
+ this.createTerminal();
+ $(window).off('resize.terminal').on('resize.terminal', () => {
+ this.terminal.fit();
+ });
+ }
+
+ setSocketUrl() {
+ const { protocol, hostname, port } = window.location;
+ const wsProtocol = protocol === 'https:' ? 'wss://' : 'ws://';
+ const path = this.container.dataset.projectPath;
+
+ this.socketUrl = `${wsProtocol}${hostname}:${port}${path}`;
+ }
+
+ createTerminal() {
+ this.terminal = new Terminal(this.options);
+ this.socket = new WebSocket(this.socketUrl, ['terminal.gitlab.com']);
+ this.socket.binaryType = 'arraybuffer';
+
+ this.terminal.open(this.container);
+ this.socket.onopen = () => { this.runTerminal(); };
+ this.socket.onerror = () => { this.handleSocketFailure(); };
+ }
+
+ runTerminal() {
+ const decoder = new TextDecoder('utf-8');
+ const encoder = new TextEncoder('utf-8');
+
+ this.terminal.on('data', (data) => {
+ this.socket.send(encoder.encode(data));
+ });
+
+ this.socket.addEventListener('message', (ev) => {
+ this.terminal.write(decoder.decode(ev.data));
+ });
+
+ this.isTerminalInitialized = true;
+ this.terminal.fit();
+ }
+
+ handleSocketFailure() {
+ this.terminal.write('\r\nConnection failure');
+ }
+
+ }
+
+ window.gl = window.gl || {};
+ gl.Terminal = GLTerminal;
+})();
diff --git a/app/assets/javascripts/terminal/terminal_bundle.js.es6 b/app/assets/javascripts/terminal/terminal_bundle.js.es6
new file mode 100644
index 00000000000..33d2c1e1a17
--- /dev/null
+++ b/app/assets/javascripts/terminal/terminal_bundle.js.es6
@@ -0,0 +1,7 @@
+//= require xterm/encoding-indexes
+//= require xterm/encoding
+//= require xterm/xterm.js
+//= require xterm/fit.js
+//= require ./terminal.js
+
+$(() => new gl.Terminal({ selector: '#terminal' }));
diff --git a/app/assets/javascripts/todos.js.es6 b/app/assets/javascripts/todos.js.es6
index 213e80825b7..d8713600030 100644
--- a/app/assets/javascripts/todos.js.es6
+++ b/app/assets/javascripts/todos.js.es6
@@ -1,4 +1,7 @@
-/* eslint-disable */
+/* eslint-disable padded-blocks, class-methods-use-this, no-new, func-names, prefer-template, no-unneeded-ternary, object-shorthand, space-before-function-paren, comma-dangle, quote-props, consistent-return, no-else-return, semi, no-param-reassign, max-len */
+/* global UsersSelect */
+/* global Turbolinks */
+
((global) => {
class Todos {
@@ -72,7 +75,7 @@
allDoneClicked(e) {
e.preventDefault();
e.stopImmediatePropagation();
- $target = $(e.currentTarget);
+ const $target = $(e.currentTarget);
$target.disable();
return $.ajax({
type: 'POST',
diff --git a/app/assets/javascripts/u2f/authenticate.js b/app/assets/javascripts/u2f/authenticate.js.es6
index 5d991542b51..2b992109a8c 100644
--- a/app/assets/javascripts/u2f/authenticate.js
+++ b/app/assets/javascripts/u2f/authenticate.js.es6
@@ -1,24 +1,33 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, prefer-arrow-callback, no-undef, no-else-return, quotes, quote-props, comma-dangle, one-var, one-var-declaration-per-line, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, prefer-arrow-callback, no-else-return, quotes, quote-props, comma-dangle, one-var, one-var-declaration-per-line, padded-blocks, max-len */
+/* global u2f */
+/* global U2FError */
+/* global U2FUtil */
+
// Authenticate U2F (universal 2nd factor) devices for users to authenticate with.
//
// State Flow #1: setup -> in_progress -> authenticated -> POST to server
// State Flow #2: setup -> in_progress -> error -> setup
(function() {
+ const global = window.gl || (window.gl = {});
+
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
- this.U2FAuthenticate = (function() {
- function U2FAuthenticate(container, u2fParams) {
+ global.U2FAuthenticate = (function() {
+ function U2FAuthenticate(container, form, u2fParams, fallbackButton, fallbackUI) {
this.container = container;
this.renderNotSupported = bind(this.renderNotSupported, this);
this.renderAuthenticated = bind(this.renderAuthenticated, this);
this.renderError = bind(this.renderError, this);
this.renderInProgress = bind(this.renderInProgress, this);
- this.renderSetup = bind(this.renderSetup, this);
this.renderTemplate = bind(this.renderTemplate, this);
this.authenticate = bind(this.authenticate, this);
this.start = bind(this.start, this);
this.appId = u2fParams.app_id;
this.challenge = u2fParams.challenge;
+ this.form = form;
+ this.fallbackButton = fallbackButton;
+ this.fallbackUI = fallbackUI;
+ if (this.fallbackButton) this.fallbackButton.addEventListener('click', this.switchToFallbackUI.bind(this));
this.signRequests = u2fParams.sign_requests.map(function(request) {
// The U2F Javascript API v1.1 requires a single challenge, with
// _no challenges per-request_. The U2F Javascript API v1.0 requires a
@@ -37,7 +46,7 @@
U2FAuthenticate.prototype.start = function() {
if (U2FUtil.isU2FSupported()) {
- return this.renderSetup();
+ return this.renderInProgress();
} else {
return this.renderNotSupported();
}
@@ -73,11 +82,6 @@
return this.container.html(template(params));
};
- U2FAuthenticate.prototype.renderSetup = function() {
- this.renderTemplate('setup');
- return this.container.find('#js-login-u2f-device').on('click', this.renderInProgress);
- };
-
U2FAuthenticate.prototype.renderInProgress = function() {
this.renderTemplate('inProgress');
return this.authenticate();
@@ -85,24 +89,32 @@
U2FAuthenticate.prototype.renderError = function(error) {
this.renderTemplate('error', {
- error_message: error.message()
+ error_message: error.message(),
+ error_code: error.errorCode
});
- return this.container.find('#js-u2f-try-again').on('click', this.renderSetup);
+ return this.container.find('#js-u2f-try-again').on('click', this.renderInProgress);
};
U2FAuthenticate.prototype.renderAuthenticated = function(deviceResponse) {
this.renderTemplate('authenticated');
- // Prefer to do this instead of interpolating using Underscore templates
- // because of JSON escaping issues.
- return this.container.find("#js-device-response").val(deviceResponse);
+ const container = this.container[0];
+ container.querySelector('#js-device-response').value = deviceResponse;
+ container.querySelector(this.form).submit();
+ this.fallbackButton.classList.add('hidden');
};
U2FAuthenticate.prototype.renderNotSupported = function() {
return this.renderTemplate('notSupported');
};
+ U2FAuthenticate.prototype.switchToFallbackUI = function() {
+ this.fallbackButton.classList.add('hidden');
+ this.container[0].classList.add('hidden');
+ this.fallbackUI.classList.remove('hidden');
+ };
+
return U2FAuthenticate;
})();
-}).call(this);
+})();
diff --git a/app/assets/javascripts/u2f/error.js b/app/assets/javascripts/u2f/error.js
index 4c70a6e9bb6..bb9942a3aa0 100644
--- a/app/assets/javascripts/u2f/error.js
+++ b/app/assets/javascripts/u2f/error.js
@@ -1,4 +1,6 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-console, quotes, prefer-template, no-undef, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-console, quotes, prefer-template, padded-blocks, max-len */
+/* global u2f */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
@@ -7,7 +9,6 @@
this.errorCode = errorCode;
this.message = bind(this.message, this);
this.httpsDisabled = window.location.protocol !== 'https:';
- console.error("U2F Error Code: " + this.errorCode);
}
U2FError.prototype.message = function() {
diff --git a/app/assets/javascripts/u2f/register.js b/app/assets/javascripts/u2f/register.js
index 97d8993cac2..050c9bfc02e 100644
--- a/app/assets/javascripts/u2f/register.js
+++ b/app/assets/javascripts/u2f/register.js
@@ -1,4 +1,8 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-undef, no-else-return, quotes, quote-props, comma-dangle, one-var, one-var-declaration-per-line, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-else-return, quotes, quote-props, comma-dangle, one-var, one-var-declaration-per-line, padded-blocks, max-len */
+/* global u2f */
+/* global U2FError */
+/* global U2FUtil */
+
// Register U2F (universal 2nd factor) devices for users to authenticate with.
//
// State Flow #1: setup -> in_progress -> registered -> POST to server
@@ -72,7 +76,8 @@
U2FRegister.prototype.renderError = function(error) {
this.renderTemplate('error', {
- error_message: error.message()
+ error_message: error.message(),
+ error_code: error.errorCode
});
return this.container.find('#js-u2f-try-again').on('click', this.renderSetup);
};
diff --git a/app/assets/javascripts/user.js.es6 b/app/assets/javascripts/user.js.es6
index 5e869e99fdb..0a2db7c05fe 100644
--- a/app/assets/javascripts/user.js.es6
+++ b/app/assets/javascripts/user.js.es6
@@ -1,4 +1,6 @@
-/* eslint-disable */
+/* eslint-disable class-methods-use-this, comma-dangle, arrow-parens, no-param-reassign, semi */
+/* global Cookies */
+
((global) => {
global.User = class {
constructor({ action }) {
diff --git a/app/assets/javascripts/user_tabs.js.es6 b/app/assets/javascripts/user_tabs.js.es6
index 5a625611987..b9c23b51b4d 100644
--- a/app/assets/javascripts/user_tabs.js.es6
+++ b/app/assets/javascripts/user_tabs.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable max-len, space-before-function-paren, no-underscore-dangle, array-bracket-spacing, consistent-return, comma-dangle, no-unused-vars, dot-notation, no-new, no-return-assign, camelcase, semi, no-param-reassign */
+
/*
UserTabs
diff --git a/app/assets/javascripts/username_validator.js.es6 b/app/assets/javascripts/username_validator.js.es6
index c4dde575c6e..137cefa3b8e 100644
--- a/app/assets/javascripts/username_validator.js.es6
+++ b/app/assets/javascripts/username_validator.js.es6
@@ -1,4 +1,5 @@
-/* eslint-disable */
+/* eslint-disable comma-dangle, consistent-return, class-methods-use-this, arrow-parens, no-param-reassign, max-len */
+
((global) => {
const debounceTimeoutDuration = 1000;
const invalidInputClass = 'gl-field-error-outline';
@@ -77,7 +78,7 @@
this.renderState();
return $.ajax({
type: 'GET',
- url: `/users/${username}/exists`,
+ url: `${gon.relative_url_root}/users/${username}/exists`,
dataType: 'json',
success: (res) => this.setAvailabilityState(res.exists)
});
diff --git a/app/assets/javascripts/users/calendar.js b/app/assets/javascripts/users/calendar.js
index ba7f533c349..578be7c3590 100644
--- a/app/assets/javascripts/users/calendar.js
+++ b/app/assets/javascripts/users/calendar.js
@@ -1,4 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, camelcase, vars-on-top, semi, keyword-spacing, no-plusplus, no-undef, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, camelcase, vars-on-top, semi, keyword-spacing, no-plusplus, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, padded-blocks, max-len */
+/* global d3 */
+/* global dateFormat */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js
index c6e18fad832..d4b5e03aa35 100644
--- a/app/assets/javascripts/users_select.js
+++ b/app/assets/javascripts/users_select.js
@@ -1,4 +1,8 @@
-/* eslint-disable func-names, space-before-function-paren, one-var, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, max-len, one-var-declaration-per-line, vars-on-top, prefer-arrow-callback, consistent-return, no-undef, comma-dangle, object-shorthand, no-shadow, no-unused-vars, no-plusplus, no-else-return, no-self-compare, prefer-template, no-unused-expressions, no-lonely-if, yoda, prefer-spread, no-void, camelcase, keyword-spacing, no-param-reassign, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, one-var, no-var, space-before-blocks, prefer-rest-params, wrap-iife, quotes, max-len, one-var-declaration-per-line, vars-on-top, prefer-arrow-callback, consistent-return, comma-dangle, object-shorthand, no-shadow, no-unused-vars, no-plusplus, no-else-return, no-self-compare, prefer-template, no-unused-expressions, no-lonely-if, yoda, prefer-spread, no-void, camelcase, keyword-spacing, no-param-reassign, padded-blocks */
+/* global Vue */
+/* global Issuable */
+/* global ListUser */
+
(function() {
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
slice = [].slice;
diff --git a/app/assets/javascripts/vue_pagination/index.js.es6 b/app/assets/javascripts/vue_pagination/index.js.es6
new file mode 100644
index 00000000000..605824fa939
--- /dev/null
+++ b/app/assets/javascripts/vue_pagination/index.js.es6
@@ -0,0 +1,148 @@
+/* global Vue, gl */
+/* eslint-disable no-param-reassign, no-plusplus */
+
+((gl) => {
+ const PAGINATION_UI_BUTTON_LIMIT = 4;
+ const UI_LIMIT = 6;
+ const SPREAD = '...';
+ const PREV = 'Prev';
+ const NEXT = 'Next';
+ const FIRST = '<< First';
+ const LAST = 'Last >>';
+
+ gl.VueGlPagination = Vue.extend({
+ props: {
+
+ /**
+ This function will take the information given by the pagination component
+ And make a new Turbolinks call
+
+ Here is an example `change` method:
+
+ change(pagenum, apiScope) {
+ Turbolinks.visit(`?scope=${apiScope}&p=${pagenum}`);
+ },
+ */
+
+ change: {
+ type: Function,
+ required: true,
+ },
+
+ /**
+ pageInfo will come from the headers of the API call
+ in the `.then` clause of the VueResource API call
+ there should be a function that contructs the pageInfo for this component
+
+ This is an example:
+
+ const pageInfo = headers => ({
+ perPage: +headers['X-Per-Page'],
+ page: +headers['X-Page'],
+ total: +headers['X-Total'],
+ totalPages: +headers['X-Total-Pages'],
+ nextPage: +headers['X-Next-Page'],
+ previousPage: +headers['X-Prev-Page'],
+ });
+ */
+
+ pageInfo: {
+ type: Object,
+ required: true,
+ },
+ },
+ methods: {
+ changePage(e) {
+ let apiScope = gl.utils.getParameterByName('scope');
+
+ if (!apiScope) apiScope = 'all';
+
+ const text = e.target.innerText;
+ const { totalPages, nextPage, previousPage } = this.pageInfo;
+
+ switch (text) {
+ case SPREAD:
+ break;
+ case LAST:
+ this.change(totalPages, apiScope);
+ break;
+ case NEXT:
+ this.change(nextPage, apiScope);
+ break;
+ case PREV:
+ this.change(previousPage, apiScope);
+ break;
+ case FIRST:
+ this.change(1, apiScope);
+ break;
+ default:
+ this.change(+text, apiScope);
+ break;
+ }
+ },
+ },
+ computed: {
+ prev() {
+ return this.pageInfo.previousPage;
+ },
+ next() {
+ return this.pageInfo.nextPage;
+ },
+ getItems() {
+ const total = this.pageInfo.totalPages;
+ const page = this.pageInfo.page;
+ const items = [];
+
+ if (page > 1) items.push({ title: FIRST });
+
+ if (page > 1) {
+ items.push({ title: PREV, prev: true });
+ } else {
+ items.push({ title: PREV, disabled: true, prev: true });
+ }
+
+ if (page > UI_LIMIT) items.push({ title: SPREAD, separator: true });
+
+ const start = Math.max(page - PAGINATION_UI_BUTTON_LIMIT, 1);
+ const end = Math.min(page + PAGINATION_UI_BUTTON_LIMIT, total);
+
+ for (let i = start; i <= end; i++) {
+ const isActive = i === page;
+ items.push({ title: i, active: isActive, page: true });
+ }
+
+ if (total - page > PAGINATION_UI_BUTTON_LIMIT) {
+ items.push({ title: SPREAD, separator: true, page: true });
+ }
+
+ if (page === total) {
+ items.push({ title: NEXT, disabled: true, next: true });
+ } else if (total - page >= 1) {
+ items.push({ title: NEXT, next: true });
+ }
+
+ if (total - page >= 1) items.push({ title: LAST, last: true });
+
+ return items;
+ },
+ },
+ template: `
+ <div class="gl-pagination">
+ <ul class="pagination clearfix">
+ <li v-for='item in getItems'
+ :class='{
+ page: item.page,
+ prev: item.prev,
+ next: item.next,
+ separator: item.separator,
+ active: item.active,
+ disabled: item.disabled
+ }'
+ >
+ <a @click="changePage($event)">{{item.title}}</a>
+ </li>
+ </ul>
+ </div>
+ `,
+ });
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/vue_pipelines_index/index.js.es6 b/app/assets/javascripts/vue_pipelines_index/index.js.es6
new file mode 100644
index 00000000000..edd01f17a97
--- /dev/null
+++ b/app/assets/javascripts/vue_pipelines_index/index.js.es6
@@ -0,0 +1,42 @@
+/* global Vue, VueResource, gl */
+/*= require vue_common_component/commit */
+/*= require vue_pagination/index */
+/*= require vue-resource
+/*= require boards/vue_resource_interceptor */
+/*= require ./status.js.es6 */
+/*= require ./store.js.es6 */
+/*= require ./pipeline_url.js.es6 */
+/*= require ./stage.js.es6 */
+/*= require ./stages.js.es6 */
+/*= require ./pipeline_actions.js.es6 */
+/*= require ./time_ago.js.es6 */
+/*= require ./pipelines.js.es6 */
+
+(() => {
+ const project = document.querySelector('.pipelines');
+ const entry = document.querySelector('.vue-pipelines-index');
+ const svgs = document.querySelector('.pipeline-svgs');
+
+ Vue.use(VueResource);
+
+ if (!entry) return null;
+ return new Vue({
+ el: entry,
+ data: {
+ scope: project.dataset.url,
+ store: new gl.PipelineStore(),
+ svgs: svgs.dataset,
+ },
+ components: {
+ 'vue-pipelines': gl.VuePipelines,
+ },
+ template: `
+ <vue-pipelines
+ :scope='scope'
+ :store='store'
+ :svgs='svgs'
+ >
+ </vue-pipelines>
+ `,
+ });
+})();
diff --git a/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6
new file mode 100644
index 00000000000..ad5cb30cc42
--- /dev/null
+++ b/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6
@@ -0,0 +1,99 @@
+/* global Vue, Flash, gl */
+/* eslint-disable no-param-reassign */
+
+((gl) => {
+ gl.VuePipelineActions = Vue.extend({
+ props: ['pipeline', 'svgs'],
+ computed: {
+ actions() {
+ return this.pipeline.details.manual_actions.length > 0;
+ },
+ artifacts() {
+ return this.pipeline.details.artifacts.length > 0;
+ },
+ },
+ methods: {
+ download(name) {
+ return `Download ${name} artifacts`;
+ },
+ },
+ template: `
+ <td class="pipeline-actions hidden-xs">
+ <div class="controls pull-right">
+ <div class="btn-group inline">
+ <div class="btn-group">
+ <a
+ v-if='actions'
+ class="dropdown-toggle btn btn-default js-pipeline-dropdown-manual-actions"
+ data-toggle="dropdown"
+ title="Manual build"
+ alt="Manual Build"
+ >
+ <span v-html='svgs.iconPlay'></span>
+ <i class="fa fa-caret-down"></i>
+ </a>
+ <ul class="dropdown-menu dropdown-menu-align-right">
+ <li v-for='action in pipeline.details.manual_actions'>
+ <a
+ rel="nofollow"
+ data-method="post"
+ :href='action.path'
+ title="Manual build"
+ >
+ <span v-html='svgs.iconPlay'></span>
+ <span title="Manual build">{{action.name}}</span>
+ </a>
+ </li>
+ </ul>
+ </div>
+ <div class="btn-group">
+ <a
+ v-if='artifacts'
+ class="dropdown-toggle btn btn-default build-artifacts js-pipeline-dropdown-download"
+ data-toggle="dropdown"
+ type="button"
+ >
+ <i class="fa fa-download"></i>
+ <i class="fa fa-caret-down"></i>
+ </a>
+ <ul class="dropdown-menu dropdown-menu-align-right">
+ <li v-for='artifact in pipeline.details.artifacts'>
+ <a
+ rel="nofollow"
+ :href='artifact.path'
+ >
+ <i class="fa fa-download"></i>
+ <span>{{download(artifact.name)}}</span>
+ </a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ <div class="cancel-retry-btns inline">
+ <a
+ v-if='pipeline.flags.retryable'
+ class="btn has-tooltip"
+ title="Retry"
+ rel="nofollow"
+ data-method="post"
+ :href='pipeline.retry_path'
+ >
+ <i class="fa fa-repeat"></i>
+ </a>
+ <a
+ v-if='pipeline.flags.cancelable'
+ class="btn btn-remove has-tooltip"
+ title="Cancel"
+ rel="nofollow"
+ data-method="post"
+ :href='pipeline.cancel_path'
+ data-original-title="Cancel"
+ >
+ <i class="fa fa-remove"></i>
+ </a>
+ </div>
+ </div>
+ </td>
+ `,
+ });
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/vue_pipelines_index/pipeline_url.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipeline_url.js.es6
new file mode 100644
index 00000000000..ae5649f0519
--- /dev/null
+++ b/app/assets/javascripts/vue_pipelines_index/pipeline_url.js.es6
@@ -0,0 +1,63 @@
+/* global Vue, gl */
+/* eslint-disable no-param-reassign */
+
+((gl) => {
+ gl.VuePipelineUrl = Vue.extend({
+ props: [
+ 'pipeline',
+ ],
+ computed: {
+ user() {
+ return !!this.pipeline.user;
+ },
+ },
+ template: `
+ <td>
+ <a :href='pipeline.path'>
+ <span class="pipeline-id">#{{pipeline.id}}</span>
+ </a>
+ <span>by</span>
+ <a
+ v-if='user'
+ :href='pipeline.user.web_url'
+ >
+ <img
+ v-if='user'
+ class="avatar has-tooltip s20 "
+ :title='pipeline.user.name'
+ data-container="body"
+ :src='pipeline.user.avatar_url'
+ >
+ </a>
+ <span
+ v-if='!user'
+ class="api monospace"
+ >
+ API
+ </span>
+ <span
+ v-if='pipeline.flags.latest'
+ class="label label-success has-tooltip"
+ title="Latest pipeline for this branch"
+ data-original-title="Latest pipeline for this branch"
+ >
+ latest
+ </span>
+ <span
+ v-if='pipeline.flags.yaml_errors'
+ class="label label-danger has-tooltip"
+ :title='pipeline.yaml_errors'
+ :data-original-title='pipeline.yaml_errors'
+ >
+ yaml invalid
+ </span>
+ <span
+ v-if='pipeline.flags.stuck'
+ class="label label-warning"
+ >
+ stuck
+ </span>
+ </td>
+ `,
+ });
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6
new file mode 100644
index 00000000000..b2ed05503c9
--- /dev/null
+++ b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6
@@ -0,0 +1,131 @@
+/* global Vue, Turbolinks, gl */
+/* eslint-disable no-param-reassign */
+
+((gl) => {
+ gl.VuePipelines = Vue.extend({
+ components: {
+ runningPipeline: gl.VueRunningPipeline,
+ pipelineActions: gl.VuePipelineActions,
+ stages: gl.VueStages,
+ commit: gl.CommitComponent,
+ pipelineUrl: gl.VuePipelineUrl,
+ pipelineHead: gl.VuePipelineHead,
+ glPagination: gl.VueGlPagination,
+ statusScope: gl.VueStatusScope,
+ timeAgo: gl.VueTimeAgo,
+ },
+ data() {
+ return {
+ pipelines: [],
+ timeLoopInterval: '',
+ intervalId: '',
+ apiScope: 'all',
+ pageInfo: {},
+ pagenum: 1,
+ count: { all: 0, running_or_pending: 0 },
+ pageRequest: false,
+ };
+ },
+ props: ['scope', 'store', 'svgs'],
+ created() {
+ const pagenum = gl.utils.getParameterByName('p');
+ const scope = gl.utils.getParameterByName('scope');
+ if (pagenum) this.pagenum = pagenum;
+ if (scope) this.apiScope = scope;
+ this.store.fetchDataLoop.call(this, Vue, this.pagenum, this.scope, this.apiScope);
+ },
+ methods: {
+ change(pagenum, apiScope) {
+ Turbolinks.visit(`?scope=${apiScope}&p=${pagenum}`);
+ },
+ author(pipeline) {
+ if (!pipeline.commit) return { avatar_url: '', web_url: '', username: '' };
+ if (pipeline.commit.author) return pipeline.commit.author;
+ return {
+ avatar_url: pipeline.commit.author_gravatar_url,
+ web_url: `mailto:${pipeline.commit.author_email}`,
+ username: pipeline.commit.author_name,
+ };
+ },
+ ref(pipeline) {
+ const { ref } = pipeline;
+ return { name: ref.name, tag: ref.tag, ref_url: ref.path };
+ },
+ commitTitle(pipeline) {
+ return pipeline.commit ? pipeline.commit.title : '';
+ },
+ commitSha(pipeline) {
+ return pipeline.commit ? pipeline.commit.short_id : '';
+ },
+ commitUrl(pipeline) {
+ return pipeline.commit ? pipeline.commit.commit_path : '';
+ },
+ match(string) {
+ return string.replace(/_([a-z])/g, (m, w) => w.toUpperCase());
+ },
+ },
+ template: `
+ <div>
+ <div class="pipelines realtime-loading" v-if='pipelines.length < 1'>
+ <i class="fa fa-spinner fa-spin"></i>
+ </div>
+ <div class="table-holder" v-if='pipelines.length'>
+ <table class="table ci-table">
+ <thead>
+ <tr>
+ <th class="pipeline-status">Status</th>
+ <th class="pipeline-info">Pipeline</th>
+ <th class="pipeline-commit">Commit</th>
+ <th class="pipeline-stages">Stages</th>
+ <th class="pipeline-date"></th>
+ <th class="pipeline-actions hidden-xs"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr class="commit" v-for='pipeline in pipelines'>
+ <status-scope
+ :pipeline='pipeline'
+ :match='match'
+ :svgs='svgs'
+ >
+ </status-scope>
+ <pipeline-url :pipeline='pipeline'></pipeline-url>
+ <td>
+ <commit
+ :commit-icon-svg='svgs.commitIconSvg'
+ :author='author(pipeline)'
+ :tag="pipeline.ref.tag"
+ :title='commitTitle(pipeline)'
+ :commit-ref='ref(pipeline)'
+ :short-sha='commitSha(pipeline)'
+ :commit-url='commitUrl(pipeline)'
+ >
+ </commit>
+ </td>
+ <stages
+ :pipeline='pipeline'
+ :svgs='svgs'
+ :match='match'
+ >
+ </stages>
+ <time-ago :pipeline='pipeline' :svgs='svgs'></time-ago>
+ <pipeline-actions :pipeline='pipeline' :svgs='svgs'></pipeline-actions>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <div class="pipelines realtime-loading" v-if='pageRequest'>
+ <i class="fa fa-spinner fa-spin"></i>
+ </div>
+ <gl-pagination
+ v-if='pageInfo.total > pageInfo.perPage'
+ :pagenum='pagenum'
+ :change='change'
+ :count='count.all'
+ :pageInfo='pageInfo'
+ >
+ </gl-pagination>
+ </div>
+ `,
+ });
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/vue_pipelines_index/stage.js.es6 b/app/assets/javascripts/vue_pipelines_index/stage.js.es6
new file mode 100644
index 00000000000..f075a995846
--- /dev/null
+++ b/app/assets/javascripts/vue_pipelines_index/stage.js.es6
@@ -0,0 +1,69 @@
+/* global Vue, Flash, gl */
+/* eslint-disable no-param-reassign, no-bitwise */
+
+((gl) => {
+ gl.VueStage = Vue.extend({
+ data() {
+ return {
+ count: 0,
+ builds: '',
+ spinner: '<span class="fa fa-spinner fa-spin"></span>',
+ };
+ },
+ props: ['stage', 'svgs', 'match'],
+ methods: {
+ fetchBuilds() {
+ if (this.count > 0) return null;
+ return this.$http.get(this.stage.dropdown_path)
+ .then((response) => {
+ this.count += 1;
+ this.builds = JSON.parse(response.body).html;
+ }, () => {
+ const flash = new Flash('Something went wrong on our end.');
+ return flash;
+ });
+ },
+ },
+ computed: {
+ buildsOrSpinner() {
+ return this.builds ? this.builds : this.spinner;
+ },
+ dropdownClass() {
+ if (this.builds) return 'js-builds-dropdown-container';
+ return 'js-builds-dropdown-loading builds-dropdown-loading';
+ },
+ buildStatus() {
+ return `Build: ${this.stage.status.label}`;
+ },
+ tooltip() {
+ return `has-tooltip ci-status-icon ci-status-icon-${this.stage.status.group}`;
+ },
+ svg() {
+ const icon = this.stage.status.icon;
+ const stageIcon = icon.replace(/icon/i, 'stage_icon');
+ return this.svgs[this.match(stageIcon)];
+ },
+ triggerButtonClass() {
+ return `mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-${this.stage.status.group}`;
+ },
+ },
+ template: `
+ <div>
+ <button
+ @click='fetchBuilds'
+ :class="triggerButtonClass"
+ :title='stage.title'
+ data-placement="top"
+ data-toggle="dropdown"
+ type="button">
+ <span v-html="svg"></span>
+ <i class="fa fa-caret-down "></i>
+ </button>
+ <ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
+ <div class="arrow-up"></div>
+ <div :class="dropdownClass" class="js-builds-dropdown-list scrollable-menu" v-html="buildsOrSpinner"></div>
+ </ul>
+ </div>
+ `,
+ });
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/vue_pipelines_index/stages.js.es6 b/app/assets/javascripts/vue_pipelines_index/stages.js.es6
new file mode 100644
index 00000000000..cb176b3f0c6
--- /dev/null
+++ b/app/assets/javascripts/vue_pipelines_index/stages.js.es6
@@ -0,0 +1,21 @@
+/* global Vue, gl */
+/* eslint-disable no-param-reassign */
+
+((gl) => {
+ gl.VueStages = Vue.extend({
+ components: {
+ 'vue-stage': gl.VueStage,
+ },
+ props: ['pipeline', 'svgs', 'match'],
+ template: `
+ <td class="stage-cell">
+ <div
+ class="stage-container dropdown js-mini-pipeline-graph"
+ v-for='stage in pipeline.details.stages'
+ >
+ <vue-stage :stage='stage' :svgs='svgs' :match='match'></vue-stage>
+ </div>
+ </td>
+ `,
+ });
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/vue_pipelines_index/status.js.es6 b/app/assets/javascripts/vue_pipelines_index/status.js.es6
new file mode 100644
index 00000000000..05175082704
--- /dev/null
+++ b/app/assets/javascripts/vue_pipelines_index/status.js.es6
@@ -0,0 +1,34 @@
+/* global Vue, gl */
+/* eslint-disable no-param-reassign */
+
+((gl) => {
+ gl.VueStatusScope = Vue.extend({
+ props: [
+ 'pipeline', 'svgs', 'match',
+ ],
+ computed: {
+ cssClasses() {
+ const cssObject = { 'ci-status': true };
+ cssObject[`ci-${this.pipeline.details.status.group}`] = true;
+ return cssObject;
+ },
+ svg() {
+ return this.svgs[this.match(this.pipeline.details.status.icon)];
+ },
+ detailsPath() {
+ const { status } = this.pipeline.details;
+ return status.has_details ? status.details_path : false;
+ },
+ },
+ template: `
+ <td class="commit-link">
+ <a
+ :class='cssClasses'
+ :href='detailsPath'
+ v-html='svg + pipeline.details.status.text'
+ >
+ </a>
+ </td>
+ `,
+ });
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/vue_pipelines_index/store.js.es6 b/app/assets/javascripts/vue_pipelines_index/store.js.es6
new file mode 100644
index 00000000000..1982142853a
--- /dev/null
+++ b/app/assets/javascripts/vue_pipelines_index/store.js.es6
@@ -0,0 +1,69 @@
+/* global gl, Flash */
+/* eslint-disable no-param-reassign, no-underscore-dangle */
+/*= require vue_realtime_listener/index.js */
+
+((gl) => {
+ const pageValues = (headers) => {
+ const normalizedHeaders = {};
+
+ Object.keys(headers).forEach((e) => {
+ normalizedHeaders[e.toUpperCase()] = headers[e];
+ });
+
+ const paginationInfo = {
+ perPage: +normalizedHeaders['X-PER-PAGE'],
+ page: +normalizedHeaders['X-PAGE'],
+ total: +normalizedHeaders['X-TOTAL'],
+ totalPages: +normalizedHeaders['X-TOTAL-PAGES'],
+ nextPage: +normalizedHeaders['X-NEXT-PAGE'],
+ previousPage: +normalizedHeaders['X-PREV-PAGE'],
+ };
+
+ return paginationInfo;
+ };
+
+ gl.PipelineStore = class {
+ fetchDataLoop(Vue, pageNum, url, apiScope) {
+ const updatePipelineNums = (count) => {
+ const { all } = count;
+ const running = count.running_or_pending;
+ document.querySelector('.js-totalbuilds-count').innerHTML = all;
+ document.querySelector('.js-running-count').innerHTML = running;
+ };
+
+ const goFetch = () =>
+ this.$http.get(`${url}?scope=${apiScope}&page=${pageNum}`)
+ .then((response) => {
+ const pageInfo = pageValues(response.headers);
+ this.pageInfo = Object.assign({}, this.pageInfo, pageInfo);
+
+ const res = JSON.parse(response.body);
+ this.count = Object.assign({}, this.count, res.count);
+ this.pipelines = Object.assign([], this.pipelines, res.pipelines);
+
+ updatePipelineNums(this.count);
+ this.pageRequest = false;
+ }, () => {
+ this.pageRequest = false;
+ return new Flash('Something went wrong on our end.');
+ });
+
+ goFetch();
+
+ const startTimeLoops = () => {
+ this.timeLoopInterval = setInterval(() => {
+ this.$children
+ .filter(e => e.$options._componentTag === 'time-ago')
+ .forEach(e => e.changeTime());
+ }, 10000);
+ };
+
+ startTimeLoops();
+
+ const removeIntervals = () => clearInterval(this.timeLoopInterval);
+ const startIntervals = () => startTimeLoops();
+
+ gl.VueRealtimeListener(removeIntervals, startIntervals);
+ }
+ };
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/vue_pipelines_index/time_ago.js.es6 b/app/assets/javascripts/vue_pipelines_index/time_ago.js.es6
new file mode 100644
index 00000000000..655110feba1
--- /dev/null
+++ b/app/assets/javascripts/vue_pipelines_index/time_ago.js.es6
@@ -0,0 +1,73 @@
+/* global Vue, gl */
+/* eslint-disable no-param-reassign */
+
+((gl) => {
+ gl.VueTimeAgo = Vue.extend({
+ data() {
+ return {
+ currentTime: new Date(),
+ };
+ },
+ props: ['pipeline', 'svgs'],
+ computed: {
+ timeAgo() {
+ return gl.utils.getTimeago();
+ },
+ localTimeFinished() {
+ return gl.utils.formatDate(this.pipeline.details.finished_at);
+ },
+ timeStopped() {
+ const changeTime = this.currentTime;
+ const options = {
+ weekday: 'long',
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ };
+ options.timeZoneName = 'short';
+ const finished = this.pipeline.details.finished_at;
+ if (!finished && changeTime) return false;
+ return ({ words: this.timeAgo.format(finished) });
+ },
+ duration() {
+ const { duration } = this.pipeline.details;
+ const date = new Date(duration * 1000);
+
+ let hh = date.getUTCHours();
+ let mm = date.getUTCMinutes();
+ let ss = date.getSeconds();
+
+ if (hh < 10) hh = `0${hh}`;
+ if (mm < 10) mm = `0${mm}`;
+ if (ss < 10) ss = `0${ss}`;
+
+ if (duration !== null) return `${hh}:${mm}:${ss}`;
+ return false;
+ },
+ },
+ methods: {
+ changeTime() {
+ this.currentTime = new Date();
+ },
+ },
+ template: `
+ <td>
+ <p class="duration" v-if='duration'>
+ <span v-html='svgs.iconTimer'></span>
+ {{duration}}
+ </p>
+ <p class="finished-at" v-if='timeStopped'>
+ <i class="fa fa-calendar"></i>
+ <time
+ data-toggle="tooltip"
+ data-placement="top"
+ data-container="body"
+ :data-original-title='localTimeFinished'
+ >
+ {{timeStopped.words}}
+ </time>
+ </p>
+ </td>
+ `,
+ });
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/vue_realtime_listener/index.js.es6 b/app/assets/javascripts/vue_realtime_listener/index.js.es6
new file mode 100644
index 00000000000..23cac1466d2
--- /dev/null
+++ b/app/assets/javascripts/vue_realtime_listener/index.js.es6
@@ -0,0 +1,18 @@
+/* eslint-disable no-param-reassign */
+
+((gl) => {
+ gl.VueRealtimeListener = (removeIntervals, startIntervals) => {
+ const removeAll = () => {
+ removeIntervals();
+ window.removeEventListener('beforeunload', removeIntervals);
+ window.removeEventListener('focus', startIntervals);
+ window.removeEventListener('blur', removeIntervals);
+ document.removeEventListener('page:fetch', removeAll);
+ };
+
+ window.addEventListener('beforeunload', removeIntervals);
+ window.addEventListener('focus', startIntervals);
+ window.addEventListener('blur', removeIntervals);
+ document.addEventListener('page:fetch', removeAll);
+ };
+})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js
index 82eb761442a..e09b59dd5aa 100644
--- a/app/assets/javascripts/zen_mode.js
+++ b/app/assets/javascripts/zen_mode.js
@@ -1,4 +1,7 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-unused-vars, consistent-return, no-undef, camelcase, comma-dangle, padded-blocks, max-len */
+/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-unused-vars, consistent-return, camelcase, comma-dangle, padded-blocks, max-len */
+/* global Dropzone */
+/* global Mousetrap */
+
// Zen Mode (full screen) textarea
//
/*= provides zen_mode:enter */
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index c82a9a2b9e3..3cf49f4ff1b 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -9,6 +9,7 @@
@import "framework/asciidoctor.scss";
@import "framework/blocks.scss";
@import "framework/buttons.scss";
+@import "framework/badges.scss";
@import "framework/calendar.scss";
@import "framework/callout.scss";
@import "framework/common.scss";
@@ -44,3 +45,6 @@
@import "framework/awards.scss";
@import "framework/images.scss";
@import "framework/broadcast-messages";
+@import "framework/emojis.scss";
+@import "framework/icons.scss";
+@import "framework/snippets.scss";
diff --git a/app/assets/stylesheets/framework/animations.scss b/app/assets/stylesheets/framework/animations.scss
index f1d36efb3de..8d38fc78a19 100644
--- a/app/assets/stylesheets/framework/animations.scss
+++ b/app/assets/stylesheets/framework/animations.scss
@@ -50,3 +50,77 @@
.pulse {
@include webkit-prefix(animation-name, pulse);
}
+
+/*
+* General hover animations
+*/
+
+
+// Sass multiple transitions mixin | https://gist.github.com/tobiasahlin/7a421fb9306a4f518aab
+// Usage: @include transition(width, height 0.3s ease-in-out);
+// Output: -webkit-transition(width 0.2s, height 0.3s ease-in-out);
+// transition(width 0.2s, height 0.3s ease-in-out);
+//
+// Pass in any number of transitions
+@mixin transition($transitions...) {
+ $unfoldedTransitions: ();
+ @each $transition in $transitions {
+ $unfoldedTransitions: append($unfoldedTransitions, unfoldTransition($transition), comma);
+ }
+
+ transition: $unfoldedTransitions;
+}
+
+@function unfoldTransition ($transition) {
+ // Default values
+ $property: all;
+ $duration: $general-hover-transition-duration;
+ $easing: $general-hover-transition-curve; // Browser default is ease, which is what we want
+ $delay: null; // Browser default is 0, which is what we want
+ $defaultProperties: ($property, $duration, $easing, $delay);
+
+ // Grab transition properties if they exist
+ $unfoldedTransition: ();
+ @for $i from 1 through length($defaultProperties) {
+ $p: null;
+ @if $i <= length($transition) {
+ $p: nth($transition, $i);
+ } @else {
+ $p: nth($defaultProperties, $i);
+ }
+ $unfoldedTransition: append($unfoldedTransition, $p);
+ }
+
+ @return $unfoldedTransition;
+}
+
+.btn,
+.side-nav-toggle {
+ @include transition(background-color, border-color, color, box-shadow);
+}
+
+.dropdown-menu-toggle,
+.avatar-circle,
+.header-user-avatar {
+ @include transition(border-color);
+}
+
+.note-action-button .link-highlight,
+.toolbar-btn,
+.dropdown-toggle-caret,
+.fa:not(.fa-bell) {
+ @include transition(color);
+}
+
+a {
+ @include transition(background-color, color, border);
+}
+
+.tree-table td,
+.well-list > li {
+ @include transition(background-color, border-color);
+}
+
+.stage-nav-item {
+ @include transition(background-color, box-shadow);
+}
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index 000e591e09c..8392b98f0a7 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -52,6 +52,10 @@
border-radius: 0;
border: none;
}
+
+ &:not([href]):hover {
+ border-color: rgba($avatar-border, .2);
+ }
}
.identicon {
@@ -64,7 +68,7 @@
&.s32 { font-size: 20px; line-height: 30px; }
&.s40 { font-size: 16px; line-height: 38px; }
&.s60 { font-size: 32px; line-height: 58px; }
- &.s70 { font-size: 34px; line-height: 68px; }
+ &.s70 { font-size: 34px; line-height: 70px; }
&.s90 { font-size: 36px; line-height: 88px; }
&.s110 { font-size: 40px; line-height: 108px; font-weight: 300; }
&.s140 { font-size: 72px; line-height: 138px; }
diff --git a/app/assets/stylesheets/framework/awards.scss b/app/assets/stylesheets/framework/awards.scss
index dece5c3202b..49907417e26 100644
--- a/app/assets/stylesheets/framework/awards.scss
+++ b/app/assets/stylesheets/framework/awards.scss
@@ -12,8 +12,8 @@
z-index: 9;
width: 300px;
font-size: 14px;
- background-color: $award-emoji-menu-bg;
- border: 1px solid $award-emoji-menu-border;
+ background-color: $white-light;
+ border: 1px solid $border-white-light;
border-radius: $border-radius-base;
box-shadow: 0 6px 12px $award-emoji-menu-shadow;
pointer-events: none;
@@ -97,8 +97,20 @@
padding: 5px 6px;
outline: 0;
- &:hover,
+ &.disabled {
+ cursor: default;
+
+ &:hover,
+ &:focus,
+ &:active {
+ background-color: $white-light;
+ border-color: $border-color;
+ box-shadow: none;
+ }
+ }
+
&.active,
+ &:hover,
&:active {
background-color: $row-hover;
border-color: $row-hover-border;
@@ -135,7 +147,7 @@
}
.award-control-icon {
- color: $award-emoji-new-btn-icon-color;
+ color: $border-gray-normal;
margin-top: 1px;
}
}
diff --git a/app/assets/stylesheets/framework/badges.scss b/app/assets/stylesheets/framework/badges.scss
new file mode 100644
index 00000000000..47a8f44c709
--- /dev/null
+++ b/app/assets/stylesheets/framework/badges.scss
@@ -0,0 +1,6 @@
+.badge {
+ font-weight: normal;
+ background-color: $badge-bg;
+ color: $badge-color;
+ vertical-align: baseline;
+}
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index 95c02499271..407c800feb7 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -1,15 +1,15 @@
.centered-light-block {
text-align: center;
- color: $gl-gray;
+ color: $gl-text-color;
margin: 20px;
}
.nothing-here-block {
text-align: center;
padding: 20px;
- color: $gl-gray;
+ color: $gl-text-color;
font-weight: normal;
- font-size: 16px;
+ font-size: 14px;
line-height: 36px;
&.diff-collapsed {
@@ -24,12 +24,12 @@
.row-content-block {
margin-top: 0;
margin-bottom: -$gl-padding;
- background-color: $background-color;
+ background-color: $gray-light;
padding: $gl-padding;
margin-bottom: 0;
border-top: 1px solid $white-dark;
border-bottom: 1px solid $white-dark;
- color: $gl-gray;
+ color: $gl-text-color;
&.oneline-block {
line-height: 42px;
@@ -118,7 +118,7 @@
.cover-block {
text-align: center;
- background: $background-color;
+ background: $gray-light;
padding-top: 44px;
position: relative;
@@ -135,11 +135,11 @@
}
.cover-title {
- color: $gl-header-color;
+ color: $gl-text-color;
font-size: 23px;
h1 {
- color: $gl-gray-dark;
+ color: $gl-text-color;
margin-bottom: 6px;
font-size: 23px;
}
@@ -153,7 +153,7 @@
p {
padding: 0 $gl-padding;
- color: $gl-text-color-dark;
+ color: $gl-text-color;
}
}
@@ -211,7 +211,7 @@
display: inline;
font-weight: normal;
font-size: 24px;
- color: $gl-title-color;
+ color: $gl-text-color;
}
}
}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 1c7b2f4df7c..e04a87a7327 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -88,11 +88,11 @@
}
@mixin btn-gray {
- @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-normal, $gray-dark, $border-gray-dark, $gl-gray-dark);
+ @include btn-color($gray-light, $border-gray-normal, $gray-normal, $border-gray-normal, $gray-dark, $border-gray-dark, $gl-text-color);
}
@mixin btn-white {
- @include btn-color($white-light, $border-color, $white-normal, $border-white-normal, $white-dark, $border-white-dark, $gl-text-color);
+ @include btn-color($white-light, $border-color, $white-normal, $border-white-normal, $white-dark, $border-gray-dark, $gl-text-color);
}
@mixin btn-with-margin {
@@ -230,12 +230,19 @@
}
}
+.btn-terminal {
+ svg {
+ height: 14px;
+ width: 18px;
+ }
+}
+
.btn-lg {
padding: 12px 20px;
}
.btn-transparent {
- color: $btn-transparent-color;
+ color: $gl-text-color-secondary;
background-color: transparent;
border: 0;
@@ -289,7 +296,7 @@
.active {
box-shadow: $gl-btn-active-background;
- border: 1px solid $border-white-dark !important;
+ border: 1px solid $border-gray-dark !important;
background-color: $btn-active-gray-light !important;
}
}
@@ -309,8 +316,8 @@
text-align: left;
padding: 6px 16px;
border-color: $border-color;
- color: $btn-placeholder-gray;
- background-color: $background-color;
+ color: $gray-darkest;
+ background-color: $gray-light;
&:hover,
&:active,
@@ -318,8 +325,8 @@
cursor: text;
box-shadow: none;
border-color: $border-color;
- color: $btn-placeholder-gray;
- background-color: $background-color;
+ color: $gray-darkest;
+ background-color: $gray-light;
}
}
@@ -331,7 +338,7 @@
margin-left: 10px;
i {
- color: $gl-icon-color;
+ color: $gl-text-color-secondary;
}
}
@@ -344,8 +351,8 @@
}
.btn-static {
- background-color: $background-color !important;
- border: 1px solid $border-gray-light;
+ background-color: $gray-light !important;
+ border: 1px solid $border-gray-normal;
cursor: default;
&:active {
diff --git a/app/assets/stylesheets/framework/callout.scss b/app/assets/stylesheets/framework/callout.scss
index 2a100980aca..e0e46dd73af 100644
--- a/app/assets/stylesheets/framework/callout.scss
+++ b/app/assets/stylesheets/framework/callout.scss
@@ -11,7 +11,7 @@
padding: $gl-padding;
border-left: 3px solid $border-color;
color: $text-color;
- background: $background-color;
+ background: $gray-light;
}
.bs-callout h4 {
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 251e43d2edd..0ce94a26a7f 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -26,6 +26,7 @@
.append-bottom-default { margin-bottom: $gl-padding; }
.inline { display: inline-block; }
.center { text-align: center; }
+.vertical-align-middle { vertical-align: middle; }
.underlined-link { text-decoration: underline; }
.hint { font-style: italic; color: $hint-color; }
@@ -57,16 +58,33 @@ pre {
border-radius: 0;
color: $well-pre-color;
}
+
+ &.wrap {
+ word-break: break-word;
+ white-space: pre-wrap;
+ }
}
hr {
margin: $gl-padding 0;
+ border-top: 1px solid darken($gray-normal, 8%);
}
.str-truncated {
@include str-truncated;
}
+.block-truncated {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ > div,
+ .str-truncated {
+ display: inline;
+ }
+}
+
.item-title { font-weight: 600; }
/** FLASH message **/
@@ -394,7 +412,7 @@ table {
padding: 0 10px;
clip: auto;
text-decoration: none;
- color: $gl-title-color;
+ color: $gl-text-color;
background: $gray-light;
z-index: 1;
}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index d5914b900e2..755eddefa42 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -10,7 +10,7 @@
@mixin chevron-active {
.fa-chevron-down {
- color: $dropdown-toggle-hover-icon-color;
+ color: $gray-darkest;
}
}
@@ -28,14 +28,14 @@
.dropdown-toggle,
.dropdown-menu-toggle {
@include chevron-active;
- border-color: $dropdown-toggle-hover-border-color;
+ border-color: $gray-darkest;
}
}
.dropdown-toggle {
padding: 6px 8px 6px 10px;
- background-color: $dropdown-toggle-bg;
- color: $dropdown-toggle-color;
+ background-color: $white-light;
+ color: $gl-text-color;
font-size: 14px;
text-align: left;
border: 1px solid $border-color;
@@ -73,7 +73,7 @@
}
.fa {
- color: $dropdown-toggle-icon-color;
+ color: $gray-darkest;
}
.fa-chevron-down {
@@ -85,7 +85,7 @@
&:hover {
@include chevron-active;
- border-color: $dropdown-toggle-hover-border-color;
+ border-color: $gray-darkest;
}
&:focus:active {
@@ -98,7 +98,7 @@
@extend .dropdown-toggle;
padding-right: 20px;
position: relative;
- width: 160px;
+ width: 163px;
text-overflow: ellipsis;
overflow: hidden;
@@ -131,7 +131,7 @@
font-size: 14px;
font-weight: normal;
padding: 8px 0;
- background-color: $dropdown-bg;
+ background-color: $white-light;
border: 1px solid $dropdown-border-color;
border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color;
@@ -188,7 +188,6 @@
&.is-focused {
background-color: $dropdown-link-hover-bg;
text-decoration: none;
- outline: 0;
}
&.dropdown-menu-empty-link {
@@ -202,7 +201,7 @@
}
.icon-play {
- fill: $table-text-gray;
+ fill: $gl-text-color-secondary;
margin-right: 6px;
height: 12px;
width: 11px;
@@ -210,7 +209,7 @@
}
.dropdown-header {
- color: $dropdown-header-color;
+ color: $gl-text-color-secondary;
font-size: 13px;
line-height: 22px;
padding: 0 10px;
@@ -223,7 +222,7 @@
.unclickable {
cursor: not-allowed;
padding: 5px 8px;
- color: $dropdown-header-color;
+ color: $gl-text-color-secondary;
}
}
@@ -593,7 +592,7 @@
}
.ui-datepicker-title {
- color: $gl-gray;
+ color: $gl-text-color;
font-size: 14px;
line-height: 1;
font-weight: normal;
@@ -602,30 +601,30 @@
th {
padding: 2px 0;
- color: $calendar-header-color;
+ color: $note-disabled-comment-color;
font-weight: normal;
text-transform: lowercase;
border-top: 1px solid $calendar-border-color;
}
.ui-datepicker-unselectable {
- background-color: $calendar-unselectable-bg;
+ background-color: $gray-light;
}
}
.dropdown-menu-inner-title {
display: block;
- color: $gl-title-color;
+ color: $gl-text-color;
font-weight: 600;
}
.dropdown-menu-inner-content {
display: block;
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
}
.dropdown-toggle-text {
&.is-default {
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
}
}
diff --git a/app/assets/stylesheets/pages/emojis.scss b/app/assets/stylesheets/framework/emojis.scss
index f17797b2381..7158de65143 100644
--- a/app/assets/stylesheets/pages/emojis.scss
+++ b/app/assets/stylesheets/framework/emojis.scss
@@ -1,4 +1,4 @@
-.emoji-0023-20E3 { background-position: 0 0px; }
+.emoji-0023-20E3 { background-position: 0 0; }
.emoji-002A-20E3 { background-position: -20px 0; }
.emoji-0030-20E3 { background-position: 0 -20px; }
.emoji-0031-20E3 { background-position: -20px -20px; }
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index ab0b81f77f7..c51912b4ac4 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -19,7 +19,7 @@
.file-title {
position: relative;
- background-color: $background-color;
+ background-color: $gray-light;
border-bottom: 1px solid $border-color;
margin: 0;
text-align: left;
@@ -182,3 +182,52 @@ span.idiff {
border-bottom-right-radius: 2px;
}
}
+
+.file-stats {
+ ul {
+ list-style: none;
+ margin: 0;
+ padding: 10px 0;
+
+ li {
+ padding: 3px 0;
+ line-height: 20px;
+ }
+ }
+
+ .new-file {
+ a {
+ color: $gl-text-green;
+ }
+ }
+
+ .renamed-file {
+ a {
+ color: $gl-text-orange;
+ }
+ }
+
+ .deleted-file {
+ a {
+ color: $gl-text-red;
+ }
+ }
+
+ .edit-file {
+ a {
+ color: $gl-text-color;
+ }
+ }
+
+ a {
+ text-decoration: none;
+
+ .new-file {
+ color: $notify-new-file;
+ }
+
+ .deleted-file {
+ color: $notify-deleted-file;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 19827943385..fee38b05023 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -23,3 +23,118 @@
}
}
+.filtered-search-container {
+ display: -webkit-flex;
+ display: flex;
+}
+
+.filtered-search-input-container {
+ display: -webkit-flex;
+ display: flex;
+ position: relative;
+ width: 100%;
+
+ .form-control {
+ padding-left: 25px;
+ padding-right: 25px;
+
+ &:focus ~ .fa-filter {
+ color: $common-gray-dark;
+ }
+ }
+
+ .fa-filter {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ color: $gray-darkest;
+ }
+
+ .fa-times {
+ right: 10px;
+ color: $gray-darkest;
+ }
+
+ .clear-search {
+ width: 35px;
+ background-color: transparent;
+ border: none;
+ position: absolute;
+ right: 0;
+ height: 100%;
+ outline: none;
+
+ &:hover .fa-times {
+ color: $common-gray-dark;
+ }
+ }
+}
+
+.dropdown-menu .filter-dropdown-item {
+ padding: 0;
+}
+
+.filter-dropdown {
+ max-height: 215px;
+ overflow-x: scroll;
+}
+
+.filter-dropdown-item {
+ .btn {
+ border: none;
+ width: 100%;
+ text-align: left;
+ padding: 8px 16px;
+ text-overflow: ellipsis;
+ overflow-y: hidden;
+ border-radius: 0;
+
+ .fa {
+ width: 15px;
+ }
+
+ .dropdown-label-box {
+ border-color: $white-light;
+ border-style: solid;
+ border-width: 1px;
+ width: 17px;
+ height: 17px;
+ }
+
+ &:hover,
+ &:focus {
+ background-color: $dropdown-hover-color;
+ color: $white-light;
+ text-decoration: none;
+
+ .avatar {
+ border-color: $white-light;
+ }
+ }
+ }
+
+ .dropdown-light-content {
+ font-size: 14px;
+ font-weight: 400;
+ }
+
+ .dropdown-user {
+ display: -webkit-flex;
+ display: flex;
+ }
+
+ .dropdown-user-details {
+ display: -webkit-flex;
+ display: flex;
+ -webkit-flex-direction: column;
+ flex-direction: column;
+ }
+}
+
+.hint-dropdown {
+ width: 250px;
+}
+
+.filter-dropdown-loading {
+ padding: 8px 16px;
+}
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 25a2b38baaa..25d6fbe465a 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -22,7 +22,7 @@ input[type='text'].danger {
margin-top: 0;
margin-bottom: -$gl-padding;
padding: $gl-padding;
- background-color: $background-color;
+ background-color: $gray-light;
border-top: 1px solid $border-color;
}
@@ -96,6 +96,10 @@ label {
code {
line-height: 1.8;
}
+
+ img {
+ margin-right: $gl-padding;
+ }
}
@media(max-width: $screen-xs-max) {
@@ -149,7 +153,7 @@ label {
}
.form-control::-webkit-input-placeholder {
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
}
.input-group {
diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss
index 5cd242af91d..d6566dc4ec9 100644
--- a/app/assets/stylesheets/framework/gitlab-theme.scss
+++ b/app/assets/stylesheets/framework/gitlab-theme.scss
@@ -80,29 +80,32 @@
}
}
+ .about-gitlab {
+ color: $color-light;
+ }
}
}
}
-$theme-charcoal: #3d454d;
-$theme-charcoal-light: #485157;
-$theme-charcoal-dark: #383f45;
-$theme-charcoal-text: #b9bbbe;
+$theme-charcoal-light: #b9bbbe;
+$theme-charcoal: #485157;
+$theme-charcoal-dark: #3d454d;
+$theme-charcoal-darker: #383f45;
$theme-blue-light: #becde9;
$theme-blue: #2980b9;
$theme-blue-dark: #1970a9;
$theme-blue-darker: #096099;
-$theme-graphite-lighter: #ccc;
-$theme-graphite-light: #777;
-$theme-graphite: #666;
-$theme-graphite-dark: #555;
+$theme-graphite-light: #ccc;
+$theme-graphite: #777;
+$theme-graphite-dark: #666;
+$theme-graphite-darker: #555;
-$theme-gray-light: #979797;
-$theme-gray: #373737;
-$theme-gray-dark: #272727;
-$theme-gray-darker: #222;
+$theme-black-light: #979797;
+$theme-black: #373737;
+$theme-black-dark: #272727;
+$theme-black-darker: #222;
$theme-green-light: #adc;
$theme-green: #019875;
@@ -120,15 +123,15 @@ body {
}
&.ui_charcoal {
- @include gitlab-theme($theme-charcoal-text, $theme-charcoal-light, $theme-charcoal, $theme-charcoal-dark);
+ @include gitlab-theme($theme-charcoal-light, $theme-charcoal, $theme-charcoal-dark, $theme-charcoal-darker);
}
&.ui_graphite {
- @include gitlab-theme($theme-graphite-lighter, $theme-graphite-light, $theme-graphite, $theme-graphite-dark);
+ @include gitlab-theme($theme-graphite-light, $theme-graphite, $theme-graphite-dark, $theme-graphite-darker);
}
- &.ui_gray {
- @include gitlab-theme($theme-gray-light, $theme-gray, $theme-gray-dark, $theme-gray-darker);
+ &.ui_black {
+ @include gitlab-theme($theme-black-light, $theme-black, $theme-black-dark, $theme-black-darker);
}
&.ui_green {
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index cc2286038c0..24a1ce2b84d 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -9,7 +9,7 @@ header {
&.navbar-empty {
height: $header-height;
background: $white-light;
- border-bottom: 1px solid $btn-gray-hover;
+ border-bottom: 1px solid $white-normal;
.center-logo {
margin: 8px 0;
@@ -27,7 +27,7 @@ header {
z-index: 100;
margin-bottom: 0;
height: $header-height;
- background-color: $background-color;
+ background-color: $gray-light;
border: none;
border-bottom: 1px solid $border-color;
@@ -45,7 +45,7 @@ header {
padding: 0;
.nav > li > a {
- color: $gl-icon-color;
+ color: $gl-text-color-secondary;
font-size: 18px;
padding: 0;
margin: ($header-height - 28) / 2 0;
@@ -57,13 +57,21 @@ header {
&.header-user-dropdown-toggle {
margin-left: 14px;
+
+ &:hover,
+ &:focus,
+ &:active {
+ .header-user-avatar {
+ border-color: rgba($avatar-border, .2);
+ }
+ }
}
&:hover,
&:focus,
&:active {
- background-color: $background-color;
- color: darken($gl-icon-color, 30%);
+ background-color: $gray-light;
+ color: darken($gl-text-color-secondary, 30%);
.todos-pending-count {
background: darken($todo-alert-blue, 10%);
@@ -84,11 +92,11 @@ header {
padding: 6px 10px;
&:hover {
- background-color: $btn-gray-hover;
+ background-color: $white-normal;
}
&.active {
- color: $gl-icon-color;
+ color: $gl-text-color-secondary;
}
}
}
@@ -100,10 +108,11 @@ header {
font-size: 18px;
padding: 6px 10px;
border: none;
- background-color: $background-color;
+ background-color: $gray-light;
&:hover {
- background-color: $btn-gray-hover;
+ background-color: $white-normal;
+ color: $gl-header-nav-hover-color;
}
}
}
@@ -180,6 +189,7 @@ header {
&:hover {
text-decoration: underline;
+ color: $gl-header-nav-hover-color;
}
}
@@ -198,7 +208,7 @@ header {
cursor: pointer;
&:hover {
- color: darken($color: $gl-text-color, $amount: 30%);
+ color: $gl-header-nav-hover-color;
}
}
@@ -271,4 +281,5 @@ header {
float: left;
margin-right: 5px;
border-radius: 50%;
+ border: 1px solid $avatar-border;
}
diff --git a/app/assets/stylesheets/pages/icons.scss b/app/assets/stylesheets/framework/icons.scss
index 226bd2ead31..dccf5177e35 100644
--- a/app/assets/stylesheets/pages/icons.scss
+++ b/app/assets/stylesheets/framework/icons.scss
@@ -34,10 +34,10 @@
.ci-status-icon-canceled,
.ci-status-icon-disabled,
.ci-status-icon-not-found {
- color: $gl-gray;
+ color: $gl-text-color;
svg {
- fill: $gl-gray;
+ fill: $gl-text-color;
}
}
@@ -49,3 +49,11 @@
fill: $gray-darkest;
}
}
+
+.ci-status-icon-manual {
+ color: $gl-text-color;
+
+ svg {
+ fill: $gl-text-color;
+ }
+}
diff --git a/app/assets/stylesheets/framework/images.scss b/app/assets/stylesheets/framework/images.scss
index 878f44116ba..09a569ad415 100644
--- a/app/assets/stylesheets/framework/images.scss
+++ b/app/assets/stylesheets/framework/images.scss
@@ -4,7 +4,7 @@
}
.appearance-light-logo-preview {
- background-color: $background-color;
+ background-color: $gray-light;
max-width: 72px;
padding: 10px;
margin-bottom: 10px;
diff --git a/app/assets/stylesheets/framework/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss
index 44834a84234..46632f15f35 100644
--- a/app/assets/stylesheets/framework/issue_box.scss
+++ b/app/assets/stylesheets/framework/issue_box.scss
@@ -41,6 +41,6 @@
}
&.status-box-upcoming {
- background: $issue-box-upcoming-bg;
+ background: $gl-text-color-secondary;
}
}
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index dfaf2f7f1d3..29d55c44699 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -26,6 +26,62 @@ body {
.container-limited {
max-width: $fixed-layout-width;
+
+ &.limit-container-width {
+ max-width: $limited-layout-width;
+ }
+}
+
+.alert-wrapper {
+ .alert {
+ margin-bottom: 0;
+
+ &:last-child {
+ margin-bottom: $gl-padding;
+ }
+ }
+
+ .alert-link-group {
+ float: right;
+ }
+
+ /* Center alert text and alert action links on smaller screens */
+ @media (max-width: $screen-sm-max) {
+ .alert {
+ text-align: center;
+ }
+
+ .alert-link-group {
+ float: none;
+ }
+ }
+
+ /* Stripe the background colors so that adjacent alert-warnings are distinct from one another */
+ .alert-warning {
+ transition: background-color 0.15s, border-color 0.15s;
+ background-color: lighten($gl-warning, 4%);
+ border-color: lighten($gl-warning, 4%);
+ }
+
+ .alert-warning + .alert-warning {
+ background-color: $gl-warning;
+ border-color: $gl-warning;
+ }
+
+ .alert-warning + .alert-warning + .alert-warning {
+ background-color: darken($gl-warning, 4%);
+ border-color: darken($gl-warning, 4%);
+ }
+
+ .alert-warning + .alert-warning + .alert-warning + .alert-warning {
+ background-color: darken($gl-warning, 8%);
+ border-color: darken($gl-warning, 8%);
+ }
+
+ .alert-warning:only-of-type {
+ background-color: $gl-warning;
+ border-color: $gl-warning;
+ }
}
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index ed4b60faf92..1c6698ad0c6 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -36,7 +36,7 @@
color: $list-warning-row-color;
}
- &.smoke { background-color: $background-color; }
+ &.smoke { background-color: $gray-light; }
&:not(.ui-sort-disabled):hover {
background: $row-hover;
@@ -46,7 +46,7 @@
border-bottom: none;
&.bottom {
- background: $background-color;
+ background: $gray-light;
}
}
@@ -59,7 +59,7 @@
p {
padding-top: 1px;
margin: 0;
- color: $gray-dark;
+ color: $white-normal;
img {
position: relative;
@@ -113,7 +113,7 @@ ul.content-list {
padding: 0;
li {
- border-color: $table-border-color;
+ border-color: $white-normal;
font-size: $list-font-size;
color: $list-text-color;
@@ -128,7 +128,7 @@ ul.content-list {
}
a {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
.member-group-link {
@@ -163,6 +163,10 @@ ul.content-list {
&:last-child {
margin-right: 0;
+
+ @media(max-width: $screen-xs-max) {
+ margin: 0 auto;
+ }
}
}
@@ -186,7 +190,7 @@ ul.content-list {
&.list-placeholder {
background-color: $gray-light;
- border: dotted 1px $gray-dark;
+ border: dotted 1px $white-normal;
margin: 1px 0;
min-height: 52px;
}
@@ -199,6 +203,7 @@ ul.content-list {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
+ align-items: center;
white-space: nowrap;
}
@@ -208,6 +213,11 @@ ul.content-list {
padding-right: 8px;
}
+ .row-fixed-content {
+ flex: 0 0 auto;
+ margin-left: auto;
+ }
+
.row-title {
font-weight: 600;
}
@@ -224,22 +234,53 @@ ul.content-list {
}
.label-default {
- color: $btn-transparent-color;
+ color: $gl-text-color-secondary;
}
}
-.panel > .content-list > li {
- padding: $gl-padding-top $gl-padding;
+// Table list
+.table-list {
+ display: table;
+ width: 100%;
+
+ .table-list-row {
+ display: table-row;
+ }
+
+ .table-list-cell {
+ display: table-cell;
+ vertical-align: top;
+ padding: 10px 16px;
+ border-bottom: 1px solid $gray-darker;
+
+ &.avatar-cell {
+ width: 36px;
+ padding-right: 0;
+
+ img {
+ margin-right: 0;
+ }
+ }
+ }
+
+ &.table-wide {
+ .table-list-cell {
+ &:last-of-type {
+ padding-right: 0;
+ }
- &.commit {
- @media (min-width: $screen-sm-min) {
- padding-left: 46px + $gl-padding;
+ &:first-of-type {
+ padding-left: 0;
+ }
}
}
}
+.panel > .content-list > li {
+ padding: $gl-padding-top $gl-padding;
+}
+
ul.controls {
- padding-top: 1px;
float: right;
list-style: none;
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index 59a30d31ac7..5bff694658c 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -73,7 +73,7 @@
}
.referenced-users {
- color: $gl-header-color;
+ color: $gl-text-color;
padding-top: 10px;
}
@@ -114,7 +114,7 @@
// Border around images in issue and MR comments.
img:not(.emoji) {
- border: 1px solid $table-border-gray;
+ border: 1px solid $white-normal;
padding: 5px;
margin: 5px 0;
// Ensure that image does not exceed viewport
@@ -135,7 +135,7 @@
.toolbar-btn {
float: left;
padding: 0 5px;
- color: $note-toolbar-color;
+ color: $gl-text-color-secondary;
background: transparent;
border: 0;
outline: 0;
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 4f2ac77f228..1acd06122a3 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -46,7 +46,7 @@
&.light {
a {
- color: $gl-gray;
+ color: $gl-text-color;
}
}
}
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index abfdd7a759d..8e2c56a8488 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -23,21 +23,21 @@
margin-right: 0;
}
- .issues-details-filters,
+ .issues-details-filters:not(.filtered-search-block),
.dash-projects-filters,
.check-all-holder {
display: none;
}
- .rss-btn {
+ .issues-holder .issue-check {
display: none;
}
- .project-home-links {
+ .rss-btn {
display: none;
}
- .project-avatar {
+ .project-home-links {
display: none;
}
@@ -54,7 +54,7 @@
}
// Display Star and Fork buttons without counters on mobile.
- .project-action-buttons {
+ .project-repo-buttons {
display: block;
.count-buttons .btn {
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index ea77348633d..401c2d0f6ee 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -51,7 +51,7 @@
margin-bottom: -1px;
font-size: 14px;
line-height: 28px;
- color: $note-toolbar-color;
+ color: $gl-text-color-secondary;
border-bottom: 2px solid transparent;
&:hover,
@@ -76,21 +76,14 @@
color: $black;
}
}
-
- .badge {
- font-weight: normal;
- background-color: $nav-badge-bg;
- color: $btn-transparent-color;
- vertical-align: baseline;
- }
}
&.sub-nav {
text-align: center;
- background-color: $dark-background-color;
+ background-color: $gray-normal;
.container-fluid {
- background-color: $dark-background-color;
+ background-color: $gray-normal;
margin-bottom: 0;
}
@@ -108,7 +101,7 @@
&:hover,
&:active,
&:focus {
- border-bottom: none;
+ border-color: transparent;
}
}
}
@@ -117,14 +110,14 @@
.top-area {
@include clearfix;
- border-bottom: 1px solid $btn-gray-hover;
+ border-bottom: 1px solid $white-normal;
.nav-text {
padding-top: 16px;
padding-bottom: 11px;
display: inline-block;
- width: 50%;
line-height: 28px;
+ white-space: normal;
/* Small devices (phones, tablets, 768px and lower) */
@media (max-width: $screen-xs-max) {
@@ -165,30 +158,24 @@
}
.nav-controls {
- width: 50%;
display: inline-block;
float: right;
text-align: right;
padding: 11px 0;
margin-bottom: 0;
- > .dropdown {
- margin-right: $gl-padding-top;
- display: inline-block;
- vertical-align: top;
-
- &:last-child {
- margin-right: 0;
- }
- }
-
- > .btn {
+ > .btn,
+ > .btn-container,
+ > .dropdown,
+ > input,
+ > form {
margin-right: $gl-padding-top;
display: inline-block;
vertical-align: top;
&:last-child {
margin-right: 0;
+ float: right;
}
}
@@ -196,19 +183,21 @@
float: none;
}
- > form {
- display: inline-block;
- }
-
.icon-label {
display: none;
}
- input {
+ .btn,
+ .dropdown,
+ .dropdown-toggle,
+ input,
+ form {
height: 35px;
+ }
+
+ input {
display: inline-block;
position: relative;
- margin-right: $gl-padding-top;
/* Medium devices (desktops, 992px and up) */
@media (min-width: $screen-md-min) { width: 200px; }
@@ -232,6 +221,7 @@
.btn,
form,
.dropdown,
+ .dropdown-toggle,
.dropdown-menu-toggle,
.form-control {
margin: 0 0 10px;
@@ -270,6 +260,10 @@
.nav-text,
.nav-controls {
width: auto;
+
+ @media (max-width: $screen-xs-max) {
+ width: 100%;
+ }
}
}
@@ -282,6 +276,10 @@
padding: 17px 0;
}
}
+
+ pre {
+ width: 100%;
+ }
}
.layout-nav {
@@ -289,7 +287,7 @@
top: $header-height;
width: 100%;
z-index: 11;
- background: $background-color;
+ background: $gray-light;
border-bottom: 1px solid $border-color;
transition: padding $sidebar-transition-duration;
text-align: center;
@@ -317,7 +315,7 @@
.fa-caret-down {
margin-left: 5px;
- color: $gl-icon-color;
+ color: $gl-text-color-secondary;
}
.dropdown {
@@ -352,7 +350,7 @@
}
.fade-right {
- @include fade(left, $background-color);
+ @include fade(left, $gray-light);
right: -5px;
.fa {
@@ -361,7 +359,7 @@
}
.fade-left {
- @include fade(right, $background-color);
+ @include fade(right, $gray-light);
left: -5px;
.fa {
@@ -372,7 +370,7 @@
&.sub-nav-scroll {
.fade-right {
- @include fade(left, $dark-background-color);
+ @include fade(left, $gray-normal);
right: 0;
.fa {
@@ -381,7 +379,7 @@
}
.fade-left {
- @include fade(right, $dark-background-color);
+ @include fade(right, $gray-normal);
left: 0;
.fa {
@@ -435,3 +433,40 @@
}
}
}
+
+@media (max-width: $screen-xs-max) {
+ .top-area {
+ flex-flow: row wrap;
+
+ .nav-controls {
+ $controls-margin: $btn-xs-side-margin - 2px;
+ flex: 0 0 100%;
+
+ &.controls-flex {
+ display: flex;
+ flex-flow: row wrap;
+ align-items: center;
+ justify-content: center;
+ padding: 0 0 $gl-padding-top;
+ }
+
+ .controls-item,
+ .controls-item-full,
+ .controls-item:last-child {
+ flex: 1 1 35%;
+ display: block;
+ width: 100%;
+ margin: $controls-margin;
+
+ .btn,
+ .dropdown {
+ margin: 0;
+ }
+ }
+
+ .controls-item-full {
+ flex: 1 1 100%;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/framework/page-header.scss b/app/assets/stylesheets/framework/page-header.scss
index 85c1385d5d9..4decee2c525 100644
--- a/app/assets/stylesheets/framework/page-header.scss
+++ b/app/assets/stylesheets/framework/page-header.scss
@@ -14,7 +14,7 @@
.header-action-buttons {
i {
- color: $gl-icon-color;
+ color: $gl-text-color-secondary;
font-size: 13px;
margin-right: 3px;
}
@@ -42,7 +42,7 @@
.commit-committer-link,
.commit-author-link {
- color: $gl-gray;
+ color: $gl-text-color;
font-weight: bold;
}
@@ -57,7 +57,6 @@
}
.ci-status-link {
-
svg {
position: relative;
top: 2px;
diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss
index 5ba0486177f..efe93724013 100644
--- a/app/assets/stylesheets/framework/panels.scss
+++ b/app/assets/stylesheets/framework/panels.scss
@@ -18,6 +18,20 @@
margin-top: -2px;
margin-left: 5px;
}
+
+ &.split {
+ display: flex;
+ align-items: center;
+ }
+
+ .left {
+ flex: 1 1 auto;
+ }
+
+ .right {
+ flex: 0 0 auto;
+ text-align: right;
+ }
}
.panel-body {
@@ -34,3 +48,11 @@
line-height: inherit;
}
}
+
+.panel-default {
+ .table-list-row:last-child {
+ .table-list-cell {
+ border-bottom: 0;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index fde1431b13e..9ab17e67d4c 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -39,7 +39,7 @@
}
&:hover {
- background-color: $gray-dark;
+ background-color: $white-normal;
border-color: $border-white-normal;
color: $gl-text-color;
}
@@ -108,7 +108,7 @@
border-color: $input-border;
color: $gl-text-color;
line-height: 15px;
- background-color: $background-color;
+ background-color: $gray-light;
background-image: none;
.select2-search-choice-close {
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index 0aa609b8dd5..f0b03710c79 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -23,7 +23,7 @@
.sidebar-wrapper {
z-index: 1000;
- background: $background-color;
+ background: $gray-light;
.nicescroll-rails-hr {
// TODO: Figure out why nicescroll doesn't hide horizontal bar
@@ -101,6 +101,17 @@
padding: 0 8px;
border-radius: 6px;
}
+
+ .about-gitlab {
+ padding: 7px $gl-sidebar-padding;
+ font-size: $gl-font-size;
+ line-height: 24px;
+ display: block;
+ text-decoration: none;
+ font-weight: normal;
+ position: absolute;
+ bottom: 10px;
+ }
}
.sidebar-action-buttons {
@@ -172,7 +183,9 @@
&.right-sidebar-expanded {
.line-resolve-all-container {
- display: none;
+ @media (min-width: $sidebar-breakpoint) {
+ display: none;
+ }
}
}
}
@@ -223,9 +236,13 @@ header.header-sidebar-pinned {
@media (min-width: $screen-md-min) {
padding-right: $gutter_width;
- .merge-request-tabs-holder.affix {
+ &:not(.with-overlay) .merge-request-tabs-holder.affix {
right: $gutter_width;
}
+
+ &.with-overlay .merge-request-tabs-holder.affix {
+ right: $sidebar_collapsed_width;
+ }
}
&.with-overlay {
diff --git a/app/assets/stylesheets/pages/snippets.scss b/app/assets/stylesheets/framework/snippets.scss
index ff13b86acf0..5f7e1b17cc7 100644
--- a/app/assets/stylesheets/pages/snippets.scss
+++ b/app/assets/stylesheets/framework/snippets.scss
@@ -22,16 +22,6 @@
.snippet-file-content {
border-radius: 3px;
- margin-bottom: $gl-padding;
-
- .btn-clipboard {
- @extend .btn;
- }
-}
-
-.project-snippets .awards {
- border-bottom: 1px solid $table-border-color;
- padding-bottom: $gl-padding;
}
.snippet-header {
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
index 5d0ca63ea08..6d9fa74a030 100644
--- a/app/assets/stylesheets/framework/tables.scss
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -31,7 +31,7 @@ table {
}
th {
- background-color: $background-color;
+ background-color: $gray-light;
font-weight: normal;
border-bottom: none;
@@ -41,7 +41,7 @@ table {
}
td {
- border-color: $table-border-color;
+ border-color: $white-normal;
}
}
}
diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss
index 875cded8b4e..ff185cd8767 100644
--- a/app/assets/stylesheets/framework/timeline.scss
+++ b/app/assets/stylesheets/framework/timeline.scss
@@ -6,8 +6,8 @@
.timeline-entry {
padding: $gl-padding $gl-btn-padding 11px;
- border-color: $table-border-color;
- color: $gl-gray;
+ border-color: $white-normal;
+ color: $gl-text-color;
border-bottom: 1px solid $border-white-light;
&:target {
@@ -32,7 +32,7 @@
.system-note {
.note-text {
- color: $gl-gray !important;
+ color: $gl-text-color !important;
}
}
diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss
index 55bc325b858..12d56359d7d 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap.scss
@@ -91,14 +91,14 @@
// Labels
.label {
padding: 4px 5px;
- font-size: 13px;
+ font-size: 12px;
font-style: normal;
font-weight: normal;
display: inline-block;
&.label-gray {
background-color: $label-gray-bg;
- color: $gl-gray;
+ color: $gl-text-color;
text-shadow: none;
}
diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
index c731a8f222f..0fc89d5976a 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
@@ -65,11 +65,11 @@ $legend-color: $text-color;
//
//##
-$pagination-color: $gl-gray;
+$pagination-color: $gl-text-color;
$pagination-bg: $white-light;
$pagination-border: $border-color;
-$pagination-hover-color: $gl-gray;
+$pagination-hover-color: $gl-text-color;
$pagination-hover-bg: $row-hover;
$pagination-hover-border: $border-color;
@@ -78,7 +78,7 @@ $pagination-active-bg: $white-light;
$pagination-active-border: $border-color;
$pagination-disabled-color: #cdcdcd;
-$pagination-disabled-bg: $background-color;
+$pagination-disabled-bg: $gray-light;
$pagination-disabled-border: $border-color;
@@ -117,10 +117,13 @@ $alert-border-radius: 0;
$panel-border-radius: 2px;
$panel-default-text: $text-color;
$panel-default-border: $border-color;
-$panel-default-heading-bg: $background-color;
-$panel-footer-bg: $background-color;
+$panel-default-heading-bg: $gray-light;
+$panel-footer-bg: $gray-light;
$panel-inner-border: $border-color;
+$badge-bg: $badge-bg;
+$badge-color: $badge-color;
+
//== Wells
//
//##
@@ -153,8 +156,8 @@ $nav-link-padding: 13px $gl-padding;
//== Code
//
//##
-$pre-bg: $background-color !default;
-$pre-color: $gl-gray !default;
+$pre-bg: $gray-light !default;
+$pre-color: $gl-text-color !default;
$pre-border-color: $border-color;
-$table-bg-accent: $background-color;
+$table-bg-accent: $gray-light;
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index d906d26bba9..bd58a26f429 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -1,5 +1,5 @@
@mixin md-typography {
- color: $md-text-color;
+ color: $gl-text-color;
word-wrap: break-word;
a {
@@ -50,14 +50,14 @@
margin: 16px 0 10px;
padding: 0 0 0.3em;
border-bottom: 1px solid $white-dark;
- color: $gl-gray-dark;
+ color: $gl-text-color;
}
h2 {
font-size: 1.5em;
font-weight: 600;
margin: 16px 0 10px;
- color: $gl-gray-dark;
+ color: $gl-text-color;
}
h3 {
@@ -100,7 +100,7 @@
}
p {
- color: $gl-text-color-dark;
+ color: $gl-text-color;
margin: 6px 0 0;
}
@@ -108,7 +108,7 @@
@extend .table;
@extend .table-bordered;
margin: 12px 0;
- color: $gl-text-color-dark;
+ color: $gl-text-color;
th {
background: $label-gray-bg;
@@ -230,7 +230,7 @@ h3,
h4,
h5,
h6 {
- color: $gl-title-color;
+ color: $gl-text-color;
font-weight: 600;
}
@@ -292,7 +292,7 @@ h2,
h3,
h4 {
small {
- color: $gl-gray;
+ color: $gl-text-color;
}
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index a1d5f6427f4..07cb669a46e 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -5,7 +5,7 @@ $sidebar_collapsed_width: 62px;
$sidebar_width: 220px;
$gutter_collapsed_width: 62px;
$gutter_width: 290px;
-$gutter_inner_width: 258px;
+$gutter_inner_width: 250px;
$sidebar-transition-duration: .15s;
$sidebar-breakpoint: 1024px;
@@ -17,16 +17,16 @@ $darken-dark-factor: 10%;
$darken-border-factor: 5%;
$white-light: #fff;
-$white-normal: darken($white-light, $darken-normal-factor);
-$white-dark: darken($white-light, $darken-dark-factor);
+$white-normal: #f0f0f0;
+$white-dark: #eaeaea;
$gray-lightest: #fdfdfd;
$gray-light: #fafafa;
$gray-lighter: #f9f9f9;
-$gray-normal: darken($gray-light, $darken-normal-factor);
+$gray-normal: #f5f5f5;
$gray-dark: darken($gray-light, $darken-dark-factor);
$gray-darker: #eee;
-$gray-darkest: #c9c9c9;
+$gray-darkest: #c4c4c4;
$green-light: #3cbd70;
$green-normal: darken($green-light, $darken-normal-factor);
@@ -55,11 +55,10 @@ $black-transparent: rgba(0, 0, 0, 0.3);
$border-white-light: darken($white-light, $darken-border-factor);
$border-white-normal: darken($white-normal, $darken-border-factor);
-$border-white-dark: darken($white-dark, $darken-border-factor);
$border-gray-light: darken($gray-light, $darken-border-factor);
$border-gray-normal: darken($gray-normal, $darken-border-factor);
-$border-gray-dark: darken($gray-dark, $darken-border-factor);
+$border-gray-dark: darken($white-normal, $darken-border-factor);
$border-green-extra-light: #9adb84;
$border-green-light: darken($green-light, $darken-border-factor);
@@ -78,9 +77,6 @@ $border-red-light: darken($red-light, $darken-border-factor);
$border-red-normal: darken($red-normal, $darken-border-factor);
$border-red-dark: darken($red-dark, $darken-border-factor);
-$help-well-bg: $gray-light;
-$help-well-border: #e5e5e5;
-
$warning-message-bg: #fbf2d9;
$warning-message-color: #9e8e60;
$warning-message-border: #f0e2bb;
@@ -90,10 +86,7 @@ $warning-message-border: #f0e2bb;
*/
$border-color: #e5e5e5;
$focus-border-color: #3aabf0;
-$table-border-color: #f0f0f0;
-$background-color: $gray-light;
-$dark-background-color: #f5f5f5;
-$table-text-gray: #8f8f8f;
+$sidebar-collapsed-icon-color: #999;
$well-expand-item: #e8f2f7;
$well-inner-border: #eef0f2;
$well-light-border: #f1f1f1;
@@ -103,31 +96,26 @@ $well-light-text-color: #5b6169;
* Text
*/
$gl-font-size: 14px;
-$gl-title-color: #333;
-$gl-text-color: #5c5c5c;
-$gl-text-color-dark: #5c5d5e;
-$gl-text-color-light: #8c8c8c;
+$gl-text-color: rgba(0, 0, 0, .85);
+$gl-text-color-secondary: rgba(0, 0, 0, .55);
+$gl-text-color-disabled: rgba(0, 0, 0, .35);
$gl-text-green: #4a2;
$gl-text-red: #d12f19;
$gl-text-orange: #d90;
$gl-link-color: #3777b0;
-$gl-diff-text-color: #555;
-$gl-dark-link-color: #333;
-$gl-placeholder-color: #8f8f8f;
-$gl-icon-color: $gl-placeholder-color;
$gl-grayish-blue: #7f8fa4;
$gl-gray: $gl-text-color;
$gl-gray-dark: #313236;
-$gl-gray-light: $gl-placeholder-color;
$gl-header-color: #4c4e54;
+$gl-header-nav-hover-color: #434343;
/*
* Lists
*/
$list-font-size: $gl-font-size;
-$list-title-color: $gl-title-color;
+$list-title-color: $gl-text-color;
$list-text-color: $gl-text-color;
-$list-text-disabled-color: #888;
+$list-text-disabled-color: $gl-text-color-disabled;
$list-border-light: #eee;
$list-border: rgba(0, 0, 0, 0.05);
$list-text-height: 42px;
@@ -138,15 +126,14 @@ $list-warning-row-color: #8a6d3b;
/*
* Markdown
*/
-$md-text-color: $gl-text-color;
$md-link-color: $gl-link-color;
$md-area-border: #ddd;
/*
* Code
*/
-$code_font_size: 13px;
-$code_line_height: 1.5;
+$code_font_size: 12px;
+$code_line_height: 1.6;
/*
* Padding
@@ -166,11 +153,11 @@ $row-hover-border: #b2d7ff;
$progress-color: #c0392b;
$header-height: 50px;
$fixed-layout-width: 1280px;
+$limited-layout-width: 990px;
+$gl-avatar-size: 40px;
$error-exclamation-point: #e62958;
$border-radius-default: 2px;
-$btn-transparent-color: #8f8f8f;
$settings-icon-size: 18px;
-$provider-btn-group-border: #e5e5e5;
$provider-btn-not-active-color: #4688f1;
$link-underline-blue: #4a8bee;
$active-item-blue: #4a8bee;
@@ -179,9 +166,7 @@ $btn-side-margin: 10px;
$btn-sm-side-margin: 7px;
$btn-xs-side-margin: 5px;
$issue-status-expired: #cea61b;
-$issuable-sidebar-color: #999;
-$issuable-avatar-hover-border: #999;
-$issuable-clipboard-color: #999;
+$issuable-sidebar-color: $gl-text-color-secondary;
$show-aside-bg: #eee;
$show-aside-color: #777;
$show-aside-shadow: #ddd;
@@ -193,7 +178,9 @@ $count-arrow-border: #dce0e5;
$save-project-loader-color: #555;
$divergence-graph-bar-bg: #ccc;
$divergence-graph-separator-bg: #ccc;
-$issue-box-upcoming-bg: #8f8f8f;
+$general-hover-transition-duration: 150ms;
+$general-hover-transition-curve: linear;
+
/*
* Common component specific colors
@@ -246,8 +233,6 @@ $line-removed-dark: #fac5cd;
$line-number-old: #f9d7dc;
$line-number-new: #ddfbe6;
$line-number-select: #fbf2da;
-$match-line: $gray-light;
-$table-border-gray: #f0f0f0;
$line-target-blue: #f6faff;
$line-select-yellow: #fcf8e7;
$line-select-yellow-dark: #f0e2bd;
@@ -257,7 +242,6 @@ $file-mode-changed: #777;
$file-mode-changed: #777;
$diff-image-bg: #ddd;
$diff-image-info-color: grey;
-$diff-image-img-bg: #e5e5e5;
$diff-swipe-border: #999;
$diff-view-modes-color: grey;
$diff-view-modes-border: #c1c1c1;
@@ -272,14 +256,12 @@ $regular_font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-San
* Dropdowns
*/
$dropdown-width: 300px;
-$dropdown-bg: #fff;
$dropdown-link-color: #555;
$dropdown-link-hover-bg: $row-hover;
$dropdown-empty-row-bg: rgba(#000, .04);
$dropdown-border-color: $border-color;
$dropdown-shadow-color: rgba(#000, .1);
$dropdown-divider-color: rgba(#000, .1);
-$dropdown-header-color: #959494;
$dropdown-title-btn-color: #bfbfbf;
$dropdown-input-color: #555;
$dropdown-input-fa-color: #c7c7c7;
@@ -287,31 +269,31 @@ $dropdown-input-focus-border: $focus-border-color;
$dropdown-input-focus-shadow: rgba($dropdown-input-focus-border, .4);
$dropdown-loading-bg: rgba(#fff, .6);
$dropdown-chevron-size: 10px;
+$dropdown-toggle-active-border-color: darken($border-color, 14%);
+
-$dropdown-toggle-bg: #fff;
-$dropdown-toggle-color: #5c5c5c;
-$dropdown-toggle-border-color: #e5e5e5;
-$dropdown-toggle-hover-border-color: darken($dropdown-toggle-border-color, 13%);
-$dropdown-toggle-active-border-color: darken($dropdown-toggle-border-color, 14%);
-$dropdown-toggle-icon-color: #c4c4c4;
-$dropdown-toggle-hover-icon-color: darken($dropdown-toggle-icon-color, 7%);
+/*
+* Filtered Search
+*/
+$dropdown-hover-color: #3b86ff;
/*
* Buttons
*/
$btn-active-gray: #ececec;
$btn-active-gray-light: e4e7ed;
-$btn-placeholder-gray: #c7c7c7;
$btn-white-active: #848484;
-$btn-gray-hover: #eee;
+
+/*
+* Badges
+*/
+$badge-bg: #eee;
+$badge-color: $gl-text-color-secondary;
/*
* Award emoji
*/
-$award-emoji-menu-bg: #fff;
-$award-emoji-menu-border: #f1f2f4;
$award-emoji-menu-shadow: rgba(0,0,0,.175);
-$award-emoji-new-btn-icon-color: #dcdcdc;
/*
* Search Box
@@ -319,22 +301,15 @@ $award-emoji-new-btn-icon-color: #dcdcdc;
$search-input-border-color: rgba(#4688f1, .8);
$search-input-focus-shadow-color: $dropdown-input-focus-shadow;
$search-input-width: 220px;
-$location-badge-color: #aaa;
-$location-badge-bg: $dark-background-color;
$location-badge-active-bg: #4f91f8;
$location-icon-color: #e7e9ed;
-$location-icon-active-color: #807e7e;
/*
* Notes
*/
-$notes-light-color: #8e8e8e;
-$notes-action-color: #c3c3c3;
-$notes-role-color: #8e8e8e;
-$notes-role-border-color: #e4e4e4;
+$notes-light-color: $gl-text-color-secondary;
+$notes-role-color: $gl-text-color-secondary;
$note-disabled-comment-color: #b2b2b2;
-$note-form-border-color: #e5e5e5;
-$note-toolbar-color: #959494;
$note-targe3-outside: #fffff0;
$note-targe3-inside: #ffffd3;
$note-line2-border: #ddd;
@@ -344,15 +319,12 @@ $note-line2-border: #ddd;
* Zen
*/
$zen-control-color: #555;
-$zen-control-hover-color: #111;
/*
* Calendar
*/
-$calendar-header-color: #b8b8b8;
$calendar-hover-bg: #ecf3fe;
$calendar-border-color: rgba(#000, .1);
-$calendar-unselectable-bg: $gray-light;
$calendar-user-contrib-text: #959494;
/*
@@ -361,20 +333,13 @@ $calendar-user-contrib-text: #959494;
$cycle-analytics-box-padding: 30px;
$cycle-analytics-box-text-color: #8c8c8c;
$cycle-analytics-big-font: 19px;
-$cycle-analytics-dark-text: $gl-title-color;
+$cycle-analytics-dark-text: $gl-text-color;
$cycle-analytics-light-gray: #bfbfbf;
$cycle-analytics-dismiss-icon-color: #b2b2b2;
/*
- * Personal Access Tokens
- */
-$personal-access-tokens-disabled-label-color: #bbb;
-
-/*
* CI
*/
-$ci-output-bg: #1d1f21;
-$ci-text-color: #c5c8c6;
$ci-skipped-color: #888;
/*
@@ -414,14 +379,13 @@ $callout-success-color: #3c763d;
/*
* Commit Page
*/
-$commit-committer-color: #999;
$commit-max-width-marker-color: rgba(0, 0, 0, 0.0);
$commit-message-text-area-bg: rgba(0, 0, 0, 0.0);
/*
* Common
*/
-$common-gray: $gl-gray;
+$common-gray: $gl-text-color;
$common-gray-light: #bbb;
$common-gray-dark: #444;
$common-red: $gl-text-red;
@@ -470,9 +434,9 @@ $help-shortcut-header-color: #333;
/*
* Issues
*/
-$issues-border: #e5e5e5;
$issues-today-bg: #f3fff2;
$issues-today-border: #e1e8d5;
+$compare-display-color: #888;
/*
* jQuery UI
@@ -486,7 +450,7 @@ $jq-ui-default-color: #777;
$label-gray-bg: #f8fafc;
$label-inverse-bg: #333;
$label-remove-border: rgba(0, 0, 0, .1);
-$label-border-radius: 14px;
+$label-border-radius: 100px;
/*
* Lint
@@ -522,16 +486,15 @@ $project-option-descr-color: #54565b;
$project-breadcrumb-color: #999;
$project-private-forks-notice-odd: #2aa056;
$project-network-controls-color: #888;
-$project-limit-message-bg: #f28d35;
/*
* Runners
*/
$runner-state-shared-bg: #32b186;
$runner-state-specific-bg: #3498db;
-$runner-status-online-color: green;
-$runner-status-offline-color: gray;
-$runner-status-paused-color: red;
+$runner-status-online-color: $green-normal;
+$runner-status-offline-color: $gray-darkest;
+$runner-status-paused-color: $red-normal;
/*
Stat Graph
@@ -572,3 +535,10 @@ $body-text-shadow: rgba(255,255,255,0.01);
*/
$ui-dev-kit-example-color: #bbb;
$ui-dev-kit-example-border: #ddd;
+
+/*
+Pipeline Graph
+*/
+$stage-hover-bg: #eaf3fc;
+$stage-hover-border: #d1e7fc;
+$action-icon-color: #d6d6d6; \ No newline at end of file
diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss
index f2860dfe84d..32eb750180f 100644
--- a/app/assets/stylesheets/framework/wells.scss
+++ b/app/assets/stylesheets/framework/wells.scss
@@ -1,6 +1,6 @@
.info-well {
- background: $background-color;
- color: $gl-gray;
+ background: $gray-light;
+ color: $gl-text-color;
border: 1px solid $border-color;
border-radius: $border-radius-default;
@@ -45,7 +45,7 @@
}
.light-well {
- background-color: $background-color;
+ background-color: $gray-light;
padding: 15px;
}
diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss
index e5c7d70d45a..97ade638db6 100644
--- a/app/assets/stylesheets/framework/zen.scss
+++ b/app/assets/stylesheets/framework/zen.scss
@@ -40,7 +40,7 @@
}
.zen-control-full {
- color: $note-toolbar-color;
+ color: $gl-text-color-secondary;
&:hover {
color: $gl-link-color;
@@ -57,6 +57,6 @@
font-size: 36px;
&:hover {
- color: $zen-control-hover-color;
+ color: $black;
}
}
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index 1adab3ffd94..b425c78e0d5 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -3,7 +3,7 @@
/*
* White Syntax Colors
*/
-$white-code-color: #333;
+$white-code-color: $gl-text-color;
$white-highlight: #fafe3d;
$white-pre-hll-bg: #f8eec7;
$white-hll-bg: #f8f8f8;
@@ -69,14 +69,14 @@ $white-gc-bg: #eaf2f5;
@mixin matchLine {
color: $black-transparent;
- background-color: $match-line;
+ background-color: $gray-light;
}
.code.white {
// Line numbers
.line-numbers,
.diff-line-num {
- background-color: $background-color;
+ background-color: $gray-light;
}
.diff-line-num,
@@ -87,7 +87,7 @@ $white-gc-bg: #eaf2f5;
// Code itself
pre.code,
.diff-line-num {
- border-color: $table-border-gray;
+ border-color: $white-normal;
}
&,
diff --git a/app/assets/stylesheets/mailers/highlighted_diff_email.scss b/app/assets/stylesheets/mailers/highlighted_diff_email.scss
index 024b4df6bd0..60ff72c703e 100644
--- a/app/assets/stylesheets/mailers/highlighted_diff_email.scss
+++ b/app/assets/stylesheets/mailers/highlighted_diff_email.scss
@@ -91,9 +91,9 @@ $highlighted-gc-bg: #eaf2f5;
padding: 0 5px;
text-align: right;
width: 35px;
- background-color: $background-color;
+ background-color: $gray-light;
color: $black-transparent;
- border-right: 1px solid $table-border-gray;
+ border-right: 1px solid $white-normal;
&.old {
background-color: $line-number-old;
@@ -130,7 +130,7 @@ $highlighted-gc-bg: #eaf2f5;
&.match {
color: $black-transparent;
- background-color: $match-line;
+ background-color: $gray-light;
}
}
diff --git a/app/assets/stylesheets/notify.scss b/app/assets/stylesheets/notify.scss
index ddc382362f7..a81e5eb5ebf 100644
--- a/app/assets/stylesheets/notify.scss
+++ b/app/assets/stylesheets/notify.scss
@@ -18,15 +18,3 @@ p.details {
pre.commit-message {
white-space: pre-wrap;
}
-
-.file-stats > a {
- text-decoration: none;
-
- > .new-file {
- color: $notify-new-file;
- }
-
- > .deleted-file {
- color: $notify-deleted-file;
- }
-}
diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss
index 0d9cf679e7c..f2d60bff2b5 100644
--- a/app/assets/stylesheets/pages/boards.scss
+++ b/app/assets/stylesheets/pages/boards.scss
@@ -31,7 +31,7 @@
.dropdown-content {
max-height: 150px;
- }
+ }
}
.issue-board-dropdown-content {
@@ -74,6 +74,7 @@
height: 475px; // Needed for PhantomJS
height: calc(100vh - 220px);
min-height: 475px;
+ transition: width .2s;
&.is-compact {
width: calc(100% - 290px);
@@ -98,7 +99,7 @@
.board-inner {
height: 100%;
font-size: $issue-boards-font-size;
- background: $background-color;
+ background: $gray-light;
border: 1px solid $border-color;
border-radius: $border-radius-default;
}
@@ -109,6 +110,12 @@
&.has-border {
border-top: 3px solid;
+ margin-top: -1px;
+ margin-right: -1px;
+ margin-left: -1px;
+ padding-top: 1px;
+ padding-right: 1px;
+ padding-left: 1px;
.board-title {
padding-top: ($gl-padding - 3px);
@@ -253,7 +260,7 @@
.board-list-count {
padding: 10px 0;
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
font-size: 13px;
> .fa {
@@ -332,3 +339,18 @@
}
}
}
+
+.right-sidebar.right-sidebar-expanded {
+ &.boards-sidebar-slide-enter-active,
+ &.boards-sidebar-slide-leave-active {
+ transition: width .2s,
+ padding .2s;
+ }
+
+ &.boards-sidebar-slide-enter,
+ &.boards-sidebar-slide-leave-active {
+ width: 0;
+ padding-left: 0;
+ padding-right: 0;
+ }
+}
diff --git a/app/assets/stylesheets/pages/branches.scss b/app/assets/stylesheets/pages/branches.scss
new file mode 100644
index 00000000000..3e2fa8ca88d
--- /dev/null
+++ b/app/assets/stylesheets/pages/branches.scss
@@ -0,0 +1,55 @@
+.divergence-graph {
+ padding: 12px 12px 0 0;
+ float: right;
+
+ .graph-side {
+ position: relative;
+ width: 80px;
+ height: 22px;
+ padding: 5px 0 13px;
+ float: left;
+
+ .bar {
+ position: absolute;
+ height: 4px;
+ background-color: $divergence-graph-bar-bg;
+ }
+
+ .bar-behind {
+ right: 0;
+ border-radius: 3px 0 0 3px;
+ }
+
+ .bar-ahead {
+ left: 0;
+ border-radius: 0 3px 3px 0;
+ }
+
+ .count {
+ padding-top: 6px;
+ padding-bottom: 0;
+ font-size: 12px;
+ color: $gl-text-color;
+ display: block;
+ }
+
+ .count-behind {
+ padding-right: 4px;
+ text-align: right;
+ }
+
+ .count-ahead {
+ padding-left: 4px;
+ text-align: left;
+ }
+ }
+
+ .graph-separator {
+ position: relative;
+ width: 1px;
+ height: 18px;
+ margin: 5px 0 0;
+ float: left;
+ background-color: $divergence-graph-separator-bg;
+ }
+}
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index dcc13f6d74a..fd101d43b5b 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -1,3 +1,34 @@
+@keyframes fade-out-status {
+ 0%, 50% { opacity: 1; }
+ 100% { opacity: 0; }
+}
+
+@keyframes blinking-dots {
+ 0% {
+ background-color: rgba($white-light, 1);
+ box-shadow: 12px 0 0 0 rgba($white-light,0.2),
+ 24px 0 0 0 rgba($white-light,0.2);
+ }
+
+ 25% {
+ background-color: rgba($white-light, 0.4);
+ box-shadow: 12px 0 0 0 rgba($white-light,2),
+ 24px 0 0 0 rgba($white-light,0.2);
+ }
+
+ 75% {
+ background-color: rgba($white-light, 0.4);
+ box-shadow: 12px 0 0 0 rgba($white-light,0.2),
+ 24px 0 0 0 rgba($white-light,1);
+ }
+
+ 100% {
+ background-color: rgba($white-light, 1);
+ box-shadow: 12px 0 0 0 rgba($white-light,0.2),
+ 24px 0 0 0 rgba($white-light,0.2);
+ }
+}
+
.build-page {
pre.trace {
background: $builds-trace-bg;
@@ -14,45 +45,99 @@
}
}
- .scroll-controls {
- .scroll-step {
- width: 31px;
- margin: 0 0 0 auto;
+ .environment-information {
+ background-color: $gray-light;
+ border: 1px solid $border-color;
+ padding: 12px $gl-padding;
+ border-radius: $border-radius-default;
+
+ svg {
+ position: relative;
+ top: 1px;
+ margin-right: 5px;
+ }
+ }
+}
+
+.scroll-controls {
+ height: 100%;
+
+ .scroll-step {
+ width: 31px;
+ margin: 0 0 0 auto;
+ }
+
+ .scroll-link,
+ .autoscroll-container {
+ right: 25px;
+ z-index: 1;
+ }
+
+ .scroll-link {
+ position: fixed;
+ display: block;
+ margin-bottom: 10px;
+
+ &.scroll-top .gitlab-icon-scroll-up-hover,
+ &.scroll-top:hover .gitlab-icon-scroll-up,
+ &.scroll-bottom .gitlab-icon-scroll-down-hover,
+ &.scroll-bottom:hover .gitlab-icon-scroll-down {
+ display: none;
}
- &.affix-bottom {
- position: absolute;
- right: 25px;
+ &.scroll-top:hover .gitlab-icon-scroll-up-hover,
+ &.scroll-bottom:hover .gitlab-icon-scroll-down-hover {
+ display: inline-block;
}
- &.affix {
- right: 25px;
- bottom: 15px;
- z-index: 1;
+ &.scroll-top {
+ top: 110px;
}
- &.sidebar-expanded {
- right: #{$gutter_width + ($gl-padding * 2)};
+ &.scroll-bottom {
+ bottom: -2px;
}
+ }
- a {
- display: block;
- margin-bottom: 10px;
+ .autoscroll-container {
+ position: absolute;
+ }
+
+ &.sidebar-expanded {
+
+ .scroll-link,
+ .autoscroll-container {
+ right: ($gutter_width + ($gl-padding * 2));
}
}
+}
- .environment-information {
- background-color: $background-color;
- border: 1px solid $border-color;
- padding: 12px $gl-padding;
- border-radius: $border-radius-default;
+.status-message {
+ display: inline-block;
+ color: $white-light;
- svg {
- position: relative;
- top: 1px;
- margin-right: 5px;
+ .status-icon {
+ display: inline-block;
+ width: 16px;
+ height: 33px;
+ }
+
+ .status-text {
+ float: left;
+ opacity: 0;
+ margin-right: 10px;
+ font-weight: normal;
+ line-height: 1.8;
+ transition: opacity 1s ease-out;
+
+ &.animate {
+ animation: fade-out-status 2s ease;
}
}
+
+ &:hover .status-text {
+ opacity: 1;
+ }
}
.build-header {
@@ -75,7 +160,7 @@
flex: 1;
a {
- color: $gl-gray;
+ color: $gl-text-color;
&:hover {
color: $gl-link-color;
@@ -96,8 +181,8 @@
}
.build-trace {
- background: $ci-output-bg;
- color: $ci-text-color;
+ background: $black;
+ color: $gray-darkest;
white-space: pre;
overflow-x: auto;
font-size: 12px;
@@ -109,6 +194,15 @@
.bash {
display: block;
}
+
+ .build-loader-animation {
+ position: relative;
+ width: 6px;
+ height: 6px;
+ margin: auto auto 12px 2px;
+ border-radius: 50%;
+ animation: blinking-dots 1s linear infinite;
+ }
}
.right-sidebar.build-sidebar {
@@ -248,6 +342,12 @@
}
}
+.build-sidebar {
+ .container-fluid.container-limited {
+ max-width: 100%;
+ }
+}
+
.build-detail-row {
margin-bottom: 5px;
@@ -257,7 +357,7 @@
}
.build-light-text {
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
}
.build-gutter-toggle {
diff --git a/app/assets/stylesheets/pages/ci_projects.scss b/app/assets/stylesheets/pages/ci_projects.scss
index d1cd1e5d848..90643832390 100644
--- a/app/assets/stylesheets/pages/ci_projects.scss
+++ b/app/assets/stylesheets/pages/ci_projects.scss
@@ -18,7 +18,7 @@
}
td {
- color: $gl-gray;
+ color: $gl-text-color;
vertical-align: middle !important;
a {
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
deleted file mode 100644
index bf656d0e28e..00000000000
--- a/app/assets/stylesheets/pages/commit.scss
+++ /dev/null
@@ -1,132 +0,0 @@
-.commit-title {
- display: block;
-}
-
-.commit-author,
-.commit-committer {
- display: block;
- color: $commit-committer-color;
- font-weight: normal;
- font-style: italic;
-}
-
-.commit-author strong,
-.commit-committer strong {
- font-weight: bold;
- font-style: normal;
-}
-
-.commit-description {
- background: none;
- border: none;
- margin: 0;
- padding: 0;
- margin-top: 10px;
- word-break: normal;
- white-space: pre-wrap;
-}
-
-.js-details-expand {
- &:hover {
- text-decoration: none;
- }
-}
-
-.ci-status-link {
- svg {
- overflow: visible;
- }
-}
-
-.commit-box {
- border-top: 1px solid $border-color;
- padding: $gl-padding 0;
-
- .commit-title {
- margin: 0;
- font-size: 23px;
- color: $gl-gray-dark;
- }
-
- .commit-description {
- margin-top: 15px;
- }
-}
-
-.commit-hash-full {
- @media (max-width: $screen-sm-max) {
- width: 80px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- display: inline-block;
- vertical-align: bottom;
- }
-}
-
-.file-stats {
- ul {
- list-style: none;
- margin: 0;
- padding: 10px 0;
-
- li {
- padding: 3px 0;
- line-height: 20px;
- }
- }
-
- .new-file {
- a {
- color: $gl-text-green;
- }
- }
-
- .renamed-file {
- a {
- color: $gl-text-orange;
- }
- }
-
- .deleted-file {
- a {
- color: $gl-text-red;
- }
- }
-
- .edit-file {
- a {
- color: $gl-text-color;
- }
- }
-}
-
-/*
- * Commit message textarea for web editor and
- * custom merge request message
- */
-.commit-message-container {
- background-color: $body-bg;
- position: relative;
- font-family: $monospace_font;
- $left: 12px;
- overflow: hidden; // See https://gitlab.com/gitlab-org/gitlab-ce/issues/13987
- .max-width-marker {
- width: 72ch;
- color: $commit-max-width-marker-color;
- font-family: inherit;
- left: $left;
- height: 100%;
- border-right: 1px solid mix($input-border, $white-light);
- position: absolute;
- z-index: 1;
- }
-
- > textarea {
- background-color: $commit-message-text-area-bg;
- font-family: inherit;
- padding-left: $left;
- position: relative;
- z-index: 2;
- }
-}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index c29b5fdea78..fef8e8eec27 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -1,14 +1,82 @@
+.commit-description {
+ background: none;
+ border: none;
+ padding: 0;
+ margin-top: 10px;
+ word-break: normal;
+ white-space: pre-wrap;
+}
+
+.js-details-expand {
+ &:hover {
+ text-decoration: none;
+ }
+}
+
+.commit-box {
+ border-top: 1px solid $border-color;
+ padding: $gl-padding 0;
+
+ .commit-title {
+ margin: 0;
+ color: $gl-text-color;
+ }
+
+ .commit-description {
+ margin-top: 15px;
+ }
+}
+
+.commit-hash-full {
+ @media (max-width: $screen-sm-max) {
+ width: 80px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: inline-block;
+ vertical-align: bottom;
+ }
+}
+
+/*
+ * Commit message textarea for web editor and
+ * custom merge request message
+ */
+.commit-message-container {
+ background-color: $body-bg;
+ position: relative;
+ font-family: $monospace_font;
+ $left: 12px;
+ overflow: hidden; // See https://gitlab.com/gitlab-org/gitlab-ce/issues/13987
+ .max-width-marker {
+ width: 72ch;
+ color: $commit-max-width-marker-color;
+ font-family: inherit;
+ left: $left;
+ height: 100%;
+ border-right: 1px solid mix($input-border, $white-light);
+ position: absolute;
+ z-index: 1;
+ }
+
+ textarea {
+ background-color: $commit-message-text-area-bg;
+ font-family: inherit;
+ padding-left: $left;
+ position: relative;
+ z-index: 2;
+ }
+}
+
+
.commits-compare-switch {
- @include btn-default;
- @include btn-white;
float: left;
margin-right: 9px;
}
.commit-header {
padding: 5px 10px;
- background-color: $background-color;
- border-top: 1px solid $gray-darker;
+ background-color: $gray-light;
border-bottom: 1px solid $gray-darker;
font-size: 14px;
@@ -18,8 +86,6 @@
}
.commit-row-title {
- line-height: 1.35;
-
.notes_count {
float: right;
margin-right: 10px;
@@ -30,15 +96,14 @@
}
.commit-row-message {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
-
}
.text-expander {
display: inline-block;
background: $gray-light;
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
padding: 0 5px;
cursor: pointer;
border: 1px solid $border-gray-dark;
@@ -54,9 +119,8 @@
.commit-actions {
@media (min-width: $screen-sm-min) {
- float: right;
- margin-left: $gl-padding;
- margin-top: 2px;
+ width: 300px;
+ text-align: right;
font-size: 0;
}
@@ -86,38 +150,16 @@
.commit,
.generic_commit_status {
- padding: 10px 0;
- position: relative;
-
- @media (min-width: $screen-sm-min) {
- padding-left: 46px;
- }
-
- &:not(:last-child) {
- border-bottom: 1px solid $gray-darker;
- }
a,
button {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
vertical-align: baseline;
}
- .avatar {
- margin-left: -46px;
- }
-
- .item-title {
- display: inline-block;
-
- @media (min-width: $screen-sm-min) {
- max-width: 70%;
- }
- }
-
.commit-row-description {
font-size: 14px;
- border-left: 1px solid $btn-gray-hover;
+ border-left: 1px solid $white-normal;
padding: 10px 15px;
margin: 10px 0;
background: $gray-light;
@@ -134,20 +176,7 @@
}
a {
- color: $gl-dark-link-color;
- }
- }
-
- .commit-row-info {
- color: $gl-gray;
- line-height: 1.35;
-
- a {
- color: $gl-gray;
- }
-
- .avatar {
- margin-right: 8px;
+ color: $gl-text-color;
}
}
@@ -164,7 +193,7 @@
}
.branch-commit {
- color: $gl-gray;
+ color: $gl-text-color;
.commit-icon {
text-align: center;
@@ -174,7 +203,7 @@
height: 14px;
width: 14px;
vertical-align: middle;
- fill: $table-text-gray;
+ fill: $gl-text-color-secondary;
}
}
@@ -183,62 +212,6 @@
}
.commit-row-message {
- color: $gl-gray;
- }
-}
-
-.divergence-graph {
- padding: 12px 12px 0 0;
- float: right;
-
- .graph-side {
- position: relative;
- width: 80px;
- height: 22px;
- padding: 5px 0 13px;
- float: left;
-
- .bar {
- position: absolute;
- height: 4px;
- background-color: $divergence-graph-bar-bg;
- }
-
- .bar-behind {
- right: 0;
- border-radius: 3px 0 0 3px;
- }
-
- .bar-ahead {
- left: 0;
- border-radius: 0 3px 3px 0;
- }
-
- .count {
- padding-top: 6px;
- padding-bottom: 0;
- font-size: 12px;
- color: $gl-title-color;
- display: block;
- }
-
- .count-behind {
- padding-right: 4px;
- text-align: right;
- }
-
- .count-ahead {
- padding-left: 4px;
- text-align: left;
- }
- }
-
- .graph-separator {
- position: relative;
- width: 1px;
- height: 18px;
- margin: 5px 0 0;
- float: left;
- background-color: $divergence-graph-separator-bg;
+ color: $gl-text-color;
}
}
diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss
index 57146e1fccd..cda069e6c0e 100644
--- a/app/assets/stylesheets/pages/cycle_analytics.scss
+++ b/app/assets/stylesheets/pages/cycle_analytics.scss
@@ -20,15 +20,19 @@
.fa {
color: $cycle-analytics-light-gray;
+
+ &:hover {
+ color: $gl-text-color;
+ }
}
.stage-header {
- width: 28%;
+ width: 26%;
padding-left: $gl-padding;
}
.median-header {
- width: 12%;
+ width: 14%;
}
.event-header {
@@ -111,14 +115,14 @@
line-height: 19px;
font-size: 14px;
font-weight: 600;
- color: $gl-title-color;
+ color: $gl-text-color;
}
&.text {
color: $layout-link-gray;
&.value-col {
- color: $gl-title-color;
+ color: $gl-text-color;
}
}
}
@@ -141,7 +145,7 @@
.dismiss-icon {
position: absolute;
- right: $cycle-analytics-dismiss-icon-color;
+ right: $cycle-analytics-box-padding;
cursor: pointer;
color: $cycle-analytics-dismiss-icon-color;
}
@@ -215,7 +219,6 @@
border-bottom: 1px solid transparent;
border-right: 1px solid $border-color;
background-color: $gray-light;
- cursor: default;
&.active {
background-color: transparent;
@@ -232,6 +235,7 @@
&:hover:not(.active) {
background-color: $gray-lightest;
box-shadow: inset 2px 0 0 0 $border-color;
+ cursor: pointer;
}
&:first-child {
@@ -246,11 +250,11 @@
float: left;
&.stage-name {
- width: 70%;
+ width: 65%;
}
&.stage-median {
- width: 30%;
+ width: 35%;
}
}
@@ -260,7 +264,7 @@
.stage-empty,
.not-available {
- color: $gl-text-color-light;
+ color: $gl-text-color-secondary;
}
}
}
@@ -327,7 +331,7 @@
@include text-overflow();
a {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
}
}
@@ -355,7 +359,7 @@
.issue-link,
.commit-author-link,
.issue-author-link {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
// Custom CSS for components
@@ -396,11 +400,11 @@
}
.item-build-name {
- color: $gl-title-color;
+ color: $gl-text-color;
}
.pipeline-id {
- color: $gl-title-color;
+ color: $gl-text-color;
padding: 0 3px 0 0;
}
@@ -423,7 +427,7 @@
}
.fa {
- color: $gl-text-color-light;
+ color: $gl-text-color-secondary;
font-size: $code_font_size;
}
}
@@ -435,7 +439,7 @@
width: 75%;
margin: 0 auto;
padding-top: 130px;
- color: $gl-text-color-light;
+ color: $gl-text-color-secondary;
h4 {
color: $gl-text-color;
diff --git a/app/assets/stylesheets/pages/deploy_keys.scss b/app/assets/stylesheets/pages/deploy_keys.scss
new file mode 100644
index 00000000000..2fafe052106
--- /dev/null
+++ b/app/assets/stylesheets/pages/deploy_keys.scss
@@ -0,0 +1,13 @@
+.deploy-keys-list {
+ width: 100%;
+ overflow: auto;
+
+ table {
+ border: 1px solid $table-border-color;
+ }
+}
+
+.deploy-keys-title {
+ padding-bottom: 2px;
+ line-height: 2;
+}
diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss
index 80baebd5ea3..46fd19c93f9 100644
--- a/app/assets/stylesheets/pages/detail_page.scss
+++ b/app/assets/stylesheets/pages/detail_page.scss
@@ -1,16 +1,15 @@
.detail-page-header {
padding: $gl-padding-top 0;
border-bottom: 1px solid $border-color;
- color: $gl-text-color-dark;
- font-size: 16px;
+ color: $gl-text-color;
line-height: 34px;
.author {
- color: $gl-text-color-dark;
+ color: $gl-text-color;
}
.identifier {
- color: $gl-text-color-dark;
+ color: $gl-text-color;
}
.issue_created_ago,
@@ -23,7 +22,7 @@
.title {
margin: 0 0 16px;
font-size: 2em;
- color: $gl-gray-dark;
+ color: $gl-text-color;
padding: 0 0 0.3em;
border-bottom: 1px solid $white-dark;
}
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 737f6e0f4be..96ba7c40634 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -11,10 +11,10 @@
.diff-header {
position: relative;
- background: $background-color;
+ background: $gray-light;
border-bottom: 1px solid $border-color;
padding: 10px 16px;
- color: $gl-diff-text-color;
+ color: $gl-text-color;
z-index: 10;
border-radius: 3px 3px 0 0;
@@ -38,7 +38,7 @@
cursor: pointer;
&:hover {
- background-color: $dark-background-color;
+ background-color: $gray-normal;
}
.diff-toggle-caret {
@@ -50,7 +50,7 @@
overflow: auto;
overflow-y: hidden;
background: $white-light;
- color: $gl-title-color;
+ color: $gl-text-color;
border-radius: 0 0 3px 3px;
.unfold {
@@ -187,8 +187,8 @@
img {
border: 1px solid $white-light;
- background-image: linear-gradient(45deg, $diff-image-img-bg 25%, transparent 25%, transparent 75%, $diff-image-img-bg 75%, $diff-image-img-bg 100%),
- linear-gradient(45deg, $diff-image-img-bg 25%, transparent 25%, transparent 75%, $diff-image-img-bg 75%, $diff-image-img-bg 100%);
+ background-image: linear-gradient(45deg, $border-color 25%, transparent 25%, transparent 75%, $border-color 75%, $border-color 100%),
+ linear-gradient(45deg, $border-color 25%, transparent 25%, transparent 75%, $border-color 75%, $border-color 100%);
background-size: 10px 10px;
background-position: 0 0, 5px 5px;
max-width: 100%;
@@ -380,7 +380,7 @@
}
cursor: default;
- color: $gl-title-color;
+ color: $gl-text-color;
}
&.disabled {
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 6cde9c592de..4af267403d8 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -10,7 +10,7 @@
}
.ace_gutter-cell {
- background-color: $background-color;
+ background-color: $gray-light;
}
.cancel-btn {
@@ -34,7 +34,7 @@
}
.editor-ref {
- background: $background-color;
+ background: $gray-light;
padding-right: $gl-padding;
border-right: 1px solid $border-color;
display: block;
@@ -51,8 +51,16 @@
.new-file-name {
display: inline-block;
- width: 450px;
+ max-width: 450px;
float: left;
+
+ @media(max-width: $screen-md-max) {
+ width: 280px;
+ }
+
+ @media(max-width: $screen-sm-max) {
+ width: 180px;
+ }
}
.file-buttons {
@@ -67,7 +75,8 @@
.soft-wrap-toggle,
.license-selector,
.gitignore-selector,
- .gitlab-ci-yml-selector {
+ .gitlab-ci-yml-selector,
+ .dockerfile-selector {
display: inline-block;
vertical-align: top;
font-family: $regular_font;
@@ -97,7 +106,8 @@
.gitignore-selector,
.license-selector,
- .gitlab-ci-yml-selector {
+ .gitlab-ci-yml-selector,
+ .dockerfile-selector {
.dropdown {
line-height: 21px;
}
@@ -114,3 +124,42 @@
}
}
}
+
+@media(max-width: $screen-xs-max){
+ .file-editor {
+ .file-title {
+ .pull-right {
+ height: auto;
+ }
+ }
+
+ .new-file-name {
+ max-width: none;
+ width: 100%;
+ margin-bottom: 3px;
+ }
+
+ .file-buttons {
+ display: block;
+ width: 100%;
+ margin-bottom: 10px;
+
+ .soft-wrap-toggle {
+ width: 100%;
+ margin: 3px 0;
+ }
+
+ .encoding-selector,
+ .license-selector,
+ .gitignore-selector,
+ .gitlab-ci-yml-selector {
+ display: block;
+ margin: 3px 0;
+
+ button {
+ width: 100%;
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index e716f24c8e2..778ef01430e 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -30,19 +30,25 @@
display: table-cell;
}
+ .environments-name,
.environments-commit,
.environments-actions {
width: 20%;
}
- .environments-deploy,
- .environments-build,
.environments-date {
width: 10%;
}
- .environments-name {
- width: 30%;
+ .environments-deploy,
+ .environments-build {
+ width: 15%;
+ }
+
+ .environment-name,
+ .environments-build-cell,
+ .deployment-column {
+ word-break: break-all;
}
.deployment-column {
@@ -66,25 +72,25 @@
.external-url,
.dropdown-new {
- color: $table-text-gray;
+ color: $gl-text-color-secondary;
}
.dropdown-menu {
.fa {
margin-right: 6px;
- color: $table-text-gray;
+ color: $gl-text-color-secondary;
}
}
.build-link,
.branch-name {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
.stop-env-link,
.external-url {
- color: $table-text-gray;
+ color: $gl-text-color-secondary;
.stop-env-icon {
font-size: 14px;
@@ -95,7 +101,7 @@
.build-column {
.build-link {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
.avatar {
@@ -115,13 +121,6 @@
.folder-name {
cursor: pointer;
-
- .badge {
- font-weight: normal;
- background-color: $gray-darker;
- color: $gl-placeholder-color;
- vertical-align: baseline;
- }
}
}
@@ -136,4 +135,4 @@
margin-right: 0;
}
}
-}
+} \ No newline at end of file
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index dc67d411c71..b989d72ce1c 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -5,7 +5,7 @@
.event-item {
font-size: $gl-font-size;
padding: $gl-padding-top 0 $gl-padding-top ($gl-avatar-size + $gl-padding-top);
- border-bottom: 1px solid $table-border-color;
+ border-bottom: 1px solid $white-normal;
color: $list-text-color;
&.event-inline {
@@ -21,7 +21,7 @@
}
a {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
.avatar {
diff --git a/app/assets/stylesheets/pages/explore.scss b/app/assets/stylesheets/pages/explore.scss
deleted file mode 100644
index 9b92128624c..00000000000
--- a/app/assets/stylesheets/pages/explore.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-.explore-title {
- text-align: center;
-
- h3 {
- font-weight: normal;
- font-size: 30px;
- }
-}
diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss
index a9af7af59e2..d377526e655 100644
--- a/app/assets/stylesheets/pages/groups.scss
+++ b/app/assets/stylesheets/pages/groups.scss
@@ -13,7 +13,7 @@
.stats {
float: right;
line-height: $list-text-height;
- color: $gl-gray;
+ color: $gl-text-color;
span {
margin-right: 15px;
@@ -27,12 +27,6 @@
}
}
-.group-buttons {
- .notification-dropdown {
- display: inline-block;
- }
-}
-
.groups-header {
@media (min-width: $screen-sm-min) {
.nav-links {
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index e2e644dc23b..dae8ccdef6c 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -60,7 +60,7 @@
// Border around images in the help pages.
img:not(.emoji) {
- border: 1px solid $table-border-gray;
+ border: 1px solid $white-normal;
padding: 5px;
margin: 5px;
max-height: calc(100vh - 100px);
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 407c0afbac8..324c6cec96a 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -1,3 +1,52 @@
+// Limit MR description for side-by-side diff view
+.fixed-width-container {
+ max-width: $limited-layout-width - ($gl-padding * 2);
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.limit-container-width {
+ .detail-page-header {
+ @extend .fixed-width-container;
+ }
+
+ .issuable-details {
+ .detail-page-description,
+ .mr-source-target,
+ .mr-state-widget,
+ .merge-manually {
+ @extend .fixed-width-container;
+ }
+
+ .merge-request-tabs-holder {
+ &.affix {
+ border-bottom: 1px solid $border-color;
+
+ .nav-links {
+ border: 0;
+ }
+ }
+
+ .container-fluid {
+ @extend .fixed-width-container;
+ }
+ }
+ }
+
+ .merge-request-details {
+ .emoji-list-container {
+ @extend .fixed-width-container;
+ }
+ }
+
+ .diffs {
+ .mr-version-controls,
+ .files-changed {
+ @extend .fixed-width-container;
+ }
+ }
+}
+
.issuable-details {
section {
.issuable-discussion {
@@ -5,11 +54,16 @@
}
}
+ .title {
+ padding: 0;
+ margin: 0;
+ border-bottom: none;
+ }
+
// Border around images in issue and MR descriptions.
.description img:not(.emoji) {
- border: 1px solid $table-border-gray;
+ border: 1px solid $white-normal;
padding: 5px;
- margin: 5px;
max-height: calc(100vh - 100px);
}
}
@@ -51,7 +105,7 @@
.block {
@include clearfix;
padding: $gl-padding 0;
- border-bottom: 1px solid $border-gray-light;
+ border-bottom: 1px solid $border-gray-normal;
// This prevents the mess when resizing the sidebar
// of elements repositioning themselves..
width: $gutter_inner_width;
@@ -98,10 +152,10 @@
}
.edit-link {
- color: $gl-gray;
+ color: $gl-text-color;
- &:hover {
- color: $md-link-color;
+ &:not([href]):hover {
+ color: rgba($avatar-border, .2);
}
}
}
@@ -134,7 +188,7 @@
}
.btn-clipboard:hover {
- color: $gl-gray;
+ color: $gl-text-color;
}
}
@@ -169,7 +223,7 @@
}
.no-value {
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
}
.sidebar-collapsed-icon {
@@ -178,7 +232,7 @@
.gutter-toggle {
margin-top: 7px;
- border-left: 1px solid $border-gray-light;
+ border-left: 1px solid $border-gray-normal;
}
.assignee .avatar {
@@ -216,7 +270,7 @@
}
.participants {
- border-bottom: 1px solid $border-gray-light;
+ border-bottom: 1px solid $border-gray-normal;
}
.hide-collapsed {
@@ -237,7 +291,7 @@
color: $issuable-sidebar-color;
&:hover {
- color: $gl-gray;
+ color: $gl-text-color;
}
span {
@@ -250,16 +304,16 @@
}
.avatar:hover {
- border-color: $issuable-avatar-hover-border;
+ border-color: $issuable-sidebar-color;
}
.btn-clipboard {
border: none;
- color: $issuable-clipboard-color;
+ color: $issuable-sidebar-color;
&:hover {
background: transparent;
- color: $gl-gray;
+ color: $gl-text-color;
}
}
}
@@ -278,6 +332,10 @@
&:hover {
color: $md-link-color;
text-decoration: none;
+
+ .avatar {
+ border-color: rgba($avatar-border, .2);
+ }
}
}
@@ -333,7 +391,7 @@
margin-left: 5px;
a {
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
}
}
@@ -388,6 +446,7 @@
.issuable-meta {
display: inline-block;
line-height: 18px;
+ font-size: 14px;
}
.js-issuable-selector-wrap {
@@ -414,3 +473,102 @@
}
}
}
+
+.time_tracker {
+ padding-bottom: 0;
+ border-bottom: 0;
+
+
+ .sidebar-collapsed-icon {
+
+ > .stopwatch-svg {
+ display: inline-block;
+ }
+
+ svg {
+ width: 16px;
+ height: 16px;
+ fill: $sidebar-collapsed-icon-color;
+ }
+
+ &:hover svg {
+ fill: $gl-text-color;
+ }
+ }
+
+ .help-button,
+ .close-help-button {
+ cursor: pointer;
+ }
+
+ .compare-meter {
+ &.within_estimate {
+ .meter-fill {
+ background: $gl-primary;
+ }
+ }
+
+ &.over_estimate {
+ .meter-fill {
+ background: $red-light;
+ }
+
+ .time-remaining,
+ .compare-value.spent {
+ color: $red-light;
+ }
+ }
+ }
+
+ .meter-container {
+ background: $border-gray-light;
+ border-radius: 3px;
+
+ .meter-fill {
+ max-width: 100%;
+ height: 5px;
+ border-radius: 3px;
+ background: $gl-primary;
+ }
+ }
+
+ .compare-display-container {
+ display: flex;
+ justify-content: space-between;
+ margin-top: 5px;
+
+ .compare-display {
+ font-size: 13px;
+ color: $compare-display-color;
+
+ .compare-value {
+ color: $gl-text-color;
+ }
+ }
+ }
+
+ .time-tracking-help-state {
+ background: $white-light;
+ margin: 16px -20px 0;
+ padding: 16px 20px;
+ border-top: 1px solid $border-gray-light;
+ border-bottom: 1px solid $border-gray-light;
+
+ a:hover {
+ color: $btn-white-active;
+ }
+ }
+
+ .help-state-toggle-enter-active {
+ transition: all .8s ease;
+ }
+
+ .help-state-toggle-leave-active {
+ transition: all .5s ease;
+ }
+
+ .help-state-toggle-enter,
+ .help-state-toggle-leave-active {
+ opacity: 0;
+ }
+}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 3b47f99df2c..8734a3b1598 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -88,12 +88,12 @@ ul.related-merge-requests > li {
&.closed {
background: $gray-light;
- border-color: $issues-border;
+ border-color: $border-color;
}
&.merged {
background: $gray-light;
- border-color: $issues-border;
+ border-color: $border-color;
}
}
@@ -144,7 +144,7 @@ ul.related-merge-requests > li {
}
.btn {
- background-color: $background-color;
- border: 1px solid $border-gray-light;
+ background-color: $gray-light;
+ border: 1px solid $border-gray-normal;
}
}
diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss
index 25c91203ff4..21d9b4c54ea 100644
--- a/app/assets/stylesheets/pages/labels.scss
+++ b/app/assets/stylesheets/pages/labels.scss
@@ -98,7 +98,7 @@
}
.label {
- padding: 9px;
+ padding: 8px 9px 9px;
font-size: 14px;
}
}
@@ -117,7 +117,7 @@
.manage-labels-list {
.btn-action {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
.fa {
font-size: 18px;
@@ -201,6 +201,12 @@
.label-remove {
border-left: 1px solid $label-remove-border;
z-index: 3;
+ border-radius: $label-border-radius;
+ padding: 6px 10px 6px 9px;
+
+ &:hover {
+ box-shadow: inset 0 0 0 80px $label-remove-border;
+ }
}
.btn {
diff --git a/app/assets/stylesheets/pages/lint.scss b/app/assets/stylesheets/pages/lint.scss
index a7c80dce424..68b6c5ecbd4 100644
--- a/app/assets/stylesheets/pages/lint.scss
+++ b/app/assets/stylesheets/pages/lint.scss
@@ -9,3 +9,13 @@
color: $lint-correct-color;
}
}
+
+.ci-linter {
+ .ci-editor {
+ height: 400px;
+ }
+
+ .ci-template pre {
+ white-space: pre-wrap;
+ }
+}
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index dd27a06fcd2..71ed5b1361a 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -17,14 +17,19 @@
line-height: 1.5;
p {
- font-size: 18px;
+ font-size: 16px;
color: $login-brand-holder-color;
}
h1:first-child {
font-weight: normal;
- margin-bottom: 30px;
+ margin-bottom: 0.68em;
margin-top: 0;
+ font-size: 34px;
+ }
+
+ h3 {
+ font-size: 22px;
}
img {
@@ -105,19 +110,19 @@
li {
flex: 1;
text-align: center;
+ border-left: 1px solid $border-color;
&:first-of-type {
+ border-left: none;
border-top-left-radius: $border-radius-default;
}
&:last-of-type {
- border-left: 1px solid $border-color;
border-top-right-radius: $border-radius-default;
}
&:not(.active) {
background-color: $gray-light;
- border-left: 1px solid $border-color;
}
a {
diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss
index 5f3bbb40ba0..be7193bae04 100644
--- a/app/assets/stylesheets/pages/members.scss
+++ b/app/assets/stylesheets/pages/members.scss
@@ -25,7 +25,7 @@
}
.form-horizontal {
- margin-top: 5px;
+ margin-top: 20px;
@media (min-width: $screen-sm-min) {
display: -webkit-flex;
@@ -78,19 +78,48 @@
float: right;
}
+ .dropdown {
+ width: 100%;
+ margin-top: 5px;
+
+ .dropdown-menu-toggle {
+ vertical-align: middle;
+ width: 100%;
+ }
+
+ @media (min-width: $screen-sm-min) {
+ margin-top: 0;
+ width: 155px;
+ }
+ }
+
.form-control {
width: 100%;
padding-right: 35px;
@media (min-width: $screen-sm-min) {
+ width: 250px;
+ }
+
+ @media (min-width: $screen-md-min) {
width: 350px;
}
+
+ &.input-short {
+ @media (min-width: $screen-md-min) {
+ width: 170px;
+ }
+
+ @media (min-width: $screen-lg-min) {
+ width: 210px;
+ }
+ }
}
}
.member-search-btn {
position: absolute;
- right: 0;
+ right: 4px;
top: 0;
height: 35px;
padding-left: 10px;
@@ -99,4 +128,8 @@
background: transparent;
border: 0;
outline: 0;
+
+ @media (min-width: $screen-sm-min) {
+ right: 160px;
+ }
}
diff --git a/app/assets/stylesheets/pages/merge_conflicts.scss b/app/assets/stylesheets/pages/merge_conflicts.scss
index 7a90713dd3f..5a9f199fb34 100644
--- a/app/assets/stylesheets/pages/merge_conflicts.scss
+++ b/app/assets/stylesheets/pages/merge_conflicts.scss
@@ -274,7 +274,7 @@ $colors: (
}
.discard-changes-alert {
- background-color: $background-color;
+ background-color: $gray-light;
text-align: right;
padding: $gl-padding-top $gl-padding;
color: $gl-text-color;
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 6234779ac19..45ff9f7ff5f 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -3,8 +3,8 @@
*
*/
.mr-state-widget {
- background: $background-color;
- color: $gl-gray;
+ background: $gray-light;
+ color: $gl-text-color;
border: 1px solid $border-color;
border-radius: 2px;
@@ -21,6 +21,14 @@
display: inline-block;
float: left;
+ .btn-success.dropdown-toggle .fa {
+ color: inherit;
+ }
+
+ .btn-success.dropdown-toggle:disabled {
+ background-color: $gl-success;
+ }
+
.accept_merge_request {
&.ci-pending,
&.ci-running {
@@ -50,7 +58,7 @@
padding-right: 0;
a {
- color: $gl-gray;
+ color: $gl-text-color;
}
}
@@ -62,7 +70,7 @@
.ci_widget {
border-bottom: 1px solid $well-inner-border;
- color: $gl-gray;
+ color: $gl-text-color;
svg {
margin-right: 4px;
@@ -86,7 +94,7 @@
}
.normal {
- color: $gl-text-color-dark;
+ color: $gl-text-color;
}
.js-deployment-link {
@@ -96,9 +104,9 @@
.mr-widget-body {
h4 {
font-weight: 600;
- font-size: 17px;
+ font-size: 16px;
margin: 5px 0;
- color: $gl-gray-dark;
+ color: $gl-text-color;
&.has-conflicts .fa-exclamation-triangle {
color: $gl-warning;
@@ -182,7 +190,7 @@
}
.label-branch {
- color: $gl-gray-dark;
+ color: $gl-text-color;
font-family: $monospace_font;
font-weight: bold;
overflow: hidden;
@@ -302,10 +310,6 @@
left: 0;
top: 2px;
}
-
- .commit-row-info {
- line-height: 20px;
- }
}
.btn-clipboard {
@@ -359,7 +363,7 @@
th {
background-color: $white-light;
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
}
}
}
@@ -375,7 +379,7 @@
}
.mr-version-controls {
- background: $background-color;
+ background: $gray-light;
border-bottom: 1px solid $border-color;
color: $gl-text-color;
@@ -416,11 +420,19 @@
.merge-request-tabs-holder {
background-color: $white-light;
+ .container-limited {
+ max-width: $limited-layout-width;
+ }
+
&.affix {
top: 100px;
left: 0;
z-index: 10;
transition: right .15s;
+
+ @media (max-width: $screen-xs-max) {
+ right: 0;
+ }
}
&:not(.affix) .container-fluid {
diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
index dfc6079bd15..686b64cdd24 100644
--- a/app/assets/stylesheets/pages/milestone.scss
+++ b/app/assets/stylesheets/pages/milestone.scss
@@ -25,12 +25,6 @@
}
.issuable-row {
- .color-label {
- border-radius: 2px;
- padding: 3px !important;
- margin-right: 7px;
- }
-
span a {
color: $gl-text-color;
word-wrap: break-word;
@@ -108,13 +102,17 @@
margin-top: 7px;
.issuable-number {
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
margin-right: 5px;
}
.avatar {
float: none;
}
+
+ > a:not(:last-of-type) {
+ margin-right: 5px;
+ }
}
}
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index c35d71f9e7b..f984b469609 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -27,6 +27,7 @@
.new-note,
.note-edit-form {
.note-form-actions {
+ position: relative;
margin-top: $gl-padding;
}
@@ -44,7 +45,7 @@
.note-textarea {
display: block;
padding: 10px 0;
- color: $gl-gray;
+ color: $gl-text-color;
font-family: $regular_font;
border: 0;
@@ -62,7 +63,7 @@
.common-note-form {
.md-area {
padding: $gl-padding-top $gl-padding;
- border: 1px solid $note-form-border-color;
+ border: 1px solid $border-color;
border-radius: $border-radius-base;
transition: border-color ease-in-out 0.15s,
box-shadow ease-in-out 0.15s;
@@ -109,7 +110,7 @@
margin: auto;
margin-top: 0;
text-align: center;
- font-size: 13px;
+ font-size: 12px;
@media (max-width: $screen-sm-max) {
// On smaller devices the warning becomes the fourth item in the list,
@@ -204,7 +205,7 @@
.comment-toolbar {
padding-top: $gl-padding-top;
- color: $note-toolbar-color;
+ color: $gl-text-color-secondary;
border-top: 1px solid $border-color;
}
@@ -265,3 +266,18 @@
}
}
}
+
+.note-edit-warning.settings-message {
+ display: none;
+ padding: 5px 10px;
+ position: absolute;
+ left: 127px;
+ top: 2px;
+
+ @media (max-width: $screen-xs-max) {
+ position: relative;
+ top: 0;
+ left: 0;
+ margin-bottom: 10px;
+ }
+}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 10eb3d4203e..e2a0253da38 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -43,7 +43,7 @@ ul.notes {
}
.system-note-message {
- display: inline-block;
+ display: inline;
&::first-letter {
text-transform: lowercase;
@@ -55,7 +55,7 @@ ul.notes {
}
p {
- display: inline-block;
+ display: inline;
margin: 0;
&::first-letter {
@@ -166,7 +166,7 @@ ul.notes {
.note {
display: block;
position: relative;
- border-bottom: 1px solid $table-border-gray;
+ border-bottom: 1px solid $white-normal;
&.note-discussion {
&.timeline-entry {
@@ -291,14 +291,14 @@ ul.notes {
font-family: $regular_font;
td {
- border: 1px solid $table-border-gray;
+ border: 1px solid $white-normal;
border-left: none;
&.notes_line {
vertical-align: middle;
text-align: center;
padding: 10px 0;
- background: $background-color;
+ background: $gray-light;
color: $text-color;
}
@@ -309,7 +309,7 @@ ul.notes {
}
&.notes_content {
- background-color: $background-color;
+ background-color: $gray-light;
border-width: 1px 0;
padding: 0;
vertical-align: top;
@@ -345,7 +345,7 @@ ul.notes {
}
.author_link {
- color: $gl-gray;
+ color: $gl-text-color;
}
}
@@ -353,6 +353,14 @@ ul.notes {
font-size: 14px;
}
+.note-headline-light {
+ display: inline;
+
+ @media (max-width: $screen-xs-min) {
+ display: block;
+ }
+}
+
.note-headline-light,
.discussion-headline-light {
color: $notes-light-color;
@@ -372,7 +380,7 @@ ul.notes {
.note-actions {
float: right;
margin-left: 10px;
- color: $notes-action-color;
+ color: $gray-darkest;
}
.note-actions {
@@ -383,10 +391,6 @@ ul.notes {
.note-action-button {
margin-left: 10px;
}
-
- @media (min-width: $screen-sm-min) {
- position: relative;
- }
}
.discussion-actions {
@@ -411,7 +415,7 @@ ul.notes {
}
.fa {
- color: $notes-action-color;
+ color: $gray-darkest;
position: relative;
font-size: 17px;
}
@@ -448,15 +452,10 @@ ul.notes {
color: $notes-role-color;
font-size: 12px;
line-height: 20px;
- border: 1px solid $notes-role-border-color;
+ border: 1px solid $border-color;
border-radius: $border-radius-base;
}
-.diff-file .note .note-actions {
- right: 0;
- top: 0;
-}
-
/**
* Line note button on the side of diffs
@@ -527,27 +526,24 @@ ul.notes {
}
.line-resolve-all {
+ vertical-align: middle;
display: inline-block;
- padding: 5px 10px;
- background-color: $background-color;
+ padding: 6px 10px;
+ background-color: $gray-light;
border: 1px solid $border-color;
border-radius: $border-radius-default;
&.has-next-btn {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
+ border-right: 0;
}
.line-resolve-btn {
- vertical-align: middle;
margin-right: 5px;
}
}
-.line-resolve-text {
- vertical-align: middle;
-}
-
.line-resolve-btn {
display: inline-block;
position: relative;
@@ -566,18 +562,14 @@ ul.notes {
&.is-active {
color: $gl-text-green;
- svg path {
+ svg {
fill: $gl-text-green;
}
}
svg {
position: relative;
- color: $notes-action-color;
-
- path {
- fill: $notes-action-color;
- }
+ fill: $gray-darkest;
}
}
@@ -590,3 +582,17 @@ ul.notes {
}
}
}
+
+// Merge request notes in diffs
+.diff-file {
+ // Diff is side by side
+ .notes_content.parallel .note-header .note-headline-light {
+ display: block;
+ position: relative;
+ }
+ // Diff is inline
+ .notes_content .note-header .note-headline-light {
+ display: inline-block;
+ position: relative;
+ }
+}
diff --git a/app/assets/stylesheets/pages/notifications.scss b/app/assets/stylesheets/pages/notifications.scss
index 7d61390a439..bdf07a99daf 100644
--- a/app/assets/stylesheets/pages/notifications.scss
+++ b/app/assets/stylesheets/pages/notifications.scss
@@ -10,19 +10,7 @@
position: relative;
top: 1px;
- > .fa {
+ .fa {
font-size: 18px;
}
}
-
-.ns-part {
- color: $gl-text-green;
-}
-
-.ns-watch {
- color: $gl-success;
-}
-
-.ns-mute {
- color: $gl-danger;
-}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 6822f916cc5..8861315d776 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -1,4 +1,9 @@
.pipelines {
+ .realtime-loading {
+ font-size: 40px;
+ text-align: center;
+ }
+
.stage {
max-width: 90px;
width: 90px;
@@ -22,17 +27,26 @@
.table.ci-table {
min-width: 1200px;
+ table-layout: fixed;
+
+ .label {
+ margin-bottom: 3px;
+ }
.pipeline-id {
color: $black;
}
- .branch-commit {
- width: 30%;
+ .pipeline-date,
+ .pipeline-status {
+ width: 10%;
+ }
- .branch-name {
- max-width: 195px;
- }
+ .pipeline-info,
+ .pipeline-commit,
+ .pipeline-actions,
+ .pipeline-stages {
+ width: 20%;
}
}
}
@@ -47,6 +61,10 @@
}
}
+.content-list.pipelines .table-holder {
+ min-height: 300px;
+}
+
.pipeline-holder {
width: 100%;
overflow: auto;
@@ -75,6 +93,10 @@
td {
padding: 10px 8px;
}
+
+ .commit-link {
+ padding: 9px 8px 10px;
+ }
}
tbody {
@@ -106,7 +128,7 @@
.branch-name {
font-weight: bold;
- max-width: 150px;
+ max-width: 120px;
overflow: hidden;
display: inline-block;
white-space: nowrap;
@@ -118,7 +140,7 @@
height: 14px;
width: 14px;
vertical-align: middle;
- fill: $table-text-gray;
+ fill: $gl-text-color-secondary;
}
.fa {
@@ -132,7 +154,7 @@
.commit-title {
margin-top: 4px;
- max-width: 300px;
+ max-width: 225px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
@@ -164,12 +186,14 @@
.stage-cell {
font-size: 0;
- svg {
- height: 18px;
- width: 18px;
- position: relative;
+ > .stage-container > div > button > span > svg,
+ > .stage-container > button > svg {
+ height: 22px;
+ width: 22px;
+ position: absolute;
+ top: -1px;
+ left: -1px;
z-index: 2;
- vertical-align: middle;
overflow: visible;
}
@@ -187,21 +211,17 @@
content: '';
width: 8px;
position: absolute;
- right: -7px;
- bottom: 9px;
+ right: -8px;
+ top: 10px;
border-bottom: 2px solid $border-color;
}
}
-
- a {
- display: block;
- }
}
}
.duration,
.finished-at {
- color: $table-text-gray;
+ color: $gl-text-color-secondary;
margin: 4px 0;
.fa {
@@ -222,7 +242,7 @@
.btn {
margin: 0;
- color: $table-text-gray;
+ color: $gl-text-color-secondary;
}
.cancel-retry-btns {
@@ -235,10 +255,10 @@
.dropdown-toggle,
.dropdown-menu {
- color: $table-text-gray;
+ color: $gl-text-color-secondary;
.fa {
- color: $table-text-gray;
+ color: $gl-text-color-secondary;
font-size: 14px;
}
@@ -272,7 +292,7 @@
.build-link {
a {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
}
@@ -288,69 +308,162 @@
}
// Pipeline visualization
+.pipeline-actions {
+ border-bottom: none;
+}
+
+.tab-pane {
+ &.pipelines {
+ .ci-table {
+ min-width: 900px;
+ }
-.toggle-pipeline-btn {
- background-color: $gray-dark;
+ .content-list.pipelines {
+ overflow: auto;
+ }
- &.graph-collapsed {
- background-color: $white-light;
+ .stage {
+ max-width: 100px;
+ width: 100px;
+ }
+
+ .pipeline-actions {
+ min-width: initial;
+ }
+ }
+
+ &.builds {
+ .ci-table {
+ tr {
+ height: 71px;
+ }
+ }
}
}
+// Pipeline graph
.pipeline-graph {
width: 100%;
- background-color: $background-color;
+ background-color: $gray-light;
padding: $gl-padding;
- overflow: auto;
white-space: nowrap;
transition: max-height 0.3s, padding 0.3s;
- &.graph-collapsed {
- max-height: 0;
- padding: 0 16px;
+ .stage-column-list,
+ .builds-container > ul {
+ padding: 0;
}
-}
-.pipeline-visualization {
- position: relative;
+ a {
+ text-decoration: none;
+ color: $gl-text-color-secondary;
+ }
- ul {
- padding: 0;
+ svg {
+ vertical-align: middle;
+ margin-right: 3px;
}
-}
-.stage-column {
- display: inline-block;
- vertical-align: top;
+ .stage-column {
+ display: inline-block;
+ vertical-align: top;
- &:not(:last-child) {
- margin-right: 44px;
- }
+ &:not(:last-child) {
+ margin-right: 44px;
+ }
- &.left-margin {
- &:not(:first-child) {
- margin-left: 44px;
+ &.left-margin {
+ &:not(:first-child) {
+ margin-left: 44px;
- .left-connector {
- &::before {
- content: '';
- position: absolute;
- top: 48%;
- left: -48px;
- border-top: 2px solid $border-color;
- width: 48px;
- height: 1px;
+ .left-connector {
+ &::before {
+ content: '';
+ position: absolute;
+ top: 48%;
+ left: -48px;
+ border-top: 2px solid $border-color;
+ width: 48px;
+ height: 1px;
+ }
}
}
}
- }
- &.no-margin {
- margin: 0;
- }
+ &.no-margin {
+ margin: 0;
+ }
- li {
- list-style: none;
+ li {
+ list-style: none;
+ }
+
+ &:last-child {
+ .build {
+ // Remove right connecting horizontal line from first build in last stage
+ &:first-child {
+ &::after {
+ border: none;
+ }
+ }
+ // Remove right curved connectors from all builds in last stage
+ &:not(:first-child) {
+ &::after {
+ border: none;
+ }
+ }
+ // Remove opposite curve
+ .curve {
+ &::before {
+ display: none;
+ }
+ }
+ }
+ }
+
+ &:first-child {
+ .build {
+ // Remove left curved connectors from all builds in first stage
+ &:not(:first-child) {
+ &::before {
+ border: none;
+ }
+ }
+ // Remove opposite curve
+ .curve {
+ &::after {
+ display: none;
+ }
+ }
+ }
+ }
+
+ // Curve first child connecting lines in opposite direction
+ .curve {
+ display: none;
+
+ &::before,
+ &::after {
+ content: '';
+ width: 21px;
+ height: 25px;
+ position: absolute;
+ top: -31px;
+ border-top: 2px solid $border-color;
+ }
+
+ &::after {
+ left: -44px;
+ border-right: 2px solid $border-color;
+ border-radius: 0 20px;
+ }
+
+ &::before {
+ right: -44px;
+ border-left: 2px solid $border-color;
+ border-radius: 20px 0 0;
+ }
+ }
}
.stage-name {
@@ -363,167 +476,114 @@
}
.build {
- border: 1px solid $border-color;
- background-color: $white-light;
position: relative;
- padding: 7px 10px 8px;
- border-radius: 30px;
width: 186px;
margin-bottom: 10px;
+ white-space: normal;
+ color: $gl-text-color-secondary;
+
+ // Action Icons in big pipeline-graph nodes
+ > .ci-action-icon-container .ci-action-icon-wrapper {
+ i {
+ color: $border-color;
+ border-radius: 100%;
+ border: 1px solid $border-color;
+ padding: 5px 6px;
+ font-size: 13px;
+ background: $white-light;
+ height: 30px;
+ width: 30px;
- &:hover {
- background-color: $gray-lighter;
- }
-
- &.playable {
-
- svg {
- height: 13px;
- width: 20px;
- position: relative;
- top: 1px;
-
- path {
- fill: $layout-link-gray;
- }
- }
- }
-
- .build-content {
- display: -ms-flexbox;
- display: -webkit-flex;
- display: flex;
- width: 164px;
-
- .ci-status-icon {
- svg {
- height: 20px;
- width: 20px;
+ &::before {
+ position: relative;
+ top: 3px;
+ left: 3px;
}
- }
-
- .tooltip {
- white-space: nowrap;
- .tooltip-inner {
- overflow: hidden;
- text-overflow: ellipsis;
+ &:hover {
+ color: $gl-text-color;
+ background-color: $stage-hover-bg;
+ border: 1px solid $stage-hover-bg;
}
}
- .ci-status-text {
- width: 135px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- vertical-align: middle;
- display: inline-block;
- position: relative;
- top: -1px;
- }
-
- a {
- color: $gl-text-color-light;
- text-decoration: none;
+ .ci-play-icon {
+ padding: 5px 5px 5px 7px;
}
+ }
- .dropdown-menu-toggle {
- background-color: transparent;
- border: none;
- width: auto;
- padding: 0;
- color: $gl-text-color-light;
- flex-grow: 1;
-
- .ci-status-text {
- max-width: 112px;
- width: auto;
- }
- }
+ > .ci-action-icon-container {
+ position: absolute;
+ right: 5px;
+ top: 5px;
+ }
- .grouped-pipeline-dropdown {
- padding: 0;
- width: 186px;
- left: auto;
- right: -197px;
- top: -9px;
+ .ci-status-icon svg {
+ height: 20px;
+ width: 20px;
+ }
- ul {
- max-height: 245px;
- overflow: auto;
+ .dropdown-menu-toggle {
+ background-color: transparent;
+ border: none;
+ padding: 0;
+ color: $gl-text-color-secondary;
- li:first-child {
- padding-top: 8px;
- }
+ &:focus {
+ outline: none;
+ }
- li:last-child {
- padding-bottom: 8px;
- }
- }
+ &:hover {
+ color: $gl-text-color;
- a {
+ .dropdown-counter-badge {
color: $gl-text-color;
- padding: 7px 8px 8px;
-
- &:hover {
- background-color: $blue-light-transparent;
- border-radius: 3px;
-
- .ci-status-text {
- text-decoration: none;
- }
- }
- }
-
- svg {
- width: 14px;
- height: 14px;
}
+ }
+ }
- .ci-status-text {
- width: 112px;
- }
+ > .build-content {
+ display: inline-block;
+ padding: 8px 10px 9px;
+ width: 100%;
+ border: 1px solid $border-color;
+ border-radius: 30px;
+ background-color: $white-light;
- .arrow {
- &::before,
- &::after {
- content: '';
- display: inline-block;
- position: absolute;
- width: 0;
- height: 0;
- border-color: transparent;
- border-style: solid;
- top: 18px;
- }
+ &:hover {
+ background-color: $stage-hover-bg;
+ border: 1px solid $stage-hover-border;
+ color: $gl-text-color;
+ }
+ }
- &::before {
- left: -5px;
- margin-top: -6px;
- border-width: 7px 5px 7px 0;
- border-right-color: $border-color;
- }
- &::after {
- left: -4px;
- margin-top: -9px;
- border-width: 10px 7px 10px 0;
- border-right-color: $white-light;
- }
- }
+ .arrow {
+ &::before,
+ &::after {
+ content: '';
+ display: inline-block;
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+ top: 18px;
}
- .badge {
- background-color: $gray-darker;
- color: $gl-text-color-light;
- font-weight: normal;
- margin-left: $btn-xs-side-margin;
+ &::before {
+ left: -5px;
+ margin-top: -6px;
+ border-width: 7px 5px 7px 0;
+ border-right-color: $border-color;
}
- }
- svg {
- vertical-align: middle;
- margin-right: 5px;
+ &::after {
+ left: -4px;
+ margin-top: -9px;
+ border-width: 10px 7px 10px 0;
+ border-right-color: $white-light;
+ }
}
// Connect first build in each stage with right horizontal line
@@ -579,110 +639,302 @@
}
}
}
+}
- &:last-child {
- .build {
- // Remove right connecting horizontal line from first build in last stage
- &:first-child {
- &::after {
- border: none;
- }
- }
- // Remove right curved connectors from all builds in last stage
- &:not(:first-child) {
- &::after {
- border: none;
- }
- }
- // Remove opposite curve
- .curve {
- &::before {
- display: none;
- }
- }
+// Triggers the dropdown in the big pipeline graph
+.dropdown-counter-badge {
+ color: $border-color;
+ font-weight: 100;
+ font-size: 15px;
+ position: absolute;
+ right: 5px;
+ top: 8px;
+}
+
+.ci-status-text {
+ max-width: 110px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: bottom;
+ display: inline-block;
+ position: relative;
+ font-weight: 200;
+}
+
+// Dropdown button in mini pipeline graph
+.mini-pipeline-graph-dropdown-toggle {
+ border-radius: 100px;
+ background-color: $white-light;
+ border-width: 1px;
+ border-style: solid;
+ width: 22px;
+ height: 22px;
+ margin: 0;
+ padding: 0;
+ transition: all 0.2s linear;
+ position: relative;
+
+ > .fa.fa-caret-down {
+ position: absolute;
+ left: 20px;
+ top: 5px;
+ display: inline-block;
+ visibility: hidden;
+ opacity: 0;
+ color: inherit;
+ font-size: 12px;
+ transition: visibility 0.1s, opacity 0.1s linear;
+ }
+
+ &:active,
+ &:focus,
+ &:hover {
+ outline: none;
+ width: 35px;
+
+ .fa.fa-caret-down {
+ visibility: visible;
+ opacity: 1;
}
}
- &:first-child {
- .build {
- // Remove left curved connectors from all builds in first stage
- &:not(:first-child) {
- &::before {
- border: none;
- }
- }
- // Remove opposite curve
- .curve {
- &::after {
- display: none;
- }
- }
+ // Dropdown button animation in mini pipeline graph
+ &.ci-status-icon-success {
+ border-color: $gl-success;
+ color: $gl-success;
+
+ &:hover,
+ &:focus,
+ &:active {
+ background-color: rgba($gl-success, 0.1);
+ border-color: $gl-success;
}
}
- // Curve first child connecting lines in opposite direction
- .curve {
- display: none;
+ &.ci-status-icon-failed {
+ border-color: $gl-danger;
+ color: $gl-danger;
- &::before,
- &::after {
- content: '';
- width: 21px;
- height: 25px;
- position: absolute;
- top: -32px;
- border-top: 2px solid $border-color;
+ &:hover,
+ &:focus,
+ &:active {
+ background-color: rgba($gl-danger, 0.1);
+ border-color: $gl-danger;
}
+ }
- &::after {
- left: -44px;
- border-right: 2px solid $border-color;
- border-radius: 0 20px;
+ &.ci-status-icon-pending,
+ &.ci-status-icon-success_with_warnings {
+ border-color: $gl-warning;
+ color: $gl-warning;
+
+ &:hover,
+ &:focus,
+ &:active {
+ background-color: rgba($gl-warning, 0.1);
+ border-color: $gl-warning;
}
+ }
- &::before {
- right: -44px;
- border-left: 2px solid $border-color;
- border-radius: 20px 0 0;
+ &.ci-status-icon-running {
+ border-color: $blue-normal;
+ color: $blue-normal;
+
+ &:hover,
+ &:focus,
+ &:active {
+ background-color: rgba($blue-normal, 0.1);
+ border-color: $blue-normal;
}
}
-}
-.pipeline-actions {
- border-bottom: none;
+ &.ci-status-icon-canceled,
+ &.ci-status-icon-disabled,
+ &.ci-status-icon-not-found,
+ &.ci-status-icon-manual {
+ border-color: $gl-text-color;
+ color: $gl-text-color;
+
+ &:hover,
+ &:focus,
+ &:active {
+ background-color: rgba($gl-text-color, 0.1);
+ border-color: $gl-text-color;
+ }
+ }
+
+ &.ci-status-icon-created,
+ &.ci-status-icon-skipped {
+ border-color: $gray-darkest;
+ color: $gray-darkest;
+
+ &:hover,
+ &:focus,
+ &:active {
+ background-color: rgba($gray-darkest, 0.1);
+ border-color: $gray-darkest;
+ }
+ }
}
-.toggle-pipeline-btn {
+// dropdown content for big and mini pipeline
+.big-pipeline-graph-dropdown-menu,
+.mini-pipeline-graph-dropdown-menu {
+ width: 195px;
+ max-width: 195px;
- .fa {
- color: $dropdown-header-color;
+ li {
+ padding: 2px 3px;
+ }
+
+ .scrollable-menu {
+ max-height: 245px;
+ overflow: auto;
+ }
+
+ // Loading icon
+ .builds-dropdown-loading {
+ margin: 0 auto;
+ width: 20px;
+ }
+
+ // Action icon on the right
+ a.ci-action-icon-wrapper {
+ color: $action-icon-color;
+ border: 1px solid $action-icon-color;
+ border-radius: 20px;
+ width: 22px;
+ height: 22px;
+ padding: 2px 0 0 5px;
+ cursor: pointer;
+ float: right;
+ margin: -26px 9px 0 0;
+ font-size: 12px;
+ background-color: $white-light;
+
+ &:hover,
+ &:focus {
+ text-decoration: none;
+ color: $gl-text-color;
+ background-color: $stage-hover-bg;
+ border: 1px solid transparent;
+ }
+ }
+
+ // link to the build
+ .mini-pipeline-graph-dropdown-item {
+ padding: 3px 7px 4px;
+ clear: both;
+ font-weight: normal;
+ line-height: 1.428571429;
+ white-space: nowrap;
+ margin: 0 5px;
+ border-radius: 3px;
+
+ // build name
+ .ci-build-text {
+ font-weight: 200;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ width: 90px;
+ color: $gl-text-color-secondary;
+ margin-left: 2px;
+ display: inline-block;
+ top: 1px;
+ vertical-align: text-bottom;
+ position: relative;
+ }
+
+ // status icon on the left
+ .ci-status-icon {
+ top: 3px;
+ position: relative;
+
+ > svg {
+ overflow: visible;
+ width: 18px;
+ height: 18px;
+ }
+ }
+
+ &:hover,
+ &:focus {
+ outline: none;
+ text-decoration: none;
+ color: $gl-text-color;
+ background-color: $stage-hover-bg;
+ }
}
}
-.tab-pane {
+// Dropdown in the big pipeline graph
+.big-pipeline-graph-dropdown-menu {
+ width: 195px;
+ min-width: 195px;
+ left: auto;
+ right: -195px;
+ top: -4px;
+ box-shadow: 0 1px 5px $black-transparent;
- &.pipelines {
+ .mini-pipeline-graph-dropdown-item {
+ .ci-status-icon {
+ top: -1px;
+ }
+ }
+}
- .ci-table {
- min-width: 900px;
+/**
+ * Top arrow in the dropdown in the mini pipeline graph
+ */
+.mini-pipeline-graph-dropdown-menu {
+ .arrow-up {
+ &::before,
+ &::after {
+ content: '';
+ display: inline-block;
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+ top: -6px;
+ left: 2px;
+ border-width: 0 5px 6px;
}
- .stage {
- max-width: 100px;
- width: 100px;
+ &::before {
+ border-width: 0 5px 5px;
+ border-bottom-color: $border-color;
}
- .pipeline-actions {
- min-width: initial;
+ &::after {
+ margin-top: 1px;
+ border-bottom-color: $white-light;
}
}
+}
+
+/**
+ * Terminal
+ */
+.terminal-icon {
+ margin-left: 3px;
+}
+
+.terminal-container {
+ .content-block {
+ border-bottom: none;
+ }
- &.builds {
+ #terminal {
+ margin-top: 10px;
+ min-height: 450px;
+ box-sizing: border-box;
- .ci-table {
- tr {
- height: 71px;
- }
+ > div {
+ min-height: 450px;
}
}
}
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index f8677f93fe0..722b3006f7c 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -60,8 +60,8 @@
.account-well {
padding: 10px;
- background-color: $help-well-bg;
- border: 1px solid $help-well-border;
+ background-color: $gray-light;
+ border: 1px solid $border-color;
border-radius: $border-radius-base;
ul {
@@ -136,7 +136,7 @@
.provider-btn-group {
display: inline-block;
margin-right: 10px;
- border: 1px solid $provider-btn-group-border;
+ border: 1px solid $border-color;
border-radius: 3px;
&:last-child {
@@ -147,7 +147,7 @@
.provider-btn-image {
display: inline-block;
padding: 5px 10px;
- border-right: 1px solid $provider-btn-group-border;
+ border-right: 1px solid $border-color;
> img {
width: 20px;
@@ -198,7 +198,7 @@
}
.personal-access-tokens-never-expires-label {
- color: $personal-access-tokens-disabled-label-color;
+ color: $note-disabled-comment-color;
}
.datepicker.personal-access-tokens-expires-at .ui-state-disabled span {
@@ -216,8 +216,8 @@
}
}
-.user-profile {
+.user-profile {
.cover-controls a {
margin-left: 5px;
}
@@ -231,8 +231,11 @@
}
}
- @media (max-width: $screen-xs-max) {
+ .user-profile-nav {
+ font-size: 0;
+ }
+ @media (max-width: $screen-xs-max) {
.cover-block {
padding-top: 20px;
}
@@ -253,6 +256,12 @@
}
}
}
+
+ .user-profile-nav {
+ a {
+ margin-right: 0;
+ }
+ }
}
}
@@ -262,3 +271,13 @@ table.u2f-registrations {
border-right: solid 1px transparent;
}
}
+
+.oauth-application-show {
+ .scope-name {
+ font-weight: 600;
+ }
+
+ .scopes-list {
+ padding-left: 18px;
+ }
+}
diff --git a/app/assets/stylesheets/pages/profiles/preferences.scss b/app/assets/stylesheets/pages/profiles/preferences.scss
index f8da0983b77..100ace41f2a 100644
--- a/app/assets/stylesheets/pages/profiles/preferences.scss
+++ b/app/assets/stylesheets/pages/profiles/preferences.scss
@@ -22,8 +22,8 @@
background: $theme-graphite;
}
- &.ui_gray {
- background: $theme-gray;
+ &.ui_black {
+ background: $theme-black;
}
&.ui_green {
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 6e0f6b1cd81..9455ba3b98a 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -6,12 +6,6 @@
}
}
-.no-ssh-key-message,
-.project-limit-message {
- background-color: $project-limit-message-bg;
- margin-bottom: 0;
-}
-
.new_project,
.edit-project {
@@ -32,7 +26,7 @@
margin-bottom: 5px;
}
- &> .form-group {
+ & > .form-group {
padding-left: 0;
}
}
@@ -79,7 +73,7 @@
border: 1px solid $border-color;
}
- &+ .select2 a {
+ & + .select2 a {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
@@ -99,7 +93,6 @@
.group-avatar {
float: none;
margin: 0 auto;
- border: none;
&.identicon {
border-radius: 50%;
@@ -151,8 +144,6 @@
.project-repo-buttons,
.group-buttons {
- margin-top: 15px;
-
.btn {
@include btn-gray;
padding: 3px 10px;
@@ -181,11 +172,9 @@
}
}
- .download-button,
- .dropdown-toggle,
- .notification-dropdown,
- .project-dropdown {
- margin-left: 10px;
+ .project-action-button {
+ margin: 15px 5px 0;
+ vertical-align: top;
}
.notification-dropdown .dropdown-menu {
@@ -201,13 +190,15 @@
.count-buttons {
display: inline-block;
vertical-align: top;
+ margin-top: 15px;
}
.project-clone-holder {
display: inline-block;
+ margin: 15px 5px 0 0;
input {
- height: 29px;
+ height: 28px;
}
}
@@ -261,7 +252,7 @@
line-height: 13px;
padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px;
- padding: 7px 14px;
+ padding: 6px 14px;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
@@ -301,7 +292,7 @@
.option-title {
font-weight: normal;
display: inline-block;
- color: $gl-gray-dark;
+ color: $gl-text-color;
}
.option-descr {
@@ -340,7 +331,7 @@
a.deploy-project-label {
padding: 5px;
margin-right: 5px;
- color: $gl-gray;
+ color: $gl-text-color;
background-color: $row-hover;
&:hover {
@@ -381,7 +372,7 @@ a.deploy-project-label {
}
a {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
.dropdown-menu {
@@ -420,13 +411,13 @@ a.deploy-project-label {
width: 100px;
height: 100px;
background-color: $gray-light;
- border: 1px solid $gray-dark;
+ border: 1px solid $white-normal;
margin: 0 auto;
border-radius: 50%;
i {
font-size: 100px;
- color: $gray-dark;
+ color: $white-normal;
}
}
@@ -435,7 +426,7 @@ a.deploy-project-label {
width: 100%;
height: 100%;
padding-top: $gl-padding;
- color: $gl-gray;
+ color: $gl-text-color;
.caption {
min-height: 30px;
@@ -498,6 +489,7 @@ a.deploy-project-label {
.project-stats {
font-size: 0;
+ text-align: center;
border-bottom: 1px solid $border-color;
.nav {
@@ -536,7 +528,7 @@ a.deploy-project-label {
}
li.missing {
- border: 1px dashed $border-gray-light;
+ border: 1px dashed $border-gray-normal;
border-radius: $border-radius-default;
a {
@@ -560,7 +552,7 @@ pre.light-well {
margin: 0 7px 7px;
h5 {
- color: $gl-text-color-dark;
+ color: $gl-text-color;
}
.light-well {
@@ -591,15 +583,25 @@ pre.light-well {
@include basic-list;
.project-row {
- border-color: $table-border-color;
+ border-color: $white-normal;
.project-full-name {
@include str-truncated;
+
+ @media (max-width: $screen-xs-max) {
+ max-width: 50%;
+ }
}
.controls {
line-height: $list-text-height;
+ .badge {
+ @media (max-width: $screen-xs-max) {
+ display: none;
+ }
+ }
+
a:hover {
text-decoration: none;
}
@@ -613,6 +615,12 @@ pre.light-well {
top: 2px;
}
}
+
+ .description p {
+ @media (max-width: $screen-xs-max) {
+ max-width: 50%;
+ }
+ }
}
.bottom {
@@ -626,7 +634,6 @@ pre.light-well {
margin: 0;
}
-
.activity-filter-block {
.controls {
padding-bottom: 7px;
@@ -635,6 +642,12 @@ pre.light-well {
}
}
+.commits-search-form {
+ .input-short {
+ min-width: 200px;
+ }
+}
+
.project-last-commit {
@media (min-width: $screen-sm-min) {
margin-top: $gl-padding;
@@ -643,7 +656,7 @@ pre.light-well {
&.container-fluid {
padding-top: 12px;
padding-bottom: 12px;
- background-color: $background-color;
+ background-color: $gray-light;
border: 1px solid $border-color;
border-right-width: 0;
border-left-width: 0;
@@ -665,7 +678,7 @@ pre.light-well {
}
.commit-row-message {
- color: $gl-gray;
+ color: $gl-text-color;
}
.commit_short_id {
@@ -753,7 +766,7 @@ pre.light-well {
.protected-branches-list {
a {
- color: $gl-gray;
+ color: $gl-text-color;
&:hover {
color: $gl-link-color;
@@ -813,7 +826,31 @@ pre.light-well {
.compare-form-group {
.dropdown-menu {
- width: 300px;
+ width: 100%;
+
+ @media (min-width: $screen-sm-min) {
+ width: 300px;
+ }
+ }
+
+ + .compare-ellipsis {
+ width: 100%;
+ vertical-align: middle;
+ text-align: center;
+ margin-top: -20px;
+
+ @media (min-width: $screen-sm-min) {
+ margin-top: 0;
+ width: auto;
+ }
+ }
+
+ .inline-input-group {
+ width: 100%;
+
+ @media (min-width: $screen-sm-min) {
+ width: 250px;
+ }
}
}
@@ -888,3 +925,23 @@ pre.light-well {
width: 30%;
}
}
+
+.services-installation-info .row {
+ margin-bottom: 10px;
+}
+
+.service-installation {
+ padding: 32px;
+ margin: 32px;
+ border-radius: 3px;
+ background-color: $white-light;
+
+ h3 {
+ margin-top: 0;
+ }
+
+ hr {
+ margin: 32px 0;
+ border-color: $border-color;
+ }
+}
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 63d0a34e610..12bff32bbf3 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -14,6 +14,20 @@
}
}
+.search form:hover,
+.file-finder-input:hover,
+.issuable-search-form:hover,
+.search-text-input:hover,
+textarea:hover,
+.form-control:hover {
+ border-color: lighten($dropdown-input-focus-border, 20%);
+ box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%);
+}
+
+input[type="checkbox"]:hover {
+ box-shadow: 0 0 2px 2px lighten($search-input-focus-shadow-color, 20%), 0 0 0 1px lighten($search-input-focus-shadow-color, 20%);
+}
+
.search {
margin-right: 10px;
margin-left: 10px;
@@ -51,9 +65,9 @@
border-radius: $border-radius-default;
font-size: 14px;
font-style: normal;
- color: $location-badge-color;
+ color: $note-disabled-comment-color;
display: inline-block;
- background-color: $location-badge-bg;
+ background-color: $gray-normal;
vertical-align: top;
cursor: default;
}
@@ -140,7 +154,7 @@
.search-input-wrap {
i {
- color: $location-icon-active-color;
+ color: $layout-link-gray;
}
}
}
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 51c926608f9..a28a87ed4f8 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -1,5 +1,5 @@
.settings-list-icon {
- color: $gl-placeholder-color;
+ color: $gl-text-color-secondary;
font-size: $settings-icon-size;
line-height: 42px;
}
diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss
index 5084b466722..f19275770be 100644
--- a/app/assets/stylesheets/pages/status.scss
+++ b/app/assets/stylesheets/pages/status.scss
@@ -1,6 +1,6 @@
.container-fluid {
.ci-status {
- padding: 2px 7px;
+ padding: 2px 7px 4px;
margin-right: 10px;
border: 1px solid $gray-darker;
white-space: nowrap;
@@ -15,8 +15,7 @@
height: 13px;
width: 13px;
position: relative;
- top: 1px;
- margin-right: 3px;
+ top: 2px;
overflow: visible;
}
@@ -25,7 +24,7 @@
border-color: $gl-danger;
&:not(span):hover {
- background-color: rgba( $gl-danger, .07);
+ background-color: rgba($gl-danger, .07);
}
svg {
@@ -39,7 +38,7 @@
border-color: $gl-success;
&:not(span):hover {
- background-color: rgba( $gl-success, .07);
+ background-color: rgba($gl-success, .07);
}
svg {
@@ -52,7 +51,7 @@
border-color: $gl-info;
&:not(span):hover {
- background-color: rgba( $gl-info, .07);
+ background-color: rgba($gl-info, .07);
}
svg {
@@ -62,15 +61,15 @@
&.ci-canceled,
&.ci-disabled {
- color: $gl-gray;
- border-color: $gl-gray;
+ color: $gl-text-color;
+ border-color: $gl-text-color;
&:not(span):hover {
- background-color: rgba( $gl-gray, .07);
+ background-color: rgba($gl-text-color, .07);
}
svg {
- fill: $gl-gray;
+ fill: $gl-text-color;
}
}
@@ -79,7 +78,7 @@
border-color: $gl-warning;
&:not(span):hover {
- background-color: rgba( $gl-warning, .07);
+ background-color: rgba($gl-warning, .07);
}
svg {
@@ -92,7 +91,7 @@
border-color: $blue-normal;
&:not(span):hover {
- background-color: rgba( $blue-normal, .07);
+ background-color: rgba($blue-normal, .07);
}
svg {
@@ -102,15 +101,28 @@
&.ci-created,
&.ci-skipped {
- color: $table-text-gray;
- border-color: $table-text-gray;
+ color: $gl-text-color-secondary;
+ border-color: $gl-text-color-secondary;
&:not(span):hover {
- background-color: rgba( $table-text-gray, .07);
+ background-color: rgba($gl-text-color-secondary, .07);
}
svg {
- fill: $table-text-gray;
+ fill: $gl-text-color-secondary;
+ }
+ }
+
+ &.ci-manual {
+ color: $gl-text-color;
+ border-color: $gl-text-color;
+
+ &:not(span):hover {
+ background-color: rgba($gl-text-color, .07);
+ }
+
+ svg {
+ fill: $gl-text-color;
}
}
}
@@ -123,3 +135,9 @@
left: 5px;
}
}
+
+.ci-status-link {
+ svg {
+ overflow: visible;
+ }
+}
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index 508b30f3947..01675acc62e 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -90,7 +90,7 @@
}
p {
- color: $gl-text-color-dark;
+ color: $gl-text-color;
}
}
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index 20ad63be045..4cce1c363eb 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -14,14 +14,15 @@
.add-to-tree {
vertical-align: top;
+ padding: 6px 10px;
}
.tree-table {
margin-bottom: 0;
tr {
- border-bottom: 1px solid $table-border-gray;
- border-top: 1px solid $table-border-gray;
+ border-bottom: 1px solid $white-normal;
+ border-top: 1px solid $white-normal;
td,
th {
@@ -39,7 +40,7 @@
.commit-history-link-spacer {
margin: 0 10px;
- color: $table-border-color;
+ color: $white-normal;
}
&:hover {
@@ -53,7 +54,7 @@
&.selected {
td {
- background: $gray-dark;
+ background: $white-normal;
border-top: 1px solid $border-gray-dark;
border-bottom: 1px solid $border-gray-dark;
}
@@ -77,7 +78,7 @@
i,
a {
- color: $gl-dark-link-color;
+ color: $gl-text-color;
}
img {
@@ -103,21 +104,21 @@
padding-right: 8px;
.commit-author-name {
- color: $gl-gray;
+ color: $gl-text-color;
}
}
.tree-time-ago {
min-width: 135px;
- color: $gl-gray-light;
+ color: $gl-text-color-secondary;
}
.tree-commit {
max-width: 320px;
- color: $gl-gray-light;
+ color: $gl-text-color-secondary;
.tree-commit-link {
- color: $gl-gray-light;
+ color: $gl-text-color-secondary;
&:hover {
text-decoration: underline;
@@ -133,21 +134,18 @@
.blob-commit-info {
list-style: none;
- padding: $gl-padding;
- background: $background-color;
+ background: $gray-light;
+ padding: 6px 0;
border: 1px solid $border-color;
border-bottom: none;
margin: 0;
- .commit {
- padding-top: 0;
- padding-bottom: 0;
+ .table-list-cell {
+ border-bottom: none;
+ }
- .commit-row-title {
- .commit-row-message {
- font-weight: normal;
- }
- }
+ .commit-actions {
+ width: 200px;
}
}
@@ -172,7 +170,7 @@
position: relative;
z-index: 2;
- .download-button {
+ .project-action-button {
margin-left: $btn-side-margin;
}
}
diff --git a/app/assets/stylesheets/pages/wiki.scss b/app/assets/stylesheets/pages/wiki.scss
index b9f81533150..d5783e14b21 100644
--- a/app/assets/stylesheets/pages/wiki.scss
+++ b/app/assets/stylesheets/pages/wiki.scss
@@ -15,7 +15,7 @@
}
.wiki-last-edit-by {
- color: $gl-gray-light;
+ color: $gl-text-color-secondary;
strong {
color: $gl-text-color;
@@ -24,7 +24,7 @@
.light {
font-weight: normal;
- color: $gl-gray-light;
+ color: $gl-text-color-secondary;
}
.git-access-header {
diff --git a/app/assets/stylesheets/pages/xterm.scss b/app/assets/stylesheets/pages/xterm.scss
index 9f9d630978a..b085c56390d 100644
--- a/app/assets/stylesheets/pages/xterm.scss
+++ b/app/assets/stylesheets/pages/xterm.scss
@@ -18,7 +18,7 @@
$l-blue: #81a2be;
$l-magenta: #b294bb;
$l-cyan: #8abeb7;
- $l-white: $ci-text-color;
+ $l-white: $gray-darkest;
/*
* xterm colors