summaryrefslogtreecommitdiff
path: root/app/assets/javascripts
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/activities.js10
-rw-r--r--app/assets/javascripts/behaviors/copy_to_clipboard.js2
-rw-r--r--app/assets/javascripts/behaviors/details_behavior.js8
-rw-r--r--app/assets/javascripts/behaviors/markdown/copy_as_gfm.js107
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_math.js8
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_mermaid.js58
-rw-r--r--app/assets/javascripts/behaviors/preview_markdown.js111
-rw-r--r--app/assets/javascripts/behaviors/quick_submit.js40
-rw-r--r--app/assets/javascripts/behaviors/requires_input.js3
-rw-r--r--app/assets/javascripts/behaviors/secret_values.js8
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js30
-rw-r--r--app/assets/javascripts/behaviors/toggler_behavior.js4
-rw-r--r--app/assets/javascripts/blob/3d_viewer/index.js58
-rw-r--r--app/assets/javascripts/blob/3d_viewer/mesh_object.js21
-rw-r--r--app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js2
-rw-r--r--app/assets/javascripts/blob/blob_file_dropzone.js28
-rw-r--r--app/assets/javascripts/blob/blob_line_permalink_updater.js18
-rw-r--r--app/assets/javascripts/blob/file_template_selector.js8
-rw-r--r--app/assets/javascripts/blob/notebook/index.js7
-rw-r--r--app/assets/javascripts/blob/sketch/index.js2
-rw-r--r--app/assets/javascripts/blob/stl_viewer.js4
-rw-r--r--app/assets/javascripts/blob/template_selector.js8
-rw-r--r--app/assets/javascripts/blob/template_selectors/license_selector.js2
-rw-r--r--app/assets/javascripts/blob/template_selectors/type_selector.js1
-rw-r--r--app/assets/javascripts/blob/viewer/index.js42
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js4
-rw-r--r--app/assets/javascripts/blob_edit/edit_blob.js8
-rw-r--r--app/assets/javascripts/boards/components/board.js3
-rw-r--r--app/assets/javascripts/boards/components/issue_card_inner.vue10
-rw-r--r--app/assets/javascripts/boards/components/modal/list.vue10
-rw-r--r--app/assets/javascripts/boards/components/modal/lists_dropdown.vue6
-rw-r--r--app/assets/javascripts/boards/components/project_select.vue32
-rw-r--r--app/assets/javascripts/breadcrumb.js15
-rw-r--r--app/assets/javascripts/build_artifacts.js18
-rw-r--r--app/assets/javascripts/ci_variable_list/ajax_variable_list.js56
-rw-r--r--app/assets/javascripts/ci_variable_list/ci_variable_list.js37
-rw-r--r--app/assets/javascripts/ci_variable_list/native_form_variable_list.js5
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js10
-rw-r--r--app/assets/javascripts/clusters/clusters_index.js5
-rw-r--r--app/assets/javascripts/clusters/components/application_row.vue293
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue2
-rw-r--r--app/assets/javascripts/clusters/constants.js1
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js8
-rw-r--r--app/assets/javascripts/comment_type_toggle.js56
-rw-r--r--app/assets/javascripts/commit/image_file.js320
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_bundle.js10
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table.vue122
-rw-r--r--app/assets/javascripts/commit_merge_requests.js7
-rw-r--r--app/assets/javascripts/commits.js38
-rw-r--r--app/assets/javascripts/commons/bootstrap.js12
-rw-r--r--app/assets/javascripts/compare_autocomplete.js2
-rw-r--r--app/assets/javascripts/confirm_danger_modal.js24
-rw-r--r--app/assets/javascripts/contextual_sidebar.js7
-rw-r--r--app/assets/javascripts/create_item_dropdown.js13
-rw-r--r--app/assets/javascripts/create_label.js63
-rw-r--r--app/assets/javascripts/cycle_analytics/components/banner.vue43
-rw-r--r--app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue22
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_code_component.vue36
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_component.vue37
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue47
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_review_component.vue40
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue50
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_test_component.vue54
-rw-r--r--app/assets/javascripts/cycle_analytics/components/total_time_component.vue24
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js24
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_service.js5
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_store.js36
-rw-r--r--app/assets/javascripts/deploy_keys/components/app.vue6
-rw-r--r--app/assets/javascripts/deploy_keys/service/index.js9
-rw-r--r--app/assets/javascripts/diff.js14
-rw-r--r--app/assets/javascripts/diff_notes/components/comment_resolve_btn.js30
-rw-r--r--app/assets/javascripts/diff_notes/components/diff_note_avatars.js28
-rw-r--r--app/assets/javascripts/diff_notes/components/jump_to_discussion.js35
-rw-r--r--app/assets/javascripts/diff_notes/components/resolve_count.js10
-rw-r--r--app/assets/javascripts/diff_notes/mixins/discussion.js10
-rw-r--r--app/assets/javascripts/diff_notes/models/discussion.js18
-rw-r--r--app/assets/javascripts/diff_notes/stores/comments.js14
-rw-r--r--app/assets/javascripts/diffs/components/app.vue18
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue4
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions_dropdown.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue12
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue10
-rw-r--r--app/assets/javascripts/diffs/components/tree_list.vue116
-rw-r--r--app/assets/javascripts/diffs/store/actions.js24
-rw-r--r--app/assets/javascripts/diffs/store/modules/diff_state.js4
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js94
-rw-r--r--app/assets/javascripts/dirty_submit/dirty_submit_collection.js13
-rw-r--r--app/assets/javascripts/dirty_submit/dirty_submit_factory.js9
-rw-r--r--app/assets/javascripts/dirty_submit/dirty_submit_form.js82
-rw-r--r--app/assets/javascripts/dismissable_callout.js27
-rw-r--r--app/assets/javascripts/droplab/constants.js9
-rw-r--r--app/assets/javascripts/droplab/drop_down.js4
-rw-r--r--app/assets/javascripts/droplab/drop_lab.js5
-rw-r--r--app/assets/javascripts/droplab/keyboard.js53
-rw-r--r--app/assets/javascripts/droplab/plugins/ajax.js4
-rw-r--r--app/assets/javascripts/droplab/plugins/ajax_filter.js18
-rw-r--r--app/assets/javascripts/droplab/plugins/filter.js39
-rw-r--r--app/assets/javascripts/droplab/plugins/input_setter.js4
-rw-r--r--app/assets/javascripts/droplab/utils.js15
-rw-r--r--app/assets/javascripts/dropzone_input.js41
-rw-r--r--app/assets/javascripts/due_date_select.js3
-rw-r--r--app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js55
-rw-r--r--app/assets/javascripts/environments/components/container.vue64
-rw-r--r--app/assets/javascripts/environments/components/empty_state.vue61
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue8
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue34
-rw-r--r--app/assets/javascripts/environments/components/environment_rollback.vue4
-rw-r--r--app/assets/javascripts/environments/folder/environments_folder_bundle.js55
-rw-r--r--app/assets/javascripts/environments/folder/environments_folder_view.vue71
-rw-r--r--app/assets/javascripts/environments/index.js63
-rw-r--r--app/assets/javascripts/environments/mixins/environments_mixin.js20
-rw-r--r--app/assets/javascripts/experimental_flags.js2
-rw-r--r--app/assets/javascripts/feature_highlight/feature_highlight.js16
-rw-r--r--app/assets/javascripts/feature_highlight/feature_highlight_helper.js18
-rw-r--r--app/assets/javascripts/files_comment_button.js12
-rw-r--r--app/assets/javascripts/filterable_list.js25
-rw-r--r--app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js33
-rw-r--r--app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue8
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_emoji.js15
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_hint.js19
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_non_user.js8
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_utils.js54
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown.js12
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_token_keys.js28
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_tokenizer.js63
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js125
-rw-r--r--app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js137
-rw-r--r--app/assets/javascripts/filtered_search/recent_searches_root.js11
-rw-r--r--app/assets/javascripts/filtered_search/stores/recent_searches_store.js13
-rw-r--r--app/assets/javascripts/flash.js42
-rw-r--r--app/assets/javascripts/fly_out_nav.js52
-rw-r--r--app/assets/javascripts/frequent_items/components/frequent_items_search_input.vue13
-rw-r--r--app/assets/javascripts/gl_field_error.js3
-rw-r--r--app/assets/javascripts/gl_field_errors.js14
-rw-r--r--app/assets/javascripts/gl_form.js19
-rw-r--r--app/assets/javascripts/group_avatar.js5
-rw-r--r--app/assets/javascripts/group_label_subscription.js10
-rw-r--r--app/assets/javascripts/groups/components/item_stats.vue72
-rw-r--r--app/assets/javascripts/groups/components/item_stats_value.vue86
-rw-r--r--app/assets/javascripts/groups/new_group_child.js22
-rw-r--r--app/assets/javascripts/groups/store/groups_store.js23
-rw-r--r--app/assets/javascripts/groups/transfer_dropdown.js2
-rw-r--r--app/assets/javascripts/groups_select.js9
-rw-r--r--app/assets/javascripts/helpers/avatar_helper.js4
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/upload.vue38
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/mutations.js1
-rw-r--r--app/assets/javascripts/image_diff/image_diff.js6
-rw-r--r--app/assets/javascripts/image_diff/init_discussion_tab.js3
-rw-r--r--app/assets/javascripts/image_diff/replaced_image_diff.js15
-rw-r--r--app/assets/javascripts/importer_status.js122
-rw-r--r--app/assets/javascripts/init_changes_dropdown.js2
-rw-r--r--app/assets/javascripts/init_notes.js8
-rw-r--r--app/assets/javascripts/integrations/integration_settings_form.js5
-rw-r--r--app/assets/javascripts/issuable/auto_width_dropdown_select.js5
-rw-r--r--app/assets/javascripts/issuable_bulk_update_actions.js10
-rw-r--r--app/assets/javascripts/issuable_form.js34
-rw-r--r--app/assets/javascripts/issuable_index.js9
-rw-r--r--app/assets/javascripts/issue.js73
-rw-r--r--app/assets/javascripts/job.js190
-rw-r--r--app/assets/javascripts/jobs/components/job_app.vue277
-rw-r--r--app/assets/javascripts/jobs/components/job_container_item.vue65
-rw-r--r--app/assets/javascripts/jobs/components/job_log.vue54
-rw-r--r--app/assets/javascripts/jobs/components/job_log_controllers.vue8
-rw-r--r--app/assets/javascripts/jobs/components/jobs_container.vue53
-rw-r--r--app/assets/javascripts/jobs/components/sidebar.vue327
-rw-r--r--app/assets/javascripts/jobs/components/stages_dropdown.vue20
-rw-r--r--app/assets/javascripts/jobs/components/stuck_block.vue16
-rw-r--r--app/assets/javascripts/jobs/index.js26
-rw-r--r--app/assets/javascripts/jobs/job_details_bundle.js74
-rw-r--r--app/assets/javascripts/jobs/store/actions.js128
-rw-r--r--app/assets/javascripts/jobs/store/getters.js21
-rw-r--r--app/assets/javascripts/jobs/store/mutation_types.js19
-rw-r--r--app/assets/javascripts/jobs/store/mutations.js77
-rw-r--r--app/assets/javascripts/jobs/store/state.js31
-rw-r--r--app/assets/javascripts/jobs/svg/scroll_down.svg5
-rw-r--r--app/assets/javascripts/label_manager.js14
-rw-r--r--app/assets/javascripts/labels.js2
-rw-r--r--app/assets/javascripts/layout_nav.js60
-rw-r--r--app/assets/javascripts/lib/ace.js1
-rw-r--r--app/assets/javascripts/lib/utils/ace_utils.js6
-rw-r--r--app/assets/javascripts/lib/utils/datefix.js28
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js118
-rw-r--r--app/assets/javascripts/lib/utils/pretty_time.js63
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js17
-rw-r--r--app/assets/javascripts/lib/utils/text_utility.js5
-rw-r--r--app/assets/javascripts/line_highlighter.js28
-rw-r--r--app/assets/javascripts/locale/sprintf.js2
-rw-r--r--app/assets/javascripts/main.js1
-rw-r--r--app/assets/javascripts/member_expiration_date.js10
-rw-r--r--app/assets/javascripts/merge_conflicts/components/diff_file_editor.js3
-rw-r--r--app/assets/javascripts/merge_request.js23
-rw-r--r--app/assets/javascripts/merge_request_tabs.js2
-rw-r--r--app/assets/javascripts/milestone.js34
-rw-r--r--app/assets/javascripts/mini_pipeline_graph_dropdown.js17
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue8
-rw-r--r--app/assets/javascripts/monitoring/components/graph.vue5
-rw-r--r--app/assets/javascripts/mr_notes/index.js2
-rw-r--r--app/assets/javascripts/namespace_select.js8
-rw-r--r--app/assets/javascripts/network/branch_graph.js162
-rw-r--r--app/assets/javascripts/network/raphael.js2
-rw-r--r--app/assets/javascripts/new_branch_form.js14
-rw-r--r--app/assets/javascripts/new_commit_form.js4
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue1
-rw-r--r--app/assets/javascripts/notes/components/discussion_counter.vue5
-rw-r--r--app/assets/javascripts/notes/components/discussion_filter.vue82
-rw-r--r--app/assets/javascripts/notes/components/note_awards_list.vue25
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue14
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue11
-rw-r--r--app/assets/javascripts/notes/discussion_filters.js33
-rw-r--r--app/assets/javascripts/notes/index.js3
-rw-r--r--app/assets/javascripts/notes/services/notes_service.js5
-rw-r--r--app/assets/javascripts/notes/stores/actions.js25
-rw-r--r--app/assets/javascripts/notes/stores/collapse_utils.js5
-rw-r--r--app/assets/javascripts/notes/stores/getters.js6
-rw-r--r--app/assets/javascripts/notes/stores/index.js3
-rw-r--r--app/assets/javascripts/notes/stores/modules/index.js1
-rw-r--r--app/assets/javascripts/notes/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/notes/stores/mutations.js4
-rw-r--r--app/assets/javascripts/notes/stores/utils.js12
-rw-r--r--app/assets/javascripts/notifications_dropdown.js4
-rw-r--r--app/assets/javascripts/notifications_form.js10
-rw-r--r--app/assets/javascripts/pager.js44
-rw-r--r--app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js2
-rw-r--r--app/assets/javascripts/pages/admin/admin.js15
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/account_and_limits.js8
-rw-r--r--app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js36
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue65
-rw-r--r--app/assets/javascripts/pages/admin/projects/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/projects/index/components/delete_project_modal.vue139
-rw-r--r--app/assets/javascripts/pages/admin/projects/index/index.js2
-rw-r--r--app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue187
-rw-r--r--app/assets/javascripts/pages/admin/users/index.js6
-rw-r--r--app/assets/javascripts/pages/admin/users/new/index.js6
-rw-r--r--app/assets/javascripts/pages/dashboard/todos/index/todos.js15
-rw-r--r--app/assets/javascripts/pages/groups/edit/index.js7
-rw-r--r--app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue169
-rw-r--r--app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js16
-rw-r--r--app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js16
-rw-r--r--app/assets/javascripts/pages/profiles/index.js7
-rw-r--r--app/assets/javascripts/pages/profiles/two_factor_auths/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/branches/new/index.js11
-rw-r--r--app/assets/javascripts/pages/projects/graphs/charts/index.js22
-rw-r--r--app/assets/javascripts/pages/projects/graphs/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors.js91
-rw-r--r--app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js221
-rw-r--r--app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_util.js64
-rw-r--r--app/assets/javascripts/pages/projects/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/init_blob.js3
-rw-r--r--app/assets/javascripts/pages/projects/init_form.js2
-rw-r--r--app/assets/javascripts/pages/projects/issues/show.js2
-rw-r--r--app/assets/javascripts/pages/projects/jobs/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/labels/components/promote_label_modal.vue124
-rw-r--r--app/assets/javascripts/pages/projects/labels/index/index.js16
-rw-r--r--app/assets/javascripts/pages/projects/network/network.js10
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js22
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue102
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue46
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/target_branch_dropdown.js3
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js4
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/charts/index.js59
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/index/index.js66
-rw-r--r--app/assets/javascripts/pages/projects/pipelines/init_pipelines.js7
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue114
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/project_setting_row.vue36
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/constants.js6
-rw-r--r--app/assets/javascripts/pages/projects/shared/project_avatar.js5
-rw-r--r--app/assets/javascripts/pages/projects/wikis/index.js3
-rw-r--r--app/assets/javascripts/pages/root/index.js5
-rw-r--r--app/assets/javascripts/pages/search/show/search.js25
-rw-r--r--app/assets/javascripts/pages/sessions/new/signin_tabs_memoizer.js2
-rw-r--r--app/assets/javascripts/pages/sessions/new/username_validator.js10
-rw-r--r--app/assets/javascripts/pages/users/index.js6
-rw-r--r--app/assets/javascripts/pages/users/user_overview_block.js15
-rw-r--r--app/assets/javascripts/pages/users/user_tabs.js31
-rw-r--r--app/assets/javascripts/pdf/index.vue103
-rw-r--r--app/assets/javascripts/pdf/page/index.vue103
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue15
-rw-r--r--app/assets/javascripts/performance_bar/components/simple_metric.vue46
-rw-r--r--app/assets/javascripts/performance_bar/index.js3
-rw-r--r--app/assets/javascripts/performance_bar/services/performance_bar_service.js11
-rw-r--r--app/assets/javascripts/performance_bar/stores/performance_bar_store.js4
-rw-r--r--app/assets/javascripts/persistent_user_callout.js34
-rw-r--r--app/assets/javascripts/pipelines/components/graph/graph_component.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue (renamed from app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue)54
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_item.vue (renamed from app/assets/javascripts/pipelines/components/graph/job_component.vue)0
-rw-r--r--app/assets/javascripts/pipelines/components/graph/stage_column_component.vue36
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_table_row.vue5
-rw-r--r--app/assets/javascripts/pipelines/components/stage.vue6
-rw-r--r--app/assets/javascripts/profile/account/components/delete_account_modal.vue126
-rw-r--r--app/assets/javascripts/profile/gl_crop.js47
-rw-r--r--app/assets/javascripts/profile/profile.js6
-rw-r--r--app/assets/javascripts/project_find_file.js95
-rw-r--r--app/assets/javascripts/project_import.js1
-rw-r--r--app/assets/javascripts/project_label_subscription.js43
-rw-r--r--app/assets/javascripts/project_select.js49
-rw-r--r--app/assets/javascripts/project_select_combo_button.js27
-rw-r--r--app/assets/javascripts/project_visibility.js5
-rw-r--r--app/assets/javascripts/prometheus_metrics/prometheus_metrics.js36
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_create.js8
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_edit.js59
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_create.js4
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_edit.js37
-rw-r--r--app/assets/javascripts/raven/raven_config.js2
-rw-r--r--app/assets/javascripts/ref_select_dropdown.js5
-rw-r--r--app/assets/javascripts/registry/components/app.vue65
-rw-r--r--app/assets/javascripts/registry/components/collapsible_container.vue99
-rw-r--r--app/assets/javascripts/registry/components/table_registry.vue102
-rw-r--r--app/assets/javascripts/registry/index.js39
-rw-r--r--app/assets/javascripts/registry/stores/mutations.js1
-rw-r--r--app/assets/javascripts/reports/components/grouped_test_reports_app.vue129
-rw-r--r--app/assets/javascripts/reports/components/issue_status_icon.vue6
-rw-r--r--app/assets/javascripts/reports/components/issues_list.vue6
-rw-r--r--app/assets/javascripts/reports/components/modal.vue40
-rw-r--r--app/assets/javascripts/reports/components/test_issue_body.vue42
-rw-r--r--app/assets/javascripts/reports/store/actions.js8
-rw-r--r--app/assets/javascripts/reports/store/index.js13
-rw-r--r--app/assets/javascripts/reports/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/reports/store/mutations.js3
-rw-r--r--app/assets/javascripts/reports/store/state.js1
-rw-r--r--app/assets/javascripts/right_sidebar.js2
-rw-r--r--app/assets/javascripts/settings_panels.js16
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue3
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue6
-rw-r--r--app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue23
-rw-r--r--app/assets/javascripts/sidebar/components/participants/participants.vue132
-rw-r--r--app/assets/javascripts/sidebar/components/participants/sidebar_participants.vue34
-rw-r--r--app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue7
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue192
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/help_state.vue14
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue6
-rw-r--r--app/assets/javascripts/sidebar/components/todo_toggle/todo.vue6
-rw-r--r--app/assets/javascripts/sidebar/lib/sidebar_move_issue.js20
-rw-r--r--app/assets/javascripts/sidebar/mount_milestone_sidebar.js19
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js39
-rw-r--r--app/assets/javascripts/sidebar/services/sidebar_service.js14
-rw-r--r--app/assets/javascripts/single_file_diff.js34
-rw-r--r--app/assets/javascripts/smart_interval.js20
-rw-r--r--app/assets/javascripts/star.js8
-rw-r--r--app/assets/javascripts/task_list.js9
-rw-r--r--app/assets/javascripts/templates/issuable_template_selector.js18
-rw-r--r--app/assets/javascripts/terminal/terminal.js12
-rw-r--r--app/assets/javascripts/test_utils/simulate_drag.js56
-rw-r--r--app/assets/javascripts/test_utils/simulate_input.js2
-rw-r--r--app/assets/javascripts/toggle_buttons.js2
-rw-r--r--app/assets/javascripts/tree.js18
-rw-r--r--app/assets/javascripts/u2f/authenticate.js14
-rw-r--r--app/assets/javascripts/u2f/register.js13
-rw-r--r--app/assets/javascripts/u2f/util.js5
-rw-r--r--app/assets/javascripts/ui_development_kit.js18
-rw-r--r--app/assets/javascripts/usage_ping_consent.js5
-rw-r--r--app/assets/javascripts/users_select.js1095
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment.vue83
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/memory_usage.vue32
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author.vue56
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue52
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_merge_help.vue36
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_related_links.vue50
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue50
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue22
-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.vue50
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_closed.vue32
-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_merge_when_pipeline_succeeds.vue142
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue206
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merging.vue26
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue68
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue142
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/dependencies.js47
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/ee_switch_mr_widget_options.js3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/index.js5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue108
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/services/ee_switch_mr_widget_service.js3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_get_state_key.js3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_mr_widget_store.js3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_state_maps.js3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/bar_chart.vue10
-rw-r--r--app/assets/javascripts/vue_shared/components/ci_badge_link.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/deprecated_modal.vue150
-rw-r--r--app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js5
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue34
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue143
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_countdown.vue49
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue31
-rw-r--r--app/assets/javascripts/vue_shared/components/icon.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/issue_warning.vue51
-rw-r--r--app/assets/javascripts/vue_shared/components/loading_button.vue56
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue236
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/header.vue117
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar.vue48
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue72
-rw-r--r--app/assets/javascripts/vue_shared/components/memory_graph.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue68
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue32
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/system_note.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/panel_resizer.vue156
-rw-r--r--app/assets/javascripts/vue_shared/components/pikaday.vue106
-rw-r--r--app/assets/javascripts/vue_shared/components/project_avatar/image.vue123
-rw-r--r--app/assets/javascripts/vue_shared/components/recaptcha_modal.vue94
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue182
-rw-r--r--app/assets/javascripts/vue_shared/components/table_pagination.vue206
-rw-r--r--app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/toggle_button.vue94
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_svg.vue2
-rw-r--r--app/assets/javascripts/vue_shared/directives/tooltip.js8
-rw-r--r--app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js19
-rw-r--r--app/assets/javascripts/vue_shared/models/label.js2
-rw-r--r--app/assets/javascripts/vue_shared/translate.js9
-rw-r--r--app/assets/javascripts/vue_shared/vue_resource_interceptor.js2
-rw-r--r--app/assets/javascripts/zen_mode.js32
417 files changed, 8622 insertions, 7134 deletions
diff --git a/app/assets/javascripts/activities.js b/app/assets/javascripts/activities.js
index de4566bb119..05de970e387 100644
--- a/app/assets/javascripts/activities.js
+++ b/app/assets/javascripts/activities.js
@@ -6,10 +6,12 @@ import Pager from './pager';
import { localTimeAgo } from './lib/utils/datetime_utility';
export default class Activities {
- constructor() {
- Pager.init(20, true, false, data => data, this.updateTooltips);
+ constructor(container = '') {
+ this.container = container;
- $('.event-filter-link').on('click', (e) => {
+ Pager.init(20, true, false, data => data, this.updateTooltips, this.container);
+
+ $('.event-filter-link').on('click', e => {
e.preventDefault();
this.toggleFilter(e.currentTarget);
this.reloadActivities();
@@ -22,7 +24,7 @@ export default class Activities {
reloadActivities() {
$('.content_list').html('');
- Pager.init(20, true, false, data => data, this.updateTooltips);
+ Pager.init(20, true, false, data => data, this.updateTooltips, this.container);
}
toggleFilter(sender) {
diff --git a/app/assets/javascripts/behaviors/copy_to_clipboard.js b/app/assets/javascripts/behaviors/copy_to_clipboard.js
index 00419e80cbb..9a33a060c76 100644
--- a/app/assets/javascripts/behaviors/copy_to_clipboard.js
+++ b/app/assets/javascripts/behaviors/copy_to_clipboard.js
@@ -51,7 +51,7 @@ export default function initCopyToClipboard() {
* the last minute to deconstruct this JSON hash and set the `text/plain` and `text/x-gfm` copy
* data types to the intended values.
*/
- $(document).on('copy', 'body > textarea[readonly]', (e) => {
+ $(document).on('copy', 'body > textarea[readonly]', e => {
const { clipboardData } = e.originalEvent;
if (!clipboardData) return;
diff --git a/app/assets/javascripts/behaviors/details_behavior.js b/app/assets/javascripts/behaviors/details_behavior.js
index 1d63f5baeee..9bdfc21c7e4 100644
--- a/app/assets/javascripts/behaviors/details_behavior.js
+++ b/app/assets/javascripts/behaviors/details_behavior.js
@@ -2,7 +2,9 @@ import $ from 'jquery';
$(() => {
$('body').on('click', '.js-details-target', function target() {
- $(this).closest('.js-details-container').toggleClass('open');
+ $(this)
+ .closest('.js-details-container')
+ .toggleClass('open');
});
// Show details content. Hides link after click.
@@ -13,7 +15,9 @@ $(() => {
//
$('body').on('click', '.js-details-expand', function expand(e) {
e.preventDefault();
- $(this).next('.js-details-content').removeClass('hide');
+ $(this)
+ .next('.js-details-content')
+ .removeClass('hide');
$(this).hide();
const truncatedItem = $(this).siblings('.js-details-short');
diff --git a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
index 0d7e8a5a3cb..fe02096d903 100644
--- a/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/copy_as_gfm.js
@@ -34,7 +34,7 @@ const gfmRules = {
},
},
AutolinkFilter: {
- 'a'(el, text) {
+ a(el, text) {
// Fallback on the regular MarkdownFilter's `a` handler.
if (text !== el.getAttribute('href')) return false;
@@ -60,7 +60,7 @@ const gfmRules = {
},
},
ImageLazyLoadFilter: {
- 'img'(el, text) {
+ img(el, text) {
return `![${el.getAttribute('alt')}](${el.getAttribute('src')})`;
},
},
@@ -71,7 +71,7 @@ const gfmRules = {
return CopyAsGFM.nodeToGFM(videoEl);
},
- 'video'(el) {
+ video(el) {
return `![${el.dataset.title}](${el.getAttribute('src')})`;
},
},
@@ -118,11 +118,14 @@ const gfmRules = {
'a[name]:not([href]):empty'(el) {
return el.outerHTML;
},
- 'dl'(el, text) {
- let lines = text.replace(/\n\n/g, '\n').trim().split('\n');
+ dl(el, text) {
+ let lines = text
+ .replace(/\n\n/g, '\n')
+ .trim()
+ .split('\n');
// Add two spaces to the front of subsequent list items lines,
// or leave the line entirely blank.
- lines = lines.map((l) => {
+ lines = lines.map(l => {
const line = l.trim();
if (line.length === 0) return '';
@@ -151,27 +154,30 @@ const gfmRules = {
// Prefixes lines with 4 spaces if the code contains triple backticks
if (lang === '' && text.match(/^```/gm)) {
- return text.split('\n').map((l) => {
- const line = l.trim();
- if (line.length === 0) return '';
-
- return ` ${line}`;
- }).join('\n');
+ return text
+ .split('\n')
+ .map(l => {
+ const line = l.trim();
+ if (line.length === 0) return '';
+
+ return ` ${line}`;
+ })
+ .join('\n');
}
return `\`\`\`${lang}\n${text}\n\`\`\``;
},
'pre > code'(el, text) {
- // Don't wrap code blocks in ``
+ // Don't wrap code blocks in ``
return text;
},
},
MarkdownFilter: {
- 'br'(el) {
+ br(el) {
// Two spaces at the end of a line are turned into a BR
return ' ';
},
- 'code'(el, text) {
+ code(el, text) {
let backtickCount = 1;
const backtickMatch = text.match(/`+/);
if (backtickMatch) {
@@ -183,27 +189,31 @@ const gfmRules = {
return backticks + spaceOrNoSpace + text.trim() + spaceOrNoSpace + backticks;
},
- 'blockquote'(el, text) {
- return text.trim().split('\n').map(s => `> ${s}`.trim()).join('\n');
+ blockquote(el, text) {
+ return text
+ .trim()
+ .split('\n')
+ .map(s => `> ${s}`.trim())
+ .join('\n');
},
- 'img'(el) {
+ img(el) {
const imageSrc = el.src;
- const imageUrl = imageSrc && imageSrc !== placeholderImage ? imageSrc : (el.dataset.src || '');
+ const imageUrl = imageSrc && imageSrc !== placeholderImage ? imageSrc : el.dataset.src || '';
return `![${el.getAttribute('alt')}](${imageUrl})`;
},
'a.anchor'(el, text) {
// Don't render a Markdown link for the anchor link inside a heading
return text;
},
- 'a'(el, text) {
+ a(el, text) {
return `[${text}](${el.getAttribute('href')})`;
},
- 'li'(el, text) {
+ li(el, text) {
const lines = text.trim().split('\n');
const firstLine = `- ${lines.shift()}`;
// Add four spaces to the front of subsequent list items lines,
// or leave the line entirely blank.
- const nextLines = lines.map((s) => {
+ const nextLines = lines.map(s => {
if (s.trim().length === 0) return '';
return ` ${s}`;
@@ -211,49 +221,49 @@ const gfmRules = {
return `${firstLine}\n${nextLines.join('\n')}`;
},
- 'ul'(el, text) {
+ ul(el, text) {
return text;
},
- 'ol'(el, text) {
+ ol(el, text) {
// LIs get a `- ` prefix by default, which we replace by `1. ` for ordered lists.
- return text.replace(/^- /mg, '1. ');
+ return text.replace(/^- /gm, '1. ');
},
- 'h1'(el, text) {
+ h1(el, text) {
return `# ${text.trim()}\n`;
},
- 'h2'(el, text) {
+ h2(el, text) {
return `## ${text.trim()}\n`;
},
- 'h3'(el, text) {
+ h3(el, text) {
return `### ${text.trim()}\n`;
},
- 'h4'(el, text) {
+ h4(el, text) {
return `#### ${text.trim()}\n`;
},
- 'h5'(el, text) {
+ h5(el, text) {
return `##### ${text.trim()}\n`;
},
- 'h6'(el, text) {
+ h6(el, text) {
return `###### ${text.trim()}\n`;
},
- 'strong'(el, text) {
+ strong(el, text) {
return `**${text}**`;
},
- 'em'(el, text) {
+ em(el, text) {
return `_${text}_`;
},
- 'del'(el, text) {
+ del(el, text) {
return `~~${text}~~`;
},
- 'hr'(el) {
+ hr(el) {
// extra leading \n is to ensure that there is a blank line between
// a list followed by an hr, otherwise this breaks old redcarpet rendering
return '\n-----\n';
},
- 'p'(el, text) {
+ p(el, text) {
return `${text.trim()}\n`;
},
- 'table'(el) {
+ table(el) {
const theadEl = el.querySelector('thead');
const tbodyEl = el.querySelector('tbody');
if (!theadEl || !tbodyEl) return false;
@@ -263,8 +273,8 @@ const gfmRules = {
return [theadText, tbodyText].join('\n');
},
- 'thead'(el, text) {
- const cells = _.map(el.querySelectorAll('th'), (cell) => {
+ thead(el, text) {
+ const cells = _.map(el.querySelectorAll('th'), cell => {
let chars = CopyAsGFM.nodeToGFM(cell).length + 2;
let before = '';
@@ -296,7 +306,7 @@ const gfmRules = {
return [text, separatorRow].join('\n');
},
- 'tr'(el) {
+ tr(el) {
const cellEls = el.querySelectorAll('td, th');
if (cellEls.length === 0) return false;
@@ -315,8 +325,12 @@ export class CopyAsGFM {
const isIOS = /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent);
if (isIOS) return;
- $(document).on('copy', '.md, .wiki', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection); });
- $(document).on('copy', 'pre.code.highlight, .diff-content .line_content', (e) => { CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformCodeSelection); });
+ $(document).on('copy', '.md, .wiki', e => {
+ CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformGFMSelection);
+ });
+ $(document).on('copy', 'pre.code.highlight, .diff-content .line_content', e => {
+ CopyAsGFM.copyAsGFM(e, CopyAsGFM.transformCodeSelection);
+ });
$(document).on('paste', '.js-gfm-input', CopyAsGFM.pasteGFM);
}
@@ -356,7 +370,7 @@ export class CopyAsGFM {
// This will break down when the actual code block contains an uneven
// number of backticks, but this is a rare edge case.
const backtickMatch = textBefore.match(/`/g);
- const insideCodeBlock = backtickMatch && (backtickMatch.length % 2) === 1;
+ const insideCodeBlock = backtickMatch && backtickMatch.length % 2 === 1;
if (insideCodeBlock) {
return text;
@@ -393,7 +407,9 @@ export class CopyAsGFM {
let lineSelector = '.line';
if (target) {
- const lineClass = ['left-side', 'right-side'].filter(name => target.classList.contains(name))[0];
+ const lineClass = ['left-side', 'right-side'].filter(name =>
+ target.classList.contains(name),
+ )[0];
if (lineClass) {
lineSelector = `.line_content.${lineClass} ${lineSelector}`;
}
@@ -436,7 +452,8 @@ export class CopyAsGFM {
return node.textContent;
}
- const respectWhitespace = respectWhitespaceParam || (node.nodeName === 'PRE' || node.nodeName === 'CODE');
+ const respectWhitespace =
+ respectWhitespaceParam || (node.nodeName === 'PRE' || node.nodeName === 'CODE');
const text = this.innerGFM(node, respectWhitespace);
diff --git a/app/assets/javascripts/behaviors/markdown/render_math.js b/app/assets/javascripts/behaviors/markdown/render_math.js
index eb4e59d12b1..a68936d79e2 100644
--- a/app/assets/javascripts/behaviors/markdown/render_math.js
+++ b/app/assets/javascripts/behaviors/markdown/render_math.js
@@ -32,7 +32,9 @@ export default function renderMath($els) {
Promise.all([
import(/* webpackChunkName: 'katex' */ 'katex'),
import(/* webpackChunkName: 'katex' */ 'katex/dist/katex.min.css'),
- ]).then(([katex]) => {
- renderWithKaTeX($els, katex);
- }).catch(() => flash(__('An error occurred while rendering KaTeX')));
+ ])
+ .then(([katex]) => {
+ renderWithKaTeX($els, katex);
+ })
+ .catch(() => flash(__('An error occurred while rendering KaTeX')));
}
diff --git a/app/assets/javascripts/behaviors/markdown/render_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
index 56b1896e9f1..720f30e18e6 100644
--- a/app/assets/javascripts/behaviors/markdown/render_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
@@ -17,41 +17,43 @@ import flash from '~/flash';
export default function renderMermaid($els) {
if (!$els.length) return;
- import(/* webpackChunkName: 'mermaid' */ 'blackst0ne-mermaid').then((mermaid) => {
- mermaid.initialize({
- // mermaid core options
- mermaid: {
- startOnLoad: false,
- },
- // mermaidAPI options
- theme: 'neutral',
- });
+ import(/* webpackChunkName: 'mermaid' */ 'mermaid')
+ .then(mermaid => {
+ mermaid.initialize({
+ // mermaid core options
+ mermaid: {
+ startOnLoad: false,
+ },
+ // mermaidAPI options
+ theme: 'neutral',
+ });
- $els.each((i, el) => {
- const source = el.textContent;
+ $els.each((i, el) => {
+ const source = el.textContent;
- // Remove any extra spans added by the backend syntax highlighting.
- Object.assign(el, { textContent: source });
+ // Remove any extra spans added by the backend syntax highlighting.
+ Object.assign(el, { textContent: source });
- mermaid.init(undefined, el, (id) => {
- const svg = document.getElementById(id);
+ mermaid.init(undefined, el, id => {
+ const svg = document.getElementById(id);
- svg.classList.add('mermaid');
+ svg.classList.add('mermaid');
- // pre > code > svg
- svg.closest('pre').replaceWith(svg);
+ // pre > code > svg
+ svg.closest('pre').replaceWith(svg);
- // We need to add the original source into the DOM to allow Copy-as-GFM
- // to access it.
- const sourceEl = document.createElement('text');
- sourceEl.classList.add('source');
- sourceEl.setAttribute('display', 'none');
- sourceEl.textContent = source;
+ // We need to add the original source into the DOM to allow Copy-as-GFM
+ // to access it.
+ const sourceEl = document.createElement('text');
+ sourceEl.classList.add('source');
+ sourceEl.setAttribute('display', 'none');
+ sourceEl.textContent = source;
- svg.appendChild(sourceEl);
+ svg.appendChild(sourceEl);
+ });
});
+ })
+ .catch(err => {
+ flash(`Can't load mermaid module: ${err}`);
});
- }).catch((err) => {
- flash(`Can't load mermaid module: ${err}`);
- });
}
diff --git a/app/assets/javascripts/behaviors/preview_markdown.js b/app/assets/javascripts/behaviors/preview_markdown.js
index 0964baf8954..35f1bb6b080 100644
--- a/app/assets/javascripts/behaviors/preview_markdown.js
+++ b/app/assets/javascripts/behaviors/preview_markdown.js
@@ -26,7 +26,7 @@ MarkdownPreview.prototype.emptyMessage = 'Nothing to preview.';
MarkdownPreview.prototype.ajaxCache = {};
-MarkdownPreview.prototype.showPreview = function ($form) {
+MarkdownPreview.prototype.showPreview = function($form) {
var mdText;
var markdownVersion;
var url;
@@ -44,34 +44,40 @@ MarkdownPreview.prototype.showPreview = function ($form) {
this.hideReferencedUsers($form);
} else {
preview.addClass('md-preview-loading').text('Loading...');
- this.fetchMarkdownPreview(mdText, url, (function (response) {
- var body;
- if (response.body.length > 0) {
- ({ body } = response);
- } else {
- body = this.emptyMessage;
- }
-
- preview.removeClass('md-preview-loading').html(body);
- preview.renderGFM();
- this.renderReferencedUsers(response.references.users, $form);
-
- if (response.references.commands) {
- this.renderReferencedCommands(response.references.commands, $form);
- }
- }).bind(this));
+ this.fetchMarkdownPreview(
+ mdText,
+ url,
+ function(response) {
+ var body;
+ if (response.body.length > 0) {
+ ({ body } = response);
+ } else {
+ body = this.emptyMessage;
+ }
+
+ preview.removeClass('md-preview-loading').html(body);
+ preview.renderGFM();
+ this.renderReferencedUsers(response.references.users, $form);
+
+ if (response.references.commands) {
+ this.renderReferencedCommands(response.references.commands, $form);
+ }
+ }.bind(this),
+ );
}
};
-MarkdownPreview.prototype.versionedPreviewPath = function (markdownPreviewPath, markdownVersion) {
+MarkdownPreview.prototype.versionedPreviewPath = function(markdownPreviewPath, markdownVersion) {
if (typeof markdownVersion === 'undefined') {
return markdownPreviewPath;
}
- return `${markdownPreviewPath}${markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'}markdown_version=${markdownVersion}`;
+ return `${markdownPreviewPath}${
+ markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'
+ }markdown_version=${markdownVersion}`;
};
-MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) {
+MarkdownPreview.prototype.fetchMarkdownPreview = function(text, url, success) {
if (!url) {
return;
}
@@ -79,24 +85,25 @@ MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) {
success(this.ajaxCache.response);
return;
}
- axios.post(url, {
- text,
- })
- .then(({ data }) => {
- this.ajaxCache = {
- text: text,
- response: data,
- };
- success(data);
- })
- .catch(() => flash(__('An error occurred while fetching markdown preview')));
+ axios
+ .post(url, {
+ text,
+ })
+ .then(({ data }) => {
+ this.ajaxCache = {
+ text: text,
+ response: data,
+ };
+ success(data);
+ })
+ .catch(() => flash(__('An error occurred while fetching markdown preview')));
};
-MarkdownPreview.prototype.hideReferencedUsers = function ($form) {
+MarkdownPreview.prototype.hideReferencedUsers = function($form) {
$form.find('.referenced-users').hide();
};
-MarkdownPreview.prototype.renderReferencedUsers = function (users, $form) {
+MarkdownPreview.prototype.renderReferencedUsers = function(users, $form) {
var referencedUsers;
referencedUsers = $form.find('.referenced-users');
if (referencedUsers.length) {
@@ -109,11 +116,11 @@ MarkdownPreview.prototype.renderReferencedUsers = function (users, $form) {
}
};
-MarkdownPreview.prototype.hideReferencedCommands = function ($form) {
+MarkdownPreview.prototype.hideReferencedCommands = function($form) {
$form.find('.referenced-commands').hide();
};
-MarkdownPreview.prototype.renderReferencedCommands = function (commands, $form) {
+MarkdownPreview.prototype.renderReferencedCommands = function(commands, $form) {
var referencedCommands;
referencedCommands = $form.find('.referenced-commands');
if (commands.length > 0) {
@@ -132,14 +139,14 @@ writeButtonSelector = '.js-md-write-button';
lastTextareaPreviewed = null;
const markdownToolbar = $('.md-header-toolbar');
-$.fn.setupMarkdownPreview = function () {
+$.fn.setupMarkdownPreview = function() {
var $form = $(this);
- $form.find('textarea.markdown-area').on('input', function () {
+ $form.find('textarea.markdown-area').on('input', function() {
markdownPreview.hideReferencedUsers($form);
});
};
-$(document).on('markdown-preview:show', function (e, $form) {
+$(document).on('markdown-preview:show', function(e, $form) {
if (!$form) {
return;
}
@@ -148,8 +155,14 @@ $(document).on('markdown-preview:show', function (e, $form) {
lastTextareaHeight = lastTextareaPreviewed.height();
// toggle tabs
- $form.find(writeButtonSelector).parent().removeClass('active');
- $form.find(previewButtonSelector).parent().addClass('active');
+ $form
+ .find(writeButtonSelector)
+ .parent()
+ .removeClass('active');
+ $form
+ .find(previewButtonSelector)
+ .parent()
+ .addClass('active');
// toggle content
$form.find('.md-write-holder').hide();
@@ -158,7 +171,7 @@ $(document).on('markdown-preview:show', function (e, $form) {
markdownPreview.showPreview($form);
});
-$(document).on('markdown-preview:hide', function (e, $form) {
+$(document).on('markdown-preview:hide', function(e, $form) {
if (!$form) {
return;
}
@@ -169,8 +182,14 @@ $(document).on('markdown-preview:hide', function (e, $form) {
}
// toggle tabs
- $form.find(writeButtonSelector).parent().addClass('active');
- $form.find(previewButtonSelector).parent().removeClass('active');
+ $form
+ .find(writeButtonSelector)
+ .parent()
+ .addClass('active');
+ $form
+ .find(previewButtonSelector)
+ .parent()
+ .removeClass('active');
// toggle content
$form.find('.md-write-holder').show();
@@ -181,7 +200,7 @@ $(document).on('markdown-preview:hide', function (e, $form) {
markdownPreview.hideReferencedCommands($form);
});
-$(document).on('markdown-preview:toggle', function (e, keyboardEvent) {
+$(document).on('markdown-preview:toggle', function(e, keyboardEvent) {
var $target;
$target = $(keyboardEvent.target);
if ($target.is('textarea.markdown-area')) {
@@ -194,14 +213,14 @@ $(document).on('markdown-preview:toggle', function (e, keyboardEvent) {
}
});
-$(document).on('click', previewButtonSelector, function (e) {
+$(document).on('click', previewButtonSelector, function(e) {
var $form;
e.preventDefault();
$form = $(this).closest('form');
$(document).triggerHandler('markdown-preview:show', [$form]);
});
-$(document).on('click', writeButtonSelector, function (e) {
+$(document).on('click', writeButtonSelector, function(e) {
var $form;
e.preventDefault();
$form = $(this).closest('form');
diff --git a/app/assets/javascripts/behaviors/quick_submit.js b/app/assets/javascripts/behaviors/quick_submit.js
index b6e2781773c..c1ea67f9293 100644
--- a/app/assets/javascripts/behaviors/quick_submit.js
+++ b/app/assets/javascripts/behaviors/quick_submit.js
@@ -28,7 +28,7 @@ function keyCodeIs(e, keyCode) {
return e.keyCode === keyCode;
}
-$(document).on('keydown.quick_submit', '.js-quick-submit', (e) => {
+$(document).on('keydown.quick_submit', '.js-quick-submit', e => {
// Enter
if (!keyCodeIs(e, 13)) {
return;
@@ -55,23 +55,25 @@ $(document).on('keydown.quick_submit', '.js-quick-submit', (e) => {
// If the user tabs to a submit button on a `js-quick-submit` form, display a
// tooltip to let them know they could've used the hotkey
-$(document).on('keyup.quick_submit', '.js-quick-submit input[type=submit], .js-quick-submit button[type=submit]', function displayTooltip(e) {
- // Tab
- if (!keyCodeIs(e, 9)) {
- return;
- }
+$(document).on(
+ 'keyup.quick_submit',
+ '.js-quick-submit input[type=submit], .js-quick-submit button[type=submit]',
+ function displayTooltip(e) {
+ // Tab
+ if (!keyCodeIs(e, 9)) {
+ return;
+ }
- const $this = $(this);
- const title = isMac() ?
- 'You can also press ⌘-Enter' :
- 'You can also press Ctrl-Enter';
+ const $this = $(this);
+ const title = isMac() ? 'You can also press ⌘-Enter' : 'You can also press Ctrl-Enter';
- $this.tooltip({
- container: 'body',
- html: 'true',
- placement: 'top',
- title,
- trigger: 'manual',
- });
- $this.tooltip('show').one('blur click', () => $this.tooltip('hide'));
-});
+ $this.tooltip({
+ container: 'body',
+ html: 'true',
+ placement: 'top',
+ title,
+ trigger: 'manual',
+ });
+ $this.tooltip('show').one('blur click', () => $this.tooltip('hide'));
+ },
+);
diff --git a/app/assets/javascripts/behaviors/requires_input.js b/app/assets/javascripts/behaviors/requires_input.js
index a8b6dbf0948..c09d9ccddd6 100644
--- a/app/assets/javascripts/behaviors/requires_input.js
+++ b/app/assets/javascripts/behaviors/requires_input.js
@@ -18,7 +18,8 @@ import '../commons/bootstrap';
$.fn.requiresInput = function requiresInput() {
const $form = $(this);
const $button = $('button[type=submit], input[type=submit]', $form);
- const fieldSelector = 'input[required=required], select[required=required], textarea[required=required]';
+ const fieldSelector =
+ 'input[required=required], select[required=required], textarea[required=required]';
function requireInput() {
// Collect the input values of *all* required fields
diff --git a/app/assets/javascripts/behaviors/secret_values.js b/app/assets/javascripts/behaviors/secret_values.js
index 0d6e0dbefcc..f6bf62d734e 100644
--- a/app/assets/javascripts/behaviors/secret_values.js
+++ b/app/assets/javascripts/behaviors/secret_values.js
@@ -32,16 +32,18 @@ export default class SecretValues {
updateDom(isRevealed) {
const values = this.container.querySelectorAll(this.valueSelector);
- values.forEach((value) => {
+ values.forEach(value => {
value.classList.toggle('hide', !isRevealed);
});
const placeholders = this.container.querySelectorAll(this.placeholderSelector);
- placeholders.forEach((placeholder) => {
+ placeholders.forEach(placeholder => {
placeholder.classList.toggle('hide', isRevealed);
});
- this.revealButton.textContent = isRevealed ? n__('Hide value', 'Hide values', values.length) : n__('Reveal value', 'Reveal values', values.length);
+ this.revealButton.textContent = isRevealed
+ ? n__('Hide value', 'Hide values', values.length)
+ : n__('Reveal value', 'Reveal values', values.length);
this.revealButton.dataset.secretRevealStatus = isRevealed;
}
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index 6719bfd6d22..8b5a3c1c69d 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -88,22 +88,24 @@ export default class Shortcuts {
return null;
}
- return axios.get(gon.shortcuts_path, {
- responseType: 'text',
- }).then(({ data }) => {
- $.globalEval(data);
-
- if (location && location.length > 0) {
- const results = [];
- for (let i = 0, len = location.length; i < len; i += 1) {
- results.push($(location[i]).show());
+ return axios
+ .get(gon.shortcuts_path, {
+ responseType: 'text',
+ })
+ .then(({ data }) => {
+ $.globalEval(data);
+
+ if (location && location.length > 0) {
+ const results = [];
+ for (let i = 0, len = location.length; i < len; i += 1) {
+ results.push($(location[i]).show());
+ }
+ return results;
}
- return results;
- }
- $('.hidden-shortcut').show();
- return $('.js-more-help-button').remove();
- });
+ $('.hidden-shortcut').show();
+ return $('.js-more-help-button').remove();
+ });
}
focusFilter(e) {
diff --git a/app/assets/javascripts/behaviors/toggler_behavior.js b/app/assets/javascripts/behaviors/toggler_behavior.js
index 4446be0e52f..ef8b8788abf 100644
--- a/app/assets/javascripts/behaviors/toggler_behavior.js
+++ b/app/assets/javascripts/behaviors/toggler_behavior.js
@@ -18,9 +18,7 @@ $(() => {
.toggleClass('fa-chevron-up', toggleState)
.toggleClass('fa-chevron-down', toggleState !== undefined ? !toggleState : undefined);
- $container
- .find('.js-toggle-content')
- .toggle(toggleState);
+ $container.find('.js-toggle-content').toggle(toggleState);
}
$('body').on('click', '.js-toggle-button', function toggleButton(e) {
diff --git a/app/assets/javascripts/blob/3d_viewer/index.js b/app/assets/javascripts/blob/3d_viewer/index.js
index 1bdf1aeb76c..2d4f45cc365 100644
--- a/app/assets/javascripts/blob/3d_viewer/index.js
+++ b/app/assets/javascripts/blob/3d_viewer/index.js
@@ -18,12 +18,7 @@ export default class Renderer {
this.loader = new STLLoader();
this.fov = 45;
- this.camera = new THREE.PerspectiveCamera(
- this.fov,
- this.width / this.height,
- 1,
- 1000,
- );
+ this.camera = new THREE.PerspectiveCamera(this.fov, this.width / this.height, 1, 1000);
this.scene = new THREE.Scene();
@@ -35,10 +30,7 @@ export default class Renderer {
this.setupLight();
// Set up OrbitControls
- this.controls = new OrbitControls(
- this.camera,
- this.renderer.domElement,
- );
+ this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.minDistance = 5;
this.controls.maxDistance = 30;
this.controls.enableKeys = false;
@@ -51,47 +43,32 @@ export default class Renderer {
antialias: true,
});
- this.renderer.setClearColor(0xFFFFFF);
+ this.renderer.setClearColor(0xffffff);
this.renderer.setPixelRatio(window.devicePixelRatio);
- this.renderer.setSize(
- this.width,
- this.height,
- );
+ this.renderer.setSize(this.width, this.height);
}
setupLight() {
// Point light illuminates the object
- const pointLight = new THREE.PointLight(
- 0xFFFFFF,
- 2,
- 0,
- );
+ const pointLight = new THREE.PointLight(0xffffff, 2, 0);
pointLight.castShadow = true;
this.camera.add(pointLight);
// Ambient light illuminates the scene
- const ambientLight = new THREE.AmbientLight(
- 0xFFFFFF,
- 1,
- );
+ const ambientLight = new THREE.AmbientLight(0xffffff, 1);
this.scene.add(ambientLight);
}
setupGrid() {
- this.grid = new THREE.GridHelper(
- 20,
- 20,
- 0x000000,
- 0x000000,
- );
+ this.grid = new THREE.GridHelper(20, 20, 0x000000, 0x000000);
this.scene.add(this.grid);
}
loadFile() {
- this.loader.load(this.container.dataset.endpoint, (geo) => {
+ this.loader.load(this.container.dataset.endpoint, geo => {
const obj = new MeshObject(geo);
this.objects.push(obj);
@@ -116,30 +93,23 @@ export default class Renderer {
}
render() {
- this.renderer.render(
- this.scene,
- this.camera,
- );
+ this.renderer.render(this.scene, this.camera);
requestAnimationFrame(this.renderWrapper);
}
changeObjectMaterials(type) {
- this.objects.forEach((obj) => {
+ this.objects.forEach(obj => {
obj.changeMaterial(type);
});
}
setDefaultCameraPosition() {
const obj = this.objects[0];
- const radius = (obj.geometry.boundingSphere.radius / 1.5);
- const dist = radius / (Math.sin((this.fov * (Math.PI / 180)) / 2));
-
- this.camera.position.set(
- 0,
- dist + 1,
- dist,
- );
+ const radius = obj.geometry.boundingSphere.radius / 1.5;
+ const dist = radius / Math.sin((this.fov * (Math.PI / 180)) / 2);
+
+ this.camera.position.set(0, dist + 1, dist);
this.camera.lookAt(this.grid);
this.controls.update();
diff --git a/app/assets/javascripts/blob/3d_viewer/mesh_object.js b/app/assets/javascripts/blob/3d_viewer/mesh_object.js
index 96758884abf..cb7fcff8674 100644
--- a/app/assets/javascripts/blob/3d_viewer/mesh_object.js
+++ b/app/assets/javascripts/blob/3d_viewer/mesh_object.js
@@ -1,10 +1,6 @@
-import {
- Matrix4,
- MeshLambertMaterial,
- Mesh,
-} from 'three/build/three.module';
+import { Matrix4, MeshLambertMaterial, Mesh } from 'three/build/three.module';
-const defaultColor = 0xE24329;
+const defaultColor = 0xe24329;
const materials = {
default: new MeshLambertMaterial({
color: defaultColor,
@@ -17,10 +13,7 @@ const materials = {
export default class MeshObject extends Mesh {
constructor(geo) {
- super(
- geo,
- materials.default,
- );
+ super(geo, materials.default);
this.geometry.computeBoundingSphere();
@@ -29,13 +22,7 @@ export default class MeshObject extends Mesh {
if (this.geometry.boundingSphere.radius > 4) {
const scale = 4 / this.geometry.boundingSphere.radius;
- this.geometry.applyMatrix(
- new Matrix4().makeScale(
- scale,
- scale,
- scale,
- ),
- );
+ this.geometry.applyMatrix(new Matrix4().makeScale(scale, scale, scale));
this.geometry.computeBoundingSphere();
this.position.x = -this.geometry.boundingSphere.center.x;
diff --git a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js
index 7986287f7e7..75777b910ca 100644
--- a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js
+++ b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js
@@ -42,7 +42,7 @@ class BalsamiqViewer {
this.initDatabase(loadEvent.target.response);
const previews = this.getPreviews();
- previews.forEach((preview) => {
+ previews.forEach(preview => {
const renderedPreview = this.renderPreview(preview);
container.appendChild(renderedPreview);
diff --git a/app/assets/javascripts/blob/blob_file_dropzone.js b/app/assets/javascripts/blob/blob_file_dropzone.js
index ff1739b1679..cd3251ad1ca 100644
--- a/app/assets/javascripts/blob/blob_file_dropzone.js
+++ b/app/assets/javascripts/blob/blob_file_dropzone.js
@@ -41,39 +41,45 @@ export default class BlobFileDropzone {
addRemoveLinks: true,
previewsContainer: '.dropzone-previews',
headers: csrf.headers,
- init: function () {
- this.on('addedfile', function () {
+ init: function() {
+ this.on('addedfile', function() {
toggleLoading(submitButton, submitButtonLoadingIcon, false);
dropzoneMessage.addClass(HIDDEN_CLASS);
- $('.dropzone-alerts').html('').hide();
+ $('.dropzone-alerts')
+ .html('')
+ .hide();
});
- this.on('removedfile', function () {
+ this.on('removedfile', function() {
toggleLoading(submitButton, submitButtonLoadingIcon, false);
dropzoneMessage.removeClass(HIDDEN_CLASS);
});
- this.on('success', function (header, response) {
+ this.on('success', function(header, response) {
$('#modal-upload-blob').modal('hide');
visitUrl(response.filePath);
});
- this.on('maxfilesexceeded', function (file) {
+ this.on('maxfilesexceeded', function(file) {
dropzoneMessage.addClass(HIDDEN_CLASS);
this.removeFile(file);
});
- this.on('sending', function (file, xhr, formData) {
+ this.on('sending', function(file, xhr, formData) {
formData.append('branch_name', form.find('.js-branch-name').val());
formData.append('create_merge_request', form.find('.js-create-merge-request').val());
formData.append('commit_message', form.find('.js-commit-message').val());
});
},
// Override behavior of adding error underneath preview
- error: function (file, errorMessage) {
- const stripped = $('<div/>').html(errorMessage).text();
- $('.dropzone-alerts').html(`Error uploading file: "${stripped}"`).show();
+ error: function(file, errorMessage) {
+ const stripped = $('<div/>')
+ .html(errorMessage)
+ .text();
+ $('.dropzone-alerts')
+ .html(`Error uploading file: "${stripped}"`)
+ .show();
this.removeFile(file);
},
});
- submitButton.on('click', (e) => {
+ submitButton.on('click', e => {
e.preventDefault();
e.stopPropagation();
if (dropzone[0].dropzone.getQueuedFiles().length === 0) {
diff --git a/app/assets/javascripts/blob/blob_line_permalink_updater.js b/app/assets/javascripts/blob/blob_line_permalink_updater.js
index d36d9f0de2d..62f0a56ed75 100644
--- a/app/assets/javascripts/blob/blob_line_permalink_updater.js
+++ b/app/assets/javascripts/blob/blob_line_permalink_updater.js
@@ -2,17 +2,19 @@ import { getLocationHash } from '../lib/utils/url_utility';
const lineNumberRe = /^L[0-9]+/;
-const updateLineNumbersOnBlobPermalinks = (linksToUpdate) => {
+const updateLineNumbersOnBlobPermalinks = linksToUpdate => {
const hash = getLocationHash();
if (hash && lineNumberRe.test(hash)) {
const hashUrlString = `#${hash}`;
- [].concat(Array.prototype.slice.call(linksToUpdate)).forEach((permalinkButton) => {
- const baseHref = permalinkButton.getAttribute('data-original-href') || (() => {
- const href = permalinkButton.getAttribute('href');
- permalinkButton.setAttribute('data-original-href', href);
- return href;
- })();
+ [].concat(Array.prototype.slice.call(linksToUpdate)).forEach(permalinkButton => {
+ const baseHref =
+ permalinkButton.getAttribute('data-original-href') ||
+ (() => {
+ const href = permalinkButton.getAttribute('href');
+ permalinkButton.setAttribute('data-original-href', href);
+ return href;
+ })();
permalinkButton.setAttribute('href', `${baseHref}${hashUrlString}`);
});
}
@@ -26,7 +28,7 @@ function BlobLinePermalinkUpdater(blobContentHolder, lineNumberSelector, element
}, 0);
};
- blobContentHolder.addEventListener('click', (e) => {
+ blobContentHolder.addEventListener('click', e => {
if (e.target.matches(lineNumberSelector)) {
updateBlameAndBlobPermalinkCb();
}
diff --git a/app/assets/javascripts/blob/file_template_selector.js b/app/assets/javascripts/blob/file_template_selector.js
index 02228434a29..476901aae75 100644
--- a/app/assets/javascripts/blob/file_template_selector.js
+++ b/app/assets/javascripts/blob/file_template_selector.js
@@ -45,15 +45,11 @@ export default class FileTemplateSelector {
}
renderLoading() {
- this.$loadingIcon
- .addClass('fa-spinner fa-spin')
- .removeClass('fa-chevron-down');
+ this.$loadingIcon.addClass('fa-spinner fa-spin').removeClass('fa-chevron-down');
}
renderLoaded() {
- this.$loadingIcon
- .addClass('fa-chevron-down')
- .removeClass('fa-spinner fa-spin');
+ this.$loadingIcon.addClass('fa-chevron-down').removeClass('fa-spinner fa-spin');
}
reportSelection(options) {
diff --git a/app/assets/javascripts/blob/notebook/index.js b/app/assets/javascripts/blob/notebook/index.js
index 6f1350e80fc..071022a9a75 100644
--- a/app/assets/javascripts/blob/notebook/index.js
+++ b/app/assets/javascripts/blob/notebook/index.js
@@ -40,13 +40,14 @@ export default () => {
},
methods: {
loadFile() {
- axios.get(el.dataset.endpoint)
+ axios
+ .get(el.dataset.endpoint)
.then(res => res.data)
- .then((data) => {
+ .then(data => {
this.json = data;
this.loading = false;
})
- .catch((e) => {
+ .catch(e => {
if (e.status !== 200) {
this.loadError = true;
}
diff --git a/app/assets/javascripts/blob/sketch/index.js b/app/assets/javascripts/blob/sketch/index.js
index 13318c58006..57c1baa9886 100644
--- a/app/assets/javascripts/blob/sketch/index.js
+++ b/app/assets/javascripts/blob/sketch/index.js
@@ -13,7 +13,7 @@ export default class SketchLoader {
return this.getZipFile()
.then(data => JSZip.loadAsync(data))
.then(asyncResult => asyncResult.files['previews/preview.png'].async('uint8array'))
- .then((content) => {
+ .then(content => {
const url = window.URL || window.webkitURL;
const blob = new Blob([new Uint8Array(content)], {
type: 'image/png',
diff --git a/app/assets/javascripts/blob/stl_viewer.js b/app/assets/javascripts/blob/stl_viewer.js
index 339906adc34..f129b6e631e 100644
--- a/app/assets/javascripts/blob/stl_viewer.js
+++ b/app/assets/javascripts/blob/stl_viewer.js
@@ -3,8 +3,8 @@ import Renderer from './3d_viewer';
export default () => {
const viewer = new Renderer(document.getElementById('js-stl-viewer'));
- [].slice.call(document.querySelectorAll('.js-material-changer')).forEach((el) => {
- el.addEventListener('click', (e) => {
+ [].slice.call(document.querySelectorAll('.js-material-changer')).forEach(el => {
+ el.addEventListener('click', e => {
const { target } = e;
e.preventDefault();
diff --git a/app/assets/javascripts/blob/template_selector.js b/app/assets/javascripts/blob/template_selector.js
index 9db1fa70ffb..37e348d93d3 100644
--- a/app/assets/javascripts/blob/template_selector.js
+++ b/app/assets/javascripts/blob/template_selector.js
@@ -81,14 +81,10 @@ export default class TemplateSelector {
}
startLoadingSpinner() {
- this.$dropdownIcon
- .addClass('fa-spinner fa-spin')
- .removeClass('fa-chevron-down');
+ this.$dropdownIcon.addClass('fa-spinner fa-spin').removeClass('fa-chevron-down');
}
stopLoadingSpinner() {
- this.$dropdownIcon
- .addClass('fa-chevron-down')
- .removeClass('fa-spinner fa-spin');
+ this.$dropdownIcon.addClass('fa-chevron-down').removeClass('fa-spinner fa-spin');
}
}
diff --git a/app/assets/javascripts/blob/template_selectors/license_selector.js b/app/assets/javascripts/blob/template_selectors/license_selector.js
index ac1fe95eee5..d01ab9257d6 100644
--- a/app/assets/javascripts/blob/template_selectors/license_selector.js
+++ b/app/assets/javascripts/blob/template_selectors/license_selector.js
@@ -22,7 +22,7 @@ export default class BlobLicenseSelector extends FileTemplateSelector {
search: {
fields: ['name'],
},
- clicked: (options) => {
+ clicked: options => {
const { e } = options;
const el = options.$el;
const query = options.selectedObj;
diff --git a/app/assets/javascripts/blob/template_selectors/type_selector.js b/app/assets/javascripts/blob/template_selectors/type_selector.js
index a09381014a7..db3c144cbe3 100644
--- a/app/assets/javascripts/blob/template_selectors/type_selector.js
+++ b/app/assets/javascripts/blob/template_selectors/type_selector.js
@@ -21,5 +21,4 @@ export default class FileTemplateTypeSelector extends FileTemplateSelector {
text: item => item.name,
});
}
-
}
diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js
index 5485248cfaf..befa1dc455f 100644
--- a/app/assets/javascripts/blob/viewer/index.js
+++ b/app/assets/javascripts/blob/viewer/index.js
@@ -22,9 +22,8 @@ export default class BlobViewer {
const viewer = document.querySelector('.blob-viewer[data-type="rich"]');
if (!viewer || !viewer.dataset.richType) return;
- const initViewer = promise => promise
- .then(module => module.default(viewer))
- .catch((error) => {
+ const initViewer = promise =>
+ promise.then(module => module.default(viewer)).catch(error => {
Flash('Error loading file viewer.');
throw error;
});
@@ -79,10 +78,9 @@ export default class BlobViewer {
initBindings() {
if (this.switcherBtns.length) {
- Array.from(this.switcherBtns)
- .forEach((el) => {
- el.addEventListener('click', this.switchViewHandler.bind(this));
- });
+ Array.from(this.switcherBtns).forEach(el => {
+ el.addEventListener('click', this.switchViewHandler.bind(this));
+ });
}
if (this.copySourceBtn) {
@@ -109,7 +107,10 @@ export default class BlobViewer {
this.copySourceBtn.setAttribute('title', 'Copy source to clipboard');
this.copySourceBtn.classList.remove('disabled');
} else if (this.activeViewer === this.simpleViewer) {
- this.copySourceBtn.setAttribute('title', 'Wait for the source to load to copy it to the clipboard');
+ this.copySourceBtn.setAttribute(
+ 'title',
+ 'Wait for the source to load to copy it to the clipboard',
+ );
this.copySourceBtn.classList.add('disabled');
} else {
this.copySourceBtn.setAttribute('title', 'Switch to the source to copy it to the clipboard');
@@ -147,15 +148,15 @@ export default class BlobViewer {
this.toggleCopyButtonState();
BlobViewer.loadViewer(newViewer)
- .then((viewer) => {
- $(viewer).renderGFM();
+ .then(viewer => {
+ $(viewer).renderGFM();
- this.$fileHolder.trigger('highlight:line');
- handleLocationHash();
+ this.$fileHolder.trigger('highlight:line');
+ handleLocationHash();
- this.toggleCopyButtonState();
- })
- .catch(() => new Flash('Error loading viewer'));
+ this.toggleCopyButtonState();
+ })
+ .catch(() => new Flash('Error loading viewer'));
}
static loadViewer(viewerParam) {
@@ -168,12 +169,11 @@ export default class BlobViewer {
viewer.setAttribute('data-loading', 'true');
- return axios.get(url)
- .then(({ data }) => {
- viewer.innerHTML = data.html;
- viewer.setAttribute('data-loaded', 'true');
+ return axios.get(url).then(({ data }) => {
+ viewer.innerHTML = data.html;
+ viewer.setAttribute('data-loaded', 'true');
- return viewer;
- });
+ return viewer;
+ });
}
}
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index 4e4598870fa..3cc89ff1955 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -13,11 +13,11 @@ export default () => {
if (editBlobForm.length) {
const urlRoot = editBlobForm.data('relativeUrlRoot');
const assetsPath = editBlobForm.data('assetsPrefix');
- const blobLanguage = editBlobForm.data('blobLanguage');
+ const filePath = editBlobForm.data('blobFilename')
const currentAction = $('.js-file-title').data('currentAction');
const projectId = editBlobForm.data('project-id');
- new EditBlob(`${urlRoot}${assetsPath}`, blobLanguage, currentAction, projectId);
+ new EditBlob(`${urlRoot}${assetsPath}`, filePath, currentAction, projectId);
new NewCommitForm(editBlobForm);
}
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index ec2b130ab7d..6e19548eed2 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -5,6 +5,7 @@ import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import { __ } from '~/locale';
import TemplateSelectorMediator from '../blob/file_template_mediator';
+import getModeByFileExtension from '~/lib/utils/ace_utils';
export default class EditBlob {
constructor(assetsPath, aceMode, currentAction, projectId) {
@@ -14,9 +15,10 @@ export default class EditBlob {
this.initFileSelectors(currentAction, projectId);
}
- configureAceEditor(aceMode, assetsPath) {
+ configureAceEditor(filePath, assetsPath) {
ace.config.set('modePath', `${assetsPath}/ace`);
ace.config.loadModule('ace/ext/searchbox');
+ ace.config.loadModule('ace/ext/modelist');
this.editor = ace.edit('editor');
@@ -25,8 +27,8 @@ export default class EditBlob {
this.editor.focus();
- if (aceMode) {
- this.editor.getSession().setMode(`ace/mode/${aceMode}`);
+ if (filePath) {
+ this.editor.getSession().setMode(getModeByFileExtension(filePath));
}
}
diff --git a/app/assets/javascripts/boards/components/board.js b/app/assets/javascripts/boards/components/board.js
index 75477ebb3b3..623cda5679a 100644
--- a/app/assets/javascripts/boards/components/board.js
+++ b/app/assets/javascripts/boards/components/board.js
@@ -53,6 +53,9 @@ export default Vue.extend({
const { issuesSize } = this.list;
return `${n__('%d issue', '%d issues', issuesSize)}`;
},
+ isNewIssueShown() {
+ return this.list.type === 'backlog' || (!this.disabled && this.list.type !== 'closed');
+ }
},
watch: {
filter: {
diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue
index 28956c2f3c5..aa98f35786e 100644
--- a/app/assets/javascripts/boards/components/issue_card_inner.vue
+++ b/app/assets/javascripts/boards/components/issue_card_inner.vue
@@ -1,5 +1,6 @@
<script>
import $ from 'jquery';
+ import Icon from '~/vue_shared/components/icon.vue';
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import eventHub from '../eventhub';
import tooltip from '../../vue_shared/directives/tooltip';
@@ -8,6 +9,7 @@
export default {
components: {
UserAvatarLink,
+ Icon,
},
directives: {
tooltip,
@@ -140,11 +142,11 @@
<div>
<div class="board-card-header">
<h4 class="board-card-title">
- <i
+ <icon
v-if="issue.confidential"
- class="fa fa-eye-slash confidential-icon"
- aria-hidden="true"
- ></i>
+ name="eye-slash"
+ class="confidential-icon"
+ />
<a
:href="issue.path"
:title="issue.title"
diff --git a/app/assets/javascripts/boards/components/modal/list.vue b/app/assets/javascripts/boards/components/modal/list.vue
index a58b5afe970..c93fd9f415c 100644
--- a/app/assets/javascripts/boards/components/modal/list.vue
+++ b/app/assets/javascripts/boards/components/modal/list.vue
@@ -1,4 +1,5 @@
<script>
+ import Icon from '~/vue_shared/components/icon.vue';
import bp from '../../../breakpoints';
import ModalStore from '../../stores/modal_store';
import IssueCardInner from '../issue_card_inner.vue';
@@ -6,6 +7,7 @@
export default {
components: {
IssueCardInner,
+ Icon,
},
props: {
issueLinkBase: {
@@ -147,13 +149,13 @@
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"/>
- <span
+ <icon
v-if="issue.selected"
:aria-label="'Issue #' + issue.id + ' selected'"
+ name="mobile-issue-close"
aria-checked="true"
- class="issue-card-selected text-center">
- <i class="fa fa-check"></i>
- </span>
+ class="issue-card-selected text-center"
+ />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue
index 4622fd28220..3baac08d411 100644
--- a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue
+++ b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue
@@ -1,11 +1,13 @@
<script>
import { Link } from '@gitlab-org/gitlab-ui';
+import Icon from '~/vue_shared/components/icon.vue';
import ModalStore from '../../stores/modal_store';
import boardsStore from '../../stores/boards_store';
export default {
components: {
'gl-link': Link,
+ Icon,
},
data() {
return {
@@ -35,7 +37,9 @@ export default {
class="dropdown-label-box">
</span>
{{ selected.title }}
- <i class="fa fa-chevron-down"></i>
+ <icon
+ name="chevron-down"
+ />
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-drop-up">
<ul>
diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue
index d4676914e02..427a0868b0c 100644
--- a/app/assets/javascripts/boards/components/project_select.vue
+++ b/app/assets/javascripts/boards/components/project_select.vue
@@ -1,11 +1,15 @@
<script>
import $ from 'jquery';
import _ from 'underscore';
+import Icon from '~/vue_shared/components/icon.vue';
import eventHub from '../eventhub';
import Api from '../../api';
export default {
name: 'BoardProjectSelect',
+ components: {
+ Icon,
+ },
props: {
groupId: {
type: Number,
@@ -42,7 +46,7 @@ export default {
selectable: true,
data: (term, callback) => {
this.loading = true;
- return Api.groupProjects(this.groupId, term, {}, projects => {
+ return Api.groupProjects(this.groupId, term, {with_issues_enabled: true}, projects => {
this.loading = false;
callback(projects);
});
@@ -78,11 +82,9 @@ export default {
aria-expanded="false"
>
{{ selectedProjectName }}
- <i
- class="fa fa-chevron-down"
- aria-hidden="true"
- >
- </i>
+ <icon
+ name="chevron-down"
+ />
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-full-width">
<div class="dropdown-title">
@@ -92,12 +94,11 @@ export default {
type="button"
class="dropdown-title-button dropdown-menu-close"
>
- <i
- aria-hidden="true"
+ <icon
+ name="merge-request-close-m"
data-hidden="true"
- class="fa fa-times dropdown-menu-close-icon"
- >
- </i>
+ class="dropdown-menu-close-icon"
+ />
</button>
</div>
<div class="dropdown-input">
@@ -106,12 +107,11 @@ export default {
type="search"
placeholder="Search projects"
/>
- <i
- aria-hidden="true"
+ <icon
+ name="search"
+ class="dropdown-input-search"
data-hidden="true"
- class="fa fa-search dropdown-input-search"
- >
- </i>
+ />
</div>
<div class="dropdown-content"></div>
<div class="dropdown-loading">
diff --git a/app/assets/javascripts/breadcrumb.js b/app/assets/javascripts/breadcrumb.js
index 1474d93dde6..a37838694ec 100644
--- a/app/assets/javascripts/breadcrumb.js
+++ b/app/assets/javascripts/breadcrumb.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
-export const addTooltipToEl = (el) => {
+export const addTooltipToEl = el => {
const textEl = el.querySelector('.js-breadcrumb-item-text');
if (textEl && textEl.scrollWidth > textEl.offsetWidth) {
@@ -14,17 +14,18 @@ export default () => {
const breadcrumbs = document.querySelector('.js-breadcrumbs-list');
if (breadcrumbs) {
- const topLevelLinks = [...breadcrumbs.children].filter(el => !el.classList.contains('dropdown'))
+ const topLevelLinks = [...breadcrumbs.children]
+ .filter(el => !el.classList.contains('dropdown'))
.map(el => el.querySelector('a'))
.filter(el => el);
const $expander = $('.js-breadcrumbs-collapsed-expander');
topLevelLinks.forEach(el => addTooltipToEl(el));
- $expander.closest('.dropdown')
- .on('show.bs.dropdown hide.bs.dropdown', (e) => {
- $('.js-breadcrumbs-collapsed-expander', e.currentTarget).toggleClass('open')
- .tooltip('hide');
- });
+ $expander.closest('.dropdown').on('show.bs.dropdown hide.bs.dropdown', e => {
+ $('.js-breadcrumbs-collapsed-expander', e.currentTarget)
+ .toggleClass('open')
+ .tooltip('hide');
+ });
}
};
diff --git a/app/assets/javascripts/build_artifacts.js b/app/assets/javascripts/build_artifacts.js
index e338376fcaa..97a1645aa51 100644
--- a/app/assets/javascripts/build_artifacts.js
+++ b/app/assets/javascripts/build_artifacts.js
@@ -12,16 +12,16 @@ export default class BuildArtifacts {
}
// eslint-disable-next-line class-methods-use-this
disablePropagation() {
- $('.top-block').on('click', '.download', function (e) {
+ $('.top-block').on('click', '.download', function(e) {
return e.stopPropagation();
});
- return $('.tree-holder').on('click', 'tr[data-link] a', function (e) {
+ return $('.tree-holder').on('click', 'tr[data-link] a', function(e) {
return e.stopImmediatePropagation();
});
}
// eslint-disable-next-line class-methods-use-this
setupEntryClick() {
- return $('.tree-holder').on('click', 'tr[data-link]', function () {
+ return $('.tree-holder').on('click', 'tr[data-link]', function() {
visitUrl(this.dataset.link, convertPermissionToBoolean(this.dataset.externalLink));
});
}
@@ -37,11 +37,15 @@ export default class BuildArtifacts {
// We want the tooltip to show if you hover anywhere on the row
// But be placed below and in the middle of the file name
$('.js-artifact-tree-row')
- .on('mouseenter', (e) => {
- $(e.currentTarget).find('.js-artifact-tree-tooltip').tooltip('show');
+ .on('mouseenter', e => {
+ $(e.currentTarget)
+ .find('.js-artifact-tree-tooltip')
+ .tooltip('show');
})
- .on('mouseleave', (e) => {
- $(e.currentTarget).find('.js-artifact-tree-tooltip').tooltip('hide');
+ .on('mouseleave', e => {
+ $(e.currentTarget)
+ .find('.js-artifact-tree-tooltip')
+ .tooltip('hide');
});
}
}
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 b33adff609f..1089d0a72d3 100644
--- a/app/assets/javascripts/ci_variable_list/ajax_variable_list.js
+++ b/app/assets/javascripts/ci_variable_list/ajax_variable_list.js
@@ -7,11 +7,13 @@ import statusCodes from '../lib/utils/http_status';
import VariableList from './ci_variable_list';
function generateErrorBoxContent(errors) {
- const errorList = [].concat(errors).map(errorString => `
+ const errorList = [].concat(errors).map(
+ errorString => `
<li>
${_.escape(errorString)}
</li>
- `);
+ `,
+ );
return `
<p>
@@ -25,13 +27,7 @@ function generateErrorBoxContent(errors) {
// Used for the variable list on CI/CD projects/groups settings page
export default class AjaxVariableList {
- constructor({
- container,
- saveButton,
- errorBox,
- formField = 'variables',
- saveEndpoint,
- }) {
+ constructor({ container, saveButton, errorBox, formField = 'variables', saveEndpoint }) {
this.container = container;
this.saveButton = saveButton;
this.errorBox = errorBox;
@@ -58,18 +54,21 @@ export default class AjaxVariableList {
// to match it up in `updateRowsWithPersistedVariables`
this.variableList.toggleEnableRow(false);
- return axios.patch(this.saveEndpoint, {
- variables_attributes: this.variableList.getAllData(),
- }, {
- // We want to be able to process the `res.data` from a 400 error response
- // and print the validation messages such as duplicate variable keys
- validateStatus: status => (
- status >= statusCodes.OK &&
- status < statusCodes.MULTIPLE_CHOICES
- ) ||
- status === statusCodes.BAD_REQUEST,
- })
- .then((res) => {
+ return axios
+ .patch(
+ this.saveEndpoint,
+ {
+ variables_attributes: this.variableList.getAllData(),
+ },
+ {
+ // We want to be able to process the `res.data` from a 400 error response
+ // and print the validation messages such as duplicate variable keys
+ validateStatus: status =>
+ (status >= statusCodes.OK && status < statusCodes.MULTIPLE_CHOICES) ||
+ status === statusCodes.BAD_REQUEST,
+ },
+ )
+ .then(res => {
loadingIcon.classList.toggle('hide', true);
this.variableList.toggleEnableRow(true);
@@ -90,18 +89,21 @@ export default class AjaxVariableList {
}
updateRowsWithPersistedVariables(persistedVariables = []) {
- const persistedVariableMap = [].concat(persistedVariables).reduce((variableMap, variable) => ({
- ...variableMap,
- [variable.key]: variable,
- }), {});
+ const persistedVariableMap = [].concat(persistedVariables).reduce(
+ (variableMap, variable) => ({
+ ...variableMap,
+ [variable.key]: variable,
+ }),
+ {},
+ );
- this.container.querySelectorAll('.js-row').forEach((row) => {
+ this.container.querySelectorAll('.js-row').forEach(row => {
// 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)) {
row.remove();
- // Update the ID input so any future edits and `_destroy` will apply on the BE
+ // Update the ID input so any future edits and `_destroy` will apply on the BE
} else {
const key = row.querySelector('.js-ci-variable-input-key').value;
const persistedVariable = persistedVariableMap[key];
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 47efb3a8cee..7bdc18ce03e 100644
--- a/app/assets/javascripts/ci_variable_list/ci_variable_list.js
+++ b/app/assets/javascripts/ci_variable_list/ci_variable_list.js
@@ -16,10 +16,7 @@ function createEnvironmentItem(value) {
}
export default class VariableList {
- constructor({
- container,
- formField,
- }) {
+ constructor({ container, formField }) {
this.$container = $(container);
this.formField = formField;
this.environmentDropdownMap = new WeakMap();
@@ -71,7 +68,7 @@ export default class VariableList {
this.initRow(rowEl);
});
- this.$container.on('click', '.js-row-remove-button', (e) => {
+ this.$container.on('click', '.js-row-remove-button', e => {
e.preventDefault();
this.removeRow($(e.currentTarget).closest('.js-row'));
});
@@ -81,7 +78,7 @@ export default class VariableList {
.join(',');
// Remove any empty rows except the last row
- this.$container.on('blur', inputSelector, (e) => {
+ this.$container.on('blur', inputSelector, e => {
const $row = $(e.currentTarget).closest('.js-row');
if ($row.is(':not(:last-child)') && !this.checkIfRowTouched($row)) {
@@ -136,7 +133,7 @@ export default class VariableList {
$rowClone.removeAttr('data-is-persisted');
// Reset the inputs to their defaults
- Object.keys(this.inputMap).forEach((name) => {
+ Object.keys(this.inputMap).forEach(name => {
const entry = this.inputMap[name];
$rowClone.find(entry.selector).val(entry.default);
});
@@ -171,7 +168,7 @@ export default class VariableList {
}
checkIfRowTouched($row) {
- return Object.keys(this.inputMap).some((name) => {
+ return Object.keys(this.inputMap).some(name => {
const entry = this.inputMap[name];
const $el = $row.find(entry.selector);
return $el.length && $el.val() !== entry.default;
@@ -190,11 +187,14 @@ export default class VariableList {
getAllData() {
// Ignore the last empty row because we don't want to try persist
// a blank variable and run into validation problems.
- const validRows = this.$container.find('.js-row').toArray().slice(0, -1);
+ const validRows = this.$container
+ .find('.js-row')
+ .toArray()
+ .slice(0, -1);
- return validRows.map((rowEl) => {
+ return validRows.map(rowEl => {
const resultant = {};
- Object.keys(this.inputMap).forEach((name) => {
+ Object.keys(this.inputMap).forEach(name => {
const entry = this.inputMap[name];
const $input = $(rowEl).find(entry.selector);
if ($input.length) {
@@ -207,11 +207,16 @@ export default class VariableList {
}
getEnvironmentValues() {
- const valueMap = this.$container.find(this.inputMap.environment_scope.selector).toArray()
- .reduce((prevValueMap, envInput) => ({
- ...prevValueMap,
- [envInput.value]: envInput.value,
- }), {});
+ const valueMap = this.$container
+ .find(this.inputMap.environment_scope.selector)
+ .toArray()
+ .reduce(
+ (prevValueMap, envInput) => ({
+ ...prevValueMap,
+ [envInput.value]: envInput.value,
+ }),
+ {},
+ );
return Object.keys(valueMap).map(createEnvironmentItem);
}
diff --git a/app/assets/javascripts/ci_variable_list/native_form_variable_list.js b/app/assets/javascripts/ci_variable_list/native_form_variable_list.js
index 7cd5916ac9c..e7111c666a2 100644
--- a/app/assets/javascripts/ci_variable_list/native_form_variable_list.js
+++ b/app/assets/javascripts/ci_variable_list/native_form_variable_list.js
@@ -2,10 +2,7 @@ import $ from 'jquery';
import VariableList from './ci_variable_list';
// Used for the variable list on scheduled pipeline edit page
-export default function setupNativeFormVariableList({
- container,
- formField = 'variables',
-}) {
+export default function setupNativeFormVariableList({ container, formField = 'variables' }) {
const $container = $(container);
const variableList = new VariableList({
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 65e7cee7039..ebf76af5966 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -1,6 +1,6 @@
import Visibility from 'visibilityjs';
import Vue from 'vue';
-import PersistentUserCallout from '../persistent_user_callout';
+import initDismissableCallout from '~/dismissable_callout';
import { s__, sprintf } from '../locale';
import Flash from '../flash';
import Poll from '../lib/utils/poll';
@@ -62,7 +62,7 @@ export default class Clusters {
this.showTokenButton = document.querySelector('.js-show-cluster-token');
this.tokenField = document.querySelector('.js-cluster-token');
- Clusters.initDismissableCallout();
+ initDismissableCallout('.js-cluster-security-warning');
initSettingsPanels();
setupToggleButtons(document.querySelector('.js-cluster-enable-toggle-area'));
this.initApplications();
@@ -105,12 +105,6 @@ export default class Clusters {
});
}
- static initDismissableCallout() {
- const callout = document.querySelector('.js-cluster-security-warning');
-
- if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
- }
-
addListeners() {
if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken);
eventHub.$on('installApplication', this.installApplication);
diff --git a/app/assets/javascripts/clusters/clusters_index.js b/app/assets/javascripts/clusters/clusters_index.js
index e32d507d1f7..789c8360124 100644
--- a/app/assets/javascripts/clusters/clusters_index.js
+++ b/app/assets/javascripts/clusters/clusters_index.js
@@ -1,15 +1,14 @@
import createFlash from '~/flash';
import { __ } from '~/locale';
import setupToggleButtons from '~/toggle_buttons';
-import PersistentUserCallout from '../persistent_user_callout';
+import initDismissableCallout from '~/dismissable_callout';
import ClustersService from './services/clusters_service';
export default () => {
const clusterList = document.querySelector('.js-clusters-list');
- const callout = document.querySelector('.gcp-signup-offer');
- if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
+ initDismissableCallout('.gcp-signup-offer');
// The empty state won't have a clusterList
if (clusterList) {
diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue
index 0452729d3ff..236bb1394c8 100644
--- a/app/assets/javascripts/clusters/components/application_row.vue
+++ b/app/assets/javascripts/clusters/components/application_row.vue
@@ -1,153 +1,162 @@
<script>
- /* eslint-disable vue/require-default-prop */
- import { s__, sprintf } from '../../locale';
- import eventHub from '../event_hub';
- import identicon from '../../vue_shared/components/identicon.vue';
- import loadingButton from '../../vue_shared/components/loading_button.vue';
- import {
- APPLICATION_STATUS,
- REQUEST_LOADING,
- REQUEST_SUCCESS,
- REQUEST_FAILURE,
- } from '../constants';
+/* eslint-disable vue/require-default-prop */
+import { s__, sprintf } from '../../locale';
+import eventHub from '../event_hub';
+import identicon from '../../vue_shared/components/identicon.vue';
+import loadingButton from '../../vue_shared/components/loading_button.vue';
+import {
+ APPLICATION_STATUS,
+ REQUEST_LOADING,
+ REQUEST_SUCCESS,
+ REQUEST_FAILURE,
+} from '../constants';
- export default {
- components: {
- loadingButton,
- identicon,
+export default {
+ components: {
+ loadingButton,
+ identicon,
+ },
+ props: {
+ id: {
+ type: String,
+ required: true,
},
- props: {
- id: {
- type: String,
- required: true,
- },
- title: {
- type: String,
- required: true,
- },
- titleLink: {
- type: String,
- required: false,
- },
- manageLink: {
- type: String,
- required: false,
- },
- logoUrl: {
- type: String,
- required: false,
- default: null,
- },
- disabled: {
- type: Boolean,
- required: false,
- default: false,
- },
- status: {
- type: String,
- required: false,
- },
- statusReason: {
- type: String,
- required: false,
- },
- requestStatus: {
- type: String,
- required: false,
- },
- requestReason: {
- type: String,
- required: false,
- },
- installApplicationRequestParams: {
- type: Object,
- required: false,
- default: () => ({}),
- },
+ title: {
+ type: String,
+ required: true,
},
- computed: {
- isUnknownStatus() {
- return !this.isKnownStatus && this.status !== null;
- },
- isKnownStatus() {
- return Object.values(APPLICATION_STATUS).includes(this.status);
- },
- isInstalled() {
- return (
- this.status === APPLICATION_STATUS.INSTALLED || this.status === APPLICATION_STATUS.UPDATED
- );
- },
- hasLogo() {
- return !!this.logoUrl;
- },
- identiconId() {
- // generate a deterministic integer id for the identicon background
- return this.id.charCodeAt(0);
- },
- rowJsClass() {
- return `js-cluster-application-row-${this.id}`;
- },
- installButtonLoading() {
- return !this.status ||
- this.status === APPLICATION_STATUS.SCHEDULED ||
- this.status === APPLICATION_STATUS.INSTALLING ||
- this.requestStatus === REQUEST_LOADING;
- },
- installButtonDisabled() {
- // Avoid the potential for the real-time data to say APPLICATION_STATUS.INSTALLABLE but
- // we already made a request to install and are just waiting for the real-time
- // to sync up.
- return ((this.status !== APPLICATION_STATUS.INSTALLABLE
- && this.status !== APPLICATION_STATUS.ERROR) ||
+ titleLink: {
+ type: String,
+ required: false,
+ },
+ manageLink: {
+ type: String,
+ required: false,
+ },
+ logoUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ disabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ status: {
+ type: String,
+ required: false,
+ },
+ statusReason: {
+ type: String,
+ required: false,
+ },
+ requestStatus: {
+ type: String,
+ required: false,
+ },
+ requestReason: {
+ type: String,
+ required: false,
+ },
+ installApplicationRequestParams: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ },
+ computed: {
+ isUnknownStatus() {
+ return !this.isKnownStatus && this.status !== null;
+ },
+ isKnownStatus() {
+ return Object.values(APPLICATION_STATUS).includes(this.status);
+ },
+ isInstalled() {
+ return (
+ this.status === APPLICATION_STATUS.INSTALLED ||
+ this.status === APPLICATION_STATUS.UPDATED ||
+ this.status === APPLICATION_STATUS.UPDATING
+ );
+ },
+ hasLogo() {
+ return !!this.logoUrl;
+ },
+ identiconId() {
+ // generate a deterministic integer id for the identicon background
+ return this.id.charCodeAt(0);
+ },
+ rowJsClass() {
+ return `js-cluster-application-row-${this.id}`;
+ },
+ installButtonLoading() {
+ return (
+ !this.status ||
+ this.status === APPLICATION_STATUS.SCHEDULED ||
+ this.status === APPLICATION_STATUS.INSTALLING ||
+ this.requestStatus === REQUEST_LOADING
+ );
+ },
+ installButtonDisabled() {
+ // Avoid the potential for the real-time data to say APPLICATION_STATUS.INSTALLABLE but
+ // we already made a request to install and are just waiting for the real-time
+ // to sync up.
+ return (
+ ((this.status !== APPLICATION_STATUS.INSTALLABLE &&
+ this.status !== APPLICATION_STATUS.ERROR) ||
this.requestStatus === REQUEST_LOADING ||
- this.requestStatus === REQUEST_SUCCESS) && this.isKnownStatus;
- },
- installButtonLabel() {
- let label;
- if (
- this.status === APPLICATION_STATUS.NOT_INSTALLABLE ||
- this.status === APPLICATION_STATUS.INSTALLABLE ||
- this.status === APPLICATION_STATUS.ERROR ||
- this.isUnknownStatus
- ) {
- label = s__('ClusterIntegration|Install');
- } else if (this.status === APPLICATION_STATUS.SCHEDULED ||
- this.status === APPLICATION_STATUS.INSTALLING) {
- label = s__('ClusterIntegration|Installing');
- } else if (this.status === APPLICATION_STATUS.INSTALLED ||
- this.status === APPLICATION_STATUS.UPDATED) {
- label = s__('ClusterIntegration|Installed');
- }
+ this.requestStatus === REQUEST_SUCCESS) &&
+ this.isKnownStatus
+ );
+ },
+ installButtonLabel() {
+ let label;
+ if (
+ this.status === APPLICATION_STATUS.NOT_INSTALLABLE ||
+ this.status === APPLICATION_STATUS.INSTALLABLE ||
+ this.status === APPLICATION_STATUS.ERROR ||
+ this.isUnknownStatus
+ ) {
+ label = s__('ClusterIntegration|Install');
+ } else if (
+ this.status === APPLICATION_STATUS.SCHEDULED ||
+ this.status === APPLICATION_STATUS.INSTALLING
+ ) {
+ label = s__('ClusterIntegration|Installing');
+ } else if (
+ this.status === APPLICATION_STATUS.INSTALLED ||
+ this.status === APPLICATION_STATUS.UPDATED ||
+ this.status === APPLICATION_STATUS.UPDATING
+ ) {
+ label = s__('ClusterIntegration|Installed');
+ }
- return label;
- },
- showManageButton() {
- return this.manageLink && this.status === APPLICATION_STATUS.INSTALLED;
- },
- manageButtonLabel() {
- return s__('ClusterIntegration|Manage');
- },
- hasError() {
- return this.status === APPLICATION_STATUS.ERROR ||
- this.requestStatus === REQUEST_FAILURE;
- },
- generalErrorDescription() {
- return sprintf(
- s__('ClusterIntegration|Something went wrong while installing %{title}'), {
- title: this.title,
- },
- );
- },
+ return label;
+ },
+ showManageButton() {
+ return this.manageLink && this.status === APPLICATION_STATUS.INSTALLED;
+ },
+ manageButtonLabel() {
+ return s__('ClusterIntegration|Manage');
+ },
+ hasError() {
+ return this.status === APPLICATION_STATUS.ERROR || this.requestStatus === REQUEST_FAILURE;
+ },
+ generalErrorDescription() {
+ return sprintf(s__('ClusterIntegration|Something went wrong while installing %{title}'), {
+ title: this.title,
+ });
},
- methods: {
- installClicked() {
- eventHub.$emit('installApplication', {
- id: this.id,
- params: this.installApplicationRequestParams,
- });
- },
+ },
+ methods: {
+ installClicked() {
+ eventHub.$emit('installApplication', {
+ id: this.id,
+ params: this.installApplicationRequestParams,
+ });
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index a1069985178..6e7b5eb5526 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -1,6 +1,6 @@
<script>
import _ from 'underscore';
-import helmInstallIllustration from '@gitlab-org/gitlab-svgs/illustrations/kubernetes-installation.svg';
+import helmInstallIllustration from '@gitlab-org/gitlab-svgs/dist/illustrations/kubernetes-installation.svg';
import elasticsearchLogo from 'images/cluster_app_logos/elasticsearch.png';
import gitlabLogo from 'images/cluster_app_logos/gitlab.png';
import helmLogo from 'images/cluster_app_logos/helm.png';
diff --git a/app/assets/javascripts/clusters/constants.js b/app/assets/javascripts/clusters/constants.js
index 72fc9355d82..24a49624583 100644
--- a/app/assets/javascripts/clusters/constants.js
+++ b/app/assets/javascripts/clusters/constants.js
@@ -6,6 +6,7 @@ export const APPLICATION_STATUS = {
INSTALLING: 'installing',
INSTALLED: 'installed',
UPDATED: 'updated',
+ UPDATING: 'updating',
ERROR: 'errored',
};
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index d90db7b103c..106ac3cb516 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -76,12 +76,8 @@ export default class ClusterStore {
this.state.status = serverState.status;
this.state.statusReason = serverState.status_reason;
- serverState.applications.forEach((serverAppEntry) => {
- const {
- name: appId,
- status,
- status_reason: statusReason,
- } = serverAppEntry;
+ serverState.applications.forEach(serverAppEntry => {
+ const { name: appId, status, status_reason: statusReason } = serverAppEntry;
this.state.applications[appId] = {
...(this.state.applications[appId] || {}),
diff --git a/app/assets/javascripts/comment_type_toggle.js b/app/assets/javascripts/comment_type_toggle.js
index c74184949df..a259667bb75 100644
--- a/app/assets/javascripts/comment_type_toggle.js
+++ b/app/assets/javascripts/comment_type_toggle.js
@@ -24,36 +24,44 @@ class CommentTypeToggle {
setConfig() {
const config = {
- InputSetter: [{
- input: this.noteTypeInput,
- valueAttribute: 'data-value',
- },
- {
- input: this.submitButton,
- valueAttribute: 'data-submit-text',
- }],
+ InputSetter: [
+ {
+ input: this.noteTypeInput,
+ valueAttribute: 'data-value',
+ },
+ {
+ input: this.submitButton,
+ valueAttribute: 'data-submit-text',
+ },
+ ],
};
if (this.closeButton) {
- config.InputSetter.push({
- input: this.closeButton,
- valueAttribute: 'data-close-text',
- }, {
- input: this.closeButton,
- valueAttribute: 'data-close-text',
- inputAttribute: 'data-alternative-text',
- });
+ config.InputSetter.push(
+ {
+ input: this.closeButton,
+ valueAttribute: 'data-close-text',
+ },
+ {
+ input: this.closeButton,
+ valueAttribute: 'data-close-text',
+ inputAttribute: 'data-alternative-text',
+ },
+ );
}
if (this.reopenButton) {
- config.InputSetter.push({
- input: this.reopenButton,
- valueAttribute: 'data-reopen-text',
- }, {
- input: this.reopenButton,
- valueAttribute: 'data-reopen-text',
- inputAttribute: 'data-alternative-text',
- });
+ config.InputSetter.push(
+ {
+ input: this.reopenButton,
+ valueAttribute: 'data-reopen-text',
+ },
+ {
+ input: this.reopenButton,
+ valueAttribute: 'data-reopen-text',
+ inputAttribute: 'data-alternative-text',
+ },
+ );
}
return config;
diff --git a/app/assets/javascripts/commit/image_file.js b/app/assets/javascripts/commit/image_file.js
index 30d9b656fec..d4ecfa4aa93 100644
--- a/app/assets/javascripts/commit/image_file.js
+++ b/app/assets/javascripts/commit/image_file.js
@@ -9,44 +9,60 @@ const viewModes = ['two-up', 'swipe'];
export default class ImageFile {
constructor(file) {
this.file = file;
- this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) {
- return function(deletedWidth, deletedHeight) {
- return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) {
- _this.initViewModes();
-
- // Load two-up view after images are loaded
- // so that we can display the correct width and height information
- const $images = $('.two-up.view img', _this.file);
-
- $images.waitForImages(function() {
- _this.initView('two-up');
+ this.requestImageInfo(
+ $('.two-up.view .frame.deleted img', this.file),
+ (function(_this) {
+ return function(deletedWidth, deletedHeight) {
+ return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(
+ width,
+ height,
+ ) {
+ _this.initViewModes();
+
+ // Load two-up view after images are loaded
+ // so that we can display the correct width and height information
+ const $images = $('.two-up.view img', _this.file);
+
+ $images.waitForImages(function() {
+ _this.initView('two-up');
+ });
});
- });
- };
- })(this));
+ };
+ })(this),
+ );
}
initViewModes() {
const viewMode = viewModes[0];
$('.view-modes', this.file).removeClass('hide');
- $('.view-modes-menu', this.file).on('click', 'li', (function(_this) {
- return function(event) {
- if (!$(event.currentTarget).hasClass('active')) {
- return _this.activateViewMode(event.currentTarget.className);
- }
- };
- })(this));
+ $('.view-modes-menu', this.file).on(
+ 'click',
+ 'li',
+ (function(_this) {
+ return function(event) {
+ if (!$(event.currentTarget).hasClass('active')) {
+ return _this.activateViewMode(event.currentTarget.className);
+ }
+ };
+ })(this),
+ );
return this.activateViewMode(viewMode);
}
activateViewMode(viewMode) {
- $('.view-modes-menu li', this.file).removeClass('active').filter("." + viewMode).addClass('active');
- return $(".view:visible:not(." + viewMode + ")", this.file).fadeOut(200, (function(_this) {
- return function() {
- $(".view." + viewMode, _this.file).fadeIn(200);
- return _this.initView(viewMode);
- };
- })(this));
+ $('.view-modes-menu li', this.file)
+ .removeClass('active')
+ .filter('.' + viewMode)
+ .addClass('active');
+ return $('.view:visible:not(.' + viewMode + ')', this.file).fadeOut(
+ 200,
+ (function(_this) {
+ return function() {
+ $('.view.' + viewMode, _this.file).fadeIn(200);
+ return _this.initView(viewMode);
+ };
+ })(this),
+ );
}
initView(viewMode) {
@@ -63,135 +79,154 @@ export default class ImageFile {
$body.css('user-select', 'none');
});
- $body.off('mouseup').off('mousemove').on('mouseup', function() {
- dragging = false;
- $body.css('user-select', '');
- })
- .on('mousemove', function(e) {
- var left;
- if (!dragging) return;
-
- left = e.pageX - ($offsetEl.offset().left + padding);
-
- callback(e, left);
- });
+ $body
+ .off('mouseup')
+ .off('mousemove')
+ .on('mouseup', function() {
+ dragging = false;
+ $body.css('user-select', '');
+ })
+ .on('mousemove', function(e) {
+ var left;
+ if (!dragging) return;
+
+ left = e.pageX - ($offsetEl.offset().left + padding);
+
+ callback(e, left);
+ });
}
prepareFrames(view) {
var maxHeight, maxWidth;
maxWidth = 0;
maxHeight = 0;
- $('.frame', view).each((function(_this) {
- return function(index, frame) {
- var height, width;
- width = $(frame).width();
- height = $(frame).height();
- maxWidth = width > maxWidth ? width : maxWidth;
- return maxHeight = height > maxHeight ? height : maxHeight;
- };
- })(this)).css({
- width: maxWidth,
- height: maxHeight
- });
+ $('.frame', view)
+ .each(
+ (function(_this) {
+ return function(index, frame) {
+ var height, width;
+ width = $(frame).width();
+ height = $(frame).height();
+ maxWidth = width > maxWidth ? width : maxWidth;
+ return (maxHeight = height > maxHeight ? height : maxHeight);
+ };
+ })(this),
+ )
+ .css({
+ width: maxWidth,
+ height: maxHeight,
+ });
return [maxWidth, maxHeight];
}
views = {
'two-up': function() {
- return $('.two-up.view .wrap', this.file).each((function(_this) {
- return function(index, wrap) {
- $('img', wrap).each(function() {
- var currentWidth;
- currentWidth = $(this).width();
- if (currentWidth > availWidth / 2) {
- return $(this).width(availWidth / 2);
- }
- });
- return _this.requestImageInfo($('img', wrap), function(width, height) {
- $('.image-info .meta-width', wrap).text(width + "px");
- $('.image-info .meta-height', wrap).text(height + "px");
- return $('.image-info', wrap).removeClass('hide');
- });
- };
- })(this));
+ return $('.two-up.view .wrap', this.file).each(
+ (function(_this) {
+ return function(index, wrap) {
+ $('img', wrap).each(function() {
+ var currentWidth;
+ currentWidth = $(this).width();
+ if (currentWidth > availWidth / 2) {
+ return $(this).width(availWidth / 2);
+ }
+ });
+ return _this.requestImageInfo($('img', wrap), function(width, height) {
+ $('.image-info .meta-width', wrap).text(width + 'px');
+ $('.image-info .meta-height', wrap).text(height + 'px');
+ return $('.image-info', wrap).removeClass('hide');
+ });
+ };
+ })(this),
+ );
},
- 'swipe': function() {
+ swipe() {
var maxHeight, maxWidth;
maxWidth = 0;
maxHeight = 0;
- return $('.swipe.view', this.file).each((function(_this) {
- return function(index, view) {
- var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref;
- ref = _this.prepareFrames(view), [maxWidth, maxHeight] = ref;
- $swipeFrame = $('.swipe-frame', view);
- $swipeWrap = $('.swipe-wrap', view);
- $swipeBar = $('.swipe-bar', view);
-
- $swipeFrame.css({
- width: maxWidth + 16,
- height: maxHeight + 28
- });
- $swipeWrap.css({
- width: maxWidth + 1,
- height: maxHeight + 2
- });
- // Set swipeBar left position to match image frame
- $swipeBar.css({
- left: 1
- });
-
- wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
-
- _this.initDraggable($swipeBar, wrapPadding, function(e, left) {
- if (left > 0 && left < $swipeFrame.width() - (wrapPadding * 2)) {
- $swipeWrap.width((maxWidth + 1) - left);
- $swipeBar.css('left', left);
- }
- });
- };
- })(this));
+ return $('.swipe.view', this.file).each(
+ (function(_this) {
+ return function(index, view) {
+ var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref;
+ (ref = _this.prepareFrames(view)), ([maxWidth, maxHeight] = ref);
+ $swipeFrame = $('.swipe-frame', view);
+ $swipeWrap = $('.swipe-wrap', view);
+ $swipeBar = $('.swipe-bar', view);
+
+ $swipeFrame.css({
+ width: maxWidth + 16,
+ height: maxHeight + 28,
+ });
+ $swipeWrap.css({
+ width: maxWidth + 1,
+ height: maxHeight + 2,
+ });
+ // Set swipeBar left position to match image frame
+ $swipeBar.css({
+ left: 1,
+ });
+
+ wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10);
+
+ _this.initDraggable($swipeBar, wrapPadding, function(e, left) {
+ if (left > 0 && left < $swipeFrame.width() - wrapPadding * 2) {
+ $swipeWrap.width(maxWidth + 1 - left);
+ $swipeBar.css('left', left);
+ }
+ });
+ };
+ })(this),
+ );
},
'onion-skin': function() {
var dragTrackWidth, maxHeight, maxWidth;
maxWidth = 0;
maxHeight = 0;
dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width();
- return $('.onion-skin.view', this.file).each((function(_this) {
- return function(index, view) {
- var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false;
- ref = _this.prepareFrames(view), [maxWidth, maxHeight] = ref;
- $frame = $('.onion-skin-frame', view);
- $frameAdded = $('.frame.added', view);
- $track = $('.drag-track', view);
- $dragger = $('.dragger', $track);
-
- $frame.css({
- width: maxWidth + 16,
- height: maxHeight + 28
- });
- $('.swipe-wrap', view).css({
- width: maxWidth + 1,
- height: maxHeight + 2
- });
- $dragger.css({
- left: dragTrackWidth
- });
-
- $frameAdded.css('opacity', 1);
- framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10);
-
- _this.initDraggable($dragger, framePadding, function(e, left) {
- var opacity = left / dragTrackWidth;
-
- if (opacity >= 0 && opacity <= 1) {
- $dragger.css('left', left);
- $frameAdded.css('opacity', opacity);
- }
- });
- };
- })(this));
- }
- }
+ return $('.onion-skin.view', this.file).each(
+ (function(_this) {
+ return function(index, view) {
+ var $frame,
+ $track,
+ $dragger,
+ $frameAdded,
+ framePadding,
+ ref,
+ dragging = false;
+ (ref = _this.prepareFrames(view)), ([maxWidth, maxHeight] = ref);
+ $frame = $('.onion-skin-frame', view);
+ $frameAdded = $('.frame.added', view);
+ $track = $('.drag-track', view);
+ $dragger = $('.dragger', $track);
+
+ $frame.css({
+ width: maxWidth + 16,
+ height: maxHeight + 28,
+ });
+ $('.swipe-wrap', view).css({
+ width: maxWidth + 1,
+ height: maxHeight + 2,
+ });
+ $dragger.css({
+ left: dragTrackWidth,
+ });
+
+ $frameAdded.css('opacity', 1);
+ framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10);
+
+ _this.initDraggable($dragger, framePadding, function(e, left) {
+ var opacity = left / dragTrackWidth;
+
+ if (opacity >= 0 && opacity <= 1) {
+ $dragger.css('left', left);
+ $frameAdded.css('opacity', opacity);
+ }
+ });
+ };
+ })(this),
+ );
+ },
+ };
requestImageInfo(img, callback) {
const domImg = img.get(0);
@@ -199,11 +234,14 @@ export default class ImageFile {
if (domImg.complete) {
return callback.call(this, domImg.naturalWidth, domImg.naturalHeight);
} else {
- return img.on('load', (function(_this) {
- return function() {
- return callback.call(_this, domImg.naturalWidth, domImg.naturalHeight);
- };
- })(this));
+ return img.on(
+ 'load',
+ (function(_this) {
+ return function() {
+ return callback.call(_this, domImg.naturalWidth, domImg.naturalHeight);
+ };
+ })(this),
+ );
}
}
}
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
index 3d89bf1316e..340a93e4e66 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
+++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
@@ -19,11 +19,13 @@ export default () => {
const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view');
if (pipelineTableViewEl) {
- // Update MR and Commits tabs
- pipelineTableViewEl.addEventListener('update-pipelines-count', (event) => {
- if (event.detail.pipelines &&
+ // Update MR and Commits tabs
+ pipelineTableViewEl.addEventListener('update-pipelines-count', event => {
+ if (
+ event.detail.pipelines &&
event.detail.pipelines.count &&
- event.detail.pipelines.count.all) {
+ event.detail.pipelines.count.all
+ ) {
const badge = document.querySelector('.js-pipelines-mr-count');
badge.textContent = event.detail.pipelines.count.all;
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.vue b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
index 4849b0fa3db..a2aa3d197e3 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_table.vue
+++ b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
@@ -1,77 +1,73 @@
<script>
- import PipelinesService from '../../pipelines/services/pipelines_service';
- import PipelineStore from '../../pipelines/stores/pipelines_store';
- import pipelinesMixin from '../../pipelines/mixins/pipelines';
+import PipelinesService from '../../pipelines/services/pipelines_service';
+import PipelineStore from '../../pipelines/stores/pipelines_store';
+import pipelinesMixin from '../../pipelines/mixins/pipelines';
- export default {
- mixins: [
- pipelinesMixin,
- ],
- props: {
- endpoint: {
- type: String,
- required: true,
- },
- helpPagePath: {
- type: String,
- required: true,
- },
- autoDevopsHelpPath: {
- type: String,
- required: true,
- },
- errorStateSvgPath: {
- type: String,
- required: true,
- },
- viewType: {
- type: String,
- required: false,
- default: 'child',
- },
+export default {
+ mixins: [pipelinesMixin],
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
},
+ helpPagePath: {
+ type: String,
+ required: true,
+ },
+ autoDevopsHelpPath: {
+ type: String,
+ required: true,
+ },
+ errorStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ viewType: {
+ type: String,
+ required: false,
+ default: 'child',
+ },
+ },
- data() {
- const store = new PipelineStore();
+ data() {
+ const store = new PipelineStore();
- return {
- store,
- state: store.state,
- };
- },
+ return {
+ store,
+ state: store.state,
+ };
+ },
- computed: {
- shouldRenderTable() {
- return !this.isLoading &&
- this.state.pipelines.length > 0 &&
- !this.hasError;
- },
- shouldRenderErrorState() {
- return this.hasError && !this.isLoading;
- },
+ computed: {
+ shouldRenderTable() {
+ return !this.isLoading && this.state.pipelines.length > 0 && !this.hasError;
},
- created() {
- this.service = new PipelinesService(this.endpoint);
+ shouldRenderErrorState() {
+ return this.hasError && !this.isLoading;
},
- methods: {
- successCallback(resp) {
- // depending of the endpoint the response can either bring a `pipelines` key or not.
- const pipelines = resp.data.pipelines || resp.data;
- this.setCommonData(pipelines);
+ },
+ created() {
+ this.service = new PipelinesService(this.endpoint);
+ },
+ methods: {
+ successCallback(resp) {
+ // depending of the endpoint the response can either bring a `pipelines` key or not.
+ const pipelines = resp.data.pipelines || resp.data;
+ this.setCommonData(pipelines);
- const updatePipelinesEvent = new CustomEvent('update-pipelines-count', {
- detail: {
- pipelines: resp.data,
- },
- });
+ const updatePipelinesEvent = new CustomEvent('update-pipelines-count', {
+ detail: {
+ pipelines: resp.data,
+ },
+ });
- // notifiy to update the count in tabs
- if (this.$el.parentElement) {
- this.$el.parentElement.dispatchEvent(updatePipelinesEvent);
- }
- },
+ // notifiy to update the count in tabs
+ if (this.$el.parentElement) {
+ this.$el.parentElement.dispatchEvent(updatePipelinesEvent);
+ }
},
- };
+ },
+};
</script>
<template>
<div class="content-list pipelines">
diff --git a/app/assets/javascripts/commit_merge_requests.js b/app/assets/javascripts/commit_merge_requests.js
index 102b4ee8463..3a0ab119df6 100644
--- a/app/assets/javascripts/commit_merge_requests.js
+++ b/app/assets/javascripts/commit_merge_requests.js
@@ -50,7 +50,7 @@ export function createContent(mergeRequests) {
if (mergeRequests.length === 0) {
$content.text(s__('Commits|No related merge requests found'));
} else {
- mergeRequests.forEach((mergeRequest) => {
+ mergeRequests.forEach(mergeRequest => {
const $header = createHeader($content.children().length, mergeRequests.length);
const $item = createItem(mergeRequest);
$content.append($header);
@@ -64,8 +64,9 @@ export function createContent(mergeRequests) {
export function fetchCommitMergeRequests() {
const $container = $('.merge-requests');
- axios.get($container.data('projectCommitPath'))
- .then((response) => {
+ axios
+ .get($container.data('projectCommitPath'))
+ .then(response => {
const $content = createContent(response.data);
$container.html($content);
diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js
index 9a3ea7a55b6..54e2589c707 100644
--- a/app/assets/javascripts/commits.js
+++ b/app/assets/javascripts/commits.js
@@ -32,22 +32,31 @@ export default class CommitsList {
if (search === this.lastSearch) return Promise.resolve();
const commitsUrl = `${form.attr('action')}?${form.serialize()}`;
this.content.fadeTo('fast', 0.5);
- const params = form.serializeArray().reduce((acc, obj) => Object.assign(acc, {
- [obj.name]: obj.value,
- }), {});
+ const params = form.serializeArray().reduce(
+ (acc, obj) =>
+ Object.assign(acc, {
+ [obj.name]: obj.value,
+ }),
+ {},
+ );
- return axios.get(form.attr('action'), {
- params,
- })
+ return axios
+ .get(form.attr('action'), {
+ params,
+ })
.then(({ data }) => {
this.lastSearch = search;
this.content.html(data.html);
this.content.fadeTo('fast', 1.0);
// Change url so if user reload a page - search results are saved
- window.history.replaceState({
- page: commitsUrl,
- }, document.title, commitsUrl);
+ window.history.replaceState(
+ {
+ page: commitsUrl,
+ },
+ document.title,
+ commitsUrl,
+ );
})
.catch(() => {
this.content.fadeTo('fast', 1.0);
@@ -75,8 +84,15 @@ export default class CommitsList {
processedData = $processedData.not(`li.js-commit-header[data-day='${loadedShownDayFirst}']`);
// Update commits count in the previous commits header.
- commitsCount += Number($(processedData).nextUntil('li.js-commit-header').first().find('li.commit').length);
- $commitsHeadersLast.find('span.commits-count').text(`${commitsCount} ${pluralize('commit', commitsCount)}`);
+ commitsCount += Number(
+ $(processedData)
+ .nextUntil('li.js-commit-header')
+ .first()
+ .find('li.commit').length,
+ );
+ $commitsHeadersLast
+ .find('span.commits-count')
+ .text(`${commitsCount} ${pluralize('commit', commitsCount)}`);
}
localTimeAgo($processedData.find('.js-timeago'));
diff --git a/app/assets/javascripts/commons/bootstrap.js b/app/assets/javascripts/commons/bootstrap.js
index 50e2949ab55..fba30aea9ae 100644
--- a/app/assets/javascripts/commons/bootstrap.js
+++ b/app/assets/javascripts/commons/bootstrap.js
@@ -5,6 +5,14 @@ import 'bootstrap';
// custom jQuery functions
$.fn.extend({
- disable() { return $(this).prop('disabled', true).addClass('disabled'); },
- enable() { return $(this).prop('disabled', false).removeClass('disabled'); },
+ disable() {
+ return $(this)
+ .prop('disabled', true)
+ .addClass('disabled');
+ },
+ enable() {
+ return $(this)
+ .prop('disabled', false)
+ .removeClass('disabled');
+ },
});
diff --git a/app/assets/javascripts/compare_autocomplete.js b/app/assets/javascripts/compare_autocomplete.js
index 852d71f4e84..37a3ceb5341 100644
--- a/app/assets/javascripts/compare_autocomplete.js
+++ b/app/assets/javascripts/compare_autocomplete.js
@@ -40,7 +40,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = (
},
selectable: true,
filterable: true,
- filterRemote: true,
+ filterRemote: !!$dropdown.data('refsUrl'),
fieldName: $dropdown.data('fieldName'),
filterInput: 'input[type="search"]',
renderRow: function(ref) {
diff --git a/app/assets/javascripts/confirm_danger_modal.js b/app/assets/javascripts/confirm_danger_modal.js
index b0c85c2572e..1000c310e35 100644
--- a/app/assets/javascripts/confirm_danger_modal.js
+++ b/app/assets/javascripts/confirm_danger_modal.js
@@ -13,19 +13,23 @@ function openConfirmDangerModal($form, text) {
$submit.disable();
$input.focus();
- $('.js-confirm-danger-input').off('input').on('input', function handleInput() {
- const confirmText = rstrip($(this).val());
- if (confirmText === confirmTextMatch) {
- $submit.enable();
- } else {
- $submit.disable();
- }
- });
- $('.js-confirm-danger-submit').off('click').on('click', () => $form.submit());
+ $('.js-confirm-danger-input')
+ .off('input')
+ .on('input', function handleInput() {
+ const confirmText = rstrip($(this).val());
+ if (confirmText === confirmTextMatch) {
+ $submit.enable();
+ } else {
+ $submit.disable();
+ }
+ });
+ $('.js-confirm-danger-submit')
+ .off('click')
+ .on('click', () => $form.submit());
}
export default function initConfirmDangerModal() {
- $(document).on('click', '.js-confirm-danger', (e) => {
+ $(document).on('click', '.js-confirm-danger', e => {
e.preventDefault();
const $btn = $(e.target);
const $form = $btn.closest('form');
diff --git a/app/assets/javascripts/contextual_sidebar.js b/app/assets/javascripts/contextual_sidebar.js
index 3a50e73ad85..dff0adba25a 100644
--- a/app/assets/javascripts/contextual_sidebar.js
+++ b/app/assets/javascripts/contextual_sidebar.js
@@ -20,8 +20,11 @@ export default class ContextualSidebar {
}
bindEvents() {
- document.addEventListener('click', (e) => {
- if (!e.target.closest('.nav-sidebar') && (bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md')) {
+ document.addEventListener('click', e => {
+ if (
+ !e.target.closest('.nav-sidebar') &&
+ (bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md')
+ ) {
this.toggleCollapsedSidebar(true);
}
});
diff --git a/app/assets/javascripts/create_item_dropdown.js b/app/assets/javascripts/create_item_dropdown.js
index 8ef9aa7f529..916b190f469 100644
--- a/app/assets/javascripts/create_item_dropdown.js
+++ b/app/assets/javascripts/create_item_dropdown.js
@@ -36,7 +36,7 @@ export default class CreateItemDropdown {
},
selectable: true,
toggleLabel(selected) {
- return (selected && 'id' in selected) ? _.escape(selected.title) : this.defaultToggleLabel;
+ return selected && 'id' in selected ? _.escape(selected.title) : this.defaultToggleLabel;
},
fieldName: this.fieldName,
text(item) {
@@ -46,7 +46,7 @@ export default class CreateItemDropdown {
return _.escape(item.id);
},
onFilter: this.toggleCreateNewButton.bind(this),
- clicked: (options) => {
+ clicked: options => {
options.e.preventDefault();
this.onSelect();
},
@@ -77,9 +77,8 @@ export default class CreateItemDropdown {
getData(term, callback) {
this.getDataOption(term, (data = []) => {
// Ensure the selected item isn't already in the data to avoid duplicates
- const alreadyHasSelectedItem = this.selectedItem && data.some(item =>
- item.id === this.selectedItem.id,
- );
+ const alreadyHasSelectedItem =
+ this.selectedItem && data.some(item => item.id === this.selectedItem.id);
let uniqueData = data;
if (!alreadyHasSelectedItem) {
@@ -106,9 +105,7 @@ export default class CreateItemDropdown {
if (newValue) {
this.selectedItem = this.createNewItemFromValue(newValue);
- this.$dropdownContainer
- .find('.js-dropdown-create-new-item code')
- .text(newValue);
+ this.$dropdownContainer.find('.js-dropdown-create-new-item code').text(newValue);
}
this.toggleFooter(!newValue);
diff --git a/app/assets/javascripts/create_label.js b/app/assets/javascripts/create_label.js
index a999c21b2e9..28ca7d97314 100644
--- a/app/assets/javascripts/create_label.js
+++ b/app/assets/javascripts/create_label.js
@@ -37,7 +37,7 @@ export default class CreateLabelDropdown {
addBinding() {
const self = this;
- this.$colorSuggestions.on('click', function (e) {
+ this.$colorSuggestions.on('click', function(e) {
const $this = $(this);
self.addColorValue(e, $this);
});
@@ -47,7 +47,7 @@ export default class CreateLabelDropdown {
this.$dropdownBack.on('click', this.resetForm.bind(this));
- this.$cancelButton.on('click', function (e) {
+ this.$cancelButton.on('click', function(e) {
e.preventDefault();
e.stopPropagation();
@@ -79,13 +79,9 @@ export default class CreateLabelDropdown {
}
resetForm() {
- this.$newLabelField
- .val('')
- .trigger('change');
+ this.$newLabelField.val('').trigger('change');
- this.$newColorField
- .val('')
- .trigger('change');
+ this.$newColorField.val('').trigger('change');
this.$colorPreview
.css('background-color', '')
@@ -97,31 +93,34 @@ export default class CreateLabelDropdown {
e.preventDefault();
e.stopPropagation();
- Api.newLabel(this.namespacePath, this.projectPath, {
- title: this.$newLabelField.val(),
- color: this.$newColorField.val(),
- }, (label) => {
- this.$newLabelCreateButton.enable();
-
- if (label.message) {
- let errors;
-
- if (typeof label.message === 'string') {
- errors = label.message;
+ Api.newLabel(
+ this.namespacePath,
+ this.projectPath,
+ {
+ title: this.$newLabelField.val(),
+ color: this.$newColorField.val(),
+ },
+ label => {
+ this.$newLabelCreateButton.enable();
+
+ if (label.message) {
+ let errors;
+
+ if (typeof label.message === 'string') {
+ errors = label.message;
+ } else {
+ errors = Object.keys(label.message)
+ .map(key => `${humanize(key)} ${label.message[key].join(', ')}`)
+ .join('<br/>');
+ }
+
+ this.$newLabelError.html(errors).show();
} else {
- errors = Object.keys(label.message).map(key =>
- `${humanize(key)} ${label.message[key].join(', ')}`,
- ).join('<br/>');
- }
+ this.$dropdownBack.trigger('click');
- this.$newLabelError
- .html(errors)
- .show();
- } else {
- this.$dropdownBack.trigger('click');
-
- $(document).trigger('created.label', label);
- }
- });
+ $(document).trigger('created.label', label);
+ }
+ },
+ );
}
}
diff --git a/app/assets/javascripts/cycle_analytics/components/banner.vue b/app/assets/javascripts/cycle_analytics/components/banner.vue
index 410d4873e55..82b0f523d2e 100644
--- a/app/assets/javascripts/cycle_analytics/components/banner.vue
+++ b/app/assets/javascripts/cycle_analytics/components/banner.vue
@@ -1,24 +1,28 @@
<script>
- import iconCycleAnalyticsSplash from 'icons/_icon_cycle_analytics_splash.svg';
+import Icon from '~/vue_shared/components/icon.vue';
+import iconCycleAnalyticsSplash from 'icons/_icon_cycle_analytics_splash.svg';
- export default {
- props: {
- documentationLink: {
- type: String,
- required: true,
- },
+export default {
+ components: {
+ Icon,
+ },
+ props: {
+ documentationLink: {
+ type: String,
+ required: true,
},
- computed: {
- iconCycleAnalyticsSplash() {
- return iconCycleAnalyticsSplash;
- },
+ },
+ computed: {
+ iconCycleAnalyticsSplash() {
+ return iconCycleAnalyticsSplash;
},
- methods: {
- dismissOverviewDialog() {
- this.$emit('dismiss-overview-dialog');
- },
+ },
+ methods: {
+ dismissOverviewDialog() {
+ this.$emit('dismiss-overview-dialog');
},
- };
+ },
+};
</script>
<template>
<div class="landing content-block">
@@ -28,10 +32,9 @@
type="button"
@click="dismissOverviewDialog"
>
- <i
- class="fa fa-times"
- aria-hidden="true">
- </i>
+ <icon
+ name="close"
+ />
</button>
<div
class="svg-container"
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 b626b187651..f6a7d9962eb 100644
--- a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
@@ -1,17 +1,17 @@
<script>
- import tooltip from '../../vue_shared/directives/tooltip';
+import tooltip from '../../vue_shared/directives/tooltip';
- export default {
- directives: {
- tooltip,
+export default {
+ directives: {
+ tooltip,
+ },
+ props: {
+ count: {
+ type: Number,
+ required: true,
},
- props: {
- count: {
- type: Number,
- required: true,
- },
- },
- };
+ },
+};
</script>
<template>
<span
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 a71dcf78103..429fef176c3 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_code_component.vue
@@ -1,25 +1,25 @@
<script>
- import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
- import limitWarning from './limit_warning_component.vue';
- import totalTime from './total_time_component.vue';
+import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+import limitWarning from './limit_warning_component.vue';
+import totalTime from './total_time_component.vue';
- export default {
- components: {
- userAvatarImage,
- limitWarning,
- totalTime,
+export default {
+ components: {
+ userAvatarImage,
+ limitWarning,
+ totalTime,
+ },
+ props: {
+ items: {
+ type: Array,
+ default: () => [],
},
- props: {
- items: {
- type: Array,
- default: () => [],
- },
- stage: {
- type: Object,
- default: () => ({}),
- },
+ stage: {
+ type: Object,
+ default: () => ({}),
},
- };
+ },
+};
</script>
<template>
<div>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
index 312fe75dde4..56e851fa528 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_component.vue
@@ -1,25 +1,25 @@
<script>
- import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
- import limitWarning from './limit_warning_component.vue';
- import totalTime from './total_time_component.vue';
+import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+import limitWarning from './limit_warning_component.vue';
+import totalTime from './total_time_component.vue';
- export default {
- components: {
- userAvatarImage,
- limitWarning,
- totalTime,
+export default {
+ components: {
+ userAvatarImage,
+ limitWarning,
+ totalTime,
+ },
+ props: {
+ items: {
+ type: Array,
+ default: () => [],
},
- props: {
- items: {
- type: Array,
- default: () => [],
- },
- stage: {
- type: Object,
- default: () => ({}),
- },
+ stage: {
+ type: Object,
+ default: () => ({}),
},
- };
+ },
+};
</script>
<template>
<div>
@@ -73,4 +73,3 @@
</ul>
</div>
</template>
-
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 cee294b4ac2..54b9da4983a 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.vue
@@ -1,31 +1,31 @@
<script>
- import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
- import iconCommit from '../svg/icon_commit.svg';
- import limitWarning from './limit_warning_component.vue';
- import totalTime from './total_time_component.vue';
+import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+import iconCommit from '../svg/icon_commit.svg';
+import limitWarning from './limit_warning_component.vue';
+import totalTime from './total_time_component.vue';
- export default {
- components: {
- userAvatarImage,
- totalTime,
- limitWarning,
+export default {
+ components: {
+ userAvatarImage,
+ totalTime,
+ limitWarning,
+ },
+ props: {
+ items: {
+ type: Array,
+ default: () => [],
},
- props: {
- items: {
- type: Array,
- default: () => [],
- },
- stage: {
- type: Object,
- default: () => ({}),
- },
+ stage: {
+ type: Object,
+ default: () => ({}),
},
- computed: {
- iconCommit() {
- return iconCommit;
- },
+ },
+ computed: {
+ iconCommit() {
+ return iconCommit;
},
- };
+ },
+};
</script>
<template>
<div>
@@ -74,4 +74,3 @@
</ul>
</div>
</template>
-
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 d4735d030fc..f9c80d237d7 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.vue
@@ -1,27 +1,27 @@
<script>
- import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
- import limitWarning from './limit_warning_component.vue';
- import totalTime from './total_time_component.vue';
- import icon from '../../vue_shared/components/icon.vue';
+import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+import limitWarning from './limit_warning_component.vue';
+import totalTime from './total_time_component.vue';
+import icon from '../../vue_shared/components/icon.vue';
- export default {
- components: {
- userAvatarImage,
- totalTime,
- limitWarning,
- icon,
+export default {
+ components: {
+ userAvatarImage,
+ totalTime,
+ limitWarning,
+ icon,
+ },
+ props: {
+ items: {
+ type: Array,
+ default: () => [],
},
- props: {
- items: {
- type: Array,
- default: () => [],
- },
- stage: {
- type: Object,
- default: () => ({}),
- },
+ stage: {
+ type: Object,
+ default: () => ({}),
},
- };
+ },
+};
</script>
<template>
<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 22637485c01..e83b66eef86 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
@@ -1,33 +1,33 @@
<script>
- import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
- import iconBranch from '../svg/icon_branch.svg';
- import limitWarning from './limit_warning_component.vue';
- import totalTime from './total_time_component.vue';
- import icon from '../../vue_shared/components/icon.vue';
+import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
+import iconBranch from '../svg/icon_branch.svg';
+import limitWarning from './limit_warning_component.vue';
+import totalTime from './total_time_component.vue';
+import icon from '../../vue_shared/components/icon.vue';
- export default {
- components: {
- userAvatarImage,
- totalTime,
- limitWarning,
- icon,
+export default {
+ components: {
+ userAvatarImage,
+ totalTime,
+ limitWarning,
+ icon,
+ },
+ props: {
+ items: {
+ type: Array,
+ default: () => [],
},
- props: {
- items: {
- type: Array,
- default: () => [],
- },
- stage: {
- type: Object,
- default: () => ({}),
- },
+ stage: {
+ type: Object,
+ default: () => ({}),
},
- computed: {
- iconBranch() {
- return iconBranch;
- },
+ },
+ computed: {
+ iconBranch() {
+ return iconBranch;
},
- };
+ },
+};
</script>
<template>
<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 a0796f299e7..a8196dc879a 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
@@ -1,35 +1,35 @@
<script>
- import iconBuildStatus from '../svg/icon_build_status.svg';
- import iconBranch from '../svg/icon_branch.svg';
- import limitWarning from './limit_warning_component.vue';
- import totalTime from './total_time_component.vue';
- import icon from '../../vue_shared/components/icon.vue';
+import iconBuildStatus from '../svg/icon_build_status.svg';
+import iconBranch from '../svg/icon_branch.svg';
+import limitWarning from './limit_warning_component.vue';
+import totalTime from './total_time_component.vue';
+import icon from '../../vue_shared/components/icon.vue';
- export default {
- components: {
- totalTime,
- limitWarning,
- icon,
+export default {
+ components: {
+ totalTime,
+ limitWarning,
+ icon,
+ },
+ props: {
+ items: {
+ type: Array,
+ default: () => [],
},
- props: {
- items: {
- type: Array,
- default: () => [],
- },
- stage: {
- type: Object,
- default: () => ({}),
- },
+ stage: {
+ type: Object,
+ default: () => ({}),
},
- computed: {
- iconBuildStatus() {
- return iconBuildStatus;
- },
- iconBranch() {
- return iconBranch;
- },
+ },
+ computed: {
+ iconBuildStatus() {
+ return iconBuildStatus;
},
- };
+ iconBranch() {
+ return iconBranch;
+ },
+ },
+};
</script>
<template>
<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 7758bf0cb3f..4db50134208 100644
--- a/app/assets/javascripts/cycle_analytics/components/total_time_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/total_time_component.vue
@@ -1,18 +1,18 @@
<script>
- export default {
- props: {
- time: {
- type: Object,
- required: false,
- default: () => ({}),
- },
+export default {
+ props: {
+ time: {
+ type: Object,
+ required: false,
+ default: () => ({}),
},
- computed: {
- hasData() {
- return Object.keys(this.time).length;
- },
+ },
+ computed: {
+ hasData() {
+ return Object.keys(this.time).length;
},
- };
+ },
+};
</script>
<template>
<span class="total-time">
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
index 1c43fc3cdc7..4de425b48e7 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
@@ -18,7 +18,8 @@ Vue.use(Translate);
export default () => {
const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed';
- new Vue({ // eslint-disable-line no-new
+ // eslint-disable-next-line no-new
+ new Vue({
el: '#cycle-analytics',
name: 'CycleAnalytics',
components: {
@@ -66,14 +67,17 @@ export default () => {
const $dropdown = $('.js-ca-dropdown');
const $label = $dropdown.find('.dropdown-label');
- $dropdown.find('li a').off('click').on('click', (e) => {
- e.preventDefault();
- const $target = $(e.currentTarget);
- this.startDate = $target.data('value');
+ $dropdown
+ .find('li a')
+ .off('click')
+ .on('click', e => {
+ e.preventDefault();
+ const $target = $(e.currentTarget);
+ this.startDate = $target.data('value');
- $label.text($target.text().trim());
- this.fetchCycleAnalyticsData({ startDate: this.startDate });
- });
+ $label.text($target.text().trim());
+ this.fetchCycleAnalyticsData({ startDate: this.startDate });
+ });
},
fetchCycleAnalyticsData(options) {
const fetchOptions = options || { startDate: this.startDate };
@@ -82,7 +86,7 @@ export default () => {
this.service
.fetchCycleAnalyticsData(fetchOptions)
- .then((response) => {
+ .then(response => {
this.store.setCycleAnalyticsData(response);
this.selectDefaultStage();
this.initDropdown();
@@ -115,7 +119,7 @@ export default () => {
stage,
startDate: this.startDate,
})
- .then((response) => {
+ .then(response => {
this.isEmptyStage = !response.events.length;
this.store.setStageEvents(response.events, stage);
this.isLoadingStage = false;
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js
index 4cf416c50e5..a0426301a0a 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_service.js
@@ -18,10 +18,7 @@ export default class CycleAnalyticsService {
}
fetchStageData(options) {
- const {
- stage,
- startDate,
- } = options;
+ const { stage, startDate } = options;
return this.axios
.get(`events/${stage.name}.json`, {
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js
index a8cd8c20f8f..18fb57c8b4f 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_store.js
@@ -5,13 +5,27 @@ import { dasherize } from '../lib/utils/text_utility';
import DEFAULT_EVENT_OBJECTS from './default_event_objects';
const EMPTY_STAGE_TEXTS = {
- issue: __('The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.'),
- plan: __('The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.'),
- code: __('The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.'),
- test: __('The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.'),
- review: __('The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.'),
- staging: __('The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.'),
- production: __('The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.'),
+ issue: __(
+ 'The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.',
+ ),
+ plan: __(
+ 'The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.',
+ ),
+ code: __(
+ 'The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.',
+ ),
+ test: __(
+ 'The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.',
+ ),
+ review: __(
+ 'The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.',
+ ),
+ staging: __(
+ 'The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.',
+ ),
+ production: __(
+ 'The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.',
+ ),
};
export default {
@@ -31,11 +45,11 @@ export default {
newData.stages = data.stats || [];
newData.summary = data.summary || [];
- newData.summary.forEach((item) => {
+ newData.summary.forEach(item => {
item.value = item.value || '-';
});
- newData.stages.forEach((item) => {
+ newData.stages.forEach(item => {
const stageSlug = dasherize(item.name.toLowerCase());
item.active = false;
item.isUserAllowed = data.permissions[stageSlug];
@@ -53,7 +67,7 @@ export default {
this.state.hasError = state;
},
deactivateAllStages() {
- this.state.stages.forEach((stage) => {
+ this.state.stages.forEach(stage => {
stage.active = false;
});
},
@@ -67,7 +81,7 @@ export default {
decorateEvents(events, stage) {
const newEvents = [];
- events.forEach((item) => {
+ events.forEach(item => {
if (!item) return;
const eventItem = Object.assign({}, DEFAULT_EVENT_OBJECTS[stage.slug], item);
diff --git a/app/assets/javascripts/deploy_keys/components/app.vue b/app/assets/javascripts/deploy_keys/components/app.vue
index aa52f120fe7..3589599986d 100644
--- a/app/assets/javascripts/deploy_keys/components/app.vue
+++ b/app/assets/javascripts/deploy_keys/components/app.vue
@@ -95,8 +95,10 @@ export default {
.catch(() => new Flash(s__('DeployKeys|Error enabling deploy key')));
},
disableKey(deployKey, callback) {
- // eslint-disable-next-line no-alert
- if (window.confirm(s__('DeployKeys|You are going to remove this deploy key. Are you sure?'))) {
+ if (
+ // eslint-disable-next-line no-alert
+ window.confirm(s__('DeployKeys|You are going to remove this deploy key. Are you sure?'))
+ ) {
this.service
.disableKey(deployKey.id)
.then(this.fetchKeys)
diff --git a/app/assets/javascripts/deploy_keys/service/index.js b/app/assets/javascripts/deploy_keys/service/index.js
index 9dc3b21f6f6..268a37008c5 100644
--- a/app/assets/javascripts/deploy_keys/service/index.js
+++ b/app/assets/javascripts/deploy_keys/service/index.js
@@ -8,17 +8,14 @@ export default class DeployKeysService {
}
getKeys() {
- return this.axios.get()
- .then(response => response.data);
+ return this.axios.get().then(response => response.data);
}
enableKey(id) {
- return this.axios.put(`${id}/enable`)
- .then(response => response.data);
+ return this.axios.put(`${id}/enable`).then(response => response.data);
}
disableKey(id) {
- return this.axios.put(`${id}/disable`)
- .then(response => response.data);
+ return this.axios.put(`${id}/disable`).then(response => response.data);
}
}
diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js
index a044fc1ab42..245f1a7c558 100644
--- a/app/assets/javascripts/diff.js
+++ b/app/assets/javascripts/diff.js
@@ -21,9 +21,12 @@ export default class Diff {
});
const tab = document.getElementById('diffs');
- if (!tab || (tab && tab.dataset && tab.dataset.isLocked !== '')) FilesCommentButton.init($diffFile);
+ if (!tab || (tab && tab.dataset && tab.dataset.isLocked !== ''))
+ FilesCommentButton.init($diffFile);
- const firstFile = $('.files').first().get(0);
+ const firstFile = $('.files')
+ .first()
+ .get(0);
const canCreateNote = firstFile && firstFile.hasAttribute('data-can-create-note');
$diffFile.each((index, file) => imageDiffHelper.initImageDiff(file, canCreateNote));
@@ -73,9 +76,10 @@ export default class Diff {
const view = file.data('view');
const params = { since, to, bottom, offset, unfold, view };
- axios.get(link, { params })
- .then(({ data }) => $target.parent().replaceWith(data))
- .catch(() => flash(__('An error occurred while loading diff')));
+ axios
+ .get(link, { params })
+ .then(({ data }) => $target.parent().replaceWith(data))
+ .catch(() => flash(__('An error occurred while loading diff')));
}
openAnchoredDiff(cb) {
diff --git a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
index 87621761500..4ae4ceabc21 100644
--- a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
+++ b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
@@ -18,52 +18,56 @@ const CommentAndResolveBtn = Vue.extend({
};
},
computed: {
- showButton: function () {
+ showButton: function() {
if (this.discussion) {
return this.discussion.isResolvable();
} else {
return false;
}
},
- isDiscussionResolved: function () {
+ isDiscussionResolved: function() {
return this.discussion.isResolved();
},
- buttonText: function () {
+ buttonText: function() {
if (this.isDiscussionResolved) {
if (this.textareaIsEmpty) {
- return "Unresolve discussion";
+ return 'Unresolve discussion';
} else {
- return "Comment & unresolve discussion";
+ return 'Comment & unresolve discussion';
}
} else {
if (this.textareaIsEmpty) {
- return "Resolve discussion";
+ return 'Resolve discussion';
} else {
- return "Comment & resolve discussion";
+ return 'Comment & resolve discussion';
}
}
- }
+ },
},
created() {
if (this.discussionId) {
this.discussion = CommentsStore.state[this.discussionId];
}
},
- mounted: function () {
+ mounted: function() {
if (!this.discussionId) return;
- const $textarea = $(`.js-discussion-note-form[data-discussion-id=${this.discussionId}] .note-textarea`);
+ const $textarea = $(
+ `.js-discussion-note-form[data-discussion-id=${this.discussionId}] .note-textarea`,
+ );
this.textareaIsEmpty = $textarea.val() === '';
$textarea.on('input.comment-and-resolve-btn', () => {
this.textareaIsEmpty = $textarea.val() === '';
});
},
- destroyed: function () {
+ destroyed: function() {
if (!this.discussionId) return;
- $(`.js-discussion-note-form[data-discussion-id=${this.discussionId}] .note-textarea`).off('input.comment-and-resolve-btn');
- }
+ $(`.js-discussion-note-form[data-discussion-id=${this.discussionId}] .note-textarea`).off(
+ 'input.comment-and-resolve-btn',
+ );
+ },
});
Vue.component('comment-and-resolve-btn', CommentAndResolveBtn);
diff --git a/app/assets/javascripts/diff_notes/components/diff_note_avatars.js b/app/assets/javascripts/diff_notes/components/diff_note_avatars.js
index 5528d2a542b..5bdeaaade68 100644
--- a/app/assets/javascripts/diff_notes/components/diff_note_avatars.js
+++ b/app/assets/javascripts/diff_notes/components/diff_note_avatars.js
@@ -83,7 +83,11 @@ const DiffNoteAvatars = Vue.extend({
this.addNoCommentClass();
this.setDiscussionVisible();
- this.lineType = $(this.$el).closest('.diff-line-num').hasClass('old_line') ? 'old' : 'new';
+ this.lineType = $(this.$el)
+ .closest('.diff-line-num')
+ .hasClass('old_line')
+ ? 'old'
+ : 'new';
});
$(document).on('toggle.comments', () => {
@@ -113,20 +117,30 @@ const DiffNoteAvatars = Vue.extend({
addNoCommentClass() {
const { notesCount } = this;
- $(this.$el).closest('.js-avatar-container')
+ $(this.$el)
+ .closest('.js-avatar-container')
.toggleClass('no-comment-btn', notesCount > 0)
.nextUntil('.js-avatar-container')
.toggleClass('no-comment-btn', notesCount > 0);
},
toggleDiscussionsToggleState() {
- const $notesHolders = $(this.$el).closest('.code').find('.notes_holder');
+ const $notesHolders = $(this.$el)
+ .closest('.code')
+ .find('.notes_holder');
const $visibleNotesHolders = $notesHolders.filter(':visible');
- const $toggleDiffCommentsBtn = $(this.$el).closest('.diff-file').find('.js-toggle-diff-comments');
-
- $toggleDiffCommentsBtn.toggleClass('active', $notesHolders.length === $visibleNotesHolders.length);
+ const $toggleDiffCommentsBtn = $(this.$el)
+ .closest('.diff-file')
+ .find('.js-toggle-diff-comments');
+
+ $toggleDiffCommentsBtn.toggleClass(
+ 'active',
+ $notesHolders.length === $visibleNotesHolders.length,
+ );
},
setDiscussionVisible() {
- this.isVisible = $(`.diffs .notes[data-discussion-id="${this.discussion.id}"]`).is(':visible');
+ this.isVisible = $(`.diffs .notes[data-discussion-id="${this.discussion.id}"]`).is(
+ ':visible',
+ );
},
getTooltipText(note) {
return `${note.authorName}: ${note.noteTruncated}`;
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 2b78bb58735..c0c21416275 100644
--- a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
+++ b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
@@ -14,24 +14,24 @@ const JumpToDiscussion = Vue.extend({
required: true,
},
},
- data: function () {
+ data: function() {
return {
discussions: CommentsStore.state,
discussion: {},
};
},
computed: {
- buttonText: function () {
+ buttonText: function() {
if (this.discussionId) {
return 'Jump to next unresolved discussion';
} else {
return 'Jump to first unresolved discussion';
}
},
- allResolved: function () {
+ allResolved: function() {
return this.unresolvedDiscussionCount === 0;
},
- showButton: function () {
+ showButton: function() {
if (this.discussionId) {
if (this.unresolvedDiscussionCount > 1) {
return true;
@@ -42,7 +42,7 @@ const JumpToDiscussion = Vue.extend({
return this.unresolvedDiscussionCount >= 1;
}
},
- lastResolvedId: function () {
+ lastResolvedId: function() {
let lastId;
for (const discussionId in this.discussions) {
const discussion = this.discussions[discussionId];
@@ -52,13 +52,13 @@ const JumpToDiscussion = Vue.extend({
}
}
return lastId;
- }
+ },
},
created() {
this.discussion = this.discussions[this.discussionId];
},
methods: {
- jumpToNextUnresolvedDiscussion: function () {
+ jumpToNextUnresolvedDiscussion: function() {
let discussionsSelector;
let discussionIdsInScope;
let firstUnresolvedDiscussionId;
@@ -68,9 +68,11 @@ const JumpToDiscussion = Vue.extend({
let jumpToFirstDiscussion = !this.discussionId;
const discussionIdsForElements = function(elements) {
- return elements.map(function() {
- return $(this).attr('data-discussion-id');
- }).toArray();
+ return elements
+ .map(function() {
+ return $(this).attr('data-discussion-id');
+ })
+ .toArray();
};
const { discussions } = this;
@@ -144,8 +146,7 @@ const JumpToDiscussion = Vue.extend({
if (!discussion.isResolved()) {
nextUnresolvedDiscussionId = discussionId;
break;
- }
- else {
+ } else {
continue;
}
}
@@ -175,9 +176,9 @@ const JumpToDiscussion = Vue.extend({
// Resolved discussions are hidden in the diffs tab by default.
// If they are marked unresolved on the notes tab, they will still be hidden on the diffs tab.
// When jumping between unresolved discussions on the diffs tab, we show them.
- $target.closest(".content").show();
+ $target.closest('.content').show();
- const $notesHolder = $target.closest("tr.notes_holder");
+ const $notesHolder = $target.closest('tr.notes_holder');
// Image diff discussions does not use notes_holder
// so we should keep original $target value in those cases
@@ -194,7 +195,7 @@ const JumpToDiscussion = Vue.extend({
prevEl = $target.prev();
// If the discussion doesn't have 4 lines above it, we'll have to do with fewer.
- if (!prevEl.hasClass("line_holder")) {
+ if (!prevEl.hasClass('line_holder')) {
break;
}
@@ -203,9 +204,9 @@ const JumpToDiscussion = Vue.extend({
}
$.scrollTo($target, {
- offset: -150
+ offset: -150,
});
- }
+ },
},
});
diff --git a/app/assets/javascripts/diff_notes/components/resolve_count.js b/app/assets/javascripts/diff_notes/components/resolve_count.js
index eb539c6b348..d8b056096f4 100644
--- a/app/assets/javascripts/diff_notes/components/resolve_count.js
+++ b/app/assets/javascripts/diff_notes/components/resolve_count.js
@@ -13,17 +13,17 @@ window.ResolveCount = Vue.extend({
required: true,
},
},
- data: function () {
+ data: function() {
return {
- discussions: CommentsStore.state
+ discussions: CommentsStore.state,
};
},
computed: {
- allResolved: function () {
+ allResolved: function() {
return this.resolvedDiscussionCount === this.discussionCount;
},
resolvedCountText() {
return this.discussionCount === 1 ? 'discussion' : 'discussions';
- }
- }
+ },
+ },
});
diff --git a/app/assets/javascripts/diff_notes/mixins/discussion.js b/app/assets/javascripts/diff_notes/mixins/discussion.js
index 7589f9dd6e0..dea64dca132 100644
--- a/app/assets/javascripts/diff_notes/mixins/discussion.js
+++ b/app/assets/javascripts/diff_notes/mixins/discussion.js
@@ -2,10 +2,10 @@
const DiscussionMixins = {
computed: {
- discussionCount: function () {
+ discussionCount: function() {
return Object.keys(this.discussions).length;
},
- resolvedDiscussionCount: function () {
+ resolvedDiscussionCount: function() {
let resolvedCount = 0;
for (const discussionId in this.discussions) {
@@ -18,7 +18,7 @@ const DiscussionMixins = {
return resolvedCount;
},
- unresolvedDiscussionCount: function () {
+ unresolvedDiscussionCount: function() {
let unresolvedCount = 0;
for (const discussionId in this.discussions) {
@@ -30,8 +30,8 @@ const DiscussionMixins = {
}
return unresolvedCount;
- }
- }
+ },
+ },
};
export default DiscussionMixins;
diff --git a/app/assets/javascripts/diff_notes/models/discussion.js b/app/assets/javascripts/diff_notes/models/discussion.js
index 787e6d8855f..daf61e5d467 100644
--- a/app/assets/javascripts/diff_notes/models/discussion.js
+++ b/app/assets/javascripts/diff_notes/models/discussion.js
@@ -6,22 +6,22 @@ import Vue from 'vue';
import { localTimeAgo } from '../../lib/utils/datetime_utility';
class DiscussionModel {
- constructor (discussionId) {
+ constructor(discussionId) {
this.id = discussionId;
this.notes = {};
this.loading = false;
this.canResolve = false;
}
- createNote (noteObj) {
+ createNote(noteObj) {
Vue.set(this.notes, noteObj.noteId, new NoteModel(this.id, noteObj));
}
- deleteNote (noteId) {
+ deleteNote(noteId) {
Vue.delete(this.notes, noteId);
}
- getNote (noteId) {
+ getNote(noteId) {
return this.notes[noteId];
}
@@ -29,7 +29,7 @@ class DiscussionModel {
return Object.keys(this.notes).length;
}
- isResolved () {
+ isResolved() {
for (const noteId in this.notes) {
const note = this.notes[noteId];
@@ -40,7 +40,7 @@ class DiscussionModel {
return true;
}
- resolveAllNotes (resolved_by) {
+ resolveAllNotes(resolved_by) {
for (const noteId in this.notes) {
const note = this.notes[noteId];
@@ -51,7 +51,7 @@ class DiscussionModel {
}
}
- unResolveAllNotes () {
+ unResolveAllNotes() {
for (const noteId in this.notes) {
const note = this.notes[noteId];
@@ -62,7 +62,7 @@ class DiscussionModel {
}
}
- updateHeadline (data) {
+ updateHeadline(data) {
const discussionSelector = `.discussion[data-discussion-id="${this.id}"]`;
const $discussionHeadline = $(`${discussionSelector} .js-discussion-headline`);
@@ -79,7 +79,7 @@ class DiscussionModel {
}
}
- isResolvable () {
+ isResolvable() {
if (!this.canResolve) {
return false;
}
diff --git a/app/assets/javascripts/diff_notes/stores/comments.js b/app/assets/javascripts/diff_notes/stores/comments.js
index d012cd02d10..060bb044f78 100644
--- a/app/assets/javascripts/diff_notes/stores/comments.js
+++ b/app/assets/javascripts/diff_notes/stores/comments.js
@@ -5,10 +5,10 @@ import Vue from 'vue';
window.CommentsStore = {
state: {},
- get: function (discussionId, noteId) {
+ get: function(discussionId, noteId) {
return this.state[discussionId].getNote(noteId);
},
- createDiscussion: function (discussionId, canResolve) {
+ createDiscussion: function(discussionId, canResolve) {
let discussion = this.state[discussionId];
if (!this.state[discussionId]) {
discussion = new DiscussionModel(discussionId);
@@ -21,18 +21,18 @@ window.CommentsStore = {
return discussion;
},
- create: function (noteObj) {
+ create: function(noteObj) {
const discussion = this.createDiscussion(noteObj.discussionId);
discussion.createNote(noteObj);
},
- update: function (discussionId, noteId, resolved, resolved_by) {
+ update: function(discussionId, noteId, resolved, resolved_by) {
const discussion = this.state[discussionId];
const note = discussion.getNote(noteId);
note.resolved = resolved;
note.resolved_by = resolved_by;
},
- delete: function (discussionId, noteId) {
+ delete: function(discussionId, noteId) {
const discussion = this.state[discussionId];
discussion.deleteNote(noteId);
@@ -40,7 +40,7 @@ window.CommentsStore = {
Vue.delete(this.state, discussionId);
}
},
- unresolvedDiscussionIds: function () {
+ unresolvedDiscussionIds: function() {
const ids = [];
for (const discussionId in this.state) {
@@ -52,5 +52,5 @@ window.CommentsStore = {
}
return ids;
- }
+ },
};
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index edca45f22f9..a8d615dd8f0 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -41,6 +41,11 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ assignedDiscussions: false,
+ };
+ },
computed: {
...mapState({
isLoading: state => state.diffs.isLoading,
@@ -58,9 +63,9 @@ export default {
plainDiffPath: state => state.diffs.plainDiffPath,
emailPatchPath: state => state.diffs.emailPatchPath,
}),
- ...mapState('diffs', ['showTreeList']),
+ ...mapState('diffs', ['showTreeList', 'isLoading']),
...mapGetters('diffs', ['isParallelView']),
- ...mapGetters(['isNotesFetched', 'discussionsStructuredByLineCode']),
+ ...mapGetters(['isNotesFetched', 'getNoteableData']),
targetBranch() {
return {
branchName: this.targetBranchName,
@@ -147,11 +152,12 @@ export default {
}
},
setDiscussions() {
- if (this.isNotesFetched) {
+ if (this.isNotesFetched && !this.assignedDiscussions && !this.isLoading) {
requestIdleCallback(
- () => {
- this.assignDiscussionsToDiff(this.discussionsStructuredByLineCode);
- },
+ () =>
+ this.assignDiscussionsToDiff().then(() => {
+ this.assignedDiscussions = true;
+ }),
{ timeout: 1000 },
);
}
diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
index 993206b2e73..23d0bad2ecb 100644
--- a/app/assets/javascripts/diffs/components/commit_item.vue
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -43,7 +43,9 @@ export default {
return (this.commit.author && this.commit.author.name) || this.commit.authorName;
},
authorUrl() {
- return (this.commit.author && this.commit.author.webUrl) || `mailto:${this.commit.authorEmail}`;
+ return (
+ (this.commit.author && this.commit.author.webUrl) || `mailto:${this.commit.authorEmail}`
+ );
},
authorAvatar() {
return (this.commit.author && this.commit.author.avatarUrl) || this.commit.authorGravatarUrl;
diff --git a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
index c3acc352d5e..f4b333f3700 100644
--- a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
+++ b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
@@ -115,7 +115,7 @@ export default {
<span>
{{ selectedVersionName }}
</span>
- <Icon
+ <icon
:size="12"
name="angle-down"
class="position-absolute"
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index 4e04e50c52a..958e57c5652 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -29,7 +29,7 @@ export default {
},
computed: {
...mapState('diffs', ['currentDiffFileId']),
- ...mapGetters(['isNotesFetched', 'discussionsStructuredByLineCode']),
+ ...mapGetters(['isNotesFetched']),
isCollapsed() {
return this.file.collapsed || false;
},
@@ -46,10 +46,10 @@ export default {
showExpandMessage() {
return (
this.isCollapsed ||
- !this.file.highlightedDiffLines &&
- !this.isLoadingCollapsedDiff &&
- !this.file.tooLarge &&
- this.file.text
+ (!this.file.highlightedDiffLines &&
+ !this.isLoadingCollapsedDiff &&
+ !this.file.tooLarge &&
+ this.file.text)
);
},
showLoadingIcon() {
@@ -79,7 +79,7 @@ export default {
.then(() => {
requestIdleCallback(
() => {
- this.assignDiscussionsToDiff(this.discussionsStructuredByLineCode);
+ this.assignDiscussionsToDiff();
},
{ timeout: 1000 },
);
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index 15b37243030..dcf1057eb84 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -20,6 +20,11 @@ export default {
Tooltip,
},
props: {
+ discussionPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
diffFile: {
type: Object,
required: true,
@@ -65,8 +70,7 @@ export default {
if (this.diffFile.submodule) {
return this.diffFile.submoduleTreeUrl || this.diffFile.submoduleLink;
}
-
- return `#${this.diffFile.fileHash}`;
+ return this.discussionPath;
},
filePath() {
if (this.diffFile.submodule) {
@@ -152,7 +156,7 @@ export default {
v-once
ref="titleWrapper"
:href="titleLink"
- class="append-right-4"
+ class="append-right-4 js-title-wrapper"
>
<file-icon
:file-name="filePath"
diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue
index cfe4273742f..34e836a570a 100644
--- a/app/assets/javascripts/diffs/components/tree_list.vue
+++ b/app/assets/javascripts/diffs/components/tree_list.vue
@@ -1,17 +1,30 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
+import { TooltipDirective as Tooltip } from '@gitlab-org/gitlab-ui';
+import { convertPermissionToBoolean } 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';
+const treeListStorageKey = 'mr_diff_tree_list';
+
export default {
+ directives: {
+ Tooltip,
+ },
components: {
Icon,
FileRow,
},
data() {
+ const treeListStored = localStorage.getItem(treeListStorageKey);
+ const renderTreeList = treeListStored !== null ?
+ convertPermissionToBoolean(treeListStored) : true;
+
return {
search: '',
+ renderTreeList,
+ focusSearch: false,
};
},
computed: {
@@ -20,15 +33,35 @@ export default {
filteredTreeList() {
const search = this.search.toLowerCase().trim();
- if (search === '') return this.tree;
+ if (search === '') return this.renderTreeList ? this.tree : this.allBlobs;
return this.allBlobs.filter(f => f.name.toLowerCase().indexOf(search) >= 0);
},
+ rowDisplayTextKey() {
+ if (this.renderTreeList && this.search.trim() === '') {
+ return 'name';
+ }
+
+ return 'path';
+ },
},
methods: {
...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile']),
clearSearch() {
this.search = '';
+ this.toggleFocusSearch(false);
+ },
+ toggleRenderTreeList(toggle) {
+ this.renderTreeList = toggle;
+ localStorage.setItem(treeListStorageKey, this.renderTreeList);
+ },
+ toggleFocusSearch(toggle) {
+ this.focusSearch = toggle;
+ },
+ blurSearch() {
+ if (this.search.trim() === '') {
+ this.toggleFocusSearch(false);
+ }
},
},
FileRowStats,
@@ -37,28 +70,67 @@ export default {
<template>
<div class="tree-list-holder d-flex flex-column">
- <div class="append-bottom-8 position-relative tree-list-search">
- <icon
- name="search"
- class="position-absolute tree-list-icon"
- />
- <input
- v-model="search"
- :placeholder="s__('MergeRequest|Filter files')"
- type="search"
- class="form-control"
- />
- <button
- v-show="search"
- :aria-label="__('Clear search')"
- type="button"
- class="position-absolute tree-list-icon tree-list-clear-icon border-0 p-0"
- @click="clearSearch"
- >
+ <div class="append-bottom-8 position-relative tree-list-search d-flex">
+ <div class="flex-fill d-flex">
<icon
- name="close"
+ 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)"
+ @blur="blurSearch"
/>
- </button>
+ <button
+ v-show="search"
+ :aria-label="__('Clear search')"
+ type="button"
+ class="position-absolute bg-transparent tree-list-icon tree-list-clear-icon border-0 p-0"
+ @click="clearSearch"
+ >
+ <icon
+ name="close"
+ />
+ </button>
+ </div>
+ <div
+ v-show="!focusSearch"
+ class="btn-group prepend-left-8 tree-list-view-toggle"
+ >
+ <button
+ v-tooltip.hover
+ :aria-label="__('List view')"
+ :title="__('List view')"
+ :class="{
+ active: !renderTreeList
+ }"
+ class="btn btn-default pt-0 pb-0 d-flex align-items-center"
+ type="button"
+ @click="toggleRenderTreeList(false)"
+ >
+ <icon
+ name="hamburger"
+ />
+ </button>
+ <button
+ v-tooltip.hover
+ :aria-label="__('Tree view')"
+ :title="__('Tree view')"
+ :class="{
+ active: renderTreeList
+ }"
+ class="btn btn-default pt-0 pb-0 d-flex align-items-center"
+ type="button"
+ @click="toggleRenderTreeList(true)"
+ >
+ <icon
+ name="file-tree"
+ />
+ </button>
+ </div>
</div>
<div
class="tree-list-scroll"
@@ -72,6 +144,8 @@ export default {
:hide-extra-on-tree="true"
:extra-component="$options.FileRowStats"
:show-changed-icon="true"
+ :display-text-key="rowDisplayTextKey"
+ :should-truncate-start="true"
@toggleTreeOpen="toggleTreeOpen"
@clickFile="scrollToFile"
/>
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 1e0b27b538d..ca8ae605cb4 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -5,7 +5,6 @@ import createFlash from '~/flash';
import { s__ } from '~/locale';
import { handleLocationHash, historyPushState } from '~/lib/utils/common_utils';
import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility';
-import { reduceDiscussionsToLineCodes } from '../../notes/stores/utils';
import { getDiffPositionByLineCode, getNoteFormData } from './utils';
import * as types from './mutation_types';
import {
@@ -36,18 +35,17 @@ export const fetchDiffFiles = ({ state, commit }) => {
// This is adding line discussions to the actual lines in the diff tree
// once for parallel and once for inline mode
-export const assignDiscussionsToDiff = ({ state, commit }, allLineDiscussions) => {
+export const assignDiscussionsToDiff = (
+ { commit, state, rootState },
+ discussions = rootState.notes.discussions,
+) => {
const diffPositionByLineCode = getDiffPositionByLineCode(state.diffFiles);
- Object.values(allLineDiscussions).forEach(discussions => {
- if (discussions.length > 0) {
- const { fileHash } = discussions[0];
- commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, {
- fileHash,
- discussions,
- diffPositionByLineCode,
- });
- }
+ discussions.filter(discussion => discussion.diff_discussion).forEach(discussion => {
+ commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, {
+ discussion,
+ diffPositionByLineCode,
+ });
});
};
@@ -190,9 +188,7 @@ export const saveDiffDiscussion = ({ dispatch }, { note, formData }) => {
return dispatch('saveNote', postData, { root: true })
.then(result => dispatch('updateDiscussion', result.discussion, { root: true }))
- .then(discussion =>
- dispatch('assignDiscussionsToDiff', reduceDiscussionsToLineCodes([discussion])),
- )
+ .then(discussion => dispatch('assignDiscussionsToDiff', [discussion]))
.catch(() => createFlash(s__('MergeRequests|Saving the comment failed')));
};
diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js
index ae8930c8968..1c5c35071de 100644
--- a/app/assets/javascripts/diffs/store/modules/diff_state.js
+++ b/app/assets/javascripts/diffs/store/modules/diff_state.js
@@ -1,5 +1,6 @@
import Cookies from 'js-cookie';
import { getParameterValues } from '~/lib/utils/url_utility';
+import bp from '~/breakpoints';
import { INLINE_DIFF_VIEW_TYPE, DIFF_VIEW_COOKIE_NAME, MR_TREE_SHOW_KEY } from '../../constants';
const viewTypeFromQueryString = getParameterValues('view')[0];
@@ -20,6 +21,7 @@ export default () => ({
diffViewType: viewTypeFromQueryString || viewTypeFromCookie || defaultViewType,
tree: [],
treeEntries: {},
- showTreeList: storedTreeShow === null ? true : storedTreeShow === 'true',
+ showTreeList:
+ storedTreeShow === null ? bp.getBreakpointSize() !== 'xs' : storedTreeShow === 'true',
currentDiffFileId: '',
});
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 0b4485ecdb5..5a8aebd2086 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -90,53 +90,67 @@ export default {
}));
},
- [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, discussions, diffPositionByLineCode }) {
- const selectedFile = state.diffFiles.find(f => f.fileHash === fileHash);
- const firstDiscussion = discussions[0];
- const isDiffDiscussion = firstDiscussion.diff_discussion;
- const hasLineCode = firstDiscussion.line_code;
- const diffPosition = diffPositionByLineCode[firstDiscussion.line_code];
-
- if (
- selectedFile &&
- isDiffDiscussion &&
- hasLineCode &&
- diffPosition &&
+ [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { discussion, diffPositionByLineCode }) {
+ const { latestDiff } = state;
+
+ const discussionLineCode = discussion.line_code;
+ const fileHash = discussion.diff_file.file_hash;
+ const lineCheck = ({ lineCode }) =>
+ lineCode === discussionLineCode &&
isDiscussionApplicableToLine({
- discussion: firstDiscussion,
- diffPosition,
- latestDiff: state.latestDiff,
- })
- ) {
- const targetLine = selectedFile.parallelDiffLines.find(
- line =>
- (line.left && line.left.lineCode === firstDiscussion.line_code) ||
- (line.right && line.right.lineCode === firstDiscussion.line_code),
- );
- if (targetLine) {
- if (targetLine.left && targetLine.left.lineCode === firstDiscussion.line_code) {
- Object.assign(targetLine.left, {
- discussions,
- });
- } else {
- Object.assign(targetLine.right, {
- discussions,
+ discussion,
+ diffPosition: diffPositionByLineCode[lineCode],
+ latestDiff,
+ });
+
+ state.diffFiles = state.diffFiles.map(diffFile => {
+ if (diffFile.fileHash === fileHash) {
+ const file = { ...diffFile };
+
+ if (file.highlightedDiffLines) {
+ file.highlightedDiffLines = file.highlightedDiffLines.map(line => {
+ if (lineCheck(line)) {
+ return {
+ ...line,
+ discussions: line.discussions.concat(discussion),
+ };
+ }
+
+ return line;
});
}
- }
-
- if (selectedFile.highlightedDiffLines) {
- const targetInlineLine = selectedFile.highlightedDiffLines.find(
- line => line.lineCode === firstDiscussion.line_code,
- );
- if (targetInlineLine) {
- Object.assign(targetInlineLine, {
- discussions,
+ if (file.parallelDiffLines) {
+ file.parallelDiffLines = file.parallelDiffLines.map(line => {
+ const left = line.left && lineCheck(line.left);
+ const right = line.right && lineCheck(line.right);
+
+ if (left || right) {
+ return {
+ left: {
+ ...line.left,
+ discussions: left ? line.left.discussions.concat(discussion) : [],
+ },
+ right: {
+ ...line.right,
+ discussions: right ? line.right.discussions.concat(discussion) : [],
+ },
+ };
+ }
+
+ return line;
});
}
+
+ if (!file.parallelDiffLines || !file.highlightedDiffLines) {
+ file.discussions = file.discussions.concat(discussion);
+ }
+
+ return file;
}
- }
+
+ return diffFile;
+ });
},
[types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode }) {
diff --git a/app/assets/javascripts/dirty_submit/dirty_submit_collection.js b/app/assets/javascripts/dirty_submit/dirty_submit_collection.js
new file mode 100644
index 00000000000..42b051b2270
--- /dev/null
+++ b/app/assets/javascripts/dirty_submit/dirty_submit_collection.js
@@ -0,0 +1,13 @@
+import DirtySubmitForm from './dirty_submit_form';
+
+class DirtySubmitCollection {
+ constructor(forms) {
+ this.forms = forms;
+
+ this.dirtySubmits = [];
+
+ this.forms.forEach(form => this.dirtySubmits.push(new DirtySubmitForm(form)));
+ }
+}
+
+export default DirtySubmitCollection;
diff --git a/app/assets/javascripts/dirty_submit/dirty_submit_factory.js b/app/assets/javascripts/dirty_submit/dirty_submit_factory.js
new file mode 100644
index 00000000000..95a896a7f0b
--- /dev/null
+++ b/app/assets/javascripts/dirty_submit/dirty_submit_factory.js
@@ -0,0 +1,9 @@
+import DirtySubmitCollection from './dirty_submit_collection';
+import DirtySubmitForm from './dirty_submit_form';
+
+export default function dirtySubmitFactory(formOrForms) {
+ const isCollection = formOrForms instanceof NodeList || formOrForms instanceof Array;
+ const DirtySubmitClass = isCollection ? DirtySubmitCollection : DirtySubmitForm;
+
+ return new DirtySubmitClass(formOrForms);
+}
diff --git a/app/assets/javascripts/dirty_submit/dirty_submit_form.js b/app/assets/javascripts/dirty_submit/dirty_submit_form.js
new file mode 100644
index 00000000000..5bea47f23c5
--- /dev/null
+++ b/app/assets/javascripts/dirty_submit/dirty_submit_form.js
@@ -0,0 +1,82 @@
+import _ from 'underscore';
+
+class DirtySubmitForm {
+ constructor(form) {
+ this.form = form;
+ this.dirtyInputs = [];
+ this.isDisabled = true;
+
+ this.init();
+ }
+
+ init() {
+ this.inputs = this.form.querySelectorAll('input, textarea, select');
+ this.submits = this.form.querySelectorAll('input[type=submit], button[type=submit]');
+
+ this.inputs.forEach(DirtySubmitForm.initInput);
+ this.toggleSubmission();
+
+ this.registerListeners();
+ }
+
+ registerListeners() {
+ const throttledUpdateDirtyInput = _.throttle(
+ event => this.updateDirtyInput(event),
+ DirtySubmitForm.THROTTLE_DURATION,
+ );
+ this.form.addEventListener('input', throttledUpdateDirtyInput);
+ this.form.addEventListener('submit', event => this.formSubmit(event));
+ }
+
+ updateDirtyInput(event) {
+ const input = event.target;
+
+ if (!input.dataset.dirtySubmitOriginalValue) return;
+
+ this.updateDirtyInputs(input);
+ this.toggleSubmission();
+ }
+
+ updateDirtyInputs(input) {
+ const { name } = input;
+ const isDirty =
+ input.dataset.dirtySubmitOriginalValue !== DirtySubmitForm.inputCurrentValue(input);
+ const indexOfInputName = this.dirtyInputs.indexOf(name);
+ const isExisting = indexOfInputName !== -1;
+
+ if (isDirty && !isExisting) this.dirtyInputs.push(name);
+ if (!isDirty && isExisting) this.dirtyInputs.splice(indexOfInputName, 1);
+ }
+
+ toggleSubmission() {
+ this.isDisabled = this.dirtyInputs.length === 0;
+ this.submits.forEach(element => {
+ element.disabled = this.isDisabled;
+ });
+ }
+
+ formSubmit(event) {
+ if (this.isDisabled) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+
+ return !this.isDisabled;
+ }
+
+ static initInput(element) {
+ element.dataset.dirtySubmitOriginalValue = DirtySubmitForm.inputCurrentValue(element);
+ }
+
+ static isInputCheckable(input) {
+ return input.type === 'checkbox' || input.type === 'radio';
+ }
+
+ static inputCurrentValue(input) {
+ return DirtySubmitForm.isInputCheckable(input) ? input.checked.toString() : input.value;
+ }
+}
+
+DirtySubmitForm.THROTTLE_DURATION = 500;
+
+export default DirtySubmitForm;
diff --git a/app/assets/javascripts/dismissable_callout.js b/app/assets/javascripts/dismissable_callout.js
new file mode 100644
index 00000000000..5185b019376
--- /dev/null
+++ b/app/assets/javascripts/dismissable_callout.js
@@ -0,0 +1,27 @@
+import $ from 'jquery';
+import axios from '~/lib/utils/axios_utils';
+import { __ } from '~/locale';
+import Flash from '~/flash';
+
+export default function initDismissableCallout(alertSelector) {
+ const alertEl = document.querySelector(alertSelector);
+ if (!alertEl) {
+ return;
+ }
+
+ const closeButtonEl = alertEl.getElementsByClassName('close')[0];
+ const { dismissEndpoint, featureId } = closeButtonEl.dataset;
+
+ closeButtonEl.addEventListener('click', () => {
+ axios
+ .post(dismissEndpoint, {
+ feature_name: featureId,
+ })
+ .then(() => {
+ $(alertEl).alert('close');
+ })
+ .catch(() => {
+ Flash(__('An error occurred while dismissing the alert. Refresh the page and try again.'));
+ });
+ });
+}
diff --git a/app/assets/javascripts/droplab/constants.js b/app/assets/javascripts/droplab/constants.js
index 868d47e91b3..6451af49d36 100644
--- a/app/assets/javascripts/droplab/constants.js
+++ b/app/assets/javascripts/droplab/constants.js
@@ -6,11 +6,4 @@ const IGNORE_CLASS = 'droplab-item-ignore';
// Matches `{{anything}}` and `{{ everything }}`.
const TEMPLATE_REGEX = /\{\{(.+?)\}\}/g;
-export {
- DATA_TRIGGER,
- DATA_DROPDOWN,
- SELECTED_CLASS,
- ACTIVE_CLASS,
- TEMPLATE_REGEX,
- IGNORE_CLASS,
-};
+export { DATA_TRIGGER, DATA_DROPDOWN, SELECTED_CLASS, ACTIVE_CLASS, TEMPLATE_REGEX, IGNORE_CLASS };
diff --git a/app/assets/javascripts/droplab/drop_down.js b/app/assets/javascripts/droplab/drop_down.js
index 3cc316c3f3e..ccb3d56ed8c 100644
--- a/app/assets/javascripts/droplab/drop_down.js
+++ b/app/assets/javascripts/droplab/drop_down.js
@@ -2,7 +2,7 @@ import utils from './utils';
import { SELECTED_CLASS, IGNORE_CLASS } from './constants';
class DropDown {
- constructor(list, config = { }) {
+ constructor(list, config = {}) {
this.currentIndex = 0;
this.hidden = true;
this.list = typeof list === 'string' ? document.querySelector(list) : list;
@@ -157,7 +157,7 @@ class DropDown {
static setImagesSrc(template) {
const images = [...template.querySelectorAll('img[data-src]')];
- images.forEach((image) => {
+ images.forEach(image => {
const img = image;
img.src = img.getAttribute('data-src');
diff --git a/app/assets/javascripts/droplab/drop_lab.js b/app/assets/javascripts/droplab/drop_lab.js
index 2a02ede72bf..1339e28d8b8 100644
--- a/app/assets/javascripts/droplab/drop_lab.js
+++ b/app/assets/javascripts/droplab/drop_lab.js
@@ -51,7 +51,7 @@ class DropLab {
}
processData(trigger, data, methodName) {
- this.hooks.forEach((hook) => {
+ this.hooks.forEach(hook => {
if (Array.isArray(trigger)) hook.list[methodName](trigger);
if (hook.trigger.id === trigger) hook.list[methodName](data);
@@ -78,7 +78,8 @@ class DropLab {
}
changeHookList(trigger, list, plugins, config) {
- const availableTrigger = typeof trigger === 'string' ? document.getElementById(trigger) : trigger;
+ const availableTrigger =
+ typeof trigger === 'string' ? document.getElementById(trigger) : trigger;
this.hooks.forEach((hook, i) => {
const aHook = hook;
diff --git a/app/assets/javascripts/droplab/keyboard.js b/app/assets/javascripts/droplab/keyboard.js
index 02f1b805ce4..40837ffdf8f 100644
--- a/app/assets/javascripts/droplab/keyboard.js
+++ b/app/assets/javascripts/droplab/keyboard.js
@@ -2,15 +2,18 @@
import { ACTIVE_CLASS } from './constants';
-const Keyboard = function () {
+const Keyboard = function() {
var currentKey;
var currentFocus;
var isUpArrow = false;
var isDownArrow = false;
var removeHighlight = function removeHighlight(list) {
- var itemElements = Array.prototype.slice.call(list.list.querySelectorAll('li:not(.divider):not(.hidden)'), 0);
+ var itemElements = Array.prototype.slice.call(
+ list.list.querySelectorAll('li:not(.divider):not(.hidden)'),
+ 0,
+ );
var listItems = [];
- for(var i = 0; i < itemElements.length; i++) {
+ for (var i = 0; i < itemElements.length; i++) {
var listItem = itemElements[i];
listItem.classList.remove(ACTIVE_CLASS);
@@ -23,13 +26,13 @@ const Keyboard = function () {
var setMenuForArrows = function setMenuForArrows(list) {
var listItems = removeHighlight(list);
- if(list.currentIndex>0){
- if(!listItems[list.currentIndex-1]){
- list.currentIndex = list.currentIndex-1;
+ if (list.currentIndex > 0) {
+ if (!listItems[list.currentIndex - 1]) {
+ list.currentIndex = list.currentIndex - 1;
}
- if (listItems[list.currentIndex-1]) {
- var el = listItems[list.currentIndex-1];
+ if (listItems[list.currentIndex - 1]) {
+ var el = listItems[list.currentIndex - 1];
var filterDropdownEl = el.closest('.filter-dropdown');
el.classList.add(ACTIVE_CLASS);
@@ -55,7 +58,7 @@ const Keyboard = function () {
};
var selectItem = function selectItem(list) {
var listItems = removeHighlight(list);
- var currentItem = listItems[list.currentIndex-1];
+ var currentItem = listItems[list.currentIndex - 1];
var listEvent = new CustomEvent('click.dl', {
detail: {
list: list,
@@ -65,43 +68,49 @@ const Keyboard = function () {
});
list.list.dispatchEvent(listEvent);
list.hide();
- }
+ };
- var keydown = function keydown(e){
+ var keydown = function keydown(e) {
var typedOn = e.target;
var list = e.detail.hook.list;
var currentIndex = list.currentIndex;
isUpArrow = false;
isDownArrow = false;
- if(e.detail.which){
+ if (e.detail.which) {
currentKey = e.detail.which;
- if(currentKey === 13){
+ if (currentKey === 13) {
selectItem(e.detail.hook.list);
return;
}
- if(currentKey === 38) {
+ if (currentKey === 38) {
isUpArrow = true;
}
- if(currentKey === 40) {
+ if (currentKey === 40) {
isDownArrow = true;
}
- } else if(e.detail.key) {
+ } else if (e.detail.key) {
currentKey = e.detail.key;
- if(currentKey === 'Enter'){
+ if (currentKey === 'Enter') {
selectItem(e.detail.hook.list);
return;
}
- if(currentKey === 'ArrowUp') {
+ if (currentKey === 'ArrowUp') {
isUpArrow = true;
}
- if(currentKey === 'ArrowDown') {
+ if (currentKey === 'ArrowDown') {
isDownArrow = true;
}
}
- if(isUpArrow){ currentIndex--; }
- if(isDownArrow){ currentIndex++; }
- if(currentIndex < 0){ currentIndex = 0; }
+ if (isUpArrow) {
+ currentIndex--;
+ }
+ if (isDownArrow) {
+ currentIndex++;
+ }
+ if (currentIndex < 0) {
+ currentIndex = 0;
+ }
list.currentIndex = currentIndex;
setMenuForArrows(e.detail.hook.list);
};
diff --git a/app/assets/javascripts/droplab/plugins/ajax.js b/app/assets/javascripts/droplab/plugins/ajax.js
index 267b53fa4f2..48b2a90c459 100644
--- a/app/assets/javascripts/droplab/plugins/ajax.js
+++ b/app/assets/javascripts/droplab/plugins/ajax.js
@@ -43,12 +43,12 @@ const Ajax = {
return AjaxCache.retrieve(config.endpoint)
.then(self.preprocessing.bind(null, config))
- .then((data) => self._loadData(data, config, self))
+ .then(data => self._loadData(data, config, self))
.catch(config.onError);
},
destroy: function() {
this.destroyed = true;
- }
+ },
};
export default Ajax;
diff --git a/app/assets/javascripts/droplab/plugins/ajax_filter.js b/app/assets/javascripts/droplab/plugins/ajax_filter.js
index 1db20227a16..66a52548417 100644
--- a/app/assets/javascripts/droplab/plugins/ajax_filter.js
+++ b/app/assets/javascripts/droplab/plugins/ajax_filter.js
@@ -41,8 +41,10 @@ const AjaxFilter = {
if (config.searchValueFunction) {
searchValue = config.searchValueFunction();
}
- if (config.loadingTemplate && this.hook.list.data === undefined ||
- this.hook.list.data.length === 0) {
+ if (
+ (config.loadingTemplate && this.hook.list.data === undefined) ||
+ this.hook.list.data.length === 0
+ ) {
var dynamicList = this.hook.list.list.querySelector('[data-dynamic]');
var loadingTemplate = document.createElement('div');
loadingTemplate.innerHTML = config.loadingTemplate;
@@ -61,7 +63,7 @@ const AjaxFilter = {
params[config.searchKey] = searchValue;
var url = config.endpoint + this.buildParams(params);
return AjaxCache.retrieve(url)
- .then((data) => {
+ .then(data => {
this._loadData(data, config);
if (config.onLoadingFinished) {
config.onLoadingFinished(data);
@@ -72,8 +74,7 @@ const AjaxFilter = {
_loadData(data, config) {
const list = this.hook.list;
- if (config.loadingTemplate && list.data === undefined ||
- list.data.length === 0) {
+ if ((config.loadingTemplate && list.data === undefined) || list.data.length === 0) {
const dataLoadingTemplate = list.list.querySelector('[data-loading-template]');
if (dataLoadingTemplate) {
dataLoadingTemplate.outerHTML = this.listTemplate;
@@ -81,7 +82,8 @@ const AjaxFilter = {
}
if (!this.destroyed) {
var hookListChildren = list.list.children;
- var onlyDynamicList = hookListChildren.length === 1 && hookListChildren[0].hasAttribute('data-dynamic');
+ var onlyDynamicList =
+ hookListChildren.length === 1 && hookListChildren[0].hasAttribute('data-dynamic');
if (onlyDynamicList && data.length === 0) {
list.hide();
}
@@ -100,12 +102,12 @@ const AjaxFilter = {
},
destroy: function destroy() {
- if (this.timeout)clearTimeout(this.timeout);
+ if (this.timeout) clearTimeout(this.timeout);
this.destroyed = true;
this.hook.trigger.removeEventListener('keydown.dl', this.eventWrapper.debounceTrigger);
this.hook.trigger.removeEventListener('focus', this.eventWrapper.debounceTrigger);
- }
+ },
};
export default AjaxFilter;
diff --git a/app/assets/javascripts/droplab/plugins/filter.js b/app/assets/javascripts/droplab/plugins/filter.js
index 404d707cf7a..6f1dc252d24 100644
--- a/app/assets/javascripts/droplab/plugins/filter.js
+++ b/app/assets/javascripts/droplab/plugins/filter.js
@@ -1,7 +1,7 @@
/* eslint-disable */
const Filter = {
- keydown: function(e){
+ keydown: function(e) {
if (this.destroyed) return;
var hiddenCount = 0;
@@ -14,14 +14,14 @@ const Filter = {
var matches = [];
var filterFunction;
// will only work on dynamically set data
- if(!data){
+ if (!data) {
return;
}
if (config && config.filterFunction && typeof config.filterFunction === 'function') {
filterFunction = config.filterFunction;
} else {
- filterFunction = function(o){
+ filterFunction = function(o) {
// cheap string search
o.droplab_hidden = o[config.template].toLowerCase().indexOf(value) === -1;
return o;
@@ -47,20 +47,23 @@ const Filter = {
},
debounceKeydown: function debounceKeydown(e) {
- if ([
- 13, // enter
- 16, // shift
- 17, // ctrl
- 18, // alt
- 20, // caps lock
- 37, // left arrow
- 38, // up arrow
- 39, // right arrow
- 40, // down arrow
- 91, // left window
- 92, // right window
- 93, // select
- ].indexOf(e.detail.which || e.detail.keyCode) > -1) return;
+ if (
+ [
+ 13, // enter
+ 16, // shift
+ 17, // ctrl
+ 18, // alt
+ 20, // caps lock
+ 37, // left arrow
+ 38, // up arrow
+ 39, // right arrow
+ 40, // down arrow
+ 91, // left window
+ 92, // right window
+ 93, // select
+ ].indexOf(e.detail.which || e.detail.keyCode) > -1
+ )
+ return;
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(this.keydown.bind(this, e), 200);
@@ -87,7 +90,7 @@ const Filter = {
this.hook.trigger.removeEventListener('keydown.dl', this.eventWrapper.debounceKeydown);
this.hook.trigger.removeEventListener('mousedown.dl', this.eventWrapper.debounceKeydown);
- }
+ },
};
export default Filter;
diff --git a/app/assets/javascripts/droplab/plugins/input_setter.js b/app/assets/javascripts/droplab/plugins/input_setter.js
index d01fbc5830d..6cfc738a1e3 100644
--- a/app/assets/javascripts/droplab/plugins/input_setter.js
+++ b/app/assets/javascripts/droplab/plugins/input_setter.js
@@ -36,8 +36,8 @@ const InputSetter = {
const inputAttribute = config.inputAttribute;
if (input.hasAttribute(inputAttribute)) return input.setAttribute(inputAttribute, newValue);
- if (input.tagName === 'INPUT') return input.value = newValue;
- return input.textContent = newValue;
+ if (input.tagName === 'INPUT') return (input.value = newValue);
+ return (input.textContent = newValue);
},
destroy() {
diff --git a/app/assets/javascripts/droplab/utils.js b/app/assets/javascripts/droplab/utils.js
index bfe056a0fcc..5272778ce2d 100644
--- a/app/assets/javascripts/droplab/utils.js
+++ b/app/assets/javascripts/droplab/utils.js
@@ -5,7 +5,12 @@ import { DATA_TRIGGER, DATA_DROPDOWN, TEMPLATE_REGEX } from './constants';
const utils = {
toCamelCase(attr) {
- return this.camelize(attr.split('-').slice(1).join(' '));
+ return this.camelize(
+ attr
+ .split('-')
+ .slice(1)
+ .join(' '),
+ );
},
template(templateString, data) {
@@ -17,9 +22,11 @@ const utils = {
},
camelize(str) {
- return str.replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => {
- return index === 0 ? letter.toLowerCase() : letter.toUpperCase();
- }).replace(/\s+/g, '');
+ return str
+ .replace(/(?:^\w|[A-Z]|\b\w)/g, (letter, index) => {
+ return index === 0 ? letter.toLowerCase() : letter.toUpperCase();
+ })
+ .replace(/\s+/g, '');
},
closest(thisTag, stopTag) {
diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js
index d2778bcdf1c..9987fbcb6a7 100644
--- a/app/assets/javascripts/dropzone_input.js
+++ b/app/assets/javascripts/dropzone_input.js
@@ -136,7 +136,7 @@ export default function dropzoneInput(form) {
// removeAllFiles(true) stops uploading files (if any)
// and remove them from dropzone files queue.
- $cancelButton.on('click', (e) => {
+ $cancelButton.on('click', e => {
e.preventDefault();
e.stopPropagation();
Dropzone.forElement($formDropzone.get(0)).removeAllFiles(true);
@@ -146,8 +146,10 @@ export default function dropzoneInput(form) {
// clear dropzone files queue, change status of failed files to undefined,
// and add that files to the dropzone files queue again.
// addFile() adds file to dropzone files queue and upload it.
- $retryLink.on('click', (e) => {
- const dropzoneInstance = Dropzone.forElement(e.target.closest('.js-main-target-form').querySelector('.div-dropzone'));
+ $retryLink.on('click', e => {
+ const dropzoneInstance = Dropzone.forElement(
+ e.target.closest('.js-main-target-form').querySelector('.div-dropzone'),
+ );
const failedFiles = dropzoneInstance.files;
e.preventDefault();
@@ -156,7 +158,7 @@ export default function dropzoneInput(form) {
// uploading of files that are being uploaded at the moment.
dropzoneInstance.removeAllFiles(true);
- failedFiles.map((failedFile) => {
+ failedFiles.map(failedFile => {
const file = failedFile;
if (file.status === Dropzone.ERROR) {
@@ -168,7 +170,7 @@ export default function dropzoneInput(form) {
});
});
// eslint-disable-next-line consistent-return
- handlePaste = (event) => {
+ handlePaste = event => {
const pasteEvent = event.originalEvent;
if (pasteEvent.clipboardData && pasteEvent.clipboardData.items) {
const image = isImage(pasteEvent);
@@ -182,7 +184,7 @@ export default function dropzoneInput(form) {
}
};
- isImage = (data) => {
+ isImage = data => {
let i = 0;
while (i < data.clipboardData.items.length) {
const item = data.clipboardData.items[i];
@@ -203,8 +205,12 @@ export default function dropzoneInput(form) {
const caretStart = textarea.selectionStart;
const caretEnd = textarea.selectionEnd;
const textEnd = $(child).val().length;
- const beforeSelection = $(child).val().substring(0, caretStart);
- const afterSelection = $(child).val().substring(caretEnd, textEnd);
+ const beforeSelection = $(child)
+ .val()
+ .substring(0, caretStart);
+ const afterSelection = $(child)
+ .val()
+ .substring(caretEnd, textEnd);
$(child).val(beforeSelection + formattedText + afterSelection);
textarea.setSelectionRange(caretStart + formattedText.length, caretEnd + formattedText.length);
textarea.style.height = `${textarea.scrollHeight}px`;
@@ -212,11 +218,11 @@ export default function dropzoneInput(form) {
return formTextarea.trigger('input');
};
- addFileToForm = (path) => {
+ addFileToForm = path => {
$(form).append(`<input type="hidden" name="files[]" value="${_.escape(path)}">`);
};
- getFilename = (e) => {
+ getFilename = e => {
let value;
if (window.clipboardData && window.clipboardData.getData) {
value = window.clipboardData.getData('Text');
@@ -231,7 +237,7 @@ export default function dropzoneInput(form) {
const closeSpinner = () => $uploadingProgressContainer.addClass('hide');
- const showError = (message) => {
+ const showError = message => {
$uploadingErrorContainer.removeClass('hide');
$uploadingErrorMessage.html(message);
};
@@ -252,14 +258,15 @@ export default function dropzoneInput(form) {
showSpinner();
closeAlertMessage();
- axios.post(uploadsPath, formData)
+ axios
+ .post(uploadsPath, formData)
.then(({ data }) => {
const md = data.link.markdown;
insertToTextArea(filename, md);
closeSpinner();
})
- .catch((e) => {
+ .catch(e => {
showError(e.response.data.message);
closeSpinner();
});
@@ -267,7 +274,8 @@ export default function dropzoneInput(form) {
updateAttachingMessage = (files, messageContainer) => {
let attachingMessage;
- const filesCount = files.filter(file => file.status === 'uploading' || file.status === 'queued').length;
+ const filesCount = files.filter(file => file.status === 'uploading' || file.status === 'queued')
+ .length;
// Dinamycally change uploading files text depending on files number in
// dropzone files queue.
@@ -282,7 +290,10 @@ export default function dropzoneInput(form) {
form.find('.markdown-selector').click(function onMarkdownClick(e) {
e.preventDefault();
- $(this).closest('.gfm-form').find('.div-dropzone').click();
+ $(this)
+ .closest('.gfm-form')
+ .find('.div-dropzone')
+ .click();
formTextarea.focus();
});
diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js
index c7b5a35cc14..dbfcf8cc921 100644
--- a/app/assets/javascripts/due_date_select.js
+++ b/app/assets/javascripts/due_date_select.js
@@ -3,8 +3,7 @@ import Pikaday from 'pikaday';
import dateFormat from 'dateformat';
import { __ } from '~/locale';
import axios from './lib/utils/axios_utils';
-import { timeFor } from './lib/utils/datetime_utility';
-import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
+import { timeFor, parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
import boardsStore from './boards/stores/boards_store';
class DueDateSelect {
diff --git a/app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js b/app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js
index e9defb62cf8..c5f9fcf6358 100644
--- a/app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js
+++ b/app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js
@@ -13,9 +13,11 @@ const rainbowCodePoint = 127752; // parseInt('1F308', 16)
function isRainbowFlagEmoji(emojiUnicode) {
const characters = Array.from(emojiUnicode);
// Length 4 because flags are made of 2 characters which are surrogate pairs
- return emojiUnicode.length === 4 &&
+ return (
+ emojiUnicode.length === 4 &&
characters[0].codePointAt(0) === baseFlagCodePoint &&
- characters[1].codePointAt(0) === rainbowCodePoint;
+ characters[1].codePointAt(0) === rainbowCodePoint
+ );
}
// Chrome <57 renders keycaps oddly
@@ -26,22 +28,28 @@ function isKeycapEmoji(emojiUnicode) {
}
// Check for a skin tone variation emoji which aren't always supported
-const tone1 = 127995;// parseInt('1F3FB', 16)
-const tone5 = 127999;// parseInt('1F3FF', 16)
+const tone1 = 127995; // parseInt('1F3FB', 16)
+const tone5 = 127999; // parseInt('1F3FF', 16)
function isSkinToneComboEmoji(emojiUnicode) {
- return emojiUnicode.length > 2 && Array.from(emojiUnicode).some((char) => {
- const cp = char.codePointAt(0);
- return cp >= tone1 && cp <= tone5;
- });
+ return (
+ emojiUnicode.length > 2 &&
+ Array.from(emojiUnicode).some(char => {
+ const cp = char.codePointAt(0);
+ return cp >= tone1 && cp <= tone5;
+ })
+ );
}
// macOS supports most skin tone emoji's but
// doesn't support the skin tone versions of horse racing
-const horseRacingCodePoint = 127943;// parseInt('1F3C7', 16)
+const horseRacingCodePoint = 127943; // parseInt('1F3C7', 16)
function isHorceRacingSkinToneComboEmoji(emojiUnicode) {
const firstCharacter = Array.from(emojiUnicode)[0];
- return firstCharacter && firstCharacter.codePointAt(0) === horseRacingCodePoint &&
- isSkinToneComboEmoji(emojiUnicode);
+ return (
+ firstCharacter &&
+ firstCharacter.codePointAt(0) === horseRacingCodePoint &&
+ isSkinToneComboEmoji(emojiUnicode)
+ );
}
// Check for `family_*`, `kiss_*`, `couple_*`
@@ -52,7 +60,7 @@ const personEndCodePoint = 128105; // parseInt('1F469', 16)
function isPersonZwjEmoji(emojiUnicode) {
let hasPersonEmoji = false;
let hasZwj = false;
- Array.from(emojiUnicode).forEach((character) => {
+ Array.from(emojiUnicode).forEach(character => {
const cp = character.codePointAt(0);
if (cp === zwj) {
hasZwj = true;
@@ -80,10 +88,7 @@ function checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) {
// in `isEmojiUnicodeSupported` logic
function checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) {
const isSkinToneResult = isSkinToneComboEmoji(emojiUnicode);
- return (
- (unicodeSupportMap.skinToneModifier && isSkinToneResult) ||
- !isSkinToneResult
- );
+ return (unicodeSupportMap.skinToneModifier && isSkinToneResult) || !isSkinToneResult;
}
// Helper func so we don't have to run `isHorceRacingSkinToneComboEmoji` twice
@@ -91,8 +96,7 @@ function checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) {
function checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isHorseRacingSkinToneResult = isHorceRacingSkinToneComboEmoji(emojiUnicode);
return (
- (unicodeSupportMap.horseRacing && isHorseRacingSkinToneResult) ||
- !isHorseRacingSkinToneResult
+ (unicodeSupportMap.horseRacing && isHorseRacingSkinToneResult) || !isHorseRacingSkinToneResult
);
}
@@ -100,10 +104,7 @@ function checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnico
// in `isEmojiUnicodeSupported` logic
function checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isPersonZwjResult = isPersonZwjEmoji(emojiUnicode);
- return (
- (unicodeSupportMap.personZwj && isPersonZwjResult) ||
- !isPersonZwjResult
- );
+ return (unicodeSupportMap.personZwj && isPersonZwjResult) || !isPersonZwjResult;
}
// Takes in a support map and determines whether
@@ -111,16 +112,20 @@ function checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode) {
//
// Combines all the edge case tests into a one-stop shop method
function isEmojiUnicodeSupported(unicodeSupportMap = {}, emojiUnicode, unicodeVersion) {
- const isOlderThanChrome57 = unicodeSupportMap.meta && unicodeSupportMap.meta.isChrome &&
+ const isOlderThanChrome57 =
+ unicodeSupportMap.meta &&
+ unicodeSupportMap.meta.isChrome &&
unicodeSupportMap.meta.chromeVersion < 57;
// For comments about each scenario, see the comments above each individual respective function
- return unicodeSupportMap[unicodeVersion] &&
+ return (
+ unicodeSupportMap[unicodeVersion] &&
!(isOlderThanChrome57 && isKeycapEmoji(emojiUnicode)) &&
checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) &&
checkSkinToneModifierSupport(unicodeSupportMap, emojiUnicode) &&
checkHorseRacingSkinToneComboEmojiSupport(unicodeSupportMap, emojiUnicode) &&
- checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode);
+ checkPersonEmojiSupport(unicodeSupportMap, emojiUnicode)
+ );
}
export {
diff --git a/app/assets/javascripts/environments/components/container.vue b/app/assets/javascripts/environments/components/container.vue
index 9de851c9409..00d197d294f 100644
--- a/app/assets/javascripts/environments/components/container.vue
+++ b/app/assets/javascripts/environments/components/container.vue
@@ -1,40 +1,40 @@
<script>
- import tablePagination from '../../vue_shared/components/table_pagination.vue';
- import environmentTable from '../components/environments_table.vue';
+import tablePagination from '../../vue_shared/components/table_pagination.vue';
+import environmentTable from '../components/environments_table.vue';
- export default {
- components: {
- environmentTable,
- tablePagination,
+export default {
+ components: {
+ environmentTable,
+ tablePagination,
+ },
+ props: {
+ isLoading: {
+ type: Boolean,
+ required: true,
},
- props: {
- isLoading: {
- type: Boolean,
- required: true,
- },
- environments: {
- type: Array,
- required: true,
- },
- pagination: {
- type: Object,
- required: true,
- },
- canCreateDeployment: {
- type: Boolean,
- required: true,
- },
- canReadEnvironment: {
- type: Boolean,
- required: true,
- },
+ environments: {
+ type: Array,
+ required: true,
},
- methods: {
- onChangePage(page) {
- this.$emit('onChangePage', page);
- },
+ pagination: {
+ type: Object,
+ required: true,
},
- };
+ canCreateDeployment: {
+ type: Boolean,
+ required: true,
+ },
+ canReadEnvironment: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ methods: {
+ onChangePage(page) {
+ this.$emit('onChangePage', page);
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/environments/components/empty_state.vue b/app/assets/javascripts/environments/components/empty_state.vue
index cf78f89981e..2360a52645b 100644
--- a/app/assets/javascripts/environments/components/empty_state.vue
+++ b/app/assets/javascripts/environments/components/empty_state.vue
@@ -1,44 +1,45 @@
<script>
- export default {
- name: 'EnvironmentsEmptyState',
- props: {
- newPath: {
- type: String,
- required: true,
- },
- canCreateEnvironment: {
- type: Boolean,
- required: true,
- },
- helpPath: {
- type: String,
- required: true,
- },
+export default {
+ name: 'EnvironmentsEmptyState',
+ props: {
+ newPath: {
+ type: String,
+ required: true,
},
- };
+ canCreateEnvironment: {
+ type: Boolean,
+ required: true,
+ },
+ helpPath: {
+ type: String,
+ required: true,
+ },
+ },
+};
</script>
<template>
- <div class="blank-state-row">
- <div class="blank-state-center">
- <h2 class="blank-state-title js-blank-state-title">
- {{ s__("Environments|You don't have any environments right now.") }}
- </h2>
+ <div class="empty-state">
+ <div class="text-content">
+ <h4 class="blank-state-title js-blank-state-title">
+ {{ 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.`) }}
- <br />
+ code gets deployed, such as staging or production.`) }}
<a :href="helpPath">
{{ s__("Environments|Read more about environments") }}
</a>
</p>
- <a
- v-if="canCreateEnvironment"
- :href="newPath"
- class="btn btn-success js-new-environment-button"
- >
- {{ s__("Environments|New environment") }}
- </a>
+ <div class="text-center">
+ <a
+ v-if="canCreateEnvironment"
+ :href="newPath"
+ class="btn btn-success js-new-environment-button"
+ >
+ {{ s__("Environments|New environment") }}
+ </a>
+ </div>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index e1f9248bc4c..2bc168a6b02 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -60,11 +60,9 @@ export default {
>
<span>
<icon name="play" />
- <i
- class="fa fa-caret-down"
- aria-hidden="true"
- >
- </i>
+ <icon
+ name="chevron-down"
+ />
<gl-loading-icon v-if="isLoading" />
</span>
</button>
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index ad5d16874f3..bb9c139727e 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -4,6 +4,7 @@ import _ from 'underscore';
import tooltip from '~/vue_shared/directives/tooltip';
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';
import ActionsComponent from './environment_actions.vue';
import ExternalUrlComponent from './environment_external_url.vue';
import StopComponent from './environment_stop.vue';
@@ -24,6 +25,7 @@ export default {
components: {
UserAvatarLink,
CommitComponent,
+ Icon,
ActionsComponent,
ExternalUrlComponent,
StopComponent,
@@ -448,6 +450,10 @@ export default {
this.canRetry
);
},
+
+ folderIconName() {
+ return this.model.isOpen ? 'chevron-down' : 'chevron-right';
+ },
},
methods: {
@@ -494,27 +500,15 @@ export default {
role="button"
@click="onClickFolder">
- <span class="folder-icon">
- <i
- v-show="model.isOpen"
- class="fa fa-caret-down"
- aria-hidden="true"
- >
- </i>
- <i
- v-show="!model.isOpen"
- class="fa fa-caret-right"
- aria-hidden="true"
- >
- </i>
- </span>
+ <icon
+ :name="folderIconName"
+ class="folder-icon"
+ />
- <span class="folder-icon">
- <i
- class="fa fa-folder"
- aria-hidden="true">
- </i>
- </span>
+ <icon
+ name="folder"
+ class="folder-icon"
+ />
<span>
{{ model.folderName }}
diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue
index efbf88d0f11..9e137f79dcc 100644
--- a/app/assets/javascripts/environments/components/environment_rollback.vue
+++ b/app/assets/javascripts/environments/components/environment_rollback.vue
@@ -38,7 +38,9 @@ export default {
computed: {
title() {
- return this.isLastDeployment ? s__('Environments|Re-deploy to environment') : s__('Environments|Rollback environment');
+ return this.isLastDeployment
+ ? s__('Environments|Re-deploy to environment')
+ : s__('Environments|Rollback environment');
},
},
diff --git a/app/assets/javascripts/environments/folder/environments_folder_bundle.js b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
index de0fbdb2e91..f044d31c776 100644
--- a/app/assets/javascripts/environments/folder/environments_folder_bundle.js
+++ b/app/assets/javascripts/environments/folder/environments_folder_bundle.js
@@ -5,31 +5,32 @@ import Translate from '../../vue_shared/translate';
Vue.use(Translate);
-export default () => new Vue({
- el: '#environments-folder-list-view',
- components: {
- environmentsFolderApp,
- },
- data() {
- const environmentsData = document.querySelector(this.$options.el).dataset;
+export default () =>
+ new Vue({
+ el: '#environments-folder-list-view',
+ components: {
+ environmentsFolderApp,
+ },
+ data() {
+ const environmentsData = document.querySelector(this.$options.el).dataset;
- return {
- endpoint: environmentsData.endpoint,
- folderName: environmentsData.folderName,
- cssContainerClass: environmentsData.cssClass,
- canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
- canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
- };
- },
- render(createElement) {
- return createElement('environments-folder-app', {
- props: {
- endpoint: this.endpoint,
- folderName: this.folderName,
- cssContainerClass: this.cssContainerClass,
- canCreateDeployment: this.canCreateDeployment,
- canReadEnvironment: this.canReadEnvironment,
- },
- });
- },
-});
+ return {
+ endpoint: environmentsData.endpoint,
+ folderName: environmentsData.folderName,
+ cssContainerClass: environmentsData.cssClass,
+ canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
+ canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
+ };
+ },
+ render(createElement) {
+ return createElement('environments-folder-app', {
+ props: {
+ endpoint: this.endpoint,
+ folderName: this.folderName,
+ cssContainerClass: this.cssContainerClass,
+ canCreateDeployment: this.canCreateDeployment,
+ canReadEnvironment: this.canReadEnvironment,
+ },
+ });
+ },
+ });
diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.vue b/app/assets/javascripts/environments/folder/environments_folder_view.vue
index e69bfa0b2cc..6be4845fe4c 100644
--- a/app/assets/javascripts/environments/folder/environments_folder_view.vue
+++ b/app/assets/javascripts/environments/folder/environments_folder_view.vue
@@ -1,46 +1,43 @@
<script>
- import environmentsMixin from '../mixins/environments_mixin';
- import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
- import StopEnvironmentModal from '../components/stop_environment_modal.vue';
+import environmentsMixin from '../mixins/environments_mixin';
+import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
+import StopEnvironmentModal from '../components/stop_environment_modal.vue';
- export default {
- components: {
- StopEnvironmentModal,
- },
+export default {
+ components: {
+ StopEnvironmentModal,
+ },
- mixins: [
- environmentsMixin,
- CIPaginationMixin,
- ],
+ mixins: [environmentsMixin, CIPaginationMixin],
- props: {
- endpoint: {
- type: String,
- required: true,
- },
- folderName: {
- type: String,
- required: true,
- },
- cssContainerClass: {
- type: String,
- required: true,
- },
- canCreateDeployment: {
- type: Boolean,
- required: true,
- },
- canReadEnvironment: {
- type: Boolean,
- required: true,
- },
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ folderName: {
+ type: String,
+ required: true,
+ },
+ cssContainerClass: {
+ type: String,
+ required: true,
+ },
+ canCreateDeployment: {
+ type: Boolean,
+ required: true,
+ },
+ canReadEnvironment: {
+ type: Boolean,
+ required: true,
},
- methods: {
- successCallback(resp) {
- this.saveData(resp);
- },
+ },
+ methods: {
+ successCallback(resp) {
+ this.saveData(resp);
},
- };
+ },
+};
</script>
<template>
<div :class="cssContainerClass">
diff --git a/app/assets/javascripts/environments/index.js b/app/assets/javascripts/environments/index.js
index afc4aba6554..5b6833fb15d 100644
--- a/app/assets/javascripts/environments/index.js
+++ b/app/assets/javascripts/environments/index.js
@@ -5,35 +5,36 @@ import Translate from '../vue_shared/translate';
Vue.use(Translate);
-export default () => new Vue({
- el: '#environments-list-view',
- components: {
- environmentsComponent,
- },
- data() {
- const environmentsData = document.querySelector(this.$options.el).dataset;
+export default () =>
+ new Vue({
+ el: '#environments-list-view',
+ components: {
+ environmentsComponent,
+ },
+ data() {
+ const environmentsData = document.querySelector(this.$options.el).dataset;
- return {
- endpoint: environmentsData.environmentsDataEndpoint,
- newEnvironmentPath: environmentsData.newEnvironmentPath,
- helpPagePath: environmentsData.helpPagePath,
- cssContainerClass: environmentsData.cssClass,
- canCreateEnvironment: convertPermissionToBoolean(environmentsData.canCreateEnvironment),
- canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
- canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
- };
- },
- render(createElement) {
- return createElement('environments-component', {
- props: {
- endpoint: this.endpoint,
- newEnvironmentPath: this.newEnvironmentPath,
- helpPagePath: this.helpPagePath,
- cssContainerClass: this.cssContainerClass,
- canCreateEnvironment: this.canCreateEnvironment,
- canCreateDeployment: this.canCreateDeployment,
- canReadEnvironment: this.canReadEnvironment,
- },
- });
- },
-});
+ return {
+ endpoint: environmentsData.environmentsDataEndpoint,
+ newEnvironmentPath: environmentsData.newEnvironmentPath,
+ helpPagePath: environmentsData.helpPagePath,
+ cssContainerClass: environmentsData.cssClass,
+ canCreateEnvironment: convertPermissionToBoolean(environmentsData.canCreateEnvironment),
+ canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
+ canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
+ };
+ },
+ render(createElement) {
+ return createElement('environments-component', {
+ props: {
+ endpoint: this.endpoint,
+ newEnvironmentPath: this.newEnvironmentPath,
+ helpPagePath: this.helpPagePath,
+ cssContainerClass: this.cssContainerClass,
+ canCreateEnvironment: this.canCreateEnvironment,
+ canCreateDeployment: this.canCreateDeployment,
+ canReadEnvironment: this.canReadEnvironment,
+ },
+ });
+ },
+ });
diff --git a/app/assets/javascripts/environments/mixins/environments_mixin.js b/app/assets/javascripts/environments/mixins/environments_mixin.js
index d71964612c5..96dc1f07cb9 100644
--- a/app/assets/javascripts/environments/mixins/environments_mixin.js
+++ b/app/assets/javascripts/environments/mixins/environments_mixin.js
@@ -4,9 +4,7 @@
import _ from 'underscore';
import Visibility from 'visibilityjs';
import Poll from '../../lib/utils/poll';
-import {
- getParameterByName,
-} from '../../lib/utils/common_utils';
+import { getParameterByName } from '../../lib/utils/common_utils';
import { s__ } from '../../locale';
import Flash from '../../flash';
import eventHub from '../event_hub';
@@ -19,7 +17,6 @@ import tabs from '../../vue_shared/components/navigation_tabs.vue';
import container from '../components/container.vue';
export default {
-
components: {
environmentTable,
container,
@@ -65,7 +62,8 @@ export default {
updateContent(parameters) {
this.updateInternalState(parameters);
// fetch new data
- return this.service.fetchEnvironments(this.requestData)
+ return this.service
+ .fetchEnvironments(this.requestData)
.then(response => this.successCallback(response))
.then(() => {
// restart polling
@@ -88,7 +86,8 @@ export default {
if (!this.isMakingRequest) {
this.isLoading = true;
- this.service.postAction(endpoint)
+ this.service
+ .postAction(endpoint)
.then(() => this.fetchEnvironments())
.catch(() => {
this.isLoading = false;
@@ -100,7 +99,8 @@ export default {
fetchEnvironments() {
this.isLoading = true;
- return this.service.fetchEnvironments(this.requestData)
+ return this.service
+ .fetchEnvironments(this.requestData)
.then(this.successCallback)
.catch(this.errorCallback);
},
@@ -111,7 +111,9 @@ export default {
stopEnvironment(environment) {
const endpoint = environment.stop_path;
- const errorMessage = s__('Environments|An error occurred while stopping the environment, please try again');
+ const errorMessage = s__(
+ 'Environments|An error occurred while stopping the environment, please try again',
+ );
this.postAction({ endpoint, errorMessage });
},
},
@@ -149,7 +151,7 @@ export default {
data: this.requestData,
successCallback: this.successCallback,
errorCallback: this.errorCallback,
- notificationCallback: (isMakingRequest) => {
+ notificationCallback: isMakingRequest => {
this.isMakingRequest = isMakingRequest;
},
});
diff --git a/app/assets/javascripts/experimental_flags.js b/app/assets/javascripts/experimental_flags.js
index 1d60847147b..42b3fb8c6da 100644
--- a/app/assets/javascripts/experimental_flags.js
+++ b/app/assets/javascripts/experimental_flags.js
@@ -2,7 +2,7 @@ import $ from 'jquery';
import Cookies from 'js-cookie';
export default () => {
- $('.js-experiment-feature-toggle').on('change', (e) => {
+ $('.js-experiment-feature-toggle').on('change', e => {
const el = e.target;
Cookies.set(el.name, el.value, {
diff --git a/app/assets/javascripts/feature_highlight/feature_highlight.js b/app/assets/javascripts/feature_highlight/feature_highlight.js
index 03dfa942d69..173fe7c69de 100644
--- a/app/assets/javascripts/feature_highlight/feature_highlight.js
+++ b/app/assets/javascripts/feature_highlight/feature_highlight.js
@@ -1,13 +1,6 @@
import $ from 'jquery';
-import {
- getSelector,
- inserted,
-} from './feature_highlight_helper';
-import {
- togglePopover,
- mouseenter,
- debouncedMouseleave,
-} from '../shared/popover';
+import { getSelector, inserted } from './feature_highlight_helper';
+import { togglePopover, mouseenter, debouncedMouseleave } from '../shared/popover';
export function setupFeatureHighlightPopover(id, debounceTimeout = 300) {
const $selector = $(getSelector(id));
@@ -41,8 +34,9 @@ export function setupFeatureHighlightPopover(id, debounceTimeout = 300) {
export function findHighestPriorityFeature() {
let priorityFeature;
- const sortedFeatureEls = [].slice.call(document.querySelectorAll('.js-feature-highlight')).sort((a, b) =>
- (a.dataset.highlightPriority || 0) < (b.dataset.highlightPriority || 0));
+ const sortedFeatureEls = [].slice
+ .call(document.querySelectorAll('.js-feature-highlight'))
+ .sort((a, b) => (a.dataset.highlightPriority || 0) < (b.dataset.highlightPriority || 0));
const [priorityFeatureEl] = sortedFeatureEls;
if (priorityFeatureEl) {
diff --git a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js
index d5b97ebb264..fd9433b625c 100644
--- a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js
+++ b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js
@@ -8,10 +8,17 @@ import { togglePopover } from '../shared/popover';
export const getSelector = highlightId => `.js-feature-highlight[data-highlight=${highlightId}]`;
export function dismiss(highlightId) {
- axios.post(this.attr('data-dismiss-endpoint'), {
- feature_name: highlightId,
- })
- .catch(() => Flash(__('An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again.')));
+ axios
+ .post(this.attr('data-dismiss-endpoint'), {
+ feature_name: highlightId,
+ })
+ .catch(() =>
+ Flash(
+ __(
+ 'An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again.',
+ ),
+ ),
+ );
togglePopover.call(this, false);
this.hide();
@@ -23,8 +30,7 @@ export function inserted() {
const $popover = $(this);
const dismissWrapper = dismiss.bind($popover, highlightId);
- $(`#${popoverId} .dismiss-feature-highlight`)
- .on('click', dismissWrapper);
+ $(`#${popoverId} .dismiss-feature-highlight`).on('click', dismissWrapper);
const lazyImg = $(`#${popoverId} .feature-highlight-illustration`)[0];
if (lazyImg) {
diff --git a/app/assets/javascripts/files_comment_button.js b/app/assets/javascripts/files_comment_button.js
index 6a4874e1ab8..3233f5c4f71 100644
--- a/app/assets/javascripts/files_comment_button.js
+++ b/app/assets/javascripts/files_comment_button.js
@@ -25,13 +25,15 @@ export default {
if (!this.userCanCreateNote) {
// data-can-create-note is an empty string when true, otherwise undefined
- this.userCanCreateNote = $diffFile.closest(DIFF_CONTAINER_SELECTOR).data('canCreateNote') === '';
+ this.userCanCreateNote =
+ $diffFile.closest(DIFF_CONTAINER_SELECTOR).data('canCreateNote') === '';
}
this.isParallelView = Cookies.get('diff_view') === 'parallel';
if (this.userCanCreateNote) {
- $diffFile.on('mouseover', LINE_COLUMN_CLASSES, e => this.showButton(this.isParallelView, e))
+ $diffFile
+ .on('mouseover', LINE_COLUMN_CLASSES, e => this.showButton(this.isParallelView, e))
.on('mouseleave', LINE_COLUMN_CLASSES, e => this.hideButton(this.isParallelView, e));
}
},
@@ -64,9 +66,11 @@ export default {
},
validateButtonParent(buttonParentElement) {
- return !buttonParentElement.classList.contains(EMPTY_CELL_CLASS) &&
+ return (
+ !buttonParentElement.classList.contains(EMPTY_CELL_CLASS) &&
!buttonParentElement.classList.contains(UNFOLDABLE_LINE_CLASS) &&
!buttonParentElement.classList.contains(NO_COMMENT_CLASS) &&
- !buttonParentElement.parentNode.classList.contains(DIFF_EXPANDED_CLASS);
+ !buttonParentElement.parentNode.classList.contains(DIFF_EXPANDED_CLASS)
+ );
},
};
diff --git a/app/assets/javascripts/filterable_list.js b/app/assets/javascripts/filterable_list.js
index b17ba3c21db..64b09c8b62c 100644
--- a/app/assets/javascripts/filterable_list.js
+++ b/app/assets/javascripts/filterable_list.js
@@ -65,12 +65,15 @@ export default class FilterableList {
this.isBusy = true;
- return axios.get(this.getFilterEndpoint(), {
- params,
- }).then((res) => {
- this.onFilterSuccess(res, params);
- this.onFilterComplete();
- }).catch(() => this.onFilterComplete());
+ return axios
+ .get(this.getFilterEndpoint(), {
+ params,
+ })
+ .then(res => {
+ this.onFilterSuccess(res, params);
+ this.onFilterComplete();
+ })
+ .catch(() => this.onFilterComplete());
}
onFilterSuccess(response, queryData) {
@@ -81,9 +84,13 @@ export default class FilterableList {
// Change url so if user reload a page - search results are saved
const currentPath = this.getPagePath(queryData);
- return window.history.replaceState({
- page: currentPath,
- }, document.title, currentPath);
+ return window.history.replaceState(
+ {
+ page: currentPath,
+ },
+ document.title,
+ currentPath,
+ );
}
onFilterComplete() {
diff --git a/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js
index d7aa4ce597f..934375023ba 100644
--- a/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js
+++ b/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js
@@ -1,20 +1,23 @@
import FilteredSearchTokenKeys from './filtered_search_token_keys';
-const tokenKeys = [{
- key: 'status',
- type: 'string',
- param: 'status',
- symbol: '',
- icon: 'messages',
- tag: 'status',
-}, {
- key: 'type',
- type: 'string',
- param: 'type',
- symbol: '',
- icon: 'cube',
- tag: 'type',
-}];
+const tokenKeys = [
+ {
+ key: 'status',
+ type: 'string',
+ param: 'status',
+ symbol: '',
+ icon: 'messages',
+ tag: 'status',
+ },
+ {
+ key: 'type',
+ type: 'string',
+ param: 'type',
+ symbol: '',
+ icon: 'cube',
+ tag: 'type',
+ },
+];
const AdminRunnersFilteredSearchTokenKeys = new FilteredSearchTokenKeys(tokenKeys);
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 21b5ccdb613..b9bc5e6ed7f 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
@@ -21,9 +21,11 @@ export default {
},
computed: {
processedItems() {
- return this.items.map((item) => {
- const { tokens, searchToken }
- = FilteredSearchTokenizer.processTokens(item, this.allowedKeys);
+ return this.items.map(item => {
+ const { tokens, searchToken } = FilteredSearchTokenizer.processTokens(
+ item,
+ this.allowedKeys,
+ );
const resultantTokens = tokens.map(token => ({
prefix: `${token.key}:`,
diff --git a/app/assets/javascripts/filtered_search/dropdown_emoji.js b/app/assets/javascripts/filtered_search/dropdown_emoji.js
index 5ddd0e5e690..af7936a92fb 100644
--- a/app/assets/javascripts/filtered_search/dropdown_emoji.js
+++ b/app/assets/javascripts/filtered_search/dropdown_emoji.js
@@ -24,8 +24,12 @@ export default class DropdownEmoji extends FilteredSearchDropdown {
};
import(/* webpackChunkName: 'emoji' */ '~/emoji')
- .then(({ glEmojiTag }) => { this.glEmojiTag = glEmojiTag; })
- .catch(() => { /* ignore error and leave emoji name in the search bar */ });
+ .then(({ glEmojiTag }) => {
+ this.glEmojiTag = glEmojiTag;
+ })
+ .catch(() => {
+ /* ignore error and leave emoji name in the search bar */
+ });
this.unbindEvents();
this.bindEvents();
@@ -48,7 +52,7 @@ export default class DropdownEmoji extends FilteredSearchDropdown {
}
itemClicked(e) {
- super.itemClicked(e, (selected) => {
+ super.itemClicked(e, selected => {
const name = selected.querySelector('.js-data-value').innerText.trim();
return DropdownUtils.getEscapedText(name);
});
@@ -64,7 +68,7 @@ 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) => {
+ dropdownItems.forEach(dropdownItem => {
const name = dropdownItem.querySelector('.js-data-value').innerText;
const emojiTag = this.glEmojiTag(name);
const emojiElement = dropdownItem.querySelector('gl-emoji');
@@ -73,7 +77,6 @@ export default class DropdownEmoji extends FilteredSearchDropdown {
}
init() {
- this.droplab
- .addHook(this.input, this.dropdown, [Ajax, Filter], this.config).init();
+ this.droplab.addHook(this.input, this.dropdown, [Ajax, Filter], this.config).init();
}
}
diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js b/app/assets/javascripts/filtered_search/dropdown_hint.js
index c568f4e4ebf..1a1135ae929 100644
--- a/app/assets/javascripts/filtered_search/dropdown_hint.js
+++ b/app/assets/javascripts/filtered_search/dropdown_hint.js
@@ -41,8 +41,10 @@ export default class DropdownHint extends FilteredSearchDropdown {
previousInputValues.forEach((value, index) => {
searchTerms.push(value);
- if (index === previousInputValues.length - 1
- && token.indexOf(value.toLowerCase()) !== -1) {
+ if (
+ index === previousInputValues.length - 1 &&
+ token.indexOf(value.toLowerCase()) !== -1
+ ) {
searchTerms.pop();
}
});
@@ -64,13 +66,12 @@ export default class DropdownHint extends FilteredSearchDropdown {
}
renderContent() {
- const dropdownData = this.tokenKeys.get()
- .map(tokenKey => ({
- icon: `${gon.sprite_icons}#${tokenKey.icon}`,
- hint: tokenKey.key,
- tag: `:${tokenKey.tag}`,
- type: tokenKey.type,
- }));
+ const dropdownData = this.tokenKeys.get().map(tokenKey => ({
+ icon: `${gon.sprite_icons}#${tokenKey.icon}`,
+ hint: tokenKey.key,
+ tag: `:${tokenKey.tag}`,
+ type: tokenKey.type,
+ }));
this.droplab.changeHookList(this.hookId, this.dropdown, [Filter], this.config);
this.droplab.setData(this.hookId, dropdownData);
diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js b/app/assets/javascripts/filtered_search/dropdown_non_user.js
index 2ffda7e2037..0264f934914 100644
--- a/app/assets/javascripts/filtered_search/dropdown_non_user.js
+++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js
@@ -29,20 +29,18 @@ export default class DropdownNonUser extends FilteredSearchDropdown {
}
itemClicked(e) {
- super.itemClicked(e, (selected) => {
+ super.itemClicked(e, selected => {
const title = selected.querySelector('.js-data-value').innerText.trim();
return `${this.symbol}${DropdownUtils.getEscapedText(title)}`;
});
}
renderContent(forceShowList = false) {
- this.droplab
- .changeHookList(this.hookId, this.dropdown, [Ajax, Filter], this.config);
+ this.droplab.changeHookList(this.hookId, this.dropdown, [Ajax, Filter], this.config);
super.renderContent(forceShowList);
}
init() {
- this.droplab
- .addHook(this.input, this.dropdown, [Ajax, Filter], this.config).init();
+ this.droplab.addHook(this.input, this.dropdown, [Ajax, Filter], this.config).init();
}
}
diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js b/app/assets/javascripts/filtered_search/dropdown_utils.js
index 6da6ca10008..1b79a3320c6 100644
--- a/app/assets/javascripts/filtered_search/dropdown_utils.js
+++ b/app/assets/javascripts/filtered_search/dropdown_utils.js
@@ -41,7 +41,7 @@ export default class DropdownUtils {
// Removes the first character if it is a quotation so that we can search
// with multiple words
- if ((value[0] === '"' || value[0] === '\'') && title.indexOf(' ') !== -1) {
+ if ((value[0] === '"' || value[0] === "'") && title.indexOf(' ') !== -1) {
value = value.slice(1);
}
@@ -82,11 +82,13 @@ export default class DropdownUtils {
// Reduce the colors to 4
colors.length = Math.min(colors.length, 4);
- const color = colors.map((c, i) => {
- const percentFirst = Math.floor(spacing * i);
- const percentSecond = Math.floor(spacing * (i + 1));
- return `${c} ${percentFirst}%, ${c} ${percentSecond}%`;
- }).join(', ');
+ const color = colors
+ .map((c, i) => {
+ const percentFirst = Math.floor(spacing * i);
+ const percentSecond = Math.floor(spacing * (i + 1));
+ return `${c} ${percentFirst}%, ${c} ${percentSecond}%`;
+ })
+ .join(', ');
return `linear-gradient(${color})`;
}
@@ -97,17 +99,16 @@ export default class DropdownUtils {
data.forEach(DropdownUtils.mergeDuplicateLabels.bind(null, dataMap));
- Object.keys(dataMap)
- .forEach((key) => {
- const label = dataMap[key];
+ Object.keys(dataMap).forEach(key => {
+ const label = dataMap[key];
- if (label.multipleColors) {
- label.color = DropdownUtils.duplicateLabelColor(label.multipleColors);
- label.text_color = '#000000';
- }
+ if (label.multipleColors) {
+ label.color = DropdownUtils.duplicateLabelColor(label.multipleColors);
+ label.text_color = '#000000';
+ }
- results.push(label);
- });
+ results.push(label);
+ });
results.preprocessed = true;
@@ -118,8 +119,7 @@ export default class DropdownUtils {
const { input, allowedKeys } = config;
const updatedItem = item;
const searchInput = DropdownUtils.getSearchQuery(input);
- const { lastToken, tokens } =
- FilteredSearchTokenizer.processTokens(searchInput, allowedKeys);
+ const { lastToken, tokens } = FilteredSearchTokenizer.processTokens(searchInput, allowedKeys);
const lastKey = lastToken.key || lastToken || '';
const allowMultiple = item.type === 'array';
const itemInExistingTokens = tokens.some(t => t.key === item.hint);
@@ -154,7 +154,10 @@ export default class DropdownUtils {
static getVisualTokenValues(visualToken) {
const tokenName = visualToken && visualToken.querySelector('.name').textContent.trim();
- let tokenValue = visualToken && visualToken.querySelector('.value') && visualToken.querySelector('.value').textContent.trim();
+ let tokenValue =
+ visualToken &&
+ visualToken.querySelector('.value') &&
+ visualToken.querySelector('.value').textContent.trim();
if (tokenName === 'label' && tokenValue) {
// remove leading symbol and wrapping quotes
tokenValue = tokenValue.replace(/^~("|')?(.*)/, '$2').replace(/("|')$/, '');
@@ -174,7 +177,7 @@ export default class DropdownUtils {
tokens.splice(inputIndex + 1);
}
- tokens.forEach((token) => {
+ tokens.forEach(token => {
if (token.classList.contains('js-visual-token')) {
const name = token.querySelector('.name');
const value = token.querySelector('.value');
@@ -194,8 +197,9 @@ export default class DropdownUtils {
values.push(name.innerText);
}
} else if (token.classList.contains('input-token')) {
- const { isLastVisualTokenValid } =
- FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ const {
+ isLastVisualTokenValid,
+ } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
const input = FilteredSearchContainer.container.querySelector('.filtered-search');
const inputValue = input && input.value;
@@ -209,9 +213,7 @@ export default class DropdownUtils {
}
});
- return values
- .map(value => value.trim())
- .join(' ');
+ return values.map(value => value.trim()).join(' ');
}
static getSearchInput(filteredSearchInput) {
@@ -227,7 +229,9 @@ export default class DropdownUtils {
// Replace all spaces inside quote marks with underscores
// (will continue to match entire string until an end quote is found if any)
// This helps with matching the beginning & end of a token:key
- inputValue = inputValue.replace(/(('[^']*'{0,1})|("[^"]*"{0,1})|:\s+)/g, str => str.replace(/\s/g, '_'));
+ inputValue = inputValue.replace(/(('[^']*'{0,1})|("[^"]*"{0,1})|:\s+)/g, str =>
+ str.replace(/\s/g, '_'),
+ );
// Get the right position for the word selected
// Regex matches first space
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
index fb4ae1d17dd..4eb67ff7649 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown.js
@@ -87,10 +87,12 @@ export default class FilteredSearchDropdown {
dispatchInputEvent() {
// Propogate input change to FilteredSearchDropdownManager
// so that it can determine which dropdowns to open
- this.input.dispatchEvent(new CustomEvent('input', {
- bubbles: true,
- cancelable: true,
- }));
+ this.input.dispatchEvent(
+ new CustomEvent('input', {
+ bubbles: true,
+ cancelable: true,
+ }),
+ );
}
dispatchFormSubmitEvent() {
@@ -114,7 +116,7 @@ export default class FilteredSearchDropdown {
if (!data) return;
- const results = data.map((o) => {
+ const results = data.map(o => {
const updated = o;
updated.droplab_hidden = false;
return updated;
diff --git a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js
index a09ad3e4758..e01dedbb57c 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_token_keys.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_token_keys.js
@@ -42,19 +42,21 @@ export default class FilteredSearchTokenKeys {
}
searchByKeyParam(keyParam) {
- return this.tokenKeysWithAlternative.find((tokenKey) => {
- let tokenKeyParam = tokenKey.key;
+ return (
+ this.tokenKeysWithAlternative.find(tokenKey => {
+ let tokenKeyParam = tokenKey.key;
- // Replace hyphen with underscore to compare keyParam with tokenKeyParam
- // e.g. 'my-reaction' => 'my_reaction'
- tokenKeyParam = tokenKeyParam.replace('-', '_');
+ // Replace hyphen with underscore to compare keyParam with tokenKeyParam
+ // e.g. 'my-reaction' => 'my_reaction'
+ tokenKeyParam = tokenKeyParam.replace('-', '_');
- if (tokenKey.param) {
- tokenKeyParam += `_${tokenKey.param}`;
- }
+ if (tokenKey.param) {
+ tokenKeyParam += `_${tokenKey.param}`;
+ }
- return keyParam === tokenKeyParam;
- }) || null;
+ return keyParam === tokenKeyParam;
+ }) || null
+ );
}
searchByConditionUrl(url) {
@@ -62,8 +64,10 @@ export default class FilteredSearchTokenKeys {
}
searchByConditionKeyValue(key, value) {
- return this.conditions
- .find(condition => condition.tokenKey === key && condition.value === value) || null;
+ return (
+ this.conditions.find(condition => condition.tokenKey === key && condition.value === value) ||
+ null
+ );
}
addExtraTokensForMergeRequests() {
diff --git a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js
index d75610f6d68..b5c4cb15aac 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_tokenizer.js
@@ -4,41 +4,48 @@ export default class FilteredSearchTokenizer {
static processTokens(input, allowedKeys) {
// Regex extracts `(token):(symbol)(value)`
// Values that start with a double quote must end in a double quote (same for single)
- const tokenRegex = new RegExp(`(${allowedKeys.join('|')}):([~%@]?)(?:('[^']*'{0,1})|("[^"]*"{0,1})|(\\S+))`, 'g');
+ const tokenRegex = new RegExp(
+ `(${allowedKeys.join('|')}):([~%@]?)(?:('[^']*'{0,1})|("[^"]*"{0,1})|(\\S+))`,
+ 'g',
+ );
const tokens = [];
const tokenIndexes = []; // stores key+value for simple search
let lastToken = null;
- const searchToken = input.replace(tokenRegex, (match, key, symbol, v1, v2, v3) => {
- let tokenValue = v1 || v2 || v3;
- let tokenSymbol = symbol;
- let tokenIndex = '';
-
- if (tokenValue === '~' || tokenValue === '%' || tokenValue === '@') {
- tokenSymbol = tokenValue;
- tokenValue = '';
- }
-
- tokenIndex = `${key}:${tokenValue}`;
-
- // Prevent adding duplicates
- if (tokenIndexes.indexOf(tokenIndex) === -1) {
- tokenIndexes.push(tokenIndex);
-
- tokens.push({
- key,
- value: tokenValue || '',
- symbol: tokenSymbol || '',
- });
- }
-
- return '';
- }).replace(/\s{2,}/g, ' ').trim() || '';
+ const searchToken =
+ input
+ .replace(tokenRegex, (match, key, symbol, v1, v2, v3) => {
+ let tokenValue = v1 || v2 || v3;
+ let tokenSymbol = symbol;
+ let tokenIndex = '';
+
+ if (tokenValue === '~' || tokenValue === '%' || tokenValue === '@') {
+ tokenSymbol = tokenValue;
+ tokenValue = '';
+ }
+
+ tokenIndex = `${key}:${tokenValue}`;
+
+ // Prevent adding duplicates
+ if (tokenIndexes.indexOf(tokenIndex) === -1) {
+ tokenIndexes.push(tokenIndex);
+
+ tokens.push({
+ key,
+ value: tokenValue || '',
+ symbol: tokenSymbol || '',
+ });
+ }
+
+ return '';
+ })
+ .replace(/\s{2,}/g, ' ')
+ .trim() || '';
if (tokens.length > 0) {
const last = tokens[tokens.length - 1];
const lastString = `${last.key}:${last.symbol}${last.value}`;
- lastToken = input.lastIndexOf(lastString) ===
- input.length - lastString.length ? last : searchToken;
+ lastToken =
+ input.lastIndexOf(lastString) === input.length - lastString.length ? last : searchToken;
} else {
lastToken = searchToken;
}
diff --git a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js
index 0854c1822fb..c23d4c484a5 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js
@@ -13,7 +13,10 @@ export default class FilteredSearchVisualTokens {
return {
lastVisualToken,
- isLastVisualTokenValid: lastVisualToken === null || lastVisualToken.className.indexOf('filtered-search-term') !== -1 || (lastVisualToken && lastVisualToken.querySelector('.value') !== null),
+ isLastVisualTokenValid:
+ lastVisualToken === null ||
+ lastVisualToken.className.indexOf('filtered-search-term') !== -1 ||
+ (lastVisualToken && lastVisualToken.querySelector('.value') !== null),
};
}
@@ -33,7 +36,9 @@ export default class FilteredSearchVisualTokens {
}
static unselectTokens() {
- const otherTokens = FilteredSearchContainer.container.querySelectorAll('.js-visual-token .selectable.selected');
+ const otherTokens = FilteredSearchContainer.container.querySelectorAll(
+ '.js-visual-token .selectable.selected',
+ );
[].forEach.call(otherTokens, t => t.classList.remove('selected'));
}
@@ -56,11 +61,7 @@ export default class FilteredSearchVisualTokens {
}
static createVisualTokenElementHTML(options = {}) {
- const {
- canEdit = true,
- uppercaseTokenName = false,
- capitalizeTokenValue = false,
- } = options;
+ const { canEdit = true, uppercaseTokenName = false, capitalizeTokenValue = false } = options;
return `
<div class="${canEdit ? 'selectable' : 'hidden'}" role="button">
@@ -115,15 +116,20 @@ export default class FilteredSearchVisualTokens {
return AjaxCache.retrieve(labelsEndpoint)
.then(FilteredSearchVisualTokens.preprocessLabel.bind(null, labelsEndpoint))
- .then((labels) => {
- const matchingLabel = (labels || []).find(label => `~${DropdownUtils.getEscapedText(label.title)}` === tokenValue);
+ .then(labels => {
+ const matchingLabel = (labels || []).find(
+ label => `~${DropdownUtils.getEscapedText(label.title)}` === tokenValue,
+ );
if (!matchingLabel) {
return;
}
- FilteredSearchVisualTokens
- .setTokenStyle(tokenValueContainer, matchingLabel.color, matchingLabel.text_color);
+ FilteredSearchVisualTokens.setTokenStyle(
+ tokenValueContainer,
+ matchingLabel.color,
+ matchingLabel.text_color,
+ );
})
.catch(() => new Flash('An error occurred while fetching label colors.'));
}
@@ -134,39 +140,43 @@ export default class FilteredSearchVisualTokens {
}
const username = tokenValue.replace(/^@/, '');
- return UsersCache.retrieve(username)
- .then((user) => {
- if (!user) {
- return;
- }
-
- /* eslint-disable no-param-reassign */
- tokenValueContainer.dataset.originalValue = tokenValue;
- tokenValueElement.innerHTML = `
+ return (
+ UsersCache.retrieve(username)
+ .then(user => {
+ if (!user) {
+ return;
+ }
+
+ /* eslint-disable no-param-reassign */
+ tokenValueContainer.dataset.originalValue = tokenValue;
+ tokenValueElement.innerHTML = `
<img class="avatar s20" src="${user.avatar_url}" alt="">
${_.escape(user.name)}
`;
- /* eslint-enable no-param-reassign */
- })
- // ignore error and leave username in the search bar
- .catch(() => { });
+ /* eslint-enable no-param-reassign */
+ })
+ // ignore error and leave username in the search bar
+ .catch(() => {})
+ );
}
static updateEmojiTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue) {
const container = tokenValueContainer;
const element = tokenValueElement;
- return import(/* webpackChunkName: 'emoji' */ '../emoji')
- .then((Emoji) => {
- if (!Emoji.isEmojiNameValid(tokenValue)) {
- return;
- }
-
- container.dataset.originalValue = tokenValue;
- element.innerHTML = Emoji.glEmojiTag(tokenValue);
- })
- // ignore error and leave emoji name in the search bar
- .catch(() => { });
+ return (
+ import(/* webpackChunkName: 'emoji' */ '../emoji')
+ .then(Emoji => {
+ if (!Emoji.isEmojiNameValid(tokenValue)) {
+ return;
+ }
+
+ container.dataset.originalValue = tokenValue;
+ element.innerHTML = Emoji.glEmojiTag(tokenValue);
+ })
+ // ignore error and leave emoji name in the search bar
+ .catch(() => {})
+ );
}
static renderVisualTokenValue(parentElement, tokenName, tokenValue) {
@@ -177,24 +187,23 @@ export default class FilteredSearchVisualTokens {
const tokenType = tokenName.toLowerCase();
if (tokenType === 'label') {
FilteredSearchVisualTokens.updateLabelTokenColor(tokenValueContainer, tokenValue);
- } else if ((tokenType === 'author') || (tokenType === 'assignee')) {
+ } else if (tokenType === 'author' || tokenType === 'assignee') {
FilteredSearchVisualTokens.updateUserTokenAppearance(
- tokenValueContainer, tokenValueElement, tokenValue,
+ tokenValueContainer,
+ tokenValueElement,
+ tokenValue,
);
} else if (tokenType === 'my-reaction') {
FilteredSearchVisualTokens.updateEmojiTokenAppearance(
- tokenValueContainer, tokenValueElement, tokenValue,
+ tokenValueContainer,
+ tokenValueElement,
+ tokenValue,
);
}
}
static addVisualTokenElement(name, value, options = {}) {
- const {
- isSearchTerm = false,
- canEdit,
- uppercaseTokenName,
- capitalizeTokenValue,
- } = options;
+ const { isSearchTerm = false, canEdit, uppercaseTokenName, capitalizeTokenValue } = options;
const li = document.createElement('li');
li.classList.add('js-visual-token');
li.classList.add(isSearchTerm ? 'filtered-search-term' : 'filtered-search-token');
@@ -217,8 +226,10 @@ export default class FilteredSearchVisualTokens {
}
static addValueToPreviousVisualTokenElement(value) {
- const { lastVisualToken, isLastVisualTokenValid } =
- FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ const {
+ lastVisualToken,
+ isLastVisualTokenValid,
+ } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
if (!isLastVisualTokenValid && lastVisualToken.classList.contains('filtered-search-token')) {
const name = FilteredSearchVisualTokens.getLastTokenPartial();
@@ -228,13 +239,15 @@ export default class FilteredSearchVisualTokens {
}
}
- static addFilterVisualToken(tokenName, tokenValue, {
- canEdit,
- uppercaseTokenName = false,
- capitalizeTokenValue = false,
- } = {}) {
- const { lastVisualToken, isLastVisualTokenValid }
- = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ static addFilterVisualToken(
+ tokenName,
+ tokenValue,
+ { canEdit, uppercaseTokenName = false, capitalizeTokenValue = false } = {},
+ ) {
+ const {
+ lastVisualToken,
+ isLastVisualTokenValid,
+ } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
const { addVisualTokenElement } = FilteredSearchVisualTokens;
if (isLastVisualTokenValid) {
@@ -308,8 +321,7 @@ export default class FilteredSearchVisualTokens {
static tokenizeInput() {
const input = FilteredSearchContainer.container.querySelector('.filtered-search');
- const { isLastVisualTokenValid } =
- FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ const { isLastVisualTokenValid } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
if (input.value) {
if (isLastVisualTokenValid) {
@@ -375,8 +387,7 @@ export default class FilteredSearchVisualTokens {
FilteredSearchVisualTokens.tokenizeInput();
if (!tokenContainer.lastElementChild.isEqualNode(inputLi)) {
- const { isLastVisualTokenValid } =
- FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
+ const { isLastVisualTokenValid } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput();
if (!isLastVisualTokenValid) {
const lastPartial = FilteredSearchVisualTokens.getLastTokenPartial();
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 cc7291c9f59..b70125c80ca 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
@@ -1,34 +1,39 @@
import FilteredSearchTokenKeys from './filtered_search_token_keys';
-export const tokenKeys = [{
- key: 'author',
- type: 'string',
- param: 'username',
- symbol: '@',
- icon: 'pencil',
- tag: '@author',
-}, {
- key: 'assignee',
- type: 'string',
- param: 'username',
- symbol: '@',
- icon: 'user',
- tag: '@assignee',
-}, {
- key: 'milestone',
- type: 'string',
- param: 'title',
- symbol: '%',
- icon: 'clock',
- tag: '%milestone',
-}, {
- key: 'label',
- type: 'array',
- param: 'name[]',
- symbol: '~',
- icon: 'labels',
- tag: '~label',
-}];
+export const tokenKeys = [
+ {
+ key: 'author',
+ type: 'string',
+ param: 'username',
+ symbol: '@',
+ icon: 'pencil',
+ tag: '@author',
+ },
+ {
+ key: 'assignee',
+ type: 'string',
+ param: 'username',
+ symbol: '@',
+ icon: 'user',
+ tag: '@assignee',
+ },
+ {
+ key: 'milestone',
+ type: 'string',
+ param: 'title',
+ symbol: '%',
+ icon: 'clock',
+ tag: '%milestone',
+ },
+ {
+ key: 'label',
+ type: 'array',
+ param: 'name[]',
+ symbol: '~',
+ icon: 'labels',
+ tag: '~label',
+ },
+];
if (gon.current_user_id) {
// Appending tokenkeys only logged-in
@@ -42,36 +47,52 @@ if (gon.current_user_id) {
});
}
-export const alternativeTokenKeys = [{
- key: 'label',
- type: 'string',
- param: 'name',
- symbol: '~',
-}];
+export const alternativeTokenKeys = [
+ {
+ key: 'label',
+ type: 'string',
+ param: 'name',
+ symbol: '~',
+ },
+];
-export const conditions = [{
- url: 'assignee_id=0',
- tokenKey: 'assignee',
- value: 'none',
-}, {
- url: 'milestone_title=No+Milestone',
- tokenKey: 'milestone',
- value: 'none',
-}, {
- url: 'milestone_title=%23upcoming',
- tokenKey: 'milestone',
- value: 'upcoming',
-}, {
- url: 'milestone_title=%23started',
- tokenKey: 'milestone',
- value: 'started',
-}, {
- url: 'label_name[]=No+Label',
- tokenKey: 'label',
- value: 'none',
-}];
+export const conditions = [
+ {
+ url: 'assignee_id=0',
+ tokenKey: 'assignee',
+ value: 'none',
+ },
+ {
+ url: 'milestone_title=No+Milestone',
+ tokenKey: 'milestone',
+ value: 'none',
+ },
+ {
+ url: 'milestone_title=Any+Milestone',
+ tokenKey: 'milestone',
+ value: 'any',
+ },
+ {
+ url: 'milestone_title=%23upcoming',
+ tokenKey: 'milestone',
+ value: 'upcoming',
+ },
+ {
+ url: 'milestone_title=%23started',
+ tokenKey: 'milestone',
+ value: 'started',
+ },
+ {
+ url: 'label_name[]=No+Label',
+ tokenKey: 'label',
+ value: 'none',
+ },
+];
-const IssuableFilteredSearchTokenKeys =
- new FilteredSearchTokenKeys(tokenKeys, alternativeTokenKeys, conditions);
+const IssuableFilteredSearchTokenKeys = new FilteredSearchTokenKeys(
+ tokenKeys,
+ alternativeTokenKeys,
+ conditions,
+);
export default IssuableFilteredSearchTokenKeys;
diff --git a/app/assets/javascripts/filtered_search/recent_searches_root.js b/app/assets/javascripts/filtered_search/recent_searches_root.js
index c1efa9c86f4..6c8e77a7fe5 100644
--- a/app/assets/javascripts/filtered_search/recent_searches_root.js
+++ b/app/assets/javascripts/filtered_search/recent_searches_root.js
@@ -3,11 +3,7 @@ import RecentSearchesDropdownContent from './components/recent_searches_dropdown
import eventHub from './event_hub';
class RecentSearchesRoot {
- constructor(
- recentSearchesStore,
- recentSearchesService,
- wrapperElement,
- ) {
+ constructor(recentSearchesStore, recentSearchesService, wrapperElement) {
this.store = recentSearchesStore;
this.service = recentSearchesService;
this.wrapperElement = wrapperElement;
@@ -35,7 +31,9 @@ class RecentSearchesRoot {
components: {
RecentSearchesDropdownContent,
},
- data() { return state; },
+ data() {
+ return state;
+ },
template: `
<recent-searches-dropdown-content
:items="recentSearches"
@@ -57,7 +55,6 @@ class RecentSearchesRoot {
this.vm.$destroy();
}
}
-
}
export default RecentSearchesRoot;
diff --git a/app/assets/javascripts/filtered_search/stores/recent_searches_store.js b/app/assets/javascripts/filtered_search/stores/recent_searches_store.js
index aaa0c349d93..76d40bfdaf8 100644
--- a/app/assets/javascripts/filtered_search/stores/recent_searches_store.js
+++ b/app/assets/javascripts/filtered_search/stores/recent_searches_store.js
@@ -2,11 +2,14 @@ import _ from 'underscore';
class RecentSearchesStore {
constructor(initialState = {}, allowedKeys) {
- this.state = Object.assign({
- isLocalStorageAvailable: true,
- recentSearches: [],
- allowedKeys,
- }, initialState);
+ this.state = Object.assign(
+ {
+ isLocalStorageAvailable: true,
+ recentSearches: [],
+ allowedKeys,
+ },
+ initialState,
+ );
}
addRecentSearch(newSearch) {
diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js
index a29de9ae899..749c09f897c 100644
--- a/app/assets/javascripts/flash.js
+++ b/app/assets/javascripts/flash.js
@@ -8,14 +8,19 @@ const hideFlash = (flashEl, fadeTransition = true) => {
});
}
- flashEl.addEventListener('transitionend', () => {
- flashEl.remove();
- window.dispatchEvent(new Event('resize'));
- if (document.body.classList.contains('flash-shown')) document.body.classList.remove('flash-shown');
- }, {
- once: true,
- passive: true,
- });
+ flashEl.addEventListener(
+ 'transitionend',
+ () => {
+ flashEl.remove();
+ window.dispatchEvent(new Event('resize'));
+ if (document.body.classList.contains('flash-shown'))
+ document.body.classList.remove('flash-shown');
+ },
+ {
+ once: true,
+ passive: true,
+ },
+ );
if (!fadeTransition) flashEl.dispatchEvent(new Event('transitionend'));
};
@@ -30,12 +35,12 @@ const createAction = config => `
</a>
`;
-const createFlashEl = (message, type, isInContentWrapper = false) => `
+const createFlashEl = (message, type, isFixedLayout = false) => `
<div
class="flash-${type}"
>
<div
- class="flash-text ${isInContentWrapper ? 'container-fluid container-limited' : ''}"
+ class="flash-text ${isFixedLayout ? 'container-fluid container-limited limit-container-width' : ''}"
>
${_.escape(message)}
</div>
@@ -69,12 +74,13 @@ const createFlash = function createFlash(
addBodyClass = false,
) {
const flashContainer = parent.querySelector('.flash-container');
+ const navigation = parent.querySelector('.content');
if (!flashContainer) return null;
- const isInContentWrapper = flashContainer.parentNode.classList.contains('content-wrapper');
+ const isFixedLayout = navigation ? navigation.parentNode.classList.contains('container-limited') : true;
- flashContainer.innerHTML = createFlashEl(message, type, isInContentWrapper);
+ flashContainer.innerHTML = createFlashEl(message, type, isFixedLayout);
const flashEl = flashContainer.querySelector(`.flash-${type}`);
removeFlashClickListener(flashEl, fadeTransition);
@@ -83,7 +89,9 @@ const createFlash = function createFlash(
flashEl.innerHTML += createAction(actionConfig);
if (actionConfig.clickHandler) {
- flashEl.querySelector('.flash-action').addEventListener('click', e => actionConfig.clickHandler(e));
+ flashEl
+ .querySelector('.flash-action')
+ .addEventListener('click', e => actionConfig.clickHandler(e));
}
}
@@ -94,11 +102,5 @@ const createFlash = function createFlash(
return flashContainer;
};
-export {
- createFlash as default,
- createFlashEl,
- createAction,
- hideFlash,
- removeFlashClickListener,
-};
+export { createFlash as default, createFlashEl, createAction, hideFlash, removeFlashClickListener };
window.Flash = createFlash;
diff --git a/app/assets/javascripts/fly_out_nav.js b/app/assets/javascripts/fly_out_nav.js
index f820f0dc3f0..3ac00c51df4 100644
--- a/app/assets/javascripts/fly_out_nav.js
+++ b/app/assets/javascripts/fly_out_nav.js
@@ -11,9 +11,13 @@ let sidebar;
export const mousePos = [];
-export const setSidebar = (el) => { sidebar = el; };
+export const setSidebar = el => {
+ sidebar = el;
+};
export const getOpenMenu = () => currentOpenMenu;
-export const setOpenMenu = (menu = null) => { currentOpenMenu = menu; };
+export const setOpenMenu = (menu = null) => {
+ currentOpenMenu = menu;
+};
export const slope = (a, b) => (b.y - a.y) / (b.x - a.x);
@@ -21,9 +25,10 @@ let headerHeight = 50;
export const getHeaderHeight = () => headerHeight;
-export const isSidebarCollapsed = () => sidebar && sidebar.classList.contains('sidebar-collapsed-desktop');
+export const isSidebarCollapsed = () =>
+ sidebar && sidebar.classList.contains('sidebar-collapsed-desktop');
-export const canShowActiveSubItems = (el) => {
+export const canShowActiveSubItems = el => {
if (el.classList.contains('active') && !isSidebarCollapsed()) {
return false;
}
@@ -31,7 +36,10 @@ export const canShowActiveSubItems = (el) => {
return true;
};
-export const canShowSubItems = () => bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md' || bp.getBreakpointSize() === 'lg';
+export const canShowSubItems = () =>
+ bp.getBreakpointSize() === 'sm' ||
+ bp.getBreakpointSize() === 'md' ||
+ bp.getBreakpointSize() === 'lg';
export const getHideSubItemsInterval = () => {
if (!currentOpenMenu || !mousePos.length) return 0;
@@ -41,11 +49,12 @@ export const getHideSubItemsInterval = () => {
const currentMousePosY = currentMousePos.y;
const [menuTop, menuBottom] = menuCornerLocs;
- if (currentMousePosY < menuTop.y ||
- currentMousePosY > menuBottom.y) return 0;
+ if (currentMousePosY < menuTop.y || currentMousePosY > menuBottom.y) return 0;
- if (slope(prevMousePos, menuBottom) < slope(currentMousePos, menuBottom) &&
- slope(prevMousePos, menuTop) > slope(currentMousePos, menuTop)) {
+ if (
+ slope(prevMousePos, menuBottom) < slope(currentMousePos, menuBottom) &&
+ slope(prevMousePos, menuTop) > slope(currentMousePos, menuTop)
+ ) {
return HIDE_INTERVAL_TIMEOUT;
}
@@ -56,11 +65,12 @@ export const calculateTop = (boundingRect, outerHeight) => {
const windowHeight = window.innerHeight;
const bottomOverflow = windowHeight - (boundingRect.top + outerHeight);
- return bottomOverflow < 0 ? (boundingRect.top - outerHeight) + boundingRect.height :
- boundingRect.top;
+ return bottomOverflow < 0
+ ? boundingRect.top - outerHeight + boundingRect.height
+ : boundingRect.top;
};
-export const hideMenu = (el) => {
+export const hideMenu = el => {
if (!el) return;
const parentEl = el.parentNode;
@@ -101,7 +111,7 @@ export const moveSubItemsToPosition = (el, subItems) => {
}
};
-export const showSubLevelItems = (el) => {
+export const showSubLevelItems = el => {
const subItems = el.querySelector('.sidebar-sub-level-items');
const isIconOnly = subItems && subItems.classList.contains('is-fly-out-only');
@@ -128,16 +138,20 @@ export const mouseEnterTopItems = (el, timeout = getHideSubItemsInterval()) => {
}, timeout);
};
-export const mouseLeaveTopItem = (el) => {
+export const mouseLeaveTopItem = el => {
const subItems = el.querySelector('.sidebar-sub-level-items');
- if (!canShowSubItems() || !canShowActiveSubItems(el) ||
- (subItems && subItems === currentOpenMenu)) return;
+ if (
+ !canShowSubItems() ||
+ !canShowActiveSubItems(el) ||
+ (subItems && subItems === currentOpenMenu)
+ )
+ return;
el.classList.remove(IS_OVER_CLASS);
};
-export const documentMouseMove = (e) => {
+export const documentMouseMove = e => {
mousePos.push({
x: e.clientX,
y: e.clientY,
@@ -146,7 +160,7 @@ export const documentMouseMove = (e) => {
if (mousePos.length > 6) mousePos.shift();
};
-export const subItemsMouseLeave = (relatedTarget) => {
+export const subItemsMouseLeave = relatedTarget => {
clearTimeout(timeoutId);
if (relatedTarget && !relatedTarget.closest(`.${IS_OVER_CLASS}`)) {
@@ -174,7 +188,7 @@ export default () => {
headerHeight = document.querySelector('.nav-sidebar').offsetTop;
- items.forEach((el) => {
+ items.forEach(el => {
const subItems = el.querySelector('.sidebar-sub-level-items');
if (subItems) {
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 a6a265eb3fd..14c223c61a4 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
@@ -1,10 +1,14 @@
<script>
import _ from 'underscore';
import { mapActions } from 'vuex';
+import Icon from '~/vue_shared/components/icon.vue';
import eventHub from '../event_hub';
import frequentItemsMixin from './frequent_items_mixin';
export default {
+ components: {
+ Icon,
+ },
mixins: [frequentItemsMixin],
data() {
return {
@@ -45,11 +49,10 @@ export default {
type="search"
class="form-control"
/>
- <i
+ <icon
v-if="!searchQuery"
- class="search-icon fa fa-fw fa-search"
- aria-hidden="true"
- >
- </i>
+ name="search"
+ class="search-icon"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/gl_field_error.js b/app/assets/javascripts/gl_field_error.js
index 87c6e37b9fb..a5b8c357e8a 100644
--- a/app/assets/javascripts/gl_field_error.js
+++ b/app/assets/javascripts/gl_field_error.js
@@ -116,7 +116,8 @@ export default class GlFieldError {
this.form.focusOnFirstInvalid.apply(this.form);
// For UX, wait til after first invalid submission to check each keyup
- this.inputElement.off('keyup.fieldValidator')
+ this.inputElement
+ .off('keyup.fieldValidator')
.on('keyup.fieldValidator', this.updateValidity.bind(this));
}
diff --git a/app/assets/javascripts/gl_field_errors.js b/app/assets/javascripts/gl_field_errors.js
index b9c51045b1d..3764e7ab422 100644
--- a/app/assets/javascripts/gl_field_errors.js
+++ b/app/assets/javascripts/gl_field_errors.js
@@ -16,9 +16,12 @@ export default class GlFieldErrors {
initValidators() {
// register selectors here as needed
const validateSelectors = [':text', ':password', '[type=email]']
- .map(selector => `input${selector}`).join(',');
+ .map(selector => `input${selector}`)
+ .join(',');
- this.state.inputs = this.form.find(validateSelectors).toArray()
+ this.state.inputs = this.form
+ .find(validateSelectors)
+ .toArray()
.filter(input => !input.classList.contains(customValidationFlag))
.map(input => new GlFieldError({ input, formErrors: this }));
@@ -42,7 +45,7 @@ export default class GlFieldErrors {
/* Public method for triggering validity updates manually */
updateFormValidityState() {
- this.state.inputs.forEach((field) => {
+ this.state.inputs.forEach(field => {
if (field.state.submitted) {
field.updateValidity();
}
@@ -50,8 +53,9 @@ export default class GlFieldErrors {
}
focusOnFirstInvalid() {
- const firstInvalid = this.state.inputs
- .filter(input => !input.inputDomElement.validity.valid)[0];
+ const firstInvalid = this.state.inputs.filter(
+ input => !input.inputDomElement.validity.valid,
+ )[0];
firstInvalid.inputElement.focus();
}
}
diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js
index e672284a2d0..f842d2d74db 100644
--- a/app/assets/javascripts/gl_form.js
+++ b/app/assets/javascripts/gl_form.js
@@ -39,7 +39,10 @@ export default class GLForm {
this.form.find('.div-dropzone').remove();
this.form.addClass('gfm-form');
// remove notify commit author checkbox for non-commit notes
- gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button, .js-note-new-discussion'));
+ gl.utils.disableButtonIfEmptyField(
+ this.form.find('.js-note-text'),
+ this.form.find('.js-comment-button, .js-note-new-discussion'),
+ );
this.autoComplete = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
this.autoComplete.setup(this.form.find('.js-gfm-input'), this.enableGFM);
dropzoneInput(this.form);
@@ -55,11 +58,9 @@ export default class GLForm {
}
setupAutosize() {
- this.textarea.off('autosize:resized')
- .on('autosize:resized', this.setHeightData.bind(this));
+ this.textarea.off('autosize:resized').on('autosize:resized', this.setHeightData.bind(this));
- this.textarea.off('mouseup.autosize')
- .on('mouseup.autosize', this.destroyAutosize.bind(this));
+ this.textarea.off('mouseup.autosize').on('mouseup.autosize', this.destroyAutosize.bind(this));
setTimeout(() => {
autosize(this.textarea);
@@ -91,10 +92,14 @@ export default class GLForm {
addEventListeners() {
this.textarea.on('focus', function focusTextArea() {
- $(this).closest('.md-area').addClass('is-focused');
+ $(this)
+ .closest('.md-area')
+ .addClass('is-focused');
});
this.textarea.on('blur', function blurTextArea() {
- $(this).closest('.md-area').removeClass('is-focused');
+ $(this)
+ .closest('.md-area')
+ .removeClass('is-focused');
});
}
}
diff --git a/app/assets/javascripts/group_avatar.js b/app/assets/javascripts/group_avatar.js
index beaac61e887..dcda625f587 100644
--- a/app/assets/javascripts/group_avatar.js
+++ b/app/assets/javascripts/group_avatar.js
@@ -7,8 +7,9 @@ export default function groupAvatar() {
});
$('.js-group-avatar-input').on('change', function onChangeAvatarInput() {
const form = $(this).closest('form');
- // eslint-disable-next-line no-useless-escape
- const filename = $(this).val().replace(/^.*[\\\/]/, '');
+ 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/group_label_subscription.js b/app/assets/javascripts/group_label_subscription.js
index d33e3a37580..9b74560f914 100644
--- a/app/assets/javascripts/group_label_subscription.js
+++ b/app/assets/javascripts/group_label_subscription.js
@@ -23,7 +23,8 @@ export default class GroupLabelSubscription {
event.preventDefault();
const url = this.$unsubscribeButtons.attr('data-url');
- axios.post(url)
+ axios
+ .post(url)
.then(() => {
this.toggleSubscriptionButtons();
this.$unsubscribeButtons.removeAttr('data-url');
@@ -39,7 +40,8 @@ export default class GroupLabelSubscription {
this.$unsubscribeButtons.attr('data-url', url);
- axios.post(url)
+ axios
+ .post(url)
.then(() => GroupLabelSubscription.setNewTooltip($btn))
.then(() => this.toggleSubscriptionButtons())
.catch(() => flash(__('There was an error when subscribing to this label.')));
@@ -58,6 +60,8 @@ export default class GroupLabelSubscription {
const newTitle = tooltipTitles[type];
$('.js-unsubscribe-button', $button.closest('.label-actions-list'))
- .tooltip('hide').attr('title', newTitle).tooltip('_fixTitle');
+ .tooltip('hide')
+ .attr('title', newTitle)
+ .tooltip('_fixTitle');
}
}
diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue
index 87ab5480c15..829924ba63c 100644
--- a/app/assets/javascripts/groups/components/item_stats.vue
+++ b/app/assets/javascripts/groups/components/item_stats.vue
@@ -1,44 +1,44 @@
<script>
- import icon from '~/vue_shared/components/icon.vue';
- import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
- import {
- ITEM_TYPE,
- VISIBILITY_TYPE_ICON,
- GROUP_VISIBILITY_TYPE,
- PROJECT_VISIBILITY_TYPE,
- } from '../constants';
- import itemStatsValue from './item_stats_value.vue';
+import icon from '~/vue_shared/components/icon.vue';
+import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import {
+ ITEM_TYPE,
+ VISIBILITY_TYPE_ICON,
+ GROUP_VISIBILITY_TYPE,
+ PROJECT_VISIBILITY_TYPE,
+} from '../constants';
+import itemStatsValue from './item_stats_value.vue';
- export default {
- components: {
- icon,
- timeAgoTooltip,
- itemStatsValue,
+export default {
+ components: {
+ icon,
+ timeAgoTooltip,
+ itemStatsValue,
+ },
+ props: {
+ item: {
+ type: Object,
+ required: true,
},
- props: {
- item: {
- type: Object,
- required: true,
- },
+ },
+ computed: {
+ visibilityIcon() {
+ return VISIBILITY_TYPE_ICON[this.item.visibility];
},
- computed: {
- visibilityIcon() {
- return VISIBILITY_TYPE_ICON[this.item.visibility];
- },
- visibilityTooltip() {
- if (this.item.type === ITEM_TYPE.GROUP) {
- return GROUP_VISIBILITY_TYPE[this.item.visibility];
- }
- return PROJECT_VISIBILITY_TYPE[this.item.visibility];
- },
- isProject() {
- return this.item.type === ITEM_TYPE.PROJECT;
- },
- isGroup() {
- return this.item.type === ITEM_TYPE.GROUP;
- },
+ visibilityTooltip() {
+ if (this.item.type === ITEM_TYPE.GROUP) {
+ return GROUP_VISIBILITY_TYPE[this.item.visibility];
+ }
+ return PROJECT_VISIBILITY_TYPE[this.item.visibility];
},
- };
+ isProject() {
+ return this.item.type === ITEM_TYPE.PROJECT;
+ },
+ isGroup() {
+ return this.item.type === ITEM_TYPE.GROUP;
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/groups/components/item_stats_value.vue b/app/assets/javascripts/groups/components/item_stats_value.vue
index ef9f2bca76c..c542ca946d3 100644
--- a/app/assets/javascripts/groups/components/item_stats_value.vue
+++ b/app/assets/javascripts/groups/components/item_stats_value.vue
@@ -1,52 +1,52 @@
<script>
- import tooltip from '~/vue_shared/directives/tooltip';
- import icon from '~/vue_shared/components/icon.vue';
+import tooltip from '~/vue_shared/directives/tooltip';
+import icon from '~/vue_shared/components/icon.vue';
- export default {
- components: {
- icon,
+export default {
+ components: {
+ icon,
+ },
+ directives: {
+ tooltip,
+ },
+ props: {
+ title: {
+ type: String,
+ required: false,
+ default: '',
},
- directives: {
- tooltip,
+ cssClass: {
+ type: String,
+ required: false,
+ default: '',
},
- props: {
- title: {
- type: String,
- required: false,
- default: '',
- },
- cssClass: {
- type: String,
- required: false,
- default: '',
- },
- iconName: {
- type: String,
- required: true,
- },
- tooltipPlacement: {
- type: String,
- required: false,
- default: 'bottom',
- },
- /**
- * value could either be number or string
- * as `memberCount` is always passed as string
- * while `subgroupCount` & `projectCount`
- * are always number
- */
- value: {
- type: [Number, String],
- required: false,
- default: '',
- },
+ iconName: {
+ type: String,
+ required: true,
},
- computed: {
- isValuePresent() {
- return this.value !== '';
- },
+ tooltipPlacement: {
+ type: String,
+ required: false,
+ default: 'bottom',
},
- };
+ /**
+ * value could either be number or string
+ * as `memberCount` is always passed as string
+ * while `subgroupCount` & `projectCount`
+ * are always number
+ */
+ value: {
+ type: [Number, String],
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ isValuePresent() {
+ return this.value !== '';
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/groups/new_group_child.js b/app/assets/javascripts/groups/new_group_child.js
index a120d501e35..012177479c6 100644
--- a/app/assets/javascripts/groups/new_group_child.js
+++ b/app/assets/javascripts/groups/new_group_child.js
@@ -37,20 +37,22 @@ export default class NewGroupChild {
getDroplabConfig() {
return {
- InputSetter: [{
- input: this.newGroupChildButton,
- valueAttribute: 'data-value',
- inputAttribute: 'data-action',
- }, {
- input: this.newGroupChildButton,
- valueAttribute: 'data-text',
- }],
+ InputSetter: [
+ {
+ input: this.newGroupChildButton,
+ valueAttribute: 'data-value',
+ inputAttribute: 'data-action',
+ },
+ {
+ input: this.newGroupChildButton,
+ valueAttribute: 'data-text',
+ },
+ ],
};
}
bindEvents() {
- this.newGroupChildButton
- .addEventListener('click', this.onClickNewGroupChildButton.bind(this));
+ this.newGroupChildButton.addEventListener('click', this.onClickNewGroupChildButton.bind(this));
}
onClickNewGroupChildButton(e) {
diff --git a/app/assets/javascripts/groups/store/groups_store.js b/app/assets/javascripts/groups/store/groups_store.js
index 4a7569078a1..16f95d5a0cc 100644
--- a/app/assets/javascripts/groups/store/groups_store.js
+++ b/app/assets/javascripts/groups/store/groups_store.js
@@ -17,13 +17,14 @@ export default class GroupsStore {
}
setSearchedGroups(rawGroups) {
- const formatGroups = groups => groups.map((group) => {
- const formattedGroup = this.formatGroupItem(group);
- if (formattedGroup.children && formattedGroup.children.length) {
- formattedGroup.children = formatGroups(formattedGroup.children);
- }
- return formattedGroup;
- });
+ const formatGroups = groups =>
+ groups.map(group => {
+ const formattedGroup = this.formatGroupItem(group);
+ if (formattedGroup.children && formattedGroup.children.length) {
+ formattedGroup.children = formatGroups(formattedGroup.children);
+ }
+ return formattedGroup;
+ });
if (rawGroups && rawGroups.length) {
this.state.groups = formatGroups(rawGroups);
@@ -62,10 +63,10 @@ export default class GroupsStore {
formatGroupItem(rawGroupItem) {
const groupChildren = rawGroupItem.children || [];
- const groupIsOpen = (groupChildren.length > 0) || false;
- const childrenCount = this.hideProjects ?
- rawGroupItem.subgroup_count :
- rawGroupItem.children_count;
+ const groupIsOpen = groupChildren.length > 0 || false;
+ const childrenCount = this.hideProjects
+ ? rawGroupItem.subgroup_count
+ : rawGroupItem.children_count;
return {
id: rawGroupItem.id,
diff --git a/app/assets/javascripts/groups/transfer_dropdown.js b/app/assets/javascripts/groups/transfer_dropdown.js
index e0eb118ddf7..26510fcdb2a 100644
--- a/app/assets/javascripts/groups/transfer_dropdown.js
+++ b/app/assets/javascripts/groups/transfer_dropdown.js
@@ -22,7 +22,7 @@ export default class TransferDropdown {
search: { fields: ['text'] },
data: extraOptions.concat(this.data),
text: item => item.text,
- clicked: (options) => {
+ clicked: options => {
const { e } = options;
e.preventDefault();
this.assignSelected(options.selectedObj);
diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js
index e37fc5c4be6..b4a3037c1b7 100644
--- a/app/assets/javascripts/groups_select.js
+++ b/app/assets/javascripts/groups_select.js
@@ -23,7 +23,7 @@ export default function groupsSelect() {
axios[params.type.toLowerCase()](params.url, {
params: params.data,
})
- .then((res) => {
+ .then(res => {
const results = res.data || [];
const headers = normalizeHeaders(res.headers);
const currentPage = parseInt(headers['X-PAGE'], 10) || 0;
@@ -36,7 +36,8 @@ export default function groupsSelect() {
more,
},
});
- }).catch(params.error);
+ })
+ .catch(params.error);
},
data(search, page) {
return {
@@ -68,7 +69,9 @@ export default function groupsSelect() {
}
},
formatResult(object) {
- return `<div class='group-result'> <div class='group-name'>${object.full_name}</div> <div class='group-path'>${object.full_path}</div> </div>`;
+ return `<div class='group-result'> <div class='group-name'>${
+ object.full_name
+ }</div> <div class='group-path'>${object.full_path}</div> </div>`;
},
formatSelection(object) {
return object.full_name;
diff --git a/app/assets/javascripts/helpers/avatar_helper.js b/app/assets/javascripts/helpers/avatar_helper.js
index d3b1d0f11fd..35ac7b2629c 100644
--- a/app/assets/javascripts/helpers/avatar_helper.js
+++ b/app/assets/javascripts/helpers/avatar_helper.js
@@ -19,7 +19,9 @@ export function renderIdenticon(entity, options = {}) {
const bgClass = getIdenticonBackgroundClass(entity.id);
const title = getIdenticonTitle(entity.name);
- return `<div class="avatar identicon ${_.escape(sizeClass)} ${_.escape(bgClass)}">${_.escape(title)}</div>`;
+ return `<div class="avatar identicon ${_.escape(sizeClass)} ${_.escape(bgClass)}">${_.escape(
+ title,
+ )}</div>`;
}
export function renderAvatar(entity, options = {}) {
diff --git a/app/assets/javascripts/ide/components/new_dropdown/upload.vue b/app/assets/javascripts/ide/components/new_dropdown/upload.vue
index e2be805ed22..ec759043efc 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/upload.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/upload.vue
@@ -25,14 +25,32 @@ export default {
},
},
methods: {
- createFile(target, file, isText) {
+ isText(content, fileType) {
+ const knownBinaryFileTypes = ['image/'];
+ const knownTextFileTypes = ['text/'];
+ const isKnownBinaryFileType = knownBinaryFileTypes.find(type => fileType.includes(type));
+ const isKnownTextFileType = knownTextFileTypes.find(type => fileType.includes(type));
+ const asciiRegex = /^[ -~\t\n\r]+$/; // tests whether a string contains ascii characters only (ranges from space to tilde, tabs and new lines)
+
+ if (isKnownBinaryFileType) {
+ return false;
+ }
+
+ if (isKnownTextFileType) {
+ return true;
+ }
+
+ // if it's not a known file type, determine the type by evaluating the file contents
+ return asciiRegex.test(content);
+ },
+ createFile(target, file) {
const { name } = file;
let { result } = target;
+ const encodedContent = result.split('base64,')[1];
+ const rawContent = encodedContent ? atob(encodedContent) : '';
+ const isText = this.isText(rawContent, file.type);
- if (!isText) {
- // eslint-disable-next-line prefer-destructuring
- result = result.split('base64,')[1];
- }
+ result = isText ? rawContent : encodedContent;
this.$emit('create', {
name: `${this.path ? `${this.path}/` : ''}${name}`,
@@ -43,15 +61,9 @@ export default {
},
readFile(file) {
const reader = new FileReader();
- const isText = file.type.match(/text.*/) !== null;
- reader.addEventListener('load', e => this.createFile(e.target, file, isText), { once: true });
-
- if (isText) {
- reader.readAsText(file);
- } else {
- reader.readAsDataURL(file);
- }
+ reader.addEventListener('load', e => this.createFile(e.target, file), { once: true });
+ reader.readAsDataURL(file);
},
openFile() {
Array.from(this.$refs.fileUpload.files).forEach(file => this.readFile(file));
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js b/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js
index d519c033769..25a65b047f1 100644
--- a/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js
@@ -13,6 +13,7 @@ export default {
},
[types.SET_SELECTED_TEMPLATE_TYPE](state, type) {
state.selectedTemplateType = type;
+ state.templates = [];
},
[types.SET_UPDATE_SUCCESS](state, success) {
state.updateSuccess = success;
diff --git a/app/assets/javascripts/image_diff/image_diff.js b/app/assets/javascripts/image_diff/image_diff.js
index fab0255c378..3587f073a00 100644
--- a/app/assets/javascripts/image_diff/image_diff.js
+++ b/app/assets/javascripts/image_diff/image_diff.js
@@ -60,8 +60,10 @@ export default class ImageDiff {
}
renderBadge(discussionEl, index) {
- const imageBadge = imageDiffHelper
- .generateBadgeFromDiscussionDOM(this.imageFrameEl, discussionEl);
+ const imageBadge = imageDiffHelper.generateBadgeFromDiscussionDOM(
+ this.imageFrameEl,
+ discussionEl,
+ );
this.imageBadges.push(imageBadge);
diff --git a/app/assets/javascripts/image_diff/init_discussion_tab.js b/app/assets/javascripts/image_diff/init_discussion_tab.js
index 2f16c6ef115..dbe4c06a4e9 100644
--- a/app/assets/javascripts/image_diff/init_discussion_tab.js
+++ b/app/assets/javascripts/image_diff/init_discussion_tab.js
@@ -8,5 +8,6 @@ export default () => {
const diffFileEls = document.querySelectorAll('.timeline-content .diff-file.js-image-file');
[...diffFileEls].forEach(diffFileEl =>
- imageDiffHelper.initImageDiff(diffFileEl, canCreateNote, renderCommentBadge));
+ imageDiffHelper.initImageDiff(diffFileEl, canCreateNote, renderCommentBadge),
+ );
};
diff --git a/app/assets/javascripts/image_diff/replaced_image_diff.js b/app/assets/javascripts/image_diff/replaced_image_diff.js
index 4abd13fb472..8d9e65155d8 100644
--- a/app/assets/javascripts/image_diff/replaced_image_diff.js
+++ b/app/assets/javascripts/image_diff/replaced_image_diff.js
@@ -26,7 +26,7 @@ export default class ReplacedImageDiff extends ImageDiff {
this.imageEls = {};
const viewTypeNames = Object.getOwnPropertyNames(viewTypes);
- viewTypeNames.forEach((viewType) => {
+ viewTypeNames.forEach(viewType => {
this.imageEls[viewType] = this.imageFrameEls[viewType].querySelector('img');
});
}
@@ -79,13 +79,12 @@ export default class ReplacedImageDiff extends ImageDiff {
// Re-render indicator in new view
if (indicator.removed) {
- const normalizedIndicator = imageDiffHelper
- .resizeCoordinatesToImageElement(this.imageEl, {
- x: indicator.x,
- y: indicator.y,
- width: indicator.image.width,
- height: indicator.image.height,
- });
+ const normalizedIndicator = imageDiffHelper.resizeCoordinatesToImageElement(this.imageEl, {
+ x: indicator.x,
+ y: indicator.y,
+ width: indicator.image.width,
+ height: indicator.image.height,
+ });
imageDiffHelper.showCommentIndicator(this.imageFrameEl, normalizedIndicator);
}
}
diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js
index eda8cdad908..f1beb1a8ea5 100644
--- a/app/assets/javascripts/importer_status.js
+++ b/app/assets/javascripts/importer_status.js
@@ -60,66 +60,71 @@ class ImporterStatus {
attributes = Object.assign(repoData, attributes);
}
- return axios.post(this.importUrl, attributes)
- .then(({ data }) => {
- const job = $(`tr#repo_${id}`);
- job.attr('id', `project_${data.id}`);
-
- job.find('.import-target').html(`<a href="${data.full_path}">${data.full_path}</a>`);
- $('table.import-jobs tbody').prepend(job);
-
- job.addClass('table-active');
- const connectingVerb = this.ciCdOnly ? __('connecting') : __('importing');
- job.find('.import-actions').html(sprintf(
- _.escape(__('%{loadingIcon} Started')), {
- loadingIcon: `<i class="fa fa-spinner fa-spin" aria-label="${_.escape(connectingVerb)}"></i>`,
- },
- false,
- ));
- })
- .catch((error) => {
- let details = error;
-
- const $statusField = $(`#repo_${this.id} .job-status`);
- $statusField.text(__('Failed'));
-
- if (error.response && error.response.data && error.response.data.errors) {
- details = error.response.data.errors;
- }
-
- flash(sprintf(__('An error occurred while importing project: %{details}'), { details }));
- });
+ return axios
+ .post(this.importUrl, attributes)
+ .then(({ data }) => {
+ const job = $(`tr#repo_${id}`);
+ job.attr('id', `project_${data.id}`);
+
+ job.find('.import-target').html(`<a href="${data.full_path}">${data.full_path}</a>`);
+ $('table.import-jobs tbody').prepend(job);
+
+ job.addClass('table-active');
+ const connectingVerb = this.ciCdOnly ? __('connecting') : __('importing');
+ job.find('.import-actions').html(
+ sprintf(
+ _.escape(__('%{loadingIcon} Started')),
+ {
+ loadingIcon: `<i class="fa fa-spinner fa-spin" aria-label="${_.escape(
+ connectingVerb,
+ )}"></i>`,
+ },
+ false,
+ ),
+ );
+ })
+ .catch(error => {
+ let details = error;
+
+ const $statusField = $(`#repo_${this.id} .job-status`);
+ $statusField.text(__('Failed'));
+
+ if (error.response && error.response.data && error.response.data.errors) {
+ details = error.response.data.errors;
+ }
+
+ flash(sprintf(__('An error occurred while importing project: %{details}'), { details }));
+ });
}
autoUpdate() {
- return axios.get(this.jobsUrl)
- .then(({ data = [] }) => {
- data.forEach((job) => {
- const jobItem = $(`#project_${job.id}`);
- const statusField = jobItem.find('.job-status');
-
- const spinner = '<i class="fa fa-spinner fa-spin"></i>';
-
- switch (job.import_status) {
- case 'finished':
- jobItem.removeClass('table-active').addClass('table-success');
- statusField.html(`<span><i class="fa fa-check"></i> ${__('Done')}</span>`);
- break;
- case 'scheduled':
- statusField.html(`${spinner} ${__('Scheduled')}`);
- break;
- case 'started':
- statusField.html(`${spinner} ${__('Started')}`);
- break;
- case 'failed':
- statusField.html(__('Failed'));
- break;
- default:
- statusField.html(job.import_status);
- break;
- }
- });
+ return axios.get(this.jobsUrl).then(({ data = [] }) => {
+ data.forEach(job => {
+ const jobItem = $(`#project_${job.id}`);
+ const statusField = jobItem.find('.job-status');
+
+ const spinner = '<i class="fa fa-spinner fa-spin"></i>';
+
+ switch (job.import_status) {
+ case 'finished':
+ jobItem.removeClass('table-active').addClass('table-success');
+ statusField.html(`<span><i class="fa fa-check"></i> ${__('Done')}</span>`);
+ break;
+ case 'scheduled':
+ statusField.html(`${spinner} ${__('Scheduled')}`);
+ break;
+ case 'started':
+ statusField.html(`${spinner} ${__('Started')}`);
+ break;
+ case 'failed':
+ statusField.html(__('Failed'));
+ break;
+ default:
+ statusField.html(job.import_status);
+ break;
+ }
});
+ });
}
setAutoUpdate() {
@@ -141,7 +146,4 @@ function initImporterStatus() {
}
}
-export {
- initImporterStatus as default,
- ImporterStatus,
-};
+export { initImporterStatus as default, ImporterStatus };
diff --git a/app/assets/javascripts/init_changes_dropdown.js b/app/assets/javascripts/init_changes_dropdown.js
index 5c5a6e01848..e708e5d0978 100644
--- a/app/assets/javascripts/init_changes_dropdown.js
+++ b/app/assets/javascripts/init_changes_dropdown.js
@@ -1,7 +1,7 @@
import $ from 'jquery';
import { stickyMonitor } from './lib/utils/sticky';
-export default (stickyTop) => {
+export default stickyTop => {
stickyMonitor(document.querySelector('.js-diff-files-changed'), stickyTop);
$('.js-diff-stats-dropdown').glDropdown({
diff --git a/app/assets/javascripts/init_notes.js b/app/assets/javascripts/init_notes.js
index 3c71258e53b..a77828e8cf2 100644
--- a/app/assets/javascripts/init_notes.js
+++ b/app/assets/javascripts/init_notes.js
@@ -2,13 +2,7 @@ import Notes from './notes';
export default () => {
const dataEl = document.querySelector('.js-notes-data');
- const {
- notesUrl,
- notesIds,
- now,
- diffView,
- enableGFM,
- } = JSON.parse(dataEl.innerHTML);
+ const { notesUrl, notesIds, now, diffView, enableGFM } = JSON.parse(dataEl.innerHTML);
// Create a singleton so that we don't need to assign
// into the window object, we can just access the current isntance with Notes.instance
diff --git a/app/assets/javascripts/integrations/integration_settings_form.js b/app/assets/javascripts/integrations/integration_settings_form.js
index bd90d0eaa32..08b858305ab 100644
--- a/app/assets/javascripts/integrations/integration_settings_form.js
+++ b/app/assets/javascripts/integrations/integration_settings_form.js
@@ -97,7 +97,8 @@ export default class IntegrationSettingsForm {
testSettings(formData) {
this.toggleSubmitBtnState(true);
- return axios.put(this.testEndPoint, formData)
+ return axios
+ .put(this.testEndPoint, formData)
.then(({ data }) => {
if (data.error) {
let flashActions;
@@ -105,7 +106,7 @@ export default class IntegrationSettingsForm {
if (data.test_failed) {
flashActions = {
title: 'Save anyway',
- clickHandler: (e) => {
+ clickHandler: e => {
e.preventDefault();
this.$form.submit();
},
diff --git a/app/assets/javascripts/issuable/auto_width_dropdown_select.js b/app/assets/javascripts/issuable/auto_width_dropdown_select.js
index 07cf1eff279..612c524ca1c 100644
--- a/app/assets/javascripts/issuable/auto_width_dropdown_select.js
+++ b/app/assets/javascripts/issuable/auto_width_dropdown_select.js
@@ -27,7 +27,10 @@ class AutoWidthDropdownSelect {
// We have to look at the parent because
// `offsetParent` on a `display: none;` is `null`
- const offsetParentWidth = $(this).parent().offsetParent().width();
+ const offsetParentWidth = $(this)
+ .parent()
+ .offsetParent()
+ .width();
// Reset any width to let it naturally flow
$dropdown.css('width', 'auto');
if ($dropdown.outerWidth(false) > offsetParentWidth) {
diff --git a/app/assets/javascripts/issuable_bulk_update_actions.js b/app/assets/javascripts/issuable_bulk_update_actions.js
index 9848bcc2e64..b844e4c5e5b 100644
--- a/app/assets/javascripts/issuable_bulk_update_actions.js
+++ b/app/assets/javascripts/issuable_bulk_update_actions.js
@@ -32,7 +32,7 @@ export default {
onFormSubmitFailure() {
this.form.find('[type="submit"]').enable();
- return new Flash("Issue update failed");
+ return new Flash('Issue update failed');
},
getSelectedIssues() {
@@ -63,7 +63,7 @@ export default {
const result = [];
const labelsToKeep = this.$labelDropdown.data('indeterminate');
- this.getLabelsFromSelection().forEach((id) => {
+ this.getLabelsFromSelection().forEach(id => {
if (labelsToKeep.indexOf(id) === -1) {
result.push(id);
}
@@ -89,8 +89,8 @@ export default {
issuable_ids: this.form.find('input[name="update[issuable_ids]"]').val(),
subscription_event: this.form.find('input[name="update[subscription_event]"]').val(),
add_label_ids: [],
- remove_label_ids: []
- }
+ remove_label_ids: [],
+ },
};
if (this.willUpdateLabels) {
formData.update.add_label_ids = this.$labelDropdown.data('marked');
@@ -134,7 +134,7 @@ export default {
// Collect unique label IDs for all checked issues
this.getElement('.selected-issuable:checked').each((i, el) => {
issuableLabels = this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels');
- issuableLabels.forEach((labelId) => {
+ issuableLabels.forEach(labelId => {
// Store unique IDs
if (uniqueIds.indexOf(labelId) === -1) {
uniqueIds.push(labelId);
diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js
index 0140960b367..c81a2230310 100644
--- a/app/assets/javascripts/issuable_form.js
+++ b/app/assets/javascripts/issuable_form.js
@@ -1,6 +1,3 @@
-/* eslint-disable no-new, no-unused-vars, consistent-return, no-else-return */
-/* global GitLab */
-
import $ from 'jquery';
import Pikaday from 'pikaday';
import Autosave from './autosave';
@@ -8,7 +5,7 @@ import UsersSelect from './users_select';
import GfmAutoComplete from './gfm_auto_complete';
import ZenMode from './zen_mode';
import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
-import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
+import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
export default class IssuableForm {
constructor(form) {
@@ -19,9 +16,11 @@ export default class IssuableForm {
this.handleSubmit = this.handleSubmit.bind(this);
this.wipRegex = /^\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i;
- new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources).setup();
- new UsersSelect();
- new ZenMode();
+ this.gfmAutoComplete = new GfmAutoComplete(
+ gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources,
+ ).setup();
+ this.usersSelect = new UsersSelect();
+ this.zenMode = new ZenMode();
this.titleField = this.form.find('input[name*="[title]"]');
this.descriptionField = this.form.find('textarea[name*="[description]"]');
@@ -57,8 +56,16 @@ export default class IssuableForm {
}
initAutosave() {
- new Autosave(this.titleField, [document.location.pathname, document.location.search, 'title']);
- return new Autosave(this.descriptionField, [document.location.pathname, document.location.search, 'description']);
+ this.autosave = new Autosave(this.titleField, [
+ document.location.pathname,
+ document.location.search,
+ 'title',
+ ]);
+ return new Autosave(this.descriptionField, [
+ document.location.pathname,
+ document.location.search,
+ 'description',
+ ]);
}
handleSubmit() {
@@ -74,7 +81,7 @@ export default class IssuableForm {
this.$wipExplanation = this.form.find('.js-wip-explanation');
this.$noWipExplanation = this.form.find('.js-no-wip-explanation');
if (!(this.$wipExplanation.length && this.$noWipExplanation.length)) {
- return;
+ return undefined;
}
this.form.on('click', '.js-toggle-wip', this.toggleWip);
this.titleField.on('keyup blur', this.renderWipExplanation);
@@ -89,10 +96,9 @@ export default class IssuableForm {
if (this.workInProgress()) {
this.$wipExplanation.show();
return this.$noWipExplanation.hide();
- } else {
- this.$wipExplanation.hide();
- return this.$noWipExplanation.show();
}
+ this.$wipExplanation.hide();
+ return this.$noWipExplanation.show();
}
toggleWip(event) {
@@ -110,7 +116,7 @@ export default class IssuableForm {
}
addWip() {
- this.titleField.val(`WIP: ${(this.titleField.val())}`);
+ this.titleField.val(`WIP: ${this.titleField.val()}`);
}
initTargetBranchDropdown() {
diff --git a/app/assets/javascripts/issuable_index.js b/app/assets/javascripts/issuable_index.js
index 06ec4546164..ffcbd7cf28c 100644
--- a/app/assets/javascripts/issuable_index.js
+++ b/app/assets/javascripts/issuable_index.js
@@ -26,14 +26,17 @@ export default class IssuableIndex {
static resetIncomingEmailToken() {
const $resetToken = $('.incoming-email-token-reset');
- $resetToken.on('click', (e) => {
+ $resetToken.on('click', e => {
e.preventDefault();
$resetToken.text('resetting...');
- axios.put($resetToken.attr('href'))
+ axios
+ .put($resetToken.attr('href'))
.then(({ data }) => {
- $('#issuable_email').val(data.new_address).focus();
+ $('#issuable_email')
+ .val(data.new_address)
+ .focus();
$resetToken.text('reset it');
})
diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js
index 4b4e9aa48ab..94b78907d9a 100644
--- a/app/assets/javascripts/issue.js
+++ b/app/assets/javascripts/issue.js
@@ -28,7 +28,7 @@ export default class Issue {
}
// Listen to state changes in the Vue app
- document.addEventListener('issuable_vue_app:change', (event) => {
+ document.addEventListener('issuable_vue_app:change', event => {
this.updateTopState(event.detail.isClosed, event.detail.data);
});
}
@@ -55,7 +55,13 @@ export default class Issue {
$(document).trigger('issuable:change', isClosed);
this.toggleCloseReopenButton(isClosed);
- let numProjectIssues = Number(projectIssuesCounter.first().text().trim().replace(/[^\d]/, ''));
+ let numProjectIssues = Number(
+ projectIssuesCounter
+ .first()
+ .text()
+ .trim()
+ .replace(/[^\d]/, ''),
+ );
numProjectIssues = isClosed ? numProjectIssues - 1 : numProjectIssues + 1;
projectIssuesCounter.text(addDelimiter(numProjectIssues));
@@ -76,29 +82,34 @@ export default class Issue {
initIssueBtnEventListeners() {
const issueFailMessage = 'Unable to update this issue at this time.';
- return $(document).on('click', '.js-issuable-actions a.btn-close, .js-issuable-actions a.btn-reopen', (e) => {
- var $button, shouldSubmit, url;
- e.preventDefault();
- e.stopImmediatePropagation();
- $button = $(e.currentTarget);
- shouldSubmit = $button.hasClass('btn-comment');
- if (shouldSubmit) {
- Issue.submitNoteForm($button.closest('form'));
- }
-
- this.disableCloseReopenButton($button);
+ return $(document).on(
+ 'click',
+ '.js-issuable-actions a.btn-close, .js-issuable-actions a.btn-reopen',
+ e => {
+ var $button, shouldSubmit, url;
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ $button = $(e.currentTarget);
+ shouldSubmit = $button.hasClass('btn-comment');
+ if (shouldSubmit) {
+ Issue.submitNoteForm($button.closest('form'));
+ }
- url = $button.attr('href');
- return axios.put(url)
- .then(({ data }) => {
- const isClosed = $button.hasClass('btn-close');
- this.updateTopState(isClosed, data);
- })
- .catch(() => flash(issueFailMessage))
- .then(() => {
- this.disableCloseReopenButton($button, false);
- });
- });
+ this.disableCloseReopenButton($button);
+
+ url = $button.attr('href');
+ return axios
+ .put(url)
+ .then(({ data }) => {
+ const isClosed = $button.hasClass('btn-close');
+ this.updateTopState(isClosed, data);
+ })
+ .catch(() => flash(issueFailMessage))
+ .then(() => {
+ this.disableCloseReopenButton($button, false);
+ });
+ },
+ );
}
initCloseReopenReport() {
@@ -124,7 +135,7 @@ export default class Issue {
static submitNoteForm(form) {
var noteText;
- noteText = form.find("textarea.js-note-text").val();
+ noteText = form.find('textarea.js-note-text').val();
if (noteText && noteText.trim().length > 0) {
return form.submit();
}
@@ -133,22 +144,26 @@ export default class Issue {
static initMergeRequests() {
var $container;
$container = $('#merge-requests');
- return axios.get($container.data('url'))
+ return axios
+ .get($container.data('url'))
.then(({ data }) => {
if ('html' in data) {
$container.html(data.html);
}
- }).catch(() => flash('Failed to load referenced merge requests'));
+ })
+ .catch(() => flash('Failed to load referenced merge requests'));
}
static initRelatedBranches() {
var $container;
$container = $('#related-branches');
- return axios.get($container.data('url'))
+ return axios
+ .get($container.data('url'))
.then(({ data }) => {
if ('html' in data) {
$container.html(data.html);
}
- }).catch(() => flash('Failed to load related branches'));
+ })
+ .catch(() => flash('Failed to load related branches'));
}
}
diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js
deleted file mode 100644
index 854445bd2a4..00000000000
--- a/app/assets/javascripts/job.js
+++ /dev/null
@@ -1,190 +0,0 @@
-import $ from 'jquery';
-import _ from 'underscore';
-import { polyfillSticky } from './lib/utils/sticky';
-import axios from './lib/utils/axios_utils';
-import { visitUrl } from './lib/utils/url_utility';
-import bp from './breakpoints';
-import { numberToHumanSize } from './lib/utils/number_utils';
-import { setCiStatusFavicon } from './lib/utils/common_utils';
-import { isScrolledToBottom, scrollDown, scrollUp } from './lib/utils/scroll_utils';
-import LogOutputBehaviours from './lib/utils/logoutput_behaviours';
-
-export default class Job extends LogOutputBehaviours {
- constructor(options) {
- super();
- this.timeout = null;
- this.state = null;
- this.fetchingStatusFavicon = false;
- this.options = options || $('.js-build-options').data();
-
- this.pagePath = this.options.pagePath;
- this.buildStatus = this.options.buildStatus;
- this.state = this.options.logState;
- this.buildStage = this.options.buildStage;
- this.$document = $(document);
- this.$window = $(window);
- this.logBytes = 0;
-
- this.$buildTrace = $('#build-trace');
- this.$buildRefreshAnimation = $('.js-build-refresh');
- this.$truncatedInfo = $('.js-truncated-info');
- this.$buildTraceOutput = $('.js-build-output');
- this.$topBar = $('.js-top-bar');
-
- clearTimeout(this.timeout);
-
- this.initSidebar();
- this.sidebarOnResize();
-
- this.$document
- .off('click', '.js-sidebar-build-toggle')
- .on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this));
-
- this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100);
-
- this.$window
- .off('scroll')
- .on('scroll', () => {
- if (!isScrolledToBottom()) {
- this.toggleScrollAnimation(false);
- } else if (isScrolledToBottom() && !this.isLogComplete) {
- this.toggleScrollAnimation(true);
- }
- this.scrollThrottled();
- });
-
- this.$window
- .off('resize.build')
- .on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100));
-
- this.initAffixTopArea();
-
- this.getBuildTrace();
- }
-
- initAffixTopArea() {
- polyfillSticky(this.$topBar);
- }
-
- scrollToBottom() {
- scrollDown();
- this.hasBeenScrolled = true;
- this.toggleScroll();
- }
-
- scrollToTop() {
- scrollUp();
- this.hasBeenScrolled = true;
- this.toggleScroll();
- }
-
- toggleScrollAnimation(toggle) {
- this.$scrollBottomBtn.toggleClass('animate', toggle);
- }
-
- initSidebar() {
- this.$sidebar = $('.js-build-sidebar');
- }
-
- getBuildTrace() {
- return axios.get(`${this.pagePath}/trace.json`, {
- params: { state: this.state },
- })
- .then((res) => {
- const log = res.data;
-
- if (!this.fetchingStatusFavicon) {
- this.fetchingStatusFavicon = true;
-
- setCiStatusFavicon(`${this.pagePath}/status.json`)
- .then(() => {
- this.fetchingStatusFavicon = false;
- })
- .catch(() => {
- this.fetchingStatusFavicon = false;
- });
- }
-
- if (log.state) {
- this.state = log.state;
- }
-
- this.isScrollInBottom = isScrolledToBottom();
-
- if (log.append) {
- this.$buildTraceOutput.append(log.html);
- this.logBytes += log.size;
- } else {
- this.$buildTraceOutput.html(log.html);
- this.logBytes = log.size;
- }
-
- // if the incremental sum of logBytes we received is less than the total
- // we need to show a message warning the user about that.
- if (this.logBytes < log.total) {
- // size is in bytes, we need to calculate KiB
- const size = numberToHumanSize(this.logBytes);
- $('.js-truncated-info-size').html(`${size}`);
- this.$truncatedInfo.removeClass('hidden');
- } else {
- this.$truncatedInfo.addClass('hidden');
- }
- this.isLogComplete = log.complete;
-
- if (log.complete === false) {
- this.timeout = setTimeout(() => {
- this.getBuildTrace();
- }, 4000);
- } else {
- this.$buildRefreshAnimation.remove();
- this.toggleScrollAnimation(false);
- }
-
- if (log.status !== this.buildStatus) {
- visitUrl(this.pagePath);
- }
- })
- .catch(() => {
- this.$buildRefreshAnimation.remove();
- })
- .then(() => {
- if (this.isScrollInBottom) {
- scrollDown();
- }
- })
- .then(() => this.toggleScroll());
- }
- // eslint-disable-next-line class-methods-use-this
- shouldHideSidebarForViewport() {
- const bootstrapBreakpoint = bp.getBreakpointSize();
- return bootstrapBreakpoint === 'xs';
- }
-
- toggleSidebar(shouldHide) {
- const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
- const $toggleButton = $('.js-sidebar-build-toggle-header');
-
- this.$sidebar
- .toggleClass('right-sidebar-expanded', shouldShow)
- .toggleClass('right-sidebar-collapsed', shouldHide);
-
- this.$topBar
- .toggleClass('sidebar-expanded', shouldShow)
- .toggleClass('sidebar-collapsed', shouldHide);
-
- if (this.$sidebar.hasClass('right-sidebar-expanded')) {
- $toggleButton.addClass('hidden');
- } else {
- $toggleButton.removeClass('hidden');
- }
- }
-
- sidebarOnResize() {
- this.toggleSidebar(this.shouldHideSidebarForViewport());
- }
-
- sidebarOnClick() {
- if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
- }
-
-}
diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue
index 047e55866ce..ac19034f69d 100644
--- a/app/assets/javascripts/jobs/components/job_app.vue
+++ b/app/assets/javascripts/jobs/components/job_app.vue
@@ -1,41 +1,162 @@
<script>
- import { mapGetters, mapState } from 'vuex';
+ import _ from 'underscore';
+ import { mapGetters, mapState, mapActions } from 'vuex';
+ import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
+ import bp from '~/breakpoints';
import CiHeader from '~/vue_shared/components/header_ci_component.vue';
import Callout from '~/vue_shared/components/callout.vue';
+ import createStore from '../store';
import EmptyState from './empty_state.vue';
import EnvironmentsBlock from './environments_block.vue';
import ErasedBlock from './erased_block.vue';
+ import Log from './job_log.vue';
+ import LogTopBar from './job_log_controllers.vue';
import StuckBlock from './stuck_block.vue';
+ import Sidebar from './sidebar.vue';
export default {
name: 'JobPageApp',
+ store: createStore(),
components: {
CiHeader,
Callout,
EmptyState,
EnvironmentsBlock,
ErasedBlock,
+ Log,
+ LogTopBar,
StuckBlock,
+ Sidebar,
},
props: {
+ runnerSettingsUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
runnerHelpUrl: {
type: String,
required: false,
default: null,
},
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ terminalPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ pagePath: {
+ type: String,
+ required: true,
+ },
+ logState: {
+ type: String,
+ required: true,
+ },
},
computed: {
- ...mapState(['isLoading', 'job']),
+ ...mapState([
+ 'isLoading',
+ 'job',
+ 'isSidebarOpen',
+ 'trace',
+ 'isTraceComplete',
+ 'traceSize',
+ 'isTraceSizeVisible',
+ 'isScrollBottomDisabled',
+ 'isScrollTopDisabled',
+ 'isScrolledToBottomBeforeReceivingTrace',
+ 'hasError',
+ ]),
...mapGetters([
'headerActions',
'headerTime',
'shouldRenderCalloutMessage',
- 'jobHasStarted',
+ 'shouldRenderTriggeredLabel',
'hasEnvironment',
- 'isJobStuck',
'hasTrace',
'emptyStateIllustration',
+ 'isScrollingDown',
+ 'emptyStateAction',
+ 'hasRunnersForProject',
]),
+
+ shouldRenderContent() {
+ return !this.isLoading && !this.hasError;
+ }
+ },
+ watch: {
+ // Once the job log is loaded,
+ // fetch the stages for the dropdown on the sidebar
+ job(newVal, oldVal) {
+ if (_.isEmpty(oldVal) && !_.isEmpty(newVal.pipeline)) {
+ this.fetchStages();
+ }
+ },
+ },
+ created() {
+ this.throttled = _.throttle(this.toggleScrollButtons, 100);
+
+ this.setJobEndpoint(this.endpoint);
+ this.setTraceOptions({
+ logState: this.logState,
+ pagePath: this.pagePath,
+ });
+
+ this.fetchJob();
+ this.fetchTrace();
+
+ window.addEventListener('resize', this.onResize);
+ window.addEventListener('scroll', this.updateScroll);
+ },
+
+ mounted() {
+ this.updateSidebar();
+ },
+
+ destroyed() {
+ window.removeEventListener('resize', this.onResize);
+ window.removeEventListener('scroll', this.updateScroll);
+ },
+
+ methods: {
+ ...mapActions([
+ 'setJobEndpoint',
+ 'setTraceOptions',
+ 'fetchJob',
+ 'fetchStages',
+ 'hideSidebar',
+ 'showSidebar',
+ 'toggleSidebar',
+ 'fetchTrace',
+ 'scrollBottom',
+ 'scrollTop',
+ 'toggleScrollButtons',
+ 'toggleScrollAnimation',
+ ]),
+ onResize() {
+ this.updateSidebar();
+ this.updateScroll();
+ },
+ updateSidebar() {
+ if (bp.getBreakpointSize() === 'xs') {
+ this.hideSidebar();
+ } else if (!this.isSidebarOpen) {
+ this.showSidebar();
+ }
+ },
+ updateScroll() {
+ if (!isScrolledToBottom()) {
+ this.toggleScrollAnimation(false);
+ } else if (this.isScrollingDown) {
+ this.toggleScrollAnimation(true);
+ }
+
+ this.throttled();
+ },
},
};
</script>
@@ -44,71 +165,107 @@
<gl-loading-icon
v-if="isLoading"
:size="2"
- class="prepend-top-20"
+ class="js-job-loading qa-loading-animation prepend-top-20"
/>
- <template v-else>
- <!-- Header Section -->
- <header>
- <div class="js-build-header build-header top-area">
- <ci-header
- :status="job.status"
- :item-id="job.id"
- :time="headerTime"
- :user="job.user"
- :actions="headerActions"
- :has-sidebar-button="true"
- :should-render-triggered-label="jobHasStarted"
- :item-name="__('Job')"
+ <template v-else-if="shouldRenderContent">
+ <div class="js-job-content build-page">
+ <!-- Header Section -->
+ <header>
+ <div class="js-build-header build-header top-area">
+ <ci-header
+ :status="job.status"
+ :item-id="job.id"
+ :time="headerTime"
+ :user="job.user"
+ :actions="headerActions"
+ :has-sidebar-button="true"
+ :should-render-triggered-label="shouldRenderTriggeredLabel"
+ :item-name="__('Job')"
+ @clickedSidebarButton="toggleSidebar"
+ />
+ </div>
+
+ <callout
+ v-if="shouldRenderCalloutMessage"
+ :message="job.callout_message"
+ />
+ </header>
+ <!-- EO Header Section -->
+
+ <!-- Body Section -->
+ <stuck-block
+ v-if="job.stuck"
+ class="js-job-stuck"
+ :has-no-runners-for-project="hasRunnersForProject"
+ :tags="job.tags"
+ :runners-path="runnerSettingsUrl"
+ />
+
+ <environments-block
+ v-if="hasEnvironment"
+ class="js-job-environment"
+ :deployment-status="job.deployment_status"
+ :icon-status="job.status"
+ />
+
+ <erased-block
+ v-if="job.erased_at"
+ class="js-job-erased-block"
+ :user="job.erased_by"
+ :erased-at="job.erased_at"
+ />
+
+ <!--job log -->
+ <div
+ v-if="hasTrace"
+ class="build-trace-container prepend-top-default">
+ <log-top-bar
+ :class="{
+ 'sidebar-expanded': isSidebarOpen,
+ 'sidebar-collapsed': !isSidebarOpen
+ }"
+ :erase-path="job.erase_path"
+ :size="traceSize"
+ :raw-path="job.raw_path"
+ :is-scroll-bottom-disabled="isScrollBottomDisabled"
+ :is-scroll-top-disabled="isScrollTopDisabled"
+ :is-trace-size-visible="isTraceSizeVisible"
+ :is-scrolling-down="isScrollingDown"
+ @scrollJobLogTop="scrollTop"
+ @scrollJobLogBottom="scrollBottom"
+ />
+ <log
+ :trace="trace"
+ :is-complete="isTraceComplete"
/>
</div>
+ <!-- EO job log -->
- <callout
- v-if="shouldRenderCalloutMessage"
- :message="job.callout_message"
+ <!--empty state -->
+ <empty-state
+ v-if="!hasTrace"
+ class="js-job-empty-state"
+ :illustration-path="emptyStateIllustration.image"
+ :illustration-size-class="emptyStateIllustration.size"
+ :title="emptyStateIllustration.title"
+ :content="emptyStateIllustration.content"
+ :action="emptyStateAction"
/>
- </header>
- <!-- EO Header Section -->
-
- <!-- Body Section -->
- <stuck-block
- v-if="isJobStuck"
- class="js-job-stuck"
- :has-no-runners-for-project="job.runners.available"
- :tags="job.tags"
- :runners-path="runnerHelpUrl"
- />
-
- <environments-block
- v-if="hasEnvironment"
- class="js-job-environment"
- :deployment-status="job.deployment_status"
- :icon-status="job.status"
- />
-
- <erased-block
- v-if="job.erased"
- class="js-job-erased"
- :user="job.erased_by"
- :erased-at="job.erased_at"
- />
-
- <!--job log -->
- <!-- EO job log -->
-
- <!--empty state -->
- <empty-state
- v-if="!hasTrace"
- class="js-job-empty-state"
- :illustration-path="emptyStateIllustration.image"
- :illustration-size-class="emptyStateIllustration.size"
- :title="emptyStateIllustration.title"
- :content="emptyStateIllustration.content"
- :action="job.status.action"
- />
<!-- EO empty state -->
<!-- EO Body Section -->
+ </div>
</template>
+
+ <sidebar
+ v-if="shouldRenderContent"
+ class="js-job-sidebar"
+ :class="{
+ 'right-sidebar-expanded': isSidebarOpen,
+ 'right-sidebar-collapsed': !isSidebarOpen
+ }"
+ :runner-help-url="runnerHelpUrl"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/job_container_item.vue b/app/assets/javascripts/jobs/components/job_container_item.vue
new file mode 100644
index 00000000000..6486b25c8a7
--- /dev/null
+++ b/app/assets/javascripts/jobs/components/job_container_item.vue
@@ -0,0 +1,65 @@
+<script>
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import Icon from '~/vue_shared/components/icon.vue';
+import tooltip from '~/vue_shared/directives/tooltip';
+
+export default {
+ components: {
+ CiIcon,
+ Icon,
+ },
+ directives: {
+ tooltip,
+ },
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ isActive: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ tooltipText() {
+ return `${this.job.name} - ${this.job.status.tooltip}`;
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ class="build-job"
+ :class="{
+ retried: job.retried,
+ active: isActive
+ }"
+ >
+ <a
+ v-tooltip
+ :href="job.status.details_path"
+ :title="tooltipText"
+ data-container="body"
+ data-boundary="viewport"
+ class="js-job-link"
+ >
+ <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"
+ />
+ </a>
+ </div>
+</template>
diff --git a/app/assets/javascripts/jobs/components/job_log.vue b/app/assets/javascripts/jobs/components/job_log.vue
index 9d78d89239a..ffa6ada3e28 100644
--- a/app/assets/javascripts/jobs/components/job_log.vue
+++ b/app/assets/javascripts/jobs/components/job_log.vue
@@ -1,20 +1,48 @@
<script>
-export default {
- name: 'JobLog',
- props: {
- trace: {
- type: String,
- required: true,
+ import { mapState, mapActions } from 'vuex';
+
+ export default {
+ name: 'JobLog',
+ props: {
+ trace: {
+ type: String,
+ required: true,
+ },
+ isComplete: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapState(['isScrolledToBottomBeforeReceivingTrace']),
+ },
+ updated() {
+ this.$nextTick(() => this.handleScrollDown());
+ },
+ mounted() {
+ this.$nextTick(() => this.handleScrollDown());
},
- isComplete: {
- type: Boolean,
- required: true,
+ methods: {
+ ...mapActions(['scrollBottom']),
+ /**
+ * The job log is sent in HTML, which means we need to use `v-html` to render it
+ * Using the updated hook with $nextTick is not enough to wait for the DOM to be updated
+ * in this case because it runs before `v-html` has finished running, since there's no
+ * Vue binding.
+ * In order to scroll the page down after `v-html` has finished, we need to use setTimeout
+ */
+ handleScrollDown() {
+ if (this.isScrolledToBottomBeforeReceivingTrace) {
+ setTimeout(() => {
+ this.scrollBottom();
+ }, 0);
+ }
+ },
},
- },
-};
+ };
</script>
<template>
- <pre class="build-trace">
+ <pre class="js-build-trace build-trace qa-build-trace">
<code
class="bash"
v-html="trace"
@@ -22,7 +50,7 @@ export default {
</code>
<div
- v-if="isComplete"
+ v-if="!isComplete"
class="js-log-animation build-loader-animation"
>
<div class="dot"></div>
diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue
index 35d40c6898e..94ab1b16c84 100644
--- a/app/assets/javascripts/jobs/components/job_log_controllers.vue
+++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue
@@ -4,6 +4,7 @@ import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import { sprintf } from '~/locale';
+import scrollDown from '../svg/scroll_down.svg';
export default {
components: {
@@ -12,6 +13,7 @@ export default {
directives: {
tooltip,
},
+ scrollDown,
props: {
erasePath: {
type: String,
@@ -65,7 +67,7 @@ export default {
};
</script>
<template>
- <div class="top-bar">
+ <div class="top-bar affix">
<!-- truncate information -->
<div class="js-truncated-info truncated-info d-none d-sm-block float-left">
<template v-if="isTraceSizeVisible">
@@ -100,7 +102,7 @@ export default {
v-tooltip
:title="s__('Job|Erase job log')"
:href="erasePath"
- data-confirm="__('Are you sure you want to erase this build?')"
+ :data-confirm="__('Are you sure you want to erase this build?')"
class="js-erase-link controllers-buttons"
data-container="body"
data-method="post"
@@ -138,8 +140,8 @@ export default {
class="js-scroll-bottom btn-scroll btn-transparent btn-blank"
:class="{ animate: isScrollingDown }"
@click="handleScrollToBottom"
+ v-html="$options.scrollDown"
>
- <icon name="scroll_down"/>
</button>
</div>
<!-- eo scroll buttons -->
diff --git a/app/assets/javascripts/jobs/components/jobs_container.vue b/app/assets/javascripts/jobs/components/jobs_container.vue
index 03f36ec5c8b..951bcb36600 100644
--- a/app/assets/javascripts/jobs/components/jobs_container.vue
+++ b/app/assets/javascripts/jobs/components/jobs_container.vue
@@ -1,17 +1,11 @@
<script>
-import _ from 'underscore';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import Icon from '~/vue_shared/components/icon.vue';
-import tooltip from '~/vue_shared/directives/tooltip';
+import JobContainerItem from './job_container_item.vue';
export default {
components: {
- CiIcon,
- Icon,
- },
- directives: {
- tooltip,
+ JobContainerItem,
},
+
props: {
jobs: {
type: Array,
@@ -26,49 +20,16 @@ export default {
isJobActive(currentJobId) {
return this.jobId === currentJobId;
},
- tooltipText(job) {
- return `${_.escape(job.name)} - ${job.status.tooltip}`;
- },
},
};
</script>
<template>
<div class="js-jobs-container builds-container">
- <div
+ <job-container-item
v-for="job in jobs"
:key="job.id"
- class="build-job"
- :class="{ retried: job.retried, active: isJobActive(job.id) }"
- >
- <a
- v-tooltip
- :href="job.status.details_path"
- :title="tooltipText(job)"
- data-container="body"
- >
- <icon
- v-if="isJobActive(job.id)"
- name="arrow-right"
- class="js-arrow-right icon-arrow-right"
- />
-
- <ci-icon :status="job.status" />
-
- <span>
- <template v-if="job.name">
- {{ job.name }}
- </template>
- <template v-else>
- {{ job.id }}
- </template>
- </span>
-
- <icon
- v-if="job.retried"
- name="retry"
- class="js-retry-icon"
- />
- </a>
- </div>
+ :job="job"
+ :is-active="isJobActive(job.id)"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue
index 7f0f301d72a..28a02230d89 100644
--- a/app/assets/javascripts/jobs/components/sidebar.vue
+++ b/app/assets/javascripts/jobs/components/sidebar.vue
@@ -29,14 +29,9 @@ export default {
required: false,
default: '',
},
- terminalPath: {
- type: String,
- required: false,
- default: null,
- },
},
computed: {
- ...mapState(['job', 'isLoading', 'stages', 'jobs']),
+ ...mapState(['job', 'stages', 'jobs', 'selectedStage', 'isLoadingStages']),
coverage() {
return `${this.job.coverage}%`;
},
@@ -100,195 +95,191 @@ export default {
);
},
commit() {
- return this.job.pipeline.commit || {};
+ return this.job.pipeline && this.job.pipeline.commit ? this.job.pipeline.commit : {};
},
},
methods: {
- ...mapActions(['fetchJobsForStage']),
+ ...mapActions(['fetchJobsForStage', 'toggleSidebar']),
},
};
</script>
<template>
<aside
- class="right-sidebar right-sidebar-expanded build-sidebar"
+ class="right-sidebar build-sidebar"
data-offset-top="101"
data-spy="affix"
>
<div class="sidebar-container">
<div class="blocks-container">
- <template v-if="!isLoading">
- <div class="block">
- <strong class="inline prepend-top-8">
- {{ job.name }}
- </strong>
- <a
- v-if="job.retry_path"
- :class="retryButtonClass"
- :href="job.retry_path"
- data-method="post"
- rel="nofollow"
- >
- {{ __('Retry') }}
- </a>
- <a
- v-if="terminalPath"
- :href="terminalPath"
- class="js-terminal-link pull-right btn btn-primary
- btn-inverted visible-md-block visible-lg-block"
- target="_blank"
- >
- {{ __('Debug') }}
- <icon name="external-link" />
- </a>
- <button
- :aria-label="__('Toggle Sidebar')"
- type="button"
- class="btn btn-blank gutter-toggle
- float-right d-block d-md-none js-sidebar-build-toggle"
- >
- <i
- aria-hidden="true"
- data-hidden="true"
- class="fa fa-angle-double-right"
- ></i>
- </button>
- </div>
- <div
- v-if="job.retry_path || job.new_issue_path"
- class="block retry-link"
+ <div class="block">
+ <strong class="inline prepend-top-8">
+ {{ job.name }}
+ </strong>
+ <a
+ v-if="job.retry_path"
+ :class="retryButtonClass"
+ :href="job.retry_path"
+ data-method="post"
+ rel="nofollow"
>
- <a
- v-if="job.new_issue_path"
- :href="job.new_issue_path"
- class="js-new-issue btn btn-success btn-inverted"
- >
- {{ __('New issue') }}
+ {{ __('Retry') }}
+ </a>
+ <a
+ v-if="job.terminal_path"
+ :href="job.terminal_path"
+ class="js-terminal-link pull-right btn btn-primary
+ btn-inverted visible-md-block visible-lg-block"
+ target="_blank"
+ >
+ {{ __('Debug') }}
+ <icon name="external-link" />
+ </a>
+ <button
+ :aria-label="__('Toggle Sidebar')"
+ type="button"
+ class="btn btn-blank gutter-toggle
+ 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>
+ </button>
+ </div>
+ <div
+ v-if="job.retry_path || job.new_issue_path"
+ class="block retry-link"
+ >
+ <a
+ v-if="job.new_issue_path"
+ :href="job.new_issue_path"
+ class="js-new-issue btn btn-success btn-inverted"
+ >
+ {{ __('New issue') }}
+ </a>
+ <a
+ v-if="job.retry_path"
+ :href="job.retry_path"
+ class="js-retry-job btn btn-inverted-secondary"
+ data-method="post"
+ rel="nofollow"
+ >
+ {{ __('Retry') }}
+ </a>
+ </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>
+ <a :href="job.merge_request.path">
+ !{{ job.merge_request.iid }}
</a>
+ </p>
+
+ <detail-row
+ v-if="job.duration"
+ :value="duration"
+ class="js-job-duration"
+ title="Duration"
+ />
+ <detail-row
+ v-if="job.finished_at"
+ :value="timeFormated(job.finished_at)"
+ class="js-job-finished"
+ title="Finished"
+ />
+ <detail-row
+ v-if="job.erased_at"
+ :value="timeFormated(job.erased_at)"
+ class="js-job-erased"
+ title="Erased"
+ />
+ <detail-row
+ v-if="job.queued"
+ :value="queued"
+ class="js-job-queued"
+ title="Queued"
+ />
+ <detail-row
+ v-if="hasTimeout"
+ :help-url="runnerHelpUrl"
+ :value="timeout"
+ 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.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">
+ {{ tag }}
+ </span>
+ </p>
+
+ <div
+ v-if="job.cancel_path"
+ class="btn-group prepend-top-5"
+ role="group">
<a
- v-if="job.retry_path"
- :href="job.retry_path"
- class="js-retry-job btn btn-inverted-secondary"
+ :href="job.cancel_path"
+ class="js-cancel-job btn btn-sm btn-default"
data-method="post"
rel="nofollow"
>
- {{ __('Retry') }}
+ {{ __('Cancel') }}
</a>
</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>
- <a :href="job.merge_request.path">
- !{{ job.merge_request.iid }}
- </a>
- </p>
-
- <detail-row
- v-if="job.duration"
- :value="duration"
- class="js-job-duration"
- title="Duration"
- />
- <detail-row
- v-if="job.finished_at"
- :value="timeFormated(job.finished_at)"
- class="js-job-finished"
- title="Finished"
- />
- <detail-row
- v-if="job.erased_at"
- :value="timeFormated(job.erased_at)"
- class="js-job-erased"
- title="Erased"
- />
- <detail-row
- v-if="job.queued"
- :value="queued"
- class="js-job-queued"
- title="Queued"
- />
- <detail-row
- v-if="hasTimeout"
- :help-url="runnerHelpUrl"
- :value="timeout"
- 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.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">
- {{ tag }}
- </span>
- </p>
-
- <div
- v-if="job.cancel_path"
- class="btn-group prepend-top-5"
- role="group">
- <a
- :href="job.cancel_path"
- class="js-cancel-job btn btn-sm btn-default"
- data-method="post"
- rel="nofollow"
- >
- {{ __('Cancel') }}
- </a>
- </div>
- </div>
- <artifacts-block
- v-if="hasArtifact"
- :artifact="job.artifact"
- />
- <trigger-block
- v-if="hasTriggers"
- :trigger="job.trigger"
- />
- <commit-block
- :is-last-block="hasStages"
- :commit="commit"
- :merge-request="job.merge_request"
- />
+ </div>
- <stages-dropdown
- :stages="stages"
- :pipeline="job.pipeline"
- @requestSidebarStageDropdown="fetchJobsForStage"
- />
+ <artifacts-block
+ v-if="hasArtifact"
+ :artifact="job.artifact"
+ />
+ <trigger-block
+ v-if="hasTriggers"
+ :trigger="job.trigger"
+ />
+ <commit-block
+ :is-last-block="hasStages"
+ :commit="commit"
+ :merge-request="job.merge_request"
+ />
- </template>
- <gl-loading-icon
- v-else
- :size="2"
- class="prepend-top-10"
+ <stages-dropdown
+ v-if="!isLoadingStages"
+ :stages="stages"
+ :pipeline="job.pipeline"
+ :selected-stage="selectedStage"
+ @requestSidebarStageDropdown="fetchJobsForStage"
/>
</div>
<jobs-container
- v-if="!isLoading && jobs.length"
+ v-if="jobs.length"
:jobs="jobs"
:job-id="job.id"
/>
diff --git a/app/assets/javascripts/jobs/components/stages_dropdown.vue b/app/assets/javascripts/jobs/components/stages_dropdown.vue
index 34d47b3a3bb..dc26b246d71 100644
--- a/app/assets/javascripts/jobs/components/stages_dropdown.vue
+++ b/app/assets/javascripts/jobs/components/stages_dropdown.vue
@@ -2,7 +2,6 @@
import _ from 'underscore';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import Icon from '~/vue_shared/components/icon.vue';
-import { __ } from '~/locale';
export default {
components: {
@@ -18,30 +17,19 @@ export default {
type: Array,
required: true,
},
- },
- data() {
- return {
- selectedStage: this.stages.length > 0 ? this.stages[0].name : __('More'),
- };
+ selectedStage: {
+ type: String,
+ required: true,
+ },
},
computed: {
hasRef() {
return !_.isEmpty(this.pipeline.ref);
},
},
- watch: {
- // When the component is initially mounted it may start with an empty stages array.
- // Once the prop is updated, we set the first stage as the selected one
- stages(newVal) {
- if (newVal.length) {
- this.selectedStage = newVal[0].name;
- }
- },
- },
methods: {
onStageClick(stage) {
this.$emit('requestSidebarStageDropdown', stage);
- this.selectedStage = stage.name;
},
},
};
diff --git a/app/assets/javascripts/jobs/components/stuck_block.vue b/app/assets/javascripts/jobs/components/stuck_block.vue
index a60643b2c65..1d5789b175a 100644
--- a/app/assets/javascripts/jobs/components/stuck_block.vue
+++ b/app/assets/javascripts/jobs/components/stuck_block.vue
@@ -23,14 +23,7 @@ export default {
<template>
<div class="bs-callout bs-callout-warning">
<p
- v-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-if="tags.length"
+ v-if="tags.length"
class="js-stuck-with-tags append-bottom-0"
>
{{ s__(`This job is stuck, because you don't have
@@ -44,6 +37,13 @@ export default {
</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>
+ <p
v-else
class="js-stuck-no-active-runner append-bottom-0"
>
diff --git a/app/assets/javascripts/jobs/index.js b/app/assets/javascripts/jobs/index.js
new file mode 100644
index 00000000000..ccd096a1da5
--- /dev/null
+++ b/app/assets/javascripts/jobs/index.js
@@ -0,0 +1,26 @@
+import Vue from 'vue';
+import JobApp from './components/job_app.vue';
+
+export default () => {
+ const element = document.getElementById('js-job-vue-app');
+
+ return new Vue({
+ el: element,
+ components: {
+ JobApp,
+ },
+ render(createElement) {
+ return createElement('job-app', {
+ props: {
+ runnerHelpUrl: element.dataset.runnerHelpUrl,
+ runnerSettingsUrl: element.dataset.runnerSettingsUrl,
+ endpoint: element.dataset.endpoint,
+ pagePath: element.dataset.buildOptionsPagePath,
+ logState: element.dataset.buildOptionsLogState,
+ buildStatus: element.dataset.buildOptionsBuildStatus,
+ },
+ });
+ },
+ });
+};
+
diff --git a/app/assets/javascripts/jobs/job_details_bundle.js b/app/assets/javascripts/jobs/job_details_bundle.js
deleted file mode 100644
index 3eb75e72506..00000000000
--- a/app/assets/javascripts/jobs/job_details_bundle.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import _ from 'underscore';
-import { mapState, mapActions } from 'vuex';
-import Vue from 'vue';
-import Job from '../job';
-import JobApp from './components/job_app.vue';
-import Sidebar from './components/sidebar.vue';
-import createStore from './store';
-
-export default () => {
- const { dataset } = document.getElementById('js-job-details-vue');
-
- // eslint-disable-next-line no-new
- new Job();
-
- const store = createStore();
- store.dispatch('setJobEndpoint', dataset.endpoint);
-
- store.dispatch('fetchJob');
-
- // Header
- // eslint-disable-next-line no-new
- new Vue({
- el: '#js-build-header-vue',
- components: {
- JobApp,
- },
- store,
- computed: {
- ...mapState(['job', 'isLoading']),
- },
- render(createElement) {
- return createElement('job-app', {
- props: {
- isLoading: this.isLoading,
- job: this.job,
- runnerHelpUrl: dataset.runnerHelpUrl,
- },
- });
- },
- });
-
- // Sidebar information block
- const detailsBlockElement = document.getElementById('js-details-block-vue');
- const detailsBlockDataset = detailsBlockElement.dataset;
- // eslint-disable-next-line
- new Vue({
- el: detailsBlockElement,
- components: {
- Sidebar,
- },
- computed: {
- ...mapState(['job']),
- },
- watch: {
- job(newVal, oldVal) {
- if (_.isEmpty(oldVal) && !_.isEmpty(newVal.pipeline)) {
- this.fetchStages();
- }
- },
- },
- methods: {
- ...mapActions(['fetchStages']),
- },
- store,
- render(createElement) {
- return createElement('sidebar', {
- props: {
- runnerHelpUrl: dataset.runnerHelpUrl,
- terminalPath: detailsBlockDataset.terminalPath,
- },
- });
- },
- });
-};
diff --git a/app/assets/javascripts/jobs/store/actions.js b/app/assets/javascripts/jobs/store/actions.js
index 298367c9342..54ed217572a 100644
--- a/app/assets/javascripts/jobs/store/actions.js
+++ b/app/assets/javascripts/jobs/store/actions.js
@@ -1,17 +1,32 @@
import Visibility from 'visibilityjs';
import * as types from './mutation_types';
-import axios from '../../lib/utils/axios_utils';
-import Poll from '../../lib/utils/poll';
-import { setCiStatusFavicon } from '../../lib/utils/common_utils';
-import flash from '../../flash';
-import { __ } from '../../locale';
+import axios from '~/lib/utils/axios_utils';
+import Poll from '~/lib/utils/poll';
+import { setFaviconOverlay, resetFavicon } from '~/lib/utils/common_utils';
+import flash from '~/flash';
+import { __ } from '~/locale';
+import {
+ canScroll,
+ isScrolledToBottom,
+ isScrolledToTop,
+ isScrolledToMiddle,
+ scrollDown,
+ scrollUp,
+} from '~/lib/utils/scroll_utils';
export const setJobEndpoint = ({ commit }, endpoint) => commit(types.SET_JOB_ENDPOINT, endpoint);
-export const setTraceEndpoint = ({ commit }, endpoint) =>
- commit(types.SET_TRACE_ENDPOINT, endpoint);
-export const setStagesEndpoint = ({ commit }, endpoint) =>
- commit(types.SET_STAGES_ENDPOINT, endpoint);
-export const setJobsEndpoint = ({ commit }, endpoint) => commit(types.SET_JOBS_ENDPOINT, endpoint);
+export const setTraceOptions = ({ commit }, options) => commit(types.SET_TRACE_OPTIONS, options);
+
+export const hideSidebar = ({ commit }) => commit(types.HIDE_SIDEBAR);
+export const showSidebar = ({ commit }) => commit(types.SHOW_SIDEBAR);
+
+export const toggleSidebar = ({ dispatch, state }) => {
+ if (state.isSidebarOpen) {
+ dispatch('hideSidebar');
+ } else {
+ dispatch('showSidebar');
+ }
+};
let eTagPoll;
@@ -62,41 +77,84 @@ export const fetchJob = ({ state, dispatch }) => {
});
};
-export const receiveJobSuccess = ({ commit }, data) => {
+export const receiveJobSuccess = ({ commit }, data = {}) => {
commit(types.RECEIVE_JOB_SUCCESS, data);
+
+ if (data.favicon) {
+ setFaviconOverlay(data.favicon);
+ } else {
+ resetFavicon();
+ }
};
export const receiveJobError = ({ commit }) => {
commit(types.RECEIVE_JOB_ERROR);
flash(__('An error occurred while fetching the job.'));
+ resetFavicon();
};
/**
* Job's Trace
*/
-export const scrollTop = ({ commit }) => {
- commit(types.SCROLL_TO_TOP);
- window.scrollTo({ top: 0 });
+export const scrollTop = ({ dispatch }) => {
+ scrollUp();
+ dispatch('toggleScrollButtons');
};
-export const scrollBottom = ({ commit }) => {
- commit(types.SCROLL_TO_BOTTOM);
- window.scrollTo({ top: document.height });
+export const scrollBottom = ({ dispatch }) => {
+ scrollDown();
+ dispatch('toggleScrollButtons');
+};
+
+/**
+ * Responsible for toggling the disabled state of the scroll buttons
+ */
+export const toggleScrollButtons = ({ dispatch }) => {
+ if (canScroll()) {
+ if (isScrolledToMiddle()) {
+ dispatch('enableScrollTop');
+ dispatch('enableScrollBottom');
+ } else if (isScrolledToTop()) {
+ dispatch('disableScrollTop');
+ dispatch('enableScrollBottom');
+ } else if (isScrolledToBottom()) {
+ dispatch('disableScrollBottom');
+ dispatch('enableScrollTop');
+ }
+ } else {
+ dispatch('disableScrollBottom');
+ dispatch('disableScrollTop');
+ }
+};
+
+export const disableScrollBottom = ({ commit }) => commit(types.DISABLE_SCROLL_BOTTOM);
+export const disableScrollTop = ({ commit }) => commit(types.DISABLE_SCROLL_TOP);
+export const enableScrollBottom = ({ commit }) => commit(types.ENABLE_SCROLL_BOTTOM);
+export const enableScrollTop = ({ commit }) => commit(types.ENABLE_SCROLL_TOP);
+
+/**
+ * While the automatic scroll down is active,
+ * we show the scroll down button with an animation
+ */
+export const toggleScrollAnimation = ({ commit }, toggle) =>
+ commit(types.TOGGLE_SCROLL_ANIMATION, toggle);
+
+/**
+ * Responsible to handle automatic scroll
+ */
+export const toggleScrollisInBottom = ({ commit }, toggle) => {
+ commit(types.TOGGLE_IS_SCROLL_IN_BOTTOM_BEFORE_UPDATING_TRACE, toggle);
};
export const requestTrace = ({ commit }) => commit(types.REQUEST_TRACE);
let traceTimeout;
-export const fetchTrace = ({ dispatch, state }) => {
- dispatch('requestTrace');
-
+export const fetchTrace = ({ dispatch, state }) =>
axios
.get(`${state.traceEndpoint}/trace.json`, {
params: { state: state.traceState },
})
.then(({ data }) => {
- if (!state.fetchingStatusFavicon) {
- dispatch('fetchFavicon');
- }
+ dispatch('toggleScrollisInBottom', isScrolledToBottom());
dispatch('receiveTraceSuccess', data);
if (!data.complete) {
@@ -108,7 +166,7 @@ export const fetchTrace = ({ dispatch, state }) => {
}
})
.catch(() => dispatch('receiveTraceError'));
-};
+
export const stopPollingTrace = ({ commit }) => {
commit(types.STOP_POLLING_TRACE);
clearTimeout(traceTimeout);
@@ -120,17 +178,6 @@ export const receiveTraceError = ({ commit }) => {
flash(__('An error occurred while fetching the job log.'));
};
-export const fetchFavicon = ({ state, dispatch }) => {
- dispatch('requestStatusFavicon');
- setCiStatusFavicon(`${state.pagePath}/status.json`)
- .then(() => dispatch('receiveStatusFaviconSuccess'))
- .catch(() => dispatch('requestStatusFaviconError'));
-};
-export const requestStatusFavicon = ({ commit }) => commit(types.REQUEST_STATUS_FAVICON);
-export const receiveStatusFaviconSuccess = ({ commit }) =>
- commit(types.RECEIVE_STATUS_FAVICON_SUCCESS);
-export const requestStatusFaviconError = ({ commit }) => commit(types.RECEIVE_STATUS_FAVICON_ERROR);
-
/**
* Stages dropdown on sidebar
*/
@@ -139,10 +186,12 @@ export const fetchStages = ({ state, dispatch }) => {
dispatch('requestStages');
axios
- .get(state.job.pipeline.path)
+ .get(`${state.job.pipeline.path}.json`)
.then(({ data }) => {
+ // Set selected stage
dispatch('receiveStagesSuccess', data.details.stages);
- dispatch('fetchJobsForStage', data.details.stages[0]);
+ const selectedStage = data.details.stages.find(stage => stage.name === state.selectedStage);
+ dispatch('fetchJobsForStage', selectedStage);
})
.catch(() => dispatch('receiveStagesError'));
};
@@ -156,11 +205,12 @@ export const receiveStagesError = ({ commit }) => {
/**
* Jobs list on sidebar - depend on stages dropdown
*/
-export const requestJobsForStage = ({ commit }) => commit(types.REQUEST_JOBS_FOR_STAGE);
+export const requestJobsForStage = ({ commit }, stage) =>
+ commit(types.REQUEST_JOBS_FOR_STAGE, stage);
// On stage click, set selected stage + fetch job
export const fetchJobsForStage = ({ dispatch }, stage) => {
- dispatch('requestJobsForStage');
+ dispatch('requestJobsForStage', stage);
axios
.get(stage.dropdown_path, {
diff --git a/app/assets/javascripts/jobs/store/getters.js b/app/assets/javascripts/jobs/store/getters.js
index afe5f88b292..4de01f8e532 100644
--- a/app/assets/javascripts/jobs/store/getters.js
+++ b/app/assets/javascripts/jobs/store/getters.js
@@ -1,5 +1,6 @@
import _ from 'underscore';
import { __ } from '~/locale';
+import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
export const headerActions = state => {
if (state.job.new_issue_path) {
@@ -22,10 +23,10 @@ export const shouldRenderCalloutMessage = state =>
!_.isEmpty(state.job.status) && !_.isEmpty(state.job.callout_message);
/**
- * When job has not started the key will be `false`
+ * When job has not started the key will be null
* When job started the key will be a string with a date.
*/
-export const jobHasStarted = state => !(state.job.started === false);
+export const shouldRenderTriggeredLabel = state => _.isString(state.job.started);
export const hasEnvironment = state => !_.isEmpty(state.job.deployment_status);
@@ -34,20 +35,16 @@ export const hasEnvironment = state => !_.isEmpty(state.job.deployment_status);
* Used to check if it should render the job log or the empty state
* @returns {Boolean}
*/
-export const hasTrace = state => state.job.has_trace || state.job.status.group === 'running';
+export const hasTrace = state => state.job.has_trace || (!_.isEmpty(state.job.status) && state.job.status.group === 'running');
export const emptyStateIllustration = state =>
(state.job && state.job.status && state.job.status.illustration) || {};
-/**
- * When the job is pending and there are no available runners
- * we need to render the stuck block;
- *
- * @returns {Boolean}
- */
-export const isJobStuck = state =>
- state.job.status.group === 'pending' &&
- (!_.isEmpty(state.job.runners) && state.job.runners.available === false);
+export const emptyStateAction = state => (state.job && state.job.status && state.job.status.action) || {};
+
+export const isScrollingDown = state => isScrolledToBottom() && !state.isTraceComplete;
+
+export const hasRunnersForProject = state => state.job.runners.available && !state.job.runners.online;
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/jobs/store/mutation_types.js b/app/assets/javascripts/jobs/store/mutation_types.js
index e66e1d4f116..fd098f13e90 100644
--- a/app/assets/javascripts/jobs/store/mutation_types.js
+++ b/app/assets/javascripts/jobs/store/mutation_types.js
@@ -1,10 +1,19 @@
export const SET_JOB_ENDPOINT = 'SET_JOB_ENDPOINT';
-export const SET_TRACE_ENDPOINT = 'SET_TRACE_ENDPOINT';
-export const SET_STAGES_ENDPOINT = 'SET_STAGES_ENDPOINT';
-export const SET_JOBS_ENDPOINT = 'SET_JOBS_ENDPOINT';
+export const SET_TRACE_OPTIONS = 'SET_TRACE_OPTIONS';
+
+export const HIDE_SIDEBAR = 'HIDE_SIDEBAR';
+export const SHOW_SIDEBAR = 'SHOW_SIDEBAR';
export const SCROLL_TO_TOP = 'SCROLL_TO_TOP';
export const SCROLL_TO_BOTTOM = 'SCROLL_TO_BOTTOM';
+export const DISABLE_SCROLL_BOTTOM = 'DISABLE_SCROLL_BOTTOM';
+export const DISABLE_SCROLL_TOP = 'DISABLE_SCROLL_TOP';
+export const ENABLE_SCROLL_BOTTOM = 'ENABLE_SCROLL_BOTTOM';
+export const ENABLE_SCROLL_TOP = 'ENABLE_SCROLL_TOP';
+// TODO
+export const TOGGLE_SCROLL_ANIMATION = 'TOGGLE_SCROLL_ANIMATION';
+
+export const TOGGLE_IS_SCROLL_IN_BOTTOM_BEFORE_UPDATING_TRACE = 'TOGGLE_IS_SCROLL_IN_BOTTOM';
export const REQUEST_JOB = 'REQUEST_JOB';
export const RECEIVE_JOB_SUCCESS = 'RECEIVE_JOB_SUCCESS';
@@ -15,10 +24,6 @@ export const STOP_POLLING_TRACE = 'STOP_POLLING_TRACE';
export const RECEIVE_TRACE_SUCCESS = 'RECEIVE_TRACE_SUCCESS';
export const RECEIVE_TRACE_ERROR = 'RECEIVE_TRACE_ERROR';
-export const REQUEST_STATUS_FAVICON = 'REQUEST_STATUS_FAVICON';
-export const RECEIVE_STATUS_FAVICON_SUCCESS = 'RECEIVE_STATUS_FAVICON_SUCCESS';
-export const RECEIVE_STATUS_FAVICON_ERROR = 'RECEIVE_STATUS_FAVICON_ERROR';
-
export const REQUEST_STAGES = 'REQUEST_STAGES';
export const RECEIVE_STAGES_SUCCESS = 'RECEIVE_STAGES_SUCCESS';
export const RECEIVE_STAGES_ERROR = 'RECEIVE_STAGES_ERROR';
diff --git a/app/assets/javascripts/jobs/store/mutations.js b/app/assets/javascripts/jobs/store/mutations.js
index c3f2359fa4d..cd440d21c1f 100644
--- a/app/assets/javascripts/jobs/store/mutations.js
+++ b/app/assets/javascripts/jobs/store/mutations.js
@@ -4,14 +4,17 @@ export default {
[types.SET_JOB_ENDPOINT](state, endpoint) {
state.jobEndpoint = endpoint;
},
- [types.REQUEST_STATUS_FAVICON](state) {
- state.fetchingStatusFavicon = true;
+
+ [types.SET_TRACE_OPTIONS](state, options = {}) {
+ state.traceEndpoint = options.pagePath;
+ state.traceState = options.logState;
},
- [types.RECEIVE_STATUS_FAVICON_SUCCESS](state) {
- state.fetchingStatusFavicon = false;
+
+ [types.HIDE_SIDEBAR](state) {
+ state.isSidebarOpen = false;
},
- [types.RECEIVE_STATUS_FAVICON_ERROR](state) {
- state.fetchingStatusFavicon = false;
+ [types.SHOW_SIDEBAR](state) {
+ state.isSidebarOpen = true;
},
[types.RECEIVE_TRACE_SUCCESS](state, log) {
@@ -23,8 +26,12 @@ export default {
state.trace += log.html;
state.traceSize += log.size;
} else {
- state.trace = log.html;
- state.traceSize = log.size;
+ // When the job still does not have a trace
+ // the trace response will not have a defined
+ // html or size. We keep the old value otherwise these
+ // will be set to `undefined`
+ state.trace = log.html || state.trace;
+ state.traceSize = log.size || state.traceSize;
}
if (state.traceSize < log.total) {
@@ -33,40 +40,65 @@ export default {
state.isTraceSizeVisible = false;
}
- state.isTraceComplete = log.complete;
- state.hasTraceError = false;
+ state.isTraceComplete = log.complete || state.isTraceComplete;
},
+
+ /**
+ * Will remove loading animation
+ */
[types.STOP_POLLING_TRACE](state) {
state.isTraceComplete = true;
},
- // todo_fl: check this.
+
+ /**
+ * Will remove loading animation
+ */
[types.RECEIVE_TRACE_ERROR](state) {
- state.isLoadingTrace = false;
state.isTraceComplete = true;
- state.hasTraceError = true;
},
[types.REQUEST_JOB](state) {
state.isLoading = true;
},
[types.RECEIVE_JOB_SUCCESS](state, job) {
- state.isLoading = false;
state.hasError = false;
+ state.isLoading = false;
state.job = job;
+
+ /**
+ * We only update it on the first request
+ * The dropdown can be changed by the user
+ * after the first request,
+ * and we do not want to hijack that
+ */
+ if (state.selectedStage === '' && job.stage) {
+ state.selectedStage = job.stage;
+ }
},
[types.RECEIVE_JOB_ERROR](state) {
state.isLoading = false;
- state.hasError = true;
state.job = {};
+ state.hasError = true;
},
- [types.SCROLL_TO_TOP](state) {
- state.isTraceScrolledToBottom = false;
- state.hasBeenScrolled = true;
+ [types.ENABLE_SCROLL_TOP](state) {
+ state.isScrollTopDisabled = false;
+ },
+ [types.DISABLE_SCROLL_TOP](state) {
+ state.isScrollTopDisabled = true;
+ },
+ [types.ENABLE_SCROLL_BOTTOM](state) {
+ state.isScrollBottomDisabled = false;
},
- [types.SCROLL_TO_BOTTOM](state) {
- state.isTraceScrolledToBottom = true;
- state.hasBeenScrolled = true;
+ [types.DISABLE_SCROLL_BOTTOM](state) {
+ state.isScrollBottomDisabled = true;
+ },
+ [types.TOGGLE_SCROLL_ANIMATION](state, toggle) {
+ state.isScrollingDown = toggle;
+ },
+
+ [types.TOGGLE_IS_SCROLL_IN_BOTTOM_BEFORE_UPDATING_TRACE](state, toggle) {
+ state.isScrolledToBottomBeforeReceivingTrace = toggle;
},
[types.REQUEST_STAGES](state) {
@@ -81,8 +113,9 @@ export default {
state.stages = [];
},
- [types.REQUEST_JOBS_FOR_STAGE](state) {
+ [types.REQUEST_JOBS_FOR_STAGE](state, stage) {
state.isLoadingJobs = true;
+ state.selectedStage = stage.name;
},
[types.RECEIVE_JOBS_FOR_STAGE_SUCCESS](state, jobs) {
state.isLoadingJobs = false;
diff --git a/app/assets/javascripts/jobs/store/state.js b/app/assets/javascripts/jobs/store/state.js
index 509cb69a5d3..04825187c99 100644
--- a/app/assets/javascripts/jobs/store/state.js
+++ b/app/assets/javascripts/jobs/store/state.js
@@ -2,39 +2,32 @@ export default () => ({
jobEndpoint: null,
traceEndpoint: null,
- // dropdown options
- stagesEndpoint: null,
- // list of jobs on sidebard
- stageJobsEndpoint: null,
+ // sidebar
+ isSidebarOpen: true,
- // job log
isLoading: false,
hasError: false,
job: {},
- // trace
- isLoadingTrace: false,
- hasTraceError: false,
+ // scroll buttons state
+ isScrollBottomDisabled: true,
+ isScrollTopDisabled: true,
- trace: '',
-
- isTraceScrolledToBottom: false,
- hasBeenScrolled: false,
+ // Used to check if we should keep the automatic scroll
+ isScrolledToBottomBeforeReceivingTrace: true,
+ trace: '',
isTraceComplete: false,
- traceSize: 0, // todo_fl: needs to be converted into human readable format in components
+ traceSize: 0,
isTraceSizeVisible: false,
- fetchingStatusFavicon: false,
- // used as a query parameter
+ // used as a query parameter to fetch the trace
traceState: null,
- // used to check if we need to redirect the user - todo_fl: check if actually needed
- traceStatus: null,
- // sidebar dropdown
+ // sidebar dropdown & list of jobs
isLoadingStages: false,
isLoadingJobs: false,
- selectedStage: null,
+ selectedStage: '',
stages: [],
jobs: [],
});
diff --git a/app/assets/javascripts/jobs/svg/scroll_down.svg b/app/assets/javascripts/jobs/svg/scroll_down.svg
new file mode 100644
index 00000000000..1d22870ec09
--- /dev/null
+++ b/app/assets/javascripts/jobs/svg/scroll_down.svg
@@ -0,0 +1,5 @@
+<svg width="12" height="16" viewBox="0 0 12 16" xmlns="http://www.w3.org/2000/svg">
+ <path class="first-triangle" d="M1.048 14.155a.508.508 0 0 0-.32.105c-.091.07-.136.154-.136.25v.71c0 .095.045.178.135.249.09.07.197.105.321.105h10.043c.124 0 .23-.035.321-.105.09-.07.136-.154.136-.25v-.71c0-.095-.045-.178-.136-.249a.508.508 0 0 0-.32-.105"/>
+ <path class="second-triangle" d="M.687 8.027c-.09-.087-.122-.16-.093-.22.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 12.91a.458.458 0 0 1-.136.089h-.37a.626.626 0 0 1-.136-.09"/>
+ <path class="third-triangle" d="M.687 1.027C.597.94.565.867.594.807c.028-.06.104-.09.228-.09h10.5c.123 0 .2.03.228.09.029.06-.002.133-.093.22L6.393 5.91A.458.458 0 0 1 6.257 6h-.37a.626.626 0 0 1-.136-.09"/>
+</svg>
diff --git a/app/assets/javascripts/label_manager.js b/app/assets/javascripts/label_manager.js
index 2c995c5902f..062501d1d04 100644
--- a/app/assets/javascripts/label_manager.js
+++ b/app/assets/javascripts/label_manager.js
@@ -47,7 +47,10 @@ export default class LabelManager {
}
toggleEmptyState($label, $btn, action) {
- this.emptyState.classList.toggle('hidden', !!this.prioritizedLabels[0].querySelector(':scope > li'));
+ this.emptyState.classList.toggle(
+ 'hidden',
+ !!this.prioritizedLabels[0].querySelector(':scope > li'),
+ );
}
toggleLabelPriority($label, action, persistState) {
@@ -80,16 +83,14 @@ export default class LabelManager {
return;
}
if (action === 'remove') {
- axios.delete(url)
- .catch(rollbackLabelPosition);
+ axios.delete(url).catch(rollbackLabelPosition);
// Restore empty message
if (!$from.find('li').length) {
$from.find('.empty-message').removeClass('hidden');
}
} else {
- this.savePrioritySort($label, action)
- .catch(rollbackLabelPosition);
+ this.savePrioritySort($label, action).catch(rollbackLabelPosition);
}
}
@@ -102,8 +103,7 @@ export default class LabelManager {
}
onPrioritySortUpdate() {
- this.savePrioritySort()
- .catch(() => flash(this.errorMessage));
+ this.savePrioritySort().catch(() => flash(this.errorMessage));
}
savePrioritySort() {
diff --git a/app/assets/javascripts/labels.js b/app/assets/javascripts/labels.js
index d85ae851706..2bc09237495 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 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/layout_nav.js b/app/assets/javascripts/layout_nav.js
index e3177188772..b8c3c237eb3 100644
--- a/app/assets/javascripts/layout_nav.js
+++ b/app/assets/javascripts/layout_nav.js
@@ -5,7 +5,9 @@ import initFlyOutNav from './fly_out_nav';
function hideEndFade($scrollingTabs) {
$scrollingTabs.each(function scrollTabsLoop() {
const $this = $(this);
- $this.siblings('.fade-right').toggleClass('scrolling', Math.round($this.width()) < $this.prop('scrollWidth'));
+ $this
+ .siblings('.fade-right')
+ .toggleClass('scrolling', Math.round($this.width()) < $this.prop('scrollWidth'));
});
}
@@ -15,38 +17,42 @@ export default function initLayoutNav() {
initFlyOutNav();
- $(document).on('init.scrolling-tabs', () => {
- const $scrollingTabs = $('.scrolling-tabs').not('.is-initialized');
- $scrollingTabs.addClass('is-initialized');
+ $(document)
+ .on('init.scrolling-tabs', () => {
+ const $scrollingTabs = $('.scrolling-tabs').not('.is-initialized');
+ $scrollingTabs.addClass('is-initialized');
- $(window).on('resize.nav', () => {
- hideEndFade($scrollingTabs);
- }).trigger('resize.nav');
+ $(window)
+ .on('resize.nav', () => {
+ hideEndFade($scrollingTabs);
+ })
+ .trigger('resize.nav');
- $scrollingTabs.on('scroll', function tabsScrollEvent() {
- const $this = $(this);
- const currentPosition = $this.scrollLeft();
- const maxPosition = $this.prop('scrollWidth') - $this.outerWidth();
+ $scrollingTabs.on('scroll', function tabsScrollEvent() {
+ const $this = $(this);
+ const currentPosition = $this.scrollLeft();
+ const maxPosition = $this.prop('scrollWidth') - $this.outerWidth();
- $this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0);
- $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1);
- });
+ $this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0);
+ $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1);
+ });
- $scrollingTabs.each(function scrollTabsEachLoop() {
- const $this = $(this);
- const scrollingTabWidth = $this.width();
- const $active = $this.find('.active');
- const activeWidth = $active.width();
+ $scrollingTabs.each(function scrollTabsEachLoop() {
+ const $this = $(this);
+ const scrollingTabWidth = $this.width();
+ const $active = $this.find('.active');
+ const activeWidth = $active.width();
- if ($active.length) {
- const offset = $active.offset().left + activeWidth;
+ if ($active.length) {
+ const offset = $active.offset().left + activeWidth;
- if (offset > scrollingTabWidth - 30) {
- const scrollLeft = (offset - (scrollingTabWidth / 2)) - (activeWidth / 2);
+ if (offset > scrollingTabWidth - 30) {
+ const scrollLeft = offset - scrollingTabWidth / 2 - activeWidth / 2;
- $this.scrollLeft(scrollLeft);
+ $this.scrollLeft(scrollLeft);
+ }
}
- }
- });
- }).trigger('init.scrolling-tabs');
+ });
+ })
+ .trigger('init.scrolling-tabs');
}
diff --git a/app/assets/javascripts/lib/ace.js b/app/assets/javascripts/lib/ace.js
index 9cdc0309503..e90b3d2eec7 100644
--- a/app/assets/javascripts/lib/ace.js
+++ b/app/assets/javascripts/lib/ace.js
@@ -1,3 +1,4 @@
/*= require ace/ace */
+/*= require ace/ext-modelist */
/*= require ace/ext-searchbox */
/*= require ./ace/ace_config_paths */
diff --git a/app/assets/javascripts/lib/utils/ace_utils.js b/app/assets/javascripts/lib/utils/ace_utils.js
new file mode 100644
index 00000000000..efc4b2a8d94
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/ace_utils.js
@@ -0,0 +1,6 @@
+/* global ace */
+
+export default function getModeByFileExtension(path) {
+ const modelist = ace.require("ace/ext/modelist");
+ return modelist.getModeForPath(path).mode;
+};
diff --git a/app/assets/javascripts/lib/utils/datefix.js b/app/assets/javascripts/lib/utils/datefix.js
deleted file mode 100644
index 19e4085dbbb..00000000000
--- a/app/assets/javascripts/lib/utils/datefix.js
+++ /dev/null
@@ -1,28 +0,0 @@
-export const pad = (val, len = 2) => `0${val}`.slice(-len);
-
-/**
- * Formats dates in Pickaday
- * @param {String} dateString Date in yyyy-mm-dd format
- * @return {Date} UTC format
- */
-export const parsePikadayDate = dateString => {
- const parts = dateString.split('-');
- const year = parseInt(parts[0], 10);
- const month = parseInt(parts[1] - 1, 10);
- const day = parseInt(parts[2], 10);
-
- return new Date(year, month, day);
-};
-
-/**
- * Used `onSelect` method in pickaday
- * @param {Date} date UTC format
- * @return {String} Date formated in yyyy-mm-dd
- */
-export const pikadayToString = date => {
- const day = pad(date.getDate());
- const month = pad(date.getMonth() + 1);
- const year = date.getFullYear();
-
- return `${year}-${month}-${day}`;
-};
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index 833dbefd3dc..46740308f17 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import _ from 'underscore';
import timeago from 'timeago.js';
import dateFormat from 'dateformat';
import { pluralize } from './text_utility';
@@ -46,6 +47,8 @@ const getMonthNames = abbreviated => {
];
};
+export const pad = (val, len = 2) => `0${val}`.slice(-len);
+
/**
* Given a date object returns the day of the week in English
* @param {date} date
@@ -74,10 +77,10 @@ let timeagoInstance;
/**
* Sets a timeago Instance
*/
-export function getTimeago() {
+export const getTimeago = () => {
if (!timeagoInstance) {
- const localeRemaining = function getLocaleRemaining(number, index) {
- return [
+ const localeRemaining = (number, index) =>
+ [
[s__('Timeago|just now'), s__('Timeago|right now')],
[s__('Timeago|%s seconds ago'), s__('Timeago|%s seconds remaining')],
[s__('Timeago|1 minute ago'), s__('Timeago|1 minute remaining')],
@@ -93,9 +96,9 @@ export function getTimeago() {
[s__('Timeago|1 year ago'), s__('Timeago|1 year remaining')],
[s__('Timeago|%s years ago'), s__('Timeago|%s years remaining')],
][index];
- };
- const locale = function getLocale(number, index) {
- return [
+
+ const locale = (number, index) =>
+ [
[s__('Timeago|just now'), s__('Timeago|right now')],
[s__('Timeago|%s seconds ago'), s__('Timeago|in %s seconds')],
[s__('Timeago|1 minute ago'), s__('Timeago|in 1 minute')],
@@ -111,7 +114,6 @@ export function getTimeago() {
[s__('Timeago|1 year ago'), s__('Timeago|in 1 year')],
[s__('Timeago|%s years ago'), s__('Timeago|in %s years')],
][index];
- };
timeago.register(timeagoLanguageCode, locale);
timeago.register(`${timeagoLanguageCode}-remaining`, localeRemaining);
@@ -119,7 +121,7 @@ export function getTimeago() {
}
return timeagoInstance;
-}
+};
/**
* For the given element, renders a timeago instance.
@@ -184,7 +186,7 @@ export const getDayDifference = (a, b) => {
* @param {Number} seconds
* @return {String}
*/
-export function timeIntervalInWords(intervalInSeconds) {
+export const timeIntervalInWords = intervalInSeconds => {
const secondsInteger = parseInt(intervalInSeconds, 10);
const minutes = Math.floor(secondsInteger / 60);
const seconds = secondsInteger - minutes * 60;
@@ -196,9 +198,9 @@ export function timeIntervalInWords(intervalInSeconds) {
text = `${seconds} ${pluralize('second', seconds)}`;
}
return text;
-}
+};
-export function dateInWords(date, abbreviated = false, hideYear = false) {
+export const dateInWords = (date, abbreviated = false, hideYear = false) => {
if (!date) return date;
const month = date.getMonth();
@@ -240,7 +242,7 @@ export function dateInWords(date, abbreviated = false, hideYear = false) {
}
return `${monthName} ${date.getDate()}, ${year}`;
-}
+};
/**
* Returns month name based on provided date.
@@ -391,3 +393,95 @@ export const formatTime = milliseconds => {
formattedTime += remainingSeconds;
return formattedTime;
};
+
+/**
+ * Formats dates in Pickaday
+ * @param {String} dateString Date in yyyy-mm-dd format
+ * @return {Date} UTC format
+ */
+export const parsePikadayDate = dateString => {
+ const parts = dateString.split('-');
+ const year = parseInt(parts[0], 10);
+ const month = parseInt(parts[1] - 1, 10);
+ const day = parseInt(parts[2], 10);
+
+ return new Date(year, month, day);
+};
+
+/**
+ * Used `onSelect` method in pickaday
+ * @param {Date} date UTC format
+ * @return {String} Date formated in yyyy-mm-dd
+ */
+export const pikadayToString = date => {
+ const day = pad(date.getDate());
+ const month = pad(date.getMonth() + 1);
+ const year = date.getFullYear();
+
+ return `${year}-${month}-${day}`;
+};
+
+/**
+ * Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # }
+ * Seconds can be negative or positive, zero or non-zero. Can be configured for any day
+ * or week length.
+ */
+export const parseSeconds = (seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) => {
+ const DAYS_PER_WEEK = daysPerWeek;
+ const HOURS_PER_DAY = hoursPerDay;
+ const MINUTES_PER_HOUR = 60;
+ const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR;
+ const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR;
+
+ const timePeriodConstraints = {
+ weeks: MINUTES_PER_WEEK,
+ days: MINUTES_PER_DAY,
+ hours: MINUTES_PER_HOUR,
+ minutes: 1,
+ };
+
+ let unorderedMinutes = Math.abs(seconds / MINUTES_PER_HOUR);
+
+ return _.mapObject(timePeriodConstraints, minutesPerPeriod => {
+ const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
+
+ unorderedMinutes -= periodCount * minutesPerPeriod;
+
+ return periodCount;
+ });
+};
+
+/**
+ * Accepts a timeObject (see parseSeconds) and returns a condensed string representation of it
+ * (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included.
+ */
+export const stringifyTime = timeObject => {
+ const reducedTime = _.reduce(
+ timeObject,
+ (memo, unitValue, unitName) => {
+ const isNonZero = !!unitValue;
+ return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo;
+ },
+ '',
+ ).trim();
+ return reducedTime.length ? reducedTime : '0m';
+};
+
+/**
+ * Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns
+ * the first non-zero unit/value pair.
+ */
+export const abbreviateTime = timeStr =>
+ timeStr.split(' ').filter(unitStr => unitStr.charAt(0) !== '0')[0];
+
+/**
+ * Calculates the milliseconds between now and a given date string.
+ * The result cannot become negative.
+ *
+ * @param endDate date string that the time difference is calculated for
+ * @return {number} number of milliseconds remaining until the given date
+ */
+export const calculateRemainingMilliseconds = endDate => {
+ const remainingMilliseconds = new Date(endDate).getTime() - Date.now();
+ return Math.max(remainingMilliseconds, 0);
+};
diff --git a/app/assets/javascripts/lib/utils/pretty_time.js b/app/assets/javascripts/lib/utils/pretty_time.js
deleted file mode 100644
index d92b8a7179f..00000000000
--- a/app/assets/javascripts/lib/utils/pretty_time.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import _ from 'underscore';
-
-/*
- * TODO: Make these methods more configurable (e.g. stringifyTime condensed or
- * non-condensed, abbreviateTimelengths)
- * */
-
-/*
- * Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # }
- * Seconds can be negative or positive, zero or non-zero. Can be configured for any day
- * or week length.
-*/
-
-export function parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) {
- const DAYS_PER_WEEK = daysPerWeek;
- const HOURS_PER_DAY = hoursPerDay;
- const MINUTES_PER_HOUR = 60;
- const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR;
- const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR;
-
- const timePeriodConstraints = {
- weeks: MINUTES_PER_WEEK,
- days: MINUTES_PER_DAY,
- hours: MINUTES_PER_HOUR,
- minutes: 1,
- };
-
- let unorderedMinutes = Math.abs(seconds / MINUTES_PER_HOUR);
-
- return _.mapObject(timePeriodConstraints, minutesPerPeriod => {
- const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
-
- unorderedMinutes -= periodCount * minutesPerPeriod;
-
- return periodCount;
- });
-}
-
-/*
-* Accepts a timeObject (see parseSeconds) and returns a condensed string representation of it
-* (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included.
-*/
-
-export function stringifyTime(timeObject) {
- const reducedTime = _.reduce(
- timeObject,
- (memo, unitValue, unitName) => {
- const isNonZero = !!unitValue;
- return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo;
- },
- '',
- ).trim();
- return reducedTime.length ? reducedTime : '0m';
-}
-
-/*
-* Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns
-* the first non-zero unit/value pair.
-*/
-
-export function abbreviateTime(timeStr) {
- return timeStr.split(' ').filter(unitStr => unitStr.charAt(0) !== '0')[0];
-}
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index e26a6b986be..c52cfb806a2 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -2,6 +2,8 @@
import $ from 'jquery';
import { insertText } from '~/lib/utils/common_utils';
+const LINK_TAG_PATTERN = '[{text}](url)';
+
function selectedText(text, textarea) {
return text.substring(textarea.selectionStart, textarea.selectionEnd);
}
@@ -76,6 +78,21 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr
removedFirstNewLine = false;
currentLineEmpty = false;
+ // check for link pattern and selected text is an URL
+ // if so fill in the url part instead of the text part of the pattern.
+ if (tag === LINK_TAG_PATTERN) {
+ if (URL) {
+ try {
+ const ignoredUrl = new URL(selected);
+ // valid url
+ tag = '[text]({text})';
+ select = 'text';
+ } catch (e) {
+ // ignore - no valid url
+ }
+ }
+ }
+
// Remove the first newline
if (selected.indexOf('\n') === 0) {
removedFirstNewLine = true;
diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js
index 250980919dd..7cc7cd6d20e 100644
--- a/app/assets/javascripts/lib/utils/text_utility.js
+++ b/app/assets/javascripts/lib/utils/text_utility.js
@@ -53,10 +53,7 @@ export const slugify = str => str.trim().toLowerCase();
* @param {String} str
* @returns {String}
*/
-export const slugifyWithHyphens = str => {
- const regex = new RegExp(/\s+/, 'g');
- return str.toLowerCase().replace(regex, '-');
-};
+export const slugifyWithHyphens = str => str.toLowerCase().replace(/\s+/g, '-');
/**
* Truncates given text
diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js
index d58fd63bb33..4db63c841a9 100644
--- a/app/assets/javascripts/line_highlighter.js
+++ b/app/assets/javascripts/line_highlighter.js
@@ -70,7 +70,7 @@ LineHighlighter.prototype.highlightHash = function(newHash) {
const scrollOptions = {
// Scroll to the first highlighted line on initial load
// Offset -50 for the sticky top bar, and another -100 for some context
- offset: -150
+ offset: -150,
};
if (this.options.scrollFileHolder) {
$(this.options.fileHolderSelector).scrollTo(lineSelector, scrollOptions);
@@ -85,7 +85,9 @@ LineHighlighter.prototype.clickHandler = function(event) {
var current, lineNumber, range;
event.preventDefault();
this.clearHighlight();
- lineNumber = $(event.target).closest('a').data('lineNumber');
+ lineNumber = $(event.target)
+ .closest('a')
+ .data('lineNumber');
current = this.hashToRange(this._hash);
if (!(current[0] && event.shiftKey)) {
// If there's no current selection, or there is but Shift wasn't held,
@@ -104,7 +106,7 @@ LineHighlighter.prototype.clickHandler = function(event) {
};
LineHighlighter.prototype.clearHighlight = function() {
- return $("." + this.highlightLineClass).removeClass(this.highlightLineClass);
+ return $('.' + this.highlightLineClass).removeClass(this.highlightLineClass);
};
// Convert a URL hash String into line numbers
@@ -135,7 +137,7 @@ LineHighlighter.prototype.hashToRange = function(hash) {
//
// lineNumber - Line number to highlight
LineHighlighter.prototype.highlightLine = function(lineNumber) {
- return $("#LC" + lineNumber).addClass(this.highlightLineClass);
+ return $('#LC' + lineNumber).addClass(this.highlightLineClass);
};
// Highlight all lines within a range
@@ -160,9 +162,9 @@ LineHighlighter.prototype.highlightRange = function(range) {
LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
var hash;
if (lastLineNumber) {
- hash = "#L" + firstLineNumber + "-" + lastLineNumber;
+ hash = '#L' + firstLineNumber + '-' + lastLineNumber;
} else {
- hash = "#L" + firstLineNumber;
+ hash = '#L' + firstLineNumber;
}
this._hash = hash;
return this.__setLocationHash__(hash);
@@ -172,11 +174,15 @@ LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
//
// This method is stubbed in tests.
LineHighlighter.prototype.__setLocationHash__ = function(value) {
- return window.history.pushState({
- url: value
- // We're using pushState instead of assigning location.hash directly to
- // prevent the page from scrolling on the hashchange event
- }, document.title, value);
+ return window.history.pushState(
+ {
+ url: value,
+ // We're using pushState instead of assigning location.hash directly to
+ // prevent the page from scrolling on the hashchange event
+ },
+ document.title,
+ value,
+ );
};
export default LineHighlighter;
diff --git a/app/assets/javascripts/locale/sprintf.js b/app/assets/javascripts/locale/sprintf.js
index 599104dcfa0..5246c49842e 100644
--- a/app/assets/javascripts/locale/sprintf.js
+++ b/app/assets/javascripts/locale/sprintf.js
@@ -15,7 +15,7 @@ export default (input, parameters, escapeParameters = true) => {
let output = input;
if (parameters) {
- Object.keys(parameters).forEach((parameterName) => {
+ Object.keys(parameters).forEach(parameterName => {
const parameterValue = parameters[parameterName];
const escapedParameterValue = escapeParameters ? _.escape(parameterValue) : parameterValue;
output = output.replace(new RegExp(`%{${parameterName}}`, 'g'), escapedParameterValue);
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index e8aac51a299..a88b575ad99 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -202,7 +202,6 @@ document.addEventListener('DOMContentLoaded', () => {
$('.navbar-toggler').on('click', () => {
$('.header-content').toggleClass('menu-expanded');
- gl.lazyLoader.loadCheck();
});
// Show/hide comments on diff
diff --git a/app/assets/javascripts/member_expiration_date.js b/app/assets/javascripts/member_expiration_date.js
index d27922a2099..0beedcacf33 100644
--- a/app/assets/javascripts/member_expiration_date.js
+++ b/app/assets/javascripts/member_expiration_date.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import Pikaday from 'pikaday';
-import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
+import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
// Add datepickers to all `js-access-expiration-date` elements. If those elements are
// children of an element with the `clearable-input` class, and have a sibling
@@ -9,7 +9,9 @@ import { parsePikadayDate, pikadayToString } from './lib/utils/datefix';
//
export default function memberExpirationDate(selector = '.js-access-expiration-date') {
function toggleClearInput() {
- $(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== '');
+ $(this)
+ .closest('.clearable-input')
+ .toggleClass('has-value', $(this).val() !== '');
}
const inputs = $(selector);
@@ -40,7 +42,9 @@ export default function memberExpirationDate(selector = '.js-access-expiration-d
inputs.next('.js-clear-input').on('click', function clicked(event) {
event.preventDefault();
- const input = $(this).closest('.clearable-input').find(selector);
+ const input = $(this)
+ .closest('.clearable-input')
+ .find(selector);
const calendar = input.data('pikaday');
calendar.setDate(null);
diff --git a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js
index 425b806e9d6..a62ebe23646 100644
--- a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js
+++ b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.js
@@ -5,6 +5,7 @@ import Vue from 'vue';
import axios from '~/lib/utils/axios_utils';
import flash from '~/flash';
import { __ } from '~/locale';
+import getModeByFileExtension from '~/lib/utils/ace_utils';
(global => {
global.mergeConflicts = global.mergeConflicts || {};
@@ -72,7 +73,7 @@ import { __ } from '~/locale';
this.fileLoaded = true;
this.editor = ace.edit(content);
this.editor.$blockScrolling = Infinity; // Turn off annoying warning
- this.editor.getSession().setMode(`ace/mode/${data.blob_ace_mode}`);
+ this.editor.getSession().setMode(getModeByFileExtension(data.new_path));
this.editor.on('change', () => {
this.saveDiffResolution();
});
diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js
index 9b6d7d1772f..0deae478deb 100644
--- a/app/assets/javascripts/merge_request.js
+++ b/app/assets/javascripts/merge_request.js
@@ -16,26 +16,29 @@ function MergeRequest(opts) {
this.opts = opts != null ? opts : {};
this.submitNoteForm = this.submitNoteForm.bind(this);
this.$el = $('.merge-request');
- this.$('.show-all-commits').on('click', (function(_this) {
- return function() {
- return _this.showAllCommits();
- };
- })(this));
+ this.$('.show-all-commits').on(
+ 'click',
+ (function(_this) {
+ return function() {
+ return _this.showAllCommits();
+ };
+ })(this),
+ );
this.initTabs();
this.initMRBtnListeners();
this.initCommitMessageListeners();
this.closeReopenReportToggle = IssuablesHelper.initCloseReopenReport();
- if ($("a.btn-close").length) {
+ if ($('a.btn-close').length) {
this.taskList = new TaskList({
dataType: 'merge_request',
fieldName: 'description',
selector: '.detail-page-description',
- onSuccess: (result) => {
+ onSuccess: result => {
document.querySelector('#task_status').innerText = result.task_status;
document.querySelector('#task_status_short').innerText = result.task_status_short;
- }
+ },
});
}
}
@@ -84,7 +87,7 @@ MergeRequest.prototype.initMRBtnListeners = function() {
MergeRequest.prototype.submitNoteForm = function(form, $button) {
var noteText;
- noteText = form.find("textarea.js-note-text").val();
+ noteText = form.find('textarea.js-note-text').val();
if (noteText.trim().length > 0) {
form.submit();
$button.data('submitted', true);
@@ -122,7 +125,7 @@ MergeRequest.setStatusBoxToMerged = function() {
MergeRequest.decreaseCounter = function(by = 1) {
const $el = $('.js-merge-counter');
- const count = Math.max((parseInt($el.text().replace(/[^\d]/, ''), 10) - by), 0);
+ const count = Math.max(parseInt($el.text().replace(/[^\d]/, ''), 10) - by, 0);
$el.text(addDelimiter(count));
};
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 03f3bb42193..2950c2299ab 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -419,7 +419,7 @@ export default class MergeRequestTabs {
if (this.diffViewType() === 'parallel' || removeLimited) {
$wrapper.removeClass('container-limited');
} else {
- $wrapper.addClass('container-limited');
+ $wrapper.toggleClass('container-limited', this.fixedLayoutPref);
}
}
diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js
index 6da04020881..f211632cf24 100644
--- a/app/assets/javascripts/milestone.js
+++ b/app/assets/javascripts/milestone.js
@@ -15,7 +15,7 @@ export default class Milestone {
}
bindTabsSwitching() {
- return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => {
+ return $('a[data-toggle="tab"]').on('show.bs.tab', e => {
const $target = $(e.target);
window.location.hash = $target.attr('href');
@@ -36,7 +36,8 @@ export default class Milestone {
const tabElId = $target.attr('href');
if (endpoint && !$target.hasClass('is-loaded')) {
- axios.get(endpoint)
+ axios
+ .get(endpoint)
.then(({ data }) => {
$(tabElId).html(data.html);
$target.addClass('is-loaded');
@@ -46,23 +47,28 @@ export default class Milestone {
}
static initDeprecationMessage() {
- const deprecationMesssageContainer = document.querySelector('.js-milestone-deprecation-message');
+ const deprecationMesssageContainer = document.querySelector(
+ '.js-milestone-deprecation-message',
+ );
if (!deprecationMesssageContainer) return;
- const deprecationMessage = deprecationMesssageContainer.querySelector('.js-milestone-deprecation-message-template').innerHTML;
+ const deprecationMessage = deprecationMesssageContainer.querySelector(
+ '.js-milestone-deprecation-message-template',
+ ).innerHTML;
const $popover = $('.js-popover-link', deprecationMesssageContainer);
const hideOnScroll = togglePopover.bind($popover, false);
- $popover.popover({
- content: deprecationMessage,
- html: true,
- placement: 'bottom',
- })
- .on('mouseenter', mouseenter)
- .on('mouseleave', debouncedMouseleave())
- .on('show.bs.popover', () => {
- window.addEventListener('scroll', hideOnScroll, { once: true });
- });
+ $popover
+ .popover({
+ content: deprecationMessage,
+ html: true,
+ placement: 'bottom',
+ })
+ .on('mouseenter', mouseenter)
+ .on('mouseleave', debouncedMouseleave())
+ .on('show.bs.popover', () => {
+ window.addEventListener('scroll', hideOnScroll, { once: true });
+ });
}
}
diff --git a/app/assets/javascripts/mini_pipeline_graph_dropdown.js b/app/assets/javascripts/mini_pipeline_graph_dropdown.js
index f8257b6abab..81ab9d8be4b 100644
--- a/app/assets/javascripts/mini_pipeline_graph_dropdown.js
+++ b/app/assets/javascripts/mini_pipeline_graph_dropdown.js
@@ -46,7 +46,7 @@ export default class MiniPipelineGraph {
$(document).on(
'click',
`${this.container} .js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item`,
- (e) => {
+ e => {
e.stopPropagation();
},
);
@@ -82,7 +82,8 @@ export default class MiniPipelineGraph {
this.renderBuildsList(button, '');
this.toggleLoading(button);
- axios.get(endpoint)
+ axios
+ .get(endpoint)
.then(({ data }) => {
this.toggleLoading(button);
this.renderBuildsList(button, data.html);
@@ -90,7 +91,11 @@ export default class MiniPipelineGraph {
})
.catch(() => {
this.toggleLoading(button);
- if ($(button).parent().hasClass('open')) {
+ if (
+ $(button)
+ .parent()
+ .hasClass('open')
+ ) {
$(button).dropdown('toggle');
}
flash('An error occurred while fetching the builds.', 'alert');
@@ -104,8 +109,8 @@ export default class MiniPipelineGraph {
* @return {type}
*/
toggleLoading(stageContainer) {
- stageContainer.parentElement.querySelector(
- `${this.dropdownListSelector} .js-builds-dropdown-loading`,
- ).classList.toggle('hidden');
+ stageContainer.parentElement
+ .querySelector(`${this.dropdownListSelector} .js-builds-dropdown-loading`)
+ .classList.toggle('hidden');
}
}
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 67338aa96c3..98182d92c2f 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -149,7 +149,7 @@ export default {
.catch(() => Flash(s__('Metrics|There was an error getting deployment information.'))),
this.service
.getEnvironmentsData()
- .then((data) => this.store.storeEnvironmentsData(data))
+ .then(data => this.store.storeEnvironmentsData(data))
.catch(() => Flash(s__('Metrics|There was an error getting environments information.'))),
])
.then(() => {
@@ -157,6 +157,7 @@ export default {
this.state = 'noData';
return;
}
+
this.showEmptyState = false;
})
.then(this.resize)
@@ -195,7 +196,10 @@ export default {
name="chevron-down"
/>
</button>
- <div class="dropdown-menu dropdown-menu-selectable dropdown-menu-drop-up">
+ <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"
diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue
index ed5c8b15945..5c6e2e09e46 100644
--- a/app/assets/javascripts/monitoring/components/graph.vue
+++ b/app/assets/javascripts/monitoring/components/graph.vue
@@ -121,6 +121,7 @@ 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;
@@ -130,13 +131,13 @@ export default {
this.unitOfDisplay = query.unit || '';
this.yAxisLabel = this.graphData.y_label || 'Values';
this.legendTitle = query.label || 'Average';
- this.graphWidth = this.$refs.baseSvg.clientWidth - this.margin.left - this.margin.right;
+ this.graphWidth = svgWidth - this.margin.left - this.margin.right;
this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom;
this.baseGraphHeight = this.graphHeight - 50;
this.baseGraphWidth = this.graphWidth;
// pixel offsets inside the svg and outside are not 1:1
- this.realPixelRatio = this.$refs.baseSvg.clientWidth / this.baseGraphWidth;
+ this.realPixelRatio = svgWidth / this.baseGraphWidth;
this.renderAxesPaths();
this.formatDeployments();
diff --git a/app/assets/javascripts/mr_notes/index.js b/app/assets/javascripts/mr_notes/index.js
index 8aabb840847..1c98683c597 100644
--- a/app/assets/javascripts/mr_notes/index.js
+++ b/app/assets/javascripts/mr_notes/index.js
@@ -4,6 +4,7 @@ import { mapActions, mapState, mapGetters } from 'vuex';
import initDiffsApp from '../diffs';
import notesApp from '../notes/components/notes_app.vue';
import discussionCounter from '../notes/components/discussion_counter.vue';
+import initDiscussionFilters from '../notes/discussion_filters';
import store from './stores';
import MergeRequest from '../merge_request';
@@ -88,5 +89,6 @@ export default function initMrNotes() {
},
});
+ initDiscussionFilters(store);
initDiffsApp(store);
}
diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js
index ec4c0910e92..cba6759ebf5 100644
--- a/app/assets/javascripts/namespace_select.js
+++ b/app/assets/javascripts/namespace_select.js
@@ -14,14 +14,14 @@ export default class NamespaceSelect {
selectable: true,
filterRemote: true,
search: {
- fields: ['path']
+ fields: ['path'],
},
fieldName: fieldName,
toggleLabel: function(selected) {
if (selected.id == null) {
return selected.text;
} else {
- return selected.kind + ": " + selected.full_path;
+ return selected.kind + ': ' + selected.full_path;
}
},
data: function(term, dataCallback) {
@@ -29,7 +29,7 @@ export default class NamespaceSelect {
if (isFilter) {
const anyNamespace = {
text: 'Any namespace',
- id: null
+ id: null,
};
namespaces.unshift(anyNamespace);
namespaces.splice(1, 0, 'divider');
@@ -41,7 +41,7 @@ export default class NamespaceSelect {
if (namespace.id == null) {
return namespace.text;
} else {
- return namespace.kind + ": " + namespace.full_path;
+ return namespace.kind + ': ' + namespace.full_path;
}
},
renderRow: this.renderRow,
diff --git a/app/assets/javascripts/network/branch_graph.js b/app/assets/javascripts/network/branch_graph.js
index ad7136adb8c..d1fa9f5e2a2 100644
--- a/app/assets/javascripts/network/branch_graph.js
+++ b/app/assets/javascripts/network/branch_graph.js
@@ -20,7 +20,7 @@ export default (function() {
this.mtime = 0;
this.mspace = 0;
this.parents = {};
- this.colors = ["#000"];
+ this.colors = ['#000'];
this.offsetX = 150;
this.offsetY = 20;
this.unitTime = 30;
@@ -30,9 +30,10 @@ export default (function() {
}
BranchGraph.prototype.load = function() {
- axios.get(this.options.url)
+ axios
+ .get(this.options.url)
.then(({ data }) => {
- $(".loading", this.element).hide();
+ $('.loading', this.element).hide();
this.prepareData(data.days, data.commits);
this.buildGraph();
})
@@ -71,17 +72,19 @@ export default (function() {
c = ref[j];
this.mtime = Math.max(this.mtime, c.time);
this.mspace = Math.max(this.mspace, c.space);
- results.push((function() {
- var l, len1, ref1, results1;
- ref1 = c.parents;
- results1 = [];
- for (l = 0, len1 = ref1.length; l < len1; l += 1) {
- p = ref1[l];
- this.parents[p[0]] = true;
- results1.push(this.mspace = Math.max(this.mspace, p[1]));
- }
- return results1;
- }).call(this));
+ results.push(
+ function() {
+ var l, len1, ref1, results1;
+ ref1 = c.parents;
+ results1 = [];
+ for (l = 0, len1 = ref1.length; l < len1; l += 1) {
+ p = ref1[l];
+ this.parents[p[0]] = true;
+ results1.push((this.mspace = Math.max(this.mspace, p[1])));
+ }
+ return results1;
+ }.call(this),
+ );
}
return results;
};
@@ -91,11 +94,11 @@ export default (function() {
k = 0;
results = [];
while (k < this.mspace) {
- this.colors.push(Raphael.getColor(.8));
+ this.colors.push(Raphael.getColor(0.8));
// Skipping a few colors in the spectrum to get more contrast between colors
Raphael.getColor();
Raphael.getColor();
- results.push(k += 1);
+ results.push((k += 1));
}
return results;
};
@@ -104,12 +107,12 @@ export default (function() {
var cuday, cumonth, day, j, len, mm, ref;
const { r } = this;
cuday = 0;
- cumonth = "";
+ cumonth = '';
r.rect(0, 0, 40, this.barHeight).attr({
- fill: "#222"
+ fill: '#222',
});
r.rect(40, 0, 30, this.barHeight).attr({
- fill: "#444"
+ fill: '#444',
});
ref = this.days;
@@ -118,16 +121,16 @@ export default (function() {
if (cuday !== day[0] || cumonth !== day[1]) {
// Dates
r.text(55, this.offsetY + this.unitTime * mm, day[0]).attr({
- font: "12px Monaco, monospace",
- fill: "#BBB"
+ font: '12px Monaco, monospace',
+ fill: '#BBB',
});
[cuday] = day;
}
if (cumonth !== day[1]) {
// Months
r.text(20, this.offsetY + this.unitTime * mm, day[1]).attr({
- font: "12px Monaco, monospace",
- fill: "#EEE"
+ font: '12px Monaco, monospace',
+ fill: '#EEE',
});
// eslint-disable-next-line prefer-destructuring
@@ -173,11 +176,13 @@ export default (function() {
BranchGraph.prototype.bindEvents = function() {
const { element } = this;
- return $(element).scroll((function(_this) {
- return function(event) {
- return _this.renderPartialGraph();
- };
- })(this));
+ return $(element).scroll(
+ (function(_this) {
+ return function(event) {
+ return _this.renderPartialGraph();
+ };
+ })(this),
+ );
};
BranchGraph.prototype.scrollDown = function() {
@@ -219,46 +224,53 @@ export default (function() {
shortrefs = commit.refs;
// Truncate if longer than 15 chars
if (shortrefs.length > 17) {
- shortrefs = shortrefs.substr(0, 15) + "…";
+ shortrefs = shortrefs.substr(0, 15) + '…';
}
text = r.text(x + 4, y, shortrefs).attr({
- "text-anchor": "start",
- font: "10px Monaco, monospace",
- fill: "#FFF",
- title: commit.refs
+ 'text-anchor': 'start',
+ font: '10px Monaco, monospace',
+ fill: '#FFF',
+ title: commit.refs,
});
textbox = text.getBBox();
// Create rectangle based on the size of the textbox
rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr({
- fill: "#000",
- "fill-opacity": .5,
- stroke: "none"
+ fill: '#000',
+ 'fill-opacity': 0.5,
+ stroke: 'none',
});
- triangle = r.path(["M", x - 5, y, "L", x - 15, y - 4, "L", x - 15, y + 4, "Z"]).attr({
- fill: "#000",
- "fill-opacity": .5,
- stroke: "none"
+ triangle = r.path(['M', x - 5, y, 'L', x - 15, y - 4, 'L', x - 15, y + 4, 'Z']).attr({
+ fill: '#000',
+ 'fill-opacity': 0.5,
+ stroke: 'none',
});
label = r.set(rect, text);
- label.transform(["t", -rect.getBBox().width - 15, 0]);
+ label.transform(['t', -rect.getBBox().width - 15, 0]);
// Set text to front
return text.toFront();
};
BranchGraph.prototype.appendAnchor = function(x, y, commit) {
const { r, top, options } = this;
- const anchor = r.circle(x, y, 10).attr({
- fill: "#000",
- opacity: 0,
- cursor: "pointer"
- }).click(function() {
- return window.open(options.commit_url.replace("%s", commit.id), "_blank");
- }).hover(function() {
- this.tooltip = r.commitTooltip(x + 5, y, commit);
- return top.push(this.tooltip.insertBefore(this));
- }, function() {
- return this.tooltip && this.tooltip.remove() && delete this.tooltip;
- });
+ const anchor = r
+ .circle(x, y, 10)
+ .attr({
+ fill: '#000',
+ opacity: 0,
+ cursor: 'pointer',
+ })
+ .click(function() {
+ return window.open(options.commit_url.replace('%s', commit.id), '_blank');
+ })
+ .hover(
+ function() {
+ this.tooltip = r.commitTooltip(x + 5, y, commit);
+ return top.push(this.tooltip.insertBefore(this));
+ },
+ function() {
+ return this.tooltip && this.tooltip.remove() && delete this.tooltip;
+ },
+ );
return top.push(anchor);
};
@@ -266,7 +278,7 @@ export default (function() {
const { r } = this;
r.circle(x, y, 3).attr({
fill: this.colors[commit.space],
- stroke: "none"
+ stroke: 'none',
});
const avatar_box_x = this.offsetX + this.unitSpace * this.mspace + 10;
@@ -274,13 +286,15 @@ export default (function() {
r.rect(avatar_box_x, avatar_box_y, 20, 20).attr({
stroke: this.colors[commit.space],
- "stroke-width": 2
+ 'stroke-width': 2,
});
r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20);
- return r.text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split("\n")[0]).attr({
- "text-anchor": "start",
- font: "14px Monaco, monospace"
- });
+ return r
+ .text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split('\n')[0])
+ .attr({
+ 'text-anchor': 'start',
+ font: '14px Monaco, monospace',
+ });
};
BranchGraph.prototype.drawLines = function(x, y, commit) {
@@ -304,30 +318,32 @@ export default (function() {
// Build line shape
if (parent[1] === commit.space) {
offset = [0, 5];
- arrow = "l-2,5,4,0,-2,-5,0,5";
+ arrow = 'l-2,5,4,0,-2,-5,0,5';
} else if (parent[1] < commit.space) {
offset = [3, 3];
- arrow = "l5,0,-2,4,-3,-4,4,2";
+ arrow = 'l5,0,-2,4,-3,-4,4,2';
} else {
offset = [-3, 3];
- arrow = "l-5,0,2,4,3,-4,-4,2";
+ arrow = 'l-5,0,2,4,3,-4,-4,2';
}
// Start point
- route = ["M", x + offset[0], y + offset[1]];
+ route = ['M', x + offset[0], y + offset[1]];
// Add arrow if not first parent
if (i > 0) {
route.push(arrow);
}
// Circumvent if overlap
if (commit.space !== parentCommit.space || commit.space !== parent[1]) {
- route.push("L", parentX2, y + 10, "L", parentX2, parentY - 5);
+ route.push('L', parentX2, y + 10, 'L', parentX2, parentY - 5);
}
// End point
- route.push("L", parentX1, parentY);
- results.push(r.path(route).attr({
- stroke: color,
- "stroke-width": 2
- }));
+ route.push('L', parentX1, parentY);
+ results.push(
+ r.path(route).attr({
+ stroke: color,
+ 'stroke-width': 2,
+ }),
+ );
}
return results;
};
@@ -337,10 +353,10 @@ export default (function() {
const { r } = this;
const x = this.offsetX + this.unitSpace * (this.mspace - commit.space);
const y = this.offsetY + this.unitTime * commit.time;
- r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr({
- fill: "#000",
- "fill-opacity": .5,
- stroke: "none"
+ r.path(['M', x + 5, y, 'L', x + 15, y + 4, 'L', x + 15, y - 4, 'Z']).attr({
+ fill: '#000',
+ 'fill-opacity': 0.5,
+ stroke: 'none',
});
// Displayed in the center
return this.element.scrollTop(y - this.graphHeight / 2);
diff --git a/app/assets/javascripts/network/raphael.js b/app/assets/javascripts/network/raphael.js
index 09dcf716148..22e06a35d91 100644
--- a/app/assets/javascripts/network/raphael.js
+++ b/app/assets/javascripts/network/raphael.js
@@ -49,7 +49,7 @@ Raphael.prototype.textWrap = function testWrap(t, width) {
const s = [];
for (let j = 0, len = words.length; j < len; j += 1) {
const word = words[j];
- if (x + (word.length * letterWidth) > width) {
+ if (x + word.length * letterWidth > width) {
s.push('\n');
x = 0;
}
diff --git a/app/assets/javascripts/new_branch_form.js b/app/assets/javascripts/new_branch_form.js
index 8f6ea9e61c1..f338dbbb0a6 100644
--- a/app/assets/javascripts/new_branch_form.js
+++ b/app/assets/javascripts/new_branch_form.js
@@ -30,24 +30,24 @@ export default class NewBranchForm {
startsWith = {
pattern: /^(\/|\.)/g,
prefix: "can't start with",
- conjunction: "or"
+ conjunction: 'or',
};
endsWith = {
pattern: /(\/|\.|\.lock)$/g,
prefix: "can't end in",
- conjunction: "or"
+ conjunction: 'or',
};
invalid = {
pattern: /(\s|~|\^|:|\?|\*|\[|\\|\.\.|@\{|\/{2,}){1}/g,
prefix: "can't contain",
- conjunction: ", "
+ conjunction: ', ',
};
single = {
pattern: /^@+$/g,
prefix: "can't be",
- conjunction: "or"
+ conjunction: 'or',
};
- return this.restrictions = [startsWith, invalid, endsWith, single];
+ return (this.restrictions = [startsWith, invalid, endsWith, single]);
}
validate() {
@@ -73,7 +73,7 @@ export default class NewBranchForm {
return "'" + value + "'";
}
});
- return restriction.prefix + " " + (formatted.join(restriction.conjunction));
+ return restriction.prefix + ' ' + formatted.join(restriction.conjunction);
};
validator = (function(_this) {
return function(errors, restriction) {
@@ -88,7 +88,7 @@ export default class NewBranchForm {
})(this);
errors = this.restrictions.reduce(validator, []);
if (errors.length > 0) {
- errorMessage = $("<span/>").text(errors.join(', '));
+ errorMessage = $('<span/>').text(errors.join(', '));
return this.branchNameError.append(errorMessage);
}
}
diff --git a/app/assets/javascripts/new_commit_form.js b/app/assets/javascripts/new_commit_form.js
index 17ec20f1cc1..b142f212eb0 100644
--- a/app/assets/javascripts/new_commit_form.js
+++ b/app/assets/javascripts/new_commit_form.js
@@ -6,9 +6,7 @@ export default class NewCommitForm {
this.branchName = form.find('.js-branch-name');
this.originalBranch = form.find('.js-original-branch');
this.createMergeRequest = form.find('.js-create-merge-request');
- this.createMergeRequestContainer = form.find(
- '.js-create-merge-request-container',
- );
+ this.createMergeRequestContainer = form.find('.js-create-merge-request-container');
this.branchName.keyup(this.renderDestination);
this.renderDestination();
}
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index 353aa790743..d9e99603238 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -94,6 +94,7 @@ export default {
class="diff-file file-holder"
>
<diff-file-header
+ :discussion-path="discussion.discussionPath"
:diff-file="diffFile"
:can-current-user-fork="false"
:discussions-expanded="isDiscussionsExpanded"
diff --git a/app/assets/javascripts/notes/components/discussion_counter.vue b/app/assets/javascripts/notes/components/discussion_counter.vue
index ad6e7cf501d..1f80f24e045 100644
--- a/app/assets/javascripts/notes/components/discussion_counter.vue
+++ b/app/assets/javascripts/notes/components/discussion_counter.vue
@@ -56,10 +56,11 @@ export default {
</script>
<template>
- <div class="line-resolve-all-container prepend-top-10">
+ <div
+ v-if="discussionCount > 0"
+ class="line-resolve-all-container prepend-top-8">
<div>
<div
- v-if="discussionCount > 0"
:class="{ 'has-next-btn': hasNextButton }"
class="line-resolve-all">
<span
diff --git a/app/assets/javascripts/notes/components/discussion_filter.vue b/app/assets/javascripts/notes/components/discussion_filter.vue
new file mode 100644
index 00000000000..27972682ca1
--- /dev/null
+++ b/app/assets/javascripts/notes/components/discussion_filter.vue
@@ -0,0 +1,82 @@
+<script>
+import $ from 'jquery';
+import Icon from '~/vue_shared/components/icon.vue';
+import { mapGetters, mapActions } from 'vuex';
+
+export default {
+ components: {
+ Icon,
+ },
+ props: {
+ filters: {
+ type: Array,
+ required: true,
+ },
+ defaultValue: {
+ type: Number,
+ default: null,
+ required: false,
+ },
+ },
+ data() {
+ return { currentValue: this.defaultValue };
+ },
+ computed: {
+ ...mapGetters([
+ 'getNotesDataByProp',
+ ]),
+ currentFilter() {
+ if (!this.currentValue) return this.filters[0];
+ return this.filters.find(filter => filter.value === this.currentValue);
+ },
+ },
+ methods: {
+ ...mapActions(['filterDiscussion']),
+ selectFilter(value) {
+ const filter = parseInt(value, 10);
+
+ // close dropdown
+ $(this.$refs.dropdownToggle).dropdown('toggle');
+
+ if (filter === this.currentValue) return;
+ this.currentValue = filter;
+ this.filterDiscussion({ path: this.getNotesDataByProp('discussionsPath'), filter });
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="discussion-filter-container d-inline-block align-bottom">
+ <button
+ id="discussion-filter-dropdown"
+ ref="dropdownToggle"
+ class="btn btn-default"
+ data-toggle="dropdown"
+ aria-expanded="false"
+ >
+ {{ currentFilter.title }}
+ <icon name="chevron-down" />
+ </button>
+ <div
+ class="dropdown-menu dropdown-menu-selectable dropdown-menu-right"
+ aria-labelledby="discussion-filter-dropdown">
+ <div class="dropdown-content">
+ <ul>
+ <li
+ v-for="filter in filters"
+ :key="filter.value"
+ >
+ <button
+ :class="{ 'is-active': filter.value === currentValue }"
+ type="button"
+ @click="selectFilter(filter.value)"
+ >
+ {{ filter.title }}
+ </button>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/notes/components/note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue
index c68860d98ae..e707f44bf5a 100644
--- a/app/assets/javascripts/notes/components/note_awards_list.vue
+++ b/app/assets/javascripts/notes/components/note_awards_list.vue
@@ -95,29 +95,20 @@ export default {
return awardList.filter(award => award.user.id === this.getUserData.id).length;
},
awardTitle(awardsList) {
- const hasReactionByCurrentUser = this.hasReactionByCurrentUser(
- awardsList,
- );
+ const hasReactionByCurrentUser = this.hasReactionByCurrentUser(awardsList);
const TOOLTIP_NAME_COUNT = hasReactionByCurrentUser ? 9 : 10;
let awardList = awardsList;
// Filter myself from list if I am awarded.
if (hasReactionByCurrentUser) {
- awardList = awardList.filter(
- award => award.user.id !== this.getUserData.id,
- );
+ awardList = awardList.filter(award => award.user.id !== this.getUserData.id);
}
// Get only 9-10 usernames to show in tooltip text.
- const namesToShow = awardList
- .slice(0, TOOLTIP_NAME_COUNT)
- .map(award => award.user.name);
+ const namesToShow = awardList.slice(0, TOOLTIP_NAME_COUNT).map(award => award.user.name);
// Get the remaining list to use in `and x more` text.
- const remainingAwardList = awardList.slice(
- TOOLTIP_NAME_COUNT,
- awardList.length,
- );
+ const remainingAwardList = awardList.slice(TOOLTIP_NAME_COUNT, awardList.length);
// Add myself to the begining of the list so title will start with You.
if (hasReactionByCurrentUser) {
@@ -128,9 +119,7 @@ export default {
// We have 10+ awarded user, join them with comma and add `and x more`.
if (remainingAwardList.length) {
- title = `${namesToShow.join(', ')}, and ${
- remainingAwardList.length
- } more.`;
+ title = `${namesToShow.join(', ')}, and ${remainingAwardList.length} more.`;
} else if (namesToShow.length > 1) {
// Join all names with comma but not the last one, it will be added with and text.
title = namesToShow.slice(0, namesToShow.length - 1).join(', ');
@@ -170,9 +159,7 @@ export default {
awardName: parsedName,
};
- this.toggleAwardRequest(data).catch(() =>
- Flash('Something went wrong on our end.'),
- );
+ this.toggleAwardRequest(data).catch(() => Flash('Something went wrong on our end.'));
},
},
};
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 33998394a69..38c43e5fe08 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -102,6 +102,18 @@ export default {
},
methods: {
...mapActions(['toggleResolveNote']),
+ shouldToggleResolved(shouldResolve, beforeSubmitDiscussionState) {
+ // shouldBeResolved() checks the actual resolution state,
+ // considering batchComments (EEP), if applicable/enabled.
+ const newResolvedStateAfterUpdate =
+ this.shouldBeResolved && this.shouldBeResolved(shouldResolve);
+
+ const shouldToggleState =
+ newResolvedStateAfterUpdate !== undefined &&
+ beforeSubmitDiscussionState !== newResolvedStateAfterUpdate;
+
+ return shouldResolve || shouldToggleState;
+ },
handleUpdate(shouldResolve) {
const beforeSubmitDiscussionState = this.discussionResolved;
this.isSubmitting = true;
@@ -109,7 +121,7 @@ export default {
this.$emit('handleFormUpdate', this.updatedNoteBody, this.$refs.editNoteForm, () => {
this.isSubmitting = false;
- if (shouldResolve) {
+ if (this.shouldToggleResolved(shouldResolve, beforeSubmitDiscussionState)) {
this.resolveHandler(beforeSubmitDiscussionState);
}
});
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index 618a1581d8f..b0faa443a18 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -50,11 +50,11 @@ export default {
},
data() {
return {
- isLoading: true,
+ currentFilter: null,
};
},
computed: {
- ...mapGetters(['isNotesFetched', 'discussions', 'getNotesDataByProp', 'discussionCount']),
+ ...mapGetters(['isNotesFetched', 'discussions', 'getNotesDataByProp', 'discussionCount', 'isLoading']),
noteableType() {
return this.noteableData.noteableType;
},
@@ -102,6 +102,7 @@ export default {
},
methods: {
...mapActions({
+ setLoadingState: 'setLoadingState',
fetchDiscussions: 'fetchDiscussions',
poll: 'poll',
actionToggleAward: 'toggleAward',
@@ -133,19 +134,19 @@ export default {
return discussion.individual_note ? { note: discussion.notes[0] } : { discussion };
},
fetchNotes() {
- return this.fetchDiscussions(this.getNotesDataByProp('discussionsPath'))
+ return this.fetchDiscussions({ path: this.getNotesDataByProp('discussionsPath') })
.then(() => {
this.initPolling();
})
.then(() => {
- this.isLoading = false;
+ this.setLoadingState(false);
this.setNotesFetchedState(true);
eventHub.$emit('fetchedNotesData');
})
.then(() => this.$nextTick())
.then(() => this.checkLocationHash())
.catch(() => {
- this.isLoading = false;
+ this.setLoadingState(false);
this.setNotesFetchedState(true);
Flash('Something went wrong while fetching comments. Please try again.');
});
diff --git a/app/assets/javascripts/notes/discussion_filters.js b/app/assets/javascripts/notes/discussion_filters.js
new file mode 100644
index 00000000000..012ffc4093e
--- /dev/null
+++ b/app/assets/javascripts/notes/discussion_filters.js
@@ -0,0 +1,33 @@
+import Vue from 'vue';
+import DiscussionFilter from './components/discussion_filter.vue';
+
+export default (store) => {
+ const discussionFilterEl = document.getElementById('js-vue-discussion-filter');
+
+ if (discussionFilterEl) {
+ const { defaultFilter, notesFilters } = discussionFilterEl.dataset;
+ const defaultValue = defaultFilter ? parseInt(defaultFilter, 10) : null;
+ const filterValues = notesFilters ? JSON.parse(notesFilters) : {};
+ const filters = Object.keys(filterValues).map(entry =>
+ ({ title: entry, value: filterValues[entry] }));
+
+ return new Vue({
+ el: discussionFilterEl,
+ name: 'DiscussionFilter',
+ components: {
+ DiscussionFilter,
+ },
+ store,
+ render(createElement) {
+ return createElement('discussion-filter', {
+ props: {
+ filters,
+ defaultValue,
+ },
+ });
+ },
+ });
+ }
+
+ return null;
+};
diff --git a/app/assets/javascripts/notes/index.js b/app/assets/javascripts/notes/index.js
index 3aef30c608c..2f715c85fa6 100644
--- a/app/assets/javascripts/notes/index.js
+++ b/app/assets/javascripts/notes/index.js
@@ -1,10 +1,13 @@
import Vue from 'vue';
import notesApp from './components/notes_app.vue';
+import initDiscussionFilters from './discussion_filters';
import createStore from './stores';
document.addEventListener('DOMContentLoaded', () => {
const store = createStore();
+ initDiscussionFilters(store);
+
return new Vue({
el: '#js-vue-notes',
components: {
diff --git a/app/assets/javascripts/notes/services/notes_service.js b/app/assets/javascripts/notes/services/notes_service.js
index f5dce94caad..47a6f07cce2 100644
--- a/app/assets/javascripts/notes/services/notes_service.js
+++ b/app/assets/javascripts/notes/services/notes_service.js
@@ -5,8 +5,9 @@ import * as constants from '../constants';
Vue.use(VueResource);
export default {
- fetchDiscussions(endpoint) {
- return Vue.http.get(endpoint);
+ fetchDiscussions(endpoint, filter) {
+ const config = filter !== undefined ? { params: { notes_filter: filter } } : null;
+ return Vue.http.get(endpoint, config);
},
deleteNote(endpoint) {
return Vue.http.delete(endpoint);
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 7ab7e5a9abb..b5dd49bc6c9 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -11,6 +11,7 @@ import loadAwardsHandler from '../../awards_handler';
import sidebarTimeTrackingEventHub from '../../sidebar/event_hub';
import { isInViewport, scrollToElement } from '../../lib/utils/common_utils';
import mrWidgetEventHub from '../../vue_merge_request_widget/event_hub';
+import { __ } from '~/locale';
let eTagPoll;
@@ -36,9 +37,9 @@ export const setNotesFetchedState = ({ commit }, state) =>
export const toggleDiscussion = ({ commit }, data) => commit(types.TOGGLE_DISCUSSION, data);
-export const fetchDiscussions = ({ commit }, path) =>
+export const fetchDiscussions = ({ commit }, { path, filter }) =>
service
- .fetchDiscussions(path)
+ .fetchDiscussions(path, filter)
.then(res => res.json())
.then(discussions => {
commit(types.SET_INITIAL_DISCUSSIONS, discussions);
@@ -251,7 +252,7 @@ const pollSuccessCallBack = (resp, commit, state, getters, dispatch) => {
if (discussion) {
commit(types.ADD_NEW_REPLY_TO_DISCUSSION, note);
} else if (note.type === constants.DIFF_NOTE) {
- dispatch('fetchDiscussions', state.notesData.discussionsPath);
+ dispatch('fetchDiscussions', { path: state.notesData.discussionsPath });
} else {
commit(types.ADD_NEW_NOTE, note);
}
@@ -345,5 +346,23 @@ export const updateMergeRequestWidget = () => {
mrWidgetEventHub.$emit('mr.discussion.updated');
};
+export const setLoadingState = ({ commit }, data) => {
+ commit(types.SET_NOTES_LOADING_STATE, data);
+};
+
+export const filterDiscussion = ({ dispatch }, { path, filter }) => {
+ dispatch('setLoadingState', true);
+ dispatch('fetchDiscussions', { path, filter })
+ .then(() => {
+ dispatch('setLoadingState', false);
+ dispatch('setNotesFetchedState', true);
+ })
+ .catch(() => {
+ dispatch('setLoadingState', false);
+ dispatch('setNotesFetchedState', true);
+ Flash(__('Something went wrong while fetching comments. Please try again.'));
+ });
+};
+
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/notes/stores/collapse_utils.js b/app/assets/javascripts/notes/stores/collapse_utils.js
index fa4a1c56b20..4532226aa07 100644
--- a/app/assets/javascripts/notes/stores/collapse_utils.js
+++ b/app/assets/javascripts/notes/stores/collapse_utils.js
@@ -68,10 +68,7 @@ export const collapseSystemNotes = notes => {
lastDescriptionSystemNote = note;
lastDescriptionSystemNoteIndex = acc.length;
} else if (lastDescriptionSystemNote) {
- const timeDifferenceMinutes = getTimeDifferenceMinutes(
- lastDescriptionSystemNote,
- note,
- );
+ const timeDifferenceMinutes = getTimeDifferenceMinutes(lastDescriptionSystemNote, note);
// are they less than 10 minutes appart?
if (timeDifferenceMinutes > 10) {
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index a829149a17e..e4f36154fcd 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -1,6 +1,5 @@
import _ from 'underscore';
import * as constants from '../constants';
-import { reduceDiscussionsToLineCodes } from './utils';
import { collapseSystemNotes } from './collapse_utils';
export const discussions = state => collapseSystemNotes(state.discussions);
@@ -11,6 +10,8 @@ export const getNotesData = state => state.notesData;
export const isNotesFetched = state => state.isNotesFetched;
+export const isLoading = state => state.isLoading;
+
export const getNotesDataByProp = state => prop => state.notesData[prop];
export const getNoteableData = state => state.noteableData;
@@ -29,9 +30,6 @@ export const notesById = state =>
return acc;
}, {});
-export const discussionsStructuredByLineCode = state =>
- reduceDiscussionsToLineCodes(state.discussions);
-
export const noteableType = state => {
const { ISSUE_NOTEABLE_TYPE, MERGE_REQUEST_NOTEABLE_TYPE, EPIC_NOTEABLE_TYPE } = constants;
diff --git a/app/assets/javascripts/notes/stores/index.js b/app/assets/javascripts/notes/stores/index.js
index f105b7d0d11..d41b02b4a4b 100644
--- a/app/assets/javascripts/notes/stores/index.js
+++ b/app/assets/javascripts/notes/stores/index.js
@@ -4,5 +4,4 @@ import notesModule from './modules';
Vue.use(Vuex);
-export default () =>
- new Vuex.Store(notesModule());
+export default () => new Vuex.Store(notesModule());
diff --git a/app/assets/javascripts/notes/stores/modules/index.js b/app/assets/javascripts/notes/stores/modules/index.js
index 61dbb075586..400142668ea 100644
--- a/app/assets/javascripts/notes/stores/modules/index.js
+++ b/app/assets/javascripts/notes/stores/modules/index.js
@@ -11,6 +11,7 @@ export default () => ({
// View layer
isToggleStateButtonLoading: false,
isNotesFetched: false,
+ isLoading: true,
// holds endpoints and permissions provided through haml
notesData: {
diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js
index 6f374f78691..2fa53aef1d4 100644
--- a/app/assets/javascripts/notes/stores/mutation_types.js
+++ b/app/assets/javascripts/notes/stores/mutation_types.js
@@ -14,6 +14,7 @@ export const UPDATE_NOTE = 'UPDATE_NOTE';
export const UPDATE_DISCUSSION = 'UPDATE_DISCUSSION';
export const SET_DISCUSSION_DIFF_LINES = 'SET_DISCUSSION_DIFF_LINES';
export const SET_NOTES_FETCHED_STATE = 'SET_NOTES_FETCHED_STATE';
+export const SET_NOTES_LOADING_STATE = 'SET_NOTES_LOADING_STATE';
// DISCUSSION
export const COLLAPSE_DISCUSSION = 'COLLAPSE_DISCUSSION';
diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js
index 73e55705f39..65085452139 100644
--- a/app/assets/javascripts/notes/stores/mutations.js
+++ b/app/assets/javascripts/notes/stores/mutations.js
@@ -216,6 +216,10 @@ export default {
Object.assign(state, { isNotesFetched: value });
},
+ [types.SET_NOTES_LOADING_STATE](state, value) {
+ state.isLoading = value;
+ },
+
[types.SET_DISCUSSION_DIFF_LINES](state, { discussionId, diffLines }) {
const discussion = utils.findNoteObjectById(state.discussions, discussionId);
diff --git a/app/assets/javascripts/notes/stores/utils.js b/app/assets/javascripts/notes/stores/utils.js
index 0e41ff03d67..dd57539e4d8 100644
--- a/app/assets/javascripts/notes/stores/utils.js
+++ b/app/assets/javascripts/notes/stores/utils.js
@@ -25,18 +25,6 @@ export const getQuickActionText = note => {
return text;
};
-export const reduceDiscussionsToLineCodes = selectedDiscussions =>
- selectedDiscussions.reduce((acc, note) => {
- if (note.diff_discussion && note.line_code) {
- // For context about line notes: there might be multiple notes with the same line code
- const items = acc[note.line_code] || [];
- items.push(note);
-
- Object.assign(acc, { [note.line_code]: items });
- }
- return acc;
- }, {});
-
export const hasQuickActions = note => REGEX_QUICK_ACTIONS.test(note);
export const stripQuickActions = note => note.replace(REGEX_QUICK_ACTIONS, '').trim();
diff --git a/app/assets/javascripts/notifications_dropdown.js b/app/assets/javascripts/notifications_dropdown.js
index 8ff8bb446ad..c4c8cf86cb0 100644
--- a/app/assets/javascripts/notifications_dropdown.js
+++ b/app/assets/javascripts/notifications_dropdown.js
@@ -18,7 +18,9 @@ export default function notificationsDropdown() {
$(document).on('ajax:success', '.notification-form', (e, data) => {
if (data.saved) {
- $(e.currentTarget).closest('.js-notification-dropdown').replaceWith(data.html);
+ $(e.currentTarget)
+ .closest('.js-notification-dropdown')
+ .replaceWith(data.html);
} else {
Flash('Failed to save new settings', 'alert');
}
diff --git a/app/assets/javascripts/notifications_form.js b/app/assets/javascripts/notifications_form.js
index 00e27ca0e70..45f033f2822 100644
--- a/app/assets/javascripts/notifications_form.js
+++ b/app/assets/javascripts/notifications_form.js
@@ -22,7 +22,8 @@ export default class NotificationsForm {
// eslint-disable-next-line class-methods-use-this
showCheckboxLoadingSpinner($parent) {
- $parent.addClass('is-loading')
+ $parent
+ .addClass('is-loading')
.find('.custom-notification-event-loading')
.removeClass('fa-check')
.addClass('fa-spin fa-spinner')
@@ -38,9 +39,12 @@ export default class NotificationsForm {
.then(({ data }) => {
$checkbox.enable();
if (data.saved) {
- $parent.find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done');
+ $parent
+ .find('.custom-notification-event-loading')
+ .toggleClass('fa-spin fa-spinner fa-check is-done');
setTimeout(() => {
- $parent.removeClass('is-loading')
+ $parent
+ .removeClass('is-loading')
.find('.custom-notification-event-loading')
.toggleClass('fa-spin fa-spinner fa-check is-done');
}, 2000);
diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js
index 86a43b66cc8..386a9b2c740 100644
--- a/app/assets/javascripts/pager.js
+++ b/app/assets/javascripts/pager.js
@@ -7,14 +7,21 @@ const ENDLESS_SCROLL_BOTTOM_PX = 400;
const ENDLESS_SCROLL_FIRE_DELAY_MS = 1000;
export default {
- init(limit = 0, preload = false, disable = false, prepareData = $.noop, callback = $.noop) {
+ init(
+ limit = 0,
+ preload = false,
+ disable = false,
+ prepareData = $.noop,
+ callback = $.noop,
+ container = '',
+ ) {
this.url = $('.content_list').data('href') || removeParams(['limit', 'offset']);
this.limit = limit;
this.offset = parseInt(getParameterByName('offset'), 10) || this.limit;
this.disable = disable;
this.prepareData = prepareData;
this.callback = callback;
- this.loading = $('.loading').first();
+ this.loading = $(`${container} .loading`).first();
if (preload) {
this.offset = 0;
this.getOld();
@@ -24,22 +31,25 @@ export default {
getOld() {
this.loading.show();
- axios.get(this.url, {
- params: {
- limit: this.limit,
- offset: this.offset,
- },
- }).then(({ data }) => {
- this.append(data.count, this.prepareData(data.html));
- this.callback();
+ axios
+ .get(this.url, {
+ params: {
+ limit: this.limit,
+ offset: this.offset,
+ },
+ })
+ .then(({ data }) => {
+ this.append(data.count, this.prepareData(data.html));
+ this.callback();
- // keep loading until we've filled the viewport height
- if (!this.disable && !this.isScrollable()) {
- this.getOld();
- } else {
- this.loading.hide();
- }
- }).catch(() => this.loading.hide());
+ // keep loading until we've filled the viewport height
+ if (!this.disable && !this.isScrollable()) {
+ this.getOld();
+ } else {
+ this.loading.hide();
+ }
+ })
+ .catch(() => this.loading.hide());
},
append(count, html) {
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 15e737fff05..d9cf62db3f7 100644
--- a/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
+++ b/app/assets/javascripts/pages/admin/abuse_reports/abuse_reports.js
@@ -31,7 +31,7 @@ export default class AbuseReports {
$messageCellElement.text(originalMessage);
} else {
$messageCellElement.data('messageTruncated', 'true');
- $messageCellElement.text(`${originalMessage.substr(0, (MAX_MESSAGE_LENGTH - 3))}...`);
+ $messageCellElement.text(`${originalMessage.substr(0, MAX_MESSAGE_LENGTH - 3)}...`);
}
}
}
diff --git a/app/assets/javascripts/pages/admin/admin.js b/app/assets/javascripts/pages/admin/admin.js
index ff4d6ab15f9..4616a075729 100644
--- a/app/assets/javascripts/pages/admin/admin.js
+++ b/app/assets/javascripts/pages/admin/admin.js
@@ -23,7 +23,7 @@ export default function adminInit() {
}
});
- $('body').on('click', '.js-toggle-colors-link', (e) => {
+ $('body').on('click', '.js-toggle-colors-link', e => {
e.preventDefault();
$('.js-toggle-colors-container').toggleClass('hide');
});
@@ -33,12 +33,15 @@ export default function adminInit() {
$(this).tab('show');
});
- $('.log-bottom').on('click', (e) => {
+ $('.log-bottom').on('click', e => {
e.preventDefault();
const $visibleLog = $('.file-content:visible');
- $visibleLog.animate({
- scrollTop: $visibleLog.find('ol').height(),
- }, 'fast');
+ $visibleLog.animate(
+ {
+ scrollTop: $visibleLog.find('ol').height(),
+ },
+ 'fast',
+ );
});
$('.change-owner-link').on('click', function changeOwnerLinkClick(e) {
@@ -47,7 +50,7 @@ export default function adminInit() {
modal.show();
});
- $('.change-owner-cancel-link').on('click', (e) => {
+ $('.change-owner-cancel-link').on('click', e => {
e.preventDefault();
modal.hide();
$('.change-owner-link').show();
diff --git a/app/assets/javascripts/pages/admin/application_settings/account_and_limits.js b/app/assets/javascripts/pages/admin/application_settings/account_and_limits.js
index 7281f907ec7..455c637a6b3 100644
--- a/app/assets/javascripts/pages/admin/application_settings/account_and_limits.js
+++ b/app/assets/javascripts/pages/admin/application_settings/account_and_limits.js
@@ -1,10 +1,14 @@
import { __ } from '~/locale';
export const PLACEHOLDER_USER_EXTERNAL_DEFAULT_TRUE = __('Regex pattern');
-export const PLACEHOLDER_USER_EXTERNAL_DEFAULT_FALSE = __('To define internal users, first enable new users set to external');
+export const PLACEHOLDER_USER_EXTERNAL_DEFAULT_FALSE = __(
+ 'To define internal users, first enable new users set to external',
+);
function setUserInternalRegexPlaceholder(checkbox) {
- const userInternalRegex = document.getElementById('application_setting_user_default_internal_regex');
+ const userInternalRegex = document.getElementById(
+ 'application_setting_user_default_internal_regex',
+ );
if (checkbox && userInternalRegex) {
if (checkbox.checked) {
userInternalRegex.readOnly = false;
diff --git a/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js
index e7ceccb6f47..d5ded3f9a79 100644
--- a/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js
+++ b/app/assets/javascripts/pages/admin/broadcast_messages/broadcast_message.js
@@ -17,20 +17,24 @@ export default () => {
const previewPath = $('textarea#broadcast_message_message').data('previewPath');
- $('textarea#broadcast_message_message').on('input', _.debounce(function onMessageInput() {
- const message = $(this).val();
- if (message === '') {
- $('.js-broadcast-message-preview').text('Your message here');
- } else {
- axios.post(previewPath, {
- broadcast_message: {
- message,
- },
- })
- .then(({ data }) => {
- $('.js-broadcast-message-preview').html(data.message);
- })
- .catch(() => flash(__('An error occurred while rendering preview broadcast message')));
- }
- }, 250));
+ $('textarea#broadcast_message_message').on(
+ 'input',
+ _.debounce(function onMessageInput() {
+ const message = $(this).val();
+ if (message === '') {
+ $('.js-broadcast-message-preview').text('Your message here');
+ } else {
+ axios
+ .post(previewPath, {
+ broadcast_message: {
+ message,
+ },
+ })
+ .then(({ data }) => {
+ $('.js-broadcast-message-preview').html(data.message);
+ })
+ .catch(() => flash(__('An error occurred while rendering preview broadcast message')));
+ }
+ }, 250),
+ );
};
diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue b/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
index bc84666779e..e2fec3c7172 100644
--- a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
+++ b/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
@@ -1,39 +1,42 @@
<script>
- import axios from '~/lib/utils/axios_utils';
- import createFlash from '~/flash';
- import GlModal from '~/vue_shared/components/gl_modal.vue';
- import { redirectTo } from '~/lib/utils/url_utility';
- import { s__ } from '~/locale';
+import axios from '~/lib/utils/axios_utils';
+import createFlash from '~/flash';
+import GlModal from '~/vue_shared/components/gl_modal.vue';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { s__ } from '~/locale';
- export default {
- components: {
- GlModal,
+export default {
+ components: {
+ GlModal,
+ },
+ props: {
+ url: {
+ type: String,
+ required: true,
},
- props: {
- url: {
- type: String,
- required: true,
- },
+ },
+ computed: {
+ text() {
+ return s__(
+ 'AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running.',
+ );
},
- computed: {
- text() {
- return s__('AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running.');
- },
+ },
+ methods: {
+ onSubmit() {
+ return axios
+ .post(this.url)
+ .then(response => {
+ // follow the rediect to refresh the page
+ redirectTo(response.request.responseURL);
+ })
+ .catch(error => {
+ createFlash(s__('AdminArea|Stopping jobs failed'));
+ throw error;
+ });
},
- methods: {
- onSubmit() {
- return axios.post(this.url)
- .then((response) => {
- // follow the rediect to refresh the page
- redirectTo(response.request.responseURL);
- })
- .catch((error) => {
- createFlash(s__('AdminArea|Stopping jobs failed'));
- throw error;
- });
- },
- },
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/pages/admin/projects/index.js b/app/assets/javascripts/pages/admin/projects/index.js
index 31c96eb87af..d6b1e747aec 100644
--- a/app/assets/javascripts/pages/admin/projects/index.js
+++ b/app/assets/javascripts/pages/admin/projects/index.js
@@ -4,6 +4,7 @@ import NamespaceSelect from '../../../namespace_select';
document.addEventListener('DOMContentLoaded', () => {
new ProjectsList(); // eslint-disable-line no-new
- document.querySelectorAll('.js-namespace-select')
+ document
+ .querySelectorAll('.js-namespace-select')
.forEach(dropdown => new NamespaceSelect({ dropdown }));
});
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 ff66d3a8ac4..3c383735f4a 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
@@ -1,81 +1,84 @@
<script>
- import _ from 'underscore';
- import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
- import { s__, sprintf } from '~/locale';
+import _ from 'underscore';
+import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
+import { s__, sprintf } from '~/locale';
- export default {
- components: {
- DeprecatedModal,
+export default {
+ components: {
+ DeprecatedModal,
+ },
+ props: {
+ deleteProjectUrl: {
+ type: String,
+ required: false,
+ default: '',
},
- props: {
- deleteProjectUrl: {
- type: String,
- required: false,
- default: '',
- },
- projectName: {
- type: String,
- required: false,
- default: '',
- },
- csrfToken: {
- type: String,
- required: false,
- default: '',
- },
+ projectName: {
+ type: String,
+ required: false,
+ default: '',
},
- data() {
- return {
- enteredProjectName: '',
- };
+ csrfToken: {
+ type: String,
+ required: false,
+ default: '',
},
- computed: {
- title() {
- return sprintf(s__('AdminProjects|Delete Project %{projectName}?'),
- {
- projectName: `'${_.escape(this.projectName)}'`,
- },
- false,
- );
- },
- text() {
- return sprintf(s__(`AdminProjects|
+ },
+ data() {
+ return {
+ enteredProjectName: '',
+ };
+ },
+ computed: {
+ title() {
+ return sprintf(
+ s__('AdminProjects|Delete Project %{projectName}?'),
+ {
+ projectName: `'${_.escape(this.projectName)}'`,
+ },
+ false,
+ );
+ },
+ text() {
+ return sprintf(
+ s__(`AdminProjects|
You’re about to permanently delete the project %{projectName}, its repository,
and all related resources including issues, merge requests, etc.. Once you confirm and press
%{strong_start}Delete project%{strong_end}, it cannot be undone or recovered.`),
- {
- projectName: `<strong>${_.escape(this.projectName)}</strong>`,
- strong_start: '<strong>',
- strong_end: '</strong>',
- },
- false,
- );
- },
- confirmationTextLabel() {
- return sprintf(s__('AdminUsers|To confirm, type %{projectName}'),
- {
- projectName: `<code>${_.escape(this.projectName)}</code>`,
- },
- false,
- );
- },
- primaryButtonLabel() {
- return s__('AdminProjects|Delete project');
- },
- canSubmit() {
- return this.enteredProjectName === this.projectName;
- },
+ {
+ projectName: `<strong>${_.escape(this.projectName)}</strong>`,
+ strong_start: '<strong>',
+ strong_end: '</strong>',
+ },
+ false,
+ );
+ },
+ confirmationTextLabel() {
+ return sprintf(
+ s__('AdminUsers|To confirm, type %{projectName}'),
+ {
+ projectName: `<code>${_.escape(this.projectName)}</code>`,
+ },
+ false,
+ );
+ },
+ primaryButtonLabel() {
+ return s__('AdminProjects|Delete project');
+ },
+ canSubmit() {
+ return this.enteredProjectName === this.projectName;
+ },
+ },
+ methods: {
+ onCancel() {
+ this.enteredProjectName = '';
},
- methods: {
- onCancel() {
- this.enteredProjectName = '';
- },
- onSubmit() {
- this.$refs.form.submit();
- this.enteredProjectName = '';
- },
+ onSubmit() {
+ this.$refs.form.submit();
+ this.enteredProjectName = '';
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/pages/admin/projects/index/index.js b/app/assets/javascripts/pages/admin/projects/index/index.js
index ddbefec87b6..6fa8760545d 100644
--- a/app/assets/javascripts/pages/admin/projects/index/index.js
+++ b/app/assets/javascripts/pages/admin/projects/index/index.js
@@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', () => {
},
});
- $(document).on('shown.bs.modal', (event) => {
+ $(document).on('shown.bs.modal', event => {
if (event.relatedTarget.classList.contains('delete-project-button')) {
const buttonProps = event.relatedTarget.dataset;
deleteModal.deleteProjectUrl = buttonProps.deleteProjectUrl;
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 8d5efcdcd96..4b33fcc759a 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
@@ -1,114 +1,119 @@
<script>
- import _ from 'underscore';
- import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
- import { s__, sprintf } from '~/locale';
+import _ from 'underscore';
+import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
+import { s__, sprintf } from '~/locale';
- export default {
- components: {
- DeprecatedModal,
+export default {
+ components: {
+ DeprecatedModal,
+ },
+ props: {
+ deleteUserUrl: {
+ type: String,
+ required: false,
+ default: '',
},
- props: {
- deleteUserUrl: {
- type: String,
- required: false,
- default: '',
- },
- blockUserUrl: {
- type: String,
- required: false,
- default: '',
- },
- deleteContributions: {
- type: Boolean,
- required: false,
- default: false,
- },
- username: {
- type: String,
- required: false,
- default: '',
- },
- csrfToken: {
- type: String,
- required: false,
- default: '',
- },
+ blockUserUrl: {
+ type: String,
+ required: false,
+ default: '',
},
- data() {
- return {
- enteredUsername: '',
- };
+ deleteContributions: {
+ type: Boolean,
+ required: false,
+ default: false,
},
- computed: {
- title() {
- const keepContributionsTitle = s__('AdminUsers|Delete User %{username}?');
- const deleteContributionsTitle = s__('AdminUsers|Delete User %{username} and contributions?');
+ username: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ csrfToken: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ enteredUsername: '',
+ };
+ },
+ computed: {
+ title() {
+ const keepContributionsTitle = s__('AdminUsers|Delete User %{username}?');
+ const deleteContributionsTitle = s__('AdminUsers|Delete User %{username} and contributions?');
- return sprintf(
- this.deleteContributions ? deleteContributionsTitle : keepContributionsTitle, {
- username: `'${_.escape(this.username)}'`,
- }, false);
- },
- text() {
- const keepContributionsText = s__(`AdminArea|
+ return sprintf(
+ this.deleteContributions ? deleteContributionsTitle : keepContributionsTitle,
+ {
+ username: `'${_.escape(this.username)}'`,
+ },
+ false,
+ );
+ },
+ text() {
+ const keepContributionsText = s__(`AdminArea|
You are about to permanently delete the user %{username}.
Issues, merge requests, and groups linked to them will be transferred to a system-wide "Ghost-user".
To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead.
Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered.`);
- const deleteContributionsText = s__(`AdminArea|
+ const deleteContributionsText = s__(`AdminArea|
You are about to permanently delete the user %{username}.
This will delete all of the issues, merge requests, and groups linked to them.
To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead.
Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered.`);
- return sprintf(this.deleteContributions ? deleteContributionsText : keepContributionsText,
- {
- username: `<strong>${_.escape(this.username)}</strong>`,
- strong_start: '<strong>',
- strong_end: '</strong>',
- },
- false,
- );
- },
- confirmationTextLabel() {
- return sprintf(s__('AdminUsers|To confirm, type %{username}'),
- {
- username: `<code>${_.escape(this.username)}</code>`,
- },
- false,
- );
- },
- primaryButtonLabel() {
- const keepContributionsLabel = s__('AdminUsers|Delete user');
- const deleteContributionsLabel = s__('AdminUsers|Delete user and contributions');
+ return sprintf(
+ this.deleteContributions ? deleteContributionsText : keepContributionsText,
+ {
+ username: `<strong>${_.escape(this.username)}</strong>`,
+ strong_start: '<strong>',
+ strong_end: '</strong>',
+ },
+ false,
+ );
+ },
+ confirmationTextLabel() {
+ return sprintf(
+ s__('AdminUsers|To confirm, type %{username}'),
+ {
+ username: `<code>${_.escape(this.username)}</code>`,
+ },
+ false,
+ );
+ },
+ primaryButtonLabel() {
+ const keepContributionsLabel = s__('AdminUsers|Delete user');
+ const deleteContributionsLabel = s__('AdminUsers|Delete user and contributions');
- return this.deleteContributions ? deleteContributionsLabel : keepContributionsLabel;
- },
- secondaryButtonLabel() {
- return s__('AdminUsers|Block user');
- },
- canSubmit() {
- return this.enteredUsername === this.username;
- },
+ return this.deleteContributions ? deleteContributionsLabel : keepContributionsLabel;
},
- methods: {
- onCancel() {
- this.enteredUsername = '';
- },
- onSecondaryAction() {
- const { form } = this.$refs;
+ secondaryButtonLabel() {
+ return s__('AdminUsers|Block user');
+ },
+ canSubmit() {
+ return this.enteredUsername === this.username;
+ },
+ },
+ methods: {
+ onCancel() {
+ this.enteredUsername = '';
+ },
+ onSecondaryAction() {
+ const { form } = this.$refs;
- form.action = this.blockUserUrl;
- this.$refs.method.value = 'put';
+ form.action = this.blockUserUrl;
+ this.$refs.method.value = 'put';
- form.submit();
- },
- onSubmit() {
- this.$refs.form.submit();
- this.enteredUsername = '';
- },
+ form.submit();
+ },
+ onSubmit() {
+ this.$refs.form.submit();
+ this.enteredUsername = '';
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/pages/admin/users/index.js b/app/assets/javascripts/pages/admin/users/index.js
index 06599c3fd5f..45046688b57 100644
--- a/app/assets/javascripts/pages/admin/users/index.js
+++ b/app/assets/javascripts/pages/admin/users/index.js
@@ -32,12 +32,14 @@ document.addEventListener('DOMContentLoaded', () => {
},
});
- $(document).on('shown.bs.modal', (event) => {
+ $(document).on('shown.bs.modal', event => {
if (event.relatedTarget.classList.contains('delete-user-button')) {
const buttonProps = event.relatedTarget.dataset;
deleteModal.deleteUserUrl = buttonProps.deleteUserUrl;
deleteModal.blockUserUrl = buttonProps.blockUserUrl;
- deleteModal.deleteContributions = event.relatedTarget.hasAttribute('data-delete-contributions');
+ deleteModal.deleteContributions = event.relatedTarget.hasAttribute(
+ 'data-delete-contributions',
+ );
deleteModal.username = buttonProps.username;
}
});
diff --git a/app/assets/javascripts/pages/admin/users/new/index.js b/app/assets/javascripts/pages/admin/users/new/index.js
index 58bfa8d64e7..3e6a090cb0e 100644
--- a/app/assets/javascripts/pages/admin/users/new/index.js
+++ b/app/assets/javascripts/pages/admin/users/new/index.js
@@ -4,7 +4,9 @@ export default class UserInternalRegexHandler {
constructor() {
this.regexPattern = $('[data-user-internal-regex-pattern]').data('user-internal-regex-pattern');
if (this.regexPattern && this.regexPattern !== '') {
- this.regexOptions = $('[data-user-internal-regex-options]').data('user-internal-regex-options');
+ this.regexOptions = $('[data-user-internal-regex-options]').data(
+ 'user-internal-regex-options',
+ );
this.external = $('#user_external');
this.warningMessage = $('#warning_external_automatically_set');
this.addListenerToEmailField();
@@ -13,7 +15,7 @@ export default class UserInternalRegexHandler {
}
addListenerToEmailField() {
- $('#user_email').on('input', (event) => {
+ $('#user_email').on('input', event => {
this.setExternalCheckbox(event.currentTarget.value);
});
}
diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
index 72f3f70b98f..1b56b97f751 100644
--- a/app/assets/javascripts/pages/dashboard/todos/index/todos.js
+++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
@@ -79,7 +79,8 @@ export default class Todos {
.then(({ data }) => {
this.updateRowState(target);
this.updateBadges(data);
- }).catch(() => {
+ })
+ .catch(() => {
this.updateRowState(target, true);
return flash(__('Error updating todo status.'));
});
@@ -118,10 +119,12 @@ export default class Todos {
axios[target.dataset.method](target.dataset.href, {
ids: this.todo_ids,
- }).then(({ data }) => {
- this.updateAllState(target, data);
- this.updateBadges(data);
- }).catch(() => flash(__('Error updating status for all todos.')));
+ })
+ .then(({ data }) => {
+ this.updateAllState(target, data);
+ this.updateBadges(data);
+ })
+ .catch(() => flash(__('Error updating status for all todos.')));
}
updateAllState(target, data) {
@@ -133,7 +136,7 @@ export default class Todos {
target.removeAttribute('disabled');
target.classList.remove('disabled');
- this.todo_ids = (target === markAllDoneBtn) ? data.updated_ids : [];
+ this.todo_ids = target === markAllDoneBtn ? data.updated_ids : [];
undoAllBtn.classList.toggle('hidden');
markAllDoneBtn.classList.toggle('hidden');
todoListContainer.classList.toggle('hidden');
diff --git a/app/assets/javascripts/pages/groups/edit/index.js b/app/assets/javascripts/pages/groups/edit/index.js
index 002b2279fcc..32b55575f95 100644
--- a/app/assets/javascripts/pages/groups/edit/index.js
+++ b/app/assets/javascripts/pages/groups/edit/index.js
@@ -2,13 +2,20 @@ import groupAvatar from '~/group_avatar';
import TransferDropdown from '~/groups/transfer_dropdown';
import initConfirmDangerModal from '~/confirm_danger_modal';
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 projectSelect from '~/project_select';
document.addEventListener('DOMContentLoaded', () => {
groupAvatar();
new TransferDropdown(); // eslint-disable-line no-new
initConfirmDangerModal();
initSettingsPanels();
+ dirtySubmitFactory(
+ document.querySelectorAll('.js-general-settings-form, .js-general-permissions-form'),
+ );
mountBadgeSettings(GROUP_BADGE);
+
+ 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 48668562f09..a4778077bc4 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
@@ -1,94 +1,117 @@
<script>
- import axios from '~/lib/utils/axios_utils';
+import axios from '~/lib/utils/axios_utils';
- import Flash from '~/flash';
- import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
- import { n__, s__, sprintf } from '~/locale';
- import { redirectTo } from '~/lib/utils/url_utility';
- import eventHub from '../event_hub';
+import Flash from '~/flash';
+import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
+import { n__, s__, sprintf } from '~/locale';
+import { redirectTo } from '~/lib/utils/url_utility';
+import eventHub from '../event_hub';
- export default {
- components: {
- DeprecatedModal,
+export default {
+ components: {
+ DeprecatedModal,
+ },
+ props: {
+ issueCount: {
+ type: Number,
+ required: true,
},
- props: {
- issueCount: {
- type: Number,
- required: true,
- },
- mergeRequestCount: {
- type: Number,
- required: true,
- },
- milestoneId: {
- type: Number,
- required: true,
- },
- milestoneTitle: {
- type: String,
- required: true,
- },
- milestoneUrl: {
- type: String,
- required: true,
- },
+ mergeRequestCount: {
+ type: Number,
+ required: true,
},
- computed: {
- text() {
- const milestoneTitle = sprintf('<strong>%{milestoneTitle}</strong>', { milestoneTitle: this.milestoneTitle });
-
- if (this.issueCount === 0 && this.mergeRequestCount === 0) {
- return sprintf(
- s__(`Milestones|
-You’re about to permanently delete the milestone %{milestoneTitle}.
-This milestone is not currently used in any issues or merge requests.`),
- {
- milestoneTitle,
- },
- false,
- );
- }
+ milestoneId: {
+ type: Number,
+ required: true,
+ },
+ milestoneTitle: {
+ type: String,
+ required: true,
+ },
+ milestoneUrl: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ text() {
+ const milestoneTitle = sprintf('<strong>%{milestoneTitle}</strong>', {
+ milestoneTitle: this.milestoneTitle,
+ });
+ if (this.issueCount === 0 && this.mergeRequestCount === 0) {
return sprintf(
s__(`Milestones|
-You’re about to permanently delete the milestone %{milestoneTitle} and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}.
-Once deleted, it cannot be undone or recovered.`),
+You’re about to permanently delete the milestone %{milestoneTitle}.
+This milestone is not currently used in any issues or merge requests.`),
{
milestoneTitle,
- issuesWithCount: n__('%d issue', '%d issues', this.issueCount),
- mergeRequestsWithCount: n__('%d merge request', '%d merge requests', this.mergeRequestCount),
},
false,
);
- },
- title() {
- return sprintf(s__('Milestones|Delete milestone %{milestoneTitle}?'), { milestoneTitle: this.milestoneTitle });
- },
- },
- methods: {
- onSubmit() {
- eventHub.$emit('deleteMilestoneModal.requestStarted', this.milestoneUrl);
+ }
- return axios.delete(this.milestoneUrl)
- .then((response) => {
- eventHub.$emit('deleteMilestoneModal.requestFinished', { milestoneUrl: this.milestoneUrl, successful: true });
+ return sprintf(
+ s__(`Milestones|
+You’re about to permanently delete the milestone %{milestoneTitle} and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}.
+Once deleted, it cannot be undone or recovered.`),
+ {
+ milestoneTitle,
+ issuesWithCount: n__('%d issue', '%d issues', this.issueCount),
+ mergeRequestsWithCount: n__(
+ '%d merge request',
+ '%d merge requests',
+ this.mergeRequestCount,
+ ),
+ },
+ false,
+ );
+ },
+ title() {
+ return sprintf(s__('Milestones|Delete milestone %{milestoneTitle}?'), {
+ milestoneTitle: this.milestoneTitle,
+ });
+ },
+ },
+ methods: {
+ onSubmit() {
+ eventHub.$emit('deleteMilestoneModal.requestStarted', this.milestoneUrl);
- // follow the rediect to milestones overview page
- redirectTo(response.request.responseURL);
- })
- .catch((error) => {
- eventHub.$emit('deleteMilestoneModal.requestFinished', { milestoneUrl: this.milestoneUrl, successful: false });
+ return axios
+ .delete(this.milestoneUrl)
+ .then(response => {
+ eventHub.$emit('deleteMilestoneModal.requestFinished', {
+ milestoneUrl: this.milestoneUrl,
+ successful: true,
+ });
- if (error.response && error.response.status === 404) {
- Flash(sprintf(s__('Milestones|Milestone %{milestoneTitle} was not found'), { milestoneTitle: this.milestoneTitle }));
- } else {
- Flash(sprintf(s__('Milestones|Failed to delete milestone %{milestoneTitle}'), { milestoneTitle: this.milestoneTitle }));
- }
- throw error;
+ // follow the rediect to milestones overview page
+ redirectTo(response.request.responseURL);
+ })
+ .catch(error => {
+ eventHub.$emit('deleteMilestoneModal.requestFinished', {
+ milestoneUrl: this.milestoneUrl,
+ successful: false,
});
- },
+
+ if (error.response && error.response.status === 404) {
+ Flash(
+ sprintf(s__('Milestones|Milestone %{milestoneTitle} was not found'), {
+ milestoneTitle: this.milestoneTitle,
+ }),
+ );
+ } else {
+ Flash(
+ sprintf(s__('Milestones|Failed to delete milestone %{milestoneTitle}'), {
+ milestoneTitle: this.milestoneTitle,
+ }),
+ );
+ }
+ throw error;
+ });
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js b/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js
index d51b5c221e3..1d559dc6e41 100644
--- a/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js
+++ b/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js
@@ -7,7 +7,9 @@ export default () => {
Vue.use(Translate);
const onRequestFinished = ({ milestoneUrl, successful }) => {
- const button = document.querySelector(`.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`);
+ const button = document.querySelector(
+ `.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`,
+ );
if (!successful) {
button.removeAttribute('disabled');
@@ -16,14 +18,16 @@ export default () => {
button.querySelector('.js-loading-icon').classList.add('hidden');
};
- const onRequestStarted = (milestoneUrl) => {
- const button = document.querySelector(`.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`);
+ const onRequestStarted = milestoneUrl => {
+ const button = document.querySelector(
+ `.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`,
+ );
button.setAttribute('disabled', '');
button.querySelector('.js-loading-icon').classList.remove('hidden');
eventHub.$once('deleteMilestoneModal.requestFinished', onRequestFinished);
};
- const onDeleteButtonClick = (event) => {
+ const onDeleteButtonClick = event => {
const button = event.currentTarget;
const modalProps = {
milestoneId: parseInt(button.dataset.milestoneId, 10),
@@ -37,12 +41,12 @@ export default () => {
};
const deleteMilestoneButtons = document.querySelectorAll('.js-delete-milestone-button');
- deleteMilestoneButtons.forEach((button) => {
+ deleteMilestoneButtons.forEach(button => {
button.addEventListener('click', onDeleteButtonClick);
});
eventHub.$once('deleteMilestoneModal.mounted', () => {
- deleteMilestoneButtons.forEach((button) => {
+ deleteMilestoneButtons.forEach(button => {
button.removeAttribute('disabled');
});
});
diff --git a/app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js b/app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js
index 8e79341e96a..fcc62a2b2af 100644
--- a/app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js
+++ b/app/assets/javascripts/pages/milestones/shared/promote_milestone_modal_init.js
@@ -7,20 +7,24 @@ Vue.use(Translate);
export default () => {
const onRequestFinished = ({ milestoneUrl, successful }) => {
- const button = document.querySelector(`.js-promote-project-milestone-button[data-url="${milestoneUrl}"]`);
+ const button = document.querySelector(
+ `.js-promote-project-milestone-button[data-url="${milestoneUrl}"]`,
+ );
if (!successful) {
button.removeAttribute('disabled');
}
};
- const onRequestStarted = (milestoneUrl) => {
- const button = document.querySelector(`.js-promote-project-milestone-button[data-url="${milestoneUrl}"]`);
+ const onRequestStarted = milestoneUrl => {
+ const button = document.querySelector(
+ `.js-promote-project-milestone-button[data-url="${milestoneUrl}"]`,
+ );
button.setAttribute('disabled', '');
eventHub.$once('promoteMilestoneModal.requestFinished', onRequestFinished);
};
- const onDeleteButtonClick = (event) => {
+ const onDeleteButtonClick = event => {
const button = event.currentTarget;
const modalProps = {
milestoneTitle: button.dataset.milestoneTitle,
@@ -32,12 +36,12 @@ export default () => {
};
const promoteMilestoneButtons = document.querySelectorAll('.js-promote-project-milestone-button');
- promoteMilestoneButtons.forEach((button) => {
+ promoteMilestoneButtons.forEach(button => {
button.addEventListener('click', onDeleteButtonClick);
});
eventHub.$once('promoteMilestoneModal.mounted', () => {
- promoteMilestoneButtons.forEach((button) => {
+ promoteMilestoneButtons.forEach(button => {
button.removeAttribute('disabled');
});
});
diff --git a/app/assets/javascripts/pages/profiles/index.js b/app/assets/javascripts/pages/profiles/index.js
index 04e50963699..883be18b336 100644
--- a/app/assets/javascripts/pages/profiles/index.js
+++ b/app/assets/javascripts/pages/profiles/index.js
@@ -3,9 +3,12 @@ import '~/profile/gl_crop';
import Profile from '~/profile/profile';
document.addEventListener('DOMContentLoaded', () => {
- $(document).on('input.ssh_key', '#key_key', function () { // eslint-disable-line func-names
+ // eslint-disable-next-line func-names
+ $(document).on('input.ssh_key', '#key_key', function() {
const $title = $('#key_title');
- const comment = $(this).val().match(/^\S+ \S+ (.+)\n?$/);
+ const comment = $(this)
+ .val()
+ .match(/^\S+ \S+ (.+)\n?$/);
// Extract the SSH Key title from its comment
if (comment && comment.length > 1) {
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 8e8f47c21d8..417935e2ad0 100644
--- a/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
+++ b/app/assets/javascripts/pages/profiles/two_factor_auths/index.js
@@ -5,7 +5,9 @@ document.addEventListener('DOMContentLoaded', () => {
const twoFactorNode = document.querySelector('.js-two-factor-auth');
const skippable = twoFactorNode.dataset.twoFactorSkippable === 'true';
if (skippable) {
- const button = `<a class="btn btn-sm btn-warning float-right" data-method="patch" href="${twoFactorNode.dataset.two_factor_skip_url}">Configure it later</a>`;
+ const button = `<a class="btn btn-sm btn-warning float-right" data-method="patch" href="${
+ twoFactorNode.dataset.two_factor_skip_url
+ }">Configure it later</a>`;
const flashAlert = document.querySelector('.flash-alert .container-fluid');
if (flashAlert) flashAlert.insertAdjacentHTML('beforeend', button);
}
diff --git a/app/assets/javascripts/pages/projects/branches/new/index.js b/app/assets/javascripts/pages/projects/branches/new/index.js
index a9658fd1eb4..13ff47d53c2 100644
--- a/app/assets/javascripts/pages/projects/branches/new/index.js
+++ b/app/assets/javascripts/pages/projects/branches/new/index.js
@@ -1,6 +1,11 @@
import $ from 'jquery';
import NewBranchForm from '~/new_branch_form';
-document.addEventListener('DOMContentLoaded', () => (
- new NewBranchForm($('.js-create-branch-form'), JSON.parse(document.getElementById('availableRefs').innerHTML))
-));
+document.addEventListener(
+ 'DOMContentLoaded',
+ () =>
+ new NewBranchForm(
+ $('.js-create-branch-form'),
+ JSON.parse(document.getElementById('availableRefs').innerHTML),
+ ),
+);
diff --git a/app/assets/javascripts/pages/projects/graphs/charts/index.js b/app/assets/javascripts/pages/projects/graphs/charts/index.js
index 80159a82bd4..3ccad513c05 100644
--- a/app/assets/javascripts/pages/projects/graphs/charts/index.js
+++ b/app/assets/javascripts/pages/projects/graphs/charts/index.js
@@ -31,14 +31,16 @@ document.addEventListener('DOMContentLoaded', () => {
const chartData = data => ({
labels: Object.keys(data),
- datasets: [{
- fillColor: 'rgba(220,220,220,0.5)',
- strokeColor: 'rgba(220,220,220,1)',
- barStrokeWidth: 1,
- barValueSpacing: 1,
- barDatasetSpacing: 1,
- data: _.values(data),
- }],
+ datasets: [
+ {
+ fillColor: 'rgba(220,220,220,0.5)',
+ strokeColor: 'rgba(220,220,220,1)',
+ barStrokeWidth: 1,
+ barValueSpacing: 1,
+ barDatasetSpacing: 1,
+ data: _.values(data),
+ },
+ ],
});
const hourData = chartData(projectChartData.hour);
@@ -51,7 +53,9 @@ document.addEventListener('DOMContentLoaded', () => {
responsiveChart($('#month-chart'), monthData);
const data = projectChartData.languages;
- const ctx = $('#languages-chart').get(0).getContext('2d');
+ const ctx = $('#languages-chart')
+ .get(0)
+ .getContext('2d');
const options = {
scaleOverlay: true,
responsive: true,
diff --git a/app/assets/javascripts/pages/projects/graphs/show/index.js b/app/assets/javascripts/pages/projects/graphs/show/index.js
index 71f629fbc13..f79c386b59e 100644
--- a/app/assets/javascripts/pages/projects/graphs/show/index.js
+++ b/app/assets/javascripts/pages/projects/graphs/show/index.js
@@ -7,7 +7,8 @@ import ContributorsStatGraph from './stat_graph_contributors';
document.addEventListener('DOMContentLoaded', () => {
const url = document.querySelector('.js-graphs-show').dataset.projectGraphPath;
- axios.get(url)
+ axios
+ .get(url)
.then(({ data }) => {
const graph = new ContributorsStatGraph();
graph.init(data);
diff --git a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors.js b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors.js
index 58bb8c5b0c8..76613394af6 100644
--- a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors.js
+++ b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors.js
@@ -3,7 +3,11 @@
import $ from 'jquery';
import _ from 'underscore';
import { n__, s__, createDateTimeFormat, sprintf } from '~/locale';
-import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph';
+import {
+ ContributorsGraph,
+ ContributorsAuthorGraph,
+ ContributorsMasterGraph,
+} from './stat_graph_contributors_graph';
import ContributorsStatGraphUtil from './stat_graph_contributors_util';
export default (function() {
@@ -14,7 +18,7 @@ export default (function() {
ContributorsStatGraph.prototype.init = function(log) {
var author_commits, total_commits;
this.parsed_log = ContributorsStatGraphUtil.parse_log(log);
- this.set_current_field("commits");
+ this.set_current_field('commits');
total_commits = ContributorsStatGraphUtil.get_total_data(this.parsed_log, this.field);
author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field);
this.add_master_graph(total_commits);
@@ -31,23 +35,26 @@ export default (function() {
var limited_author_data;
this.authors = [];
limited_author_data = author_data.slice(0, 100);
- return _.each(limited_author_data, (function(_this) {
- return function(d) {
- var author_graph, author_header;
- author_header = _this.create_author_header(d);
- $(".contributors-list").append(author_header);
-
- author_graph = new ContributorsAuthorGraph(d.dates);
- _this.authors[d.author_name] = author_graph;
- return author_graph.draw();
- };
- })(this));
+ return _.each(
+ limited_author_data,
+ (function(_this) {
+ return function(d) {
+ var author_graph, author_header;
+ author_header = _this.create_author_header(d);
+ $('.contributors-list').append(author_header);
+
+ author_graph = new ContributorsAuthorGraph(d.dates);
+ _this.authors[d.author_name] = author_graph;
+ return author_graph.draw();
+ };
+ })(this),
+ );
};
ContributorsStatGraph.prototype.format_author_commit_info = function(author) {
var commits;
commits = $('<span/>', {
- "class": 'graph-author-commits-count'
+ class: 'graph-author-commits-count',
});
commits.text(n__('%d commit', '%d commits', author.commits));
return $('<span/>').append(commits);
@@ -56,13 +63,13 @@ export default (function() {
ContributorsStatGraph.prototype.create_author_header = function(author) {
var author_commit_info, author_commit_info_span, author_email, author_name, list_item;
list_item = $('<li/>', {
- "class": 'person',
- style: 'display: block;'
+ class: 'person',
+ style: 'display: block;',
});
author_name = $('<h4>' + author.author_name + '</h4>');
author_email = $('<p class="graph-author-email">' + author.author_email + '</p>');
author_commit_info_span = $('<span/>', {
- "class": 'commits'
+ class: 'commits',
});
author_commit_info = this.format_author_commit_info(author);
author_commit_info_span.html(author_commit_info);
@@ -80,37 +87,41 @@ export default (function() {
};
ContributorsStatGraph.prototype.redraw_authors = function() {
- $("ol").html("");
+ $('ol').html('');
const { x_domain } = ContributorsGraph.prototype;
- const author_commits = ContributorsStatGraphUtil.get_author_data(this.parsed_log, this.field, x_domain);
-
- return _.each(author_commits, (function(_this) {
- return function(d) {
- _this.redraw_author_commit_info(d);
- if (_this.authors[d.author_name] != null) {
- $(_this.authors[d.author_name].list_item).appendTo("ol");
- _this.authors[d.author_name].set_data(d.dates);
- return _this.authors[d.author_name].redraw();
- }
- return '';
- };
- })(this));
+ const author_commits = ContributorsStatGraphUtil.get_author_data(
+ this.parsed_log,
+ this.field,
+ x_domain,
+ );
+
+ return _.each(
+ author_commits,
+ (function(_this) {
+ return function(d) {
+ _this.redraw_author_commit_info(d);
+ if (_this.authors[d.author_name] != null) {
+ $(_this.authors[d.author_name].list_item).appendTo('ol');
+ _this.authors[d.author_name].set_data(d.dates);
+ return _this.authors[d.author_name].redraw();
+ }
+ return '';
+ };
+ })(this),
+ );
};
ContributorsStatGraph.prototype.set_current_field = function(field) {
- return this.field = field;
+ return (this.field = field);
};
ContributorsStatGraph.prototype.change_date_header = function() {
const { x_domain } = ContributorsGraph.prototype;
- const formattedDateRange = sprintf(
- s__('ContributorsPage|%{startDate} – %{endDate}'),
- {
- startDate: this.dateFormat.format(new Date(x_domain[0])),
- endDate: this.dateFormat.format(new Date(x_domain[1])),
- },
- );
+ const formattedDateRange = sprintf(s__('ContributorsPage|%{startDate} – %{endDate}'), {
+ startDate: this.dateFormat.format(new Date(x_domain[0])),
+ endDate: this.dateFormat.format(new Date(x_domain[1])),
+ });
return $('#date_header').text(formattedDateRange);
};
@@ -120,7 +131,7 @@ export default (function() {
if ($author != null) {
author_list_item = $(this.authors[author.author_name].list_item);
author_commit_info = this.format_author_commit_info(author);
- return author_list_item.find("span").html(author_commit_info);
+ return author_list_item.find('span').html(author_commit_info);
}
return '';
};
diff --git a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js
index 5f91686347a..377dce6c746 100644
--- a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js
+++ b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_graph.js
@@ -11,10 +11,32 @@ import { brushX } from 'd3-brush';
import { timeParse } from 'd3-time-format';
import { dateTickFormat } from '~/lib/utils/tick_formats';
-const d3 = { extent, max, select, scaleTime, scaleLinear, axisLeft, axisBottom, area, brushX, timeParse };
+const d3 = {
+ extent,
+ max,
+ select,
+ scaleTime,
+ scaleLinear,
+ axisLeft,
+ axisBottom,
+ area,
+ brushX,
+ timeParse,
+};
const hasProp = {}.hasOwnProperty;
-const extend = function(child, parent) { for (const key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+const extend = function(child, parent) {
+ for (const key in parent) {
+ if (hasProp.call(parent, key)) child[key] = parent[key];
+ }
+ function ctor() {
+ this.constructor = child;
+ }
+ ctor.prototype = parent.prototype;
+ child.prototype = new ctor();
+ child.__super__ = parent.prototype;
+ return child;
+};
export const ContributorsGraph = (function() {
function ContributorsGraph() {}
@@ -23,7 +45,7 @@ export const ContributorsGraph = (function() {
top: 20,
right: 10,
bottom: 30,
- left: 40
+ left: 40,
};
ContributorsGraph.prototype.x_domain = null;
@@ -33,35 +55,39 @@ export const ContributorsGraph = (function() {
ContributorsGraph.prototype.dates = [];
ContributorsGraph.prototype.determine_width = function(baseWidth, $parentElement) {
- const parentPaddingWidth = parseFloat($parentElement.css('padding-left')) + parseFloat($parentElement.css('padding-right'));
+ const parentPaddingWidth =
+ parseFloat($parentElement.css('padding-left')) +
+ parseFloat($parentElement.css('padding-right'));
const marginWidth = this.MARGIN.left + this.MARGIN.right;
return baseWidth - parentPaddingWidth - marginWidth;
};
ContributorsGraph.set_x_domain = function(data) {
- return ContributorsGraph.prototype.x_domain = data;
+ return (ContributorsGraph.prototype.x_domain = data);
};
ContributorsGraph.set_y_domain = function(data) {
- return ContributorsGraph.prototype.y_domain = [
- 0, d3.max(data, function(d) {
- return d.commits = d.commits || d.additions || d.deletions;
- })
- ];
+ return (ContributorsGraph.prototype.y_domain = [
+ 0,
+ d3.max(data, function(d) {
+ return (d.commits = d.commits || d.additions || d.deletions);
+ }),
+ ]);
};
ContributorsGraph.init_x_domain = function(data) {
- return ContributorsGraph.prototype.x_domain = d3.extent(data, function(d) {
+ return (ContributorsGraph.prototype.x_domain = d3.extent(data, function(d) {
return d.date;
- });
+ }));
};
ContributorsGraph.init_y_domain = function(data) {
- return ContributorsGraph.prototype.y_domain = [
- 0, d3.max(data, function(d) {
- return d.commits = d.commits || d.additions || d.deletions;
- })
- ];
+ return (ContributorsGraph.prototype.y_domain = [
+ 0,
+ d3.max(data, function(d) {
+ return (d.commits = d.commits || d.additions || d.deletions);
+ }),
+ ]);
};
ContributorsGraph.init_domain = function(data) {
@@ -70,7 +96,7 @@ export const ContributorsGraph = (function() {
};
ContributorsGraph.set_dates = function(data) {
- return ContributorsGraph.prototype.dates = data;
+ return (ContributorsGraph.prototype.dates = data);
};
ContributorsGraph.prototype.set_x_domain = function() {
@@ -87,20 +113,33 @@ export const ContributorsGraph = (function() {
};
ContributorsGraph.prototype.create_scale = function(width, height) {
- this.x = d3.scaleTime().range([0, width]).clamp(true);
- return this.y = d3.scaleLinear().range([height, 0]).nice();
+ this.x = d3
+ .scaleTime()
+ .range([0, width])
+ .clamp(true);
+ return (this.y = d3
+ .scaleLinear()
+ .range([height, 0])
+ .nice());
};
ContributorsGraph.prototype.draw_x_axis = function() {
- return this.svg.append("g").attr("class", "x axis").attr("transform", "translate(0, " + this.height + ")").call(this.x_axis);
+ return this.svg
+ .append('g')
+ .attr('class', 'x axis')
+ .attr('transform', 'translate(0, ' + this.height + ')')
+ .call(this.x_axis);
};
ContributorsGraph.prototype.draw_y_axis = function() {
- return this.svg.append("g").attr("class", "y axis").call(this.y_axis);
+ return this.svg
+ .append('g')
+ .attr('class', 'y axis')
+ .call(this.y_axis);
};
ContributorsGraph.prototype.set_data = function(data) {
- return this.data = data;
+ return (this.data = data);
};
return ContributorsGraph;
@@ -137,9 +176,9 @@ export const ContributorsMasterGraph = (function(superClass) {
};
ContributorsMasterGraph.prototype.parse_dates = function(data) {
- const parseDate = d3.timeParse("%Y-%m-%d");
+ const parseDate = d3.timeParse('%Y-%m-%d');
return data.forEach(function(d) {
- return d.date = parseDate(d.date);
+ return (d.date = parseDate(d.date));
});
};
@@ -148,42 +187,63 @@ export const ContributorsMasterGraph = (function(superClass) {
};
ContributorsMasterGraph.prototype.create_axes = function() {
- this.x_axis = d3.axisBottom()
+ this.x_axis = d3
+ .axisBottom()
.scale(this.x)
.tickFormat(dateTickFormat);
- return this.y_axis = d3.axisLeft().scale(this.y).ticks(5);
+ return (this.y_axis = d3
+ .axisLeft()
+ .scale(this.y)
+ .ticks(5));
};
ContributorsMasterGraph.prototype.create_svg = function() {
- this.svg = d3.select("#contributors-master")
- .append("svg")
- .attr("width", this.width + this.MARGIN.left + this.MARGIN.right)
- .attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom)
- .attr("class", "tint-box")
- .append("g")
- .attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")");
+ this.svg = d3
+ .select('#contributors-master')
+ .append('svg')
+ .attr('width', this.width + this.MARGIN.left + this.MARGIN.right)
+ .attr('height', this.height + this.MARGIN.top + this.MARGIN.bottom)
+ .attr('class', 'tint-box')
+ .append('g')
+ .attr('transform', 'translate(' + this.MARGIN.left + ',' + this.MARGIN.top + ')');
return this.svg;
};
ContributorsMasterGraph.prototype.create_area = function(x, y) {
- return this.area = d3.area().x(function(d) {
- return x(d.date);
- }).y0(this.height).y1(function(d) {
- d.commits = d.commits || d.additions || d.deletions;
- return y(d.commits);
- });
+ return (this.area = d3
+ .area()
+ .x(function(d) {
+ return x(d.date);
+ })
+ .y0(this.height)
+ .y1(function(d) {
+ d.commits = d.commits || d.additions || d.deletions;
+ return y(d.commits);
+ }));
};
ContributorsMasterGraph.prototype.create_brush = function() {
- return this.brush = d3.brushX(this.x).extent([[this.x.range()[0], 0], [this.x.range()[1], this.height]]).on("end", this.update_content);
+ return (this.brush = d3
+ .brushX(this.x)
+ .extent([[this.x.range()[0], 0], [this.x.range()[1], this.height]])
+ .on('end', this.update_content));
};
ContributorsMasterGraph.prototype.draw_path = function(data) {
- return this.svg.append("path").datum(data).attr("class", "area").attr("d", this.area);
+ return this.svg
+ .append('path')
+ .datum(data)
+ .attr('class', 'area')
+ .attr('d', this.area);
};
ContributorsMasterGraph.prototype.add_brush = function() {
- return this.svg.append("g").attr("class", "selection").call(this.brush).selectAll("rect").attr("height", this.height);
+ return this.svg
+ .append('g')
+ .attr('class', 'selection')
+ .call(this.brush)
+ .selectAll('rect')
+ .attr('height', this.height);
};
ContributorsMasterGraph.prototype.update_content = function() {
@@ -193,7 +253,7 @@ export const ContributorsMasterGraph = (function(superClass) {
} else {
ContributorsGraph.set_x_domain(this.x_max_domain);
}
- return $("#brush_change").trigger('change');
+ return $('#brush_change').trigger('change');
};
ContributorsMasterGraph.prototype.draw = function() {
@@ -216,9 +276,9 @@ export const ContributorsMasterGraph = (function(superClass) {
this.process_dates(this.data);
ContributorsGraph.set_y_domain(this.data);
this.set_y_domain();
- this.svg.select("path").datum(this.data);
- this.svg.select("path").attr("d", this.area);
- return this.svg.select(".y.axis").call(this.y_axis);
+ this.svg.select('path').datum(this.data);
+ this.svg.select('path').attr('d', this.area);
+ return this.svg.select('.y.axis').call(this.y_axis);
};
return ContributorsMasterGraph;
@@ -252,43 +312,58 @@ export const ContributorsAuthorGraph = (function(superClass) {
};
ContributorsAuthorGraph.prototype.create_axes = function() {
- this.x_axis = d3.axisBottom()
+ this.x_axis = d3
+ .axisBottom()
.scale(this.x)
.ticks(8)
.tickFormat(dateTickFormat);
- return this.y_axis = d3.axisLeft().scale(this.y).ticks(5);
+ return (this.y_axis = d3
+ .axisLeft()
+ .scale(this.y)
+ .ticks(5));
};
ContributorsAuthorGraph.prototype.create_area = function(x, y) {
- return this.area = d3.area().x(function(d) {
- const parseDate = d3.timeParse("%Y-%m-%d");
- return x(parseDate(d));
- }).y0(this.height).y1((function(_this) {
- return function(d) {
- if (_this.data[d] != null) {
- return y(_this.data[d]);
- } else {
- return y(0);
- }
- };
- })(this));
+ return (this.area = d3
+ .area()
+ .x(function(d) {
+ const parseDate = d3.timeParse('%Y-%m-%d');
+ return x(parseDate(d));
+ })
+ .y0(this.height)
+ .y1(
+ (function(_this) {
+ return function(d) {
+ if (_this.data[d] != null) {
+ return y(_this.data[d]);
+ } else {
+ return y(0);
+ }
+ };
+ })(this),
+ ));
};
ContributorsAuthorGraph.prototype.create_svg = function() {
const persons = document.querySelectorAll('.person');
this.list_item = persons[persons.length - 1];
- this.svg = d3.select(this.list_item)
- .append("svg")
- .attr("width", this.width + this.MARGIN.left + this.MARGIN.right)
- .attr("height", this.height + this.MARGIN.top + this.MARGIN.bottom)
- .attr("class", "spark")
- .append("g")
- .attr("transform", "translate(" + this.MARGIN.left + "," + this.MARGIN.top + ")");
+ this.svg = d3
+ .select(this.list_item)
+ .append('svg')
+ .attr('width', this.width + this.MARGIN.left + this.MARGIN.right)
+ .attr('height', this.height + this.MARGIN.top + this.MARGIN.bottom)
+ .attr('class', 'spark')
+ .append('g')
+ .attr('transform', 'translate(' + this.MARGIN.left + ',' + this.MARGIN.top + ')');
return this.svg;
};
ContributorsAuthorGraph.prototype.draw_path = function(data) {
- return this.svg.append("path").datum(data).attr("class", "area-contributor").attr("d", this.area);
+ return this.svg
+ .append('path')
+ .datum(data)
+ .attr('class', 'area-contributor')
+ .attr('d', this.area);
};
ContributorsAuthorGraph.prototype.draw = function() {
@@ -304,10 +379,10 @@ export const ContributorsAuthorGraph = (function(superClass) {
ContributorsAuthorGraph.prototype.redraw = function() {
this.set_domain();
- this.svg.select("path").datum(this.dates);
- this.svg.select("path").attr("d", this.area);
- this.svg.select(".x.axis").call(this.x_axis);
- return this.svg.select(".y.axis").call(this.y_axis);
+ this.svg.select('path').datum(this.dates);
+ this.svg.select('path').attr('d', this.area);
+ this.svg.select('.x.axis').call(this.x_axis);
+ return this.svg.select('.y.axis').call(this.y_axis);
};
return ContributorsAuthorGraph;
diff --git a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_util.js b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_util.js
index cd0e2bc023c..988ae164955 100644
--- a/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_util.js
+++ b/app/assets/javascripts/pages/projects/graphs/show/stat_graph_contributors_util.js
@@ -26,12 +26,12 @@ export default {
by_author = _.toArray(by_author);
return {
total: total,
- by_author: by_author
+ by_author: by_author,
};
},
add_date: function(date, collection) {
collection[date] = {};
- return collection[date].date = date;
+ return (collection[date].date = date);
},
add_author: function(author, by_author, by_email) {
var data, normalized_email;
@@ -49,28 +49,28 @@ export default {
return this.store_deletions(entry, total, by_author);
},
store_commits: function(total, by_author) {
- this.add(total, "commits", 1);
- return this.add(by_author, "commits", 1);
+ this.add(total, 'commits', 1);
+ return this.add(by_author, 'commits', 1);
},
add: function(collection, field, value) {
if (collection[field] == null) {
collection[field] = 0;
}
- return collection[field] += value;
+ return (collection[field] += value);
},
store_additions: function(entry, total, by_author) {
if (entry.additions == null) {
entry.additions = 0;
}
- this.add(total, "additions", entry.additions);
- return this.add(by_author, "additions", entry.additions);
+ this.add(total, 'additions', entry.additions);
+ return this.add(by_author, 'additions', entry.additions);
},
store_deletions: function(entry, total, by_author) {
if (entry.deletions == null) {
entry.deletions = 0;
}
- this.add(total, "deletions", entry.deletions);
- return this.add(by_author, "deletions", entry.deletions);
+ this.add(total, 'deletions', entry.deletions);
+ return this.add(by_author, 'deletions', entry.deletions);
},
get_total_data: function(parsed_log, field) {
var log, total_data;
@@ -95,15 +95,18 @@ export default {
}
log = parsed_log.by_author;
author_data = [];
- _.each(log, (function(_this) {
- return function(log_entry) {
- var parsed_log_entry;
- parsed_log_entry = _this.parse_log_entry(log_entry, field, date_range);
- if (!_.isEmpty(parsed_log_entry.dates)) {
- return author_data.push(parsed_log_entry);
- }
- };
- })(this));
+ _.each(
+ log,
+ (function(_this) {
+ return function(log_entry) {
+ var parsed_log_entry;
+ parsed_log_entry = _this.parse_log_entry(log_entry, field, date_range);
+ if (!_.isEmpty(parsed_log_entry.dates)) {
+ return author_data.push(parsed_log_entry);
+ }
+ };
+ })(this),
+ );
return _.sortBy(author_data, function(d) {
return d[field];
}).reverse();
@@ -120,16 +123,19 @@ export default {
parsed_entry.additions = 0;
parsed_entry.deletions = 0;
- _.each(_.omit(log_entry, 'author_name', 'author_email'), (function(_this) {
- return function(value, key) {
- if (_this.in_range(value.date, date_range)) {
- parsed_entry.dates[value.date] = value[field];
- parsed_entry.commits += value.commits;
- parsed_entry.additions += value.additions;
- return parsed_entry.deletions += value.deletions;
- }
- };
- })(this));
+ _.each(
+ _.omit(log_entry, 'author_name', 'author_email'),
+ (function(_this) {
+ return function(value, key) {
+ if (_this.in_range(value.date, date_range)) {
+ parsed_entry.dates[value.date] = value[field];
+ parsed_entry.commits += value.commits;
+ parsed_entry.additions += value.additions;
+ return (parsed_entry.deletions += value.deletions);
+ }
+ };
+ })(this),
+ );
return parsed_entry;
},
in_range: function(date, date_range) {
@@ -139,5 +145,5 @@ export default {
} else {
return false;
}
- }
+ },
};
diff --git a/app/assets/javascripts/pages/projects/index.js b/app/assets/javascripts/pages/projects/index.js
index b0345b4e50d..5659e13981a 100644
--- a/app/assets/javascripts/pages/projects/index.js
+++ b/app/assets/javascripts/pages/projects/index.js
@@ -1,5 +1,5 @@
+import initDismissableCallout from '~/dismissable_callout';
import initGkeDropdowns from '~/projects/gke_cluster_dropdowns';
-import PersistentUserCallout from '../../persistent_user_callout';
import Project from './project';
import ShortcutsNavigation from '../../behaviors/shortcuts/shortcuts_navigation';
@@ -12,9 +12,7 @@ document.addEventListener('DOMContentLoaded', () => {
];
if (newClusterViews.indexOf(page) > -1) {
- const callout = document.querySelector('.gcp-signup-offer');
- if (callout) new PersistentUserCallout(callout); // eslint-disable-line no-new
-
+ initDismissableCallout('.gcp-signup-offer');
initGkeDropdowns();
}
diff --git a/app/assets/javascripts/pages/projects/init_blob.js b/app/assets/javascripts/pages/projects/init_blob.js
index bc08ccf3584..bd8afa2d5ba 100644
--- a/app/assets/javascripts/pages/projects/init_blob.js
+++ b/app/assets/javascripts/pages/projects/init_blob.js
@@ -16,7 +16,8 @@ export default () => {
);
const fileBlobPermalinkUrlElement = document.querySelector('.js-data-file-blob-permalink-url');
- const fileBlobPermalinkUrl = fileBlobPermalinkUrlElement && fileBlobPermalinkUrlElement.getAttribute('href');
+ const fileBlobPermalinkUrl =
+ fileBlobPermalinkUrlElement && fileBlobPermalinkUrlElement.getAttribute('href');
new ShortcutsNavigation(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/init_form.js b/app/assets/javascripts/pages/projects/init_form.js
index 9f20a3e4e46..019efe077f7 100644
--- a/app/assets/javascripts/pages/projects/init_form.js
+++ b/app/assets/javascripts/pages/projects/init_form.js
@@ -1,7 +1,7 @@
import ZenMode from '~/zen_mode';
import GLForm from '~/gl_form';
-export default function ($formEl) {
+export default function($formEl) {
new ZenMode(); // eslint-disable-line no-new
new GLForm($formEl); // eslint-disable-line no-new
}
diff --git a/app/assets/javascripts/pages/projects/issues/show.js b/app/assets/javascripts/pages/projects/issues/show.js
index ef65196872c..8987c8e3f47 100644
--- a/app/assets/javascripts/pages/projects/issues/show.js
+++ b/app/assets/javascripts/pages/projects/issues/show.js
@@ -5,7 +5,7 @@ import ZenMode from '~/zen_mode';
import '~/notes/index';
import initIssueableApp from '~/issue_show';
-export default function () {
+export default function() {
initIssueableApp();
new Issue(); // eslint-disable-line no-new
new ShortcutsIssuable(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/jobs/show/index.js b/app/assets/javascripts/pages/projects/jobs/show/index.js
index 3626f3ffec6..d57dbeb1242 100644
--- a/app/assets/javascripts/pages/projects/jobs/show/index.js
+++ b/app/assets/javascripts/pages/projects/jobs/show/index.js
@@ -1,3 +1,3 @@
-import initJobDetails from '~/jobs/job_details_bundle';
+import initJobDetails from '~/jobs';
document.addEventListener('DOMContentLoaded', initJobDetails);
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 5d2247f6c6d..e8b646f3f6e 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
@@ -1,72 +1,86 @@
<script>
- import _ from 'underscore';
- import axios from '~/lib/utils/axios_utils';
- import createFlash from '~/flash';
- import GlModal from '~/vue_shared/components/gl_modal.vue';
- import { s__, sprintf } from '~/locale';
- import { visitUrl } from '~/lib/utils/url_utility';
- import eventHub from '../event_hub';
+import _ from 'underscore';
+import axios from '~/lib/utils/axios_utils';
+import createFlash from '~/flash';
+import GlModal from '~/vue_shared/components/gl_modal.vue';
+import { s__, sprintf } from '~/locale';
+import { visitUrl } from '~/lib/utils/url_utility';
+import eventHub from '../event_hub';
- export default {
- components: {
- GlModal,
+export default {
+ components: {
+ GlModal,
+ },
+ props: {
+ url: {
+ type: String,
+ required: true,
},
- props: {
- url: {
- type: String,
- required: true,
- },
- labelTitle: {
- type: String,
- required: true,
- },
- labelColor: {
- type: String,
- required: true,
- },
- labelTextColor: {
- type: String,
- required: true,
- },
- groupName: {
- type: String,
- required: true,
- },
+ labelTitle: {
+ type: String,
+ required: true,
},
- computed: {
- text() {
- return sprintf(s__(`Labels|Promoting %{labelTitle} will make it available for all projects inside %{groupName}.
- Existing project labels with the same title will be merged. This action cannot be reversed.`), {
+ labelColor: {
+ type: String,
+ required: true,
+ },
+ labelTextColor: {
+ type: String,
+ required: true,
+ },
+ groupName: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ text() {
+ return sprintf(
+ s__(`Labels|Promoting %{labelTitle} will make it available for all projects inside %{groupName}.
+ Existing project labels with the same title will be merged. This action cannot be reversed.`),
+ {
labelTitle: this.labelTitle,
groupName: this.groupName,
- });
- },
- title() {
- const label = `<span
+ },
+ );
+ },
+ title() {
+ const label = `<span
class="label color-label"
style="background-color: ${this.labelColor}; color: ${this.labelTextColor};"
>${_.escape(this.labelTitle)}</span>`;
- return sprintf(s__('Labels|<span>Promote label</span> %{labelTitle} <span>to Group Label?</span>'), {
+ return sprintf(
+ s__('Labels|<span>Promote label</span> %{labelTitle} <span>to Group Label?</span>'),
+ {
labelTitle: label,
- }, false);
- },
+ },
+ false,
+ );
},
- methods: {
- onSubmit() {
- eventHub.$emit('promoteLabelModal.requestStarted', this.url);
- return axios.post(this.url, { params: { format: 'json' } })
- .then((response) => {
- eventHub.$emit('promoteLabelModal.requestFinished', { labelUrl: this.url, successful: true });
- visitUrl(response.data.url);
- })
- .catch((error) => {
- eventHub.$emit('promoteLabelModal.requestFinished', { labelUrl: this.url, successful: false });
- createFlash(error);
+ },
+ methods: {
+ onSubmit() {
+ eventHub.$emit('promoteLabelModal.requestStarted', this.url);
+ return axios
+ .post(this.url, { params: { format: 'json' } })
+ .then(response => {
+ eventHub.$emit('promoteLabelModal.requestFinished', {
+ labelUrl: this.url,
+ successful: true,
+ });
+ visitUrl(response.data.url);
+ })
+ .catch(error => {
+ eventHub.$emit('promoteLabelModal.requestFinished', {
+ labelUrl: this.url,
+ successful: false,
});
- },
+ createFlash(error);
+ });
},
- };
+ },
+};
</script>
<template>
<gl-modal
diff --git a/app/assets/javascripts/pages/projects/labels/index/index.js b/app/assets/javascripts/pages/projects/labels/index/index.js
index 03cfef61311..36cf485f33d 100644
--- a/app/assets/javascripts/pages/projects/labels/index/index.js
+++ b/app/assets/javascripts/pages/projects/labels/index/index.js
@@ -10,20 +10,24 @@ const initLabelIndex = () => {
initLabels();
const onRequestFinished = ({ labelUrl, successful }) => {
- const button = document.querySelector(`.js-promote-project-label-button[data-url="${labelUrl}"]`);
+ const button = document.querySelector(
+ `.js-promote-project-label-button[data-url="${labelUrl}"]`,
+ );
if (!successful) {
button.removeAttribute('disabled');
}
};
- const onRequestStarted = (labelUrl) => {
- const button = document.querySelector(`.js-promote-project-label-button[data-url="${labelUrl}"]`);
+ const onRequestStarted = labelUrl => {
+ const button = document.querySelector(
+ `.js-promote-project-label-button[data-url="${labelUrl}"]`,
+ );
button.setAttribute('disabled', '');
eventHub.$once('promoteLabelModal.requestFinished', onRequestFinished);
};
- const onDeleteButtonClick = (event) => {
+ const onDeleteButtonClick = event => {
const button = event.currentTarget;
const modalProps = {
labelTitle: button.dataset.labelTitle,
@@ -37,12 +41,12 @@ const initLabelIndex = () => {
};
const promoteLabelButtons = document.querySelectorAll('.js-promote-project-label-button');
- promoteLabelButtons.forEach((button) => {
+ promoteLabelButtons.forEach(button => {
button.addEventListener('click', onDeleteButtonClick);
});
eventHub.$once('promoteLabelModal.mounted', () => {
- promoteLabelButtons.forEach((button) => {
+ promoteLabelButtons.forEach(button => {
button.removeAttribute('disabled');
});
});
diff --git a/app/assets/javascripts/pages/projects/network/network.js b/app/assets/javascripts/pages/projects/network/network.js
index 70fbb3f301c..226d63f05c4 100644
--- a/app/assets/javascripts/pages/projects/network/network.js
+++ b/app/assets/javascripts/pages/projects/network/network.js
@@ -6,13 +6,15 @@ import BranchGraph from '../../../network/branch_graph';
export default (function() {
function Network(opts) {
var vph;
- $("#filter_ref").click(function() {
- return $(this).closest('form').submit();
+ $('#filter_ref').click(function() {
+ return $(this)
+ .closest('form')
+ .submit();
});
- this.branch_graph = new BranchGraph($(".network-graph"), opts);
+ this.branch_graph = new BranchGraph($('.network-graph'), opts);
vph = $(window).height() - 250;
$('.network-graph').css({
- 'height': vph + 'px'
+ height: vph + 'px',
});
}
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
index 544360dcd51..6197dc8a9db 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
@@ -1,12 +1,16 @@
import Vue from 'vue';
import PipelineSchedulesCallout from '../shared/components/pipeline_schedules_callout.vue';
-document.addEventListener('DOMContentLoaded', () => new Vue({
- el: '#pipeline-schedules-callout',
- components: {
- 'pipeline-schedules-callout': PipelineSchedulesCallout,
- },
- render(createElement) {
- return createElement('pipeline-schedules-callout');
- },
-}));
+document.addEventListener(
+ 'DOMContentLoaded',
+ () =>
+ new Vue({
+ el: '#pipeline-schedules-callout',
+ components: {
+ 'pipeline-schedules-callout': PipelineSchedulesCallout,
+ },
+ render(createElement) {
+ return createElement('pipeline-schedules-callout');
+ },
+ }),
+);
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 ef53d67e7cb..ab6f42d928c 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
@@ -1,63 +1,63 @@
<script>
- import _ from 'underscore';
+import _ from 'underscore';
- export default {
- props: {
- initialCronInterval: {
- type: String,
- required: false,
- default: '',
- },
- },
- data() {
- return {
- inputNameAttribute: 'schedule[cron]',
- cronInterval: this.initialCronInterval,
- cronIntervalPresets: {
- everyDay: '0 4 * * *',
- everyWeek: '0 4 * * 0',
- everyMonth: '0 4 1 * *',
- },
- cronSyntaxUrl: 'https://en.wikipedia.org/wiki/Cron',
- customInputEnabled: false,
- };
+export default {
+ props: {
+ initialCronInterval: {
+ type: String,
+ required: false,
+ default: '',
},
- computed: {
- intervalIsPreset() {
- return _.contains(this.cronIntervalPresets, this.cronInterval);
- },
- // The text input is editable when there's a custom interval, or when it's
- // a preset interval and the user clicks the 'custom' radio button
- isEditable() {
- return !!(this.customInputEnabled || !this.intervalIsPreset);
+ },
+ data() {
+ return {
+ inputNameAttribute: 'schedule[cron]',
+ cronInterval: this.initialCronInterval,
+ cronIntervalPresets: {
+ everyDay: '0 4 * * *',
+ everyWeek: '0 4 * * 0',
+ everyMonth: '0 4 1 * *',
},
+ cronSyntaxUrl: 'https://en.wikipedia.org/wiki/Cron',
+ customInputEnabled: false,
+ };
+ },
+ computed: {
+ intervalIsPreset() {
+ return _.contains(this.cronIntervalPresets, this.cronInterval);
},
- watch: {
- cronInterval() {
- // updates field validation state when model changes, as
- // glFieldError only updates on input.
- this.$nextTick(() => {
- gl.pipelineScheduleFieldErrors.updateFormValidityState();
- });
- },
+ // The text input is editable when there's a custom interval, or when it's
+ // a preset interval and the user clicks the 'custom' radio button
+ isEditable() {
+ return !!(this.customInputEnabled || !this.intervalIsPreset);
},
- created() {
- if (this.intervalIsPreset) {
- this.enableCustomInput = false;
- }
+ },
+ watch: {
+ cronInterval() {
+ // updates field validation state when model changes, as
+ // glFieldError only updates on input.
+ this.$nextTick(() => {
+ gl.pipelineScheduleFieldErrors.updateFormValidityState();
+ });
},
- methods: {
- toggleCustomInput(shouldEnable) {
- this.customInputEnabled = shouldEnable;
+ },
+ created() {
+ if (this.intervalIsPreset) {
+ this.enableCustomInput = false;
+ }
+ },
+ methods: {
+ toggleCustomInput(shouldEnable) {
+ this.customInputEnabled = shouldEnable;
- if (shouldEnable) {
- // We need to change the value so other radios don't remain selected
- // because the model (cronInterval) hasn't changed. The server trims it.
- this.cronInterval = `${this.cronInterval} `;
- }
- },
+ if (shouldEnable) {
+ // We need to change the value so other radios don't remain selected
+ // because the model (cronInterval) hasn't changed. The server trims it.
+ this.cronInterval = `${this.cronInterval} `;
+ }
},
- };
+ },
+};
</script>
<template>
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 77508e62cef..33fc2420e4d 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
@@ -1,31 +1,31 @@
<script>
- import Vue from 'vue';
- import Cookies from 'js-cookie';
- import Translate from '../../../../../vue_shared/translate';
- import illustrationSvg from '../icons/intro_illustration.svg';
+import Vue from 'vue';
+import Cookies from 'js-cookie';
+import Translate from '../../../../../vue_shared/translate';
+import illustrationSvg from '../icons/intro_illustration.svg';
- Vue.use(Translate);
+Vue.use(Translate);
- const cookieKey = 'pipeline_schedules_callout_dismissed';
+const cookieKey = 'pipeline_schedules_callout_dismissed';
- export default {
- name: 'PipelineSchedulesCallout',
- data() {
- return {
- docsUrl: document.getElementById('pipeline-schedules-callout').dataset.docsUrl,
- calloutDismissed: Cookies.get(cookieKey) === 'true',
- };
+export default {
+ name: 'PipelineSchedulesCallout',
+ data() {
+ return {
+ docsUrl: document.getElementById('pipeline-schedules-callout').dataset.docsUrl,
+ calloutDismissed: Cookies.get(cookieKey) === 'true',
+ };
+ },
+ created() {
+ this.illustrationSvg = illustrationSvg;
+ },
+ methods: {
+ dismissCallout() {
+ this.calloutDismissed = true;
+ Cookies.set(cookieKey, this.calloutDismissed, { expires: 365 });
},
- created() {
- this.illustrationSvg = illustrationSvg;
- },
- methods: {
- dismissCallout() {
- this.calloutDismissed = true;
- Cookies.set(cookieKey, this.calloutDismissed, { expires: 365 });
- },
- },
- };
+ },
+};
</script>
<template>
<div
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/target_branch_dropdown.js b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/target_branch_dropdown.js
index 4ef0d11dd36..0057700c1b3 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/target_branch_dropdown.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/target_branch_dropdown.js
@@ -26,8 +26,7 @@ export default class TargetBranchDropdown {
}
formatBranchesList() {
- return this.$dropdown.data('data')
- .map(val => ({ name: val }));
+ return this.$dropdown.data('data').map(val => ({ name: val }));
}
setDropdownToggle() {
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
index c3ac54733a3..4d494efef6c 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
@@ -11,7 +11,9 @@ Vue.use(Translate);
function initIntervalPatternInput() {
const intervalPatternMount = document.getElementById('interval-pattern-input');
- const initialCronInterval = intervalPatternMount ? intervalPatternMount.dataset.initialInterval : '';
+ const initialCronInterval = intervalPatternMount
+ ? intervalPatternMount.dataset.initialInterval
+ : '';
return new Vue({
el: intervalPatternMount,
diff --git a/app/assets/javascripts/pages/projects/pipelines/charts/index.js b/app/assets/javascripts/pages/projects/pipelines/charts/index.js
index 07b6992eba1..48353f3b4ef 100644
--- a/app/assets/javascripts/pages/projects/pipelines/charts/index.js
+++ b/app/assets/javascripts/pages/projects/pipelines/charts/index.js
@@ -7,26 +7,29 @@ const options = {
maintainAspectRatio: false,
};
-const buildChart = (chartScope) => {
+const buildChart = chartScope => {
const data = {
labels: chartScope.labels,
- datasets: [{
- fillColor: '#707070',
- strokeColor: '#707070',
- pointColor: '#707070',
- pointStrokeColor: '#EEE',
- data: chartScope.totalValues,
- },
- {
- fillColor: '#1aaa55',
- strokeColor: '#1aaa55',
- pointColor: '#1aaa55',
- pointStrokeColor: '#fff',
- data: chartScope.successValues,
- },
+ datasets: [
+ {
+ fillColor: '#707070',
+ strokeColor: '#707070',
+ pointColor: '#707070',
+ pointStrokeColor: '#EEE',
+ data: chartScope.totalValues,
+ },
+ {
+ fillColor: '#1aaa55',
+ strokeColor: '#1aaa55',
+ pointColor: '#1aaa55',
+ pointStrokeColor: '#fff',
+ data: chartScope.successValues,
+ },
],
};
- const ctx = $(`#${chartScope.scope}Chart`).get(0).getContext('2d');
+ const ctx = $(`#${chartScope.scope}Chart`)
+ .get(0)
+ .getContext('2d');
new Chart(ctx).Line(data, options);
};
@@ -36,14 +39,16 @@ document.addEventListener('DOMContentLoaded', () => {
const chartsData = JSON.parse(document.getElementById('pipelinesChartsData').innerHTML);
const data = {
labels: chartTimesData.labels,
- datasets: [{
- fillColor: 'rgba(220,220,220,0.5)',
- strokeColor: 'rgba(220,220,220,1)',
- barStrokeWidth: 1,
- barValueSpacing: 1,
- barDatasetSpacing: 1,
- data: chartTimesData.values,
- }],
+ datasets: [
+ {
+ fillColor: 'rgba(220,220,220,0.5)',
+ strokeColor: 'rgba(220,220,220,1)',
+ barStrokeWidth: 1,
+ barValueSpacing: 1,
+ barDatasetSpacing: 1,
+ data: chartTimesData.values,
+ },
+ ],
};
if (window.innerWidth < 768) {
@@ -51,7 +56,11 @@ document.addEventListener('DOMContentLoaded', () => {
options.scaleFontSize = 8;
}
- new Chart($('#build_timesChart').get(0).getContext('2d')).Bar(data, options);
+ new Chart(
+ $('#build_timesChart')
+ .get(0)
+ .getContext('2d'),
+ ).Bar(data, options);
chartsData.forEach(scope => buildChart(scope));
});
diff --git a/app/assets/javascripts/pages/projects/pipelines/index/index.js b/app/assets/javascripts/pages/projects/pipelines/index/index.js
index a84e2790680..fc337a7609b 100644
--- a/app/assets/javascripts/pages/projects/pipelines/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipelines/index/index.js
@@ -6,35 +6,39 @@ import { convertPermissionToBoolean } from '../../../../lib/utils/common_utils';
Vue.use(Translate);
-document.addEventListener('DOMContentLoaded', () => new Vue({
- el: '#pipelines-list-vue',
- components: {
- pipelinesComponent,
- },
- data() {
- return {
- store: new PipelinesStore(),
- };
- },
- created() {
- this.dataset = document.querySelector(this.$options.el).dataset;
- },
- render(createElement) {
- return createElement('pipelines-component', {
- props: {
- store: this.store,
- endpoint: this.dataset.endpoint,
- helpPagePath: this.dataset.helpPagePath,
- emptyStateSvgPath: this.dataset.emptyStateSvgPath,
- errorStateSvgPath: this.dataset.errorStateSvgPath,
- noPipelinesSvgPath: this.dataset.noPipelinesSvgPath,
- autoDevopsPath: this.dataset.helpAutoDevopsPath,
- newPipelinePath: this.dataset.newPipelinePath,
- canCreatePipeline: convertPermissionToBoolean(this.dataset.canCreatePipeline),
- hasGitlabCi: convertPermissionToBoolean(this.dataset.hasGitlabCi),
- ciLintPath: this.dataset.ciLintPath,
- resetCachePath: this.dataset.resetCachePath,
+document.addEventListener(
+ 'DOMContentLoaded',
+ () =>
+ new Vue({
+ el: '#pipelines-list-vue',
+ components: {
+ pipelinesComponent,
},
- });
- },
-}));
+ data() {
+ return {
+ store: new PipelinesStore(),
+ };
+ },
+ created() {
+ this.dataset = document.querySelector(this.$options.el).dataset;
+ },
+ render(createElement) {
+ return createElement('pipelines-component', {
+ props: {
+ store: this.store,
+ endpoint: this.dataset.endpoint,
+ helpPagePath: this.dataset.helpPagePath,
+ emptyStateSvgPath: this.dataset.emptyStateSvgPath,
+ errorStateSvgPath: this.dataset.errorStateSvgPath,
+ noPipelinesSvgPath: this.dataset.noPipelinesSvgPath,
+ autoDevopsPath: this.dataset.helpAutoDevopsPath,
+ newPipelinePath: this.dataset.newPipelinePath,
+ canCreatePipeline: convertPermissionToBoolean(this.dataset.canCreatePipeline),
+ hasGitlabCi: convertPermissionToBoolean(this.dataset.hasGitlabCi),
+ ciLintPath: this.dataset.ciLintPath,
+ resetCachePath: this.dataset.resetCachePath,
+ },
+ });
+ },
+ }),
+);
diff --git a/app/assets/javascripts/pages/projects/pipelines/init_pipelines.js b/app/assets/javascripts/pages/projects/pipelines/init_pipelines.js
index 94dfeb96e8c..ba4ae04ab3d 100644
--- a/app/assets/javascripts/pages/projects/pipelines/init_pipelines.js
+++ b/app/assets/javascripts/pages/projects/pipelines/init_pipelines.js
@@ -2,9 +2,12 @@ import Pipelines from '~/pipelines';
export default () => {
const { controllerAction } = document.querySelector('.js-pipeline-container').dataset;
- const pipelineStatusUrl = `${document.querySelector('.js-pipeline-tab-link a').getAttribute('href')}/status.json`;
+ const pipelineStatusUrl = `${document
+ .querySelector('.js-pipeline-tab-link a')
+ .getAttribute('href')}/status.json`;
- new Pipelines({ // eslint-disable-line no-new
+ // eslint-disable-next-line no-new
+ new Pipelines({
initTabs: true,
pipelineStatusUrl,
tabsOptions: {
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 06101290f6c..dced839c883 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
@@ -1,73 +1,71 @@
<script>
- import projectFeatureToggle from '../../../../../vue_shared/components/toggle_button.vue';
+import projectFeatureToggle from '../../../../../vue_shared/components/toggle_button.vue';
- export default {
- components: {
- projectFeatureToggle,
- },
+export default {
+ components: {
+ projectFeatureToggle,
+ },
- model: {
- prop: 'value',
- event: 'change',
- },
+ model: {
+ prop: 'value',
+ event: 'change',
+ },
- props: {
- name: {
- type: String,
- required: false,
- default: '',
- },
- options: {
- type: Array,
- required: false,
- default: () => [],
- },
- value: {
- type: Number,
- required: false,
- default: 0,
- },
- disabledInput: {
- type: Boolean,
- required: false,
- default: false,
- },
+ props: {
+ name: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ options: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ value: {
+ type: Number,
+ required: false,
+ default: 0,
},
+ disabledInput: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
- computed: {
- featureEnabled() {
- return this.value !== 0;
- },
+ computed: {
+ featureEnabled() {
+ return this.value !== 0;
+ },
- displayOptions() {
- if (this.featureEnabled) {
- return this.options;
- }
- return [
- [0, 'Enable feature to choose access level'],
- ];
- },
+ displayOptions() {
+ if (this.featureEnabled) {
+ return this.options;
+ }
+ return [[0, 'Enable feature to choose access level']];
+ },
- displaySelectInput() {
- return this.disabledInput || !this.featureEnabled || this.displayOptions.length < 2;
- },
+ displaySelectInput() {
+ return this.disabledInput || !this.featureEnabled || this.displayOptions.length < 2;
},
+ },
- methods: {
- toggleFeature(featureEnabled) {
- if (featureEnabled === false || this.options.length < 1) {
- this.$emit('change', 0);
- } else {
- const [firstOptionValue] = this.options[this.options.length - 1];
- this.$emit('change', firstOptionValue);
- }
- },
+ methods: {
+ toggleFeature(featureEnabled) {
+ if (featureEnabled === false || this.options.length < 1) {
+ this.$emit('change', 0);
+ } else {
+ const [firstOptionValue] = this.options[this.options.length - 1];
+ this.$emit('change', firstOptionValue);
+ }
+ },
- selectOption(e) {
- this.$emit('change', Number(e.target.value));
- },
+ selectOption(e) {
+ this.$emit('change', Number(e.target.value));
},
- };
+ },
+};
</script>
<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 83437363af5..898d605463f 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
@@ -1,23 +1,23 @@
<script>
- export default {
- props: {
- label: {
- type: String,
- required: false,
- default: null,
- },
- helpPath: {
- type: String,
- required: false,
- default: null,
- },
- helpText: {
- type: String,
- required: false,
- default: null,
- },
+export default {
+ props: {
+ label: {
+ type: String,
+ required: false,
+ default: null,
},
- };
+ helpPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ helpText: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/constants.js b/app/assets/javascripts/pages/projects/shared/permissions/constants.js
index ce47562f259..bc5c29d12b5 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/constants.js
+++ b/app/assets/javascripts/pages/projects/shared/permissions/constants.js
@@ -5,7 +5,9 @@ export const visibilityOptions = {
};
export const visibilityLevelDescriptions = {
- [visibilityOptions.PRIVATE]: 'The project is accessible only by members of the project. Access must be granted explicitly to each user.',
+ [visibilityOptions.PRIVATE]:
+ 'The project is accessible only by members of the project. Access must be granted explicitly to each user.',
[visibilityOptions.INTERNAL]: 'The project can be accessed by any user who is logged in.',
- [visibilityOptions.PUBLIC]: 'The project can be accessed by anyone, regardless of authentication.',
+ [visibilityOptions.PUBLIC]:
+ 'The project can be accessed by anyone, regardless of authentication.',
};
diff --git a/app/assets/javascripts/pages/projects/shared/project_avatar.js b/app/assets/javascripts/pages/projects/shared/project_avatar.js
index 447877752fe..1e69ecb481d 100644
--- a/app/assets/javascripts/pages/projects/shared/project_avatar.js
+++ b/app/assets/javascripts/pages/projects/shared/project_avatar.js
@@ -8,8 +8,9 @@ export default function projectAvatar() {
$('.js-project-avatar-input').bind('change', function onClickAvatarInput() {
const form = $(this).closest('form');
- // eslint-disable-next-line no-useless-escape
- const filename = $(this).val().replace(/^.*[\\\/]/, '');
+ 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/index.js b/app/assets/javascripts/pages/projects/wikis/index.js
index c2629090f01..f5fd84d69ac 100644
--- a/app/assets/javascripts/pages/projects/wikis/index.js
+++ b/app/assets/javascripts/pages/projects/wikis/index.js
@@ -21,7 +21,8 @@ document.addEventListener('DOMContentLoaded', () => {
const { deleteWikiUrl, pageTitle } = deleteWikiModalWrapperEl.dataset;
- new Vue({ // eslint-disable-line no-new
+ // eslint-disable-next-line no-new
+ new Vue({
el: deleteWikiModalWrapperEl,
data: {
deleteWikiUrl: '',
diff --git a/app/assets/javascripts/pages/root/index.js b/app/assets/javascripts/pages/root/index.js
deleted file mode 100644
index 09f8185d3b5..00000000000
--- a/app/assets/javascripts/pages/root/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// if the "projects dashboard" is a user's default dashboard, when they visit the
-// instance root index, the dashboard will be served by the root controller instead
-// of a dashboard controller. The root index redirects for all other default dashboards.
-
-import '../dashboard/projects/index';
diff --git a/app/assets/javascripts/pages/search/show/search.js b/app/assets/javascripts/pages/search/show/search.js
index e3e0ab91993..0c896c8599e 100644
--- a/app/assets/javascripts/pages/search/show/search.js
+++ b/app/assets/javascripts/pages/search/show/search.js
@@ -22,7 +22,7 @@ export default class Search {
fields: ['full_name'],
},
data(term, callback) {
- return Api.groups(term, {}, (data) => {
+ return Api.groups(term, {}, data => {
data.unshift({
full_name: 'Any',
});
@@ -37,7 +37,7 @@ export default class Search {
return obj.full_name;
},
toggleLabel(obj) {
- return `${($groupDropdown.data('defaultLabel'))} ${obj.full_name}`;
+ return `${$groupDropdown.data('defaultLabel')} ${obj.full_name}`;
},
clicked: () => Search.submitSearch(),
});
@@ -52,7 +52,7 @@ export default class Search {
},
data: (term, callback) => {
this.getProjectsData(term)
- .then((data) => {
+ .then(data => {
data.unshift({
name_with_namespace: 'Any',
});
@@ -70,7 +70,7 @@ export default class Search {
return obj.name_with_namespace;
},
toggleLabel(obj) {
- return `${($projectDropdown.data('defaultLabel'))} ${obj.name_with_namespace}`;
+ return `${$projectDropdown.data('defaultLabel')} ${obj.name_with_namespace}`;
},
clicked: () => Search.submitSearch(),
});
@@ -99,17 +99,24 @@ export default class Search {
}
clearSearchField() {
- return $(this.searchInput).val('').trigger('keyup').focus();
+ return $(this.searchInput)
+ .val('')
+ .trigger('keyup')
+ .focus();
}
getProjectsData(term) {
- return new Promise((resolve) => {
+ return new Promise(resolve => {
if (this.groupId) {
Api.groupProjects(this.groupId, term, {}, resolve);
} else {
- Api.projects(term, {
- order_by: 'id',
- }, resolve);
+ Api.projects(
+ term,
+ {
+ order_by: 'id',
+ },
+ resolve,
+ );
}
});
}
diff --git a/app/assets/javascripts/pages/sessions/new/signin_tabs_memoizer.js b/app/assets/javascripts/pages/sessions/new/signin_tabs_memoizer.js
index 1e7c29aefaa..2b8f1e8b0ef 100644
--- a/app/assets/javascripts/pages/sessions/new/signin_tabs_memoizer.js
+++ b/app/assets/javascripts/pages/sessions/new/signin_tabs_memoizer.js
@@ -20,7 +20,7 @@ export default class SigninTabsMemoizer {
bootstrap() {
const tabs = document.querySelectorAll(this.tabSelector);
if (tabs.length > 0) {
- tabs[0].addEventListener('click', (e) => {
+ tabs[0].addEventListener('click', e => {
if (e.target && e.target.nodeName === 'A') {
const anchorName = e.target.getAttribute('href');
this.saveData(anchorName);
diff --git a/app/assets/javascripts/pages/sessions/new/username_validator.js b/app/assets/javascripts/pages/sessions/new/username_validator.js
index d621f988d86..7a41805bada 100644
--- a/app/assets/javascripts/pages/sessions/new/username_validator.js
+++ b/app/assets/javascripts/pages/sessions/new/username_validator.js
@@ -22,10 +22,10 @@ export default class UsernameValidator {
available: false,
valid: false,
pending: false,
- empty: true
+ empty: true,
};
- const debounceTimeout = _.debounce((username) => {
+ const debounceTimeout = _.debounce(username => {
this.validateUsername(username);
}, debounceTimeoutDuration);
@@ -81,7 +81,8 @@ export default class UsernameValidator {
this.state.pending = true;
this.state.available = false;
this.renderState();
- axios.get(`${gon.relative_url_root}/users/${username}/exists`)
+ axios
+ .get(`${gon.relative_url_root}/users/${username}/exists`)
.then(({ data }) => this.setAvailabilityState(data.exists))
.catch(() => flash(__('An error occurred while validating username')));
}
@@ -100,8 +101,7 @@ export default class UsernameValidator {
clearFieldValidationState() {
this.inputElement.siblings('p').hide();
- this.inputElement.removeClass(invalidInputClass)
- .removeClass(successInputClass);
+ this.inputElement.removeClass(invalidInputClass).removeClass(successInputClass);
}
setUnavailableState() {
diff --git a/app/assets/javascripts/pages/users/index.js b/app/assets/javascripts/pages/users/index.js
index 6b1626b0161..a191df00dfa 100644
--- a/app/assets/javascripts/pages/users/index.js
+++ b/app/assets/javascripts/pages/users/index.js
@@ -13,10 +13,12 @@ function initUserProfile(action) {
new UserTabs({ parentEl: '.user-profile', action });
// hide project limit message
- $('.hide-project-limit-message').on('click', (e) => {
+ $('.hide-project-limit-message').on('click', e => {
e.preventDefault();
Cookies.set('hide_project_limit_message', 'false');
- $(this).parents('.project-limit-message').remove();
+ $(this)
+ .parents('.project-limit-message')
+ .remove();
});
}
diff --git a/app/assets/javascripts/pages/users/user_overview_block.js b/app/assets/javascripts/pages/users/user_overview_block.js
index 0009419cd0c..2ed177be558 100644
--- a/app/assets/javascripts/pages/users/user_overview_block.js
+++ b/app/assets/javascripts/pages/users/user_overview_block.js
@@ -1,10 +1,15 @@
import axios from '~/lib/utils/axios_utils';
+const DEFAULT_LIMIT = 20;
+
export default class UserOverviewBlock {
constructor(options = {}) {
this.container = options.container;
this.url = options.url;
- this.limit = options.limit || 20;
+ this.requestParams = {
+ limit: DEFAULT_LIMIT,
+ ...options.requestParams,
+ };
this.loadData();
}
@@ -15,9 +20,7 @@ export default class UserOverviewBlock {
axios
.get(this.url, {
- params: {
- limit: this.limit,
- },
+ params: this.requestParams,
})
.then(({ data }) => this.render(data))
.catch(() => loadingEl.classList.add('hide'));
@@ -34,7 +37,9 @@ export default class UserOverviewBlock {
if (count && count > 0) {
document.querySelector(`${this.container} .js-view-all`).classList.remove('hide');
} else {
- document.querySelector(`${this.container} .nothing-here-block`).classList.add('text-left', 'p-0');
+ document
+ .querySelector(`${this.container} .nothing-here-block`)
+ .classList.add('text-left', 'p-0');
}
loadingEl.classList.add('hide');
diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js
index 23b0348a99f..04bcb16f036 100644
--- a/app/assets/javascripts/pages/users/user_tabs.js
+++ b/app/assets/javascripts/pages/users/user_tabs.js
@@ -170,7 +170,7 @@ export default class UserTabs {
this.loadActivityCalendar('activity');
// eslint-disable-next-line no-new
- new Activities();
+ new Activities('#activity');
this.loaded.activity = true;
}
@@ -182,18 +182,22 @@ export default class UserTabs {
this.loadActivityCalendar('overview');
- UserTabs.renderMostRecentBlocks('#js-overview .activities-block', 5);
- UserTabs.renderMostRecentBlocks('#js-overview .projects-block', 10);
+ UserTabs.renderMostRecentBlocks('#js-overview .activities-block', {
+ requestParams: { limit: 5 },
+ });
+ UserTabs.renderMostRecentBlocks('#js-overview .projects-block', {
+ requestParams: { limit: 10, skip_pagination: true },
+ });
this.loaded.overview = true;
}
- static renderMostRecentBlocks(container, limit) {
+ static renderMostRecentBlocks(container, options) {
// eslint-disable-next-line no-new
new UserOverviewBlock({
container,
url: $(`${container} .overview-content-list`).data('href'),
- limit,
+ ...options,
});
}
@@ -216,7 +220,12 @@ export default class UserTabs {
let calendarHint = '';
if (action === 'activity') {
- calendarHint = sprintf(__('Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})'), { utcFormatted });
+ 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.');
}
@@ -224,7 +233,15 @@ export default class UserTabs {
$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);
+ 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.')));
}
diff --git a/app/assets/javascripts/pdf/index.vue b/app/assets/javascripts/pdf/index.vue
index 2f480ecdc69..7b079fe02d9 100644
--- a/app/assets/javascripts/pdf/index.vue
+++ b/app/assets/javascripts/pdf/index.vue
@@ -1,57 +1,58 @@
<script>
- import pdfjsLib from 'vendor/pdf';
- import workerSrc from 'vendor/pdf.worker.min';
+import pdfjsLib from 'vendor/pdf';
+import workerSrc from 'vendor/pdf.worker.min';
- import page from './page/index.vue';
+import page from './page/index.vue';
- export default {
- components: { page },
- props: {
- pdf: {
- type: [String, Uint8Array],
- required: true,
- },
+export default {
+ components: { page },
+ props: {
+ pdf: {
+ type: [String, Uint8Array],
+ required: true,
},
- data() {
- return {
- loading: false,
- pages: [],
- };
+ },
+ data() {
+ return {
+ loading: false,
+ pages: [],
+ };
+ },
+ computed: {
+ document() {
+ return typeof this.pdf === 'string' ? this.pdf : { data: this.pdf };
},
- computed: {
- document() {
- return typeof this.pdf === 'string' ? this.pdf : { data: this.pdf };
- },
- hasPDF() {
- return this.pdf && this.pdf.length > 0;
- },
+ hasPDF() {
+ return this.pdf && this.pdf.length > 0;
},
- watch: { pdf: 'load' },
- mounted() {
- pdfjsLib.PDFJS.workerSrc = workerSrc;
- if (this.hasPDF) this.load();
+ },
+ watch: { pdf: 'load' },
+ mounted() {
+ pdfjsLib.PDFJS.workerSrc = workerSrc;
+ if (this.hasPDF) this.load();
+ },
+ methods: {
+ load() {
+ this.pages = [];
+ return pdfjsLib
+ .getDocument(this.document)
+ .then(this.renderPages)
+ .then(() => this.$emit('pdflabload'))
+ .catch(error => this.$emit('pdflaberror', error))
+ .then(() => {
+ this.loading = false;
+ });
},
- methods: {
- load() {
- this.pages = [];
- return pdfjsLib.getDocument(this.document)
- .then(this.renderPages)
- .then(() => this.$emit('pdflabload'))
- .catch(error => this.$emit('pdflaberror', error))
- .then(() => { this.loading = false; });
- },
- renderPages(pdf) {
- const pagePromises = [];
- this.loading = true;
- for (let num = 1; num <= pdf.numPages; num += 1) {
- pagePromises.push(
- pdf.getPage(num).then(p => this.pages.push(p)),
- );
- }
- return Promise.all(pagePromises);
- },
+ renderPages(pdf) {
+ const pagePromises = [];
+ this.loading = true;
+ for (let num = 1; num <= pdf.numPages; num += 1) {
+ pagePromises.push(pdf.getPage(num).then(p => this.pages.push(p)));
+ }
+ return Promise.all(pagePromises);
},
- };
+ },
+};
</script>
<template>
@@ -69,9 +70,9 @@
</template>
<style>
- .pdf-viewer {
- background: url('./assets/img/bg.gif');
- display: flex;
- flex-flow: column nowrap;
- }
+.pdf-viewer {
+ background: url('./assets/img/bg.gif');
+ display: flex;
+ flex-flow: column nowrap;
+}
</style>
diff --git a/app/assets/javascripts/pdf/page/index.vue b/app/assets/javascripts/pdf/page/index.vue
index 9f06833d560..96aadf41653 100644
--- a/app/assets/javascripts/pdf/page/index.vue
+++ b/app/assets/javascripts/pdf/page/index.vue
@@ -1,44 +1,47 @@
<script>
- export default {
- props: {
- page: {
- type: Object,
- required: true,
- },
- number: {
- type: Number,
- required: true,
- },
+export default {
+ props: {
+ page: {
+ type: Object,
+ required: true,
},
- data() {
- return {
- scale: 4,
- rendering: false,
- };
+ number: {
+ type: Number,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ scale: 4,
+ rendering: false,
+ };
+ },
+ computed: {
+ viewport() {
+ return this.page.getViewport(this.scale);
},
- computed: {
- viewport() {
- return this.page.getViewport(this.scale);
- },
- context() {
- return this.$refs.canvas.getContext('2d');
- },
- renderContext() {
- return {
- canvasContext: this.context,
- viewport: this.viewport,
- };
- },
+ context() {
+ return this.$refs.canvas.getContext('2d');
},
- mounted() {
- this.$refs.canvas.height = this.viewport.height;
- this.$refs.canvas.width = this.viewport.width;
- this.rendering = true;
- this.page.render(this.renderContext)
- .then(() => { this.rendering = false; })
- .catch(error => this.$emit('pdflaberror', error));
+ renderContext() {
+ return {
+ canvasContext: this.context,
+ viewport: this.viewport,
+ };
},
- };
+ },
+ mounted() {
+ this.$refs.canvas.height = this.viewport.height;
+ this.$refs.canvas.width = this.viewport.width;
+ this.rendering = true;
+ this.page
+ .render(this.renderContext)
+ .then(() => {
+ this.rendering = false;
+ })
+ .catch(error => this.$emit('pdflaberror', error));
+ },
+};
</script>
<template>
@@ -51,20 +54,20 @@
</template>
<style>
- .pdf-page {
- margin: 8px auto 0 auto;
- border-top: 1px #ddd solid;
- border-bottom: 1px #ddd solid;
- width: 100%;
- }
+.pdf-page {
+ margin: 8px auto 0 auto;
+ border-top: 1px #ddd solid;
+ border-bottom: 1px #ddd solid;
+ width: 100%;
+}
- .pdf-page:first-child {
- margin-top: 0px;
- border-top: 0px;
- }
+.pdf-page:first-child {
+ margin-top: 0px;
+ border-top: 0px;
+}
- .pdf-page:last-child {
- margin-bottom: 0px;
- border-bottom: 0px;
- }
+.pdf-page:last-child {
+ margin-bottom: 0px;
+ border-bottom: 0px;
+}
</style>
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 1522e2227e4..300d453c174 100644
--- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
+++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
@@ -1,5 +1,6 @@
<script>
import $ from 'jquery';
+import { glEmojiTag } from '~/emoji';
import detailedMetric from './detailed_metric.vue';
import requestSelector from './request_selector.vue';
@@ -64,6 +65,16 @@ export default {
lineProfileModal() {
return $('#modal-peek-line-profile');
},
+ hasHost() {
+ return this.currentRequest && this.currentRequest.details && this.currentRequest.details.host;
+ },
+ birdEmoji() {
+ if (this.hasHost && this.currentRequest.details.host.canary) {
+ return glEmojiTag('baby_chick');
+ }
+
+ return '';
+ },
},
mounted() {
this.currentRequest = this.requestId;
@@ -93,9 +104,11 @@ export default {
class="view"
>
<span
- v-if="currentRequest.details"
+ v-if="hasHost"
class="current-host"
+ :class="{ 'canary' : currentRequest.details.host.canary }"
>
+ <span v-html="birdEmoji"></span>
{{ currentRequest.details.host.hostname }}
</span>
</div>
diff --git a/app/assets/javascripts/performance_bar/components/simple_metric.vue b/app/assets/javascripts/performance_bar/components/simple_metric.vue
index 760ea8fe1e6..7a558558c4d 100644
--- a/app/assets/javascripts/performance_bar/components/simple_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/simple_metric.vue
@@ -1,29 +1,29 @@
<script>
- export default {
- props: {
- currentRequest: {
- type: Object,
- required: true,
- },
- metric: {
- type: String,
- required: true,
- },
+export default {
+ props: {
+ currentRequest: {
+ type: Object,
+ required: true,
},
- computed: {
- duration() {
- return (
- this.currentRequest.details[this.metric] &&
- this.currentRequest.details[this.metric].duration
- );
- },
- calls() {
- return (
- this.currentRequest.details[this.metric] && this.currentRequest.details[this.metric].calls
- );
- },
+ metric: {
+ type: String,
+ required: true,
},
- };
+ },
+ computed: {
+ duration() {
+ return (
+ this.currentRequest.details[this.metric] &&
+ this.currentRequest.details[this.metric].duration
+ );
+ },
+ calls() {
+ return (
+ this.currentRequest.details[this.metric] && this.currentRequest.details[this.metric].calls
+ );
+ },
+ },
+};
</script>
<template>
<div
diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js
index 6e5ef0ac0b2..29bfb7ee5df 100644
--- a/app/assets/javascripts/performance_bar/index.js
+++ b/app/assets/javascripts/performance_bar/index.js
@@ -9,8 +9,7 @@ export default ({ container }) =>
performanceBarApp: () => import('./components/performance_bar_app.vue'),
},
data() {
- const performanceBarData = document.querySelector(this.$options.el)
- .dataset;
+ const performanceBarData = document.querySelector(this.$options.el).dataset;
const store = new PerformanceBarStore();
return {
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 60d9ba62570..3a496fa2ed8 100644
--- a/app/assets/javascripts/performance_bar/services/performance_bar_service.js
+++ b/app/assets/javascripts/performance_bar/services/performance_bar_service.js
@@ -11,8 +11,10 @@ export default class PerformanceBarService {
static registerInterceptor(peekUrl, callback) {
const interceptor = response => {
- const [fireCallback, requestId, requestUrl] =
- PerformanceBarService.callbackParams(response, peekUrl);
+ const [fireCallback, requestId, requestUrl] = PerformanceBarService.callbackParams(
+ response,
+ peekUrl,
+ );
if (fireCallback) {
callback(requestId, requestUrl);
@@ -30,10 +32,7 @@ export default class PerformanceBarService {
static removeInterceptor(interceptor) {
axios.interceptors.response.eject(interceptor);
- Vue.http.interceptors = _.without(
- Vue.http.interceptors,
- vueResourceInterceptor,
- );
+ Vue.http.interceptors = _.without(Vue.http.interceptors, vueResourceInterceptor);
}
static callbackParams(response, peekUrl) {
diff --git a/app/assets/javascripts/performance_bar/stores/performance_bar_store.js b/app/assets/javascripts/performance_bar/stores/performance_bar_store.js
index c6b2f55243c..031e774d533 100644
--- a/app/assets/javascripts/performance_bar/stores/performance_bar_store.js
+++ b/app/assets/javascripts/performance_bar/stores/performance_bar_store.js
@@ -32,8 +32,6 @@ export default class PerformanceBarStore {
}
canTrackRequest(requestUrl) {
- return (
- this.requests.filter(request => request.url === requestUrl).length < 2
- );
+ return this.requests.filter(request => request.url === requestUrl).length < 2;
}
}
diff --git a/app/assets/javascripts/persistent_user_callout.js b/app/assets/javascripts/persistent_user_callout.js
deleted file mode 100644
index 1e34e74a152..00000000000
--- a/app/assets/javascripts/persistent_user_callout.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import axios from './lib/utils/axios_utils';
-import { __ } from './locale';
-import Flash from './flash';
-
-export default class PersistentUserCallout {
- constructor(container) {
- const { dismissEndpoint, featureId } = container.dataset;
- this.container = container;
- this.dismissEndpoint = dismissEndpoint;
- this.featureId = featureId;
-
- this.init();
- }
-
- init() {
- const closeButton = this.container.querySelector('.js-close');
- closeButton.addEventListener('click', event => this.dismiss(event));
- }
-
- dismiss(event) {
- event.preventDefault();
-
- axios
- .post(this.dismissEndpoint, {
- feature_name: this.featureId,
- })
- .then(() => {
- this.container.remove();
- })
- .catch(() => {
- Flash(__('An error occurred while dismissing the alert. Refresh the page and try again.'));
- });
- }
-}
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
index 9b4ba0c1a9a..23c0be7742e 100644
--- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
@@ -70,7 +70,7 @@ export default {
v-for="(stage, index) in graph"
:key="stage.name"
:title="capitalizeStageName(stage.name)"
- :jobs="stage.groups"
+ :groups="stage.groups"
:stage-connector-class="stageConnectorClass(index, stage)"
:is-first-column="isFirstColumn(index)"
@refreshPipelineGraph="refreshPipelineGraph"
diff --git a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
index 2ad66f4fe86..34bada533df 100644
--- a/app/assets/javascripts/pipelines/components/graph/dropdown_job_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
@@ -1,31 +1,14 @@
<script>
import $ from 'jquery';
-import JobNameComponent from './job_name_component.vue';
-import JobComponent from './job_component.vue';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import JobItem from './job_item.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
/**
* Renders the dropdown for the pipeline graph.
*
- * The following object should be provided as `job`:
+ * The object provided as `group` corresponds to app/serializers/job_group_entity.rb.
*
- * {
- * "id": 4256,
- * "name": "test",
- * "status": {
- * "icon": "status_success",
- * "text": "passed",
- * "label": "passed",
- * "group": "success",
- * "details_path": "/root/ci-mock/builds/4256",
- * "action": {
- * "icon": "retry",
- * "title": "Retry",
- * "path": "/root/ci-mock/builds/4256/retry",
- * "method": "post"
- * }
- * }
- * }
*/
export default {
directives: {
@@ -33,12 +16,12 @@ export default {
},
components: {
- JobComponent,
- JobNameComponent,
+ JobItem,
+ CiIcon,
},
props: {
- job: {
+ group: {
type: Object,
required: true,
},
@@ -46,7 +29,8 @@ export default {
computed: {
tooltipText() {
- return `${this.job.name} - ${this.job.status.label}`;
+ const { name, status } = this.group;
+ return `${name} - ${status.label}`;
},
},
@@ -56,7 +40,7 @@ export default {
methods: {
/**
- * When the user right clicks or cmd/ctrl + click in the job name or the action icon
+ * When the user right clicks or cmd/ctrl + click in the group name or the action icon
* the dropdown should not be closed so we stop propagation
* of the click event inside the dropdown.
*
@@ -90,14 +74,14 @@ export default {
data-display="static"
class="dropdown-menu-toggle build-content"
>
+ <ci-icon :status="group.status" />
- <job-name-component
- :name="job.name"
- :status="job.status"
- />
+ <span class="ci-status-text">
+ {{ group.name }}
+ </span>
<span class="dropdown-counter-badge">
- {{ job.size }}
+ {{ group.size }}
</span>
</button>
@@ -105,12 +89,12 @@ export default {
<li class="scrollable-menu">
<ul>
<li
- v-for="(item, i) in job.jobs"
- :key="i"
+ v-for="job in group.jobs"
+ :key="job.id"
>
- <job-component
- :dropdown-length="job.size"
- :job="item"
+ <job-item
+ :dropdown-length="group.size"
+ :job="job"
css-class-job-name="mini-pipeline-graph-dropdown-item"
@pipelineActionRequestComplete="pipelineActionRequestComplete"
/>
diff --git a/app/assets/javascripts/pipelines/components/graph/job_component.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue
index a1504592bbc..a1504592bbc 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue
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 567ea119343..efbab51d200 100644
--- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
@@ -1,12 +1,12 @@
<script>
import _ from 'underscore';
-import JobComponent from './job_component.vue';
-import DropdownJobComponent from './dropdown_job_component.vue';
+import JobItem from './job_item.vue';
+import JobGroupDropdown from './job_group_dropdown.vue';
export default {
components: {
- JobComponent,
- DropdownJobComponent,
+ JobItem,
+ JobGroupDropdown,
},
props: {
title: {
@@ -14,7 +14,7 @@ export default {
required: true,
},
- jobs: {
+ groups: {
type: Array,
required: true,
},
@@ -33,12 +33,8 @@ export default {
},
methods: {
- firstJob(list) {
- return list[0];
- },
-
- jobId(job) {
- return `ci-badge-${_.escape(job.name)}`;
+ groupId(group) {
+ return `ci-badge-${_.escape(group.name)}`;
},
buildConnnectorClass(index) {
@@ -61,25 +57,25 @@ export default {
<div class="builds-container">
<ul>
<li
- v-for="(job, index) in jobs"
- :id="jobId(job)"
- :key="job.id"
+ v-for="(group, index) in groups"
+ :id="groupId(group)"
+ :key="group.id"
:class="buildConnnectorClass(index)"
class="build"
>
<div class="curve"></div>
- <job-component
- v-if="job.size === 1"
- :job="job"
+ <job-item
+ v-if="group.size === 1"
+ :job="group.jobs[0]"
css-class-job-name="build-content"
@pipelineActionRequestComplete="pipelineActionRequestComplete"
/>
- <dropdown-job-component
- v-if="job.size > 1"
- :job="job"
+ <job-group-dropdown
+ v-if="group.size > 1"
+ :group="group"
@pipelineActionRequestComplete="pipelineActionRequestComplete"
/>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
index b03438ddba1..4f89ee66023 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
@@ -64,10 +64,7 @@ export default {
return [];
}
const { details } = this.pipeline;
- return [
- ...(details.manual_actions || []),
- ...(details.scheduled_actions || []),
- ];
+ return [...(details.manual_actions || []), ...(details.scheduled_actions || [])];
},
/**
* If provided, returns the commit tag.
diff --git a/app/assets/javascripts/pipelines/components/stage.vue b/app/assets/javascripts/pipelines/components/stage.vue
index 47c15b1a9c4..7ec55792850 100644
--- a/app/assets/javascripts/pipelines/components/stage.vue
+++ b/app/assets/javascripts/pipelines/components/stage.vue
@@ -18,14 +18,14 @@ import Flash from '../../flash';
import axios from '../../lib/utils/axios_utils';
import eventHub from '../event_hub';
import Icon from '../../vue_shared/components/icon.vue';
-import JobComponent from './graph/job_component.vue';
+import JobItem from './graph/job_item.vue';
import tooltip from '../../vue_shared/directives/tooltip';
import { PIPELINES_TABLE } from '../constants';
export default {
components: {
Icon,
- JobComponent,
+ JobItem,
},
directives: {
@@ -198,7 +198,7 @@ export default {
v-for="job in dropdownContent"
:key="job.id"
>
- <job-component
+ <job-item
:dropdown-length="dropdownContent.length"
:job="job"
css-class-job-name="mini-pipeline-graph-dropdown-item"
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 974629fa2af..99b57f4c9d5 100644
--- a/app/assets/javascripts/profile/account/components/delete_account_modal.vue
+++ b/app/assets/javascripts/profile/account/components/delete_account_modal.vue
@@ -1,78 +1,78 @@
<script>
- import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
- import { __, s__, sprintf } from '~/locale';
- import csrf from '~/lib/utils/csrf';
+import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
+import { __, s__, sprintf } from '~/locale';
+import csrf from '~/lib/utils/csrf';
- export default {
- components: {
- DeprecatedModal,
+export default {
+ components: {
+ DeprecatedModal,
+ },
+ props: {
+ actionUrl: {
+ type: String,
+ required: true,
},
- props: {
- actionUrl: {
- type: String,
- required: true,
- },
- confirmWithPassword: {
- type: Boolean,
- required: true,
- },
- username: {
- type: String,
- required: true,
- },
+ confirmWithPassword: {
+ type: Boolean,
+ required: true,
},
- data() {
- return {
- enteredPassword: '',
- enteredUsername: '',
- };
+ username: {
+ type: String,
+ required: true,
},
- computed: {
- csrfToken() {
- return csrf.token;
- },
- inputLabel() {
- let confirmationValue;
- if (this.confirmWithPassword) {
- confirmationValue = __('password');
- } else {
- confirmationValue = __('username');
- }
+ },
+ data() {
+ return {
+ enteredPassword: '',
+ enteredUsername: '',
+ };
+ },
+ computed: {
+ csrfToken() {
+ return csrf.token;
+ },
+ inputLabel() {
+ let confirmationValue;
+ if (this.confirmWithPassword) {
+ confirmationValue = __('password');
+ } else {
+ confirmationValue = __('username');
+ }
- confirmationValue = `<code>${confirmationValue}</code>`;
+ confirmationValue = `<code>${confirmationValue}</code>`;
- return sprintf(
- s__('Profiles|Type your %{confirmationValue} to confirm:'),
- { confirmationValue },
- false,
- );
- },
- text() {
- return sprintf(
- s__(`Profiles|
+ return sprintf(
+ s__('Profiles|Type your %{confirmationValue} to confirm:'),
+ { confirmationValue },
+ false,
+ );
+ },
+ text() {
+ return sprintf(
+ s__(`Profiles|
You are about to permanently delete %{yourAccount}, and all of the issues, merge requests, and groups linked to your account.
Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
- {
- yourAccount: `<strong>${s__('Profiles|your account')}</strong>`,
- deleteAccount: `<strong>${s__('Profiles|Delete Account')}</strong>`,
- },
- false,
- );
- },
+ {
+ yourAccount: `<strong>${s__('Profiles|your account')}</strong>`,
+ deleteAccount: `<strong>${s__('Profiles|Delete Account')}</strong>`,
+ },
+ false,
+ );
},
- methods: {
- canSubmit() {
- if (this.confirmWithPassword) {
- return this.enteredPassword !== '';
- }
+ },
+ methods: {
+ canSubmit() {
+ if (this.confirmWithPassword) {
+ return this.enteredPassword !== '';
+ }
- return this.enteredUsername === this.username;
- },
- onSubmit() {
- this.$refs.form.submit();
- },
+ return this.enteredUsername === this.username;
+ },
+ onSubmit() {
+ this.$refs.form.submit();
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/profile/gl_crop.js b/app/assets/javascripts/profile/gl_crop.js
index af134881f31..befe91c332f 100644
--- a/app/assets/javascripts/profile/gl_crop.js
+++ b/app/assets/javascripts/profile/gl_crop.js
@@ -4,20 +4,35 @@ import $ from 'jquery';
import 'cropper';
import _ from 'underscore';
-((global) => {
+(global => {
// Matches everything but the file name
const FILENAMEREGEX = /^.*[\\\/]/;
class GitLabCrop {
- constructor(input, { filename, previewImage, modalCrop, pickImageEl, uploadImageBtn, modalCropImg,
- exportWidth = 200, exportHeight = 200, cropBoxWidth = 200, cropBoxHeight = 200 } = {}) {
+ constructor(
+ input,
+ {
+ filename,
+ previewImage,
+ modalCrop,
+ pickImageEl,
+ uploadImageBtn,
+ modalCropImg,
+ exportWidth = 200,
+ exportHeight = 200,
+ cropBoxWidth = 200,
+ cropBoxHeight = 200,
+ } = {},
+ ) {
this.onUploadImageBtnClick = this.onUploadImageBtnClick.bind(this);
this.onModalHide = this.onModalHide.bind(this);
this.onModalShow = this.onModalShow.bind(this);
this.onPickImageClick = this.onPickImageClick.bind(this);
this.fileInput = $(input);
this.modalCropImg = _.isString(this.modalCropImg) ? $(this.modalCropImg) : this.modalCropImg;
- this.fileInput.attr('name', `${this.fileInput.attr('name')}-trigger`).attr('id', `${this.fileInput.attr('id')}-trigger`);
+ this.fileInput
+ .attr('name', `${this.fileInput.attr('name')}-trigger`)
+ .attr('id', `${this.fileInput.attr('id')}-trigger`);
this.exportWidth = exportWidth;
this.exportHeight = exportHeight;
this.cropBoxWidth = cropBoxWidth;
@@ -59,7 +74,7 @@ import _ from 'underscore';
btn = this;
return _this.onActionBtnClick(btn);
});
- return this.croppedImageBlob = null;
+ return (this.croppedImageBlob = null);
}
onPickImageClick() {
@@ -94,9 +109,9 @@ import _ from 'underscore';
width: cropBoxWidth,
height: cropBoxHeight,
left: (container.width - cropBoxWidth) / 2,
- top: (container.height - cropBoxHeight) / 2
+ top: (container.height - cropBoxHeight) / 2,
});
- }
+ },
});
}
@@ -116,7 +131,7 @@ import _ from 'underscore';
var data, result;
data = $(btn).data();
if (this.modalCropImg.data('cropper') && data.method) {
- return result = this.modalCropImg.cropper(data.method, data.option);
+ return (result = this.modalCropImg.cropper(data.method, data.option));
}
}
@@ -127,7 +142,7 @@ import _ from 'underscore';
readFile(input) {
var _this, reader;
_this = this;
- reader = new FileReader;
+ reader = new FileReader();
reader.onload = () => {
_this.modalCropImg.attr('src', reader.result);
return _this.modalCrop.modal('show');
@@ -145,7 +160,7 @@ import _ from 'underscore';
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {
- type: 'image/png'
+ type: 'image/png',
});
}
@@ -157,11 +172,13 @@ import _ from 'underscore';
}
setBlob() {
- this.dataURL = this.modalCropImg.cropper('getCroppedCanvas', {
- width: 200,
- height: 200
- }).toDataURL('image/png');
- return this.croppedImageBlob = this.dataURLtoBlob(this.dataURL);
+ this.dataURL = this.modalCropImg
+ .cropper('getCroppedCanvas', {
+ width: 200,
+ height: 200,
+ })
+ .toDataURL('image/png');
+ return (this.croppedImageBlob = this.dataURLtoBlob(this.dataURL));
}
getBlob() {
diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js
index e49c67ffb5c..8704a655b28 100644
--- a/app/assets/javascripts/profile/profile.js
+++ b/app/assets/javascripts/profile/profile.js
@@ -26,11 +26,7 @@ export default class Profile {
}
bindEvents() {
- $('.js-preferences-form').on(
- 'change.preference',
- 'input[type=radio]',
- this.submitForm,
- );
+ $('.js-preferences-form').on('change.preference', 'input[type=radio]', this.submitForm);
$('#user_notification_email').on('change', this.submitForm);
$('#user_notified_of_own_activity').on('change', this.submitForm);
this.form.on('submit', this.onSubmitForm);
diff --git a/app/assets/javascripts/project_find_file.js b/app/assets/javascripts/project_find_file.js
index 12cfa7de316..60d3d83a4b2 100644
--- a/app/assets/javascripts/project_find_file.js
+++ b/app/assets/javascripts/project_find_file.js
@@ -10,14 +10,14 @@ import { __ } from '~/locale';
const highlighter = function(element, text, matches) {
var highlightText, j, lastIndex, len, matchIndex, matchedChars, unmatched;
lastIndex = 0;
- highlightText = "";
+ highlightText = '';
matchedChars = [];
for (j = 0, len = matches.length; j < len; j += 1) {
matchIndex = matches[j];
unmatched = text.substring(lastIndex, matchIndex);
if (unmatched) {
if (matchedChars.length) {
- element.append(matchedChars.join("").bold());
+ element.append(matchedChars.join('').bold());
}
matchedChars = [];
element.append(document.createTextNode(unmatched));
@@ -26,7 +26,7 @@ const highlighter = function(element, text, matches) {
lastIndex = matchIndex + 1;
}
if (matchedChars.length) {
- element.append(matchedChars.join("").bold());
+ element.append(matchedChars.join('').bold());
}
return element.append(document.createTextNode(text.substring(lastIndex)));
};
@@ -40,7 +40,7 @@ export default class ProjectFindFile {
this.selectRowDown = this.selectRowDown.bind(this);
this.selectRowUp = this.selectRowUp.bind(this);
this.filePaths = {};
- this.inputElement = this.element.find(".file-finder-input");
+ this.inputElement = this.element.find('.file-finder-input');
// init event
this.initEvent();
// focus text input box
@@ -50,38 +50,51 @@ export default class ProjectFindFile {
}
initEvent() {
- this.inputElement.off("keyup");
- this.inputElement.on("keyup", (function(_this) {
- return function(event) {
- var oldValue, ref, target, value;
- target = $(event.target);
- value = target.val();
- oldValue = (ref = target.data("oldValue")) != null ? ref : "";
- if (value !== oldValue) {
- target.data("oldValue", value);
- _this.findFile();
- return _this.element.find("tr.tree-item").eq(0).addClass("selected").focus();
- }
- };
- })(this));
+ this.inputElement.off('keyup');
+ this.inputElement.on(
+ 'keyup',
+ (function(_this) {
+ return function(event) {
+ var oldValue, ref, target, value;
+ target = $(event.target);
+ value = target.val();
+ oldValue = (ref = target.data('oldValue')) != null ? ref : '';
+ if (value !== oldValue) {
+ target.data('oldValue', value);
+ _this.findFile();
+ return _this.element
+ .find('tr.tree-item')
+ .eq(0)
+ .addClass('selected')
+ .focus();
+ }
+ };
+ })(this),
+ );
}
findFile() {
var result, searchText;
searchText = this.inputElement.val();
- result = searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths;
+ result =
+ searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths;
return this.renderList(result, searchText);
- // find file
+ // find file
}
// files pathes load
load(url) {
- axios.get(url)
+ axios
+ .get(url)
.then(({ data }) => {
this.element.find('.loading').hide();
this.filePaths = data;
this.findFile();
- this.element.find('.files-slider tr.tree-item').eq(0).addClass('selected').focus();
+ this.element
+ .find('.files-slider tr.tree-item')
+ .eq(0)
+ .addClass('selected')
+ .focus();
})
.catch(() => flash(__('An error occurred while loading filenames')));
}
@@ -89,7 +102,7 @@ export default class ProjectFindFile {
// render result
renderList(filePaths, searchText) {
var blobItemUrl, filePath, html, i, len, matches, results;
- this.element.find(".tree-table > tbody").empty();
+ this.element.find('.tree-table > tbody').empty();
results = [];
for (i = 0, len = filePaths.length; i < len; i += 1) {
@@ -100,9 +113,9 @@ export default class ProjectFindFile {
if (searchText) {
matches = fuzzaldrinPlus.match(filePath, searchText);
}
- blobItemUrl = this.options.blobUrlTemplate + "/" + filePath;
+ blobItemUrl = this.options.blobUrlTemplate + '/' + filePath;
html = ProjectFindFile.makeHtml(filePath, matches, blobItemUrl);
- results.push(this.element.find(".tree-table > tbody").append(html));
+ results.push(this.element.find('.tree-table > tbody').append(html));
}
return results;
}
@@ -110,52 +123,56 @@ export default class ProjectFindFile {
// make tbody row html
static makeHtml(filePath, matches, blobItemUrl) {
var $tr;
- $tr = $("<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>");
+ $tr = $(
+ "<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>",
+ );
if (matches) {
- $tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl));
+ $tr
+ .find('a')
+ .replaceWith(highlighter($tr.find('a'), filePath, matches).attr('href', blobItemUrl));
} else {
- $tr.find("a").attr("href", blobItemUrl);
- $tr.find(".str-truncated").text(filePath);
+ $tr.find('a').attr('href', blobItemUrl);
+ $tr.find('.str-truncated').text(filePath);
}
return $tr;
}
selectRow(type) {
var next, rows, selectedRow;
- rows = this.element.find(".files-slider tr.tree-item");
- selectedRow = this.element.find(".files-slider tr.tree-item.selected");
+ rows = this.element.find('.files-slider tr.tree-item');
+ selectedRow = this.element.find('.files-slider tr.tree-item.selected');
if (rows && rows.length > 0) {
if (selectedRow && selectedRow.length > 0) {
- if (type === "UP") {
+ if (type === 'UP') {
next = selectedRow.prev();
- } else if (type === "DOWN") {
+ } else if (type === 'DOWN') {
next = selectedRow.next();
}
if (next.length > 0) {
- selectedRow.removeClass("selected");
+ selectedRow.removeClass('selected');
selectedRow = next;
}
} else {
selectedRow = rows.eq(0);
}
- return selectedRow.addClass("selected").focus();
+ return selectedRow.addClass('selected').focus();
}
}
selectRowUp() {
- return this.selectRow("UP");
+ return this.selectRow('UP');
}
selectRowDown() {
- return this.selectRow("DOWN");
+ return this.selectRow('DOWN');
}
goToTree() {
- return window.location.href = this.options.treeUrl;
+ return (window.location.href = this.options.treeUrl);
}
goToBlob() {
- var $link = this.element.find(".tree-item.selected .tree-item-file-name a");
+ var $link = this.element.find('.tree-item.selected .tree-item-file-name a');
if ($link.length) {
$link.get(0).click();
diff --git a/app/assets/javascripts/project_import.js b/app/assets/javascripts/project_import.js
index 5a0d2b642eb..a51a2a2242f 100644
--- a/app/assets/javascripts/project_import.js
+++ b/app/assets/javascripts/project_import.js
@@ -5,4 +5,3 @@ export default function projectImport() {
visitUrl(window.location.href);
}, 5000);
}
-
diff --git a/app/assets/javascripts/project_label_subscription.js b/app/assets/javascripts/project_label_subscription.js
index 9049f87e037..d3c604dcee1 100644
--- a/app/assets/javascripts/project_label_subscription.js
+++ b/app/assets/javascripts/project_label_subscription.js
@@ -31,32 +31,35 @@ export default class ProjectLabelSubscription {
$btn.addClass('disabled');
- axios.post(url).then(() => {
- let newStatus;
- let newAction;
+ axios
+ .post(url)
+ .then(() => {
+ let newStatus;
+ let newAction;
- if (oldStatus === 'unsubscribed') {
- [newStatus, newAction] = ['subscribed', 'Unsubscribe'];
- } else {
- [newStatus, newAction] = ['unsubscribed', 'Subscribe'];
- }
+ if (oldStatus === 'unsubscribed') {
+ [newStatus, newAction] = ['subscribed', 'Unsubscribe'];
+ } else {
+ [newStatus, newAction] = ['unsubscribed', 'Subscribe'];
+ }
- $btn.removeClass('disabled');
+ $btn.removeClass('disabled');
- this.$buttons.attr('data-status', newStatus);
- this.$buttons.find('> span').text(newAction);
+ this.$buttons.attr('data-status', newStatus);
+ this.$buttons.find('> span').text(newAction);
- this.$buttons.map((i, button) => {
- const $button = $(button);
- const originalTitle = $button.attr('data-original-title');
+ this.$buttons.map((i, button) => {
+ const $button = $(button);
+ const originalTitle = $button.attr('data-original-title');
- if (originalTitle) {
- ProjectLabelSubscription.setNewTitle($button, originalTitle, newStatus, newAction);
- }
+ if (originalTitle) {
+ ProjectLabelSubscription.setNewTitle($button, originalTitle, newStatus, newAction);
+ }
- return button;
- });
- }).catch(() => flash(__('There was an error subscribing to this label.')));
+ return button;
+ });
+ })
+ .catch(() => flash(__('There was an error subscribing to this label.')));
}
static setNewTitle($button, originalTitle, newStatus) {
diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js
index eaaeda8b339..f1fff173619 100644
--- a/app/assets/javascripts/project_select.js
+++ b/app/assets/javascripts/project_select.js
@@ -16,28 +16,28 @@ export default function projectSelect() {
this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled');
this.allowClear = $(select).data('allowClear') || false;
- placeholder = "Search for project";
+ placeholder = 'Search for project';
if (this.includeGroups) {
- placeholder += " or group";
+ placeholder += ' or group';
}
$(select).select2({
placeholder: placeholder,
minimumInputLength: 0,
- query: (function (_this) {
- return function (query) {
+ query: (function(_this) {
+ return function(query) {
var finalCallback, projectsCallback;
- finalCallback = function (projects) {
+ finalCallback = function(projects) {
var data;
data = {
- results: projects
+ results: projects,
};
return query.callback(data);
};
if (_this.includeGroups) {
- projectsCallback = function (projects) {
+ projectsCallback = function(projects) {
var groupsCallback;
- groupsCallback = function (groups) {
+ groupsCallback = function(groups) {
var data;
data = groups.concat(projects);
return finalCallback(data);
@@ -48,17 +48,26 @@ export default function projectSelect() {
projectsCallback = finalCallback;
}
if (_this.groupId) {
- return Api.groupProjects(_this.groupId, query.term, {
- with_issues_enabled: _this.withIssuesEnabled,
- with_merge_requests_enabled: _this.withMergeRequestsEnabled,
- }, projectsCallback);
+ return Api.groupProjects(
+ _this.groupId,
+ query.term,
+ {
+ with_issues_enabled: _this.withIssuesEnabled,
+ with_merge_requests_enabled: _this.withMergeRequestsEnabled,
+ },
+ projectsCallback,
+ );
} else {
- return Api.projects(query.term, {
- order_by: _this.orderBy,
- with_issues_enabled: _this.withIssuesEnabled,
- with_merge_requests_enabled: _this.withMergeRequestsEnabled,
- membership: !_this.allProjects,
- }, projectsCallback);
+ return Api.projects(
+ query.term,
+ {
+ order_by: _this.orderBy,
+ with_issues_enabled: _this.withIssuesEnabled,
+ with_merge_requests_enabled: _this.withMergeRequestsEnabled,
+ membership: !_this.allProjects,
+ },
+ projectsCallback,
+ );
}
};
})(this),
@@ -69,7 +78,7 @@ export default function projectSelect() {
url: project.web_url,
});
},
- text: function (project) {
+ text: function(project) {
return project.name_with_namespace || project.name;
},
@@ -79,7 +88,7 @@ export default function projectSelect() {
allowClear: this.allowClear,
- dropdownCssClass: "ajax-project-dropdown"
+ dropdownCssClass: 'ajax-project-dropdown',
});
if (simpleFilter) return select;
return new ProjectSelectComboButton(select);
diff --git a/app/assets/javascripts/project_select_combo_button.js b/app/assets/javascripts/project_select_combo_button.js
index 9b404896e86..3dbac3ff942 100644
--- a/app/assets/javascripts/project_select_combo_button.js
+++ b/app/assets/javascripts/project_select_combo_button.js
@@ -14,10 +14,11 @@ export default class ProjectSelectComboButton {
}
bindEvents() {
- this.projectSelectInput.siblings('.new-project-item-select-button')
+ this.projectSelectInput
+ .siblings('.new-project-item-select-button')
.on('click', e => this.openDropdown(e));
- this.newItemBtn.on('click', (e) => {
+ this.newItemBtn.on('click', e => {
if (!this.getProjectFromLocalStorage()) {
e.preventDefault();
this.openDropdown(e);
@@ -31,14 +32,21 @@ export default class ProjectSelectComboButton {
const localStorageIsSafe = AccessorUtilities.isLocalStorageAccessSafe();
if (localStorageIsSafe) {
- this.localStorageKey = ['group', this.groupId, this.formattedText.localStorageItemType, 'recent-project'].join('-');
+ this.localStorageKey = [
+ 'group',
+ this.groupId,
+ this.formattedText.localStorageItemType,
+ 'recent-project',
+ ].join('-');
this.setBtnTextFromLocalStorage();
}
}
// eslint-disable-next-line class-methods-use-this
openDropdown(event) {
- $(event.currentTarget).siblings('.project-item-select').select2('open');
+ $(event.currentTarget)
+ .siblings('.project-item-select')
+ .select2('open');
}
selectProject() {
@@ -86,8 +94,14 @@ export default class ProjectSelectComboButton {
const defaultTextPrefix = this.resourceLabel;
// the trailing slice call depluralizes each of these strings (e.g. new-issues -> new-issue)
- const localStorageItemType = `new-${this.resourceType.split('_').join('-').slice(0, -1)}`;
- const presetTextSuffix = this.resourceType.split('_').join(' ').slice(0, -1);
+ const localStorageItemType = `new-${this.resourceType
+ .split('_')
+ .join('-')
+ .slice(0, -1)}`;
+ const presetTextSuffix = this.resourceType
+ .split('_')
+ .join(' ')
+ .slice(0, -1);
return {
localStorageItemType, // new-issue / new-merge-request
@@ -96,4 +110,3 @@ export default class ProjectSelectComboButton {
};
}
}
-
diff --git a/app/assets/javascripts/project_visibility.js b/app/assets/javascripts/project_visibility.js
index a52ac768e57..aaf6723c85c 100644
--- a/app/assets/javascripts/project_visibility.js
+++ b/app/assets/javascripts/project_visibility.js
@@ -7,7 +7,7 @@ function setVisibilityOptions(namespaceSelector) {
const selectedNamespace = namespaceSelector.options[namespaceSelector.selectedIndex];
const { name, visibility, visibilityLevel, showPath, editPath } = selectedNamespace.dataset;
- document.querySelectorAll('.visibility-level-setting .form-check').forEach((option) => {
+ document.querySelectorAll('.visibility-level-setting .form-check').forEach(option => {
const optionInput = option.querySelector('input[type=radio]');
const optionValue = optionInput ? optionInput.value : 0;
const optionTitle = option.querySelector('.option-title');
@@ -20,8 +20,7 @@ function setVisibilityOptions(namespaceSelector) {
optionInput.disabled = true;
const reason = option.querySelector('.option-disabled-reason');
if (reason) {
- reason.innerHTML =
- `This project cannot be ${optionName} because the visibility of
+ reason.innerHTML = `This project cannot be ${optionName} because the visibility of
<a href="${showPath}">${name}</a> is ${visibility}. To make this project
${optionName}, you must first <a href="${editPath}">change the visibility</a>
of the parent group.`;
diff --git a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
index 078ccbbbac2..8380cfb6c59 100644
--- a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
+++ b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
@@ -65,10 +65,14 @@ export default class PrometheusMetrics {
let totalMissingEnvVarMetrics = 0;
let totalExporters = 0;
- metrics.forEach((metric) => {
+ metrics.forEach(metric => {
if (metric.active_metrics > 0) {
totalExporters += 1;
- this.$monitoredMetricsList.append(`<li>${_.escape(metric.group)}<span class="badge">${_.escape(metric.active_metrics)}</span></li>`);
+ this.$monitoredMetricsList.append(
+ `<li>${_.escape(metric.group)}<span class="badge">${_.escape(
+ metric.active_metrics,
+ )}</span></li>`,
+ );
totalMonitoredMetrics += metric.active_metrics;
if (metric.metrics_missing_requirements > 0) {
this.$missingEnvVarMetricsList.append(`<li>${_.escape(metric.group)}</li>`);
@@ -78,17 +82,26 @@ export default class PrometheusMetrics {
});
if (totalMonitoredMetrics === 0) {
- const emptyCommonMetricsText = sprintf(s__('PrometheusService|<p class="text-tertiary">No <a href="%{docsUrl}">common metrics</a> were found</p>'), {
- docsUrl: this.helpMetricsPath,
- }, false);
+ const emptyCommonMetricsText = sprintf(
+ s__(
+ 'PrometheusService|<p class="text-tertiary">No <a href="%{docsUrl}">common metrics</a> were found</p>',
+ ),
+ {
+ docsUrl: this.helpMetricsPath,
+ },
+ false,
+ );
this.$monitoredMetricsEmpty.empty();
this.$monitoredMetricsEmpty.append(emptyCommonMetricsText);
this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
} else {
- const metricsCountText = sprintf(s__('PrometheusService|%{exporters} with %{metrics} were found'), {
- exporters: n__('%d exporter', '%d exporters', totalExporters),
- metrics: n__('%d metric', '%d metrics', totalMonitoredMetrics),
- });
+ const metricsCountText = sprintf(
+ s__('PrometheusService|%{exporters} with %{metrics} were found'),
+ {
+ exporters: n__('%d exporter', '%d exporters', totalExporters),
+ metrics: n__('%d metric', '%d metrics', totalMonitoredMetrics),
+ },
+ );
this.$monitoredMetricsCount.text(metricsCountText);
this.showMonitoringMetricsPanelState(PANEL_STATE.LIST);
@@ -102,7 +115,8 @@ export default class PrometheusMetrics {
loadActiveMetrics() {
this.showMonitoringMetricsPanelState(PANEL_STATE.LOADING);
backOff((next, stop) => {
- axios.get(this.activeMetricsEndpoint)
+ axios
+ .get(this.activeMetricsEndpoint)
.then(({ data }) => {
if (data && data.success) {
stop(data);
@@ -117,7 +131,7 @@ export default class PrometheusMetrics {
})
.catch(stop);
})
- .then((res) => {
+ .then(res => {
if (res && res.data && res.data.length) {
this.populateActiveMetrics(res.data);
} else {
diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js b/app/assets/javascripts/protected_branches/protected_branch_create.js
index b601b19e7be..48343c8ba0a 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_create.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_create.js
@@ -46,8 +46,12 @@ export default class ProtectedBranchCreate {
onSelect() {
// Enable submit button
const $branchInput = this.$form.find('input[name="protected_branch[name]"]');
- const $allowedToMergeInput = this.$form.find('input[name="protected_branch[merge_access_levels_attributes][0][access_level]"]');
- const $allowedToPushInput = this.$form.find('input[name="protected_branch[push_access_levels_attributes][0][access_level]"]');
+ const $allowedToMergeInput = this.$form.find(
+ 'input[name="protected_branch[merge_access_levels_attributes][0][access_level]"]',
+ );
+ const $allowedToPushInput = this.$form.find(
+ 'input[name="protected_branch[push_access_levels_attributes][0][access_level]"]',
+ );
const completedForm = !(
$branchInput.val() &&
$allowedToMergeInput.length &&
diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit.js b/app/assets/javascripts/protected_branches/protected_branch_edit.js
index 54560d08ad7..5bc08f60d16 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_edit.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_edit.js
@@ -29,8 +29,12 @@ export default class ProtectedBranchEdit {
}
onSelect() {
- const $allowedToMergeInput = this.$wrap.find(`input[name="${this.$allowedToMergeDropdown.data('fieldName')}"]`);
- const $allowedToPushInput = this.$wrap.find(`input[name="${this.$allowedToPushDropdown.data('fieldName')}"]`);
+ const $allowedToMergeInput = this.$wrap.find(
+ `input[name="${this.$allowedToMergeDropdown.data('fieldName')}"]`,
+ );
+ const $allowedToPushInput = this.$wrap.find(
+ `input[name="${this.$allowedToPushDropdown.data('fieldName')}"]`,
+ );
// Do not update if one dropdown has not selected any option
if (!($allowedToMergeInput.length && $allowedToPushInput.length)) return;
@@ -38,25 +42,36 @@ export default class ProtectedBranchEdit {
this.$allowedToMergeDropdown.disable();
this.$allowedToPushDropdown.disable();
- axios.patch(this.$wrap.data('url'), {
- protected_branch: {
- merge_access_levels_attributes: [{
- id: this.$allowedToMergeDropdown.data('accessLevelId'),
- access_level: $allowedToMergeInput.val(),
- }],
- push_access_levels_attributes: [{
- id: this.$allowedToPushDropdown.data('accessLevelId'),
- access_level: $allowedToPushInput.val(),
- }],
- },
- }).then(() => {
- this.$allowedToMergeDropdown.enable();
- this.$allowedToPushDropdown.enable();
- }).catch(() => {
- this.$allowedToMergeDropdown.enable();
- this.$allowedToPushDropdown.enable();
-
- flash('Failed to update branch!', 'alert', document.querySelector('.js-protected-branches-list'));
- });
+ axios
+ .patch(this.$wrap.data('url'), {
+ protected_branch: {
+ merge_access_levels_attributes: [
+ {
+ id: this.$allowedToMergeDropdown.data('accessLevelId'),
+ access_level: $allowedToMergeInput.val(),
+ },
+ ],
+ push_access_levels_attributes: [
+ {
+ id: this.$allowedToPushDropdown.data('accessLevelId'),
+ access_level: $allowedToPushInput.val(),
+ },
+ ],
+ },
+ })
+ .then(() => {
+ this.$allowedToMergeDropdown.enable();
+ this.$allowedToPushDropdown.enable();
+ })
+ .catch(() => {
+ this.$allowedToMergeDropdown.enable();
+ this.$allowedToPushDropdown.enable();
+
+ flash(
+ 'Failed to update branch!',
+ 'alert',
+ document.querySelector('.js-protected-branches-list'),
+ );
+ });
}
}
diff --git a/app/assets/javascripts/protected_tags/protected_tag_create.js b/app/assets/javascripts/protected_tags/protected_tag_create.js
index 2f8116df0d2..fddf2674cbb 100644
--- a/app/assets/javascripts/protected_tags/protected_tag_create.js
+++ b/app/assets/javascripts/protected_tags/protected_tag_create.js
@@ -40,7 +40,9 @@ export default class ProtectedTagCreate {
const $tagInput = this.$form.find('input[name="protected_tag[name]"]');
const $allowedToCreateInput = this.$form.find('#create_access_levels_attributes');
- this.$form.find('input[type="submit"]').prop('disabled', !($tagInput.val() && $allowedToCreateInput.length));
+ this.$form
+ .find('input[type="submit"]')
+ .prop('disabled', !($tagInput.val() && $allowedToCreateInput.length));
}
static getProtectedTags(term, callback) {
diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit.js b/app/assets/javascripts/protected_tags/protected_tag_edit.js
index 8687b2a4044..c52497e62f2 100644
--- a/app/assets/javascripts/protected_tags/protected_tag_edit.js
+++ b/app/assets/javascripts/protected_tags/protected_tag_edit.js
@@ -21,26 +21,33 @@ export default class ProtectedTagEdit {
}
onSelect() {
- const $allowedToCreateInput = this.$wrap.find(`input[name="${this.$allowedToCreateDropdownButton.data('fieldName')}"]`);
+ const $allowedToCreateInput = this.$wrap.find(
+ `input[name="${this.$allowedToCreateDropdownButton.data('fieldName')}"]`,
+ );
// Do not update if one dropdown has not selected any option
if (!$allowedToCreateInput.length) return;
this.$allowedToCreateDropdownButton.disable();
- axios.patch(this.$wrap.data('url'), {
- protected_tag: {
- create_access_levels_attributes: [{
- id: this.$allowedToCreateDropdownButton.data('accessLevelId'),
- access_level: $allowedToCreateInput.val(),
- }],
- },
- }).then(() => {
- this.$allowedToCreateDropdownButton.enable();
- }).catch(() => {
- this.$allowedToCreateDropdownButton.enable();
-
- flash('Failed to update tag!', 'alert', document.querySelector('.js-protected-tags-list'));
- });
+ axios
+ .patch(this.$wrap.data('url'), {
+ protected_tag: {
+ create_access_levels_attributes: [
+ {
+ id: this.$allowedToCreateDropdownButton.data('accessLevelId'),
+ access_level: $allowedToCreateInput.val(),
+ },
+ ],
+ },
+ })
+ .then(() => {
+ this.$allowedToCreateDropdownButton.enable();
+ })
+ .catch(() => {
+ this.$allowedToCreateDropdownButton.enable();
+
+ flash('Failed to update tag!', 'alert', document.querySelector('.js-protected-tags-list'));
+ });
}
}
diff --git a/app/assets/javascripts/raven/raven_config.js b/app/assets/javascripts/raven/raven_config.js
index 658caeecde1..338006ce2b9 100644
--- a/app/assets/javascripts/raven/raven_config.js
+++ b/app/assets/javascripts/raven/raven_config.js
@@ -9,7 +9,7 @@ const IGNORE_ERRORS = [
'canvas.contentDocument',
'MyApp_RemoveAllHighlights',
'http://tt.epicplay.com',
- 'Can\'t find variable: ZiteReader',
+ "Can't find variable: ZiteReader",
'jigsaw is not defined',
'ComboSearch is not defined',
'http://loading.retry.widdit.com/',
diff --git a/app/assets/javascripts/ref_select_dropdown.js b/app/assets/javascripts/ref_select_dropdown.js
index 95c5cf7b345..75bac035aca 100644
--- a/app/assets/javascripts/ref_select_dropdown.js
+++ b/app/assets/javascripts/ref_select_dropdown.js
@@ -2,7 +2,8 @@ import $ from 'jquery';
class RefSelectDropdown {
constructor($dropdownButton, availableRefs) {
- const availableRefsValue = availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML);
+ const availableRefsValue =
+ availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML);
$dropdownButton.glDropdown({
data: availableRefsValue,
filterable: true,
@@ -29,7 +30,7 @@ class RefSelectDropdown {
const $fieldInput = $(`input[name="${$dropdownButton.data('fieldName')}"]`, $dropdownContainer);
const $filterInput = $('input[type="search"]', $dropdownContainer);
- $filterInput.on('keyup', (e) => {
+ $filterInput.on('keyup', e => {
const keyCode = e.keyCode || e.which;
if (keyCode !== 13) return;
diff --git a/app/assets/javascripts/registry/components/app.vue b/app/assets/javascripts/registry/components/app.vue
index 7e2287ac4db..9dd1c87a87d 100644
--- a/app/assets/javascripts/registry/components/app.vue
+++ b/app/assets/javascripts/registry/components/app.vue
@@ -1,42 +1,35 @@
<script>
- import { mapGetters, mapActions } from 'vuex';
- import Flash from '../../flash';
- import store from '../stores';
- import collapsibleContainer from './collapsible_container.vue';
- import { errorMessages, errorMessagesTypes } from '../constants';
+import { mapGetters, mapActions } from 'vuex';
+import Flash from '../../flash';
+import store from '../stores';
+import collapsibleContainer from './collapsible_container.vue';
+import { errorMessages, errorMessagesTypes } from '../constants';
- export default {
- name: 'RegistryListApp',
- components: {
- collapsibleContainer,
+export default {
+ name: 'RegistryListApp',
+ components: {
+ collapsibleContainer,
+ },
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
},
- props: {
- endpoint: {
- type: String,
- required: true,
- },
- },
- store,
- computed: {
- ...mapGetters([
- 'isLoading',
- 'repos',
- ]),
- },
- created() {
- this.setMainEndpoint(this.endpoint);
- },
- mounted() {
- this.fetchRepos()
- .catch(() => Flash(errorMessages[errorMessagesTypes.FETCH_REPOS]));
- },
- methods: {
- ...mapActions([
- 'setMainEndpoint',
- 'fetchRepos',
- ]),
- },
- };
+ },
+ store,
+ computed: {
+ ...mapGetters(['isLoading', 'repos']),
+ },
+ created() {
+ this.setMainEndpoint(this.endpoint);
+ },
+ mounted() {
+ this.fetchRepos().catch(() => Flash(errorMessages[errorMessagesTypes.FETCH_REPOS]));
+ },
+ methods: {
+ ...mapActions(['setMainEndpoint', 'fetchRepos']),
+ },
+};
</script>
<template>
<div>
diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue
index d9bf41924d1..501b2625ae5 100644
--- a/app/assets/javascripts/registry/components/collapsible_container.vue
+++ b/app/assets/javascripts/registry/components/collapsible_container.vue
@@ -1,62 +1,59 @@
<script>
- import { mapActions } from 'vuex';
- 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 { errorMessages, errorMessagesTypes } from '../constants';
- import { __ } from '../../locale';
+import { mapActions } from 'vuex';
+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 { errorMessages, errorMessagesTypes } from '../constants';
+import { __ } from '../../locale';
- export default {
- name: 'CollapsibeContainerRegisty',
- components: {
- clipboardButton,
- tableRegistry,
+export default {
+ name: 'CollapsibeContainerRegisty',
+ components: {
+ clipboardButton,
+ tableRegistry,
+ },
+ directives: {
+ tooltip,
+ },
+ props: {
+ repo: {
+ type: Object,
+ required: true,
},
- directives: {
- tooltip,
- },
- props: {
- repo: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- isOpen: false,
- };
- },
- methods: {
- ...mapActions([
- 'fetchRepos',
- 'fetchList',
- 'deleteRepo',
- ]),
+ },
+ data() {
+ return {
+ isOpen: false,
+ };
+ },
+ methods: {
+ ...mapActions(['fetchRepos', 'fetchList', 'deleteRepo']),
- toggleRepo() {
- this.isOpen = !this.isOpen;
+ toggleRepo() {
+ this.isOpen = !this.isOpen;
- if (this.isOpen) {
- this.fetchList({ repo: this.repo })
- .catch(() => this.showError(errorMessagesTypes.FETCH_REGISTRY));
- }
- },
+ if (this.isOpen) {
+ this.fetchList({ repo: this.repo }).catch(() =>
+ this.showError(errorMessagesTypes.FETCH_REGISTRY),
+ );
+ }
+ },
- handleDeleteRepository() {
- this.deleteRepo(this.repo)
- .then(() => {
- Flash(__('This container registry has been scheduled for deletion.'), 'notice');
- this.fetchRepos();
- })
- .catch(() => this.showError(errorMessagesTypes.DELETE_REPO));
- },
+ handleDeleteRepository() {
+ this.deleteRepo(this.repo)
+ .then(() => {
+ Flash(__('This container registry has been scheduled for deletion.'), 'notice');
+ this.fetchRepos();
+ })
+ .catch(() => this.showError(errorMessagesTypes.DELETE_REPO));
+ },
- showError(message) {
- Flash(errorMessages[message]);
- },
+ showError(message) {
+ Flash(errorMessages[message]);
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/registry/components/table_registry.vue b/app/assets/javascripts/registry/components/table_registry.vue
index fafb35bd69a..bb6c977fc63 100644
--- a/app/assets/javascripts/registry/components/table_registry.vue
+++ b/app/assets/javascripts/registry/components/table_registry.vue
@@ -1,66 +1,62 @@
<script>
- import { mapActions } from 'vuex';
- 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 timeagoMixin from '../../vue_shared/mixins/timeago';
- import { errorMessages, errorMessagesTypes } from '../constants';
- import { numberToHumanSize } from '../../lib/utils/number_utils';
+import { mapActions } from 'vuex';
+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 timeagoMixin from '../../vue_shared/mixins/timeago';
+import { errorMessages, errorMessagesTypes } from '../constants';
+import { numberToHumanSize } from '../../lib/utils/number_utils';
- export default {
- components: {
- clipboardButton,
- tablePagination,
+export default {
+ components: {
+ clipboardButton,
+ tablePagination,
+ },
+ directives: {
+ tooltip,
+ },
+ mixins: [timeagoMixin],
+ props: {
+ repo: {
+ type: Object,
+ required: true,
},
- directives: {
- tooltip,
+ },
+ computed: {
+ shouldRenderPagination() {
+ return this.repo.pagination.total > this.repo.pagination.perPage;
},
- mixins: [
- timeagoMixin,
- ],
- props: {
- repo: {
- type: Object,
- required: true,
- },
- },
- computed: {
- shouldRenderPagination() {
- return this.repo.pagination.total > this.repo.pagination.perPage;
- },
- },
- methods: {
- ...mapActions([
- 'fetchList',
- 'deleteRegistry',
- ]),
+ },
+ methods: {
+ ...mapActions(['fetchList', 'deleteRegistry']),
- layers(item) {
- return item.layers ? n__('%d layer', '%d layers', item.layers) : '';
- },
+ layers(item) {
+ return item.layers ? n__('%d layer', '%d layers', item.layers) : '';
+ },
- formatSize(size) {
- return numberToHumanSize(size);
- },
+ formatSize(size) {
+ return numberToHumanSize(size);
+ },
- handleDeleteRegistry(registry) {
- this.deleteRegistry(registry)
- .then(() => this.fetchList({ repo: this.repo }))
- .catch(() => this.showError(errorMessagesTypes.DELETE_REGISTRY));
- },
+ 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));
- },
+ onPageChange(pageNumber) {
+ this.fetchList({ repo: this.repo, page: pageNumber }).catch(() =>
+ this.showError(errorMessagesTypes.FETCH_REGISTRY),
+ );
+ },
- showError(message) {
- Flash(errorMessages[message]);
- },
+ showError(message) {
+ Flash(errorMessages[message]);
},
- };
+ },
+};
</script>
<template>
<div>
diff --git a/app/assets/javascripts/registry/index.js b/app/assets/javascripts/registry/index.js
index e15cd94a915..025afefe7f0 100644
--- a/app/assets/javascripts/registry/index.js
+++ b/app/assets/javascripts/registry/index.js
@@ -4,22 +4,23 @@ import Translate from '../vue_shared/translate';
Vue.use(Translate);
-export default () => new Vue({
- el: '#js-vue-registry-images',
- components: {
- registryApp,
- },
- data() {
- const { dataset } = document.querySelector(this.$options.el);
- return {
- endpoint: dataset.endpoint,
- };
- },
- render(createElement) {
- return createElement('registry-app', {
- props: {
- endpoint: this.endpoint,
- },
- });
- },
-});
+export default () =>
+ new Vue({
+ el: '#js-vue-registry-images',
+ components: {
+ registryApp,
+ },
+ data() {
+ const { dataset } = document.querySelector(this.$options.el);
+ return {
+ endpoint: dataset.endpoint,
+ };
+ },
+ render(createElement) {
+ return createElement('registry-app', {
+ props: {
+ endpoint: this.endpoint,
+ },
+ });
+ },
+ });
diff --git a/app/assets/javascripts/registry/stores/mutations.js b/app/assets/javascripts/registry/stores/mutations.js
index 208c3c39866..69c051cd2d6 100644
--- a/app/assets/javascripts/registry/stores/mutations.js
+++ b/app/assets/javascripts/registry/stores/mutations.js
@@ -2,7 +2,6 @@ import * as types from './mutation_types';
import { parseIntPagination, normalizeHeaders } from '../../lib/utils/common_utils';
export default {
-
[types.SET_MAIN_ENDPOINT](state, endpoint) {
Object.assign(state, { endpoint });
},
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 fb8c6402d02..bd204503cc7 100644
--- a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
+++ b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
@@ -1,79 +1,72 @@
<script>
- import { mapActions, mapGetters, mapState } from 'vuex';
- import { s__ } from '~/locale';
- import { componentNames } from './issue_body';
- import ReportSection from './report_section.vue';
- import SummaryRow from './summary_row.vue';
- import IssuesList from './issues_list.vue';
- import Modal from './modal.vue';
- import createStore from '../store';
- import { summaryTextBuilder, reportTextBuilder, statusIcon } from '../store/utils';
+import { mapActions, mapGetters, mapState } from 'vuex';
+import { s__ } from '~/locale';
+import { componentNames } from './issue_body';
+import ReportSection from './report_section.vue';
+import SummaryRow from './summary_row.vue';
+import IssuesList from './issues_list.vue';
+import Modal from './modal.vue';
+import createStore from '../store';
+import { summaryTextBuilder, reportTextBuilder, statusIcon } from '../store/utils';
- export default {
- name: 'GroupedTestReportsApp',
- store: createStore(),
- components: {
- ReportSection,
- SummaryRow,
- IssuesList,
- Modal,
+export default {
+ name: 'GroupedTestReportsApp',
+ store: createStore(),
+ components: {
+ ReportSection,
+ SummaryRow,
+ IssuesList,
+ Modal,
+ },
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
},
- props: {
- endpoint: {
- type: String,
- required: true,
- },
- },
- componentNames,
- computed: {
- ...mapState([
- 'reports',
- 'isLoading',
- 'hasError',
- 'summary',
- ]),
- ...mapState({
- modalTitle: state => state.modal.title || '',
- modalData: state => state.modal.data || {},
- }),
- ...mapGetters([
- 'summaryStatus',
- ]),
- groupedSummaryText() {
- if (this.isLoading) {
- return s__('Reports|Test summary results are being parsed');
- }
+ },
+ componentNames,
+ computed: {
+ ...mapState(['reports', 'isLoading', 'hasError', 'summary']),
+ ...mapState({
+ modalTitle: state => state.modal.title || '',
+ modalData: state => state.modal.data || {},
+ }),
+ ...mapGetters(['summaryStatus']),
+ groupedSummaryText() {
+ if (this.isLoading) {
+ return s__('Reports|Test summary results are being parsed');
+ }
- if (this.hasError) {
- return s__('Reports|Test summary failed loading results');
- }
+ if (this.hasError) {
+ return s__('Reports|Test summary failed loading results');
+ }
- return summaryTextBuilder(s__('Reports|Test summary'), this.summary);
- },
+ return summaryTextBuilder(s__('Reports|Test summary'), this.summary);
},
- created() {
- this.setEndpoint(this.endpoint);
+ },
+ created() {
+ this.setEndpoint(this.endpoint);
- this.fetchReports();
+ this.fetchReports();
+ },
+ methods: {
+ ...mapActions(['setEndpoint', 'fetchReports']),
+ reportText(report) {
+ const summary = report.summary || {};
+ return reportTextBuilder(report.name, summary);
+ },
+ getReportIcon(report) {
+ return statusIcon(report.status);
},
- methods: {
- ...mapActions(['setEndpoint', 'fetchReports']),
- reportText(report) {
- const summary = report.summary || {};
- return reportTextBuilder(report.name, summary);
- },
- getReportIcon(report) {
- return statusIcon(report.status);
- },
- shouldRenderIssuesList(report) {
- return (
- report.existing_failures.length > 0 ||
- report.new_failures.length > 0 ||
- report.resolved_failures.length > 0
- );
- },
+ shouldRenderIssuesList(report) {
+ return (
+ report.existing_failures.length > 0 ||
+ report.new_failures.length > 0 ||
+ report.resolved_failures.length > 0
+ );
},
- };
+ },
+};
</script>
<template>
<report-section
@@ -82,7 +75,7 @@
:loading-text="groupedSummaryText"
:error-text="groupedSummaryText"
:has-issues="reports.length > 0"
- class="mr-widget-border-top grouped-security-reports mr-report"
+ class="mr-widget-section grouped-security-reports mr-report"
>
<div
slot="body"
diff --git a/app/assets/javascripts/reports/components/issue_status_icon.vue b/app/assets/javascripts/reports/components/issue_status_icon.vue
index 85811698a37..6e143c4f98c 100644
--- a/app/assets/javascripts/reports/components/issue_status_icon.vue
+++ b/app/assets/javascripts/reports/components/issue_status_icon.vue
@@ -1,10 +1,6 @@
<script>
import Icon from '~/vue_shared/components/icon.vue';
-import {
- STATUS_FAILED,
- STATUS_NEUTRAL,
- STATUS_SUCCESS,
-} from '../constants';
+import { STATUS_FAILED, STATUS_NEUTRAL, STATUS_SUCCESS } from '../constants';
export default {
name: 'IssueStatusIcon',
diff --git a/app/assets/javascripts/reports/components/issues_list.vue b/app/assets/javascripts/reports/components/issues_list.vue
index df42201b5de..3b425ee2fed 100644
--- a/app/assets/javascripts/reports/components/issues_list.vue
+++ b/app/assets/javascripts/reports/components/issues_list.vue
@@ -1,10 +1,6 @@
<script>
import IssuesBlock from '~/reports/components/report_issues.vue';
-import {
- STATUS_SUCCESS,
- STATUS_FAILED,
- STATUS_NEUTRAL,
-} from '~/reports/constants';
+import { STATUS_SUCCESS, STATUS_FAILED, STATUS_NEUTRAL } from '~/reports/constants';
/**
* Renders block of issues
diff --git a/app/assets/javascripts/reports/components/modal.vue b/app/assets/javascripts/reports/components/modal.vue
index acc5c6d85e2..5f9e4072b2d 100644
--- a/app/assets/javascripts/reports/components/modal.vue
+++ b/app/assets/javascripts/reports/components/modal.vue
@@ -1,27 +1,27 @@
<script>
- import Modal from '~/vue_shared/components/gl_modal.vue';
- import LoadingButton from '~/vue_shared/components/loading_button.vue';
- import CodeBlock from '~/vue_shared/components/code_block.vue';
- import { fieldTypes } from '../constants';
+import Modal from '~/vue_shared/components/gl_modal.vue';
+import LoadingButton from '~/vue_shared/components/loading_button.vue';
+import CodeBlock from '~/vue_shared/components/code_block.vue';
+import { fieldTypes } from '../constants';
- export default {
- components: {
- Modal,
- LoadingButton,
- CodeBlock,
+export default {
+ components: {
+ Modal,
+ LoadingButton,
+ CodeBlock,
+ },
+ props: {
+ title: {
+ type: String,
+ required: true,
},
- props: {
- title: {
- type: String,
- required: true,
- },
- modalData: {
- type: Object,
- required: true,
- },
+ modalData: {
+ type: Object,
+ required: true,
},
- fieldTypes,
- };
+ },
+ fieldTypes,
+};
</script>
<template>
<modal
diff --git a/app/assets/javascripts/reports/components/test_issue_body.vue b/app/assets/javascripts/reports/components/test_issue_body.vue
index cd443a49b52..1a87822fcc3 100644
--- a/app/assets/javascripts/reports/components/test_issue_body.vue
+++ b/app/assets/javascripts/reports/components/test_issue_body.vue
@@ -1,28 +1,28 @@
<script>
- import { mapActions } from 'vuex';
+import { mapActions } from 'vuex';
- export default {
- name: 'TestIssueBody',
- props: {
- issue: {
- type: Object,
- required: true,
- },
- // failed || success
- status: {
- type: String,
- required: true,
- },
- isNew: {
- type: Boolean,
- required: false,
- default: false,
- },
+export default {
+ name: 'TestIssueBody',
+ props: {
+ issue: {
+ type: Object,
+ required: true,
},
- methods: {
- ...mapActions(['openModal']),
+ // failed || success
+ status: {
+ type: String,
+ required: true,
},
- };
+ isNew: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ methods: {
+ ...mapActions(['openModal']),
+ },
+};
</script>
<template>
<div class="report-block-list-issue-description prepend-top-5 append-bottom-5">
diff --git a/app/assets/javascripts/reports/store/actions.js b/app/assets/javascripts/reports/store/actions.js
index acabcc1d193..db8ab5ccb80 100644
--- a/app/assets/javascripts/reports/store/actions.js
+++ b/app/assets/javascripts/reports/store/actions.js
@@ -43,9 +43,11 @@ export const fetchReports = ({ state, dispatch }) => {
},
data: state.endpoint,
method: 'getReports',
- successCallback: ({ data, status }) => dispatch('receiveReportsSuccess', {
- data, status,
- }),
+ successCallback: ({ data, status }) =>
+ dispatch('receiveReportsSuccess', {
+ data,
+ status,
+ }),
errorCallback: () => dispatch('receiveReportsError'),
});
diff --git a/app/assets/javascripts/reports/store/index.js b/app/assets/javascripts/reports/store/index.js
index 9d8f7dc3b74..467c692b438 100644
--- a/app/assets/javascripts/reports/store/index.js
+++ b/app/assets/javascripts/reports/store/index.js
@@ -7,9 +7,10 @@ import state from './state';
Vue.use(Vuex);
-export default () => new Vuex.Store({
- actions,
- mutations,
- getters,
- state: state(),
-});
+export default () =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ getters,
+ state: state(),
+ });
diff --git a/app/assets/javascripts/reports/store/mutation_types.js b/app/assets/javascripts/reports/store/mutation_types.js
index 82bda31df5d..599d4862dfe 100644
--- a/app/assets/javascripts/reports/store/mutation_types.js
+++ b/app/assets/javascripts/reports/store/mutation_types.js
@@ -4,4 +4,3 @@ export const REQUEST_REPORTS = 'REQUEST_REPORTS';
export const RECEIVE_REPORTS_SUCCESS = 'RECEIVE_REPORTS_SUCCESS';
export const RECEIVE_REPORTS_ERROR = 'RECEIVE_REPORTS_ERROR';
export const SET_ISSUE_MODAL_DATA = 'SET_ISSUE_MODAL_DATA';
-
diff --git a/app/assets/javascripts/reports/store/mutations.js b/app/assets/javascripts/reports/store/mutations.js
index b88bff97075..2a37f5b74fa 100644
--- a/app/assets/javascripts/reports/store/mutations.js
+++ b/app/assets/javascripts/reports/store/mutations.js
@@ -19,7 +19,6 @@ export default {
state.status = response.status;
state.reports = response.suites;
-
},
[types.RECEIVE_REPORTS_ERROR](state) {
state.isLoading = false;
@@ -36,7 +35,7 @@ export default {
[types.SET_ISSUE_MODAL_DATA](state, payload) {
state.modal.title = payload.issue.name;
- Object.keys(payload.issue).forEach((key) => {
+ Object.keys(payload.issue).forEach(key => {
if (Object.prototype.hasOwnProperty.call(state.modal.data, key)) {
state.modal.data[key] = {
...state.modal.data[key],
diff --git a/app/assets/javascripts/reports/store/state.js b/app/assets/javascripts/reports/store/state.js
index 4cab2e27a16..5484900276c 100644
--- a/app/assets/javascripts/reports/store/state.js
+++ b/app/assets/javascripts/reports/store/state.js
@@ -57,5 +57,4 @@ export default () => ({
},
},
},
-
});
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 64f3dde5be7..6b3753f7966 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -57,8 +57,6 @@ Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
$allGutterToggleIcons.removeClass('fa-angle-double-left').addClass('fa-angle-double-right');
$('aside.right-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
$('.layout-page').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
-
- if (gl.lazyLoader) gl.lazyLoader.loadCheck();
}
$this.attr('data-original-title', tooltipLabel);
diff --git a/app/assets/javascripts/settings_panels.js b/app/assets/javascripts/settings_panels.js
index 37b4a2a4c63..d22aca35e09 100644
--- a/app/assets/javascripts/settings_panels.js
+++ b/app/assets/javascripts/settings_panels.js
@@ -1,21 +1,27 @@
import $ from 'jquery';
+import { __ } from './locale';
function expandSection($section) {
- $section.find('.js-settings-toggle').text('Collapse');
- $section.find('.settings-content').off('scroll.expandSection').scrollTop(0);
+ $section.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)').text(__('Collapse'));
+ $section
+ .find('.settings-content')
+ .off('scroll.expandSection')
+ .scrollTop(0);
$section.addClass('expanded');
if (!$section.hasClass('no-animate')) {
- $section.addClass('animating')
+ $section
+ .addClass('animating')
.one('animationend.animateSection', () => $section.removeClass('animating'));
}
}
function closeSection($section) {
- $section.find('.js-settings-toggle').text('Expand');
+ $section.find('.js-settings-toggle:not(.js-settings-toggle-trigger-only)').text(__('Expand'));
$section.find('.settings-content').on('scroll.expandSection', () => expandSection($section));
$section.removeClass('expanded');
if (!$section.hasClass('no-animate')) {
- $section.addClass('animating')
+ $section
+ .addClass('animating')
.one('animationend.animateSection', () => $section.removeClass('animating'));
}
}
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
index 123c92aff64..cfa7029b388 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
@@ -69,7 +69,8 @@ export default {
this.loading = false;
}
- this.mediator.saveAssignees(this.field)
+ this.mediator
+ .saveAssignees(this.field)
.then(setLoadingFalse.bind(this))
.catch(() => {
setLoadingFalse();
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 2b8d6207dea..439e8a69df0 100644
--- a/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/confidential_issue_sidebar.vue
@@ -56,11 +56,7 @@ export default {
.update('issue', { confidential })
.then(() => window.location.reload())
.catch(() => {
- Flash(
- __(
- 'Something went wrong trying to change the confidentiality of this issue',
- ),
- );
+ Flash(__('Something went wrong trying to change the confidentiality of this issue'));
});
},
},
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 ab7fab7e5ca..48a2b9194aa 100644
--- a/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue
+++ b/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue
@@ -34,11 +34,7 @@ export default {
required: true,
type: Object,
validator(mediatorObject) {
- return (
- mediatorObject.service &&
- mediatorObject.service.update &&
- mediatorObject.store
- );
+ return mediatorObject.service && mediatorObject.service.update && mediatorObject.store;
},
},
},
@@ -67,8 +63,7 @@ export default {
methods: {
toggleForm() {
- this.mediator.store.isLockDialogOpen = !this.mediator.store
- .isLockDialogOpen;
+ this.mediator.store.isLockDialogOpen = !this.mediator.store.isLockDialogOpen;
},
updateLockedAttribute(locked) {
@@ -79,9 +74,14 @@ export default {
.then(() => window.location.reload())
.catch(() =>
Flash(
- sprintf(__('Something went wrong trying to change the locked state of this %{issuableDisplayName}'), {
- issuableDisplayName: this.issuableDisplayName,
- }),
+ sprintf(
+ __(
+ 'Something went wrong trying to change the locked state of this %{issuableDisplayName}',
+ ),
+ {
+ issuableDisplayName: this.issuableDisplayName,
+ },
+ ),
),
);
},
@@ -102,7 +102,6 @@ export default {
>
<icon
:name="lockIcon"
- aria-hidden="true"
class="sidebar-item-icon is-active"
/>
</div>
@@ -134,7 +133,6 @@ export default {
<icon
:size="16"
name="lock"
- aria-hidden="true"
class="sidebar-item-icon inline is-active"
/>
{{ __('Locked') }}
@@ -147,7 +145,6 @@ export default {
<icon
:size="16"
name="lock-open"
- aria-hidden="true"
class="sidebar-item-icon inline"
/>
{{ __('Unlocked') }}
diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue
index 286a16f7bbf..11b5dbe5f8e 100644
--- a/app/assets/javascripts/sidebar/components/participants/participants.vue
+++ b/app/assets/javascripts/sidebar/components/participants/participants.vue
@@ -1,78 +1,78 @@
<script>
- 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 { __, n__, sprintf } from '~/locale';
+import tooltip from '~/vue_shared/directives/tooltip';
+import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
- export default {
- directives: {
- tooltip,
+export default {
+ directives: {
+ tooltip,
+ },
+ components: {
+ userAvatarImage,
+ },
+ props: {
+ loading: {
+ type: Boolean,
+ required: false,
+ default: false,
},
- components: {
- userAvatarImage,
+ participants: {
+ type: Array,
+ required: false,
+ default: () => [],
},
- props: {
- loading: {
- type: Boolean,
- required: false,
- default: false,
- },
- participants: {
- type: Array,
- required: false,
- default: () => [],
- },
- numberOfLessParticipants: {
- type: Number,
- required: false,
- default: 7,
- },
+ numberOfLessParticipants: {
+ type: Number,
+ required: false,
+ default: 7,
},
- data() {
- return {
- isShowingMoreParticipants: false,
- };
+ },
+ data() {
+ return {
+ isShowingMoreParticipants: false,
+ };
+ },
+ computed: {
+ lessParticipants() {
+ return this.participants.slice(0, this.numberOfLessParticipants);
},
- computed: {
- lessParticipants() {
- return this.participants.slice(0, this.numberOfLessParticipants);
- },
- visibleParticipants() {
- return this.isShowingMoreParticipants ? this.participants : this.lessParticipants;
- },
- hasMoreParticipants() {
- return this.participants.length > this.numberOfLessParticipants;
- },
- toggleLabel() {
- let label = '';
- if (this.isShowingMoreParticipants) {
- label = __('- show less');
- } else {
- label = sprintf(__('+ %{moreCount} more'), {
- moreCount: this.participants.length - this.numberOfLessParticipants,
- });
- }
+ visibleParticipants() {
+ return this.isShowingMoreParticipants ? this.participants : this.lessParticipants;
+ },
+ hasMoreParticipants() {
+ return this.participants.length > this.numberOfLessParticipants;
+ },
+ toggleLabel() {
+ let label = '';
+ if (this.isShowingMoreParticipants) {
+ label = __('- show less');
+ } else {
+ label = sprintf(__('+ %{moreCount} more'), {
+ moreCount: this.participants.length - this.numberOfLessParticipants,
+ });
+ }
- return label;
- },
- participantLabel() {
- return sprintf(
- n__('%{count} participant', '%{count} participants', this.participants.length),
- { count: this.loading ? '' : this.participantCount },
- );
- },
- participantCount() {
- return this.participants.length;
- },
+ return label;
+ },
+ participantLabel() {
+ return sprintf(
+ n__('%{count} participant', '%{count} participants', this.participants.length),
+ { count: this.loading ? '' : this.participantCount },
+ );
+ },
+ participantCount() {
+ return this.participants.length;
+ },
+ },
+ methods: {
+ toggleMoreParticipants() {
+ this.isShowingMoreParticipants = !this.isShowingMoreParticipants;
},
- methods: {
- toggleMoreParticipants() {
- this.isShowingMoreParticipants = !this.isShowingMoreParticipants;
- },
- onClickCollapsedIcon() {
- this.$emit('toggleSidebar');
- },
+ onClickCollapsedIcon() {
+ this.$emit('toggleSidebar');
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/sidebar/components/participants/sidebar_participants.vue b/app/assets/javascripts/sidebar/components/participants/sidebar_participants.vue
index 5c1ead1a8ac..4ac515e552a 100644
--- a/app/assets/javascripts/sidebar/components/participants/sidebar_participants.vue
+++ b/app/assets/javascripts/sidebar/components/participants/sidebar_participants.vue
@@ -1,23 +1,23 @@
<script>
- import Store from '../../stores/sidebar_store';
- import participants from './participants.vue';
+import Store from '../../stores/sidebar_store';
+import participants from './participants.vue';
- export default {
- components: {
- participants,
+export default {
+ components: {
+ participants,
+ },
+ props: {
+ mediator: {
+ type: Object,
+ required: true,
},
- props: {
- mediator: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- store: new Store(),
- };
- },
- };
+ },
+ data() {
+ return {
+ store: new Store(),
+ };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue
index 385717e7c1e..95a2c8cce6e 100644
--- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue
+++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions.vue
@@ -21,10 +21,9 @@ export default {
},
methods: {
onToggleSubscription() {
- this.mediator.toggleSubscription()
- .catch(() => {
- Flash(__('Error occurred when toggling the notification subscription'));
- });
+ this.mediator.toggleSubscription().catch(() => {
+ Flash(__('Error occurred when toggling the notification subscription'));
+ });
},
},
};
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 1d030c4f67f..259858e4b46 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
@@ -1,111 +1,111 @@
<script>
- import { __, sprintf } from '~/locale';
- import { abbreviateTime } from '~/lib/utils/pretty_time';
- import icon from '~/vue_shared/components/icon.vue';
- import tooltip from '~/vue_shared/directives/tooltip';
+import { __, sprintf } from '~/locale';
+import { abbreviateTime } from '~/lib/utils/datetime_utility';
+import icon from '~/vue_shared/components/icon.vue';
+import tooltip from '~/vue_shared/directives/tooltip';
- export default {
- name: 'TimeTrackingCollapsedState',
- components: {
- icon,
+export default {
+ name: 'TimeTrackingCollapsedState',
+ components: {
+ icon,
+ },
+ directives: {
+ tooltip,
+ },
+ props: {
+ showComparisonState: {
+ type: Boolean,
+ required: true,
},
- directives: {
- tooltip,
+ showSpentOnlyState: {
+ type: Boolean,
+ required: true,
},
- props: {
- showComparisonState: {
- type: Boolean,
- required: true,
- },
- showSpentOnlyState: {
- type: Boolean,
- required: true,
- },
- showEstimateOnlyState: {
- type: Boolean,
- required: true,
- },
- showNoTimeTrackingState: {
- type: Boolean,
- required: true,
- },
- timeSpentHumanReadable: {
- type: String,
- required: false,
- default: '',
- },
- timeEstimateHumanReadable: {
- type: String,
- required: false,
- default: '',
- },
+ showEstimateOnlyState: {
+ type: Boolean,
+ required: true,
},
- computed: {
- timeSpent() {
- return this.abbreviateTime(this.timeSpentHumanReadable);
- },
- timeEstimate() {
- return this.abbreviateTime(this.timeEstimateHumanReadable);
- },
- divClass() {
- if (this.showComparisonState) {
- return 'compare';
- } else if (this.showEstimateOnlyState) {
- return 'estimate-only';
- } else if (this.showSpentOnlyState) {
- return 'spend-only';
- } else if (this.showNoTimeTrackingState) {
- return 'no-tracking';
- }
+ showNoTimeTrackingState: {
+ type: Boolean,
+ required: true,
+ },
+ timeSpentHumanReadable: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ timeEstimateHumanReadable: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ timeSpent() {
+ return this.abbreviateTime(this.timeSpentHumanReadable);
+ },
+ timeEstimate() {
+ return this.abbreviateTime(this.timeEstimateHumanReadable);
+ },
+ divClass() {
+ if (this.showComparisonState) {
+ return 'compare';
+ } else if (this.showEstimateOnlyState) {
+ return 'estimate-only';
+ } else if (this.showSpentOnlyState) {
+ return 'spend-only';
+ } else if (this.showNoTimeTrackingState) {
+ return 'no-tracking';
+ }
+ return '';
+ },
+ spanClass() {
+ if (this.showComparisonState) {
return '';
- },
- spanClass() {
- if (this.showComparisonState) {
- return '';
- } else if (this.showEstimateOnlyState || this.showSpentOnlyState) {
- return 'bold';
- } else if (this.showNoTimeTrackingState) {
- return 'no-value';
- }
+ } else if (this.showEstimateOnlyState || this.showSpentOnlyState) {
+ return 'bold';
+ } else if (this.showNoTimeTrackingState) {
+ return 'no-value';
+ }
- return '';
- },
- text() {
- if (this.showComparisonState) {
- return `${this.timeSpent} / ${this.timeEstimate}`;
- } else if (this.showEstimateOnlyState) {
- return `-- / ${this.timeEstimate}`;
- } else if (this.showSpentOnlyState) {
- return `${this.timeSpent} / --`;
- } else if (this.showNoTimeTrackingState) {
- return 'None';
- }
+ return '';
+ },
+ text() {
+ if (this.showComparisonState) {
+ return `${this.timeSpent} / ${this.timeEstimate}`;
+ } else if (this.showEstimateOnlyState) {
+ return `-- / ${this.timeEstimate}`;
+ } else if (this.showSpentOnlyState) {
+ return `${this.timeSpent} / --`;
+ } else if (this.showNoTimeTrackingState) {
+ return 'None';
+ }
- return '';
- },
- timeTrackedTooltipText() {
- let title;
- if (this.showComparisonState) {
- title = __('Time remaining');
- } else if (this.showEstimateOnlyState) {
- title = __('Estimated');
- } else if (this.showSpentOnlyState) {
- title = __('Time spent');
- }
+ return '';
+ },
+ timeTrackedTooltipText() {
+ let title;
+ if (this.showComparisonState) {
+ title = __('Time remaining');
+ } else if (this.showEstimateOnlyState) {
+ title = __('Estimated');
+ } else if (this.showSpentOnlyState) {
+ title = __('Time spent');
+ }
- return sprintf('%{title}: %{text}', ({ title, text: this.text }));
- },
- tooltipText() {
- return this.showNoTimeTrackingState ? __('Time tracking') : this.timeTrackedTooltipText;
- },
+ return sprintf('%{title}: %{text}', { title, text: this.text });
+ },
+ tooltipText() {
+ return this.showNoTimeTrackingState ? __('Time tracking') : this.timeTrackedTooltipText;
},
- methods: {
- abbreviateTime(timeStr) {
- return abbreviateTime(timeStr);
- },
+ },
+ methods: {
+ abbreviateTime(timeStr) {
+ return abbreviateTime(timeStr);
},
- };
+ },
+};
</script>
<template>
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 dc599e1b9fc..e74912d628f 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
@@ -1,5 +1,5 @@
<script>
-import { parseSeconds, stringifyTime } from '../../../lib/utils/pretty_time';
+import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
import tooltip from '../../../vue_shared/directives/tooltip';
export default {
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 19ec0f05a26..91909cd49b8 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/help_state.vue
@@ -15,16 +15,22 @@ export default {
},
estimateText() {
return sprintf(
- s__('estimateCommand|%{slash_command} will update the estimated time with the latest command.'), {
+ s__(
+ 'estimateCommand|%{slash_command} will update the estimated time with the latest command.',
+ ),
+ {
slash_command: '<code>/estimate</code>',
- }, false,
+ },
+ false,
);
},
spendText() {
return sprintf(
- s__('spendCommand|%{slash_command} will update the sum of the time spent.'), {
+ s__('spendCommand|%{slash_command} will update the sum of the time spent.'),
+ {
slash_command: '<code>/spend</code>',
- }, false,
+ },
+ false,
);
},
},
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
index 8660b0546cf..8e8b9f19b6e 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
@@ -26,7 +26,7 @@ export default {
methods: {
listenForQuickActions() {
$(document).on('ajax:success', '.gfm-form', this.quickActionListened);
- eventHub.$on('timeTrackingUpdated', (data) => {
+ eventHub.$on('timeTrackingUpdated', data => {
this.quickActionListened(null, data);
});
},
@@ -34,9 +34,7 @@ export default {
const subscribedCommands = ['spend_time', 'time_estimate'];
let changedCommands;
if (data !== undefined) {
- changedCommands = data.commands_changes
- ? Object.keys(data.commands_changes)
- : [];
+ changedCommands = data.commands_changes ? Object.keys(data.commands_changes) : [];
} else {
changedCommands = [];
}
diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue
index a6b3a674952..bc59774f0a8 100644
--- a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue
+++ b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue
@@ -41,9 +41,9 @@ export default {
},
computed: {
buttonClasses() {
- return this.collapsed ?
- 'btn-blank btn-todo sidebar-collapsed-icon dont-change-state' :
- 'btn btn-default btn-todo issuable-header-btn float-right';
+ return this.collapsed
+ ? 'btn-blank btn-todo sidebar-collapsed-icon dont-change-state'
+ : 'btn btn-default btn-todo issuable-header-btn float-right';
},
buttonLabel() {
return this.isTodo ? MARK_TEXT : TODO_TEXT;
diff --git a/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js b/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js
index b267422cd97..225ebb61195 100644
--- a/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js
+++ b/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js
@@ -37,7 +37,8 @@ class SidebarMoveIssue {
// Keep the dropdown open after selecting an option
shouldPropagate: false,
data: (searchTerm, callback) => {
- this.mediator.fetchAutocompleteProjects(searchTerm)
+ this.mediator
+ .fetchAutocompleteProjects(searchTerm)
.then(callback)
.catch(() => new window.Flash('An error occurred while fetching projects autocomplete.'));
},
@@ -48,7 +49,7 @@ class SidebarMoveIssue {
</a>
</li>
`,
- clicked: (options) => {
+ clicked: options => {
const project = options.selectedObj;
const selectedProjectId = options.isMarking ? project.id : 0;
this.mediator.setMoveToProjectId(selectedProjectId);
@@ -68,17 +69,12 @@ class SidebarMoveIssue {
onConfirmClicked() {
if (isValidProjectId(this.mediator.store.moveToProjectId)) {
- this.$confirmButton
- .disable()
- .addClass('is-loading');
+ this.$confirmButton.disable().addClass('is-loading');
- this.mediator.moveIssue()
- .catch(() => {
- window.Flash('An error occurred while moving the issue.');
- this.$confirmButton
- .enable()
- .removeClass('is-loading');
- });
+ this.mediator.moveIssue().catch(() => {
+ window.Flash('An error occurred while moving the issue.');
+ this.$confirmButton.enable().removeClass('is-loading');
+ });
}
}
}
diff --git a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
index 87da65a1b1f..1ebdbec7bc9 100644
--- a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
@@ -15,15 +15,16 @@ export default class SidebarMilestone {
components: {
timeTracker,
},
- render: createElement => createElement('timeTracker', {
- props: {
- timeEstimate: parseInt(timeEstimate, 10),
- timeSpent: parseInt(timeSpent, 10),
- humanTimeEstimate,
- humanTimeSpent,
- rootPath: '/',
- },
- }),
+ render: createElement =>
+ createElement('timeTracker', {
+ props: {
+ timeEstimate: parseInt(timeEstimate, 10),
+ timeSpent: parseInt(timeSpent, 10),
+ humanTimeEstimate,
+ humanTimeSpent,
+ rootPath: '/',
+ },
+ }),
});
}
}
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 655bf9198b7..6f8214b18ee 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -22,14 +22,15 @@ function mountAssigneesComponent(mediator) {
components: {
SidebarAssignees,
},
- render: createElement => createElement('sidebar-assignees', {
- props: {
- mediator,
- field: el.dataset.field,
- signedIn: el.hasAttribute('data-signed-in'),
- issuableType: gl.utils.isInIssuePage() ? 'issue' : 'merge_request',
- },
- }),
+ render: createElement =>
+ createElement('sidebar-assignees', {
+ props: {
+ mediator,
+ field: el.dataset.field,
+ signedIn: el.hasAttribute('data-signed-in'),
+ issuableType: gl.utils.isInIssuePage() ? 'issue' : 'merge_request',
+ },
+ }),
});
}
@@ -83,11 +84,12 @@ function mountParticipantsComponent(mediator) {
components: {
sidebarParticipants,
},
- render: createElement => createElement('sidebar-participants', {
- props: {
- mediator,
- },
- }),
+ render: createElement =>
+ createElement('sidebar-participants', {
+ props: {
+ mediator,
+ },
+ }),
});
}
@@ -102,11 +104,12 @@ function mountSubscriptionsComponent(mediator) {
components: {
sidebarSubscriptions,
},
- render: createElement => createElement('sidebar-subscriptions', {
- props: {
- mediator,
- },
- }),
+ render: createElement =>
+ createElement('sidebar-subscriptions', {
+ props: {
+ mediator,
+ },
+ }),
});
}
diff --git a/app/assets/javascripts/sidebar/services/sidebar_service.js b/app/assets/javascripts/sidebar/services/sidebar_service.js
index 37c97225bfd..cbe20f761ff 100644
--- a/app/assets/javascripts/sidebar/services/sidebar_service.js
+++ b/app/assets/javascripts/sidebar/services/sidebar_service.js
@@ -22,11 +22,15 @@ export default class SidebarService {
}
update(key, data) {
- return Vue.http.put(this.endpoint, {
- [key]: data,
- }, {
- emulateJSON: true,
- });
+ return Vue.http.put(
+ this.endpoint,
+ {
+ [key]: data,
+ },
+ {
+ emulateJSON: true,
+ },
+ );
}
getProjectsAutocomplete(searchTerm) {
diff --git a/app/assets/javascripts/single_file_diff.js b/app/assets/javascripts/single_file_diff.js
index 99c93952e2a..f2b9d75dd00 100644
--- a/app/assets/javascripts/single_file_diff.js
+++ b/app/assets/javascripts/single_file_diff.js
@@ -10,8 +10,10 @@ import syntaxHighlight from './syntax_highlight';
const WRAPPER = '<div class="diff-content"></div>';
const LOADING_HTML = '<i class="fa fa-spinner fa-spin"></i>';
-const ERROR_HTML = '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>';
-const COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <button class="click-to-expand btn btn-link">Click to expand it.</button></div>';
+const ERROR_HTML =
+ '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>';
+const COLLAPSED_HTML =
+ '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <button class="click-to-expand btn btn-link">Click to expand it.</button></div>';
export default class SingleFileDiff {
constructor(file) {
@@ -23,23 +25,36 @@ export default class SingleFileDiff {
this.isOpen = !this.diffForPath;
if (this.diffForPath) {
this.collapsedContent = this.content;
- this.loadingContent = $(WRAPPER).addClass('loading').html(LOADING_HTML).hide();
+ this.loadingContent = $(WRAPPER)
+ .addClass('loading')
+ .html(LOADING_HTML)
+ .hide();
this.content = null;
this.collapsedContent.after(this.loadingContent);
this.$toggleIcon.addClass('fa-caret-right');
} else {
- this.collapsedContent = $(WRAPPER).html(COLLAPSED_HTML).hide();
+ this.collapsedContent = $(WRAPPER)
+ .html(COLLAPSED_HTML)
+ .hide();
this.content.after(this.collapsedContent);
this.$toggleIcon.addClass('fa-caret-down');
}
- $('.js-file-title, .click-to-expand', this.file).on('click', (function (e) {
- this.toggleDiff($(e.target));
- }).bind(this));
+ $('.js-file-title, .click-to-expand', this.file).on(
+ 'click',
+ function(e) {
+ this.toggleDiff($(e.target));
+ }.bind(this),
+ );
}
toggleDiff($target, cb) {
- if (!$target.hasClass('js-file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
+ if (
+ !$target.hasClass('js-file-title') &&
+ !$target.hasClass('click-to-expand') &&
+ !$target.hasClass('diff-toggle-caret')
+ )
+ return;
this.isOpen = !this.isOpen;
if (!this.isOpen && !this.hasError) {
this.content.hide();
@@ -65,7 +80,8 @@ export default class SingleFileDiff {
this.collapsedContent.hide();
this.loadingContent.show();
- axios.get(this.diffForPath)
+ axios
+ .get(this.diffForPath)
.then(({ data }) => {
this.loadingContent.hide();
if (data.html) {
diff --git a/app/assets/javascripts/smart_interval.js b/app/assets/javascripts/smart_interval.js
index 5e385400747..8ca590123ae 100644
--- a/app/assets/javascripts/smart_interval.js
+++ b/app/assets/javascripts/smart_interval.js
@@ -93,7 +93,9 @@ export default class SmartInterval {
destroy() {
this.cancel();
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
- $(document).off('visibilitychange').off('beforeunload');
+ $(document)
+ .off('visibilitychange')
+ .off('beforeunload');
}
/* private */
@@ -111,11 +113,12 @@ export default class SmartInterval {
triggerCallback() {
this.isLoading = true;
- this.cfg.callback()
+ this.cfg
+ .callback()
.then(() => {
this.isLoading = false;
})
- .catch((err) => {
+ .catch(err => {
this.isLoading = false;
throw err;
});
@@ -134,9 +137,9 @@ export default class SmartInterval {
handleVisibilityChange(e) {
this.state.pageVisibility = e.target.visibilityState;
- const intervalAction = this.isPageVisible() ?
- this.onVisibilityVisible :
- this.onVisibilityHidden;
+ const intervalAction = this.isPageVisible()
+ ? this.onVisibilityVisible
+ : this.onVisibilityHidden;
intervalAction.apply(this);
}
@@ -162,7 +165,9 @@ export default class SmartInterval {
this.setCurrentInterval(nextInterval);
}
- isPageVisible() { return this.state.pageVisibility === 'visible'; }
+ isPageVisible() {
+ return this.state.pageVisibility === 'visible';
+ }
stopTimer() {
const { state } = this;
@@ -170,4 +175,3 @@ export default class SmartInterval {
state.intervalId = window.clearInterval(state.intervalId);
}
}
-
diff --git a/app/assets/javascripts/star.js b/app/assets/javascripts/star.js
index f5a7fdae5d7..007b83e1927 100644
--- a/app/assets/javascripts/star.js
+++ b/app/assets/javascripts/star.js
@@ -11,10 +11,14 @@ export default class Star {
const $starSpan = $this.find('span');
const $startIcon = $this.find('svg');
- axios.post($this.data('endpoint'))
+ axios
+ .post($this.data('endpoint'))
.then(({ data }) => {
const isStarred = $starSpan.hasClass('starred');
- $this.parent().find('.star-count').text(data.star_count);
+ $this
+ .parent()
+ .find('.star-count')
+ .text(data.star_count);
if (isStarred) {
$starSpan.removeClass('starred').text(s__('StarProject|Star'));
diff --git a/app/assets/javascripts/task_list.js b/app/assets/javascripts/task_list.js
index 48782e63b9b..edefb3735d7 100644
--- a/app/assets/javascripts/task_list.js
+++ b/app/assets/javascripts/task_list.js
@@ -26,7 +26,11 @@ export default class TaskList {
// Prevent duplicate event bindings
this.disable();
$(`${this.selector} .js-task-list-container`).taskList('enable');
- $(document).on('tasklist:changed', `${this.selector} .js-task-list-container`, this.update.bind(this));
+ $(document).on(
+ 'tasklist:changed',
+ `${this.selector} .js-task-list-container`,
+ this.update.bind(this),
+ );
}
disable() {
@@ -41,7 +45,8 @@ export default class TaskList {
[this.fieldName]: $target.val(),
};
- return axios.patch($target.data('updateUrl') || $('form.js-issuable-update').attr('action'), patchData)
+ return axios
+ .patch($target.data('updateUrl') || $('form.js-issuable-update').attr('action'), patchData)
.then(({ data }) => this.onSuccess(data))
.catch(err => this.onError(err));
}
diff --git a/app/assets/javascripts/templates/issuable_template_selector.js b/app/assets/javascripts/templates/issuable_template_selector.js
index 74166313940..6065770e68d 100644
--- a/app/assets/javascripts/templates/issuable_template_selector.js
+++ b/app/assets/javascripts/templates/issuable_template_selector.js
@@ -31,12 +31,18 @@ export default class IssuableTemplateSelector extends TemplateSelector {
requestFile(query) {
this.startLoadingSpinner();
- Api.issueTemplate(this.namespacePath, this.projectPath, query.name, this.issuableType, (err, currentTemplate) => {
- this.currentTemplate = currentTemplate;
- this.stopLoadingSpinner();
- if (err) return; // Error handled by global AJAX error handler
- this.setInputValueToTemplateContent();
- });
+ Api.issueTemplate(
+ this.namespacePath,
+ this.projectPath,
+ query.name,
+ this.issuableType,
+ (err, currentTemplate) => {
+ this.currentTemplate = currentTemplate;
+ this.stopLoadingSpinner();
+ if (err) return; // Error handled by global AJAX error handler
+ this.setInputValueToTemplateContent();
+ },
+ );
return;
}
diff --git a/app/assets/javascripts/terminal/terminal.js b/app/assets/javascripts/terminal/terminal.js
index 74c5bbe45a4..b24aa8a3a34 100644
--- a/app/assets/javascripts/terminal/terminal.js
+++ b/app/assets/javascripts/terminal/terminal.js
@@ -4,10 +4,14 @@ import * as fit from 'xterm/lib/addons/fit/fit';
export default class GLTerminal {
constructor(options = {}) {
- this.options = Object.assign({}, {
- cursorBlink: true,
- screenKeys: true,
- }, options);
+ this.options = Object.assign(
+ {},
+ {
+ cursorBlink: true,
+ screenKeys: true,
+ },
+ options,
+ );
this.container = document.querySelector(options.selector);
diff --git a/app/assets/javascripts/test_utils/simulate_drag.js b/app/assets/javascripts/test_utils/simulate_drag.js
index a5c18042ce7..be9ebc81c6b 100644
--- a/app/assets/javascripts/test_utils/simulate_drag.js
+++ b/app/assets/javascripts/test_utils/simulate_drag.js
@@ -4,15 +4,43 @@ function simulateEvent(el, type, options = {}) {
if (/^mouse/.test(type)) {
event = el.ownerDocument.createEvent('MouseEvents');
- event.initMouseEvent(type, true, true, el.ownerDocument.defaultView,
- options.button, options.screenX, options.screenY, options.clientX, options.clientY,
- options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el);
+ event.initMouseEvent(
+ type,
+ true,
+ true,
+ el.ownerDocument.defaultView,
+ options.button,
+ options.screenX,
+ options.screenY,
+ options.clientX,
+ options.clientY,
+ options.ctrlKey,
+ options.altKey,
+ options.shiftKey,
+ options.metaKey,
+ options.button,
+ el,
+ );
} else {
event = el.ownerDocument.createEvent('CustomEvent');
- event.initCustomEvent(type, true, true, el.ownerDocument.defaultView,
- options.button, options.screenX, options.screenY, options.clientX, options.clientY,
- options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, el);
+ event.initCustomEvent(
+ type,
+ true,
+ true,
+ el.ownerDocument.defaultView,
+ options.button,
+ options.screenX,
+ options.screenY,
+ options.clientX,
+ options.clientY,
+ options.ctrlKey,
+ options.altKey,
+ options.shiftKey,
+ options.metaKey,
+ options.button,
+ el,
+ );
event.dataTransfer = {
data: {},
@@ -37,14 +65,16 @@ function simulateEvent(el, type, options = {}) {
}
function isLast(target) {
- const el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
+ const el =
+ typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
const { children } = el;
return children.length - 1 === target.index;
}
function getTarget(target) {
- const el = typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
+ const el =
+ typeof target.el === 'string' ? document.getElementById(target.el.substr(1)) : target.el;
const { children } = el;
return (
@@ -58,13 +88,13 @@ function getTarget(target) {
function getRect(el) {
const rect = el.getBoundingClientRect();
const width = rect.right - rect.left;
- const height = (rect.bottom - rect.top) + 10;
+ const height = rect.bottom - rect.top + 10;
return {
x: rect.left,
y: rect.top,
- cx: rect.left + (width / 2),
- cy: rect.top + (height / 2),
+ cx: rect.left + width / 2,
+ cy: rect.top + height / 2,
w: width,
h: height,
hw: width / 2,
@@ -112,8 +142,8 @@ export default function simulateDrag(options) {
const dragInterval = setInterval(() => {
const progress = (new Date().getTime() - startTime) / duration;
- const x = (fromRect.cx + ((toRect.cx - fromRect.cx) * progress));
- const y = (fromRect.cy + ((toRect.cy - fromRect.cy) * progress));
+ const x = fromRect.cx + (toRect.cx - fromRect.cx) * progress;
+ const y = fromRect.cy + (toRect.cy - fromRect.cy) * progress;
const overEl = fromEl.ownerDocument.elementFromPoint(x, y);
simulateEvent(overEl, 'mousemove', {
diff --git a/app/assets/javascripts/test_utils/simulate_input.js b/app/assets/javascripts/test_utils/simulate_input.js
index 90c1b7cb57e..c300c806e6d 100644
--- a/app/assets/javascripts/test_utils/simulate_input.js
+++ b/app/assets/javascripts/test_utils/simulate_input.js
@@ -12,7 +12,7 @@ export default function simulateInput(target, text) {
}
if (text.length > 0) {
- Array.prototype.forEach.call(text, (char) => {
+ Array.prototype.forEach.call(text, char => {
input.value += char;
triggerEvents(input);
});
diff --git a/app/assets/javascripts/toggle_buttons.js b/app/assets/javascripts/toggle_buttons.js
index 199b14458ed..d83ffc7e211 100644
--- a/app/assets/javascripts/toggle_buttons.js
+++ b/app/assets/javascripts/toggle_buttons.js
@@ -49,7 +49,7 @@ function onToggleClicked(toggle, input, clickCallback) {
export default function setupToggleButtons(container, clickCallback = () => {}) {
const toggles = container.querySelectorAll('.js-project-feature-toggle');
- toggles.forEach((toggle) => {
+ toggles.forEach(toggle => {
const input = toggle.querySelector('.js-project-feature-toggle-input');
const isOn = convertPermissionToBoolean(input.value);
diff --git a/app/assets/javascripts/tree.js b/app/assets/javascripts/tree.js
index 066fd6278a7..3e659c9e7ea 100644
--- a/app/assets/javascripts/tree.js
+++ b/app/assets/javascripts/tree.js
@@ -8,7 +8,7 @@ export default class TreeView {
this.initKeyNav();
// Code browser tree slider
// Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
- $(".tree-content-holder .tree-item").on('click', function(e) {
+ $('.tree-content-holder .tree-item').on('click', function(e) {
var $clickedEl, path;
$clickedEl = $(e.target);
path = $('.tree-item-file-name a', this).attr('href');
@@ -27,33 +27,33 @@ export default class TreeView {
initKeyNav() {
var li, liSelected;
- li = $("tr.tree-item");
+ li = $('tr.tree-item');
liSelected = null;
return $('body').keydown(function(e) {
var next, path;
- if ($("input:focus").length > 0 && (e.which === 38 || e.which === 40)) {
+ if ($('input:focus').length > 0 && (e.which === 38 || e.which === 40)) {
return false;
}
if (e.which === 40) {
if (liSelected) {
next = liSelected.next();
if (next.length > 0) {
- liSelected.removeClass("selected");
- liSelected = next.addClass("selected");
+ liSelected.removeClass('selected');
+ liSelected = next.addClass('selected');
}
} else {
- liSelected = li.eq(0).addClass("selected");
+ liSelected = li.eq(0).addClass('selected');
}
return $(liSelected).focus();
} else if (e.which === 38) {
if (liSelected) {
next = liSelected.prev();
if (next.length > 0) {
- liSelected.removeClass("selected");
- liSelected = next.addClass("selected");
+ liSelected.removeClass('selected');
+ liSelected = next.addClass('selected');
}
} else {
- liSelected = li.last().addClass("selected");
+ liSelected = li.last().addClass('selected');
}
return $(liSelected).focus();
} else if (e.which === 13) {
diff --git a/app/assets/javascripts/u2f/authenticate.js b/app/assets/javascripts/u2f/authenticate.js
index 78fd7ad441f..abfc81e681e 100644
--- a/app/assets/javascripts/u2f/authenticate.js
+++ b/app/assets/javascripts/u2f/authenticate.js
@@ -49,7 +49,7 @@ export default class U2FAuthenticate {
start() {
return importU2FLibrary()
- .then((utils) => {
+ .then(utils => {
this.u2fUtils = utils;
this.renderInProgress();
})
@@ -57,14 +57,19 @@ export default class U2FAuthenticate {
}
authenticate() {
- return this.u2fUtils.sign(this.appId, this.challenge, this.signRequests,
- (response) => {
+ return this.u2fUtils.sign(
+ this.appId,
+ this.challenge,
+ this.signRequests,
+ response => {
if (response.errorCode) {
const error = new U2FError(response.errorCode, 'authenticate');
return this.renderError(error);
}
return this.renderAuthenticated(JSON.stringify(response));
- }, 10);
+ },
+ 10,
+ );
}
renderTemplate(name, params) {
@@ -99,5 +104,4 @@ export default class U2FAuthenticate {
this.container[0].classList.add('hidden');
this.fallbackUI.classList.remove('hidden');
}
-
}
diff --git a/app/assets/javascripts/u2f/register.js b/app/assets/javascripts/u2f/register.js
index 01e259a741d..43c814c8070 100644
--- a/app/assets/javascripts/u2f/register.js
+++ b/app/assets/javascripts/u2f/register.js
@@ -34,7 +34,7 @@ export default class U2FRegister {
start() {
return importU2FLibrary()
- .then((utils) => {
+ .then(utils => {
this.u2fUtils = utils;
this.renderSetup();
})
@@ -42,14 +42,19 @@ export default class U2FRegister {
}
register() {
- return this.u2fUtils.register(this.appId, this.registerRequests, this.signRequests,
- (response) => {
+ return this.u2fUtils.register(
+ this.appId,
+ this.registerRequests,
+ this.signRequests,
+ response => {
if (response.errorCode) {
const error = new U2FError(response.errorCode, 'register');
return this.renderError(error);
}
return this.renderRegistered(JSON.stringify(response));
- }, 10);
+ },
+ 10,
+ );
}
renderTemplate(name, params) {
diff --git a/app/assets/javascripts/u2f/util.js b/app/assets/javascripts/u2f/util.js
index 5778f00332d..b706481c02f 100644
--- a/app/assets/javascripts/u2f/util.js
+++ b/app/assets/javascripts/u2f/util.js
@@ -19,11 +19,10 @@ function getChromeVersion(userAgent) {
export function canInjectU2fApi(userAgent) {
const isSupportedChrome = isChrome(userAgent) && getChromeVersion(userAgent) >= 41;
const isSupportedOpera = isOpera(userAgent) && getOperaVersion(userAgent) >= 40;
- const isMobile = (
+ const isMobile =
userAgent.indexOf('droid') >= 0 ||
userAgent.indexOf('CriOS') >= 0 ||
- /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent)
- );
+ /\b(iPad|iPhone|iPod)(?=;)/.test(userAgent);
return (isSupportedChrome || isSupportedOpera) && !isMobile;
}
diff --git a/app/assets/javascripts/ui_development_kit.js b/app/assets/javascripts/ui_development_kit.js
index 9b242ea779d..be18ac5da24 100644
--- a/app/assets/javascripts/ui_development_kit.js
+++ b/app/assets/javascripts/ui_development_kit.js
@@ -4,13 +4,17 @@ import Api from './api';
export default () => {
$('#js-project-dropdown').glDropdown({
data: (term, callback) => {
- Api.projects(term, {
- order_by: 'last_activity_at',
- }, (data) => {
- callback(data);
- });
+ Api.projects(
+ term,
+ {
+ order_by: 'last_activity_at',
+ },
+ data => {
+ callback(data);
+ },
+ );
},
- text: project => (project.name_with_namespace || project.name),
+ text: project => project.name_with_namespace || project.name,
selectable: true,
fieldName: 'author_id',
filterable: true,
@@ -18,6 +22,6 @@ export default () => {
fields: ['name_with_namespace'],
},
id: data => data.id,
- isSelected: data => (data.id === 2),
+ isSelected: data => data.id === 2,
});
};
diff --git a/app/assets/javascripts/usage_ping_consent.js b/app/assets/javascripts/usage_ping_consent.js
index ae3fde190e3..05607f09a7e 100644
--- a/app/assets/javascripts/usage_ping_consent.js
+++ b/app/assets/javascripts/usage_ping_consent.js
@@ -4,7 +4,7 @@ import Flash, { hideFlash } from './flash';
import { convertPermissionToBoolean } from './lib/utils/common_utils';
export default () => {
- $('body').on('click', '.js-usage-consent-action', (e) => {
+ $('body').on('click', '.js-usage-consent-action', e => {
e.preventDefault();
e.stopImmediatePropagation(); // overwrite rails listener
@@ -18,7 +18,8 @@ export default () => {
const hideConsentMessage = () => hideFlash(document.querySelector('.ping-consent-message'));
- axios.put(url, data)
+ axios
+ .put(url, data)
.then(() => {
hideConsentMessage();
})
diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js
index e2259a8d07b..4b090212d83 100644
--- a/app/assets/javascripts/users_select.js
+++ b/app/assets/javascripts/users_select.js
@@ -15,8 +15,8 @@ function UsersSelect(currentUser, els, options = {}) {
var $els;
this.users = this.users.bind(this);
this.user = this.user.bind(this);
- this.usersPath = "/autocomplete/users.json";
- this.userPath = "/autocomplete/users/:id.json";
+ this.usersPath = '/autocomplete/users.json';
+ this.userPath = '/autocomplete/users/:id.json';
if (currentUser != null) {
if (typeof currentUser === 'object') {
this.currentUser = currentUser;
@@ -33,156 +33,180 @@ function UsersSelect(currentUser, els, options = {}) {
$els = $('.js-user-search');
}
- $els.each((function(_this) {
- return function(i, dropdown) {
- var options = {};
- var $block, $collapsedSidebar, $dropdown, $loading, $selectbox, $value, abilityName, assignTo, assigneeTemplate, collapsedAssigneeTemplate, defaultLabel, defaultNullUser, firstUser, issueURL, selectedId, selectedIdDefault, showAnyUser, showNullUser, showMenuAbove;
- $dropdown = $(dropdown);
- options.projectId = $dropdown.data('projectId');
- options.groupId = $dropdown.data('groupId');
- options.showCurrentUser = $dropdown.data('currentUser');
- options.todoFilter = $dropdown.data('todoFilter');
- options.todoStateFilter = $dropdown.data('todoStateFilter');
- showNullUser = $dropdown.data('nullUser');
- defaultNullUser = $dropdown.data('nullUserDefault');
- showMenuAbove = $dropdown.data('showMenuAbove');
- showAnyUser = $dropdown.data('anyUser');
- firstUser = $dropdown.data('firstUser');
- options.authorId = $dropdown.data('authorId');
- defaultLabel = $dropdown.data('defaultLabel');
- issueURL = $dropdown.data('issueUpdate');
- $selectbox = $dropdown.closest('.selectbox');
- $block = $selectbox.closest('.block');
- abilityName = $dropdown.data('abilityName');
- $value = $block.find('.value');
- $collapsedSidebar = $block.find('.sidebar-collapsed-user');
- $loading = $block.find('.block-loading').fadeOut();
- selectedIdDefault = (defaultNullUser && showNullUser) ? 0 : null;
- selectedId = $dropdown.data('selected');
-
- if (selectedId === undefined) {
- selectedId = selectedIdDefault;
- }
-
- const assignYourself = function () {
- const unassignedSelected = $dropdown.closest('.selectbox')
- .find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
-
- if (unassignedSelected) {
- unassignedSelected.remove();
+ $els.each(
+ (function(_this) {
+ return function(i, dropdown) {
+ var options = {};
+ var $block,
+ $collapsedSidebar,
+ $dropdown,
+ $loading,
+ $selectbox,
+ $value,
+ abilityName,
+ assignTo,
+ assigneeTemplate,
+ collapsedAssigneeTemplate,
+ defaultLabel,
+ defaultNullUser,
+ firstUser,
+ issueURL,
+ selectedId,
+ selectedIdDefault,
+ showAnyUser,
+ showNullUser,
+ showMenuAbove;
+ $dropdown = $(dropdown);
+ options.projectId = $dropdown.data('projectId');
+ options.groupId = $dropdown.data('groupId');
+ options.showCurrentUser = $dropdown.data('currentUser');
+ options.todoFilter = $dropdown.data('todoFilter');
+ options.todoStateFilter = $dropdown.data('todoStateFilter');
+ showNullUser = $dropdown.data('nullUser');
+ defaultNullUser = $dropdown.data('nullUserDefault');
+ showMenuAbove = $dropdown.data('showMenuAbove');
+ showAnyUser = $dropdown.data('anyUser');
+ firstUser = $dropdown.data('firstUser');
+ options.authorId = $dropdown.data('authorId');
+ defaultLabel = $dropdown.data('defaultLabel');
+ issueURL = $dropdown.data('issueUpdate');
+ $selectbox = $dropdown.closest('.selectbox');
+ $block = $selectbox.closest('.block');
+ abilityName = $dropdown.data('abilityName');
+ $value = $block.find('.value');
+ $collapsedSidebar = $block.find('.sidebar-collapsed-user');
+ $loading = $block.find('.block-loading').fadeOut();
+ selectedIdDefault = defaultNullUser && showNullUser ? 0 : null;
+ selectedId = $dropdown.data('selected');
+
+ if (selectedId === undefined) {
+ selectedId = selectedIdDefault;
}
- // Save current selected user to the DOM
- const input = document.createElement('input');
- input.type = 'hidden';
- input.name = $dropdown.data('fieldName');
+ const assignYourself = function() {
+ const unassignedSelected = $dropdown
+ .closest('.selectbox')
+ .find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
- const currentUserInfo = $dropdown.data('currentUserInfo');
-
- if (currentUserInfo) {
- input.value = currentUserInfo.id;
- input.dataset.meta = _.escape(currentUserInfo.name);
- } else if (_this.currentUser) {
- input.value = _this.currentUser.id;
- }
-
- if ($selectbox) {
- $dropdown.parent().before(input);
- } else {
- $dropdown.after(input);
- }
- };
-
- if ($block[0]) {
- $block[0].addEventListener('assignYourself', assignYourself);
- }
-
- const getSelectedUserInputs = function() {
- return $selectbox
- .find(`input[name="${$dropdown.data('fieldName')}"]`);
- };
+ if (unassignedSelected) {
+ unassignedSelected.remove();
+ }
- const getSelected = function() {
- return getSelectedUserInputs()
- .map((index, input) => parseInt(input.value, 10))
- .get();
- };
+ // Save current selected user to the DOM
+ const input = document.createElement('input');
+ input.type = 'hidden';
+ input.name = $dropdown.data('fieldName');
- const checkMaxSelect = function() {
- const maxSelect = $dropdown.data('maxSelect');
- if (maxSelect) {
- const selected = getSelected();
+ const currentUserInfo = $dropdown.data('currentUserInfo');
- if (selected.length > maxSelect) {
- const firstSelectedId = selected[0];
- const firstSelected = $dropdown.closest('.selectbox')
- .find(`input[name='${$dropdown.data('fieldName')}'][value=${firstSelectedId}]`);
+ if (currentUserInfo) {
+ input.value = currentUserInfo.id;
+ input.dataset.meta = _.escape(currentUserInfo.name);
+ } else if (_this.currentUser) {
+ input.value = _this.currentUser.id;
+ }
- firstSelected.remove();
- emitSidebarEvent('sidebar.removeAssignee', {
- id: firstSelectedId,
- });
+ if ($selectbox) {
+ $dropdown.parent().before(input);
+ } else {
+ $dropdown.after(input);
}
- }
- };
+ };
- const getMultiSelectDropdownTitle = function(selectedUser, isSelected) {
- const selectedUsers = getSelected()
- .filter(u => u !== 0);
-
- const firstUser = getSelectedUserInputs()
- .map((index, input) => ({
- name: input.dataset.meta,
- value: parseInt(input.value, 10),
- }))
- .filter(u => u.id !== 0)
- .get(0);
-
- if (selectedUsers.length === 0) {
- return 'Unassigned';
- } else if (selectedUsers.length === 1) {
- return firstUser.name;
- } else if (isSelected) {
- const otherSelected = selectedUsers.filter(s => s !== selectedUser.id);
- return `${selectedUser.name} + ${otherSelected.length} more`;
- } else {
- return `${firstUser.name} + ${selectedUsers.length - 1} more`;
+ if ($block[0]) {
+ $block[0].addEventListener('assignYourself', assignYourself);
}
- };
- $('.assign-to-me-link').on('click', (e) => {
- e.preventDefault();
- $(e.currentTarget).hide();
+ const getSelectedUserInputs = function() {
+ return $selectbox.find(`input[name="${$dropdown.data('fieldName')}"]`);
+ };
+
+ const getSelected = function() {
+ return getSelectedUserInputs()
+ .map((index, input) => parseInt(input.value, 10))
+ .get();
+ };
+
+ const checkMaxSelect = function() {
+ const maxSelect = $dropdown.data('maxSelect');
+ if (maxSelect) {
+ const selected = getSelected();
+
+ if (selected.length > maxSelect) {
+ const firstSelectedId = selected[0];
+ const firstSelected = $dropdown
+ .closest('.selectbox')
+ .find(`input[name='${$dropdown.data('fieldName')}'][value=${firstSelectedId}]`);
+
+ firstSelected.remove();
+ emitSidebarEvent('sidebar.removeAssignee', {
+ id: firstSelectedId,
+ });
+ }
+ }
+ };
+
+ const getMultiSelectDropdownTitle = function(selectedUser, isSelected) {
+ const selectedUsers = getSelected().filter(u => u !== 0);
+
+ const firstUser = getSelectedUserInputs()
+ .map((index, input) => ({
+ name: input.dataset.meta,
+ value: parseInt(input.value, 10),
+ }))
+ .filter(u => u.id !== 0)
+ .get(0);
+
+ if (selectedUsers.length === 0) {
+ return 'Unassigned';
+ } else if (selectedUsers.length === 1) {
+ return firstUser.name;
+ } else if (isSelected) {
+ const otherSelected = selectedUsers.filter(s => s !== selectedUser.id);
+ return `${selectedUser.name} + ${otherSelected.length} more`;
+ } else {
+ return `${firstUser.name} + ${selectedUsers.length - 1} more`;
+ }
+ };
- if ($dropdown.data('multiSelect')) {
- assignYourself();
- checkMaxSelect();
+ $('.assign-to-me-link').on('click', e => {
+ e.preventDefault();
+ $(e.currentTarget).hide();
- const currentUserInfo = $dropdown.data('currentUserInfo');
- $dropdown.find('.dropdown-toggle-text').text(getMultiSelectDropdownTitle(currentUserInfo)).removeClass('is-default');
- } else {
- const $input = $(`input[name="${$dropdown.data('fieldName')}"]`);
- $input.val(gon.current_user_id);
- selectedId = $input.val();
- $dropdown.find('.dropdown-toggle-text').text(gon.current_user_fullname).removeClass('is-default');
- }
- });
-
- $block.on('click', '.js-assign-yourself', (e) => {
- e.preventDefault();
- return assignTo(_this.currentUser.id);
- });
-
- assignTo = function(selected) {
- var data;
- data = {};
- data[abilityName] = {};
- data[abilityName].assignee_id = selected != null ? selected : null;
- $loading.removeClass('hidden').fadeIn();
- $dropdown.trigger('loading.gl.dropdown');
-
- return axios.put(issueURL, data)
- .then(({ data }) => {
+ if ($dropdown.data('multiSelect')) {
+ assignYourself();
+ checkMaxSelect();
+
+ const currentUserInfo = $dropdown.data('currentUserInfo');
+ $dropdown
+ .find('.dropdown-toggle-text')
+ .text(getMultiSelectDropdownTitle(currentUserInfo))
+ .removeClass('is-default');
+ } else {
+ const $input = $(`input[name="${$dropdown.data('fieldName')}"]`);
+ $input.val(gon.current_user_id);
+ selectedId = $input.val();
+ $dropdown
+ .find('.dropdown-toggle-text')
+ .text(gon.current_user_fullname)
+ .removeClass('is-default');
+ }
+ });
+
+ $block.on('click', '.js-assign-yourself', e => {
+ e.preventDefault();
+ return assignTo(_this.currentUser.id);
+ });
+
+ assignTo = function(selected) {
+ var data;
+ data = {};
+ data[abilityName] = {};
+ data[abilityName].assignee_id = selected != null ? selected : null;
+ $loading.removeClass('hidden').fadeIn();
+ $dropdown.trigger('loading.gl.dropdown');
+
+ return axios.put(issueURL, data).then(({ data }) => {
var user, tooltipTitle;
$dropdown.trigger('loaded.gl.dropdown');
$loading.fadeOut();
@@ -190,14 +214,14 @@ function UsersSelect(currentUser, els, options = {}) {
user = {
name: data.assignee.name,
username: data.assignee.username,
- avatar: data.assignee.avatar_url
+ avatar: data.assignee.avatar_url,
};
tooltipTitle = _.escape(user.name);
} else {
user = {
name: 'Unassigned',
username: '',
- avatar: ''
+ avatar: '',
};
tooltipTitle = __('Assignee');
}
@@ -205,319 +229,341 @@ function UsersSelect(currentUser, els, options = {}) {
$collapsedSidebar.attr('title', tooltipTitle).tooltip('_fixTitle');
return $collapsedSidebar.html(collapsedAssigneeTemplate(user));
});
- };
- collapsedAssigneeTemplate = _.template('<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>');
- assigneeTemplate = _.template('<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself"> No assignee - <a href="#" class="js-assign-yourself"> assign yourself </a> </span> <% } %>');
- return $dropdown.glDropdown({
- showMenuAbove: showMenuAbove,
- data: function(term, callback) {
- return _this.users(term, options, function(users) {
- // GitLabDropdownFilter returns this.instance
- // GitLabDropdownRemote returns this.options.instance
- const glDropdown = this.instance || this.options.instance;
- glDropdown.options.processData(term, users, callback);
- }.bind(this));
- },
- processData: function(term, data, callback) {
- let users = data;
-
- // Only show assigned user list when there is no search term
- if ($dropdown.hasClass('js-multiselect') && term.length === 0) {
- const selectedInputs = getSelectedUserInputs();
-
- // Potential duplicate entries when dealing with issue board
- // because issue board is also managed by vue
- const selectedUsers = _.uniq(selectedInputs, false, a => a.value)
- .filter((input) => {
- const userId = parseInt(input.value, 10);
- const inUsersArray = users.find(u => u.id === userId);
-
- return !inUsersArray && userId !== 0;
- })
- .map((input) => {
- const userId = parseInt(input.value, 10);
- const { avatarUrl, avatar_url, name, username } = input.dataset;
- return {
- avatar_url: avatarUrl || avatar_url,
- id: userId,
- name,
- username,
- };
- });
+ };
+ collapsedAssigneeTemplate = _.template(
+ '<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>',
+ );
+ assigneeTemplate = _.template(
+ '<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself"> No assignee - <a href="#" class="js-assign-yourself"> assign yourself </a> </span> <% } %>',
+ );
+ return $dropdown.glDropdown({
+ showMenuAbove: showMenuAbove,
+ data: function(term, callback) {
+ return _this.users(
+ term,
+ options,
+ function(users) {
+ // GitLabDropdownFilter returns this.instance
+ // GitLabDropdownRemote returns this.options.instance
+ const glDropdown = this.instance || this.options.instance;
+ glDropdown.options.processData(term, users, callback);
+ }.bind(this),
+ );
+ },
+ processData: function(term, data, callback) {
+ let users = data;
+
+ // Only show assigned user list when there is no search term
+ if ($dropdown.hasClass('js-multiselect') && term.length === 0) {
+ const selectedInputs = getSelectedUserInputs();
+
+ // Potential duplicate entries when dealing with issue board
+ // because issue board is also managed by vue
+ const selectedUsers = _.uniq(selectedInputs, false, a => a.value)
+ .filter(input => {
+ const userId = parseInt(input.value, 10);
+ const inUsersArray = users.find(u => u.id === userId);
+
+ return !inUsersArray && userId !== 0;
+ })
+ .map(input => {
+ const userId = parseInt(input.value, 10);
+ const { avatarUrl, avatar_url, name, username } = input.dataset;
+ return {
+ avatar_url: avatarUrl || avatar_url,
+ id: userId,
+ name,
+ username,
+ };
+ });
- users = data.concat(selectedUsers);
- }
+ users = data.concat(selectedUsers);
+ }
- let anyUser;
- let index;
- let len;
- let name;
- let obj;
- let showDivider;
- if (term.length === 0) {
- showDivider = 0;
- if (firstUser) {
- // Move current user to the front of the list
- for (index = 0, len = users.length; index < len; index += 1) {
- obj = users[index];
- if (obj.username === firstUser) {
- users.splice(index, 1);
- users.unshift(obj);
- break;
+ let anyUser;
+ let index;
+ let len;
+ let name;
+ let obj;
+ let showDivider;
+ if (term.length === 0) {
+ showDivider = 0;
+ if (firstUser) {
+ // Move current user to the front of the list
+ for (index = 0, len = users.length; index < len; index += 1) {
+ obj = users[index];
+ if (obj.username === firstUser) {
+ users.splice(index, 1);
+ users.unshift(obj);
+ break;
+ }
}
}
- }
- if (showNullUser) {
- showDivider += 1;
- users.unshift({
- beforeDivider: true,
- name: 'Unassigned',
- id: 0
- });
- }
- if (showAnyUser) {
- showDivider += 1;
- name = showAnyUser;
- if (name === true) {
- name = 'Any User';
+ if (showNullUser) {
+ showDivider += 1;
+ users.unshift({
+ beforeDivider: true,
+ name: 'Unassigned',
+ id: 0,
+ });
+ }
+ if (showAnyUser) {
+ showDivider += 1;
+ name = showAnyUser;
+ if (name === true) {
+ name = 'Any User';
+ }
+ anyUser = {
+ beforeDivider: true,
+ name: name,
+ id: null,
+ };
+ users.unshift(anyUser);
}
- anyUser = {
- beforeDivider: true,
- name: name,
- id: null
- };
- users.unshift(anyUser);
- }
- if (showDivider) {
- users.splice(showDivider, 0, 'divider');
- }
+ if (showDivider) {
+ users.splice(showDivider, 0, 'divider');
+ }
- if ($dropdown.hasClass('js-multiselect')) {
- const selected = getSelected().filter(i => i !== 0);
+ if ($dropdown.hasClass('js-multiselect')) {
+ const selected = getSelected().filter(i => i !== 0);
- if (selected.length > 0) {
- if ($dropdown.data('dropdownHeader')) {
- showDivider += 1;
- users.splice(showDivider, 0, {
- header: $dropdown.data('dropdownHeader'),
- });
- }
+ if (selected.length > 0) {
+ if ($dropdown.data('dropdownHeader')) {
+ showDivider += 1;
+ users.splice(showDivider, 0, {
+ header: $dropdown.data('dropdownHeader'),
+ });
+ }
- const selectedUsers = users
- .filter(u => selected.indexOf(u.id) !== -1)
- .sort((a, b) => a.name > b.name);
+ const selectedUsers = users
+ .filter(u => selected.indexOf(u.id) !== -1)
+ .sort((a, b) => a.name > b.name);
- users = users.filter(u => selected.indexOf(u.id) === -1);
+ users = users.filter(u => selected.indexOf(u.id) === -1);
- selectedUsers.forEach((selectedUser) => {
- showDivider += 1;
- users.splice(showDivider, 0, selectedUser);
- });
+ selectedUsers.forEach(selectedUser => {
+ showDivider += 1;
+ users.splice(showDivider, 0, selectedUser);
+ });
- users.splice(showDivider + 1, 0, 'divider');
+ users.splice(showDivider + 1, 0, 'divider');
+ }
}
}
- }
- callback(users);
- if (showMenuAbove) {
- $dropdown.data('glDropdown').positionMenuAbove();
- }
- },
- filterable: true,
- filterRemote: true,
- search: {
- fields: ['name', 'username']
- },
- selectable: true,
- fieldName: $dropdown.data('fieldName'),
- toggleLabel: function(selected, el, glDropdown) {
- const inputValue = glDropdown.filterInput.val();
-
- if (this.multiSelect && inputValue === '') {
- // Remove non-users from the fullData array
- const users = glDropdown.filteredFullData();
- const callback = glDropdown.parseData.bind(glDropdown);
-
- // Update the data model
- this.processData(inputValue, users, callback);
- }
+ callback(users);
+ if (showMenuAbove) {
+ $dropdown.data('glDropdown').positionMenuAbove();
+ }
+ },
+ filterable: true,
+ filterRemote: true,
+ search: {
+ fields: ['name', 'username'],
+ },
+ selectable: true,
+ fieldName: $dropdown.data('fieldName'),
+ toggleLabel: function(selected, el, glDropdown) {
+ const inputValue = glDropdown.filterInput.val();
+
+ if (this.multiSelect && inputValue === '') {
+ // Remove non-users from the fullData array
+ const users = glDropdown.filteredFullData();
+ const callback = glDropdown.parseData.bind(glDropdown);
+
+ // Update the data model
+ this.processData(inputValue, users, callback);
+ }
- if (this.multiSelect) {
- return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active'));
- }
+ if (this.multiSelect) {
+ return getMultiSelectDropdownTitle(selected, $(el).hasClass('is-active'));
+ }
- if (selected && 'id' in selected && $(el).hasClass('is-active')) {
- $dropdown.find('.dropdown-toggle-text').removeClass('is-default');
- if (selected.text) {
- return selected.text;
+ if (selected && 'id' in selected && $(el).hasClass('is-active')) {
+ $dropdown.find('.dropdown-toggle-text').removeClass('is-default');
+ if (selected.text) {
+ return selected.text;
+ } else {
+ return selected.name;
+ }
} else {
- return selected.name;
+ $dropdown.find('.dropdown-toggle-text').addClass('is-default');
+ return defaultLabel;
+ }
+ },
+ defaultLabel: defaultLabel,
+ hidden: function(e) {
+ if ($dropdown.hasClass('js-multiselect')) {
+ emitSidebarEvent('sidebar.saveAssignees');
}
- } else {
- $dropdown.find('.dropdown-toggle-text').addClass('is-default');
- return defaultLabel;
- }
- },
- defaultLabel: defaultLabel,
- hidden: function(e) {
- if ($dropdown.hasClass('js-multiselect')) {
- emitSidebarEvent('sidebar.saveAssignees');
- }
-
- if (!$dropdown.data('alwaysShowSelectbox')) {
- $selectbox.hide();
- // Recalculate where .value is because vue might have changed it
- $block = $selectbox.closest('.block');
- $value = $block.find('.value');
- // display:block overrides the hide-collapse rule
- $value.css('display', '');
- }
- },
- multiSelect: $dropdown.hasClass('js-multiselect'),
- inputMeta: $dropdown.data('inputMeta'),
- clicked: function(options) {
- const { $el, e, isMarking } = options;
- const user = options.selectedObj;
-
- if ($dropdown.hasClass('js-multiselect')) {
- const isActive = $el.hasClass('is-active');
- const previouslySelected = $dropdown.closest('.selectbox')
- .find("input[name='" + ($dropdown.data('fieldName')) + "'][value!=0]");
-
- // Enables support for limiting the number of users selected
- // Automatically removes the first on the list if more users are selected
- checkMaxSelect();
+ if (!$dropdown.data('alwaysShowSelectbox')) {
+ $selectbox.hide();
- if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') {
- // Unassigned selected
- previouslySelected.each((index, element) => {
- const id = parseInt(element.value, 10);
- element.remove();
- });
- emitSidebarEvent('sidebar.removeAllAssignees');
- } else if (isActive) {
- // user selected
- emitSidebarEvent('sidebar.addAssignee', user);
+ // Recalculate where .value is because vue might have changed it
+ $block = $selectbox.closest('.block');
+ $value = $block.find('.value');
+ // display:block overrides the hide-collapse rule
+ $value.css('display', '');
+ }
+ },
+ multiSelect: $dropdown.hasClass('js-multiselect'),
+ inputMeta: $dropdown.data('inputMeta'),
+ clicked: function(options) {
+ const { $el, e, isMarking } = options;
+ const user = options.selectedObj;
- // Remove unassigned selection (if it was previously selected)
- const unassignedSelected = $dropdown.closest('.selectbox')
- .find("input[name='" + ($dropdown.data('fieldName')) + "'][value=0]");
+ if ($dropdown.hasClass('js-multiselect')) {
+ const isActive = $el.hasClass('is-active');
+ const previouslySelected = $dropdown
+ .closest('.selectbox')
+ .find("input[name='" + $dropdown.data('fieldName') + "'][value!=0]");
+
+ // Enables support for limiting the number of users selected
+ // Automatically removes the first on the list if more users are selected
+ checkMaxSelect();
+
+ if (user.beforeDivider && user.name.toLowerCase() === 'unassigned') {
+ // Unassigned selected
+ previouslySelected.each((index, element) => {
+ const id = parseInt(element.value, 10);
+ element.remove();
+ });
+ emitSidebarEvent('sidebar.removeAllAssignees');
+ } else if (isActive) {
+ // user selected
+ emitSidebarEvent('sidebar.addAssignee', user);
+
+ // Remove unassigned selection (if it was previously selected)
+ const unassignedSelected = $dropdown
+ .closest('.selectbox')
+ .find("input[name='" + $dropdown.data('fieldName') + "'][value=0]");
+
+ if (unassignedSelected) {
+ unassignedSelected.remove();
+ }
+ } else {
+ if (previouslySelected.length === 0) {
+ // Select unassigned because there is no more selected users
+ this.addInput($dropdown.data('fieldName'), 0, {});
+ }
- if (unassignedSelected) {
- unassignedSelected.remove();
- }
- } else {
- if (previouslySelected.length === 0) {
- // Select unassigned because there is no more selected users
- this.addInput($dropdown.data('fieldName'), 0, {});
+ // User unselected
+ emitSidebarEvent('sidebar.removeAssignee', user);
}
- // User unselected
- emitSidebarEvent('sidebar.removeAssignee', user);
+ if (getSelected().find(u => u === gon.current_user_id)) {
+ $('.assign-to-me-link').hide();
+ } else {
+ $('.assign-to-me-link').show();
+ }
}
- if (getSelected().find(u => u === gon.current_user_id)) {
- $('.assign-to-me-link').hide();
- } else {
- $('.assign-to-me-link').show();
+ var isIssueIndex, isMRIndex, page, selected;
+ page = $('body').attr('data-page');
+ isIssueIndex = page === 'projects:issues:index';
+ isMRIndex = page === page && page === 'projects:merge_requests:index';
+ if (
+ $dropdown.hasClass('js-filter-bulk-update') ||
+ $dropdown.hasClass('js-issuable-form-dropdown')
+ ) {
+ e.preventDefault();
+
+ const isSelecting = user.id !== selectedId;
+ selectedId = isSelecting ? user.id : selectedIdDefault;
+
+ if (selectedId === gon.current_user_id) {
+ $('.assign-to-me-link').hide();
+ } else {
+ $('.assign-to-me-link').show();
+ }
+ return;
+ }
+ if ($el.closest('.add-issues-modal').length) {
+ ModalStore.store.filter[$dropdown.data('fieldName')] = user.id;
+ } else if (handleClick) {
+ e.preventDefault();
+ handleClick(user, isMarking);
+ } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
+ return Issuable.filterResults($dropdown.closest('form'));
+ } else if ($dropdown.hasClass('js-filter-submit')) {
+ return $dropdown.closest('form').submit();
+ } else if (!$dropdown.hasClass('js-multiselect')) {
+ selected = $dropdown
+ .closest('.selectbox')
+ .find("input[name='" + $dropdown.data('fieldName') + "']")
+ .val();
+ return assignTo(selected);
}
- }
- var isIssueIndex, isMRIndex, page, selected;
- page = $('body').attr('data-page');
- isIssueIndex = page === 'projects:issues:index';
- isMRIndex = (page === page && page === 'projects:merge_requests:index');
- if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {
- e.preventDefault();
+ // Automatically close dropdown after assignee is selected
+ // since CE has no multiple assignees
+ // EE does not have a max-select
+ if (
+ $dropdown.data('maxSelect') &&
+ getSelected().length === $dropdown.data('maxSelect')
+ ) {
+ // Close the dropdown
+ $dropdown.dropdown('toggle');
+ }
+ },
+ id: function(user) {
+ return user.id;
+ },
+ opened: function(e) {
+ const $el = $(e.currentTarget);
+ const selected = getSelected();
+ if ($dropdown.hasClass('js-issue-board-sidebar') && selected.length === 0) {
+ this.addInput($dropdown.data('fieldName'), 0, {});
+ }
+ $el.find('.is-active').removeClass('is-active');
- const isSelecting = (user.id !== selectedId);
- selectedId = isSelecting ? user.id : selectedIdDefault;
+ function highlightSelected(id) {
+ $el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active');
+ }
- if (selectedId === gon.current_user_id) {
- $('.assign-to-me-link').hide();
+ if (selected.length > 0) {
+ getSelected().forEach(selectedId => highlightSelected(selectedId));
+ } else if ($dropdown.hasClass('js-issue-board-sidebar')) {
+ highlightSelected(0);
} else {
- $('.assign-to-me-link').show();
+ highlightSelected(selectedId);
}
- return;
- }
- if ($el.closest('.add-issues-modal').length) {
- ModalStore.store.filter[$dropdown.data('fieldName')] = user.id;
- } else if (handleClick) {
- e.preventDefault();
- handleClick(user, isMarking);
- } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
- return Issuable.filterResults($dropdown.closest('form'));
- } else if ($dropdown.hasClass('js-filter-submit')) {
- return $dropdown.closest('form').submit();
- } else if (!$dropdown.hasClass('js-multiselect')) {
- selected = $dropdown.closest('.selectbox').find("input[name='" + ($dropdown.data('fieldName')) + "']").val();
- return assignTo(selected);
- }
-
- // Automatically close dropdown after assignee is selected
- // since CE has no multiple assignees
- // EE does not have a max-select
- if ($dropdown.data('maxSelect') &&
- getSelected().length === $dropdown.data('maxSelect')) {
- // Close the dropdown
- $dropdown.dropdown('toggle');
- }
- },
- id: function (user) {
- return user.id;
- },
- opened: function(e) {
- const $el = $(e.currentTarget);
- const selected = getSelected();
- if ($dropdown.hasClass('js-issue-board-sidebar') && selected.length === 0) {
- this.addInput($dropdown.data('fieldName'), 0, {});
- }
- $el.find('.is-active').removeClass('is-active');
-
- function highlightSelected(id) {
- $el.find(`li[data-user-id="${id}"] .dropdown-menu-user-link`).addClass('is-active');
- }
+ },
+ updateLabel: $dropdown.data('dropdownTitle'),
+ renderRow: function(user) {
+ var avatar, img, listClosingTags, listWithName, listWithUserName, username;
+ username = user.username ? '@' + user.username : '';
+ avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url;
- if (selected.length > 0) {
- getSelected().forEach(selectedId => highlightSelected(selectedId));
- } else if ($dropdown.hasClass('js-issue-board-sidebar')) {
- highlightSelected(0);
- } else {
- highlightSelected(selectedId);
- }
- },
- updateLabel: $dropdown.data('dropdownTitle'),
- renderRow: function(user) {
- var avatar, img, listClosingTags, listWithName, listWithUserName, username;
- username = user.username ? "@" + user.username : "";
- avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url;
+ let selected = false;
- let selected = false;
+ if (this.multiSelect) {
+ selected = getSelected().find(u => user.id === u);
- if (this.multiSelect) {
- selected = getSelected().find(u => user.id === u);
+ const { fieldName } = this;
+ const field = $dropdown
+ .closest('.selectbox')
+ .find("input[name='" + fieldName + "'][value='" + user.id + "']");
- const { fieldName } = this;
- const field = $dropdown.closest('.selectbox').find("input[name='" + fieldName + "'][value='" + user.id + "']");
-
- if (field.length) {
- selected = true;
+ if (field.length) {
+ selected = true;
+ }
+ } else {
+ selected = user.id === selectedId;
}
- } else {
- selected = user.id === selectedId;
- }
- img = "";
- if (user.beforeDivider != null) {
- `<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${_.escape(user.name)}</a></li>`;
- } else {
- img = "<img src='" + avatar + "' class='avatar avatar-inline' width='32' />";
- }
+ img = '';
+ if (user.beforeDivider != null) {
+ `<li><a href='#' class='${selected === true ? 'is-active' : ''}'>${_.escape(
+ user.name,
+ )}</a></li>`;
+ } else {
+ img = "<img src='" + avatar + "' class='avatar avatar-inline' width='32' />";
+ }
- return `
+ return `
<li data-user-id=${user.id}>
<a href='#' class='dropdown-menu-user-link ${selected === true ? 'is-active' : ''}'>
${img}
@@ -528,114 +574,117 @@ function UsersSelect(currentUser, els, options = {}) {
</a>
</li>
`;
- }
- });
- };
- })(this));
- $('.ajax-users-select').each((function(_this) {
- return function(i, select) {
- var firstUser, showAnyUser, showEmailUser, showNullUser;
- var options = {};
- options.skipLdap = $(select).hasClass('skip_ldap');
- options.projectId = $(select).data('projectId');
- options.groupId = $(select).data('groupId');
- options.showCurrentUser = $(select).data('currentUser');
- options.authorId = $(select).data('authorId');
- options.skipUsers = $(select).data('skipUsers');
- showNullUser = $(select).data('nullUser');
- showAnyUser = $(select).data('anyUser');
- showEmailUser = $(select).data('emailUser');
- firstUser = $(select).data('firstUser');
- return $(select).select2({
- placeholder: "Search for a user",
- multiple: $(select).hasClass('multiselect'),
- minimumInputLength: 0,
- query: function(query) {
- return _this.users(query.term, options, function(users) {
- var anyUser, data, emailUser, index, len, name, nullUser, obj, ref;
- data = {
- results: users
- };
- if (query.term.length === 0) {
- if (firstUser) {
- // Move current user to the front of the list
- ref = data.results;
-
- for (index = 0, len = ref.length; index < len; index += 1) {
- obj = ref[index];
- if (obj.username === firstUser) {
- data.results.splice(index, 1);
- data.results.unshift(obj);
- break;
+ },
+ });
+ };
+ })(this),
+ );
+ $('.ajax-users-select').each(
+ (function(_this) {
+ return function(i, select) {
+ var firstUser, showAnyUser, showEmailUser, showNullUser;
+ var options = {};
+ options.skipLdap = $(select).hasClass('skip_ldap');
+ options.projectId = $(select).data('projectId');
+ options.groupId = $(select).data('groupId');
+ options.showCurrentUser = $(select).data('currentUser');
+ options.authorId = $(select).data('authorId');
+ options.skipUsers = $(select).data('skipUsers');
+ showNullUser = $(select).data('nullUser');
+ showAnyUser = $(select).data('anyUser');
+ showEmailUser = $(select).data('emailUser');
+ firstUser = $(select).data('firstUser');
+ return $(select).select2({
+ placeholder: 'Search for a user',
+ multiple: $(select).hasClass('multiselect'),
+ minimumInputLength: 0,
+ query: function(query) {
+ return _this.users(query.term, options, function(users) {
+ var anyUser, data, emailUser, index, len, name, nullUser, obj, ref;
+ data = {
+ results: users,
+ };
+ if (query.term.length === 0) {
+ if (firstUser) {
+ // Move current user to the front of the list
+ ref = data.results;
+
+ for (index = 0, len = ref.length; index < len; index += 1) {
+ obj = ref[index];
+ if (obj.username === firstUser) {
+ data.results.splice(index, 1);
+ data.results.unshift(obj);
+ break;
+ }
}
}
- }
- if (showNullUser) {
- nullUser = {
- name: 'Unassigned',
- id: 0
- };
- data.results.unshift(nullUser);
- }
- if (showAnyUser) {
- name = showAnyUser;
- if (name === true) {
- name = 'Any User';
+ if (showNullUser) {
+ nullUser = {
+ name: 'Unassigned',
+ id: 0,
+ };
+ data.results.unshift(nullUser);
}
- anyUser = {
- name: name,
- id: null
+ if (showAnyUser) {
+ name = showAnyUser;
+ if (name === true) {
+ name = 'Any User';
+ }
+ anyUser = {
+ name: name,
+ id: null,
+ };
+ data.results.unshift(anyUser);
+ }
+ }
+ if (showEmailUser && data.results.length === 0 && query.term.match(/^[^@]+@[^@]+$/)) {
+ var trimmed = query.term.trim();
+ emailUser = {
+ name: 'Invite "' + trimmed + '" by email',
+ username: trimmed,
+ id: trimmed,
+ invite: true,
};
- data.results.unshift(anyUser);
+ data.results.unshift(emailUser);
}
- }
- if (showEmailUser && data.results.length === 0 && query.term.match(/^[^@]+@[^@]+$/)) {
- var trimmed = query.term.trim();
- emailUser = {
- name: "Invite \"" + trimmed + "\" by email",
- username: trimmed,
- id: trimmed,
- invite: true
- };
- data.results.unshift(emailUser);
- }
- return query.callback(data);
- });
- },
- initSelection: function() {
- var args;
- args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
- return _this.initSelection.apply(_this, args);
- },
- formatResult: function() {
- var args;
- args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
- return _this.formatResult.apply(_this, args);
- },
- formatSelection: function() {
- var args;
- args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
- return _this.formatSelection.apply(_this, args);
- },
- dropdownCssClass: "ajax-users-dropdown",
- // we do not want to escape markup since we are displaying html in results
- escapeMarkup: function(m) {
- return m;
- }
- });
- };
- })(this));
+ return query.callback(data);
+ });
+ },
+ initSelection: function() {
+ var args;
+ args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
+ return _this.initSelection.apply(_this, args);
+ },
+ formatResult: function() {
+ var args;
+ args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
+ return _this.formatResult.apply(_this, args);
+ },
+ formatSelection: function() {
+ var args;
+ args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
+ return _this.formatSelection.apply(_this, args);
+ },
+ dropdownCssClass: 'ajax-users-dropdown',
+ // we do not want to escape markup since we are displaying html in results
+ escapeMarkup: function(m) {
+ return m;
+ },
+ });
+ };
+ })(this),
+ );
}
UsersSelect.prototype.initSelection = function(element, callback) {
var id, nullUser;
id = $(element).val();
- if (id === "0") {
+ if (id === '0') {
nullUser = {
- name: 'Unassigned'
+ name: 'Unassigned',
};
return callback(nullUser);
- } else if (id !== "") {
+ } else if (id !== '') {
return this.user(id, callback);
}
};
@@ -647,7 +696,17 @@ UsersSelect.prototype.formatResult = function(user) {
} else {
avatar = gon.default_avatar_url;
}
- return "<div class='user-result " + (!user.username ? 'no-username' : void 0) + "'> <div class='user-image'><img class='avatar avatar-inline s32' src='" + avatar + "'></div> <div class='user-name dropdown-menu-user-full-name'>" + _.escape(user.name) + "</div> <div class='user-username dropdown-menu-user-username'>" + (!user.invite ? "@" + _.escape(user.username) : "") + "</div> </div>";
+ return (
+ "<div class='user-result " +
+ (!user.username ? 'no-username' : void 0) +
+ "'> <div class='user-image'><img class='avatar avatar-inline s32' src='" +
+ avatar +
+ "'></div> <div class='user-name dropdown-menu-user-full-name'>" +
+ _.escape(user.name) +
+ "</div> <div class='user-username dropdown-menu-user-username'>" +
+ (!user.invite ? '@' + _.escape(user.username) : '') +
+ '</div> </div>'
+ );
};
UsersSelect.prototype.formatSelection = function(user) {
@@ -662,10 +721,9 @@ UsersSelect.prototype.user = function(user_id, callback) {
var url;
url = this.buildUrl(this.userPath);
url = url.replace(':id', user_id);
- return axios.get(url)
- .then(({ data }) => {
- callback(data);
- });
+ return axios.get(url).then(({ data }) => {
+ callback(data);
+ });
};
// Return users list. Filtered by query
@@ -682,12 +740,11 @@ UsersSelect.prototype.users = function(query, options, callback) {
todo_state_filter: options.todoStateFilter || null,
current_user: options.showCurrentUser || null,
author_id: options.authorId || null,
- skip_users: options.skipUsers || null
+ skip_users: options.skipUsers || null,
};
- return axios.get(url, { params })
- .then(({ data }) => {
- callback(data);
- });
+ return axios.get(url, { params }).then(({ data }) => {
+ callback(data);
+ });
};
UsersSelect.prototype.buildUrl = function(url) {
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 70518ad73e8..6c87287a4c4 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
@@ -1,6 +1,7 @@
<script>
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 timeagoMixin from '../../vue_shared/mixins/timeago';
import tooltip from '../../vue_shared/directives/tooltip';
import LoadingButton from '../../vue_shared/components/loading_button.vue';
@@ -18,13 +19,12 @@ export default {
StatusIcon,
Icon,
TooltipOnTruncate,
+ FilteredSearchDropdown,
},
directives: {
tooltip,
},
- mixins: [
- timeagoMixin,
- ],
+ mixins: [timeagoMixin],
props: {
deployment: {
type: Object,
@@ -32,8 +32,10 @@ export default {
},
},
data() {
+ const features = window.gon.features || {};
return {
isStopping: false,
+ enableCiEnvironmentsStatusChanges: features.ciEnvironmentsStatusChanges,
};
},
computed: {
@@ -50,7 +52,7 @@ export default {
return !!(this.deployment.url && this.deployment.name);
},
hasMetrics() {
- return !!(this.deployment.metrics_url);
+ return !!this.deployment.metrics_url;
},
},
methods: {
@@ -63,7 +65,7 @@ export default {
MRWidgetService.stopEnvironment(this.deployment.stop_url)
.then(res => res.data)
- .then((data) => {
+ .then(data => {
if (data.redirect_url) {
visitUrl(data.redirect_url);
}
@@ -120,18 +122,65 @@ export default {
/>
</div>
<div>
- <a
- v-if="hasExternalUrls"
- :href="deployment.external_url"
- target="_blank"
- rel="noopener noreferrer nofollow"
- class="deploy-link js-deploy-url btn btn-default btn-sm inline"
- >
- <span>
- View app
- <icon name="external-link" />
- </span>
- </a>
+ <template v-if="hasExternalUrls">
+ <filtered-search-dropdown
+ v-if="enableCiEnvironmentsStatusChanges"
+ class="js-mr-wigdet-deployment-dropdown inline"
+ :items="deployment.changes"
+ :main-action-link="deployment.external_url"
+ filter-key="path"
+ >
+ <template
+ slot="mainAction"
+ slot-scope="slotProps"
+ >
+ <a
+ :href="deployment.external_url"
+ target="_blank"
+ rel="noopener noreferrer nofollow"
+ class="deploy-link js-deploy-url inline"
+ :class="slotProps.className"
+ >
+ <span>
+ {{ __('View app') }}
+ <icon name="external-link" />
+ </span>
+ </a>
+ </template>
+
+ <template
+ slot="result"
+ slot-scope="slotProps"
+ >
+ <a
+ :href="slotProps.result.external_url"
+ target="_blank"
+ rel="noopener noreferrer nofollow"
+ class="menu-item"
+ >
+ <strong class="str-truncated-100 append-bottom-0 d-block">
+ {{ slotProps.result.path }}
+ </strong>
+
+ <p class="text-secondary str-truncated-100 append-bottom-0 d-block">
+ {{ slotProps.result.external_url }}
+ </p>
+ </a>
+ </template>
+ </filtered-search-dropdown>
+ <a
+ v-else
+ :href="deployment.external_url"
+ target="_blank"
+ rel="noopener noreferrer nofollow"
+ class="js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inline"
+ >
+ <span>
+ {{ __('View app') }}
+ <icon name="external-link" />
+ </span>
+ </a>
+ </template>
<loading-button
v-if="deployment.stop_url"
:loading="isStopping"
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 5e76f6b1cac..41dbc5c9cbb 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
@@ -60,11 +60,29 @@ export default {
let memoryUsageMsg = '';
if (memoryTo > memoryFrom) {
- memoryUsageMsg = sprintf(s__('mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} increased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB'), messageProps, false);
+ memoryUsageMsg = sprintf(
+ s__(
+ 'mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} increased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB',
+ ),
+ messageProps,
+ false,
+ );
} else if (memoryTo < memoryFrom) {
- memoryUsageMsg = sprintf(s__('mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} decreased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB'), messageProps, false);
+ memoryUsageMsg = sprintf(
+ s__(
+ 'mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} decreased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB',
+ ),
+ messageProps,
+ false,
+ );
} else {
- memoryUsageMsg = sprintf(s__('mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB'), messageProps, false);
+ memoryUsageMsg = sprintf(
+ s__(
+ 'mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB',
+ ),
+ messageProps,
+ false,
+ );
}
return memoryUsageMsg;
@@ -77,7 +95,7 @@ export default {
methods: {
getMegabytes(bytesString) {
const valueInBytes = Number(bytesString).toFixed(2);
- return (bytesToMiB(valueInBytes)).toFixed(2);
+ return bytesToMiB(valueInBytes).toFixed(2);
},
computeGraphData(metrics, deploymentTime) {
this.loadingMetrics = false;
@@ -103,7 +121,7 @@ export default {
loadMetrics() {
backOff((next, stop) => {
MRWidgetService.fetchMetrics(this.metricsUrl)
- .then((res) => {
+ .then(res => {
if (res.status === statusCodes.NO_CONTENT) {
this.backOffRequestCounter += 1;
/* eslint-disable no-unused-expressions */
@@ -114,14 +132,14 @@ export default {
})
.catch(stop);
})
- .then((res) => {
+ .then(res => {
if (res.status === statusCodes.NO_CONTENT) {
return res;
}
return res.data;
})
- .then((data) => {
+ .then(data => {
this.computeGraphData(data.metrics, data.deployment_time);
return data;
})
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 22c2f74f900..2ad9e8be655 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
@@ -1,36 +1,36 @@
<script>
- import tooltip from '../../vue_shared/directives/tooltip';
+import tooltip from '../../vue_shared/directives/tooltip';
- export default {
- name: 'MrWidgetAuthor',
- directives: {
- tooltip,
+export default {
+ name: 'MrWidgetAuthor',
+ directives: {
+ tooltip,
+ },
+ props: {
+ author: {
+ type: Object,
+ required: true,
},
- props: {
- author: {
- type: Object,
- required: true,
- },
- showAuthorName: {
- type: Boolean,
- required: false,
- default: true,
- },
- showAuthorTooltip: {
- type: Boolean,
- required: false,
- default: false,
- },
+ showAuthorName: {
+ type: Boolean,
+ required: false,
+ default: true,
},
- computed: {
- authorUrl() {
- return this.author.webUrl || this.author.web_url;
- },
- avatarUrl() {
- return this.author.avatarUrl || this.author.avatar_url;
- },
+ showAuthorTooltip: {
+ type: Boolean,
+ required: false,
+ default: false,
},
- };
+ },
+ computed: {
+ authorUrl() {
+ return this.author.webUrl || this.author.web_url;
+ },
+ avatarUrl() {
+ return this.author.avatarUrl || this.author.avatar_url;
+ },
+ },
+};
</script>
<template>
<a
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 ba16cb9e2c8..1d902131f49 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
@@ -1,34 +1,34 @@
<script>
- import tooltip from '~/vue_shared/directives/tooltip';
- import MrWidgetAuthor from './mr_widget_author.vue';
+import tooltip from '~/vue_shared/directives/tooltip';
+import MrWidgetAuthor from './mr_widget_author.vue';
- export default {
- name: 'MrWidgetAuthorTime',
- components: {
- MrWidgetAuthor,
+export default {
+ name: 'MrWidgetAuthorTime',
+ components: {
+ MrWidgetAuthor,
+ },
+ directives: {
+ tooltip,
+ },
+ props: {
+ actionText: {
+ type: String,
+ required: true,
},
- directives: {
- tooltip,
+ author: {
+ type: Object,
+ required: true,
},
- props: {
- actionText: {
- type: String,
- required: true,
- },
- author: {
- type: Object,
- required: true,
- },
- dateTitle: {
- type: String,
- required: true,
- },
- dateReadable: {
- type: String,
- required: true,
- },
+ dateTitle: {
+ type: String,
+ required: true,
},
- };
+ dateReadable: {
+ type: String,
+ required: true,
+ },
+ },
+};
</script>
<template>
<h4 class="js-mr-widget-author">
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 62b61e1f41f..37c6af13c03 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
@@ -1,24 +1,26 @@
<script>
- import { sprintf, s__ } from '~/locale';
+import { sprintf, s__ } from '~/locale';
- export default {
- name: 'MRWidgetMergeHelp',
- props: {
- missingBranch: {
- type: String,
- required: false,
- default: '',
- },
+export default {
+ name: 'MRWidgetMergeHelp',
+ props: {
+ missingBranch: {
+ type: String,
+ required: false,
+ default: '',
},
- computed: {
- missingBranchInfo() {
- return sprintf(
- s__('mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the'),
- { branch: this.missingBranch },
- );
- },
+ },
+ computed: {
+ missingBranchInfo() {
+ return sprintf(
+ s__(
+ 'mrWidget|If the %{branch} branch exists in your local repository, you can merge this merge request manually using the',
+ ),
+ { branch: this.missingBranch },
+ );
},
- };
+ },
+};
</script>
<template>
<section class="mr-widget-help">
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 88d0fcd70f5..cc77b96a589 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
@@ -1,32 +1,32 @@
<script>
- import { s__ } from '~/locale';
+import { s__ } from '~/locale';
- export default {
- name: 'MRWidgetRelatedLinks',
- props: {
- relatedLinks: {
- type: Object,
- required: true,
- default: () => ({}),
- },
- state: {
- type: String,
- required: false,
- default: '',
- },
+export default {
+ name: 'MRWidgetRelatedLinks',
+ props: {
+ relatedLinks: {
+ type: Object,
+ required: true,
+ default: () => ({}),
},
- computed: {
- closesText() {
- if (this.state === 'merged') {
- return s__('mrWidget|Closed');
- }
- if (this.state === 'closed') {
- return s__('mrWidget|Did not close');
- }
- return s__('mrWidget|Closes');
- },
+ state: {
+ type: String,
+ required: false,
+ default: '',
},
- };
+ },
+ computed: {
+ closesText() {
+ if (this.state === 'merged') {
+ return s__('mrWidget|Closed');
+ }
+ if (this.state === 'closed') {
+ return s__('mrWidget|Did not close');
+ }
+ return s__('mrWidget|Closes');
+ },
+ },
+};
</script>
<template>
<section class="mr-info-list mr-links">
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 035ae791a1d..ba6a1687e51 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,33 +1,33 @@
<script>
- import ciIcon from '../../vue_shared/components/ci_icon.vue';
+import ciIcon from '../../vue_shared/components/ci_icon.vue';
- export default {
- components: {
- ciIcon,
+export default {
+ components: {
+ ciIcon,
+ },
+ props: {
+ status: {
+ type: String,
+ required: true,
},
- props: {
- status: {
- type: String,
- required: true,
- },
- showDisabledButton: {
- type: Boolean,
- required: false,
- default: false,
- },
+ showDisabledButton: {
+ type: Boolean,
+ required: false,
+ default: false,
},
- computed: {
- isLoading() {
- return this.status === 'loading';
- },
- statusObj() {
- return {
- group: this.status,
- icon: `status_${this.status}`,
- };
- },
+ },
+ computed: {
+ isLoading() {
+ return this.status === 'loading';
},
- };
+ statusObj() {
+ return {
+ group: this.status,
+ icon: `status_${this.status}`,
+ };
+ },
+ },
+};
</script>
<template>
<div class="space-children d-flex append-right-10 widget-status-icon">
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 56879c04d16..01f707163d4 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
@@ -1,16 +1,16 @@
<script>
- import tooltip from '../../vue_shared/directives/tooltip';
- import { __ } from '../../locale';
+import tooltip from '../../vue_shared/directives/tooltip';
+import { __ } from '../../locale';
- export default {
- directives: {
- tooltip,
- },
- created() {
- this.removesBranchText = __('<strong>Removes</strong> source branch');
- this.tooltipTitle = __('A user with write access to the source branch selected this option');
- },
- };
+export default {
+ directives: {
+ tooltip,
+ },
+ created() {
+ this.removesBranchText = __('<strong>Removes</strong> source branch');
+ this.tooltipTitle = __('A user with write access to the source branch selected this option');
+ },
+};
</script>
<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 cfbd44d41b2..2a76a878448 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
@@ -1,12 +1,12 @@
<script>
- import statusIcon from '../mr_widget_status_icon.vue';
+import statusIcon from '../mr_widget_status_icon.vue';
- export default {
- name: 'MRWidgetArchived',
- components: {
- statusIcon,
- },
- };
+export default {
+ name: 'MRWidgetArchived',
+ components: {
+ statusIcon,
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
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 01294d5b40c..4f8b07484c0 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,32 +1,32 @@
<script>
- import eventHub from '../../event_hub';
- import statusIcon from '../mr_widget_status_icon.vue';
+import eventHub from '../../event_hub';
+import statusIcon from '../mr_widget_status_icon.vue';
- export default {
- name: 'MRWidgetAutoMergeFailed',
- components: {
- statusIcon,
+export default {
+ name: 'MRWidgetAutoMergeFailed',
+ components: {
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
},
- props: {
- mr: {
- type: Object,
- required: true,
- },
+ },
+ data() {
+ return {
+ isRefreshing: false,
+ };
+ },
+ methods: {
+ refreshWidget() {
+ this.isRefreshing = true;
+ eventHub.$emit('MRWidgetUpdateRequested', () => {
+ this.isRefreshing = false;
+ });
},
- data() {
- return {
- isRefreshing: false,
- };
- },
- methods: {
- refreshWidget() {
- this.isRefreshing = true;
- eventHub.$emit('MRWidgetUpdateRequested', () => {
- this.isRefreshing = false;
- });
- },
- },
- };
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
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 ae6630dcd6f..fdf0a9fd994 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
@@ -1,12 +1,12 @@
<script>
- import statusIcon from '../mr_widget_status_icon.vue';
+import statusIcon from '../mr_widget_status_icon.vue';
- export default {
- name: 'MRWidgetChecking',
- components: {
- statusIcon,
- },
- };
+export default {
+ name: 'MRWidgetChecking',
+ components: {
+ statusIcon,
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
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 25a57e520ee..f06eab95c7e 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
@@ -1,23 +1,23 @@
<script>
- import MrWidgetAuthorTime from '../../components/mr_widget_author_time.vue';
- import statusIcon from '../mr_widget_status_icon.vue';
+import MrWidgetAuthorTime from '../../components/mr_widget_author_time.vue';
+import statusIcon from '../mr_widget_status_icon.vue';
- export default {
- name: 'MRWidgetClosed',
- components: {
- MrWidgetAuthorTime,
- statusIcon,
- },
- props: {
- /* TODO: This is providing all store and service down when it
+export default {
+ name: 'MRWidgetClosed',
+ components: {
+ MrWidgetAuthorTime,
+ statusIcon,
+ },
+ props: {
+ /* TODO: This is providing all store and service down when it
only needs metrics and targetBranch */
- mr: {
- type: Object,
- required: true,
- default: () => ({}),
- },
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
},
- };
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
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 dff9ec657b9..8c808296178 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
@@ -1,21 +1,21 @@
<script>
- import statusIcon from '../mr_widget_status_icon.vue';
+import statusIcon from '../mr_widget_status_icon.vue';
- export default {
- name: 'MRWidgetConflicts',
- components: {
- statusIcon,
- },
- props: {
- /* TODO: This is providing all store and service down when it
+export default {
+ name: 'MRWidgetConflicts',
+ components: {
+ statusIcon,
+ },
+ props: {
+ /* TODO: This is providing all store and service down when it
only needs a few props */
- mr: {
- type: Object,
- required: true,
- default: () => ({}),
- },
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
},
- };
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
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 97f4196b94d..484b5600d63 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
@@ -1,82 +1,82 @@
<script>
- import Flash from '../../../flash';
- import statusIcon from '../mr_widget_status_icon.vue';
- import MrWidgetAuthor from '../../components/mr_widget_author.vue';
- import eventHub from '../../event_hub';
+import Flash from '../../../flash';
+import statusIcon from '../mr_widget_status_icon.vue';
+import MrWidgetAuthor from '../../components/mr_widget_author.vue';
+import eventHub from '../../event_hub';
- export default {
- name: 'MRWidgetMergeWhenPipelineSucceeds',
- components: {
- MrWidgetAuthor,
- statusIcon,
+export default {
+ name: 'MRWidgetMergeWhenPipelineSucceeds',
+ components: {
+ MrWidgetAuthor,
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
},
- props: {
- mr: {
- type: Object,
- required: true,
- default: () => ({}),
- },
- service: {
- type: Object,
- required: true,
- default: () => ({}),
- },
+ service: {
+ type: Object,
+ required: true,
+ default: () => ({}),
},
- data() {
- return {
- isCancellingAutoMerge: false,
- isRemovingSourceBranch: false,
- };
- },
- computed: {
- canRemoveSourceBranch() {
- const {
- shouldRemoveSourceBranch,
- canRemoveSourceBranch,
- mergeUserId,
- currentUserId,
- } = this.mr;
+ },
+ data() {
+ return {
+ isCancellingAutoMerge: false,
+ isRemovingSourceBranch: false,
+ };
+ },
+ computed: {
+ canRemoveSourceBranch() {
+ const {
+ shouldRemoveSourceBranch,
+ canRemoveSourceBranch,
+ mergeUserId,
+ currentUserId,
+ } = this.mr;
- return !shouldRemoveSourceBranch &&
- canRemoveSourceBranch &&
- mergeUserId === currentUserId;
- },
+ return !shouldRemoveSourceBranch && canRemoveSourceBranch && mergeUserId === currentUserId;
},
- methods: {
- cancelAutomaticMerge() {
- this.isCancellingAutoMerge = true;
- this.service.cancelAutomaticMerge()
- .then(res => res.data)
- .then((data) => {
- eventHub.$emit('UpdateWidgetData', data);
- })
- .catch(() => {
- this.isCancellingAutoMerge = false;
- Flash('Something went wrong. Please try again.');
- });
- },
- removeSourceBranch() {
- const options = {
- sha: this.mr.sha,
- merge_when_pipeline_succeeds: true,
- should_remove_source_branch: true,
- };
+ },
+ methods: {
+ cancelAutomaticMerge() {
+ this.isCancellingAutoMerge = true;
+ this.service
+ .cancelAutomaticMerge()
+ .then(res => res.data)
+ .then(data => {
+ eventHub.$emit('UpdateWidgetData', data);
+ })
+ .catch(() => {
+ this.isCancellingAutoMerge = false;
+ Flash('Something went wrong. Please try again.');
+ });
+ },
+ removeSourceBranch() {
+ const options = {
+ sha: this.mr.sha,
+ merge_when_pipeline_succeeds: true,
+ should_remove_source_branch: true,
+ };
- this.isRemovingSourceBranch = true;
- this.service.merge(options)
- .then(res => res.data)
- .then((data) => {
- if (data.status === 'merge_when_pipeline_succeeds') {
- eventHub.$emit('MRWidgetUpdateRequested');
- }
- })
- .catch(() => {
- this.isRemovingSourceBranch = false;
- Flash('Something went wrong. Please try again.');
- });
- },
+ this.isRemovingSourceBranch = true;
+ this.service
+ .merge(options)
+ .then(res => res.data)
+ .then(data => {
+ if (data.status === 'merge_when_pipeline_succeeds') {
+ eventHub.$emit('MRWidgetUpdateRequested');
+ }
+ })
+ .catch(() => {
+ this.isRemovingSourceBranch = false;
+ Flash('Something went wrong. Please try again.');
+ });
},
- };
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
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 8184ef33022..656c3b5c47e 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
@@ -1,106 +1,100 @@
<script>
- import Flash from '~/flash';
- import tooltip from '~/vue_shared/directives/tooltip';
- import { s__, __ } from '~/locale';
- 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 Flash from '~/flash';
+import tooltip from '~/vue_shared/directives/tooltip';
+import { s__, __ } from '~/locale';
+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';
- export default {
- name: 'MRWidgetMerged',
- directives: {
- tooltip,
+export default {
+ name: 'MRWidgetMerged',
+ directives: {
+ tooltip,
+ },
+ components: {
+ MrWidgetAuthorTime,
+ statusIcon,
+ ClipboardButton,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
},
- components: {
- MrWidgetAuthorTime,
- statusIcon,
- ClipboardButton,
+ service: {
+ type: Object,
+ required: true,
+ default: () => ({}),
},
- props: {
- mr: {
- type: Object,
- required: true,
- default: () => ({}),
- },
- service: {
- type: Object,
- required: true,
- default: () => ({}),
- },
+ },
+ data() {
+ return {
+ isMakingRequest: false,
+ };
+ },
+ computed: {
+ shouldShowRemoveSourceBranch() {
+ const { sourceBranchRemoved, isRemovingSourceBranch, canRemoveSourceBranch } = this.mr;
+
+ return (
+ !sourceBranchRemoved &&
+ canRemoveSourceBranch &&
+ !this.isMakingRequest &&
+ !isRemovingSourceBranch
+ );
},
- data() {
- return {
- isMakingRequest: false,
- };
+ shouldShowSourceBranchRemoving() {
+ const { sourceBranchRemoved, isRemovingSourceBranch } = this.mr;
+ return !sourceBranchRemoved && (isRemovingSourceBranch || this.isMakingRequest);
},
- computed: {
- shouldShowRemoveSourceBranch() {
- const {
- sourceBranchRemoved,
- isRemovingSourceBranch,
- canRemoveSourceBranch,
- } = this.mr;
-
- return !sourceBranchRemoved &&
- canRemoveSourceBranch &&
- !this.isMakingRequest &&
- !isRemovingSourceBranch;
- },
- shouldShowSourceBranchRemoving() {
- const {
- sourceBranchRemoved,
- isRemovingSourceBranch,
- } = this.mr;
- return !sourceBranchRemoved &&
- (isRemovingSourceBranch || this.isMakingRequest);
- },
- shouldShowMergedButtons() {
- const {
- canRevertInCurrentMR,
- canCherryPickInCurrentMR,
- revertInForkPath,
- cherryPickInForkPath,
- } = this.mr;
+ shouldShowMergedButtons() {
+ const {
+ canRevertInCurrentMR,
+ canCherryPickInCurrentMR,
+ revertInForkPath,
+ cherryPickInForkPath,
+ } = this.mr;
- return canRevertInCurrentMR ||
- canCherryPickInCurrentMR ||
- revertInForkPath ||
- cherryPickInForkPath;
- },
- revertTitle() {
- return s__('mrWidget|Revert this merge request in a new merge request');
- },
- cherryPickTitle() {
- return s__('mrWidget|Cherry-pick this merge request in a new merge request');
- },
- revertLabel() {
- return s__('mrWidget|Revert');
- },
- cherryPickLabel() {
- return s__('mrWidget|Cherry-pick');
- },
+ return (
+ canRevertInCurrentMR || canCherryPickInCurrentMR || revertInForkPath || cherryPickInForkPath
+ );
+ },
+ revertTitle() {
+ return s__('mrWidget|Revert this merge request in a new merge request');
+ },
+ cherryPickTitle() {
+ return s__('mrWidget|Cherry-pick this merge request in a new merge request');
},
- methods: {
- removeSourceBranch() {
- this.isMakingRequest = true;
+ revertLabel() {
+ return s__('mrWidget|Revert');
+ },
+ cherryPickLabel() {
+ return s__('mrWidget|Cherry-pick');
+ },
+ },
+ methods: {
+ removeSourceBranch() {
+ this.isMakingRequest = true;
- this.service.removeSourceBranch()
- .then(res => res.data)
- .then((data) => {
- if (data.message === 'Branch was removed') {
- eventHub.$emit('MRWidgetUpdateRequested', () => {
- this.isMakingRequest = false;
- });
- }
- })
- .catch(() => {
- this.isMakingRequest = false;
- Flash(__('Something went wrong. Please try again.'));
- });
- },
+ this.service
+ .removeSourceBranch()
+ .then(res => res.data)
+ .then(data => {
+ if (data.message === 'Branch was removed') {
+ eventHub.$emit('MRWidgetUpdateRequested', () => {
+ this.isMakingRequest = false;
+ });
+ }
+ })
+ .catch(() => {
+ this.isMakingRequest = false;
+ Flash(__('Something went wrong. Please try again.'));
+ });
},
- };
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
@@ -162,18 +156,20 @@
<span class="label-branch">
<a :href="mr.targetBranchPath">{{ mr.targetBranch }}</a>
</span>
- with
- <a
- :href="mr.mergeCommitPath"
- class="commit-sha js-mr-merged-commit-sha"
- v-text="mr.shortMergeCommitSha"
- >
- </a>
- <clipboard-button
- :title="__('Copy commit SHA to clipboard')"
- :text="mr.mergeCommitSha"
- css-class="btn-default btn-transparent btn-clipboard js-mr-merged-copy-sha"
- />
+ <template v-if="mr.mergeCommitSha">
+ with
+ <a
+ :href="mr.mergeCommitPath"
+ class="commit-sha js-mr-merged-commit-sha"
+ v-text="mr.shortMergeCommitSha"
+ >
+ </a>
+ <clipboard-button
+ :title="__('Copy commit SHA to clipboard')"
+ :text="mr.mergeCommitSha"
+ css-class="btn-default btn-transparent btn-clipboard js-mr-merged-copy-sha"
+ />
+ </template>
</p>
<p v-if="mr.sourceBranchRemoved">
{{ s__("mrWidget|The source branch has been removed") }}
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 953ddf40a51..139e64d1878 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
@@ -1,19 +1,19 @@
<script>
- import statusIcon from '../mr_widget_status_icon.vue';
+import statusIcon from '../mr_widget_status_icon.vue';
- export default {
- name: 'MRWidgetMerging',
- components: {
- statusIcon,
+export default {
+ name: 'MRWidgetMerging',
+ components: {
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
+ default: () => ({}),
},
- props: {
- mr: {
- type: Object,
- required: true,
- default: () => ({}),
- },
- },
- };
+ },
+};
</script>
<template>
<div class="mr-widget-body mr-state-locked media">
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 b0e96f74626..227e9b85f9d 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
@@ -1,40 +1,48 @@
<script>
- import { sprintf, s__ } from '~/locale';
- import tooltip from '~/vue_shared/directives/tooltip';
- import statusIcon from '../mr_widget_status_icon.vue';
- import mrWidgetMergeHelp from '../../components/mr_widget_merge_help.vue';
+import { sprintf, s__ } from '~/locale';
+import tooltip from '~/vue_shared/directives/tooltip';
+import statusIcon from '../mr_widget_status_icon.vue';
+import mrWidgetMergeHelp from '../../components/mr_widget_merge_help.vue';
- export default {
- name: 'MRWidgetMissingBranch',
- directives: {
- tooltip,
+export default {
+ name: 'MRWidgetMissingBranch',
+ directives: {
+ tooltip,
+ },
+ components: {
+ mrWidgetMergeHelp,
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
},
- components: {
- mrWidgetMergeHelp,
- statusIcon,
+ },
+ computed: {
+ missingBranchName() {
+ return this.mr.sourceBranchRemoved ? 'source' : 'target';
},
- props: {
- mr: {
- type: Object,
- required: true,
- },
- },
- computed: {
- missingBranchName() {
- return this.mr.sourceBranchRemoved ? 'source' : 'target';
- },
- missingBranchNameMessage() {
- return sprintf(s__('mrWidget| Please restore it or use a different %{missingBranchName} branch'), {
+ missingBranchNameMessage() {
+ return sprintf(
+ s__('mrWidget| Please restore it or use a different %{missingBranchName} branch'),
+ {
missingBranchName: this.missingBranchName,
- });
- },
- message() {
- return sprintf(s__('mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line'), {
+ },
+ );
+ },
+ message() {
+ return sprintf(
+ s__(
+ 'mrWidget|If the %{missingBranchName} branch exists in your local repository, you can merge this merge request manually using the command line',
+ ),
+ {
missingBranchName: this.missingBranchName,
- });
- },
+ },
+ );
},
- };
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
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 92eee2cf5dd..360559ae0f0 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
@@ -1,12 +1,12 @@
<script>
- import StatusIcon from '../mr_widget_status_icon.vue';
+import StatusIcon from '../mr_widget_status_icon.vue';
- export default {
- name: 'MRWidgetNotAllowed',
- components: {
- StatusIcon,
- },
- };
+export default {
+ name: 'MRWidgetNotAllowed',
+ components: {
+ StatusIcon,
+ },
+};
</script>
<template>
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 37ee5215cea..a4eb5afb21c 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
@@ -1,12 +1,12 @@
<script>
- import StatusIcon from '../mr_widget_status_icon.vue';
+import StatusIcon from '../mr_widget_status_icon.vue';
- export default {
- name: 'MRWidgetPipelineBlocked',
- components: {
- StatusIcon,
- },
- };
+export default {
+ name: 'MRWidgetPipelineBlocked',
+ components: {
+ StatusIcon,
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
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 f31c7a3edb8..041fa13a8f5 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,85 +1,87 @@
<script>
- import simplePoll from '../../../lib/utils/simple_poll';
- import eventHub from '../../event_hub';
- import statusIcon from '../mr_widget_status_icon.vue';
- import Flash from '../../../flash';
+import simplePoll from '../../../lib/utils/simple_poll';
+import eventHub from '../../event_hub';
+import statusIcon from '../mr_widget_status_icon.vue';
+import Flash from '../../../flash';
- export default {
- name: 'MRWidgetRebase',
- components: {
- statusIcon,
+export default {
+ name: 'MRWidgetRebase',
+ components: {
+ statusIcon,
+ },
+ props: {
+ mr: {
+ type: Object,
+ required: true,
},
- props: {
- mr: {
- type: Object,
- required: true,
- },
- service: {
- type: Object,
- required: true,
- },
+ service: {
+ type: Object,
+ required: true,
},
- data() {
- return {
- isMakingRequest: false,
- rebasingError: null,
- };
+ },
+ data() {
+ return {
+ isMakingRequest: false,
+ rebasingError: null,
+ };
+ },
+ computed: {
+ status() {
+ if (this.mr.rebaseInProgress || this.isMakingRequest) {
+ return 'loading';
+ }
+ if (!this.mr.canPushToSourceBranch && !this.mr.rebaseInProgress) {
+ return 'warning';
+ }
+ return 'success';
},
- computed: {
- status() {
- if (this.mr.rebaseInProgress || this.isMakingRequest) {
- return 'loading';
- }
- if (!this.mr.canPushToSourceBranch && !this.mr.rebaseInProgress) {
- return 'warning';
- }
- return 'success';
- },
- showDisabledButton() {
- return ['failed', 'loading'].includes(this.status);
- },
+ showDisabledButton() {
+ return ['failed', 'loading'].includes(this.status);
},
- methods: {
- rebase() {
- this.isMakingRequest = true;
- this.rebasingError = null;
+ },
+ methods: {
+ rebase() {
+ this.isMakingRequest = true;
+ this.rebasingError = null;
- this.service.rebase()
- .then(() => {
- simplePoll(this.checkRebaseStatus);
- })
- .catch((error) => {
- this.rebasingError = error.merge_error;
+ this.service
+ .rebase()
+ .then(() => {
+ simplePoll(this.checkRebaseStatus);
+ })
+ .catch(error => {
+ this.rebasingError = error.merge_error;
+ this.isMakingRequest = false;
+ Flash('Something went wrong. Please try again.');
+ });
+ },
+ checkRebaseStatus(continuePolling, stopPolling) {
+ this.service
+ .poll()
+ .then(res => res.data)
+ .then(res => {
+ if (res.rebase_in_progress) {
+ continuePolling();
+ } else {
this.isMakingRequest = false;
- Flash('Something went wrong. Please try again.');
- });
- },
- checkRebaseStatus(continuePolling, stopPolling) {
- this.service.poll()
- .then(res => res.data)
- .then((res) => {
- if (res.rebase_in_progress) {
- continuePolling();
- } else {
- this.isMakingRequest = false;
-
- if (res.merge_error && res.merge_error.length) {
- this.rebasingError = res.merge_error;
- Flash('Something went wrong. Please try again.');
- }
- eventHub.$emit('MRWidgetUpdateRequested');
- stopPolling();
+ if (res.merge_error && res.merge_error.length) {
+ this.rebasingError = res.merge_error;
+ Flash('Something went wrong. Please try again.');
}
- })
- .catch(() => {
- this.isMakingRequest = false;
- Flash('Something went wrong. Please try again.');
+
+ eventHub.$emit('MRWidgetUpdateRequested');
stopPolling();
- });
- },
+ }
+ })
+ .catch(() => {
+ this.isMakingRequest = false;
+ Flash('Something went wrong. Please try again.');
+ stopPolling();
+ });
},
- };
+ },
+};
</script>
<template>
<div class="mr-widget-body media">
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 89c9a41f316..9129fcbb918 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
@@ -24,9 +24,10 @@ export default {
methods: {
removeWIP() {
this.isMakingRequest = true;
- this.service.removeWIP()
+ this.service
+ .removeWIP()
.then(res => res.data)
- .then((data) => {
+ .then(data => {
eventHub.$emit('UpdateWidgetData', data);
new window.Flash('The merge request can now be merged.', 'notice'); // eslint-disable-line
$('.merge-request .detail-page-description .title').text(this.mr.title);
diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
deleted file mode 100644
index a23496c6bf5..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * This file is the centerpiece of an attempt to reduce potential conflicts
- * between the CE and EE versions of the MR widget. EE additions to the MR widget should
- * be contained in the ee/vue_merge_request_widget directory, and should **extend**
- * rather than mutate CE MR Widget code.
- *
- * This file should be the only source of conflicts between EE and CE. EE-only components should
- * imported directly where they are needed, and import paths for EE extensions of CE components
- * should overwrite import paths **without** changing the order of dependencies listed here.
- */
-
-export { default as Vue } from 'vue';
-export { default as SmartInterval } from '~/smart_interval';
-export { default as WidgetHeader } from './components/mr_widget_header.vue';
-export { default as WidgetMergeHelp } from './components/mr_widget_merge_help.vue';
-export { default as WidgetPipeline } from './components/mr_widget_pipeline.vue';
-export { default as Deployment } from './components/deployment.vue';
-export { default as WidgetRelatedLinks } from './components/mr_widget_related_links.vue';
-export { default as MergedState } from './components/states/mr_widget_merged.vue';
-export { default as FailedToMerge } from './components/states/mr_widget_failed_to_merge.vue';
-export { default as ClosedState } from './components/states/mr_widget_closed.vue';
-export { default as MergingState } from './components/states/mr_widget_merging.vue';
-export { default as WorkInProgressState } from './components/states/work_in_progress.vue';
-export { default as ArchivedState } from './components/states/mr_widget_archived.vue';
-export { default as ConflictsState } from './components/states/mr_widget_conflicts.vue';
-export { default as NothingToMergeState } from './components/states/nothing_to_merge.vue';
-export { default as MissingBranchState } from './components/states/mr_widget_missing_branch.vue';
-export { default as NotAllowedState } from './components/states/mr_widget_not_allowed.vue';
-export { default as ReadyToMergeState } from './components/states/ready_to_merge.vue';
-export { default as ShaMismatchState } from './components/states/sha_mismatch.vue';
-export { default as UnresolvedDiscussionsState } from './components/states/unresolved_discussions.vue';
-export { default as PipelineBlockedState } from './components/states/mr_widget_pipeline_blocked.vue';
-export { default as PipelineFailedState } from './components/states/pipeline_failed.vue';
-export { default as MergeWhenPipelineSucceedsState } from './components/states/mr_widget_merge_when_pipeline_succeeds.vue';
-export { default as RebaseState } from './components/states/mr_widget_rebase.vue';
-export { default as AutoMergeFailed } from './components/states/mr_widget_auto_merge_failed.vue';
-export { default as CheckingState } from './components/states/mr_widget_checking.vue';
-export { default as MRWidgetStore } from './stores/mr_widget_store';
-export { default as MRWidgetService } from './services/mr_widget_service';
-export { default as eventHub } from './event_hub';
-export { default as getStateKey } from './stores/get_state_key';
-export { default as stateMaps } from './stores/state_maps';
-export { default as SquashBeforeMerge } from './components/states/squash_before_merge.vue';
-export { default as notify } from '../lib/utils/notify';
-export { default as SourceBranchRemovalStatus } from './components/source_branch_removal_status.vue';
-
-export { default as mrWidgetOptions } from './mr_widget_options.vue';
diff --git a/app/assets/javascripts/vue_merge_request_widget/ee_switch_mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/ee_switch_mr_widget_options.js
new file mode 100644
index 00000000000..8780aa4bd1c
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/ee_switch_mr_widget_options.js
@@ -0,0 +1,3 @@
+import MRWidgetOptions from './mr_widget_options.vue';
+
+export default MRWidgetOptions;
diff --git a/app/assets/javascripts/vue_merge_request_widget/index.js b/app/assets/javascripts/vue_merge_request_widget/index.js
index cc6e620f365..60cebbfc2b2 100644
--- a/app/assets/javascripts/vue_merge_request_widget/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/index.js
@@ -1,4 +1,5 @@
-import { Vue, mrWidgetOptions } from './dependencies';
+import Vue from 'vue';
+import MrWidgetOptions from './ee_switch_mr_widget_options';
import Translate from '../vue_shared/translate';
Vue.use(Translate);
@@ -6,7 +7,7 @@ Vue.use(Translate);
export default () => {
gl.mrWidgetData.gitlabLogo = gon.gitlab_logo;
- const vm = new Vue(mrWidgetOptions);
+ const vm = new Vue(MrWidgetOptions);
window.gl.mrWidget = {
checkStatus: vm.checkStatus,
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 0e445a29de4..5d9f7cebcf2 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
@@ -1,41 +1,38 @@
<script>
-
import Project from '~/pages/projects/project';
import SmartInterval from '~/smart_interval';
import createFlash from '../flash';
-import {
- WidgetHeader,
- WidgetMergeHelp,
- WidgetPipeline,
- Deployment,
- WidgetRelatedLinks,
- MergedState,
- ClosedState,
- MergingState,
- RebaseState,
- WorkInProgressState,
- ArchivedState,
- ConflictsState,
- NothingToMergeState,
- MissingBranchState,
- NotAllowedState,
- ReadyToMergeState,
- ShaMismatchState,
- UnresolvedDiscussionsState,
- PipelineBlockedState,
- PipelineFailedState,
- FailedToMerge,
- MergeWhenPipelineSucceedsState,
- AutoMergeFailed,
- CheckingState,
- MRWidgetStore,
- MRWidgetService,
- eventHub,
- stateMaps,
- SquashBeforeMerge,
- notify,
- SourceBranchRemovalStatus,
-} from './dependencies';
+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 Deployment from './components/deployment.vue';
+import WidgetRelatedLinks from './components/mr_widget_related_links.vue';
+import MergedState from './components/states/mr_widget_merged.vue';
+import ClosedState from './components/states/mr_widget_closed.vue';
+import MergingState from './components/states/mr_widget_merging.vue';
+import RebaseState from './components/states/mr_widget_rebase.vue';
+import WorkInProgressState from './components/states/work_in_progress.vue';
+import ArchivedState from './components/states/mr_widget_archived.vue';
+import ConflictsState from './components/states/mr_widget_conflicts.vue';
+import NothingToMergeState from './components/states/nothing_to_merge.vue';
+import MissingBranchState from './components/states/mr_widget_missing_branch.vue';
+import NotAllowedState from './components/states/mr_widget_not_allowed.vue';
+import ReadyToMergeState from './components/states/ready_to_merge.vue';
+import ShaMismatchState from './components/states/sha_mismatch.vue';
+import UnresolvedDiscussionsState from './components/states/unresolved_discussions.vue';
+import PipelineBlockedState from './components/states/mr_widget_pipeline_blocked.vue';
+import PipelineFailedState from './components/states/pipeline_failed.vue';
+import FailedToMerge from './components/states/mr_widget_failed_to_merge.vue';
+import MergeWhenPipelineSucceedsState from './components/states/mr_widget_merge_when_pipeline_succeeds.vue';
+import AutoMergeFailed from './components/states/mr_widget_auto_merge_failed.vue';
+import CheckingState from './components/states/mr_widget_checking.vue';
+import MRWidgetStore from './stores/ee_switch_mr_widget_store';
+import MRWidgetService from './services/ee_switch_mr_widget_service';
+import eventHub from './event_hub';
+import stateMaps from './stores/ee_switch_state_maps';
+import SquashBeforeMerge from './components/states/squash_before_merge.vue';
+import notify from '~/lib/utils/notify';
+import SourceBranchRemovalStatus from './components/source_branch_removal_status.vue';
import GroupedTestReportsApp from '../reports/components/grouped_test_reports_app.vue';
import { setFaviconOverlay } from '../lib/utils/common_utils';
@@ -100,8 +97,11 @@ export default {
return !!this.mr.relatedLinks && !this.mr.isNothingToMergeState;
},
shouldRenderSourceBranchRemovalStatus() {
- return !this.mr.canRemoveSourceBranch && this.mr.shouldRemoveSourceBranch &&
- (!this.mr.isNothingToMergeState && !this.mr.isMergedState);
+ return (
+ !this.mr.canRemoveSourceBranch &&
+ this.mr.shouldRemoveSourceBranch &&
+ (!this.mr.isNothingToMergeState && !this.mr.isMergedState)
+ );
},
},
created() {
@@ -110,7 +110,8 @@ export default {
eventHub.$on('mr.discussion.updated', this.checkStatus);
},
mounted() {
- this.handleMounted();
+ this.setFaviconHelper();
+ this.initDeploymentsPolling();
},
beforeDestroy() {
eventHub.$off('mr.discussion.updated', this.checkStatus);
@@ -133,9 +134,10 @@ export default {
return new MRWidgetService(endpoints);
},
checkStatus(cb) {
- return this.service.checkStatus()
+ return this.service
+ .checkStatus()
.then(res => res.data)
- .then((data) => {
+ .then(data => {
this.handleNotification(data);
this.mr.setData(data);
this.setFaviconHelper();
@@ -172,20 +174,24 @@ export default {
return Promise.resolve();
},
fetchDeployments() {
- return this.service.fetchDeployments()
+ return this.service
+ .fetchDeployments()
.then(res => res.data)
- .then((data) => {
+ .then(data => {
if (data.length) {
this.mr.deployments = data;
}
})
.catch(() => {
- createFlash('Something went wrong while fetching the environments for this merge request. Please try again.');
+ createFlash(
+ 'Something went wrong while fetching the environments for this merge request. Please try again.',
+ );
});
},
fetchActionsContent() {
- this.service.fetchMergeActionsContent()
- .then((res) => {
+ this.service
+ .fetchMergeActionsContent()
+ .then(res => {
if (res.data) {
const el = document.createElement('div');
el.innerHTML = res.data;
@@ -212,22 +218,22 @@ export default {
this.pollingInterval.stopTimer();
},
bindEventHubListeners() {
- eventHub.$on('MRWidgetUpdateRequested', (cb) => {
+ eventHub.$on('MRWidgetUpdateRequested', cb => {
this.checkStatus(cb);
});
// `params` should be an Array contains a Boolean, like `[true]`
// Passing parameter as Boolean didn't work.
- eventHub.$on('SetBranchRemoveFlag', (params) => {
+ eventHub.$on('SetBranchRemoveFlag', params => {
[this.mr.isRemovingSourceBranch] = params;
});
- eventHub.$on('FailedToMerge', (mergeError) => {
+ eventHub.$on('FailedToMerge', mergeError => {
this.mr.state = 'failedToMerge';
this.mr.mergeError = mergeError;
});
- eventHub.$on('UpdateWidgetData', (data) => {
+ eventHub.$on('UpdateWidgetData', data => {
this.mr.setData(data);
});
@@ -243,10 +249,6 @@ export default {
this.stopPolling();
});
},
- handleMounted() {
- this.setFaviconHelper();
- this.initDeploymentsPolling();
- },
},
};
</script>
@@ -271,8 +273,10 @@ export default {
<div class="mr-section-container">
<grouped-test-reports-app
v-if="mr.testResultsPath"
+ class="js-reports-container"
:endpoint="mr.testResultsPath"
/>
+
<div class="mr-widget-section">
<component
:is="componentName"
diff --git a/app/assets/javascripts/vue_merge_request_widget/services/ee_switch_mr_widget_service.js b/app/assets/javascripts/vue_merge_request_widget/services/ee_switch_mr_widget_service.js
new file mode 100644
index 00000000000..ea2aabb78fe
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/services/ee_switch_mr_widget_service.js
@@ -0,0 +1,3 @@
+import MRWidgetService from './mr_widget_service';
+
+export default MRWidgetService;
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_get_state_key.js b/app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_get_state_key.js
new file mode 100644
index 00000000000..ebef30e3eab
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_get_state_key.js
@@ -0,0 +1,3 @@
+import getStateKey from './get_state_key';
+
+export default getStateKey;
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_mr_widget_store.js
new file mode 100644
index 00000000000..92a07c53f2d
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_mr_widget_store.js
@@ -0,0 +1,3 @@
+import MergeRequestStore from './mr_widget_store';
+
+export default MergeRequestStore;
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_state_maps.js b/app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_state_maps.js
new file mode 100644
index 00000000000..50cf9503ea7
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/ee_switch_state_maps.js
@@ -0,0 +1,3 @@
+import stateMaps from './state_maps';
+
+export default stateMaps;
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 672e5280b5e..e6655914700 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -1,5 +1,5 @@
import Timeago from 'timeago.js';
-import { getStateKey } from '../dependencies';
+import getStateKey from './ee_switch_get_state_key';
import { stateKey } from './state_maps';
import { formatDate } from '../../lib/utils/datetime_utility';
diff --git a/app/assets/javascripts/vue_shared/components/bar_chart.vue b/app/assets/javascripts/vue_shared/components/bar_chart.vue
index 33af7a7f1df..690dd794ba4 100644
--- a/app/assets/javascripts/vue_shared/components/bar_chart.vue
+++ b/app/assets/javascripts/vue_shared/components/bar_chart.vue
@@ -118,7 +118,9 @@ export default {
this.rectYAxisLabelDims.height != null ? this.rectYAxisLabelDims.height / 2 : 0;
const yCoord = this.vbHeight / 2 + rectWidth - 5;
- return `translate(${this.minX + this.yAxisTextTransformPadding}, ${yCoord}) rotate(-${this.yAxisTextRotation})`;
+ return `translate(${this.minX + this.yAxisTextTransformPadding}, ${yCoord}) rotate(-${
+ this.yAxisTextRotation
+ })`;
},
},
mounted() {
@@ -207,8 +209,7 @@ export default {
renderedYAxis.selectAll('.tick').each(function createTickLines(d, i) {
if (i > 0) {
- d3
- .select(this)
+ d3.select(this)
.select('line')
.attr('x2', width)
.attr('class', 'axis-tick');
@@ -217,8 +218,7 @@ export default {
// Add the panning capabilities
if (this.isPanAvailable) {
- d3
- .select(this.$refs.baseSvg)
+ d3.select(this.$refs.baseSvg)
.call(this.zoom)
.on('wheel.zoom', null); // This disables the pan of the graph with the scroll of the mouse wheel
}
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 a2518e2a611..c60052fec50 100644
--- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
+++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
@@ -43,7 +43,7 @@ export default {
computed: {
cssClass() {
const className = this.status.group;
- return className ? `ci-status ci-${className}` : 'ci-status';
+ return className ? `ci-status ci-${className} qa-status-badge` : 'ci-status qa-status-badge';
},
},
};
diff --git a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
index 9c1e5c68649..4d63296e332 100644
--- a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
@@ -1,85 +1,85 @@
<script>
- /* eslint-disable vue/require-default-prop */
- export default {
- name: 'DeprecatedModal', // use GlModal instead
+/* eslint-disable vue/require-default-prop */
+export default {
+ name: 'DeprecatedModal', // use GlModal instead
- props: {
- id: {
- type: String,
- required: false,
- },
- title: {
- type: String,
- required: false,
- },
- text: {
- type: String,
- required: false,
- },
- hideFooter: {
- type: Boolean,
- required: false,
- default: false,
- },
- kind: {
- type: String,
- required: false,
- default: 'primary',
- },
- modalDialogClass: {
- type: String,
- required: false,
- default: '',
- },
- closeKind: {
- type: String,
- required: false,
- default: 'default',
- },
- closeButtonLabel: {
- type: String,
- required: false,
- default: 'Cancel',
- },
- primaryButtonLabel: {
- type: String,
- required: false,
- default: '',
- },
- secondaryButtonLabel: {
- type: String,
- required: false,
- default: '',
- },
- submitDisabled: {
- type: Boolean,
- required: false,
- default: false,
- },
+ props: {
+ id: {
+ type: String,
+ required: false,
},
+ title: {
+ type: String,
+ required: false,
+ },
+ text: {
+ type: String,
+ required: false,
+ },
+ hideFooter: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ kind: {
+ type: String,
+ required: false,
+ default: 'primary',
+ },
+ modalDialogClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ closeKind: {
+ type: String,
+ required: false,
+ default: 'default',
+ },
+ closeButtonLabel: {
+ type: String,
+ required: false,
+ default: 'Cancel',
+ },
+ primaryButtonLabel: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ secondaryButtonLabel: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ submitDisabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
- computed: {
- btnKindClass() {
- return {
- [`btn-${this.kind}`]: true,
- };
- },
- btnCancelKindClass() {
- return {
- [`btn-${this.closeKind}`]: true,
- };
- },
+ computed: {
+ btnKindClass() {
+ return {
+ [`btn-${this.kind}`]: true,
+ };
+ },
+ btnCancelKindClass() {
+ return {
+ [`btn-${this.closeKind}`]: true,
+ };
},
+ },
- methods: {
- emitCancel(event) {
- this.$emit('cancel', event);
- },
- emitSubmit(event) {
- this.$emit('submit', event);
- },
+ methods: {
+ emitCancel(event) {
+ this.$emit('cancel', event);
+ },
+ emitSubmit(event) {
+ this.$emit('submit', event);
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
index 9bca1993ccc..bffaa096210 100644
--- a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
+++ b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
@@ -549,6 +549,7 @@ const fileNameIcons = {
jenkinsfile: 'jenkins',
'firebase.json': 'firebase',
'.firebaserc': 'firebase',
+ Rakefile: 'ruby',
'rollup.config.js': 'rollup',
'rollup.config.ts': 'rollup',
'rollup-config.js': 'rollup',
@@ -583,7 +584,5 @@ const fileNameIcons = {
};
export default function getIconForFile(name) {
- return fileNameIcons[name] ||
- fileExtensionIcons[name ? name.split('.').pop() : ''] ||
- '';
+ return fileNameIcons[name] || fileExtensionIcons[name ? name.split('.').pop() : ''] || '';
}
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index 36a345130c0..2d89a156117 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -34,10 +34,21 @@ export default {
required: false,
default: false,
},
+ displayTextKey: {
+ type: String,
+ required: false,
+ default: 'name',
+ },
+ shouldTruncateStart: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
mouseOver: false,
+ truncateStart: 0,
};
},
computed: {
@@ -60,6 +71,15 @@ export default {
'is-open': this.file.opened,
};
},
+ outputText() {
+ const text = this.file[this.displayTextKey];
+
+ if (this.truncateStart === 0) {
+ return text;
+ }
+
+ return `...${text.substring(this.truncateStart, text.length)}`;
+ },
},
watch: {
'file.active': function fileActiveWatch(active) {
@@ -72,6 +92,15 @@ export default {
if (this.hasPathAtCurrentRoute()) {
this.scrollIntoView(true);
}
+
+ if (this.shouldTruncateStart) {
+ const { scrollWidth, offsetWidth } = this.$refs.textOutput;
+ const textOverflow = scrollWidth - offsetWidth;
+
+ if (textOverflow > 0) {
+ this.truncateStart = Math.ceil(textOverflow / 5) + 3;
+ }
+ }
},
methods: {
toggleTreeOpen(path) {
@@ -139,6 +168,7 @@ export default {
class="file-row-name-container"
>
<span
+ ref="textOutput"
:style="levelIndentation"
class="file-row-name str-truncated"
>
@@ -156,7 +186,7 @@ export default {
:size="16"
class="append-right-5"
/>
- {{ file.name }}
+ {{ outputText }}
</span>
<component
:is="extraComponent"
@@ -175,6 +205,8 @@ export default {
:hide-extra-on-tree="hideExtraOnTree"
:extra-component="extraComponent"
:show-changed-icon="showChangedIcon"
+ :display-text-key="displayTextKey"
+ :should-truncate-start="shouldTruncateStart"
@toggleTreeOpen="toggleTreeOpen"
@clickFile="clickedFile"
/>
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
new file mode 100644
index 00000000000..460fa6ad72e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
@@ -0,0 +1,143 @@
+<script>
+import $ from 'jquery';
+import Icon from '~/vue_shared/components/icon.vue';
+/**
+ * Renders a split dropdown with
+ * an input that allows to search through the given
+ * array of options.
+ */
+export default {
+ name: 'FilteredSearchDropdown',
+ components: {
+ Icon,
+ },
+ props: {
+ title: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ buttonType: {
+ required: false,
+ validator: value =>
+ ['primary', 'default', 'secondary', 'success', 'info', 'warning', 'danger'].indexOf(
+ value,
+ ) !== -1,
+ default: 'default',
+ },
+ size: {
+ required: false,
+ type: String,
+ default: 'sm',
+ },
+ items: {
+ type: Array,
+ required: true,
+ },
+ visibleItems: {
+ type: Number,
+ required: false,
+ default: 5,
+ },
+ filterKey: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ filter: '',
+ };
+ },
+ computed: {
+ className() {
+ return `btn btn-${this.buttonType} btn-${this.size}`;
+ },
+ filteredResults() {
+ if (this.filter !== '') {
+ return this.items.filter(
+ item => item[this.filterKey] && item[this.filterKey].toLowerCase().includes(this.filter.toLowerCase()),
+ );
+ }
+
+ return this.items.slice(0, this.visibleItems);
+ }
+ },
+ mounted() {
+ /**
+ * Resets the filter every time the user closes the dropdown
+ */
+ $(this.$el)
+ .on('shown.bs.dropdown', () => {
+ this.$nextTick(() => this.$refs.searchInput.focus());
+ })
+ .on('hidden.bs.dropdown', () => {
+ this.filter = '';
+ });
+ },
+};
+</script>
+<template>
+ <div class="dropdown">
+ <div class="btn-group">
+ <slot
+ name="mainAction"
+ :class-name="className"
+ >
+ <button
+ type="button"
+ :class="className"
+ >
+ {{ title }}
+ </button>
+ </slot>
+
+ <button
+ type="button"
+ :class="className"
+ class="dropdown-toggle dropdown-toggle-split"
+ data-toggle="dropdown"
+ aria-haspopup="true"
+ aria-expanded="false"
+ aria-label="Expand dropdown"
+ >
+ <icon
+ name="angle-down"
+ :size="12"
+ />
+ </button>
+ <div class="dropdown-menu dropdown-menu-right">
+ <div class="dropdown-input">
+ <input
+ ref="searchInput"
+ v-model="filter"
+ type="search"
+ placeholder="Filter"
+ class="js-filtered-dropdown-input dropdown-input-field"
+ />
+ <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>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/gl_countdown.vue b/app/assets/javascripts/vue_shared/components/gl_countdown.vue
new file mode 100644
index 00000000000..9327a2a4a6c
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/gl_countdown.vue
@@ -0,0 +1,49 @@
+<script>
+import { calculateRemainingMilliseconds, formatTime } from '~/lib/utils/datetime_utility';
+
+/**
+ * Counts down to a given end date.
+ */
+export default {
+ props: {
+ endDateString: {
+ type: String,
+ required: true,
+ validator(value) {
+ return !Number.isNaN(new Date(value).getTime());
+ },
+ },
+ },
+
+ data() {
+ return {
+ remainingTime: formatTime(0),
+ countdownUpdateIntervalId: null,
+ };
+ },
+
+ mounted() {
+ const updateRemainingTime = () => {
+ const remainingMilliseconds = calculateRemainingMilliseconds(this.endDateString);
+ this.remainingTime = formatTime(remainingMilliseconds);
+ };
+
+ updateRemainingTime();
+ this.countdownUpdateIntervalId = window.setInterval(updateRemainingTime, 1000);
+ },
+
+ beforeDestroy() {
+ window.clearInterval(this.countdownUpdateIntervalId);
+ },
+};
+</script>
+
+<template>
+ <time
+ v-gl-tooltip
+ :datetime="endDateString"
+ :title="endDateString"
+ >
+ {{ remainingTime }}
+ </time>
+</template>
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 b371b6adf7e..aee88cae48d 100644
--- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue
+++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
@@ -69,6 +69,9 @@ export default {
onClickAction(action) {
this.$emit('actionClicked', action);
},
+ onClickSidebarButton() {
+ this.$emit('clickedSidebarButton');
+ },
},
};
</script>
@@ -161,21 +164,21 @@ export default {
</i>
</button>
</template>
- <button
- v-if="hasSidebarButton"
- id="toggleSidebar"
- type="button"
- class="btn btn-default d-block d-sm-none d-md-none
+ </section>
+ <button
+ v-if="hasSidebarButton"
+ id="toggleSidebar"
+ type="button"
+ class="btn btn-default d-block d-sm-none
sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header"
- aria-label="Toggle Sidebar"
+ @click="onClickSidebarButton"
+ >
+ <i
+ class="fa fa-angle-double-left"
+ aria-hidden="true"
+ aria-labelledby="toggleSidebar"
>
- <i
- class="fa fa-angle-double-left"
- aria-hidden="true"
- aria-labelledby="toggleSidebar"
- >
- </i>
- </button>
- </section>
+ </i>
+ </button>
</header>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/icon.vue b/app/assets/javascripts/vue_shared/components/icon.vue
index 5e0e7315e99..26f9d5ddc91 100644
--- a/app/assets/javascripts/vue_shared/components/icon.vue
+++ b/app/assets/javascripts/vue_shared/components/icon.vue
@@ -1,5 +1,4 @@
<script>
-
// only allow classes in images.scss e.g. s12
const validSizes = [8, 10, 12, 16, 18, 24, 32, 48, 72];
let iconValidator = () => true;
@@ -105,6 +104,7 @@ export default {
:x="x"
:y="y"
:tabindex="tabIndex"
+ aria-hidden="true"
>
<use v-bind="{ 'xlink:href':spriteHref }"/>
</svg>
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 ca8ce554588..dc88749c18f 100644
--- a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
+++ b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
@@ -1,34 +1,34 @@
<script>
- import icon from '../../../vue_shared/components/icon.vue';
+import icon from '../../../vue_shared/components/icon.vue';
- export default {
- components: {
- icon,
+export default {
+ components: {
+ icon,
+ },
+ props: {
+ isLocked: {
+ type: Boolean,
+ default: false,
+ required: false,
},
- props: {
- isLocked: {
- type: Boolean,
- default: false,
- required: false,
- },
- isConfidential: {
- type: Boolean,
- default: false,
- required: false,
- },
+ isConfidential: {
+ type: Boolean,
+ default: false,
+ required: false,
},
- computed: {
- warningIcon() {
- if (this.isConfidential) return 'eye-slash';
- if (this.isLocked) return 'lock';
+ },
+ computed: {
+ warningIcon() {
+ if (this.isConfidential) return 'eye-slash';
+ if (this.isLocked) return 'lock';
- return '';
- },
- isLockedAndConfidential() {
- return this.isConfidential && this.isLocked;
- },
+ return '';
},
- };
+ isLockedAndConfidential() {
+ return this.isConfidential && this.isLocked;
+ },
+ },
+};
</script>
<template>
<div class="issuable-note-warning">
@@ -37,7 +37,6 @@
:name="warningIcon"
:size="16"
class="icon inline"
- aria-hidden="true"
/>
<span v-if="isLockedAndConfidential">
diff --git a/app/assets/javascripts/vue_shared/components/loading_button.vue b/app/assets/javascripts/vue_shared/components/loading_button.vue
index 4cbd3e6429d..f9b7fd5b1f9 100644
--- a/app/assets/javascripts/vue_shared/components/loading_button.vue
+++ b/app/assets/javascripts/vue_shared/components/loading_button.vue
@@ -1,6 +1,6 @@
<script>
- /* eslint-disable vue/require-default-prop */
- /* This is a re-usable vue component for rendering a button
+/* 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
to show the loading status by setting the `loading` option.
This can also be used for initial page load when you don't
@@ -17,34 +17,34 @@
*/
- export default {
- props: {
- loading: {
- type: Boolean,
- required: false,
- default: false,
- },
- disabled: {
- type: Boolean,
- required: false,
- default: false,
- },
- label: {
- type: String,
- required: false,
- },
- containerClass: {
- type: [String, Array, Object],
- required: false,
- default: 'btn btn-align-content',
- },
+export default {
+ props: {
+ loading: {
+ type: Boolean,
+ required: false,
+ default: false,
},
- methods: {
- onClick(e) {
- this.$emit('click', e);
- },
+ disabled: {
+ type: Boolean,
+ required: false,
+ default: false,
},
- };
+ label: {
+ type: String,
+ required: false,
+ },
+ containerClass: {
+ type: [String, Array, Object],
+ required: false,
+ default: 'btn btn-align-content',
+ },
+ },
+ methods: {
+ onClick(e) {
+ this.$emit('click', e);
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index 10e8ddad9cd..4687de62614 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -1,141 +1,141 @@
<script>
- import $ from 'jquery';
- import { s__ } from '~/locale';
- import Flash from '../../../flash';
- import GLForm from '../../../gl_form';
- import markdownHeader from './header.vue';
- import markdownToolbar from './toolbar.vue';
- import icon from '../icon.vue';
+import $ from 'jquery';
+import { s__ } from '~/locale';
+import Flash from '../../../flash';
+import GLForm from '../../../gl_form';
+import markdownHeader from './header.vue';
+import markdownToolbar from './toolbar.vue';
+import icon from '../icon.vue';
- export default {
- components: {
- markdownHeader,
- markdownToolbar,
- icon,
+export default {
+ components: {
+ markdownHeader,
+ markdownToolbar,
+ icon,
+ },
+ props: {
+ markdownPreviewPath: {
+ type: String,
+ required: false,
+ default: '',
},
- props: {
- markdownPreviewPath: {
- type: String,
- required: false,
- default: '',
- },
- markdownDocsPath: {
- type: String,
- required: true,
- },
- markdownVersion: {
- type: Number,
- required: false,
- default: 0,
- },
- addSpacingClasses: {
- type: Boolean,
- required: false,
- default: true,
- },
- quickActionsDocsPath: {
- type: String,
- required: false,
- default: '',
- },
- canAttachFile: {
- type: Boolean,
- required: false,
- default: true,
- },
- enableAutocomplete: {
- type: Boolean,
- required: false,
- default: true,
- },
+ markdownDocsPath: {
+ type: String,
+ required: true,
},
- data() {
- return {
- markdownPreview: '',
- referencedCommands: '',
- referencedUsers: '',
- markdownPreviewLoading: false,
- previewMarkdown: false,
- };
+ markdownVersion: {
+ type: Number,
+ required: false,
+ default: 0,
},
- computed: {
- shouldShowReferencedUsers() {
- const referencedUsersThreshold = 10;
- return this.referencedUsers.length >= referencedUsersThreshold;
- },
+ addSpacingClasses: {
+ type: Boolean,
+ required: false,
+ default: true,
},
- mounted() {
- /*
- GLForm class handles all the toolbar buttons
- */
- return new GLForm($(this.$refs['gl-form']), {
- emojis: this.enableAutocomplete,
- members: this.enableAutocomplete,
- issues: this.enableAutocomplete,
- mergeRequests: this.enableAutocomplete,
- epics: this.enableAutocomplete,
- milestones: this.enableAutocomplete,
- labels: this.enableAutocomplete,
- snippets: this.enableAutocomplete,
- });
+ quickActionsDocsPath: {
+ type: String,
+ required: false,
+ default: '',
},
- beforeDestroy() {
- const glForm = $(this.$refs['gl-form']).data('glForm');
- if (glForm) {
- glForm.destroy();
- }
+ canAttachFile: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ enableAutocomplete: {
+ type: Boolean,
+ required: false,
+ default: true,
},
- methods: {
- showPreviewTab() {
- if (this.previewMarkdown) return;
+ },
+ data() {
+ return {
+ markdownPreview: '',
+ referencedCommands: '',
+ referencedUsers: '',
+ markdownPreviewLoading: false,
+ previewMarkdown: false,
+ };
+ },
+ computed: {
+ shouldShowReferencedUsers() {
+ const referencedUsersThreshold = 10;
+ return this.referencedUsers.length >= referencedUsersThreshold;
+ },
+ },
+ mounted() {
+ /*
+ GLForm class handles all the toolbar buttons
+ */
+ return new GLForm($(this.$refs['gl-form']), {
+ emojis: this.enableAutocomplete,
+ members: this.enableAutocomplete,
+ issues: this.enableAutocomplete,
+ mergeRequests: this.enableAutocomplete,
+ epics: this.enableAutocomplete,
+ milestones: this.enableAutocomplete,
+ labels: this.enableAutocomplete,
+ snippets: this.enableAutocomplete,
+ });
+ },
+ beforeDestroy() {
+ const glForm = $(this.$refs['gl-form']).data('glForm');
+ if (glForm) {
+ glForm.destroy();
+ }
+ },
+ methods: {
+ showPreviewTab() {
+ if (this.previewMarkdown) return;
- this.previewMarkdown = true;
+ this.previewMarkdown = true;
- /*
+ /*
Can't use `$refs` as the component is technically in the parent component
so we access the VNode & then get the element
*/
- const text = this.$slots.textarea[0].elm.value;
+ const text = this.$slots.textarea[0].elm.value;
- if (text) {
- this.markdownPreviewLoading = true;
- this.$http
- .post(this.versionedPreviewPath(), { text })
- .then(resp => resp.json())
- .then(data => this.renderMarkdown(data))
- .catch(() => new Flash(s__('Error loading markdown preview')));
- } else {
- this.renderMarkdown();
- }
- },
+ if (text) {
+ this.markdownPreviewLoading = true;
+ this.$http
+ .post(this.versionedPreviewPath(), { text })
+ .then(resp => resp.json())
+ .then(data => this.renderMarkdown(data))
+ .catch(() => new Flash(s__('Error loading markdown preview')));
+ } else {
+ this.renderMarkdown();
+ }
+ },
- showWriteTab() {
- this.markdownPreview = '';
- this.previewMarkdown = false;
- },
+ showWriteTab() {
+ this.markdownPreview = '';
+ this.previewMarkdown = false;
+ },
- renderMarkdown(data = {}) {
- this.markdownPreviewLoading = false;
- this.markdownPreview = data.body || 'Nothing to preview.';
+ renderMarkdown(data = {}) {
+ this.markdownPreviewLoading = false;
+ this.markdownPreview = data.body || 'Nothing to preview.';
- if (data.references) {
- this.referencedCommands = data.references.commands;
- this.referencedUsers = data.references.users;
- }
+ if (data.references) {
+ this.referencedCommands = data.references.commands;
+ this.referencedUsers = data.references.users;
+ }
- this.$nextTick(() => {
- $(this.$refs['markdown-preview']).renderGFM();
- });
- },
+ this.$nextTick(() => {
+ $(this.$refs['markdown-preview']).renderGFM();
+ });
+ },
- versionedPreviewPath() {
- const { markdownPreviewPath, markdownVersion } = this;
- return `${markdownPreviewPath}${
- markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'
- }markdown_version=${markdownVersion}`;
- },
+ versionedPreviewPath() {
+ const { markdownPreviewPath, markdownVersion } = this;
+ return `${markdownPreviewPath}${
+ markdownPreviewPath.indexOf('?') === -1 ? '?' : '&'
+ }markdown_version=${markdownVersion}`;
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue
index ccd53158820..3ddb39730c4 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue
@@ -1,63 +1,64 @@
<script>
- import $ from 'jquery';
- import tooltip from '../../directives/tooltip';
- import toolbarButton from './toolbar_button.vue';
- import icon from '../icon.vue';
+import $ from 'jquery';
+import Tooltip from '../../directives/tooltip';
+import ToolbarButton from './toolbar_button.vue';
+import Icon from '../icon.vue';
- export default {
- directives: {
- tooltip,
+export default {
+ directives: {
+ Tooltip,
+ },
+ components: {
+ ToolbarButton,
+ Icon,
+ },
+ props: {
+ previewMarkdown: {
+ type: Boolean,
+ required: true,
},
- components: {
- toolbarButton,
- icon,
+ },
+ computed: {
+ mdTable() {
+ return [
+ '| header | header |',
+ '| ------ | ------ |',
+ '| cell | cell |',
+ '| cell | cell |',
+ ].join('\n');
},
- props: {
- previewMarkdown: {
- type: Boolean,
- required: true,
- },
+ },
+ mounted() {
+ $(document).on('markdown-preview:show.vue', this.previewMarkdownTab);
+ $(document).on('markdown-preview:hide.vue', this.writeMarkdownTab);
+ },
+ beforeDestroy() {
+ $(document).off('markdown-preview:show.vue', this.previewMarkdownTab);
+ $(document).off('markdown-preview:hide.vue', this.writeMarkdownTab);
+ },
+ methods: {
+ isValid(form) {
+ return (
+ !form ||
+ (form.find('.js-vue-markdown-field').length && $(this.$el).closest('form')[0] === form[0])
+ );
},
- computed: {
- mdTable() {
- return [
- '| header | header |',
- '| ------ | ------ |',
- '| cell | cell |',
- '| cell | cell |',
- ].join('\n');
- },
- },
- mounted() {
- $(document).on('markdown-preview:show.vue', this.previewMarkdownTab);
- $(document).on('markdown-preview:hide.vue', this.writeMarkdownTab);
- },
- beforeDestroy() {
- $(document).off('markdown-preview:show.vue', this.previewMarkdownTab);
- $(document).off('markdown-preview:hide.vue', this.writeMarkdownTab);
- },
- methods: {
- isValid(form) {
- return !form ||
- form.find('.js-vue-markdown-field').length &&
- $(this.$el).closest('form')[0] === form[0];
- },
- previewMarkdownTab(event, form) {
- if (event.target.blur) event.target.blur();
- if (!this.isValid(form)) return;
+ previewMarkdownTab(event, form) {
+ if (event.target.blur) event.target.blur();
+ if (!this.isValid(form)) return;
- this.$emit('preview-markdown');
- },
+ this.$emit('preview-markdown');
+ },
- writeMarkdownTab(event, form) {
- if (event.target.blur) event.target.blur();
- if (!this.isValid(form)) return;
+ writeMarkdownTab(event, form) {
+ if (event.target.blur) event.target.blur();
+ if (!this.isValid(form)) return;
- this.$emit('write-markdown');
- },
+ this.$emit('write-markdown');
},
- };
+ },
+};
</script>
<template>
@@ -67,27 +68,27 @@
:class="{ active: !previewMarkdown }"
class="md-header-tab"
>
- <a
+ <button
class="js-write-link"
- href="#md-write-holder"
tabindex="-1"
- @click.prevent="writeMarkdownTab($event)"
+ type="button"
+ @click="writeMarkdownTab($event)"
>
Write
- </a>
+ </button>
</li>
<li
:class="{ active: previewMarkdown }"
class="md-header-tab"
>
- <a
+ <button
class="js-preview-link js-md-preview-button"
- href="#md-preview-holder"
tabindex="-1"
- @click.prevent="previewMarkdownTab($event)"
+ type="button"
+ @click="previewMarkdownTab($event)"
>
Preview
- </a>
+ </button>
</li>
<li
:class="{ active: !previewMarkdown }"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
index c45dafa9807..feb7b8f227e 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
@@ -1,32 +1,32 @@
<script>
- import { Link } from '@gitlab-org/gitlab-ui';
+import { Link } from '@gitlab-org/gitlab-ui';
- export default {
- components: {
- 'gl-link': Link,
+export default {
+ components: {
+ 'gl-link': Link,
+ },
+ props: {
+ markdownDocsPath: {
+ type: String,
+ required: true,
},
- props: {
- markdownDocsPath: {
- type: String,
- required: true,
- },
- quickActionsDocsPath: {
- type: String,
- required: false,
- default: '',
- },
- canAttachFile: {
- type: Boolean,
- required: false,
- default: true,
- },
+ quickActionsDocsPath: {
+ type: String,
+ required: false,
+ default: '',
},
- computed: {
- hasQuickActionsDocsPath() {
- return this.quickActionsDocsPath !== '';
- },
+ canAttachFile: {
+ type: Boolean,
+ required: false,
+ default: true,
},
- };
+ },
+ computed: {
+ hasQuickActionsDocsPath() {
+ return this.quickActionsDocsPath !== '';
+ },
+ },
+};
</script>
<template>
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 bda33636369..3e89e1c1e75 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
@@ -1,44 +1,44 @@
<script>
- import tooltip from '../../directives/tooltip';
- import icon from '../icon.vue';
+import tooltip from '../../directives/tooltip';
+import icon from '../icon.vue';
- export default {
- components: {
- icon,
+export default {
+ components: {
+ icon,
+ },
+ directives: {
+ tooltip,
+ },
+ props: {
+ buttonTitle: {
+ type: String,
+ required: true,
},
- directives: {
- tooltip,
+ icon: {
+ type: String,
+ required: true,
},
- props: {
- buttonTitle: {
- type: String,
- required: true,
- },
- icon: {
- type: String,
- required: true,
- },
- tag: {
- type: String,
- required: true,
- },
- tagBlock: {
- type: String,
- required: false,
- default: '',
- },
- tagSelect: {
- type: String,
- required: false,
- default: '',
- },
- prepend: {
- type: Boolean,
- required: false,
- default: false,
- },
+ tag: {
+ type: String,
+ required: true,
},
- };
+ tagBlock: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ tagSelect: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ prepend: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/memory_graph.vue b/app/assets/javascripts/vue_shared/components/memory_graph.vue
index 552a92541be..964dedb38c4 100644
--- a/app/assets/javascripts/vue_shared/components/memory_graph.vue
+++ b/app/assets/javascripts/vue_shared/components/memory_graph.vue
@@ -41,7 +41,8 @@ export default {
// Find metric timestamp which is closest to deploymentTime
timestampDiff = Math.abs(metricTimestamps[0] - median);
metricTimestamps.forEach((timestamp, index) => {
- if (index === 0) { // Skip first element
+ if (index === 0) {
+ // Skip first element
return;
}
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 38115f268bb..dcad79e521d 100644
--- a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
@@ -1,41 +1,39 @@
<script>
- /**
- * Common component to render a placeholder note and user information.
- *
- * This component needs to be used with a vuex store.
- * That vuex store needs to have a `getUserData` getter that contains
- * {
- * path: String,
- * avatar_url: String,
- * name: String,
- * username: String,
- * }
- *
- * @example
- * <placeholder-note
- * :note="{body: 'This is a note'}"
- * />
- */
- import { mapGetters } from 'vuex';
- import userAvatarLink from '../user_avatar/user_avatar_link.vue';
+/**
+ * Common component to render a placeholder note and user information.
+ *
+ * This component needs to be used with a vuex store.
+ * That vuex store needs to have a `getUserData` getter that contains
+ * {
+ * path: String,
+ * avatar_url: String,
+ * name: String,
+ * username: String,
+ * }
+ *
+ * @example
+ * <placeholder-note
+ * :note="{body: 'This is a note'}"
+ * />
+ */
+import { mapGetters } from 'vuex';
+import userAvatarLink from '../user_avatar/user_avatar_link.vue';
- export default {
- name: 'PlaceholderNote',
- components: {
- userAvatarLink,
+export default {
+ name: 'PlaceholderNote',
+ components: {
+ userAvatarLink,
+ },
+ props: {
+ note: {
+ type: Object,
+ required: true,
},
- props: {
- note: {
- type: Object,
- required: true,
- },
- },
- computed: {
- ...mapGetters([
- 'getUserData',
- ]),
- },
- };
+ },
+ computed: {
+ ...mapGetters(['getUserData']),
+ },
+};
</script>
<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 95e2b38e292..674f923478d 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,21 +1,21 @@
<script>
- /**
- * Common component to render a placeholder system note.
- *
- * @example
- * <placeholder-system-note
- * :note="{ body: 'Commands are being applied'}"
- * />
- */
- export default {
- name: 'PlaceholderSystemNote',
- props: {
- note: {
- type: Object,
- required: true,
- },
+/**
+ * Common component to render a placeholder system note.
+ *
+ * @example
+ * <placeholder-system-note
+ * :note="{ body: 'Commands are being applied'}"
+ * />
+ */
+export default {
+ name: 'PlaceholderSystemNote',
+ props: {
+ note: {
+ type: Object,
+ required: true,
},
- };
+ },
+};
</script>
<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 2122d0a508e..de3c7a80365 100644
--- a/app/assets/javascripts/vue_shared/components/notes/system_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/system_note.vue
@@ -109,7 +109,7 @@ export default {
class="system-note-commit-list-toggler flex-row"
@click="expanded = !expanded"
>
- <Icon
+ <icon
:name="toggleIcon"
:size="8"
class="append-right-5"
diff --git a/app/assets/javascripts/vue_shared/components/panel_resizer.vue b/app/assets/javascripts/vue_shared/components/panel_resizer.vue
index 7947ae1e4da..bf736a378dd 100644
--- a/app/assets/javascripts/vue_shared/components/panel_resizer.vue
+++ b/app/assets/javascripts/vue_shared/components/panel_resizer.vue
@@ -1,90 +1,90 @@
<script>
- export default {
- props: {
- startSize: {
- type: Number,
- required: true,
- },
- side: {
- type: String,
- required: true,
- },
- minSize: {
- type: Number,
- required: false,
- default: 0,
- },
- maxSize: {
- type: Number,
- required: false,
- default: Number.MAX_VALUE,
- },
- enabled: {
- type: Boolean,
- required: false,
- default: true,
- },
+export default {
+ props: {
+ startSize: {
+ type: Number,
+ required: true,
},
- data() {
- return {
- size: this.startSize,
- };
+ side: {
+ type: String,
+ required: true,
},
- computed: {
- className() {
- return `drag-${this.side}`;
- },
- cursorStyle() {
- if (this.enabled) {
- return { cursor: 'ew-resize' };
- }
- return {};
- },
+ minSize: {
+ type: Number,
+ required: false,
+ default: 0,
},
- methods: {
- resetSize(e) {
- e.preventDefault();
- this.$emit('resize-start', this.size);
+ maxSize: {
+ type: Number,
+ required: false,
+ default: Number.MAX_VALUE,
+ },
+ enabled: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ },
+ data() {
+ return {
+ size: this.startSize,
+ };
+ },
+ computed: {
+ className() {
+ return `drag-${this.side}`;
+ },
+ cursorStyle() {
+ if (this.enabled) {
+ return { cursor: 'ew-resize' };
+ }
+ return {};
+ },
+ },
+ methods: {
+ resetSize(e) {
+ e.preventDefault();
+ this.$emit('resize-start', this.size);
- this.size = this.startSize;
- this.$emit('update:size', this.size);
+ this.size = this.startSize;
+ this.$emit('update:size', this.size);
- // End resizing on next tick so that listeners can react to DOM changes
- this.$nextTick(() => {
- this.$emit('resize-end', this.size);
- });
- },
- startDrag(e) {
- if (this.enabled) {
- e.preventDefault();
- this.startPos = e.clientX;
- this.currentStartSize = this.size;
- document.addEventListener('mousemove', this.drag);
- document.addEventListener('mouseup', this.endDrag, { once: true });
- this.$emit('resize-start', this.size);
- }
- },
- drag(e) {
+ // End resizing on next tick so that listeners can react to DOM changes
+ this.$nextTick(() => {
+ this.$emit('resize-end', this.size);
+ });
+ },
+ startDrag(e) {
+ if (this.enabled) {
e.preventDefault();
- let moved = e.clientX - this.startPos;
- if (this.side === 'left') moved = -moved;
- let newSize = this.currentStartSize + moved;
- if (newSize < this.minSize) {
- newSize = this.minSize;
- } else if (newSize > this.maxSize) {
- newSize = this.maxSize;
- }
- this.size = newSize;
+ this.startPos = e.clientX;
+ this.currentStartSize = this.size;
+ document.addEventListener('mousemove', this.drag);
+ document.addEventListener('mouseup', this.endDrag, { once: true });
+ this.$emit('resize-start', this.size);
+ }
+ },
+ drag(e) {
+ e.preventDefault();
+ let moved = e.clientX - this.startPos;
+ if (this.side === 'left') moved = -moved;
+ let newSize = this.currentStartSize + moved;
+ if (newSize < this.minSize) {
+ newSize = this.minSize;
+ } else if (newSize > this.maxSize) {
+ newSize = this.maxSize;
+ }
+ this.size = newSize;
- this.$emit('update:size', newSize);
- },
- endDrag(e) {
- e.preventDefault();
- document.removeEventListener('mousemove', this.drag);
- this.$emit('resize-end', this.size);
- },
+ this.$emit('update:size', newSize);
+ },
+ endDrag(e) {
+ e.preventDefault();
+ document.removeEventListener('mousemove', this.drag);
+ this.$emit('resize-end', this.size);
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/pikaday.vue b/app/assets/javascripts/vue_shared/components/pikaday.vue
index bfeece12077..26c99aecae4 100644
--- a/app/assets/javascripts/vue_shared/components/pikaday.vue
+++ b/app/assets/javascripts/vue_shared/components/pikaday.vue
@@ -1,62 +1,62 @@
<script>
- import Pikaday from 'pikaday';
- import { parsePikadayDate, pikadayToString } from '../../lib/utils/datefix';
+import Pikaday from 'pikaday';
+import { parsePikadayDate, pikadayToString } from '~/lib/utils/datetime_utility';
- export default {
- name: 'DatePicker',
- props: {
- label: {
- type: String,
- required: false,
- default: 'Date picker',
- },
- selectedDate: {
- type: Date,
- required: false,
- default: null,
- },
- minDate: {
- type: Date,
- required: false,
- default: null,
- },
- maxDate: {
- type: Date,
- required: false,
- default: null,
- },
+export default {
+ name: 'DatePicker',
+ props: {
+ label: {
+ type: String,
+ required: false,
+ default: 'Date picker',
},
- mounted() {
- this.calendar = new Pikaday({
- field: this.$el.querySelector('.dropdown-menu-toggle'),
- theme: 'gitlab-theme animate-picker',
- format: 'yyyy-mm-dd',
- container: this.$el,
- defaultDate: this.selectedDate,
- setDefaultDate: !!this.selectedDate,
- minDate: this.minDate,
- maxDate: this.maxDate,
- parse: dateString => parsePikadayDate(dateString),
- toString: date => pikadayToString(date),
- onSelect: this.selected.bind(this),
- onClose: this.toggled.bind(this),
- });
-
- this.$el.append(this.calendar.el);
- this.calendar.show();
+ selectedDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ minDate: {
+ type: Date,
+ required: false,
+ default: null,
},
- beforeDestroy() {
- this.calendar.destroy();
+ maxDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ },
+ mounted() {
+ this.calendar = new Pikaday({
+ field: this.$el.querySelector('.dropdown-menu-toggle'),
+ theme: 'gitlab-theme animate-picker',
+ format: 'yyyy-mm-dd',
+ container: this.$el,
+ defaultDate: this.selectedDate,
+ setDefaultDate: !!this.selectedDate,
+ minDate: this.minDate,
+ maxDate: this.maxDate,
+ parse: dateString => parsePikadayDate(dateString),
+ toString: date => pikadayToString(date),
+ onSelect: this.selected.bind(this),
+ onClose: this.toggled.bind(this),
+ });
+
+ this.$el.append(this.calendar.el);
+ this.calendar.show();
+ },
+ beforeDestroy() {
+ this.calendar.destroy();
+ },
+ methods: {
+ selected(dateText) {
+ this.$emit('newDateSelected', this.calendar.toString(dateText));
},
- methods: {
- selected(dateText) {
- this.$emit('newDateSelected', this.calendar.toString(dateText));
- },
- toggled() {
- this.$emit('hidePicker');
- },
+ toggled() {
+ this.$emit('hidePicker');
},
- };
+ },
+};
</script>
<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 97ca4d93bd7..1a2fd2ad985 100644
--- a/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
+++ b/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
@@ -1,6 +1,5 @@
<script>
-
- /* This is a re-usable vue component for rendering a project avatar that
+/* This is a re-usable vue component for rendering a project avatar that
does not need to link to the project's profile. The image and an optional
tooltip can be configured by props passed to this component.
@@ -16,70 +15,70 @@
*/
- import defaultAvatarUrl from 'images/no_avatar.png';
- import { placeholderImage } from '../../../lazy_loader';
- import tooltip from '../../directives/tooltip';
+import defaultAvatarUrl from 'images/no_avatar.png';
+import { placeholderImage } from '../../../lazy_loader';
+import tooltip from '../../directives/tooltip';
- export default {
- name: 'ProjectAvatarImage',
- directives: {
- tooltip,
+export default {
+ name: 'ProjectAvatarImage',
+ directives: {
+ tooltip,
+ },
+ props: {
+ lazy: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ imgSrc: {
+ type: String,
+ required: false,
+ default: defaultAvatarUrl,
+ },
+ cssClasses: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ imgAlt: {
+ type: String,
+ required: false,
+ default: 'project avatar',
+ },
+ size: {
+ type: Number,
+ required: false,
+ default: 20,
+ },
+ tooltipText: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ tooltipPlacement: {
+ type: String,
+ required: false,
+ default: 'top',
+ },
+ },
+ computed: {
+ // API response sends null when gravatar is disabled and
+ // we provide an empty string when we use it inside project avatar link.
+ // In both cases we should render the defaultAvatarUrl
+ sanitizedSource() {
+ return this.imgSrc === '' || this.imgSrc === null ? defaultAvatarUrl : this.imgSrc;
+ },
+ resultantSrcAttribute() {
+ return this.lazy ? placeholderImage : this.sanitizedSource;
},
- props: {
- lazy: {
- type: Boolean,
- required: false,
- default: false,
- },
- imgSrc: {
- type: String,
- required: false,
- default: defaultAvatarUrl,
- },
- cssClasses: {
- type: String,
- required: false,
- default: '',
- },
- imgAlt: {
- type: String,
- required: false,
- default: 'project avatar',
- },
- size: {
- type: Number,
- required: false,
- default: 20,
- },
- tooltipText: {
- type: String,
- required: false,
- default: '',
- },
- tooltipPlacement: {
- type: String,
- required: false,
- default: 'top',
- },
+ tooltipContainer() {
+ return this.tooltipText ? 'body' : null;
},
- computed: {
- // API response sends null when gravatar is disabled and
- // we provide an empty string when we use it inside project avatar link.
- // In both cases we should render the defaultAvatarUrl
- sanitizedSource() {
- return this.imgSrc === '' || this.imgSrc === null ? defaultAvatarUrl : this.imgSrc;
- },
- resultantSrcAttribute() {
- return this.lazy ? placeholderImage : this.sanitizedSource;
- },
- tooltipContainer() {
- return this.tooltipText ? 'body' : null;
- },
- avatarSizeClass() {
- return `s${this.size}`;
- },
+ avatarSizeClass() {
+ return `s${this.size}`;
},
- };
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
index a2a9a5e6987..09394847b10 100644
--- a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue
@@ -1,67 +1,67 @@
<script>
- import DeprecatedModal from './deprecated_modal.vue';
+import DeprecatedModal from './deprecated_modal.vue';
- export default {
- name: 'RecaptchaModal',
+export default {
+ name: 'RecaptchaModal',
- components: {
- DeprecatedModal,
- },
+ components: {
+ DeprecatedModal,
+ },
- props: {
- html: {
- type: String,
- required: false,
- default: '',
- },
+ props: {
+ html: {
+ type: String,
+ required: false,
+ default: '',
},
+ },
- data() {
- return {
- script: {},
- scriptSrc: 'https://www.google.com/recaptcha/api.js',
- };
- },
+ data() {
+ return {
+ script: {},
+ scriptSrc: 'https://www.google.com/recaptcha/api.js',
+ };
+ },
- watch: {
- html() {
- this.appendRecaptchaScript();
- },
+ watch: {
+ html() {
+ this.appendRecaptchaScript();
},
+ },
- mounted() {
- window.recaptchaDialogCallback = this.submit.bind(this);
- },
+ mounted() {
+ window.recaptchaDialogCallback = this.submit.bind(this);
+ },
- methods: {
- appendRecaptchaScript() {
- this.removeRecaptchaScript();
+ methods: {
+ appendRecaptchaScript() {
+ this.removeRecaptchaScript();
- const script = document.createElement('script');
- script.src = this.scriptSrc;
- script.classList.add('js-recaptcha-script');
- script.async = true;
- script.defer = true;
+ const script = document.createElement('script');
+ script.src = this.scriptSrc;
+ script.classList.add('js-recaptcha-script');
+ script.async = true;
+ script.defer = true;
- this.script = script;
+ this.script = script;
- document.body.appendChild(script);
- },
+ document.body.appendChild(script);
+ },
- removeRecaptchaScript() {
- if (this.script instanceof Element) this.script.remove();
- },
+ removeRecaptchaScript() {
+ if (this.script instanceof Element) this.script.remove();
+ },
- close() {
- this.removeRecaptchaScript();
- this.$emit('close');
- },
+ close() {
+ this.removeRecaptchaScript();
+ this.$emit('close');
+ },
- submit() {
- this.$el.querySelector('form').submit();
- },
+ submit() {
+ this.$el.querySelector('form').submit();
},
- };
+ },
+};
</script>
<template>
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 9d757b27edc..500586302cf 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
@@ -1,96 +1,96 @@
<script>
- import datePicker from '../pikaday.vue';
- import toggleSidebar from './toggle_sidebar.vue';
- import collapsedCalendarIcon from './collapsed_calendar_icon.vue';
- import { dateInWords } from '../../../lib/utils/datetime_utility';
+import datePicker from '../pikaday.vue';
+import toggleSidebar from './toggle_sidebar.vue';
+import collapsedCalendarIcon from './collapsed_calendar_icon.vue';
+import { dateInWords } from '../../../lib/utils/datetime_utility';
- export default {
- name: 'SidebarDatePicker',
- components: {
- datePicker,
- toggleSidebar,
- collapsedCalendarIcon,
- },
- props: {
- blockClass: {
- type: String,
- required: false,
- default: '',
- },
- collapsed: {
- type: Boolean,
- required: false,
- default: true,
- },
- showToggleSidebar: {
- type: Boolean,
- required: false,
- default: false,
- },
- isLoading: {
- type: Boolean,
- required: false,
- default: false,
- },
- editable: {
- type: Boolean,
- required: false,
- default: false,
- },
- label: {
- type: String,
- required: false,
- default: 'Date picker',
- },
- selectedDate: {
- type: Date,
- required: false,
- default: null,
- },
- minDate: {
- type: Date,
- required: false,
- default: null,
- },
- maxDate: {
- type: Date,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- editing: false,
- };
- },
- computed: {
- selectedAndEditable() {
- return this.selectedDate && this.editable;
- },
- selectedDateWords() {
- return dateInWords(this.selectedDate, true);
- },
- collapsedText() {
- return this.selectedDateWords ? this.selectedDateWords : 'None';
- },
- },
- methods: {
- stopEditing() {
- this.editing = false;
- },
- toggleDatePicker() {
- this.editing = !this.editing;
- },
- newDateSelected(date = null) {
- this.date = date;
- this.editing = false;
- this.$emit('saveDate', date);
- },
- toggleSidebar() {
- this.$emit('toggleCollapse');
- },
- },
- };
+export default {
+ name: 'SidebarDatePicker',
+ components: {
+ datePicker,
+ toggleSidebar,
+ collapsedCalendarIcon,
+ },
+ props: {
+ blockClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ collapsed: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ showToggleSidebar: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ editable: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ label: {
+ type: String,
+ required: false,
+ default: 'Date picker',
+ },
+ selectedDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ minDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ maxDate: {
+ type: Date,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ editing: false,
+ };
+ },
+ computed: {
+ selectedAndEditable() {
+ return this.selectedDate && this.editable;
+ },
+ selectedDateWords() {
+ return dateInWords(this.selectedDate, true);
+ },
+ collapsedText() {
+ return this.selectedDateWords ? this.selectedDateWords : 'None';
+ },
+ },
+ methods: {
+ stopEditing() {
+ this.editing = false;
+ },
+ toggleDatePicker() {
+ this.editing = !this.editing;
+ },
+ newDateSelected(date = null) {
+ this.date = date;
+ this.editing = false;
+ this.$emit('saveDate', date);
+ },
+ toggleSidebar() {
+ this.$emit('toggleCollapse');
+ },
+ },
+};
</script>
<template>
diff --git a/app/assets/javascripts/vue_shared/components/table_pagination.vue b/app/assets/javascripts/vue_shared/components/table_pagination.vue
index 8e9621c956f..03a5a078879 100644
--- a/app/assets/javascripts/vue_shared/components/table_pagination.vue
+++ b/app/assets/javascripts/vue_shared/components/table_pagination.vue
@@ -1,17 +1,17 @@
<script>
- import { s__ } from '../../locale';
-
- const PAGINATION_UI_BUTTON_LIMIT = 4;
- const UI_LIMIT = 6;
- const SPREAD = '...';
- const PREV = s__('Pagination|Prev');
- const NEXT = s__('Pagination|Next');
- const FIRST = s__('Pagination|« First');
- const LAST = s__('Pagination|Last »');
-
- export default {
- props: {
- /**
+import { s__ } from '../../locale';
+
+const PAGINATION_UI_BUTTON_LIMIT = 4;
+const UI_LIMIT = 6;
+const SPREAD = '...';
+const PREV = s__('Pagination|Prev');
+const NEXT = s__('Pagination|Next');
+const FIRST = s__('Pagination|« First');
+const LAST = s__('Pagination|Last »');
+
+export default {
+ props: {
+ /**
This function will take the information given by the pagination component
Here is an example `change` method:
@@ -20,12 +20,12 @@
gl.utils.visitUrl(`?page=${pagenum}`);
},
*/
- change: {
- type: Function,
- required: true,
- },
+ change: {
+ type: Function,
+ required: true,
+ },
- /**
+ /**
pageInfo will come from the headers of the API call
in the `.then` clause of the VueResource API call
there should be a function that contructs the pageInfo for this component
@@ -41,94 +41,94 @@
previousPage: +headers['X-Prev-Page'],
});
*/
- pageInfo: {
- type: Object,
- required: true,
- },
+ pageInfo: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ prev() {
+ return this.pageInfo.previousPage;
+ },
+ next() {
+ return this.pageInfo.nextPage;
+ },
+ getItems() {
+ const total = this.pageInfo.totalPages;
+ const { page } = this.pageInfo;
+ const items = [];
+
+ if (page > 1) {
+ items.push({ title: FIRST, first: true });
+ }
+
+ if (page > 1) {
+ items.push({ title: PREV, prev: true });
+ } else {
+ items.push({ title: PREV, disabled: true, prev: true });
+ }
+
+ if (page > UI_LIMIT) items.push({ title: SPREAD, separator: true });
+
+ const start = Math.max(page - PAGINATION_UI_BUTTON_LIMIT, 1);
+ const end = Math.min(page + PAGINATION_UI_BUTTON_LIMIT, total);
+
+ for (let i = start; i <= end; i += 1) {
+ const isActive = i === page;
+ items.push({ title: i, active: isActive, page: true });
+ }
+
+ if (total - page > PAGINATION_UI_BUTTON_LIMIT) {
+ items.push({ title: SPREAD, separator: true, page: true });
+ }
+
+ if (page === total) {
+ items.push({ title: NEXT, disabled: true, next: true });
+ } else if (total - page >= 1) {
+ items.push({ title: NEXT, next: true });
+ }
+
+ if (total - page >= 1) {
+ items.push({ title: LAST, last: true });
+ }
+
+ return items;
+ },
+ showPagination() {
+ return this.pageInfo.totalPages > 1;
},
- computed: {
- prev() {
- return this.pageInfo.previousPage;
- },
- next() {
- return this.pageInfo.nextPage;
- },
- getItems() {
- const total = this.pageInfo.totalPages;
- const { page } = this.pageInfo;
- const items = [];
-
- if (page > 1) {
- items.push({ title: FIRST, first: true });
- }
-
- if (page > 1) {
- items.push({ title: PREV, prev: true });
- } else {
- items.push({ title: PREV, disabled: true, prev: true });
- }
-
- if (page > UI_LIMIT) items.push({ title: SPREAD, separator: true });
-
- const start = Math.max(page - PAGINATION_UI_BUTTON_LIMIT, 1);
- const end = Math.min(page + PAGINATION_UI_BUTTON_LIMIT, total);
-
- for (let i = start; i <= end; i += 1) {
- const isActive = i === page;
- items.push({ title: i, active: isActive, page: true });
- }
-
- if (total - page > PAGINATION_UI_BUTTON_LIMIT) {
- items.push({ title: SPREAD, separator: true, page: true });
- }
-
- if (page === total) {
- items.push({ title: NEXT, disabled: true, next: true });
- } else if (total - page >= 1) {
- items.push({ title: NEXT, next: true });
- }
-
- if (total - page >= 1) {
- items.push({ title: LAST, last: true });
- }
-
- return items;
- },
- showPagination() {
- return this.pageInfo.totalPages > 1;
- },
+ },
+ methods: {
+ changePage(text, isDisabled) {
+ if (isDisabled) return;
+
+ const { totalPages, nextPage, previousPage } = this.pageInfo;
+
+ switch (text) {
+ case SPREAD:
+ break;
+ case LAST:
+ this.change(totalPages);
+ break;
+ case NEXT:
+ this.change(nextPage);
+ break;
+ case PREV:
+ this.change(previousPage);
+ break;
+ case FIRST:
+ this.change(1);
+ break;
+ default:
+ this.change(+text);
+ break;
+ }
},
- methods: {
- changePage(text, isDisabled) {
- if (isDisabled) return;
-
- const { totalPages, nextPage, previousPage } = this.pageInfo;
-
- switch (text) {
- case SPREAD:
- break;
- case LAST:
- this.change(totalPages);
- break;
- case NEXT:
- this.change(nextPage);
- break;
- case PREV:
- this.change(previousPage);
- break;
- case FIRST:
- this.change(1);
- break;
- default:
- this.change(+text);
- break;
- }
- },
- hideOnSmallScreen(item) {
- return !item.first && !item.last && !item.next && !item.prev && !item.active;
- },
+ hideOnSmallScreen(item) {
+ return !item.first && !item.last && !item.next && !item.prev && !item.active;
},
- };
+ },
+};
</script>
<template>
<div
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 368eeb6c453..d760263929a 100644
--- a/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
+++ b/app/assets/javascripts/vue_shared/components/time_ago_tooltip.vue
@@ -11,9 +11,7 @@ export default {
directives: {
tooltip,
},
- mixins: [
- timeagoMixin,
- ],
+ mixins: [timeagoMixin],
props: {
time: {
type: String,
diff --git a/app/assets/javascripts/vue_shared/components/toggle_button.vue b/app/assets/javascripts/vue_shared/components/toggle_button.vue
index 5b9c51786d6..4e9289cbed8 100644
--- a/app/assets/javascripts/vue_shared/components/toggle_button.vue
+++ b/app/assets/javascripts/vue_shared/components/toggle_button.vue
@@ -1,60 +1,60 @@
<script>
- import { s__ } from '../../locale';
- import icon from './icon.vue';
+import { s__ } from '../../locale';
+import icon from './icon.vue';
- const ICON_ON = 'status_success_borderless';
- const ICON_OFF = 'status_failed_borderless';
- const LABEL_ON = s__('ToggleButton|Toggle Status: ON');
- const LABEL_OFF = s__('ToggleButton|Toggle Status: OFF');
+const ICON_ON = 'status_success_borderless';
+const ICON_OFF = 'status_failed_borderless';
+const LABEL_ON = s__('ToggleButton|Toggle Status: ON');
+const LABEL_OFF = s__('ToggleButton|Toggle Status: OFF');
- export default {
- components: {
- icon,
- },
+export default {
+ components: {
+ icon,
+ },
- model: {
- prop: 'value',
- event: 'change',
- },
+ model: {
+ prop: 'value',
+ event: 'change',
+ },
- props: {
- name: {
- type: String,
- required: false,
- default: null,
- },
- value: {
- type: Boolean,
- required: false,
- default: null,
- },
- disabledInput: {
- type: Boolean,
- required: false,
- default: false,
- },
- isLoading: {
- type: Boolean,
- required: false,
- default: false,
- },
+ props: {
+ name: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ value: {
+ type: Boolean,
+ required: false,
+ default: null,
},
+ disabledInput: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
- computed: {
- toggleIcon() {
- return this.value ? ICON_ON : ICON_OFF;
- },
- ariaLabel() {
- return this.value ? LABEL_ON : LABEL_OFF;
- },
+ computed: {
+ toggleIcon() {
+ return this.value ? ICON_ON : ICON_OFF;
+ },
+ ariaLabel() {
+ return this.value ? LABEL_ON : LABEL_OFF;
},
+ },
- methods: {
- toggleFeature() {
- if (!this.disabledInput) this.$emit('change', !this.value);
- },
+ methods: {
+ toggleFeature() {
+ if (!this.disabledInput) this.$emit('change', !this.value);
},
- };
+ },
+};
</script>
<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 ee3157bcb1b..14cb44b8619 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
@@ -1,5 +1,4 @@
<script>
-
/* This is a re-usable vue component for rendering a user avatar wrapped in
a clickable link (likely to the user's profile). The link, image, and
tooltip can be configured by props passed to this component.
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 ef3b16edf5f..8e460566d09 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
@@ -1,5 +1,4 @@
<script>
-
/* This is a re-usable vue component for rendering a user avatar svg (typically
for a blank state). It will receive styles comparable to the user avatar,
but no image is loaded, it isn't wrapped in a link, and tooltips aren't supported.
@@ -42,4 +41,3 @@ export default {
v-html="svg"
/>
</template>
-
diff --git a/app/assets/javascripts/vue_shared/directives/tooltip.js b/app/assets/javascripts/vue_shared/directives/tooltip.js
index 4f2412ce520..549d27e96d9 100644
--- a/app/assets/javascripts/vue_shared/directives/tooltip.js
+++ b/app/assets/javascripts/vue_shared/directives/tooltip.js
@@ -9,6 +9,14 @@ export default {
componentUpdated(el) {
$(el).tooltip('_fixTitle');
+
+ // update visible tooltips
+ const tooltipInstance = $(el).data('bs.tooltip');
+ const tip = tooltipInstance.getTipElement();
+ tooltipInstance.setElementContent(
+ $(tip.querySelectorAll('.tooltip-inner')),
+ tooltipInstance.getTitle(),
+ );
},
unbind(el) {
diff --git a/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js b/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js
index f94cc670edf..67a1632269e 100644
--- a/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js
+++ b/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js
@@ -4,10 +4,7 @@
*
* Components need to have `scope`, `page` and `requestData`
*/
-import {
- historyPushState,
- buildUrlWithCurrentLocation,
-} from '../../lib/utils/common_utils';
+import { historyPushState, buildUrlWithCurrentLocation } from '../../lib/utils/common_utils';
export default {
methods: {
@@ -24,12 +21,14 @@ export default {
// stop polling
this.poll.stop();
- const queryString = Object.keys(parameters).map((parameter) => {
- const value = parameters[parameter];
- // update internal state for UI
- this[parameter] = value;
- return `${parameter}=${encodeURIComponent(value)}`;
- }).join('&');
+ const queryString = Object.keys(parameters)
+ .map(parameter => {
+ const value = parameters[parameter];
+ // update internal state for UI
+ this[parameter] = value;
+ return `${parameter}=${encodeURIComponent(value)}`;
+ })
+ .join('&');
// update polling parameters
this.requestData = parameters;
diff --git a/app/assets/javascripts/vue_shared/models/label.js b/app/assets/javascripts/vue_shared/models/label.js
index d29c7fe973a..2d2732d0661 100644
--- a/app/assets/javascripts/vue_shared/models/label.js
+++ b/app/assets/javascripts/vue_shared/models/label.js
@@ -6,7 +6,7 @@ export default class ListLabel {
this.color = obj.color;
this.textColor = obj.text_color;
this.description = obj.description;
- this.priority = (obj.priority !== null) ? obj.priority : Infinity;
+ this.priority = obj.priority !== null ? obj.priority : Infinity;
}
}
diff --git a/app/assets/javascripts/vue_shared/translate.js b/app/assets/javascripts/vue_shared/translate.js
index 48c63373b77..e0baf03acc3 100644
--- a/app/assets/javascripts/vue_shared/translate.js
+++ b/app/assets/javascripts/vue_shared/translate.js
@@ -1,11 +1,6 @@
-import {
- __,
- n__,
- s__,
- sprintf,
-} from '../locale';
+import { __, n__, s__, sprintf } from '../locale';
-export default (Vue) => {
+export default Vue => {
Vue.mixin({
methods: {
/**
diff --git a/app/assets/javascripts/vue_shared/vue_resource_interceptor.js b/app/assets/javascripts/vue_shared/vue_resource_interceptor.js
index b9693892f45..754025207c8 100644
--- a/app/assets/javascripts/vue_shared/vue_resource_interceptor.js
+++ b/app/assets/javascripts/vue_shared/vue_resource_interceptor.js
@@ -21,7 +21,7 @@ Vue.http.interceptors.push((request, next) => {
Vue.http.interceptors.push((request, next) => {
request.headers.set(csrf.headerKey, csrf.token);
- next((response) => {
+ next(response => {
// Headers object has a `forEach` property that iterates through all values.
const headers = {};
diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js
index bdb2351c344..e98c4d7bf7a 100644
--- a/app/assets/javascripts/zen_mode.js
+++ b/app/assets/javascripts/zen_mode.js
@@ -47,16 +47,26 @@ export default class ZenMode {
e.preventDefault();
return $(e.currentTarget).trigger('zen_mode:leave');
});
- $(document).on('zen_mode:enter', (function(_this) {
- return function(e) {
- return _this.enter($(e.target).closest('.md-area').find('.zen-backdrop'));
- };
- })(this));
- $(document).on('zen_mode:leave', (function(_this) {
- return function(e) {
- return _this.exit();
- };
- })(this));
+ $(document).on(
+ 'zen_mode:enter',
+ (function(_this) {
+ return function(e) {
+ return _this.enter(
+ $(e.target)
+ .closest('.md-area')
+ .find('.zen-backdrop'),
+ );
+ };
+ })(this),
+ );
+ $(document).on(
+ 'zen_mode:leave',
+ (function(_this) {
+ return function(e) {
+ return _this.exit();
+ };
+ })(this),
+ );
$(document).on('keydown', function(e) {
// Esc
if (e.keyCode === 27) {
@@ -93,7 +103,7 @@ export default class ZenMode {
scrollTo(zen_area) {
return $.scrollTo(zen_area, 0, {
- offset: -150
+ offset: -150,
});
}
}