summaryrefslogtreecommitdiff
path: root/app/assets/javascripts
diff options
context:
space:
mode:
authorAhmad Hassan <ahmad.hassan612@gmail.com>2018-12-11 16:48:26 +0200
committerAhmad Hassan <ahmad.hassan612@gmail.com>2018-12-11 16:48:26 +0200
commitdfc54352c001e8544972c3d40bfc82e55a11c6a0 (patch)
tree6f108bc06cef6db48bdc5fe09f50749c2e49b456 /app/assets/javascripts
parentd0daa1591b7e4dc8cf5ba787420d09cb7e76d8d7 (diff)
parent56936cd89838d85f038a6f25bb3033f8fa7a0ee1 (diff)
downloadgitlab-ce-dfc54352c001e8544972c3d40bfc82e55a11c6a0.tar.gz
Merge remote-tracking branch 'origin/master' into support-gitaly-tls
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/api.js61
-rw-r--r--app/assets/javascripts/badges/components/badge.vue34
-rw-r--r--app/assets/javascripts/badges/components/badge_form.vue55
-rw-r--r--app/assets/javascripts/badges/components/badge_list.vue29
-rw-r--r--app/assets/javascripts/badges/components/badge_list_row.vue27
-rw-r--r--app/assets/javascripts/badges/components/badge_settings.vue13
-rw-r--r--app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js4
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_gfm.js2
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_mermaid.js3
-rw-r--r--app/assets/javascripts/behaviors/requires_input.js7
-rw-r--r--app/assets/javascripts/behaviors/secret_values.js8
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js3
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js31
-rw-r--r--app/assets/javascripts/blob/file_template_mediator.js2
-rw-r--r--app/assets/javascripts/blob/viewer/index.js10
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js8
-rw-r--r--app/assets/javascripts/boards/components/board_blank_state.vue26
-rw-r--r--app/assets/javascripts/boards/components/board_card.vue5
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue38
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.vue32
-rw-r--r--app/assets/javascripts/boards/components/issue_card_inner.vue32
-rw-r--r--app/assets/javascripts/boards/components/issue_due_date.vue38
-rw-r--r--app/assets/javascripts/boards/components/issue_time_estimate.vue18
-rw-r--r--app/assets/javascripts/boards/components/modal/empty_state.vue10
-rw-r--r--app/assets/javascripts/boards/components/modal/footer.vue23
-rw-r--r--app/assets/javascripts/boards/components/modal/header.vue8
-rw-r--r--app/assets/javascripts/boards/components/modal/index.vue17
-rw-r--r--app/assets/javascripts/boards/components/modal/list.vue36
-rw-r--r--app/assets/javascripts/boards/components/modal/lists_dropdown.vue31
-rw-r--r--app/assets/javascripts/boards/components/modal/tabs.vue26
-rw-r--r--app/assets/javascripts/boards/components/project_select.vue64
-rw-r--r--app/assets/javascripts/boards/components/sidebar/remove_issue.vue10
-rw-r--r--app/assets/javascripts/boards/index.js4
-rw-r--r--app/assets/javascripts/boards/stores/boards_store.js4
-rw-r--r--app/assets/javascripts/build_artifacts.js4
-rw-r--r--app/assets/javascripts/ci_variable_list/ajax_variable_list.js6
-rw-r--r--app/assets/javascripts/ci_variable_list/ci_variable_list.js4
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js2
-rw-r--r--app/assets/javascripts/clusters/components/application_row.vue52
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue275
-rw-r--r--app/assets/javascripts/clusters/constants.js1
-rw-r--r--app/assets/javascripts/clusters/services/clusters_service.js1
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js16
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table.vue12
-rw-r--r--app/assets/javascripts/contextual_sidebar.js3
-rw-r--r--app/assets/javascripts/cycle_analytics/components/banner.vue27
-rw-r--r--app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue20
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_code_component.vue31
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_component.vue37
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue33
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_review_component.vue53
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue59
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_test_component.vue61
-rw-r--r--app/assets/javascripts/cycle_analytics/components/total_time_component.vue22
-rw-r--r--app/assets/javascripts/deploy_keys/components/action_btn.vue10
-rw-r--r--app/assets/javascripts/deploy_keys/components/app.vue24
-rw-r--r--app/assets/javascripts/deploy_keys/components/key.vue61
-rw-r--r--app/assets/javascripts/deploy_keys/components/keys_panel.vue23
-rw-r--r--app/assets/javascripts/diff_notes/components/jump_to_discussion.js2
-rw-r--r--app/assets/javascripts/diffs/components/app.vue97
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue34
-rw-r--r--app/assets/javascripts/diffs/components/commit_widget.vue6
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions.vue55
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions_dropdown.vue24
-rw-r--r--app/assets/javascripts/diffs/components/diff_content.vue11
-rw-r--r--app/assets/javascripts/diffs/components/diff_discussions.vue23
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue50
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue55
-rw-r--r--app/assets/javascripts/diffs/components/diff_gutter_avatars.vue13
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_gutter_content.vue35
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_note_form.vue5
-rw-r--r--app/assets/javascripts/diffs/components/diff_table_cell.vue13
-rw-r--r--app/assets/javascripts/diffs/components/edit_button.vue8
-rw-r--r--app/assets/javascripts/diffs/components/file_row_stats.vue13
-rw-r--r--app/assets/javascripts/diffs/components/hidden_files_warning.vue21
-rw-r--r--app/assets/javascripts/diffs/components/image_diff_overlay.vue19
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_comment_row.vue34
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_table_row.vue19
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_view.vue24
-rw-r--r--app/assets/javascripts/diffs/components/no_changes.vue21
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue64
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_table_row.vue35
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_view.vue18
-rw-r--r--app/assets/javascripts/diffs/components/tree_list.vue61
-rw-r--r--app/assets/javascripts/diffs/store/actions.js79
-rw-r--r--app/assets/javascripts/diffs/store/getters.js38
-rw-r--r--app/assets/javascripts/diffs/store/modules/diff_state.js5
-rw-r--r--app/assets/javascripts/diffs/store/mutation_types.js4
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js47
-rw-r--r--app/assets/javascripts/diffs/store/utils.js13
-rw-r--r--app/assets/javascripts/environments/components/container.vue8
-rw-r--r--app/assets/javascripts/environments/components/empty_state.vue12
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue29
-rw-r--r--app/assets/javascripts/environments/components/environment_external_url.vue2
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue125
-rw-r--r--app/assets/javascripts/environments/components/environment_monitoring.vue2
-rw-r--r--app/assets/javascripts/environments/components/environment_rollback.vue11
-rw-r--r--app/assets/javascripts/environments/components/environment_stop.vue4
-rw-r--r--app/assets/javascripts/environments/components/environment_terminal_button.vue2
-rw-r--r--app/assets/javascripts/environments/components/environments_app.vue18
-rw-r--r--app/assets/javascripts/environments/components/environments_table.vue68
-rw-r--r--app/assets/javascripts/environments/components/stop_environment_modal.vue22
-rw-r--r--app/assets/javascripts/environments/folder/environments_folder_bundle.js6
-rw-r--r--app/assets/javascripts/environments/folder/environments_folder_view.vue14
-rw-r--r--app/assets/javascripts/environments/index.js8
-rw-r--r--app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue21
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_emoji.js11
-rw-r--r--app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js7
-rw-r--r--app/assets/javascripts/frequent_items/components/app.vue11
-rw-r--r--app/assets/javascripts/frequent_items/components/frequent_items_list.vue6
-rw-r--r--app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue31
-rw-r--r--app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue6
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js33
-rw-r--r--app/assets/javascripts/groups/components/app.vue2
-rw-r--r--app/assets/javascripts/groups/components/group_folder.vue15
-rw-r--r--app/assets/javascripts/groups/components/group_item.vue81
-rw-r--r--app/assets/javascripts/groups/components/groups.vue16
-rw-r--r--app/assets/javascripts/groups/components/item_actions.vue10
-rw-r--r--app/assets/javascripts/groups/components/item_caret.vue7
-rw-r--r--app/assets/javascripts/groups/components/item_stats.vue10
-rw-r--r--app/assets/javascripts/groups/components/item_stats_value.vue8
-rw-r--r--app/assets/javascripts/groups/components/item_type_icon.vue4
-rw-r--r--app/assets/javascripts/groups/index.js3
-rw-r--r--app/assets/javascripts/groups_select.js7
-rw-r--r--app/assets/javascripts/header.js3
-rw-r--r--app/assets/javascripts/ide/components/activity_bar.vue24
-rw-r--r--app/assets/javascripts/ide/components/branches/item.vue24
-rw-r--r--app/assets/javascripts/ide/components/branches/search_list.vue29
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/actions.vue6
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue17
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue20
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/form.vue26
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list.vue54
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue22
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list_item.vue13
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/message_field.vue43
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue19
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/stage_button.vue21
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/success_message.vue20
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/unstage_button.vue13
-rw-r--r--app/assets/javascripts/ide/components/editor_mode_dropdown.vue20
-rw-r--r--app/assets/javascripts/ide/components/error_message.vue17
-rw-r--r--app/assets/javascripts/ide/components/external_link.vue11
-rw-r--r--app/assets/javascripts/ide/components/file_finder/index.vue34
-rw-r--r--app/assets/javascripts/ide/components/file_finder/item.vue17
-rw-r--r--app/assets/javascripts/ide/components/file_row_extra.vue9
-rw-r--r--app/assets/javascripts/ide/components/file_templates/bar.vue11
-rw-r--r--app/assets/javascripts/ide/components/file_templates/dropdown.vue41
-rw-r--r--app/assets/javascripts/ide/components/ide.vue59
-rw-r--r--app/assets/javascripts/ide/components/ide_project_header.vue14
-rw-r--r--app/assets/javascripts/ide/components/ide_review.vue15
-rw-r--r--app/assets/javascripts/ide/components/ide_side_bar.vue23
-rw-r--r--app/assets/javascripts/ide/components/ide_status_bar.vue56
-rw-r--r--app/assets/javascripts/ide/components/ide_tree.vue12
-rw-r--r--app/assets/javascripts/ide/components/ide_tree_list.vue21
-rw-r--r--app/assets/javascripts/ide/components/jobs/detail.vue37
-rw-r--r--app/assets/javascripts/ide/components/jobs/detail/description.vue19
-rw-r--r--app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue4
-rw-r--r--app/assets/javascripts/ide/components/jobs/item.vue12
-rw-r--r--app/assets/javascripts/ide/components/jobs/list.vue8
-rw-r--r--app/assets/javascripts/ide/components/jobs/stage.vue43
-rw-r--r--app/assets/javascripts/ide/components/merge_requests/info.vue9
-rw-r--r--app/assets/javascripts/ide/components/merge_requests/item.vue19
-rw-r--r--app/assets/javascripts/ide/components/merge_requests/list.vue40
-rw-r--r--app/assets/javascripts/ide/components/nav_dropdown.vue13
-rw-r--r--app/assets/javascripts/ide/components/nav_dropdown_button.vue25
-rw-r--r--app/assets/javascripts/ide/components/nav_form.vue12
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/button.vue5
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/index.vue29
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/modal.vue21
-rw-r--r--app/assets/javascripts/ide/components/panes/right.vue20
-rw-r--r--app/assets/javascripts/ide/components/pipelines/list.vue89
-rw-r--r--app/assets/javascripts/ide/components/preview/clientside.vue23
-rw-r--r--app/assets/javascripts/ide/components/preview/navigator.vue29
-rw-r--r--app/assets/javascripts/ide/components/repo_commit_section.vue18
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue41
-rw-r--r--app/assets/javascripts/ide/components/repo_file_status_icon.vue12
-rw-r--r--app/assets/javascripts/ide/components/repo_tab.vue31
-rw-r--r--app/assets/javascripts/ide/components/repo_tabs.vue11
-rw-r--r--app/assets/javascripts/ide/components/resizable_panel.vue4
-rw-r--r--app/assets/javascripts/ide/components/shared/tokened_input.vue27
-rw-r--r--app/assets/javascripts/ide/constants.js1
-rw-r--r--app/assets/javascripts/ide/index.js14
-rw-r--r--app/assets/javascripts/ide/services/index.js6
-rw-r--r--app/assets/javascripts/ide/stores/actions/file.js13
-rw-r--r--app/assets/javascripts/ide/stores/actions/merge_request.js7
-rw-r--r--app/assets/javascripts/ide/stores/actions/project.js2
-rw-r--r--app/assets/javascripts/ide/stores/actions/tree.js2
-rw-r--r--app/assets/javascripts/ide/stores/modules/merge_requests/actions.js12
-rw-r--r--app/assets/javascripts/ide/stores/modules/pipelines/actions.js6
-rw-r--r--app/assets/javascripts/ide/stores/modules/pipelines/getters.js10
-rw-r--r--app/assets/javascripts/image_diff/helpers/badge_helper.js2
-rw-r--r--app/assets/javascripts/importer_status.js4
-rw-r--r--app/assets/javascripts/init_legacy_filters.js14
-rw-r--r--app/assets/javascripts/issuable_suggestions/components/app.vue96
-rw-r--r--app/assets/javascripts/issuable_suggestions/components/item.vue137
-rw-r--r--app/assets/javascripts/issuable_suggestions/index.js38
-rw-r--r--app/assets/javascripts/issuable_suggestions/queries/issues.graphql26
-rw-r--r--app/assets/javascripts/issue_show/components/app.vue6
-rw-r--r--app/assets/javascripts/issue_show/components/description.vue14
-rw-r--r--app/assets/javascripts/issue_show/components/edit_actions.vue26
-rw-r--r--app/assets/javascripts/issue_show/components/edited.vue19
-rw-r--r--app/assets/javascripts/issue_show/components/fields/description.vue9
-rw-r--r--app/assets/javascripts/issue_show/components/fields/description_template.vue52
-rw-r--r--app/assets/javascripts/issue_show/components/fields/title.vue9
-rw-r--r--app/assets/javascripts/issue_show/components/form.vue9
-rw-r--r--app/assets/javascripts/issue_show/components/locked_warning.vue7
-rw-r--r--app/assets/javascripts/issue_show/components/title.vue8
-rw-r--r--app/assets/javascripts/jobs/components/artifacts_block.vue26
-rw-r--r--app/assets/javascripts/jobs/components/commit_block.vue26
-rw-r--r--app/assets/javascripts/jobs/components/empty_state.vue25
-rw-r--r--app/assets/javascripts/jobs/components/environments_block.vue9
-rw-r--r--app/assets/javascripts/jobs/components/erased_block.vue14
-rw-r--r--app/assets/javascripts/jobs/components/job_app.vue34
-rw-r--r--app/assets/javascripts/jobs/components/job_container_item.vue16
-rw-r--r--app/assets/javascripts/jobs/components/job_log_controllers.vue22
-rw-r--r--app/assets/javascripts/jobs/components/sidebar.vue90
-rw-r--r--app/assets/javascripts/jobs/components/sidebar_detail_row.vue26
-rw-r--r--app/assets/javascripts/jobs/components/stages_dropdown.vue33
-rw-r--r--app/assets/javascripts/jobs/components/stuck_block.vue51
-rw-r--r--app/assets/javascripts/jobs/components/trigger_block.vue79
-rw-r--r--app/assets/javascripts/jobs/store/getters.js2
-rw-r--r--app/assets/javascripts/labels.js2
-rw-r--r--app/assets/javascripts/landing.js3
-rw-r--r--app/assets/javascripts/lazy_loader.js10
-rw-r--r--app/assets/javascripts/lib/graphql.js9
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js48
-rw-r--r--app/assets/javascripts/lib/utils/dom_utils.js5
-rw-r--r--app/assets/javascripts/lib/utils/file_upload.js13
-rw-r--r--app/assets/javascripts/lib/utils/http_status.js2
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js11
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js38
-rw-r--r--app/assets/javascripts/lib/utils/users_cache.js28
-rw-r--r--app/assets/javascripts/main.js2
-rw-r--r--app/assets/javascripts/merge_request_tabs.js31
-rw-r--r--app/assets/javascripts/milestone_select.js8
-rw-r--r--app/assets/javascripts/mirrors/constants.js4
-rw-r--r--app/assets/javascripts/mirrors/mirror_repos.js (renamed from app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js)15
-rw-r--r--app/assets/javascripts/mirrors/ssh_mirror.js299
-rw-r--r--app/assets/javascripts/monitoring/components/charts/area.vue97
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue38
-rw-r--r--app/assets/javascripts/monitoring/components/empty_state.vue61
-rw-r--r--app/assets/javascripts/monitoring/components/graph.vue81
-rw-r--r--app/assets/javascripts/monitoring/components/graph/axis.vue15
-rw-r--r--app/assets/javascripts/monitoring/components/graph/deployment.vue41
-rw-r--r--app/assets/javascripts/monitoring/components/graph/flag.vue56
-rw-r--r--app/assets/javascripts/monitoring/components/graph/legend.vue20
-rw-r--r--app/assets/javascripts/monitoring/components/graph/path.vue6
-rw-r--r--app/assets/javascripts/monitoring/components/graph/track_line.vue4
-rw-r--r--app/assets/javascripts/monitoring/components/graph_group.vue16
-rw-r--r--app/assets/javascripts/monitoring/monitoring_bundle.js4
-rw-r--r--app/assets/javascripts/monitoring/stores/monitoring_store.js34
-rw-r--r--app/assets/javascripts/namespace_select.js3
-rw-r--r--app/assets/javascripts/notebook/cells/code.vue6
-rw-r--r--app/assets/javascripts/notebook/cells/code/index.vue11
-rw-r--r--app/assets/javascripts/notebook/cells/markdown.vue5
-rw-r--r--app/assets/javascripts/notebook/cells/output/image.vue5
-rw-r--r--app/assets/javascripts/notebook/cells/output/index.vue2
-rw-r--r--app/assets/javascripts/notebook/cells/prompt.vue4
-rw-r--r--app/assets/javascripts/notebook/index.vue3
-rw-r--r--app/assets/javascripts/notes.js2
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue278
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue124
-rw-r--r--app/assets/javascripts/notes/components/discussion_counter.vue50
-rw-r--r--app/assets/javascripts/notes/components/discussion_filter.vue18
-rw-r--r--app/assets/javascripts/notes/components/discussion_locked_widget.vue6
-rw-r--r--app/assets/javascripts/notes/components/note_actions.vue100
-rw-r--r--app/assets/javascripts/notes/components/note_attachment.vue23
-rw-r--r--app/assets/javascripts/notes/components/note_awards_list.vue27
-rw-r--r--app/assets/javascripts/notes/components/note_body.vue17
-rw-r--r--app/assets/javascripts/notes/components/note_edited_text.vue9
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue57
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue45
-rw-r--r--app/assets/javascripts/notes/components/note_signed_out_widget.vue6
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue429
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue101
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue114
-rw-r--r--app/assets/javascripts/notes/components/toggle_replies_widget.vue35
-rw-r--r--app/assets/javascripts/notes/mixins/discussion_navigation.js53
-rw-r--r--app/assets/javascripts/notes/mixins/resolvable.js2
-rw-r--r--app/assets/javascripts/notes/stores/actions.js28
-rw-r--r--app/assets/javascripts/notes/stores/getters.js65
-rw-r--r--app/assets/javascripts/notes/stores/modules/index.js3
-rw-r--r--app/assets/javascripts/notes/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/notes/stores/mutations.js45
-rw-r--r--app/assets/javascripts/notifications_dropdown.js4
-rw-r--r--app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js3
-rw-r--r--app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue24
-rw-r--r--app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue24
-rw-r--r--app/assets/javascripts/pages/dashboard/issues/index.js10
-rw-r--r--app/assets/javascripts/pages/dashboard/merge_requests/index.js12
-rw-r--r--app/assets/javascripts/pages/groups/edit/index.js4
-rw-r--r--app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue9
-rw-r--r--app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue4
-rw-r--r--app/assets/javascripts/pages/profiles/show/emoji_menu.js1
-rw-r--r--app/assets/javascripts/pages/profiles/two_factor_auths/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/commit/show/index.js5
-rw-r--r--app/assets/javascripts/pages/projects/edit/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/issues/form.js5
-rw-r--r--app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue8
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue36
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue40
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/index/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/project.js9
-rw-r--r--app/assets/javascripts/pages/projects/serverless/index.js5
-rw-r--r--app/assets/javascripts/pages/projects/settings/repository/form.js2
-rw-r--r--app/assets/javascripts/pages/projects/settings/repository/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue18
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue26
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue43
-rw-r--r--app/assets/javascripts/pages/projects/shared/project_avatar.js16
-rw-r--r--app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue30
-rw-r--r--app/assets/javascripts/pages/projects/wikis/wikis.js4
-rw-r--r--app/assets/javascripts/pages/users/activity_calendar.js5
-rw-r--r--app/assets/javascripts/pages/users/user_overview_block.js5
-rw-r--r--app/assets/javascripts/pages/users/user_tabs.js110
-rw-r--r--app/assets/javascripts/pdf/index.vue4
-rw-r--r--app/assets/javascripts/pdf/page/index.vue7
-rw-r--r--app/assets/javascripts/performance_bar/components/detailed_metric.vue36
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue49
-rw-r--r--app/assets/javascripts/performance_bar/components/request_selector.vue6
-rw-r--r--app/assets/javascripts/performance_bar/components/simple_metric.vue14
-rw-r--r--app/assets/javascripts/performance_bar/services/performance_bar_service.js4
-rw-r--r--app/assets/javascripts/pipelines/components/blank_state.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/empty_state.vue29
-rw-r--r--app/assets/javascripts/pipelines/components/graph/action_component.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/graph/graph_component.vue18
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue15
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_item.vue19
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_name_component.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/graph/stage_column_component.vue10
-rw-r--r--app/assets/javascripts/pipelines/components/header_component.vue8
-rw-r--r--app/assets/javascripts/pipelines/components/nav_controls.vue8
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue26
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines.vue29
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_actions.vue23
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_artifacts.vue25
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_table.vue26
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_table_row.vue41
-rw-r--r--app/assets/javascripts/pipelines/components/stage.vue27
-rw-r--r--app/assets/javascripts/pipelines/components/time_ago.vue28
-rw-r--r--app/assets/javascripts/pipelines/mixins/pipelines.js2
-rw-r--r--app/assets/javascripts/profile/account/components/delete_account_modal.vue33
-rw-r--r--app/assets/javascripts/profile/account/components/update_username.vue8
-rw-r--r--app/assets/javascripts/profile/profile.js3
-rw-r--r--app/assets/javascripts/project_select.js5
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js2
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue27
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue31
-rw-r--r--app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue25
-rw-r--r--app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue13
-rw-r--r--app/assets/javascripts/registry/components/app.vue25
-rw-r--r--app/assets/javascripts/registry/components/collapsible_container.vue93
-rw-r--r--app/assets/javascripts/registry/components/table_registry.vue77
-rw-r--r--app/assets/javascripts/registry/stores/actions.js36
-rw-r--r--app/assets/javascripts/registry/stores/index.js28
-rw-r--r--app/assets/javascripts/registry/stores/mutations.js1
-rw-r--r--app/assets/javascripts/registry/stores/state.js26
-rw-r--r--app/assets/javascripts/reports/components/grouped_test_reports_app.vue14
-rw-r--r--app/assets/javascripts/reports/components/issue_status_icon.vue5
-rw-r--r--app/assets/javascripts/reports/components/modal.vue19
-rw-r--r--app/assets/javascripts/reports/components/modal_open_name.vue2
-rw-r--r--app/assets/javascripts/reports/components/report_item.vue18
-rw-r--r--app/assets/javascripts/reports/components/report_link.vue10
-rw-r--r--app/assets/javascripts/reports/components/report_section.vue12
-rw-r--r--app/assets/javascripts/reports/components/summary_row.vue22
-rw-r--r--app/assets/javascripts/reports/components/test_issue_body.vue10
-rw-r--r--app/assets/javascripts/search_autocomplete.js9
-rw-r--r--app/assets/javascripts/serverless/components/empty_state.vue40
-rw-r--r--app/assets/javascripts/serverless/components/function_row.vue40
-rw-r--r--app/assets/javascripts/serverless/components/functions.vue123
-rw-r--r--app/assets/javascripts/serverless/event_hub.js3
-rw-r--r--app/assets/javascripts/serverless/serverless_bundle.js106
-rw-r--r--app/assets/javascripts/serverless/services/get_functions_service.js11
-rw-r--r--app/assets/javascripts/serverless/stores/serverless_store.js24
-rw-r--r--app/assets/javascripts/set_status_modal/set_status_modal_trigger.vue8
-rw-r--r--app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue29
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignee_title.vue21
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignees.vue56
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue20
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/edit_form.vue10
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue12
-rw-r--r--app/assets/javascripts/sidebar/components/lock/edit_form.vue17
-rw-r--r--app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue12
-rw-r--r--app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue32
-rw-r--r--app/assets/javascripts/sidebar/components/participants/participants.vue30
-rw-r--r--app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue9
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue23
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/estimate_only_pane.vue5
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/help_state.vue21
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/no_tracking_pane.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue3
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue34
-rw-r--r--app/assets/javascripts/sidebar/components/todo_toggle/todo.vue14
-rw-r--r--app/assets/javascripts/star.js4
-rw-r--r--app/assets/javascripts/terminal/index.js2
-rw-r--r--app/assets/javascripts/terminal/terminal.js57
-rw-r--r--app/assets/javascripts/toggle_buttons.js6
-rw-r--r--app/assets/javascripts/usage_ping_consent.js6
-rw-r--r--app/assets/javascripts/user_popovers.js107
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment.vue39
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue12
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_container.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue51
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_icon.vue17
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue134
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue74
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue17
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue18
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue15
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue9
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue13
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue28
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue34
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue43
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue19
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue19
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue11
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue11
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue34
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue17
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/pipeline_failed.vue11
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue70
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue11
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue9
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue19
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue74
-rw-r--r--app/assets/javascripts/vue_shared/components/bar_chart.vue85
-rw-r--r--app/assets/javascripts/vue_shared/components/callout.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/changed_file_icon.vue15
-rw-r--r--app/assets/javascripts/vue_shared/components/ci_badge_link.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/ci_icon.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/clipboard_button.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/commit.vue48
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue15
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue25
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/deprecated_modal.vue52
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue31
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/viewers/download_diff_viewer.vue32
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue41
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue36
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue53
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/viewers/mode_changed.vue30
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/viewers/renamed.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue29
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_hidden_input.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/expand_button.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/file_icon.vue21
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue21
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue35
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_countdown.vue10
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_modal.vue27
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue30
-rw-r--r--app/assets/javascripts/vue_shared/components/help_popover.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/icon.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/identicon.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/issue_assignees.vue94
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/issue_milestone.vue90
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/issue_warning.vue16
-rw-r--r--app/assets/javascripts/vue_shared/components/loading_button.vue18
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue60
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/header.vue51
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar.vue81
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/memory_graph.vue15
-rw-r--r--app/assets/javascripts/vue_shared/components/navigation_tabs.vue13
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue46
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue15
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue21
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/system_note.vue66
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/timeline_entry_item.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/pagination_links.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/pikaday.vue17
-rw-r--r--app/assets/javascripts/vue_shared/components/project_avatar/default.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/project_avatar/image.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/recaptcha_modal.vue10
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue13
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue47
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue28
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue24
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue13
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value.vue14
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/smart_virtual_list.vue13
-rw-r--r--app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/svg_gradient.vue17
-rw-r--r--app/assets/javascripts/vue_shared/components/table_pagination.vue12
-rw-r--r--app/assets/javascripts/vue_shared/components/tabs/tab.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue13
-rw-r--r--app/assets/javascripts/vue_shared/components/toggle_button.vue17
-rw-r--r--app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue13
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue104
513 files changed, 5663 insertions, 7523 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 3f7a1ef1bfc..e2740981a4b 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -5,21 +5,25 @@ import axios from './lib/utils/axios_utils';
const Api = {
groupsPath: '/api/:version/groups.json',
groupPath: '/api/:version/groups/:id',
+ subgroupsPath: '/api/:version/groups/:id/subgroups',
namespacesPath: '/api/:version/namespaces.json',
groupProjectsPath: '/api/:version/groups/:id/projects.json',
projectsPath: '/api/:version/projects.json',
projectPath: '/api/:version/projects/:id',
projectLabelsPath: '/:namespace_path/:project_path/labels',
- mergeRequestPath: '/api/:version/projects/:id/merge_requests/:mrid',
+ projectMergeRequestPath: '/api/:version/projects/:id/merge_requests/:mrid',
+ projectMergeRequestChangesPath: '/api/:version/projects/:id/merge_requests/:mrid/changes',
+ projectMergeRequestVersionsPath: '/api/:version/projects/:id/merge_requests/:mrid/versions',
+ projectRunnersPath: '/api/:version/projects/:id/runners',
mergeRequestsPath: '/api/:version/merge_requests',
- mergeRequestChangesPath: '/api/:version/projects/:id/merge_requests/:mrid/changes',
- mergeRequestVersionsPath: '/api/:version/projects/:id/merge_requests/:mrid/versions',
groupLabelsPath: '/groups/:namespace_path/-/labels',
issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key',
projectTemplatePath: '/api/:version/projects/:id/templates/:type/:key',
projectTemplatesPath: '/api/:version/projects/:id/templates/:type',
usersPath: '/api/:version/users.json',
- userStatusPath: '/api/:version/user/status',
+ userPath: '/api/:version/users/:id',
+ userStatusPath: '/api/:version/users/:id/status',
+ userPostStatusPath: '/api/:version/user/status',
commitPath: '/api/:version/projects/:id/repository/commits',
commitPipelinesPath: '/:project_id/commit/:sha/pipelines',
branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch',
@@ -99,36 +103,45 @@ const Api = {
},
// Return Merge Request for project
- mergeRequest(projectPath, mergeRequestId, params = {}) {
- const url = Api.buildUrl(Api.mergeRequestPath)
+ projectMergeRequest(projectPath, mergeRequestId, params = {}) {
+ const url = Api.buildUrl(Api.projectMergeRequestPath)
.replace(':id', encodeURIComponent(projectPath))
.replace(':mrid', mergeRequestId);
return axios.get(url, { params });
},
- mergeRequests(params = {}) {
- const url = Api.buildUrl(Api.mergeRequestsPath);
-
- return axios.get(url, { params });
- },
-
- mergeRequestChanges(projectPath, mergeRequestId) {
- const url = Api.buildUrl(Api.mergeRequestChangesPath)
+ projectMergeRequestChanges(projectPath, mergeRequestId) {
+ const url = Api.buildUrl(Api.projectMergeRequestChangesPath)
.replace(':id', encodeURIComponent(projectPath))
.replace(':mrid', mergeRequestId);
return axios.get(url);
},
- mergeRequestVersions(projectPath, mergeRequestId) {
- const url = Api.buildUrl(Api.mergeRequestVersionsPath)
+ projectMergeRequestVersions(projectPath, mergeRequestId) {
+ const url = Api.buildUrl(Api.projectMergeRequestVersionsPath)
.replace(':id', encodeURIComponent(projectPath))
.replace(':mrid', mergeRequestId);
return axios.get(url);
},
+ projectRunners(projectPath, config = {}) {
+ const url = Api.buildUrl(Api.projectRunnersPath).replace(
+ ':id',
+ encodeURIComponent(projectPath),
+ );
+
+ return axios.get(url, config);
+ },
+
+ mergeRequests(params = {}) {
+ const url = Api.buildUrl(Api.mergeRequestsPath);
+
+ return axios.get(url, { params });
+ },
+
newLabel(namespacePath, projectPath, data, callback) {
let url;
@@ -243,6 +256,20 @@ const Api = {
});
},
+ user(id, options) {
+ const url = Api.buildUrl(this.userPath).replace(':id', encodeURIComponent(id));
+ return axios.get(url, {
+ params: options,
+ });
+ },
+
+ userStatus(id, options) {
+ const url = Api.buildUrl(this.userStatusPath).replace(':id', encodeURIComponent(id));
+ return axios.get(url, {
+ params: options,
+ });
+ },
+
branches(id, query = '', options = {}) {
const url = Api.buildUrl(this.createBranchPath).replace(':id', encodeURIComponent(id));
@@ -265,7 +292,7 @@ const Api = {
},
postUserStatus({ emoji, message }) {
- const url = Api.buildUrl(this.userStatusPath);
+ const url = Api.buildUrl(this.userPostStatusPath);
return axios.put(url, {
emoji,
diff --git a/app/assets/javascripts/badges/components/badge.vue b/app/assets/javascripts/badges/components/badge.vue
index 8512bf9dd7b..ae2916e3a3b 100644
--- a/app/assets/javascripts/badges/components/badge.vue
+++ b/app/assets/javascripts/badges/components/badge.vue
@@ -1,17 +1,15 @@
<script>
import Icon from '~/vue_shared/components/icon.vue';
-import Tooltip from '~/vue_shared/directives/tooltip';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
export default {
name: 'Badge',
components: {
Icon,
- Tooltip,
GlLoadingIcon,
},
directives: {
- Tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
imageUrl: {
@@ -65,12 +63,7 @@ export default {
<template>
<div>
- <a
- v-show="!isLoading && !hasError"
- :href="linkUrl"
- target="_blank"
- rel="noopener noreferrer"
- >
+ <a v-show="!isLoading && !hasError" :href="linkUrl" target="_blank" rel="noopener noreferrer">
<img
:src="imageUrlWithRetries"
class="project-badge"
@@ -80,15 +73,9 @@ export default {
/>
</a>
- <gl-loading-icon
- v-show="isLoading"
- :inline="true"
- />
+ <gl-loading-icon v-show="isLoading" :inline="true" />
- <div
- v-show="hasError"
- class="btn-group"
- >
+ <div v-show="hasError" class="btn-group">
<div class="btn btn-default btn-sm disabled">
<icon
:size="16"
@@ -97,25 +84,20 @@ export default {
aria-hidden="true"
/>
</div>
- <div
- class="btn btn-default btn-sm disabled"
- >
+ <div class="btn btn-default btn-sm disabled">
<span class="prepend-left-8 append-right-8">{{ s__('Badges|No badge image') }}</span>
</div>
</div>
<button
v-show="hasError"
- v-tooltip
+ v-gl-tooltip.hover
:title="s__('Badges|Reload badge image')"
class="btn btn-transparent btn-sm text-primary"
type="button"
@click="reloadImage"
>
- <icon
- :size="16"
- name="retry"
- />
+ <icon :size="16" name="retry" />
</button>
</div>
</template>
diff --git a/app/assets/javascripts/badges/components/badge_form.vue b/app/assets/javascripts/badges/components/badge_form.vue
index 47e6e618219..85a15b38de1 100644
--- a/app/assets/javascripts/badges/components/badge_form.vue
+++ b/app/assets/javascripts/badges/components/badge_form.vue
@@ -4,7 +4,7 @@ import { mapActions, mapState } from 'vuex';
import createFlash from '~/flash';
import { s__, sprintf } from '~/locale';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import createEmptyBadge from '../empty_badge';
import Badge from './badge.vue';
@@ -155,10 +155,7 @@ export default {
@submit.prevent.stop="onSubmit"
>
<div class="form-group">
- <label
- for="badge-link-url"
- class="label-bold"
- >{{ s__('Badges|Link') }}</label>
+ <label for="badge-link-url" class="label-bold">{{ s__('Badges|Link') }}</label>
<p v-html="helpText"></p>
<input
id="badge-link-url"
@@ -168,19 +165,12 @@ export default {
required
@input="debouncedPreview"
/>
- <div class="invalid-feedback">
- {{ s__('Badges|Please fill in a valid URL') }}
- </div>
- <span class="form-text text-muted">
- {{ badgeLinkUrlExample }}
- </span>
+ <div class="invalid-feedback">{{ s__('Badges|Please fill in a valid URL') }}</div>
+ <span class="form-text text-muted"> {{ badgeLinkUrlExample }} </span>
</div>
<div class="form-group">
- <label
- for="badge-image-url"
- class="label-bold"
- >{{ s__('Badges|Badge image URL') }}</label>
+ <label for="badge-image-url" class="label-bold">{{ s__('Badges|Badge image URL') }}</label>
<p v-html="helpText"></p>
<input
id="badge-image-url"
@@ -190,12 +180,8 @@ export default {
required
@input="debouncedPreview"
/>
- <div class="invalid-feedback">
- {{ s__('Badges|Please fill in a valid URL') }}
- </div>
- <span class="form-text text-muted">
- {{ badgeImageUrlExample }}
- </span>
+ <div class="invalid-feedback">{{ s__('Badges|Please fill in a valid URL') }}</div>
+ <span class="form-text text-muted"> {{ badgeImageUrlExample }} </span>
</div>
<div class="form-group">
@@ -206,37 +192,22 @@ export default {
:image-url="renderedImageUrl"
:link-url="renderedLinkUrl"
/>
- <p v-show="isRendering">
- <gl-loading-icon
- :inline="true"
- />
+ <p v-show="isRendering"><gl-loading-icon :inline="true" /></p>
+ <p v-show="!renderedBadge && !isRendering" class="disabled-content">
+ {{ s__('Badges|No image to preview') }}
</p>
- <p
- v-show="!renderedBadge && !isRendering"
- class="disabled-content"
- >{{ s__('Badges|No image to preview') }}</p>
</div>
- <div
- v-if="isEditing"
- class="row-content-block"
- >
+ <div v-if="isEditing" class="row-content-block">
<loading-button
:loading="isSaving"
:label="s__('Badges|Save changes')"
type="submit"
container-class="btn btn-success"
/>
- <button
- class="btn btn-cancel"
- type="button"
- @click="onCancel"
- >{{ __('Cancel') }}</button>
+ <button class="btn btn-cancel" type="button" @click="onCancel">{{ __('Cancel') }}</button>
</div>
- <div
- v-else
- class="form-group"
- >
+ <div v-else class="form-group">
<loading-button
:loading="isSaving"
:label="s__('Badges|Add badge')"
diff --git a/app/assets/javascripts/badges/components/badge_list.vue b/app/assets/javascripts/badges/components/badge_list.vue
index ab518820378..d2767dd6c64 100644
--- a/app/assets/javascripts/badges/components/badge_list.vue
+++ b/app/assets/javascripts/badges/components/badge_list.vue
@@ -1,6 +1,6 @@
<script>
import { mapState } from 'vuex';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import BadgeListRow from './badge_list_row.vue';
import { GROUP_BADGE } from '../constants';
@@ -26,32 +26,15 @@ export default {
<div class="card">
<div class="card-header">
{{ s__('Badges|Your badges') }}
- <span
- v-show="!isLoading"
- class="badge badge-pill"
- >{{ badges.length }}</span>
+ <span v-show="!isLoading" class="badge badge-pill">{{ badges.length }}</span>
</div>
- <gl-loading-icon
- v-show="isLoading"
- :size="2"
- class="card-body"
- />
- <div
- v-if="hasNoBadges"
- class="card-body"
- >
+ <gl-loading-icon v-show="isLoading" :size="2" class="card-body" />
+ <div v-if="hasNoBadges" class="card-body">
<span v-if="isGroupBadge">{{ s__('Badges|This group has no badges') }}</span>
<span v-else>{{ s__('Badges|This project has no badges') }}</span>
</div>
- <div
- v-else
- class="card-body"
- >
- <badge-list-row
- v-for="badge in badges"
- :key="badge.id"
- :badge="badge"
- />
+ <div v-else class="card-body">
+ <badge-list-row v-for="badge in badges" :key="badge.id" :badge="badge" />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/badges/components/badge_list_row.vue b/app/assets/javascripts/badges/components/badge_list_row.vue
index f28eff18f03..9051be1e102 100644
--- a/app/assets/javascripts/badges/components/badge_list_row.vue
+++ b/app/assets/javascripts/badges/components/badge_list_row.vue
@@ -2,7 +2,7 @@
import { mapActions, mapState } from 'vuex';
import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import { PROJECT_BADGE } from '../constants';
import Badge from './badge.vue';
@@ -50,20 +50,14 @@ export default {
<span class="badge badge-pill">{{ badgeKindText }}</span>
</div>
<div class="table-section section-15 table-button-footer">
- <div
- v-if="canEditBadge"
- class="table-action-buttons">
+ <div v-if="canEditBadge" class="table-action-buttons">
<button
:disabled="badge.isDeleting"
class="btn btn-default append-right-8"
type="button"
- @click="editBadge(badge)"
+ @click="editBadge(badge);"
>
- <icon
- :size="16"
- :aria-label="__('Edit')"
- name="pencil"
- />
+ <icon :size="16" :aria-label="__('Edit')" name="pencil" />
</button>
<button
:disabled="badge.isDeleting"
@@ -71,18 +65,11 @@ export default {
type="button"
data-toggle="modal"
data-target="#delete-badge-modal"
- @click="updateBadgeInModal(badge)"
+ @click="updateBadgeInModal(badge);"
>
- <icon
- :size="16"
- :aria-label="__('Delete')"
- name="remove"
- />
+ <icon :size="16" :aria-label="__('Delete')" name="remove" />
</button>
- <gl-loading-icon
- v-show="badge.isDeleting"
- :inline="true"
- />
+ <gl-loading-icon v-show="badge.isDeleting" :inline="true" />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/badges/components/badge_settings.vue b/app/assets/javascripts/badges/components/badge_settings.vue
index cc47e56dd1e..75a522efe7e 100644
--- a/app/assets/javascripts/badges/components/badge_settings.vue
+++ b/app/assets/javascripts/badges/components/badge_settings.vue
@@ -46,7 +46,8 @@ export default {
:header-title-text="s__('Badges|Delete badge?')"
:footer-primary-button-text="s__('Badges|Delete badge')"
footer-primary-button-variant="danger"
- @submit="onSubmitModal">
+ @submit="onSubmitModal"
+ >
<div class="well">
<badge
:image-url="badgeInModal ? badgeInModal.renderedImageUrl : ''"
@@ -56,15 +57,9 @@ export default {
<p v-html="deleteModalText"></p>
</gl-modal>
- <badge-form
- v-show="isEditing"
- :is-editing="true"
- />
+ <badge-form v-show="isEditing" :is-editing="true" />
- <badge-form
- v-show="!isEditing"
- :is-editing="false"
- />
+ <badge-form v-show="!isEditing" :is-editing="false" />
<badge-list v-show="!isEditing" />
</div>
</template>
diff --git a/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
index a303e504cc7..55c68139ded 100644
--- a/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
+++ b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
@@ -1,11 +1,11 @@
import $ from 'jquery';
-import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
+import { parseBoolean } from '~/lib/utils/common_utils';
import GfmAutoComplete from '~/gfm_auto_complete';
export default function initGFMInput() {
$('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
- const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
+ const enableGFM = parseBoolean(el.dataset.supportsAutocomplete);
gfm.setup($(el), {
emojis: true,
diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js
index a2d4331b6d1..fc9286d15e6 100644
--- a/app/assets/javascripts/behaviors/markdown/render_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js
@@ -3,6 +3,7 @@ import syntaxHighlight from '~/syntax_highlight';
import renderMath from './render_math';
import renderMermaid from './render_mermaid';
import highlightCurrentUser from './highlight_current_user';
+import initUserPopovers from '../../user_popovers';
// Render GitLab flavoured Markdown
//
@@ -13,6 +14,7 @@ $.fn.renderGFM = function renderGFM() {
renderMath(this.find('.js-render-math'));
renderMermaid(this.find('.js-render-mermaid'));
highlightCurrentUser(this.find('.gfm-project_member').get());
+ initUserPopovers(this.find('.gfm-project_member').get());
return this;
};
diff --git a/app/assets/javascripts/behaviors/markdown/render_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
index 720f30e18e6..35380ca49fb 100644
--- a/app/assets/javascripts/behaviors/markdown/render_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
@@ -26,6 +26,9 @@ export default function renderMermaid($els) {
},
// mermaidAPI options
theme: 'neutral',
+ flowchart: {
+ htmlLabels: false,
+ },
});
$els.each((i, el) => {
diff --git a/app/assets/javascripts/behaviors/requires_input.js b/app/assets/javascripts/behaviors/requires_input.js
index c09d9ccddd6..d8056e48d4e 100644
--- a/app/assets/javascripts/behaviors/requires_input.js
+++ b/app/assets/javascripts/behaviors/requires_input.js
@@ -50,10 +50,11 @@ function hideOrShowHelpBlock(form) {
}
$(() => {
- const $form = $('form.js-requires-input');
- if ($form) {
+ $('form.js-requires-input').each((i, el) => {
+ const $form = $(el);
+
$form.requiresInput();
hideOrShowHelpBlock($form);
$('.select2.js-select-namespace').change(() => hideOrShowHelpBlock($form));
- }
+ });
});
diff --git a/app/assets/javascripts/behaviors/secret_values.js b/app/assets/javascripts/behaviors/secret_values.js
index f6bf62d734e..5b92608d536 100644
--- a/app/assets/javascripts/behaviors/secret_values.js
+++ b/app/assets/javascripts/behaviors/secret_values.js
@@ -1,5 +1,5 @@
import { n__ } from '../locale';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
export default class SecretValues {
constructor({
@@ -16,7 +16,7 @@ export default class SecretValues {
this.revealButton = this.container.querySelector('.js-secret-value-reveal-button');
if (this.revealButton) {
- const isRevealed = convertPermissionToBoolean(this.revealButton.dataset.secretRevealStatus);
+ const isRevealed = parseBoolean(this.revealButton.dataset.secretRevealStatus);
this.updateDom(isRevealed);
this.revealButton.addEventListener('click', this.onRevealButtonClicked.bind(this));
@@ -24,9 +24,7 @@ export default class SecretValues {
}
onRevealButtonClicked() {
- const previousIsRevealed = convertPermissionToBoolean(
- this.revealButton.dataset.secretRevealStatus,
- );
+ const previousIsRevealed = parseBoolean(this.revealButton.dataset.secretRevealStatus);
this.updateDom(!previousIsRevealed);
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index 8b5a3c1c69d..eade1283513 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -4,6 +4,7 @@ import Mousetrap from 'mousetrap';
import axios from '../../lib/utils/axios_utils';
import { refreshCurrentPage, visitUrl } from '../../lib/utils/url_utility';
import findAndFollowLink from '../../lib/utils/navigation_utility';
+import { parseBoolean } from '~/lib/utils/common_utils';
const defaultStopCallback = Mousetrap.stopCallback;
Mousetrap.stopCallback = (e, element, combo) => {
@@ -61,7 +62,7 @@ export default class Shortcuts {
static onTogglePerfBar(e) {
e.preventDefault();
const performanceBarCookieName = 'perf_bar_enabled';
- if (Cookies.get(performanceBarCookieName) === 'true') {
+ if (parseBoolean(Cookies.get(performanceBarCookieName))) {
Cookies.set(performanceBarCookieName, 'false', { path: '/' });
} else {
Cookies.set(performanceBarCookieName, 'true', { path: '/' });
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
index 5e48bf5a35c..2918e1486a7 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
@@ -4,6 +4,7 @@ import _ from 'underscore';
import Sidebar from '../../right_sidebar';
import Shortcuts from './shortcuts';
import { CopyAsGFM } from '../markdown/copy_as_gfm';
+import { getSelectedFragment } from '~/lib/utils/common_utils';
export default class ShortcutsIssuable extends Shortcuts {
constructor(isMergeRequest) {
@@ -24,17 +25,43 @@ export default class ShortcutsIssuable extends Shortcuts {
static replyWithSelectedText() {
const $replyField = $('.js-main-target-form .js-vue-comment-form');
- const documentFragment = window.gl.utils.getSelectedFragment();
- if (!$replyField.length) {
+ if (!$replyField.length || $replyField.is(':hidden') /* Other tab selected in MR */) {
return false;
}
+ const documentFragment = getSelectedFragment(document.querySelector('#content-body'));
+
if (!documentFragment) {
$replyField.focus();
return false;
}
+ // Sanity check: Make sure the selected text comes from a discussion : it can either contain a message...
+ let foundMessage = !!documentFragment.querySelector('.md, .wiki');
+
+ // ... Or come from a message
+ if (!foundMessage) {
+ if (documentFragment.originalNodes) {
+ documentFragment.originalNodes.forEach(e => {
+ let node = e;
+ do {
+ // Text nodes don't define the `matches` method
+ if (node.matches && node.matches('.md, .wiki')) {
+ foundMessage = true;
+ }
+ node = node.parentNode;
+ } while (node && !foundMessage);
+ });
+ }
+
+ // If there is no message, just select the reply field
+ if (!foundMessage) {
+ $replyField.focus();
+ return false;
+ }
+ }
+
const el = CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true));
const selected = CopyAsGFM.nodeToGFM(el);
diff --git a/app/assets/javascripts/blob/file_template_mediator.js b/app/assets/javascripts/blob/file_template_mediator.js
index addacf29f1e..106fe2e0cef 100644
--- a/app/assets/javascripts/blob/file_template_mediator.js
+++ b/app/assets/javascripts/blob/file_template_mediator.js
@@ -124,7 +124,7 @@ export default class FileTemplateMediator {
selectTemplateFile(selector, query, data) {
selector.renderLoading();
- // in case undo menu is already already there
+ // in case undo menu is already there
this.destroyUndoMenu();
this.fetchFileTemplate(selector.config.type, query, data)
.then(file => {
diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js
index befa1dc455f..d0359fc5fe9 100644
--- a/app/assets/javascripts/blob/viewer/index.js
+++ b/app/assets/javascripts/blob/viewer/index.js
@@ -23,10 +23,12 @@ export default class BlobViewer {
if (!viewer || !viewer.dataset.richType) return;
const initViewer = promise =>
- promise.then(module => module.default(viewer)).catch(error => {
- Flash('Error loading file viewer.');
- throw error;
- });
+ promise
+ .then(module => module.default(viewer))
+ .catch(error => {
+ Flash('Error loading file viewer.');
+ throw error;
+ });
switch (viewer.dataset.richType) {
case 'balsamiq':
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index ec27ae8c291..9f547471170 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -16,9 +16,17 @@ export default () => {
const filePath = editBlobForm.data('blobFilename');
const currentAction = $('.js-file-title').data('currentAction');
const projectId = editBlobForm.data('project-id');
+ const commitButton = $('.js-commit-button');
+
+ commitButton.on('click', () => {
+ window.onbeforeunload = null;
+ });
new EditBlob(`${urlRoot}${assetsPath}`, filePath, currentAction, projectId);
new NewCommitForm(editBlobForm);
+
+ // returning here blocks page navigation
+ window.onbeforeunload = () => '';
}
if (uploadBlobForm.length) {
diff --git a/app/assets/javascripts/boards/components/board_blank_state.vue b/app/assets/javascripts/boards/components/board_blank_state.vue
index 561a4636ef5..667eea17d44 100644
--- a/app/assets/javascripts/boards/components/board_blank_state.vue
+++ b/app/assets/javascripts/boards/components/board_blank_state.vue
@@ -61,35 +61,25 @@ export default {
<template>
<div class="board-blank-state">
- <p>
- Add the following default lists to your Issue Board with one click:
- </p>
+ <p>Add the following default lists to your Issue Board with one click:</p>
<ul class="board-blank-state-list">
- <li
- v-for="(label, index) in predefinedLabels"
- :key="index"
- >
- <span
- :style="{ backgroundColor: label.color }"
- class="label-color">
- </span>
+ <li v-for="(label, index) in predefinedLabels" :key="index">
+ <span :style="{ backgroundColor: label.color }" class="label-color"> </span>
{{ label.title }}
</li>
</ul>
<p>
- Starting out with the default set of lists will get you
- right on the way to making the most of your board.
+ Starting out with the default set of lists will get you right on the way to making the most of
+ your board.
</p>
<button
class="btn btn-success btn-inverted btn-block"
type="button"
- @click.stop="addDefaultLists">
+ @click.stop="addDefaultLists"
+ >
Add default lists
</button>
- <button
- class="btn btn-default btn-block"
- type="button"
- @click.stop="clearBlankState">
+ <button class="btn btn-default btn-block" type="button" @click.stop="clearBlankState">
Nevermind, I'll use my own
</button>
</div>
diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue
index 2f31316aa76..30fbdb9e97f 100644
--- a/app/assets/javascripts/boards/components/board_card.vue
+++ b/app/assets/javascripts/boards/components/board_card.vue
@@ -79,14 +79,15 @@ export default {
:class="{
'user-can-drag': !disabled && issue.id,
'is-disabled': disabled || !issue.id,
- 'is-active': issueDetailVisible
+ 'is-active': issueDetailVisible,
}"
:index="index"
:data-issue-id="issue.id"
class="board-card"
@mousedown="mouseDown"
@mousemove="mouseMove"
- @mouseup="showIssue($event)">
+ @mouseup="showIssue($event);"
+ >
<issue-card-inner
:list="list"
:issue="issue"
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index 5e28fc396ab..f3f341ece5c 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -1,6 +1,6 @@
<script>
import Sortable from 'sortablejs';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import boardNewIssue from './board_new_issue.vue';
import boardCard from './board_card.vue';
import eventHub from '../eventhub';
@@ -222,23 +222,22 @@ export default {
<template>
<div class="board-list-component">
- <div
- v-if="loading"
- class="board-list-loading text-center"
- aria-label="Loading issues">
+ <div v-if="loading" class="board-list-loading text-center" aria-label="Loading issues">
<gl-loading-icon />
</div>
<board-new-issue
v-if="list.type !== 'closed' && showIssueForm"
:group-id="groupId"
- :list="list"/>
+ :list="list"
+ />
<ul
v-show="!loading"
ref="list"
:data-board="list.id"
:data-board-type="list.type"
:class="{ 'is-smaller': showIssueForm }"
- class="board-list js-board-list">
+ class="board-list js-board-list"
+ >
<board-card
v-for="(issue, index) in issues"
ref="issue"
@@ -249,25 +248,12 @@ export default {
:issue-link-base="issueLinkBase"
:group-id="groupId"
:root-path="rootPath"
- :disabled="disabled" />
- <li
- v-if="showCount"
- class="board-list-count text-center"
- data-issue-id="-1">
- <gl-loading-icon
- v-show="list.loadingMore"
- label="Loading more issues"
- />
- <span
- v-if="list.issues.length === list.issuesSize"
- >
- Showing all issues
- </span>
- <span
- v-else
- >
- Showing {{ list.issues.length }} of {{ list.issuesSize }} issues
- </span>
+ :disabled="disabled"
+ />
+ <li v-if="showCount" class="board-list-count text-center" data-issue-id="-1">
+ <gl-loading-icon v-show="list.loadingMore" label="Loading more issues" />
+ <span v-if="list.issues.length === list.issuesSize"> Showing all issues </span>
+ <span v-else> Showing {{ list.issues.length }} of {{ list.issuesSize }} issues </span>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue
index ee3dc38bca6..93bcb4e129e 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.vue
+++ b/app/assets/javascripts/boards/components/board_new_issue.vue
@@ -1,6 +1,6 @@
<script>
import $ from 'jquery';
-import { GlButton } from '@gitlab-org/gitlab-ui';
+import { GlButton } from '@gitlab/ui';
import eventHub from '../eventhub';
import ProjectSelect from './project_select.vue';
import ListIssue from '../models/issue';
@@ -96,21 +96,11 @@ export default {
<template>
<div class="board-new-issue-form">
<div class="board-card">
- <form @submit="submit($event)">
- <div
- v-if="error"
- class="flash-container"
- >
- <div class="flash-alert">
- An error occurred. Please try again.
- </div>
+ <form @submit="submit($event);">
+ <div v-if="error" class="flash-container">
+ <div class="flash-alert">An error occurred. Please try again.</div>
</div>
- <label
- :for="list.id + '-title'"
- class="label-bold"
- >
- Title
- </label>
+ <label :for="list.id + '-title'" class="label-bold"> Title </label>
<input
:id="list.id + '-title'"
ref="input"
@@ -120,10 +110,7 @@ export default {
name="issue_title"
autocomplete="off"
/>
- <project-select
- v-if="groupId"
- :group-id="groupId"
- />
+ <project-select v-if="groupId" :group-id="groupId" />
<div class="clearfix prepend-top-10">
<gl-button
ref="submit-button"
@@ -134,12 +121,7 @@ export default {
>
Submit issue
</gl-button>
- <gl-button
- class="float-right"
- type="button"
- variant="default"
- @click="cancel"
- >
+ <gl-button class="float-right" type="button" variant="default" @click="cancel">
Cancel
</gl-button>
</div>
diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue
index 2315a48a306..0f581c3d37d 100644
--- a/app/assets/javascripts/boards/components/issue_card_inner.vue
+++ b/app/assets/javascripts/boards/components/issue_card_inner.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import { sprintf, __ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
@@ -169,17 +169,12 @@ export default {
:title="__('Confidential')"
class="confidential-icon append-right-4"
:aria-label="__('Confidential')"
- /><a
- :href="issue.path"
- :title="issue.title"
- class="js-no-trigger"
- @mousemove.stop>{{ issue.title }}</a>
+ /><a :href="issue.path" :title="issue.title" class="js-no-trigger" @mousemove.stop>{{
+ issue.title
+ }}</a>
</h4>
</div>
- <div
- v-if="showLabelFooter"
- class="board-card-labels prepend-top-4 d-flex flex-wrap"
- >
+ <div v-if="showLabelFooter" class="board-card-labels prepend-top-4 d-flex flex-wrap">
<button
v-for="label in issue.labels"
v-if="showLabel(label)"
@@ -189,13 +184,15 @@ export default {
:title="label.description"
class="badge color-label append-right-4 prepend-top-4"
type="button"
- @click="filterByLabel(label)"
+ @click="filterByLabel(label);"
>
{{ label.title }}
</button>
</div>
<div class="board-card-footer d-flex justify-content-between align-items-end">
- <div class="d-flex align-items-start flex-wrap-reverse board-card-number-container js-board-card-number-container">
+ <div
+ class="d-flex align-items-start flex-wrap-reverse board-card-number-container js-board-card-number-container"
+ >
<span
v-if="issue.referencePath"
class="board-card-number d-flex append-right-8 prepend-top-8"
@@ -205,13 +202,11 @@ export default {
:title="issueReferencePath"
placement="bottom"
class="board-issue-path block-truncated bold"
- >{{ issueReferencePath }}</tooltip-on-truncate>#{{ issue.iid }}
+ >{{ issueReferencePath }}</tooltip-on-truncate
+ >#{{ issue.iid }}
</span>
<span class="board-info-items prepend-top-8 d-inline-block">
- <issue-due-date
- v-if="issue.dueDate"
- :date="issue.dueDate"
- /><issue-time-estimate
+ <issue-due-date v-if="issue.dueDate" :date="issue.dueDate" /><issue-time-estimate
v-if="issue.timeEstimate"
:estimate="issue.timeEstimate"
/>
@@ -230,8 +225,7 @@ export default {
tooltip-placement="bottom"
>
<span class="js-assignee-tooltip">
- <span class="bold d-block">Assignee</span>
- {{ assignee.name }}
+ <span class="bold d-block">Assignee</span> {{ assignee.name }}
<span class="text-white-50">@{{ assignee.username }}</span>
</span>
</user-avatar-link>
diff --git a/app/assets/javascripts/boards/components/issue_due_date.vue b/app/assets/javascripts/boards/components/issue_due_date.vue
index 025ef7e9743..e038198e6f0 100644
--- a/app/assets/javascripts/boards/components/issue_due_date.vue
+++ b/app/assets/javascripts/boards/components/issue_due_date.vue
@@ -1,6 +1,6 @@
<script>
import dateFormat from 'dateformat';
-import { GlTooltip } from '@gitlab-org/gitlab-ui';
+import { GlTooltip } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { __ } from '~/locale';
import { getDayDifference, getTimeago, dateInWords } from '~/lib/utils/datetime_utility';
@@ -15,6 +15,16 @@ export default {
type: String,
required: true,
},
+ cssClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ tooltipPlacement: {
+ type: String,
+ required: false,
+ default: 'bottom',
+ },
},
computed: {
title() {
@@ -66,25 +76,15 @@ export default {
<template>
<span>
- <span
- ref="issueDueDate"
- class="board-card-info card-number"
- >
- <icon
- :class="{'text-danger': isPastDue, 'board-card-info-icon': true}"
- name="calendar"
- /><time
- :class="{'text-danger': isPastDue}"
- datetime="date"
- class="board-card-info-text">{{ body }}</time>
+ <span ref="issueDueDate" :class="cssClass" class="board-card-info card-number">
+ <icon :class="{ 'text-danger': isPastDue, 'board-card-info-icon': true }" name="calendar" />
+ <time :class="{ 'text-danger': isPastDue }" datetime="date" class="board-card-info-text">{{
+ body
+ }}</time>
</span>
- <gl-tooltip
- :target="() => $refs.issueDueDate"
- placement="bottom"
- >
- <span class="bold">{{ __('Due date') }}</span>
- <br />
- <span :class="{'text-danger-muted': isPastDue}">{{ title }}</span>
+ <gl-tooltip :target="() => $refs.issueDueDate" :placement="tooltipPlacement">
+ <span class="bold">{{ __('Due date') }}</span> <br />
+ <span :class="{ 'text-danger-muted': isPastDue }">{{ title }}</span>
</gl-tooltip>
</span>
</template>
diff --git a/app/assets/javascripts/boards/components/issue_time_estimate.vue b/app/assets/javascripts/boards/components/issue_time_estimate.vue
index efc7daf7812..5acc3025b2c 100644
--- a/app/assets/javascripts/boards/components/issue_time_estimate.vue
+++ b/app/assets/javascripts/boards/components/issue_time_estimate.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltip } from '@gitlab-org/gitlab-ui';
+import { GlTooltip } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
@@ -27,22 +27,18 @@ export default {
<template>
<span>
- <span
- ref="issueTimeEstimate"
- class="board-card-info card-number"
- >
- <icon
- name="hourglass"
- css-classes="board-card-info-icon"
- /><time class="board-card-info-text">{{ timeEstimate }}</time>
+ <span ref="issueTimeEstimate" class="board-card-info card-number">
+ <icon name="hourglass" css-classes="board-card-info-icon" /><time
+ class="board-card-info-text"
+ >{{ timeEstimate }}</time
+ >
</span>
<gl-tooltip
:target="() => $refs.issueTimeEstimate"
placement="bottom"
class="js-issue-time-estimate"
>
- <span class="bold d-block">{{ __('Time estimate') }}</span>
- {{ title }}
+ <span class="bold d-block">{{ __('Time estimate') }}</span> {{ title }}
</gl-tooltip>
</span>
</template>
diff --git a/app/assets/javascripts/boards/components/modal/empty_state.vue b/app/assets/javascripts/boards/components/modal/empty_state.vue
index 795ba864545..08408eb0b52 100644
--- a/app/assets/javascripts/boards/components/modal/empty_state.vue
+++ b/app/assets/javascripts/boards/components/modal/empty_state.vue
@@ -45,24 +45,20 @@ export default {
<section class="empty-state">
<div class="row">
<div class="col-12 col-md-6 order-md-last">
- <aside class="svg-content"><img :src="emptyStateSvg"/></aside>
+ <aside class="svg-content"><img :src="emptyStateSvg" /></aside>
</div>
<div class="col-12 col-md-6 order-md-first">
<div class="text-content">
<h4>{{ contents.title }}</h4>
<p v-html="contents.content"></p>
- <a
- v-if="activeTab === 'all'"
- :href="newIssuePath"
- class="btn btn-success btn-inverted"
- >
+ <a v-if="activeTab === 'all'" :href="newIssuePath" class="btn btn-success btn-inverted">
New issue
</a>
<button
v-if="activeTab === 'selected'"
class="btn btn-default"
type="button"
- @click="changeTab('all')"
+ @click="changeTab('all');"
>
Open issues
</button>
diff --git a/app/assets/javascripts/boards/components/modal/footer.vue b/app/assets/javascripts/boards/components/modal/footer.vue
index d51597ed22d..b1bc7d87086 100644
--- a/app/assets/javascripts/boards/components/modal/footer.vue
+++ b/app/assets/javascripts/boards/components/modal/footer.vue
@@ -63,28 +63,15 @@ export default {
};
</script>
<template>
- <footer
- class="form-actions add-issues-footer"
- >
+ <footer class="form-actions add-issues-footer">
<div class="float-left">
- <button
- :disabled="submitDisabled"
- class="btn btn-success"
- type="button"
- @click="addIssues"
- >
+ <button :disabled="submitDisabled" class="btn btn-success" type="button" @click="addIssues">
{{ submitText }}
</button>
- <span class="inline add-issues-footer-to-list">
- to list
- </span>
- <lists-dropdown/>
+ <span class="inline add-issues-footer-to-list"> to list </span>
+ <lists-dropdown />
</div>
- <button
- class="btn btn-default float-right"
- type="button"
- @click="toggleModal(false)"
- >
+ <button class="btn btn-default float-right" type="button" @click="toggleModal(false);">
Cancel
</button>
</footer>
diff --git a/app/assets/javascripts/boards/components/modal/header.vue b/app/assets/javascripts/boards/components/modal/header.vue
index fc6cefa89a9..d0e285a149e 100644
--- a/app/assets/javascripts/boards/components/modal/header.vue
+++ b/app/assets/javascripts/boards/components/modal/header.vue
@@ -58,16 +58,14 @@ export default {
class="close"
data-dismiss="modal"
aria-label="Close"
- @click="toggleModal(false)"
+ @click="toggleModal(false);"
>
<span aria-hidden="true">×</span>
</button>
</h2>
</header>
- <modal-tabs v-if="!loading && issuesCount > 0"/>
- <div
- v-if="showSearch"
- class="add-issues-search append-bottom-10">
+ <modal-tabs v-if="!loading && issuesCount > 0" />
+ <div v-if="showSearch" class="add-issues-search append-bottom-10">
<modal-filters :store="filter" />
<button
ref="selectAllBtn"
diff --git a/app/assets/javascripts/boards/components/modal/index.vue b/app/assets/javascripts/boards/components/modal/index.vue
index fdd1346d4c7..1e5761cf268 100644
--- a/app/assets/javascripts/boards/components/modal/index.vue
+++ b/app/assets/javascripts/boards/components/modal/index.vue
@@ -6,7 +6,7 @@ import ModalList from './list.vue';
import ModalFooter from './footer.vue';
import EmptyState from './empty_state.vue';
import ModalStore from '../../stores/modal_store';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
@@ -143,9 +143,7 @@ export default {
};
</script>
<template>
- <div
- v-if="showAddIssuesModal"
- class="add-issues-modal">
+ <div v-if="showAddIssuesModal" class="add-issues-modal">
<div class="add-issues-container">
<modal-header
:project-id="projectId"
@@ -163,15 +161,10 @@ export default {
:new-issue-path="newIssuePath"
:empty-state-svg="emptyStateSvg"
/>
- <section
- v-if="loading || filterLoading"
- class="add-issues-list text-center"
- >
- <div class="add-issues-list-loading">
- <gl-loading-icon />
- </div>
+ <section v-if="loading || filterLoading" class="add-issues-list text-center">
+ <div class="add-issues-list-loading"><gl-loading-icon /></div>
</section>
- <modal-footer/>
+ <modal-footer />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/boards/components/modal/list.vue b/app/assets/javascripts/boards/components/modal/list.vue
index e11f398e70d..878bb002c6c 100644
--- a/app/assets/javascripts/boards/components/modal/list.vue
+++ b/app/assets/javascripts/boards/components/modal/list.vue
@@ -117,38 +117,22 @@ export default {
};
</script>
<template>
- <section
- ref="list"
- class="add-issues-list add-issues-list-columns">
+ <section ref="list" class="add-issues-list add-issues-list-columns">
<div
v-if="issuesCount > 0 && issues.length === 0"
- class="empty-state add-issues-empty-state-filter text-center">
- <div class="svg-content">
- <img :src="emptyStateSvg" />
- </div>
- <div class="text-content">
- <h4>
- There are no issues to show.
- </h4>
- </div>
+ class="empty-state add-issues-empty-state-filter text-center"
+ >
+ <div class="svg-content"><img :src="emptyStateSvg" /></div>
+ <div class="text-content"><h4>There are no issues to show.</h4></div>
</div>
- <div
- v-for="(group, index) in groupedIssues"
- :key="index"
- class="add-issues-list-column">
- <div
- v-for="issue in group"
- v-if="showIssue(issue)"
- :key="issue.id"
- class="board-card-parent">
+ <div v-for="(group, index) in groupedIssues" :key="index" class="add-issues-list-column">
+ <div v-for="issue in group" v-if="showIssue(issue)" :key="issue.id" class="board-card-parent">
<div
:class="{ 'is-active': issue.selected }"
class="board-card"
- @click="toggleIssue($event, issue)">
- <issue-card-inner
- :issue="issue"
- :issue-link-base="issueLinkBase"
- :root-path="rootPath"/>
+ @click="toggleIssue($event, issue);"
+ >
+ <issue-card-inner :issue="issue" :issue-link-base="issueLinkBase" :root-path="rootPath" />
<icon
v-if="issue.selected"
:aria-label="'Issue #' + issue.id + ' selected'"
diff --git a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue
index 20665f903d5..820d0679df5 100644
--- a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue
+++ b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import ModalStore from '../../stores/modal_store';
import boardsStore from '../../stores/boards_store';
@@ -27,35 +27,20 @@ export default {
</script>
<template>
<div class="dropdown inline">
- <button
- class="dropdown-menu-toggle"
- type="button"
- data-toggle="dropdown"
- aria-expanded="false">
- <span
- :style="{ backgroundColor: selected.label.color }"
- class="dropdown-label-box">
- </span>
- {{ selected.title }}
- <icon
- name="chevron-down"
- />
+ <button class="dropdown-menu-toggle" type="button" data-toggle="dropdown" aria-expanded="false">
+ <span :style="{ backgroundColor: selected.label.color }" class="dropdown-label-box"> </span>
+ {{ selected.title }} <icon name="chevron-down" />
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-drop-up">
<ul>
- <li
- v-for="(list, i) in state.lists"
- v-if="list.type == 'label'"
- :key="i">
+ <li v-for="(list, i) in state.lists" v-if="list.type == 'label'" :key="i">
<gl-link
:class="{ 'is-active': list.id == selected.id }"
href="#"
role="button"
- @click.prevent="modal.selectedList = list">
- <span
- :style="{ backgroundColor: list.label.color }"
- class="dropdown-label-box">
- </span>
+ @click.prevent="modal.selectedList = list;"
+ >
+ <span :style="{ backgroundColor: list.label.color }" class="dropdown-label-box"> </span>
{{ list.title }}
</gl-link>
</li>
diff --git a/app/assets/javascripts/boards/components/modal/tabs.vue b/app/assets/javascripts/boards/components/modal/tabs.vue
index 5d661590e8e..7b800a6ab97 100644
--- a/app/assets/javascripts/boards/components/modal/tabs.vue
+++ b/app/assets/javascripts/boards/components/modal/tabs.vue
@@ -20,28 +20,14 @@ export default {
<template>
<div class="top-area prepend-top-10 append-bottom-10">
<ul class="nav-links issues-state-filters">
- <li :class="{ 'active': activeTab == 'all' }">
- <a
- href="#"
- role="button"
- @click.prevent="changeTab('all')"
- >
- Open issues
- <span class="badge badge-pill">
- {{ issuesCount }}
- </span>
+ <li :class="{ active: activeTab == 'all' }">
+ <a href="#" role="button" @click.prevent="changeTab('all');">
+ Open issues <span class="badge badge-pill"> {{ issuesCount }} </span>
</a>
</li>
- <li :class="{ 'active': activeTab == 'selected' }">
- <a
- href="#"
- role="button"
- @click.prevent="changeTab('selected')"
- >
- Selected issues
- <span class="badge badge-pill">
- {{ selectedCount }}
- </span>
+ <li :class="{ active: activeTab == 'selected' }">
+ <a href="#" role="button" @click.prevent="changeTab('selected');">
+ Selected issues <span class="badge badge-pill"> {{ selectedCount }} </span>
</a>
</li>
</ul>
diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue
index 503417644fa..d899b7fbd8c 100644
--- a/app/assets/javascripts/boards/components/project_select.vue
+++ b/app/assets/javascripts/boards/components/project_select.vue
@@ -2,7 +2,7 @@
import $ from 'jquery';
import _ from 'underscore';
import Icon from '~/vue_shared/components/icon.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../eventhub';
import Api from '../../api';
@@ -48,10 +48,19 @@ export default {
selectable: true,
data: (term, callback) => {
this.loading = true;
- return Api.groupProjects(this.groupId, term, { with_issues_enabled: true }, projects => {
- this.loading = false;
- callback(projects);
- });
+ return Api.groupProjects(
+ this.groupId,
+ term,
+ {
+ with_issues_enabled: true,
+ with_shared: false,
+ include_subgroups: true,
+ },
+ projects => {
+ this.loading = false;
+ callback(projects);
+ },
+ );
},
renderRow(project) {
return `
@@ -72,55 +81,24 @@ export default {
<template>
<div>
- <label class="label-bold prepend-top-10">
- Project
- </label>
- <div
- ref="projectsDropdown"
- class="dropdown"
- >
+ <label class="label-bold prepend-top-10"> Project </label>
+ <div ref="projectsDropdown" class="dropdown">
<button
class="dropdown-menu-toggle wide"
type="button"
data-toggle="dropdown"
aria-expanded="false"
>
- {{ selectedProjectName }}
- <icon
- name="chevron-down"
- />
+ {{ selectedProjectName }} <icon name="chevron-down" />
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-full-width">
- <div class="dropdown-title">
- <span>Projects</span>
- <button
- aria-label="Close"
- type="button"
- class="dropdown-title-button dropdown-menu-close"
- >
- <icon
- name="merge-request-close-m"
- data-hidden="true"
- class="dropdown-menu-close-icon"
- />
- </button>
- </div>
+ <div class="dropdown-title">Projects</div>
<div class="dropdown-input">
- <input
- class="dropdown-input-field"
- type="search"
- placeholder="Search projects"
- />
- <icon
- name="search"
- class="dropdown-input-search"
- data-hidden="true"
- />
+ <input class="dropdown-input-field" type="search" placeholder="Search projects" />
+ <icon name="search" class="dropdown-input-search" data-hidden="true" />
</div>
<div class="dropdown-content"></div>
- <div class="dropdown-loading">
- <gl-loading-icon />
- </div>
+ <div class="dropdown-loading"><gl-loading-icon /></div>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/boards/components/sidebar/remove_issue.vue b/app/assets/javascripts/boards/components/sidebar/remove_issue.vue
index d681e6a431c..a2b8a0af236 100644
--- a/app/assets/javascripts/boards/components/sidebar/remove_issue.vue
+++ b/app/assets/javascripts/boards/components/sidebar/remove_issue.vue
@@ -74,14 +74,8 @@ export default Vue.extend({
});
</script>
<template>
- <div
- class="block list"
- >
- <button
- class="btn btn-default btn-block"
- type="button"
- @click="removeIssue"
- >
+ <div class="block list">
+ <button class="btn btn-default btn-block" type="button" @click="removeIssue">
Remove from board
</button>
</div>
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index 61a3072ac27..f88e9b55988 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -24,7 +24,7 @@ import BoardSidebar from './components/board_sidebar';
import initNewListDropdown from './components/new_list_dropdown';
import BoardAddIssuesModal from './components/modal/index.vue';
import '~/vue_shared/vue_resource_interceptor';
-import { NavigationType } from '~/lib/utils/common_utils';
+import { NavigationType, parseBoolean } from '~/lib/utils/common_utils';
let issueBoardsApp;
@@ -60,7 +60,7 @@ export default () => {
boardsEndpoint: $boardApp.dataset.boardsEndpoint,
listsEndpoint: $boardApp.dataset.listsEndpoint,
boardId: $boardApp.dataset.boardId,
- disabled: $boardApp.dataset.disabled === 'true',
+ disabled: parseBoolean($boardApp.dataset.disabled),
issueLinkBase: $boardApp.dataset.issueLinkBase,
rootPath: $boardApp.dataset.rootPath,
bulkUpdatePath: $boardApp.dataset.bulkUpdatePath,
diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js
index eefe14a1d79..cf88a973d33 100644
--- a/app/assets/javascripts/boards/stores/boards_store.js
+++ b/app/assets/javascripts/boards/stores/boards_store.js
@@ -5,7 +5,7 @@ import $ from 'jquery';
import _ from 'underscore';
import Vue from 'vue';
import Cookies from 'js-cookie';
-import { getUrlParamsArray } from '~/lib/utils/common_utils';
+import { getUrlParamsArray, parseBoolean } from '~/lib/utils/common_utils';
const boardsStore = {
disabled: false,
@@ -78,7 +78,7 @@ const boardsStore = {
});
},
welcomeIsHidden() {
- return Cookies.get('issue_board_welcome_hidden') === 'true';
+ return parseBoolean(Cookies.get('issue_board_welcome_hidden'));
},
removeList(id, type = 'blank') {
const list = this.findList('id', id, type);
diff --git a/app/assets/javascripts/build_artifacts.js b/app/assets/javascripts/build_artifacts.js
index 97a1645aa51..b2c88e8c14e 100644
--- a/app/assets/javascripts/build_artifacts.js
+++ b/app/assets/javascripts/build_artifacts.js
@@ -2,7 +2,7 @@
import $ from 'jquery';
import { visitUrl } from './lib/utils/url_utility';
-import { convertPermissionToBoolean } from './lib/utils/common_utils';
+import { parseBoolean } from './lib/utils/common_utils';
export default class BuildArtifacts {
constructor() {
@@ -22,7 +22,7 @@ export default class BuildArtifacts {
// eslint-disable-next-line class-methods-use-this
setupEntryClick() {
return $('.tree-holder').on('click', 'tr[data-link]', function() {
- visitUrl(this.dataset.link, convertPermissionToBoolean(this.dataset.externalLink));
+ visitUrl(this.dataset.link, parseBoolean(this.dataset.externalLink));
});
}
// eslint-disable-next-line class-methods-use-this
diff --git a/app/assets/javascripts/ci_variable_list/ajax_variable_list.js b/app/assets/javascripts/ci_variable_list/ajax_variable_list.js
index c7a917457f3..592e1fd1c31 100644
--- a/app/assets/javascripts/ci_variable_list/ajax_variable_list.js
+++ b/app/assets/javascripts/ci_variable_list/ajax_variable_list.js
@@ -2,7 +2,7 @@ import _ from 'underscore';
import axios from '../lib/utils/axios_utils';
import { s__ } from '../locale';
import Flash from '../flash';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
import statusCodes from '../lib/utils/http_status';
import VariableList from './ci_variable_list';
@@ -84,7 +84,7 @@ export default class AjaxVariableList {
.catch(() => {
loadingIcon.classList.toggle('hide', true);
this.variableList.toggleEnableRow(true);
- Flash(s__('CiVariable|Error occured while saving variables'));
+ Flash(s__('CiVariable|Error occurred while saving variables'));
});
}
@@ -101,7 +101,7 @@ export default class AjaxVariableList {
// If we submitted a row that was destroyed, remove it so we don't try
// to destroy it again which would cause a BE error
const destroyInput = row.querySelector('.js-ci-variable-input-destroy');
- if (convertPermissionToBoolean(destroyInput.value)) {
+ if (parseBoolean(destroyInput.value)) {
row.remove();
// Update the ID input so any future edits and `_destroy` will apply on the BE
} else {
diff --git a/app/assets/javascripts/ci_variable_list/ci_variable_list.js b/app/assets/javascripts/ci_variable_list/ci_variable_list.js
index 7bdc18ce03e..ee0f7cda189 100644
--- a/app/assets/javascripts/ci_variable_list/ci_variable_list.js
+++ b/app/assets/javascripts/ci_variable_list/ci_variable_list.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
import { s__ } from '../locale';
import setupToggleButtons from '../toggle_buttons';
import CreateItemDropdown from '../create_item_dropdown';
@@ -150,7 +150,7 @@ export default class VariableList {
removeRow(row) {
const $row = $(row);
- const isPersisted = convertPermissionToBoolean($row.attr('data-is-persisted'));
+ const isPersisted = parseBoolean($row.attr('data-is-persisted'));
if (isPersisted) {
$row.hide();
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 71fc2ac7d80..cf70a48f076 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -26,6 +26,7 @@ export default class Clusters {
statusPath,
installHelmPath,
installIngressPath,
+ installCertManagerPath,
installRunnerPath,
installJupyterPath,
installKnativePath,
@@ -48,6 +49,7 @@ export default class Clusters {
endpoint: statusPath,
installHelmEndpoint: installHelmPath,
installIngressEndpoint: installIngressPath,
+ installCertManagerEndpoint: installCertManagerPath,
installRunnerEndpoint: installRunnerPath,
installPrometheusEndpoint: installPrometheusPath,
installJupyterEndpoint: installJupyterPath,
diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue
index 236bb1394c8..d4354dcfebd 100644
--- a/app/assets/javascripts/clusters/components/application_row.vue
+++ b/app/assets/javascripts/clusters/components/application_row.vue
@@ -164,35 +164,21 @@ export default {
:class="[
rowJsClass,
isInstalled && 'cluster-application-installed',
- disabled && 'cluster-application-disabled'
+ disabled && 'cluster-application-disabled',
]"
class="cluster-application-row gl-responsive-table-row gl-responsive-table-row-col-span"
>
- <div
- class="gl-responsive-table-row-layout"
- role="row"
- >
- <div
- class="table-section append-right-8 section-align-top"
- role="gridcell"
- >
+ <div class="gl-responsive-table-row-layout" role="row">
+ <div class="table-section append-right-8 section-align-top" role="gridcell">
<img
v-if="hasLogo"
:src="logoUrl"
:alt="`${title} logo`"
class="cluster-application-logo avatar s40"
/>
- <identicon
- v-else
- :entity-id="identiconId"
- :entity-name="title"
- size-class="s40"
- />
+ <identicon v-else :entity-id="identiconId" :entity-name="title" size-class="s40" />
</div>
- <div
- class="table-section cluster-application-description section-wrap"
- role="gridcell"
- >
+ <div class="table-section cluster-application-description section-wrap" role="gridcell">
<strong>
<a
v-if="titleLink"
@@ -203,12 +189,7 @@ export default {
>
{{ title }}
</a>
- <span
- v-else
- class="js-cluster-application-title"
- >
- {{ title }}
- </span>
+ <span v-else class="js-cluster-application-title"> {{ title }} </span>
</strong>
<slot name="description"></slot>
<div
@@ -219,16 +200,10 @@ export default {
{{ generalErrorDescription }}
</p>
<ul v-if="statusReason || requestReason">
- <li
- v-if="statusReason"
- class="js-cluster-application-status-error-message"
- >
+ <li v-if="statusReason" class="js-cluster-application-status-error-message">
{{ statusReason }}
</li>
- <li
- v-if="requestReason"
- class="js-cluster-application-request-error-message"
- >
+ <li v-if="requestReason" class="js-cluster-application-request-error-message">
{{ requestReason }}
</li>
</ul>
@@ -239,15 +214,8 @@ export default {
class="table-section table-button-footer section-align-top"
role="gridcell"
>
- <div
- v-if="showManageButton"
- class="btn-group table-action-buttons"
- >
- <a
- :href="manageLink"
- :class="{ disabled: disabled }"
- class="btn"
- >
+ <div v-if="showManageButton" class="btn-group table-action-buttons">
+ <a :href="manageLink" :class="{ disabled: disabled }" class="btn">
{{ manageButtonLabel }}
</a>
</div>
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index c1026d1273a..489615f1f78 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -7,6 +7,7 @@ import helmLogo from 'images/cluster_app_logos/helm.png';
import jeagerLogo from 'images/cluster_app_logos/jeager.png';
import jupyterhubLogo from 'images/cluster_app_logos/jupyterhub.png';
import kubernetesLogo from 'images/cluster_app_logos/kubernetes.png';
+import certManagerLogo from 'images/cluster_app_logos/cert_manager.png';
import knativeLogo from 'images/cluster_app_logos/knative.png';
import meltanoLogo from 'images/cluster_app_logos/meltano.png';
import prometheusLogo from 'images/cluster_app_logos/prometheus.png';
@@ -59,6 +60,7 @@ export default {
jeagerLogo,
jupyterhubLogo,
kubernetesLogo,
+ certManagerLogo,
knativeLogo,
meltanoLogo,
prometheusLogo,
@@ -82,6 +84,9 @@ export default {
ingressExternalIp() {
return this.applications.ingress.externalIp;
},
+ certManagerInstalled() {
+ return this.applications.cert_manager.status === APPLICATION_STATUS.INSTALLED;
+ },
ingressDescription() {
const extraCostParagraph = sprintf(
_.escape(
@@ -124,6 +129,23 @@ export default {
</p>
`;
},
+ certManagerDescription() {
+ return sprintf(
+ _.escape(
+ s__(
+ `ClusterIntegration|Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates.
+ Installing Cert-Manager on your cluster will issue a certificate by %{letsEncrypt} and ensure that certificates
+ are valid and up-to-date.`,
+ ),
+ ),
+ {
+ letsEncrypt: `<a href="https://letsencrypt.org/"
+ target="_blank" rel="noopener noreferrer">
+ ${_.escape(s__("ClusterIntegration|Let's Encrypt"))}</a>`,
+ },
+ false,
+ );
+ },
prometheusDescription() {
return sprintf(
_.escape(
@@ -149,6 +171,9 @@ export default {
knativeInstalled() {
return this.applications.knative.status === APPLICATION_STATUS.INSTALLED;
},
+ knativeExternalIp() {
+ return this.applications.knative.externalIp;
+ },
},
created() {
this.helmInstallIllustration = helmInstallIllustration;
@@ -158,15 +183,13 @@ export default {
<template>
<section id="cluster-applications">
- <h4>
- {{ s__('ClusterIntegration|Applications') }}
- </h4>
+ <h4>{{ s__('ClusterIntegration|Applications') }}</h4>
<p class="append-bottom-0">
- {{ s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster.
- Helm Tiller is required to install any of the following applications.`) }}
- <a :href="helpPath">
- {{ __('More information') }}
- </a>
+ {{
+ s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster.
+ Helm Tiller is required to install any of the following applications.`)
+ }}
+ <a :href="helpPath"> {{ __('More information') }} </a>
</p>
<div class="cluster-application-list prepend-top-10">
@@ -182,23 +205,20 @@ export default {
title-link="https://docs.helm.sh/"
>
<div slot="description">
- {{ s__(`ClusterIntegration|Helm streamlines installing
+ {{
+ s__(`ClusterIntegration|Helm streamlines installing
and managing Kubernetes applications.
Tiller runs inside of your Kubernetes Cluster,
- and manages releases of your charts.`) }}
+ and manages releases of your charts.`)
+ }}
</div>
</application-row>
- <div
- v-show="!helmInstalled"
- class="cluster-application-warning"
- >
- <div
- class="svg-container"
- v-html="helmInstallIllustration"
- >
- </div>
- {{ s__(`ClusterIntegration|You must first install Helm Tiller before
- installing the applications below`) }}
+ <div v-show="!helmInstalled" class="cluster-application-warning">
+ <div class="svg-container" v-html="helmInstallIllustration"></div>
+ {{
+ s__(`ClusterIntegration|You must first install Helm Tiller before
+ installing the applications below`)
+ }}
</div>
<application-row
:id="ingressId"
@@ -213,9 +233,11 @@ export default {
>
<div slot="description">
<p>
- {{ s__(`ClusterIntegration|Ingress gives you a way to route
+ {{
+ s__(`ClusterIntegration|Ingress gives you a way to route
requests to services based on the request host or path,
- centralizing a number of services into a single entrypoint.`) }}
+ centralizing a number of services into a single entrypoint.`)
+ }}
</p>
<template v-if="ingressInstalled">
@@ -223,10 +245,7 @@ export default {
<label for="ingress-ip-address">
{{ s__('ClusterIntegration|Ingress IP Address') }}
</label>
- <div
- v-if="ingressExternalIp"
- class="input-group"
- >
+ <div v-if="ingressExternalIp" class="input-group">
<input
id="ingress-ip-address"
:value="ingressExternalIp"
@@ -242,53 +261,79 @@ export default {
/>
</span>
</div>
- <input
- v-else
- type="text"
- class="form-control js-ip-address"
- readonly
- value="?"
- />
+ <input v-else type="text" class="form-control js-ip-address" readonly value="?" />
+ <p class="form-text text-muted">
+ {{
+ s__(`ClusterIntegration|Point a wildcard DNS to this
+ generated IP address in order to access
+ your application after it has been deployed.`)
+ }}
+ <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
+ {{ __('More information') }}
+ </a>
+ </p>
</div>
- <p
- v-if="!ingressExternalIp"
- class="settings-message js-no-ip-message"
- >
- {{ s__(`ClusterIntegration|The IP address is in
+ <p v-if="!ingressExternalIp" class="settings-message js-no-ip-message">
+ {{
+ s__(`ClusterIntegration|The IP address is in
the process of being assigned. Please check your Kubernetes
- cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) }}
+ cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
+ }}
- <a
- :href="ingressHelpPath"
- target="_blank"
- rel="noopener noreferrer"
- >
+ <a :href="ingressHelpPath" target="_blank" rel="noopener noreferrer">
{{ __('More information') }}
</a>
</p>
-
- <p>
- {{ s__(`ClusterIntegration|Point a wildcard DNS to this
- generated IP address in order to access
- your application after it has been deployed.`) }}
- <a
- :href="ingressDnsHelpPath"
- target="_blank"
- rel="noopener noreferrer"
- >
- {{ __('More information') }}
- </a>
- </p>
-
</template>
- <div
- v-html="ingressDescription"
- >
- </div>
+ <div v-html="ingressDescription"></div>
</div>
</application-row>
<application-row
+ id="cert_manager"
+ :logo-url="certManagerLogo"
+ :title="applications.cert_manager.title"
+ :status="applications.cert_manager.status"
+ :status-reason="applications.cert_manager.statusReason"
+ :request-status="applications.cert_manager.requestStatus"
+ :request-reason="applications.cert_manager.requestReason"
+ :install-application-request-params="{ email: applications.cert_manager.email }"
+ :disabled="!helmInstalled"
+ title-link="https://cert-manager.readthedocs.io/en/latest/#"
+ >
+ <template>
+ <div slot="description">
+ <p v-html="certManagerDescription"></p>
+ <div class="form-group">
+ <label for="cert-manager-issuer-email">
+ {{ s__('ClusterIntegration|Issuer Email') }}
+ </label>
+ <div class="input-group">
+ <input
+ v-model="applications.cert_manager.email"
+ :readonly="certManagerInstalled"
+ type="text"
+ class="form-control js-email"
+ />
+ </div>
+ <p class="form-text text-muted">
+ {{
+ s__(`ClusterIntegration|Issuers represent a certificate authority.
+ You must provide an email address for your Issuer. `)
+ }}
+ <a
+ href="http://docs.cert-manager.io/en/latest/reference/issuers.html?highlight=email"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ {{ __('More information') }}
+ </a>
+ </p>
+ </div>
+ </div>
+ </template>
+ </application-row>
+ <application-row
v-if="isProjectCluster"
id="prometheus"
:logo-url="prometheusLogo"
@@ -301,11 +346,7 @@ export default {
:disabled="!helmInstalled"
title-link="https://prometheus.io/docs/introduction/overview/"
>
- <div
- slot="description"
- v-html="prometheusDescription"
- >
- </div>
+ <div slot="description" v-html="prometheusDescription"></div>
</application-row>
<application-row
v-if="isProjectCluster"
@@ -320,10 +361,12 @@ export default {
title-link="https://docs.gitlab.com/runner/"
>
<div slot="description">
- {{ s__(`ClusterIntegration|GitLab Runner connects to this
+ {{
+ s__(`ClusterIntegration|GitLab Runner connects to this
project's repository and executes CI/CD jobs,
pushing results back and deploying,
- applications to production.`) }}
+ applications to production.`)
+ }}
</div>
</application-row>
<application-row
@@ -341,11 +384,13 @@ export default {
>
<div slot="description">
<p>
- {{ s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns,
+ {{
+ s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns,
manages, and proxies multiple instances of the single-user
Jupyter notebook server. JupyterHub can be used to serve
notebooks to a class of students, a corporate data science group,
- or a scientific research group.`) }}
+ or a scientific research group.`)
+ }}
</p>
<template v-if="ingressExternalIp">
@@ -361,9 +406,7 @@ export default {
type="text"
class="form-control js-hostname"
/>
- <span
- class="input-group-btn"
- >
+ <span class="input-group-btn">
<clipboard-button
:text="jupyterHostname"
:title="s__('ClusterIntegration|Copy Jupyter Hostname to clipboard')"
@@ -371,22 +414,22 @@ export default {
/>
</span>
</div>
+
+ <p v-if="ingressInstalled" class="form-text text-muted">
+ {{
+ s__(`ClusterIntegration|Replace this with your own hostname if you want.
+ If you do so, point hostname to Ingress IP Address from above.`)
+ }}
+ <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
+ {{ __('More information') }}
+ </a>
+ </p>
</div>
- <p v-if="ingressInstalled">
- {{ s__(`ClusterIntegration|Replace this with your own hostname if you want.
- If you do so, point hostname to Ingress IP Address from above.`) }}
- <a
- :href="ingressDnsHelpPath"
- target="_blank"
- rel="noopener noreferrer"
- >
- {{ __('More information') }}
- </a>
- </p>
</template>
</div>
</application-row>
<application-row
+ v-if="isProjectCluster"
id="knative"
:logo-url="knativeLogo"
:title="applications.knative.title"
@@ -394,19 +437,18 @@ export default {
:status-reason="applications.knative.statusReason"
:request-status="applications.knative.requestStatus"
:request-reason="applications.knative.requestReason"
- :install-application-request-params="{ hostname: applications.knative.hostname}"
+ :install-application-request-params="{ hostname: applications.knative.hostname }"
:disabled="!helmInstalled"
- class="hide-bottom-border rounded-bottom"
title-link="https://github.com/knative/docs"
>
<div slot="description">
<p>
- {{ s__(`ClusterIntegration|A Knative build extends Kubernetes
- and utilizes existing Kubernetes primitives to provide you with
- the ability to run on-cluster container builds from source.
- For example, you can write a build that uses Kubernetes-native
- resources to obtain your source code from a repository,
- build it into container a image, and then run that image.`) }}
+ {{
+ s__(`ClusterIntegration|Knative extends Kubernetes to provide
+ a set of middleware components that are essential to build modern,
+ source-centric, and container-based applications that can run
+ anywhere: on premises, in the cloud, or even in a third-party data center.`)
+ }}
</p>
<template v-if="knativeInstalled">
@@ -423,7 +465,7 @@ export default {
/>
</div>
</template>
- <template v-else>
+ <template v-else-if="helmInstalled">
<div class="form-group">
<label for="knative-domainname">
{{ s__('ClusterIntegration|Knative Domain Name:') }}
@@ -436,6 +478,49 @@ export default {
/>
</div>
</template>
+ <template v-if="knativeInstalled">
+ <div class="form-group">
+ <label for="knative-ip-address">
+ {{ s__('ClusterIntegration|Knative IP Address:') }}
+ </label>
+ <div v-if="knativeExternalIp" class="input-group">
+ <input
+ id="knative-ip-address"
+ :value="knativeExternalIp"
+ type="text"
+ class="form-control js-ip-address"
+ readonly
+ />
+ <span class="input-group-append">
+ <clipboard-button
+ :text="knativeExternalIp"
+ :title="s__('ClusterIntegration|Copy Knative IP Address to clipboard')"
+ class="input-group-text js-clipboard-btn"
+ />
+ </span>
+ </div>
+ <input v-else type="text" class="form-control js-ip-address" readonly value="?" />
+ </div>
+
+ <p v-if="!knativeExternalIp" class="settings-message js-no-ip-message">
+ {{
+ s__(`ClusterIntegration|The IP address is in
+ the process of being assigned. Please check your Kubernetes
+ cluster or Quotas on Google Kubernetes Engine if it takes a long time.`)
+ }}
+ </p>
+
+ <p>
+ {{
+ s__(`ClusterIntegration|Point a wildcard DNS to this
+ generated IP address in order to access
+ your application after it has been deployed.`)
+ }}
+ <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
+ {{ __('More information') }}
+ </a>
+ </p>
+ </template>
</div>
</application-row>
</div>
diff --git a/app/assets/javascripts/clusters/constants.js b/app/assets/javascripts/clusters/constants.js
index 15cf4a56138..e31afadf186 100644
--- a/app/assets/javascripts/clusters/constants.js
+++ b/app/assets/javascripts/clusters/constants.js
@@ -24,3 +24,4 @@ export const REQUEST_FAILURE = 'request-failure';
export const INGRESS = 'ingress';
export const JUPYTER = 'jupyter';
export const KNATIVE = 'knative';
+export const CERT_MANAGER = 'cert_manager';
diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js
index da562b09ee5..89dda4b7902 100644
--- a/app/assets/javascripts/clusters/services/clusters_service.js
+++ b/app/assets/javascripts/clusters/services/clusters_service.js
@@ -6,6 +6,7 @@ export default class ClusterService {
this.appInstallEndpointMap = {
helm: this.options.installHelmEndpoint,
ingress: this.options.installIngressEndpoint,
+ cert_manager: this.options.installCertManagerEndpoint,
runner: this.options.installRunnerEndpoint,
prometheus: this.options.installPrometheusEndpoint,
jupyter: this.options.installJupyterEndpoint,
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index e45da967392..c750daab112 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -1,5 +1,5 @@
import { s__ } from '../../locale';
-import { INGRESS, JUPYTER, KNATIVE } from '../constants';
+import { INGRESS, JUPYTER, KNATIVE, CERT_MANAGER } from '../constants';
export default class ClusterStore {
constructor() {
@@ -24,6 +24,14 @@ export default class ClusterStore {
requestReason: null,
externalIp: null,
},
+ cert_manager: {
+ title: s__('ClusterIntegration|Cert-Manager'),
+ status: null,
+ statusReason: null,
+ requestStatus: null,
+ requestReason: null,
+ email: null,
+ },
runner: {
title: s__('ClusterIntegration|GitLab Runner'),
status: null,
@@ -53,6 +61,7 @@ export default class ClusterStore {
requestStatus: null,
requestReason: null,
hostname: null,
+ externalIp: null,
},
},
};
@@ -95,6 +104,9 @@ export default class ClusterStore {
if (appId === INGRESS) {
this.state.applications.ingress.externalIp = serverAppEntry.external_ip;
+ } else if (appId === CERT_MANAGER) {
+ this.state.applications.cert_manager.email =
+ this.state.applications.cert_manager.email || serverAppEntry.email;
} else if (appId === JUPYTER) {
this.state.applications.jupyter.hostname =
serverAppEntry.hostname ||
@@ -104,6 +116,8 @@ export default class ClusterStore {
} else if (appId === KNATIVE) {
this.state.applications.knative.hostname =
serverAppEntry.hostname || this.state.applications.knative.hostname;
+ this.state.applications.knative.externalIp =
+ serverAppEntry.external_ip || this.state.applications.knative.externalIp;
}
});
}
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.vue b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
index 82532539c9c..3e01841d563 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_table.vue
+++ b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
@@ -82,7 +82,6 @@ export default {
</script>
<template>
<div class="content-list pipelines">
-
<gl-loading-icon
v-if="isLoading"
:label="s__('Pipelines|Loading Pipelines')"
@@ -93,14 +92,13 @@ export default {
<svg-blank-state
v-else-if="shouldRenderErrorState"
:svg-path="errorStateSvgPath"
- :message="s__(`Pipelines|There was an error fetching the pipelines.
- Try again in a few moments or contact your support team.`)"
+ :message="
+ s__(`Pipelines|There was an error fetching the pipelines.
+ Try again in a few moments or contact your support team.`)
+ "
/>
- <div
- v-else-if="shouldRenderTable"
- class="table-holder"
- >
+ <div v-else-if="shouldRenderTable" class="table-holder">
<pipelines-table-component
:pipelines="state.pipelines"
:update-graph-dropdown="updateGraphDropdown"
diff --git a/app/assets/javascripts/contextual_sidebar.js b/app/assets/javascripts/contextual_sidebar.js
index dff0adba25a..10f02739ec8 100644
--- a/app/assets/javascripts/contextual_sidebar.js
+++ b/app/assets/javascripts/contextual_sidebar.js
@@ -2,6 +2,7 @@ import $ from 'jquery';
import Cookies from 'js-cookie';
import _ from 'underscore';
import bp from './breakpoints';
+import { parseBoolean } from '~/lib/utils/common_utils';
export default class ContextualSidebar {
constructor() {
@@ -78,7 +79,7 @@ export default class ContextualSidebar {
if (breakpoint === 'sm' || breakpoint === 'md') {
this.toggleCollapsedSidebar(true);
} else if (breakpoint === 'lg') {
- const collapse = Cookies.get('sidebar_collapsed') === 'true';
+ const collapse = parseBoolean(Cookies.get('sidebar_collapsed'));
this.toggleCollapsedSidebar(collapse);
}
}
diff --git a/app/assets/javascripts/cycle_analytics/components/banner.vue b/app/assets/javascripts/cycle_analytics/components/banner.vue
index 82b0f523d2e..e44588efbfc 100644
--- a/app/assets/javascripts/cycle_analytics/components/banner.vue
+++ b/app/assets/javascripts/cycle_analytics/components/banner.vue
@@ -32,30 +32,19 @@ export default {
type="button"
@click="dismissOverviewDialog"
>
- <icon
- name="close"
- />
+ <icon name="close" />
</button>
- <div
- class="svg-container"
- v-html="iconCycleAnalyticsSplash"
- >
- </div>
+ <div class="svg-container" v-html="iconCycleAnalyticsSplash"></div>
<div class="inner-content">
- <h4>
- {{ __('Introducing Cycle Analytics') }}
- </h4>
+ <h4>{{ __('Introducing Cycle Analytics') }}</h4>
<p>
- {{ __(`Cycle Analytics gives an overview
-of how much time it takes to go from idea to production in your project.`) }}
+ {{
+ __(`Cycle Analytics gives an overview
+of how much time it takes to go from idea to production in your project.`)
+ }}
</p>
<p>
- <a
- :href="documentationLink"
- target="_blank"
- rel="nofollow"
- class="btn"
- >
+ <a :href="documentationLink" target="_blank" rel="nofollow" class="btn">
{{ __('Read more') }}
</a>
</p>
diff --git a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
index f6a7d9962eb..ff0f352b333 100644
--- a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
@@ -1,9 +1,9 @@
<script>
-import tooltip from '../../vue_shared/directives/tooltip';
+import { GlTooltipDirective } from '@gitlab/ui';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
count: {
@@ -14,20 +14,14 @@ export default {
};
</script>
<template>
- <span
- v-if="count === 50"
- class="events-info float-right"
- >
+ <span v-if="count === 50" class="events-info float-right">
<i
- v-tooltip
- :title="n__(
- 'Limited to showing %d event at most',
- 'Limited to showing %d events at most',
- 50
- )"
+ v-gl-tooltip
+ :title="
+ n__('Limited to showing %d event at most', 'Limited to showing %d events at most', 50)
+ "
class="fa fa-warning"
aria-hidden="true"
- data-placement="top"
>
</i>
{{ n__('Showing %d event', 'Showing %d events', 50) }}
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
index 429fef176c3..333ea111cd6 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
@@ -28,45 +28,26 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
- <li
- v-for="(mergeRequest, i) in items"
- :key="i"
- class="stage-event-item"
- >
+ <li v-for="(mergeRequest, i) in items" :key="i" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="mergeRequest.author.avatarUrl" />
<h5 class="item-title merge-merquest-title">
- <a :href="mergeRequest.url">
- {{ mergeRequest.title }}
- </a>
+ <a :href="mergeRequest.url"> {{ mergeRequest.title }} </a>
</h5>
- <a
- :href="mergeRequest.url"
- class="issue-link">
- !{{ mergeRequest.iid }}
- </a>
- &middot;
+ <a :href="mergeRequest.url" class="issue-link"> !{{ mergeRequest.iid }} </a> &middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
- <a
- :href="mergeRequest.url"
- class="issue-date">
- {{ mergeRequest.createdAt }}
- </a>
+ <a :href="mergeRequest.url" class="issue-date"> {{ mergeRequest.createdAt }} </a>
</span>
<span>
{{ s__('ByAuthor|by') }}
- <a
- :href="mergeRequest.author.webUrl"
- class="issue-author-link">
+ <a :href="mergeRequest.author.webUrl" class="issue-author-link">
{{ mergeRequest.author.name }}
</a>
</span>
</div>
- <div class="item-time">
- <total-time :time="mergeRequest.totalTime" />
- </div>
+ <div class="item-time"><total-time :time="mergeRequest.totalTime" /></div>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
index 56e851fa528..c4f5172df3b 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
@@ -28,47 +28,24 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
- <li
- v-for="(issue, i) in items"
- :key="i"
- class="stage-event-item"
- >
+ <li v-for="(issue, i) in items" :key="i" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
- <user-avatar-image :img-src="issue.author.avatarUrl"/>
+ <user-avatar-image :img-src="issue.author.avatarUrl" />
<h5 class="item-title issue-title">
- <a
- :href="issue.url"
- class="issue-title"
- >
- {{ issue.title }}
- </a>
+ <a :href="issue.url" class="issue-title"> {{ issue.title }} </a>
</h5>
- <a
- :href="issue.url"
- class="issue-link"
- >#{{ issue.iid }}</a>
- &middot;
+ <a :href="issue.url" class="issue-link">#{{ issue.iid }}</a> &middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
- <a
- :href="issue.url"
- class="issue-date"
- >{{ issue.createdAt }}</a>
+ <a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
- <a
- :href="issue.author.webUrl"
- class="issue-author-link"
- >
- {{ issue.author.name }}
- </a>
+ <a :href="issue.author.webUrl" class="issue-author-link"> {{ issue.author.name }} </a>
</span>
</div>
- <div class="item-time">
- <total-time :time="issue.totalTime" />
- </div>
+ <div class="item-time"><total-time :time="issue.totalTime" /></div>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
index 54b9da4983a..6c256fa6736 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
@@ -34,42 +34,25 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
- <li
- v-for="(commit, i) in items"
- :key="i"
- class="stage-event-item"
- >
+ <li v-for="(commit, i) in items" :key="i" class="stage-event-item">
<div class="item-details item-conmmit-component">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="commit.author.avatarUrl" />
<h5 class="item-title commit-title">
- <a :href="commit.commitUrl">
- {{ commit.title }}
- </a>
+ <a :href="commit.commitUrl"> {{ commit.title }} </a>
</h5>
<span>
- {{ s__('FirstPushedBy|First') }}
- <span
- class="commit-icon"
- v-html="iconCommit"
- >
- </span>
- <a
- :href="commit.commitUrl"
- class="commit-hash-link commit-sha"
- >{{ commit.shortSha }}</a>
+ {{ s__('FirstPushedBy|First') }} <span class="commit-icon" v-html="iconCommit"> </span>
+ <a :href="commit.commitUrl" class="commit-hash-link commit-sha">{{
+ commit.shortSha
+ }}</a>
{{ s__('FirstPushedBy|pushed by') }}
- <a
- :href="commit.author.webUrl"
- class="commit-author-link"
- >
+ <a :href="commit.author.webUrl" class="commit-author-link">
{{ commit.author.name }}
</a>
</span>
</div>
- <div class="item-time">
- <total-time :time="commit.totalTime" />
- </div>
+ <div class="item-time"><total-time :time="commit.totalTime" /></div>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
index f9c80d237d7..f874f11aff0 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
@@ -30,66 +30,37 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
- <li
- v-for="(mergeRequest, i) in items"
- :key="i"
- class="stage-event-item"
- >
+ <li v-for="(mergeRequest, i) in items" :key="i" class="stage-event-item">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
<user-avatar-image :img-src="mergeRequest.author.avatarUrl" />
<h5 class="item-title merge-merquest-title">
- <a :href="mergeRequest.url">
- {{ mergeRequest.title }}
- </a>
+ <a :href="mergeRequest.url"> {{ mergeRequest.title }} </a>
</h5>
- <a
- :href="mergeRequest.url"
- class="issue-link"
- >!{{ mergeRequest.iid }}</a>
- &middot;
+ <a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a> &middot;
<span>
{{ s__('OpenedNDaysAgo|Opened') }}
- <a
- :href="mergeRequest.url"
- class="issue-date"
- >{{ mergeRequest.createdAt }}</a>
+ <a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
{{ s__('ByAuthor|by') }}
- <a
- :href="mergeRequest.author.webUrl"
- class="issue-author-link"
- >{{ mergeRequest.author.name }}</a>
+ <a :href="mergeRequest.author.webUrl" class="issue-author-link">{{
+ mergeRequest.author.name
+ }}</a>
</span>
<template v-if="mergeRequest.state === 'closed'">
<span class="merge-request-state">
- <i
- class="fa fa-ban"
- aria-hidden="true"
- >
- </i>
- {{ mergeRequest.state.toUpperCase() }}
+ <i class="fa fa-ban" aria-hidden="true"> </i> {{ mergeRequest.state.toUpperCase() }}
</span>
</template>
<template v-else>
- <span
- v-if="mergeRequest.branch"
- class="merge-request-branch"
- >
- <icon
- :size="16"
- name="fork"
- />
- <a :href="mergeRequest.branch.url">
- {{ mergeRequest.branch.name }}
- </a>
+ <span v-if="mergeRequest.branch" class="merge-request-branch">
+ <icon :size="16" name="fork" />
+ <a :href="mergeRequest.branch.url"> {{ mergeRequest.branch.name }} </a>
</span>
</template>
</div>
- <div class="item-time">
- <total-time :time="mergeRequest.totalTime" />
- </div>
+ <div class="item-time"><total-time :time="mergeRequest.totalTime" /></div>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
index e83b66eef86..c5146c3bf88 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
@@ -36,62 +36,23 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
- <li
- v-for="(build, i) in items"
- :key="i"
- class="stage-event-item item-build-component"
- >
+ <li v-for="(build, i) in items" :key="i" class="stage-event-item item-build-component">
<div class="item-details">
<!-- FIXME: Pass an alt attribute here for accessibility -->
- <user-avatar-image :img-src="build.author.avatarUrl"/>
+ <user-avatar-image :img-src="build.author.avatarUrl" />
<h5 class="item-title">
- <a
- :href="build.url"
- class="pipeline-id"
- >
- #{{ build.id }}
- </a>
- <icon
- :size="16"
- name="fork"
- />
- <a
- :href="build.branch.url"
- class="ref-name"
- >
- {{ build.branch.name }}
- </a>
- <span
- class="icon-branch"
- v-html="iconBranch"
- >
- </span>
- <a
- :href="build.commitUrl"
- class="commit-sha"
- >
- {{ build.shortSha }}
- </a>
+ <a :href="build.url" class="pipeline-id"> #{{ build.id }} </a>
+ <icon :size="16" name="fork" />
+ <a :href="build.branch.url" class="ref-name"> {{ build.branch.name }} </a>
+ <span class="icon-branch" v-html="iconBranch"> </span>
+ <a :href="build.commitUrl" class="commit-sha"> {{ build.shortSha }} </a>
</h5>
<span>
- <a
- :href="build.url"
- class="build-date"
- >
- {{ build.date }}
- </a>
- {{ s__('ByAuthor|by') }}
- <a
- :href="build.author.webUrl"
- class="issue-author-link"
- >
- {{ build.author.name }}
- </a>
+ <a :href="build.url" class="build-date"> {{ build.date }} </a> {{ s__('ByAuthor|by') }}
+ <a :href="build.author.webUrl" class="issue-author-link"> {{ build.author.name }} </a>
</span>
</div>
- <div class="item-time">
- <total-time :time="build.totalTime" />
- </div>
+ <div class="item-time"><total-time :time="build.totalTime" /></div>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
index a8196dc879a..35721384210 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
@@ -38,63 +38,22 @@ export default {
<limit-warning :count="items.length" />
</div>
<ul class="stage-event-list">
- <li
- v-for="(build, i) in items"
- :key="i"
- class="stage-event-item item-build-component"
- >
+ <li v-for="(build, i) in items" :key="i" class="stage-event-item item-build-component">
<div class="item-details">
<h5 class="item-title">
- <span
- class="icon-build-status"
- v-html="iconBuildStatus"
- >
- </span>
- <a
- :href="build.url"
- class="item-build-name"
- >
- {{ build.name }}
- </a>
- &middot;
- <a
- :href="build.url"
- class="pipeline-id"
- >
- #{{ build.id }}
- </a>
- <icon
- :size="16"
- name="fork"
- />
- <a
- :href="build.branch.url"
- class="ref-name"
- >
- {{ build.branch.name }}
- </a>
- <span
- class="icon-branch"
- v-html="iconBranch"
- >
- </span>
- <a
- :href="build.commitUrl"
- class="commit-sha">
- {{ build.shortSha }}
- </a>
+ <span class="icon-build-status" v-html="iconBuildStatus"> </span>
+ <a :href="build.url" class="item-build-name"> {{ build.name }} </a> &middot;
+ <a :href="build.url" class="pipeline-id"> #{{ build.id }} </a>
+ <icon :size="16" name="fork" />
+ <a :href="build.branch.url" class="ref-name"> {{ build.branch.name }} </a>
+ <span class="icon-branch" v-html="iconBranch"> </span>
+ <a :href="build.commitUrl" class="commit-sha"> {{ build.shortSha }} </a>
</h5>
<span>
- <a
- :href="build.url"
- class="issue-date">
- {{ build.date }}
- </a>
+ <a :href="build.url" class="issue-date"> {{ build.date }} </a>
</span>
</div>
- <div class="item-time">
- <total-time :time="build.totalTime" />
- </div>
+ <div class="item-time"><total-time :time="build.totalTime" /></div>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/cycle_analytics/components/total_time_component.vue b/app/assets/javascripts/cycle_analytics/components/total_time_component.vue
index 4db50134208..b93a7d3c4f9 100644
--- a/app/assets/javascripts/cycle_analytics/components/total_time_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/total_time_component.vue
@@ -18,28 +18,16 @@ export default {
<span class="total-time">
<template v-if="hasData">
<template v-if="time.days">
- {{ time.days }}
- <span>
- {{ n__('day', 'days', time.days) }}
- </span>
+ {{ time.days }} <span> {{ n__('day', 'days', time.days) }} </span>
</template>
<template v-if="time.hours">
- {{ time.hours }}
- <span>
- {{ n__('Time|hr', 'Time|hrs', time.hours) }}
- </span>
+ {{ time.hours }} <span> {{ n__('Time|hr', 'Time|hrs', time.hours) }} </span>
</template>
<template v-if="time.mins && !time.days">
- {{ time.mins }}
- <span>
- {{ n__('Time|min', 'Time|mins', time.mins) }}
- </span>
+ {{ time.mins }} <span> {{ n__('Time|min', 'Time|mins', time.mins) }} </span>
</template>
- <template v-if="time.seconds && hasData === 1 || time.seconds === 0">
- {{ time.seconds }}
- <span>
- {{ s__('Time|s') }}
- </span>
+ <template v-if="(time.seconds && hasData === 1) || time.seconds === 0">
+ {{ time.seconds }} <span> {{ s__('Time|s') }} </span>
</template>
</template>
<template v-else>
diff --git a/app/assets/javascripts/deploy_keys/components/action_btn.vue b/app/assets/javascripts/deploy_keys/components/action_btn.vue
index ea74fd27ff6..af7c391ab70 100644
--- a/app/assets/javascripts/deploy_keys/components/action_btn.vue
+++ b/app/assets/javascripts/deploy_keys/components/action_btn.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../eventhub';
export default {
@@ -43,11 +43,9 @@ export default {
:class="[{ disabled: isLoading }, btnCssClass]"
:disabled="isLoading"
class="btn"
- @click="doAction">
+ @click="doAction"
+ >
<slot></slot>
- <gl-loading-icon
- v-if="isLoading"
- :inline="true"
- />
+ <gl-loading-icon v-if="isLoading" :inline="true" />
</button>
</template>
diff --git a/app/assets/javascripts/deploy_keys/components/app.vue b/app/assets/javascripts/deploy_keys/components/app.vue
index 631a9673b3e..922c907bb36 100644
--- a/app/assets/javascripts/deploy_keys/components/app.vue
+++ b/app/assets/javascripts/deploy_keys/components/app.vue
@@ -6,7 +6,7 @@ import eventHub from '../eventhub';
import DeployKeysService from '../service';
import DeployKeysStore from '../store';
import KeysPanel from './keys_panel.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
@@ -123,26 +123,10 @@ export default {
/>
<template v-else-if="hasKeys">
<div class="top-area scrolling-tabs-container inner-page-scroll-tabs">
- <div class="fade-left">
- <i
- class="fa fa-angle-left"
- aria-hidden="true"
- >
- </i>
- </div>
- <div class="fade-right">
- <i
- class="fa fa-angle-right"
- aria-hidden="true"
- >
- </i>
- </div>
+ <div class="fade-left"><i class="fa fa-angle-left" aria-hidden="true"> </i></div>
+ <div class="fade-right"><i class="fa fa-angle-right" aria-hidden="true"> </i></div>
- <navigation-tabs
- :tabs="tabs"
- scope="deployKeys"
- @onChangeTab="onChangeTab"
- />
+ <navigation-tabs :tabs="tabs" scope="deployKeys" @onChangeTab="onChangeTab" />
</div>
<keys-panel
:project-id="projectId"
diff --git a/app/assets/javascripts/deploy_keys/components/key.vue b/app/assets/javascripts/deploy_keys/components/key.vue
index c05b9b1de79..f01e6f2a639 100644
--- a/app/assets/javascripts/deploy_keys/components/key.vue
+++ b/app/assets/javascripts/deploy_keys/components/key.vue
@@ -112,26 +112,14 @@ export default {
<template>
<div class="gl-responsive-table-row deploy-key">
<div class="table-section section-40">
- <div
- role="rowheader"
- class="table-mobile-header">
- {{ s__('DeployKeys|Deploy key') }}
- </div>
+ <div role="rowheader" class="table-mobile-header">{{ s__('DeployKeys|Deploy key') }}</div>
<div class="table-mobile-content">
- <strong class="title qa-key-title">
- {{ deployKey.title }}
- </strong>
- <div class="fingerprint qa-key-fingerprint">
- {{ deployKey.fingerprint }}
- </div>
+ <strong class="title qa-key-title"> {{ deployKey.title }} </strong>
+ <div class="fingerprint qa-key-fingerprint">{{ deployKey.fingerprint }}</div>
</div>
</div>
<div class="table-section section-30 section-wrap">
- <div
- role="rowheader"
- class="table-mobile-header">
- {{ s__('DeployKeys|Project usage') }}
- </div>
+ <div role="rowheader" class="table-mobile-header">{{ s__('DeployKeys|Project usage') }}</div>
<div class="table-mobile-content deploy-project-list">
<template v-if="projects.length > 0">
<a
@@ -139,10 +127,8 @@ export default {
:title="projectTooltipTitle(firstProject)"
class="label deploy-project-label"
>
- <span>
- {{ firstProject.project.full_name }}
- </span>
- <icon :name="firstProject.can_push ? 'lock-open' : 'lock'"/>
+ <span> {{ firstProject.project.full_name }} </span>
+ <icon :name="firstProject.can_push ? 'lock-open' : 'lock'" />
</a>
<a
v-if="isExpandable"
@@ -162,39 +148,24 @@ export default {
:title="projectTooltipTitle(deployKeysProject)"
class="label deploy-project-label"
>
- <span>
- {{ deployKeysProject.project.full_name }}
- </span>
- <icon :name="deployKeysProject.can_push ? 'lock-open' : 'lock'"/>
+ <span> {{ deployKeysProject.project.full_name }} </span>
+ <icon :name="deployKeysProject.can_push ? 'lock-open' : 'lock'" />
</a>
</template>
- <span
- v-else
- class="text-secondary">{{ __('None') }}</span>
+ <span v-else class="text-secondary">{{ __('None') }}</span>
</div>
</div>
<div class="table-section section-15 text-right">
- <div
- role="rowheader"
- class="table-mobile-header">
- {{ __('Created') }}
- </div>
+ <div role="rowheader" class="table-mobile-header">{{ __('Created') }}</div>
<div class="table-mobile-content text-secondary key-created-at">
- <span
- v-tooltip
- :title="tooltipTitle(deployKey.created_at)">
- <icon name="calendar"/>
- <span>{{ timeFormated(deployKey.created_at) }}</span>
+ <span v-tooltip :title="tooltipTitle(deployKey.created_at)">
+ <icon name="calendar" /> <span>{{ timeFormated(deployKey.created_at) }}</span>
</span>
</div>
</div>
<div class="table-section section-15 table-button-footer deploy-key-actions">
<div class="btn-group table-action-buttons">
- <action-btn
- v-if="!isEnabled"
- :deploy-key="deployKey"
- type="enable"
- >
+ <action-btn v-if="!isEnabled" :deploy-key="deployKey" type="enable">
{{ __('Enable') }}
</action-btn>
<a
@@ -205,7 +176,7 @@ export default {
class="btn btn-default text-secondary"
data-container="body"
>
- <icon name="pencil"/>
+ <icon name="pencil" />
</a>
<action-btn
v-if="isRemovable"
@@ -216,7 +187,7 @@ export default {
type="remove"
data-container="body"
>
- <icon name="remove"/>
+ <icon name="remove" />
</action-btn>
<action-btn
v-else-if="isEnabled"
@@ -227,7 +198,7 @@ export default {
type="disable"
data-container="body"
>
- <icon name="cancel"/>
+ <icon name="cancel" />
</action-btn>
</div>
</div>
diff --git a/app/assets/javascripts/deploy_keys/components/keys_panel.vue b/app/assets/javascripts/deploy_keys/components/keys_panel.vue
index 2f057ca29f6..2693cd08cc3 100644
--- a/app/assets/javascripts/deploy_keys/components/keys_panel.vue
+++ b/app/assets/javascripts/deploy_keys/components/keys_panel.vue
@@ -30,24 +30,14 @@ export default {
<template>
<div class="deploy-keys-panel table-holder">
<template v-if="keys.length > 0">
- <div
- role="row"
- class="gl-responsive-table-row table-row-header">
- <div
- role="rowheader"
- class="table-section section-40">
+ <div role="row" class="gl-responsive-table-row table-row-header">
+ <div role="rowheader" class="table-section section-40">
{{ s__('DeployKeys|Deploy key') }}
</div>
- <div
- role="rowheader"
- class="table-section section-30">
+ <div role="rowheader" class="table-section section-30">
{{ s__('DeployKeys|Project usage') }}
</div>
- <div
- role="rowheader"
- class="table-section section-15 text-right">
- {{ __('Created') }}
- </div>
+ <div role="rowheader" class="table-section section-15 text-right">{{ __('Created') }}</div>
</div>
<deploy-key
v-for="deployKey in keys"
@@ -58,10 +48,7 @@ export default {
:project-id="projectId"
/>
</template>
- <div
- v-else
- class="settings-message text-center"
- >
+ <div v-else class="settings-message text-center">
{{ s__('DeployKeys|No deploy keys found. Create one with the form above.') }}
</div>
</div>
diff --git a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
index c0c21416275..8542a6e718a 100644
--- a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
+++ b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
@@ -112,7 +112,7 @@ const JumpToDiscussion = Vue.extend({
if (!hasDiscussionsToJumpTo) {
// If there are no discussions to jump to on the current page,
- // switch to the notes tab and jump to the first disucssion there.
+ // switch to the notes tab and jump to the first discussion there.
window.mrTabs.activateTab('show');
activeTab = 'show';
jumpToFirstDiscussion = true;
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index b885fa49365..bf9244df7f7 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -3,7 +3,7 @@ import { mapState, mapGetters, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import { __ } from '~/locale';
import createFlash from '~/flash';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../../notes/event_hub';
import CompareVersions from './compare_versions.vue';
import DiffFile from './diff_file.vue';
@@ -55,8 +55,6 @@ export default {
diffViewType: state => state.diffs.diffViewType,
mergeRequestDiffs: state => state.diffs.mergeRequestDiffs,
mergeRequestDiff: state => state.diffs.mergeRequestDiff,
- latestVersionPath: state => state.diffs.latestVersionPath,
- startVersion: state => state.diffs.startVersion,
commit: state => state.diffs.commit,
targetBranchName: state => state.diffs.targetBranchName,
renderOverflowWarning: state => state.diffs.renderOverflowWarning,
@@ -75,24 +73,6 @@ export default {
path: '',
};
},
- notAllCommentsDisplayed() {
- if (this.commit) {
- return __('Only comments from the following commit are shown below');
- } else if (this.startVersion) {
- return __(
- "Not all comments are displayed because you're comparing two versions of the diff.",
- );
- }
- return __(
- "Not all comments are displayed because you're viewing an old version of the diff.",
- );
- },
- showLatestVersion() {
- if (this.commit) {
- return __('Show latest version of the diff');
- }
- return __('Show latest version');
- },
canCurrentUserFork() {
return this.currentUser.can_fork === true && this.currentUser.can_create_merge_request;
},
@@ -122,6 +102,12 @@ export default {
if (this.shouldShow) {
this.fetchData();
}
+
+ const id = window && window.location && window.location.hash;
+
+ if (id) {
+ this.setHighlightedRow(id.slice(1));
+ }
},
created() {
this.adjustView();
@@ -134,6 +120,7 @@ export default {
'fetchDiffFiles',
'startRenderDiffsQueue',
'assignDiscussionsToDiff',
+ 'setHighlightedRow',
]),
fetchData() {
this.fetchDiffFiles()
@@ -181,23 +168,11 @@ export default {
<template>
<div v-show="shouldShow">
- <div
- v-if="isLoading"
- class="loading"
- >
- <gl-loading-icon />
- </div>
- <div
- v-else
- id="diffs"
- :class="{ active: shouldShow }"
- class="diffs tab-pane"
- >
+ <div v-if="isLoading" class="loading"><gl-loading-icon /></div>
+ <div v-else id="diffs" :class="{ active: shouldShow }" class="diffs tab-pane">
<compare-versions
- v-if="showCompareVersions"
:merge-request-diffs="mergeRequestDiffs"
:merge-request-diff="mergeRequestDiff"
- :start-version="startVersion"
:target-branch="targetBranch"
/>
@@ -210,50 +185,22 @@ export default {
/>
<div
- v-if="commit || startVersion || (mergeRequestDiff && !mergeRequestDiff.latest)"
- class="mr-version-controls"
- >
- <div class="content-block comments-disabled-notif clearfix">
- <i class="fa fa-info-circle"></i>
- {{ notAllCommentsDisplayed }}
- <div class="pull-right">
- <a
- :href="latestVersionPath"
- class="btn btn-sm"
- >
- {{ showLatestVersion }}
- </a>
- </div>
- </div>
- </div>
-
- <commit-widget
- v-if="commit"
- :commit="commit"
- />
-
- <div
:data-can-create-note="getNoteableData.current_user.can_create_note"
class="files d-flex prepend-top-default"
>
- <div
- v-show="showTreeList"
- class="diff-tree-list"
- >
- <tree-list />
- </div>
- <div
- v-if="diffFiles.length > 0"
- class="diff-files-holder"
- >
- <diff-file
- v-for="file in diffFiles"
- :key="file.newPath"
- :file="file"
- :can-current-user-fork="canCurrentUserFork"
- />
+ <div v-show="showTreeList" class="diff-tree-list"><tree-list /></div>
+ <div class="diff-files-holder">
+ <commit-widget v-if="commit" :commit="commit" />
+ <template v-if="diffFiles.length > 0">
+ <diff-file
+ v-for="file in diffFiles"
+ :key="file.newPath"
+ :file="file"
+ :can-current-user-fork="canCurrentUserFork"
+ />
+ </template>
+ <no-changes v-else />
</div>
- <no-changes v-else />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
index aa72aca1478..ebc4a83af4d 100644
--- a/app/assets/javascripts/diffs/components/commit_item.vue
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -1,5 +1,4 @@
<script>
-import tooltip from '~/vue_shared/directives/tooltip';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import Icon from '~/vue_shared/components/icon.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
@@ -21,9 +20,6 @@ import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_sta
*
*/
export default {
- directives: {
- tooltip,
- },
components: {
UserAvatarLink,
Icon,
@@ -73,10 +69,7 @@ export default {
v-html="commit.title_html"
></a>
- <span class="commit-row-message d-block d-sm-none">
- &middot;
- {{ commit.short_id }}
- </span>
+ <span class="commit-row-message d-block d-sm-none"> &middot; {{ commit.short_id }} </span>
<button
v-if="commit.description_html"
@@ -84,21 +77,12 @@ export default {
type="button"
:aria-label="__('Toggle commit description')"
>
- <icon
- :size="12"
- name="ellipsis_h"
- />
+ <icon :size="12" name="ellipsis_h" />
</button>
<div class="commiter">
- <a
- :href="authorUrl"
- v-text="authorName"
- ></a>
- {{ s__('CommitWidget|authored') }}
- <time-ago-tooltip
- :time="commit.authored_date"
- />
+ <a :href="authorUrl" v-text="authorName"></a> {{ s__('CommitWidget|authored') }}
+ <time-ago-tooltip :time="commit.authored_date" />
</div>
<pre
@@ -108,19 +92,13 @@ export default {
></pre>
</div>
<div class="commit-actions flex-row d-none d-sm-flex">
- <div
- v-if="commit.signature_html"
- v-html="commit.signature_html"
- ></div>
+ <div v-if="commit.signature_html" v-html="commit.signature_html"></div>
<commit-pipeline-status
v-if="commit.pipeline_status_path"
:endpoint="commit.pipeline_status_path"
/>
<div class="commit-sha-group">
- <div
- class="label label-monospace"
- v-text="commit.short_id"
- ></div>
+ <div class="label label-monospace" v-text="commit.short_id"></div>
<clipboard-button
:text="commit.id"
:title="__('Copy commit SHA to clipboard')"
diff --git a/app/assets/javascripts/diffs/components/commit_widget.vue b/app/assets/javascripts/diffs/components/commit_widget.vue
index cc8e72eb1c8..d45f91c7023 100644
--- a/app/assets/javascripts/diffs/components/commit_widget.vue
+++ b/app/assets/javascripts/diffs/components/commit_widget.vue
@@ -28,12 +28,10 @@ export default {
</script>
<template>
- <div class="info-well prepend-top-default">
+ <div class="info-well w-100">
<div class="well-segment">
<ul class="blob-commit-info">
- <commit-item
- :commit="commit"
- />
+ <commit-item :commit="commit" />
</ul>
</div>
</div>
diff --git a/app/assets/javascripts/diffs/components/compare_versions.vue b/app/assets/javascripts/diffs/components/compare_versions.vue
index a5b87dfc2d9..f75345d31f8 100644
--- a/app/assets/javascripts/diffs/components/compare_versions.vue
+++ b/app/assets/javascripts/diffs/components/compare_versions.vue
@@ -1,6 +1,6 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
-import Tooltip from '@gitlab-org/gitlab-ui/dist/directives/tooltip';
+import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
import { getParameterValues, mergeUrlParams } from '~/lib/utils/url_utility';
import Icon from '~/vue_shared/components/icon.vue';
@@ -10,9 +10,11 @@ export default {
components: {
CompareVersionsDropdown,
Icon,
+ GlLink,
+ GlButton,
},
directives: {
- Tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
mergeRequestDiffs: {
@@ -21,12 +23,8 @@ export default {
},
mergeRequestDiff: {
type: Object,
- required: true,
- },
- startVersion: {
- type: Object,
required: false,
- default: null,
+ default: () => ({}),
},
targetBranch: {
type: Object,
@@ -35,7 +33,7 @@ export default {
},
},
computed: {
- ...mapState('diffs', ['commit', 'showTreeList']),
+ ...mapState('diffs', ['commit', 'showTreeList', 'startVersion', 'latestVersionPath']),
...mapGetters('diffs', ['isInlineView', 'isParallelView', 'hasCollapsedFile']),
comparableDiffs() {
return this.mergeRequestDiffs.slice(1);
@@ -73,27 +71,20 @@ export default {
<template>
<div class="mr-version-controls">
- <div
- class="mr-version-menus-container content-block"
- >
+ <div class="mr-version-menus-container content-block">
<button
- v-tooltip.hover
+ v-gl-tooltip.hover
type="button"
class="btn btn-default append-right-8 js-toggle-tree-list"
:class="{
- active: showTreeList
+ active: showTreeList,
}"
:title="__('Toggle file browser')"
@click="toggleShowTreeList"
>
- <icon
- name="hamburger"
- />
+ <icon name="hamburger" />
</button>
- <div
- v-if="showDropdowns"
- class="d-flex align-items-center compare-versions-container"
- >
+ <div v-if="showDropdowns" class="d-flex align-items-center compare-versions-container">
Changes between
<compare-versions-dropdown
:other-versions="mergeRequestDiffs"
@@ -109,20 +100,22 @@ export default {
class="mr-version-compare-dropdown"
/>
</div>
- <div
- class="inline-parallel-buttons d-none d-md-flex ml-auto"
- >
- <a
- v-show="hasCollapsedFile"
- class="btn btn-default append-right-8"
- @click="expandAllFiles"
+ <div v-else-if="commit">
+ {{ __('Viewing commit') }}
+ <gl-link :href="commit.commit_url" class="monospace">{{ commit.short_id }}</gl-link>
+ </div>
+ <div class="inline-parallel-buttons d-none d-md-flex ml-auto">
+ <gl-button
+ v-if="commit || startVersion"
+ :href="latestVersionPath"
+ class="append-right-8 js-latest-version"
>
+ {{ __('Show latest version') }}
+ </gl-button>
+ <a v-show="hasCollapsedFile" class="btn btn-default append-right-8" @click="expandAllFiles">
{{ __('Expand all') }}
</a>
- <a
- :href="toggleWhitespacePath"
- class="btn btn-default qa-toggle-whitespace"
- >
+ <a :href="toggleWhitespacePath" class="btn btn-default qa-toggle-whitespace">
{{ toggleWhitespaceText }}
</a>
<div class="btn-group prepend-left-8">
diff --git a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
index 112206e4ad6..8da02ed0b7c 100644
--- a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
+++ b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
@@ -112,26 +112,14 @@ export default {
data-toggle="dropdown"
aria-expanded="false"
>
- <span>
- {{ selectedVersionName }}
- </span>
- <icon
- :size="12"
- name="angle-down"
- class="position-absolute"
- />
+ <span> {{ selectedVersionName }} </span>
+ <icon :size="12" name="angle-down" class="position-absolute" />
</a>
<div class="dropdown-menu dropdown-select dropdown-menu-selectable">
<div class="dropdown-content">
<ul>
- <li
- v-for="version in targetVersions"
- :key="version.id"
- >
- <a
- :class="{ 'is-active': isActive(version) }"
- :href="href(version)"
- >
+ <li v-for="version in targetVersions" :key="version.id">
+ <a :class="{ 'is-active': isActive(version) }" :href="href(version)">
<div>
<strong>
{{ versionName(version) }}
@@ -141,9 +129,7 @@ export default {
</strong>
</div>
<div>
- <small class="commit-sha">
- {{ version.truncated_commit_sha }}
- </small>
+ <small class="commit-sha"> {{ version.truncated_commit_sha }} </small>
</div>
<div>
<small>
diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue
index 5e5fda5fba6..11cc4c09fed 100644
--- a/app/assets/javascripts/diffs/components/diff_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_content.vue
@@ -90,6 +90,8 @@ export default {
:old-sha="diffFile.diff_refs.base_sha"
:file-hash="diffFile.file_hash"
:project-path="projectPath"
+ :a-mode="diffFile.a_mode"
+ :b-mode="diffFile.b_mode"
>
<image-diff-overlay
slot="image-overlay"
@@ -97,10 +99,7 @@ export default {
:file-hash="diffFile.file_hash"
:can-comment="getNoteableData.current_user.can_create_note"
/>
- <div
- v-if="showNotesContainer"
- class="note-container"
- >
+ <div v-if="showNotesContainer" class="note-container">
<diff-discussions
v-if="diffFile.discussions.length"
class="diff-file-discussions"
@@ -115,8 +114,8 @@ export default {
:save-button-title="__('Comment')"
class="diff-comment-form new-note discussion-form discussion-form-container"
@handleFormUpdate="handleSaveNote"
- @cancelForm="closeDiffFileCommentForm(diffFile.file_hash)"
- />
+ @cancelForm="closeDiffFileCommentForm(diffFile.file_hash);"
+ />
</div>
</diff-viewer>
</div>
diff --git a/app/assets/javascripts/diffs/components/diff_discussions.vue b/app/assets/javascripts/diffs/components/diff_discussions.vue
index b9de487a737..bee29b04e92 100644
--- a/app/assets/javascripts/diffs/components/diff_discussions.vue
+++ b/app/assets/javascripts/diffs/components/diff_discussions.vue
@@ -45,29 +45,22 @@ export default {
v-for="(discussion, index) in discussions"
:key="discussion.id"
:class="{
- collapsed: !isExpanded(discussion)
+ collapsed: !isExpanded(discussion),
}"
class="discussion-notes diff-discussions position-relative"
>
- <ul
- :data-discussion-id="discussion.id"
- class="notes"
- >
+ <ul :data-discussion-id="discussion.id" class="notes">
<template v-if="shouldCollapseDiscussions">
<button
:class="{
'diff-notes-collapse': discussion.expanded,
- 'btn-transparent badge badge-pill': !discussion.expanded
+ 'btn-transparent badge badge-pill': !discussion.expanded,
}"
type="button"
class="js-diff-notes-toggle"
- @click="toggleDiscussion({ discussionId: discussion.id })"
+ @click="toggleDiscussion({ discussionId: discussion.id });"
>
- <icon
- v-if="discussion.expanded"
- name="collapse"
- class="collapse-icon"
- />
+ <icon v-if="discussion.expanded" name="collapse" class="collapse-icon" />
<template v-else>
{{ index + 1 }}
</template>
@@ -81,11 +74,7 @@ export default {
:discussions-by-diff-order="true"
@noteDeleted="deleteNoteHandler"
>
- <span
- v-if="renderAvatarBadge"
- slot="avatar-badge"
- class="badge badge-pill"
- >
+ <span v-if="renderAvatarBadge" slot="avatar-badge" class="badge badge-pill">
{{ index + 1 }}
</span>
</noteable-discussion>
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index 872131a5900..bed29efb253 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -3,7 +3,8 @@ import { mapActions, mapGetters, mapState } from 'vuex';
import _ from 'underscore';
import { __, sprintf } from '~/locale';
import createFlash from '~/flash';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
+import eventHub from '../../notes/event_hub';
import DiffFileHeader from './diff_file_header.vue';
import DiffContent from './diff_content.vue';
@@ -52,7 +53,9 @@ export default {
(!this.file.highlighted_diff_lines &&
!this.isLoadingCollapsedDiff &&
!this.file.too_large &&
- this.file.text)
+ this.file.text &&
+ !this.file.renamed_file &&
+ !this.file.mode_changed)
);
},
showLoadingIcon() {
@@ -73,6 +76,9 @@ export default {
}
},
},
+ created() {
+ eventHub.$on(`loadCollapsedDiff/${this.file.file_hash}`, this.handleLoadCollapsedDiff);
+ },
methods: {
...mapActions('diffs', ['loadCollapsedDiff', 'assignDiscussionsToDiff']),
handleToggle() {
@@ -119,7 +125,7 @@ export default {
<div
:id="file.file_hash"
:class="{
- 'is-active': currentDiffFileId === file.file_hash
+ 'is-active': currentDiffFileId === file.file_hash,
}"
class="diff-file file-holder"
>
@@ -134,20 +140,17 @@ export default {
@showForkMessage="showForkMessage"
/>
- <div
- v-if="forkMessageVisible"
- class="js-file-fork-suggestion-section file-fork-suggestion">
+ <div v-if="forkMessageVisible" class="js-file-fork-suggestion-section file-fork-suggestion">
<span class="file-fork-suggestion-note">
- You're not allowed to <span class="js-file-fork-suggestion-section-action">edit</span>
- files in this project directly. Please fork this project,
- make your changes there, and submit a merge request.
+ You're not allowed to <span class="js-file-fork-suggestion-section-action">edit</span> files
+ in this project directly. Please fork this project, make your changes there, and submit a
+ merge request.
</span>
<a
:href="file.fork_path"
class="js-fork-suggestion-button btn btn-grouped btn-inverted btn-success"
+ >Fork</a
>
- Fork
- </a>
<button
class="js-cancel-fork-suggestion-button btn btn-grouped"
type="button"
@@ -162,27 +165,14 @@ export default {
:class="{ hidden: isCollapsed || file.too_large }"
:diff-file="file"
/>
- <gl-loading-icon
- v-if="showLoadingIcon"
- class="diff-content loading"
- />
- <div
- v-else-if="showExpandMessage"
- class="nothing-here-block diff-collapsed"
- >
+ <gl-loading-icon v-if="showLoadingIcon" class="diff-content loading" />
+ <div v-else-if="showExpandMessage" class="nothing-here-block diff-collapsed">
{{ __('This diff is collapsed.') }}
- <a
- class="click-to-expand js-click-to-expand"
- href="#"
- @click.prevent="handleToggle"
- >
- {{ __('Click to expand it.') }}
- </a>
+ <a class="click-to-expand js-click-to-expand" href="#" @click.prevent="handleToggle">{{
+ __('Click to expand it.')
+ }}</a>
</div>
- <div
- v-if="file.too_large"
- class="nothing-here-block diff-collapsed js-too-large-diff"
- >
+ <div v-if="file.too_large" class="nothing-here-block diff-collapsed js-too-large-diff">
{{ __('This source diff could not be displayed because it is too large.') }}
<span v-html="viewBlobLink"></span>
</div>
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index af03cec6582..f75a01b023b 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -1,10 +1,11 @@
<script>
import _ from 'underscore';
import { mapActions, mapGetters } from 'vuex';
+import { polyfillSticky } from '~/lib/utils/sticky';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import Icon from '~/vue_shared/components/icon.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
-import Tooltip from '~/vue_shared/directives/tooltip';
+import { GlTooltipDirective } from '@gitlab/ui';
import { truncateSha } from '~/lib/utils/text_utility';
import { __, s__, sprintf } from '~/locale';
import EditButton from './edit_button.vue';
@@ -17,7 +18,7 @@ export default {
FileIcon,
},
directives: {
- Tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
discussionPath: {
@@ -116,6 +117,9 @@ export default {
return `\`${this.diffFile.file_path}\``;
},
},
+ mounted() {
+ polyfillSticky(this.$refs.header);
+ },
methods: {
...mapActions('diffs', ['toggleFileDiscussions']),
handleToggleFile(e, checkTarget) {
@@ -141,7 +145,7 @@ export default {
<div
ref="header"
class="js-file-title file-title file-title-flex-parent"
- @click="handleToggleFile($event, true)"
+ @click="handleToggleFile($event, true);"
>
<div class="file-header-content">
<icon
@@ -152,12 +156,7 @@ export default {
class="diff-toggle-caret append-right-5"
@click.stop="handleToggle"
/>
- <a
- v-once
- ref="titleWrapper"
- :href="titleLink"
- class="append-right-4 js-title-wrapper"
- >
+ <a v-once ref="titleWrapper" :href="titleLink" class="append-right-4 js-title-wrapper">
<file-icon
:file-name="filePath"
:size="18"
@@ -166,29 +165,21 @@ export default {
/>
<span v-if="diffFile.renamed_file">
<strong
- v-tooltip
+ v-gl-tooltip
:title="diffFile.old_path"
class="file-title-name"
- data-container="body"
v-html="diffFile.old_path_html"
></strong>
→
<strong
- v-tooltip
+ v-gl-tooltip
:title="diffFile.new_path"
class="file-title-name"
- data-container="body"
v-html="diffFile.new_path_html"
></strong>
</span>
- <strong
- v-else
- v-tooltip
- :title="filePath"
- class="file-title-name"
- data-container="body"
- >
+ <strong v-else v-gl-tooltip :title="filePath" class="file-title-name" data-container="body">
{{ filePath }}
</strong>
</a>
@@ -200,28 +191,18 @@ export default {
css-class="btn-default btn-transparent btn-clipboard"
/>
- <small
- v-if="diffFile.mode_changed"
- ref="fileMode"
- >
+ <small v-if="diffFile.mode_changed" ref="fileMode">
{{ diffFile.a_mode }} → {{ diffFile.b_mode }}
</small>
- <span
- v-if="isUsingLfs"
- class="label label-lfs append-right-5"
- >
- {{ __('LFS') }}
- </span>
+ <span v-if="isUsingLfs" class="label label-lfs append-right-5"> {{ __('LFS') }} </span>
</div>
<div
v-if="!diffFile.submodule && addMergeRequestButtons"
class="file-actions d-none d-sm-block"
>
- <template
- v-if="diffFile.blob && diffFile.blob.readable_text"
- >
+ <template v-if="diffFile.blob && diffFile.blob.readable_text">
<button
:disabled="!diffHasDiscussions(diffFile)"
:class="{ active: hasExpandedDiscussions }"
@@ -249,16 +230,12 @@ export default {
v-html="viewReplacedFileButtonText"
>
</a>
- <a
- :href="diffFile.view_path"
- class="btn view-file js-view-file"
- v-html="viewFileButtonText"
- >
+ <a :href="diffFile.view_path" class="btn view-file js-view-file" v-html="viewFileButtonText">
</a>
<a
v-if="diffFile.external_url"
- v-tooltip
+ v-gl-tooltip.hover
:href="diffFile.external_url"
:title="`View on ${diffFile.formatted_external_url}`"
target="_blank"
diff --git a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue
index 254bc235691..0c0a0faa59d 100644
--- a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue
+++ b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue
@@ -3,7 +3,7 @@ import { mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import { pluralize, truncate } from '~/lib/utils/text_utility';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import { COUNT_OF_AVATARS_IN_GUTTER, LENGTH_OF_AVATAR_TOOLTIP } from '../constants';
export default {
@@ -56,9 +56,12 @@ export default {
return `${noteData.author.name}: ${note}`;
},
toggleDiscussions() {
+ const forceExpanded = this.discussions.some(discussion => !discussion.expanded);
+
this.discussions.forEach(discussion => {
this.toggleDiscussion({
discussionId: discussion.id,
+ forceExpanded,
});
});
},
@@ -75,10 +78,7 @@ export default {
class="diff-notes-collapse js-diff-comment-avatar js-diff-comment-button"
@click="toggleDiscussions"
>
- <icon
- :size="12"
- name="collapse"
- />
+ <icon :size="12" name="collapse" />
</button>
<template v-else>
<user-avatar-image
@@ -99,7 +99,8 @@ export default {
data-placement="top"
role="button"
@click="toggleDiscussions"
- >+{{ moreCount }}</span>
+ >+{{ moreCount }}</span
+ >
</template>
</div>
</template>
diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
index 8f037eeefc4..c0613d80d37 100644
--- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
@@ -72,6 +72,13 @@ export default {
diffFiles: state => state.diffs.diffFiles,
}),
...mapGetters(['isLoggedIn']),
+ lineCode() {
+ return (
+ this.line.line_code ||
+ (this.line.left && this.line.line.left.line_code) ||
+ (this.line.right && this.line.right.line_code)
+ );
+ },
lineHref() {
return `#${this.line.line_code || ''}`;
},
@@ -97,9 +104,9 @@ export default {
},
},
methods: {
- ...mapActions('diffs', ['loadMoreLines', 'showCommentForm']),
+ ...mapActions('diffs', ['loadMoreLines', 'showCommentForm', 'setHighlightedRow']),
handleCommentButton() {
- this.showCommentForm({ lineCode: this.line.line_code });
+ this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.fileHash });
},
handleLoadMoreLines() {
if (this.isRequesting) {
@@ -155,37 +162,27 @@ export default {
<template>
<div>
- <span
- v-if="isMatchLine"
- class="context-cell"
- role="button"
- @click="handleLoadMoreLines"
- >...</span>
- <template
- v-else
+ <span v-if="isMatchLine" class="context-cell" role="button" @click="handleLoadMoreLines"
+ >...</span
>
+ <template v-else>
<button
- v-if="shouldShowCommentButton"
+ v-show="shouldShowCommentButton"
type="button"
class="add-diff-note js-add-diff-note-button qa-diff-comment"
title="Add a comment to this line"
@click="handleCommentButton"
>
- <icon
- :size="12"
- name="comment"
- />
+ <icon :size="12" name="comment" />
</button>
<a
v-if="lineNumber"
:data-linenumber="lineNumber"
:href="lineHref"
+ @click="setHighlightedRow(lineCode);"
>
</a>
- <diff-gutter-avatars
- v-if="shouldShowAvatarsOnGutter"
- :discussions="line.discussions"
- />
+ <diff-gutter-avatars v-if="shouldShowAvatarsOnGutter" :discussions="line.discussions" />
</template>
</div>
</template>
diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
index 07f38172575..9fd02acbd6e 100644
--- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
@@ -73,6 +73,7 @@ export default {
this.cancelCommentForm({
lineCode: this.line.line_code,
+ fileHash: this.diffFileHash,
});
this.$nextTick(() => {
this.resetAutoSave();
@@ -88,9 +89,7 @@ export default {
</script>
<template>
- <div
- class="content discussion-form discussion-form-container discussion-notes"
- >
+ <div class="content discussion-form discussion-form-container discussion-notes">
<note-form
ref="noteForm"
:is-editing="true"
diff --git a/app/assets/javascripts/diffs/components/diff_table_cell.vue b/app/assets/javascripts/diffs/components/diff_table_cell.vue
index 0a893a57f07..d174b13e133 100644
--- a/app/assets/javascripts/diffs/components/diff_table_cell.vue
+++ b/app/assets/javascripts/diffs/components/diff_table_cell.vue
@@ -1,5 +1,5 @@
<script>
-import { mapGetters } from 'vuex';
+import { mapGetters, mapActions } from 'vuex';
import DiffLineGutterContent from './diff_line_gutter_content.vue';
import {
MATCH_LINE_TYPE,
@@ -30,6 +30,11 @@ export default {
type: String,
required: true,
},
+ isHighlighted: {
+ type: Boolean,
+ required: true,
+ default: false,
+ },
diffViewType: {
type: String,
required: false,
@@ -85,6 +90,7 @@ export default {
const { type } = this.line;
return {
+ hll: this.isHighlighted,
[type]: type,
[LINE_UNFOLD_CLASS_NAME]: this.isMatchLine,
[LINE_HOVER_CLASS_NAME]:
@@ -99,13 +105,12 @@ export default {
return this.lineType === OLD_LINE_TYPE ? this.line.old_line : this.line.new_line;
},
},
+ methods: mapActions('diffs', ['setHighlightedRow']),
};
</script>
<template>
- <td
- :class="classNameMap"
- >
+ <td :class="classNameMap">
<diff-line-gutter-content
:line="line"
:file-hash="fileHash"
diff --git a/app/assets/javascripts/diffs/components/edit_button.vue b/app/assets/javascripts/diffs/components/edit_button.vue
index 2fb85ca2f07..5d38d545ce8 100644
--- a/app/assets/javascripts/diffs/components/edit_button.vue
+++ b/app/assets/javascripts/diffs/components/edit_button.vue
@@ -32,11 +32,5 @@ export default {
</script>
<template>
- <a
- :href="editPath"
- class="btn btn-default js-edit-blob"
- @click="handleEditClick"
- >
- Edit
- </a>
+ <a :href="editPath" class="btn btn-default js-edit-blob" @click="handleEditClick"> Edit </a>
</template>
diff --git a/app/assets/javascripts/diffs/components/file_row_stats.vue b/app/assets/javascripts/diffs/components/file_row_stats.vue
index 105f7ebdbed..784f74e498f 100644
--- a/app/assets/javascripts/diffs/components/file_row_stats.vue
+++ b/app/assets/javascripts/diffs/components/file_row_stats.vue
@@ -10,16 +10,9 @@ export default {
</script>
<template>
- <span
- v-once
- class="file-row-stats"
- >
- <span class="cgreen">
- +{{ file.addedLines }}
- </span>
- <span class="cred">
- -{{ file.removedLines }}
- </span>
+ <span v-once class="file-row-stats">
+ <span class="cgreen"> +{{ file.addedLines }} </span>
+ <span class="cred"> -{{ file.removedLines }} </span>
</span>
</template>
diff --git a/app/assets/javascripts/diffs/components/hidden_files_warning.vue b/app/assets/javascripts/diffs/components/hidden_files_warning.vue
index 017dcfcc357..119e139de21 100644
--- a/app/assets/javascripts/diffs/components/hidden_files_warning.vue
+++ b/app/assets/javascripts/diffs/components/hidden_files_warning.vue
@@ -26,26 +26,13 @@ export default {
<h4>
{{ __('Too many changes to show.') }}
<div class="pull-right">
- <a
- :href="plainDiffPath"
- class="btn btn-sm"
- >
- {{ __('Plain diff') }}
- </a>
- <a
- :href="emailPatchPath"
- class="btn btn-sm"
- >
- {{ __('Email patch') }}
- </a>
+ <a :href="plainDiffPath" class="btn btn-sm"> {{ __('Plain diff') }} </a>
+ <a :href="emailPatchPath" class="btn btn-sm"> {{ __('Email patch') }} </a>
</div>
</h4>
<p>
- To preserve performance only
- <strong>
- {{ visible }} of {{ total }}
- </strong>
- files are displayed.
+ To preserve performance only <strong> {{ visible }} of {{ total }} </strong> files are
+ displayed.
</p>
</div>
</template>
diff --git a/app/assets/javascripts/diffs/components/image_diff_overlay.vue b/app/assets/javascripts/diffs/components/image_diff_overlay.vue
index ae1b0a52901..d30e64312aa 100644
--- a/app/assets/javascripts/diffs/components/image_diff_overlay.vue
+++ b/app/assets/javascripts/diffs/components/image_diff_overlay.vue
@@ -97,11 +97,9 @@ export default {
v-if="canComment"
type="button"
class="btn-transparent position-absolute image-diff-overlay-add-comment w-100 h-100 js-add-image-diff-note-button"
- @click="clickedImage($event.offsetX, $event.offsetY)"
+ @click="clickedImage($event.offsetX, $event.offsetY);"
>
- <span class="sr-only">
- {{ __('Add image comment') }}
- </span>
+ <span class="sr-only"> {{ __('Add image comment') }} </span>
</button>
<button
v-for="(discussion, index) in allDiscussions"
@@ -111,12 +109,9 @@ export default {
:disabled="!shouldToggleDiscussion"
class="js-image-badge"
type="button"
- @click="toggleDiscussion({ discussionId: discussion.id })"
+ @click="toggleDiscussion({ discussionId: discussion.id });"
>
- <icon
- v-if="showCommentIcon"
- name="image-comment-dark"
- />
+ <icon v-if="showCommentIcon" name="image-comment-dark" />
<template v-else>
{{ index + 1 }}
</template>
@@ -125,15 +120,13 @@ export default {
v-if="currentCommentForm"
:style="{
left: `${currentCommentForm.x}px`,
- top: `${currentCommentForm.y}px`
+ top: `${currentCommentForm.y}px`,
}"
:aria-label="__('Comment form position')"
class="btn-transparent comment-indicator"
type="button"
>
- <icon
- name="image-comment-dark"
- />
+ <icon name="image-comment-dark" />
</button>
</div>
</template>
diff --git a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue
index b9e14c53d2c..aa40b24950a 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue
@@ -1,5 +1,4 @@
<script>
-import { mapState } from 'vuex';
import diffDiscussions from './diff_discussions.vue';
import diffLineNoteForm from './diff_line_note_form.vue';
@@ -17,38 +16,31 @@ export default {
type: String,
required: true,
},
- lineIndex: {
- type: Number,
- required: true,
- },
},
computed: {
- ...mapState({
- diffLineCommentForms: state => state.diffs.diffLineCommentForms,
- }),
className() {
return this.line.discussions.length ? '' : 'js-temp-notes-holder';
},
+ shouldRender() {
+ if (this.line.hasForm) return true;
+
+ if (!this.line.discussions || !this.line.discussions.length) {
+ return false;
+ }
+
+ return this.line.discussions.every(discussion => discussion.expanded);
+ },
},
};
</script>
<template>
- <tr
- :class="className"
- class="notes_holder"
- >
- <td
- class="notes_content"
- colspan="3"
- >
+ <tr v-if="shouldRender" :class="className" class="notes_holder">
+ <td class="notes_content" colspan="3">
<div class="content">
- <diff-discussions
- v-if="line.discussions.length"
- :discussions="line.discussions"
- />
+ <diff-discussions v-if="line.discussions.length" :discussions="line.discussions" />
<diff-line-note-form
- v-if="diffLineCommentForms[line.line_code]"
+ v-if="line.hasForm"
:diff-file-hash="diffFileHash"
:line="line"
:note-target-line="line"
diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
index 1f4088066d1..c764cbeb8e0 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
@@ -1,5 +1,5 @@
<script>
-import { mapGetters, mapActions } from 'vuex';
+import { mapGetters, mapActions, mapState } from 'vuex';
import DiffTableCell from './diff_table_cell.vue';
import {
NEW_LINE_TYPE,
@@ -40,6 +40,11 @@ export default {
};
},
computed: {
+ ...mapState({
+ isHighlighted(state) {
+ return this.line.line_code !== null && this.line.line_code === state.diffs.highlightedRow;
+ },
+ }),
...mapGetters('diffs', ['isInlineView']),
isContextLine() {
return this.line.type === CONTEXT_LINE_TYPE;
@@ -91,6 +96,7 @@ export default {
:is-bottom="isBottom"
:is-hover="isHover"
:show-comment-button="true"
+ :is-highlighted="isHighlighted"
class="diff-line-num old_line"
/>
<diff-table-cell
@@ -100,13 +106,18 @@ export default {
:line-type="newLineType"
:is-bottom="isBottom"
:is-hover="isHover"
+ :is-highlighted="isHighlighted"
class="diff-line-num new_line qa-new-diff-line"
/>
<td
- :class="line.type"
+ :class="[
+ line.type,
+ {
+ hll: isHighlighted,
+ },
+ ]"
class="line_content"
v-html="line.rich_text"
- >
- </td>
+ ></td>
</tr>
</template>
diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue
index 79efac89e98..6a0ce760e6d 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_view.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue
@@ -1,5 +1,5 @@
<script>
-import { mapGetters, mapState } from 'vuex';
+import { mapGetters } from 'vuex';
import inlineDiffTableRow from './inline_diff_table_row.vue';
import inlineDiffCommentRow from './inline_diff_comment_row.vue';
@@ -19,29 +19,23 @@ export default {
},
},
computed: {
- ...mapGetters('diffs', ['commitId', 'shouldRenderInlineCommentRow']),
- ...mapState({
- diffLineCommentForms: state => state.diffs.diffLineCommentForms,
- }),
+ ...mapGetters('diffs', ['commitId']),
diffLinesLength() {
return this.diffLines.length;
},
- userColorScheme() {
- return window.gon.user_color_scheme;
- },
},
+ userColorScheme: window.gon.user_color_scheme,
};
</script>
<template>
<table
- :class="userColorScheme"
+ :class="$options.userColorScheme"
:data-commit-id="commitId"
- class="code diff-wrap-lines js-syntax-highlight text-file js-diff-inline-view">
+ class="code diff-wrap-lines js-syntax-highlight text-file js-diff-inline-view"
+ >
<tbody>
- <template
- v-for="(line, index) in diffLines"
- >
+ <template v-for="(line, index) in diffLines">
<inline-diff-table-row
:key="line.line_code"
:file-hash="diffFile.file_hash"
@@ -50,11 +44,9 @@ export default {
:is-bottom="index + 1 === diffLinesLength"
/>
<inline-diff-comment-row
- v-if="shouldRenderInlineCommentRow(line)"
- :key="index"
+ :key="`icr-${index}`"
:diff-file-hash="diffFile.file_hash"
:line="line"
- :line-index="index"
/>
</template>
</tbody>
diff --git a/app/assets/javascripts/diffs/components/no_changes.vue b/app/assets/javascripts/diffs/components/no_changes.vue
index 6905630ad8c..25ec157ed25 100644
--- a/app/assets/javascripts/diffs/components/no_changes.vue
+++ b/app/assets/javascripts/diffs/components/no_changes.vue
@@ -19,29 +19,16 @@ export default {
</script>
<template>
- <div
- class="row empty-state nothing-here-block"
- >
+ <div class="row empty-state nothing-here-block">
<div class="col-xs-12">
- <div class="svg-content">
- <span
- v-html="emptyImage"
- ></span>
- </div>
+ <div class="svg-content"><span v-html="emptyImage"></span></div>
</div>
<div class="col-xs-12">
<div class="text-content text-center">
- No changes between
- <span class="ref-name">{{ sourceBranch }}</span>
- and
+ No changes between <span class="ref-name">{{ sourceBranch }}</span> and
<span class="ref-name">{{ targetBranch }}</span>
<div class="text-center">
- <a
- :href="newBlobPath"
- class="btn btn-success"
- >
- {{ __('Create commit') }}
- </a>
+ <a :href="newBlobPath" class="btn btn-success"> {{ __('Create commit') }} </a>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
index 00c2df4dac1..b98463d3dd3 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
@@ -1,5 +1,4 @@
<script>
-import { mapState } from 'vuex';
import diffDiscussions from './diff_discussions.vue';
import diffLineNoteForm from './diff_line_note_form.vue';
@@ -23,22 +22,13 @@ export default {
},
},
computed: {
- ...mapState({
- diffLineCommentForms: state => state.diffs.diffLineCommentForms,
- }),
- leftLineCode() {
- return this.line.left && this.line.left.line_code;
- },
- rightLineCode() {
- return this.line.right && this.line.right.line_code;
- },
hasExpandedDiscussionOnLeft() {
- return this.line.left && this.line.left.discussions
+ return this.line.left && this.line.left.discussions.length
? this.line.left.discussions.every(discussion => discussion.expanded)
: false;
},
hasExpandedDiscussionOnRight() {
- return this.line.right && this.line.right.discussions
+ return this.line.right && this.line.right.discussions.length
? this.line.right.discussions.every(discussion => discussion.expanded)
: false;
},
@@ -57,9 +47,10 @@ export default {
);
},
showRightSideCommentForm() {
- return (
- this.line.right && this.line.right.type && this.diffLineCommentForms[this.rightLineCode]
- );
+ return this.line.right && this.line.right.type && this.line.right.hasForm;
+ },
+ showLeftSideCommentForm() {
+ return this.line.left && this.line.left.hasForm;
},
className() {
return (this.left && this.line.left.discussions.length > 0) ||
@@ -67,42 +58,47 @@ export default {
? ''
: 'js-temp-notes-holder';
},
+ shouldRender() {
+ const { line } = this;
+ const hasDiscussion =
+ (line.left && line.left.discussions && line.left.discussions.length) ||
+ (line.right && line.right.discussions && line.right.discussions.length);
+
+ if (
+ hasDiscussion &&
+ (this.hasExpandedDiscussionOnLeft || this.hasExpandedDiscussionOnRight)
+ ) {
+ return true;
+ }
+
+ const hasCommentFormOnLeft = line.left && line.left.hasForm;
+ const hasCommentFormOnRight = line.right && line.right.hasForm;
+
+ return hasCommentFormOnLeft || hasCommentFormOnRight;
+ },
},
};
</script>
<template>
- <tr
- :class="className"
- class="notes_holder"
- >
- <td
- class="notes_content parallel old"
- colspan="2">
- <div
- v-if="shouldRenderDiscussionsOnLeft"
- class="content"
- >
+ <tr v-if="shouldRender" :class="className" class="notes_holder">
+ <td class="notes_content parallel old" colspan="2">
+ <div v-if="shouldRenderDiscussionsOnLeft" class="content">
<diff-discussions
v-if="line.left.discussions.length"
:discussions="line.left.discussions"
/>
</div>
<diff-line-note-form
- v-if="diffLineCommentForms[leftLineCode]"
+ v-if="showLeftSideCommentForm"
:diff-file-hash="diffFileHash"
:line="line.left"
:note-target-line="line.left"
line-position="left"
/>
</td>
- <td
- class="notes_content parallel new"
- colspan="2">
- <div
- v-if="shouldRenderDiscussionsOnRight"
- class="content"
- >
+ <td class="notes_content parallel new" colspan="2">
+ <div v-if="shouldRenderDiscussionsOnRight" class="content">
<diff-discussions
v-if="line.right.discussions.length"
:discussions="line.right.discussions"
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
index 2d87db12fd6..caf0df8a4e3 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
@@ -1,5 +1,5 @@
<script>
-import { mapActions } from 'vuex';
+import { mapActions, mapState } from 'vuex';
import $ from 'jquery';
import DiffTableCell from './diff_table_cell.vue';
import {
@@ -43,6 +43,15 @@ export default {
};
},
computed: {
+ ...mapState({
+ isHighlighted(state) {
+ const lineCode =
+ (this.line.left && this.line.left.line_code) ||
+ (this.line.right && this.line.right.line_code);
+
+ return lineCode ? lineCode === state.diffs.highlightedRow : false;
+ },
+ }),
isContextLine() {
return this.line.left && this.line.left.type === CONTEXT_LINE_TYPE;
},
@@ -57,7 +66,14 @@ export default {
return OLD_NO_NEW_LINE_TYPE;
}
- return this.line.left ? this.line.left.type : EMPTY_CELL_TYPE;
+ const lineTypeClass = this.line.left ? this.line.left.type : EMPTY_CELL_TYPE;
+
+ return [
+ lineTypeClass,
+ {
+ hll: this.isHighlighted,
+ },
+ ];
},
},
created() {
@@ -114,6 +130,7 @@ export default {
:line-type="oldLineType"
:is-bottom="isBottom"
:is-hover="isLeftHover"
+ :is-highlighted="isHighlighted"
:show-comment-button="true"
:diff-view-type="parallelDiffViewType"
line-position="left"
@@ -125,8 +142,7 @@ export default {
class="line_content parallel left-side"
@mousedown.native="handleParallelLineMouseDown"
v-html="line.left.rich_text"
- >
- </td>
+ ></td>
</template>
<template v-else>
<td class="diff-line-num old_line empty-cell"></td>
@@ -140,6 +156,7 @@ export default {
:line-type="newLineType"
:is-bottom="isBottom"
:is-hover="isRightHover"
+ :is-highlighted="isHighlighted"
:show-comment-button="true"
:diff-view-type="parallelDiffViewType"
line-position="right"
@@ -147,12 +164,16 @@ export default {
/>
<td
:id="line.right.line_code"
- :class="line.right.type"
+ :class="[
+ line.right.type,
+ {
+ hll: isHighlighted,
+ },
+ ]"
class="line_content parallel right-side"
@mousedown.native="handleParallelLineMouseDown"
v-html="line.right.rich_text"
- >
- </td>
+ ></td>
</template>
<template v-else>
<td class="diff-line-num old_line empty-cell"></td>
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue
index 6942f9b53e0..9a6e0e82529 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue
@@ -1,5 +1,5 @@
<script>
-import { mapState, mapGetters } from 'vuex';
+import { mapGetters } from 'vuex';
import parallelDiffTableRow from './parallel_diff_table_row.vue';
import parallelDiffCommentRow from './parallel_diff_comment_row.vue';
@@ -19,31 +19,24 @@ export default {
},
},
computed: {
- ...mapGetters('diffs', ['commitId', 'shouldRenderParallelCommentRow']),
- ...mapState({
- diffLineCommentForms: state => state.diffs.diffLineCommentForms,
- }),
+ ...mapGetters('diffs', ['commitId']),
diffLinesLength() {
return this.diffLines.length;
},
- userColorScheme() {
- return window.gon.user_color_scheme;
- },
},
+ userColorScheme: window.gon.user_color_scheme,
};
</script>
<template>
<div
- :class="userColorScheme"
+ :class="$options.userColorScheme"
:data-commit-id="commitId"
class="code diff-wrap-lines js-syntax-highlight text-file"
>
<table>
<tbody>
- <template
- v-for="(line, index) in diffLines"
- >
+ <template v-for="(line, index) in diffLines">
<parallel-diff-table-row
:key="index"
:file-hash="diffFile.file_hash"
@@ -52,7 +45,6 @@ export default {
:is-bottom="index + 1 === diffLinesLength"
/>
<parallel-diff-comment-row
- v-if="shouldRenderParallelCommentRow(line)"
:key="`dcr-${index}`"
:line="line"
:diff-file-hash="diffFile.file_hash"
diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue
index ff1eb23cea3..f40a7b25fde 100644
--- a/app/assets/javascripts/diffs/components/tree_list.vue
+++ b/app/assets/javascripts/diffs/components/tree_list.vue
@@ -1,7 +1,7 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
-import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
+import { GlTooltipDirective } from '@gitlab/ui';
+import { parseBoolean } from '~/lib/utils/common_utils';
import Icon from '~/vue_shared/components/icon.vue';
import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowStats from './file_row_stats.vue';
@@ -18,8 +18,7 @@ export default {
},
data() {
const treeListStored = localStorage.getItem(treeListStorageKey);
- const renderTreeList =
- treeListStored !== null ? convertPermissionToBoolean(treeListStored) : true;
+ const renderTreeList = treeListStored !== null ? parseBoolean(treeListStored) : true;
return {
search: '',
@@ -72,16 +71,13 @@ export default {
<div class="tree-list-holder d-flex flex-column">
<div class="append-bottom-8 position-relative tree-list-search d-flex">
<div class="flex-fill d-flex">
- <icon
- name="search"
- class="position-absolute tree-list-icon"
- />
+ <icon name="search" class="position-absolute tree-list-icon" />
<input
v-model="search"
:placeholder="s__('MergeRequest|Filter files')"
type="search"
class="form-control"
- @focus="toggleFocusSearch(true)"
+ @focus="toggleFocusSearch(true);"
@blur="blurSearch"
/>
<button
@@ -91,50 +87,39 @@ export default {
class="position-absolute bg-transparent tree-list-icon tree-list-clear-icon border-0 p-0"
@click="clearSearch"
>
- <icon
- name="close"
- />
+ <icon name="close" />
</button>
</div>
- <div
- v-show="!focusSearch"
- class="btn-group prepend-left-8 tree-list-view-toggle"
- >
+ <div v-show="!focusSearch" class="btn-group prepend-left-8 tree-list-view-toggle">
<button
v-gl-tooltip.hover
:aria-label="__('List view')"
:title="__('List view')"
:class="{
- active: !renderTreeList
+ active: !renderTreeList,
}"
class="btn btn-default pt-0 pb-0 d-flex align-items-center"
type="button"
- @click="toggleRenderTreeList(false)"
+ @click="toggleRenderTreeList(false);"
>
- <icon
- name="hamburger"
- />
+ <icon name="hamburger" />
</button>
<button
v-gl-tooltip.hover
:aria-label="__('Tree view')"
:title="__('Tree view')"
:class="{
- active: renderTreeList
+ active: renderTreeList,
}"
class="btn btn-default pt-0 pb-0 d-flex align-items-center"
type="button"
- @click="toggleRenderTreeList(true)"
+ @click="toggleRenderTreeList(true);"
>
- <icon
- name="file-tree"
- />
+ <icon name="file-tree" />
</button>
</div>
</div>
- <div
- class="tree-list-scroll"
- >
+ <div class="tree-list-scroll">
<template v-if="filteredTreeList.length">
<file-row
v-for="file in filteredTreeList"
@@ -150,25 +135,15 @@ export default {
@clickFile="scrollToFile"
/>
</template>
- <p
- v-else
- class="prepend-top-20 append-bottom-20 text-center"
- >
+ <p v-else class="prepend-top-20 append-bottom-20 text-center">
{{ s__('MergeRequest|No files found') }}
</p>
</div>
- <div
- v-once
- class="pt-3 pb-3 text-center"
- >
+ <div v-once class="pt-3 pb-3 text-center">
{{ n__('%d changed file', '%d changed files', diffFilesLength) }}
<div>
- <span class="cgreen">
- {{ n__('%d addition', '%d additions', addedLines) }}
- </span>
- <span class="cred">
- {{ n__('%d deleted', '%d deletions', removedLines) }}
- </span>
+ <span class="cgreen"> {{ n__('%d addition', '%d additions', addedLines) }} </span>
+ <span class="cred"> {{ n__('%d deleted', '%d deletions', removedLines) }} </span>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index fb648527450..00a4bb6d3a3 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -3,8 +3,9 @@ import axios from '~/lib/utils/axios_utils';
import Cookies from 'js-cookie';
import createFlash from '~/flash';
import { s__ } from '~/locale';
-import { handleLocationHash, historyPushState } from '~/lib/utils/common_utils';
+import { handleLocationHash, historyPushState, scrollToElement } from '~/lib/utils/common_utils';
import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility';
+import eventHub from '../../notes/event_hub';
import { getDiffPositionByLineCode, getNoteFormData } from './utils';
import * as types from './mutation_types';
import {
@@ -33,6 +34,10 @@ export const fetchDiffFiles = ({ state, commit }) => {
.then(handleLocationHash);
};
+export const setHighlightedRow = ({ commit }, lineCode) => {
+ commit(types.SET_HIGHLIGHTED_ROW, lineCode);
+};
+
// This is adding line discussions to the actual lines in the diff tree
// once for parallel and once for inline mode
export const assignDiscussionsToDiff = (
@@ -41,11 +46,17 @@ export const assignDiscussionsToDiff = (
) => {
const diffPositionByLineCode = getDiffPositionByLineCode(state.diffFiles);
- discussions.filter(discussion => discussion.diff_discussion).forEach(discussion => {
- commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, {
- discussion,
- diffPositionByLineCode,
+ discussions
+ .filter(discussion => discussion.diff_discussion)
+ .forEach(discussion => {
+ commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, {
+ discussion,
+ diffPositionByLineCode,
+ });
});
+
+ Vue.nextTick(() => {
+ eventHub.$emit('scrollToDiscussion');
});
};
@@ -54,6 +65,27 @@ export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => {
commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash: file_hash, lineCode: line_code, id });
};
+export const renderFileForDiscussionId = ({ commit, rootState, state }, discussionId) => {
+ const discussion = rootState.notes.discussions.find(d => d.id === discussionId);
+
+ if (discussion) {
+ const file = state.diffFiles.find(f => f.file_hash === discussion.diff_file.file_hash);
+
+ if (file) {
+ if (!file.renderIt) {
+ commit(types.RENDER_FILE, file);
+ }
+
+ if (file.collapsed) {
+ eventHub.$emit(`loadCollapsedDiff/${file.file_hash}`);
+ scrollToElement(document.getElementById(file.file_hash));
+ } else {
+ eventHub.$emit('scrollToDiscussion');
+ }
+ }
+ }
+};
+
export const startRenderDiffsQueue = ({ state, commit }) => {
const checkItem = () =>
new Promise(resolve => {
@@ -97,12 +129,12 @@ export const setParallelDiffViewType = ({ commit }) => {
historyPushState(url);
};
-export const showCommentForm = ({ commit }, params) => {
- commit(types.ADD_COMMENT_FORM_LINE, params);
+export const showCommentForm = ({ commit }, { lineCode, fileHash }) => {
+ commit(types.TOGGLE_LINE_HAS_FORM, { lineCode, fileHash, hasForm: true });
};
-export const cancelCommentForm = ({ commit }, params) => {
- commit(types.REMOVE_COMMENT_FORM_LINE, params);
+export const cancelCommentForm = ({ commit }, { lineCode, fileHash }) => {
+ commit(types.TOGGLE_LINE_HAS_FORM, { lineCode, fileHash, hasForm: false });
};
export const loadMoreLines = ({ commit }, options) => {
@@ -125,7 +157,7 @@ export const loadMoreLines = ({ commit }, options) => {
export const scrollToLineIfNeededInline = (_, line) => {
const hash = getLocationHash();
- if (hash && line.lineCode === hash) {
+ if (hash && line.line_code === hash) {
handleLocationHash();
}
};
@@ -135,19 +167,25 @@ export const scrollToLineIfNeededParallel = (_, line) => {
if (
hash &&
- ((line.left && line.left.lineCode === hash) || (line.right && line.right.lineCode === hash))
+ ((line.left && line.left.line_code === hash) || (line.right && line.right.line_code === hash))
) {
handleLocationHash();
}
};
-export const loadCollapsedDiff = ({ commit }, file) =>
- axios.get(file.loadCollapsedDiffUrl).then(res => {
- commit(types.ADD_COLLAPSED_DIFFS, {
- file,
- data: res.data,
+export const loadCollapsedDiff = ({ commit, getters }, file) =>
+ axios
+ .get(file.load_collapsed_diff_url, {
+ params: {
+ commit_id: getters.commitId,
+ },
+ })
+ .then(res => {
+ commit(types.ADD_COLLAPSED_DIFFS, {
+ file,
+ data: res.data,
+ });
});
- });
export const expandAllFiles = ({ commit }) => {
commit(types.EXPAND_ALL_FILES);
@@ -167,7 +205,7 @@ export const expandAllFiles = ({ commit }) => {
export const toggleFileDiscussions = ({ getters, dispatch }, diff) => {
const discussions = getters.getDiffFileDiscussions(diff);
const shouldCloseAll = getters.diffHasAllExpandedDiscussions(diff);
- const shouldExpandAll = getters.diffHasAllCollpasedDiscussions(diff);
+ const shouldExpandAll = getters.diffHasAllCollapsedDiscussions(diff);
discussions.forEach(discussion => {
const data = { discussionId: discussion.id };
@@ -180,8 +218,9 @@ export const toggleFileDiscussions = ({ getters, dispatch }, diff) => {
});
};
-export const saveDiffDiscussion = ({ dispatch }, { note, formData }) => {
+export const saveDiffDiscussion = ({ state, dispatch }, { note, formData }) => {
const postData = getNoteFormData({
+ commit: state.commit,
note,
...formData,
});
@@ -189,8 +228,8 @@ export const saveDiffDiscussion = ({ dispatch }, { note, formData }) => {
return dispatch('saveNote', postData, { root: true })
.then(result => dispatch('updateDiscussion', result.discussion, { root: true }))
.then(discussion => dispatch('assignDiscussionsToDiff', [discussion]))
+ .then(() => dispatch('updateResolvableDiscussonsCounts', null, { root: true }))
.then(() => dispatch('closeDiffFileCommentForm', formData.diffFile.file_hash))
- .then(() => dispatch('startTaskList', null, { root: true }))
.catch(() => createFlash(s__('MergeRequests|Saving the comment failed')));
};
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 7f02c67a64e..fdf1efbb10e 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -23,11 +23,11 @@ export const diffHasAllExpandedDiscussions = (state, getters) => diff => {
};
/**
- * Checks if the diff has all discussions collpased
+ * Checks if the diff has all discussions collapsed
* @param {Object} diff
* @returns {Boolean}
*/
-export const diffHasAllCollpasedDiscussions = (state, getters) => diff => {
+export const diffHasAllCollapsedDiscussions = (state, getters) => diff => {
const discussions = getters.getDiffFileDiscussions(diff);
return (
@@ -70,40 +70,6 @@ export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) =
discussion => discussion.diff_discussion && discussion.diff_file.file_hash === diff.file_hash,
) || [];
-export const shouldRenderParallelCommentRow = state => line => {
- const hasDiscussion =
- (line.left && line.left.discussions && line.left.discussions.length) ||
- (line.right && line.right.discussions && line.right.discussions.length);
-
- const hasExpandedDiscussionOnLeft =
- line.left && line.left.discussions && line.left.discussions.length
- ? line.left.discussions.every(discussion => discussion.expanded)
- : false;
- const hasExpandedDiscussionOnRight =
- line.right && line.right.discussions && line.right.discussions.length
- ? line.right.discussions.every(discussion => discussion.expanded)
- : false;
-
- if (hasDiscussion && (hasExpandedDiscussionOnLeft || hasExpandedDiscussionOnRight)) {
- return true;
- }
-
- const hasCommentFormOnLeft = line.left && state.diffLineCommentForms[line.left.line_code];
- const hasCommentFormOnRight = line.right && state.diffLineCommentForms[line.right.line_code];
-
- return hasCommentFormOnLeft || hasCommentFormOnRight;
-};
-
-export const shouldRenderInlineCommentRow = state => line => {
- if (state.diffLineCommentForms[line.line_code]) return true;
-
- if (!line.discussions || line.discussions.length === 0) {
- return false;
- }
-
- return line.discussions.every(discussion => discussion.expanded);
-};
-
// prevent babel-plugin-rewire from generating an invalid default during karma∂ tests
export const getDiffFileByHash = state => fileHash =>
state.diffFiles.find(file => file.file_hash === fileHash);
diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js
index 085e255f1d3..98e57d52d77 100644
--- a/app/assets/javascripts/diffs/store/modules/diff_state.js
+++ b/app/assets/javascripts/diffs/store/modules/diff_state.js
@@ -1,6 +1,7 @@
import Cookies from 'js-cookie';
import { getParameterValues } from '~/lib/utils/url_utility';
import bp from '~/breakpoints';
+import { parseBoolean } from '~/lib/utils/common_utils';
import { INLINE_DIFF_VIEW_TYPE, DIFF_VIEW_COOKIE_NAME, MR_TREE_SHOW_KEY } from '../../constants';
const viewTypeFromQueryString = getParameterValues('view')[0];
@@ -17,13 +18,13 @@ export default () => ({
diffFiles: [],
mergeRequestDiffs: [],
mergeRequestDiff: null,
- diffLineCommentForms: {},
diffViewType: viewTypeFromQueryString || viewTypeFromCookie || defaultViewType,
tree: [],
treeEntries: {},
showTreeList:
- storedTreeShow === null ? bp.getBreakpointSize() !== 'xs' : storedTreeShow === 'true',
+ storedTreeShow === null ? bp.getBreakpointSize() !== 'xs' : parseBoolean(storedTreeShow),
currentDiffFileId: '',
projectPath: '',
commentForms: [],
+ highlightedRow: null,
});
diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js
index e011031e72c..0338cde3658 100644
--- a/app/assets/javascripts/diffs/store/mutation_types.js
+++ b/app/assets/javascripts/diffs/store/mutation_types.js
@@ -3,8 +3,7 @@ export const SET_LOADING = 'SET_LOADING';
export const SET_DIFF_DATA = 'SET_DIFF_DATA';
export const SET_DIFF_VIEW_TYPE = 'SET_DIFF_VIEW_TYPE';
export const SET_MERGE_REQUEST_DIFFS = 'SET_MERGE_REQUEST_DIFFS';
-export const ADD_COMMENT_FORM_LINE = 'ADD_COMMENT_FORM_LINE';
-export const REMOVE_COMMENT_FORM_LINE = 'REMOVE_COMMENT_FORM_LINE';
+export const TOGGLE_LINE_HAS_FORM = 'TOGGLE_LINE_HAS_FORM';
export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES';
export const ADD_COLLAPSED_DIFFS = 'ADD_COLLAPSED_DIFFS';
export const EXPAND_ALL_FILES = 'EXPAND_ALL_FILES';
@@ -18,3 +17,4 @@ export const UPDATE_CURRENT_DIFF_FILE_ID = 'UPDATE_CURRENT_DIFF_FILE_ID';
export const OPEN_DIFF_FILE_COMMENT_FORM = 'OPEN_DIFF_FILE_COMMENT_FORM';
export const UPDATE_DIFF_FILE_COMMENT_FORM = 'UPDATE_DIFF_FILE_COMMENT_FORM';
export const CLOSE_DIFF_FILE_COMMENT_FORM = 'CLOSE_DIFF_FILE_COMMENT_FORM';
+export const SET_HIGHLIGHTED_ROW = 'SET_HIGHLIGHTED_ROW';
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 2133cfe4825..61314db1dbd 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -1,4 +1,3 @@
-import Vue from 'vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { sortTree } from '~/ide/stores/utils';
import {
@@ -49,12 +48,30 @@ export default {
Object.assign(state, { diffViewType });
},
- [types.ADD_COMMENT_FORM_LINE](state, { lineCode }) {
- Vue.set(state.diffLineCommentForms, lineCode, true);
- },
+ [types.TOGGLE_LINE_HAS_FORM](state, { lineCode, fileHash, hasForm }) {
+ const diffFile = state.diffFiles.find(f => f.file_hash === fileHash);
+
+ if (!diffFile) return;
+
+ if (diffFile.highlighted_diff_lines) {
+ diffFile.highlighted_diff_lines.find(l => l.line_code === lineCode).hasForm = hasForm;
+ }
+
+ if (diffFile.parallel_diff_lines) {
+ const line = diffFile.parallel_diff_lines.find(l => {
+ const { left, right } = l;
+
+ return (left && left.line_code === lineCode) || (right && right.line_code === lineCode);
+ });
+
+ if (line.left && line.left.line_code === lineCode) {
+ line.left.hasForm = hasForm;
+ }
- [types.REMOVE_COMMENT_FORM_LINE](state, { lineCode }) {
- Vue.delete(state.diffLineCommentForms, lineCode);
+ if (line.right && line.right.line_code === lineCode) {
+ line.right.hasForm = hasForm;
+ }
+ }
},
[types.ADD_CONTEXT_LINES](state, options) {
@@ -68,6 +85,7 @@ export default {
...line,
line_code: line.line_code || `${fileHash}_${line.old_line}_${line.new_line}`,
discussions: line.discussions || [],
+ hasForm: false,
}));
addContextLines({
@@ -112,7 +130,7 @@ export default {
if (file.highlighted_diff_lines) {
file.highlighted_diff_lines = file.highlighted_diff_lines.map(line => {
- if (lineCheck(line)) {
+ if (!line.discussions.some(({ id }) => discussion.id === id) && lineCheck(line)) {
return {
...line,
discussions: line.discussions.concat(discussion),
@@ -132,11 +150,17 @@ export default {
return {
left: {
...line.left,
- discussions: left ? line.left.discussions.concat(discussion) : [],
+ discussions:
+ left && !line.left.discussions.some(({ id }) => id === discussion.id)
+ ? line.left.discussions.concat(discussion)
+ : (line.left && line.left.discussions) || [],
},
right: {
...line.right,
- discussions: right && !left ? line.right.discussions.concat(discussion) : [],
+ discussions:
+ right && !left && !line.right.discussions.some(({ id }) => id === discussion.id)
+ ? line.right.discussions.concat(discussion)
+ : (line.right && line.right.discussions) || [],
},
};
}
@@ -146,7 +170,7 @@ export default {
}
if (!file.parallel_diff_lines || !file.highlighted_diff_lines) {
- file.discussions = file.discussions.concat(discussion);
+ file.discussions = (file.discussions || []).concat(discussion);
}
return file;
@@ -223,4 +247,7 @@ export default {
[types.CLOSE_DIFF_FILE_COMMENT_FORM](state, fileHash) {
state.commentForms = state.commentForms.filter(form => form.fileHash !== fileHash);
},
+ [types.SET_HIGHLIGHTED_ROW](state, lineCode) {
+ state.highlightedRow = lineCode;
+ },
};
diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js
index d9d3c0f2ca2..cbaa0e26395 100644
--- a/app/assets/javascripts/diffs/store/utils.js
+++ b/app/assets/javascripts/diffs/store/utils.js
@@ -27,6 +27,7 @@ export const getReversePosition = linePosition => {
export function getFormData(params) {
const {
+ commit,
note,
noteableType,
noteableData,
@@ -66,7 +67,7 @@ export function getFormData(params) {
position,
noteable_type: noteableType,
noteable_id: noteableData.id,
- commit_id: '',
+ commit_id: commit && commit.id,
type:
diffFile.diff_refs.start_sha && diffFile.diff_refs.head_sha
? DIFF_NOTE_TYPE
@@ -209,9 +210,11 @@ export function prepareDiffData(diffData) {
const line = file.parallel_diff_lines[u];
if (line.left) {
line.left = trimFirstCharOfLineContent(line.left);
+ line.left.hasForm = false;
}
if (line.right) {
line.right = trimFirstCharOfLineContent(line.right);
+ line.right.hasForm = false;
}
}
}
@@ -220,7 +223,7 @@ export function prepareDiffData(diffData) {
const linesLength = file.highlighted_diff_lines.length;
for (let u = 0; u < linesLength; u += 1) {
const line = file.highlighted_diff_lines[u];
- Object.assign(line, { ...trimFirstCharOfLineContent(line) });
+ Object.assign(line, { ...trimFirstCharOfLineContent(line), hasForm: false });
}
showingLines += file.parallel_diff_lines.length;
}
@@ -322,5 +325,9 @@ export const generateTreeList = files =>
export const getDiffMode = diffFile => {
const diffModeKey = Object.keys(diffModes).find(key => diffFile[`${key}_file`]);
- return diffModes[diffModeKey] || diffModes.replaced;
+ return (
+ diffModes[diffModeKey] ||
+ (diffFile.mode_changed && diffModes.mode_changed) ||
+ diffModes.replaced
+ );
};
diff --git a/app/assets/javascripts/environments/components/container.vue b/app/assets/javascripts/environments/components/container.vue
index a48f5fcb7d6..bd402c0eea5 100644
--- a/app/assets/javascripts/environments/components/container.vue
+++ b/app/assets/javascripts/environments/components/container.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import tablePagination from '../../vue_shared/components/table_pagination.vue';
import environmentTable from '../components/environments_table.vue';
@@ -41,7 +41,6 @@ export default {
<template>
<div class="environments-container">
-
<gl-loading-icon
v-if="isLoading"
:size="3"
@@ -51,10 +50,7 @@ export default {
<slot name="emptyState"></slot>
- <div
- v-if="!isLoading && environments.length > 0"
- class="table-holder">
-
+ <div v-if="!isLoading && environments.length > 0" class="table-holder">
<environment-table
:environments="environments"
:can-create-deployment="canCreateDeployment"
diff --git a/app/assets/javascripts/environments/components/empty_state.vue b/app/assets/javascripts/environments/components/empty_state.vue
index 2360a52645b..ca2ac4c3c53 100644
--- a/app/assets/javascripts/environments/components/empty_state.vue
+++ b/app/assets/javascripts/environments/components/empty_state.vue
@@ -24,11 +24,11 @@ export default {
{{ s__("Environments|You don't have any environments right now") }}
</h4>
<p class="blank-state-text">
- {{ s__(`Environments|Environments are places where
- code gets deployed, such as staging or production.`) }}
- <a :href="helpPath">
- {{ s__("Environments|Read more about environments") }}
- </a>
+ {{
+ s__(`Environments|Environments are places where
+ code gets deployed, such as staging or production.`)
+ }}
+ <a :href="helpPath"> {{ s__('Environments|Read more about environments') }} </a>
</p>
<div class="text-center">
@@ -37,7 +37,7 @@ export default {
:href="newPath"
class="btn btn-success js-new-environment-button"
>
- {{ s__("Environments|New environment") }}
+ {{ s__('Environments|New environment') }}
</a>
</div>
</div>
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index 03c3ad0401f..1f7dab9fbd2 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -4,7 +4,7 @@ import { formatTime } from '~/lib/utils/datetime_utility';
import Icon from '~/vue_shared/components/icon.vue';
import eventHub from '../event_hub';
import tooltip from '../../vue_shared/directives/tooltip';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
export default {
directives: {
@@ -68,9 +68,7 @@ export default {
};
</script>
<template>
- <div
- class="btn-group"
- role="group">
+ <div class="btn-group" role="group">
<button
v-tooltip
:title="title"
@@ -82,34 +80,23 @@ export default {
data-toggle="dropdown"
>
<span>
- <icon name="play" />
- <icon
- name="chevron-down"
- />
+ <icon name="play" /> <icon name="chevron-down" />
<gl-loading-icon v-if="isLoading" />
</span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
- <li
- v-for="(action, i) in actions"
- :key="i">
+ <li v-for="(action, i) in actions" :key="i">
<button
:class="{ disabled: isActionDisabled(action) }"
:disabled="isActionDisabled(action)"
type="button"
class="js-manual-action-link no-btn btn d-flex align-items-center"
- @click="onClickAction(action)"
+ @click="onClickAction(action);"
>
- <span class="flex-fill">
- {{ action.name }}
- </span>
- <span
- v-if="action.scheduledAt"
- class="text-secondary"
- >
- <icon name="clock" />
- {{ remainingTime(action) }}
+ <span class="flex-fill"> {{ action.name }} </span>
+ <span v-if="action.scheduledAt" class="text-secondary">
+ <icon name="clock" /> {{ remainingTime(action) }}
</span>
</button>
</li>
diff --git a/app/assets/javascripts/environments/components/environment_external_url.vue b/app/assets/javascripts/environments/components/environment_external_url.vue
index 1e8a892c0b8..af537cfb991 100644
--- a/app/assets/javascripts/environments/components/environment_external_url.vue
+++ b/app/assets/javascripts/environments/components/environment_external_url.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { s__ } from '~/locale';
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index 50b0e9747ee..cd2f46fd07a 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -1,7 +1,7 @@
<script>
import Timeago from 'timeago.js';
import _ from 'underscore';
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import { humanize } from '~/lib/utils/text_utility';
import Icon from '~/vue_shared/components/icon.vue';
@@ -453,53 +453,28 @@ export default {
'folder-row': model.isFolder,
}"
class="gl-responsive-table-row"
- role="row">
+ role="row"
+ >
<div
v-gl-tooltip
:title="model.name"
class="table-section section-wrap section-15 text-truncate"
role="gridcell"
>
- <div
- v-if="!model.isFolder"
- class="table-mobile-header"
- role="rowheader"
- >
- {{ s__("Environments|Environment") }}
+ <div v-if="!model.isFolder" class="table-mobile-header" role="rowheader">
+ {{ s__('Environments|Environment') }}
</div>
- <span
- v-if="!model.isFolder"
- class="environment-name table-mobile-content">
- <a
- class="qa-environment-link"
- :href="environmentPath"
- >
- {{ model.name }}
- </a>
+ <span v-if="!model.isFolder" class="environment-name table-mobile-content">
+ <a class="qa-environment-link" :href="environmentPath"> {{ model.name }} </a>
</span>
- <span
- v-else
- class="folder-name"
- role="button"
- @click="onClickFolder">
-
- <icon
- :name="folderIconName"
- class="folder-icon"
- />
+ <span v-else class="folder-name" role="button" @click="onClickFolder">
+ <icon :name="folderIconName" class="folder-icon" />
- <icon
- name="folder"
- class="folder-icon"
- />
+ <icon name="folder" class="folder-icon" />
- <span>
- {{ model.folderName }}
- </span>
+ <span> {{ model.folderName }} </span>
- <span class="badge badge-pill">
- {{ model.size }}
- </span>
+ <span class="badge badge-pill"> {{ model.size }} </span>
</span>
</div>
@@ -507,9 +482,7 @@ export default {
class="table-section section-10 deployment-column d-none d-sm-none d-md-block"
role="gridcell"
>
- <span v-if="shouldRenderDeploymentID">
- {{ deploymentInternalId }}
- </span>
+ <span v-if="shouldRenderDeploymentID"> {{ deploymentInternalId }} </span>
<span v-if="!model.isFolder && deploymentHasUser">
by
@@ -523,61 +496,32 @@ export default {
</span>
</div>
- <div
- class="table-section section-15 d-none d-sm-none d-md-block"
- role="gridcell"
- >
- <a
- v-if="shouldRenderBuildName"
- :href="buildPath"
- class="build-link flex-truncate-parent"
- >
+ <div class="table-section section-15 d-none d-sm-none d-md-block" role="gridcell">
+ <a v-if="shouldRenderBuildName" :href="buildPath" class="build-link flex-truncate-parent">
<span class="flex-truncate-child">{{ buildName }}</span>
</a>
</div>
- <div
- v-if="!model.isFolder"
- class="table-section section-20"
- role="gridcell"
- >
- <div
- role="rowheader"
- class="table-mobile-header"
- >
- {{ s__("Environments|Commit") }}
- </div>
- <div
- v-if="hasLastDeploymentKey"
- class="js-commit-component table-mobile-content">
+ <div v-if="!model.isFolder" class="table-section section-20" role="gridcell">
+ <div role="rowheader" class="table-mobile-header">{{ s__('Environments|Commit') }}</div>
+ <div v-if="hasLastDeploymentKey" class="js-commit-component table-mobile-content">
<commit-component
:tag="commitTag"
:commit-ref="commitRef"
:commit-url="commitUrl"
:short-sha="commitShortSha"
:title="commitTitle"
- :author="commitAuthor"/>
+ :author="commitAuthor"
+ />
</div>
- <div
- v-if="!hasLastDeploymentKey"
- class="commit-title table-mobile-content">
- {{ s__("Environments|No deployments yet") }}
+ <div v-if="!hasLastDeploymentKey" class="commit-title table-mobile-content">
+ {{ s__('Environments|No deployments yet') }}
</div>
</div>
- <div
- v-if="!model.isFolder"
- class="table-section section-10"
- role="gridcell"
- >
- <div
- role="rowheader"
- class="table-mobile-header">
- {{ s__("Environments|Updated") }}
- </div>
- <span
- v-if="canShowDate"
- class="environment-created-date-timeago table-mobile-content">
+ <div v-if="!model.isFolder" class="table-section section-10" role="gridcell">
+ <div role="rowheader" class="table-mobile-header">{{ s__('Environments|Updated') }}</div>
+ <span v-if="canShowDate" class="environment-created-date-timeago table-mobile-content">
{{ createdDate }}
</span>
</div>
@@ -585,12 +529,9 @@ export default {
<div
v-if="!model.isFolder && displayEnvironmentActions"
class="table-section section-30 table-button-footer"
- role="gridcell">
-
- <div
- class="btn-group table-action-buttons"
- role="group">
-
+ role="gridcell"
+ >
+ <div class="btn-group table-action-buttons" role="group">
<external-url-component
v-if="externalURL && canReadEnvironment"
:external-url="externalURL"
@@ -601,10 +542,7 @@ export default {
:monitoring-url="monitoringUrl"
/>
- <actions-component
- v-if="actions.length > 0"
- :actions="actions"
- />
+ <actions-component v-if="actions.length > 0" :actions="actions" />
<terminal-button-component
v-if="model && model.terminal_path"
@@ -617,10 +555,7 @@ export default {
:retry-url="retryUrl"
/>
- <stop-component
- v-if="canStopEnvironment"
- :environment="model"
- />
+ <stop-component v-if="canStopEnvironment" :environment="model" />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/environments/components/environment_monitoring.vue b/app/assets/javascripts/environments/components/environment_monitoring.vue
index 7c723fa8979..ae4f07a71cd 100644
--- a/app/assets/javascripts/environments/components/environment_monitoring.vue
+++ b/app/assets/javascripts/environments/components/environment_monitoring.vue
@@ -2,7 +2,7 @@
/**
* Renders the Monitoring (Metrics) link in environments table.
*/
-import { GlButton, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
export default {
diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue
index 298469e6482..50c86af057c 100644
--- a/app/assets/javascripts/environments/components/environment_rollback.vue
+++ b/app/assets/javascripts/environments/components/environment_rollback.vue
@@ -6,7 +6,7 @@
* Makes a post request when the button is clicked.
*/
import { s__ } from '~/locale';
-import { GlTooltipDirective, GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import eventHub from '../event_hub';
@@ -61,14 +61,7 @@ export default {
class="btn d-none d-sm-none d-md-block"
@click="onClick"
>
- <icon
- v-if="isLastDeployment"
- name="repeat"
- />
- <icon
- v-else
- name="redo"
- />
+ <icon v-if="isLastDeployment" name="repeat" /> <icon v-else name="redo" />
<gl-loading-icon v-if="isLoading" />
</button>
</template>
diff --git a/app/assets/javascripts/environments/components/environment_stop.vue b/app/assets/javascripts/environments/components/environment_stop.vue
index 327c96a93e9..99f50b499d0 100644
--- a/app/assets/javascripts/environments/components/environment_stop.vue
+++ b/app/assets/javascripts/environments/components/environment_stop.vue
@@ -5,7 +5,7 @@
*/
import $ from 'jquery';
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
@@ -65,6 +65,6 @@ export default {
data-target="#stop-environment-modal"
@click="onClick"
>
- <icon name="stop"/>
+ <icon name="stop" />
</loading-button>
</template>
diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.vue b/app/assets/javascripts/environments/components/environment_terminal_button.vue
index b8b909f350c..83727caad16 100644
--- a/app/assets/javascripts/environments/components/environment_terminal_button.vue
+++ b/app/assets/javascripts/environments/components/environment_terminal_button.vue
@@ -3,7 +3,7 @@
* Renders a terminal button to open a web terminal.
* Used in environments table.
*/
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
export default {
diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue
index 557b2062c64..ae9459a2482 100644
--- a/app/assets/javascripts/environments/components/environments_app.vue
+++ b/app/assets/javascripts/environments/components/environments_app.vue
@@ -93,21 +93,11 @@ export default {
<stop-environment-modal :environment="environmentInStopModal" />
<div class="top-area">
- <tabs
- :tabs="tabs"
- scope="environments"
- @onChangeTab="onChangeTab"
- />
+ <tabs :tabs="tabs" scope="environments" @onChangeTab="onChangeTab" />
- <div
- v-if="canCreateEnvironment && !isLoading"
- class="nav-controls"
- >
- <a
- :href="newEnvironmentPath"
- class="btn btn-success"
- >
- {{ s__("Environments|New environment") }}
+ <div v-if="canCreateEnvironment && !isLoading" class="nav-controls">
+ <a :href="newEnvironmentPath" class="btn btn-success">
+ {{ s__('Environments|New environment') }}
</a>
</div>
</div>
diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue
index c03d4f29ff9..533e90e2222 100644
--- a/app/assets/javascripts/environments/components/environments_table.vue
+++ b/app/assets/javascripts/environments/components/environments_table.vue
@@ -2,7 +2,7 @@
/**
* Render environments table.
*/
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import environmentItem from './environment_item.vue';
export default {
@@ -41,48 +41,25 @@ export default {
};
</script>
<template>
- <div
- class="ci-table"
- role="grid"
- >
- <div
- class="gl-responsive-table-row table-row-header"
- role="row"
- >
- <div
- class="table-section section-15 environments-name"
- role="columnheader"
- >
- {{ s__("Environments|Environment") }}
+ <div class="ci-table" role="grid">
+ <div class="gl-responsive-table-row table-row-header" role="row">
+ <div class="table-section section-15 environments-name" role="columnheader">
+ {{ s__('Environments|Environment') }}
</div>
- <div
- class="table-section section-10 environments-deploy"
- role="columnheader"
- >
- {{ s__("Environments|Deployment") }}
+ <div class="table-section section-10 environments-deploy" role="columnheader">
+ {{ s__('Environments|Deployment') }}
</div>
- <div
- class="table-section section-15 environments-build"
- role="columnheader"
- >
- {{ s__("Environments|Job") }}
+ <div class="table-section section-15 environments-build" role="columnheader">
+ {{ s__('Environments|Job') }}
</div>
- <div
- class="table-section section-20 environments-commit"
- role="columnheader"
- >
- {{ s__("Environments|Commit") }}
+ <div class="table-section section-20 environments-commit" role="columnheader">
+ {{ s__('Environments|Commit') }}
</div>
- <div
- class="table-section section-10 environments-date"
- role="columnheader"
- >
- {{ s__("Environments|Updated") }}
+ <div class="table-section section-10 environments-date" role="columnheader">
+ {{ s__('Environments|Updated') }}
</div>
</div>
- <template
- v-for="(model, i) in environments"
- :model="model">
+ <template v-for="(model, i) in environments" :model="model">
<div
is="environment-item"
:key="`environment-item-${i}`"
@@ -91,13 +68,9 @@ export default {
:can-read-environment="canReadEnvironment"
/>
- <template
- v-if="shouldRenderFolderContent(model)"
- >
- <div
- v-if="model.isLoadingFolderContent"
- :key="`loading-item-${i}`">
- <gl-loading-icon :size="2" />
+ <template v-if="shouldRenderFolderContent(model)">
+ <div v-if="model.isLoadingFolderContent" :key="`loading-item-${i}`">
+ <gl-loading-icon :size="2" class="prepend-top-16" />
</div>
<template v-else>
@@ -112,11 +85,8 @@ export default {
<div :key="`sub-div-${i}`">
<div class="text-center prepend-top-10">
- <a
- :href="folderUrl(model)"
- class="btn btn-default"
- >
- {{ s__("Environments|Show all") }}
+ <a :href="folderUrl(model)" class="btn btn-default">
+ {{ s__('Environments|Show all') }}
</a>
</div>
</div>
diff --git a/app/assets/javascripts/environments/components/stop_environment_modal.vue b/app/assets/javascripts/environments/components/stop_environment_modal.vue
index 6397f6caf1b..c78d86e9b97 100644
--- a/app/assets/javascripts/environments/components/stop_environment_modal.vue
+++ b/app/assets/javascripts/environments/components/stop_environment_modal.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import GlModal from '~/vue_shared/components/gl_modal.vue';
import { s__, sprintf } from '~/locale';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
@@ -62,31 +62,25 @@ export default {
@submit="onSubmit"
>
<template slot="header">
- <h4
- class="modal-title d-flex mw-100"
- >
+ <h4 class="modal-title d-flex mw-100">
Stopping
- <span
- v-gl-tooltip
- :title="environment.name"
- class="text-truncate ml-1 mr-1 flex-fill"
- >{{ environment.name }}</span>
+ <span v-gl-tooltip :title="environment.name" class="text-truncate ml-1 mr-1 flex-fill">{{
+ environment.name
+ }}</span>
?
</h4>
</template>
<p>{{ s__('Environments|Are you sure you want to stop this environment?') }}</p>
- <div
- v-if="!environment.has_stop_action"
- class="warning_message"
- >
+ <div v-if="!environment.has_stop_action" class="warning_message">
<p v-html="noStopActionMessage"></p>
<a
href="https://docs.gitlab.com/ee/ci/environments.html#stopping-an-environment"
target="_blank"
rel="noopener noreferrer"
- >{{ s__('Environments|Learn more about stopping environments') }}</a>
+ >{{ s__('Environments|Learn more about stopping environments') }}</a
+ >
</div>
</gl-modal>
</template>
diff --git a/app/assets/javascripts/environments/folder/environments_folder_bundle.js b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
index f044d31c776..3cf6e4ad14d 100644
--- a/app/assets/javascripts/environments/folder/environments_folder_bundle.js
+++ b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import environmentsFolderApp from './environments_folder_view.vue';
-import { convertPermissionToBoolean } from '../../lib/utils/common_utils';
+import { parseBoolean } from '../../lib/utils/common_utils';
import Translate from '../../vue_shared/translate';
Vue.use(Translate);
@@ -18,8 +18,8 @@ export default () =>
endpoint: environmentsData.endpoint,
folderName: environmentsData.folderName,
cssContainerClass: environmentsData.cssClass,
- canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
- canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
+ canCreateDeployment: parseBoolean(environmentsData.canCreateDeployment),
+ canReadEnvironment: parseBoolean(environmentsData.canReadEnvironment),
};
},
render(createElement) {
diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.vue b/app/assets/javascripts/environments/folder/environments_folder_view.vue
index 6be4845fe4c..d6f0b6115a6 100644
--- a/app/assets/javascripts/environments/folder/environments_folder_view.vue
+++ b/app/assets/javascripts/environments/folder/environments_folder_view.vue
@@ -43,20 +43,12 @@ export default {
<div :class="cssContainerClass">
<stop-environment-modal :environment="environmentInStopModal" />
- <div
- v-if="!isLoading"
- class="top-area"
- >
-
+ <div v-if="!isLoading" class="top-area">
<h4 class="js-folder-name environments-folder-name">
- {{ s__("Environments|Environments") }} / <b>{{ folderName }}</b>
+ {{ s__('Environments|Environments') }} / <b>{{ folderName }}</b>
</h4>
- <tabs
- :tabs="tabs"
- scope="environments"
- @onChangeTab="onChangeTab"
- />
+ <tabs :tabs="tabs" scope="environments" @onChangeTab="onChangeTab" />
</div>
<container
diff --git a/app/assets/javascripts/environments/index.js b/app/assets/javascripts/environments/index.js
index 5b6833fb15d..d366e7550b7 100644
--- a/app/assets/javascripts/environments/index.js
+++ b/app/assets/javascripts/environments/index.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import environmentsComponent from './components/environments_app.vue';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
import Translate from '../vue_shared/translate';
Vue.use(Translate);
@@ -19,9 +19,9 @@ export default () =>
newEnvironmentPath: environmentsData.newEnvironmentPath,
helpPagePath: environmentsData.helpPagePath,
cssContainerClass: environmentsData.cssClass,
- canCreateEnvironment: convertPermissionToBoolean(environmentsData.canCreateEnvironment),
- canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
- canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
+ canCreateEnvironment: parseBoolean(environmentsData.canCreateEnvironment),
+ canCreateDeployment: parseBoolean(environmentsData.canCreateDeployment),
+ canReadEnvironment: parseBoolean(environmentsData.canReadEnvironment),
};
},
render(createElement) {
diff --git a/app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue b/app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue
index b9bc5e6ed7f..6b1a934d3fe 100644
--- a/app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue
+++ b/app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue
@@ -58,20 +58,16 @@ export default {
</script>
<template>
<div>
- <div
- v-if="!isLocalStorageAvailable"
- class="dropdown-info-note">
+ <div v-if="!isLocalStorageAvailable" class="dropdown-info-note">
This feature requires local storage to be enabled
</div>
<ul v-else-if="hasItems">
- <li
- v-for="(item, index) in processedItems"
- :key="`processed-items-${index}`"
- >
+ <li v-for="(item, index) in processedItems" :key="`processed-items-${index}`">
<button
type="button"
class="filtered-search-history-dropdown-item"
- @click="onItemActivated(item.text)">
+ @click="onItemActivated(item.text);"
+ >
<span>
<span
v-for="(token, tokenIndex) in item.tokens"
@@ -92,15 +88,12 @@ export default {
<button
type="button"
class="filtered-search-history-clear-button"
- @click="onRequestClearRecentSearches($event)">
+ @click="onRequestClearRecentSearches($event);"
+ >
Clear recent searches
</button>
</li>
</ul>
- <div
- v-else
- class="dropdown-info-note">
- You don't have any recent searches
- </div>
+ <div v-else class="dropdown-info-note">You don't have any recent searches</div>
</div>
</template>
diff --git a/app/assets/javascripts/filtered_search/dropdown_emoji.js b/app/assets/javascripts/filtered_search/dropdown_emoji.js
index af7936a92fb..d9a4d06b549 100644
--- a/app/assets/javascripts/filtered_search/dropdown_emoji.js
+++ b/app/assets/javascripts/filtered_search/dropdown_emoji.js
@@ -69,10 +69,13 @@ export default class DropdownEmoji extends FilteredSearchDropdown {
// Replace empty gl-emoji tag to real content
const dropdownItems = [...this.dropdown.querySelectorAll('.filter-dropdown-item')];
dropdownItems.forEach(dropdownItem => {
- const name = dropdownItem.querySelector('.js-data-value').innerText;
- const emojiTag = this.glEmojiTag(name);
- const emojiElement = dropdownItem.querySelector('gl-emoji');
- emojiElement.outerHTML = emojiTag;
+ const valueElement = dropdownItem.querySelector('.js-data-value');
+ if (valueElement !== null) {
+ const name = valueElement.innerText;
+ const emojiTag = this.glEmojiTag(name);
+ const emojiElement = dropdownItem.querySelector('gl-emoji');
+ emojiElement.outerHTML = emojiTag;
+ }
});
}
diff --git a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
index bb0ecb8efe7..b494b7e2de0 100644
--- a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
+++ b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
@@ -88,11 +88,16 @@ export const conditions = [
value: 'started',
},
{
- url: 'label_name[]=No+Label',
+ url: 'label_name[]=None',
tokenKey: 'label',
value: 'none',
},
{
+ url: 'label_name[]=Any',
+ tokenKey: 'any',
+ value: 'any',
+ },
+ {
url: 'my_reaction_emoji=None',
tokenKey: 'my-reaction',
value: 'none',
diff --git a/app/assets/javascripts/frequent_items/components/app.vue b/app/assets/javascripts/frequent_items/components/app.vue
index 159c0bdc992..63531f1f246 100644
--- a/app/assets/javascripts/frequent_items/components/app.vue
+++ b/app/assets/javascripts/frequent_items/components/app.vue
@@ -1,7 +1,7 @@
<script>
import { mapState, mapActions, mapGetters } from 'vuex';
import AccessorUtilities from '~/lib/utils/accessor';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../event_hub';
import store from '../store/';
import { FREQUENT_ITEMS, STORAGE_KEY } from '../constants';
@@ -95,19 +95,14 @@ export default {
<template>
<div>
- <frequent-items-search-input
- :namespace="namespace"
- />
+ <frequent-items-search-input :namespace="namespace" />
<gl-loading-icon
v-if="isLoadingItems"
:label="translations.loadingMessage"
:size="2"
class="loading-animation prepend-top-20"
/>
- <div
- v-if="!isLoadingItems && !hasSearchQuery"
- class="section-header"
- >
+ <div v-if="!isLoadingItems && !hasSearchQuery" class="section-header">
{{ translations.header }}
</div>
<frequent-items-list
diff --git a/app/assets/javascripts/frequent_items/components/frequent_items_list.vue b/app/assets/javascripts/frequent_items/components/frequent_items_list.vue
index 8e511aa2a36..67ffa97a046 100644
--- a/app/assets/javascripts/frequent_items/components/frequent_items_list.vue
+++ b/app/assets/javascripts/frequent_items/components/frequent_items_list.vue
@@ -55,11 +55,7 @@ export default {
<template>
<div class="frequent-items-list-container">
<ul class="list-unstyled">
- <li
- v-if="isListEmpty"
- :class="{ 'section-failure': isFetchFailed }"
- class="section-empty"
- >
+ <li v-if="isListEmpty" :class="{ 'section-failure': isFetchFailed }" class="section-empty">
{{ listEmptyMessage }}
</li>
<frequent-items-list-item
diff --git a/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue b/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue
index 2399ee15332..2cbc7c7077b 100644
--- a/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue
+++ b/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue
@@ -80,35 +80,14 @@ export default {
<template>
<li class="frequent-items-list-item-container">
- <a
- :href="webUrl"
- class="clearfix"
- >
+ <a :href="webUrl" class="clearfix">
<div class="frequent-items-item-avatar-container">
- <img
- v-if="hasAvatar"
- :src="avatarUrl"
- class="avatar s32"
- />
- <identicon
- v-else
- :entity-id="itemId"
- :entity-name="itemName"
- size-class="s32"
- />
+ <img v-if="hasAvatar" :src="avatarUrl" class="avatar s32" />
+ <identicon v-else :entity-id="itemId" :entity-name="itemName" size-class="s32" />
</div>
<div class="frequent-items-item-metadata-container">
- <div
- :title="itemName"
- class="frequent-items-item-title"
- v-html="highlightedItemName"
- >
- </div>
- <div
- v-if="truncatedNamespace"
- :title="namespace"
- class="frequent-items-item-namespace"
- >
+ <div :title="itemName" class="frequent-items-item-title" v-html="highlightedItemName"></div>
+ <div v-if="truncatedNamespace" :title="namespace" class="frequent-items-item-namespace">
{{ truncatedNamespace }}
</div>
</div>
diff --git a/app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue b/app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue
index 14c223c61a4..c69e1b792dc 100644
--- a/app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue
+++ b/app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue
@@ -49,10 +49,6 @@ export default {
type="search"
class="form-control"
/>
- <icon
- v-if="!searchQuery"
- name="search"
- class="search-icon"
- />
+ <icon v-if="!searchQuery" name="search" class="search-icon" />
</div>
</template>
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 00b3d283570..c14eb936930 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -62,9 +62,11 @@ class GfmAutoComplete {
skipMarkdownCharacterTest: true,
data: GfmAutoComplete.defaultLoadingData,
displayTpl(value) {
+ const cssClasses = [];
+
if (GfmAutoComplete.isLoading(value)) return GfmAutoComplete.Loading.template;
// eslint-disable-next-line no-template-curly-in-string
- let tpl = '<li><span class="name">/${name}</span>';
+ let tpl = '<li class="<%- className %>"><span class="name">/${name}</span>';
if (value.aliases.length > 0) {
tpl += ' <small class="aliases">(or /<%- aliases.join(", /") %>)</small>';
}
@@ -72,10 +74,19 @@ class GfmAutoComplete {
tpl += ' <small class="params"><%- params.join(" ") %></small>';
}
if (value.description !== '') {
- tpl += '<small class="description"><i><%- description %></i></small>';
+ tpl += '<small class="description"><i><%- description %> <%- warningText %></i></small>';
}
tpl += '</li>';
- return _.template(tpl)(value);
+
+ if (value.warning) {
+ cssClasses.push('has-warning');
+ }
+
+ return _.template(tpl)({
+ ...value,
+ className: cssClasses.join(' '),
+ warningText: value.warning ? `(${value.warning})` : '',
+ });
},
insertTpl(value) {
// eslint-disable-next-line no-template-curly-in-string
@@ -104,6 +115,7 @@ class GfmAutoComplete {
aliases: c.aliases,
params: c.params,
description: c.description,
+ warning: c.warning,
search,
};
});
@@ -151,10 +163,16 @@ class GfmAutoComplete {
// Team Members
$input.atwho({
at: '@',
+ alias: 'users',
displayTpl(value) {
let tmpl = GfmAutoComplete.Loading.template;
- if (value.username != null) {
- tmpl = GfmAutoComplete.Members.template;
+ const { avatarTag, username, title } = value;
+ if (username != null) {
+ tmpl = GfmAutoComplete.Members.templateFunction({
+ avatarTag,
+ username,
+ title,
+ });
}
return tmpl;
},
@@ -565,8 +583,9 @@ GfmAutoComplete.Emoji = {
};
// Team Members
GfmAutoComplete.Members = {
- // eslint-disable-next-line no-template-curly-in-string
- template: '<li>${avatarTag} ${username} <small>${title}</small></li>',
+ templateFunction({ avatarTag, username, title }) {
+ return `<li>${avatarTag} ${username} <small>${_.escape(title)}</small></li>`;
+ },
};
GfmAutoComplete.Labels = {
template:
diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue
index 2a4a39436e7..29dc2d6a8a3 100644
--- a/app/assets/javascripts/groups/components/app.vue
+++ b/app/assets/javascripts/groups/components/app.vue
@@ -8,7 +8,7 @@ import { HIDDEN_CLASS } from '~/lib/utils/constants';
import { getParameterByName } from '~/lib/utils/common_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../event_hub';
import { COMMON_STR, CONTENT_LIST_CLASS } from '../constants';
import groupsComponent from './groups.vue';
diff --git a/app/assets/javascripts/groups/components/group_folder.vue b/app/assets/javascripts/groups/components/group_folder.vue
index bcc7a638346..e885b2b5f41 100644
--- a/app/assets/javascripts/groups/components/group_folder.vue
+++ b/app/assets/javascripts/groups/components/group_folder.vue
@@ -43,18 +43,9 @@ export default {
:parent-group="parentGroup"
:action="action"
/>
- <li
- v-if="hasMoreChildren"
- class="group-row">
- <a
- :href="parentGroup.relativePath"
- class="group-row-contents has-more-items">
- <i
- class="fa fa-external-link"
- aria-hidden="true"
- >
- </i>
- {{ moreChildrenStats }}
+ <li v-if="hasMoreChildren" class="group-row">
+ <a :href="parentGroup.relativePath" class="group-row-contents has-more-items">
+ <i class="fa fa-external-link" aria-hidden="true"> </i> {{ moreChildrenStats }}
</a>
</li>
</ul>
diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue
index 44d6fa26914..688bd37cc56 100644
--- a/app/assets/javascripts/groups/components/group_item.vue
+++ b/app/assets/javascripts/groups/components/group_item.vue
@@ -77,89 +77,46 @@ export default {
</script>
<template>
- <li
- :id="groupDomId"
- :class="rowClass"
- class="group-row"
- @click.stop="onClickRowGroup"
- >
+ <li :id="groupDomId" :class="rowClass" class="group-row" @click.stop="onClickRowGroup">
<div
:class="{ 'project-row-contents': !isGroup }"
class="group-row-contents d-flex justify-content-end align-items-center"
>
- <div
- class="folder-toggle-wrap append-right-4 d-flex align-items-center"
- >
- <item-caret
- :is-group-open="group.isOpen"
- />
- <item-type-icon
- :item-type="group.type"
- :is-group-open="group.isOpen"
- />
+ <div class="folder-toggle-wrap append-right-4 d-flex align-items-center">
+ <item-caret :is-group-open="group.isOpen" />
+ <item-type-icon :item-type="group.type" :is-group-open="group.isOpen" />
</div>
<div
:class="{ 'content-loading': group.isChildrenLoading }"
class="avatar-container s24 d-none d-sm-flex"
>
- <a
- :href="group.relativePath"
- class="no-expand"
- >
- <img
- v-if="hasAvatar"
- :src="group.avatarUrl"
- class="avatar s24"
- />
- <identicon
- v-else
- :entity-id="group.id"
- :entity-name="group.name"
- size-class="s24"
- />
+ <a :href="group.relativePath" class="no-expand">
+ <img v-if="hasAvatar" :src="group.avatarUrl" class="avatar s24" />
+ <identicon v-else :entity-id="group.id" :entity-name="group.name" size-class="s24" />
</a>
</div>
- <div
- class="group-text flex-grow"
- >
- <div
- class="title namespace-title append-right-8"
- >
+ <div class="group-text flex-grow">
+ <div class="title namespace-title append-right-8">
<a
v-tooltip
:href="group.relativePath"
:title="group.fullName"
class="no-expand"
data-placement="bottom"
- >{{
- // ending bracket must be by closing tag to prevent
- // link hover text-decoration from over-extending
- group.name
- }}</a>
- <span
- v-if="group.permission"
- class="user-access-role"
+ >{{
+ // ending bracket must be by closing tag to prevent
+ // link hover text-decoration from over-extending
+ group.name
+ }}</a
>
- {{ group.permission }}
- </span>
+ <span v-if="group.permission" class="user-access-role"> {{ group.permission }} </span>
</div>
- <div
- v-if="group.description"
- class="description"
- >
- <span v-html="group.description">
- </span>
+ <div v-if="group.description" class="description">
+ <span v-html="group.description"> </span>
</div>
</div>
- <item-stats
- :item="group"
- class="group-stats prepend-top-2"
- />
- <item-actions
- v-if="isGroup"
- :group="group"
- :parent-group="parentGroup"
- />
+ <item-stats :item="group" class="group-stats prepend-top-2" />
+ <item-actions v-if="isGroup" :group="group" :parent-group="parentGroup" />
</div>
<group-folder
v-if="group.isOpen && hasChildren"
diff --git a/app/assets/javascripts/groups/components/groups.vue b/app/assets/javascripts/groups/components/groups.vue
index 81b2e5ea37b..f0f5b8395c9 100644
--- a/app/assets/javascripts/groups/components/groups.vue
+++ b/app/assets/javascripts/groups/components/groups.vue
@@ -43,19 +43,9 @@ export default {
<template>
<div class="groups-list-tree-container qa-groups-list-tree-container">
- <div
- v-if="searchEmpty"
- class="has-no-search-results"
- >
- {{ searchEmptyMessage }}
- </div>
- <template
- v-else
- >
- <group-folder
- :groups="groups"
- :action="action"
- />
+ <div v-if="searchEmpty" class="has-no-search-results">{{ searchEmptyMessage }}</div>
+ <template v-else>
+ <group-folder :groups="groups" :action="action" />
<pagination-links
:change="change"
:page-info="pageInfo"
diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue
index c1783d5ce25..a7995865c77 100644
--- a/app/assets/javascripts/groups/components/item_actions.vue
+++ b/app/assets/javascripts/groups/components/item_actions.vue
@@ -53,8 +53,9 @@ export default {
:aria-label="editBtnTitle"
data-container="body"
data-placement="bottom"
- class="edit-group btn no-expand">
- <icon name="settings"/>
+ class="edit-group btn no-expand"
+ >
+ <icon name="settings" />
</a>
<a
v-if="group.canLeave"
@@ -65,8 +66,9 @@ export default {
data-container="body"
data-placement="bottom"
class="leave-group btn no-expand"
- @click.prevent="onLeaveGroup">
- <icon name="leave"/>
+ @click.prevent="onLeaveGroup"
+ >
+ <icon name="leave" />
</a>
</div>
</template>
diff --git a/app/assets/javascripts/groups/components/item_caret.vue b/app/assets/javascripts/groups/components/item_caret.vue
index 2a5bec5e86c..43b9607ea8e 100644
--- a/app/assets/javascripts/groups/components/item_caret.vue
+++ b/app/assets/javascripts/groups/components/item_caret.vue
@@ -21,10 +21,5 @@ export default {
</script>
<template>
- <span class="folder-caret">
- <icon
- :size="12"
- :name="iconClass"
- />
- </span>
+ <span class="folder-caret"> <icon :size="12" :name="iconClass" /> </span>
</template>
diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue
index 829924ba63c..bc6851ea2bf 100644
--- a/app/assets/javascripts/groups/components/item_stats.vue
+++ b/app/assets/javascripts/groups/components/item_stats.vue
@@ -76,14 +76,8 @@ export default {
css-class="item-visibility"
tooltip-placement="left"
/>
- <div
- v-if="isProject"
- class="last-updated"
- >
- <time-ago-tooltip
- :time="item.updatedAt"
- tooltip-placement="bottom"
- />
+ <div v-if="isProject" class="last-updated">
+ <time-ago-tooltip :time="item.updatedAt" tooltip-placement="bottom" />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/groups/components/item_stats_value.vue b/app/assets/javascripts/groups/components/item_stats_value.vue
index c542ca946d3..27b1c632643 100644
--- a/app/assets/javascripts/groups/components/item_stats_value.vue
+++ b/app/assets/javascripts/groups/components/item_stats_value.vue
@@ -57,12 +57,6 @@ export default {
:title="title"
data-container="body"
>
- <icon :name="iconName" />
- <span
- v-if="isValuePresent"
- class="stat-value"
- >
- {{ value }}
- </span>
+ <icon :name="iconName" /> <span v-if="isValuePresent" class="stat-value"> {{ value }} </span>
</span>
</template>
diff --git a/app/assets/javascripts/groups/components/item_type_icon.vue b/app/assets/javascripts/groups/components/item_type_icon.vue
index 118d94d4937..e1ebd03cb5f 100644
--- a/app/assets/javascripts/groups/components/item_type_icon.vue
+++ b/app/assets/javascripts/groups/components/item_type_icon.vue
@@ -29,7 +29,5 @@ export default {
</script>
<template>
- <span class="item-type-icon">
- <icon :name="iconClass"/>
- </span>
+ <span class="item-type-icon"> <icon :name="iconClass" /> </span>
</template>
diff --git a/app/assets/javascripts/groups/index.js b/app/assets/javascripts/groups/index.js
index 0f68f05b523..928f1fe409f 100644
--- a/app/assets/javascripts/groups/index.js
+++ b/app/assets/javascripts/groups/index.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
import Translate from '../vue_shared/translate';
import GroupFilterableList from './groups_filterable_list';
import GroupsStore from './store/groups_store';
@@ -38,7 +39,7 @@ export default (containerId = 'js-groups-tree', endpoint, action = '') => {
},
data() {
const { dataset } = dataEl || this.$options.el;
- const hideProjects = dataset.hideProjects === 'true';
+ const hideProjects = parseBoolean(dataset.hideProjects);
const service = new GroupsService(endpoint || dataset.endpoint);
const store = new GroupsStore(hideProjects);
diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js
index b4a3037c1b7..2049760fe29 100644
--- a/app/assets/javascripts/groups_select.js
+++ b/app/assets/javascripts/groups_select.js
@@ -10,13 +10,18 @@ export default function groupsSelect() {
const $select = $(this);
const allAvailable = $select.data('allAvailable');
const skipGroups = $select.data('skipGroups') || [];
+ const parentGroupID = $select.data('parentId');
+ const groupsPath = parentGroupID
+ ? Api.subgroupsPath.replace(':id', parentGroupID)
+ : Api.groupsPath;
+
$select.select2({
placeholder: 'Search for a group',
allowClear: $select.hasClass('allowClear'),
multiple: $select.hasClass('multiselect'),
minimumInputLength: 0,
ajax: {
- url: Api.buildUrl(Api.groupsPath),
+ url: Api.buildUrl(groupsPath),
dataType: 'json',
quietMillis: 250,
transport(params) {
diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js
index 175d0b8498b..2fa7a219ea8 100644
--- a/app/assets/javascripts/header.js
+++ b/app/assets/javascripts/header.js
@@ -4,6 +4,7 @@ import Translate from '~/vue_shared/translate';
import { highCountTrim } from '~/lib/utils/text_utility';
import SetStatusModalTrigger from './set_status_modal/set_status_modal_trigger.vue';
import SetStatusModalWrapper from './set_status_modal/set_status_modal_wrapper.vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
/**
* Updates todo counter when todos are toggled.
@@ -36,7 +37,7 @@ document.addEventListener('DOMContentLoaded', () => {
const { hasStatus } = this.$options.el.dataset;
return {
- hasStatus: hasStatus === 'true',
+ hasStatus: parseBoolean(hasStatus),
};
},
render(createElement) {
diff --git a/app/assets/javascripts/ide/components/activity_bar.vue b/app/assets/javascripts/ide/components/activity_bar.vue
index 2cebacc1c4c..a1f66ff764d 100644
--- a/app/assets/javascripts/ide/components/activity_bar.vue
+++ b/app/assets/javascripts/ide/components/activity_bar.vue
@@ -37,7 +37,7 @@ export default {
<button
v-tooltip
:class="{
- active: currentActivityView === $options.activityBarViews.edit
+ active: currentActivityView === $options.activityBarViews.edit,
}"
:title="s__('IDE|Edit')"
:aria-label="s__('IDE|Edit')"
@@ -45,18 +45,16 @@ export default {
data-placement="right"
type="button"
class="ide-sidebar-link js-ide-edit-mode"
- @click.prevent="changedActivityView($event, $options.activityBarViews.edit)"
+ @click.prevent="changedActivityView($event, $options.activityBarViews.edit);"
>
- <icon
- name="code"
- />
+ <icon name="code" />
</button>
</li>
<li>
<button
v-tooltip
:class="{
- active: currentActivityView === $options.activityBarViews.review
+ active: currentActivityView === $options.activityBarViews.review,
}"
:title="s__('IDE|Review')"
:aria-label="s__('IDE|Review')"
@@ -64,18 +62,16 @@ export default {
data-placement="right"
type="button"
class="ide-sidebar-link js-ide-review-mode"
- @click.prevent="changedActivityView($event, $options.activityBarViews.review)"
+ @click.prevent="changedActivityView($event, $options.activityBarViews.review);"
>
- <icon
- name="file-modified"
- />
+ <icon name="file-modified" />
</button>
</li>
<li v-show="hasChanges">
<button
v-tooltip
:class="{
- active: currentActivityView === $options.activityBarViews.commit
+ active: currentActivityView === $options.activityBarViews.commit,
}"
:title="s__('IDE|Commit')"
:aria-label="s__('IDE|Commit')"
@@ -83,11 +79,9 @@ export default {
data-placement="right"
type="button"
class="ide-sidebar-link js-ide-commit-mode"
- @click.prevent="changedActivityView($event, $options.activityBarViews.commit)"
+ @click.prevent="changedActivityView($event, $options.activityBarViews.commit);"
>
- <icon
- name="commit"
- />
+ <icon name="commit" />
</button>
</li>
</ul>
diff --git a/app/assets/javascripts/ide/components/branches/item.vue b/app/assets/javascripts/ide/components/branches/item.vue
index cc3e84e3f77..4dff3f7e755 100644
--- a/app/assets/javascripts/ide/components/branches/item.vue
+++ b/app/assets/javascripts/ide/components/branches/item.vue
@@ -32,28 +32,14 @@ export default {
</script>
<template>
- <a
- :href="branchHref"
- class="btn-link d-flex align-items-center"
- >
+ <a :href="branchHref" class="btn-link d-flex align-items-center">
<span class="d-flex append-right-default ide-search-list-current-icon">
- <icon
- v-if="isActive"
- :size="18"
- name="mobile-issue-close"
- />
+ <icon v-if="isActive" :size="18" name="mobile-issue-close" />
</span>
<span>
- <strong>
- {{ item.name }}
- </strong>
- <span
- class="ide-merge-request-project-path d-block mt-1"
- >
- Updated
- <timeago
- :time="item.committedDate || ''"
- />
+ <strong> {{ item.name }} </strong>
+ <span class="ide-merge-request-project-path d-block mt-1">
+ Updated <timeago :time="item.committedDate || ''" />
</span>
</span>
</a>
diff --git a/app/assets/javascripts/ide/components/branches/search_list.vue b/app/assets/javascripts/ide/components/branches/search_list.vue
index 358f1153de2..3cfdc1a367a 100644
--- a/app/assets/javascripts/ide/components/branches/search_list.vue
+++ b/app/assets/javascripts/ide/components/branches/search_list.vue
@@ -2,7 +2,7 @@
import { mapActions, mapState } from 'vuex';
import _ from 'underscore';
import Icon from '~/vue_shared/components/icon.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import Item from './item.vue';
export default {
@@ -68,11 +68,7 @@ export default {
class="form-control dropdown-input-field"
@input="searchBranches"
/>
- <icon
- :size="18"
- name="search"
- class="input-icon"
- />
+ <icon :size="18" name="search" class="input-icon" />
</div>
</div>
<div class="dropdown-content ide-merge-requests-dropdown-content d-flex">
@@ -81,26 +77,13 @@ export default {
:size="2"
class="mt-3 mb-3 align-self-center ml-auto mr-auto"
/>
- <ul
- v-else
- class="mb-3 w-100"
- >
+ <ul v-else class="mb-3 w-100">
<template v-if="hasBranches">
- <li
- v-for="item in branches"
- :key="item.name"
- >
- <item
- :item="item"
- :project-id="currentProjectId"
- :is-active="isActiveBranch(item)"
- />
+ <li v-for="item in branches" :key="item.name">
+ <item :item="item" :project-id="currentProjectId" :is-active="isActiveBranch(item)" />
</li>
</template>
- <li
- v-else
- class="ide-search-list-empty d-flex align-items-center justify-content-center"
- >
+ <li v-else class="ide-search-list-empty d-flex align-items-center justify-content-center">
<template v-if="hasNoSearchResults">
{{ __('No branches found') }}
</template>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
index a8b5c7a16d0..d360dc42cd3 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
@@ -57,11 +57,7 @@ export default {
:disabled="currentBranch && !currentBranch.can_push"
:title="$options.currentBranchPermissionsTooltip"
>
- <span
- class="ide-radio-label"
- v-html="commitToCurrentBranchText"
- >
- </span>
+ <span class="ide-radio-label" v-html="commitToCurrentBranchText"> </span>
</radio-group>
<radio-group
:value="$options.commitToNewBranch"
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
index b0e60edcbe5..5119dbf32eb 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
@@ -42,18 +42,9 @@ export default {
<template>
<div class="d-flex ide-commit-editor-header align-items-center">
- <file-icon
- :file-name="activeFile.name"
- :size="16"
- class="mr-2"
- />
- <strong class="mr-2">
- {{ activeFile.path }}
- </strong>
- <changed-file-icon
- :file="activeFile"
- class="ml-0"
- />
+ <file-icon :file-name="activeFile.name" :size="16" class="mr-2" />
+ <strong class="mr-2"> {{ activeFile.path }} </strong>
+ <changed-file-icon :file="activeFile" class="ml-0" />
<div class="ml-auto">
<button
v-if="!isStaged"
@@ -66,7 +57,7 @@ export default {
<button
:class="{
'btn-success': !isStaged,
- 'btn-warning': isStaged
+ 'btn-warning': isStaged,
}"
type="button"
class="btn btn-inverted"
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue b/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue
index d0a60d647e5..a23bae8e4c7 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/empty_state.vue
@@ -13,22 +13,12 @@ export default {
v-if="!lastCommitMsg"
class="multi-file-commit-panel-section ide-commit-empty-state js-empty-state"
>
- <div
- class="ide-commit-empty-state-container"
- >
- <div class="svg-content svg-80">
- <img :src="noChangesStateSvgPath" />
- </div>
+ <div class="ide-commit-empty-state-container">
+ <div class="svg-content svg-80"><img :src="noChangesStateSvgPath" /></div>
<div class="append-right-default prepend-left-default">
- <div
- class="text-content text-center"
- >
- <h4>
- {{ __('No changes') }}
- </h4>
- <p>
- {{ __('Edit files in the editor and commit changes here') }}
- </p>
+ <div class="text-content text-center">
+ <h4>{{ __('No changes') }}</h4>
+ <p>{{ __('Edit files in the editor and commit changes here') }}</p>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue
index 802827fce76..f7ed7006874 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue
@@ -96,7 +96,7 @@ export default {
<div
:class="{
'is-compact': isCompact,
- 'is-full': !isCompact
+ 'is-full': !isCompact,
}"
:style="{
height: componentHeight ? `${componentHeight}px` : null,
@@ -109,11 +109,7 @@ export default {
@enter="enterTransition"
@after-enter="afterEndTransition"
>
- <div
- v-if="isCompact"
- ref="compactEl"
- class="commit-form-compact"
- >
+ <div v-if="isCompact" ref="compactEl" class="commit-form-compact">
<button
:disabled="!hasChanges"
type="button"
@@ -122,25 +118,15 @@ export default {
>
{{ __('Commit…') }}
</button>
- <p
- class="text-center"
- v-html="overviewText"
- ></p>
+ <p class="text-center" v-html="overviewText"></p>
</div>
- <form
- v-if="!isCompact"
- ref="formEl"
- @submit.prevent.stop="commitChanges"
- >
- <transition name="fade">
- <success-message
- v-show="lastCommitMsg"
- />
- </transition>
+ <form v-if="!isCompact" ref="formEl" @submit.prevent.stop="commitChanges">
+ <transition name="fade"> <success-message v-show="lastCommitMsg" /> </transition>
<commit-message-field
:text="commitMessage"
:placeholder="preBuiltCommitMessage"
@input="updateCommitMessage"
+ @submit="commitChanges"
/>
<div class="clearfix prepend-top-15">
<actions />
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list.vue b/app/assets/javascripts/ide/components/commit_sidebar/list.vue
index 3e3539e364b..a1094570275 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list.vue
@@ -93,24 +93,11 @@ export default {
</script>
<template>
- <div
- class="ide-commit-list-container"
- >
- <header
- class="multi-file-commit-panel-header d-flex mb-0"
- >
- <div
- class="d-flex align-items-center flex-fill"
- >
- <icon
- v-once
- :name="iconName"
- :size="18"
- class="append-right-8"
- />
- <strong>
- {{ titleText }}
- </strong>
+ <div class="ide-commit-list-container">
+ <header class="multi-file-commit-panel-header d-flex mb-0">
+ <div class="d-flex align-items-center flex-fill">
+ <icon v-once :name="iconName" :size="18" class="append-right-8" />
+ <strong> {{ titleText }} </strong>
<div class="d-flex ml-auto">
<button
ref="actionBtn"
@@ -119,7 +106,7 @@ export default {
:aria-label="actionBtnText"
:disabled="!filesLength"
:class="{
- 'disabled-content': !filesLength
+ 'disabled-content': !filesLength,
}"
type="button"
class="d-flex ide-staged-action-btn p-0 border-0 align-items-center"
@@ -128,11 +115,7 @@ export default {
data-boundary="viewport"
@click="actionBtnClicked"
>
- <icon
- :name="actionBtnIcon"
- :size="16"
- class="ml-auto mr-auto"
- />
+ <icon :name="actionBtnIcon" :size="16" class="ml-auto mr-auto" />
</button>
<button
v-if="!stagedList"
@@ -141,7 +124,7 @@ export default {
:aria-label="__('Discard all changes')"
:disabled="!filesLength"
:class="{
- 'disabled-content': !filesLength
+ 'disabled-content': !filesLength,
}"
type="button"
class="d-flex ide-staged-action-btn p-0 border-0 align-items-center"
@@ -150,23 +133,13 @@ export default {
data-boundary="viewport"
@click="openDiscardModal"
>
- <icon
- :size="16"
- name="remove-all"
- class="ml-auto mr-auto"
- />
+ <icon :size="16" name="remove-all" class="ml-auto mr-auto" />
</button>
</div>
</div>
</header>
- <ul
- v-if="filesLength"
- class="multi-file-commit-list list-unstyled append-bottom-0"
- >
- <li
- v-for="file in fileList"
- :key="file.key"
- >
+ <ul v-if="filesLength" class="multi-file-commit-list list-unstyled append-bottom-0">
+ <li v-for="file in fileList" :key="file.key">
<list-item
:file="file"
:action-component="itemActionComponent"
@@ -176,10 +149,7 @@ export default {
/>
</li>
</ul>
- <p
- v-else
- class="multi-file-commit-list form-text text-muted text-center"
- >
+ <p v-else class="multi-file-commit-list form-text text-muted text-center">
{{ emptyStateText }}
</p>
<gl-modal
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue
index 699fa7dc937..3156a398113 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list_collapsed.vue
@@ -69,9 +69,7 @@ export default {
</script>
<template>
- <div
- class="multi-file-commit-list-collapsed text-center"
- >
+ <div class="multi-file-commit-list-collapsed text-center">
<div
v-tooltip
:title="titleTooltip"
@@ -79,11 +77,7 @@ export default {
data-placement="left"
class="append-bottom-15"
>
- <icon
- v-once
- :name="iconName"
- :size="18"
- />
+ <icon v-once :name="iconName" :size="18" />
</div>
<div
v-tooltip
@@ -92,11 +86,7 @@ export default {
data-placement="left"
class="append-bottom-10"
>
- <icon
- :name="additionIconName"
- :size="18"
- :css-classes="addedFilesIconClass"
- />
+ <icon :name="additionIconName" :size="18" :css-classes="addedFilesIconClass" />
</div>
{{ addedFilesLength }}
<div
@@ -106,11 +96,7 @@ export default {
data-placement="left"
class="prepend-top-10 append-bottom-10"
>
- <icon
- :name="modifiedIconName"
- :size="18"
- :css-classes="modifiedFilesClass"
- />
+ <icon :name="modifiedIconName" :size="18" :css-classes="modifiedFilesClass" />
</div>
{{ modifiedFilesLength }}
</div>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
index ee0e72cd05f..4be4b02ac1e 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
@@ -99,7 +99,7 @@ export default {
v-tooltip
:title="tooltipTitle"
:class="{
- 'is-active': isActive
+ 'is-active': isActive,
}"
class="multi-file-commit-list-path w-100 border-0 ml-0 mr-0"
role="button"
@@ -107,18 +107,11 @@ export default {
@click="openFileInEditor"
>
<span class="multi-file-commit-list-file-path d-flex align-items-center">
- <file-icon
- :file-name="file.name"
- class="append-right-8"
- />{{ file.name }}
+ <file-icon :file-name="file.name" class="append-right-8" />{{ file.name }}
</span>
<div class="ml-auto d-flex align-items-center">
<div class="d-flex align-items-center ide-commit-list-changed-icon">
- <icon
- :name="iconName"
- :size="16"
- :css-classes="iconClass"
- />
+ <icon :name="iconName" :size="16" :css-classes="iconClass" />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue
index 37ca108fafc..6f1ded91753 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue
@@ -49,6 +49,10 @@ export default {
onInput(e) {
this.$emit('input', e.target.value);
},
+ onCtrlEnter() {
+ if (!this.isFocused) return;
+ this.$emit('submit');
+ },
updateIsFocused(isFocused) {
this.isFocused = isFocused;
},
@@ -71,24 +75,16 @@ export default {
<fieldset class="common-note-form ide-commit-message-field">
<div
:class="{
- 'is-focused': isFocused
+ 'is-focused': isFocused,
}"
class="md-area"
>
- <div
- v-once
- class="md-header"
- >
+ <div v-once class="md-header">
<ul class="nav-links">
<li>
{{ __('Commit Message') }}
- <span
- v-popover="$options.popoverOptions"
- class="form-text text-muted prepend-left-10"
- >
- <icon
- name="question"
- />
+ <span v-popover="$options.popoverOptions" class="form-text text-muted prepend-left-10">
+ <icon name="question" />
</span>
</li>
</ul>
@@ -97,22 +93,13 @@ export default {
<div class="ide-commit-message-highlights-container">
<div
:style="{
- transform: `translate3d(0, ${-scrollTop}px, 0)`
+ transform: `translate3d(0, ${-scrollTop}px, 0)`,
}"
class="note-textarea highlights monospace"
>
- <div
- v-for="(line, index) in allLines"
- :key="index"
- >
- <span
- v-text="line.text"
- >
- </span><mark
- v-show="line.highlightedText"
- v-text="line.highlightedText"
- >
- </mark>
+ <div v-for="(line, index) in allLines" :key="index">
+ <span v-text="line.text"> </span
+ ><mark v-show="line.highlightedText" v-text="line.highlightedText"> </mark>
</div>
</div>
</div>
@@ -124,8 +111,10 @@ export default {
name="commit-message"
@scroll="handleScroll"
@input="onInput"
- @focus="updateIsFocused(true)"
- @blur="updateIsFocused(false)"
+ @focus="updateIsFocused(true);"
+ @blur="updateIsFocused(false);"
+ @keydown.ctrl.enter="onCtrlEnter"
+ @keydown.meta.enter="onCtrlEnter"
>
</textarea>
</div>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue b/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue
index 969e2aa61c4..3525084b1cb 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue
@@ -56,7 +56,7 @@ export default {
v-tooltip
:title="tooltipTitle"
:class="{
- 'is-disabled': disabled
+ 'is-disabled': disabled,
}"
>
<input
@@ -65,27 +65,18 @@ export default {
:disabled="disabled"
type="radio"
name="commit-action"
- @change="updateCommitAction($event.target.value)"
+ @change="updateCommitAction($event.target.value);"
/>
<span class="prepend-left-10">
- <span
- v-if="label"
- class="ide-radio-label"
- >
- {{ label }}
- </span>
- <slot v-else></slot>
+ <span v-if="label" class="ide-radio-label"> {{ label }} </span> <slot v-else></slot>
</span>
</label>
- <div
- v-if="commitAction === value && showInput"
- class="ide-commit-new-branch"
- >
+ <div v-if="commitAction === value && showInput" class="ide-commit-new-branch">
<input
:placeholder="newBranchName"
type="text"
class="form-control monospace"
- @input="updateBranchName($event.target.value)"
+ @input="updateBranchName($event.target.value);"
/>
</div>
</fieldset>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/stage_button.vue b/app/assets/javascripts/ide/components/commit_sidebar/stage_button.vue
index adf4b479c97..02c2004d495 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/stage_button.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/stage_button.vue
@@ -38,10 +38,7 @@ export default {
</script>
<template>
- <div
- v-once
- class="multi-file-discard-btn d-flex"
- >
+ <div v-once class="multi-file-discard-btn d-flex">
<button
v-tooltip
:aria-label="__('Stage changes')"
@@ -51,13 +48,9 @@ export default {
data-container="body"
data-boundary="viewport"
data-placement="bottom"
- @click.stop.prevent="stageChange(path)"
+ @click.stop.prevent="stageChange(path);"
>
- <icon
- :size="16"
- name="mobile-issue-close"
- class="ml-auto mr-auto"
- />
+ <icon :size="16" name="mobile-issue-close" class="ml-auto mr-auto" />
</button>
<button
v-tooltip
@@ -70,18 +63,14 @@ export default {
data-placement="bottom"
@click.stop.prevent="showDiscardModal"
>
- <icon
- :size="16"
- name="remove"
- class="ml-auto mr-auto"
- />
+ <icon :size="16" name="remove" class="ml-auto mr-auto" />
</button>
<gl-modal
:id="modalId"
:header-title-text="modalTitle"
:footer-primary-button-text="__('Discard changes')"
footer-primary-button-variant="danger"
- @submit="discardFileChanges(path)"
+ @submit="discardFileChanges(path);"
>
{{ __("You will loose all changes you've made to this file. This action cannot be undone.") }}
</gl-modal>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue
index a6df91b79c2..b1d5de8682d 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/success_message.vue
@@ -9,23 +9,11 @@ export default {
</script>
<template>
- <div
- class="multi-file-commit-panel-success-message"
- aria-live="assertive"
- >
- <div class="svg-content svg-80">
- <img
- :src="committedStateSvgPath"
- alt=""
- />
- </div>
+ <div class="multi-file-commit-panel-success-message" aria-live="assertive">
+ <div class="svg-content svg-80"><img :src="committedStateSvgPath" alt="" /></div>
<div class="append-right-default prepend-left-default">
- <div
- class="text-content text-center"
- >
- <h4>
- {{ __('All changes are committed') }}
- </h4>
+ <div class="text-content text-center">
+ <h4>{{ __('All changes are committed') }}</h4>
<p v-html="lastCommitMsg"></p>
</div>
</div>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/unstage_button.vue b/app/assets/javascripts/ide/components/commit_sidebar/unstage_button.vue
index 86c40602074..ce41fcdb087 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/unstage_button.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/unstage_button.vue
@@ -23,10 +23,7 @@ export default {
</script>
<template>
- <div
- v-once
- class="multi-file-discard-btn d-flex"
- >
+ <div v-once class="multi-file-discard-btn d-flex">
<button
v-tooltip
:aria-label="__('Unstage changes')"
@@ -36,13 +33,9 @@ export default {
data-container="body"
data-boundary="viewport"
data-placement="bottom"
- @click.stop.prevent="unstageChange(path)"
+ @click.stop.prevent="unstageChange(path);"
>
- <icon
- :size="16"
- name="redo"
- class="ml-auto mr-auto"
- />
+ <icon :size="16" name="redo" class="ml-auto mr-auto" />
</button>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/editor_mode_dropdown.vue b/app/assets/javascripts/ide/components/editor_mode_dropdown.vue
index 95598c9aca6..5f99261ec39 100644
--- a/app/assets/javascripts/ide/components/editor_mode_dropdown.vue
+++ b/app/assets/javascripts/ide/components/editor_mode_dropdown.vue
@@ -30,16 +30,8 @@ export default {
</script>
<template>
- <div
- class="dropdown"
- >
- <button
- type="button"
- class="btn btn-link"
- data-toggle="dropdown"
- >
- {{ __('Edit') }}
- </button>
+ <div class="dropdown">
+ <button type="button" class="btn btn-link" data-toggle="dropdown">{{ __('Edit') }}</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-open-left">
<ul>
<li>
@@ -48,11 +40,9 @@ export default {
'is-active': viewer === $options.viewerTypes.mr,
}"
href="#"
- @click.prevent="changeMode($options.viewerTypes.mr)"
+ @click.prevent="changeMode($options.viewerTypes.mr);"
>
- <strong class="dropdown-menu-inner-title">
- {{ mergeReviewLine }}
- </strong>
+ <strong class="dropdown-menu-inner-title"> {{ mergeReviewLine }} </strong>
<span class="dropdown-menu-inner-content">
{{ __('Compare changes with the merge request target branch') }}
</span>
@@ -64,7 +54,7 @@ export default {
'is-active': viewer === $options.viewerTypes.diff,
}"
href="#"
- @click.prevent="changeMode($options.viewerTypes.diff)"
+ @click.prevent="changeMode($options.viewerTypes.diff);"
>
<strong class="dropdown-menu-inner-title">{{ __('Reviewing') }}</strong>
<span class="dropdown-menu-inner-content">
diff --git a/app/assets/javascripts/ide/components/error_message.vue b/app/assets/javascripts/ide/components/error_message.vue
index 2d9bd99e82a..22113692968 100644
--- a/app/assets/javascripts/ide/components/error_message.vue
+++ b/app/assets/javascripts/ide/components/error_message.vue
@@ -1,6 +1,6 @@
<script>
import { mapActions } from 'vuex';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
@@ -43,15 +43,9 @@ export default {
</script>
<template>
- <div
- class="flash-container flash-container-page"
- @click="clickFlash"
- >
+ <div class="flash-container flash-container-page" @click="clickFlash">
<div class="flash-alert">
- <span
- v-html="message.text"
- >
- </span>
+ <span v-html="message.text"> </span>
<button
v-if="message.action"
type="button"
@@ -59,10 +53,7 @@ export default {
@click.stop.prevent="clickAction"
>
{{ message.actionText }}
- <gl-loading-icon
- v-show="isLoading"
- inline
- />
+ <gl-loading-icon v-show="isLoading" inline />
</button>
</div>
</div>
diff --git a/app/assets/javascripts/ide/components/external_link.vue b/app/assets/javascripts/ide/components/external_link.vue
index e24fe5bbccb..954f84cea17 100644
--- a/app/assets/javascripts/ide/components/external_link.vue
+++ b/app/assets/javascripts/ide/components/external_link.vue
@@ -20,10 +20,7 @@ export default {
</script>
<template>
- <div
- v-if="showButtons"
- class="pull-right ide-btn-group"
- >
+ <div v-if="showButtons" class="pull-right ide-btn-group">
<a
:href="file.permalink"
:title="s__('IDE|Open in file view')"
@@ -31,11 +28,7 @@ export default {
rel="noopener noreferrer"
>
<span class="vertical-align-middle">Open in file view</span>
- <icon
- :size="16"
- name="external-link"
- css-classes="vertical-align-middle space-right"
- />
+ <icon :size="16" name="external-link" css-classes="vertical-align-middle space-right" />
</a>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/file_finder/index.vue b/app/assets/javascripts/ide/components/file_finder/index.vue
index 760ed8654ee..bb391912572 100644
--- a/app/assets/javascripts/ide/components/file_finder/index.vue
+++ b/app/assets/javascripts/ide/components/file_finder/index.vue
@@ -164,13 +164,8 @@ export default {
</script>
<template>
- <div
- class="ide-file-finder-overlay"
- @mousedown.self="toggleFileFinder(false)"
- >
- <div
- class="dropdown-menu diff-file-changes ide-file-finder show"
- >
+ <div class="ide-file-finder-overlay" @mousedown.self="toggleFileFinder(false);">
+ <div class="dropdown-menu diff-file-changes ide-file-finder show">
<div class="dropdown-input">
<input
ref="searchInput"
@@ -179,12 +174,12 @@ export default {
type="search"
class="dropdown-input-field"
autocomplete="off"
- @keydown="onKeydown($event)"
- @keyup="onKeyup($event)"
+ @keydown="onKeydown($event);"
+ @keyup="onKeyup($event);"
/>
<i
:class="{
- hidden: showClearInputButton
+ hidden: showClearInputButton,
}"
aria-hidden="true"
class="fa fa-search dropdown-input-search"
@@ -192,7 +187,7 @@ export default {
<i
:aria-label="__('Clear search input')"
:class="{
- show: showClearInputButton
+ show: showClearInputButton,
}"
role="button"
class="fa fa-times dropdown-input-clear"
@@ -200,17 +195,9 @@ export default {
></i>
</div>
<div>
- <virtual-list
- ref="virtualScrollList"
- :size="listHeight"
- :remain="listShowCount"
- wtag="ul"
- >
+ <virtual-list ref="virtualScrollList" :size="listHeight" :remain="listShowCount" wtag="ul">
<template v-if="filteredBlobsLength">
- <li
- v-for="(file, index) in filteredBlobs"
- :key="file.key"
- >
+ <li v-for="(file, index) in filteredBlobs" :key="file.key">
<item
:file="file"
:search-text="searchText"
@@ -223,10 +210,7 @@ export default {
/>
</li>
</template>
- <li
- v-else
- class="dropdown-menu-empty-item"
- >
+ <li v-else class="dropdown-menu-empty-item">
<div class="append-right-default prepend-left-default prepend-top-8 append-bottom-8">
<template v-if="loading">
{{ __('Loading...') }}
diff --git a/app/assets/javascripts/ide/components/file_finder/item.vue b/app/assets/javascripts/ide/components/file_finder/item.vue
index 72ce37be63a..83e80d50aff 100644
--- a/app/assets/javascripts/ide/components/file_finder/item.vue
+++ b/app/assets/javascripts/ide/components/file_finder/item.vue
@@ -74,9 +74,7 @@ export default {
css-classes="diff-file-changed-icon append-right-8"
/>
<span class="diff-changed-file-content append-right-8">
- <strong
- class="diff-changed-file-name"
- >
+ <strong class="diff-changed-file-name">
<span
v-for="(char, charIndex) in file.name.split('')"
:key="charIndex + char"
@@ -87,9 +85,7 @@ export default {
>
</span>
</strong>
- <span
- class="diff-changed-file-path prepend-top-5"
- >
+ <span class="diff-changed-file-path prepend-top-5">
<span
v-for="(char, charIndex) in pathWithEllipsis.split('')"
:key="charIndex + char"
@@ -101,13 +97,8 @@ export default {
</span>
</span>
</span>
- <span
- v-if="file.changed || file.tempFile"
- class="diff-changed-stats"
- >
- <changed-file-icon
- :file="file"
- />
+ <span v-if="file.changed || file.tempFile" class="diff-changed-stats">
+ <changed-file-icon :file="file" />
</span>
</button>
</template>
diff --git a/app/assets/javascripts/ide/components/file_row_extra.vue b/app/assets/javascripts/ide/components/file_row_extra.vue
index 2ad14b88410..d6673cf0421 100644
--- a/app/assets/javascripts/ide/components/file_row_extra.vue
+++ b/app/assets/javascripts/ide/components/file_row_extra.vue
@@ -69,13 +69,8 @@ export default {
<template>
<div class="float-right ide-file-icon-holder">
- <mr-file-icon
- v-if="file.mrChange"
- />
- <span
- v-if="showTreeChangesCount"
- class="ide-tree-changes"
- >
+ <mr-file-icon v-if="file.mrChange" />
+ <span v-if="showTreeChangesCount" class="ide-tree-changes">
{{ changesCount }}
<icon
v-tooltip
diff --git a/app/assets/javascripts/ide/components/file_templates/bar.vue b/app/assets/javascripts/ide/components/file_templates/bar.vue
index 3587626c580..d459e3b43d3 100644
--- a/app/assets/javascripts/ide/components/file_templates/bar.vue
+++ b/app/assets/javascripts/ide/components/file_templates/bar.vue
@@ -48,9 +48,7 @@ export default {
<template>
<div class="d-flex align-items-center ide-file-templates qa-file-templates-bar">
- <strong class="append-right-default">
- {{ __('File templates') }}
- </strong>
+ <strong class="append-right-default"> {{ __('File templates') }} </strong>
<dropdown
:data="templateTypes"
:label="selectedTemplateType.name || __('Choose a type...')"
@@ -67,12 +65,7 @@ export default {
@click="selectTemplate"
/>
<transition name="fade">
- <button
- v-show="updateSuccess"
- type="button"
- class="btn btn-default"
- @click="undo"
- >
+ <button v-show="updateSuccess" type="button" class="btn btn-default" @click="undo">
{{ __('Undo') }}
</button>
</transition>
diff --git a/app/assets/javascripts/ide/components/file_templates/dropdown.vue b/app/assets/javascripts/ide/components/file_templates/dropdown.vue
index 891f7d48b4c..414ea9c7d4d 100644
--- a/app/assets/javascripts/ide/components/file_templates/dropdown.vue
+++ b/app/assets/javascripts/ide/components/file_templates/dropdown.vue
@@ -2,7 +2,7 @@
import $ from 'jquery';
import { mapActions, mapState } from 'vuex';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
@@ -75,48 +75,23 @@ export default {
<template>
<div class="dropdown">
- <dropdown-button
- :toggle-text="label"
- data-display="static"
- />
+ <dropdown-button :toggle-text="label" data-display="static" />
<div class="dropdown-menu pb-0">
- <div
- v-if="title"
- class="dropdown-title ml-0 mr-0"
- >
- {{ title }}
- </div>
- <div
- v-if="!showLoading && searchable"
- class="dropdown-input"
- >
+ <div v-if="title" class="dropdown-title ml-0 mr-0">{{ title }}</div>
+ <div v-if="!showLoading && searchable" class="dropdown-input">
<input
v-model="search"
:placeholder="__('Filter...')"
type="search"
class="dropdown-input-field qa-dropdown-filter-input"
/>
- <i
- aria-hidden="true"
- class="fa fa-search dropdown-input-search"
- ></i>
+ <i aria-hidden="true" class="fa fa-search dropdown-input-search"></i>
</div>
<div class="dropdown-content">
- <gl-loading-icon
- v-if="showLoading"
- :size="2"
- />
+ <gl-loading-icon v-if="showLoading" :size="2" />
<ul v-else>
- <li
- v-for="(item, index) in outputData"
- :key="index"
- >
- <button
- type="button"
- @click="clickItem(item)"
- >
- {{ item.name }}
- </button>
+ <li v-for="(item, index) in outputData" :key="index">
+ <button type="button" @click="clickItem(item);">{{ item.name }}</button>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue
index 0a368f6558c..caec8779cac 100644
--- a/app/assets/javascripts/ide/components/ide.vue
+++ b/app/assets/javascripts/ide/components/ide.vue
@@ -88,27 +88,13 @@ export default {
<template>
<article class="ide position-relative d-flex flex-column align-items-stretch">
- <error-message
- v-if="errorMessage"
- :message="errorMessage"
- />
- <div
- class="ide-view flex-grow d-flex"
- >
- <find-file
- v-show="fileFindVisible"
- />
+ <error-message v-if="errorMessage" :message="errorMessage" />
+ <div class="ide-view flex-grow d-flex">
+ <find-file v-show="fileFindVisible" />
<ide-sidebar />
- <div
- class="multi-file-edit-pane"
- >
- <template
- v-if="activeFile"
- >
- <commit-editor-header
- v-if="isCommitModeActive"
- :active-file="activeFile"
- />
+ <div class="multi-file-edit-pane">
+ <template v-if="activeFile">
+ <commit-editor-header v-if="isCommitModeActive" :active-file="activeFile" />
<repo-tabs
v-else
:active-file="activeFile"
@@ -117,32 +103,20 @@ export default {
:has-changes="hasChanges"
:merge-request-id="currentMergeRequestId"
/>
- <repo-editor
- :file="activeFile"
- class="multi-file-edit-pane-content"
- />
+ <repo-editor :file="activeFile" class="multi-file-edit-pane-content" />
</template>
- <template
- v-else
- >
- <div
- v-once
- class="ide-empty-state"
- >
+ <template v-else>
+ <div v-once class="ide-empty-state">
<div class="row js-empty-state">
<div class="col-12">
- <div class="svg-content svg-250">
- <img :src="emptyStateSvgPath" />
- </div>
+ <div class="svg-content svg-250"><img :src="emptyStateSvgPath" /></div>
</div>
<div class="col-12">
<div class="text-content text-center">
- <h4>
- Welcome to the GitLab IDE
- </h4>
+ <h4>Welcome to the GitLab IDE</h4>
<p>
- Select a file from the left sidebar to begin editing.
- Afterwards, you'll be able to commit your changes.
+ Select a file from the left sidebar to begin editing. Afterwards, you'll be able
+ to commit your changes.
</p>
</div>
</div>
@@ -150,12 +124,9 @@ export default {
</div>
</template>
</div>
- <component
- :is="rightPaneComponent"
- v-if="currentProjectId"
- />
+ <component :is="rightPaneComponent" v-if="currentProjectId" />
</div>
- <ide-status-bar :file="activeFile"/>
+ <ide-status-bar :file="activeFile" />
<new-modal />
</article>
</template>
diff --git a/app/assets/javascripts/ide/components/ide_project_header.vue b/app/assets/javascripts/ide/components/ide_project_header.vue
index 6cf190288e8..36bc7c70196 100644
--- a/app/assets/javascripts/ide/components/ide_project_header.vue
+++ b/app/assets/javascripts/ide/components/ide_project_header.vue
@@ -16,18 +16,10 @@ export default {
<template>
<div class="context-header ide-context-header">
- <a
- :href="project.web_url"
- :title="s__('IDE|Go to project')"
- >
- <project-avatar-default
- :project="project"
- :size="48"
- />
+ <a :href="project.web_url" :title="s__('IDE|Go to project')">
+ <project-avatar-default :project="project" :size="48" />
<span class="ide-sidebar-project-title">
- <span class="sidebar-context-title">
- {{ project.name }}
- </span>
+ <span class="sidebar-context-title"> {{ project.name }} </span>
<span class="sidebar-context-title text-secondary">
{{ project.path_with_namespace }}
</span>
diff --git a/app/assets/javascripts/ide/components/ide_review.vue b/app/assets/javascripts/ide/components/ide_review.vue
index d09c99050fe..901b8892e80 100644
--- a/app/assets/javascripts/ide/components/ide_review.vue
+++ b/app/assets/javascripts/ide/components/ide_review.vue
@@ -42,13 +42,8 @@ export default {
</script>
<template>
- <ide-tree-list
- :viewer-type="viewer"
- header-class="ide-review-header"
- >
- <template
- slot="header"
- >
+ <ide-tree-list :viewer-type="viewer" header-class="ide-review-header">
+ <template slot="header">
<div class="ide-review-button-holder">
{{ __('Review') }}
<editor-mode-dropdown
@@ -63,12 +58,12 @@ export default {
{{ __('Latest changes') }}
</template>
<template v-else-if="showMergeRequestText">
- {{ __('Merge request') }}
- (<a
+ {{ __('Merge request') }} (<a
v-if="currentMergeRequest"
:href="currentMergeRequest.web_url"
v-text="mergeRequestId"
- ></a>)
+ ></a
+ >)
</template>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue
index 364ab9426e0..6178d2b1fc7 100644
--- a/app/assets/javascripts/ide/components/ide_side_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_side_bar.vue
@@ -1,6 +1,6 @@
<script>
import { mapState, mapGetters } from 'vuex';
-import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui';
+import { GlSkeletonLoading } from '@gitlab/ui';
import IdeTree from './ide_tree.vue';
import ResizablePanel from './resizable_panel.vue';
import ActivityBar from './activity_bar.vue';
@@ -37,34 +37,21 @@ export default {
</script>
<template>
- <resizable-panel
- :collapsible="false"
- :initial-width="340"
- side="left"
- class="flex-column"
- >
+ <resizable-panel :collapsible="false" :initial-width="340" side="left" class="flex-column">
<template v-if="loading">
<div class="multi-file-commit-panel-inner">
- <div
- v-for="n in 3"
- :key="n"
- class="multi-file-loading-container"
- >
+ <div v-for="n in 3" :key="n" class="multi-file-loading-container">
<gl-skeleton-loading />
</div>
</div>
</template>
<template v-else>
- <ide-project-header
- :project="currentProject"
- />
+ <ide-project-header :project="currentProject" />
<div class="ide-context-body d-flex flex-fill">
<activity-bar />
<div class="multi-file-commit-panel-inner">
<div class="multi-file-commit-panel-inner-content">
- <component
- :is="currentActivityView"
- />
+ <component :is="currentActivityView" />
</div>
<commit-form />
</div>
diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue
index a04d09ef374..e2e0acc22b1 100644
--- a/app/assets/javascripts/ide/components/ide_status_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_status_bar.vue
@@ -79,18 +79,12 @@ export default {
<template>
<footer class="ide-status-bar">
- <div
- v-if="lastCommit"
- class="ide-status-branch"
- >
- <span
- v-if="latestPipeline && latestPipeline.details"
- class="ide-status-pipeline"
- >
+ <div v-if="lastCommit" class="ide-status-branch">
+ <span v-if="latestPipeline && latestPipeline.details" class="ide-status-pipeline">
<button
type="button"
class="p-0 border-0 h-50"
- @click="openRightPane($options.rightSidebarViews.pipelines)"
+ @click="openRightPane($options.rightSidebarViews.pipelines);"
>
<ci-icon
v-tooltip
@@ -99,24 +93,21 @@ export default {
/>
</button>
Pipeline
- <a
- :href="latestPipeline.details.status.details_path"
- class="monospace">#{{ latestPipeline.id }}</a>
- {{ latestPipeline.details.status.text }}
- for
+ <a :href="latestPipeline.details.status.details_path" class="monospace"
+ >#{{ latestPipeline.id }}</a
+ >
+ {{ latestPipeline.details.status.text }} for
</span>
- <icon
- name="commit"
- />
+ <icon name="commit" />
<a
v-tooltip
:title="lastCommit.message"
:href="getCommitPath(lastCommit.short_id)"
class="commit-sha"
- >{{ lastCommit.short_id }}</a>
- by
- {{ lastCommit.author_name }}
+ >{{ lastCommit.short_id }}</a
+ >
+ by {{ lastCommit.author_name }}
<time
v-tooltip
:datetime="lastCommit.committed_date"
@@ -127,28 +118,11 @@ export default {
{{ lastCommitFormatedAge }}
</time>
</div>
- <div
- v-if="file"
- class="ide-status-file"
- >
- {{ file.name }}
- </div>
- <div
- v-if="file"
- class="ide-status-file"
- >
- {{ file.eol }}
- </div>
- <div
- v-if="file && !file.binary"
- class="ide-status-file">
+ <div v-if="file" class="ide-status-file">{{ file.name }}</div>
+ <div v-if="file" class="ide-status-file">{{ file.eol }}</div>
+ <div v-if="file && !file.binary" class="ide-status-file">
{{ file.editorRow }}:{{ file.editorColumn }}
</div>
- <div
- v-if="file"
- class="ide-status-file"
- >
- {{ file.fileLanguage }}
- </div>
+ <div v-if="file" class="ide-status-file">{{ file.fileLanguage }}</div>
</footer>
</template>
diff --git a/app/assets/javascripts/ide/components/ide_tree.vue b/app/assets/javascripts/ide/components/ide_tree.vue
index 9f9e638f1aa..9fc21adae7c 100644
--- a/app/assets/javascripts/ide/components/ide_tree.vue
+++ b/app/assets/javascripts/ide/components/ide_tree.vue
@@ -34,12 +34,8 @@ export default {
</script>
<template>
- <ide-tree-list
- viewer-type="editor"
- >
- <template
- slot="header"
- >
+ <ide-tree-list viewer-type="editor">
+ <template slot="header">
{{ __('Edit') }}
<div class="ide-tree-actions ml-auto d-flex">
<new-entry-button
@@ -47,7 +43,7 @@ export default {
:show-label="false"
class="d-flex border-0 p-0 mr-3 qa-new-file"
icon="doc-new"
- @click="openNewEntryModal({ type: 'blob' })"
+ @click="openNewEntryModal({ type: 'blob' });"
/>
<upload
:show-label="false"
@@ -60,7 +56,7 @@ export default {
:show-label="false"
class="d-flex border-0 p-0"
icon="folder-new"
- @click="openNewEntryModal({ type: 'tree' })"
+ @click="openNewEntryModal({ type: 'tree' });"
/>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue
index d2ff55a4ee3..81374f26645 100644
--- a/app/assets/javascripts/ide/components/ide_tree_list.vue
+++ b/app/assets/javascripts/ide/components/ide_tree_list.vue
@@ -1,7 +1,7 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
-import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui';
+import { GlSkeletonLoading } from '@gitlab/ui';
import FileRow from '~/vue_shared/components/file_row.vue';
import NavDropdown from './nav_dropdown.vue';
import FileRowExtra from './file_row_extra.vue';
@@ -42,29 +42,18 @@ export default {
</script>
<template>
- <div
- class="ide-file-list qa-file-list"
- >
+ <div class="ide-file-list qa-file-list">
<template v-if="showLoading">
- <div
- v-for="n in 3"
- :key="n"
- class="multi-file-loading-container"
- >
+ <div v-for="n in 3" :key="n" class="multi-file-loading-container">
<gl-skeleton-loading />
</div>
</template>
<template v-else>
- <header
- :class="headerClass"
- class="ide-tree-header"
- >
+ <header :class="headerClass" class="ide-tree-header">
<nav-dropdown />
<slot name="header"></slot>
</header>
- <div
- class="ide-tree-body h-100"
- >
+ <div class="ide-tree-body h-100">
<file-row
v-for="file in currentTree.tree"
:key="file.key"
diff --git a/app/assets/javascripts/ide/components/jobs/detail.vue b/app/assets/javascripts/ide/components/jobs/detail.vue
index f884c26ed6a..e8fe5fc696d 100644
--- a/app/assets/javascripts/ide/components/jobs/detail.vue
+++ b/app/assets/javascripts/ide/components/jobs/detail.vue
@@ -75,20 +75,12 @@ export default {
<template>
<div class="ide-pipeline build-page d-flex flex-column flex-fill">
<header class="ide-job-header d-flex align-items-center">
- <button
- class="btn btn-default btn-sm d-flex"
- @click="setDetailJob(null)"
- >
- <icon
- name="chevron-left"
- />
- {{ __('View jobs') }}
+ <button class="btn btn-default btn-sm d-flex" @click="setDetailJob(null);">
+ <icon name="chevron-left" /> {{ __('View jobs') }}
</button>
</header>
<div class="top-bar d-flex border-left-0">
- <job-description
- :job="detailJob"
- />
+ <job-description :job="detailJob" />
<div class="controllers ml-auto">
<a
v-tooltip
@@ -99,28 +91,13 @@ export default {
class="controllers-buttons"
target="_blank"
>
- <i
- aria-hidden="true"
- class="fa fa-file-text-o"
- ></i>
+ <i aria-hidden="true" class="fa fa-file-text-o"></i>
</a>
- <scroll-button
- :disabled="isScrolledToTop"
- direction="up"
- @click="scrollUp"
- />
- <scroll-button
- :disabled="isScrolledToBottom"
- direction="down"
- @click="scrollDown"
- />
+ <scroll-button :disabled="isScrolledToTop" direction="up" @click="scrollUp" />
+ <scroll-button :disabled="isScrolledToBottom" direction="down" @click="scrollDown" />
</div>
</div>
- <pre
- ref="buildTrace"
- class="build-trace mb-0 h-100"
- @scroll="scrollBuildLog"
- >
+ <pre ref="buildTrace" class="build-trace mb-0 h-100" @scroll="scrollBuildLog">
<code
v-show="!detailJob.isLoading"
class="bash"
diff --git a/app/assets/javascripts/ide/components/jobs/detail/description.vue b/app/assets/javascripts/ide/components/jobs/detail/description.vue
index 7e24974f7e5..7280fba9e7a 100644
--- a/app/assets/javascripts/ide/components/jobs/detail/description.vue
+++ b/app/assets/javascripts/ide/components/jobs/detail/description.vue
@@ -23,24 +23,11 @@ export default {
<template>
<div class="d-flex align-items-center">
- <ci-icon
- :status="job.status"
- :borderless="true"
- :size="24"
- class="d-flex"
- />
+ <ci-icon :status="job.status" :borderless="true" :size="24" class="d-flex" />
<span class="prepend-left-8">
{{ job.name }}
- <a
- :href="job.path"
- target="_blank"
- class="ide-external-link"
- >
- {{ jobId }}
- <icon
- :size="12"
- name="external-link"
- />
+ <a :href="job.path" target="_blank" class="ide-external-link">
+ {{ jobId }} <icon :size="12" name="external-link" />
</a>
</span>
</div>
diff --git a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue
index 103a407987f..5674d3ffa80 100644
--- a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue
+++ b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue
@@ -58,9 +58,7 @@ export default {
type="button"
@click="clickedScroll"
>
- <icon
- :name="iconName"
- />
+ <icon :name="iconName" />
</button>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/jobs/item.vue b/app/assets/javascripts/ide/components/jobs/item.vue
index 7f4695a0451..be8bf77bba0 100644
--- a/app/assets/javascripts/ide/components/jobs/item.vue
+++ b/app/assets/javascripts/ide/components/jobs/item.vue
@@ -26,17 +26,9 @@ export default {
<template>
<div class="ide-job-item">
- <job-description
- :job="job"
- class="append-right-default"
- />
+ <job-description :job="job" class="append-right-default" />
<div class="ml-auto align-self-center">
- <button
- v-if="job.started"
- type="button"
- class="btn btn-default btn-sm"
- @click="clickViewLog"
- >
+ <button v-if="job.started" type="button" class="btn btn-default btn-sm" @click="clickViewLog">
{{ __('View log') }}
</button>
</div>
diff --git a/app/assets/javascripts/ide/components/jobs/list.vue b/app/assets/javascripts/ide/components/jobs/list.vue
index 57da8b4e2cb..2cb5050c3f0 100644
--- a/app/assets/javascripts/ide/components/jobs/list.vue
+++ b/app/assets/javascripts/ide/components/jobs/list.vue
@@ -1,6 +1,6 @@
<script>
import { mapActions } from 'vuex';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import Stage from './stage.vue';
export default {
@@ -26,11 +26,7 @@ export default {
<template>
<div>
- <gl-loading-icon
- v-if="loading && !stages.length"
- :size="2"
- class="prepend-top-default"
- />
+ <gl-loading-icon v-if="loading && !stages.length" :size="2" class="prepend-top-default" />
<template v-else>
<stage
v-for="stage in stages"
diff --git a/app/assets/javascripts/ide/components/jobs/stage.vue b/app/assets/javascripts/ide/components/jobs/stage.vue
index 5644759d2f9..b1be25ea602 100644
--- a/app/assets/javascripts/ide/components/jobs/stage.vue
+++ b/app/assets/javascripts/ide/components/jobs/stage.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import tooltip from '../../../vue_shared/directives/tooltip';
import Icon from '../../../vue_shared/components/icon.vue';
import CiIcon from '../../../vue_shared/components/ci_icon.vue';
@@ -56,20 +56,15 @@ export default {
</script>
<template>
- <div
- class="ide-stage card prepend-top-default"
- >
+ <div class="ide-stage card prepend-top-default">
<div
:class="{
- 'border-bottom-0': stage.isCollapsed
+ 'border-bottom-0': stage.isCollapsed,
}"
class="card-header"
@click="toggleCollapsed"
>
- <ci-icon
- :status="stage.status"
- :size="24"
- />
+ <ci-icon :status="stage.status" :size="24" />
<strong
ref="stageTitle"
v-tooltip="showTooltip"
@@ -79,33 +74,15 @@ export default {
>
{{ stage.name }}
</strong>
- <div
- v-if="!stage.isLoading || stage.jobs.length"
- class="append-right-8 prepend-left-4"
- >
- <span class="badge badge-pill">
- {{ jobsCount }}
- </span>
+ <div v-if="!stage.isLoading || stage.jobs.length" class="append-right-8 prepend-left-4">
+ <span class="badge badge-pill"> {{ jobsCount }} </span>
</div>
- <icon
- :name="collapseIcon"
- css-classes="ide-stage-collapse-icon"
- />
+ <icon :name="collapseIcon" css-classes="ide-stage-collapse-icon" />
</div>
- <div
- v-show="!stage.isCollapsed"
- class="card-body"
- >
- <gl-loading-icon
- v-if="showLoadingIcon"
- />
+ <div v-show="!stage.isCollapsed" class="card-body">
+ <gl-loading-icon v-if="showLoadingIcon" />
<template v-else>
- <item
- v-for="job in stage.jobs"
- :key="job.id"
- :job="job"
- @clickViewLog="clickViewLog"
- />
+ <item v-for="job in stage.jobs" :key="job.id" :job="job" @clickViewLog="clickViewLog" />
</template>
</div>
</div>
diff --git a/app/assets/javascripts/ide/components/merge_requests/info.vue b/app/assets/javascripts/ide/components/merge_requests/info.vue
index 199d2e74971..73ec992466c 100644
--- a/app/assets/javascripts/ide/components/merge_requests/info.vue
+++ b/app/assets/javascripts/ide/components/merge_requests/info.vue
@@ -19,13 +19,8 @@ export default {
<template>
<div class="ide-merge-request-info h-100 d-flex flex-column">
<div class="detail-page-header">
- <icon
- name="git-merge"
- class="align-self-center append-right-8"
- />
- <strong>
- !{{ currentMergeRequest.iid }}
- </strong>
+ <icon name="git-merge" class="align-self-center append-right-8" />
+ <strong> !{{ currentMergeRequest.iid }} </strong>
</div>
<div class="issuable-details">
<title-component
diff --git a/app/assets/javascripts/ide/components/merge_requests/item.vue b/app/assets/javascripts/ide/components/merge_requests/item.vue
index 0c4ea80ba08..60889c893cf 100644
--- a/app/assets/javascripts/ide/components/merge_requests/item.vue
+++ b/app/assets/javascripts/ide/components/merge_requests/item.vue
@@ -40,24 +40,13 @@ export default {
</script>
<template>
- <a
- :href="mergeRequestHref"
- class="btn-link d-flex align-items-center"
- >
+ <a :href="mergeRequestHref" class="btn-link d-flex align-items-center">
<span class="d-flex append-right-default ide-search-list-current-icon">
- <icon
- v-if="isActive"
- :size="18"
- name="mobile-issue-close"
- />
+ <icon v-if="isActive" :size="18" name="mobile-issue-close" />
</span>
<span>
- <strong>
- {{ item.title }}
- </strong>
- <span class="ide-merge-request-project-path d-block mt-1">
- {{ pathWithID }}
- </span>
+ <strong> {{ item.title }} </strong>
+ <span class="ide-merge-request-project-path d-block mt-1"> {{ pathWithID }} </span>
</span>
</a>
</template>
diff --git a/app/assets/javascripts/ide/components/merge_requests/list.vue b/app/assets/javascripts/ide/components/merge_requests/list.vue
index e4000f588bd..ac2b0eddfb4 100644
--- a/app/assets/javascripts/ide/components/merge_requests/list.vue
+++ b/app/assets/javascripts/ide/components/merge_requests/list.vue
@@ -3,7 +3,7 @@ import { mapActions, mapState } from 'vuex';
import _ from 'underscore';
import { __ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import Item from './item.vue';
import TokenedInput from '../shared/tokened_input.vue';
@@ -84,13 +84,9 @@ export default {
:placeholder="__('Search merge requests')"
@focus="onSearchFocus"
@input="searchMergeRequests"
- @removeToken="setSearchType(null)"
- />
- <icon
- :size="18"
- name="search"
- class="input-icon"
+ @removeToken="setSearchType(null);"
/>
+ <icon :size="18" name="search" class="input-icon" />
</div>
</div>
<div class="dropdown-content ide-merge-requests-dropdown-content d-flex">
@@ -100,36 +96,23 @@ export default {
class="mt-3 mb-3 align-self-center ml-auto mr-auto"
/>
<template v-else>
- <ul
- class="mb-3 w-100"
- >
+ <ul class="mb-3 w-100">
<template v-if="showSearchTypes">
- <li
- v-for="searchType in $options.searchTypes"
- :key="searchType.type"
- >
+ <li v-for="searchType in $options.searchTypes" :key="searchType.type">
<button
type="button"
class="btn-link d-flex align-items-center"
- @click.stop="setSearchType(searchType)"
+ @click.stop="setSearchType(searchType);"
>
<span class="d-flex append-right-default ide-search-list-current-icon">
- <icon
- :size="18"
- name="search"
- />
- </span>
- <span>
- {{ searchType.label }}
+ <icon :size="18" name="search" />
</span>
+ <span> {{ searchType.label }} </span>
</button>
</li>
</template>
<template v-else-if="hasMergeRequests">
- <li
- v-for="item in mergeRequests"
- :key="item.id"
- >
+ <li v-for="item in mergeRequests" :key="item.id">
<item
:item="item"
:current-id="currentMergeRequestId"
@@ -137,10 +120,7 @@ export default {
/>
</li>
</template>
- <li
- v-else
- class="ide-search-list-empty d-flex align-items-center justify-content-center"
- >
+ <li v-else class="ide-search-list-empty d-flex align-items-center justify-content-center">
{{ __('No merge requests found') }}
</li>
</ul>
diff --git a/app/assets/javascripts/ide/components/nav_dropdown.vue b/app/assets/javascripts/ide/components/nav_dropdown.vue
index db36779c395..e45d2a62dae 100644
--- a/app/assets/javascripts/ide/components/nav_dropdown.vue
+++ b/app/assets/javascripts/ide/components/nav_dropdown.vue
@@ -43,17 +43,8 @@ export default {
</script>
<template>
- <div
- ref="dropdown"
- class="btn-group ide-nav-dropdown dropdown"
- >
+ <div ref="dropdown" class="btn-group ide-nav-dropdown dropdown">
<nav-dropdown-button />
- <div
- class="dropdown-menu dropdown-menu-left p-0"
- >
- <nav-form
- v-if="isVisibleDropdown"
- />
- </div>
+ <div class="dropdown-menu dropdown-menu-left p-0"><nav-form v-if="isVisibleDropdown" /></div>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/nav_dropdown_button.vue b/app/assets/javascripts/ide/components/nav_dropdown_button.vue
index 6cee4e9a8f0..f1d44443125 100644
--- a/app/assets/javascripts/ide/components/nav_dropdown_button.vue
+++ b/app/assets/javascripts/ide/components/nav_dropdown_button.vue
@@ -24,27 +24,12 @@ export default {
<template>
<dropdown-button>
- <span
- class="row"
- >
- <span
- class="col-7 text-truncate"
- >
- <icon
- :size="16"
- :aria-label="__('Current Branch')"
- name="branch"
- />
- {{ branchLabel }}
+ <span class="row">
+ <span class="col-7 text-truncate">
+ <icon :size="16" :aria-label="__('Current Branch')" name="branch" /> {{ branchLabel }}
</span>
- <span
- class="col-5 pl-0 text-truncate"
- >
- <icon
- :size="16"
- :aria-label="__('Merge Request')"
- name="merge-request"
- />
+ <span class="col-5 pl-0 text-truncate">
+ <icon :size="16" :aria-label="__('Merge Request')" name="merge-request" />
{{ mergeRequestLabel }}
</span>
</span>
diff --git a/app/assets/javascripts/ide/components/nav_form.vue b/app/assets/javascripts/ide/components/nav_form.vue
index 718b836e11c..23c068f329d 100644
--- a/app/assets/javascripts/ide/components/nav_form.vue
+++ b/app/assets/javascripts/ide/components/nav_form.vue
@@ -15,15 +15,9 @@ export default {
</script>
<template>
- <div
- class="ide-nav-form p-0"
- >
- <tabs
- stop-propagation
- >
- <tab
- active
- >
+ <div class="ide-nav-form p-0">
+ <tabs stop-propagation>
+ <tab active>
<template slot="title">
{{ __('Merge Requests') }}
</template>
diff --git a/app/assets/javascripts/ide/components/new_dropdown/button.vue b/app/assets/javascripts/ide/components/new_dropdown/button.vue
index aa5fce59dbf..062a64a19d7 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/button.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/button.vue
@@ -52,10 +52,7 @@ export default {
class="btn-blank"
@click.stop.prevent="clicked"
>
- <icon
- :name="icon"
- :css-classes="iconClasses"
- />
+ <icon :name="icon" :css-classes="iconClasses" />
<template v-if="showLabel">
{{ label }}
</template>
diff --git a/app/assets/javascripts/ide/components/new_dropdown/index.vue b/app/assets/javascripts/ide/components/new_dropdown/index.vue
index f02fd6cf7ea..a50d729036f 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/index.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/index.vue
@@ -73,19 +73,11 @@ export default {
:aria-label="__('Create new file or directory')"
type="button"
class="rounded border-0 d-flex ide-entry-dropdown-toggle"
- @click.stop="openDropdown()"
+ @click.stop="openDropdown();"
>
- <icon
- name="ellipsis_v"
- />
- <icon
- name="arrow-down"
- />
+ <icon name="ellipsis_v" /> <icon name="arrow-down" />
</button>
- <ul
- ref="dropdownMenu"
- class="dropdown-menu dropdown-menu-right"
- >
+ <ul ref="dropdownMenu" class="dropdown-menu dropdown-menu-right">
<template v-if="type === 'tree'">
<li>
<item-button
@@ -93,22 +85,17 @@ export default {
class="d-flex"
icon="doc-new"
icon-classes="mr-2"
- @click="createNewItem('blob')"
- />
- </li>
- <li>
- <upload
- :path="path"
- @create="createTempEntry"
+ @click="createNewItem('blob');"
/>
</li>
+ <li><upload :path="path" @create="createTempEntry" /></li>
<li>
<item-button
:label="__('New directory')"
class="d-flex"
icon="folder-new"
icon-classes="mr-2"
- @click="createNewItem($options.modalTypes.tree)"
+ @click="createNewItem($options.modalTypes.tree);"
/>
</li>
<li class="divider"></li>
@@ -119,7 +106,7 @@ export default {
class="d-flex"
icon="pencil"
icon-classes="mr-2"
- @click="createNewItem($options.modalTypes.rename)"
+ @click="createNewItem($options.modalTypes.rename);"
/>
</li>
<li>
@@ -128,7 +115,7 @@ export default {
class="d-flex"
icon="remove"
icon-classes="mr-2"
- @click="deleteEntry(path)"
+ @click="deleteEntry(path);"
/>
</li>
</ul>
diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
index f0a04011a3e..63cbf41b89b 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
@@ -99,12 +99,8 @@ export default {
@open="focusInput"
@closed="closedModal"
>
- <div
- class="form-group row"
- >
- <label class="label-bold col-form-label col-sm-2">
- {{ __('Name') }}
- </label>
+ <div class="form-group row">
+ <label class="label-bold col-form-label col-sm-2"> {{ __('Name') }} </label>
<div class="col-sm-10">
<input
ref="fieldName"
@@ -113,19 +109,12 @@ export default {
class="form-control qa-full-file-path"
placeholder="/dir/file_name"
/>
- <ul
- v-if="isCreatingNew"
- class="prepend-top-default list-inline qa-template-list"
- >
- <li
- v-for="(template, index) in templateTypes"
- :key="index"
- class="list-inline-item"
- >
+ <ul v-if="isCreatingNew" class="prepend-top-default list-inline qa-template-list">
+ <li v-for="(template, index) in templateTypes" :key="index" class="list-inline-item">
<button
type="button"
class="btn btn-missing p-1 pr-2 pl-2"
- @click="createFromTemplate(template)"
+ @click="createFromTemplate(template);"
>
{{ template.name }}
</button>
diff --git a/app/assets/javascripts/ide/components/panes/right.vue b/app/assets/javascripts/ide/components/panes/right.vue
index 10aa96dffaf..7a57ccf2dd3 100644
--- a/app/assets/javascripts/ide/components/panes/right.vue
+++ b/app/assets/javascripts/ide/components/panes/right.vue
@@ -89,9 +89,7 @@ export default {
</script>
<template>
- <div
- class="multi-file-commit-panel ide-right-sidebar"
- >
+ <div class="multi-file-commit-panel ide-right-sidebar">
<resizable-panel
v-show="isOpen"
:collapsible="false"
@@ -107,32 +105,26 @@ export default {
:key="tabView.name"
class="h-100"
>
- <component :is="tabView.name" />
+ <component :is="tabView.component || tabView.name" />
</div>
</resizable-panel>
<nav class="ide-activity-bar">
<ul class="list-unstyled">
- <li
- v-for="tab of tabs"
- :key="tab.title"
- >
+ <li v-for="tab of tabs" :key="tab.title">
<button
v-tooltip
:title="tab.title"
:aria-label="tab.title"
:class="{
- active: isActiveTab(tab) && isOpen
+ active: isActiveTab(tab) && isOpen,
}"
data-container="body"
data-placement="left"
class="ide-sidebar-link is-right"
type="button"
- @click="clickTab($event, tab)"
+ @click="clickTab($event, tab);"
>
- <icon
- :size="16"
- :name="tab.icon"
- />
+ <icon :size="16" :name="tab.icon" />
</button>
</li>
</ul>
diff --git a/app/assets/javascripts/ide/components/pipelines/list.vue b/app/assets/javascripts/ide/components/pipelines/list.vue
index 16aec1decd6..451c8030e16 100644
--- a/app/assets/javascripts/ide/components/pipelines/list.vue
+++ b/app/assets/javascripts/ide/components/pipelines/list.vue
@@ -1,7 +1,7 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import _ from 'underscore';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import { sprintf, __ } from '../../../locale';
import Icon from '../../../vue_shared/components/icon.vue';
import CiIcon from '../../../vue_shared/components/ci_icon.vue';
@@ -50,34 +50,14 @@ export default {
<template>
<div class="ide-pipeline">
- <gl-loading-icon
- v-if="showLoadingIcon"
- :size="2"
- class="prepend-top-default"
- />
+ <gl-loading-icon v-if="showLoadingIcon" :size="2" class="prepend-top-default" />
<template v-else-if="latestPipeline !== null">
- <header
- v-if="latestPipeline"
- class="ide-tree-header ide-pipeline-header"
- >
- <ci-icon
- :status="latestPipeline.details.status"
- :size="24"
- />
+ <header v-if="latestPipeline" class="ide-tree-header ide-pipeline-header">
+ <ci-icon :status="latestPipeline.details.status" :size="24" />
<span class="prepend-left-8">
- <strong>
- {{ __('Pipeline') }}
- </strong>
- <a
- :href="latestPipeline.path"
- target="_blank"
- class="ide-external-link"
- >
- #{{ latestPipeline.id }}
- <icon
- :size="12"
- name="external-link"
- />
+ <strong> {{ __('Pipeline') }} </strong>
+ <a :href="latestPipeline.path" target="_blank" class="ide-external-link">
+ #{{ latestPipeline.id }} <icon :size="12" name="external-link" />
</a>
</span>
</header>
@@ -87,58 +67,25 @@ export default {
:empty-state-svg-path="pipelinesEmptyStateSvgPath"
:can-set-ci="true"
/>
- <div
- v-else-if="latestPipeline.yamlError"
- class="bs-callout bs-callout-danger"
- >
- <p class="append-bottom-0">
- {{ __('Found errors in your .gitlab-ci.yml:') }}
- </p>
- <p class="append-bottom-0 break-word">
- {{ latestPipeline.yamlError }}
- </p>
- <p
- class="append-bottom-0"
- v-html="ciLintText"
- ></p>
+ <div v-else-if="latestPipeline.yamlError" class="bs-callout bs-callout-danger">
+ <p class="append-bottom-0">{{ __('Found errors in your .gitlab-ci.yml:') }}</p>
+ <p class="append-bottom-0 break-word">{{ latestPipeline.yamlError }}</p>
+ <p class="append-bottom-0" v-html="ciLintText"></p>
</div>
- <tabs
- v-else
- class="ide-pipeline-list"
- >
- <tab
- :active="!pipelineFailed"
- >
+ <tabs v-else class="ide-pipeline-list">
+ <tab :active="!pipelineFailed">
<template slot="title">
{{ __('Jobs') }}
- <span
- v-if="jobsCount"
- class="badge badge-pill"
- >
- {{ jobsCount }}
- </span>
+ <span v-if="jobsCount" class="badge badge-pill"> {{ jobsCount }} </span>
</template>
- <jobs-list
- :loading="isLoadingJobs"
- :stages="stages"
- />
+ <jobs-list :loading="isLoadingJobs" :stages="stages" />
</tab>
- <tab
- :active="pipelineFailed"
- >
+ <tab :active="pipelineFailed">
<template slot="title">
{{ __('Failed Jobs') }}
- <span
- v-if="failedJobsCount"
- class="badge badge-pill"
- >
- {{ failedJobsCount }}
- </span>
+ <span v-if="failedJobsCount" class="badge badge-pill"> {{ failedJobsCount }} </span>
</template>
- <jobs-list
- :loading="isLoadingJobs"
- :stages="failedStages"
- />
+ <jobs-list :loading="isLoadingJobs" :stages="failedStages" />
</tab>
</tabs>
</template>
diff --git a/app/assets/javascripts/ide/components/preview/clientside.vue b/app/assets/javascripts/ide/components/preview/clientside.vue
index 0bd56ff6e9b..c98dda00817 100644
--- a/app/assets/javascripts/ide/components/preview/clientside.vue
+++ b/app/assets/javascripts/ide/components/preview/clientside.vue
@@ -3,7 +3,7 @@ import { mapActions, mapGetters, mapState } from 'vuex';
import _ from 'underscore';
import { Manager } from 'smooshpack';
import { listen } from 'codesandbox-api';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import Navigator from './navigator.vue';
import { packageJsonPath } from '../../constants';
import { createPathWithExt } from '../../utils';
@@ -146,9 +146,7 @@ export default {
<template>
<div class="preview h-100 w-100 d-flex flex-column">
<template v-if="showPreview">
- <navigator
- :manager="manager"
- />
+ <navigator :manager="manager" />
<div id="ide-preview"></div>
</template>
<div
@@ -156,15 +154,8 @@ export default {
v-once
class="d-flex h-100 flex-column align-items-center justify-content-center svg-content"
>
- <img
- :src="promotionSvgPath"
- :alt="s__('IDE|Live Preview')"
- width="130"
- height="100"
- />
- <h3>
- {{ s__('IDE|Live Preview') }}
- </h3>
+ <img :src="promotionSvgPath" :alt="s__('IDE|Live Preview')" width="130" height="100" />
+ <h3>{{ s__('IDE|Live Preview') }}</h3>
<p class="text-center">
{{ s__('IDE|Preview your web application using Web IDE client-side evaluation.') }}
</p>
@@ -177,10 +168,6 @@ export default {
{{ s__('IDE|Get started with Live Preview') }}
</a>
</div>
- <gl-loading-icon
- v-else
- :size="2"
- class="align-self-center mt-auto mb-auto"
- />
+ <gl-loading-icon v-else :size="2" class="align-self-center mt-auto mb-auto" />
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/preview/navigator.vue b/app/assets/javascripts/ide/components/preview/navigator.vue
index af8959186f9..bc80e1dba25 100644
--- a/app/assets/javascripts/ide/components/preview/navigator.vue
+++ b/app/assets/javascripts/ide/components/preview/navigator.vue
@@ -1,7 +1,7 @@
<script>
import { listen } from 'codesandbox-api';
import Icon from '~/vue_shared/components/icon.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
@@ -91,33 +91,25 @@ export default {
:aria-label="s__('IDE|Back')"
:disabled="backButtonDisabled"
:class="{
- 'disabled-content': backButtonDisabled
+ 'disabled-content': backButtonDisabled,
}"
type="button"
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
@click="back"
>
- <icon
- :size="24"
- name="chevron-left"
- class="m-auto"
- />
+ <icon :size="24" name="chevron-left" class="m-auto" />
</button>
<button
:aria-label="s__('IDE|Back')"
:disabled="forwardButtonDisabled"
:class="{
- 'disabled-content': forwardButtonDisabled
+ 'disabled-content': forwardButtonDisabled,
}"
type="button"
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
@click="forward"
>
- <icon
- :size="24"
- name="chevron-right"
- class="m-auto"
- />
+ <icon :size="24" name="chevron-right" class="m-auto" />
</button>
<button
:aria-label="s__('IDE|Refresh preview')"
@@ -125,11 +117,7 @@ export default {
class="ide-navigator-btn d-flex align-items-center d-transparent border-0 bg-transparent"
@click="refresh"
>
- <icon
- :size="18"
- name="retry"
- class="m-auto"
- />
+ <icon :size="18" name="retry" class="m-auto" />
</button>
<div class="position-relative w-100 prepend-left-4">
<input
@@ -138,10 +126,7 @@ export default {
class="ide-navigator-location form-control bg-white"
readonly
/>
- <gl-loading-icon
- v-if="loading"
- class="position-absolute ide-preview-loading-icon"
- />
+ <gl-loading-icon v-if="loading" class="position-absolute ide-preview-loading-icon" />
</div>
</header>
</template>
diff --git a/app/assets/javascripts/ide/components/repo_commit_section.vue b/app/assets/javascripts/ide/components/repo_commit_section.vue
index 5e86876c1c1..8dd88f187d4 100644
--- a/app/assets/javascripts/ide/components/repo_commit_section.vue
+++ b/app/assets/javascripts/ide/components/repo_commit_section.vue
@@ -71,9 +71,7 @@ export default {
</script>
<template>
- <div
- class="multi-file-commit-panel-section"
- >
+ <div class="multi-file-commit-panel-section">
<deprecated-modal
id="ide-create-branch-modal"
:primary-button-label="__('Create new branch')"
@@ -82,13 +80,13 @@ export default {
@submit="forceCreateNewBranch"
>
<template slot="body">
- {{ __(`This branch has changed since you started editing.
- Would you like to create a new branch?`) }}
+ {{
+ __(`This branch has changed since you started editing.
+ Would you like to create a new branch?`)
+ }}
</template>
</deprecated-modal>
- <template
- v-if="showStageUnstageArea"
- >
+ <template v-if="showStageUnstageArea">
<commit-files-list
:title="__('Unstaged')"
:key-prefix="$options.stageKeys.unstaged"
@@ -116,8 +114,6 @@ export default {
icon-name="staged"
/>
</template>
- <empty-state
- v-if="unusedSeal"
- />
+ <empty-state v-if="unusedSeal" />
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index 7b0f717962e..c13d3ec094b 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -212,20 +212,15 @@ export default {
</script>
<template>
- <div
- id="ide"
- class="blob-viewer-container blob-editor-container"
- >
+ <div id="ide" class="blob-viewer-container blob-editor-container">
<div class="ide-mode-tabs clearfix">
- <ul
- v-if="!shouldHideEditor && isEditModeActive"
- class="nav-links float-left"
- >
+ <ul v-if="!shouldHideEditor && isEditModeActive" class="nav-links float-left">
<li :class="editTabCSS">
<a
href="javascript:void(0);"
role="button"
- @click.prevent="setFileViewMode({ file, viewMode: 'editor' })">
+ @click.prevent="setFileViewMode({ file, viewMode: 'editor' });"
+ >
<template v-if="viewer === $options.viewerTypes.edit">
{{ __('Edit') }}
</template>
@@ -234,41 +229,36 @@ export default {
</template>
</a>
</li>
- <li
- v-if="file.previewMode"
- :class="previewTabCSS">
+ <li v-if="file.previewMode" :class="previewTabCSS">
<a
href="javascript:void(0);"
role="button"
- @click.prevent="setFileViewMode({ file, viewMode:'preview' })">
+ @click.prevent="setFileViewMode({ file, viewMode: 'preview' });"
+ >
{{ file.previewMode.previewTitle }}
</a>
</li>
</ul>
- <external-link
- :file="file"
- />
+ <external-link :file="file" />
</div>
- <file-templates-bar
- v-if="showFileTemplatesBar(file.name)"
- />
+ <file-templates-bar v-if="showFileTemplatesBar(file.name)" />
<div
- v-show="!shouldHideEditor && file.viewMode ==='editor'"
+ v-show="!shouldHideEditor && file.viewMode === 'editor'"
ref="editor"
:class="{
'is-readonly': isCommitModeActive,
'is-deleted': file.deleted,
- 'is-added': file.tempFile
+ 'is-added': file.tempFile,
}"
class="multi-file-editor-holder"
- >
- </div>
+ ></div>
<content-viewer
v-if="showContentViewer"
:content="file.content || file.raw"
:path="file.rawPath || file.path"
:file-size="file.size"
- :project-path="file.projectId"/>
+ :project-path="file.projectId"
+ />
<diff-viewer
v-if="showDiffViewer"
:diff-mode="file.mrChange.diffMode"
@@ -276,6 +266,7 @@ export default {
:new-sha="currentMergeRequest.sha"
:old-path="file.mrChange.old_path"
:old-sha="currentMergeRequest.baseCommitSha"
- :project-path="file.projectId"/>
+ :project-path="file.projectId"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/repo_file_status_icon.vue b/app/assets/javascripts/ide/components/repo_file_status_icon.vue
index 97589e116c5..a964d90b090 100644
--- a/app/assets/javascripts/ide/components/repo_file_status_icon.vue
+++ b/app/assets/javascripts/ide/components/repo_file_status_icon.vue
@@ -25,15 +25,7 @@ export default {
</script>
<template>
- <span
- v-if="file.file_lock"
- v-tooltip
- :title="lockTooltip"
- data-container="body"
- >
- <icon
- name="lock"
- css-classes="file-status-icon"
- />
+ <span v-if="file.file_lock" v-tooltip :title="lockTooltip" data-container="body">
+ <icon name="lock" css-classes="file-status-icon" />
</span>
</template>
diff --git a/app/assets/javascripts/ide/components/repo_tab.vue b/app/assets/javascripts/ide/components/repo_tab.vue
index d621653d6fd..4b87b83db8a 100644
--- a/app/assets/javascripts/ide/components/repo_tab.vue
+++ b/app/assets/javascripts/ide/components/repo_tab.vue
@@ -72,41 +72,26 @@ export default {
<li
:class="{
active: tab.active,
- disabled: tab.pending
+ disabled: tab.pending,
}"
- @click="clickFile(tab)"
+ @click="clickFile(tab);"
@mouseover="mouseOverTab"
@mouseout="mouseOutTab"
>
- <div
- :title="tab.url"
- class="multi-file-tab"
- >
- <file-icon
- :file-name="tab.name"
- :size="16"
- />
+ <div :title="tab.url" class="multi-file-tab">
+ <file-icon :file-name="tab.name" :size="16" />
{{ tab.name }}
- <file-status-icon
- :file="tab"
- />
+ <file-status-icon :file="tab" />
</div>
<button
:aria-label="closeLabel"
:disabled="tab.pending"
type="button"
class="multi-file-tab-close"
- @click.stop.prevent="closeFile(tab)"
+ @click.stop.prevent="closeFile(tab);"
>
- <icon
- v-if="!showChangedIcon"
- :size="12"
- name="close"
- />
- <changed-file-icon
- v-else
- :file="tab"
- />
+ <icon v-if="!showChangedIcon" :size="12" name="close" />
+ <changed-file-icon v-else :file="tab" />
</button>
</li>
</template>
diff --git a/app/assets/javascripts/ide/components/repo_tabs.vue b/app/assets/javascripts/ide/components/repo_tabs.vue
index c12a63e26be..4dbc4383894 100644
--- a/app/assets/javascripts/ide/components/repo_tabs.vue
+++ b/app/assets/javascripts/ide/components/repo_tabs.vue
@@ -51,15 +51,8 @@ export default {
<template>
<div class="multi-file-tabs">
- <ul
- ref="tabsScroller"
- class="list-unstyled append-bottom-0"
- >
- <repo-tab
- v-for="tab in files"
- :key="tab.key"
- :tab="tab"
- />
+ <ul ref="tabsScroller" class="list-unstyled append-bottom-0">
+ <repo-tab v-for="tab in files" :key="tab.key" :tab="tab" />
</ul>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/resizable_panel.vue b/app/assets/javascripts/ide/components/resizable_panel.vue
index 7277fcb7617..a89de56ab5c 100644
--- a/app/assets/javascripts/ide/components/resizable_panel.vue
+++ b/app/assets/javascripts/ide/components/resizable_panel.vue
@@ -78,8 +78,8 @@ export default {
:min-size="minSize"
:max-size="$options.maxSize"
:side="side === 'right' ? 'left' : 'right'"
- @resize-start="setResizingStatus(true)"
- @resize-end="setResizingStatus(false)"
+ @resize-start="setResizingStatus(true);"
+ @resize-end="setResizingStatus(false);"
/>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/shared/tokened_input.vue b/app/assets/javascripts/ide/components/shared/tokened_input.vue
index 30010957a16..f58e08c2cc9 100644
--- a/app/assets/javascripts/ide/components/shared/tokened_input.vue
+++ b/app/assets/javascripts/ide/components/shared/tokened_input.vue
@@ -72,31 +72,16 @@ export default {
<div class="filtered-search-wrapper">
<div class="filtered-search-box">
<div class="tokens-container list-unstyled">
- <div
- v-for="token in tokens"
- :key="token.label"
- class="filtered-search-token"
- >
+ <div v-for="token in tokens" :key="token.label" class="filtered-search-token">
<button
class="selectable btn-blank"
type="button"
- @click.stop="removeToken(token)"
- @keyup.delete="removeToken(token)"
+ @click.stop="removeToken(token);"
+ @keyup.delete="removeToken(token);"
>
- <div
- class="value-container rounded"
- >
- <div
- class="value"
- >{{ token.label }}</div>
- <div
- class="remove-token inverted"
- >
- <icon
- :size="10"
- name="close"
- />
- </div>
+ <div class="value-container rounded">
+ <div class="value">{{ token.label }}</div>
+ <div class="remove-token inverted"><icon :size="10" name="close" /></div>
</div>
</button>
</div>
diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js
index 3b201f006aa..09245ed0296 100644
--- a/app/assets/javascripts/ide/constants.js
+++ b/app/assets/javascripts/ide/constants.js
@@ -26,6 +26,7 @@ export const diffModes = {
new: 'new',
deleted: 'deleted',
renamed: 'renamed',
+ mode_changed: 'mode_changed',
};
export const rightSidebarViews = {
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index 7a5a227db30..6351948f750 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -1,10 +1,11 @@
import Vue from 'vue';
import { mapActions } from 'vuex';
+import _ from 'underscore';
import Translate from '~/vue_shared/translate';
import ide from './components/ide.vue';
import store from './stores';
import router from './ide_router';
-import { convertPermissionToBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
Vue.use(Translate);
@@ -13,19 +14,19 @@ Vue.use(Translate);
*
* @param {Element} el - The element that will contain the IDE.
* @param {Object} options - Extra options for the IDE (Used by EE).
- * @param {(e:Element) => Object} options.extraInitialData -
- * Function that returns extra properties to seed initial data.
* @param {Component} options.rootComponent -
* Component that overrides the root component.
+ * @param {(store:Vuex.Store, el:Element) => Vuex.Store} options.extendStore -
+ * Function that receives the default store and returns an extended one.
*/
export function initIde(el, options = {}) {
if (!el) return null;
- const { extraInitialData = () => ({}), rootComponent = ide } = options;
+ const { rootComponent = ide, extendStore = _.identity } = options;
return new Vue({
el,
- store,
+ store: extendStore(store, el),
router,
created() {
this.setEmptyStateSvgs({
@@ -40,8 +41,7 @@ export function initIde(el, options = {}) {
webIDEHelpPagePath: el.dataset.webIdeHelpPagePath,
});
this.setInitialData({
- clientsidePreviewEnabled: convertPermissionToBoolean(el.dataset.clientsidePreviewEnabled),
- ...extraInitialData(el),
+ clientsidePreviewEnabled: parseBoolean(el.dataset.clientsidePreviewEnabled),
});
},
methods: {
diff --git a/app/assets/javascripts/ide/services/index.js b/app/assets/javascripts/ide/services/index.js
index f0193d8e8ea..13449592e62 100644
--- a/app/assets/javascripts/ide/services/index.js
+++ b/app/assets/javascripts/ide/services/index.js
@@ -41,13 +41,13 @@ export default {
return Api.project(`${namespace}/${project}`);
},
getProjectMergeRequestData(projectId, mergeRequestId, params = {}) {
- return Api.mergeRequest(projectId, mergeRequestId, params);
+ return Api.projectMergeRequest(projectId, mergeRequestId, params);
},
getProjectMergeRequestChanges(projectId, mergeRequestId) {
- return Api.mergeRequestChanges(projectId, mergeRequestId);
+ return Api.projectMergeRequestChanges(projectId, mergeRequestId);
},
getProjectMergeRequestVersions(projectId, mergeRequestId) {
- return Api.mergeRequestVersions(projectId, mergeRequestId);
+ return Api.projectMergeRequestVersions(projectId, mergeRequestId);
},
getBranchData(projectId, currentBranchId) {
return Api.branchSingle(projectId, currentBranchId);
diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js
index 30dcf7ef4df..e74b880e02c 100644
--- a/app/assets/javascripts/ide/stores/actions/file.js
+++ b/app/assets/javascripts/ide/stores/actions/file.js
@@ -56,7 +56,10 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => {
dispatch('scrollToTab');
};
-export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive = true }) => {
+export const getFileData = (
+ { state, commit, dispatch },
+ { path, makeFileActive = true, openFile = makeFileActive },
+) => {
const file = state.entries[path];
if (file.raw || (file.tempFile && !file.prevPath)) return Promise.resolve();
@@ -71,15 +74,15 @@ export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive
const normalizedHeaders = normalizeHeaders(headers);
setPageTitle(decodeURI(normalizedHeaders['PAGE-TITLE']));
- commit(types.SET_FILE_DATA, { data, file });
- if (makeFileActive) commit(types.TOGGLE_FILE_OPEN, path);
+ if (data) commit(types.SET_FILE_DATA, { data, file });
+ if (openFile) commit(types.TOGGLE_FILE_OPEN, path);
if (makeFileActive) dispatch('setFileActive', path);
commit(types.TOGGLE_LOADING, { entry: file });
})
.catch(() => {
commit(types.TOGGLE_LOADING, { entry: file });
dispatch('setErrorMessage', {
- text: __('An error occured whilst loading the file.'),
+ text: __('An error occurred whilst loading the file.'),
action: payload =>
dispatch('getFileData', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
@@ -121,7 +124,7 @@ export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) =
})
.catch(() => {
dispatch('setErrorMessage', {
- text: __('An error occured whilst loading the file content.'),
+ text: __('An error occurred whilst loading the file content.'),
action: payload =>
dispatch('getRawFileData', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js
index 3ac2f8b3698..18c24369996 100644
--- a/app/assets/javascripts/ide/stores/actions/merge_request.js
+++ b/app/assets/javascripts/ide/stores/actions/merge_request.js
@@ -25,7 +25,7 @@ export const getMergeRequestData = (
})
.catch(() => {
dispatch('setErrorMessage', {
- text: __('An error occured whilst loading the merge request.'),
+ text: __('An error occurred whilst loading the merge request.'),
action: payload =>
dispatch('getMergeRequestData', payload).then(() =>
dispatch('setErrorMessage', null),
@@ -58,7 +58,7 @@ export const getMergeRequestChanges = (
})
.catch(() => {
dispatch('setErrorMessage', {
- text: __('An error occured whilst loading the merge request changes.'),
+ text: __('An error occurred whilst loading the merge request changes.'),
action: payload =>
dispatch('getMergeRequestChanges', payload).then(() =>
dispatch('setErrorMessage', null),
@@ -92,7 +92,7 @@ export const getMergeRequestVersions = (
})
.catch(() => {
dispatch('setErrorMessage', {
- text: __('An error occured whilst loading the merge request version data.'),
+ text: __('An error occurred whilst loading the merge request version data.'),
action: payload =>
dispatch('getMergeRequestVersions', payload).then(() =>
dispatch('setErrorMessage', null),
@@ -161,6 +161,7 @@ export const openMergeRequest = (
dispatch('getFileData', {
path: change.new_path,
makeFileActive: ind === 0,
+ openFile: true,
});
}
}
diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js
index 2cb08ab2945..b65f631c99c 100644
--- a/app/assets/javascripts/ide/stores/actions/project.js
+++ b/app/assets/javascripts/ide/stores/actions/project.js
@@ -103,7 +103,7 @@ export const createNewBranchFromDefault = ({ state, dispatch, getters }, branch)
})
.catch(() => {
dispatch('setErrorMessage', {
- text: __('An error occured creating the new branch.'),
+ text: __('An error occurred creating the new branch.'),
action: payload => dispatch('createNewBranchFromDefault', payload),
actionText: __('Please try again'),
actionPayload: branch,
diff --git a/app/assets/javascripts/ide/stores/actions/tree.js b/app/assets/javascripts/ide/stores/actions/tree.js
index 9288bbe32f5..de5f6050074 100644
--- a/app/assets/javascripts/ide/stores/actions/tree.js
+++ b/app/assets/javascripts/ide/stores/actions/tree.js
@@ -76,7 +76,7 @@ export const getFiles = ({ state, commit, dispatch }, { projectId, branchId } =
dispatch('showBranchNotFoundError', branchId);
} else {
dispatch('setErrorMessage', {
- text: __('An error occured whilst loading all the files.'),
+ text: __('An error occurred whilst loading all the files.'),
action: payload =>
dispatch('getFiles', payload).then(() => dispatch('setErrorMessage', null)),
actionText: __('Please try again'),
diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js
index 4565c11a83f..8b5f7558654 100644
--- a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js
@@ -23,13 +23,19 @@ export const receiveMergeRequestsError = ({ commit, dispatch }, { type, search }
export const receiveMergeRequestsSuccess = ({ commit }, data) =>
commit(types.RECEIVE_MERGE_REQUESTS_SUCCESS, data);
-export const fetchMergeRequests = ({ dispatch, state: { state } }, { type, search = '' }) => {
+export const fetchMergeRequests = (
+ { dispatch, state: { state }, rootState: { currentProjectId } },
+ { type, search = '' },
+) => {
dispatch('requestMergeRequests');
dispatch('resetMergeRequests');
- const scope = type ? scopes[type] : 'all';
+ const scope = type && scopes[type];
+ const request = scope
+ ? Api.mergeRequests({ scope, state, search })
+ : Api.projectMergeRequest(currentProjectId, '', { state, search });
- return Api.mergeRequests({ scope, state, search })
+ return request
.then(({ data }) => dispatch('receiveMergeRequestsSuccess', data))
.catch(() => dispatch('receiveMergeRequestsError', { type, search }));
};
diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js
index 8fa86995ef0..51cf4dede42 100644
--- a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js
@@ -28,7 +28,7 @@ export const receiveLatestPipelineError = ({ commit, dispatch }, err) => {
dispatch(
'setErrorMessage',
{
- text: __('An error occured whilst fetching the latest pipline.'),
+ text: __('An error occurred whilst fetching the latest pipeline.'),
action: () =>
dispatch('forcePipelineRequest').then(() =>
dispatch('setErrorMessage', null, { root: true }),
@@ -84,7 +84,7 @@ export const receiveJobsError = ({ commit, dispatch }, stage) => {
dispatch(
'setErrorMessage',
{
- text: __('An error occured whilst loading the pipelines jobs.'),
+ text: __('An error occurred whilst loading the pipelines jobs.'),
action: payload =>
dispatch('fetchJobs', payload).then(() =>
dispatch('setErrorMessage', null, { root: true }),
@@ -123,7 +123,7 @@ export const receiveJobTraceError = ({ commit, dispatch }) => {
dispatch(
'setErrorMessage',
{
- text: __('An error occured whilst fetching the job trace.'),
+ text: __('An error occurred whilst fetching the job trace.'),
action: () =>
dispatch('fetchJobTrace').then(() => dispatch('setErrorMessage', null, { root: true })),
actionText: __('Please try again'),
diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/getters.js b/app/assets/javascripts/ide/stores/modules/pipelines/getters.js
index f545453806f..ef7cd4ff8e8 100644
--- a/app/assets/javascripts/ide/stores/modules/pipelines/getters.js
+++ b/app/assets/javascripts/ide/stores/modules/pipelines/getters.js
@@ -6,10 +6,12 @@ export const pipelineFailed = state =>
state.latestPipeline && state.latestPipeline.details.status.text === states.failed;
export const failedStages = state =>
- state.stages.filter(stage => stage.status.text.toLowerCase() === states.failed).map(stage => ({
- ...stage,
- jobs: stage.jobs.filter(job => job.status.text.toLowerCase() === states.failed),
- }));
+ state.stages
+ .filter(stage => stage.status.text.toLowerCase() === states.failed)
+ .map(stage => ({
+ ...stage,
+ jobs: stage.jobs.filter(job => job.status.text.toLowerCase() === states.failed),
+ }));
export const failedJobsCount = state =>
state.stages.reduce(
diff --git a/app/assets/javascripts/image_diff/helpers/badge_helper.js b/app/assets/javascripts/image_diff/helpers/badge_helper.js
index eddaeda9578..000157efad0 100644
--- a/app/assets/javascripts/image_diff/helpers/badge_helper.js
+++ b/app/assets/javascripts/image_diff/helpers/badge_helper.js
@@ -12,7 +12,7 @@ export function createImageBadge(noteId, { x, y }, classNames = []) {
}
export function addImageBadge(containerEl, { coordinate, badgeText, noteId }) {
- const buttonEl = createImageBadge(noteId, coordinate, ['badge']);
+ const buttonEl = createImageBadge(noteId, coordinate, ['badge', 'badge-pill']);
buttonEl.innerText = badgeText;
containerEl.appendChild(buttonEl);
diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js
index f1beb1a8ea5..1ffd5c61282 100644
--- a/app/assets/javascripts/importer_status.js
+++ b/app/assets/javascripts/importer_status.js
@@ -3,7 +3,7 @@ import _ from 'underscore';
import { __, sprintf } from './locale';
import axios from './lib/utils/axios_utils';
import flash from './flash';
-import { convertPermissionToBoolean } from './lib/utils/common_utils';
+import { parseBoolean } from './lib/utils/common_utils';
class ImporterStatus {
constructor({ jobsUrl, importUrl, ciCdOnly }) {
@@ -141,7 +141,7 @@ function initImporterStatus() {
return new ImporterStatus({
jobsUrl: data.jobsImportPath,
importUrl: data.importPath,
- ciCdOnly: convertPermissionToBoolean(data.ciCdOnly),
+ ciCdOnly: parseBoolean(data.ciCdOnly),
});
}
}
diff --git a/app/assets/javascripts/init_legacy_filters.js b/app/assets/javascripts/init_legacy_filters.js
deleted file mode 100644
index b6ff97d1279..00000000000
--- a/app/assets/javascripts/init_legacy_filters.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/* eslint-disable no-new */
-import LabelsSelect from './labels_select';
-import subscriptionSelect from './subscription_select';
-import UsersSelect from './users_select';
-import issueStatusSelect from './issue_status_select';
-import MilestoneSelect from './milestone_select';
-
-export default () => {
- new UsersSelect();
- new LabelsSelect();
- new MilestoneSelect();
- issueStatusSelect();
- subscriptionSelect();
-};
diff --git a/app/assets/javascripts/issuable_suggestions/components/app.vue b/app/assets/javascripts/issuable_suggestions/components/app.vue
new file mode 100644
index 00000000000..eea0701312b
--- /dev/null
+++ b/app/assets/javascripts/issuable_suggestions/components/app.vue
@@ -0,0 +1,96 @@
+<script>
+import _ from 'underscore';
+import { GlTooltipDirective } from '@gitlab/ui';
+import { __ } from '~/locale';
+import Icon from '~/vue_shared/components/icon.vue';
+import Suggestion from './item.vue';
+import query from '../queries/issues.graphql';
+
+export default {
+ components: {
+ Suggestion,
+ Icon,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ projectPath: {
+ type: String,
+ required: true,
+ },
+ search: {
+ type: String,
+ required: true,
+ },
+ },
+ apollo: {
+ issues: {
+ query,
+ debounce: 250,
+ skip() {
+ return this.isSearchEmpty;
+ },
+ update: data => data.project.issues.edges.map(({ node }) => node),
+ variables() {
+ return {
+ fullPath: this.projectPath,
+ search: this.search,
+ };
+ },
+ },
+ },
+ data() {
+ return {
+ issues: [],
+ loading: 0,
+ };
+ },
+ computed: {
+ isSearchEmpty() {
+ return _.isEmpty(this.search);
+ },
+ showSuggestions() {
+ return !this.isSearchEmpty && this.issues.length && !this.loading;
+ },
+ },
+ watch: {
+ search() {
+ if (this.isSearchEmpty) {
+ this.issues = [];
+ }
+ },
+ },
+ helpText: __(
+ 'These existing issues have a similar title. It might be better to comment there instead of creating another similar issue.',
+ ),
+};
+</script>
+
+<template>
+ <div v-show="showSuggestions" class="form-group row issuable-suggestions">
+ <div v-once class="col-form-label col-sm-2 pt-0">
+ {{ __('Similar issues') }}
+ <icon
+ v-gl-tooltip.bottom
+ :title="$options.helpText"
+ :aria-label="$options.helpText"
+ name="question-o"
+ class="text-secondary suggestion-help-hover"
+ />
+ </div>
+ <div class="col-sm-10">
+ <ul class="list-unstyled m-0">
+ <li
+ v-for="(suggestion, index) in issues"
+ :key="suggestion.id"
+ :class="{
+ 'append-bottom-default': index !== issues.length - 1,
+ }"
+ >
+ <suggestion :suggestion="suggestion" />
+ </li>
+ </ul>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/issuable_suggestions/components/item.vue b/app/assets/javascripts/issuable_suggestions/components/item.vue
new file mode 100644
index 00000000000..9a16b486bf5
--- /dev/null
+++ b/app/assets/javascripts/issuable_suggestions/components/item.vue
@@ -0,0 +1,137 @@
+<script>
+import _ from 'underscore';
+import { GlLink, GlTooltip, GlTooltipDirective } from '@gitlab/ui';
+import { __ } from '~/locale';
+import Icon from '~/vue_shared/components/icon.vue';
+import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
+import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import timeago from '~/vue_shared/mixins/timeago';
+
+export default {
+ components: {
+ GlTooltip,
+ GlLink,
+ Icon,
+ UserAvatarImage,
+ TimeagoTooltip,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [timeago],
+ props: {
+ suggestion: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ isOpen() {
+ return this.suggestion.state === 'opened';
+ },
+ isClosed() {
+ return this.suggestion.state === 'closed';
+ },
+ counts() {
+ return [
+ {
+ id: _.uniqueId(),
+ icon: 'thumb-up',
+ tooltipTitle: __('Upvotes'),
+ count: this.suggestion.upvotes,
+ },
+ {
+ id: _.uniqueId(),
+ icon: 'comment',
+ tooltipTitle: __('Comments'),
+ count: this.suggestion.userNotesCount,
+ },
+ ].filter(({ count }) => count);
+ },
+ stateIcon() {
+ return this.isClosed ? 'issue-close' : 'issue-open-m';
+ },
+ stateTitle() {
+ return this.isClosed ? __('Closed') : __('Opened');
+ },
+ closedOrCreatedDate() {
+ return this.suggestion.closedAt || this.suggestion.createdAt;
+ },
+ hasUpdated() {
+ return this.suggestion.updatedAt !== this.suggestion.createdAt;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="suggestion-item">
+ <div class="d-flex align-items-center">
+ <icon
+ v-if="suggestion.confidential"
+ v-gl-tooltip.bottom
+ :title="__('Confidential')"
+ name="eye-slash"
+ class="suggestion-help-hover mr-1 suggestion-confidential"
+ />
+ <gl-link :href="suggestion.webUrl" target="_blank" class="suggestion bold str-truncated-100">
+ {{ suggestion.title }}
+ </gl-link>
+ </div>
+ <div class="text-secondary suggestion-footer">
+ <icon
+ ref="state"
+ :name="stateIcon"
+ :class="{
+ 'suggestion-state-open': isOpen,
+ 'suggestion-state-closed': isClosed,
+ }"
+ class="suggestion-help-hover"
+ />
+ <gl-tooltip :target="() => $refs.state" placement="bottom">
+ <span class="d-block">
+ <span class="bold"> {{ stateTitle }} </span> {{ timeFormated(closedOrCreatedDate) }}
+ </span>
+ <span class="text-tertiary">{{ tooltipTitle(closedOrCreatedDate) }}</span>
+ </gl-tooltip>
+ #{{ suggestion.iid }} &bull;
+ <timeago-tooltip
+ :time="suggestion.createdAt"
+ tooltip-placement="bottom"
+ class="suggestion-help-hover"
+ />
+ by
+ <gl-link :href="suggestion.author.webUrl">
+ <user-avatar-image
+ :img-src="suggestion.author.avatarUrl"
+ :size="16"
+ css-classes="mr-0 float-none"
+ tooltip-placement="bottom"
+ class="d-inline-block"
+ >
+ <span class="bold d-block">{{ __('Author') }}</span> {{ suggestion.author.name }}
+ <span class="text-tertiary">@{{ suggestion.author.username }}</span>
+ </user-avatar-image>
+ </gl-link>
+ <template v-if="hasUpdated">
+ &bull; {{ __('updated') }}
+ <timeago-tooltip
+ :time="suggestion.updatedAt"
+ tooltip-placement="bottom"
+ class="suggestion-help-hover"
+ />
+ </template>
+ <span class="suggestion-counts">
+ <span
+ v-for="{ count, icon, tooltipTitle, id } in counts"
+ :key="id"
+ v-gl-tooltip.bottom
+ :title="tooltipTitle"
+ class="suggestion-help-hover prepend-left-8 text-tertiary"
+ >
+ <icon :name="icon" /> {{ count }}
+ </span>
+ </span>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/issuable_suggestions/index.js b/app/assets/javascripts/issuable_suggestions/index.js
new file mode 100644
index 00000000000..2c80cf1797a
--- /dev/null
+++ b/app/assets/javascripts/issuable_suggestions/index.js
@@ -0,0 +1,38 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import defaultClient from '~/lib/graphql';
+import App from './components/app.vue';
+
+Vue.use(VueApollo);
+
+export default function() {
+ const el = document.getElementById('js-suggestions');
+ const issueTitle = document.getElementById('issue_title');
+ const { projectPath } = el.dataset;
+ const apolloProvider = new VueApollo({
+ defaultClient,
+ });
+
+ return new Vue({
+ el,
+ apolloProvider,
+ data() {
+ return {
+ search: issueTitle.value,
+ };
+ },
+ mounted() {
+ issueTitle.addEventListener('input', () => {
+ this.search = issueTitle.value;
+ });
+ },
+ render(h) {
+ return h(App, {
+ props: {
+ projectPath,
+ search: this.search,
+ },
+ });
+ },
+ });
+}
diff --git a/app/assets/javascripts/issuable_suggestions/queries/issues.graphql b/app/assets/javascripts/issuable_suggestions/queries/issues.graphql
new file mode 100644
index 00000000000..2384b381344
--- /dev/null
+++ b/app/assets/javascripts/issuable_suggestions/queries/issues.graphql
@@ -0,0 +1,26 @@
+query issueSuggestion($fullPath: ID!, $search: String) {
+ project(fullPath: $fullPath) {
+ issues(search: $search, sort: updated_desc, first: 5) {
+ edges {
+ node {
+ iid
+ title
+ confidential
+ userNotesCount
+ upvotes
+ webUrl
+ state
+ closedAt
+ createdAt
+ updatedAt
+ author {
+ name
+ username
+ avatarUrl
+ webUrl
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue
index 04c1cf021d9..e4e2eab2acd 100644
--- a/app/assets/javascripts/issue_show/components/app.vue
+++ b/app/assets/javascripts/issue_show/components/app.vue
@@ -294,11 +294,7 @@ export default {
:issuable-type="issuableType"
/>
- <recaptcha-modal
- v-show="showRecaptcha"
- :html="recaptchaHTML"
- @close="closeRecaptchaModal"
- />
+ <recaptcha-modal v-show="showRecaptcha" :html="recaptchaHTML" @close="closeRecaptchaModal" />
</div>
<div v-else>
<title-component
diff --git a/app/assets/javascripts/issue_show/components/description.vue b/app/assets/javascripts/issue_show/components/description.vue
index 461cb3271b7..5ca88d75063 100644
--- a/app/assets/javascripts/issue_show/components/description.vue
+++ b/app/assets/javascripts/issue_show/components/description.vue
@@ -106,7 +106,7 @@ export default {
<div
v-if="descriptionHtml"
:class="{
- 'js-task-list-container': canUpdate
+ 'js-task-list-container': canUpdate,
}"
class="description"
>
@@ -114,11 +114,11 @@ export default {
ref="gfm-content"
:class="{
'issue-realtime-pre-pulse': preAnimation,
- 'issue-realtime-trigger-pulse': pulseAnimation
+ 'issue-realtime-trigger-pulse': pulseAnimation,
}"
class="wiki"
- v-html="descriptionHtml">
- </div>
+ v-html="descriptionHtml"
+ ></div>
<textarea
v-if="descriptionText"
v-model="descriptionText"
@@ -127,10 +127,6 @@ export default {
>
</textarea>
- <recaptcha-modal
- v-show="showRecaptcha"
- :html="recaptchaHTML"
- @close="closeRecaptcha"
- />
+ <recaptcha-modal v-show="showRecaptcha" :html="recaptchaHTML" @close="closeRecaptcha" />
</div>
</template>
diff --git a/app/assets/javascripts/issue_show/components/edit_actions.vue b/app/assets/javascripts/issue_show/components/edit_actions.vue
index 5dda35d64bb..42a3de62772 100644
--- a/app/assets/javascripts/issue_show/components/edit_actions.vue
+++ b/app/assets/javascripts/issue_show/components/edit_actions.vue
@@ -68,33 +68,21 @@ export default {
:disabled="formState.updateLoading || !isSubmitEnabled"
class="btn btn-success float-left qa-save-button"
type="submit"
- @click.prevent="updateIssuable">
+ @click.prevent="updateIssuable"
+ >
Save changes
- <i
- v-if="formState.updateLoading"
- class="fa fa-spinner fa-spin"
- aria-hidden="true">
- </i>
- </button>
- <button
- class="btn btn-default float-right"
- type="button"
- @click="closeForm">
- Cancel
+ <i v-if="formState.updateLoading" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
</button>
+ <button class="btn btn-default float-right" type="button" @click="closeForm">Cancel</button>
<button
v-if="shouldShowDeleteButton"
:class="{ disabled: deleteLoading }"
:disabled="deleteLoading"
class="btn btn-danger float-right append-right-default qa-delete-button"
type="button"
- @click="deleteIssuable">
- Delete
- <i
- v-if="deleteLoading"
- class="fa fa-spinner fa-spin"
- aria-hidden="true">
- </i>
+ @click="deleteIssuable"
+ >
+ Delete <i v-if="deleteLoading" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
</button>
</div>
</template>
diff --git a/app/assets/javascripts/issue_show/components/edited.vue b/app/assets/javascripts/issue_show/components/edited.vue
index 73ecb26c28d..14ad8d3b7c9 100644
--- a/app/assets/javascripts/issue_show/components/edited.vue
+++ b/app/assets/javascripts/issue_show/components/edited.vue
@@ -31,23 +31,12 @@ export default {
</script>
<template>
- <small
- class="edited-text"
- >
+ <small class="edited-text">
Edited
- <time-ago-tooltip
- v-if="updatedAt"
- :time="updatedAt"
- tooltip-placement="bottom"
- />
- <span
- v-if="hasUpdatedBy"
- >
+ <time-ago-tooltip v-if="updatedAt" :time="updatedAt" tooltip-placement="bottom" />
+ <span v-if="hasUpdatedBy">
by
- <a
- :href="updatedByPath"
- class="author-link"
- >
+ <a :href="updatedByPath" class="author-link">
<span>{{ updatedByName }}</span>
</a>
</span>
diff --git a/app/assets/javascripts/issue_show/components/fields/description.vue b/app/assets/javascripts/issue_show/components/fields/description.vue
index e9e96a985a7..90258c0e044 100644
--- a/app/assets/javascripts/issue_show/components/fields/description.vue
+++ b/app/assets/javascripts/issue_show/components/fields/description.vue
@@ -44,11 +44,7 @@ export default {
<template>
<div class="common-note-form">
- <label
- class="sr-only"
- for="issue-description">
- Description
- </label>
+ <label class="sr-only" for="issue-description"> Description </label>
<markdown-field
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
@@ -67,7 +63,8 @@ export default {
aria-label="Description"
placeholder="Write a comment or drag your files here…"
@keydown.meta.enter="updateIssuable"
- @keydown.ctrl.enter="updateIssuable">
+ @keydown.ctrl.enter="updateIssuable"
+ >
</textarea>
</markdown-field>
</div>
diff --git a/app/assets/javascripts/issue_show/components/fields/description_template.vue b/app/assets/javascripts/issue_show/components/fields/description_template.vue
index e433bf66cfc..14f0acf6540 100644
--- a/app/assets/javascripts/issue_show/components/fields/description_template.vue
+++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue
@@ -44,9 +44,7 @@ export default {
</script>
<template>
- <div
- class="dropdown js-issuable-selector-wrap"
- data-issuable-type="issue">
+ <div class="dropdown js-issuable-selector-wrap" data-issuable-type="issue">
<button
ref="toggle"
:data-namespace-path="projectNamespace"
@@ -56,57 +54,33 @@ export default {
type="button"
data-field-name="issuable_template"
data-selected="null"
- data-toggle="dropdown">
- <span class="dropdown-toggle-text">
- Choose a template
- </span>
- <i
- aria-hidden="true"
- class="fa fa-chevron-down">
- </i>
+ data-toggle="dropdown"
+ >
+ <span class="dropdown-toggle-text"> Choose a template </span>
+ <i aria-hidden="true" class="fa fa-chevron-down"> </i>
</button>
<div class="dropdown-menu dropdown-select">
<div class="dropdown-title">
Choose a template
- <button
- class="dropdown-title-button dropdown-menu-close"
- aria-label="Close"
- type="button">
- <i
- aria-hidden="true"
- class="fa fa-times dropdown-menu-close-icon">
- </i>
+ <button class="dropdown-title-button dropdown-menu-close" aria-label="Close" type="button">
+ <i aria-hidden="true" class="fa fa-times dropdown-menu-close-icon"> </i>
</button>
</div>
<div class="dropdown-input">
- <input
- type="search"
- class="dropdown-input-field"
- placeholder="Filter"
- autocomplete="off" />
- <i
- aria-hidden="true"
- class="fa fa-search dropdown-input-search">
- </i>
+ <input type="search" class="dropdown-input-field" placeholder="Filter" autocomplete="off" />
+ <i aria-hidden="true" class="fa fa-search dropdown-input-search"> </i>
<i
role="button"
aria-label="Clear templates search input"
- class="fa fa-times dropdown-input-clear js-dropdown-input-clear">
+ class="fa fa-times dropdown-input-clear js-dropdown-input-clear"
+ >
</i>
</div>
<div class="dropdown-content"></div>
<div class="dropdown-footer">
<ul class="dropdown-footer-list">
- <li>
- <a class="no-template">
- No template
- </a>
- </li>
- <li>
- <a class="reset-template">
- Reset template
- </a>
- </li>
+ <li><a class="no-template"> No template </a></li>
+ <li><a class="reset-template"> Reset template </a></li>
</ul>
</div>
</div>
diff --git a/app/assets/javascripts/issue_show/components/fields/title.vue b/app/assets/javascripts/issue_show/components/fields/title.vue
index 11f4153b8d5..c3d7ba4907f 100644
--- a/app/assets/javascripts/issue_show/components/fields/title.vue
+++ b/app/assets/javascripts/issue_show/components/fields/title.vue
@@ -14,11 +14,7 @@ export default {
<template>
<fieldset>
- <label
- class="sr-only"
- for="issuable-title">
- Title
- </label>
+ <label class="sr-only" for="issuable-title"> Title </label>
<input
id="issuable-title"
v-model="formState.title"
@@ -27,6 +23,7 @@ export default {
placeholder="Title"
aria-label="Title"
@keydown.meta.enter="updateIssuable"
- @keydown.ctrl.enter="updateIssuable" />
+ @keydown.ctrl.enter="updateIssuable"
+ />
</fieldset>
</template>
diff --git a/app/assets/javascripts/issue_show/components/form.vue b/app/assets/javascripts/issue_show/components/form.vue
index 3b430d92912..45b60bc3392 100644
--- a/app/assets/javascripts/issue_show/components/form.vue
+++ b/app/assets/javascripts/issue_show/components/form.vue
@@ -80,9 +80,7 @@ export default {
<form>
<locked-warning v-if="formState.lockedWarningVisible" />
<div class="row">
- <div
- v-if="hasIssuableTemplates"
- class="col-sm-4 col-lg-3">
+ <div v-if="hasIssuableTemplates" class="col-sm-4 col-lg-3">
<description-template
:form-state="formState"
:issuable-templates="issuableTemplates"
@@ -96,10 +94,7 @@ export default {
'col-12': !hasIssuableTemplates,
}"
>
- <title-field
- :form-state="formState"
- :issuable-templates="issuableTemplates"
- />
+ <title-field :form-state="formState" :issuable-templates="issuableTemplates" />
</div>
</div>
<description-field
diff --git a/app/assets/javascripts/issue_show/components/locked_warning.vue b/app/assets/javascripts/issue_show/components/locked_warning.vue
index 0682c6f2a35..639221473b1 100644
--- a/app/assets/javascripts/issue_show/components/locked_warning.vue
+++ b/app/assets/javascripts/issue_show/components/locked_warning.vue
@@ -11,10 +11,7 @@ export default {
<template>
<div class="alert alert-danger">
Someone edited the issue at the same time you did. Please check out
- <a
- :href="currentPath"
- target="_blank"
- rel="nofollow">the issue</a>
- and make sure your changes will not unintentionally remove theirs.
+ <a :href="currentPath" target="_blank" rel="nofollow">the issue</a> and make sure your changes
+ will not unintentionally remove theirs.
</div>
</template>
diff --git a/app/assets/javascripts/issue_show/components/title.vue b/app/assets/javascripts/issue_show/components/title.vue
index ed26e53ac0e..3b5c95ccded 100644
--- a/app/assets/javascripts/issue_show/components/title.vue
+++ b/app/assets/javascripts/issue_show/components/title.vue
@@ -69,12 +69,11 @@ export default {
<h2
:class="{
'issue-realtime-pre-pulse': preAnimation,
- 'issue-realtime-trigger-pulse': pulseAnimation
+ 'issue-realtime-trigger-pulse': pulseAnimation,
}"
class="title"
v-html="titleHtml"
- >
- </h2>
+ ></h2>
<button
v-if="showInlineEditButton && canUpdate"
v-tooltip
@@ -86,7 +85,6 @@ export default {
data-container="body"
@click="edit"
v-html="pencilIcon"
- >
- </button>
+ ></button>
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/artifacts_block.vue b/app/assets/javascripts/jobs/components/artifacts_block.vue
index 93c89411b4a..309b7427b9e 100644
--- a/app/assets/javascripts/jobs/components/artifacts_block.vue
+++ b/app/assets/javascripts/jobs/components/artifacts_block.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
@@ -28,33 +28,19 @@ export default {
</script>
<template>
<div class="block">
- <div class="title">
- {{ s__('Job|Job artifacts') }}
- </div>
+ <div class="title">{{ s__('Job|Job artifacts') }}</div>
- <p
- v-if="isExpired"
- class="js-artifacts-removed build-detail-row"
- >
+ <p v-if="isExpired" class="js-artifacts-removed build-detail-row">
{{ s__('Job|The artifacts were removed') }}
</p>
- <p
- v-else-if="willExpire"
- class="js-artifacts-will-be-removed build-detail-row"
- >
+ <p v-else-if="willExpire" class="js-artifacts-will-be-removed build-detail-row">
{{ s__('Job|The artifacts will be removed in') }}
</p>
- <timeago-tooltip
- v-if="artifact.expire_at"
- :time="artifact.expire_at"
- />
+ <timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" />
- <div
- class="btn-group d-flex"
- role="group"
- >
+ <div class="btn-group d-flex" role="group">
<gl-link
v-if="artifact.keep_path"
:href="artifact.keep_path"
diff --git a/app/assets/javascripts/jobs/components/commit_block.vue b/app/assets/javascripts/jobs/components/commit_block.vue
index 06fe23fedce..3b9c61bd48c 100644
--- a/app/assets/javascripts/jobs/components/commit_block.vue
+++ b/app/assets/javascripts/jobs/components/commit_block.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
export default {
@@ -28,15 +28,15 @@ export default {
<div
:class="{
'block-last': isLastBlock,
- block: !isLastBlock
- }">
+ block: !isLastBlock,
+ }"
+ >
<p>
{{ __('Commit') }}
- <gl-link
- :href="commit.commit_path"
- class="js-commit-sha commit-sha link-commit"
- >{{ commit.short_id }}</gl-link>
+ <gl-link :href="commit.commit_path" class="js-commit-sha commit-sha link-commit">{{
+ commit.short_id
+ }}</gl-link>
<clipboard-button
:text="commit.short_id"
@@ -44,15 +44,11 @@ export default {
css-class="btn btn-clipboard btn-transparent"
/>
- <gl-link
- v-if="mergeRequest"
- :href="mergeRequest.path"
- class="js-link-commit link-commit"
- >!{{ mergeRequest.iid }}</gl-link>
+ <gl-link v-if="mergeRequest" :href="mergeRequest.path" class="js-link-commit link-commit"
+ >!{{ mergeRequest.iid }}</gl-link
+ >
</p>
- <p class="build-light-text append-bottom-0">
- {{ commit.title }}
- </p>
+ <p class="build-light-text append-bottom-0">{{ commit.title }}</p>
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/empty_state.vue b/app/assets/javascripts/jobs/components/empty_state.vue
index be7425c2d25..668fcf3d673 100644
--- a/app/assets/javascripts/jobs/components/empty_state.vue
+++ b/app/assets/javascripts/jobs/components/empty_state.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
export default {
components: {
@@ -42,31 +42,16 @@ export default {
<template>
<div class="row empty-state">
<div class="col-12">
- <div
- :class="illustrationSizeClass"
- class="svg-content"
- >
- <img :src="illustrationPath" />
- </div>
+ <div :class="illustrationSizeClass" class="svg-content"><img :src="illustrationPath" /></div>
</div>
<div class="col-12">
<div class="text-content">
- <h4 class="js-job-empty-state-title text-center">
- {{ title }}
- </h4>
+ <h4 class="js-job-empty-state-title text-center">{{ title }}</h4>
- <p
- v-if="content"
- class="js-job-empty-state-content"
- >
- {{ content }}
- </p>
+ <p v-if="content" class="js-job-empty-state-content">{{ content }}</p>
- <div
- v-if="action"
- class="text-center"
- >
+ <div v-if="action" class="text-center">
<gl-link
:href="action.path"
:data-method="action.method"
diff --git a/app/assets/javascripts/jobs/components/environments_block.vue b/app/assets/javascripts/jobs/components/environments_block.vue
index 6d1eb713886..f7fbb9503a0 100644
--- a/app/assets/javascripts/jobs/components/environments_block.vue
+++ b/app/assets/javascripts/jobs/components/environments_block.vue
@@ -128,13 +128,10 @@ export default {
};
</script>
<template>
- <div class="prepend-top-default js-environment-container">
+ <div class="prepend-top-default append-bottom-default js-environment-container">
<div class="environment-information">
- <ci-icon :status="iconStatus"/>
- <p
- class="inline append-bottom-0"
- v-html="environment"
- ></p>
+ <ci-icon :status="iconStatus" />
+ <p class="inline append-bottom-0" v-html="environment"></p>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/erased_block.vue b/app/assets/javascripts/jobs/components/erased_block.vue
index d80e905c68e..8437ad89301 100644
--- a/app/assets/javascripts/jobs/components/erased_block.vue
+++ b/app/assets/javascripts/jobs/components/erased_block.vue
@@ -1,6 +1,6 @@
<script>
import _ from 'underscore';
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
export default {
@@ -30,18 +30,14 @@ export default {
<div class="prepend-top-default js-build-erased">
<div class="erased alert alert-warning">
<template v-if="isErasedByUser">
- {{ s__("Job|Job has been erased by") }}
- <gl-link :href="user.web_url">
- {{ user.username }}
- </gl-link>
+ {{ s__('Job|Job has been erased by') }}
+ <gl-link :href="user.web_url"> {{ user.username }} </gl-link>
</template>
<template v-else>
- {{ s__("Job|Job has been erased") }}
+ {{ s__('Job|Job has been erased') }}
</template>
- <timeago-tooltip
- :time="erasedAt"
- />
+ <timeago-tooltip :time="erasedAt" />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue
index 90216b04e92..786ab16992d 100644
--- a/app/assets/javascripts/jobs/components/job_app.vue
+++ b/app/assets/javascripts/jobs/components/job_app.vue
@@ -1,7 +1,7 @@
<script>
import _ from 'underscore';
import { mapGetters, mapState, mapActions } from 'vuex';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
import { polyfillSticky } from '~/lib/utils/sticky';
import bp from '~/breakpoints';
@@ -210,10 +210,7 @@ export default {
/>
</div>
- <callout
- v-if="shouldRenderCalloutMessage"
- :message="job.callout_message"
- />
+ <callout v-if="shouldRenderCalloutMessage" :message="job.callout_message" />
</header>
<!-- EO Header Section -->
@@ -245,23 +242,17 @@ export default {
ref="sticky"
class="js-archived-job prepend-top-default archived-sticky sticky-top"
>
- <icon
- name="lock"
- class="align-text-bottom"
- />
+ <icon name="lock" class="align-text-bottom" />
{{ __('This job is archived. Only the complete pipeline can be retried.') }}
</div>
- <!--job log -->
- <div
- v-if="hasTrace"
- class="build-trace-container"
- >
+ <!-- job log -->
+ <div v-if="hasTrace" class="build-trace-container">
<log-top-bar
:class="{
'sidebar-expanded': isSidebarOpen,
'sidebar-collapsed': !isSidebarOpen,
- 'has-archived-block': job.archived
+ 'has-archived-block': job.archived,
}"
:erase-path="job.erase_path"
:size="traceSize"
@@ -273,14 +264,11 @@ export default {
@scrollJobLogTop="scrollTop"
@scrollJobLogBottom="scrollBottom"
/>
- <log
- :trace="trace"
- :is-complete="isTraceComplete"
- />
+ <log :trace="trace" :is-complete="isTraceComplete" />
</div>
<!-- EO job log -->
- <!--empty state -->
+ <!-- empty state -->
<empty-state
v-if="!hasTrace"
class="js-job-empty-state"
@@ -290,9 +278,9 @@ export default {
:content="emptyStateIllustration.content"
:action="emptyStateAction"
/>
- <!-- EO empty state -->
+ <!-- EO empty state -->
- <!-- EO Body Section -->
+ <!-- EO Body Section -->
</div>
</template>
@@ -301,7 +289,7 @@ export default {
class="js-job-sidebar"
:class="{
'right-sidebar-expanded': isSidebarOpen,
- 'right-sidebar-collapsed': !isSidebarOpen
+ 'right-sidebar-collapsed': !isSidebarOpen,
}"
:runner-help-url="runnerHelpUrl"
/>
diff --git a/app/assets/javascripts/jobs/components/job_container_item.vue b/app/assets/javascripts/jobs/components/job_container_item.vue
index 3ddcfd11dca..845699a90b5 100644
--- a/app/assets/javascripts/jobs/components/job_container_item.vue
+++ b/app/assets/javascripts/jobs/components/job_container_item.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
import tooltip from '~/vue_shared/directives/tooltip';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Icon from '~/vue_shared/components/icon.vue';
@@ -46,7 +46,7 @@ export default {
class="build-job"
:class="{
retried: job.retried,
- active: isActive
+ active: isActive,
}"
>
<gl-link
@@ -56,21 +56,13 @@ export default {
data-boundary="viewport"
class="js-job-link"
>
- <icon
- v-if="isActive"
- name="arrow-right"
- class="js-arrow-right icon-arrow-right"
- />
+ <icon v-if="isActive" name="arrow-right" class="js-arrow-right icon-arrow-right" />
<ci-icon :status="job.status" />
<span>{{ job.name ? job.name : job.id }}</span>
- <icon
- v-if="job.retried"
- name="retry"
- class="js-retry-icon"
- />
+ <icon v-if="job.retried" name="retry" class="js-retry-icon" />
</gl-link>
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue
index 8b506b124ec..52e14f954ee 100644
--- a/app/assets/javascripts/jobs/components/job_log_controllers.vue
+++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective, GlLink, GlButton } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
import { polyfillSticky } from '~/lib/utils/sticky';
import Icon from '~/vue_shared/components/icon.vue';
import { numberToHumanSize } from '~/lib/utils/number_utils';
@@ -75,12 +75,8 @@ export default {
<template v-if="isTraceSizeVisible">
{{ jobLogSize }}
- <gl-link
- v-if="rawPath"
- :href="rawPath"
- class="js-raw-link raw-link"
- >
- {{ s__("Job|Complete Raw") }}
+ <gl-link v-if="rawPath" :href="rawPath" class="js-raw-link raw-link">
+ {{ s__('Job|Complete Raw') }}
</gl-link>
</template>
</div>
@@ -112,11 +108,7 @@ export default {
<!-- eo links -->
<!-- scroll buttons -->
- <div
- v-gl-tooltip
- :title="s__('Job|Scroll to top')"
- class="controllers-buttons"
- >
+ <div v-gl-tooltip :title="s__('Job|Scroll to top')" class="controllers-buttons">
<gl-button
:disabled="isScrollTopDisabled"
type="button"
@@ -127,11 +119,7 @@ export default {
</gl-button>
</div>
- <div
- v-gl-tooltip
- :title="s__('Job|Scroll to bottom')"
- class="controllers-buttons"
- >
+ <div v-gl-tooltip :title="s__('Job|Scroll to bottom')" class="controllers-buttons">
<gl-button
:disabled="isScrollBottomDisabled"
class="js-scroll-bottom btn-scroll btn-transparent btn-blank"
diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue
index f7b7b8f10f7..934ecd0e3ec 100644
--- a/app/assets/javascripts/jobs/components/sidebar.vue
+++ b/app/assets/javascripts/jobs/components/sidebar.vue
@@ -1,7 +1,7 @@
<script>
import _ from 'underscore';
import { mapActions, mapState } from 'vuex';
-import { GlLink, GlButton } from '@gitlab-org/gitlab-ui';
+import { GlLink, GlButton } from '@gitlab/ui';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
import Icon from '~/vue_shared/components/icon.vue';
@@ -107,17 +107,11 @@ export default {
};
</script>
<template>
- <aside
- class="right-sidebar build-sidebar"
- data-offset-top="101"
- data-spy="affix"
- >
+ <aside class="right-sidebar build-sidebar" data-offset-top="101" data-spy="affix">
<div class="sidebar-container">
<div class="blocks-container">
<div class="block">
- <strong class="inline prepend-top-8">
- {{ job.name }}
- </strong>
+ <strong class="inline prepend-top-8"> {{ job.name }} </strong>
<gl-link
v-if="job.retry_path"
:class="retryButtonClass"
@@ -134,8 +128,7 @@ export default {
btn-inverted visible-md-block visible-lg-block"
target="_blank"
>
- {{ __('Debug') }}
- <icon name="external-link" />
+ {{ __('Debug') }} <icon name="external-link" />
</gl-link>
<gl-button
:aria-label="__('Toggle Sidebar')"
@@ -144,17 +137,10 @@ export default {
float-right d-block d-md-none js-sidebar-build-toggle"
@click="toggleSidebar"
>
- <i
- aria-hidden="true"
- data-hidden="true"
- class="fa fa-angle-double-right"
- ></i>
+ <i aria-hidden="true" data-hidden="true" class="fa fa-angle-double-right"></i>
</gl-button>
</div>
- <div
- v-if="job.retry_path || job.new_issue_path"
- class="block retry-link"
- >
+ <div v-if="job.retry_path || job.new_issue_path" class="block retry-link">
<gl-link
v-if="job.new_issue_path"
:href="job.new_issue_path"
@@ -172,17 +158,10 @@ export default {
{{ __('Retry') }}
</gl-link>
</div>
- <div :class="{ block : renderBlock }">
- <p
- v-if="job.merge_request"
- class="build-detail-row js-job-mr"
- >
- <span class="build-light-text">
- {{ __('Merge Request:') }}
- </span>
- <gl-link :href="job.merge_request.path">
- !{{ job.merge_request.iid }}
- </gl-link>
+ <div :class="{ block: renderBlock }">
+ <p v-if="job.merge_request" class="build-detail-row js-job-mr">
+ <span class="build-light-text"> {{ __('Merge Request:') }} </span>
+ <gl-link :href="job.merge_request.path"> !{{ job.merge_request.iid }} </gl-link>
</p>
<detail-row
@@ -203,12 +182,7 @@ export default {
class="js-job-erased"
title="Erased"
/>
- <detail-row
- v-if="job.queued"
- :value="queued"
- class="js-job-queued"
- title="Queued"
- />
+ <detail-row v-if="job.queued" :value="queued" class="js-job-queued" title="Queued" />
<detail-row
v-if="hasTimeout"
:help-url="runnerHelpUrl"
@@ -216,37 +190,21 @@ export default {
class="js-job-timeout"
title="Timeout"
/>
- <detail-row
- v-if="job.runner"
- :value="runnerId"
- class="js-job-runner"
- title="Runner"
- />
+ <detail-row v-if="job.runner" :value="runnerId" class="js-job-runner" title="Runner" />
<detail-row
v-if="job.coverage"
:value="coverage"
class="js-job-coverage"
title="Coverage"
/>
- <p
- v-if="job.tags.length"
- class="build-detail-row js-job-tags"
- >
- <span class="build-light-text">
- {{ __('Tags:') }}
- </span>
- <span
- v-for="(tag, i) in job.tags"
- :key="i"
- class="label label-primary">
+ <p v-if="job.tags.length" class="build-detail-row js-job-tags">
+ <span class="build-light-text"> {{ __('Tags:') }} </span>
+ <span v-for="(tag, i) in job.tags" :key="i" class="badge badge-primary">
{{ tag }}
</span>
</p>
- <div
- v-if="job.cancel_path"
- class="btn-group prepend-top-5"
- role="group">
+ <div v-if="job.cancel_path" class="btn-group prepend-top-5" role="group">
<gl-link
:href="job.cancel_path"
class="js-cancel-job btn btn-sm btn-default"
@@ -258,14 +216,8 @@ export default {
</div>
</div>
- <artifacts-block
- v-if="hasArtifact"
- :artifact="job.artifact"
- />
- <trigger-block
- v-if="hasTriggers"
- :trigger="job.trigger"
- />
+ <artifacts-block v-if="hasArtifact" :artifact="job.artifact" />
+ <trigger-block v-if="hasTriggers" :trigger="job.trigger" />
<commit-block
:is-last-block="hasStages"
:commit="commit"
@@ -281,11 +233,7 @@ export default {
/>
</div>
- <jobs-container
- v-if="jobs.length"
- :jobs="jobs"
- :job-id="job.id"
- />
+ <jobs-container v-if="jobs.length" :jobs="jobs" :job-id="job.id" />
</div>
</aside>
</template>
diff --git a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue
index cfedb38e17a..77be295e802 100644
--- a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue
+++ b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
export default {
name: 'SidebarDetailRow',
@@ -34,27 +34,11 @@ export default {
</script>
<template>
<p class="build-detail-row">
- <span
- v-if="hasTitle"
- class="build-light-text"
- >
- {{ title }}:
- </span>
- {{ value }}
+ <span v-if="hasTitle" class="build-light-text"> {{ title }}: </span> {{ value }}
- <span
- v-if="hasHelpURL"
- class="help-button float-right"
- >
- <gl-link
- :href="helpUrl"
- target="_blank"
- rel="noopener noreferrer nofollow"
- >
- <i
- class="fa fa-question-circle"
- aria-hidden="true"
- ></i>
+ <span v-if="hasHelpURL" class="help-button float-right">
+ <gl-link :href="helpUrl" target="_blank" rel="noopener noreferrer nofollow">
+ <i class="fa fa-question-circle" aria-hidden="true"></i>
</gl-link>
</span>
</p>
diff --git a/app/assets/javascripts/jobs/components/stages_dropdown.vue b/app/assets/javascripts/jobs/components/stages_dropdown.vue
index dc26b246d71..90482500bbf 100644
--- a/app/assets/javascripts/jobs/components/stages_dropdown.vue
+++ b/app/assets/javascripts/jobs/components/stages_dropdown.vue
@@ -36,26 +36,13 @@ export default {
</script>
<template>
<div class="block-last dropdown">
- <ci-icon
- :status="pipeline.details.status"
- class="vertical-align-middle"
- />
+ <ci-icon :status="pipeline.details.status" class="vertical-align-middle" />
{{ __('Pipeline') }}
- <a
- :href="pipeline.path"
- class="js-pipeline-path link-commit"
- >
- #{{ pipeline.id }}
- </a>
+ <a :href="pipeline.path" class="js-pipeline-path link-commit"> #{{ pipeline.id }} </a>
<template v-if="hasRef">
{{ __('from') }}
- <a
- :href="pipeline.ref.path"
- class="link-commit ref-name"
- >
- {{ pipeline.ref.name }}
- </a>
+ <a :href="pipeline.ref.path" class="link-commit ref-name"> {{ pipeline.ref.name }} </a>
</template>
<button
@@ -63,20 +50,12 @@ export default {
data-toggle="dropdown"
class="js-selected-stage dropdown-menu-toggle prepend-top-8"
>
- {{ selectedStage }}
- <i class="fa fa-chevron-down" ></i>
+ {{ selectedStage }} <i class="fa fa-chevron-down"></i>
</button>
<ul class="dropdown-menu">
- <li
- v-for="stage in stages"
- :key="stage.name"
- >
- <button
- type="button"
- class="js-stage-item stage-item"
- @click="onStageClick(stage)"
- >
+ <li v-for="stage in stages" :key="stage.name">
+ <button type="button" class="js-stage-item stage-item" @click="onStageClick(stage);">
{{ stage.name }}
</button>
</li>
diff --git a/app/assets/javascripts/jobs/components/stuck_block.vue b/app/assets/javascripts/jobs/components/stuck_block.vue
index ca4bf471363..ec52d272168 100644
--- a/app/assets/javascripts/jobs/components/stuck_block.vue
+++ b/app/assets/javascripts/jobs/components/stuck_block.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
/**
* Renders Stuck Runners block for job's view.
*/
@@ -26,42 +26,31 @@ export default {
</script>
<template>
<div class="bs-callout bs-callout-warning">
- <p
- v-if="tags.length"
- class="js-stuck-with-tags append-bottom-0"
- >
- {{ s__(`This job is stuck, because you don't have
- any active runners online with any of these tags assigned to them:`) }}
- <span
- v-for="(tag, index) in tags"
- :key="index"
- class="badge badge-primary"
- >
+ <p v-if="tags.length" class="js-stuck-with-tags append-bottom-0">
+ {{
+ s__(`This job is stuck because you don't have
+ any active runners online with any of these tags assigned to them:`)
+ }}
+ <span v-for="(tag, index) in tags" :key="index" class="badge badge-primary append-right-4">
{{ tag }}
</span>
</p>
- <p
- v-else-if="hasNoRunnersForProject"
- class="js-stuck-no-runners append-bottom-0"
- >
- {{ s__(`Job|This job is stuck, because the project
- doesn't have any runners online assigned to it.`) }}
+ <p v-else-if="hasNoRunnersForProject" class="js-stuck-no-runners append-bottom-0">
+ {{
+ s__(`Job|This job is stuck because the project
+ doesn't have any runners online assigned to it.`)
+ }}
</p>
- <p
- v-else
- class="js-stuck-no-active-runner append-bottom-0"
- >
- {{ s__(`This job is stuck, because you don't
- have any active runners that can run this job.`) }}
+ <p v-else class="js-stuck-no-active-runner append-bottom-0">
+ {{
+ s__(`This job is stuck because you don't
+ have any active runners that can run this job.`)
+ }}
</p>
- {{ __("Go to") }}
- <gl-link
- v-if="runnersPath"
- :href="runnersPath"
- class="js-runners-path"
- >
- {{ __("Runners page") }}
+ {{ __('Go to') }}
+ <gl-link v-if="runnersPath" :href="runnersPath" class="js-runners-path">
+ {{ __('Runners page') }}
</gl-link>
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/trigger_block.vue b/app/assets/javascripts/jobs/components/trigger_block.vue
index 1e62c05b4d1..3cd3b743108 100644
--- a/app/assets/javascripts/jobs/components/trigger_block.vue
+++ b/app/assets/javascripts/jobs/components/trigger_block.vue
@@ -1,5 +1,8 @@
<script>
-import { GlButton } from '@gitlab-org/gitlab-ui';
+import { __ } from '~/locale';
+import { GlButton } from '@gitlab/ui';
+
+const HIDDEN_VALUE = '••••••';
export default {
components: {
@@ -13,17 +16,26 @@ export default {
},
data() {
return {
- areVariablesVisible: false,
+ showVariableValues: false,
};
},
computed: {
hasVariables() {
return this.trigger.variables && this.trigger.variables.length > 0;
},
+ getToggleButtonText() {
+ return this.showVariableValues ? __('Hide values') : __('Reveal values');
+ },
+ hasValues() {
+ return this.trigger.variables.some(v => v.value);
+ },
},
methods: {
- revealVariables() {
- this.areVariablesVisible = true;
+ toggleValues() {
+ this.showVariableValues = !this.showVariableValues;
+ },
+ getDisplayValue(value) {
+ return this.showVariableValues ? value : HIDDEN_VALUE;
},
},
};
@@ -31,52 +43,35 @@ export default {
<template>
<div class="build-widget block">
- <h4 class="title">
- {{ __('Trigger') }}
- </h4>
+ <h4 class="title">{{ __('Trigger') }}</h4>
<p
v-if="trigger.short_token"
class="js-short-token"
+ :class="{ 'append-bottom-0': !hasVariables }"
>
- <span class="build-light-text">
- {{ __('Token') }}
- </span>
- {{ trigger.short_token }}
+ <span class="build-light-text"> {{ __('Token') }} </span> {{ trigger.short_token }}
</p>
- <p v-if="hasVariables">
- <gl-button
- v-if="!areVariablesVisible"
- type="button"
- class="btn btn-default group js-reveal-variables"
- @click="revealVariables"
- >
- {{ __('Reveal Variables') }}
- </gl-button>
- </p>
+ <template v-if="hasVariables">
+ <p class="trigger-variables-btn-container">
+ <span class="build-light-text"> {{ __('Variables:') }} </span>
- <dl
- v-if="areVariablesVisible"
- class="js-build-variables trigger-build-variables"
- >
- <template
- v-for="variable in trigger.variables"
- >
- <dt
- :key="`${variable.key}-variable`"
- class="js-build-variable trigger-build-variable"
- >
- {{ variable.key }}
- </dt>
+ <gl-button v-if="hasValues" class="group js-reveal-variables" @click="toggleValues">
+ {{ getToggleButtonText }}
+ </gl-button>
+ </p>
- <dd
- :key="`${variable.key}-value`"
- class="js-build-value trigger-build-value"
- >
- {{ variable.value }}
- </dd>
- </template>
- </dl>
+ <table class="js-build-variables trigger-build-variables">
+ <tr v-for="(variable, index) in trigger.variables" :key="`${variable.key}-${index}`">
+ <td class="js-build-variable trigger-build-variable trigger-variables-table-cell">
+ {{ variable.key }}
+ </td>
+ <td class="js-build-value trigger-build-value trigger-variables-table-cell">
+ {{ getDisplayValue(variable.value) }}
+ </td>
+ </tr>
+ </table>
+ </template>
</div>
</template>
diff --git a/app/assets/javascripts/jobs/store/getters.js b/app/assets/javascripts/jobs/store/getters.js
index d440b2c9ef1..35e92b0b5d9 100644
--- a/app/assets/javascripts/jobs/store/getters.js
+++ b/app/assets/javascripts/jobs/store/getters.js
@@ -42,7 +42,7 @@ export const emptyStateIllustration = state =>
(state.job && state.job.status && state.job.status.illustration) || {};
export const emptyStateAction = state =>
- (state.job && state.job.status && state.job.status.action) || {};
+ (state.job && state.job.status && state.job.status.action) || null;
export const isScrollingDown = state => isScrolledToBottom() && !state.isTraceComplete;
diff --git a/app/assets/javascripts/labels.js b/app/assets/javascripts/labels.js
index 2bc09237495..cd8cf0d354c 100644
--- a/app/assets/javascripts/labels.js
+++ b/app/assets/javascripts/labels.js
@@ -22,7 +22,7 @@ export default class Labels {
updateColorPreview() {
const previewColor = $('input#label_color').val();
return $('div.label-color-preview').css('background-color', previewColor);
- // Updates the the preview color with the hex-color input
+ // Updates the preview color with the hex-color input
}
// Updates the preview color with a click on a suggested color
diff --git a/app/assets/javascripts/landing.js b/app/assets/javascripts/landing.js
index 8c0950ad5d5..bfb4d9ce67b 100644
--- a/app/assets/javascripts/landing.js
+++ b/app/assets/javascripts/landing.js
@@ -1,4 +1,5 @@
import Cookies from 'js-cookie';
+import { parseBoolean } from '~/lib/utils/common_utils';
class Landing {
constructor(landingElement, dismissButton, cookieName) {
@@ -30,7 +31,7 @@ class Landing {
}
isDismissed() {
- return Cookies.get(this.cookieName) === 'true';
+ return parseBoolean(Cookies.get(this.cookieName));
}
}
diff --git a/app/assets/javascripts/lazy_loader.js b/app/assets/javascripts/lazy_loader.js
index 61b4862b4e3..ee01a73a6e8 100644
--- a/app/assets/javascripts/lazy_loader.js
+++ b/app/assets/javascripts/lazy_loader.js
@@ -19,7 +19,7 @@ export default class LazyLoader {
}
searchLazyImages() {
- requestIdleCallback(
+ window.requestIdleCallback(
() => {
const lazyImages = [].slice.call(document.querySelectorAll('.lazy'));
@@ -91,7 +91,9 @@ export default class LazyLoader {
onIntersection = entries => {
entries.forEach(entry => {
- if (entry.isIntersecting) {
+ // We are using `intersectionRatio > 0` over `isIntersecting`, as some browsers did not ship the latter
+ // See: https://gitlab.com/gitlab-org/gitlab-ce/issues/54407
+ if (entry.intersectionRatio > 0) {
this.intersectionObserver.unobserve(entry.target);
this.lazyImages.push(entry.target);
}
@@ -107,7 +109,7 @@ export default class LazyLoader {
}
scrollCheck() {
- requestAnimationFrame(() => this.checkElementsInView());
+ window.requestAnimationFrame(() => this.checkElementsInView());
}
checkElementsInView() {
@@ -122,7 +124,7 @@ export default class LazyLoader {
const imgBound = imgTop + imgBoundRect.height;
if (scrollTop <= imgBound && visHeight >= imgTop) {
- requestAnimationFrame(() => {
+ window.requestAnimationFrame(() => {
LazyLoader.loadImage(selectedImage);
});
return false;
diff --git a/app/assets/javascripts/lib/graphql.js b/app/assets/javascripts/lib/graphql.js
new file mode 100644
index 00000000000..20a0f142d9e
--- /dev/null
+++ b/app/assets/javascripts/lib/graphql.js
@@ -0,0 +1,9 @@
+import ApolloClient from 'apollo-boost';
+import csrf from '~/lib/utils/csrf';
+
+export default new ApolloClient({
+ uri: `${gon.relative_url_root}/api/graphql`,
+ headers: {
+ [csrf.headerKey]: csrf.token,
+ },
+});
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index e14fff7a610..9e22cdc04e9 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -192,8 +192,12 @@ export const contentTop = () => {
const mrTabsHeight = $('.merge-request-tabs').height() || 0;
const headerHeight = $('.navbar-gitlab').height() || 0;
const diffFilesChanged = $('.js-diff-files-changed').height() || 0;
+ const diffFileLargeEnoughScreen =
+ 'matchMedia' in window ? window.matchMedia('min-width: 768') : true;
+ const diffFileTitleBar =
+ (diffFileLargeEnoughScreen && $('.diff-file .file-title-flex-parent:visible').height()) || 0;
- return perfBar + mrTabsHeight + headerHeight + diffFilesChanged;
+ return perfBar + mrTabsHeight + headerHeight + diffFilesChanged + diffFileTitleBar;
};
export const scrollToElement = element => {
@@ -226,7 +230,17 @@ export const getParameterByName = (name, urlToParse) => {
return decodeURIComponent(results[2].replace(/\+/g, ' '));
};
-const handleSelectedRange = range => {
+const handleSelectedRange = (range, restrictToNode) => {
+ // Make sure this range is within the restricting container
+ if (restrictToNode && !range.intersectsNode(restrictToNode)) return null;
+
+ // If only a part of the range is within the wanted container, we need to restrict the range to it
+ if (restrictToNode && !restrictToNode.contains(range.commonAncestorContainer)) {
+ if (!restrictToNode.contains(range.startContainer)) range.setStart(restrictToNode, 0);
+ if (!restrictToNode.contains(range.endContainer))
+ range.setEnd(restrictToNode, restrictToNode.childNodes.length);
+ }
+
const container = range.commonAncestorContainer;
// add context to fragment if needed
if (container.tagName === 'OL') {
@@ -237,14 +251,22 @@ const handleSelectedRange = range => {
return range.cloneContents();
};
-export const getSelectedFragment = () => {
+export const getSelectedFragment = restrictToNode => {
const selection = window.getSelection();
if (selection.rangeCount === 0) return null;
+ // Most usages of the selection only want text from a part of the page (e.g. discussion)
+ if (restrictToNode && !selection.containsNode(restrictToNode, true)) return null;
+
const documentFragment = document.createDocumentFragment();
+ documentFragment.originalNodes = [];
for (let i = 0; i < selection.rangeCount; i += 1) {
const range = selection.getRangeAt(i);
- documentFragment.appendChild(handleSelectedRange(range));
+ const handledRange = handleSelectedRange(range, restrictToNode);
+ if (handledRange) {
+ documentFragment.appendChild(handledRange);
+ documentFragment.originalNodes.push(range.commonAncestorContainer);
+ }
}
if (documentFragment.textContent.length === 0) return null;
@@ -403,12 +425,28 @@ export const historyPushState = newUrl => {
};
/**
+ * Returns true for a String "true" and false otherwise.
+ * This is the opposite of Boolean(...).toString()
+ *
+ * @param {String} value
+ * @returns {Boolean}
+ */
+export const parseBoolean = value => value === 'true';
+
+/**
* Converts permission provided as strings to booleans.
*
* @param {String} string
* @returns {Boolean}
*/
-export const convertPermissionToBoolean = permission => permission === 'true';
+export const convertPermissionToBoolean = permission => {
+ if (process.env.NODE_ENV !== 'production') {
+ // eslint-disable-next-line no-console
+ console.warn('convertPermissionToBoolean is deprecated! Please use parseBoolean instead.');
+ }
+
+ return parseBoolean(permission);
+};
/**
* Back Off exponential algorithm
diff --git a/app/assets/javascripts/lib/utils/dom_utils.js b/app/assets/javascripts/lib/utils/dom_utils.js
index 6f42382246d..7933c234384 100644
--- a/app/assets/javascripts/lib/utils/dom_utils.js
+++ b/app/assets/javascripts/lib/utils/dom_utils.js
@@ -7,3 +7,8 @@ export const addClassIfElementExists = (element, className) => {
};
export const isInVueNoteablePage = () => isInIssuePage() || isInEpicPage() || isInMRPage();
+
+export const canScrollUp = ({ scrollTop }, margin = 0) => scrollTop > margin;
+
+export const canScrollDown = ({ scrollTop, offsetHeight, scrollHeight }, margin = 0) =>
+ scrollTop + offsetHeight < scrollHeight - margin;
diff --git a/app/assets/javascripts/lib/utils/file_upload.js b/app/assets/javascripts/lib/utils/file_upload.js
new file mode 100644
index 00000000000..b41ffb44971
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/file_upload.js
@@ -0,0 +1,13 @@
+export default (buttonSelector, fileSelector) => {
+ const btn = document.querySelector(buttonSelector);
+ const fileInput = document.querySelector(fileSelector);
+ const form = btn.closest('form');
+
+ btn.addEventListener('click', () => {
+ fileInput.click();
+ });
+
+ fileInput.addEventListener('change', () => {
+ form.querySelector('.js-filename').textContent = fileInput.value.replace(/^.*[\\\/]/, ''); // eslint-disable-line no-useless-escape
+ });
+};
diff --git a/app/assets/javascripts/lib/utils/http_status.js b/app/assets/javascripts/lib/utils/http_status.js
index e4852c85378..14c02218990 100644
--- a/app/assets/javascripts/lib/utils/http_status.js
+++ b/app/assets/javascripts/lib/utils/http_status.js
@@ -16,7 +16,9 @@ const httpStatusCodes = {
IM_USED: 226,
MULTIPLE_CHOICES: 300,
BAD_REQUEST: 400,
+ FORBIDDEN: 403,
NOT_FOUND: 404,
+ UNPROCESSABLE_ENTITY: 422,
};
export const successCodes = [
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index c52cfb806a2..3618c6af7e2 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -39,7 +39,7 @@ function blockTagText(text, textArea, blockTag, selected) {
}
}
-function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
+function moveCursor({ textArea, tag, positionBetweenTags, removedLastNewLine, select }) {
var pos;
if (!textArea.setSelectionRange) {
return;
@@ -51,7 +51,7 @@ function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
return textArea.setSelectionRange(startPosition, endPosition);
}
if (textArea.selectionStart === textArea.selectionEnd) {
- if (wrapped) {
+ if (positionBetweenTags) {
pos = textArea.selectionStart - tag.length;
} else {
pos = textArea.selectionStart;
@@ -67,7 +67,6 @@ function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) {
var textToInsert,
- inserted,
selectedSplit,
startChar,
removedLastNewLine,
@@ -155,7 +154,7 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr
return moveCursor({
textArea,
tag: tag.replace(textPlaceholder, selected),
- wrap,
+ positionBetweenTags: wrap && selected.length === 0,
removedLastNewLine,
select,
});
@@ -171,10 +170,6 @@ function updateText({ textArea, tag, blockTag, wrap, select }) {
return insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select });
}
-function replaceRange(s, start, end, substitute) {
- return s.substring(0, start) + substitute + s.substring(end);
-}
-
export function addMarkdownListeners(form) {
return $('.js-md', form)
.off('click')
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index a282c2df441..9850f7ce782 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -17,27 +17,29 @@ export function getParameterValues(sParam) {
// @param {Object} params - url keys and value to merge
// @param {String} url
export function mergeUrlParams(params, url) {
- let newUrl = Object.keys(params).reduce((acc, paramName) => {
- const paramValue = encodeURIComponent(params[paramName]);
- const pattern = new RegExp(`\\b(${paramName}=).*?(&|$)`);
-
- if (paramValue === null) {
- return acc.replace(pattern, '');
- } else if (url.search(pattern) !== -1) {
- return acc.replace(pattern, `$1${paramValue}$2`);
- }
-
- return `${acc}${acc.indexOf('?') > 0 ? '&' : '?'}${paramName}=${paramValue}`;
- }, decodeURIComponent(url));
+ const re = /^([^?#]*)(\?[^#]*)?(.*)/;
+ const merged = {};
+ const urlparts = url.match(re);
+
+ if (urlparts[2]) {
+ urlparts[2]
+ .substr(1)
+ .split('&')
+ .forEach(part => {
+ if (part.length) {
+ const kv = part.split('=');
+ merged[decodeURIComponent(kv[0])] = decodeURIComponent(kv.slice(1).join('='));
+ }
+ });
+ }
- // Remove a trailing ampersand
- const lastChar = newUrl[newUrl.length - 1];
+ Object.assign(merged, params);
- if (lastChar === '&') {
- newUrl = newUrl.slice(0, -1);
- }
+ const query = Object.keys(merged)
+ .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(merged[key])}`)
+ .join('&');
- return newUrl;
+ return `${urlparts[1]}?${query}${urlparts[3]}`;
}
export function removeParamQueryString(url, param) {
diff --git a/app/assets/javascripts/lib/utils/users_cache.js b/app/assets/javascripts/lib/utils/users_cache.js
index c0d45e017b4..9f980fd4899 100644
--- a/app/assets/javascripts/lib/utils/users_cache.js
+++ b/app/assets/javascripts/lib/utils/users_cache.js
@@ -22,6 +22,34 @@ class UsersCache extends Cache {
});
// missing catch is intentional, error handling depends on use case
}
+
+ retrieveById(userId) {
+ if (this.hasData(userId) && this.get(userId).username) {
+ return Promise.resolve(this.get(userId));
+ }
+
+ return Api.user(userId).then(({ data }) => {
+ this.internalStorage[userId] = data;
+ return data;
+ });
+ // missing catch is intentional, error handling depends on use case
+ }
+
+ retrieveStatusById(userId) {
+ if (this.hasData(userId) && this.get(userId).status) {
+ return Promise.resolve(this.get(userId).status);
+ }
+
+ return Api.userStatus(userId).then(({ data }) => {
+ if (!this.hasData(userId)) {
+ this.internalStorage[userId] = {};
+ }
+ this.internalStorage[userId].status = data;
+
+ return data;
+ });
+ // missing catch is intentional, error handling depends on use case
+ }
}
export default new UsersCache();
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index a88b575ad99..c866e8d180a 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -30,6 +30,7 @@ import initUsagePingConsent from './usage_ping_consent';
import initPerformanceBar from './performance_bar';
import initSearchAutocomplete from './search_autocomplete';
import GlFieldErrors from './gl_field_errors';
+import initUserPopovers from './user_popovers';
// expose jQuery as global (TODO: remove these)
window.jQuery = jQuery;
@@ -78,6 +79,7 @@ document.addEventListener('DOMContentLoaded', () => {
initTodoToggle();
initLogoAnimation();
initUsagePingConsent();
+ initUserPopovers();
if (document.querySelector('.search')) initSearchAutocomplete();
if (document.querySelector('#js-peek')) initPerformanceBar({ container: '#js-peek' });
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index d8255181574..b0dc5697018 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -8,7 +8,12 @@ import flash from './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import initChangesDropdown from './init_changes_dropdown';
import bp from './breakpoints';
-import { parseUrlPathname, handleLocationHash, isMetaClick } from './lib/utils/common_utils';
+import {
+ parseUrlPathname,
+ handleLocationHash,
+ isMetaClick,
+ parseBoolean,
+} from './lib/utils/common_utils';
import { isInVueNoteablePage } from './lib/utils/dom_utils';
import { getLocationHash } from './lib/utils/url_utility';
import Diff from './diff';
@@ -212,6 +217,28 @@ export default class MergeRequestTabs {
}
this.eventHub.$emit('MergeRequestTabChange', this.getCurrentAction());
+ } else if (action === this.currentAction) {
+ // ContentTop is used to handle anything at the top of the page before the main content
+ const mainContentContainer = document.querySelector('.content-wrapper');
+ const tabContentContainer = document.querySelector('.tab-content');
+
+ if (mainContentContainer && tabContentContainer) {
+ const mainContentTop = mainContentContainer.getBoundingClientRect().top;
+ const tabContentTop = tabContentContainer.getBoundingClientRect().top;
+
+ // 51px is the height of the navbar buttons, e.g. `Discussion | Commits | Changes`
+ const scrollDestination = tabContentTop - mainContentTop - 51;
+
+ // scrollBehavior is only available in browsers that support scrollToOptions
+ if ('scrollBehavior' in document.documentElement.style) {
+ window.scrollTo({
+ top: scrollDestination,
+ behavior: 'smooth',
+ });
+ } else {
+ window.scrollTo(0, scrollDestination);
+ }
+ }
}
}
@@ -440,7 +467,7 @@ export default class MergeRequestTabs {
// Expand the issuable sidebar unless the user explicitly collapsed it
expandView() {
- if (Cookies.get('collapsed_gutter') === 'true') {
+ if (parseBoolean(Cookies.get('collapsed_gutter'))) {
return;
}
const $gutterIcon = $('.js-sidebar-toggle i:visible');
diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js
index d32f39881dd..75c18a9b6a0 100644
--- a/app/assets/javascripts/milestone_select.js
+++ b/app/assets/javascripts/milestone_select.js
@@ -155,7 +155,7 @@ export default class MilestoneSelect {
const { $el, e } = clickEvent;
let selected = clickEvent.selectedObj;
- let data, boardsStore;
+ let data, modalStoreFilter;
if (!selected) return;
if (options.handleClick) {
@@ -179,11 +179,11 @@ export default class MilestoneSelect {
}
if ($dropdown.closest('.add-issues-modal').length) {
- boardsStore = ModalStore.store.filter;
+ modalStoreFilter = ModalStore.store.filter;
}
- if (boardsStore) {
- boardsStore[$dropdown.data('fieldName')] = selected.name;
+ if (modalStoreFilter) {
+ modalStoreFilter[$dropdown.data('fieldName')] = selected.name;
e.preventDefault();
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
return Issuable.filterResults($dropdown.closest('form'));
diff --git a/app/assets/javascripts/mirrors/constants.js b/app/assets/javascripts/mirrors/constants.js
new file mode 100644
index 00000000000..8dd6a726425
--- /dev/null
+++ b/app/assets/javascripts/mirrors/constants.js
@@ -0,0 +1,4 @@
+export default {
+ PASSWORD: 'password',
+ SSH: 'ssh_public_key',
+};
diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js b/app/assets/javascripts/mirrors/mirror_repos.js
index 4c56af20cc3..196b84621b6 100644
--- a/app/assets/javascripts/pages/projects/settings/repository/show/mirror_repos.js
+++ b/app/assets/javascripts/mirrors/mirror_repos.js
@@ -3,10 +3,12 @@ import _ from 'underscore';
import { __ } from '~/locale';
import Flash from '~/flash';
import axios from '~/lib/utils/axios_utils';
+import SSHMirror from './ssh_mirror';
export default class MirrorRepos {
constructor(container) {
this.$container = $(container);
+ this.$password = null;
this.$form = $('.js-mirror-form', this.$container);
this.$urlInput = $('.js-mirror-url', this.$form);
this.$protectedBranchesInput = $('.js-mirror-protected', this.$form);
@@ -26,6 +28,19 @@ export default class MirrorRepos {
this.$authMethod.on('change', () => this.togglePassword());
this.$password.on('input.updateUrl', () => this.debouncedUpdateUrl());
+
+ this.initMirrorSSH();
+ this.updateProtectedBranches();
+ }
+
+ initMirrorSSH() {
+ if (this.$password) {
+ this.$password.off('input.updateUrl');
+ }
+ this.$password = undefined;
+
+ this.sshMirror = new SSHMirror('.js-mirror-form');
+ this.sshMirror.init();
}
updateUrl() {
diff --git a/app/assets/javascripts/mirrors/ssh_mirror.js b/app/assets/javascripts/mirrors/ssh_mirror.js
new file mode 100644
index 00000000000..5bdf5d6277a
--- /dev/null
+++ b/app/assets/javascripts/mirrors/ssh_mirror.js
@@ -0,0 +1,299 @@
+import $ from 'jquery';
+import _ from 'underscore';
+import { __ } from '~/locale';
+import axios from '~/lib/utils/axios_utils';
+import Flash from '~/flash';
+import { backOff } from '~/lib/utils/common_utils';
+import AUTH_METHOD from './constants';
+
+export default class SSHMirror {
+ constructor(formSelector) {
+ this.backOffRequestCounter = 0;
+
+ this.$form = $(formSelector);
+
+ this.$repositoryUrl = this.$form.find('.js-repo-url');
+ this.$knownHosts = this.$form.find('.js-known-hosts');
+
+ this.$sectionSSHHostKeys = this.$form.find('.js-ssh-host-keys-section');
+ this.$hostKeysInformation = this.$form.find('.js-fingerprint-ssh-info');
+ this.$btnDetectHostKeys = this.$form.find('.js-detect-host-keys');
+ this.$btnSSHHostsShowAdvanced = this.$form.find('.btn-show-advanced');
+ this.$dropdownAuthType = this.$form.find('.js-mirror-auth-type');
+
+ this.$wellAuthTypeChanging = this.$form.find('.js-well-changing-auth');
+ this.$wellPasswordAuth = this.$form.find('.js-well-password-auth');
+ this.$wellSSHAuth = this.$form.find('.js-well-ssh-auth');
+ this.$sshPublicKeyWrap = this.$form.find('.js-ssh-public-key-wrap');
+ this.$regeneratePublicSshKeyButton = this.$wellSSHAuth.find('.js-btn-regenerate-ssh-key');
+ this.$regeneratePublicSshKeyModal = this.$wellSSHAuth.find(
+ '.js-regenerate-public-ssh-key-confirm-modal',
+ );
+ }
+
+ init() {
+ this.handleRepositoryUrlInput(true);
+
+ this.$repositoryUrl.on('keyup', () => this.handleRepositoryUrlInput());
+ this.$knownHosts.on('keyup', e => this.handleSSHKnownHostsInput(e));
+ this.$dropdownAuthType.on('change', e => this.handleAuthTypeChange(e));
+ this.$btnDetectHostKeys.on('click', e => this.handleDetectHostKeys(e));
+ this.$btnSSHHostsShowAdvanced.on('click', e => this.handleSSHHostsAdvanced(e));
+ this.$regeneratePublicSshKeyButton.on('click', () =>
+ this.$regeneratePublicSshKeyModal.toggle(true),
+ );
+ $('.js-confirm', this.$regeneratePublicSshKeyModal).on('click', e =>
+ this.regeneratePublicSshKey(e),
+ );
+ $('.js-cancel', this.$regeneratePublicSshKeyModal).on('click', () =>
+ this.$regeneratePublicSshKeyModal.toggle(false),
+ );
+ }
+
+ /**
+ * Method to monitor Git Repository URL input
+ */
+ handleRepositoryUrlInput(forceMatch) {
+ const protocol = this.$repositoryUrl.val().split('://')[0];
+ const protRegEx = /http|git/;
+
+ // Validate URL and verify if it consists only supported protocols
+ if (forceMatch || this.$form.get(0).checkValidity()) {
+ const isSsh = protocol === 'ssh';
+ // Hide/Show SSH Host keys section only for SSH URLs
+ this.$sectionSSHHostKeys.collapse(isSsh ? 'show' : 'hide');
+ this.$btnDetectHostKeys.enable();
+
+ // Verify if URL is http, https or git and hide/show Auth type dropdown
+ // as we don't support auth type SSH for non-SSH URLs
+ const matchesProtocol = protRegEx.test(protocol);
+ this.$dropdownAuthType.attr('disabled', matchesProtocol);
+
+ if (forceMatch && isSsh) {
+ this.$dropdownAuthType.val(AUTH_METHOD.SSH);
+ this.toggleAuthWell(AUTH_METHOD.SSH);
+ } else {
+ this.$dropdownAuthType.val(AUTH_METHOD.PASSWORD);
+ this.toggleAuthWell(AUTH_METHOD.PASSWORD);
+ }
+ }
+ }
+
+ /**
+ * Click event handler to detect SSH Host key and fingerprints from
+ * provided Git Repository URL.
+ */
+ handleDetectHostKeys() {
+ const projectMirrorSSHEndpoint = this.$form.data('project-mirror-ssh-endpoint');
+ const repositoryUrl = this.$repositoryUrl.val();
+ const currentKnownHosts = this.$knownHosts.val();
+ const $btnLoadSpinner = this.$btnDetectHostKeys.find('.js-spinner');
+
+ // Disable button while we make request
+ this.$btnDetectHostKeys.disable();
+ $btnLoadSpinner.removeClass('d-none');
+
+ // Make backOff polling to get data
+ backOff((next, stop) => {
+ axios
+ .get(
+ `${projectMirrorSSHEndpoint}?ssh_url=${repositoryUrl}&compare_host_keys=${encodeURIComponent(
+ currentKnownHosts,
+ )}`,
+ )
+ .then(({ data, status }) => {
+ if (status === 204) {
+ this.backOffRequestCounter += 1;
+ if (this.backOffRequestCounter < 3) {
+ next();
+ } else {
+ stop(data);
+ }
+ } else {
+ stop(data);
+ }
+ })
+ .catch(stop);
+ })
+ .then(res => {
+ $btnLoadSpinner.addClass('d-none');
+ // Once data is received, we show verification info along with Host keys and fingerprints
+ this.$hostKeysInformation
+ .find('.js-fingerprint-verification')
+ .collapse(res.host_keys_changed ? 'hide' : 'show');
+ if (res.known_hosts && res.fingerprints) {
+ this.showSSHInformation(res);
+ }
+ })
+ .catch(({ response }) => {
+ // Show failure message when there's an error and re-enable Detect host keys button
+ const failureMessage = response.data
+ ? response.data.message
+ : __('An error occurred while detecting host keys');
+ Flash(failureMessage);
+
+ $btnLoadSpinner.addClass('hidden');
+ this.$btnDetectHostKeys.enable();
+ });
+ }
+
+ /**
+ * Method to monitor known hosts textarea input
+ */
+ handleSSHKnownHostsInput() {
+ // Strike-out fingerprints and remove verification info if `known hosts` value is altered
+ this.$hostKeysInformation.find('.js-fingerprints-list').addClass('invalidate');
+ this.$hostKeysInformation.find('.js-fingerprint-verification').collapse('hide');
+ }
+
+ /**
+ * Click event handler for `Show advanced` button under SSH Host keys section
+ */
+ handleSSHHostsAdvanced() {
+ const $knownHost = this.$sectionSSHHostKeys.find('.js-ssh-known-hosts');
+ const toggleShowAdvanced = $knownHost.hasClass('show');
+
+ $knownHost.collapse('toggle');
+ this.$btnSSHHostsShowAdvanced.toggleClass('show-advanced', toggleShowAdvanced);
+ }
+
+ /**
+ * Authentication method dropdown change event listener
+ */
+ handleAuthTypeChange() {
+ const projectMirrorAuthTypeEndpoint = `${this.$form.attr('action')}.json`;
+ const $sshPublicKey = this.$sshPublicKeyWrap.find('.ssh-public-key');
+ const selectedAuthType = this.$dropdownAuthType.val();
+
+ this.$wellPasswordAuth.collapse('hide');
+ this.$wellSSHAuth.collapse('hide');
+
+ // This request should happen only if selected Auth type was SSH
+ // and SSH Public key was not present on page load
+ if (selectedAuthType === AUTH_METHOD.SSH && !$sshPublicKey.text().trim()) {
+ if (!this.$wellSSHAuth.length) return;
+
+ // Construct request body
+ const authTypeData = {
+ project: {
+ ...this.$regeneratePublicSshKeyButton.data().projectData,
+ },
+ };
+
+ this.$wellAuthTypeChanging.collapse('show');
+ this.$dropdownAuthType.disable();
+
+ axios
+ .put(projectMirrorAuthTypeEndpoint, JSON.stringify(authTypeData), {
+ headers: {
+ 'Content-Type': 'application/json; charset=utf-8',
+ },
+ })
+ .then(({ data }) => {
+ // Show SSH public key container and fill in public key
+ this.toggleAuthWell(selectedAuthType);
+ this.toggleSSHAuthWellMessage(true);
+ this.setSSHPublicKey(data.import_data_attributes.ssh_public_key);
+
+ this.$wellAuthTypeChanging.collapse('hide');
+ this.$dropdownAuthType.enable();
+ })
+ .catch(() => {
+ Flash(__('Something went wrong on our end.'));
+
+ this.$wellAuthTypeChanging.collapse('hide');
+ this.$dropdownAuthType.enable();
+ });
+ } else {
+ this.toggleAuthWell(selectedAuthType);
+ this.$wellSSHAuth.find('.js-ssh-public-key-present').collapse('show');
+ }
+ }
+
+ /**
+ * Method to parse SSH Host keys data and render it
+ * under SSH host keys section
+ */
+ showSSHInformation(sshHostKeys) {
+ const $fingerprintsList = this.$hostKeysInformation.find('.js-fingerprints-list');
+ let fingerprints = '';
+ sshHostKeys.fingerprints.forEach(fingerprint => {
+ const escFingerprints = _.escape(fingerprint.fingerprint);
+ fingerprints += `<code>${escFingerprints}</code>`;
+ });
+
+ this.$hostKeysInformation.collapse('show');
+ $fingerprintsList.removeClass('invalidate');
+ $fingerprintsList.html(fingerprints);
+ this.$sectionSSHHostKeys.find('.js-known-hosts').val(sshHostKeys.known_hosts);
+ }
+
+ /**
+ * Toggle Auth type information container based on provided `authType`
+ */
+ toggleAuthWell(authType) {
+ this.$wellPasswordAuth.collapse(authType === AUTH_METHOD.PASSWORD ? 'show' : 'hide');
+ this.$wellSSHAuth.collapse(authType === AUTH_METHOD.SSH ? 'show' : 'hide');
+ }
+
+ /**
+ * Toggle SSH auth information message
+ */
+ toggleSSHAuthWellMessage(sshKeyPresent) {
+ this.$sshPublicKeyWrap.collapse(sshKeyPresent ? 'show' : 'hide');
+ this.$wellSSHAuth.find('.js-ssh-public-key-present').collapse(sshKeyPresent ? 'show' : 'hide');
+ this.$regeneratePublicSshKeyButton.collapse(sshKeyPresent ? 'show' : 'hide');
+ this.$wellSSHAuth.find('.js-ssh-public-key-pending').collapse(sshKeyPresent ? 'hide' : 'show');
+ }
+
+ /**
+ * Sets SSH Public key to Clipboard button and shows it on UI.
+ */
+ setSSHPublicKey(sshPublicKey) {
+ this.$sshPublicKeyWrap.find('.ssh-public-key').text(sshPublicKey);
+ this.$sshPublicKeyWrap
+ .find('.btn-copy-ssh-public-key')
+ .attr('data-clipboard-text', sshPublicKey);
+ }
+
+ regeneratePublicSshKey(event) {
+ event.preventDefault();
+
+ this.$regeneratePublicSshKeyModal.toggle(false);
+
+ const button = this.$regeneratePublicSshKeyButton;
+ const spinner = $('.js-spinner', button);
+ const endpoint = button.data('endpoint');
+ const authTypeData = {
+ project: {
+ ...this.$regeneratePublicSshKeyButton.data().projectData,
+ },
+ };
+
+ button.attr('disabled', 'disabled');
+ spinner.removeClass('d-none');
+
+ axios
+ .patch(endpoint, authTypeData)
+ .then(({ data }) => {
+ button.removeAttr('disabled');
+ spinner.addClass('d-none');
+
+ this.setSSHPublicKey(data.import_data_attributes.ssh_public_key);
+ })
+ .catch(() => {
+ Flash(_('Unable to regenerate public ssh key.'));
+ });
+ }
+
+ destroy() {
+ this.$repositoryUrl.off('keyup');
+ this.$form.find('.js-known-hosts').off('keyup');
+ this.$dropdownAuthType.off('change');
+ this.$btnDetectHostKeys.off('click');
+ this.$btnSSHHostsShowAdvanced.off('click');
+ this.$regeneratePublicSshKeyButton.off('click');
+ $('.js-confirm', this.$regeneratePublicSshKeyModal).off('click');
+ $('.js-cancel', this.$regeneratePublicSshKeyModal).off('click');
+ }
+}
diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue
new file mode 100644
index 00000000000..12224e36ba2
--- /dev/null
+++ b/app/assets/javascripts/monitoring/components/charts/area.vue
@@ -0,0 +1,97 @@
+<script>
+import { GlAreaChart } from '@gitlab/ui';
+import dateFormat from 'dateformat';
+
+export default {
+ components: {
+ GlAreaChart,
+ },
+ props: {
+ graphData: {
+ type: Object,
+ required: true,
+ validator(data) {
+ return (
+ data.queries &&
+ Array.isArray(data.queries) &&
+ data.queries.filter(query => {
+ if (Array.isArray(query.result)) {
+ return (
+ query.result.filter(res => Array.isArray(res.values)).length === query.result.length
+ );
+ }
+ return false;
+ }).length === data.queries.length
+ );
+ },
+ },
+ },
+ computed: {
+ chartData() {
+ return this.graphData.queries.reduce((accumulator, query) => {
+ const xLabel = `${query.unit}`;
+ accumulator[xLabel] = {};
+ query.result.forEach(res =>
+ res.values.forEach(v => {
+ accumulator[xLabel][v.time.toISOString()] = v.value;
+ }),
+ );
+ return accumulator;
+ }, {});
+ },
+ chartOptions() {
+ return {
+ xAxis: {
+ name: 'Time',
+ type: 'time',
+ axisLabel: {
+ formatter: date => dateFormat(date, 'h:MMtt'),
+ },
+ nameTextStyle: {
+ padding: [18, 0, 0, 0],
+ },
+ },
+ yAxis: {
+ name: this.graphData.y_label,
+ axisLabel: {
+ formatter: value => value.toFixed(3),
+ },
+ nameTextStyle: {
+ padding: [0, 0, 36, 0],
+ },
+ },
+ legend: {
+ formatter: this.xAxisLabel,
+ },
+ };
+ },
+ xAxisLabel() {
+ return this.graphData.queries.map(query => query.label).join(', ');
+ },
+ },
+ methods: {
+ formatTooltipText(params) {
+ const [date, value] = params;
+ return [dateFormat(date, 'dd mmm yyyy, h:MMtt'), value.toFixed(3)];
+ },
+ onCreated(chart) {
+ this.$emit('created', chart);
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="prometheus-graph">
+ <div class="prometheus-graph-header">
+ <h5 class="prometheus-graph-title">{{ graphData.title }}</h5>
+ <div class="prometheus-graph-widgets"><slot></slot></div>
+ </div>
+ <gl-area-chart
+ :data="chartData"
+ :option="chartOptions"
+ :format-tooltip-text="formatTooltipText"
+ @created="onCreated"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 98182d92c2f..2d9c5050c9b 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -4,6 +4,7 @@ import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import Flash from '../../flash';
import MonitoringService from '../services/monitoring_service';
+import MonitorAreaChart from './charts/area.vue';
import GraphGroup from './graph_group.vue';
import Graph from './graph.vue';
import EmptyState from './empty_state.vue';
@@ -12,6 +13,7 @@ import eventHub from '../event_hub';
export default {
components: {
+ MonitorAreaChart,
Graph,
GraphGroup,
EmptyState,
@@ -102,6 +104,9 @@ export default {
};
},
computed: {
+ graphComponent() {
+ return gon.features && gon.features.areaChart ? MonitorAreaChart : Graph;
+ },
forceRedraw() {
return this.elWidth;
},
@@ -176,35 +181,19 @@ export default {
</script>
<template>
- <div
- v-if="!showEmptyState"
- :key="forceRedraw"
- class="prometheus-graphs prepend-top-default"
- >
+ <div v-if="!showEmptyState" :key="forceRedraw" class="prometheus-graphs prepend-top-default">
<div class="environments d-flex align-items-center">
{{ s__('Metrics|Environment') }}
<div class="dropdown prepend-left-10">
- <button
- class="dropdown-menu-toggle"
- data-toggle="dropdown"
- type="button"
- >
- <span>
- {{ currentEnvironmentName }}
- </span>
- <icon
- name="chevron-down"
- />
+ <button class="dropdown-menu-toggle" data-toggle="dropdown" type="button">
+ <span> {{ currentEnvironmentName }} </span> <icon name="chevron-down" />
</button>
- <div
- v-if="store.environmentsData.length > 0"
+ <div
+ v-if="store.environmentsData.length > 0"
class="dropdown-menu dropdown-menu-selectable dropdown-menu-drop-up"
>
<ul>
- <li
- v-for="environment in store.environmentsData"
- :key="environment.latest.id"
- >
+ <li v-for="environment in store.environmentsData" :key="environment.latest.id">
<a
:href="environment.latest.metrics_path"
:class="{ 'is-active': environment.latest.name == currentEnvironmentName }"
@@ -223,7 +212,8 @@ export default {
:name="groupData.group"
:show-panels="showPanels"
>
- <graph
+ <component
+ :is="graphComponent"
v-for="(graphData, graphIndex) in groupData.metrics"
:key="graphIndex"
:graph-data="graphData"
@@ -236,7 +226,7 @@ export default {
>
<!-- EE content -->
{{ null }}
- </graph>
+ </component>
</graph-group>
</div>
<empty-state
diff --git a/app/assets/javascripts/monitoring/components/empty_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue
index 82b9a4b1adb..0e141d02ead 100644
--- a/app/assets/javascripts/monitoring/components/empty_state.vue
+++ b/app/assets/javascripts/monitoring/components/empty_state.vue
@@ -44,9 +44,9 @@ export default {
title: 'Get started with performance monitoring',
description: `Stay updated about the performance and health
of your environment by configuring Prometheus to monitor your deployments.`,
- buttonText: 'Install Prometheus on clusters',
+ buttonText: 'Install on clusters',
buttonPath: this.clustersPath,
- secondaryButtonText: 'Configure existing Prometheus',
+ secondaryButtonText: 'Configure existing installation',
secondaryButtonPath: this.settingsPath,
},
loading: {
@@ -88,39 +88,32 @@ export default {
</script>
<template>
- <div class="prometheus-state">
- <div class="state-svg svg-content">
- <img :src="currentState.svgUrl" />
+ <div class="row empty-state js-empty-state">
+ <div class="col-12">
+ <div class="state-svg svg-content"><img :src="currentState.svgUrl" /></div>
</div>
- <h4 class="state-title">
- {{ currentState.title }}
- </h4>
- <p class="state-description">
- {{ currentState.description }}
- <a
- v-if="showButtonDescription"
- :href="settingsPath"
- >
- Prometheus server
- </a>
- </p>
- <div class="state-button">
- <a
- v-if="currentState.buttonPath"
- :href="currentState.buttonPath"
- class="btn btn-success"
- >
- {{ currentState.buttonText }}
- </a>
- </div>
- <div class="state-button">
- <a
- v-if="currentState.secondaryButtonPath"
- :href="currentState.secondaryButtonPath"
- class="btn"
- >
- {{ currentState.secondaryButtonText }}
- </a>
+
+ <div class="col-12">
+ <div class="text-content">
+ <h4 class="state-title text-center">{{ currentState.title }}</h4>
+ <p class="state-description">
+ {{ currentState.description }}
+ <a v-if="showButtonDescription" :href="settingsPath"> Prometheus server </a>
+ </p>
+
+ <div class="text-center">
+ <a v-if="currentState.buttonPath" :href="currentState.buttonPath" class="btn btn-success">
+ {{ currentState.buttonText }}
+ </a>
+ <a
+ v-if="currentState.secondaryButtonPath"
+ :href="currentState.secondaryButtonPath"
+ class="btn"
+ >
+ {{ currentState.secondaryButtonText }}
+ </a>
+ </div>
+ </div>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue
index 5c6e2e09e46..64a1df80a8e 100644
--- a/app/assets/javascripts/monitoring/components/graph.vue
+++ b/app/assets/javascripts/monitoring/components/graph.vue
@@ -105,6 +105,9 @@ export default {
deploymentFlagData() {
return this.reducedDeploymentData.find(deployment => deployment.showDeploymentFlag);
},
+ shouldRenderData() {
+ return this.graphData.queries.filter(s => s.result.length > 0).length > 0;
+ },
},
watch: {
hoverData() {
@@ -120,17 +123,17 @@ export default {
},
draw() {
const breakpointSize = bp.getBreakpointSize();
- const query = this.graphData.queries[0];
const svgWidth = this.$refs.baseSvg.getBoundingClientRect().width;
+
this.margin = measurements.large.margin;
+
if (this.smallGraph || breakpointSize === 'xs' || breakpointSize === 'sm') {
this.graphHeight = 300;
this.margin = measurements.small.margin;
this.measurements = measurements.small;
}
- this.unitOfDisplay = query.unit || '';
+
this.yAxisLabel = this.graphData.y_label || 'Values';
- this.legendTitle = query.label || 'Average';
this.graphWidth = svgWidth - this.margin.left - this.margin.right;
this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom;
this.baseGraphHeight = this.graphHeight - 50;
@@ -139,8 +142,15 @@ export default {
// pixel offsets inside the svg and outside are not 1:1
this.realPixelRatio = svgWidth / this.baseGraphWidth;
- this.renderAxesPaths();
- this.formatDeployments();
+ // set the legends on the axes
+ const [query] = this.graphData.queries;
+ this.legendTitle = query ? query.label : 'Average';
+ this.unitOfDisplay = query ? query.unit : '';
+
+ if (this.shouldRenderData) {
+ this.renderAxesPaths();
+ this.formatDeployments();
+ }
},
handleMouseOverGraph(e) {
let point = this.$refs.graphData.createSVGPoint();
@@ -247,33 +257,17 @@ export default {
<template>
<div
class="prometheus-graph"
- @mouseover="showFlagContent = true"
- @mouseleave="showFlagContent = false"
+ @mouseover="showFlagContent = true;"
+ @mouseleave="showFlagContent = false;"
>
<div class="prometheus-graph-header">
- <h5 class="prometheus-graph-title">
- {{ graphData.title }}
- </h5>
- <div class="prometheus-graph-widgets">
- <slot></slot>
- </div>
+ <h5 class="prometheus-graph-title">{{ graphData.title }}</h5>
+ <div class="prometheus-graph-widgets"><slot></slot></div>
</div>
- <div
- :style="paddingBottomRootSvg"
- class="prometheus-svg-container"
- >
- <svg
- ref="baseSvg"
- :viewBox="outerViewBox"
- >
- <g
- :transform="axisTransform"
- class="x-axis"
- />
- <g
- class="y-axis"
- transform="translate(70, 20)"
- />
+ <div :style="paddingBottomRootSvg" class="prometheus-svg-container">
+ <svg ref="baseSvg" :viewBox="outerViewBox">
+ <g :transform="axisTransform" class="x-axis" />
+ <g class="y-axis" transform="translate(70, 20)" />
<graph-axis
:graph-width="graphWidth"
:graph-height="graphHeight"
@@ -282,15 +276,8 @@ export default {
:y-axis-label="yAxisLabel"
:unit-of-display="unitOfDisplay"
/>
- <svg
- ref="graphData"
- :viewBox="innerViewBox"
- class="graph-data"
- >
- <slot
- name="additionalSvgContent"
- :graphDrawData="graphDrawData"
- />
+ <svg v-if="shouldRenderData" ref="graphData" :viewBox="innerViewBox" class="graph-data">
+ <slot name="additionalSvgContent" :graphDrawData="graphDrawData" />
<graph-path
v-for="(path, index) in timeSeries"
:key="index"
@@ -309,15 +296,21 @@ export default {
/>
<rect
ref="graphOverlay"
- :width="(graphWidth - 70)"
- :height="(graphHeight - 100)"
+ :width="graphWidth - 70"
+ :height="graphHeight - 100"
class="prometheus-graph-overlay"
transform="translate(-5, 20)"
- @mousemove="handleMouseOverGraph($event)"
+ @mousemove="handleMouseOverGraph($event);"
/>
</svg>
+ <svg v-else :viewBox="innerViewBox" class="js-no-data-to-display">
+ <text x="50%" y="50%" alignment-baseline="middle" text-anchor="middle">
+ {{ s__('Metrics|No data to display') }}
+ </text>
+ </svg>
</svg>
<graph-flag
+ v-if="shouldRenderData"
:real-pixel-ratio="realPixelRatio"
:current-x-coordinate="currentXCoordinate"
:current-data="currentData"
@@ -331,10 +324,6 @@ export default {
:current-coordinates="currentCoordinates"
/>
</div>
- <graph-legend
- v-if="showLegend"
- :legend-title="legendTitle"
- :time-series="timeSeries"
- />
+ <graph-legend v-if="showLegend" :legend-title="legendTitle" :time-series="timeSeries" />
</div>
</template>
diff --git a/app/assets/javascripts/monitoring/components/graph/axis.vue b/app/assets/javascripts/monitoring/components/graph/axis.vue
index 616410ec34f..8f046857a20 100644
--- a/app/assets/javascripts/monitoring/components/graph/axis.vue
+++ b/app/assets/javascripts/monitoring/components/graph/axis.vue
@@ -110,19 +110,8 @@ export default {
>
{{ yAxisLabelSentenceCase }}
</text>
- <rect
- :x="xPosition + 60"
- :y="graphHeight - 80"
- class="rect-axis-text"
- width="35"
- height="50"
- />
- <text
- :x="xPosition + 60"
- :y="yPosition"
- class="label-axis-text x-label-text"
- dy=".35em"
- >
+ <rect :x="xPosition + 60" :y="graphHeight - 80" class="rect-axis-text" width="35" height="50" />
+ <text :x="xPosition + 60" :y="yPosition" class="label-axis-text x-label-text" dy=".35em">
{{ timeString }}
</text>
</g>
diff --git a/app/assets/javascripts/monitoring/components/graph/deployment.vue b/app/assets/javascripts/monitoring/components/graph/deployment.vue
index a7289ed53e8..bee9784692c 100644
--- a/app/assets/javascripts/monitoring/components/graph/deployment.vue
+++ b/app/assets/javascripts/monitoring/components/graph/deployment.vue
@@ -31,41 +31,16 @@ export default {
<g
v-for="(deployment, index) in deploymentData"
:key="index"
- :transform="transformDeploymentGroup(deployment)">
- <rect
- :height="calculatedHeight"
- x="0"
- y="0"
- width="3"
- fill="url(#shadow-gradient)"
- />
- <line
- :y2="calculatedHeight"
- class="deployment-line"
- x1="0"
- y1="0"
- x2="0"
- stroke="#000"
- />
- </g>
- <svg
- height="0"
- width="0"
+ :transform="transformDeploymentGroup(deployment)"
>
+ <rect :height="calculatedHeight" x="0" y="0" width="3" fill="url(#shadow-gradient)" />
+ <line :y2="calculatedHeight" class="deployment-line" x1="0" y1="0" x2="0" stroke="#000" />
+ </g>
+ <svg height="0" width="0">
<defs>
- <linearGradient
- id="shadow-gradient"
- >
- <stop
- offset="0%"
- stop-color="#000"
- stop-opacity="0.4"
- />
- <stop
- offset="100%"
- stop-color="#000"
- stop-opacity="0"
- />
+ <linearGradient id="shadow-gradient">
+ <stop offset="0%" stop-color="#000" stop-opacity="0.4" />
+ <stop offset="100%" stop-color="#000" stop-opacity="0" />
</linearGradient>
</defs>
</svg>
diff --git a/app/assets/javascripts/monitoring/components/graph/flag.vue b/app/assets/javascripts/monitoring/components/graph/flag.vue
index 1720476480e..9d6d1caef80 100644
--- a/app/assets/javascripts/monitoring/components/graph/flag.vue
+++ b/app/assets/javascripts/monitoring/components/graph/flag.vue
@@ -117,59 +117,29 @@ export default {
</script>
<template>
- <div
- :style="cursorStyle"
- class="prometheus-graph-cursor"
- >
- <div
- v-if="showFlagContent"
- :class="flagOrientation"
- class="prometheus-graph-flag popover"
- >
+ <div :style="cursorStyle" class="prometheus-graph-cursor">
+ <div v-if="showFlagContent" :class="flagOrientation" class="prometheus-graph-flag popover">
<div class="arrow-shadow"></div>
<div class="arrow"></div>
<div class="popover-title">
- <h5 v-if="deploymentFlagData">
- Deployed
- </h5>
- {{ formatDate }}
- <strong>{{ formatTime }}</strong>
+ <h5 v-if="deploymentFlagData">Deployed</h5>
+ {{ formatDate }} <strong>{{ formatTime }}</strong>
</div>
- <div
- v-if="deploymentFlagData"
- class="popover-content deploy-meta-content"
- >
+ <div v-if="deploymentFlagData" class="popover-content deploy-meta-content">
<div>
- <icon
- :size="12"
- name="commit"
- />
- <a :href="deploymentFlagData.commitUrl">
- {{ deploymentFlagData.sha.slice(0, 8) }}
- </a>
+ <icon :size="12" name="commit" />
+ <a :href="deploymentFlagData.commitUrl"> {{ deploymentFlagData.sha.slice(0, 8) }} </a>
</div>
- <div
- v-if="deploymentFlagData.tag"
- >
- <icon
- :size="12"
- name="label"
- />
- <a :href="deploymentFlagData.tagUrl">
- {{ deploymentFlagData.ref }}
- </a>
+ <div v-if="deploymentFlagData.tag">
+ <icon :size="12" name="label" />
+ <a :href="deploymentFlagData.tagUrl"> {{ deploymentFlagData.ref }} </a>
</div>
</div>
<div class="popover-content">
<table class="prometheus-table">
- <tr
- v-for="(series, index) in timeSeries"
- :key="index"
- >
- <track-line :track="series"/>
- <td>
- {{ series.track }} {{ seriesMetricLabel(index, series) }}
- </td>
+ <tr v-for="(series, index) in timeSeries" :key="index">
+ <track-line :track="series" />
+ <td>{{ series.track }} {{ seriesMetricLabel(index, series) }}</td>
<td>
<strong>{{ seriesMetricValue(index, series) }}</strong>
</td>
diff --git a/app/assets/javascripts/monitoring/components/graph/legend.vue b/app/assets/javascripts/monitoring/components/graph/legend.vue
index ef18ae5c2c8..b5211c306a3 100644
--- a/app/assets/javascripts/monitoring/components/graph/legend.vue
+++ b/app/assets/javascripts/monitoring/components/graph/legend.vue
@@ -39,15 +39,9 @@ export default {
<strong v-if="series.renderCanary">{{ series.trackName }}</strong>
</td>
<track-line :track="series" />
- <td
- v-if="timeSeries.length > 1"
- class="legend-metric-title">
- <track-info
- v-if="series.metricTag"
- :track="series" />
- <track-info
- v-else
- :track="series">
+ <td v-if="timeSeries.length > 1" class="legend-metric-title">
+ <track-info v-if="series.metricTag" :track="series" />
+ <track-info v-else :track="series">
<strong>{{ legendTitle }}</strong> series {{ index + 1 }}
</track-info>
</td>
@@ -57,13 +51,9 @@ export default {
</track-info>
</td>
<template v-for="(track, trackIndex) in series.tracksLegend">
- <track-line
- :key="`track-line-${trackIndex}`"
- :track="track"/>
+ <track-line :key="`track-line-${trackIndex}`" :track="track" />
<td :key="`track-info-${trackIndex}`">
- <track-info
- :track="track"
- class="legend-metric-title" />
+ <track-info :track="track" class="legend-metric-title" />
</td>
</template>
</tr>
diff --git a/app/assets/javascripts/monitoring/components/graph/path.vue b/app/assets/javascripts/monitoring/components/graph/path.vue
index a9b7ce586ce..f2c237ec391 100644
--- a/app/assets/javascripts/monitoring/components/graph/path.vue
+++ b/app/assets/javascripts/monitoring/components/graph/path.vue
@@ -52,11 +52,7 @@ export default {
class="circle-path"
r="3"
/>
- <path
- :d="generatedAreaPath"
- :fill="areaColor"
- class="metric-area"
- />
+ <path :d="generatedAreaPath" :fill="areaColor" class="metric-area" />
<path
:d="generatedLinePath"
:stroke="lineColor"
diff --git a/app/assets/javascripts/monitoring/components/graph/track_line.vue b/app/assets/javascripts/monitoring/components/graph/track_line.vue
index e04fd9c1f35..d2ed1ba113e 100644
--- a/app/assets/javascripts/monitoring/components/graph/track_line.vue
+++ b/app/assets/javascripts/monitoring/components/graph/track_line.vue
@@ -18,9 +18,7 @@ export default {
</script>
<template>
<td>
- <svg
- width="16"
- height="8">
+ <svg width="16" height="8">
<line
:stroke-dasharray="stylizedLine"
:stroke="track.lineColor"
diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue
index 241627f9790..b20ad1802f3 100644
--- a/app/assets/javascripts/monitoring/components/graph_group.vue
+++ b/app/assets/javascripts/monitoring/components/graph_group.vue
@@ -15,21 +15,11 @@ export default {
</script>
<template>
- <div
- v-if="showPanels"
- class="card prometheus-panel"
- >
+ <div v-if="showPanels" class="card prometheus-panel">
<div class="card-header">
<h4>{{ name }}</h4>
</div>
- <div class="card-body prometheus-graph-group">
- <slot></slot>
- </div>
- </div>
- <div
- v-else
- class="prometheus-graph-group"
- >
- <slot></slot>
+ <div class="card-body prometheus-graph-group"><slot></slot></div>
</div>
+ <div v-else class="prometheus-graph-group"><slot></slot></div>
</template>
diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js
index 41270e015d4..9d78b5ea110 100644
--- a/app/assets/javascripts/monitoring/monitoring_bundle.js
+++ b/app/assets/javascripts/monitoring/monitoring_bundle.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
+import { parseBoolean } from '~/lib/utils/common_utils';
import Dashboard from './components/dashboard.vue';
export default () => {
@@ -13,7 +13,7 @@ export default () => {
return createElement(Dashboard, {
props: {
...el.dataset,
- hasMetrics: convertPermissionToBoolean(el.dataset.hasMetrics),
+ hasMetrics: parseBoolean(el.dataset.hasMetrics),
},
});
},
diff --git a/app/assets/javascripts/monitoring/stores/monitoring_store.js b/app/assets/javascripts/monitoring/stores/monitoring_store.js
index 176f7d9eef2..8692c873a41 100644
--- a/app/assets/javascripts/monitoring/stores/monitoring_store.js
+++ b/app/assets/javascripts/monitoring/stores/monitoring_store.js
@@ -7,10 +7,29 @@ function sortMetrics(metrics) {
.value();
}
+function checkQueryEmptyData(query) {
+ return {
+ ...query,
+ result: query.result.filter(timeSeries => {
+ const newTimeSeries = timeSeries;
+ const hasValue = series =>
+ !Number.isNaN(series.value) && (series.value !== null || series.value !== undefined);
+ const hasNonNullValue = timeSeries.values.find(hasValue);
+
+ newTimeSeries.values = hasNonNullValue ? newTimeSeries.values : [];
+
+ return newTimeSeries.values.length > 0;
+ }),
+ };
+}
+
+function removeTimeSeriesNoData(queries) {
+ return queries.reduce((series, query) => series.concat(checkQueryEmptyData(query)), []);
+}
+
function normalizeMetrics(metrics) {
- return metrics.map(metric => ({
- ...metric,
- queries: metric.queries.map(query => ({
+ return metrics.map(metric => {
+ const queries = metric.queries.map(query => ({
...query,
result: query.result.map(result => ({
...result,
@@ -19,8 +38,13 @@ function normalizeMetrics(metrics) {
value: Number(value),
})),
})),
- })),
- }));
+ }));
+
+ return {
+ ...metric,
+ queries: removeTimeSeriesNoData(queries),
+ };
+ });
}
export default class MonitoringStore {
diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js
index cba6759ebf5..ee1a5274ff7 100644
--- a/app/assets/javascripts/namespace_select.js
+++ b/app/assets/javascripts/namespace_select.js
@@ -3,10 +3,11 @@
import $ from 'jquery';
import Api from './api';
import { mergeUrlParams } from './lib/utils/url_utility';
+import { parseBoolean } from '~/lib/utils/common_utils';
export default class NamespaceSelect {
constructor(opts) {
- const isFilter = opts.dropdown.dataset.isFilter === 'true';
+ const isFilter = parseBoolean(opts.dropdown.dataset.isFilter);
const fieldName = opts.dropdown.dataset.fieldName || 'namespace_id';
$(opts.dropdown).glDropdown({
diff --git a/app/assets/javascripts/notebook/cells/code.vue b/app/assets/javascripts/notebook/cells/code.vue
index 18cef82cec0..bd6736152f5 100644
--- a/app/assets/javascripts/notebook/cells/code.vue
+++ b/app/assets/javascripts/notebook/cells/code.vue
@@ -42,12 +42,14 @@ export default {
:raw-code="rawInputCode"
:count="cell.execution_count"
:code-css-class="codeCssClass"
- type="input" />
+ type="input"
+ />
<output-cell
v-if="hasOutput"
:count="cell.execution_count"
:output="output"
- :code-css-class="codeCssClass" />
+ :code-css-class="codeCssClass"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/notebook/cells/code/index.vue b/app/assets/javascripts/notebook/cells/code/index.vue
index 0691ba64f8e..8bf2431c4c6 100644
--- a/app/assets/javascripts/notebook/cells/code/index.vue
+++ b/app/assets/javascripts/notebook/cells/code/index.vue
@@ -44,14 +44,7 @@ export default {
<template>
<div :class="type">
- <prompt
- :type="promptType"
- :count="count" />
- <pre
- ref="code"
- :class="codeCssClass"
- class="language-python"
- v-text="code">
- </pre>
+ <prompt :type="promptType" :count="count" />
+ <pre ref="code" :class="codeCssClass" class="language-python" v-text="code"></pre>
</div>
</template>
diff --git a/app/assets/javascripts/notebook/cells/markdown.vue b/app/assets/javascripts/notebook/cells/markdown.vue
index 5aa83db0986..61eabbcb8b2 100644
--- a/app/assets/javascripts/notebook/cells/markdown.vue
+++ b/app/assets/javascripts/notebook/cells/markdown.vue
@@ -100,10 +100,7 @@ export default {
<template>
<div class="cell text-cell">
<prompt />
- <div
- class="markdown"
- v-html="markdown">
- </div>
+ <div class="markdown" v-html="markdown"></div>
</div>
</template>
diff --git a/app/assets/javascripts/notebook/cells/output/image.vue b/app/assets/javascripts/notebook/cells/output/image.vue
index a17868963ce..fe8c81398fb 100644
--- a/app/assets/javascripts/notebook/cells/output/image.vue
+++ b/app/assets/javascripts/notebook/cells/output/image.vue
@@ -19,8 +19,5 @@ export default {
</script>
<template>
- <div class="output">
- <prompt />
- <img :src="'data:' + outputType + ';base64,' + rawCode" />
- </div>
+ <div class="output"><prompt /> <img :src="'data:' + outputType + ';base64,' + rawCode" /></div>
</template>
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
index d9f8604ed10..bd0bcc0d819 100644
--- a/app/assets/javascripts/notebook/cells/output/index.vue
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -22,7 +22,7 @@ export default {
},
output: {
type: Object,
- requred: true,
+ required: true,
default: () => ({}),
},
},
diff --git a/app/assets/javascripts/notebook/cells/prompt.vue b/app/assets/javascripts/notebook/cells/prompt.vue
index d96f701ee3e..3f1f239a806 100644
--- a/app/assets/javascripts/notebook/cells/prompt.vue
+++ b/app/assets/javascripts/notebook/cells/prompt.vue
@@ -22,9 +22,7 @@ export default {
<template>
<div class="prompt">
- <span v-if="hasKeys">
- {{ type }} [{{ count }}]:
- </span>
+ <span v-if="hasKeys"> {{ type }} [{{ count }}]: </span>
</div>
</template>
diff --git a/app/assets/javascripts/notebook/index.vue b/app/assets/javascripts/notebook/index.vue
index c5cc8c97dda..6a54d0b3823 100644
--- a/app/assets/javascripts/notebook/index.vue
+++ b/app/assets/javascripts/notebook/index.vue
@@ -52,7 +52,8 @@ export default {
v-for="(cell, index) in cells"
:key="index"
:cell="cell"
- :code-css-class="codeCssClass" />
+ :code-css-class="codeCssClass"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index 90fe339e3de..dfb53c986fc 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -16,7 +16,7 @@ import 'vendor/jquery.atwho';
import AjaxCache from '~/lib/utils/ajax_cache';
import Vue from 'vue';
import syntaxHighlight from '~/syntax_highlight';
-import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui';
+import { GlSkeletonLoading } from '@gitlab/ui';
import axios from './lib/utils/axios_utils';
import { getLocationHash } from './lib/utils/url_utility';
import Flash from './flash';
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 10e80883c00..ce56beb1e6b 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -4,6 +4,7 @@ import { mapActions, mapGetters, mapState } from 'vuex';
import _ from 'underscore';
import Autosize from 'autosize';
import { __, sprintf } from '~/locale';
+import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import Flash from '../../flash';
import Autosave from '../../autosave';
import {
@@ -30,6 +31,7 @@ export default {
markdownField,
userAvatarLink,
loadingButton,
+ TimelineEntryItem,
},
mixins: [issuableStateMixin],
props: {
@@ -245,15 +247,19 @@ Please check your network connection and try again.`;
} else {
this.reopenIssue()
.then(() => this.enableButton())
- .catch(() => {
+ .catch(({ data }) => {
this.enableButton();
this.toggleStateButtonLoading(false);
- Flash(
- sprintf(
- __('Something went wrong while reopening the %{issuable}. Please try again later'),
- { issuable: this.noteableDisplayName },
- ),
+ let errorMessage = sprintf(
+ __('Something went wrong while reopening the %{issuable}. Please try again later'),
+ { issuable: this.noteableDisplayName },
);
+
+ if (data) {
+ errorMessage = Object.values(data).join('\n');
+ }
+
+ Flash(errorMessage);
});
}
},
@@ -308,152 +314,136 @@ Please check your network connection and try again.`;
<template>
<div>
<note-signed-out-widget v-if="!isLoggedIn" />
- <discussion-locked-widget
- v-else-if="!canCreateNote"
- :issuable-type="issuableTypeTitle"
- />
- <div
- v-else-if="canCreateNote"
- class="notes notes-form timeline">
- <div class="timeline-entry note-form">
- <div class="timeline-entry-inner">
- <div class="flash-container error-alert timeline-content"></div>
- <div class="timeline-icon d-none d-sm-none d-md-block">
- <user-avatar-link
- v-if="author"
- :link-href="author.path"
- :img-src="author.avatar_url"
- :img-alt="author.name"
- :img-size="40"
- />
- </div>
- <div class="timeline-content timeline-content-form">
- <form
- ref="commentForm"
- class="new-note common-note-form gfm-form js-main-target-form"
- >
-
- <div class="error-alert"></div>
+ <discussion-locked-widget v-else-if="!canCreateNote" :issuable-type="issuableTypeTitle" />
+ <ul v-else-if="canCreateNote" class="notes notes-form timeline">
+ <timeline-entry-item class="note-form">
+ <div class="flash-container error-alert timeline-content"></div>
+ <div class="timeline-icon d-none d-sm-none d-md-block">
+ <user-avatar-link
+ v-if="author"
+ :link-href="author.path"
+ :img-src="author.avatar_url"
+ :img-alt="author.name"
+ :img-size="40"
+ />
+ </div>
+ <div class="timeline-content timeline-content-form">
+ <form ref="commentForm" class="new-note common-note-form gfm-form js-main-target-form">
+ <div class="error-alert"></div>
- <issue-warning
- v-if="hasWarning(getNoteableData)"
- :is-locked="isLocked(getNoteableData)"
- :is-confidential="isConfidential(getNoteableData)"
- />
+ <issue-warning
+ v-if="hasWarning(getNoteableData)"
+ :is-locked="isLocked(getNoteableData)"
+ :is-confidential="isConfidential(getNoteableData)"
+ />
- <markdown-field
- ref="markdownField"
- :markdown-preview-path="markdownPreviewPath"
- :markdown-docs-path="markdownDocsPath"
- :quick-actions-docs-path="quickActionsDocsPath"
- :markdown-version="markdownVersion"
- :add-spacing-classes="false">
- <textarea
- id="note-body"
- ref="textarea"
- slot="textarea"
- v-model="note"
- :disabled="isSubmitting"
- name="note[note]"
- class="note-textarea js-vue-comment-form js-note-text
+ <markdown-field
+ ref="markdownField"
+ :markdown-preview-path="markdownPreviewPath"
+ :markdown-docs-path="markdownDocsPath"
+ :quick-actions-docs-path="quickActionsDocsPath"
+ :markdown-version="markdownVersion"
+ :add-spacing-classes="false"
+ >
+ <textarea
+ id="note-body"
+ ref="textarea"
+ slot="textarea"
+ v-model="note"
+ :disabled="isSubmitting"
+ name="note[note]"
+ class="note-textarea js-vue-comment-form js-note-text
js-gfm-input js-autosize markdown-area js-vue-textarea qa-comment-input"
- data-supports-quick-actions="true"
- aria-label="Description"
- placeholder="Write a comment or drag your files here…"
- @keydown.up="editCurrentUserLastNote()"
- @keydown.meta.enter="handleSave()"
- @keydown.ctrl.enter="handleSave()">
- </textarea>
- </markdown-field>
- <div class="note-form-actions">
- <div
- class="float-left btn-group
-append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown">
- <button
- :disabled="isSubmitButtonDisabled"
- class="btn btn-create comment-btn js-comment-button js-comment-submit-button
+ data-supports-quick-actions="true"
+ aria-label="Description"
+ placeholder="Write a comment or drag your files here…"
+ @keydown.up="editCurrentUserLastNote();"
+ @keydown.meta.enter="handleSave();"
+ @keydown.ctrl.enter="handleSave();"
+ >
+ </textarea>
+ </markdown-field>
+ <div class="note-form-actions">
+ <div
+ class="float-left btn-group
+append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
+ >
+ <button
+ :disabled="isSubmitButtonDisabled"
+ class="btn btn-create comment-btn js-comment-button js-comment-submit-button
qa-comment-button"
- type="submit"
- @click.prevent="handleSave()">
- {{ __(commentButtonTitle) }}
- </button>
- <button
- :disabled="isSubmitButtonDisabled"
- name="button"
- type="button"
- class="btn comment-btn note-type-toggle js-note-new-discussion dropdown-toggle qa-note-dropdown"
- data-display="static"
- data-toggle="dropdown"
- aria-label="Open comment type dropdown">
- <i
- aria-hidden="true"
- class="fa fa-caret-down toggle-icon">
- </i>
- </button>
-
- <ul class="note-type-dropdown dropdown-open-top dropdown-menu">
- <li :class="{ 'droplab-item-selected': noteType === 'comment' }">
- <button
- type="button"
- class="btn btn-transparent"
- @click.prevent="setNoteType('comment')">
- <i
- aria-hidden="true"
- class="fa fa-check icon">
- </i>
- <div class="description">
- <strong>Comment</strong>
- <p>
- Add a general comment to this {{ noteableDisplayName }}.
- </p>
- </div>
- </button>
- </li>
- <li class="divider droplab-item-ignore"></li>
- <li :class="{ 'droplab-item-selected': noteType === 'discussion' }">
- <button
- type="button"
- class="btn btn-transparent qa-discussion-option"
- @click.prevent="setNoteType('discussion')">
- <i
- aria-hidden="true"
- class="fa fa-check icon">
- </i>
- <div class="description">
- <strong>Start discussion</strong>
- <p>
- {{ startDiscussionDescription }}
- </p>
- </div>
- </button>
- </li>
- </ul>
- </div>
-
- <loading-button
- v-if="canUpdateIssue"
- :loading="isToggleStateButtonLoading"
- :container-class="[
- actionButtonClassNames,
- 'btn btn-comment btn-comment-and-close js-action-button'
- ]"
- :disabled="isToggleStateButtonLoading || isSubmitting"
- :label="issueActionButtonTitle"
- @click="handleSave(true)"
- />
-
+ type="submit"
+ @click.prevent="handleSave();"
+ >
+ {{ __(commentButtonTitle) }}
+ </button>
<button
- v-if="note.length"
+ :disabled="isSubmitButtonDisabled"
+ name="button"
type="button"
- class="btn btn-cancel js-note-discard"
- @click="discard">
- Discard draft
+ class="btn comment-btn note-type-toggle js-note-new-discussion dropdown-toggle qa-note-dropdown"
+ data-display="static"
+ data-toggle="dropdown"
+ aria-label="Open comment type dropdown"
+ >
+ <i aria-hidden="true" class="fa fa-caret-down toggle-icon"> </i>
</button>
+
+ <ul class="note-type-dropdown dropdown-open-top dropdown-menu">
+ <li :class="{ 'droplab-item-selected': noteType === 'comment' }">
+ <button
+ type="button"
+ class="btn btn-transparent"
+ @click.prevent="setNoteType('comment');"
+ >
+ <i aria-hidden="true" class="fa fa-check icon"> </i>
+ <div class="description">
+ <strong>Comment</strong>
+ <p>Add a general comment to this {{ noteableDisplayName }}.</p>
+ </div>
+ </button>
+ </li>
+ <li class="divider droplab-item-ignore"></li>
+ <li :class="{ 'droplab-item-selected': noteType === 'discussion' }">
+ <button
+ type="button"
+ class="btn btn-transparent qa-discussion-option"
+ @click.prevent="setNoteType('discussion');"
+ >
+ <i aria-hidden="true" class="fa fa-check icon"> </i>
+ <div class="description">
+ <strong>Start discussion</strong>
+ <p>{{ startDiscussionDescription }}</p>
+ </div>
+ </button>
+ </li>
+ </ul>
</div>
- </form>
- </div>
+
+ <loading-button
+ v-if="canUpdateIssue"
+ :loading="isToggleStateButtonLoading"
+ :container-class="[
+ actionButtonClassNames,
+ 'btn btn-comment btn-comment-and-close js-action-button',
+ ]"
+ :disabled="isToggleStateButtonLoading || isSubmitting"
+ :label="issueActionButtonTitle"
+ @click="handleSave(true);"
+ />
+
+ <button
+ v-if="note.length"
+ type="button"
+ class="btn btn-cancel js-note-discard"
+ @click="discard"
+ >
+ Discard draft
+ </button>
+ </div>
+ </form>
</div>
- </div>
- </div>
+ </timeline-entry-item>
+ </ul>
</div>
</template>
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index 080161dfbba..af821df0fd2 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -3,8 +3,10 @@ import { mapState, mapActions } from 'vuex';
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
import ImageDiffOverlay from '~/diffs/components/image_diff_overlay.vue';
-import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui';
-import { trimFirstCharOfLineContent, getDiffMode } from '~/diffs/store/utils';
+import { GlSkeletonLoading } from '@gitlab/ui';
+import { getDiffMode } from '~/diffs/store/utils';
+
+const FIRST_CHAR_REGEX = /^(\+|-| )/;
export default {
components: {
@@ -26,46 +28,16 @@ export default {
},
computed: {
...mapState({
- noteableData: state => state.notes.noteableData,
projectPath: state => state.diffs.projectPath,
}),
diffMode() {
- return getDiffMode(this.diffFile);
+ return getDiffMode(this.discussion.diff_file);
},
hasTruncatedDiffLines() {
return (
this.discussion.truncated_diff_lines && this.discussion.truncated_diff_lines.length !== 0
);
},
- isDiscussionsExpanded() {
- return true; // TODO: @fatihacet - Fix this.
- },
- isCollapsed() {
- return this.diffFile.collapsed || false;
- },
- isImageDiff() {
- return !this.diffFile.text;
- },
- diffFileClass() {
- const { text } = this.diffFile;
- return text ? 'text-file' : 'js-image-file';
- },
- diffFile() {
- return this.discussion.diff_file;
- },
- imageDiffHtml() {
- return this.discussion.image_diff_html;
- },
- userColorScheme() {
- return window.gon.user_color_scheme;
- },
- normalizedDiffLines() {
- if (this.discussion.truncated_diff_lines) {
- return this.discussion.truncated_diff_lines.map(line => trimFirstCharOfLineContent(line));
- }
-
- return [];
- },
},
mounted() {
if (!this.hasTruncatedDiffLines) {
@@ -74,9 +46,6 @@ export default {
},
methods: {
...mapActions(['fetchDiscussionDiffLines']),
- rowTag(html) {
- return html.outerHTML ? 'tr' : 'template';
- },
fetchDiff() {
this.error = false;
this.fetchDiscussionDiffLines(this.discussion)
@@ -85,54 +54,45 @@ export default {
this.error = true;
});
},
+ trimChar(line) {
+ return line.replace(FIRST_CHAR_REGEX, '');
+ },
},
+ userColorSchemeClass: window.gon.user_color_scheme,
};
</script>
<template>
- <div
- ref="fileHolder"
- :class="diffFileClass"
- class="diff-file file-holder"
- >
+ <div :class="{ 'text-file': discussion.diff_file.text }" class="diff-file file-holder">
<diff-file-header
:discussion-path="discussion.discussion_path"
- :diff-file="diffFile"
+ :diff-file="discussion.diff_file"
:can-current-user-fork="false"
- :discussions-expanded="isDiscussionsExpanded"
- :expanded="!isCollapsed"
+ :expanded="!discussion.diff_file.collapsed"
/>
<div
- v-if="diffFile.text"
- :class="userColorScheme"
+ v-if="discussion.diff_file.text"
+ :class="$options.userColorSchemeClass"
class="diff-content code"
>
<table>
- <tr
- v-for="line in normalizedDiffLines"
- :key="line.line_code"
- class="line_holder"
- >
- <td class="diff-line-num old_line">{{ line.old_line }}</td>
- <td class="diff-line-num new_line">{{ line.new_line }}</td>
- <td
- :class="line.type"
- class="line_content"
- v-html="line.rich_text"
+ <template v-if="hasTruncatedDiffLines">
+ <tr
+ v-for="line in discussion.truncated_diff_lines"
+ v-once
+ :key="line.line_code"
+ class="line_holder"
>
- </td>
- </tr>
- <tr
- v-if="!hasTruncatedDiffLines"
- class="line_holder line-holder-placeholder"
- >
+ <td class="diff-line-num old_line">{{ line.old_line }}</td>
+ <td class="diff-line-num new_line">{{ line.new_line }}</td>
+ <td :class="line.type" class="line_content" v-html="trimChar(line.rich_text)"></td>
+ </tr>
+ </template>
+ <tr v-if="!hasTruncatedDiffLines" class="line_holder line-holder-placeholder">
<td class="old_line diff-line-num"></td>
<td class="new_line diff-line-num"></td>
- <td
- v-if="error"
- class="js-error-lazy-load-diff diff-loading-error-block"
- >
- Unable to load the diff
+ <td v-if="error" class="js-error-lazy-load-diff diff-loading-error-block">
+ {{ error }} Unable to load the diff
<button
class="btn-link btn-link-retry btn-no-padding js-toggle-lazy-diff-retry-button"
@click="fetchDiff"
@@ -140,41 +100,31 @@ export default {
Try again
</button>
</td>
- <td
- v-else
- class="line_content js-success-lazy-load"
- >
+ <td v-else class="line_content js-success-lazy-load">
<span></span>
<gl-skeleton-loading />
<span></span>
</td>
</tr>
<tr class="notes_holder">
- <td
- class="notes_content"
- colspan="3"
- >
- <slot></slot>
- </td>
+ <td class="notes_content" colspan="3"><slot></slot></td>
</tr>
</table>
</div>
- <div
- v-else
- >
+ <div v-else>
<diff-viewer
:diff-mode="diffMode"
- :new-path="diffFile.new_path"
- :new-sha="diffFile.diff_refs.head_sha"
- :old-path="diffFile.old_path"
- :old-sha="diffFile.diff_refs.base_sha"
- :file-hash="diffFile.file_hash"
+ :new-path="discussion.diff_file.new_path"
+ :new-sha="discussion.diff_file.diff_refs.head_sha"
+ :old-path="discussion.diff_file.old_path"
+ :old-sha="discussion.diff_file.diff_refs.base_sha"
+ :file-hash="discussion.diff_file.file_hash"
:project-path="projectPath"
>
<image-diff-overlay
slot="image-overlay"
:discussions="discussion"
- :file-hash="diffFile.file_hash"
+ :file-hash="discussion.diff_file.file_hash"
:show-comment-icon="true"
:should-toggle-discussion="false"
badge-class="image-comment-badge"
diff --git a/app/assets/javascripts/notes/components/discussion_counter.vue b/app/assets/javascripts/notes/components/discussion_counter.vue
index a4d76a70696..c7cfc0f0f3b 100644
--- a/app/assets/javascripts/notes/components/discussion_counter.vue
+++ b/app/assets/javascripts/notes/components/discussion_counter.vue
@@ -1,13 +1,12 @@
<script>
import { mapActions, mapGetters } from 'vuex';
+import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
-import { pluralize } from '../../lib/utils/text_utility';
import discussionNavigation from '../mixins/discussion_navigation';
-import tooltip from '../../vue_shared/directives/tooltip';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
Icon,
@@ -17,9 +16,9 @@ export default {
...mapGetters([
'getUserData',
'getNoteableData',
- 'discussionCount',
+ 'resolvableDiscussionsCount',
'firstUnresolvedDiscussionId',
- 'resolvedDiscussionCount',
+ 'unresolvedDiscussionsCount',
]),
isLoggedIn() {
return this.getUserData.id;
@@ -27,15 +26,15 @@ export default {
hasNextButton() {
return this.isLoggedIn && !this.allResolved;
},
- countText() {
- return pluralize('discussion', this.discussionCount);
- },
allResolved() {
- return this.resolvedDiscussionCount === this.discussionCount;
+ return this.unresolvedDiscussionsCount === 0;
},
resolveAllDiscussionsIssuePath() {
return this.getNoteableData.create_issue_to_resolve_discussions_path;
},
+ resolvedDiscussionsCount() {
+ return this.resolvableDiscussionsCount - this.unresolvedDiscussionsCount;
+ },
},
methods: {
...mapActions(['expandDiscussion']),
@@ -50,13 +49,9 @@ export default {
</script>
<template>
- <div
- v-if="discussionCount > 0"
- class="line-resolve-all-container prepend-top-8">
+ <div v-if="resolvableDiscussionsCount > 0" class="line-resolve-all-container prepend-top-8">
<div>
- <div
- :class="{ 'has-next-btn': hasNextButton }"
- class="line-resolve-all">
+ <div :class="{ 'has-next-btn': hasNextButton }" class="line-resolve-all">
<span
:class="{ 'is-active': allResolved }"
class="line-resolve-btn is-disabled"
@@ -65,32 +60,27 @@ export default {
<icon name="check-circle" />
</span>
<span class="line-resolve-text">
- {{ resolvedDiscussionCount }}/{{ discussionCount }} {{ countText }} resolved
+ {{ resolvedDiscussionsCount }}/{{ resolvableDiscussionsCount }}
+ {{ n__('discussion resolved', 'discussions resolved', resolvableDiscussionsCount) }}
</span>
</div>
- <div
- v-if="resolveAllDiscussionsIssuePath && !allResolved"
- class="btn-group"
- role="group">
+ <div v-if="resolveAllDiscussionsIssuePath && !allResolved" class="btn-group" role="group">
<a
- v-tooltip
+ v-gl-tooltip
:href="resolveAllDiscussionsIssuePath"
:title="s__('Resolve all discussions in new issue')"
- data-container="body"
- class="new-issue-for-discussion btn btn-default discussion-create-issue-btn">
+ class="new-issue-for-discussion btn btn-default discussion-create-issue-btn"
+ >
<icon name="issue-new" />
</a>
</div>
- <div
- v-if="isLoggedIn && !allResolved"
- class="btn-group"
- role="group">
+ <div v-if="isLoggedIn && !allResolved" class="btn-group" role="group">
<button
- v-tooltip
+ v-gl-tooltip
title="Jump to first unresolved discussion"
- data-container="body"
class="btn btn-default discussion-next-btn"
- @click="jumpToFirstUnresolvedDiscussion">
+ @click="jumpToFirstUnresolvedDiscussion"
+ >
<icon name="comment-next" />
</button>
</div>
diff --git a/app/assets/javascripts/notes/components/discussion_filter.vue b/app/assets/javascripts/notes/components/discussion_filter.vue
index affa2d1b574..86c114a761a 100644
--- a/app/assets/javascripts/notes/components/discussion_filter.vue
+++ b/app/assets/javascripts/notes/components/discussion_filter.vue
@@ -64,30 +64,24 @@ export default {
data-toggle="dropdown"
aria-expanded="false"
>
- {{ currentFilter.title }}
- <icon name="chevron-down" />
+ {{ currentFilter.title }} <icon name="chevron-down" />
</button>
<div
class="dropdown-menu dropdown-menu-selectable dropdown-menu-right"
- aria-labelledby="discussion-filter-dropdown">
+ aria-labelledby="discussion-filter-dropdown"
+ >
<div class="dropdown-content">
<ul>
- <li
- v-for="filter in filters"
- :key="filter.value"
- >
+ <li v-for="filter in filters" :key="filter.value">
<button
:class="{ 'is-active': filter.value === currentValue }"
class="qa-filter-options"
type="button"
- @click="selectFilter(filter.value)"
+ @click="selectFilter(filter.value);"
>
{{ filter.title }}
</button>
- <div
- v-if="filter.value === defaultValue"
- class="dropdown-divider"
- ></div>
+ <div v-if="filter.value === defaultValue" class="dropdown-divider"></div>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/notes/components/discussion_locked_widget.vue b/app/assets/javascripts/notes/components/discussion_locked_widget.vue
index de0a5f8489b..c469a6b7bcd 100644
--- a/app/assets/javascripts/notes/components/discussion_locked_widget.vue
+++ b/app/assets/javascripts/notes/components/discussion_locked_widget.vue
@@ -13,11 +13,7 @@ export default {
<template>
<div class="disabled-comment text-center">
<span class="issuable-note-warning inline">
- <icon
- :size="16"
- name="lock"
- class="icon"
- />
+ <icon :size="16" name="lock" class="icon" />
<span>
This {{ issuableDisplayName }} is locked. Only <b>project members</b> can comment.
</span>
diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue
index f7a61fbfcd4..d99694b06e9 100644
--- a/app/assets/javascripts/notes/components/note_actions.vue
+++ b/app/assets/javascripts/notes/components/note_actions.vue
@@ -1,8 +1,7 @@
<script>
import { mapGetters } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
-import tooltip from '~/vue_shared/directives/tooltip';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
export default {
name: 'NoteActions',
@@ -11,7 +10,7 @@ export default {
GlLoadingIcon,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
authorId: {
@@ -119,116 +118,76 @@ export default {
<template>
<div class="note-actions">
- <span
- v-if="accessLevel"
- class="note-role user-access-role">
- {{ accessLevel }}
- </span>
- <div
- v-if="canResolve"
- class="note-actions-item">
+ <span v-if="accessLevel" class="note-role user-access-role">{{ accessLevel }}</span>
+ <div v-if="canResolve" class="note-actions-item">
<button
- v-tooltip
+ v-gl-tooltip
:class="{ 'is-disabled': !resolvable, 'is-active': isResolved }"
:title="resolveButtonTitle"
:aria-label="resolveButtonTitle"
type="button"
class="line-resolve-btn note-action-button"
- @click="onResolve">
+ @click="onResolve"
+ >
<template v-if="!isResolving">
<icon name="check-circle" />
</template>
- <gl-loading-icon
- v-else
- inline
- />
+ <gl-loading-icon v-else inline />
</button>
</div>
- <div
- v-if="canAwardEmoji"
- class="note-actions-item">
+ <div v-if="canAwardEmoji" class="note-actions-item">
<a
- v-tooltip
+ v-gl-tooltip.bottom
:class="{ 'js-user-authored': isAuthoredByCurrentUser }"
class="note-action-button note-emoji-button js-add-award js-note-emoji"
data-position="right"
- data-placement="bottom"
- data-container="body"
href="#"
title="Add reaction"
>
- <gl-loading-icon inline/>
+ <gl-loading-icon inline />
<icon
css-classes="link-highlight award-control-icon-neutral"
name="emoji_slightly_smiling_face"
/>
- <icon
- css-classes="link-highlight award-control-icon-positive"
- name="emoji_smiley"
- />
- <icon
- css-classes="link-highlight award-control-icon-super-positive"
- name="emoji_smiley"
- />
+ <icon css-classes="link-highlight award-control-icon-positive" name="emoji_smiley" />
+ <icon css-classes="link-highlight award-control-icon-super-positive" name="emoji_smiley" />
</a>
</div>
- <div
- v-if="canEdit"
- class="note-actions-item">
+ <div v-if="canEdit" class="note-actions-item">
<button
- v-tooltip
+ v-gl-tooltip.bottom
type="button"
title="Edit comment"
class="note-action-button js-note-edit btn btn-transparent"
- data-container="body"
- data-placement="bottom"
- @click="onEdit">
- <icon
- name="pencil"
- css-classes="link-highlight"
- />
+ @click="onEdit"
+ >
+ <icon name="pencil" css-classes="link-highlight" />
</button>
</div>
- <div
- v-if="showDeleteAction"
- class="note-actions-item"
- >
+ <div v-if="showDeleteAction" class="note-actions-item">
<button
- v-tooltip
+ v-gl-tooltip.bottom
type="button"
title="Delete comment"
class="note-action-button js-note-delete btn btn-transparent"
- data-container="body"
- data-placement="bottom"
@click="onDelete"
>
- <icon
- name="remove"
- class="link-highlight"
- />
+ <icon name="remove" class="link-highlight" />
</button>
</div>
- <div
- v-else-if="shouldShowActionsDropdown"
- class="dropdown more-actions note-actions-item">
+ <div v-else-if="shouldShowActionsDropdown" class="dropdown more-actions note-actions-item">
<button
- v-tooltip
+ v-gl-tooltip.bottom
type="button"
title="More actions"
class="note-action-button more-actions-toggle btn btn-transparent"
data-toggle="dropdown"
- data-container="body"
- data-placement="bottom">
- <icon
- css-classes="icon"
- name="ellipsis_v"
- />
+ >
+ <icon css-classes="icon" name="ellipsis_v" />
</button>
<ul class="dropdown-menu more-actions-dropdown dropdown-open-left">
<li v-if="canReportAsAbuse">
- <a :href="reportAbusePath">
- {{ __('Report abuse to GitLab') }}
- </a>
+ <a :href="reportAbusePath">{{ __('Report abuse to GitLab') }}</a>
</li>
<li v-if="noteUrl">
<button
@@ -243,10 +202,9 @@ export default {
<button
class="btn btn-transparent js-note-delete js-note-delete"
type="button"
- @click.prevent="onDelete">
- <span class="text-danger">
- {{ __('Delete comment') }}
- </span>
+ @click.prevent="onDelete"
+ >
+ <span class="text-danger">{{ __('Delete comment') }}</span>
</button>
</li>
</ul>
diff --git a/app/assets/javascripts/notes/components/note_attachment.vue b/app/assets/javascripts/notes/components/note_attachment.vue
index 34ecbd00c63..b6d8c831e2e 100644
--- a/app/assets/javascripts/notes/components/note_attachment.vue
+++ b/app/assets/javascripts/notes/components/note_attachment.vue
@@ -12,27 +12,12 @@ export default {
<template>
<div class="note-attachment">
- <a
- v-if="attachment.image"
- :href="attachment.url"
- target="_blank"
- rel="noopener noreferrer">
- <img
- :src="attachment.url"
- class="note-image-attach"
- />
+ <a v-if="attachment.image" :href="attachment.url" target="_blank" rel="noopener noreferrer">
+ <img :src="attachment.url" class="note-image-attach" />
</a>
<div class="attachment">
- <a
- v-if="attachment.url"
- :href="attachment.url"
- target="_blank"
- rel="noopener noreferrer">
- <i
- class="fa fa-paperclip"
- aria-hidden="true">
- </i>
- {{ attachment.filename }}
+ <a v-if="attachment.url" :href="attachment.url" target="_blank" rel="noopener noreferrer">
+ <i class="fa fa-paperclip" aria-hidden="true"> </i> {{ attachment.filename }}
</a>
</div>
</div>
diff --git a/app/assets/javascripts/notes/components/note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue
index 401bcfabbe4..3d60eb02db8 100644
--- a/app/assets/javascripts/notes/components/note_awards_list.vue
+++ b/app/assets/javascripts/notes/components/note_awards_list.vue
@@ -1,16 +1,16 @@
<script>
import { mapActions, mapGetters } from 'vuex';
+import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import Flash from '../../flash';
import { glEmojiTag } from '../../emoji';
-import tooltip from '../../vue_shared/directives/tooltip';
export default {
components: {
Icon,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
awards: {
@@ -167,31 +167,27 @@ export default {
<button
v-for="(awardList, awardName, index) in groupedAwards"
:key="index"
- v-tooltip
+ v-gl-tooltip.bottom="{ boundary: 'viewport' }"
:class="getAwardClassBindings(awardList)"
:title="awardTitle(awardList)"
class="btn award-control"
- data-boundary="viewport"
- data-placement="bottom"
type="button"
- @click="handleAward(awardName)">
+ @click="handleAward(awardName);"
+ >
<span v-html="getAwardHTML(awardName)"></span>
- <span class="award-control-text js-counter">
- {{ awardList.length }}
- </span>
+ <span class="award-control-text js-counter">{{ awardList.length }}</span>
</button>
- <div
- v-if="canAwardEmoji"
- class="award-menu-holder">
+ <div v-if="canAwardEmoji" class="award-menu-holder">
<button
- v-tooltip
+ v-gl-tooltip
:class="{ 'js-user-authored': isAuthoredByMe }"
class="award-control btn js-add-award"
title="Add reaction"
aria-label="Add reaction"
data-boundary="viewport"
data-placement="bottom"
- type="button">
+ type="button"
+ >
<span class="award-control-icon award-control-icon-neutral">
<icon name="emoji_slightly_smiling_face" />
</span>
@@ -203,7 +199,8 @@ export default {
</span>
<i
aria-hidden="true"
- class="fa fa-spinner fa-spin award-control-icon award-control-icon-loading"></i>
+ class="fa fa-spinner fa-spin award-control-icon award-control-icon-loading"
+ ></i>
</button>
</div>
</div>
diff --git a/app/assets/javascripts/notes/components/note_body.vue b/app/assets/javascripts/notes/components/note_body.vue
index 9375627359c..c0bee600181 100644
--- a/app/assets/javascripts/notes/components/note_body.vue
+++ b/app/assets/javascripts/notes/components/note_body.vue
@@ -67,13 +67,8 @@ export default {
</script>
<template>
- <div
- ref="note-body"
- :class="{ 'js-task-list-container': canEdit }"
- class="note-body">
- <div
- class="note-text md"
- v-html="note.note_html"></div>
+ <div ref="note-body" :class="{ 'js-task-list-container': canEdit }" class="note-body">
+ <div class="note-text md" v-html="note.note_html"></div>
<note-form
v-if="isEditing"
ref="noteForm"
@@ -88,7 +83,8 @@ export default {
v-if="canEdit"
v-model="note.note"
:data-update-url="note.path"
- class="hidden js-task-list-field"></textarea>
+ class="hidden js-task-list-field"
+ ></textarea>
<note-edited-text
v-if="note.last_edited_at"
:edited-at="note.last_edited_at"
@@ -104,9 +100,6 @@ export default {
:toggle-award-path="note.toggle_award_path"
:can-award-emoji="note.current_user.can_award_emoji"
/>
- <note-attachment
- v-if="note.attachment"
- :attachment="note.attachment"
- />
+ <note-attachment v-if="note.attachment" :attachment="note.attachment" />
</div>
</template>
diff --git a/app/assets/javascripts/notes/components/note_edited_text.vue b/app/assets/javascripts/notes/components/note_edited_text.vue
index d848335022f..15ce49d7c31 100644
--- a/app/assets/javascripts/notes/components/note_edited_text.vue
+++ b/app/assets/javascripts/notes/components/note_edited_text.vue
@@ -40,16 +40,11 @@ export default {
{{ actionText }}
<template v-if="editedBy">
by
- <a
- :href="editedBy.path"
- class="js-vue-author author-link">
+ <a :href="editedBy.path" :data-user-id="editedBy.id" class="js-user-link author-link">
{{ editedBy.name }}
</a>
</template>
{{ actionDetailText }}
- <time-ago-tooltip
- :time="editedAt"
- tooltip-placement="bottom"
- />
+ <time-ago-tooltip :time="editedAt" tooltip-placement="bottom" />
</div>
</template>
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 31ee8fed984..95164183ccb 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -48,13 +48,19 @@ export default {
required: false,
default: '',
},
+ resolveDiscussion: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
updatedNoteBody: this.noteBody,
conflictWhileEditing: false,
isSubmitting: false,
- isResolving: false,
+ isResolving: this.resolveDiscussion,
+ isUnresolving: !this.resolveDiscussion,
resolveAsThread: true,
};
},
@@ -146,27 +152,14 @@ export default {
</script>
<template>
- <div
- ref="editNoteForm"
- class="note-edit-form current-note-edit-form js-discussion-note-form">
- <div
- v-if="conflictWhileEditing"
- class="js-conflict-edit-warning alert alert-danger">
+ <div ref="editNoteForm" class="note-edit-form current-note-edit-form js-discussion-note-form">
+ <div v-if="conflictWhileEditing" class="js-conflict-edit-warning alert alert-danger">
This comment has changed since you started editing, please review the
- <a
- :href="noteHash"
- target="_blank"
- rel="noopener noreferrer">
- updated comment
- </a>
- to ensure information is not lost.
+ <a :href="noteHash" target="_blank" rel="noopener noreferrer">updated comment</a> to ensure
+ information is not lost.
</div>
<div class="flash-container timeline-content"></div>
- <form
- :data-line-code="lineCode"
- class="edit-note common-note-form js-quick-submit gfm-form"
- >
-
+ <form :data-line-code="lineCode" class="edit-note common-note-form js-quick-submit gfm-form">
<issue-warning
v-if="hasWarning(getNoteableData)"
:is-locked="isLocked(getNoteableData)"
@@ -178,7 +171,8 @@ export default {
:markdown-docs-path="markdownDocsPath"
:markdown-version="markdownVersion"
:quick-actions-docs-path="quickActionsDocsPath"
- :add-spacing-classes="false">
+ :add-spacing-classes="false"
+ >
<textarea
id="note_note"
ref="textarea"
@@ -186,35 +180,36 @@ export default {
v-model="updatedNoteBody"
:data-supports-quick-actions="!isEditing"
name="note[note]"
- class="note-textarea js-gfm-input js-note-text
-js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input"
+ class="note-textarea js-gfm-input js-note-text js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input"
aria-label="Description"
placeholder="Write a comment or drag your files here…"
- @keydown.meta.enter="handleUpdate()"
- @keydown.ctrl.enter="handleUpdate()"
- @keydown.up="editMyLastNote()"
- @keydown.esc="cancelHandler(true)">
- </textarea>
+ @keydown.meta.enter="handleUpdate();"
+ @keydown.ctrl.enter="handleUpdate();"
+ @keydown.up="editMyLastNote();"
+ @keydown.esc="cancelHandler(true);"
+ ></textarea>
</markdown-field>
<div class="note-form-actions clearfix">
<button
:disabled="isDisabled"
type="button"
- class="js-vue-issue-save btn btn-success js-comment-button "
- @click="handleUpdate()">
+ class="js-vue-issue-save btn btn-success js-comment-button"
+ @click="handleUpdate();"
+ >
{{ saveButtonTitle }}
</button>
<button
v-if="discussion.resolvable"
class="btn btn-nr btn-default append-right-10 js-comment-resolve-button"
- @click.prevent="handleUpdate(true)"
+ @click.prevent="handleUpdate(true);"
>
{{ resolveButtonTitle }}
</button>
<button
class="btn btn-cancel note-edit-cancel js-close-discussion-note-form"
type="button"
- @click="cancelHandler()">
+ @click="cancelHandler();"
+ >
Cancel
</button>
</div>
diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue
index dd7313d7b10..7b39901024d 100644
--- a/app/assets/javascripts/notes/components/note_header.vue
+++ b/app/assets/javascripts/notes/components/note_header.vue
@@ -63,44 +63,33 @@ export default {
<template>
<div class="note-header-info">
- <div
- v-if="includeToggle"
- class="discussion-actions">
+ <div v-if="includeToggle" class="discussion-actions">
<button
class="note-action-button discussion-toggle-button js-vue-toggle-button"
type="button"
- @click="handleToggle">
- <i
- :class="toggleChevronClass"
- class="fa"
- aria-hidden="true">
- </i>
+ @click="handleToggle"
+ >
+ <i :class="toggleChevronClass" class="fa" aria-hidden="true"> </i>
{{ __('Toggle discussion') }}
</button>
</div>
<a
v-if="hasAuthor"
+ v-once
:href="author.path"
+ class="js-user-link"
+ :data-user-id="author.id"
+ :data-username="author.username"
>
<span class="note-header-author-name">{{ author.name }}</span>
- <span
- v-if="author.status_tooltip_html"
- v-html="author.status_tooltip_html"></span>
- <span class="note-headline-light">
- @{{ author.username }}
- </span>
+ <span v-if="author.status_tooltip_html" v-html="author.status_tooltip_html"></span>
+ <span class="note-headline-light"> @{{ author.username }} </span>
</a>
- <span v-else>
- {{ __('A deleted user') }}
- </span>
+ <span v-else> {{ __('A deleted user') }} </span>
<span class="note-headline-light">
<span class="note-headline-meta">
- <span class="system-note-message">
- <slot></slot>
- </span>
- <template
- v-if="createdAt"
- >
+ <span class="system-note-message"> <slot></slot> </span>
+ <template v-if="createdAt">
<span class="system-note-separator">
<template v-if="actionText">
{{ actionText }}
@@ -109,11 +98,9 @@ export default {
<a
:href="noteTimestampLink"
class="note-timestamp system-note-separator"
- @click="updateTargetNoteHash">
- <time-ago-tooltip
- :time="createdAt"
- tooltip-placement="bottom"
- />
+ @click="updateTargetNoteHash"
+ >
+ <time-ago-tooltip :time="createdAt" tooltip-placement="bottom" />
</a>
</template>
<i
diff --git a/app/assets/javascripts/notes/components/note_signed_out_widget.vue b/app/assets/javascripts/notes/components/note_signed_out_widget.vue
index 91f7c269757..e3eb92956b1 100644
--- a/app/assets/javascripts/notes/components/note_signed_out_widget.vue
+++ b/app/assets/javascripts/notes/components/note_signed_out_widget.vue
@@ -16,10 +16,6 @@ export default {
<template>
<div class="disabled-comment text-center">
- Please
- <a :href="registerLink">register</a>
- or
- <a :href="signInLink">sign in</a>
- to reply
+ Please <a :href="registerLink">register</a> or <a :href="signInLink">sign in</a> to reply
</div>
</template>
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index 7740967ccd5..5c9a28b8512 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -1,9 +1,12 @@
<script>
+import _ from 'underscore';
import { mapActions, mapGetters } from 'vuex';
+import { GlTooltipDirective } from '@gitlab/ui';
import { truncateSha } from '~/lib/utils/text_utility';
-import { s__ } from '~/locale';
+import { s__, __, sprintf } from '~/locale';
import systemNote from '~/vue_shared/components/notes/system_note.vue';
import icon from '~/vue_shared/components/icon.vue';
+import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import Flash from '../../flash';
import { SYSTEM_NOTE } from '../constants';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
@@ -20,14 +23,12 @@ import autosave from '../mixins/autosave';
import noteable from '../mixins/noteable';
import resolvable from '../mixins/resolvable';
import discussionNavigation from '../mixins/discussion_navigation';
-import tooltip from '../../vue_shared/directives/tooltip';
export default {
name: 'NoteableDiscussion',
components: {
icon,
noteableNote,
- diffWithNote,
userAvatarLink,
noteHeader,
noteSignedOutWidget,
@@ -37,9 +38,10 @@ export default {
placeholderNote,
placeholderSystemNote,
systemNote,
+ TimelineEntryItem,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
mixins: [autosave, noteable, resolvable, discussionNavigation],
props: {
@@ -64,43 +66,25 @@ export default {
},
},
data() {
+ const { diff_discussion: isDiffDiscussion, resolved } = this.discussion;
+
return {
isReplying: false,
isResolving: false,
resolveAsThread: true,
- isRepliesCollapsed: (!this.discussion.diff_discussion && this.discussion.resolved) || false,
+ isRepliesCollapsed: Boolean(!isDiffDiscussion && resolved),
};
},
computed: {
...mapGetters([
'getNoteableData',
- 'discussionCount',
- 'resolvedDiscussionCount',
- 'allDiscussions',
- 'unresolvedDiscussionsIdsByDiff',
- 'unresolvedDiscussionsIdsByDate',
- 'unresolvedDiscussions',
- 'unresolvedDiscussionsIdsOrdered',
'nextUnresolvedDiscussionId',
- 'isLastUnresolvedDiscussion',
+ 'unresolvedDiscussionsCount',
+ 'hasUnresolvedDiscussions',
+ 'showJumpToNextDiscussion',
]),
- transformedDiscussion() {
- return {
- ...this.discussion.notes[0],
- truncated_diff_lines: this.discussion.truncated_diff_lines || [],
- truncated_diff_lines_path: this.discussion.truncated_diff_lines_path,
- diff_file: this.discussion.diff_file,
- diff_discussion: this.discussion.diff_discussion,
- active: this.discussion.active,
- discussion_path: this.discussion.discussion_path,
- resolved: this.discussion.resolved,
- resolved_by: this.discussion.resolved_by,
- resolved_by_push: this.discussion.resolved_by_push,
- resolved_at: this.discussion.resolved_at,
- };
- },
author() {
- return this.transformedDiscussion.author;
+ return this.initialDiscussion.author;
},
canReply() {
return this.getNoteableData.current_user.can_create_note;
@@ -136,29 +120,19 @@ export default {
return null;
},
resolvedText() {
- return this.transformedDiscussion.resolved_by_push ? 'Automatically resolved' : 'Resolved';
+ return this.discussion.resolved_by_push ? __('Automatically resolved') : __('Resolved');
},
- hasMultipleUnresolvedDiscussions() {
- return this.unresolvedDiscussions.length > 1;
- },
- showJumpToNextDiscussion() {
- return (
- this.hasMultipleUnresolvedDiscussions &&
- !this.isLastUnresolvedDiscussion(this.discussion.id, this.discussionsByDiffOrder)
+ shouldShowJumpToNextDiscussion() {
+ return this.showJumpToNextDiscussion(
+ this.discussion.id,
+ this.discussionsByDiffOrder ? 'diff' : 'discussion',
);
},
shouldRenderDiffs() {
- return (
- this.transformedDiscussion.diff_discussion &&
- this.transformedDiscussion.diff_file &&
- this.renderDiffFile
- );
+ return this.discussion.diff_discussion && this.renderDiffFile;
},
shouldGroupReplies() {
- return !this.shouldRenderDiffs && !this.transformedDiscussion.diff_discussion;
- },
- shouldRenderHeader() {
- return this.shouldRenderDiffs;
+ return !this.shouldRenderDiffs && !this.discussion.diff_discussion;
},
wrapperComponent() {
return this.shouldRenderDiffs ? diffWithNote : 'div';
@@ -170,9 +144,6 @@ export default {
return {};
},
- wrapperClass() {
- return this.isDiffDiscussion ? '' : 'card discussion-wrapper';
- },
componentClassName() {
if (this.shouldRenderDiffs) {
if (!this.lastUpdatedAt && !this.discussion.resolved) {
@@ -183,11 +154,45 @@ export default {
return '';
},
shouldShowDiscussions() {
- const isExpanded = this.discussion.expanded;
- const { resolved } = this.transformedDiscussion;
- const isResolvedNonDiffDiscussion = !this.transformedDiscussion.diff_discussion && resolved;
+ const { expanded, resolved } = this.discussion;
+ const isResolvedNonDiffDiscussion = !this.discussion.diff_discussion && resolved;
+
+ return expanded || this.alwaysExpanded || isResolvedNonDiffDiscussion;
+ },
+ actionText() {
+ const linkStart = `<a href="${_.escape(this.discussion.discussion_path)}">`;
+ const linkEnd = '</a>';
+
+ let { commit_id: commitId } = this.discussion;
+ if (commitId) {
+ commitId = `<span class="commit-sha">${truncateSha(commitId)}</span>`;
+ }
- return isExpanded || this.alwaysExpanded || isResolvedNonDiffDiscussion;
+ let text = s__('MergeRequests|started a discussion');
+
+ if (this.discussion.for_commit) {
+ text = s__(
+ 'MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}',
+ );
+ } else if (this.discussion.diff_discussion) {
+ if (this.discussion.active) {
+ text = s__('MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}');
+ } else {
+ text = s__(
+ 'MergeRequests|started a discussion on %{linkStart}an old version of the diff%{linkEnd}',
+ );
+ }
+ }
+
+ return sprintf(
+ text,
+ {
+ commitId,
+ linkStart,
+ linkEnd,
+ },
+ false,
+ );
},
},
watch: {
@@ -195,7 +200,7 @@ export default {
if (this.isReplying) {
this.$nextTick(() => {
// Pass an extra key to separate reply and note edit forms
- this.initAutoSave(this.transformedDiscussion, ['Reply']);
+ this.initAutoSave({ ...this.initialDiscussion, ...this.discussion }, ['Reply']);
});
} else {
this.disposeAutoSave();
@@ -302,210 +307,156 @@ Please check your network connection and try again.`;
</script>
<template>
- <li
- class="note note-discussion timeline-entry"
- :class="componentClassName"
- >
- <div class="timeline-entry-inner">
- <div class="timeline-content">
- <div
- :data-discussion-id="transformedDiscussion.discussion_id"
- class="discussion js-discussion-container"
- >
- <div
- v-if="shouldRenderHeader"
- class="discussion-header note-wrapper"
- >
- <div class="timeline-icon">
- <user-avatar-link
- v-if="author"
- :link-href="author.path"
- :img-src="author.avatar_url"
- :img-alt="author.name"
- :img-size="40"
- />
- </div>
- <note-header
- :author="author"
- :created-at="transformedDiscussion.created_at"
- :note-id="transformedDiscussion.id"
- :include-toggle="true"
- :expanded="discussion.expanded"
- @toggleHandler="toggleDiscussionHandler"
- >
- <template v-if="transformedDiscussion.diff_discussion">
- started a discussion on
- <a :href="transformedDiscussion.discussion_path">
- <template v-if="transformedDiscussion.active">
- the diff
- </template>
- <template v-else>
- an old version of the diff
- </template>
- </a>
- </template>
- <template v-else-if="discussion.for_commit">
- started a discussion on commit
- <a :href="discussion.discussion_path">
- {{ truncateSha(discussion.commit_id) }}
- </a>
- </template>
- <template v-else>
- started a discussion
- </template>
- </note-header>
- <note-edited-text
- v-if="transformedDiscussion.resolved"
- :edited-at="transformedDiscussion.resolved_at"
- :edited-by="transformedDiscussion.resolved_by"
- :action-text="resolvedText"
- class-name="discussion-headline-light js-discussion-headline"
- />
- <note-edited-text
- v-else-if="lastUpdatedAt"
- :edited-at="lastUpdatedAt"
- :edited-by="lastUpdatedBy"
- action-text="Last updated"
- class-name="discussion-headline-light js-discussion-headline"
+ <timeline-entry-item class="note note-discussion" :class="componentClassName">
+ <div class="timeline-content">
+ <div :data-discussion-id="discussion.id" class="discussion js-discussion-container">
+ <div v-if="shouldRenderDiffs" class="discussion-header note-wrapper">
+ <div v-once class="timeline-icon">
+ <user-avatar-link
+ v-if="author"
+ :link-href="author.path"
+ :img-src="author.avatar_url"
+ :img-alt="author.name"
+ :img-size="40"
/>
</div>
- <div
- v-if="shouldShowDiscussions"
- class="discussion-body">
- <component
- :is="wrapperComponent"
- v-bind="wrapperComponentProps"
- :class="wrapperClass"
- >
- <div class="discussion-notes">
- <ul class="notes">
- <template v-if="shouldGroupReplies">
- <component
- :is="componentName(initialDiscussion)"
- :note="componentData(initialDiscussion)"
- @handleDeleteNote="deleteNoteHandler"
- >
- <slot
- slot="avatar-badge"
- name="avatar-badge"
- >
- </slot>
- </component>
- <toggle-replies-widget
- v-if="hasReplies"
- :collapsed="isRepliesCollapsed"
- :replies="replies"
- @toggle="toggleReplies"
- />
- <template v-if="!isRepliesCollapsed">
- <component
- :is="componentName(note)"
- v-for="note in replies"
- :key="note.id"
- :note="componentData(note)"
- @handleDeleteNote="deleteNoteHandler"
- />
- </template>
- </template>
- <template v-else>
+ <note-header
+ :author="author"
+ :created-at="initialDiscussion.created_at"
+ :note-id="initialDiscussion.id"
+ :include-toggle="true"
+ :expanded="discussion.expanded"
+ @toggleHandler="toggleDiscussionHandler"
+ >
+ <span v-html="actionText"></span>
+ </note-header>
+ <note-edited-text
+ v-if="discussion.resolved"
+ :edited-at="discussion.resolved_at"
+ :edited-by="discussion.resolved_by"
+ :action-text="resolvedText"
+ class-name="discussion-headline-light js-discussion-headline"
+ />
+ <note-edited-text
+ v-else-if="lastUpdatedAt"
+ :edited-at="lastUpdatedAt"
+ :edited-by="lastUpdatedBy"
+ action-text="Last updated"
+ class-name="discussion-headline-light js-discussion-headline"
+ />
+ </div>
+ <div v-if="shouldShowDiscussions" class="discussion-body">
+ <component
+ :is="wrapperComponent"
+ v-bind="wrapperComponentProps"
+ class="card discussion-wrapper"
+ >
+ <div class="discussion-notes">
+ <ul class="notes">
+ <template v-if="shouldGroupReplies">
+ <component
+ :is="componentName(initialDiscussion)"
+ :note="componentData(initialDiscussion)"
+ @handleDeleteNote="deleteNoteHandler"
+ >
+ <slot slot="avatar-badge" name="avatar-badge"></slot>
+ </component>
+ <toggle-replies-widget
+ v-if="hasReplies"
+ :collapsed="isRepliesCollapsed"
+ :replies="replies"
+ @toggle="toggleReplies"
+ />
+ <template v-if="!isRepliesCollapsed">
<component
:is="componentName(note)"
- v-for="(note, index) in discussion.notes"
+ v-for="note in replies"
:key="note.id"
:note="componentData(note)"
@handleDeleteNote="deleteNoteHandler"
- >
- <slot
- v-if="index === 0"
- slot="avatar-badge"
- name="avatar-badge"
- >
- </slot>
- </component>
+ />
</template>
- </ul>
- <div
- v-if="!isRepliesCollapsed"
- :class="{ 'is-replying': isReplying }"
- class="discussion-reply-holder"
- >
- <template v-if="!isReplying && canReply">
- <div class="discussion-with-resolve-btn">
+ </template>
+ <template v-else>
+ <component
+ :is="componentName(note)"
+ v-for="(note, index) in discussion.notes"
+ :key="note.id"
+ :note="componentData(note)"
+ @handleDeleteNote="deleteNoteHandler"
+ >
+ <slot v-if="index === 0" slot="avatar-badge" name="avatar-badge"></slot>
+ </component>
+ </template>
+ </ul>
+ <div
+ v-if="!isRepliesCollapsed"
+ :class="{ 'is-replying': isReplying }"
+ class="discussion-reply-holder"
+ >
+ <template v-if="!isReplying && canReply">
+ <div class="discussion-with-resolve-btn">
+ <button
+ type="button"
+ class="js-vue-discussion-reply btn btn-text-field qa-discussion-reply"
+ title="Add a reply"
+ @click="showReplyForm"
+ >
+ Reply...
+ </button>
+ <div v-if="discussion.resolvable">
<button
type="button"
- class="js-vue-discussion-reply btn btn-text-field mr-sm-2 qa-discussion-reply"
- title="Add a reply"
- @click="showReplyForm"
+ class="btn btn-default ml-sm-2"
+ @click="resolveHandler();"
>
- Reply...
+ <i v-if="isResolving" aria-hidden="true" class="fa fa-spinner fa-spin"></i>
+ {{ resolveButtonTitle }}
</button>
- <div v-if="discussion.resolvable">
+ </div>
+ <div
+ v-if="discussion.resolvable"
+ class="btn-group discussion-actions ml-sm-2"
+ role="group"
+ >
+ <div v-if="!discussionResolved" class="btn-group" role="group">
+ <a
+ v-gl-tooltip
+ :href="discussion.resolve_with_issue_path"
+ :title="s__('MergeRequests|Resolve this discussion in a new issue')"
+ class="new-issue-for-discussion btn btn-default discussion-create-issue-btn"
+ >
+ <icon name="issue-new" />
+ </a>
+ </div>
+ <div v-if="shouldShowJumpToNextDiscussion" class="btn-group" role="group">
<button
- type="button"
- class="btn btn-default mr-sm-2"
- @click="resolveHandler()"
+ v-gl-tooltip
+ class="btn btn-default discussion-next-btn"
+ title="Jump to next unresolved discussion"
+ @click="jumpToNextDiscussion"
>
- <i
- v-if="isResolving"
- aria-hidden="true"
- class="fa fa-spinner fa-spin"
- ></i>
- {{ resolveButtonTitle }}
+ <icon name="comment-next" />
</button>
</div>
- <div
- v-if="discussion.resolvable"
- class="btn-group discussion-actions ml-sm-2"
- role="group"
- >
- <div
- v-if="!discussionResolved"
- class="btn-group"
- role="group">
- <a
- v-tooltip
- :href="discussion.resolve_with_issue_path"
- :title="s__('MergeRequests|Resolve this discussion in a new issue')"
- class="new-issue-for-discussion btn
- btn-default discussion-create-issue-btn"
- data-container="body"
- >
- <icon name="issue-new" />
- </a>
- </div>
- <div
- v-if="showJumpToNextDiscussion"
- class="btn-group"
- role="group">
- <button
- v-tooltip
- class="btn btn-default discussion-next-btn"
- title="Jump to next unresolved discussion"
- data-container="body"
- @click="jumpToNextDiscussion"
- >
- <icon name="comment-next" />
- </button>
- </div>
- </div>
</div>
- </template>
- <note-form
- v-if="isReplying"
- ref="noteForm"
- :discussion="discussion"
- :is-editing="false"
- save-button-title="Comment"
- @handleFormUpdate="saveReply"
- @cancelForm="cancelReplyForm"
- />
- <note-signed-out-widget v-if="!canReply" />
- </div>
+ </div>
+ </template>
+ <note-form
+ v-if="isReplying"
+ ref="noteForm"
+ :discussion="discussion"
+ :is-editing="false"
+ save-button-title="Comment"
+ @handleFormUpdate="saveReply"
+ @cancelForm="cancelReplyForm"
+ />
+ <note-signed-out-widget v-if="!canReply" />
</div>
- </component>
- </div>
+ </div>
+ </component>
</div>
</div>
</div>
- </li>
+ </timeline-entry-item>
</template>
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue
index 9ab91e2abe5..a17be51353e 100644
--- a/app/assets/javascripts/notes/components/noteable_note.vue
+++ b/app/assets/javascripts/notes/components/noteable_note.vue
@@ -2,6 +2,7 @@
import $ from 'jquery';
import { mapGetters, mapActions } from 'vuex';
import { escape } from 'underscore';
+import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import Flash from '../../flash';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import noteHeader from './note_header.vue';
@@ -18,6 +19,7 @@ export default {
noteHeader,
noteActions,
noteBody,
+ TimelineEntryItem,
},
mixins: [noteable, resolvable],
props: {
@@ -169,65 +171,60 @@ export default {
</script>
<template>
- <li
+ <timeline-entry-item
:id="noteAnchorId"
:class="classNameBindings"
:data-award-url="note.toggle_award_path"
:data-note-id="note.id"
- class="note timeline-entry note-wrapper"
+ class="note note-wrapper"
>
- <div class="timeline-entry-inner">
- <div class="timeline-icon">
- <user-avatar-link
- :link-href="author.path"
- :img-src="author.avatar_url"
- :img-alt="author.name"
- :img-size="40"
- >
- <slot
- slot="avatar-badge"
- name="avatar-badge"
- >
- </slot>
- </user-avatar-link>
- </div>
- <div class="timeline-content">
- <div class="note-header">
- <note-header
- :author="author"
- :created-at="note.created_at"
- :note-id="note.id"
- action-text="commented"
- />
- <note-actions
- :author-id="author.id"
- :note-id="note.id"
- :note-url="note.noteable_note_url"
- :access-level="note.human_access"
- :can-edit="note.current_user.can_edit"
- :can-award-emoji="note.current_user.can_award_emoji"
- :can-delete="note.current_user.can_edit"
- :can-report-as-abuse="canReportAsAbuse"
- :can-resolve="note.current_user.can_resolve"
- :report-abuse-path="note.report_abuse_path"
- :resolvable="note.resolvable"
- :is-resolved="note.resolved"
- :is-resolving="isResolving"
- :resolved-by="note.resolved_by"
- @handleEdit="editHandler"
- @handleDelete="deleteHandler"
- @handleResolve="resolveHandler"
- />
- </div>
- <note-body
- ref="noteBody"
- :note="note"
+ <div v-once class="timeline-icon">
+ <user-avatar-link
+ :link-href="author.path"
+ :img-src="author.avatar_url"
+ :img-alt="author.name"
+ :img-size="40"
+ >
+ <slot slot="avatar-badge" name="avatar-badge"> </slot>
+ </user-avatar-link>
+ </div>
+ <div class="timeline-content">
+ <div class="note-header">
+ <note-header
+ v-once
+ :author="author"
+ :created-at="note.created_at"
+ :note-id="note.id"
+ action-text="commented"
+ />
+ <note-actions
+ :author-id="author.id"
+ :note-id="note.id"
+ :note-url="note.noteable_note_url"
+ :access-level="note.human_access"
:can-edit="note.current_user.can_edit"
- :is-editing="isEditing"
- @handleFormUpdate="formUpdateHandler"
- @cancelForm="formCancelHandler"
+ :can-award-emoji="note.current_user.can_award_emoji"
+ :can-delete="note.current_user.can_edit"
+ :can-report-as-abuse="canReportAsAbuse"
+ :can-resolve="note.current_user.can_resolve"
+ :report-abuse-path="note.report_abuse_path"
+ :resolvable="note.resolvable"
+ :is-resolved="note.resolved"
+ :is-resolving="isResolving"
+ :resolved-by="note.resolved_by"
+ @handleEdit="editHandler"
+ @handleDelete="deleteHandler"
+ @handleResolve="resolveHandler"
/>
</div>
+ <note-body
+ ref="noteBody"
+ :note="note"
+ :can-edit="note.current_user.can_edit"
+ :is-editing="isEditing"
+ @handleFormUpdate="formUpdateHandler"
+ @cancelForm="formCancelHandler"
+ />
</div>
- </li>
+ </timeline-entry-item>
</template>
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index 69ddfd751e0..445d3267a3f 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -12,6 +12,7 @@ import placeholderNote from '../../vue_shared/components/notes/placeholder_note.
import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue';
import skeletonLoadingContainer from '../../vue_shared/components/notes/skeleton_note.vue';
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
+import initUserPopovers from '../../user_popovers';
export default {
name: 'NotesApp',
@@ -22,6 +23,7 @@ export default {
commentForm,
placeholderNote,
placeholderSystemNote,
+ skeletonLoadingContainer,
},
props: {
noteableData: {
@@ -59,7 +61,6 @@ export default {
'isNotesFetched',
'discussions',
'getNotesDataByProp',
- 'discussionCount',
'isLoading',
'commentsDisabled',
]),
@@ -106,42 +107,28 @@ export default {
}
},
updated() {
- this.$nextTick(() => highlightCurrentUser(this.$el.querySelectorAll('.gfm-project_member')));
+ this.$nextTick(() => {
+ highlightCurrentUser(this.$el.querySelectorAll('.gfm-project_member'));
+ initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
+ });
},
methods: {
- ...mapActions({
- setLoadingState: 'setLoadingState',
- fetchDiscussions: 'fetchDiscussions',
- poll: 'poll',
- actionToggleAward: 'toggleAward',
- scrollToNoteIfNeeded: 'scrollToNoteIfNeeded',
- setNotesData: 'setNotesData',
- setNoteableData: 'setNoteableData',
- setUserData: 'setUserData',
- setLastFetchedAt: 'setLastFetchedAt',
- setTargetNoteHash: 'setTargetNoteHash',
- toggleDiscussion: 'toggleDiscussion',
- setNotesFetchedState: 'setNotesFetchedState',
- startTaskList: 'startTaskList',
- }),
- getComponentName(discussion) {
- if (discussion.isSkeletonNote) {
- return skeletonLoadingContainer;
- }
- if (discussion.isPlaceholderNote) {
- if (discussion.placeholderType === constants.SYSTEM_NOTE) {
- return placeholderSystemNote;
- }
- return placeholderNote;
- } else if (discussion.individual_note) {
- return discussion.notes[0].system ? systemNote : noteableNote;
- }
-
- return noteableDiscussion;
- },
- getComponentData(discussion) {
- return discussion.individual_note ? { note: discussion.notes[0] } : { discussion };
- },
+ ...mapActions([
+ 'setLoadingState',
+ 'fetchDiscussions',
+ 'poll',
+ 'toggleAward',
+ 'scrollToNoteIfNeeded',
+ 'setNotesData',
+ 'setNoteableData',
+ 'setUserData',
+ 'setLastFetchedAt',
+ 'setTargetNoteHash',
+ 'toggleDiscussion',
+ 'setNotesFetchedState',
+ 'expandDiscussion',
+ 'startTaskList',
+ ]),
fetchNotes() {
if (this.isFetching) return null;
@@ -181,37 +168,46 @@ export default {
const noteId = hash && hash.replace(/^note_/, '');
if (noteId) {
- this.discussions.forEach(discussion => {
- if (discussion.notes) {
- discussion.notes.forEach(note => {
- if (`${note.id}` === `${noteId}`) {
- // FIXME: this modifies the store state without using a mutation/action
- Object.assign(discussion, { expanded: true });
- }
- });
- }
- });
+ const discussion = this.discussions.find(d => d.notes.some(({ id }) => id === noteId));
+
+ if (discussion) {
+ this.expandDiscussion({ discussionId: discussion.id });
+ }
}
},
},
+ systemNote: constants.SYSTEM_NOTE,
};
</script>
<template>
- <div
- v-show="shouldShow"
- id="notes"
- >
- <ul
- id="notes-list"
- class="notes main-notes-list timeline"
- >
- <component
- :is="getComponentName(discussion)"
- v-for="discussion in allDiscussions"
- :key="discussion.id"
- v-bind="getComponentData(discussion)"
- />
+ <div v-show="shouldShow" id="notes">
+ <ul id="notes-list" class="notes main-notes-list timeline">
+ <template v-for="discussion in allDiscussions">
+ <skeleton-loading-container v-if="discussion.isSkeletonNote" :key="discussion.id" />
+ <template v-else-if="discussion.isPlaceholderNote">
+ <placeholder-system-note
+ v-if="discussion.placeholderType === $options.systemNote"
+ :key="discussion.id"
+ :note="discussion.notes[0]"
+ />
+ <placeholder-note v-else :key="discussion.id" :note="discussion.notes[0]" />
+ </template>
+ <template v-else-if="discussion.individual_note">
+ <system-note
+ v-if="discussion.notes[0].system"
+ :key="discussion.id"
+ :note="discussion.notes[0]"
+ />
+ <noteable-note v-else :key="discussion.id" :note="discussion.notes[0]" />
+ </template>
+ <noteable-discussion
+ v-else
+ :key="discussion.id"
+ :discussion="discussion"
+ :render-diff-file="true"
+ />
+ </template>
</ul>
<comment-form
diff --git a/app/assets/javascripts/notes/components/toggle_replies_widget.vue b/app/assets/javascripts/notes/components/toggle_replies_widget.vue
index 78ecbbb9247..72a8ff28466 100644
--- a/app/assets/javascripts/notes/components/toggle_replies_widget.vue
+++ b/app/assets/javascripts/notes/components/toggle_replies_widget.vue
@@ -42,15 +42,9 @@ export default {
</script>
<template>
- <li
- :class="className"
- class="replies-toggle"
- >
+ <li :class="className" class="replies-toggle js-toggle-replies">
<template v-if="collapsed">
- <icon
- name="chevron-right"
- @click.native="toggle"
- />
+ <icon name="chevron-right" @click.native="toggle" />
<div>
<user-avatar-link
v-for="author in uniqueAuthors"
@@ -63,32 +57,17 @@ export default {
tooltip-placement="bottom"
/>
</div>
- <button
- class="btn btn-link js-replies-text"
- type="button"
- @click="toggle"
- >
+ <button class="btn btn-link js-replies-text" type="button" @click="toggle">
{{ replies.length }} {{ n__('reply', 'replies', replies.length) }}
</button>
{{ __('Last reply by') }}
- <a
- :href="lastReply.author.path"
- class="btn btn-link author-link"
- >
+ <a :href="lastReply.author.path" class="btn btn-link author-link">
{{ lastReply.author.name }}
</a>
- <time-ago-tooltip
- :time="lastReply.created_at"
- tooltip-placement="bottom"
- />
+ <time-ago-tooltip :time="lastReply.created_at" tooltip-placement="bottom" />
</template>
- <span
- v-else
- class="collapse-replies-btn js-collapse-replies"
- @click="toggle"
- >
- <icon name="chevron-down" />
- {{ s__('Notes|Collapse replies') }}
+ <span v-else class="collapse-replies-btn js-collapse-replies" @click="toggle">
+ <icon name="chevron-down" /> {{ s__('Notes|Collapse replies') }}
</span>
</li>
</template>
diff --git a/app/assets/javascripts/notes/mixins/discussion_navigation.js b/app/assets/javascripts/notes/mixins/discussion_navigation.js
index f7c4deee1f8..3d89d907777 100644
--- a/app/assets/javascripts/notes/mixins/discussion_navigation.js
+++ b/app/assets/javascripts/notes/mixins/discussion_navigation.js
@@ -1,29 +1,56 @@
import { scrollToElement } from '~/lib/utils/common_utils';
+import eventHub from '../../notes/event_hub';
export default {
methods: {
- jumpToDiscussion(id) {
- if (id) {
- const activeTab = window.mrTabs.currentAction;
- const selector =
- activeTab === 'diffs'
- ? `ul.notes[data-discussion-id="${id}"]`
- : `div.discussion[data-discussion-id="${id}"]`;
- const el = document.querySelector(selector);
+ diffsJump(id) {
+ const selector = `ul.notes[data-discussion-id="${id}"]`;
- if (activeTab === 'commits' || activeTab === 'pipelines') {
- window.mrTabs.activateTab('show');
- }
+ eventHub.$once('scrollToDiscussion', () => {
+ const el = document.querySelector(selector);
if (el) {
- this.expandDiscussion({ discussionId: id });
-
scrollToElement(el);
+
return true;
}
+
+ return false;
+ });
+
+ this.expandDiscussion({ discussionId: id });
+ },
+ discussionJump(id) {
+ const selector = `div.discussion[data-discussion-id="${id}"]`;
+
+ const el = document.querySelector(selector);
+
+ this.expandDiscussion({ discussionId: id });
+
+ if (el) {
+ scrollToElement(el);
+
+ return true;
}
return false;
},
+ jumpToDiscussion(id) {
+ if (id) {
+ const activeTab = window.mrTabs.currentAction;
+
+ if (activeTab === 'diffs') {
+ this.diffsJump(id);
+ } else if (activeTab === 'commits' || activeTab === 'pipelines') {
+ window.mrTabs.eventHub.$once('MergeRequestTabChange', () => {
+ setTimeout(() => this.discussionJump(id), 0);
+ });
+
+ window.mrTabs.tabShown('show');
+ } else {
+ this.discussionJump(id);
+ }
+ }
+ },
},
};
diff --git a/app/assets/javascripts/notes/mixins/resolvable.js b/app/assets/javascripts/notes/mixins/resolvable.js
index cd8394e0619..8edf3d088bb 100644
--- a/app/assets/javascripts/notes/mixins/resolvable.js
+++ b/app/assets/javascripts/notes/mixins/resolvable.js
@@ -36,7 +36,7 @@ export default {
const discussion = this.resolveAsThread;
const endpoint = discussion ? this.discussion.resolve_path : `${this.note.path}/resolve`;
- this.toggleResolveNote({ endpoint, isResolved, discussion })
+ return this.toggleResolveNote({ endpoint, isResolved, discussion })
.then(() => {
this.isResolving = false;
})
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 5b2f0540020..4716ab52333 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -11,13 +11,19 @@ import * as constants from '../constants';
import service from '../services/notes_service';
import loadAwardsHandler from '../../awards_handler';
import sidebarTimeTrackingEventHub from '../../sidebar/event_hub';
-import { isInViewport, scrollToElement } from '../../lib/utils/common_utils';
+import { isInViewport, scrollToElement, isInMRPage } from '../../lib/utils/common_utils';
import mrWidgetEventHub from '../../vue_merge_request_widget/event_hub';
import { __ } from '~/locale';
let eTagPoll;
-export const expandDiscussion = ({ commit }, data) => commit(types.EXPAND_DISCUSSION, data);
+export const expandDiscussion = ({ commit, dispatch }, data) => {
+ if (data.discussionId) {
+ dispatch('diffs/renderFileForDiscussionId', data.discussionId, { root: true });
+ }
+
+ commit(types.EXPAND_DISCUSSION, data);
+};
export const collapseDiscussion = ({ commit }, data) => commit(types.COLLAPSE_DISCUSSION, data);
@@ -39,12 +45,13 @@ export const setNotesFetchedState = ({ commit }, state) =>
export const toggleDiscussion = ({ commit }, data) => commit(types.TOGGLE_DISCUSSION, data);
-export const fetchDiscussions = ({ commit }, { path, filter }) =>
+export const fetchDiscussions = ({ commit, dispatch }, { path, filter }) =>
service
.fetchDiscussions(path, filter)
.then(res => res.json())
.then(discussions => {
commit(types.SET_INITIAL_DISCUSSIONS, discussions);
+ dispatch('updateResolvableDiscussonsCounts');
});
export const updateDiscussion = ({ commit, state }, discussion) => {
@@ -53,11 +60,18 @@ export const updateDiscussion = ({ commit, state }, discussion) => {
return utils.findNoteObjectById(state.discussions, discussion.id);
};
-export const deleteNote = ({ commit, dispatch }, note) =>
+export const deleteNote = ({ commit, dispatch, state }, note) =>
service.deleteNote(note.path).then(() => {
+ const discussion = state.discussions.find(({ id }) => id === note.discussion_id);
+
commit(types.DELETE_NOTE, note);
dispatch('updateMergeRequestWidget');
+ dispatch('updateResolvableDiscussonsCounts');
+
+ if (isInMRPage()) {
+ dispatch('diffs/removeDiscussionsFromDiff', discussion);
+ }
});
export const updateNote = ({ commit, dispatch }, { endpoint, note }) =>
@@ -89,6 +103,7 @@ export const createNewNote = ({ commit, dispatch }, { endpoint, data }) =>
dispatch('updateMergeRequestWidget');
dispatch('startTaskList');
+ dispatch('updateResolvableDiscussonsCounts');
}
return res;
});
@@ -104,6 +119,8 @@ export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved,
commit(mutationType, res);
+ dispatch('updateResolvableDiscussonsCounts');
+
dispatch('updateMergeRequestWidget');
});
@@ -385,5 +402,8 @@ export const startTaskList = ({ dispatch }) =>
}),
);
+export const updateResolvableDiscussonsCounts = ({ commit }) =>
+ commit(types.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS);
+
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index 8df95c279eb..0ffc0cb2593 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -53,43 +53,41 @@ export const getCurrentUserLastNote = state =>
export const getDiscussionLastNote = state => discussion =>
reverseNotes(discussion.notes).find(el => isLastNote(el, state));
-export const discussionCount = state => {
- const filteredDiscussions = state.discussions.filter(n => !n.individual_note && n.resolvable);
+export const unresolvedDiscussionsCount = state => state.unresolvedDiscussionsCount;
+export const resolvableDiscussionsCount = state => state.resolvableDiscussionsCount;
+export const hasUnresolvedDiscussions = state => state.hasUnresolvedDiscussions;
- return filteredDiscussions.length;
-};
-
-export const unresolvedDiscussions = (state, getters) => {
- const resolvedMap = getters.resolvedDiscussionsById;
-
- return state.discussions.filter(n => !n.individual_note && !resolvedMap[n.id]);
-};
+export const showJumpToNextDiscussion = (state, getters) => (discussionId, mode = 'discussion') => {
+ const orderedDiffs =
+ mode !== 'discussion'
+ ? getters.unresolvedDiscussionsIdsByDiff
+ : getters.unresolvedDiscussionsIdsByDate;
-export const allDiscussions = (state, getters) => {
- const resolved = getters.resolvedDiscussionsById;
- const unresolved = getters.unresolvedDiscussions;
+ const indexOf = orderedDiffs.indexOf(discussionId);
- return Object.values(resolved).concat(unresolved);
+ return indexOf !== -1 && indexOf < orderedDiffs.length - 1;
};
export const isDiscussionResolved = (state, getters) => discussionId =>
getters.resolvedDiscussionsById[discussionId] !== undefined;
-export const allResolvableDiscussions = (state, getters) =>
- getters.allDiscussions.filter(d => !d.individual_note && d.resolvable);
+export const allResolvableDiscussions = state =>
+ state.discussions.filter(d => !d.individual_note && d.resolvable);
export const resolvedDiscussionsById = state => {
const map = {};
- state.discussions.filter(d => d.resolvable).forEach(n => {
- if (n.notes) {
- const resolved = n.notes.filter(note => note.resolvable).every(note => note.resolved);
+ state.discussions
+ .filter(d => d.resolvable)
+ .forEach(n => {
+ if (n.notes) {
+ const resolved = n.notes.filter(note => note.resolvable).every(note => note.resolved);
- if (resolved) {
- map[n.id] = n;
+ if (resolved) {
+ map[n.id] = n;
+ }
}
- }
- });
+ });
return map;
};
@@ -117,7 +115,7 @@ export const unresolvedDiscussionsIdsByDate = (state, getters) =>
// line numbers.
export const unresolvedDiscussionsIdsByDiff = (state, getters) =>
getters.allResolvableDiscussions
- .filter(d => !d.resolved)
+ .filter(d => !d.resolved && d.active)
.sort((a, b) => {
if (!a.diff_file || !b.diff_file) {
return 0;
@@ -145,15 +143,12 @@ export const resolvedDiscussionCount = (state, getters) => {
return Object.keys(resolvedMap).length;
};
-export const discussionTabCounter = state => {
- let all = [];
-
- state.discussions.forEach(discussion => {
- all = all.concat(discussion.notes.filter(note => !note.system && !note.placeholder));
- });
-
- return all.length;
-};
+export const discussionTabCounter = state =>
+ state.discussions.reduce(
+ (acc, discussion) =>
+ acc + discussion.notes.filter(note => !note.system && !note.placeholder).length,
+ 0,
+ );
// Returns the list of discussion IDs ordered according to given parameter
// @param {Boolean} diffOrder - is ordered by diff?
@@ -180,8 +175,10 @@ export const isLastUnresolvedDiscussion = (state, getters) => (discussionId, dif
export const nextUnresolvedDiscussionId = (state, getters) => (discussionId, diffOrder) => {
const idsOrdered = getters.unresolvedDiscussionsIdsOrdered(diffOrder);
const currentIndex = idsOrdered.indexOf(discussionId);
+ const slicedIds = idsOrdered.slice(currentIndex + 1, currentIndex + 2);
- return idsOrdered.slice(currentIndex + 1, currentIndex + 2)[0];
+ // Get the first ID if there is none after the currentIndex
+ return slicedIds.length ? idsOrdered.slice(currentIndex + 1, currentIndex + 2)[0] : idsOrdered[0];
};
// @param {Boolean} diffOrder - is ordered by diff?
diff --git a/app/assets/javascripts/notes/stores/modules/index.js b/app/assets/javascripts/notes/stores/modules/index.js
index 8aea269ea7d..b5fe8bdb1d3 100644
--- a/app/assets/javascripts/notes/stores/modules/index.js
+++ b/app/assets/javascripts/notes/stores/modules/index.js
@@ -22,6 +22,9 @@ export default () => ({
current_user: {},
},
commentsDisabled: false,
+ resolvableDiscussionsCount: 0,
+ unresolvedDiscussionsCount: 0,
+ hasUnresolvedDiscussions: false,
},
actions,
getters,
diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js
index dfbf3b7b34b..9c68ab67a8c 100644
--- a/app/assets/javascripts/notes/stores/mutation_types.js
+++ b/app/assets/javascripts/notes/stores/mutation_types.js
@@ -21,6 +21,7 @@ export const DISABLE_COMMENTS = 'DISABLE_COMMENTS';
export const COLLAPSE_DISCUSSION = 'COLLAPSE_DISCUSSION';
export const EXPAND_DISCUSSION = 'EXPAND_DISCUSSION';
export const TOGGLE_DISCUSSION = 'TOGGLE_DISCUSSION';
+export const UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS = 'UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS';
// Issue
export const CLOSE_ISSUE = 'CLOSE_ISSUE';
diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js
index f6054e0be87..39ff0ff73d7 100644
--- a/app/assets/javascripts/notes/stores/mutations.js
+++ b/app/assets/javascripts/notes/stores/mutations.js
@@ -22,8 +22,10 @@ export default {
if (isDiscussion && isInMRPage()) {
noteData.resolvable = note.resolvable;
noteData.resolved = false;
+ noteData.active = true;
noteData.resolve_path = note.resolve_path;
noteData.resolve_with_issue_path = note.resolve_with_issue_path;
+ noteData.diff_discussion = false;
}
state.discussions.push(noteData);
@@ -97,33 +99,36 @@ export default {
},
[types.SET_INITIAL_DISCUSSIONS](state, discussionsData) {
- const discussions = [];
+ const discussions = discussionsData.reduce((acc, d) => {
+ const discussion = { ...d };
+ const diffData = {};
- discussionsData.forEach(discussion => {
if (discussion.diff_file) {
- Object.assign(discussion, {
- file_hash: discussion.diff_file.file_hash,
- truncated_diff_lines: discussion.truncated_diff_lines || [],
- });
+ diffData.file_hash = discussion.diff_file.file_hash;
+ diffData.truncated_diff_lines = discussion.truncated_diff_lines || [];
}
// To support legacy notes, should be very rare case.
if (discussion.individual_note && discussion.notes.length > 1) {
discussion.notes.forEach(n => {
- discussions.push({
+ acc.push({
...discussion,
+ ...diffData,
notes: [n], // override notes array to only have one item to mimick individual_note
});
});
} else {
const oldNote = utils.findNoteObjectById(state.discussions, discussion.id);
- discussions.push({
+ acc.push({
...discussion,
+ ...diffData,
expanded: oldNote ? oldNote.expanded : discussion.expanded,
});
}
- });
+
+ return acc;
+ }, []);
Object.assign(state, { discussions });
},
@@ -174,9 +179,11 @@ export default {
}
},
- [types.TOGGLE_DISCUSSION](state, { discussionId }) {
+ [types.TOGGLE_DISCUSSION](state, { discussionId, forceExpanded = null }) {
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
- Object.assign(discussion, { expanded: !discussion.expanded });
+ Object.assign(discussion, {
+ expanded: forceExpanded === null ? !discussion.expanded : forceExpanded,
+ });
},
[types.UPDATE_NOTE](state, note) {
@@ -195,7 +202,9 @@ export default {
const selectedDiscussion = state.discussions.find(disc => disc.id === note.id);
note.expanded = true; // override expand flag to prevent collapse
if (note.diff_file) {
- Object.assign(note, { file_hash: note.diff_file.file_hash });
+ Object.assign(note, {
+ file_hash: note.diff_file.file_hash,
+ });
}
Object.assign(selectedDiscussion, { ...note });
},
@@ -229,4 +238,16 @@ export default {
[types.DISABLE_COMMENTS](state, value) {
state.commentsDisabled = value;
},
+ [types.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS](state) {
+ state.resolvableDiscussionsCount = state.discussions.filter(
+ discussion => !discussion.individual_note && discussion.resolvable,
+ ).length;
+ state.unresolvedDiscussionsCount = state.discussions.filter(
+ discussion =>
+ !discussion.individual_note &&
+ discussion.resolvable &&
+ discussion.notes.some(note => note.resolvable && !note.resolved),
+ ).length;
+ state.hasUnresolvedDiscussions = state.unresolvedDiscussionsCount > 1;
+ },
};
diff --git a/app/assets/javascripts/notifications_dropdown.js b/app/assets/javascripts/notifications_dropdown.js
index c4c8cf86cb0..e7fa05faa8a 100644
--- a/app/assets/javascripts/notifications_dropdown.js
+++ b/app/assets/javascripts/notifications_dropdown.js
@@ -12,6 +12,10 @@ export default function notificationsDropdown() {
const form = $(this).parents('.notification-form:first');
form.find('.js-notification-loading').toggleClass('fa-bell fa-spin fa-spinner');
+ if (form.hasClass('no-label')) {
+ form.find('.js-notification-loading').toggleClass('hidden');
+ form.find('.js-notifications-icon').toggleClass('hidden');
+ }
form.find('#notification_setting_level').val(notificationLevel);
form.submit();
});
diff --git a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
index d9cf62db3f7..674b807edbe 100644
--- a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
+++ b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
@@ -1,5 +1,6 @@
import $ from 'jquery';
import { truncate } from '../../../lib/utils/text_utility';
+import { parseBoolean } from '~/lib/utils/common_utils';
const MAX_MESSAGE_LENGTH = 500;
const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
@@ -26,7 +27,7 @@ export default class AbuseReports {
const $messageCellElement = $(this);
const originalMessage = $messageCellElement.data('originalMessage');
if (!originalMessage) return;
- if ($messageCellElement.data('messageTruncated') === 'true') {
+ if (parseBoolean($messageCellElement.data('messageTruncated'))) {
$messageCellElement.data('messageTruncated', 'false');
$messageCellElement.text(originalMessage);
} else {
diff --git a/app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue b/app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue
index 3c383735f4a..527c16860c0 100644
--- a/app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue
+++ b/app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue
@@ -92,28 +92,12 @@ export default {
@submit="onSubmit"
@cancel="onCancel"
>
- <template
- slot="body"
- slot-scope="props"
- >
+ <template slot="body" slot-scope="props">
<p v-html="props.text"></p>
<p v-html="confirmationTextLabel"></p>
- <form
- ref="form"
- :action="deleteProjectUrl"
- method="post"
- >
- <input
- ref="method"
- type="hidden"
- name="_method"
- value="delete"
- />
- <input
- :value="csrfToken"
- type="hidden"
- name="authenticity_token"
- />
+ <form ref="form" :action="deleteProjectUrl" method="post">
+ <input ref="method" type="hidden" name="_method" value="delete" />
+ <input :value="csrfToken" type="hidden" name="authenticity_token" />
<input
v-model="enteredProjectName"
name="projectName"
diff --git a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
index 4b33fcc759a..e8905b479ee 100644
--- a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
+++ b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
@@ -128,28 +128,12 @@ export default {
@submit="onSubmit"
@cancel="onCancel"
>
- <template
- slot="body"
- slot-scope="props"
- >
+ <template slot="body" slot-scope="props">
<p v-html="props.text"></p>
<p v-html="confirmationTextLabel"></p>
- <form
- ref="form"
- :action="deleteUserUrl"
- method="post"
- >
- <input
- ref="method"
- type="hidden"
- name="_method"
- value="delete"
- />
- <input
- :value="csrfToken"
- type="hidden"
- name="authenticity_token"
- />
+ <form ref="form" :action="deleteUserUrl" method="post">
+ <input ref="method" type="hidden" name="_method" value="delete" />
+ <input :value="csrfToken" type="hidden" name="authenticity_token" />
<input
v-model="enteredUsername"
type="text"
diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js
index c4901dd1cb6..9055738f86e 100644
--- a/app/assets/javascripts/pages/dashboard/issues/index.js
+++ b/app/assets/javascripts/pages/dashboard/issues/index.js
@@ -1,7 +1,13 @@
import projectSelect from '~/project_select';
-import initLegacyFilters from '~/init_legacy_filters';
+import initFilteredSearch from '~/pages/search/init_filtered_search';
+import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
+import { FILTERED_SEARCH } from '~/pages/constants';
document.addEventListener('DOMContentLoaded', () => {
+ initFilteredSearch({
+ page: FILTERED_SEARCH.ISSUES,
+ filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ });
+
projectSelect();
- initLegacyFilters();
});
diff --git a/app/assets/javascripts/pages/dashboard/merge_requests/index.js b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
index c4901dd1cb6..260484726f3 100644
--- a/app/assets/javascripts/pages/dashboard/merge_requests/index.js
+++ b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
@@ -1,7 +1,15 @@
import projectSelect from '~/project_select';
-import initLegacyFilters from '~/init_legacy_filters';
+import initFilteredSearch from '~/pages/search/init_filtered_search';
+import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
+import { FILTERED_SEARCH } from '~/pages/constants';
document.addEventListener('DOMContentLoaded', () => {
+ IssuableFilteredSearchTokenKeys.addExtraTokensForMergeRequests();
+
+ initFilteredSearch({
+ page: FILTERED_SEARCH.MERGE_REQUESTS,
+ filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ });
+
projectSelect();
- initLegacyFilters();
});
diff --git a/app/assets/javascripts/pages/groups/edit/index.js b/app/assets/javascripts/pages/groups/edit/index.js
index 32b55575f95..01ef445c901 100644
--- a/app/assets/javascripts/pages/groups/edit/index.js
+++ b/app/assets/javascripts/pages/groups/edit/index.js
@@ -5,6 +5,7 @@ import initSettingsPanels from '~/settings_panels';
import dirtySubmitFactory from '~/dirty_submit/dirty_submit_factory';
import mountBadgeSettings from '~/pages/shared/mount_badge_settings';
import { GROUP_BADGE } from '~/badges/constants';
+import groupsSelect from '~/groups_select';
import projectSelect from '~/project_select';
document.addEventListener('DOMContentLoaded', () => {
@@ -17,5 +18,8 @@ document.addEventListener('DOMContentLoaded', () => {
);
mountBadgeSettings(GROUP_BADGE);
+ // Initialize Subgroups selector
+ groupsSelect();
+
projectSelect();
});
diff --git a/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue b/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
index a4778077bc4..061044eba84 100644
--- a/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
+++ b/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
@@ -121,13 +121,10 @@ Once deleted, it cannot be undone or recovered.`),
:text="text"
:primary-button-label="s__('Milestones|Delete milestone')"
kind="danger"
- @submit="onSubmit">
-
- <template
- slot="body"
- slot-scope="props">
+ @submit="onSubmit"
+ >
+ <template slot="body" slot-scope="props">
<p v-html="props.text"></p>
</template>
-
</deprecated-modal>
</template>
diff --git a/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue b/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue
index 9d19e4a095d..a79ef07f1c5 100644
--- a/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue
+++ b/app/assets/javascripts/pages/milestones/shared/components/promote_milestone_modal.vue
@@ -69,9 +69,7 @@ export default {
footer-primary-button-variant="warning"
@submit="onSubmit"
>
- <template
- slot="title"
- >
+ <template slot="title">
{{ title }}
</template>
{{ text }}
diff --git a/app/assets/javascripts/pages/profiles/show/emoji_menu.js b/app/assets/javascripts/pages/profiles/show/emoji_menu.js
index 094837b40e0..286c1f1e929 100644
--- a/app/assets/javascripts/pages/profiles/show/emoji_menu.js
+++ b/app/assets/javascripts/pages/profiles/show/emoji_menu.js
@@ -1,3 +1,4 @@
+import '~/commons/bootstrap';
import { AwardsHandler } from '~/awards_handler';
class EmojiMenu extends AwardsHandler {
diff --git a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
index 417935e2ad0..10cd8ecfbc9 100644
--- a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
+++ b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
@@ -1,9 +1,10 @@
import $ from 'jquery';
import U2FRegister from '~/u2f/register';
+import { parseBoolean } from '~/lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => {
const twoFactorNode = document.querySelector('.js-two-factor-auth');
- const skippable = twoFactorNode.dataset.twoFactorSkippable === 'true';
+ const skippable = parseBoolean(twoFactorNode.dataset.twoFactorSkippable);
if (skippable) {
const button = `<a class="btn btn-sm btn-warning float-right" data-method="patch" href="${
twoFactorNode.dataset.two_factor_skip_url
diff --git a/app/assets/javascripts/pages/projects/commit/show/index.js b/app/assets/javascripts/pages/projects/commit/show/index.js
index f477424811d..6fc982967eb 100644
--- a/app/assets/javascripts/pages/projects/commit/show/index.js
+++ b/app/assets/javascripts/pages/projects/commit/show/index.js
@@ -11,6 +11,8 @@ import initDiffNotes from '~/diff_notes/diff_notes_bundle';
import { fetchCommitMergeRequests } from '~/commit_merge_requests';
document.addEventListener('DOMContentLoaded', () => {
+ const hasPerfBar = document.querySelector('.with-performance-bar');
+ const performanceHeight = hasPerfBar ? 35 : 0;
new Diff();
new ZenMode();
new ShortcutsNavigation();
@@ -18,8 +20,7 @@ document.addEventListener('DOMContentLoaded', () => {
container: '.js-commit-pipeline-graph',
}).bindEvents();
initNotes();
- const stickyBarPaddingTop = 16;
- initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - stickyBarPaddingTop);
+ initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight + performanceHeight);
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
fetchCommitMergeRequests();
initDiffNotes();
diff --git a/app/assets/javascripts/pages/projects/edit/index.js b/app/assets/javascripts/pages/projects/edit/index.js
index f5b1cf85e68..899d5925956 100644
--- a/app/assets/javascripts/pages/projects/edit/index.js
+++ b/app/assets/javascripts/pages/projects/edit/index.js
@@ -3,8 +3,8 @@ import initSettingsPanels from '~/settings_panels';
import setupProjectEdit from '~/project_edit';
import initConfirmDangerModal from '~/confirm_danger_modal';
import mountBadgeSettings from '~/pages/shared/mount_badge_settings';
+import fileUpload from '~/lib/utils/file_upload';
import initProjectLoadingSpinner from '../shared/save_project_loader';
-import projectAvatar from '../shared/project_avatar';
import initProjectPermissionsSettings from '../shared/permissions';
document.addEventListener('DOMContentLoaded', () => {
@@ -12,7 +12,7 @@ document.addEventListener('DOMContentLoaded', () => {
setupProjectEdit();
// Initialize expandable settings panels
initSettingsPanels();
- projectAvatar();
+ fileUpload('.js-choose-project-avatar-button', '.js-project-avatar-input');
initProjectPermissionsSettings();
initConfirmDangerModal();
mountBadgeSettings(PROJECT_BADGE);
diff --git a/app/assets/javascripts/pages/projects/issues/form.js b/app/assets/javascripts/pages/projects/issues/form.js
index 197bfa8a394..02a56685a35 100644
--- a/app/assets/javascripts/pages/projects/issues/form.js
+++ b/app/assets/javascripts/pages/projects/issues/form.js
@@ -7,6 +7,7 @@ import LabelsSelect from '~/labels_select';
import MilestoneSelect from '~/milestone_select';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import IssuableTemplateSelectors from '~/templates/issuable_template_selectors';
+import initSuggestions from '~/issuable_suggestions';
export default () => {
new ShortcutsNavigation();
@@ -15,4 +16,8 @@ export default () => {
new LabelsSelect();
new MilestoneSelect();
new IssuableTemplateSelectors();
+
+ if (gon.features.issueSuggestions && gon.features.graphql) {
+ initSuggestions();
+ }
};
diff --git a/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue b/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue
index e8b646f3f6e..e723cd3fea9 100644
--- a/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue
+++ b/app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue
@@ -89,13 +89,7 @@ export default {
footer-primary-button-variant="warning"
@submit="onSubmit"
>
- <div
- slot="title"
- class="modal-title-with-label"
- v-html="title"
- >
- {{ title }}
- </div>
+ <div slot="title" class="modal-title-with-label" v-html="title">{{ title }}</div>
{{ text }}
</gl-modal>
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
index ab6f42d928c..db2a4041ec0 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
@@ -70,20 +70,13 @@ export default {
:checked="isEditable"
class="label-bold"
type="radio"
- @click="toggleCustomInput(true)"
+ @click="toggleCustomInput(true);"
/>
- <label for="custom">
- {{ s__('PipelineSheduleIntervalPattern|Custom') }}
- </label>
+ <label for="custom"> {{ s__('PipelineSheduleIntervalPattern|Custom') }} </label>
<span class="cron-syntax-link-wrap">
- (<a
- :href="cronSyntaxUrl"
- target="_blank"
- >
- {{ __('Cron syntax') }}
- </a>)
+ (<a :href="cronSyntaxUrl" target="_blank"> {{ __('Cron syntax') }} </a>)
</span>
</div>
@@ -95,15 +88,10 @@ export default {
:value="cronIntervalPresets.everyDay"
class="label-bold"
type="radio"
- @click="toggleCustomInput(false)"
+ @click="toggleCustomInput(false);"
/>
- <label
- class="label-bold"
- for="every-day"
- >
- {{ __('Every day (at 4:00am)') }}
- </label>
+ <label class="label-bold" for="every-day"> {{ __('Every day (at 4:00am)') }} </label>
</div>
<div class="cron-preset-radio-input">
@@ -114,13 +102,10 @@ export default {
:value="cronIntervalPresets.everyWeek"
class="label-bold"
type="radio"
- @click="toggleCustomInput(false)"
+ @click="toggleCustomInput(false);"
/>
- <label
- class="label-bold"
- for="every-week"
- >
+ <label class="label-bold" for="every-week">
{{ __('Every week (Sundays at 4:00am)') }}
</label>
</div>
@@ -133,13 +118,10 @@ export default {
:value="cronIntervalPresets.everyMonth"
class="label-bold"
type="radio"
- @click="toggleCustomInput(false)"
+ @click="toggleCustomInput(false);"
/>
- <label
- class="label-bold"
- for="every-month"
- >
+ <label class="label-bold" for="every-month">
{{ __('Every month (on the 1st at 4:00am)') }}
</label>
</div>
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
index 33fc2420e4d..22512a6f12a 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
@@ -3,6 +3,7 @@ import Vue from 'vue';
import Cookies from 'js-cookie';
import Translate from '../../../../../vue_shared/translate';
import illustrationSvg from '../icons/intro_illustration.svg';
+import { parseBoolean } from '~/lib/utils/common_utils';
Vue.use(Translate);
@@ -13,7 +14,7 @@ export default {
data() {
return {
docsUrl: document.getElementById('pipeline-schedules-callout').dataset.docsUrl,
- calloutDismissed: Cookies.get(cookieKey) === 'true',
+ calloutDismissed: parseBoolean(Cookies.get(cookieKey)),
};
},
created() {
@@ -28,37 +29,26 @@ export default {
};
</script>
<template>
- <div
- v-if="!calloutDismissed"
- class="pipeline-schedules-user-callout user-callout">
+ <div v-if="!calloutDismissed" class="pipeline-schedules-user-callout user-callout">
<div class="bordered-box landing content-block">
- <button
- id="dismiss-callout-btn"
- class="btn btn-default close"
- @click="dismissCallout">
- <i
- aria-hidden="true"
- class="fa fa-times">
- </i>
+ <button id="dismiss-callout-btn" class="btn btn-default close" @click="dismissCallout">
+ <i aria-hidden="true" class="fa fa-times"> </i>
</button>
- <div
- class="svg-container"
- v-html="illustrationSvg">
- </div>
+ <div class="svg-container" v-html="illustrationSvg"></div>
<div class="user-callout-copy">
<h4>{{ __('Scheduling Pipelines') }}</h4>
<p>
- {{ __(`The pipelines schedule runs pipelines in the future,
+ {{
+ __(`The pipelines schedule runs pipelines in the future,
repeatedly, for specific branches or tags.
-Those scheduled pipelines will inherit limited project access based on their associated user.`) }}
+Those scheduled pipelines will inherit limited project access based on their associated user.`)
+ }}
</p>
- <p> {{ __('Learn more in the') }}
- <a
- :href="docsUrl"
- target="_blank"
- rel="nofollow"
- >
- {{ s__('Learn more in the|pipeline schedules documentation') }}</a>.
+ <p>
+ {{ __('Learn more in the') }}
+ <a :href="docsUrl" target="_blank" rel="nofollow">
+ {{ s__('Learn more in the|pipeline schedules documentation') }}</a
+ >.
<!-- oneline to prevent extra space before period -->
</p>
</div>
diff --git a/app/assets/javascripts/pages/projects/pipelines/index/index.js b/app/assets/javascripts/pages/projects/pipelines/index/index.js
index fc337a7609b..fd72d2ddbe0 100644
--- a/app/assets/javascripts/pages/projects/pipelines/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipelines/index/index.js
@@ -2,7 +2,7 @@ import Vue from 'vue';
import PipelinesStore from '../../../../pipelines/stores/pipelines_store';
import pipelinesComponent from '../../../../pipelines/components/pipelines.vue';
import Translate from '../../../../vue_shared/translate';
-import { convertPermissionToBoolean } from '../../../../lib/utils/common_utils';
+import { parseBoolean } from '../../../../lib/utils/common_utils';
Vue.use(Translate);
@@ -33,8 +33,8 @@ document.addEventListener(
noPipelinesSvgPath: this.dataset.noPipelinesSvgPath,
autoDevopsPath: this.dataset.helpAutoDevopsPath,
newPipelinePath: this.dataset.newPipelinePath,
- canCreatePipeline: convertPermissionToBoolean(this.dataset.canCreatePipeline),
- hasGitlabCi: convertPermissionToBoolean(this.dataset.hasGitlabCi),
+ canCreatePipeline: parseBoolean(this.dataset.canCreatePipeline),
+ hasGitlabCi: parseBoolean(this.dataset.hasGitlabCi),
ciLintPath: this.dataset.ciLintPath,
resetCachePath: this.dataset.resetCachePath,
},
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index a6bee49a6b1..b288989b252 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -13,6 +13,9 @@ export default class Project {
const $cloneOptions = $('ul.clone-options-dropdown');
const $projectCloneField = $('#project_clone');
const $cloneBtnLabel = $('.js-git-clone-holder .js-clone-dropdown-label');
+ const mobileCloneField = document.querySelector(
+ '.js-mobile-git-clone .js-clone-dropdown-label',
+ );
const selectedCloneOption = $cloneBtnLabel.text().trim();
if (selectedCloneOption.length > 0) {
@@ -36,7 +39,11 @@ export default class Project {
$label.text(activeText);
});
- $projectCloneField.val(url);
+ if (mobileCloneField) {
+ mobileCloneField.dataset.clipboardText = url;
+ } else {
+ $projectCloneField.val(url);
+ }
$('.js-git-empty .js-clone').text(url);
});
// Ref switcher
diff --git a/app/assets/javascripts/pages/projects/serverless/index.js b/app/assets/javascripts/pages/projects/serverless/index.js
new file mode 100644
index 00000000000..7b08620773c
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/serverless/index.js
@@ -0,0 +1,5 @@
+import ServerlessBundle from '~/serverless/serverless_bundle';
+
+document.addEventListener('DOMContentLoaded', () => {
+ new ServerlessBundle(); // eslint-disable-line no-new
+});
diff --git a/app/assets/javascripts/pages/projects/settings/repository/form.js b/app/assets/javascripts/pages/projects/settings/repository/form.js
index a52861c9efa..3e02893f24c 100644
--- a/app/assets/javascripts/pages/projects/settings/repository/form.js
+++ b/app/assets/javascripts/pages/projects/settings/repository/form.js
@@ -7,6 +7,7 @@ import initDeployKeys from '~/deploy_keys';
import ProtectedBranchCreate from '~/protected_branches/protected_branch_create';
import ProtectedBranchEditList from '~/protected_branches/protected_branch_edit_list';
import DueDateSelectors from '~/due_date_select';
+import fileUpload from '~/lib/utils/file_upload';
export default () => {
new ProtectedTagCreate();
@@ -16,4 +17,5 @@ export default () => {
new ProtectedBranchCreate();
new ProtectedBranchEditList();
new DueDateSelectors();
+ fileUpload('.js-choose-file', '.js-object-map-input');
};
diff --git a/app/assets/javascripts/pages/projects/settings/repository/show/index.js b/app/assets/javascripts/pages/projects/settings/repository/show/index.js
index 78cf5406e43..1ef4b460263 100644
--- a/app/assets/javascripts/pages/projects/settings/repository/show/index.js
+++ b/app/assets/javascripts/pages/projects/settings/repository/show/index.js
@@ -1,5 +1,5 @@
import initForm from '../form';
-import MirrorRepos from './mirror_repos';
+import MirrorRepos from '~/mirrors/mirror_repos';
document.addEventListener('DOMContentLoaded', () => {
initForm();
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue
index dced839c883..ff6dadeff7d 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue
@@ -69,16 +69,8 @@ export default {
</script>
<template>
- <div
- :data-for="name"
- class="project-feature-controls"
- >
- <input
- v-if="name"
- :name="name"
- :value="value"
- type="hidden"
- />
+ <div :data-for="name" class="project-feature-controls">
+ <input v-if="name" :name="name" :value="value" type="hidden" />
<project-feature-toggle
:value="featureEnabled"
:disabled-input="disabledInput"
@@ -99,11 +91,7 @@ export default {
{{ optionName }}
</option>
</select>
- <i
- aria-hidden="true"
- class="fa fa-chevron-down"
- >
- </i>
+ <i aria-hidden="true" class="fa fa-chevron-down"> </i>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue
index 898d605463f..92d23772565 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue
@@ -22,30 +22,12 @@ export default {
<template>
<div class="project-feature-row">
- <label
- v-if="label"
- class="label-bold"
- >
+ <label v-if="label" class="label-bold">
{{ label }}
- <a
- v-if="helpPath"
- :href="helpPath"
- target="_blank"
- >
- <i
- aria-hidden="true"
- data-hidden="true"
- class="fa fa-question-circle"
- >
- </i>
+ <a v-if="helpPath" :href="helpPath" target="_blank">
+ <i aria-hidden="true" data-hidden="true" class="fa fa-question-circle"> </i>
</a>
</label>
- <span
- v-if="helpText"
- class="form-text text-muted"
- >
- {{ helpText }}
- </span>
- <slot></slot>
+ <span v-if="helpText" class="form-text text-muted"> {{ helpText }} </span> <slot></slot>
</div>
</template>
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
index c0ec7a5dc94..08c7719dcf2 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
@@ -200,10 +200,7 @@ export default {
<template>
<div>
<div class="project-visibility-setting">
- <project-setting-row
- :help-path="visibilityHelpPath"
- label="Project visibility"
- >
+ <project-setting-row :help-path="visibilityHelpPath" label="Project visibility">
<div class="project-feature-controls">
<div class="select-wrapper">
<select
@@ -231,36 +228,21 @@ export default {
Public
</option>
</select>
- <i
- aria-hidden="true"
- data-hidden="true"
- class="fa fa-chevron-down"
- >
- </i>
+ <i aria-hidden="true" data-hidden="true" class="fa fa-chevron-down"> </i>
</div>
</div>
<span class="form-text text-muted">{{ visibilityLevelDescription }}</span>
- <label
- v-if="visibilityLevel !== visibilityOptions.PRIVATE"
- class="request-access"
- >
+ <label v-if="visibilityLevel !== visibilityOptions.PRIVATE" class="request-access">
<input
:value="requestAccessEnabled"
type="hidden"
name="project[request_access_enabled]"
/>
- <input
- v-model="requestAccessEnabled"
- type="checkbox"
- />
- Allow users to request access
+ <input v-model="requestAccessEnabled" type="checkbox" /> Allow users to request access
</label>
</project-setting-row>
</div>
- <div
- :class="{ 'highlight-changes': highlightChangesClass }"
- class="project-feature-settings"
- >
+ <div :class="{ 'highlight-changes': highlightChangesClass }" class="project-feature-settings">
<project-setting-row
label="Issues"
help-text="Lightweight issue tracking system for this project"
@@ -271,10 +253,7 @@ export default {
name="project[project_feature_attributes][issues_access_level]"
/>
</project-setting-row>
- <project-setting-row
- label="Repository"
- help-text="View and edit files in this project"
- >
+ <project-setting-row label="Repository" help-text="View and edit files in this project">
<project-feature-setting
v-model="repositoryAccessLevel"
:options="featureAccessLevelOptions"
@@ -293,10 +272,7 @@ export default {
name="project[project_feature_attributes][merge_requests_access_level]"
/>
</project-setting-row>
- <project-setting-row
- label="Pipelines"
- help-text="Build, test, and deploy your changes"
- >
+ <project-setting-row label="Pipelines" help-text="Build, test, and deploy your changes">
<project-feature-setting
v-model="buildsAccessLevel"
:options="repoFeatureAccessLevelOptions"
@@ -329,10 +305,7 @@ export default {
/>
</project-setting-row>
</div>
- <project-setting-row
- label="Wiki"
- help-text="Pages for project documentation"
- >
+ <project-setting-row label="Wiki" help-text="Pages for project documentation">
<project-feature-setting
v-model="wikiAccessLevel"
:options="featureAccessLevelOptions"
diff --git a/app/assets/javascripts/pages/projects/shared/project_avatar.js b/app/assets/javascripts/pages/projects/shared/project_avatar.js
deleted file mode 100644
index 1e69ecb481d..00000000000
--- a/app/assets/javascripts/pages/projects/shared/project_avatar.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import $ from 'jquery';
-
-export default function projectAvatar() {
- $('.js-choose-project-avatar-button').bind('click', function onClickAvatar() {
- const form = $(this).closest('form');
- return form.find('.js-project-avatar-input').click();
- });
-
- $('.js-project-avatar-input').bind('change', function onClickAvatarInput() {
- const form = $(this).closest('form');
- const filename = $(this)
- .val()
- .replace(/^.*[\\\/]/, ''); // eslint-disable-line no-useless-escape
- return form.find('.js-avatar-filename').text(filename);
- });
-}
diff --git a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue
index f970a5ebb64..b0c9ca3ec0d 100644
--- a/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue
+++ b/app/assets/javascripts/pages/projects/wikis/components/delete_wiki_modal.vue
@@ -1,7 +1,7 @@
<script>
import _ from 'underscore';
import { s__, sprintf } from '~/locale';
-import { GlModal, GlModalDirective } from '@gitlab-org/gitlab-ui';
+import { GlModal, GlModalDirective } from '@gitlab/ui';
export default {
components: {
@@ -54,13 +54,7 @@ export default {
<template>
<div class="d-inline-block">
- <button
- v-gl-modal="modalId"
- type="button"
- class="btn btn-danger"
- >
- {{ __('Delete') }}
- </button>
+ <button v-gl-modal="modalId" type="button" class="btn btn-danger">{{ __('Delete') }}</button>
<gl-modal
:title="title"
:ok-title="s__('WikiPageConfirmDelete|Delete page')"
@@ -70,23 +64,9 @@ export default {
@ok="onSubmit"
>
{{ message }}
- <form
- ref="form"
- :action="deleteWikiUrl"
- method="post"
- class="js-requires-input"
- >
- <input
- ref="method"
- type="hidden"
- name="_method"
- value="delete"
- />
- <input
- :value="csrfToken"
- type="hidden"
- name="authenticity_token"
- />
+ <form ref="form" :action="deleteWikiUrl" method="post" class="js-requires-input">
+ <input ref="method" type="hidden" name="_method" value="delete" />
+ <input :value="csrfToken" type="hidden" name="authenticity_token" />
</form>
</gl-modal>
</div>
diff --git a/app/assets/javascripts/pages/projects/wikis/wikis.js b/app/assets/javascripts/pages/projects/wikis/wikis.js
index d3e8dbf4000..9b58d42b47d 100644
--- a/app/assets/javascripts/pages/projects/wikis/wikis.js
+++ b/app/assets/javascripts/pages/projects/wikis/wikis.js
@@ -1,5 +1,4 @@
import bp from '../../../breakpoints';
-import { slugify } from '../../../lib/utils/text_utility';
import { parseQueryStringIntoObject } from '../../../lib/utils/common_utils';
import { mergeUrlParams, redirectTo } from '../../../lib/utils/url_utility';
@@ -26,7 +25,8 @@ export default class Wikis {
if (!this.newWikiForm) return;
const slugInput = this.newWikiForm.querySelector('#new_wiki_path');
- const slug = slugify(slugInput.value);
+
+ const slug = slugInput.value;
if (slug.length > 0) {
const wikisPath = slugInput.getAttribute('data-wikis-path');
diff --git a/app/assets/javascripts/pages/users/activity_calendar.js b/app/assets/javascripts/pages/users/activity_calendar.js
index bf592ba7a3c..8a84ac37dab 100644
--- a/app/assets/javascripts/pages/users/activity_calendar.js
+++ b/app/assets/javascripts/pages/users/activity_calendar.js
@@ -181,9 +181,8 @@ export default class ActivityCalendar {
.attr('y', stamp => this.dayYPos(stamp.day))
.attr('width', this.daySize)
.attr('height', this.daySize)
- .attr(
- 'fill',
- stamp => (stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed'),
+ .attr('fill', stamp =>
+ stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed',
)
.attr('title', stamp => formatTooltipText(stamp))
.attr('class', 'user-contrib-cell js-tooltip')
diff --git a/app/assets/javascripts/pages/users/user_overview_block.js b/app/assets/javascripts/pages/users/user_overview_block.js
index 2ed177be558..eec2b5ca8e5 100644
--- a/app/assets/javascripts/pages/users/user_overview_block.js
+++ b/app/assets/javascripts/pages/users/user_overview_block.js
@@ -10,6 +10,7 @@ export default class UserOverviewBlock {
limit: DEFAULT_LIMIT,
...options.requestParams,
};
+ this.postRenderCallback = options.postRenderCallback;
this.loadData();
}
@@ -43,5 +44,9 @@ export default class UserOverviewBlock {
}
loadingEl.classList.add('hide');
+
+ if (this.postRenderCallback) {
+ this.postRenderCallback.call(this);
+ }
}
}
diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js
index 04bcb16f036..aa537d4a43e 100644
--- a/app/assets/javascripts/pages/users/user_tabs.js
+++ b/app/assets/javascripts/pages/users/user_tabs.js
@@ -2,7 +2,8 @@ import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import Activities from '~/activities';
import { localTimeAgo } from '~/lib/utils/datetime_utility';
-import { __, sprintf } from '~/locale';
+import AjaxCache from '~/lib/utils/ajax_cache';
+import { __ } from '~/locale';
import flash from '~/flash';
import ActivityCalendar from './activity_calendar';
import UserOverviewBlock from './user_overview_block';
@@ -62,23 +63,20 @@ import UserOverviewBlock from './user_overview_block';
* </div>
*/
-const CALENDAR_TEMPLATES = {
- activity: `
- <div class="clearfix calendar">
- <div class="js-contrib-calendar"></div>
- <div class="calendar-hint bottom-right"></div>
- </div>
- `,
- overview: `
- <div class="clearfix calendar">
- <div class="calendar-hint"></div>
- <div class="js-contrib-calendar prepend-top-20"></div>
- </div>
- `,
-};
+const CALENDAR_TEMPLATE = `
+ <div class="clearfix calendar">
+ <div class="js-contrib-calendar"></div>
+ <div class="calendar-hint bottom-right"></div>
+ </div>
+`;
const CALENDAR_PERIOD_6_MONTHS = 6;
const CALENDAR_PERIOD_12_MONTHS = 12;
+/* computation based on
+ * width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
+ * (see activity_calendar.js)
+ */
+const OVERVIEW_CALENDAR_BREAKPOINT = 918;
export default class UserTabs {
constructor({ defaultAction, action, parentEl }) {
@@ -105,6 +103,12 @@ export default class UserTabs {
.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event))
.on('click', '.gl-pagination a', event => this.changeProjectsPage(event));
+
+ window.addEventListener('resize', () => this.onResize());
+ }
+
+ onResize() {
+ this.loadActivityCalendar();
}
changeProjectsPage(e) {
@@ -167,8 +171,6 @@ export default class UserTabs {
return;
}
- this.loadActivityCalendar('activity');
-
// eslint-disable-next-line no-new
new Activities('#activity');
@@ -180,10 +182,10 @@ export default class UserTabs {
return;
}
- this.loadActivityCalendar('overview');
+ this.loadActivityCalendar();
UserTabs.renderMostRecentBlocks('#js-overview .activities-block', {
- requestParams: { limit: 5 },
+ requestParams: { limit: 10 },
});
UserTabs.renderMostRecentBlocks('#js-overview .projects-block', {
requestParams: { limit: 10, skip_pagination: true },
@@ -198,52 +200,39 @@ export default class UserTabs {
container,
url: $(`${container} .overview-content-list`).data('href'),
...options,
+ postRenderCallback: () => localTimeAgo($('.js-timeago', container)),
});
}
- loadActivityCalendar(action) {
- const monthsAgo = action === 'overview' ? CALENDAR_PERIOD_6_MONTHS : CALENDAR_PERIOD_12_MONTHS;
+ loadActivityCalendar() {
const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar');
const calendarPath = $calendarWrap.data('calendarPath');
+
+ AjaxCache.retrieve(calendarPath)
+ .then(data => UserTabs.renderActivityCalendar(data, $calendarWrap))
+ .catch(() => flash(__('There was an error loading users activity calendar.')));
+ }
+
+ static renderActivityCalendar(data, $calendarWrap) {
+ const monthsAgo = UserTabs.getVisibleCalendarPeriod($calendarWrap);
const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath');
const utcOffset = $calendarWrap.data('utcOffset');
- let utcFormatted = 'UTC';
- if (utcOffset !== 0) {
- utcFormatted = `UTC${utcOffset > 0 ? '+' : ''}${utcOffset / 3600}`;
- }
+ const calendarHint = __('Issues, merge requests, pushes and comments.');
- axios
- .get(calendarPath)
- .then(({ data }) => {
- $calendarWrap.html(CALENDAR_TEMPLATES[action]);
-
- let calendarHint = '';
-
- if (action === 'activity') {
- calendarHint = sprintf(
- __(
- 'Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})',
- ),
- { utcFormatted },
- );
- } else if (action === 'overview') {
- calendarHint = __('Issues, merge requests, pushes and comments.');
- }
-
- $calendarWrap.find('.calendar-hint').text(calendarHint);
-
- // eslint-disable-next-line no-new
- new ActivityCalendar(
- '.tab-pane.active .js-contrib-calendar',
- '.tab-pane.active .user-calendar-activities',
- data,
- calendarActivitiesPath,
- utcOffset,
- 0,
- monthsAgo,
- );
- })
- .catch(() => flash(__('There was an error loading users activity calendar.')));
+ $calendarWrap.html(CALENDAR_TEMPLATE);
+
+ $calendarWrap.find('.calendar-hint').text(calendarHint);
+
+ // eslint-disable-next-line no-new
+ new ActivityCalendar(
+ '.tab-pane.active .js-contrib-calendar',
+ '.tab-pane.active .user-calendar-activities',
+ data,
+ calendarActivitiesPath,
+ utcOffset,
+ 0,
+ monthsAgo,
+ );
}
toggleLoading(status) {
@@ -267,4 +256,11 @@ export default class UserTabs {
getCurrentAction() {
return this.$parentEl.find('.nav-links a.active').data('action');
}
+
+ static getVisibleCalendarPeriod($calendarWrap) {
+ const width = $calendarWrap.width();
+ return width < OVERVIEW_CALENDAR_BREAKPOINT
+ ? CALENDAR_PERIOD_6_MONTHS
+ : CALENDAR_PERIOD_12_MONTHS;
+ }
}
diff --git a/app/assets/javascripts/pdf/index.vue b/app/assets/javascripts/pdf/index.vue
index 7b079fe02d9..cdf1257b4e3 100644
--- a/app/assets/javascripts/pdf/index.vue
+++ b/app/assets/javascripts/pdf/index.vue
@@ -56,9 +56,7 @@ export default {
</script>
<template>
- <div
- v-if="hasPDF"
- class="pdf-viewer">
+ <div v-if="hasPDF" class="pdf-viewer">
<page
v-for="(page, index) in pages"
:key="index"
diff --git a/app/assets/javascripts/pdf/page/index.vue b/app/assets/javascripts/pdf/page/index.vue
index 96aadf41653..f16aaca6cd7 100644
--- a/app/assets/javascripts/pdf/page/index.vue
+++ b/app/assets/javascripts/pdf/page/index.vue
@@ -45,12 +45,7 @@ export default {
</script>
<template>
- <canvas
- ref="canvas"
- :data-page="number"
- class="pdf-page"
- >
- </canvas>
+ <canvas ref="canvas" :data-page="number" class="pdf-page"> </canvas>
</template>
<style>
diff --git a/app/assets/javascripts/performance_bar/components/detailed_metric.vue b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
index dc7d6d29b8f..c729198c1d3 100644
--- a/app/assets/javascripts/performance_bar/components/detailed_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
@@ -38,20 +38,14 @@ export default {
};
</script>
<template>
- <div
- v-if="currentRequest.details"
- :id="`peek-view-${metric}`"
- class="view"
- >
+ <div v-if="currentRequest.details" :id="`peek-view-${metric}`" class="view">
<button
:data-target="`#modal-peek-${metric}-details`"
class="btn-blank btn-link bold"
type="button"
data-toggle="modal"
>
- {{ metricDetails.duration }}
- /
- {{ metricDetails.calls }}
+ {{ metricDetails.duration }} / {{ metricDetails.calls }}
</button>
<gl-modal
:id="`modal-peek-${metric}-details`"
@@ -59,35 +53,23 @@ export default {
modal-size="xl"
class="performance-bar-modal"
>
- <table
- class="table"
- >
+ <table class="table">
<template v-if="detailsList.length">
- <tr
- v-for="(item, index) in detailsList"
- :key="index"
- >
- <td><strong>{{ item.duration }}ms</strong></td>
- <td
- v-for="key in keys"
- :key="key"
- class="break-word"
- >
- {{ item[key] }}
+ <tr v-for="(item, index) in detailsList" :key="index">
+ <td>
+ <strong>{{ item.duration }}ms</strong>
</td>
+ <td v-for="key in keys" :key="key" class="break-word">{{ item[key] }}</td>
</tr>
</template>
<template v-else>
<tr>
- <td>
- No {{ header.toLowerCase() }} for this request.
- </td>
+ <td>No {{ header.toLowerCase() }} for this request.</td>
</tr>
</template>
</table>
- <div slot="footer">
- </div>
+ <div slot="footer"></div>
</gl-modal>
{{ metric }}
</div>
diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
index 300d453c174..74faa35358d 100644
--- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
+++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
@@ -91,25 +91,15 @@ export default {
};
</script>
<template>
- <div
- id="js-peek"
- :class="env"
- >
- <div
- v-if="currentRequest"
- class="d-flex container-fluid container-limited"
- >
- <div
- id="peek-view-host"
- class="view"
- >
+ <div id="js-peek" :class="env">
+ <div v-if="currentRequest" class="d-flex container-fluid container-limited">
+ <div id="peek-view-host" class="view">
<span
v-if="hasHost"
class="current-host"
- :class="{ 'canary' : currentRequest.details.host.canary }"
+ :class="{ canary: currentRequest.details.host.canary }"
>
- <span v-html="birdEmoji"></span>
- {{ currentRequest.details.host.hostname }}
+ <span v-html="birdEmoji"></span> {{ currentRequest.details.host.hostname }}
</span>
</div>
<detailed-metric
@@ -121,11 +111,7 @@ export default {
:details="metric.details"
:keys="metric.keys"
/>
- <div
- v-if="initialRequest"
- id="peek-view-rblineprof"
- class="view"
- >
+ <div v-if="initialRequest" id="peek-view-rblineprof" class="view">
<button
v-if="lineProfileModal.length"
class="btn-link btn-blank"
@@ -134,12 +120,7 @@ export default {
>
profile
</button>
- <a
- v-else
- :href="profileUrl"
- >
- profile
- </a>
+ <a v-else :href="profileUrl"> profile </a>
</div>
<simple-metric
v-for="metric in $options.simpleMetrics"
@@ -147,18 +128,10 @@ export default {
:current-request="currentRequest"
:metric="metric"
/>
- <div
- id="peek-view-gc"
- class="view"
- >
- <span
- v-if="currentRequest.details"
- class="bold"
- >
- <span title="Invoke Time">{{ currentRequest.details.gc.gc_time }}</span>ms
- /
- <span title="Invoke Count">{{ currentRequest.details.gc.invokes }}</span>
- gc
+ <div id="peek-view-gc" class="view">
+ <span v-if="currentRequest.details" class="bold">
+ <span title="Invoke Time">{{ currentRequest.details.gc.gc_time }}</span
+ >ms / <span title="Invoke Count">{{ currentRequest.details.gc.invokes }}</span> gc
</span>
</div>
<request-selector
diff --git a/app/assets/javascripts/performance_bar/components/request_selector.vue b/app/assets/javascripts/performance_bar/components/request_selector.vue
index ad74f7b38f9..fdb5c0d6939 100644
--- a/app/assets/javascripts/performance_bar/components/request_selector.vue
+++ b/app/assets/javascripts/performance_bar/components/request_selector.vue
@@ -37,11 +37,7 @@ export default {
<template>
<div id="peek-request-selector">
<select v-model="currentRequestId">
- <option
- v-for="request in requests"
- :key="request.id"
- :value="request.id"
- >
+ <option v-for="request in requests" :key="request.id" :value="request.id">
{{ truncatedUrl(request.url) }}
</option>
</select>
diff --git a/app/assets/javascripts/performance_bar/components/simple_metric.vue b/app/assets/javascripts/performance_bar/components/simple_metric.vue
index 7a558558c4d..358a57d5bc5 100644
--- a/app/assets/javascripts/performance_bar/components/simple_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/simple_metric.vue
@@ -26,18 +26,8 @@ export default {
};
</script>
<template>
- <div
- :id="`peek-view-${metric}`"
- class="view"
- >
- <span
- v-if="currentRequest.details"
- class="bold"
- >
- {{ duration }}
- /
- {{ calls }}
- </span>
+ <div :id="`peek-view-${metric}`" class="view">
+ <span v-if="currentRequest.details" class="bold"> {{ duration }} / {{ calls }} </span>
{{ metric }}
</div>
</template>
diff --git a/app/assets/javascripts/performance_bar/services/performance_bar_service.js b/app/assets/javascripts/performance_bar/services/performance_bar_service.js
index 3a496fa2ed8..d8c23c82f7f 100644
--- a/app/assets/javascripts/performance_bar/services/performance_bar_service.js
+++ b/app/assets/javascripts/performance_bar/services/performance_bar_service.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import _ from 'underscore';
import axios from '../../lib/utils/axios_utils';
+import { parseBoolean } from '~/lib/utils/common_utils';
let vueResourceInterceptor;
@@ -41,7 +42,8 @@ export default class PerformanceBarService {
// Vue Resource.
const requestUrl = (response.config || response).url;
const apiRequest = requestUrl && requestUrl.match(/^\/api\//);
- const cachedResponse = response.headers && response.headers['x-gitlab-from-cache'] === 'true';
+ const cachedResponse =
+ response.headers && parseBoolean(response.headers['x-gitlab-from-cache']);
const fireCallback = requestUrl !== peekUrl && requestId && !apiRequest && !cachedResponse;
return [fireCallback, requestId, requestUrl];
diff --git a/app/assets/javascripts/pipelines/components/blank_state.vue b/app/assets/javascripts/pipelines/components/blank_state.vue
index 34360105176..6c3a4a27606 100644
--- a/app/assets/javascripts/pipelines/components/blank_state.vue
+++ b/app/assets/javascripts/pipelines/components/blank_state.vue
@@ -18,9 +18,7 @@ export default {
<template>
<div class="row empty-state">
<div class="col-12">
- <div class="svg-content">
- <img :src="svgPath" />
- </div>
+ <div class="svg-content"><img :src="svgPath" /></div>
</div>
<div class="col-12 text-center">
diff --git a/app/assets/javascripts/pipelines/components/empty_state.vue b/app/assets/javascripts/pipelines/components/empty_state.vue
index 8a0259ed5a5..d16f49f981c 100644
--- a/app/assets/javascripts/pipelines/components/empty_state.vue
+++ b/app/assets/javascripts/pipelines/components/empty_state.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton } from '@gitlab-org/gitlab-ui';
+import { GlButton } from '@gitlab/ui';
export default {
name: 'PipelinesEmptyState',
@@ -25,44 +25,33 @@ export default {
<template>
<div class="row empty-state js-empty-state">
<div class="col-12">
- <div class="svg-content svg-250">
- <img :src="emptyStateSvgPath" />
- </div>
+ <div class="svg-content svg-250"><img :src="emptyStateSvgPath" /></div>
</div>
<div class="col-12">
<div class="text-content">
-
<template v-if="canSetCi">
- <h4 class="text-center">
- {{ s__('Pipelines|Build with confidence') }}
- </h4>
+ <h4 class="text-center">{{ s__('Pipelines|Build with confidence') }}</h4>
<p>
- {{ s__(`Pipelines|Continuous Integration can help
+ {{
+ s__(`Pipelines|Continuous Integration can help
catch bugs by running your tests automatically,
while Continuous Deployment can help you deliver
- code to your product environment.`) }}
+ code to your product environment.`)
+ }}
</p>
<div class="text-center">
- <gl-button
- :href="helpPagePath"
- variant="primary"
- class="js-get-started-pipelines"
- >
+ <gl-button :href="helpPagePath" variant="primary" class="js-get-started-pipelines">
{{ s__('Pipelines|Get started with Pipelines') }}
</gl-button>
</div>
</template>
- <p
- v-else
- class="text-center"
- >
+ <p v-else class="text-center">
{{ s__('Pipelines|This project is not currently set up to run pipelines.') }}
</p>
-
</div>
</div>
</div>
diff --git a/app/assets/javascripts/pipelines/components/graph/action_component.vue b/app/assets/javascripts/pipelines/components/graph/action_component.vue
index f6a97236ebf..8ca539351a7 100644
--- a/app/assets/javascripts/pipelines/components/graph/action_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/action_component.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective, GlButton } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective, GlButton } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
import { dasherize } from '~/lib/utils/text_utility';
import { __ } from '~/locale';
@@ -86,6 +86,6 @@ export default {
btn-transparent ci-action-icon-container ci-action-icon-wrapper"
@click="onClickAction"
>
- <icon :name="actionIcon"/>
+ <icon :name="actionIcon" />
</gl-button>
</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
index 4de8b3401e8..59cebaba717 100644
--- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
@@ -1,6 +1,6 @@
<script>
import _ from 'underscore';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import StageColumnComponent from './stage_column_component.vue';
export default {
@@ -18,23 +18,19 @@ export default {
required: true,
},
},
-
computed: {
graph() {
return this.pipeline.details && this.pipeline.details.stages;
},
},
-
methods: {
capitalizeStageName(name) {
const escapedName = _.escape(name);
return escapedName.charAt(0).toUpperCase() + escapedName.slice(1);
},
-
isFirstColumn(index) {
return index === 0;
},
-
stageConnectorClass(index, stage) {
let className;
@@ -48,7 +44,6 @@ export default {
return className;
},
-
refreshPipelineGraph() {
this.$emit('refreshPipelineGraph');
},
@@ -58,16 +53,9 @@ export default {
<template>
<div class="build-content middle-block js-pipeline-graph">
<div class="pipeline-visualization pipeline-graph pipeline-tab-content">
- <div class="text-center">
- <gl-loading-icon
- v-if="isLoading"
- :size="3"
- />
- </div>
+ <div class="text-center"><gl-loading-icon v-if="isLoading" :size="3" /></div>
- <ul
- v-if="!isLoading"
- class="stage-column-list">
+ <ul v-if="!isLoading" class="stage-column-list">
<stage-column-component
v-for="(stage, index) in graph"
:key="stage.name"
diff --git a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
index 2c3cb1959b5..482898b80c4 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
@@ -1,6 +1,6 @@
<script>
import $ from 'jquery';
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import JobItem from './job_item.vue';
@@ -69,22 +69,15 @@ export default {
>
<ci-icon :status="group.status" />
- <span class="ci-status-text">
- {{ group.name }}
- </span>
+ <span class="ci-status-text"> {{ group.name }} </span>
- <span class="dropdown-counter-badge">
- {{ group.size }}
- </span>
+ <span class="dropdown-counter-badge"> {{ group.size }} </span>
</button>
<ul class="dropdown-menu big-pipeline-graph-dropdown-menu js-grouped-pipeline-dropdown">
<li class="scrollable-menu">
<ul>
- <li
- v-for="job in group.jobs"
- :key="job.id"
- >
+ <li v-for="job in group.jobs" :key="job.id">
<job-item
:dropdown-length="group.size"
:job="job"
diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue
index 182849c6455..cf9db89e32b 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_item.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue
@@ -1,7 +1,7 @@
<script>
import ActionComponent from './action_component.vue';
import JobNameComponent from './job_name_component.vue';
-import { GlTooltipDirective, GlLink } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective, GlLink } from '@gitlab/ui';
import { sprintf } from '~/locale';
import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
@@ -84,10 +84,6 @@ export default {
return textBuilder.join(' ');
},
-
- tooltipBoundary() {
- return this.dropdownLength < 5 ? 'viewport' : null;
- },
/**
* Verifies if the provided job has an action path
*
@@ -108,16 +104,13 @@ export default {
<div class="ci-job-component">
<gl-link
v-if="status.has_details"
- v-gl-tooltip="{ boundary: tooltipBoundary }"
+ v-gl-tooltip
:href="status.details_path"
:title="tooltipText"
:class="cssClassJobName"
class="js-pipeline-graph-job-link"
>
- <job-name-component
- :name="job.name"
- :status="job.status"
- />
+ <job-name-component :name="job.name" :status="job.status" />
</gl-link>
<div
@@ -127,11 +120,7 @@ export default {
:class="cssClassJobName"
class="js-job-component-tooltip non-details-job-component"
>
-
- <job-name-component
- :name="job.name"
- :status="job.status"
- />
+ <job-name-component :name="job.name" :status="job.status" />
</div>
<action-component
diff --git a/app/assets/javascripts/pipelines/components/graph/job_name_component.vue b/app/assets/javascripts/pipelines/components/graph/job_name_component.vue
index 6fdbcc1e049..1bfab2a7fc0 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_name_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_name_component.vue
@@ -28,8 +28,6 @@ export default {
<span class="ci-job-name-component">
<ci-icon :status="status" />
- <span class="ci-status-text">
- {{ name }}
- </span>
+ <span class="ci-status-text"> {{ name }} </span>
</span>
</template>
diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
index d5f931943d5..09a50d25020 100644
--- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
@@ -42,13 +42,8 @@ export default {
};
</script>
<template>
- <li
- :class="stageConnectorClass"
- class="stage-column"
- >
- <div class="stage-name">
- {{ title }}
- </div>
+ <li :class="stageConnectorClass" class="stage-column">
+ <div class="stage-name">{{ title }}</div>
<div class="builds-container">
<ul>
<li
@@ -58,7 +53,6 @@ export default {
:class="buildConnnectorClass(index)"
class="build"
>
-
<div class="curve"></div>
<job-item
diff --git a/app/assets/javascripts/pipelines/components/header_component.vue b/app/assets/javascripts/pipelines/components/header_component.vue
index 8f004b491c8..b2e365e5cde 100644
--- a/app/assets/javascripts/pipelines/components/header_component.vue
+++ b/app/assets/javascripts/pipelines/components/header_component.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import ciHeader from '../../vue_shared/components/header_ci_component.vue';
import eventHub from '../event_hub';
@@ -89,10 +89,6 @@ export default {
item-name="Pipeline"
@actionClicked="postAction"
/>
- <gl-loading-icon
- v-if="isLoading"
- :size="2"
- class="prepend-top-default append-bottom-default"
- />
+ <gl-loading-icon v-if="isLoading" :size="2" class="prepend-top-default append-bottom-default" />
</div>
</template>
diff --git a/app/assets/javascripts/pipelines/components/nav_controls.vue b/app/assets/javascripts/pipelines/components/nav_controls.vue
index 0911acbb131..c6990683ec7 100644
--- a/app/assets/javascripts/pipelines/components/nav_controls.vue
+++ b/app/assets/javascripts/pipelines/components/nav_controls.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink, GlButton } from '@gitlab-org/gitlab-ui';
+import { GlLink, GlButton } from '@gitlab/ui';
import LoadingButton from '../../vue_shared/components/loading_button.vue';
export default {
@@ -60,11 +60,7 @@ export default {
@click="onClickResetCache"
/>
- <gl-button
- v-if="ciLintPath"
- :href="ciLintPath"
- class="js-ci-lint"
- >
+ <gl-button v-if="ciLintPath" :href="ciLintPath" class="js-ci-lint">
{{ s__('Pipelines|CI Lint') }}
</gl-button>
</div>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index be4b37f3c8c..30a5bbf92ce 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlLink, GlTooltipDirective } from '@gitlab/ui';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import popover from '~/vue_shared/directives/popover';
@@ -48,10 +48,7 @@ export default {
</script>
<template>
<div class="table-section section-15 d-none d-sm-none d-md-block pipeline-tags">
- <gl-link
- :href="pipeline.path"
- class="js-pipeline-url-link"
- >
+ <gl-link :href="pipeline.path" class="js-pipeline-url-link">
<span class="pipeline-id">#{{ pipeline.id }}</span>
</gl-link>
<span>by</span>
@@ -62,17 +59,13 @@ export default {
:tooltip-text="pipeline.user.name"
class="js-pipeline-url-user"
/>
- <span
- v-if="!user"
- class="js-pipeline-url-api api">
- API
- </span>
+ <span v-if="!user" class="js-pipeline-url-api api"> API </span>
<div class="label-container">
<span
v-if="pipeline.flags.latest"
v-gl-tooltip
class="js-pipeline-url-latest badge badge-success"
- title="Latest pipeline for this branch"
+ title="__('Latest pipeline for this branch')"
>
latest
</span>
@@ -101,11 +94,16 @@ export default {
>
Auto DevOps
</gl-link>
+ <span v-if="pipeline.flags.stuck" class="js-pipeline-url-stuck badge badge-warning">
+ stuck
+ </span>
<span
- v-if="pipeline.flags.stuck"
- class="js-pipeline-url-stuck badge badge-warning"
+ v-if="pipeline.flags.merge_request"
+ v-gl-tooltip
+ title="__('This pipeline is run in a merge request context')"
+ class="js-pipeline-url-mergerequest badge badge-info"
>
- stuck
+ merge request
</span>
</div>
</div>
diff --git a/app/assets/javascripts/pipelines/components/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines.vue
index fcd8a54c9c1..9dcea557b32 100644
--- a/app/assets/javascripts/pipelines/components/pipelines.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines.vue
@@ -247,20 +247,8 @@ export default {
v-if="shouldRenderTabs || shouldRenderButtons"
class="top-area scrolling-tabs-container inner-page-scroll-tabs"
>
- <div class="fade-left">
- <i
- class="fa fa-angle-left"
- aria-hidden="true"
- >
- </i>
- </div>
- <div class="fade-right">
- <i
- class="fa fa-angle-right"
- aria-hidden="true"
- >
- </i>
- </div>
+ <div class="fade-left"><i class="fa fa-angle-left" aria-hidden="true"> </i></div>
+ <div class="fade-right"><i class="fa fa-angle-right" aria-hidden="true"> </i></div>
<navigation-tabs
v-if="shouldRenderTabs"
@@ -280,7 +268,6 @@ export default {
</div>
<div class="content-list pipelines">
-
<gl-loading-icon
v-if="stateToRender === $options.stateMap.loading"
:label="s__('Pipelines|Loading Pipelines')"
@@ -298,8 +285,10 @@ export default {
<svg-blank-state
v-else-if="stateToRender === $options.stateMap.error"
:svg-path="errorStateSvgPath"
- :message="s__(`Pipelines|There was an error fetching the pipelines.
- Try again in a few moments or contact your support team.`)"
+ :message="
+ s__(`Pipelines|There was an error fetching the pipelines.
+ Try again in a few moments or contact your support team.`)
+ "
/>
<svg-blank-state
@@ -308,11 +297,7 @@ export default {
:message="emptyTabMessage"
/>
- <div
- v-else-if="stateToRender === $options.stateMap.tableList"
- class="table-holder"
- >
-
+ <div v-else-if="stateToRender === $options.stateMap.tableList" class="table-holder">
<pipelines-table-component
:pipelines="state.pipelines"
:update-graph-dropdown="updateGraphDropdown"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue
index 811495c45a9..2e9f2519fcb 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_actions.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
import eventHub from '../event_hub';
@@ -67,33 +67,20 @@ export default {
data-toggle="dropdown"
aria-label="Manual job"
>
- <icon
- name="play"
- class="icon-play"
- />
- <i
- class="fa fa-caret-down"
- aria-hidden="true">
- </i>
+ <icon name="play" class="icon-play" /> <i class="fa fa-caret-down" aria-hidden="true"> </i>
<gl-loading-icon v-if="isLoading" />
</gl-button>
<ul class="dropdown-menu dropdown-menu-right">
- <li
- v-for="action in actions"
- :key="action.path"
- >
+ <li v-for="action in actions" :key="action.path">
<gl-button
:class="{ disabled: isActionDisabled(action) }"
:disabled="isActionDisabled(action)"
class="js-pipeline-action-link no-btn btn"
- @click="onClickAction(action)"
+ @click="onClickAction(action);"
>
{{ action.name }}
- <span
- v-if="action.scheduled_at"
- class="pull-right"
- >
+ <span v-if="action.scheduled_at" class="pull-right">
<icon name="clock" />
<gl-countdown :end-date-string="action.scheduled_at" />
</span>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue
index 2abb24b87b6..908b10afee6 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink, GlButton, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlLink, GlButton, GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
export default {
@@ -20,10 +20,7 @@ export default {
};
</script>
<template>
- <div
- class="btn-group"
- role="group"
- >
+ <div class="btn-group" role="group">
<gl-button
v-gl-tooltip
class="dropdown-toggle build-artifacts js-pipeline-dropdown-download"
@@ -31,23 +28,11 @@ export default {
data-toggle="dropdown"
aria-label="Artifacts"
>
- <icon name="download" />
- <i
- class="fa fa-caret-down"
- aria-hidden="true"
- >
- </i>
+ <icon name="download" /> <i class="fa fa-caret-down" aria-hidden="true"> </i>
</gl-button>
<ul class="dropdown-menu dropdown-menu-right">
- <li
- v-for="(artifact, i) in artifacts"
- :key="i"
- >
- <gl-link
- :href="artifact.path"
- rel="nofollow"
- download
- >
+ <li v-for="(artifact, i) in artifacts" :key="i">
+ <gl-link :href="artifact.path" rel="nofollow" download>
Download {{ artifact.name }} artifacts
</gl-link>
</li>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_table.vue
index 3339b5c13ed..1c60ae6a152 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_table.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_table.vue
@@ -80,32 +80,17 @@ export default {
</script>
<template>
<div class="ci-table">
- <div
- class="gl-responsive-table-row table-row-header"
- role="row"
- >
- <div
- class="table-section section-10 js-pipeline-status pipeline-status"
- role="rowheader"
- >
+ <div class="gl-responsive-table-row table-row-header" role="row">
+ <div class="table-section section-10 js-pipeline-status pipeline-status" role="rowheader">
{{ s__('Pipeline|Status') }}
</div>
- <div
- class="table-section section-15 js-pipeline-info pipeline-info"
- role="rowheader"
- >
+ <div class="table-section section-15 js-pipeline-info pipeline-info" role="rowheader">
{{ s__('Pipeline|Pipeline') }}
</div>
- <div
- class="table-section section-20 js-pipeline-commit pipeline-commit"
- role="rowheader"
- >
+ <div class="table-section section-20 js-pipeline-commit pipeline-commit" role="rowheader">
{{ s__('Pipeline|Commit') }}
</div>
- <div
- class="table-section section-20 js-pipeline-stages pipeline-stages"
- role="rowheader"
- >
+ <div class="table-section section-20 js-pipeline-stages pipeline-stages" role="rowheader">
{{ s__('Pipeline|Stages') }}
</div>
</div>
@@ -128,6 +113,5 @@ export default {
>
<span v-html="modalText"></span>
</modal>
-
</div>
</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
index fd674a8d447..da42698c255 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
@@ -257,32 +257,16 @@ export default {
<template>
<div class="commit gl-responsive-table-row">
<div class="table-section section-10 commit-link">
- <div
- class="table-mobile-header"
- role="rowheader"
- >
- {{ s__('Pipeline|Status') }}
- </div>
+ <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Status') }}</div>
<div class="table-mobile-content">
- <ci-badge
- :status="pipelineStatus"
- :show-text="!isChildView"
- />
+ <ci-badge :status="pipelineStatus" :show-text="!isChildView" />
</div>
</div>
- <pipeline-url
- :pipeline="pipeline"
- :auto-devops-help-path="autoDevopsHelpPath"
- />
+ <pipeline-url :pipeline="pipeline" :auto-devops-help-path="autoDevopsHelpPath" />
<div class="table-section section-20">
- <div
- class="table-mobile-header"
- role="rowheader"
- >
- {{ s__('Pipeline|Commit') }}
- </div>
+ <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Commit') }}</div>
<div class="table-mobile-content">
<commit-component
:tag="commitTag"
@@ -297,12 +281,7 @@ export default {
</div>
<div class="table-section section-wrap section-20 stage-cell">
- <div
- class="table-mobile-header"
- role="rowheader"
- >
- {{ s__('Pipeline|Stages') }}
- </div>
+ <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Stages') }}</div>
<div class="table-mobile-content">
<template v-if="pipeline.details.stages.length > 0">
<div
@@ -320,20 +299,14 @@ export default {
</div>
</div>
- <pipelines-timeago
- :duration="pipelineDuration"
- :finished-time="pipelineFinishedAt"
- />
+ <pipelines-timeago :duration="pipelineDuration" :finished-time="pipelineFinishedAt" />
<div
v-if="displayPipelineActions"
class="table-section section-20 table-button-footer pipeline-actions"
>
<div class="btn-group table-action-buttons">
- <pipelines-actions-component
- v-if="actions.length > 0"
- :actions="actions"
- />
+ <pipelines-actions-component v-if="actions.length > 0" :actions="actions" />
<pipelines-artifacts-component
v-if="pipeline.details.artifacts.length"
diff --git a/app/assets/javascripts/pipelines/components/stage.vue b/app/assets/javascripts/pipelines/components/stage.vue
index 587c4ffa45c..2d3f667e73e 100644
--- a/app/assets/javascripts/pipelines/components/stage.vue
+++ b/app/assets/javascripts/pipelines/components/stage.vue
@@ -13,7 +13,7 @@
*/
import $ from 'jquery';
-import { GlLoadingIcon, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '../../locale';
import Flash from '../../flash';
import axios from '../../lib/utils/axios_utils';
@@ -169,35 +169,20 @@ export default {
aria-expanded="false"
@click="onClickStage"
>
-
- <span
- :aria-label="stage.title"
- aria-hidden="true"
- class="no-pointer-events"
- >
+ <span :aria-label="stage.title" aria-hidden="true" class="no-pointer-events">
<icon :name="borderlessIcon" />
</span>
- <i
- class="fa fa-caret-down"
- aria-hidden="true"
- >
- </i>
+ <i class="fa fa-caret-down" aria-hidden="true"> </i>
</button>
<div
class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container"
aria-labelledby="stageDropdown"
>
- <gl-loading-icon v-if="isLoading"/>
- <ul
- v-else
- class="js-builds-dropdown-list scrollable-menu"
- >
- <li
- v-for="job in dropdownContent"
- :key="job.id"
- >
+ <gl-loading-icon v-if="isLoading" />
+ <ul v-else class="js-builds-dropdown-list scrollable-menu">
+ <li v-for="job in dropdownContent" :key="job.id">
<job-item
:dropdown-length="dropdownContent.length"
:job="job"
diff --git a/app/assets/javascripts/pipelines/components/time_ago.vue b/app/assets/javascripts/pipelines/components/time_ago.vue
index bed690200b8..2ed0c24825c 100644
--- a/app/assets/javascripts/pipelines/components/time_ago.vue
+++ b/app/assets/javascripts/pipelines/components/time_ago.vue
@@ -56,32 +56,14 @@ export default {
</script>
<template>
<div class="table-section section-15 pipelines-time-ago">
- <div
- class="table-mobile-header"
- role="rowheader"
- >
- {{ s__('Pipeline|Duration') }}
- </div>
+ <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Duration') }}</div>
<div class="table-mobile-content">
- <p
- v-if="hasDuration"
- class="duration"
- >
- <span v-html="iconTimerSvg">
- </span>
- {{ durationFormated }}
+ <p v-if="hasDuration" class="duration">
+ <span v-html="iconTimerSvg"> </span> {{ durationFormated }}
</p>
- <p
- v-if="hasFinishedTime"
- class="finished-at d-none d-sm-none d-md-block"
- >
-
- <i
- class="fa fa-calendar"
- aria-hidden="true"
- >
- </i>
+ <p v-if="hasFinishedTime" class="finished-at d-none d-sm-none d-md-block">
+ <i class="fa fa-calendar" aria-hidden="true"> </i>
<time
v-tooltip
diff --git a/app/assets/javascripts/pipelines/mixins/pipelines.js b/app/assets/javascripts/pipelines/mixins/pipelines.js
index 41bc5dcce5c..32bfa47e5f2 100644
--- a/app/assets/javascripts/pipelines/mixins/pipelines.js
+++ b/app/assets/javascripts/pipelines/mixins/pipelines.js
@@ -1,5 +1,5 @@
import Visibility from 'visibilityjs';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import { __ } from '../../locale';
import Flash from '../../flash';
import Poll from '../../lib/utils/poll';
diff --git a/app/assets/javascripts/profile/account/components/delete_account_modal.vue b/app/assets/javascripts/profile/account/components/delete_account_modal.vue
index 99b57f4c9d5..85c5c073a74 100644
--- a/app/assets/javascripts/profile/account/components/delete_account_modal.vue
+++ b/app/assets/javascripts/profile/account/components/delete_account_modal.vue
@@ -83,34 +83,16 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
:primary-button-label="s__('Profiles|Delete account')"
:submit-disabled="!canSubmit()"
kind="danger"
- @submit="onSubmit">
-
- <template
- slot="body"
- slot-scope="props">
+ @submit="onSubmit"
+ >
+ <template slot="body" slot-scope="props">
<p v-html="props.text"></p>
- <form
- ref="form"
- :action="actionUrl"
- method="post">
+ <form ref="form" :action="actionUrl" method="post">
+ <input type="hidden" name="_method" value="delete" />
+ <input :value="csrfToken" type="hidden" name="authenticity_token" />
- <input
- type="hidden"
- name="_method"
- value="delete"
- />
- <input
- :value="csrfToken"
- type="hidden"
- name="authenticity_token"
- />
-
- <p
- id="input-label"
- v-html="inputLabel"
- >
- </p>
+ <p id="input-label" v-html="inputLabel"></p>
<input
v-if="confirmWithPassword"
@@ -130,6 +112,5 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
/>
</form>
</template>
-
</deprecated-modal>
</template>
diff --git a/app/assets/javascripts/profile/account/components/update_username.vue b/app/assets/javascripts/profile/account/components/update_username.vue
index ef484ddfd61..e1085c0a44d 100644
--- a/app/assets/javascripts/profile/account/components/update_username.vue
+++ b/app/assets/javascripts/profile/account/components/update_username.vue
@@ -87,9 +87,7 @@ Please update your Git repository remotes as soon as possible.`),
<label :for="$options.inputId">{{ s__('Profiles|Path') }}</label>
<div class="input-group">
<div class="input-group-prepend">
- <div class="input-group-text">
- {{ rootUrl }}
- </div>
+ <div class="input-group-text">{{ rootUrl }}</div>
</div>
<input
:id="$options.inputId"
@@ -99,9 +97,7 @@ Please update your Git repository remotes as soon as possible.`),
required="required"
/>
</div>
- <p class="form-text text-muted">
- {{ path }}
- </p>
+ <p class="form-text text-muted">{{ path }}</p>
</div>
<button
:data-target="`#${$options.modalId}`"
diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js
index 8704a655b28..deacff5abe7 100644
--- a/app/assets/javascripts/profile/profile.js
+++ b/app/assets/javascripts/profile/profile.js
@@ -1,6 +1,7 @@
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import flash from '../flash';
+import { parseBoolean } from '~/lib/utils/common_utils';
export default class Profile {
constructor({ form } = {}) {
@@ -80,7 +81,7 @@ export default class Profile {
setRepoRadio() {
const multiEditRadios = $('input[name="user[multi_file]"]');
- if (this.newRepoActivated || this.newRepoActivated === 'true') {
+ if (parseBoolean(this.newRepoActivated)) {
multiEditRadios.filter('[value=on]').prop('checked', true);
} else {
multiEditRadios.filter('[value=off]').prop('checked', true);
diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js
index f1fff173619..a33835472bb 100644
--- a/app/assets/javascripts/project_select.js
+++ b/app/assets/javascripts/project_select.js
@@ -14,6 +14,9 @@ export default function projectSelect() {
this.orderBy = $(select).data('orderBy') || 'id';
this.withIssuesEnabled = $(select).data('withIssuesEnabled');
this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled');
+ this.withShared =
+ $(select).data('withShared') === undefined ? true : $(select).data('withShared');
+ this.includeProjectsInSubgroups = $(select).data('includeProjectsInSubgroups') || false;
this.allowClear = $(select).data('allowClear') || false;
placeholder = 'Search for project';
@@ -54,6 +57,8 @@ export default function projectSelect() {
{
with_issues_enabled: _this.withIssuesEnabled,
with_merge_requests_enabled: _this.withMergeRequestsEnabled,
+ with_shared: _this.withShared,
+ include_subgroups: _this.includeProjectsInSubgroups,
},
projectsCallback,
);
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js
index f5dae5ad808..5a3407693e5 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js
@@ -2,7 +2,7 @@ import _ from 'underscore';
import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_search_input.vue';
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import store from '../store';
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue
index 2c02f436b69..21095fcba16 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_machine_type_dropdown.vue
@@ -47,7 +47,7 @@ export default {
errorMessage() {
return sprintf(
s__(
- 'ClusterIntegration|An error occured while trying to fetch zone machine types: %{error}',
+ 'ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}',
),
{ error: this.gapiError },
);
@@ -87,13 +87,8 @@ export default {
<template>
<div>
- <div
- class="js-gcp-machine-type-dropdown dropdown"
- >
- <dropdown-hidden-input
- :name="fieldName"
- :value="selectedMachineType"
- />
+ <div class="js-gcp-machine-type-dropdown dropdown">
+ <dropdown-hidden-input :name="fieldName" :value="selectedMachineType" />
<dropdown-button
:class="{ 'border-danger': hasErrors }"
:is-disabled="isDisabled"
@@ -112,29 +107,21 @@ export default {
{{ s__('ClusterIntegration|No machine types matched your search') }}
</span>
</li>
- <li
- v-for="result in results"
- :key="result.id"
- >
- <button
- type="button"
- @click.prevent="setItem(result.name)"
- >
+ <li v-for="result in results" :key="result.id">
+ <button type="button" @click.prevent="setItem(result.name);">
{{ result.name }}
</button>
</li>
</ul>
</div>
- <div class="dropdown-loading">
- <gl-loading-icon />
- </div>
+ <div class="dropdown-loading"><gl-loading-icon /></div>
</div>
</div>
<span
v-if="hasErrors"
:class="{
'text-danger': hasErrors,
- 'text-muted': !hasErrors
+ 'text-muted': !hasErrors,
}"
class="form-text"
>
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue
index fc17e2fab49..056584c8865 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown.vue
@@ -93,7 +93,7 @@ export default {
}
return sprintf(
- s__('ClusterIntegration|An error occured while trying to fetch your projects: %{error}'),
+ s__('ClusterIntegration|An error occurred while trying to fetch your projects: %{error}'),
{ error: this.gapiError },
);
},
@@ -145,17 +145,12 @@ export default {
<template>
<div>
- <div
- class="js-gcp-project-id-dropdown dropdown"
- >
- <dropdown-hidden-input
- :name="fieldName"
- :value="selectedProject.projectId"
- />
+ <div class="js-gcp-project-id-dropdown dropdown">
+ <dropdown-hidden-input :name="fieldName" :value="selectedProject.projectId" />
<dropdown-button
:class="{
'border-danger': hasErrors,
- 'read-only': hasOneProject
+ 'read-only': hasOneProject,
}"
:is-disabled="isDisabled"
:is-loading="isLoading"
@@ -173,28 +168,18 @@ export default {
{{ s__('ClusterIntegration|No projects matched your search') }}
</span>
</li>
- <li
- v-for="result in results"
- :key="result.project_number"
- >
- <button
- type="button"
- @click.prevent="setItem(result)"
- >
- {{ result.name }}
- </button>
+ <li v-for="result in results" :key="result.project_number">
+ <button type="button" @click.prevent="setItem(result);">{{ result.name }}</button>
</li>
</ul>
</div>
- <div class="dropdown-loading">
- <gl-loading-icon />
- </div>
+ <div class="dropdown-loading"><gl-loading-icon /></div>
</div>
</div>
<span
:class="{
'text-danger': hasErrors,
- 'text-muted': !hasErrors
+ 'text-muted': !hasErrors,
}"
class="form-text"
v-html="helpText"
diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue
index ca7c79f75f0..728616a441f 100644
--- a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue
+++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_zone_dropdown.vue
@@ -61,13 +61,8 @@ export default {
<template>
<div>
- <div
- class="js-gcp-zone-dropdown dropdown"
- >
- <dropdown-hidden-input
- :name="fieldName"
- :value="selectedZone"
- />
+ <div class="js-gcp-zone-dropdown dropdown">
+ <dropdown-hidden-input :name="fieldName" :value="selectedZone" />
<dropdown-button
:class="{ 'border-danger': hasErrors }"
:is-disabled="isDisabled"
@@ -86,29 +81,21 @@ export default {
{{ s__('ClusterIntegration|No zones matched your search') }}
</span>
</li>
- <li
- v-for="result in results"
- :key="result.id"
- >
- <button
- type="button"
- @click.prevent="setItem(result.name)"
- >
+ <li v-for="result in results" :key="result.id">
+ <button type="button" @click.prevent="setItem(result.name);">
{{ result.name }}
</button>
</li>
</ul>
</div>
- <div class="dropdown-loading">
- <gl-loading-icon />
- </div>
+ <div class="dropdown-loading"><gl-loading-icon /></div>
</div>
</div>
<span
v-if="hasErrors"
:class="{
'text-danger': hasErrors,
- 'text-muted': !hasErrors
+ 'text-muted': !hasErrors,
}"
class="form-text"
>
diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
index 9a729ca9b91..bfc55013a71 100644
--- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
+++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
@@ -5,7 +5,7 @@ import Poll from '~/lib/utils/poll';
import Flash from '~/flash';
import { s__, sprintf } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import CommitPipelineService from '../services/commit_pipeline_service';
export default {
@@ -100,15 +100,8 @@ export default {
</script>
<template>
<div class="ci-status-link">
- <gl-loading-icon
- v-if="isLoading"
- :size="3"
- label="Loading pipeline status"
- />
- <a
- v-else
- :href="ciStatus.details_path"
- >
+ <gl-loading-icon v-if="isLoading" :size="3" label="Loading pipeline status" />
+ <a v-else :href="ciStatus.details_path">
<ci-icon
v-tooltip
:title="statusTitle"
diff --git a/app/assets/javascripts/registry/components/app.vue b/app/assets/javascripts/registry/components/app.vue
index 0a906f40f5a..9af5660f764 100644
--- a/app/assets/javascripts/registry/components/app.vue
+++ b/app/assets/javascripts/registry/components/app.vue
@@ -1,15 +1,13 @@
<script>
import { mapGetters, mapActions } from 'vuex';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
-import Flash from '../../flash';
+import { GlLoadingIcon } from '@gitlab/ui';
import store from '../stores';
-import collapsibleContainer from './collapsible_container.vue';
-import { errorMessages, errorMessagesTypes } from '../constants';
+import CollapsibleContainer from './collapsible_container.vue';
export default {
name: 'RegistryListApp',
components: {
- collapsibleContainer,
+ CollapsibleContainer,
GlLoadingIcon,
},
props: {
@@ -26,7 +24,7 @@ export default {
this.setMainEndpoint(this.endpoint);
},
mounted() {
- this.fetchRepos().catch(() => Flash(errorMessages[errorMessagesTypes.FETCH_REPOS]));
+ this.fetchRepos();
},
methods: {
...mapActions(['setMainEndpoint', 'fetchRepos']),
@@ -35,21 +33,20 @@ export default {
</script>
<template>
<div>
- <gl-loading-icon
- v-if="isLoading"
- :size="3"
- />
+ <gl-loading-icon v-if="isLoading" :size="3" />
<collapsible-container
- v-for="(item, index) in repos"
+ v-for="item in repos"
v-else-if="!isLoading && repos.length"
- :key="index"
+ :key="item.id"
:repo="item"
/>
<p v-else-if="!isLoading && !repos.length">
- {{ __(`No container images stored for this project.
-Add one by following the instructions above.`) }}
+ {{
+ __(`No container images stored for this project.
+Add one by following the instructions above.`)
+ }}
</p>
</div>
</template>
diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue
index be9816a55c4..5451c61026c 100644
--- a/app/assets/javascripts/registry/components/collapsible_container.vue
+++ b/app/assets/javascripts/registry/components/collapsible_container.vue
@@ -1,22 +1,24 @@
<script>
import { mapActions } from 'vuex';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
-import Flash from '../../flash';
-import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
-import tooltip from '../../vue_shared/directives/tooltip';
-import tableRegistry from './table_registry.vue';
+import { GlLoadingIcon, GlButton, GlTooltipDirective } from '@gitlab/ui';
+import createFlash from '../../flash';
+import ClipboardButton from '../../vue_shared/components/clipboard_button.vue';
+import Icon from '../../vue_shared/components/icon.vue';
+import TableRegistry from './table_registry.vue';
import { errorMessages, errorMessagesTypes } from '../constants';
import { __ } from '../../locale';
export default {
name: 'CollapsibeContainerRegisty',
components: {
- clipboardButton,
- tableRegistry,
+ ClipboardButton,
+ TableRegistry,
GlLoadingIcon,
+ GlButton,
+ Icon,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
repo: {
@@ -29,30 +31,30 @@ export default {
isOpen: false,
};
},
+ computed: {
+ iconName() {
+ return this.isOpen ? 'angle-up' : 'angle-right';
+ },
+ },
methods: {
...mapActions(['fetchRepos', 'fetchList', 'deleteRepo']),
-
toggleRepo() {
this.isOpen = !this.isOpen;
if (this.isOpen) {
- this.fetchList({ repo: this.repo }).catch(() =>
- this.showError(errorMessagesTypes.FETCH_REGISTRY),
- );
+ this.fetchList({ repo: this.repo });
}
},
-
handleDeleteRepository() {
this.deleteRepo(this.repo)
.then(() => {
- Flash(__('This container registry has been scheduled for deletion.'), 'notice');
+ createFlash(__('This container registry has been scheduled for deletion.'), 'notice');
this.fetchRepos();
})
.catch(() => this.showError(errorMessagesTypes.DELETE_REPO));
},
-
showError(message) {
- Flash(errorMessages[message]);
+ createFlash(errorMessages[message]);
},
},
};
@@ -61,22 +63,9 @@ export default {
<template>
<div class="container-image">
<div class="container-image-head">
- <button
- type="button"
- class="js-toggle-repo btn-link"
- @click="toggleRepo"
- >
- <i
- :class="{
- 'fa-chevron-right': !isOpen,
- 'fa-chevron-up': isOpen,
- }"
- class="fa"
- aria-hidden="true"
- >
- </i>
- {{ repo.name }}
- </button>
+ <gl-button class="js-toggle-repo btn-link align-baseline" @click="toggleRepo">
+ <icon :name="iconName" /> {{ repo.name }}
+ </gl-button>
<clipboard-button
v-if="repo.location"
@@ -86,45 +75,27 @@ export default {
/>
<div class="controls d-none d-sm-block float-right">
- <button
+ <gl-button
v-if="repo.canDelete"
- v-tooltip
+ v-gl-tooltip
:title="s__('ContainerRegistry|Remove repository')"
:aria-label="s__('ContainerRegistry|Remove repository')"
- type="button"
- class="js-remove-repo btn btn-danger"
+ class="js-remove-repo"
+ variant="danger"
@click="handleDeleteRepository"
>
- <i
- class="fa fa-trash"
- aria-hidden="true"
- >
- </i>
- </button>
+ <icon name="remove" />
+ </gl-button>
</div>
</div>
- <gl-loading-icon
- v-if="repo.isLoading"
- :size="2"
- class="append-bottom-20"
- />
+ <gl-loading-icon v-if="repo.isLoading" :size="2" class="append-bottom-20" />
- <div
- v-else-if="!repo.isLoading && isOpen"
- class="container-image-tags"
- >
-
- <table-registry
- v-if="repo.list.length"
- :repo="repo"
- />
+ <div v-else-if="!repo.isLoading && isOpen" class="container-image-tags">
+ <table-registry v-if="repo.list.length" :repo="repo" />
- <div
- v-else
- class="nothing-here-block"
- >
- {{ s__("ContainerRegistry|No tags in Container Registry for this container image.") }}
+ <div v-else class="nothing-here-block">
+ {{ s__('ContainerRegistry|No tags in Container Registry for this container image.') }}
</div>
</div>
</div>
diff --git a/app/assets/javascripts/registry/components/table_registry.vue b/app/assets/javascripts/registry/components/table_registry.vue
index bb6c977fc63..78c7671856a 100644
--- a/app/assets/javascripts/registry/components/table_registry.vue
+++ b/app/assets/javascripts/registry/components/table_registry.vue
@@ -1,21 +1,24 @@
<script>
import { mapActions } from 'vuex';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import { n__ } from '../../locale';
-import Flash from '../../flash';
-import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
-import tablePagination from '../../vue_shared/components/table_pagination.vue';
-import tooltip from '../../vue_shared/directives/tooltip';
+import createFlash from '../../flash';
+import ClipboardButton from '../../vue_shared/components/clipboard_button.vue';
+import TablePagination from '../../vue_shared/components/table_pagination.vue';
+import Icon from '../../vue_shared/components/icon.vue';
import timeagoMixin from '../../vue_shared/mixins/timeago';
import { errorMessages, errorMessagesTypes } from '../constants';
import { numberToHumanSize } from '../../lib/utils/number_utils';
export default {
components: {
- clipboardButton,
- tablePagination,
+ ClipboardButton,
+ TablePagination,
+ GlButton,
+ Icon,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
mixins: [timeagoMixin],
props: {
@@ -31,29 +34,24 @@ export default {
},
methods: {
...mapActions(['fetchList', 'deleteRegistry']),
-
layers(item) {
return item.layers ? n__('%d layer', '%d layers', item.layers) : '';
},
-
formatSize(size) {
return numberToHumanSize(size);
},
-
handleDeleteRegistry(registry) {
this.deleteRegistry(registry)
.then(() => this.fetchList({ repo: this.repo }))
.catch(() => this.showError(errorMessagesTypes.DELETE_REGISTRY));
},
-
onPageChange(pageNumber) {
this.fetchList({ repo: this.repo, page: pageNumber }).catch(() =>
this.showError(errorMessagesTypes.FETCH_REGISTRY),
);
},
-
showError(message) {
- Flash(errorMessages[message]);
+ createFlash(errorMessages[message]);
},
},
};
@@ -65,19 +63,15 @@ export default {
<tr>
<th>{{ s__('ContainerRegistry|Tag') }}</th>
<th>{{ s__('ContainerRegistry|Tag ID') }}</th>
- <th>{{ s__("ContainerRegistry|Size") }}</th>
- <th>{{ s__("ContainerRegistry|Created") }}</th>
+ <th>{{ s__('ContainerRegistry|Size') }}</th>
+ <th>{{ s__('ContainerRegistry|Created') }}</th>
<th></th>
</tr>
</thead>
<tbody>
- <tr
- v-for="(item, i) in repo.list"
- :key="i">
+ <tr v-for="item in repo.list" :key="item.tag">
<td>
-
{{ item.tag }}
-
<clipboard-button
v-if="item.location"
:title="item.location"
@@ -86,49 +80,34 @@ export default {
/>
</td>
<td>
- <span
- v-tooltip
- :title="item.revision"
- data-placement="bottom"
- >
- {{ item.shortRevision }}
- </span>
+ <span v-gl-tooltip.bottom :title="item.revision">{{ item.shortRevision }}</span>
</td>
<td>
{{ formatSize(item.size) }}
- <template v-if="item.size && item.layers">
- &middot;
- </template>
+ <template v-if="item.size && item.layers"
+ >&middot;</template
+ >
{{ layers(item) }}
</td>
<td>
- <span
- v-tooltip
- :title="tooltipTitle(item.createdAt)"
- data-placement="bottom"
- >
- {{ timeFormated(item.createdAt) }}
- </span>
+ <span v-gl-tooltip.bottom :title="tooltipTitle(item.createdAt)">{{
+ timeFormated(item.createdAt)
+ }}</span>
</td>
<td class="content">
- <button
+ <gl-button
v-if="item.canDelete"
- v-tooltip
+ v-gl-tooltip
:title="s__('ContainerRegistry|Remove tag')"
:aria-label="s__('ContainerRegistry|Remove tag')"
- type="button"
- class="js-delete-registry btn btn-danger d-none d-sm-block float-right"
- data-container="body"
- @click="handleDeleteRegistry(item)"
+ variant="danger"
+ class="js-delete-registry d-none d-sm-block float-right"
+ @click="handleDeleteRegistry(item);"
>
- <i
- class="fa fa-trash"
- aria-hidden="true"
- >
- </i>
- </button>
+ <icon name="remove" />
+ </gl-button>
</td>
</tr>
</tbody>
diff --git a/app/assets/javascripts/registry/stores/actions.js b/app/assets/javascripts/registry/stores/actions.js
index a78aa90b7b5..51d057c62c1 100644
--- a/app/assets/javascripts/registry/stores/actions.js
+++ b/app/assets/javascripts/registry/stores/actions.js
@@ -1,39 +1,45 @@
-import Vue from 'vue';
-import VueResource from 'vue-resource';
+import axios from '~/lib/utils/axios_utils';
+import createFlash from '~/flash';
import * as types from './mutation_types';
-
-Vue.use(VueResource);
+import { errorMessages, errorMessagesTypes } from '../constants';
export const fetchRepos = ({ commit, state }) => {
commit(types.TOGGLE_MAIN_LOADING);
- return Vue.http
+ return axios
.get(state.endpoint)
- .then(res => res.json())
- .then(response => {
+ .then(({ data }) => {
+ commit(types.TOGGLE_MAIN_LOADING);
+ commit(types.SET_REPOS_LIST, data);
+ })
+ .catch(() => {
commit(types.TOGGLE_MAIN_LOADING);
- commit(types.SET_REPOS_LIST, response);
+ createFlash(errorMessages[errorMessagesTypes.FETCH_REPOS]);
});
};
export const fetchList = ({ commit }, { repo, page }) => {
commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo);
- return Vue.http.get(repo.tagsPath, { params: { page } }).then(response => {
- const { headers } = response;
+ return axios
+ .get(repo.tagsPath, { params: { page } })
+ .then(response => {
+ const { headers, data } = response;
- return response.json().then(resp => {
commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo);
- commit(types.SET_REGISTRY_LIST, { repo, resp, headers });
+ commit(types.SET_REGISTRY_LIST, { repo, resp: data, headers });
+ })
+ .catch(() => {
+ commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo);
+ createFlash(errorMessages[errorMessagesTypes.FETCH_REGISTRY]);
});
- });
};
// eslint-disable-next-line no-unused-vars
-export const deleteRepo = ({ commit }, repo) => Vue.http.delete(repo.destroyPath);
+export const deleteRepo = ({ commit }, repo) => axios.delete(repo.destroyPath);
// eslint-disable-next-line no-unused-vars
-export const deleteRegistry = ({ commit }, image) => Vue.http.delete(image.destroyPath);
+export const deleteRegistry = ({ commit }, image) => axios.delete(image.destroyPath);
export const setMainEndpoint = ({ commit }, data) => commit(types.SET_MAIN_ENDPOINT, data);
export const toggleLoading = ({ commit }) => commit(types.TOGGLE_MAIN_LOADING);
diff --git a/app/assets/javascripts/registry/stores/index.js b/app/assets/javascripts/registry/stores/index.js
index 78b67881210..1bb06bd6e81 100644
--- a/app/assets/javascripts/registry/stores/index.js
+++ b/app/assets/javascripts/registry/stores/index.js
@@ -3,36 +3,12 @@ import Vuex from 'vuex';
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
+import createState from './state';
Vue.use(Vuex);
export default new Vuex.Store({
- state: {
- isLoading: false,
- endpoint: '', // initial endpoint to fetch the repos list
- /**
- * Each object in `repos` has the following strucure:
- * {
- * name: String,
- * isLoading: Boolean,
- * tagsPath: String // endpoint to request the list
- * destroyPath: String // endpoit to delete the repo
- * list: Array // List of the registry images
- * }
- *
- * Each registry image inside `list` has the following structure:
- * {
- * tag: String,
- * revision: String
- * shortRevision: String
- * size: Number
- * layers: Number
- * createdAt: String
- * destroyPath: String // endpoit to delete each image
- * }
- */
- repos: [],
- },
+ state: createState(),
actions,
getters,
mutations,
diff --git a/app/assets/javascripts/registry/stores/mutations.js b/app/assets/javascripts/registry/stores/mutations.js
index 69c051cd2d6..1ac699c538f 100644
--- a/app/assets/javascripts/registry/stores/mutations.js
+++ b/app/assets/javascripts/registry/stores/mutations.js
@@ -48,6 +48,7 @@ export default {
[types.TOGGLE_REGISTRY_LIST_LOADING](state, list) {
const listToUpdate = state.repos.find(el => el.id === list.id);
+
listToUpdate.isLoading = !listToUpdate.isLoading;
},
};
diff --git a/app/assets/javascripts/registry/stores/state.js b/app/assets/javascripts/registry/stores/state.js
new file mode 100644
index 00000000000..feeac10cbe1
--- /dev/null
+++ b/app/assets/javascripts/registry/stores/state.js
@@ -0,0 +1,26 @@
+export default () => ({
+ isLoading: false,
+ endpoint: '', // initial endpoint to fetch the repos list
+ /**
+ * Each object in `repos` has the following strucure:
+ * {
+ * name: String,
+ * isLoading: Boolean,
+ * tagsPath: String // endpoint to request the list
+ * destroyPath: String // endpoit to delete the repo
+ * list: Array // List of the registry images
+ * }
+ *
+ * Each registry image inside `list` has the following structure:
+ * {
+ * tag: String,
+ * revision: String
+ * shortRevision: String
+ * size: Number
+ * layers: Number
+ * createdAt: String
+ * destroyPath: String // endpoit to delete each image
+ * }
+ */
+ repos: [],
+});
diff --git a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
index bd204503cc7..82601363aa4 100644
--- a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
+++ b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
@@ -77,13 +77,8 @@ export default {
:has-issues="reports.length > 0"
class="mr-widget-section grouped-security-reports mr-report"
>
- <div
- slot="body"
- class="mr-widget-grouped-section report-block"
- >
- <template
- v-for="(report, i) in reports"
- >
+ <div slot="body" class="mr-widget-grouped-section report-block">
+ <template v-for="(report, i) in reports">
<summary-row
:key="`summary-row-${i}`"
:summary="reportText(report)"
@@ -100,10 +95,7 @@ export default {
/>
</template>
- <modal
- :title="modalTitle"
- :modal-data="modalData"
- />
+ <modal :title="modalTitle" :modal-data="modalData" />
</div>
</report-section>
</template>
diff --git a/app/assets/javascripts/reports/components/issue_status_icon.vue b/app/assets/javascripts/reports/components/issue_status_icon.vue
index 6e143c4f98c..2946fbc6a1f 100644
--- a/app/assets/javascripts/reports/components/issue_status_icon.vue
+++ b/app/assets/javascripts/reports/components/issue_status_icon.vue
@@ -45,9 +45,6 @@ export default {
}"
class="report-block-list-icon"
>
- <icon
- :name="iconName"
- :size="32"
- />
+ <icon :name="iconName" :size="32" />
</div>
</template>
diff --git a/app/assets/javascripts/reports/components/modal.vue b/app/assets/javascripts/reports/components/modal.vue
index 5f9e4072b2d..162421b037f 100644
--- a/app/assets/javascripts/reports/components/modal.vue
+++ b/app/assets/javascripts/reports/components/modal.vue
@@ -36,23 +36,13 @@ export default {
:key="index"
class="row prepend-top-10 append-bottom-10"
>
- <strong class="col-sm-3 text-right">
- {{ field.text }}:
- </strong>
+ <strong class="col-sm-3 text-right"> {{ field.text }}: </strong>
<div class="col-sm-9 text-secondary">
- <code-block
- v-if="field.type === $options.fieldTypes.codeBock"
- :code="field.value"
- />
+ <code-block v-if="field.type === $options.fieldTypes.codeBock" :code="field.value" />
<template v-else-if="field.type === $options.fieldTypes.link">
- <a
- :href="field.value"
- target="_blank"
- rel="noopener noreferrer"
- class="js-modal-link"
- >
+ <a :href="field.value" target="_blank" rel="noopener noreferrer" class="js-modal-link">
{{ field.value }}
</a>
</template>
@@ -67,7 +57,6 @@ export default {
</div>
</div>
</slot>
- <div slot="footer">
- </div>
+ <div slot="footer"></div>
</modal>
</template>
diff --git a/app/assets/javascripts/reports/components/modal_open_name.vue b/app/assets/javascripts/reports/components/modal_open_name.vue
index 4f81cee2a38..118e4b02c46 100644
--- a/app/assets/javascripts/reports/components/modal_open_name.vue
+++ b/app/assets/javascripts/reports/components/modal_open_name.vue
@@ -26,7 +26,7 @@ export default {
<button
type="button"
class="btn-link btn-blank text-left break-link vulnerability-name-button"
- @click="handleIssueClick()"
+ @click="handleIssueClick();"
>
{{ issue.title }}
</button>
diff --git a/app/assets/javascripts/reports/components/report_item.vue b/app/assets/javascripts/reports/components/report_item.vue
index 01e6d357a21..839e86bdf17 100644
--- a/app/assets/javascripts/reports/components/report_item.vue
+++ b/app/assets/javascripts/reports/components/report_item.vue
@@ -33,21 +33,9 @@ export default {
};
</script>
<template>
- <li
- :class="{ 'is-dismissed': issue.isDismissed }"
- class="report-block-list-issue"
- >
- <issue-status-icon
- :status="status"
- class="append-right-5"
- />
+ <li :class="{ 'is-dismissed': issue.isDismissed }" class="report-block-list-issue">
+ <issue-status-icon :status="status" class="append-right-5" />
- <component
- :is="component"
- v-if="component"
- :issue="issue"
- :status="status"
- :is-new="isNew"
- />
+ <component :is="component" v-if="component" :issue="issue" :status="status" :is-new="isNew" />
</li>
</template>
diff --git a/app/assets/javascripts/reports/components/report_link.vue b/app/assets/javascripts/reports/components/report_link.vue
index 74d68f9f439..052bc53d610 100644
--- a/app/assets/javascripts/reports/components/report_link.vue
+++ b/app/assets/javascripts/reports/components/report_link.vue
@@ -20,10 +20,16 @@ export default {
rel="noopener noreferrer nofollow"
class="break-link"
>
- {{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template>
+ {{ issue.path
+ }}<template v-if="issue.line"
+ >:{{ issue.line }}</template
+ >
</a>
<template v-else>
- {{ issue.path }}<template v-if="issue.line">:{{ issue.line }}</template>
+ {{ issue.path
+ }}<template v-if="issue.line"
+ >:{{ issue.line }}</template
+ >
</template>
</div>
</template>
diff --git a/app/assets/javascripts/reports/components/report_section.vue b/app/assets/javascripts/reports/components/report_section.vue
index d196f497362..d6483e95278 100644
--- a/app/assets/javascripts/reports/components/report_section.vue
+++ b/app/assets/javascripts/reports/components/report_section.vue
@@ -143,11 +143,7 @@ export default {
<span class="js-code-text code-text">
{{ headerText }}
- <popover
- v-if="hasPopover"
- :options="popoverOptions"
- class="prepend-left-5"
- />
+ <popover v-if="hasPopover" :options="popoverOptions" class="prepend-left-5" />
</span>
<slot name="actionButtons"></slot>
@@ -163,11 +159,7 @@ export default {
</div>
</div>
- <div
- v-if="hasIssues"
- v-show="isExpanded"
- class="js-report-section-container"
- >
+ <div v-if="hasIssues" v-show="isExpanded" class="js-report-section-container">
<slot name="body">
<issues-list
:unresolved-issues="unresolvedIssues"
diff --git a/app/assets/javascripts/reports/components/summary_row.vue b/app/assets/javascripts/reports/components/summary_row.vue
index a44ba833b63..97a68531d29 100644
--- a/app/assets/javascripts/reports/components/summary_row.vue
+++ b/app/assets/javascripts/reports/components/summary_row.vue
@@ -1,7 +1,7 @@
<script>
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Popover from '~/vue_shared/components/help_popover.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
/**
* Renders the summary row for each report
@@ -46,26 +46,14 @@ export default {
<template>
<div class="report-block-list-issue report-block-list-issue-parent">
<div class="report-block-list-icon append-right-10 prepend-left-5">
- <gl-loading-icon
- v-if="statusIcon === 'loading'"
- css-class="report-block-list-loading-icon"
- />
- <ci-icon
- v-else
- :status="iconStatus"
- />
+ <gl-loading-icon v-if="statusIcon === 'loading'" css-class="report-block-list-loading-icon" />
+ <ci-icon v-else :status="iconStatus" />
</div>
<div class="report-block-list-issue-description">
- <div class="report-block-list-issue-description-text">
- {{ summary }}
- </div>
-
- <popover
- v-if="popoverOptions"
- :options="popoverOptions"
- />
+ <div class="report-block-list-issue-description-text">{{ summary }}</div>
+ <popover v-if="popoverOptions" :options="popoverOptions" />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/reports/components/test_issue_body.vue b/app/assets/javascripts/reports/components/test_issue_body.vue
index 1a87822fcc3..938e83de546 100644
--- a/app/assets/javascripts/reports/components/test_issue_body.vue
+++ b/app/assets/javascripts/reports/components/test_issue_body.vue
@@ -30,14 +30,10 @@ export default {
<button
type="button"
class="btn-link btn-blank text-left break-link vulnerability-name-button"
- @click="openModal({ issue })"
+ @click="openModal({ issue });"
>
- <div
- v-if="isNew"
- class="badge badge-danger append-right-5"
- >
- {{ s__('New') }}
- </div>{{ issue.name }}
+ <div v-if="isNew" class="badge badge-danger append-right-5">{{ s__('New') }}</div>
+ {{ issue.name }}
</button>
</div>
</div>
diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js
index 17def77b2d7..0a4583b5861 100644
--- a/app/assets/javascripts/search_autocomplete.js
+++ b/app/assets/javascripts/search_autocomplete.js
@@ -253,7 +253,6 @@ export class SearchAutocomplete {
}
getCategoryContents() {
- const userId = gon.current_user_id;
const userName = gon.current_username;
const { projectOptions, groupOptions, dashboardOptions } = gl;
@@ -279,21 +278,21 @@ export class SearchAutocomplete {
const issueItems = [
{
text: s__('SearchAutocomplete|Issues assigned to me'),
- url: `${issuesPath}/?assignee_id=${userId}`,
+ url: `${issuesPath}/?assignee_username=${userName}`,
},
{
text: s__("SearchAutocomplete|Issues I've created"),
- url: `${issuesPath}/?author_id=${userId}`,
+ url: `${issuesPath}/?author_username=${userName}`,
},
];
const mergeRequestItems = [
{
text: s__('SearchAutocomplete|Merge requests assigned to me'),
- url: `${mrPath}/?assignee_id=${userId}`,
+ url: `${mrPath}/?assignee_username=${userName}`,
},
{
text: s__("SearchAutocomplete|Merge requests I've created"),
- url: `${mrPath}/?author_id=${userId}`,
+ url: `${mrPath}/?author_username=${userName}`,
},
];
diff --git a/app/assets/javascripts/serverless/components/empty_state.vue b/app/assets/javascripts/serverless/components/empty_state.vue
new file mode 100644
index 00000000000..2683805f2f7
--- /dev/null
+++ b/app/assets/javascripts/serverless/components/empty_state.vue
@@ -0,0 +1,40 @@
+<script>
+export default {
+ props: {
+ clustersPath: {
+ type: String,
+ required: true,
+ },
+ helpPath: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="row empty-state js-empty-state">
+ <div class="col-12">
+ <div class="text-content">
+ <h4 class="state-title text-center">
+ {{ s__('Serverless|Getting started with serverless') }}
+ </h4>
+ <p class="state-description">
+ {{
+ s__(`Serverless| In order to start using functions as a service,
+ you must first install Knative on your Kubernetes cluster.`)
+ }}
+
+ <a :href="helpPath"> {{ __('More information') }} </a>
+ </p>
+
+ <div class="text-center">
+ <a :href="clustersPath" class="btn btn-success">
+ {{ s__('Serverless|Install Knative') }}
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/serverless/components/function_row.vue b/app/assets/javascripts/serverless/components/function_row.vue
new file mode 100644
index 00000000000..31f5427c771
--- /dev/null
+++ b/app/assets/javascripts/serverless/components/function_row.vue
@@ -0,0 +1,40 @@
+<script>
+import Timeago from '~/vue_shared/components/time_ago_tooltip.vue';
+
+export default {
+ components: {
+ Timeago,
+ },
+ props: {
+ func: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ name() {
+ return this.func.name;
+ },
+ url() {
+ return this.func.url;
+ },
+ image() {
+ return this.func.image;
+ },
+ timestamp() {
+ return this.func.created_at;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-responsive-table-row">
+ <div class="table-section section-20">{{ name }}</div>
+ <div class="table-section section-50">
+ <a :href="url">{{ url }}</a>
+ </div>
+ <div class="table-section section-20">{{ image }}</div>
+ <div class="table-section section-10"><timeago :time="timestamp" /></div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/serverless/components/functions.vue b/app/assets/javascripts/serverless/components/functions.vue
new file mode 100644
index 00000000000..7874a7b6b6a
--- /dev/null
+++ b/app/assets/javascripts/serverless/components/functions.vue
@@ -0,0 +1,123 @@
+<script>
+import { GlSkeletonLoading } from '@gitlab/ui';
+import FunctionRow from './function_row.vue';
+import EmptyState from './empty_state.vue';
+
+export default {
+ components: {
+ FunctionRow,
+ EmptyState,
+ GlSkeletonLoading,
+ },
+ props: {
+ functions: {
+ type: Array,
+ required: true,
+ default: () => [],
+ },
+ installed: {
+ type: Boolean,
+ required: true,
+ },
+ clustersPath: {
+ type: String,
+ required: true,
+ },
+ helpPath: {
+ type: String,
+ required: true,
+ },
+ loadingData: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ hasFunctionData: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <section id="serverless-functions">
+ <div v-if="installed">
+ <div v-if="hasFunctionData">
+ <div class="ci-table js-services-list function-element">
+ <div class="gl-responsive-table-row table-row-header" role="row">
+ <div class="table-section section-20" role="rowheader">
+ {{ s__('Serverless|Function') }}
+ </div>
+ <div class="table-section section-50" role="rowheader">
+ {{ s__('Serverless|Domain') }}
+ </div>
+ <div class="table-section section-20" role="rowheader">
+ {{ s__('Serverless|Runtime') }}
+ </div>
+ <div class="table-section section-10" role="rowheader">
+ {{ s__('Serverless|Last Update') }}
+ </div>
+ </div>
+ <template v-if="loadingData">
+ <div v-for="j in 3" :key="j" class="gl-responsive-table-row">
+ <gl-skeleton-loading />
+ </div>
+ </template>
+ <template v-else>
+ <function-row v-for="f in functions" :key="f.name" :func="f" />
+ </template>
+ </div>
+ </div>
+ <div v-else class="empty-state js-empty-state">
+ <div class="text-content">
+ <h4 class="state-title text-center">{{ s__('Serverless|No functions available') }}</h4>
+ <p class="state-description">
+ {{
+ s__(`Serverless|There is currently no function data available from Knative.
+ This could be for a variety of reasons including:`)
+ }}
+ </p>
+ <ul>
+ <li>Your repository does not have a corresponding <code>serverless.yml</code> file.</li>
+ <li>Your <code>gitlab-ci.yml</code> file is not properly configured.</li>
+ <li>
+ The functions listed in the <code>serverless.yml</code> file don't match the namespace
+ of your cluster.
+ </li>
+ <li>The deploy job has not finished.</li>
+ </ul>
+
+ <p>
+ {{
+ s__(`Serverless|If you believe none of these apply, please check
+ back later as the function data may be in the process of becoming
+ available.`)
+ }}
+ </p>
+ <div class="text-center">
+ <a :href="helpPath" class="btn btn-success">
+ {{ s__('Serverless|Learn more about Serverless') }}
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <empty-state v-else :clusters-path="clustersPath" :help-path="helpPath" />
+ </section>
+</template>
+
+<style>
+.top-area {
+ border-bottom: 0;
+}
+
+.function-element {
+ border-bottom: 1px solid #e5e5e5;
+ border-bottom-color: rgb(229, 229, 229);
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+}
+</style>
diff --git a/app/assets/javascripts/serverless/event_hub.js b/app/assets/javascripts/serverless/event_hub.js
new file mode 100644
index 00000000000..0948c2e5352
--- /dev/null
+++ b/app/assets/javascripts/serverless/event_hub.js
@@ -0,0 +1,3 @@
+import Vue from 'vue';
+
+export default new Vue();
diff --git a/app/assets/javascripts/serverless/serverless_bundle.js b/app/assets/javascripts/serverless/serverless_bundle.js
new file mode 100644
index 00000000000..3e3b81ba247
--- /dev/null
+++ b/app/assets/javascripts/serverless/serverless_bundle.js
@@ -0,0 +1,106 @@
+import Visibility from 'visibilityjs';
+import Vue from 'vue';
+import { s__ } from '../locale';
+import Flash from '../flash';
+import Poll from '../lib/utils/poll';
+import ServerlessStore from './stores/serverless_store';
+import GetFunctionsService from './services/get_functions_service';
+import Functions from './components/functions.vue';
+
+export default class Serverless {
+ constructor() {
+ const { statusPath, clustersPath, helpPath, installed } = document.querySelector(
+ '.js-serverless-functions-page',
+ ).dataset;
+
+ this.service = new GetFunctionsService(statusPath);
+ this.knativeInstalled = installed !== undefined;
+ this.store = new ServerlessStore(this.knativeInstalled, clustersPath, helpPath);
+ this.initServerless();
+ this.functionLoadCount = 0;
+
+ if (statusPath && this.knativeInstalled) {
+ this.initPolling();
+ }
+ }
+
+ initServerless() {
+ const { store } = this;
+ const el = document.querySelector('#js-serverless-functions');
+
+ this.functions = new Vue({
+ el,
+ data() {
+ return {
+ state: store.state,
+ };
+ },
+ render(createElement) {
+ return createElement(Functions, {
+ props: {
+ functions: this.state.functions,
+ installed: this.state.installed,
+ clustersPath: this.state.clustersPath,
+ helpPath: this.state.helpPath,
+ loadingData: this.state.loadingData,
+ hasFunctionData: this.state.hasFunctionData,
+ },
+ });
+ },
+ });
+ }
+
+ initPolling() {
+ this.poll = new Poll({
+ resource: this.service,
+ method: 'fetchData',
+ successCallback: data => this.handleSuccess(data),
+ errorCallback: () => this.handleError(),
+ });
+
+ if (!Visibility.hidden()) {
+ this.poll.makeRequest();
+ } else {
+ this.service
+ .fetchData()
+ .then(data => this.handleSuccess(data))
+ .catch(() => this.handleError());
+ }
+
+ Visibility.change(() => {
+ if (!Visibility.hidden() && !this.destroyed) {
+ this.poll.restart();
+ } else {
+ this.poll.stop();
+ }
+ });
+ }
+
+ handleSuccess(data) {
+ if (data.status === 200) {
+ this.store.updateFunctionsFromServer(data.data);
+ this.store.updateLoadingState(false);
+ } else if (data.status === 204) {
+ /* Time out after 3 attempts to retrieve data */
+ this.functionLoadCount += 1;
+ if (this.functionLoadCount === 3) {
+ this.poll.stop();
+ this.store.toggleNoFunctionData();
+ }
+ }
+ }
+
+ static handleError() {
+ Flash(s__('Serverless|An error occurred while retrieving serverless components'));
+ }
+
+ destroy() {
+ this.destroyed = true;
+
+ if (this.poll) {
+ this.poll.stop();
+ }
+
+ this.functions.$destroy();
+ }
+}
diff --git a/app/assets/javascripts/serverless/services/get_functions_service.js b/app/assets/javascripts/serverless/services/get_functions_service.js
new file mode 100644
index 00000000000..303b42dc66c
--- /dev/null
+++ b/app/assets/javascripts/serverless/services/get_functions_service.js
@@ -0,0 +1,11 @@
+import axios from '~/lib/utils/axios_utils';
+
+export default class GetFunctionsService {
+ constructor(endpoint) {
+ this.endpoint = endpoint;
+ }
+
+ fetchData() {
+ return axios.get(this.endpoint);
+ }
+}
diff --git a/app/assets/javascripts/serverless/stores/serverless_store.js b/app/assets/javascripts/serverless/stores/serverless_store.js
new file mode 100644
index 00000000000..774c15b5b12
--- /dev/null
+++ b/app/assets/javascripts/serverless/stores/serverless_store.js
@@ -0,0 +1,24 @@
+export default class ServerlessStore {
+ constructor(knativeInstalled = false, clustersPath, helpPath) {
+ this.state = {
+ functions: [],
+ hasFunctionData: true,
+ loadingData: true,
+ installed: knativeInstalled,
+ clustersPath,
+ helpPath,
+ };
+ }
+
+ updateFunctionsFromServer(functions = []) {
+ this.state.functions = functions;
+ }
+
+ updateLoadingState(loadingData) {
+ this.state.loadingData = loadingData;
+ }
+
+ toggleNoFunctionData() {
+ this.state.hasFunctionData = false;
+ }
+}
diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_trigger.vue b/app/assets/javascripts/set_status_modal/set_status_modal_trigger.vue
index 48e5ede80f2..0e8b6d93f42 100644
--- a/app/assets/javascripts/set_status_modal/set_status_modal_trigger.vue
+++ b/app/assets/javascripts/set_status_modal/set_status_modal_trigger.vue
@@ -23,11 +23,5 @@ export default {
</script>
<template>
- <button
- type="button"
- class="btn menu-item"
- @click="openModal"
- >
- {{ buttonText }}
- </button>
+ <button type="button" class="btn menu-item" @click="openModal">{{ buttonText }}</button>
</template>
diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
index 4d461baf74d..f04f7606976 100644
--- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
+++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
@@ -5,7 +5,7 @@ import Icon from '~/vue_shared/components/icon.vue';
import GfmAutoComplete from '~/gfm_auto_complete';
import { __, s__ } from '~/locale';
import Api from '~/api';
-import { GlModal, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlModal, GlTooltipDirective } from '@gitlab/ui';
import eventHub from './event_hub';
import EmojiMenuInModal from './emoji_menu_in_modal';
@@ -176,10 +176,7 @@ export default {
type="hidden"
name="user[status][emoji]"
/>
- <div
- ref="userStatusForm"
- class="form-group position-relative m-0"
- >
+ <div ref="userStatusForm" class="form-group position-relative m-0">
<div class="input-group">
<span class="input-group-btn">
<button
@@ -197,18 +194,9 @@ export default {
v-show="noEmoji"
class="js-no-emoji-placeholder no-emoji-placeholder position-relative"
>
- <icon
- name="emoji_slightly_smiling_face"
- css-classes="award-control-icon-neutral"
- />
- <icon
- name="emoji_smiley"
- css-classes="award-control-icon-positive"
- />
- <icon
- name="emoji_smile"
- css-classes="award-control-icon-super-positive"
- />
+ <icon name="emoji_slightly_smiling_face" css-classes="award-control-icon-neutral" />
+ <icon name="emoji_smiley" css-classes="award-control-icon-positive" />
+ <icon name="emoji_smile" css-classes="award-control-icon-super-positive" />
</span>
</button>
</span>
@@ -223,10 +211,7 @@ export default {
@keyup.enter.prevent
@click="hideEmojiMenu"
/>
- <span
- v-show="isDirty"
- class="input-group-btn"
- >
+ <span v-show="isDirty" class="input-group-btn">
<button
v-gl-tooltip.bottom
:title="s__('SetStatusModal|Clear status')"
@@ -234,7 +219,7 @@ export default {
name="button"
type="button"
class="js-clear-user-status-button clear-user-status btn"
- @click="clearStatusInputs()"
+ @click="clearStatusInputs();"
>
<icon name="close" />
</button>
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
index 284a258d3c9..0ad2b3a73a2 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
@@ -32,18 +32,8 @@ export default {
<template>
<div class="title hide-collapsed">
{{ assigneeTitle }}
- <i
- v-if="loading"
- aria-hidden="true"
- class="fa fa-spinner fa-spin block-loading"
- >
-
- </i>
- <a
- v-if="editable"
- class="js-sidebar-dropdown-toggle edit-link float-right"
- href="#"
- >
+ <i v-if="loading" aria-hidden="true" class="fa fa-spinner fa-spin block-loading"> </i>
+ <a v-if="editable" class="js-sidebar-dropdown-toggle edit-link float-right" href="#">
{{ __('Edit') }}
</a>
<a
@@ -53,12 +43,7 @@ export default {
href="#"
role="button"
>
- <i
- aria-hidden="true"
- data-hidden="true"
- class="fa fa-angle-double-right"
- >
- </i>
+ <i aria-hidden="true" data-hidden="true" class="fa fa-angle-double-right"> </i>
</a>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees.vue b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
index f1ea6aacdb2..d1a396182b3 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
@@ -133,12 +133,7 @@ export default {
data-placement="left"
data-boundary="viewport"
>
- <i
- v-if="hasNoUsers"
- aria-label="No Assignee"
- class="fa fa-user"
- >
- </i>
+ <i v-if="hasNoUsers" aria-label="No Assignee" class="fa fa-user"> </i>
<button
v-for="(user, index) in users"
v-if="shouldRenderCollapsedAssignee(index)"
@@ -152,20 +147,10 @@ export default {
width="24"
class="avatar avatar-inline s24"
/>
- <span class="author">
- {{ user.name }}
- </span>
+ <span class="author"> {{ user.name }} </span>
</button>
- <button
- v-if="hasMoreThanTwoAssignees"
- class="btn-link"
- type="button"
- >
- <span
- class="avatar-counter sidebar-avatar-counter"
- >
- {{ sidebarAvatarCounter }}
- </span>
+ <button v-if="hasMoreThanTwoAssignees" class="btn-link" type="button">
+ <span class="avatar-counter sidebar-avatar-counter"> {{ sidebarAvatarCounter }} </span>
</button>
</div>
<div class="value hide-collapsed">
@@ -173,34 +158,20 @@ export default {
<span class="assign-yourself no-value">
No assignee
<template v-if="editable">
- -
- <button
- type="button"
- class="btn-link"
- @click="assignSelf"
- >
- assign yourself
- </button>
+ - <button type="button" class="btn-link" @click="assignSelf">assign yourself</button>
</template>
</span>
</template>
<template v-else-if="hasOneUser">
- <a
- :href="assigneeUrl(firstUser)"
- class="author-link bold"
- >
+ <a :href="assigneeUrl(firstUser)" class="author-link bold">
<img
:alt="assigneeAlt(firstUser)"
:src="avatarUrl(firstUser)"
width="32"
class="avatar avatar-inline s32"
/>
- <span class="author">
- {{ firstUser.name }}
- </span>
- <span class="username">
- {{ assigneeUsername(firstUser) }}
- </span>
+ <span class="author"> {{ firstUser.name }} </span>
+ <span class="username"> {{ assigneeUsername(firstUser) }} </span>
</a>
</template>
<template v-else>
@@ -227,15 +198,8 @@ export default {
</a>
</div>
</div>
- <div
- v-if="renderShowMoreSection"
- class="user-list-more"
- >
- <button
- type="button"
- class="btn-link"
- @click="toggleShowLess"
- >
+ <div v-if="renderShowMoreSection" class="user-list-more">
+ <button type="button" class="btn-link" @click="toggleShowLess">
<template v-if="showLess">
{{ hiddenAssigneesLabel }}
</template>
diff --git a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
index 439e8a69df0..597b723a9d9 100644
--- a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
@@ -74,10 +74,7 @@ export default {
data-boundary="viewport"
@click="toggleForm"
>
- <icon
- :name="confidentialityIcon"
- aria-hidden="true"
- />
+ <icon :name="confidentialityIcon" aria-hidden="true" />
</div>
<div class="title hide-collapsed">
{{ __('Confidentiality') }}
@@ -96,20 +93,11 @@ export default {
:is-confidential="isConfidential"
:update-confidential-attribute="updateConfidentialAttribute"
/>
- <div
- v-if="!isConfidential"
- class="no-value sidebar-item-value">
- <icon
- :size="16"
- name="eye"
- aria-hidden="true"
- class="sidebar-item-icon inline"
- />
+ <div v-if="!isConfidential" class="no-value sidebar-item-value">
+ <icon :size="16" name="eye" aria-hidden="true" class="sidebar-item-icon inline" />
{{ __('Not confidential') }}
</div>
- <div
- v-else
- class="value sidebar-item-value hide-collapsed">
+ <div v-else class="value sidebar-item-value hide-collapsed">
<icon
:size="16"
name="eye-slash"
diff --git a/app/assets/javascripts/sidebar/components/confidential/edit_form.vue b/app/assets/javascripts/sidebar/components/confidential/edit_form.vue
index 4165aa19acf..0ecbf934c25 100644
--- a/app/assets/javascripts/sidebar/components/confidential/edit_form.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/edit_form.vue
@@ -35,14 +35,8 @@ export default {
<div class="dropdown show">
<div class="dropdown-menu sidebar-item-warning-message">
<div>
- <p
- v-if="!isConfidential"
- v-html="confidentialityOnWarning">
- </p>
- <p
- v-else
- v-html="confidentialityOffWarning">
- </p>
+ <p v-if="!isConfidential" v-html="confidentialityOnWarning"></p>
+ <p v-else v-html="confidentialityOffWarning"></p>
<edit-form-buttons
:is-confidential="isConfidential"
:update-confidential-attribute="updateConfidentialAttribute"
diff --git a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
index 38b1ddbfd5b..4b9bb5c7b0e 100644
--- a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
@@ -36,18 +36,10 @@ export default {
<template>
<div class="sidebar-item-warning-message-actions">
- <button
- type="button"
- class="btn btn-default append-right-10"
- @click="closeForm"
- >
+ <button type="button" class="btn btn-default append-right-10" @click="closeForm">
{{ __('Cancel') }}
</button>
- <button
- type="button"
- class="btn btn-close"
- @click.prevent="submitForm"
- >
+ <button type="button" class="btn btn-close" @click.prevent="submitForm">
{{ toggleButtonText }}
</button>
</div>
diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form.vue b/app/assets/javascripts/sidebar/components/lock/edit_form.vue
index 4906dad22e1..630da751704 100644
--- a/app/assets/javascripts/sidebar/components/lock/edit_form.vue
+++ b/app/assets/javascripts/sidebar/components/lock/edit_form.vue
@@ -43,22 +43,11 @@ export default {
<template>
<div class="dropdown show">
<div class="dropdown-menu sidebar-item-warning-message">
- <p
- v-if="isLocked"
- class="text"
- v-html="unlockWarning">
- </p>
+ <p v-if="isLocked" class="text" v-html="unlockWarning"></p>
- <p
- v-else
- class="text"
- v-html="lockWarning">
- </p>
+ <p v-else class="text" v-html="lockWarning"></p>
- <edit-form-buttons
- :is-locked="isLocked"
- :update-locked-attribute="updateLockedAttribute"
- />
+ <edit-form-buttons :is-locked="isLocked" :update-locked-attribute="updateLockedAttribute" />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
index 63082654101..902aeb9b8e4 100644
--- a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
+++ b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
@@ -41,19 +41,11 @@ export default {
<template>
<div class="sidebar-item-warning-message-actions">
- <button
- type="button"
- class="btn btn-default append-right-10"
- @click="closeForm"
- >
+ <button type="button" class="btn btn-default append-right-10" @click="closeForm">
{{ __('Cancel') }}
</button>
- <button
- type="button"
- class="btn btn-close"
- @click.prevent="submitForm"
- >
+ <button type="button" class="btn btn-close" @click.prevent="submitForm">
{{ buttonText }}
</button>
</div>
diff --git a/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue
index 48a2b9194aa..faea64c9841 100644
--- a/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue
+++ b/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue
@@ -100,14 +100,13 @@ export default {
data-boundary="viewport"
@click="toggleForm"
>
- <icon
- :name="lockIcon"
- class="sidebar-item-icon is-active"
- />
+ <icon :name="lockIcon" class="sidebar-item-icon is-active" />
</div>
<div class="title hide-collapsed">
- {{ sprintf(__('Lock %{issuableDisplayName}'), { issuableDisplayName: issuableDisplayName }) }}
+ {{
+ sprintf(__('Lock %{issuableDisplayName}'), { issuableDisplayName: issuableDisplayName })
+ }}
<button
v-if="isEditable"
class="float-right lock-edit"
@@ -126,28 +125,13 @@ export default {
:issuable-type="issuableType"
/>
- <div
- v-if="isLocked"
- class="value sidebar-item-value"
- >
- <icon
- :size="16"
- name="lock"
- class="sidebar-item-icon inline is-active"
- />
+ <div v-if="isLocked" class="value sidebar-item-value">
+ <icon :size="16" name="lock" class="sidebar-item-icon inline is-active" />
{{ __('Locked') }}
</div>
- <div
- v-else
- class="no-value sidebar-item-value hide-collapsed"
- >
- <icon
- :size="16"
- name="lock-open"
- class="sidebar-item-icon inline"
- />
- {{ __('Unlocked') }}
+ <div v-else class="no-value sidebar-item-value hide-collapsed">
+ <icon :size="16" name="lock-open" class="sidebar-item-icon inline" /> {{ __('Unlocked') }}
</div>
</div>
</div>
diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue
index fe73f6a0cef..4bfc8fa7eec 100644
--- a/app/assets/javascripts/sidebar/components/participants/participants.vue
+++ b/app/assets/javascripts/sidebar/components/participants/participants.vue
@@ -2,7 +2,7 @@
import { __, n__, sprintf } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
export default {
directives: {
@@ -88,21 +88,9 @@ export default {
data-boundary="viewport"
@click="onClickCollapsedIcon"
>
- <i
- class="fa fa-users"
- aria-hidden="true"
- >
- </i>
- <gl-loading-icon
- v-if="loading"
- class="js-participants-collapsed-loading-icon"
- />
- <span
- v-else
- class="js-participants-collapsed-count"
- >
- {{ participantCount }}
- </span>
+ <i class="fa fa-users" aria-hidden="true"> </i>
+ <gl-loading-icon v-if="loading" class="js-participants-collapsed-loading-icon" />
+ <span v-else class="js-participants-collapsed-count"> {{ participantCount }} </span>
</div>
<div class="title hide-collapsed">
<gl-loading-icon
@@ -118,10 +106,7 @@ export default {
:key="participant.id"
class="participants-author js-participants-author"
>
- <a
- :href="participant.web_url"
- class="author-link"
- >
+ <a :href="participant.web_url" class="author-link">
<user-avatar-image
:lazy="true"
:img-src="participant.avatar_url"
@@ -133,10 +118,7 @@ export default {
</a>
</div>
</div>
- <div
- v-if="hasMoreParticipants"
- class="participants-more hide-collapsed"
- >
+ <div v-if="hasMoreParticipants" class="participants-more hide-collapsed">
<button
type="button"
class="btn-transparent btn-blank js-toggle-participants-button"
diff --git a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue
index b6151aa6c64..a75daca156c 100644
--- a/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue
+++ b/app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue
@@ -73,10 +73,7 @@ export default {
<template>
<div>
- <div
- class="sidebar-collapsed-icon"
- @click="onClickCollapsedIcon"
- >
+ <div class="sidebar-collapsed-icon" @click="onClickCollapsedIcon">
<span
v-tooltip
:title="notificationTooltip"
@@ -92,9 +89,7 @@ export default {
/>
</span>
</div>
- <span class="issuable-header-text hide-collapsed float-left">
- {{ __('Notifications') }}
- </span>
+ <span class="issuable-header-text hide-collapsed float-left"> {{ __('Notifications') }} </span>
<toggle-button
ref="toggleButton"
:is-loading="showLoadingState"
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
index 259858e4b46..657ac837baf 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
@@ -120,9 +120,7 @@ export default {
<icon name="timer" />
<div class="time-tracking-collapsed-summary">
<div :class="divClass">
- <span :class="spanClass">
- {{ text }}
- </span>
+ <span :class="spanClass"> {{ text }} </span>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
index b145e5dc5e2..f4d926cd3ec 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
@@ -1,7 +1,7 @@
<script>
import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
import tooltip from '../../../vue_shared/directives/tooltip';
-import { GlProgressBar } from '@gitlab-org/gitlab-ui';
+import { GlProgressBar } from '@gitlab/ui';
export default {
name: 'TimeTrackingComparisonPane',
@@ -69,26 +69,15 @@ export default {
data-placement="top"
role="timeRemainingDisplay"
>
- <gl-progress-bar
- :value="timeRemainingPercent"
- :variant="progressBarVariant"
- />
+ <gl-progress-bar :value="timeRemainingPercent" :variant="progressBarVariant" />
<div class="compare-display-container">
<div class="compare-display float-left">
- <span class="compare-label">
- {{ s__('TimeTracking|Spent') }}
- </span>
- <span class="compare-value spent">
- {{ timeSpentHumanReadable }}
- </span>
+ <span class="compare-label"> {{ s__('TimeTracking|Spent') }} </span>
+ <span class="compare-value spent"> {{ timeSpentHumanReadable }} </span>
</div>
<div class="compare-display estimated float-right">
- <span class="compare-label">
- {{ s__('TimeTrackingEstimated|Est') }}
- </span>
- <span class="compare-value">
- {{ timeEstimateHumanReadable }}
- </span>
+ <span class="compare-label"> {{ s__('TimeTrackingEstimated|Est') }} </span>
+ <span class="compare-value"> {{ timeEstimateHumanReadable }} </span>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/estimate_only_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/estimate_only_pane.vue
index 08fce597e50..305726d9725 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/estimate_only_pane.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/estimate_only_pane.vue
@@ -12,9 +12,6 @@ export default {
<template>
<div class="time-tracking-estimate-only-pane">
- <span class="bold">
- {{ s__('TimeTracking|Estimated:') }}
- </span>
- {{ timeEstimateHumanReadable }}
+ <span class="bold"> {{ s__('TimeTracking|Estimated:') }} </span> {{ timeEstimateHumanReadable }}
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue b/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue
index 91909cd49b8..51cd5810ac0 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue
@@ -40,22 +40,11 @@ export default {
<template>
<div class="time-tracking-help-state">
<div class="time-tracking-info">
- <h4>
- {{ __('Track time with quick actions') }}
- </h4>
- <p>
- {{ __('Quick actions can be used in the issues description and comment boxes.') }}
- </p>
- <p v-html="estimateText">
- </p>
- <p v-html="spendText">
- </p>
- <a
- :href="href"
- class="btn btn-default learn-more-button"
- >
- {{ __('Learn more') }}
- </a>
+ <h4>{{ __('Track time with quick actions') }}</h4>
+ <p>{{ __('Quick actions can be used in the issues description and comment boxes.') }}</p>
+ <p v-html="estimateText"></p>
+ <p v-html="spendText"></p>
+ <a :href="href" class="btn btn-default learn-more-button"> {{ __('Learn more') }} </a>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/no_tracking_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/no_tracking_pane.vue
index 9228184df5b..45552589e50 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/no_tracking_pane.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/no_tracking_pane.vue
@@ -6,8 +6,6 @@ export default {
<template>
<div class="time-tracking-no-tracking-pane">
- <span class="no-value">
- {{ __('No estimate or time spent') }}
- </span>
+ <span class="no-value"> {{ __('No estimate or time spent') }} </span>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue
index 59cd99f8f14..7c7356e2afa 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue
@@ -12,7 +12,6 @@ export default {
<template>
<div class="time-tracking-spend-only-pane">
- <span class="bold">Spent:</span>
- {{ timeSpentHumanReadable }}
+ <span class="bold">Spent:</span> {{ timeSpentHumanReadable }}
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
index ef76dc13ce9..d3a4f9c81e0 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
@@ -90,10 +90,7 @@ export default {
</script>
<template>
- <div
- v-cloak
- class="time_tracker time-tracking-component-wrap"
- >
+ <div v-cloak class="time_tracker time-tracking-component-wrap">
<time-tracking-collapsed-state
:show-comparison-state="showComparisonState"
:show-no-time-tracking-state="showNoTimeTrackingState"
@@ -105,27 +102,15 @@ export default {
/>
<div class="title hide-collapsed">
{{ __('Time tracking') }}
- <div
- v-if="!showHelpState"
- class="help-button float-right"
- @click="toggleHelpState(true)"
- >
- <i
- class="fa fa-question-circle"
- aria-hidden="true"
- >
- </i>
+ <div v-if="!showHelpState" class="help-button float-right" @click="toggleHelpState(true);">
+ <i class="fa fa-question-circle" aria-hidden="true"> </i>
</div>
<div
v-if="showHelpState"
class="close-help-button float-right"
- @click="toggleHelpState(false)"
+ @click="toggleHelpState(false);"
>
- <i
- class="fa fa-close"
- aria-hidden="true"
- >
- </i>
+ <i class="fa fa-close" aria-hidden="true"> </i>
</div>
</div>
<div class="time-tracking-content hide-collapsed">
@@ -137,9 +122,7 @@ export default {
v-if="showSpentOnlyState"
:time-spent-human-readable="humanTimeSpent"
/>
- <time-tracking-no-tracking-pane
- v-if="showNoTimeTrackingState"
- />
+ <time-tracking-no-tracking-pane v-if="showNoTimeTrackingState" />
<time-tracking-comparison-pane
v-if="showComparisonState"
:time-estimate="timeEstimate"
@@ -148,10 +131,7 @@ export default {
:time-estimate-human-readable="humanTimeEstimate"
/>
<transition name="help-state-toggle">
- <time-tracking-help-state
- v-if="showHelpState"
- :root-path="rootPath"
- />
+ <time-tracking-help-state v-if="showHelpState" :root-path="rootPath" />
</transition>
</div>
</div>
diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue
index 913a616d9f1..706e6ca19c3 100644
--- a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue
+++ b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue
@@ -1,7 +1,7 @@
<script>
import { __ } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
@@ -84,15 +84,7 @@ export default {
:css-classes="collapsedButtonIconClasses"
:name="collapsedButtonIcon"
/>
- <span
- v-show="!collapsed"
- class="issuable-todo-inner"
- >
- {{ buttonLabel }}
- </span>
- <gl-loading-icon
- v-show="isActionActive"
- :inline="true"
- />
+ <span v-show="!collapsed" class="issuable-todo-inner"> {{ buttonLabel }} </span>
+ <gl-loading-icon v-show="isActionActive" :inline="true" />
</button>
</template>
diff --git a/app/assets/javascripts/star.js b/app/assets/javascripts/star.js
index 007b83e1927..9af5d5b23cb 100644
--- a/app/assets/javascripts/star.js
+++ b/app/assets/javascripts/star.js
@@ -23,11 +23,11 @@ export default class Star {
if (isStarred) {
$starSpan.removeClass('starred').text(s__('StarProject|Star'));
$startIcon.remove();
- $this.prepend(spriteIcon('star-o'));
+ $this.prepend(spriteIcon('star-o', 'icon'));
} else {
$starSpan.addClass('starred').text(__('Unstar'));
$startIcon.remove();
- $this.prepend(spriteIcon('star'));
+ $this.prepend(spriteIcon('star', 'icon'));
}
})
.catch(() => Flash('Star toggle failed. Try again later.'));
diff --git a/app/assets/javascripts/terminal/index.js b/app/assets/javascripts/terminal/index.js
index 49aeb377c74..8faff59fd45 100644
--- a/app/assets/javascripts/terminal/index.js
+++ b/app/assets/javascripts/terminal/index.js
@@ -1,3 +1,3 @@
import Terminal from './terminal';
-export default () => new Terminal({ selector: '#terminal' });
+export default () => new Terminal(document.getElementById('terminal'));
diff --git a/app/assets/javascripts/terminal/terminal.js b/app/assets/javascripts/terminal/terminal.js
index b24aa8a3a34..560f50ebf8f 100644
--- a/app/assets/javascripts/terminal/terminal.js
+++ b/app/assets/javascripts/terminal/terminal.js
@@ -1,9 +1,15 @@
+import _ from 'underscore';
import $ from 'jquery';
import { Terminal } from 'xterm';
import * as fit from 'xterm/lib/addons/fit/fit';
+import { canScrollUp, canScrollDown } from '~/lib/utils/dom_utils';
+
+const SCROLL_MARGIN = 5;
+
+Terminal.applyAddon(fit);
export default class GLTerminal {
- constructor(options = {}) {
+ constructor(element, options = {}) {
this.options = Object.assign(
{},
{
@@ -13,7 +19,8 @@ export default class GLTerminal {
options,
);
- this.container = document.querySelector(options.selector);
+ this.container = element;
+ this.onDispose = [];
this.setSocketUrl();
this.createTerminal();
@@ -34,8 +41,6 @@ export default class GLTerminal {
}
createTerminal() {
- Terminal.applyAddon(fit);
-
this.terminal = new Terminal(this.options);
this.socket = new WebSocket(this.socketUrl, ['terminal.gitlab.com']);
@@ -72,4 +77,48 @@ export default class GLTerminal {
handleSocketFailure() {
this.terminal.write('\r\nConnection failure');
}
+
+ addScrollListener(onScrollLimit) {
+ const viewport = this.container.querySelector('.xterm-viewport');
+ const listener = _.throttle(() => {
+ onScrollLimit({
+ canScrollUp: canScrollUp(viewport, SCROLL_MARGIN),
+ canScrollDown: canScrollDown(viewport, SCROLL_MARGIN),
+ });
+ });
+
+ this.onDispose.push(() => viewport.removeEventListener('scroll', listener));
+ viewport.addEventListener('scroll', listener);
+
+ // don't forget to initialize value before scroll!
+ listener({ target: viewport });
+ }
+
+ disable() {
+ this.terminal.setOption('cursorBlink', false);
+ this.terminal.setOption('theme', { foreground: '#707070' });
+ this.terminal.setOption('disableStdin', true);
+ this.socket.close();
+ }
+
+ dispose() {
+ this.terminal.off('data');
+ this.terminal.dispose();
+ this.socket.close();
+
+ this.onDispose.forEach(fn => fn());
+ this.onDispose.length = 0;
+ }
+
+ scrollToTop() {
+ this.terminal.scrollToTop();
+ }
+
+ scrollToBottom() {
+ this.terminal.scrollToBottom();
+ }
+
+ fit() {
+ this.terminal.fit();
+ }
}
diff --git a/app/assets/javascripts/toggle_buttons.js b/app/assets/javascripts/toggle_buttons.js
index d83ffc7e211..bcb44bf7acf 100644
--- a/app/assets/javascripts/toggle_buttons.js
+++ b/app/assets/javascripts/toggle_buttons.js
@@ -1,7 +1,7 @@
import $ from 'jquery';
import Flash from './flash';
import { __ } from './locale';
-import { convertPermissionToBoolean } from './lib/utils/common_utils';
+import { parseBoolean } from './lib/utils/common_utils';
/*
example HAML:
@@ -18,7 +18,7 @@ function updateToggle(toggle, isOn) {
}
function onToggleClicked(toggle, input, clickCallback) {
- const previousIsOn = convertPermissionToBoolean(input.value);
+ const previousIsOn = parseBoolean(input.value);
// Visually change the toggle and start loading
updateToggle(toggle, !previousIsOn);
@@ -51,7 +51,7 @@ export default function setupToggleButtons(container, clickCallback = () => {})
toggles.forEach(toggle => {
const input = toggle.querySelector('.js-project-feature-toggle-input');
- const isOn = convertPermissionToBoolean(input.value);
+ const isOn = parseBoolean(input.value);
// Get the visible toggle in sync with the hidden input
updateToggle(toggle, isOn);
diff --git a/app/assets/javascripts/usage_ping_consent.js b/app/assets/javascripts/usage_ping_consent.js
index 05607f09a7e..d3d745a3c11 100644
--- a/app/assets/javascripts/usage_ping_consent.js
+++ b/app/assets/javascripts/usage_ping_consent.js
@@ -1,7 +1,7 @@
import $ from 'jquery';
import axios from './lib/utils/axios_utils';
import Flash, { hideFlash } from './flash';
-import { convertPermissionToBoolean } from './lib/utils/common_utils';
+import { parseBoolean } from './lib/utils/common_utils';
export default () => {
$('body').on('click', '.js-usage-consent-action', e => {
@@ -11,8 +11,8 @@ export default () => {
const { url, checkEnabled, pingEnabled } = e.target.dataset;
const data = {
application_setting: {
- version_check_enabled: convertPermissionToBoolean(checkEnabled),
- usage_ping_enabled: convertPermissionToBoolean(pingEnabled),
+ version_check_enabled: parseBoolean(checkEnabled),
+ usage_ping_enabled: parseBoolean(pingEnabled),
},
};
diff --git a/app/assets/javascripts/user_popovers.js b/app/assets/javascripts/user_popovers.js
new file mode 100644
index 00000000000..948f4d5e631
--- /dev/null
+++ b/app/assets/javascripts/user_popovers.js
@@ -0,0 +1,107 @@
+import Vue from 'vue';
+
+import UsersCache from './lib/utils/users_cache';
+import UserPopover from './vue_shared/components/user_popover/user_popover.vue';
+
+let renderedPopover;
+let renderFn;
+
+const handleUserPopoverMouseOut = event => {
+ const { target } = event;
+ target.removeEventListener('mouseleave', handleUserPopoverMouseOut);
+
+ if (renderFn) {
+ clearTimeout(renderFn);
+ }
+ if (renderedPopover) {
+ renderedPopover.$destroy();
+ renderedPopover = null;
+ }
+};
+
+/**
+ * Adds a UserPopover component to the body, hands over as much data as the target element has in data attributes.
+ * loads based on data-user-id more data about a user from the API and sets it on the popover
+ */
+const handleUserPopoverMouseOver = event => {
+ const { target } = event;
+ // Add listener to actually remove it again
+ target.addEventListener('mouseleave', handleUserPopoverMouseOut);
+
+ renderFn = setTimeout(() => {
+ // Helps us to use current markdown setup without maybe breaking or duplicating for now
+ if (target.dataset.user) {
+ target.dataset.userId = target.dataset.user;
+ // Removing titles so its not showing tooltips also
+ target.dataset.originalTitle = '';
+ target.setAttribute('title', '');
+ }
+
+ const { userId, username, name, avatarUrl } = target.dataset;
+ const user = {
+ userId,
+ username,
+ name,
+ avatarUrl,
+ location: null,
+ bio: null,
+ organization: null,
+ status: null,
+ loaded: false,
+ };
+ if (userId || username) {
+ const UserPopoverComponent = Vue.extend(UserPopover);
+ renderedPopover = new UserPopoverComponent({
+ propsData: {
+ target,
+ user,
+ },
+ });
+
+ renderedPopover.$mount();
+
+ UsersCache.retrieveById(userId)
+ .then(userData => {
+ if (!userData) {
+ return;
+ }
+
+ Object.assign(user, {
+ avatarUrl: userData.avatar_url,
+ username: userData.username,
+ name: userData.name,
+ location: userData.location,
+ bio: userData.bio,
+ organization: userData.organization,
+ loaded: true,
+ });
+
+ UsersCache.retrieveStatusById(userId)
+ .then(status => {
+ if (!status) {
+ return;
+ }
+
+ Object.assign(user, {
+ status,
+ });
+ })
+ .catch(() => {
+ throw new Error(`User status for "${userId}" could not be retrieved!`);
+ });
+ })
+ .catch(() => {
+ renderedPopover.$destroy();
+ renderedPopover = null;
+ });
+ }
+ }, 200); // 200ms delay so not every mouseover triggers Popover + API Call
+};
+
+export default elements => {
+ const userLinks = elements || [...document.querySelectorAll('.js-user-link')];
+
+ userLinks.forEach(el => {
+ el.addEventListener('mouseenter', handleUserPopoverMouseOver);
+ });
+};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
index 4ec925aa8a6..2f2a37347af 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
@@ -1,10 +1,10 @@
<script>
+import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
import FilteredSearchDropdown from '~/vue_shared/components/filtered_search_dropdown.vue';
import { __ } from '~/locale';
import timeagoMixin from '../../vue_shared/mixins/timeago';
-import tooltip from '../../vue_shared/directives/tooltip';
import LoadingButton from '../../vue_shared/components/loading_button.vue';
import { visitUrl } from '../../lib/utils/url_utility';
import createFlash from '../../flash';
@@ -25,7 +25,7 @@ export default {
ReviewAppLink,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
mixins: [timeagoMixin],
props: {
@@ -33,11 +33,17 @@ export default {
type: Object,
required: true,
},
+ showMetrics: {
+ type: Boolean,
+ required: true,
+ },
},
deployedTextMap: {
running: __('Deploying to'),
success: __('Deployed to'),
failed: __('Failed to deploy to'),
+ created: __('Will deploy to'),
+ canceled: __('Failed to deploy to'),
},
data() {
return {
@@ -74,6 +80,9 @@ export default {
shouldRenderDropdown() {
return this.deployment.changes && this.deployment.changes.length > 0;
},
+ showMemoryUsage() {
+ return this.hasMetrics && this.showMetrics;
+ },
},
methods: {
stopEnvironment() {
@@ -103,15 +112,13 @@ export default {
</script>
<template>
- <div class="mr-widget-heading deploy-heading append-bottom-default">
+ <div class="deploy-heading">
<div class="ci-widget media">
<div class="media-body">
<div class="deploy-body">
<div class="js-deployment-info deployment-info">
<template v-if="hasDeploymentMeta">
- <span>
- {{ deployedText }}
- </span>
+ <span> {{ deployedText }} </span>
<tooltip-on-truncate
:title="deployment.name"
truncate-target="child"
@@ -129,14 +136,14 @@ export default {
</template>
<span
v-if="hasDeploymentTime"
- v-tooltip
+ v-gl-tooltip
:title="deployment.deployed_at_formatted"
class="js-deploy-time"
>
{{ deployTimeago }}
</span>
<memory-usage
- v-if="hasMetrics"
+ v-if="showMemoryUsage"
:metrics-url="deployment.metrics_url"
:metrics-monitoring-url="deployment.metrics_monitoring_url"
/>
@@ -150,20 +157,14 @@ export default {
:main-action-link="deployment.external_url"
filter-key="path"
>
- <template
- slot="mainAction"
- slot-scope="slotProps"
- >
+ <template slot="mainAction" slot-scope="slotProps">
<review-app-link
:link="deployment.external_url"
:css-class="`deploy-link js-deploy-url inline ${slotProps.className}`"
/>
</template>
- <template
- slot="result"
- slot-scope="slotProps"
- >
+ <template slot="result" slot-scope="slotProps">
<a
:href="slotProps.result.external_url"
target="_blank"
@@ -186,11 +187,11 @@ export default {
css-class="js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inlin"
/>
</template>
- <span
+ <span
v-if="deployment.stop_url"
- v-tooltip
+ v-gl-tooltip
:title="deployInProgressTooltip"
- class="d-inline-block"
+ class="d-inline-block"
tabindex="0"
>
<loading-button
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue b/app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue
index 41dbc5c9cbb..7ce454b7338 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue
@@ -154,27 +154,19 @@ export default {
<template>
<div class="mr-info-list clearfix mr-memory-usage js-mr-memory-usage">
- <p
- v-if="shouldShowLoading"
- class="usage-info js-usage-info usage-info-loading">
- <i
- class="fa fa-spinner fa-spin usage-info-load-spinner"
- aria-hidden="true">
- </i>{{ s__('mrWidget|Loading deployment statistics') }}
+ <p v-if="shouldShowLoading" class="usage-info js-usage-info usage-info-loading">
+ <i class="fa fa-spinner fa-spin usage-info-load-spinner" aria-hidden="true"> </i
+ >{{ s__('mrWidget|Loading deployment statistics') }}
</p>
<p
v-if="shouldShowMemoryGraph"
class="usage-info js-usage-info"
- v-html="memoryChangeMessage">
- </p>
- <p
- v-if="shouldShowLoadFailure"
- class="usage-info js-usage-info usage-info-failed">
+ v-html="memoryChangeMessage"
+ ></p>
+ <p v-if="shouldShowLoadFailure" class="usage-info js-usage-info usage-info-failed">
{{ s__('mrWidget|Failed to load deployment statistics') }}
</p>
- <p
- v-if="shouldShowMetricsUnavailable"
- class="usage-info js-usage-info usage-info-unavailable">
+ <p v-if="shouldShowMetricsUnavailable" class="usage-info js-usage-info usage-info-unavailable">
{{ s__('mrWidget|Deployment statistics are not available currently') }}
</p>
<memory-graph
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue
index 2ad9e8be655..84937aa9510 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue
@@ -39,15 +39,7 @@ export default {
:title="author.name"
class="author-link inline"
>
- <img
- :src="avatarUrl"
- class="avatar avatar-inline s16"
- />
- <span
- v-if="showAuthorName"
- class="author"
- >
- {{ author.name }}
- </span>
+ <img :src="avatarUrl" class="avatar avatar-inline s16" />
+ <span v-if="showAuthorName" class="author"> {{ author.name }} </span>
</a>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
index 1d902131f49..6b3007fce51 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
@@ -34,12 +34,6 @@ export default {
<h4 class="js-mr-widget-author">
{{ actionText }}
<mr-widget-author :author="author" />
- <time
- v-tooltip
- :title="dateTitle"
- data-container="body"
- >
- {{ dateReadable }}
- </time>
+ <time v-tooltip :title="dateTitle" data-container="body"> {{ dateReadable }} </time>
</h4>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_container.vue
new file mode 100644
index 00000000000..5967ca026e5
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_container.vue
@@ -0,0 +1,6 @@
+<template>
+ <div class="mr-widget-heading">
+ <div class="mr-widget-content"><slot name="default"></slot></div>
+ <slot name="footer"></slot>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
index acfdab3a015..3b9fc2661ef 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
@@ -6,6 +6,7 @@ import Icon from '~/vue_shared/components/icon.vue';
import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
import tooltip from '~/vue_shared/directives/tooltip';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import MrWidgetIcon from './mr_widget_icon.vue';
export default {
name: 'MRWidgetHeader',
@@ -13,6 +14,7 @@ export default {
Icon,
clipboardButton,
TooltipOnTruncate,
+ MrWidgetIcon,
},
directives: {
tooltip,
@@ -76,13 +78,11 @@ export default {
</script>
<template>
<div class="mr-source-target append-bottom-default">
- <div class="git-merge-icon-container append-right-default">
- <icon name="git-merge" />
- </div>
+ <mr-widget-icon name="git-merge" />
<div class="git-merge-container d-flex">
<div class="normal">
<strong>
- {{ s__("mrWidget|Request to merge") }}
+ {{ s__('mrWidget|Request to merge') }}
<tooltip-on-truncate
:title="mr.sourceBranch"
truncate-target="child"
@@ -93,32 +93,23 @@ export default {
:title="__('Copy branch name to clipboard')"
css-class="btn-default btn-transparent btn-clipboard"
/>
- {{ s__("mrWidget|into") }}
+ {{ s__('mrWidget|into') }}
<tooltip-on-truncate
:title="mr.targetBranch"
truncate-target="child"
class="label-branch label-truncate"
>
- <a
- :href="mr.targetBranchTreePath"
- class="js-target-branch"
- >
- {{ mr.targetBranch }}
- </a>
+ <a :href="mr.targetBranchTreePath" class="js-target-branch"> {{ mr.targetBranch }} </a>
</tooltip-on-truncate>
</strong>
<div
v-if="shouldShowCommitsBehindText"
class="diverged-commits-count"
v-html="commitsBehindText"
- >
- </div>
+ ></div>
</div>
- <div
- v-if="mr.isOpen"
- class="branch-actions d-flex"
- >
+ <div v-if="mr.isOpen" class="branch-actions d-flex">
<a
v-if="!mr.sourceBranchRemoved"
v-tooltip
@@ -130,7 +121,7 @@ export default {
tabindex="0"
role="button"
>
- {{ s__("mrWidget|Open in Web IDE") }}
+ {{ s__('mrWidget|Open in Web IDE') }}
</a>
<button
:disabled="mr.sourceBranchRemoved"
@@ -139,7 +130,7 @@ export default {
class="btn btn-default js-check-out-branch append-right-default"
type="button"
>
- {{ s__("mrWidget|Check out branch") }}
+ {{ s__('mrWidget|Check out branch') }}
</button>
<span class="dropdown">
<button
@@ -150,29 +141,17 @@ export default {
aria-haspopup="true"
aria-expanded="false"
>
- <icon name="download" />
- <i
- class="fa fa-caret-down"
- aria-hidden="true">
- </i>
+ <icon name="download" /> <i class="fa fa-caret-down" aria-hidden="true"> </i>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li>
- <a
- :href="mr.emailPatchesPath"
- class="js-download-email-patches"
- download
- >
- {{ s__("mrWidget|Email patches") }}
+ <a :href="mr.emailPatchesPath" class="js-download-email-patches" download>
+ {{ s__('mrWidget|Email patches') }}
</a>
</li>
<li>
- <a
- :href="mr.plainDiffPath"
- class="js-download-plain-diff"
- download
- >
- {{ s__("mrWidget|Plain diff") }}
+ <a :href="mr.plainDiffPath" class="js-download-plain-diff" download>
+ {{ s__('mrWidget|Plain diff') }}
</a>
</li>
</ul>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_icon.vue
new file mode 100644
index 00000000000..e3adc7f7af5
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_icon.vue
@@ -0,0 +1,17 @@
+<script>
+import Icon from '~/vue_shared/components/icon.vue';
+
+export default {
+ components: { Icon },
+ props: {
+ name: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="circle-icon-container append-right-default"><icon :name="name" /></div>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue
index 37c6af13c03..a347269c916 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue
@@ -28,7 +28,7 @@ export default {
{{ missingBranchInfo }}
</template>
<template v-else>
- {{ s__("mrWidget|You can merge this merge request manually using the") }}
+ {{ s__('mrWidget|You can merge this merge request manually using the') }}
</template>
<button
@@ -37,7 +37,7 @@ export default {
data-toggle="modal"
data-target="#modal_merge_info"
>
- {{ s__("mrWidget|command line") }}
+ {{ s__('mrWidget|command line') }}
</button>
</section>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
index 53608838f2f..f11cf21b0ca 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
@@ -79,93 +79,65 @@ export default {
</script>
<template>
- <div
- v-if="hasPipeline || hasCIError"
- class="mr-widget-heading append-bottom-default"
- >
- <div class="ci-widget media">
- <template v-if="hasCIError">
- <div
- class="add-border ci-status-icon ci-status-icon-failed ci-error
- js-ci-error append-right-default"
- >
- <icon
- :size="32"
- name="status_failed_borderless"
- />
- </div>
- <div
- class="media-body"
- v-html="errorText"
- >
- </div>
- </template>
- <template v-else-if="hasPipeline">
- <a
- :href="status.details_path"
- class="align-self-start append-right-default"
- >
- <ci-icon
- :status="status"
- :size="32"
- :borderless="true"
- class="add-border"
- />
- </a>
- <div class="ci-widget-container d-flex">
- <div class="ci-widget-content">
- <div class="media-body">
- <div class="font-weight-bold">
- Pipeline
- <a
- :href="pipeline.path"
- class="pipeline-id font-weight-normal pipeline-number"
- >#{{ pipeline.id }}</a>
+ <div v-if="hasPipeline || hasCIError" class="ci-widget media">
+ <template v-if="hasCIError">
+ <div
+ class="add-border ci-status-icon ci-status-icon-failed ci-error
+ js-ci-error append-right-default"
+ >
+ <icon :size="32" name="status_failed_borderless" />
+ </div>
+ <div class="media-body" v-html="errorText"></div>
+ </template>
+ <template v-else-if="hasPipeline">
+ <a :href="status.details_path" class="align-self-start append-right-default">
+ <ci-icon :status="status" :size="32" :borderless="true" class="add-border" />
+ </a>
+ <div class="ci-widget-container d-flex">
+ <div class="ci-widget-content">
+ <div class="media-body">
+ <div class="font-weight-bold">
+ Pipeline
+ <a :href="pipeline.path" class="pipeline-id font-weight-normal pipeline-number"
+ >#{{ pipeline.id }}</a
+ >
- {{ pipeline.details.status.label }}
+ {{ pipeline.details.status.label }}
- <template v-if="hasCommitInfo">
- for
- <a
- :href="pipeline.commit.commit_path"
- class="commit-sha js-commit-link font-weight-normal"
- >
- {{ pipeline.commit.short_id }}</a>
- on
- <tooltip-on-truncate
- :title="sourceBranch"
- truncate-target="child"
- class="label-branch label-truncate"
- v-html="sourceBranchLink"
- />
- </template>
- </div>
- <div
- v-if="pipeline.coverage"
- class="coverage"
- >
- Coverage {{ pipeline.coverage }}%
- </div>
+ <template v-if="hasCommitInfo">
+ for
+ <a
+ :href="pipeline.commit.commit_path"
+ class="commit-sha js-commit-link font-weight-normal"
+ >
+ {{ pipeline.commit.short_id }}</a
+ >
+ on
+ <tooltip-on-truncate
+ :title="sourceBranch"
+ truncate-target="child"
+ class="label-branch label-truncate"
+ v-html="sourceBranchLink"
+ />
+ </template>
</div>
+ <div v-if="pipeline.coverage" class="coverage">Coverage {{ pipeline.coverage }}%</div>
</div>
- <div>
- <span class="mr-widget-pipeline-graph">
- <span
- v-if="hasStages"
- class="stage-cell"
+ </div>
+ <div>
+ <span class="mr-widget-pipeline-graph">
+ <span v-if="hasStages" class="stage-cell">
+ <div
+ v-for="(stage, i) in pipeline.details.stages"
+ :key="i"
+ class="stage-container dropdown js-mini-pipeline-graph mr-widget-pipeline-stages"
>
- <div
- v-for="(stage, i) in pipeline.details.stages"
- :key="i"
- class="stage-container dropdown js-mini-pipeline-graph mr-widget-pipeline-stages"
- >
- <pipeline-stage :stage="stage" />
- </div>
- </span>
+ <pipeline-stage :stage="stage" />
+ </div>
</span>
- </div>
+ </span>
</div>
- </template>
- </div>
+ </div>
+ </template>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
new file mode 100644
index 00000000000..5f5fe67b3c1
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
@@ -0,0 +1,74 @@
+<script>
+import Deployment from './deployment.vue';
+import MrWidgetContainer from './mr_widget_container.vue';
+import MrWidgetPipeline from './mr_widget_pipeline.vue';
+
+/**
+ * Renders the pipeline and related deployments from the store.
+ *
+ * | Props | Description
+ * |---------------|-------------
+ * | `mr` | This is the mr_widget store
+ * | `isPostMerge` | If true, show the "post merge" pipeline and deployments
+ */
+export default {
+ name: 'MrWidgetPipelineContainer',
+ components: {
+ Deployment,
+ MrWidgetContainer,
+ MrWidgetPipeline,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ },
+ isPostMerge: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ pipeline() {
+ return this.isPostMerge ? this.mr.mergePipeline : this.mr.pipeline;
+ },
+ branch() {
+ return this.isPostMerge ? this.mr.targetBranch : this.mr.sourceBranch;
+ },
+ branchLink() {
+ return this.isPostMerge ? this.mr.targetBranch : this.mr.sourceBranchLink;
+ },
+ deployments() {
+ return this.isPostMerge ? this.mr.postMergeDeployments : this.mr.deployments;
+ },
+ deploymentClass() {
+ return this.isPostMerge ? 'js-post-deployment' : 'js-pre-deployment';
+ },
+ hasDeploymentMetrics() {
+ return this.isPostMerge;
+ },
+ },
+};
+</script>
+<template>
+ <mr-widget-container>
+ <mr-widget-pipeline
+ :pipeline="pipeline"
+ :ci-status="mr.ciStatus"
+ :has-ci="mr.hasCI"
+ :source-branch="branch"
+ :source-branch-link="branchLink"
+ :troubleshooting-docs-path="mr.troubleshootingDocsPath"
+ />
+ <div v-if="deployments.length" slot="footer" class="mr-widget-extension">
+ <deployment
+ v-for="deployment in deployments"
+ :key="deployment.id"
+ :class="deploymentClass"
+ :deployment="deployment"
+ :show-metrics="hasDeploymentMetrics"
+ />
+ </div>
+ </mr-widget-container>
+</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
index cc77b96a589..1b3b589c32f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue
@@ -30,14 +30,10 @@ export default {
</script>
<template>
<section class="mr-info-list mr-links">
- <p v-if="relatedLinks.closing">
- {{ closesText }} <span v-html="relatedLinks.closing"></span>
- </p>
+ <p v-if="relatedLinks.closing">{{ closesText }} <span v-html="relatedLinks.closing"></span></p>
<p v-if="relatedLinks.mentioned">
- {{ s__("mrWidget|Mentions") }} <span v-html="relatedLinks.mentioned"></span>
- </p>
- <p v-if="relatedLinks.assignToMe">
- <span v-html="relatedLinks.assignToMe"></span>
+ {{ s__('mrWidget|Mentions') }} <span v-html="relatedLinks.mentioned"></span>
</p>
+ <p v-if="relatedLinks.assignToMe"><span v-html="relatedLinks.assignToMe"></span></p>
</section>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
index b3340290ed3..780ced4d382 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import ciIcon from '../../vue_shared/components/ci_icon.vue';
export default {
@@ -33,18 +33,9 @@ export default {
</script>
<template>
<div class="space-children d-flex append-right-10 widget-status-icon">
- <div
- v-if="isLoading"
- class="mr-widget-icon"
- >
- <gl-loading-icon />
- </div>
+ <div v-if="isLoading" class="mr-widget-icon"><gl-loading-icon /></div>
- <ci-icon
- v-else
- :status="statusObj"
- :size="24"
- />
+ <ci-icon v-else :status="statusObj" :size="24" />
<button
v-if="showDisabledButton"
@@ -52,7 +43,7 @@ export default {
class="js-disabled-merge-button btn btn-success btn-sm"
disabled="true"
>
- {{ s__("mrWidget|Merge") }}
+ {{ s__('mrWidget|Merge') }}
</button>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue b/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue
index b007d4f4dcb..de9c122f268 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/review_app_link.vue
@@ -18,13 +18,7 @@ export default {
};
</script>
<template>
- <a
- :href="link"
- target="_blank"
- rel="noopener noreferrer nofollow"
- :class="cssClass"
- >
- {{ __('View app') }}
- <icon name="external-link" />
+ <a :href="link" target="_blank" rel="noopener noreferrer nofollow" :class="cssClass">
+ {{ __('View app') }} <icon name="external-link" />
</a>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue b/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue
index 01f707163d4..dd940548e30 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue
@@ -14,21 +14,9 @@ export default {
</script>
<template>
- <p
- v-once
- class="mr-info-list mr-links source-branch-removal-status append-bottom-0"
- >
- <span
- class="status-text"
- v-html="removesBranchText"
- >
- </span>
- <i
- v-tooltip
- :title="tooltipTitle"
- :aria-label="tooltipTitle"
- class="fa fa-question-circle"
- >
+ <p v-once class="mr-info-list mr-links source-branch-removal-status append-bottom-0">
+ <span class="status-text" v-html="removesBranchText"> </span>
+ <i v-tooltip :title="tooltipTitle" :aria-label="tooltipTitle" class="fa fa-question-circle">
</i>
</p>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue
index 2a76a878448..7ddcdd49df5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue
@@ -11,20 +11,14 @@ export default {
<template>
<div class="mr-widget-body media">
<div class="space-children">
- <status-icon
- status="warning"
- />
- <button
- type="button"
- class="btn btn-success btn-sm"
- disabled="true"
- >
- {{ s__("mrWidget|Merge") }}
+ <status-icon status="warning" />
+ <button type="button" class="btn btn-success btn-sm" disabled="true">
+ {{ s__('mrWidget|Merge') }}
</button>
</div>
<div class="media-body">
<span class="bold">
- {{ s__("mrWidget|This project is archived, write access has been disabled") }}
+ {{ s__('mrWidget|This project is archived, write access has been disabled') }}
</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue
index 4bfbdcf1404..a3a44dd8e99 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import eventHub from '../../event_hub';
import statusIcon from '../mr_widget_status_icon.vue';
@@ -35,8 +35,10 @@ export default {
<status-icon status="warning" />
<div class="media-body space-children">
<span class="bold">
- <template v-if="mr.mergeError">{{ mr.mergeError }}.</template>
- {{ s__("mrWidget|This merge request failed to be merged automatically") }}
+ <template v-if="mr.mergeError"
+ >{{ mr.mergeError }}.</template
+ >
+ {{ s__('mrWidget|This merge request failed to be merged automatically') }}
</span>
<button
:disabled="isRefreshing"
@@ -44,11 +46,8 @@ export default {
class="btn btn-sm btn-default"
@click="refreshWidget"
>
- <gl-loading-icon
- v-if="isRefreshing"
- :inline="true"
- />
- {{ s__("mrWidget|Refresh") }}
+ <gl-loading-icon v-if="isRefreshing" :inline="true" />
+ {{ s__('mrWidget|Refresh') }}
</button>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue
index fdf0a9fd994..cf26003d038 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue
@@ -10,14 +10,9 @@ export default {
</script>
<template>
<div class="mr-widget-body media">
- <status-icon
- :show-disabled-button="true"
- status="loading"
- />
+ <status-icon :show-disabled-button="true" status="loading" />
<div class="media-body space-children">
- <span class="bold">
- {{ s__("mrWidget|Checking ability to merge automatically") }}
- </span>
+ <span class="bold"> {{ s__('mrWidget|Checking ability to merge automatically') }} </span>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue
index f06eab95c7e..a5c75369fa1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue
@@ -21,9 +21,7 @@ export default {
</script>
<template>
<div class="mr-widget-body media">
- <status-icon
- status="warning"
- />
+ <status-icon status="warning" />
<div class="media-body">
<mr-widget-author-time
:action-text="s__('mrWidget|Closed by')"
@@ -34,13 +32,8 @@ export default {
<section class="mr-info-list">
<p>
- {{ s__("mrWidget|The changes were not merged into") }}
- <a
- :href="mr.targetBranchPath"
- class="label-branch"
- >
- {{ mr.targetBranch }}
- </a>
+ {{ s__('mrWidget|The changes were not merged into') }}
+ <a :href="mr.targetBranchPath" class="label-branch"> {{ mr.targetBranch }} </a>
</p>
</section>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
index 8c808296178..27352e0b2b1 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
@@ -19,25 +19,23 @@ export default {
</script>
<template>
<div class="mr-widget-body media">
- <status-icon
- :show-disabled-button="true"
- status="warning"
- />
+ <status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
- <span
- v-if="mr.shouldBeRebased"
- class="bold"
- >
- {{ s__(`mrWidget|Fast-forward merge is not possible.
-To merge this request, first rebase locally.`) }}
+ <span v-if="mr.shouldBeRebased" class="bold">
+ {{
+ s__(`mrWidget|Fast-forward merge is not possible.
+To merge this request, first rebase locally.`)
+ }}
</span>
<template v-else>
<span class="bold">
- {{ s__("mrWidget|There are merge conflicts") }}<span v-if="!mr.canMerge">.</span>
+ {{ s__('mrWidget|There are merge conflicts') }}<span v-if="!mr.canMerge">.</span>
<span v-if="!mr.canMerge">
- {{ s__(`mrWidget|Resolve these conflicts or ask someone
- with write access to this repository to merge it locally`) }}
+ {{
+ s__(`mrWidget|Resolve these conflicts or ask someone
+ with write access to this repository to merge it locally`)
+ }}
</span>
</span>
<a
@@ -45,7 +43,7 @@ To merge this request, first rebase locally.`) }}
:href="mr.conflictResolutionPath"
class="js-resolve-conflicts-button btn btn-default btn-sm"
>
- {{ s__("mrWidget|Resolve conflicts") }}
+ {{ s__('mrWidget|Resolve conflicts') }}
</a>
<button
v-if="mr.canMerge"
@@ -53,7 +51,7 @@ To merge this request, first rebase locally.`) }}
data-toggle="modal"
data-target="#modal_merge_info"
>
- {{ s__("mrWidget|Merge locally") }}
+ {{ s__('mrWidget|Merge locally') }}
</button>
</template>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
index c302960f16e..2a4dff71d9b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
@@ -74,38 +74,18 @@ export default {
<div class="mr-widget-body media">
<template v-if="isRefreshing">
<status-icon status="loading" />
- <span class="media-body bold js-refresh-label">
- {{ s__("mrWidget|Refreshing now") }}
- </span>
+ <span class="media-body bold js-refresh-label"> {{ s__('mrWidget|Refreshing now') }} </span>
</template>
<template v-else>
- <status-icon
- :show-disabled-button="true"
- status="warning"
- />
+ <status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
- <span
- v-if="mr.mergeError"
- class="has-error-message"
- >
- {{ mergeError }}.
- </span>
- <span v-else>
- {{ s__("mrWidget|Merge failed.") }}
- </span>
- <span
- :class="{ 'has-custom-error': mr.mergeError }"
- >
- {{ timerText }}
- </span>
+ <span v-if="mr.mergeError" class="has-error-message"> {{ mergeError }}. </span>
+ <span v-else> {{ s__('mrWidget|Merge failed.') }} </span>
+ <span :class="{ 'has-custom-error': mr.mergeError }"> {{ timerText }} </span>
</span>
- <button
- class="btn btn-default btn-sm js-refresh-button"
- type="button"
- @click="refresh"
- >
- {{ s__("mrWidget|Refresh now") }}
+ <button class="btn btn-default btn-sm js-refresh-button" type="button" @click="refresh">
+ {{ s__('mrWidget|Refresh now') }}
</button>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue
index 484b5600d63..02c76db4a50 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue
@@ -84,9 +84,9 @@ export default {
<div class="media-body">
<h4 class="d-flex align-items-start">
<span class="append-right-10">
- {{ s__("mrWidget|Set by") }}
+ {{ s__('mrWidget|Set by') }}
<mr-widget-author :author="mr.setToMWPSBy" />
- {{ s__("mrWidget|to be merged automatically when the pipeline succeeds") }}
+ {{ s__('mrWidget|to be merged automatically when the pipeline succeeds') }}
</span>
<a
v-if="mr.canCancelAutomaticMerge"
@@ -94,35 +94,23 @@ export default {
role="button"
href="#"
class="btn btn-sm btn-default js-cancel-auto-merge"
- @click.prevent="cancelAutomaticMerge">
- <i
- v-if="isCancellingAutoMerge"
- class="fa fa-spinner fa-spin"
- aria-hidden="true"
- >
- </i>
- {{ s__("mrWidget|Cancel automatic merge") }}
+ @click.prevent="cancelAutomaticMerge"
+ >
+ <i v-if="isCancellingAutoMerge" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
+ {{ s__('mrWidget|Cancel automatic merge') }}
</a>
</h4>
<section class="mr-info-list">
<p>
- {{ s__("mrWidget|The changes will be merged into") }}
- <a
- :href="mr.targetBranchPath"
- class="label-branch"
- >
- {{ mr.targetBranch }}
- </a>
+ {{ s__('mrWidget|The changes will be merged into') }}
+ <a :href="mr.targetBranchPath" class="label-branch"> {{ mr.targetBranch }} </a>
</p>
<p v-if="mr.shouldRemoveSourceBranch">
- {{ s__("mrWidget|The source branch will be removed") }}
+ {{ s__('mrWidget|The source branch will be removed') }}
</p>
- <p
- v-else
- class="d-flex align-items-start"
- >
+ <p v-else class="d-flex align-items-start">
<span class="append-right-10">
- {{ s__("mrWidget|The source branch will not be removed") }}
+ {{ s__('mrWidget|The source branch will not be removed') }}
</span>
<a
v-if="canRemoveSourceBranch"
@@ -132,13 +120,8 @@ export default {
href="#"
@click.prevent="removeSourceBranch"
>
- <i
- v-if="isRemovingSourceBranch"
- class="fa fa-spinner fa-spin"
- aria-hidden="true"
- >
- </i>
- {{ s__("mrWidget|Remove source branch") }}
+ <i v-if="isRemovingSourceBranch" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
+ {{ s__('mrWidget|Remove source branch') }}
</a>
</p>
</section>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
index 7e33021e4b4..fe83fe58b67 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
@@ -6,7 +6,7 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import MrWidgetAuthorTime from '../../components/mr_widget_author_time.vue';
import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
export default {
name: 'MRWidgetMerged',
@@ -154,7 +154,7 @@ export default {
</div>
<section class="mr-info-list">
<p>
- {{ s__("mrWidget|The changes were merged into") }}
+ {{ s__('mrWidget|The changes were merged into') }}
<span class="label-branch">
<a :href="mr.targetBranchPath">{{ mr.targetBranch }}</a>
</span>
@@ -174,27 +174,22 @@ export default {
</template>
</p>
<p v-if="mr.sourceBranchRemoved">
- {{ s__("mrWidget|The source branch has been removed") }}
+ {{ s__('mrWidget|The source branch has been removed') }}
</p>
- <p
- v-if="shouldShowRemoveSourceBranch"
- class="space-children"
- >
- <span>{{ s__("mrWidget|You can remove source branch now") }}</span>
+ <p v-if="shouldShowRemoveSourceBranch" class="space-children">
+ <span>{{ s__('mrWidget|You can remove source branch now') }}</span>
<button
:disabled="isMakingRequest"
type="button"
class="btn btn-sm btn-default js-remove-branch-button"
@click="removeSourceBranch"
>
- {{ s__("mrWidget|Remove Source Branch") }}
+ {{ s__('mrWidget|Remove Source Branch') }}
</button>
</p>
<p v-if="shouldShowSourceBranchRemoving">
<gl-loading-icon :inline="true" />
- <span>
- {{ s__("mrWidget|The source branch is being removed") }}
- </span>
+ <span> {{ s__('mrWidget|The source branch is being removed') }} </span>
</p>
</section>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue
index 139e64d1878..0655eef6504 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue
@@ -19,12 +19,10 @@ export default {
<div class="mr-widget-body mr-state-locked media">
<status-icon status="loading" />
<div class="media-body">
- <h4>
- {{ s__("mrWidget|This merge request is in the process of being merged") }}
- </h4>
+ <h4>{{ s__('mrWidget|This merge request is in the process of being merged') }}</h4>
<section class="mr-info-list">
<p>
- {{ s__("mrWidget|The changes will be merged into") }}
+ {{ s__('mrWidget|The changes will be merged into') }}
<span class="label-branch">
<a :href="mr.targetBranchPath">{{ mr.targetBranch }}</a>
</span>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
index 227e9b85f9d..e9aac8b385c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
@@ -46,24 +46,13 @@ export default {
</script>
<template>
<div class="mr-widget-body media">
- <status-icon
- :show-disabled-button="true"
- status="warning"
- />
+ <status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold js-branch-text">
- <span class="capitalize">
- {{ missingBranchName }}
- </span> {{ s__("mrWidget|branch does not exist.") }}
- {{ missingBranchNameMessage }}
- <i
- v-tooltip
- :title="message"
- :aria-label="message"
- class="fa fa-question-circle"
- >
- </i>
+ <span class="capitalize"> {{ missingBranchName }} </span>
+ {{ s__('mrWidget|branch does not exist.') }} {{ missingBranchNameMessage }}
+ <i v-tooltip :title="message" :aria-label="message" class="fa fa-question-circle"> </i>
</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue
index 360559ae0f0..c203d2824fa 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue
@@ -11,14 +11,13 @@ export default {
<template>
<div class="mr-widget-body media">
- <status-icon
- :show-disabled-button="true"
- status="success"
- />
+ <status-icon :show-disabled-button="true" status="success" />
<div class="media-body space-children">
<span class="bold">
- {{ s__(`mrWidget|Ready to be merged automatically.
-Ask someone with write access to this repository to merge this request`) }}
+ {{
+ s__(`mrWidget|Ready to be merged automatically.
+Ask someone with write access to this repository to merge this request`)
+ }}
</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue
index a4eb5afb21c..6331a7d8388 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue
@@ -10,14 +10,13 @@ export default {
</script>
<template>
<div class="mr-widget-body media">
- <status-icon
- :show-disabled-button="true"
- status="warning"
- />
+ <status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
- {{ s__(`mrWidget|Pipeline blocked.
-The pipeline for this merge request requires a manual action to proceed`) }}
+ {{
+ s__(`mrWidget|Pipeline blocked.
+The pipeline for this merge request requires a manual action to proceed`)
+ }}
</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
index 0e714cc2aa1..adfbcd18588 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import simplePoll from '../../../lib/utils/simple_poll';
import eventHub from '../../event_hub';
import statusIcon from '../mr_widget_status_icon.vue';
@@ -87,23 +87,17 @@ export default {
</script>
<template>
<div class="mr-widget-body media">
- <status-icon
- :status="status"
- :show-disabled-button="showDisabledButton"
- />
+ <status-icon :status="status" :show-disabled-button="showDisabledButton" />
<div class="rebase-state-find-class-convention media media-body space-children">
<template v-if="mr.rebaseInProgress || isMakingRequest">
- <span class="bold">
- Rebase in progress
- </span>
+ <span class="bold"> Rebase in progress </span>
</template>
<template v-if="!mr.rebaseInProgress && !mr.canPushToSourceBranch">
<span class="bold">
- Fast-forward merge is not possible.
- Rebase the source branch onto
- <span class="label-branch">{{ mr.targetBranch }}</span>
- to allow this merge request to be merged.
+ Fast-forward merge is not possible. Rebase the source branch onto
+ <span class="label-branch">{{ mr.targetBranch }}</span> to allow this merge request to be
+ merged.
</span>
</template>
<template v-if="!mr.rebaseInProgress && mr.canPushToSourceBranch && !isMakingRequest">
@@ -120,19 +114,11 @@ js-toggle-container accept-action media space-children"
<gl-loading-icon v-if="isMakingRequest" />
Rebase
</button>
- <span
- v-if="!rebasingError"
- class="bold"
- >
- Fast-forward merge is not possible.
- Rebase the source branch onto the target branch or merge target
- branch into source branch to allow this merge request to be merged.
- </span>
- <span
- v-else
- class="bold danger">
- {{ rebasingError }}
+ <span v-if="!rebasingError" class="bold">
+ Fast-forward merge is not possible. Rebase the source branch onto the target branch or
+ merge target branch into source branch to allow this merge request to be merged.
</span>
+ <span v-else class="bold danger"> {{ rebasingError }} </span>
</div>
</template>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
index e73b7e410d5..a38495bb4cc 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
@@ -23,21 +23,16 @@ export default {
</div>
<div class="text col-md-7 order-md-first col-12">
<span>
- Merge requests are a place to propose changes you have made to a project
- and discuss those changes with others.
+ Merge requests are a place to propose changes you have made to a project and discuss those
+ changes with others.
</span>
+ <p>Interested parties can even contribute by pushing commits if they want to.</p>
<p>
- Interested parties can even contribute by pushing commits if they want to.
- </p>
- <p>
- Currently there are no changes in this merge request's source branch.
- Please push new commits or use a different branch.
+ Currently there are no changes in this merge request's source branch. Please push new
+ commits or use a different branch.
</p>
<div>
- <a
- v-if="mr.newBlobPath"
- :href="mr.newBlobPath"
- class="btn btn-inverted btn-success">
+ <a v-if="mr.newBlobPath" :href="mr.newBlobPath" class="btn btn-inverted btn-success">
Create file
</a>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/pipeline_failed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/pipeline_failed.vue
index 2bb1a34412e..5f56157cb89 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/pipeline_failed.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/pipeline_failed.vue
@@ -11,14 +11,13 @@ export default {
<template>
<div class="mr-widget-body media">
- <status-icon
- :show-disabled-button="true"
- status="warning"
- />
+ <status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
- {{ s__(`mrWidget|The pipeline for this merge request failed.
-Please retry the job or push a new commit to fix the failure`) }}
+ {{
+ s__(`mrWidget|The pipeline for this merge request failed.
+Please retry the job or push a new commit to fix the failure`)
+ }}
</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
index e7baecbcde4..84c8a3464a5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
@@ -249,12 +249,9 @@ export default {
:class="mergeButtonClass"
type="button"
class="qa-merge-button"
- @click="handleMergeButtonClick()">
- <i
- v-if="isMakingRequest"
- class="fa fa-spinner fa-spin"
- aria-hidden="true"
- ></i>
+ @click="handleMergeButtonClick();"
+ >
+ <i v-if="isMakingRequest" class="fa fa-spinner fa-spin" aria-hidden="true"></i>
{{ mergeButtonText }}
</button>
<button
@@ -263,26 +260,23 @@ export default {
type="button"
class="btn btn-sm btn-info dropdown-toggle js-merge-moment"
data-toggle="dropdown"
- aria-label="Select merge moment">
- <i
- class="fa fa-chevron-down qa-merge-moment-dropdown"
- aria-hidden="true"
- ></i>
+ aria-label="Select merge moment"
+ >
+ <i class="fa fa-chevron-down qa-merge-moment-dropdown" aria-hidden="true"></i>
</button>
<ul
v-if="shouldShowMergeOptionsDropdown"
class="dropdown-menu dropdown-menu-right"
- role="menu">
+ role="menu"
+ >
<li>
<a
class="merge_when_pipeline_succeeds qa-merge-when-pipeline-succeeds-option"
href="#"
- @click.prevent="handleMergeButtonClick(true)">
+ @click.prevent="handleMergeButtonClick(true);"
+ >
<span class="media">
- <span
- class="merge-opt-icon"
- aria-hidden="true"
- v-html="successSvg"></span>
+ <span class="merge-opt-icon" aria-hidden="true" v-html="successSvg"></span>
<span class="media-body merge-opt-title">Merge when pipeline succeeds</span>
</span>
</a>
@@ -291,12 +285,10 @@ export default {
<a
class="accept-merge-request qa-merge-immediately-option"
href="#"
- @click.prevent="handleMergeButtonClick(false, true)">
+ @click.prevent="handleMergeButtonClick(false, true);"
+ >
<span class="media">
- <span
- class="merge-opt-icon"
- aria-hidden="true"
- v-html="warningSvg"></span>
+ <span class="merge-opt-icon" aria-hidden="true" v-html="warningSvg"></span>
<span class="media-body merge-opt-title">Merge immediately</span>
</span>
</a>
@@ -311,18 +303,19 @@ export default {
v-model="removeSourceBranch"
:disabled="isRemoveSourceBranchButtonDisabled"
class="js-remove-source-branch-checkbox"
- type="checkbox"/> Remove source branch
+ type="checkbox"
+ />
+ Remove source branch
</label>
<!-- Placeholder for EE extension of this component -->
<squash-before-merge
v-if="shouldShowSquashBeforeMerge"
:mr="mr"
- :is-merge-button-disabled="isMergeButtonDisabled" />
+ :is-merge-button-disabled="isMergeButtonDisabled"
+ />
- <span
- v-if="mr.ffOnlyEnabled"
- class="js-fast-forward-message">
+ <span v-if="mr.ffOnlyEnabled" class="js-fast-forward-message">
Fast-forward merge without a merge commit
</span>
<button
@@ -330,7 +323,8 @@ export default {
:disabled="isMergeButtonDisabled"
class="js-modify-commit-message-button btn btn-default btn-sm"
type="button"
- @click="toggleCommitMessageEditor">
+ @click="toggleCommitMessageEditor"
+ >
Modify commit message
</button>
</template>
@@ -341,15 +335,9 @@ export default {
</template>
</div>
</div>
- <div
- v-if="showCommitMessageEditor"
- class="prepend-top-default commit-message-editor">
+ <div v-if="showCommitMessageEditor" class="prepend-top-default commit-message-editor">
<div class="form-group clearfix">
- <label
- class="col-form-label"
- for="commit-message">
- Commit message
- </label>
+ <label class="col-form-label" for="commit-message"> Commit message </label>
<div class="col-sm-10">
<div class="commit-message-container">
<div class="max-width-marker"></div>
@@ -359,18 +347,14 @@ export default {
class="form-control js-commit-message"
required="required"
rows="14"
- name="Commit message"></textarea>
+ name="Commit message"
+ ></textarea>
</div>
<p class="hint">
Try to keep the first line under 52 characters and the others under 72
</p>
<div class="hint">
- <a
- href="#"
- @click.prevent="updateCommitMessage"
- >
- {{ commitMessageLinkTitle }}
- </a>
+ <a href="#" @click.prevent="updateCommitMessage"> {{ commitMessageLinkTitle }} </a>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue
index 16c903c923f..8acca0d6481 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/sha_mismatch.vue
@@ -11,14 +11,13 @@ export default {
<template>
<div class="mr-widget-body media">
- <status-icon
- :show-disabled-button="true"
- status="warning"
- />
+ <status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
- {{ s__(`mrWidget|The source branch HEAD has recently changed.
-Please reload the page and review the changes before merging`) }}
+ {{
+ s__(`mrWidget|The source branch HEAD has recently changed.
+Please reload the page and review the changes before merging`)
+ }}
</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
index 25ad329e196..e71acf0d7dd 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
@@ -55,9 +55,7 @@ export default {
rel="noopener noreferrer nofollow"
data-container="body"
>
- <icon
- name="question-o"
- />
+ <icon name="question-o" />
</a>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue
index 5eb2058a03b..a9fb40a4949 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue
@@ -17,20 +17,17 @@ export default {
<template>
<div class="mr-widget-body media">
- <status-icon
- :show-disabled-button="true"
- status="warning"
- />
+ <status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
- {{ s__("mrWidget|There are unresolved discussions. Please resolve these discussions") }}
+ {{ s__('mrWidget|There are unresolved discussions. Please resolve these discussions') }}
</span>
<a
v-if="mr.createIssueToResolveDiscussionsPath"
:href="mr.createIssueToResolveDiscussionsPath"
class="btn btn-default btn-sm js-create-issue"
>
- {{ s__("mrWidget|Create an issue to resolve them later") }}
+ {{ s__('mrWidget|Create an issue to resolve them later') }}
</a>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
index 9129fcbb918..7c322388d30 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
@@ -43,10 +43,7 @@ export default {
<template>
<div class="mr-widget-body media">
- <status-icon
- :show-disabled-button="Boolean(mr.removeWIPPath)"
- status="warning"
- />
+ <status-icon :show-disabled-button="Boolean(mr.removeWIPPath)" status="warning" />
<div class="media-body space-children">
<span class="bold">
This is a Work in Progress
@@ -56,7 +53,8 @@ export default {
title="When this merge request is ready,
remove the WIP: prefix from the title to allow it to be merged"
aria-label="When this merge request is ready,
- remove the WIP: prefix from the title to allow it to be merged">
+ remove the WIP: prefix from the title to allow it to be merged"
+ >
</i>
</span>
<button
@@ -64,13 +62,10 @@ export default {
:disabled="isMakingRequest"
type="button"
class="btn btn-default btn-sm js-remove-wip"
- @click="removeWIP">
- <i
- v-if="isMakingRequest"
- class="fa fa-spinner fa-spin"
- aria-hidden="true">
- </i>
- Resolve WIP status
+ @click="removeWIP"
+ >
+ <i v-if="isMakingRequest" class="fa fa-spinner fa-spin" aria-hidden="true"> </i> Resolve WIP
+ status
</button>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 063d1e15544..3c3e3efcc36 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -6,7 +6,7 @@ import SmartInterval from '~/smart_interval';
import createFlash from '../flash';
import WidgetHeader from './components/mr_widget_header.vue';
import WidgetMergeHelp from './components/mr_widget_merge_help.vue';
-import WidgetPipeline from './components/mr_widget_pipeline.vue';
+import MrWidgetPipelineContainer from './components/mr_widget_pipeline_container.vue';
import Deployment from './components/deployment.vue';
import WidgetRelatedLinks from './components/mr_widget_related_links.vue';
import MergedState from './components/states/mr_widget_merged.vue';
@@ -44,7 +44,7 @@ export default {
components: {
'mr-widget-header': WidgetHeader,
'mr-widget-merge-help': WidgetMergeHelp,
- 'mr-widget-pipeline': WidgetPipeline,
+ MrWidgetPipelineContainer,
Deployment,
'mr-widget-related-links': WidgetRelatedLinks,
'mr-widget-merged': MergedState,
@@ -295,25 +295,13 @@ export default {
</script>
<template>
<div class="mr-state-widget prepend-top-default">
- <mr-widget-header
- :mr="mr"
- />
- <mr-widget-pipeline
+ <mr-widget-header :mr="mr" />
+ <mr-widget-pipeline-container
v-if="shouldRenderPipelines"
- :pipeline="mr.pipeline"
- :ci-status="mr.ciStatus"
- :has-ci="mr.hasCI"
- :source-branch="mr.sourceBranch"
- :source-branch-link="mr.sourceBranchLink"
- :troubleshooting-docs-path="mr.troubleshootingDocsPath"
- />
- <deployment
- v-for="deployment in mr.deployments"
- :key="`pre-merge-deploy-${deployment.id}`"
- class="js-pre-merge-deploy"
- :deployment="deployment"
+ class="mr-widget-workflow"
+ :mr="mr"
/>
- <div class="mr-section-container">
+ <div class="mr-section-container mr-widget-workflow">
<grouped-test-reports-app
v-if="mr.testResultsPath"
class="js-reports-container"
@@ -321,17 +309,10 @@ export default {
/>
<div class="mr-widget-section">
- <component
- :is="componentName"
- :mr="mr"
- :service="service"
- />
+ <component :is="componentName" :mr="mr" :service="service" />
- <section
- v-if="mr.allowCollaboration"
- class="mr-info-list mr-links"
- >
- {{ s__("mrWidget|Allows commits from members who can merge to the target branch") }}
+ <section v-if="mr.allowCollaboration" class="mr-info-list mr-links">
+ {{ s__('mrWidget|Allows commits from members who can merge to the target branch') }}
</section>
<mr-widget-related-links
@@ -340,34 +321,15 @@ export default {
:related-links="mr.relatedLinks"
/>
- <source-branch-removal-status
- v-if="shouldRenderSourceBranchRemovalStatus"
- />
- </div>
- <div
- v-if="shouldRenderMergeHelp"
- class="mr-widget-footer"
- >
- <mr-widget-merge-help />
+ <source-branch-removal-status v-if="shouldRenderSourceBranchRemovalStatus" />
</div>
+ <div v-if="shouldRenderMergeHelp" class="mr-widget-footer"><mr-widget-merge-help /></div>
</div>
-
- <template v-if="shouldRenderMergedPipeline">
- <mr-widget-pipeline
- class="js-post-merge-pipeline prepend-top-default"
- :pipeline="mr.mergePipeline"
- :ci-status="mr.ciStatus"
- :has-ci="mr.hasCI"
- :source-branch="mr.targetBranch"
- :source-branch-link="mr.targetBranch"
- :troubleshooting-docs-path="mr.troubleshootingDocsPath"
- />
- <deployment
- v-for="postMergeDeployment in mr.postMergeDeployments"
- :key="`post-merge-deploy-${postMergeDeployment.id}`"
- :deployment="postMergeDeployment"
- class="js-post-deployment"
- />
- </template>
+ <mr-widget-pipeline-container
+ v-if="shouldRenderMergedPipeline"
+ class="js-post-merge-pipeline mr-widget-workflow"
+ :mr="mr"
+ :is-post-merge="true"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/bar_chart.vue b/app/assets/javascripts/vue_shared/components/bar_chart.vue
index 690dd794ba4..4abf795f7bd 100644
--- a/app/assets/javascripts/vue_shared/components/bar_chart.vue
+++ b/app/assets/javascripts/vue_shared/components/bar_chart.vue
@@ -271,25 +271,17 @@ export default {
};
</script>
<template>
- <div
- ref="svgContainer"
- :class="activateGrabCursor"
- class="svg-graph-container"
- >
+ <div ref="svgContainer" :class="activateGrabCursor" class="svg-graph-container">
<svg
ref="baseSvg"
:width="vpWidth"
:height="vpHeight"
:viewBox="svgViewBox"
- :preserveAspectRatio="preserveAspectRatioType">
- <g
- ref="xAxis"
- :transform="xAxisLocation"
- class="x-axis"
- />
+ :preserveAspectRatio="preserveAspectRatioType"
+ >
+ <g ref="xAxis" :transform="xAxisLocation" class="x-axis" />
<g v-if="!isLoading">
- <template
- v-for="(data, index) in graphData">
+ <template v-for="(data, index) in graphData">
<rect
:key="index"
v-tooltip
@@ -301,43 +293,24 @@ export default {
:title="setTooltipTitle(data)"
class="bar-rect"
data-placement="top"
- @mouseover="barHoveredIn(index)"
- @mouseout="barHoveredOut(index)"
+ @mouseover="barHoveredIn(index);"
+ @mouseout="barHoveredOut(index);"
/>
</template>
</g>
- <rect
- :height="vbHeight + 100"
- transform="translate(-100, -5)"
- width="100"
- fill="#fff"
- />
+ <rect :height="vbHeight + 100" transform="translate(-100, -5)" width="100" fill="#fff" />
<g class="y-axis-label">
- <line
- :x1="0"
- :x2="0"
- :y1="0"
- :y2="vbHeight"
- transform="translate(-35, 0)"
- stroke="black"
- />
- <!--Get text length and change the height of this rect accordingly-->
+ <line :x1="0" :x2="0" :y1="0" :y2="vbHeight" transform="translate(-35, 0)" stroke="black" />
+ <!-- Get text length and change the height of this rect accordingly -->
<rect
:height="rectYAxisLabelDims.height"
:transform="yAxisLabelRectTransform"
:width="30"
fill="#fff"
/>
- <text
- ref="yAxisLabel"
- :transform="yAxisLabelTextTransform"
- >
- {{ yAxisLabel }}
- </text>
+ <text ref="yAxisLabel" :transform="yAxisLabelTextTransform">{{ yAxisLabel }}</text>
</g>
- <g
- class="y-axis"
- />
+ <g class="y-axis" />
<g v-if="showScrollIndicator">
<rect
:height="vbHeight + 100"
@@ -354,38 +327,24 @@ export default {
class="animate-flicker"
/>
</g>
- <!--The line that shows up when the data elements surpass the available width -->
- <g
- v-if="showScrollIndicator"
- :transform="scrollIndicatorTransform">
- <rect
- :height="vbHeight"
- x="0"
- y="0"
- width="20"
- fill="url(#shadow-gradient)"
- />
+ <!-- The line that shows up when the data elements surpass the available width -->
+ <g v-if="showScrollIndicator" :transform="scrollIndicatorTransform">
+ <rect :height="vbHeight" x="0" y="0" width="20" fill="url(#shadow-gradient)" />
</g>
- <!--Left scroll indicator-->
- <g
- v-if="showLeftScrollIndicator"
- transform="translate(0, 0)">
- <rect
- :height="vbHeight"
- x="0"
- y="0"
- width="20"
- fill="url(#left-shadow-gradient)"
- />
+ <!-- Left scroll indicator -->
+ <g v-if="showLeftScrollIndicator" transform="translate(0, 0)">
+ <rect :height="vbHeight" x="0" y="0" width="20" fill="url(#left-shadow-gradient)" />
</g>
<svg-gradient
:colors="gradientColors"
:opacity="gradientOpacity"
- identifier-name="shadow-gradient"/>
+ identifier-name="shadow-gradient"
+ />
<svg-gradient
:colors="inverseGradientColors"
:opacity="inverseGradientOpacity"
- identifier-name="left-shadow-gradient"/>
+ identifier-name="left-shadow-gradient"
+ />
</svg>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/callout.vue b/app/assets/javascripts/vue_shared/components/callout.vue
index ccf802c456c..ddbb14ae812 100644
--- a/app/assets/javascripts/vue_shared/components/callout.vue
+++ b/app/assets/javascripts/vue_shared/components/callout.vue
@@ -17,11 +17,7 @@ export default {
};
</script>
<template>
- <div
- :class="`bs-callout bs-callout-${category}`"
- role="alert"
- aria-live="assertive"
- >
+ <div :class="`bs-callout bs-callout-${category}`" role="alert" aria-live="assertive">
{{ message }}
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
index 766fc211bf5..bb7710f708e 100644
--- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { pluralize } from '~/lib/utils/text_utility';
import { __, sprintf } from '~/locale';
@@ -78,17 +78,8 @@ export default {
</script>
<template>
- <span
- v-gl-tooltip.right
- :title="tooltipTitle"
- class="file-changed-icon ml-auto"
- >
- <icon
- v-if="showIcon"
- :name="changedIcon"
- :size="size"
- :css-classes="changedIconClass"
- />
+ <span v-gl-tooltip.right :title="tooltipTitle" class="file-changed-icon ml-auto">
+ <icon v-if="showIcon" :name="changedIcon" :size="size" :css-classes="changedIconClass" />
</span>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
index 6780254827f..b0962684430 100644
--- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
+++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import CiIcon from './ci_icon.vue';
/**
* Renders CI Badge link with CI icon and status text based on
diff --git a/app/assets/javascripts/vue_shared/components/ci_icon.vue b/app/assets/javascripts/vue_shared/components/ci_icon.vue
index 03f924ba99d..b8eb555106f 100644
--- a/app/assets/javascripts/vue_shared/components/ci_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/ci_icon.vue
@@ -59,10 +59,5 @@ export default {
};
</script>
<template>
- <span :class="cssClass">
- <icon
- :name="icon"
- :size="size"
- />
- </span>
+ <span :class="cssClass"> <icon :name="icon" :size="size" /> </span>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
index 6b90a1f540e..671b4909839 100644
--- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue
+++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
@@ -12,7 +12,7 @@
* css-class="btn-transparent"
* />
*/
-import { GlButton, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import Icon from '../components/icon.vue';
export default {
diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue
index b1139f34e41..ee685a4b8cd 100644
--- a/app/assets/javascripts/vue_shared/components/commit.vue
+++ b/app/assets/javascripts/vue_shared/components/commit.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import UserAvatarLink from './user_avatar/user_avatar_link.vue';
import Icon from '../../vue_shared/components/icon.vue';
@@ -111,44 +111,19 @@ export default {
<div class="branch-commit">
<template v-if="hasCommitRef && showBranch">
<div class="icon-container">
- <i
- v-if="tag"
- class="fa fa-tag"
- aria-hidden="true"
- >
- </i>
- <icon
- v-if="!tag"
- name="fork"
- />
+ <i v-if="tag" class="fa fa-tag" aria-hidden="true"> </i> <icon v-if="!tag" name="fork" />
</div>
- <a
- v-gl-tooltip
- :href="commitRef.ref_url"
- :title="commitRef.name"
- class="ref-name"
- >
+ <a v-gl-tooltip :href="commitRef.ref_url" :title="commitRef.name" class="ref-name">
{{ commitRef.name }}
</a>
</template>
- <icon
- name="commit"
- class="commit-icon js-commit-icon"
- />
+ <icon name="commit" class="commit-icon js-commit-icon" />
- <a
- :href="commitUrl"
- class="commit-sha"
- >
- {{ shortSha }}
- </a>
+ <a :href="commitUrl" class="commit-sha"> {{ shortSha }} </a>
<div class="commit-title flex-truncate-parent">
- <span
- v-if="title"
- class="flex-truncate-child"
- >
+ <span v-if="title" class="flex-truncate-child">
<user-avatar-link
v-if="hasAuthor"
:link-href="author.path"
@@ -157,16 +132,9 @@ export default {
:tooltip-text="author.username"
class="avatar-image-container"
/>
- <a
- :href="commitUrl"
- class="commit-row-message"
- >
- {{ title }}
- </a>
- </span>
- <span v-else>
- Can't find HEAD commit for this branch
+ <a :href="commitUrl" class="commit-row-message"> {{ title }} </a>
</span>
+ <span v-else> Can't find HEAD commit for this branch </span>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue
index c78b96695cf..c6d61d6ee62 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
import Icon from '../../icon.vue';
import { numberToHumanSize } from '../../../../lib/utils/number_utils';
@@ -39,17 +39,8 @@ export default {
({{ fileSizeReadable }})
</template>
</p>
- <gl-link
- :href="path"
- class="btn btn-default"
- rel="nofollow"
- download
- target="_blank">
- <icon
- :size="16"
- name="download"
- css-classes="float-left append-right-8"
- />
+ <gl-link :href="path" class="btn btn-default" rel="nofollow" download target="_blank">
+ <icon :size="16" name="download" css-classes="float-left append-right-8" />
{{ __('Download') }}
</gl-link>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
index 6f2f0f98690..2ca933a37d2 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
@@ -34,14 +34,7 @@ export default {
fileSizeReadable() {
return numberToHumanSize(this.fileSize);
},
- dimensionStyles() {
- if (!this.isLoaded) return {};
- return {
- width: `${this.width}px`,
- height: `${this.height}px`,
- };
- },
hasFileSize() {
return this.fileSize > 0;
},
@@ -87,22 +80,10 @@ export default {
<template>
<div>
- <div
- :class="innerCssClasses"
- :style="dimensionStyles"
- class="position-relative"
- >
- <img
- ref="contentImg"
- :src="path"
- @load="onImgLoad"
- />
- <slot name="image-overlay"></slot>
+ <div :class="innerCssClasses" class="position-relative">
+ <img ref="contentImg" :src="path" @load="onImgLoad" /> <slot name="image-overlay"></slot>
</div>
- <p
- v-if="renderInfo"
- class="image-info"
- >
+ <p v-if="renderInfo" class="image-info">
<template v-if="hasFileSize">
{{ fileSizeReadable }}
</template>
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
index 419987d2c50..c9915f7d685 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
@@ -2,7 +2,7 @@
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import $ from 'jquery';
-import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui';
+import { GlSkeletonLoading } from '@gitlab/ui';
const { CancelToken } = axios;
let axiosSource;
@@ -78,13 +78,8 @@ export default {
</script>
<template>
- <div
- ref="markdown-preview"
- class="md md-previewer">
+ <div ref="markdown-preview" class="md md-previewer">
<gl-skeleton-loading v-if="isLoading" />
- <div
- v-else
- v-html="previewContent">
- </div>
+ <div v-else v-html="previewContent"></div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
index 4d63296e332..2129f90d497 100644
--- a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
@@ -84,67 +84,41 @@ export default {
<template>
<div class="modal-open">
- <div
- :id="id"
- :class="id ? '' : 'd-block'"
- class="modal"
- role="dialog"
- tabindex="-1"
- >
- <div
- :class="modalDialogClass"
- class="modal-dialog"
- role="document"
- >
+ <div :id="id" :class="id ? '' : 'd-block'" class="modal" role="dialog" tabindex="-1">
+ <div :class="modalDialogClass" class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<slot name="header">
- <h4 class="modal-title float-left">
- {{ title }}
- </h4>
+ <h4 class="modal-title float-left">{{ title }}</h4>
<button
type="button"
class="close float-right"
data-dismiss="modal"
aria-label="Close"
- @click="emitCancel($event)"
+ @click="emitCancel($event);"
>
<span aria-hidden="true">&times;</span>
</button>
</slot>
</div>
<div class="modal-body">
- <slot
- :text="text"
- name="body"
- >
+ <slot :text="text" name="body">
<p>{{ text }}</p>
</slot>
</div>
- <div
- v-if="!hideFooter"
- class="modal-footer"
- >
+ <div v-if="!hideFooter" class="modal-footer">
<button
:class="btnCancelKindClass"
type="button"
class="btn"
data-dismiss="modal"
- @click="emitCancel($event)"
+ @click="emitCancel($event);"
>
{{ closeButtonLabel }}
</button>
- <slot
- v-if="secondaryButtonLabel"
- name="secondary-button"
- >
- <button
- v-if="secondaryButtonLabel"
- type="button"
- class="btn"
- data-dismiss="modal"
- >
+ <slot v-if="secondaryButtonLabel" name="secondary-button">
+ <button v-if="secondaryButtonLabel" type="button" class="btn" data-dismiss="modal">
{{ secondaryButtonLabel }}
</button>
</slot>
@@ -156,7 +130,7 @@ export default {
type="button"
class="btn js-primary-button"
data-dismiss="modal"
- @click="emitSubmit($event)"
+ @click="emitSubmit($event);"
>
{{ primaryButtonLabel }}
</button>
@@ -164,10 +138,6 @@ export default {
</div>
</div>
</div>
- <div
- v-if="!id"
- class="modal-backdrop fade show"
- >
- </div>
+ <div v-if="!id" class="modal-backdrop fade show"></div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
index 9c3f3e7f7a9..75c66ed850b 100644
--- a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
@@ -1,7 +1,10 @@
<script>
+import { diffModes } from '~/ide/constants';
import { viewerInformationForPath } from '../content_viewer/lib/viewer_utils';
import ImageDiffViewer from './viewers/image_diff_viewer.vue';
import DownloadDiffViewer from './viewers/download_diff_viewer.vue';
+import RenamedFile from './viewers/renamed.vue';
+import ModeChanged from './viewers/mode_changed.vue';
export default {
props: {
@@ -30,9 +33,25 @@ export default {
required: false,
default: '',
},
+ aMode: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ bMode: {
+ type: String,
+ required: false,
+ default: null,
+ },
},
computed: {
viewer() {
+ if (this.diffMode === diffModes.renamed) {
+ return RenamedFile;
+ } else if (this.diffMode === diffModes.mode_changed) {
+ return ModeChanged;
+ }
+
if (!this.newPath) return null;
const previewInfo = viewerInformationForPath(this.newPath);
@@ -60,21 +79,17 @@ export default {
</script>
<template>
- <div
- v-if="viewer"
- class="diff-file preview-container">
+ <div v-if="viewer" class="diff-file preview-container">
<component
:is="viewer"
:diff-mode="diffMode"
:new-path="fullNewPath"
:old-path="fullOldPath"
:project-path="projectPath"
+ :a-mode="aMode"
+ :b-mode="bMode"
>
- <slot
- slot="image-overlay"
- name="image-overlay"
- >
- </slot>
+ <slot slot="image-overlay" name="image-overlay"></slot>
</component>
<slot></slot>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/download_diff_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/download_diff_viewer.vue
index 50389b6ae63..40ae9ed6c02 100644
--- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/download_diff_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/download_diff_viewer.vue
@@ -32,37 +32,19 @@ export default {
<template>
<div class="diff-file-container">
<div class="diff-viewer">
- <div
- v-if="diffMode === $options.diffModes.replaced"
- class="two-up view row">
+ <div v-if="diffMode === $options.diffModes.replaced" class="two-up view row">
<div class="col-sm-6 deleted">
- <download-viewer
- :path="oldPath"
- :project-path="projectPath"
- />
+ <download-viewer :path="oldPath" :project-path="projectPath" />
</div>
<div class="col-sm-6 added">
- <download-viewer
- :path="newPath"
- :project-path="projectPath"
- />
+ <download-viewer :path="newPath" :project-path="projectPath" />
</div>
</div>
- <div
- v-else-if="diffMode === $options.diffModes.new"
- class="added">
- <download-viewer
- :path="newPath"
- :project-path="projectPath"
- />
+ <div v-else-if="diffMode === $options.diffModes.new" class="added">
+ <download-viewer :path="newPath" :project-path="projectPath" />
</div>
- <div
- v-else
- class="deleted">
- <download-viewer
- :path="oldPath"
- :project-path="projectPath"
- />
+ <div v-else class="deleted">
+ <download-viewer :path="oldPath" :project-path="projectPath" />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue
index cd0c1e850af..f085ef35ccc 100644
--- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue
@@ -100,17 +100,19 @@ export default {
<div class="onion-skin view">
<div
:style="{
- 'width': onionMaxPixelWidth,
- 'height': onionMaxPixelHeight,
+ width: onionMaxPixelWidth,
+ height: onionMaxPixelHeight,
'user-select': dragging === true ? 'none' : '',
}"
- class="onion-skin-frame">
+ class="onion-skin-frame"
+ >
<div
:style="{
- 'width': onionMaxPixelWidth,
- 'height': onionMaxPixelHeight,
+ width: onionMaxPixelWidth,
+ height: onionMaxPixelHeight,
}"
- class="frame deleted">
+ class="frame deleted"
+ >
<image-viewer
key="onionOldImg"
:render-info="false"
@@ -121,36 +123,25 @@ export default {
<div
ref="addedFrame"
:style="{
- 'opacity': onionOpacity,
- 'width': onionMaxPixelWidth,
- 'height': onionMaxPixelHeight,
+ opacity: onionOpacity,
+ width: onionMaxPixelWidth,
+ height: onionMaxPixelHeight,
}"
- class="added frame">
+ class="added frame"
+ >
<image-viewer
key="onionNewImg"
:render-info="false"
:path="newPath"
@imgLoaded="onionNewImgLoaded"
>
- <slot
- slot="image-overlay"
- name="image-overlay"
- >
- </slot>
+ <slot slot="image-overlay" name="image-overlay"> </slot>
</image-viewer>
</div>
<div class="controls">
<div class="transparent"></div>
- <div
- ref="dragTrack"
- class="drag-track"
- @mousedown="startDrag"
- @mouseup="stopDrag">
- <div
- ref="dragger"
- :style="{ 'left': onionDraggerPixelPos }"
- class="dragger">
- </div>
+ <div ref="dragTrack" class="drag-track" @mousedown="startDrag" @mouseup="stopDrag">
+ <div ref="dragger" :style="{ left: onionDraggerPixelPos }" class="dragger"></div>
</div>
<div class="opaque"></div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue
index c3cfe54eb4d..1c970b72a66 100644
--- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue
@@ -25,7 +25,7 @@ export default {
swipeMaxWidth: undefined,
swipeMaxHeight: undefined,
swipeBarPos: 1,
- swipeWrapWidth: undefined,
+ swipeWrapWidth: 0,
};
},
computed: {
@@ -63,7 +63,7 @@ export default {
leftValue = clientWidth - spaceLeft;
}
- this.swipeWrapWidth = this.swipeMaxWidth - leftValue;
+ this.swipeWrapWidth = (leftValue / clientWidth) * 100;
this.swipeBarPos = leftValue;
},
startDrag() {
@@ -81,7 +81,6 @@ export default {
// Add 2 for border width
this.swipeMaxWidth =
Math.max(this.swipeOldImgInfo.renderedWidth, this.swipeNewImgInfo.renderedWidth) + 2;
- this.swipeWrapWidth = this.swipeMaxWidth;
this.swipeMaxHeight =
Math.max(this.swipeOldImgInfo.renderedHeight, this.swipeNewImgInfo.renderedHeight) + 2;
@@ -105,13 +104,7 @@ export default {
<template>
<div class="swipe view">
- <div
- ref="swipeFrame"
- :style="{
- 'width': swipeMaxPixelWidth,
- 'height': swipeMaxPixelHeight,
- }"
- class="swipe-frame">
+ <div ref="swipeFrame" class="swipe-frame">
<image-viewer
key="swipeOldImg"
ref="swipeOldImg"
@@ -123,32 +116,31 @@ export default {
<div
ref="swipeWrap"
:style="{
- 'width': swipeWrapPixelWidth,
- 'height': swipeMaxPixelHeight,
+ width: `${swipeWrapWidth}%`,
}"
- class="swipe-wrap">
+ class="swipe-wrap"
+ >
<image-viewer
key="swipeNewImg"
:render-info="false"
:path="newPath"
+ :style="{
+ width: swipeMaxPixelWidth,
+ }"
class="frame added"
@imgLoaded="swipeNewImgLoaded"
>
- <slot
- slot="image-overlay"
- name="image-overlay"
- >
- </slot>
+ <slot slot="image-overlay" name="image-overlay"> </slot>
</image-viewer>
</div>
<span
ref="swipeBar"
- :style="{ 'left': swipeBarPixelPos }"
+ :style="{ left: swipeBarPixelPos }"
class="swipe-bar"
@mousedown="startDrag"
- @mouseup="stopDrag">
- <span class="top-handle"></span>
- <span class="bottom-handle"></span>
+ @mouseup="stopDrag"
+ >
+ <span class="top-handle"></span> <span class="bottom-handle"></span>
</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue
index 9806d65e940..a17fc022195 100644
--- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue
@@ -19,24 +19,20 @@ export default {
</script>
<template>
- <div class="two-up view">
+ <div class="two-up view d-flex">
<image-viewer
:path="oldPath"
:render-info="true"
inner-css-classes="frame deleted"
- class="wrap"
+ class="wrap w-50"
/>
<image-viewer
:path="newPath"
:render-info="true"
:inner-css-classes="['frame', 'added']"
- class="wrap"
+ class="wrap w-50"
>
- <slot
- slot="image-overlay"
- name="image-overlay"
- >
- </slot>
+ <slot slot="image-overlay" name="image-overlay"> </slot>
</image-viewer>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue
index d7f24c1afc5..d5fda7e4ed3 100644
--- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue
@@ -63,65 +63,54 @@ export default {
<template>
<div class="diff-file-container">
- <div
- v-if="diffMode === $options.diffModes.replaced"
- class="diff-viewer">
+ <div v-if="diffMode === $options.diffModes.replaced" class="diff-viewer">
<div class="image js-replaced-image">
- <component
- :is="imageViewComponent"
- v-bind="$props"
- >
- <slot
- slot="image-overlay"
- name="image-overlay"
- >
- </slot>
+ <component :is="imageViewComponent" v-bind="$props">
+ <slot slot="image-overlay" name="image-overlay"> </slot>
</component>
</div>
<div class="view-modes">
<ul class="view-modes-menu">
<li
:class="{
- active: mode === $options.imageViewMode.twoup
+ active: mode === $options.imageViewMode.twoup,
}"
- @click="changeMode($options.imageViewMode.twoup)">
+ @click="changeMode($options.imageViewMode.twoup);"
+ >
{{ s__('ImageDiffViewer|2-up') }}
</li>
<li
:class="{
- active: mode === $options.imageViewMode.swipe
+ active: mode === $options.imageViewMode.swipe,
}"
- @click="changeMode($options.imageViewMode.swipe)">
+ @click="changeMode($options.imageViewMode.swipe);"
+ >
{{ s__('ImageDiffViewer|Swipe') }}
</li>
<li
:class="{
- active: mode === $options.imageViewMode.onion
+ active: mode === $options.imageViewMode.onion,
}"
- @click="changeMode($options.imageViewMode.onion)">
+ @click="changeMode($options.imageViewMode.onion);"
+ >
{{ s__('ImageDiffViewer|Onion skin') }}
</li>
</ul>
</div>
</div>
- <div
- v-else
- class="diff-viewer"
- >
+ <div v-else class="diff-viewer">
<div class="image">
<image-viewer
:path="imagePath"
- :inner-css-classes="['frame', {
- 'added': isNew,
- 'deleted': diffMode === $options.diffModes.deleted
- }]"
+ :inner-css-classes="[
+ 'frame',
+ {
+ added: isNew,
+ deleted: diffMode === $options.diffModes.deleted,
+ },
+ ]"
>
- <slot
- v-if="isNew || isRenamed"
- slot="image-overlay"
- name="image-overlay"
- >
- </slot>
+ <slot v-if="isNew || isRenamed" slot="image-overlay" name="image-overlay"> </slot>
</image-viewer>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/mode_changed.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/mode_changed.vue
new file mode 100644
index 00000000000..3c7a4ea6183
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/mode_changed.vue
@@ -0,0 +1,30 @@
+<script>
+import { sprintf, __ } from '~/locale';
+
+export default {
+ props: {
+ aMode: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ bMode: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ computed: {
+ outputText() {
+ return sprintf(__('File mode changed from %{a_mode} to %{b_mode}'), {
+ a_mode: this.aMode,
+ b_mode: this.bMode,
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="nothing-here-block">{{ outputText }}</div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/renamed.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/renamed.vue
new file mode 100644
index 00000000000..5c1ea59b471
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/renamed.vue
@@ -0,0 +1,3 @@
+<template>
+ <div class="nothing-here-block">{{ __('File moved') }}</div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue
index 0e194eaaed5..22f370c4bca 100644
--- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue
@@ -1,6 +1,6 @@
<script>
import { __ } from '~/locale';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
export default {
components: {
@@ -34,30 +34,13 @@ export default {
data-toggle="dropdown"
aria-expanded="false"
>
- <gl-loading-icon
- v-show="isLoading"
- :inline="true"
- />
+ <gl-loading-icon v-show="isLoading" :inline="true" />
<template>
- <slot
- v-if="$slots.default"
- ></slot>
- <span
- v-else
- class="dropdown-toggle-text"
- >
- {{ toggleText }}
- </span>
+ <slot v-if="$slots.default"></slot>
+ <span v-else class="dropdown-toggle-text"> {{ toggleText }} </span>
</template>
- <span
- v-show="!isLoading"
- class="dropdown-toggle-icon"
- >
- <i
- class="fa fa-chevron-down"
- aria-hidden="true"
- data-hidden="true"
- ></i>
+ <span v-show="!isLoading" class="dropdown-toggle-icon">
+ <i class="fa fa-chevron-down" aria-hidden="true" data-hidden="true"></i>
</span>
</button>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_hidden_input.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_hidden_input.vue
index b7a4613bdd2..afde0c81580 100644
--- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_hidden_input.vue
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_hidden_input.vue
@@ -14,9 +14,5 @@ export default {
</script>
<template>
- <input
- :name="name"
- :value="value"
- type="hidden"
- />
+ <input :name="name" :value="value" type="hidden" />
</template>
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue
index 7f1912f6405..c01c7cc4ccc 100644
--- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue
@@ -29,12 +29,7 @@ export default {
type="search"
autocomplete="off"
/>
- <i
- class="fa fa-search dropdown-input-search"
- aria-hidden="true"
- data-hidden="true"
- >
- </i>
+ <i class="fa fa-search dropdown-input-search" aria-hidden="true" data-hidden="true"> </i>
<i
class="fa fa-times dropdown-input-clear js-dropdown-input-clear"
aria-hidden="true"
diff --git a/app/assets/javascripts/vue_shared/components/expand_button.vue b/app/assets/javascripts/vue_shared/components/expand_button.vue
index e6e92594b65..d64ab774431 100644
--- a/app/assets/javascripts/vue_shared/components/expand_button.vue
+++ b/app/assets/javascripts/vue_shared/components/expand_button.vue
@@ -44,14 +44,10 @@ export default {
:aria-label="ariaLabel"
type="button"
class="text-expander btn-blank"
- @click="onClick">
- <icon
- :size="12"
- name="ellipsis_h"
- />
+ @click="onClick"
+ >
+ <icon :size="12" name="ellipsis_h" />
</button>
- <span v-if="!isCollapsed">
- <slot name="expanded"></slot>
- </span>
+ <span v-if="!isCollapsed"> <slot name="expanded"></slot> </span>
</span>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/file_icon.vue b/app/assets/javascripts/vue_shared/components/file_icon.vue
index 03818be6a69..b69ecc1dce6 100644
--- a/app/assets/javascripts/vue_shared/components/file_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/file_icon.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import getIconForFile from './file_icon/file_icon_map';
import icon from '../../vue_shared/components/icon.vue';
@@ -72,21 +72,10 @@ export default {
</script>
<template>
<span>
- <svg
- v-if="!loading && !folder"
- :class="[iconSizeClass, cssClasses]"
- >
- <use v-bind="{ 'xlink:href':spriteHref }" />
+ <svg v-if="!loading && !folder" :class="[iconSizeClass, cssClasses]">
+ <use v-bind="{ 'xlink:href': spriteHref }" />
</svg>
- <icon
- v-if="!loading && folder"
- :name="folderIconName"
- :size="size"
- css-classes="folder-icon"
- />
- <gl-loading-icon
- v-if="loading"
- :inline="true"
- />
+ <icon v-if="!loading && folder" :name="folderIconName" :size="size" css-classes="folder-icon" />
+ <gl-loading-icon v-if="loading" :inline="true" />
</span>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index 2d89a156117..9e713673678 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -161,17 +161,11 @@ export default {
class="file-row"
role="button"
@click="clickFile"
- @mouseover="toggleHover(true)"
- @mouseout="toggleHover(false)"
+ @mouseover="toggleHover(true);"
+ @mouseout="toggleHover(false);"
>
- <div
- class="file-row-name-container"
- >
- <span
- ref="textOutput"
- :style="levelIndentation"
- class="file-row-name str-truncated"
- >
+ <div class="file-row-name-container">
+ <span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated">
<file-icon
v-if="!showChangedIcon || file.type === 'tree'"
:file-name="file.name"
@@ -180,12 +174,7 @@ export default {
:opened="file.opened"
:size="16"
/>
- <changed-file-icon
- v-else
- :file="file"
- :size="16"
- class="append-right-5"
- />
+ <changed-file-icon v-else :file="file" :size="16" class="append-right-5" />
{{ outputText }}
</span>
<component
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
index 388a2f4ca36..834c39a5ee0 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
@@ -82,16 +82,8 @@ export default {
<template>
<div class="dropdown">
<div class="btn-group">
- <slot
- name="mainAction"
- :class-name="className"
- >
- <button
- type="button"
- :class="className"
- >
- {{ title }}
- </button>
+ <slot name="mainAction" :class-name="className">
+ <button type="button" :class="className">{{ title }}</button>
</slot>
<button
@@ -103,10 +95,7 @@ export default {
aria-expanded="false"
aria-label="Expand dropdown"
>
- <icon
- name="angle-down"
- :size="12"
- />
+ <icon name="angle-down" :size="12" />
</button>
<div class="dropdown-menu dropdown-menu-right">
<div class="dropdown-input">
@@ -117,25 +106,13 @@ export default {
placeholder="Filter"
class="js-filtered-dropdown-input dropdown-input-field"
/>
- <icon
- class="dropdown-input-search"
- name="search"
- />
+ <icon class="dropdown-input-search" name="search" />
</div>
<div class="dropdown-content">
<ul>
- <li
- v-for="(result, i) in filteredResults"
- :key="i"
- class="js-filtered-dropdown-result"
- >
- <slot
- name="result"
- :result="result"
- >
- {{ result[filterKey] }}
- </slot>
+ <li v-for="(result, i) in filteredResults" :key="i" class="js-filtered-dropdown-result">
+ <slot name="result" :result="result"> {{ result[filterKey] }} </slot>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/gl_countdown.vue b/app/assets/javascripts/vue_shared/components/gl_countdown.vue
index a35986b2d03..c1aace31fb2 100644
--- a/app/assets/javascripts/vue_shared/components/gl_countdown.vue
+++ b/app/assets/javascripts/vue_shared/components/gl_countdown.vue
@@ -1,6 +1,6 @@
<script>
import { calculateRemainingMilliseconds, formatTime } from '~/lib/utils/datetime_utility';
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
/**
* Counts down to a given end date.
@@ -43,11 +43,5 @@ export default {
</script>
<template>
- <time
- v-gl-tooltip
- :datetime="endDateString"
- :title="endDateString"
- >
- {{ remainingTime }}
- </time>
+ <time v-gl-tooltip :datetime="endDateString" :title="endDateString"> {{ remainingTime }} </time>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/gl_modal.vue b/app/assets/javascripts/vue_shared/components/gl_modal.vue
index b5444d43ded..faf4181bbaf 100644
--- a/app/assets/javascripts/vue_shared/components/gl_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/gl_modal.vue
@@ -68,40 +68,27 @@ export default {
</script>
<template>
- <div
- :id="id"
- class="modal fade"
- tabindex="-1"
- role="dialog"
- >
- <div
- :class="modalSizeClass"
- class="modal-dialog"
- role="document"
- >
+ <div :id="id" class="modal fade" tabindex="-1" role="dialog">
+ <div :class="modalSizeClass" class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<slot name="header">
<h4 class="modal-title">
- <slot name="title">
- {{ headerTitleText }}
- </slot>
+ <slot name="title"> {{ headerTitleText }} </slot>
</h4>
<button
:aria-label="s__('Modal|Close')"
type="button"
class="close js-modal-close-action"
data-dismiss="modal"
- @click="emitCancel($event)"
+ @click="emitCancel($event);"
>
<span aria-hidden="true">&times;</span>
</button>
</slot>
</div>
- <div class="modal-body">
- <slot></slot>
- </div>
+ <div class="modal-body"><slot></slot></div>
<div class="modal-footer">
<slot name="footer">
@@ -109,7 +96,7 @@ export default {
type="button"
class="btn js-modal-cancel-action qa-modal-cancel-button"
data-dismiss="modal"
- @click="emitCancel($event)"
+ @click="emitCancel($event);"
>
{{ s__('Modal|Cancel') }}
</button>
@@ -118,7 +105,7 @@ export default {
type="button"
class="btn js-modal-primary-action qa-modal-primary-button"
data-dismiss="modal"
- @click="emitSubmit($event)"
+ @click="emitSubmit($event);"
>
{{ footerPrimaryButtonText }}
</button>
diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
index 88e95c33b9b..c830f5b49b6 100644
--- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue
+++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective, GlLink, GlButton } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
import CiIconBadge from './ci_badge_link.vue';
import TimeagoTooltip from './time_ago_tooltip.vue';
import UserAvatarImage from './user_avatar/user_avatar_image.vue';
@@ -83,12 +83,9 @@ export default {
<template>
<header class="page-content-header ci-header-container">
<section class="header-main-content">
-
<ci-icon-badge :status="status" />
- <strong>
- {{ itemName }} #{{ itemId }}
- </strong>
+ <strong> {{ itemName }} #{{ itemId }} </strong>
<template v-if="shouldRenderTriggeredLabel">
triggered
@@ -108,7 +105,6 @@ export default {
:title="user.email"
class="js-user-link commit-committer-link"
>
-
<user-avatar-image
:img-src="user.avatar_url"
:img-alt="userAvatarAltText"
@@ -118,19 +114,12 @@ export default {
{{ user.name }}
</gl-link>
- <span
- v-if="user.status_tooltip_html"
- v-html="user.status_tooltip_html"></span>
+ <span v-if="user.status_tooltip_html" v-html="user.status_tooltip_html"></span>
</template>
</section>
- <section
- v-if="actions.length"
- class="header-action-buttons"
- >
- <template
- v-for="(action, i) in actions"
- >
+ <section v-if="actions.length" class="header-action-buttons">
+ <template v-for="(action, i) in actions">
<gl-link
v-if="action.type === 'link'"
:key="i"
@@ -159,7 +148,7 @@ export default {
:class="action.cssClass"
container-class="d-inline"
:label="action.label"
- @click="onClickAction(action)"
+ @click="onClickAction(action);"
/>
</template>
</section>
@@ -170,12 +159,7 @@ export default {
sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header"
@click="onClickSidebarButton"
>
- <i
- class="fa fa-angle-double-left"
- aria-hidden="true"
- aria-labelledby="toggleSidebar"
- >
- </i>
+ <i class="fa fa-angle-double-left" aria-hidden="true" aria-labelledby="toggleSidebar"> </i>
</gl-button>
</header>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/help_popover.vue b/app/assets/javascripts/vue_shared/components/help_popover.vue
index 540df392e4e..a57fa09f753 100644
--- a/app/assets/javascripts/vue_shared/components/help_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/help_popover.vue
@@ -43,11 +43,7 @@ export default {
};
</script>
<template>
- <button
- type="button"
- class="btn btn-blank btn-transparent btn-help"
- tabindex="0"
- >
+ <button type="button" class="btn btn-blank btn-transparent btn-help" tabindex="0">
<icon name="question" />
</button>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/icon.vue b/app/assets/javascripts/vue_shared/components/icon.vue
index a25841fc02f..41c4c861566 100644
--- a/app/assets/javascripts/vue_shared/components/icon.vue
+++ b/app/assets/javascripts/vue_shared/components/icon.vue
@@ -106,6 +106,6 @@ export default {
:tabindex="tabIndex"
aria-hidden="true"
>
- <use v-bind="{ 'xlink:href':spriteHref }"/>
+ <use v-bind="{ 'xlink:href': spriteHref }" />
</svg>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/identicon.vue b/app/assets/javascripts/vue_shared/components/identicon.vue
index 0862f2c0cff..d42f0d8192c 100644
--- a/app/assets/javascripts/vue_shared/components/identicon.vue
+++ b/app/assets/javascripts/vue_shared/components/identicon.vue
@@ -29,9 +29,7 @@ export default {
</script>
<template>
- <div
- :class="[sizeClass, identiconBackgroundClass]"
- class="avatar identicon">
+ <div :class="[sizeClass, identiconBackgroundClass]" class="avatar identicon">
{{ identiconTitle }}
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/issue/issue_assignees.vue b/app/assets/javascripts/vue_shared/components/issue/issue_assignees.vue
new file mode 100644
index 00000000000..7e79e63aa1e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/issue/issue_assignees.vue
@@ -0,0 +1,94 @@
+<script>
+import { GlTooltipDirective } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
+
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+
+export default {
+ components: {
+ UserAvatarLink,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ assignees: {
+ type: Array,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ maxVisibleAssignees: 2,
+ maxAssigneeAvatars: 3,
+ maxAssignees: 99,
+ };
+ },
+ computed: {
+ countOverLimit() {
+ return this.assignees.length - this.maxVisibleAssignees;
+ },
+ assigneesToShow() {
+ if (this.assignees.length > this.maxAssigneeAvatars) {
+ return this.assignees.slice(0, this.maxVisibleAssignees);
+ }
+ return this.assignees;
+ },
+ assigneesCounterTooltip() {
+ const { countOverLimit, maxAssignees } = this;
+ const count = countOverLimit > maxAssignees ? maxAssignees : countOverLimit;
+
+ return sprintf(__('%{count} more assignees'), { count });
+ },
+ shouldRenderAssigneesCounter() {
+ const assigneesCount = this.assignees.length;
+ if (assigneesCount <= this.maxAssigneeAvatars) {
+ return false;
+ }
+
+ return assigneesCount > this.countOverLimit;
+ },
+ assigneeCounterLabel() {
+ if (this.countOverLimit > this.maxAssignees) {
+ return `${this.maxAssignees}+`;
+ }
+
+ return `+${this.countOverLimit}`;
+ },
+ },
+ methods: {
+ avatarUrlTitle(assignee) {
+ return sprintf(__('Avatar for %{assigneeName}'), {
+ assigneeName: assignee.name,
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div class="issue-assignees">
+ <user-avatar-link
+ v-for="assignee in assigneesToShow"
+ :key="assignee.id"
+ :link-href="assignee.web_url"
+ :img-alt="avatarUrlTitle(assignee)"
+ :img-src="assignee.avatar_url"
+ :img-size="24"
+ class="js-no-trigger"
+ tooltip-placement="bottom"
+ >
+ <span class="js-assignee-tooltip">
+ <span class="bold d-block">{{ __('Assignee') }}</span> {{ assignee.name }}
+ <span class="text-white-50">@{{ assignee.username }}</span>
+ </span>
+ </user-avatar-link>
+ <span
+ v-if="shouldRenderAssigneesCounter"
+ v-gl-tooltip
+ :title="assigneesCounterTooltip"
+ class="avatar-counter"
+ data-placement="bottom"
+ >{{ assigneeCounterLabel }}</span
+ >
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/issue/issue_milestone.vue b/app/assets/javascripts/vue_shared/components/issue/issue_milestone.vue
new file mode 100644
index 00000000000..d5d967e25bf
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/issue/issue_milestone.vue
@@ -0,0 +1,90 @@
+<script>
+import { GlTooltip } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
+import { timeFor, parsePikadayDate, dateInWords } from '~/lib/utils/datetime_utility';
+import Icon from '~/vue_shared/components/icon.vue';
+
+export default {
+ components: {
+ Icon,
+ GlTooltip,
+ },
+ mixins: [timeagoMixin],
+ props: {
+ milestone: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ milestoneDue: this.milestone.due_date ? parsePikadayDate(this.milestone.due_date) : null,
+ milestoneStart: this.milestone.start_date
+ ? parsePikadayDate(this.milestone.start_date)
+ : null,
+ };
+ },
+ computed: {
+ isMilestoneStarted() {
+ if (!this.milestoneStart) {
+ return false;
+ }
+ return Date.now() > this.milestoneStart;
+ },
+ isMilestonePastDue() {
+ if (!this.milestoneDue) {
+ return false;
+ }
+ return Date.now() > this.milestoneDue;
+ },
+ milestoneDatesAbsolute() {
+ if (this.milestoneDue) {
+ return `(${dateInWords(this.milestoneDue)})`;
+ } else if (this.milestoneStart) {
+ return `(${dateInWords(this.milestoneStart)})`;
+ }
+ return '';
+ },
+ milestoneDatesHuman() {
+ if (this.milestoneStart || this.milestoneDue) {
+ if (this.milestoneDue) {
+ return timeFor(
+ this.milestoneDue,
+ sprintf(__('Expired %{expiredOn}'), {
+ expiredOn: this.timeFormated(this.milestoneDue),
+ }),
+ );
+ }
+
+ return sprintf(
+ this.isMilestoneStarted ? __('Started %{startsIn}') : __('Starts %{startsIn}'),
+ {
+ startsIn: this.timeFormated(this.milestoneStart),
+ },
+ );
+ }
+ return '';
+ },
+ },
+};
+</script>
+<template>
+ <div ref="milestoneDetails" class="issue-milestone-details">
+ <icon :size="16" class="inline icon" name="clock" />
+ <span class="milestone-title">{{ milestone.title }}</span>
+ <gl-tooltip :target="() => $refs.milestoneDetails" placement="bottom" class="js-item-milestone">
+ <span class="bold">{{ __('Milestone') }}</span> <br />
+ <span>{{ milestone.title }}</span> <br />
+ <span
+ v-if="milestoneStart || milestoneDue"
+ :class="{
+ 'text-danger-muted': isMilestonePastDue,
+ 'text-tertiary': !isMilestonePastDue,
+ }"
+ ><span>{{ milestoneDatesHuman }}</span
+ ><br /><span>{{ milestoneDatesAbsolute }}</span>
+ </span>
+ </gl-tooltip>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
index dc88749c18f..e92babc499b 100644
--- a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
+++ b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
@@ -32,17 +32,14 @@ export default {
</script>
<template>
<div class="issuable-note-warning">
- <icon
- v-if="!isLockedAndConfidential"
- :name="warningIcon"
- :size="16"
- class="icon inline"
- />
+ <icon v-if="!isLockedAndConfidential" :name="warningIcon" :size="16" class="icon inline" />
<span v-if="isLockedAndConfidential">
{{ __('This issue is confidential and locked.') }}
- {{ __(`People without permission will never
-get a notification and won't be able to comment.`) }}
+ {{
+ __(`People without permission will never
+get a notification and won't be able to comment.`)
+ }}
</span>
<span v-else-if="isConfidential">
@@ -51,8 +48,7 @@ get a notification and won't be able to comment.`) }}
</span>
<span v-else-if="isLocked">
- {{ __('This issue is locked.') }}
- {{ __('Only project members can comment.') }}
+ {{ __('This issue is locked.') }} {{ __('Only project members can comment.') }}
</span>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/loading_button.vue b/app/assets/javascripts/vue_shared/components/loading_button.vue
index 69d7e5c46f5..7a53d053eec 100644
--- a/app/assets/javascripts/vue_shared/components/loading_button.vue
+++ b/app/assets/javascripts/vue_shared/components/loading_button.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
/* eslint-disable vue/require-default-prop */
/* This is a re-usable vue component for rendering a button
that will probably be sending off ajax requests and need
@@ -52,30 +52,20 @@ export default {
</script>
<template>
- <button
- :class="containerClass"
- :disabled="loading || disabled"
- type="button"
- @click="onClick"
- >
+ <button :class="containerClass" :disabled="loading || disabled" type="button" @click="onClick">
<transition name="fade">
<gl-loading-icon
v-if="loading"
:inline="true"
:class="{
- 'append-right-5': label
+ 'append-right-5': label,
}"
class="js-loading-button-icon"
/>
</transition>
<transition name="fade">
<slot>
- <span
- v-if="label"
- class="js-loading-button-label"
- >
- {{ label }}
- </span>
+ <span v-if="label" class="js-loading-button-label"> {{ label }} </span>
</slot>
</transition>
</button>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index 4687de62614..21d6519191f 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -142,27 +142,18 @@ export default {
<div
ref="gl-form"
:class="{ 'prepend-top-default append-bottom-default': addSpacingClasses }"
- class="md-area js-vue-markdown-field">
+ class="md-area js-vue-markdown-field"
+ >
<markdown-header
:preview-markdown="previewMarkdown"
@preview-markdown="showPreviewTab"
@write-markdown="showWriteTab"
/>
- <div
- v-show="!previewMarkdown"
- class="md-write-holder"
- >
+ <div v-show="!previewMarkdown" class="md-write-holder">
<div class="zen-backdrop">
<slot name="textarea"></slot>
- <a
- class="zen-control zen-control-leave js-zen-leave"
- href="#"
- aria-label="Enter zen mode"
- >
- <icon
- :size="32"
- name="screen-normal"
- />
+ <a class="zen-control zen-control-leave js-zen-leave" href="#" aria-label="Enter zen mode">
+ <icon :size="32" name="screen-normal" />
</a>
<markdown-toolbar
:markdown-docs-path="markdownDocsPath"
@@ -171,42 +162,19 @@ export default {
/>
</div>
</div>
- <div
- v-show="previewMarkdown"
- class="md md-preview-holder md-preview js-vue-md-preview"
- >
- <div
- ref="markdown-preview"
- v-html="markdownPreview"
- >
- </div>
- <span v-if="markdownPreviewLoading">
- Loading...
- </span>
+ <div v-show="previewMarkdown" class="md md-preview-holder md-preview js-vue-md-preview">
+ <div ref="markdown-preview" v-html="markdownPreview"></div>
+ <span v-if="markdownPreviewLoading"> Loading... </span>
</div>
<template v-if="previewMarkdown && !markdownPreviewLoading">
- <div
- v-if="referencedCommands"
- class="referenced-commands"
- v-html="referencedCommands"
- >
- </div>
- <div
- v-if="shouldShowReferencedUsers"
- class="referenced-users"
- >
+ <div v-if="referencedCommands" class="referenced-commands" v-html="referencedCommands"></div>
+ <div v-if="shouldShowReferencedUsers" class="referenced-users">
<span>
- <i
- class="fa fa-exclamation-triangle"
- aria-hidden="true"
- >
- </i>
- You are about to add
+ <i class="fa fa-exclamation-triangle" aria-hidden="true"> </i> You are about to add
<strong>
- <span class="js-referenced-users-count">
- {{ referencedUsers.length }}
- </span>
- </strong> people to the discussion. Proceed with caution.
+ <span class="js-referenced-users-count"> {{ referencedUsers.length }} </span>
+ </strong>
+ people to the discussion. Proceed with caution.
</span>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue
index 27e3f314dd3..4c4ba537065 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue
@@ -1,6 +1,6 @@
<script>
import $ from 'jquery';
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import ToolbarButton from './toolbar_button.vue';
import Icon from '../icon.vue';
@@ -64,58 +64,31 @@ export default {
<template>
<div class="md-header">
<ul class="nav-links clearfix">
- <li
- :class="{ active: !previewMarkdown }"
- class="md-header-tab"
- >
+ <li :class="{ active: !previewMarkdown }" class="md-header-tab">
<button
class="js-write-link"
tabindex="-1"
type="button"
- @click="writeMarkdownTab($event)"
+ @click="writeMarkdownTab($event);"
>
Write
</button>
</li>
- <li
- :class="{ active: previewMarkdown }"
- class="md-header-tab"
- >
+ <li :class="{ active: previewMarkdown }" class="md-header-tab">
<button
class="js-preview-link js-md-preview-button"
tabindex="-1"
type="button"
- @click="previewMarkdownTab($event)"
+ @click="previewMarkdownTab($event);"
>
Preview
</button>
</li>
- <li
- :class="{ active: !previewMarkdown }"
- class="md-header-toolbar"
- >
- <toolbar-button
- tag="**"
- button-title="Add bold text"
- icon="bold"
- />
- <toolbar-button
- tag="*"
- button-title="Add italic text"
- icon="italic"
- />
- <toolbar-button
- :prepend="true"
- tag="> "
- button-title="Insert a quote"
- icon="quote"
- />
- <toolbar-button
- tag="`"
- tag-block="```"
- button-title="Insert code"
- icon="code"
- />
+ <li :class="{ active: !previewMarkdown }" class="md-header-toolbar">
+ <toolbar-button tag="**" button-title="Add bold text" icon="bold" />
+ <toolbar-button tag="*" button-title="Add italic text" icon="italic" />
+ <toolbar-button :prepend="true" tag="> " button-title="Insert a quote" icon="quote" />
+ <toolbar-button tag="`" tag-block="```" button-title="Insert code" icon="code" />
<toolbar-button
tag="[{text}](url)"
tag-select="url"
@@ -155,9 +128,7 @@ export default {
title="Go full screen"
type="button"
>
- <icon
- name="screen-full"
- />
+ <icon name="screen-full" />
</button>
</li>
</ul>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
index b0a93794013..3b57b5e8da4 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLink } from '@gitlab-org/gitlab-ui';
+import { GlLink } from '@gitlab/ui';
export default {
components: {
@@ -33,92 +33,39 @@ export default {
<div class="comment-toolbar clearfix">
<div class="toolbar-text">
<template v-if="!hasQuickActionsDocsPath && markdownDocsPath">
- <gl-link
- :href="markdownDocsPath"
- target="_blank"
- tabindex="-1"
- >
+ <gl-link :href="markdownDocsPath" target="_blank" tabindex="-1">
Markdown is supported
</gl-link>
</template>
<template v-if="hasQuickActionsDocsPath && markdownDocsPath">
- <gl-link
- :href="markdownDocsPath"
- target="_blank"
- tabindex="-1"
- >
- Markdown
- </gl-link>
+ <gl-link :href="markdownDocsPath" target="_blank" tabindex="-1"> Markdown </gl-link>
and
- <gl-link
- :href="quickActionsDocsPath"
- target="_blank"
- tabindex="-1"
- >
+ <gl-link :href="quickActionsDocsPath" target="_blank" tabindex="-1">
quick actions
</gl-link>
are supported
</template>
</div>
- <span
- v-if="canAttachFile"
- class="uploading-container"
- >
+ <span v-if="canAttachFile" class="uploading-container">
<span class="uploading-progress-container hide">
- <i
- class="fa fa-file-image-o toolbar-button-icon"
- aria-hidden="true"
- >
- </i>
- <span class="attaching-file-message"></span>
- <span class="uploading-progress">0%</span>
+ <i class="fa fa-file-image-o toolbar-button-icon" aria-hidden="true"> </i>
+ <span class="attaching-file-message"></span> <span class="uploading-progress">0%</span>
<span class="uploading-spinner">
- <i
- class="fa fa-spinner fa-spin toolbar-button-icon"
- aria-hidden="true"
- >
- </i>
+ <i class="fa fa-spinner fa-spin toolbar-button-icon" aria-hidden="true"> </i>
</span>
</span>
<span class="uploading-error-container hide">
<span class="uploading-error-icon">
- <i
- class="fa fa-file-image-o toolbar-button-icon"
- aria-hidden="true"
- >
- </i>
+ <i class="fa fa-file-image-o toolbar-button-icon" aria-hidden="true"> </i>
</span>
<span class="uploading-error-message"></span>
- <button
- class="retry-uploading-link"
- type="button"
- >
- Try again
- </button>
- or
- <button
- class="attach-new-file markdown-selector"
- type="button"
- >
- attach a new file
- </button>
+ <button class="retry-uploading-link" type="button">Try again</button> or
+ <button class="attach-new-file markdown-selector" type="button">attach a new file</button>
</span>
- <button
- class="markdown-selector button-attach-file"
- tabindex="-1"
- type="button"
- >
- <i
- class="fa fa-file-image-o toolbar-button-icon"
- aria-hidden="true"
- >
- </i>
- Attach a file
+ <button class="markdown-selector button-attach-file" tabindex="-1" type="button">
+ <i class="fa fa-file-image-o toolbar-button-icon" aria-hidden="true"> </i> Attach a file
</button>
- <button
- class="btn btn-default btn-sm hide button-cancel-uploading-files"
- type="button"
- >
+ <button class="btn btn-default btn-sm hide button-cancel-uploading-files" type="button">
Cancel
</button>
</span>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
index 91d0bbfc21c..a6d2cecdf7e 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '../icon.vue';
export default {
@@ -55,8 +55,6 @@ export default {
tabindex="-1"
data-container="body"
>
- <icon
- :name="icon"
- />
+ <icon :name="icon" />
</button>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/memory_graph.vue b/app/assets/javascripts/vue_shared/components/memory_graph.vue
index 964dedb38c4..16f4ff068f6 100644
--- a/app/assets/javascripts/vue_shared/components/memory_graph.vue
+++ b/app/assets/javascripts/vue_shared/components/memory_graph.vue
@@ -118,17 +118,10 @@ export default {
:width="width"
:height="height"
class="has-tooltip"
- xmlns="http://www.w3.org/2000/svg">
- <path
- :d="pathD"
- :viewBox="pathViewBox"
- />
- <circle
- :cx="dotX"
- :cy="dotY"
- r="1.5"
- transform="translate(0 -1)"
- />
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path :d="pathD" :viewBox="pathViewBox" />
+ <circle :cx="dotX" :cy="dotY" r="1.5" transform="translate(0 -1)" />
</svg>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue
index 99d61b5639d..09a64502819 100644
--- a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue
+++ b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue
@@ -58,19 +58,10 @@ export default {
active: tab.isActive,
}"
>
- <a
- :class="`js-${scope}-tab-${tab.scope}`"
- role="button"
- @click="onTabClick(tab)"
- >
+ <a :class="`js-${scope}-tab-${tab.scope}`" role="button" @click="onTabClick(tab);">
{{ tab.name }}
- <span
- v-if="shouldRenderBadge(tab.count)"
- class="badge badge-pill"
- >
- {{ tab.count }}
- </span>
+ <span v-if="shouldRenderBadge(tab.count)" class="badge badge-pill"> {{ tab.count }} </span>
</a>
</li>
</ul>
diff --git a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
index dcad79e521d..8d3a3009c55 100644
--- a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
@@ -17,12 +17,14 @@
* />
*/
import { mapGetters } from 'vuex';
+import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import userAvatarLink from '../user_avatar/user_avatar_link.vue';
export default {
name: 'PlaceholderNote',
components: {
userAvatarLink,
+ TimelineEntryItem,
},
props: {
note: {
@@ -37,32 +39,28 @@ export default {
</script>
<template>
- <li class="note being-posted fade-in-half timeline-entry">
- <div class="timeline-entry-inner">
- <div class="timeline-icon">
- <user-avatar-link
- :link-href="getUserData.path"
- :img-src="getUserData.avatar_url"
- :img-size="40"
- />
- </div>
- <div
- :class="{ discussion: !note.individual_note }"
- class="timeline-content">
- <div class="note-header">
- <div class="note-header-info">
- <a :href="getUserData.path">
- <span class="d-none d-sm-inline-block">{{ getUserData.name }}</span>
- <span class="note-headline-light">@{{ getUserData.username }}</span>
- </a>
- </div>
+ <timeline-entry-item class="note being-posted fade-in-half">
+ <div class="timeline-icon">
+ <user-avatar-link
+ :link-href="getUserData.path"
+ :img-src="getUserData.avatar_url"
+ :img-size="40"
+ />
+ </div>
+ <div :class="{ discussion: !note.individual_note }" class="timeline-content">
+ <div class="note-header">
+ <div class="note-header-info">
+ <a :href="getUserData.path">
+ <span class="d-none d-sm-inline-block">{{ getUserData.name }}</span>
+ <span class="note-headline-light">@{{ getUserData.username }}</span>
+ </a>
</div>
- <div class="note-body">
- <div class="note-text">
- <p>{{ note.body }}</p>
- </div>
+ </div>
+ <div class="note-body">
+ <div class="note-text">
+ <p>{{ note.body }}</p>
</div>
</div>
</div>
- </li>
+ </timeline-entry-item>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue b/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue
index 674f923478d..7689425eb52 100644
--- a/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue
@@ -1,4 +1,6 @@
<script>
+import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
+
/**
* Common component to render a placeholder system note.
*
@@ -9,6 +11,9 @@
*/
export default {
name: 'PlaceholderSystemNote',
+ components: {
+ TimelineEntryItem,
+ },
props: {
note: {
type: Object,
@@ -19,11 +24,9 @@ export default {
</script>
<template>
- <li class="note system-note timeline-entry being-posted fade-in-half">
- <div class="timeline-entry-inner">
- <div class="timeline-content">
- <em>{{ note.body }}</em>
- </div>
+ <timeline-entry-item class="note system-note being-posted fade-in-half">
+ <div class="timeline-content">
+ <em>{{ note.body }}</em>
</div>
- </li>
+ </timeline-entry-item>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue
index 8cb72afcdc0..e61d1fd2031 100644
--- a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue
@@ -1,25 +1,22 @@
<script>
-import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui';
+import { GlSkeletonLoading } from '@gitlab/ui';
+import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
export default {
name: 'SkeletonNote',
components: {
GlSkeletonLoading,
+ TimelineEntryItem,
},
};
</script>
<template>
- <li class="timeline-entry note note-wrapper">
- <div class="timeline-entry-inner">
- <div class="timeline-icon">
- </div>
- <div class="timeline-content">
- <div class="note-header"></div>
- <div class="note-body">
- <gl-skeleton-loading />
- </div>
- </div>
+ <timeline-entry-item class="note note-wrapper">
+ <div class="timeline-icon"></div>
+ <div class="timeline-content">
+ <div class="note-header"></div>
+ <div class="note-body"><gl-skeleton-loading /></div>
</div>
- </li>
+ </timeline-entry-item>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/notes/system_note.vue b/app/assets/javascripts/vue_shared/components/notes/system_note.vue
index 6a44e6a29ed..31df26f7b05 100644
--- a/app/assets/javascripts/vue_shared/components/notes/system_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/system_note.vue
@@ -20,6 +20,7 @@ import $ from 'jquery';
import { mapGetters } from 'vuex';
import noteHeader from '~/notes/components/note_header.vue';
import Icon from '~/vue_shared/components/icon.vue';
+import TimelineEntryItem from './timeline_entry_item.vue';
import { spriteIcon } from '../../../lib/utils/common_utils';
const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
@@ -29,6 +30,7 @@ export default {
components: {
Icon,
noteHeader,
+ TimelineEntryItem,
},
props: {
note: {
@@ -73,52 +75,34 @@ export default {
</script>
<template>
- <li
+ <timeline-entry-item
:id="noteAnchorId"
:class="{ target: isTargetNote }"
- class="note system-note timeline-entry note-wrapper">
- <div class="timeline-entry-inner">
- <div
- class="timeline-icon"
- v-html="iconHtml">
+ class="note system-note note-wrapper"
+ >
+ <div class="timeline-icon" v-html="iconHtml"></div>
+ <div class="timeline-content">
+ <div class="note-header">
+ <note-header :author="note.author" :created-at="note.created_at" :note-id="note.id">
+ <span v-html="actionTextHtml"></span>
+ </note-header>
</div>
- <div class="timeline-content">
- <div class="note-header">
- <note-header
- :author="note.author"
- :created-at="note.created_at"
- :note-id="note.id"
- >
- <span v-html="actionTextHtml"></span>
- </note-header>
- </div>
- <div class="note-body">
- <div
- :class="{
- 'system-note-commit-list': hasMoreCommits,
- 'hide-shade': expanded
- }"
- class="note-text"
- v-html="note.note_html"
- ></div>
- <div
- v-if="hasMoreCommits"
- class="flex-list"
- >
- <div
- class="system-note-commit-list-toggler flex-row"
- @click="expanded = !expanded"
- >
- <icon
- :name="toggleIcon"
- :size="8"
- class="append-right-5"
- />
- <span>Toggle commit list</span>
- </div>
+ <div class="note-body">
+ <div
+ :class="{
+ 'system-note-commit-list': hasMoreCommits,
+ 'hide-shade': expanded,
+ }"
+ class="note-text"
+ v-html="note.note_html"
+ ></div>
+ <div v-if="hasMoreCommits" class="flex-list">
+ <div class="system-note-commit-list-toggler flex-row" @click="expanded = !expanded;">
+ <icon :name="toggleIcon" :size="8" class="append-right-5" />
+ <span>Toggle commit list</span>
</div>
</div>
</div>
</div>
- </li>
+ </timeline-entry-item>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/notes/timeline_entry_item.vue b/app/assets/javascripts/vue_shared/components/notes/timeline_entry_item.vue
new file mode 100644
index 00000000000..06974a12aed
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/notes/timeline_entry_item.vue
@@ -0,0 +1,11 @@
+<script>
+export default {
+ name: 'TimelineEntryItem',
+};
+</script>
+
+<template>
+ <li class="timeline-entry">
+ <div class="timeline-entry-inner"><slot></slot></div>
+ </li>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/pagination_links.vue b/app/assets/javascripts/vue_shared/components/pagination_links.vue
index 89dcf049f6e..0b44f8578cb 100644
--- a/app/assets/javascripts/vue_shared/components/pagination_links.vue
+++ b/app/assets/javascripts/vue_shared/components/pagination_links.vue
@@ -1,5 +1,5 @@
<script>
-import { GlPagination } from '@gitlab-org/gitlab-ui';
+import { GlPagination } from '@gitlab/ui';
import { s__ } from '../../locale';
export default {
diff --git a/app/assets/javascripts/vue_shared/components/pikaday.vue b/app/assets/javascripts/vue_shared/components/pikaday.vue
index 26c99aecae4..8bdb5bf22c2 100644
--- a/app/assets/javascripts/vue_shared/components/pikaday.vue
+++ b/app/assets/javascripts/vue_shared/components/pikaday.vue
@@ -62,20 +62,9 @@ export default {
<template>
<div class="pikaday-container">
<div class="dropdown open">
- <button
- type="button"
- class="dropdown-menu-toggle"
- data-toggle="dropdown"
- @click="toggled"
- >
- <span class="dropdown-toggle-text">
- {{ label }}
- </span>
- <i
- class="fa fa-chevron-down"
- aria-hidden="true"
- >
- </i>
+ <button type="button" class="dropdown-menu-toggle" data-toggle="dropdown" @click="toggled">
+ <span class="dropdown-toggle-text"> {{ label }} </span>
+ <i class="fa fa-chevron-down" aria-hidden="true"> </i>
</button>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/project_avatar/default.vue b/app/assets/javascripts/vue_shared/components/project_avatar/default.vue
index 17927fabbcc..b399c232937 100644
--- a/app/assets/javascripts/vue_shared/components/project_avatar/default.vue
+++ b/app/assets/javascripts/vue_shared/components/project_avatar/default.vue
@@ -26,10 +26,7 @@ export default {
</script>
<template>
- <span
- :class="sizeClass"
- class="avatar-container project-avatar"
- >
+ <span :class="sizeClass" class="avatar-container project-avatar">
<project-avatar-image
v-if="project.avatar_url"
:link-href="project.path"
@@ -37,11 +34,6 @@ export default {
:img-alt="project.name"
:img-size="size"
/>
- <identicon
- v-else
- :entity-id="project.id"
- :entity-name="project.name"
- :size-class="sizeClass"
- />
+ <identicon v-else :entity-id="project.id" :entity-name="project.name" :size-class="sizeClass" />
</span>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/project_avatar/image.vue b/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
index 1a2fd2ad985..e77b9ddc7ba 100644
--- a/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
+++ b/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
@@ -87,7 +87,7 @@ export default {
:class="{
lazy: lazy,
[avatarSizeClass]: true,
- [cssClasses]: true
+ [cssClasses]: true,
}"
:src="resultantSrcAttribute"
:width="size"
diff --git a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
index 09394847b10..1c6c3fc4734 100644
--- a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
@@ -73,14 +73,8 @@ export default {
@cancel="close"
>
<div slot="body">
- <p>
- {{ __('We want to be sure it is you, please confirm you are not a robot.') }}
- </p>
- <div
- ref="recaptcha"
- v-html="html"
- >
- </div>
+ <p>{{ __('We want to be sure it is you, please confirm you are not a robot.') }}</p>
+ <div ref="recaptcha" v-html="html"></div>
</div>
</deprecated-modal>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue
index 5841db52704..cc24fedceed 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue
@@ -47,16 +47,9 @@ export default {
data-boundary="viewport"
@click="click"
>
- <i
- v-if="showIcon"
- class="fa fa-calendar"
- aria-hidden="true"
- >
- </i>
+ <i v-if="showIcon" class="fa fa-calendar" aria-hidden="true"> </i>
<slot>
- <span>
- {{ text }}
- </span>
+ <span> {{ text }} </span>
</slot>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue
index 174c29809ac..b5e43da401e 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue
@@ -85,16 +85,10 @@ export default {
@click="toggleSidebar"
>
<span class="sidebar-collapsed-value">
- <span v-if="showFromText">From</span>
- <span>{{ dateText('min') }}</span>
+ <span v-if="showFromText">From</span> <span>{{ dateText('min') }}</span>
</span>
</collapsed-calendar-icon>
- <div
- v-if="hasMinAndMaxDates"
- class="text-center sidebar-collapsed-divider"
- >
- -
- </div>
+ <div v-if="hasMinAndMaxDates" class="text-center sidebar-collapsed-divider">-</div>
<collapsed-calendar-icon
v-if="maxDate"
:container-class="iconClass"
@@ -102,8 +96,7 @@ export default {
@click="toggleSidebar"
>
<span class="sidebar-collapsed-value">
- <span v-if="!minDate">Until</span>
- <span>{{ dateText('max') }}</span>
+ <span v-if="!minDate">Until</span> <span>{{ dateText('max') }}</span>
</span>
</collapsed-calendar-icon>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
index 5b12bb6b59e..82067129c57 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import datePicker from '../pikaday.vue';
import toggleSidebar from './toggle_sidebar.vue';
import collapsedCalendarIcon from './collapsed_calendar_icon.vue';
@@ -96,26 +96,14 @@ export default {
</script>
<template>
- <div
- :class="blockClass"
- class="block"
- >
+ <div :class="blockClass" class="block">
<div class="issuable-sidebar-header">
- <toggle-sidebar
- :collapsed="collapsed"
- @toggle="toggleSidebar"
- />
+ <toggle-sidebar :collapsed="collapsed" @toggle="toggleSidebar" />
</div>
- <collapsed-calendar-icon
- :text="collapsedText"
- class="sidebar-collapsed-icon"
- />
+ <collapsed-calendar-icon :text="collapsedText" class="sidebar-collapsed-icon" />
<div class="title">
{{ label }}
- <gl-loading-icon
- v-if="isLoading"
- :inline="true"
- />
+ <gl-loading-icon v-if="isLoading" :inline="true" />
<div class="float-right">
<button
v-if="editable && !editing"
@@ -125,11 +113,7 @@ export default {
>
Edit
</button>
- <toggle-sidebar
- v-if="showToggleSidebar"
- :collapsed="collapsed"
- @toggle="toggleSidebar"
- />
+ <toggle-sidebar v-if="showToggleSidebar" :collapsed="collapsed" @toggle="toggleSidebar" />
</div>
</div>
<div class="value">
@@ -142,32 +126,21 @@ export default {
@newDateSelected="newDateSelected"
@hidePicker="stopEditing"
/>
- <span
- v-else
- class="value-content"
- >
+ <span v-else class="value-content">
<template v-if="selectedDate">
<strong>{{ selectedDateWords }}</strong>
- <span
- v-if="selectedAndEditable"
- class="no-value"
- >
+ <span v-if="selectedAndEditable" class="no-value">
-
<button
type="button"
class="btn-blank btn-link btn-secondary-hover-link"
- @click="newDateSelected(null)"
+ @click="newDateSelected(null);"
>
remove
</button>
</span>
</template>
- <span
- v-else
- class="no-value"
- >
- None
- </span>
+ <span v-else class="no-value"> None </span>
</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue
index e50d612ce36..f66e81b1e08 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue
@@ -4,7 +4,7 @@ import { __ } from '~/locale';
import LabelsSelect from '~/labels_select';
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import DropdownTitle from './dropdown_title.vue';
import DropdownValue from './dropdown_value.vue';
import DropdownValueCollapsed from './dropdown_value_collapsed.vue';
@@ -122,30 +122,18 @@ export default {
:labels="context.labels"
@onValueClick="handleCollapsedValueClick"
/>
- <dropdown-title
- :can-edit="canEdit"
- />
- <dropdown-value
- :labels="context.labels"
- :label-filter-base-path="labelFilterBasePath"
- >
+ <dropdown-title :can-edit="canEdit" />
+ <dropdown-value :labels="context.labels" :label-filter-base-path="labelFilterBasePath">
<slot></slot>
</dropdown-value>
- <div
- v-if="canEdit"
- class="selectbox js-selectbox"
- style="display: none;"
- >
+ <div v-if="canEdit" class="selectbox js-selectbox" style="display: none;">
<dropdown-hidden-input
v-for="label in context.labels"
:key="label.id"
:name="hiddenInputName"
:value="label.id"
/>
- <div
- ref="dropdown"
- class="dropdown"
- >
+ <div ref="dropdown" class="dropdown">
<dropdown-button
:ability-name="abilityName"
:field-name="hiddenInputName"
@@ -161,11 +149,9 @@ dropdown-menu-labels dropdown-menu-selectable"
>
<div class="dropdown-page-one">
<dropdown-header v-if="showCreate" />
- <dropdown-search-input/>
+ <dropdown-search-input />
<div class="dropdown-content"></div>
- <div class="dropdown-loading">
- <gl-loading-icon />
- </div>
+ <div class="dropdown-loading"><gl-loading-icon /></div>
<dropdown-footer
v-if="showCreate"
:labels-web-url="labelsWebUrl"
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue
index 48d2f16f554..498b507d11d 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_button.vue
@@ -65,14 +65,7 @@ export default {
class="dropdown-menu-toggle wide js-label-select js-multiselect js-context-config-modal"
data-toggle="dropdown"
>
- <span class="dropdown-toggle-text">
- {{ dropdownToggleText }}
- </span>
- <i
- aria-hidden="true"
- class="fa fa-chevron-down"
- data-hidden="true"
- >
- </i>
+ <span class="dropdown-toggle-text"> {{ dropdownToggleText }} </span>
+ <i aria-hidden="true" class="fa fa-chevron-down" data-hidden="true"> </i>
</button>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue
index fe895136ccc..74c5e063c3d 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label.vue
@@ -23,12 +23,7 @@ export default {
type="button"
class="dropdown-title-button dropdown-menu-back"
>
- <i
- aria-hidden="true"
- class="fa fa-arrow-left"
- data-hidden="true"
- >
- </i>
+ <i aria-hidden="true" class="fa fa-arrow-left" data-hidden="true"> </i>
</button>
{{ headerTitle }}
<button
@@ -36,12 +31,7 @@ export default {
type="button"
class="dropdown-title-button dropdown-menu-close"
>
- <i
- aria-hidden="true"
- class="fa fa-times dropdown-menu-close-icon"
- data-hidden="true"
- >
- </i>
+ <i aria-hidden="true" class="fa fa-times dropdown-menu-close-icon" data-hidden="true"> </i>
</button>
</div>
<div class="dropdown-content">
@@ -75,16 +65,10 @@ export default {
/>
</div>
<div class="clearfix">
- <button
- type="button"
- class="btn btn-primary float-left js-new-label-btn disabled"
- >
+ <button type="button" class="btn btn-primary float-left js-new-label-btn disabled">
{{ __('Create') }}
</button>
- <button
- type="button"
- class="btn btn-default float-right js-cancel-label-btn"
- >
+ <button type="button" class="btn btn-default float-right js-cancel-label-btn">
{{ __('Cancel') }}
</button>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue
index d64ad016f9b..ebbd8d119b5 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer.vue
@@ -25,19 +25,10 @@ export default {
<div class="dropdown-footer">
<ul class="dropdown-footer-list">
<li>
- <a
- href="#"
- class="dropdown-toggle-page"
- >
- {{ createLabelTitle }}
- </a>
+ <a href="#" class="dropdown-toggle-page"> {{ createLabelTitle }} </a>
</li>
<li>
- <a
- :href="labelsWebUrl"
- data-is-link="true"
- class="dropdown-external-link"
- >
+ <a :href="labelsWebUrl" data-is-link="true" class="dropdown-external-link">
{{ manageLabelsTitle }}
</a>
</li>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header.vue
index e98b6392827..eb837be165b 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_header.vue
@@ -10,12 +10,7 @@ export default {};
type="button"
class="dropdown-title-button dropdown-menu-close"
>
- <i
- aria-hidden="true"
- class="fa fa-times dropdown-menu-close-icon"
- data-hidden="true"
- >
- </i>
+ <i aria-hidden="true" class="fa fa-times dropdown-menu-close-icon" data-hidden="true"> </i>
</button>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue
index 80d65a2a534..bf51fa3dc38 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_search_input.vue
@@ -10,12 +10,7 @@ export default {};
class="dropdown-input-field"
type="search"
/>
- <i
- aria-hidden="true"
- class="fa fa-search dropdown-input-search"
- data-hidden="true"
- >
- </i>
+ <i aria-hidden="true" class="fa fa-search dropdown-input-search" data-hidden="true"> </i>
<i
aria-hidden="true"
class="fa fa-times dropdown-input-clear js-dropdown-input-clear"
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue
index 9ac32ff13c6..cb53273c786 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue
@@ -13,16 +13,8 @@ export default {
<div class="title hide-collapsed append-bottom-10">
{{ __('Labels') }}
<template v-if="canEdit">
- <i
- aria-hidden="true"
- class="fa fa-spinner fa-spin block-loading"
- data-hidden="true"
- >
- </i>
- <button
- type="button"
- class="edit-link btn btn-blank float-right js-sidebar-dropdown-toggle"
- >
+ <i aria-hidden="true" class="fa fa-spinner fa-spin block-loading" data-hidden="true"> </i>
+ <button type="button" class="edit-link btn btn-blank float-right js-sidebar-dropdown-toggle">
{{ __('Edit') }}
</button>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value.vue
index 10e990f8a80..6faf3fafad1 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value.vue
@@ -37,22 +37,14 @@ export default {
<template>
<div
:class="{
- 'has-labels':!isEmpty,
+ 'has-labels': !isEmpty,
}"
class="hide-collapsed value issuable-show-labels js-value"
>
- <span
- v-if="isEmpty"
- class="text-secondary"
- >
+ <span v-if="isEmpty" class="text-secondary">
<slot>{{ __('None') }}</slot>
</span>
- <a
- v-for="label in labels"
- v-else
- :key="label.id"
- :href="labelFilterUrl(label)"
- >
+ <a v-for="label in labels" v-else :key="label.id" :href="labelFilterUrl(label)">
<span
v-tooltip
:style="labelStyle(label)"
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue
index 0d5fc07e6e3..373794fb1f2 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_collapsed.vue
@@ -44,14 +44,10 @@ export default {
class="sidebar-collapsed-icon"
data-placement="left"
data-container="body"
+ data-boundary="viewport"
@click="handleClick"
>
- <i
- aria-hidden="true"
- data-hidden="true"
- class="fa fa-tags"
- >
- </i>
+ <i aria-hidden="true" data-hidden="true" class="fa fa-tags"> </i>
<span>{{ labels.length }}</span>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
index 80dc7d3557c..3b5ce0e9910 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
@@ -46,7 +46,7 @@ export default {
<i
:class="{
'fa-angle-double-right': !collapsed,
- 'fa-angle-double-left': collapsed
+ 'fa-angle-double-left': collapsed,
}"
aria-label="toggle collapse"
class="fa"
diff --git a/app/assets/javascripts/vue_shared/components/smart_virtual_list.vue b/app/assets/javascripts/vue_shared/components/smart_virtual_list.vue
index 63034a45f77..49f987bb619 100644
--- a/app/assets/javascripts/vue_shared/components/smart_virtual_list.vue
+++ b/app/assets/javascripts/vue_shared/components/smart_virtual_list.vue
@@ -27,16 +27,7 @@ export default {
>
<slot></slot>
</virtual-list>
- <component
- :is="rtag"
- v-else
- class="js-plain-element"
- >
- <component
- :is="wtag"
- :class="wclass"
- >
- <slot></slot>
- </component>
+ <component :is="rtag" v-else class="js-plain-element">
+ <component :is="wtag" :class="wclass"> <slot></slot> </component>
</component>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
index cd3ee544344..8ba6b73f928 100644
--- a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
+++ b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
@@ -88,16 +88,8 @@ export default {
</script>
<template>
- <div
- :class="cssClass"
- class="stacked-progress-bar"
- >
- <span
- v-if="!totalCount"
- class="status-unavailable"
- >
- {{ __("Not available") }}
- </span>
+ <div :class="cssClass" class="stacked-progress-bar">
+ <span v-if="!totalCount" class="status-unavailable"> {{ __('Not available') }} </span>
<span
v-if="successPercent"
v-tooltip
diff --git a/app/assets/javascripts/vue_shared/components/svg_gradient.vue b/app/assets/javascripts/vue_shared/components/svg_gradient.vue
index b61a1befcd6..cca90af275e 100644
--- a/app/assets/javascripts/vue_shared/components/svg_gradient.vue
+++ b/app/assets/javascripts/vue_shared/components/svg_gradient.vue
@@ -17,20 +17,11 @@ export default {
};
</script>
<template>
- <svg
- height="0"
- width="0">
+ <svg height="0" width="0">
<defs>
- <linearGradient
- :id="identifierName">
- <stop
- :stop-color="colors[0]"
- :stop-opacity="opacity[0]"
- offset="0%" />
- <stop
- :stop-color="colors[1]"
- :stop-opacity="opacity[1]"
- offset="100%" />
+ <linearGradient :id="identifierName">
+ <stop :stop-color="colors[0]" :stop-opacity="opacity[0]" offset="0%" />
+ <stop :stop-color="colors[1]" :stop-opacity="opacity[1]" offset="100%" />
</linearGradient>
</defs>
</svg>
diff --git a/app/assets/javascripts/vue_shared/components/table_pagination.vue b/app/assets/javascripts/vue_shared/components/table_pagination.vue
index 03a5a078879..01e655d27e5 100644
--- a/app/assets/javascripts/vue_shared/components/table_pagination.vue
+++ b/app/assets/javascripts/vue_shared/components/table_pagination.vue
@@ -131,10 +131,7 @@ export default {
};
</script>
<template>
- <div
- v-if="showPagination"
- class="gl-pagination prepend-top-default"
- >
+ <div v-if="showPagination" class="gl-pagination prepend-top-default">
<ul class="pagination justify-content-center">
<li
v-for="(item, index) in getItems"
@@ -148,14 +145,11 @@ export default {
'd-none d-md-block': hideOnSmallScreen(item),
separator: item.separator,
active: item.active,
- disabled: item.disabled || item.separator
+ disabled: item.disabled || item.separator,
}"
class="page-item"
>
- <a
- class="page-link"
- @click.prevent="changePage(item.title, item.disabled)"
- >
+ <a class="page-link" @click.prevent="changePage(item.title, item.disabled);">
{{ item.title }}
</a>
</li>
diff --git a/app/assets/javascripts/vue_shared/components/tabs/tab.vue b/app/assets/javascripts/vue_shared/components/tabs/tab.vue
index 1c6011dcfd0..d24c27cfcc3 100644
--- a/app/assets/javascripts/vue_shared/components/tabs/tab.vue
+++ b/app/assets/javascripts/vue_shared/components/tabs/tab.vue
@@ -37,7 +37,7 @@ export default {
<template>
<div
:class="{
- active: localActive
+ active: localActive,
}"
class="tab-pane"
role="tabpanel"
diff --git a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
index d760263929a..8bcad7ac765 100644
--- a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
+++ b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
@@ -1,5 +1,5 @@
<script>
-import tooltip from '../directives/tooltip';
+import { GlTooltipDirective } from '@gitlab/ui';
import timeagoMixin from '../mixins/timeago';
import '../../lib/utils/datetime_utility';
@@ -9,7 +9,7 @@ import '../../lib/utils/datetime_utility';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
mixins: [timeagoMixin],
props: {
@@ -17,13 +17,11 @@ export default {
type: String,
required: true,
},
-
tooltipPlacement: {
type: String,
required: false,
default: 'top',
},
-
cssClass: {
type: String,
required: false,
@@ -34,11 +32,10 @@ export default {
</script>
<template>
<time
- v-tooltip
+ v-gl-tooltip="{ placement: tooltipPlacement }"
:class="cssClass"
:title="tooltipTitle(time)"
- :data-placement="tooltipPlacement"
- data-container="body"
- v-text="timeFormated(time)">
+ v-text="timeFormated(time)"
+ >
</time>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/toggle_button.vue b/app/assets/javascripts/vue_shared/components/toggle_button.vue
index e7cb5cfac12..de70fa2182b 100644
--- a/app/assets/javascripts/vue_shared/components/toggle_button.vue
+++ b/app/assets/javascripts/vue_shared/components/toggle_button.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab-org/gitlab-ui';
+import { GlLoadingIcon } from '@gitlab/ui';
import { s__ } from '../../locale';
import icon from './icon.vue';
@@ -61,29 +61,20 @@ export default {
<template>
<label class="toggle-wrapper">
- <input
- v-if="name"
- :name="name"
- :value="value"
- type="hidden"
- />
+ <input v-if="name" :name="name" :value="value" type="hidden" />
<button
:aria-label="ariaLabel"
:class="{
'is-checked': value,
'is-disabled': disabledInput,
- 'is-loading': isLoading
+ 'is-loading': isLoading,
}"
type="button"
class="project-feature-toggle"
@click="toggleFeature"
>
<gl-loading-icon class="loading-icon" />
- <span class="toggle-icon">
- <icon
- :name="toggleIcon"
- css-classes="toggle-icon-svg"/>
- </span>
+ <span class="toggle-icon"> <icon :name="toggleIcon" css-classes="toggle-icon-svg" /> </span>
</button>
</label>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
index d5b58574123..69eb791d195 100644
--- a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
+++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
@@ -59,9 +59,5 @@ export default {
>
<slot></slot>
</span>
- <span
- v-else
- >
- <slot></slot>
- </span>
+ <span v-else> <slot></slot> </span>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue
index 4cfb1ded0a9..e833a8e0483 100644
--- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue
@@ -15,7 +15,7 @@
*/
-import { GlTooltip } from '@gitlab-org/gitlab-ui';
+import { GlTooltip } from '@gitlab/ui';
import defaultAvatarUrl from 'images/no_avatar.png';
import { placeholderImage } from '../../../lazy_loader';
@@ -67,7 +67,7 @@ export default {
// In both cases we should render the defaultAvatarUrl
sanitizedSource() {
let baseSrc = this.imgSrc === '' || this.imgSrc === null ? defaultAvatarUrl : this.imgSrc;
- if (baseSrc.indexOf('?') === -1) baseSrc += `?width=${this.size}`;
+ if (!baseSrc.startsWith('data:') && !baseSrc.includes('?')) baseSrc += `?width=${this.size}`;
return baseSrc;
},
resultantSrcAttribute() {
@@ -87,7 +87,7 @@ export default {
:class="{
lazy: lazy,
[avatarSizeClass]: true,
- [cssClasses]: true
+ [cssClasses]: true,
}"
:src="resultantSrcAttribute"
:width="size"
@@ -97,14 +97,13 @@ export default {
class="avatar"
/>
<gl-tooltip
+ v-if="tooltipText || $slots.default"
:target="() => $refs.userAvatarImage"
:placement="tooltipPlacement"
boundary="window"
class="js-user-avatar-image-toolip"
>
- <slot>
- {{ tooltipText }}
- </slot>
+ <slot> {{ tooltipText }} </slot>
</gl-tooltip>
</span>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
index 351a639c6e8..55e2a786c8f 100644
--- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
@@ -17,7 +17,7 @@
*/
-import { GlLink, GlTooltipDirective } from '@gitlab-org/gitlab-ui';
+import { GlLink, GlTooltipDirective } from '@gitlab/ui';
import userAvatarImage from './user_avatar_image.vue';
export default {
@@ -83,9 +83,7 @@ export default {
</script>
<template>
- <gl-link
- :href="linkHref"
- class="user-avatar-link">
+ <gl-link :href="linkHref" class="user-avatar-link">
<user-avatar-image
:img-src="imgSrc"
:img-alt="imgAlt"
@@ -94,13 +92,14 @@ export default {
:tooltip-text="avatarTooltipText"
:tooltip-placement="tooltipPlacement"
>
- <slot></slot>
- </user-avatar-image><span
+ <slot></slot> </user-avatar-image
+ ><span
v-if="shouldShowUsername"
v-gl-tooltip
:title="tooltipText"
:tooltip-placement="tooltipPlacement"
class="js-user-avatar-link-username"
- >{{ username }}</span><slot name="avatar-badge"></slot>
+ >{{ username }}</span
+ ><slot name="avatar-badge"></slot>
</gl-link>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue
index 8e460566d09..7ed4da84120 100644
--- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue
@@ -34,10 +34,5 @@ export default {
</script>
<template>
- <svg
- :class="avatarSizeClass"
- :height="size"
- :width="size"
- v-html="svg"
- />
+ <svg :class="avatarSizeClass" :height="size" :width="size" v-html="svg" />
</template>
diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
new file mode 100644
index 00000000000..7fbadcc0111
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
@@ -0,0 +1,104 @@
+<script>
+import { GlPopover, GlSkeletonLoading } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
+import UserAvatarImage from '../user_avatar/user_avatar_image.vue';
+import { glEmojiTag } from '../../../emoji';
+
+export default {
+ name: 'UserPopover',
+ components: {
+ GlPopover,
+ GlSkeletonLoading,
+ UserAvatarImage,
+ },
+ props: {
+ target: {
+ type: HTMLAnchorElement,
+ required: true,
+ },
+ user: {
+ type: Object,
+ required: true,
+ default: null,
+ },
+ loaded: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ jobLine() {
+ if (this.user.bio && this.user.organization) {
+ return sprintf(__('%{bio} at %{organization}'), {
+ bio: this.user.bio,
+ organization: this.user.organization,
+ });
+ } else if (this.user.bio) {
+ return this.user.bio;
+ } else if (this.user.organization) {
+ return this.user.organization;
+ }
+ return null;
+ },
+ statusHtml() {
+ if (this.user.status.emoji && this.user.status.message) {
+ return `${glEmojiTag(this.user.status.emoji)} ${this.user.status.message}`;
+ } else if (this.user.status.message) {
+ return this.user.status.message;
+ }
+ return '';
+ },
+ nameIsLoading() {
+ return !this.user.name;
+ },
+ jobInfoIsLoading() {
+ return !this.user.loaded && this.user.organization === null;
+ },
+ locationIsLoading() {
+ return !this.user.loaded && this.user.location === null;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-popover :target="target" boundary="viewport" placement="top" show>
+ <div class="user-popover d-flex">
+ <div class="p-1 flex-shrink-1">
+ <user-avatar-image :img-src="user.avatarUrl" :size="60" css-classes="mr-2" />
+ </div>
+ <div class="p-1 w-100">
+ <h5 class="m-0">
+ {{ user.name }}
+ <gl-skeleton-loading
+ v-if="nameIsLoading"
+ :lines="1"
+ class="animation-container-small mb-1"
+ />
+ </h5>
+ <div class="text-secondary mb-2">
+ <span v-if="user.username">@{{ user.username }}</span>
+ <gl-skeleton-loading v-else :lines="1" class="animation-container-small mb-1" />
+ </div>
+ <div class="text-secondary">
+ {{ jobLine }}
+ <gl-skeleton-loading
+ v-if="jobInfoIsLoading"
+ :lines="1"
+ class="animation-container-small mb-1"
+ />
+ </div>
+ <div class="text-secondary">
+ {{ user.location }}
+ <gl-skeleton-loading
+ v-if="locationIsLoading"
+ :lines="1"
+ class="animation-container-small mb-1"
+ />
+ </div>
+ <div v-if="user.status" class="mt-2"><span v-html="statusHtml"></span></div>
+ </div>
+ </div>
+ </gl-popover>
+</template>